Mapping.Value
Mapping.Value is what you put into any mapping field that expects a value:
data, every entry under map, entries in set[], keys under policy, and
anywhere a destination rule field accepts any. It is polymorphic: a value can
be a simple string path, an object with one of several transforming keys, or an
array of those, which is a fallback chain: the first entry that resolves wins.
The shape is defined in
packages/core/src/types/mapping.ts
as Value = ValueType | Array<ValueType>, where ValueType is either a string
(path) or a ValueConfig object.
Options
| Form | Shape | What / When |
|---|---|---|
| Path | string | Reads a dot-path from the event. Use for copying raw fields straight into the output. |
| Constant | { value } | Emits a fixed value. Use when the destination needs a literal like a currency, ID, or label. |
| Map | { map: { key: Value, … } } | Builds an object from multiple paths. Use when the destination expects a structured payload. |
| Loop | { loop: [source, Value] } | Iterates an array source and transforms each item. Use for nested product, cart, or item lists. |
| Set | { set: [Value, Value, …] } | Builds an array from several values, in order. Use when the destination expects a list. |
| Fn | { fn: (value, context) => … } | Runs a custom function on the event. Use only when no declarative form fits. |
| Condition | { condition, value } | Gates the value on a predicate. Use for branching logic inside a single rule. |
| Consent | { consent: {…}, value } | Gates the value on consent states. Use to make individual fields privacy-aware. |
A ValueConfig uses one producer plus optional filters. key, fn, map,
loop and set each produce the value, so set exactly one. If you set several,
exactly one runs, in this order, and the rest never run: loop, map, set,
key, fn. value is the fallback when the producer returns nothing,
including a loop over something that is not a list. condition, consent
and validate filter the result and combine freely.
To read a field and then transform it, use fn alone. It receives the whole
source object, so fn: (source) => source.user.email.split('@')[1] does both
steps in one place. For an event field you can also rewrite it with a policy
entry and read it with key. Anything bigger belongs in a transformer.
The examples below run live: edit one and its result updates. Each calls
getMappingValue with a running collector in its context ({ collector },
from startFlow), as a step's mapping does.
Path
Extract a value by dot-path from the event.
Paths also index into arrays:
Constant
Return a fixed value, independent of the event.
Map
Build an object by mapping keys to their own Mapping.Value.
Loop
Iterate an array source and transform each element. loop: [source, value]:
source selects the array (a path, or 'this' for the event itself), value
transforms each item.
Each item is mapped under the event's consent. A loop item's consent key
neither unlocks nor holds back a value; the event's consent decides. A
condition or fn inside the item mapping sees that same consent in
context.consent.
Set
Resolve every value and return them as an array, in order. A value that resolves to nothing keeps its position as an empty entry.
{ set: ['data.id', 'data.name'] } // ['P1', 'Shirt']
For a fallback chain, where the first value that resolves wins, use a plain
array instead: ['data.email', 'user.email', { value: 'anonymous' }].
Fn
Run a custom function. The handler receives (value, context) and may return
a promise. All three callbacks (fn, condition, validate) share the same
shape.
Context object
| Field | Type | Required | Description |
|---|---|---|---|
event | WalkerOS.DeepPartialEvent | yes | The root event being mapped |
mapping | Mapping.Value | Mapping.Rule | yes | The surrounding mapping config (or rule) |
collector | Collector.Instance | yes | Active collector, use for push and queue |
logger | Logger.Instance | yes | Use for info/warn/error/debug |
consent | WalkerOS.Consent (optional) | no | Resolved consent at this evaluation point |
One-arg callbacks like (value) => value.toUpperCase() continue to work,
TypeScript ignores the unused context argument.
Condition
Only produce output when condition(event) returns truthy.
{
condition: (event) => event.data?.value > 50,
value: 'high_value',
}
Consent
Only produce output when the required consent states are granted on the event.
Nothing: marketing consent is false on the event, so the value is dropped. Set consent.marketing to true in the input to see john@example.com.
Validate
validate is a filter, not a form. Combine it with any value-producing key.
The function runs on the produced value; if it returns falsy the result is
dropped (undefined).
Policy
A policy is a record of Mapping.Values applied to the event before the rule
runs. The key is the path the result writes into; the value is any form above.
Config-level policy applies to every event handled by the source or destination:
{
config: {
policy: {
'user.email': { fn: (e) => e.user?.email?.toLowerCase() },
'data.timestamp': { fn: () => Date.now() },
},
},
}Event-level policy applies only inside the matched rule:
{
config: {
mapping: {
product: {
view: {
name: 'view_item',
policy: {
'data.id': { fn: (e) => `PRODUCT_${e.data?.id}` },
},
},
},
},
},
}Processing order: config policy → event matching → event policy → data transformation.
See also
- Mapping.Rule: the rule object that composes values
getMappingValueAPI: programmatic value resolution- Consent guide: consent model in depth