type MatchExpression = MatchCondition | { and: MatchExpression[]; } | { or: MatchExpression[]; }; interface MatchCondition { key: string; operator: MatchOperator; value: string; not?: boolean; } type MatchOperator = 'eq' | 'contains' | 'prefix' | 'suffix' | 'regex' | 'gt' | 'lt' | 'exists'; type CompiledMatcher = (context: Record) => boolean; type matcher_CompiledMatcher = CompiledMatcher; type matcher_MatchCondition = MatchCondition; type matcher_MatchExpression = MatchExpression; type matcher_MatchOperator = MatchOperator; declare namespace matcher { export type { matcher_CompiledMatcher as CompiledMatcher, matcher_MatchCondition as MatchCondition, matcher_MatchExpression as MatchExpression, matcher_MatchOperator as MatchOperator }; } /** * Shared mapping configuration interface. * Used by both Source.Config and Destination.Config. */ interface Config$7 { consent?: Consent; data?: Value | Values; include?: string[]; mapping?: Rules>; policy?: Policy$1; } interface Policy$1 { [key: string]: Value; } interface Rules { [entity: string]: Record> | undefined; } interface Rule { /** * Batch scheduling for this event mapping. When present, it splits this * event type into its own buffer, overriding `config.batch` per field * (`rule ?? config ?? default`). A bare number is the debounce `wait` * window. Object form supports `wait` (debounce ms), `size` (count cap), * and `age` (max ms since first entry). */ batch?: number | BatchOptions; condition?: Condition; consent?: Consent; settings?: Settings; data?: Data$1; include?: string[]; ignore?: boolean; silent?: boolean; name?: string; policy?: Policy$1; /** * Merge mode (config layer): a partial Rule deep-merged onto the * package-shipped default rule at the same key, instead of replacing it. * Resolved at the consuming package's init via `mergeMappingRule`; not * seen by the runtime evaluator. A `null` value clears an inherited field. * Presence of `extend` or `remove` switches this rule from replace to merge. */ extend?: RulePatch; /** * Output layer: dotted paths stripped from the produced data payload * after evaluation, regardless of how each field was produced. Applied * last, so it always wins. */ remove?: string[]; } /** * A partial Rule used by `Rule.extend`. Every field is optional, and a * `null` value clears the inherited field (JSON merge-patch delete). The * control fields `extend` and `remove` are excluded: a patch models only * direct rule fields, matching what the runtime patch schema accepts. */ type RulePatchFields = Omit, 'extend' | 'remove'>; type RulePatch = { [K in keyof RulePatchFields]?: RulePatchFields[K] | null; }; interface Result$2 { eventMapping?: Rule; mappingKey?: string; } type Data$1 = Value | Values; type Value = ValueType | Array; type Values = Array; type ValueType = string | ValueConfig; interface ValueConfig { condition?: Condition; consent?: Consent; fn?: Fn$4; key?: string; loop?: Loop; map?: Map; set?: Value[]; validate?: Validate; value?: PropertyType; } interface Context$6 { event: DeepPartialEvent; /** The surrounding mapping config: a Value (value-level) or a Rule (rule-level). */ mapping: Value | Rule; collector: Instance$6; logger: Instance$3; consent?: Consent; } type Fn$4 = (value: unknown, context: Context$6) => PromiseOrValue; type Condition = (value: unknown, context: Context$6) => PromiseOrValue; type Validate = (value: unknown, context: Context$6) => PromiseOrValue; type Loop = [Value, Value]; type Map = { [key: string]: Value; }; type mapping_Condition = Condition; type mapping_Loop = Loop; type mapping_Map = Map; type mapping_Rule = Rule; type mapping_RulePatch = RulePatch; type mapping_Rules = Rules; type mapping_Validate = Validate; type mapping_Value = Value; type mapping_ValueConfig = ValueConfig; type mapping_ValueType = ValueType; type mapping_Values = Values; declare namespace mapping { export type { mapping_Condition as Condition, Config$7 as Config, Context$6 as Context, Data$1 as Data, Fn$4 as Fn, mapping_Loop as Loop, mapping_Map as Map, Policy$1 as Policy, Result$2 as Result, mapping_Rule as Rule, mapping_RulePatch as RulePatch, mapping_Rules as Rules, mapping_Validate as Validate, mapping_Value as Value, mapping_ValueConfig as ValueConfig, mapping_ValueType as ValueType, mapping_Values as Values }; } interface BaseCacheRule { /** * Optional match expression. Omitted means always-match. */ match?: MatchExpression; ttl: number; } interface EventCacheRule extends BaseCacheRule { key: string[]; update?: Record; } interface StoreCacheRule extends BaseCacheRule { } type CacheRule = EventCacheRule | StoreCacheRule; interface Cache { /** * Stop the chain on cache HIT (default: false). When true, skip remaining steps and return cached value. */ stop?: boolean; store?: string; /** * Optional key prefix written to the store. When absent, cache keys are written directly. Same store + same key + same namespace = same cache entry. */ namespace?: string; rules: R[]; } type cache_Cache = Cache; type cache_CacheRule = CacheRule; type cache_EventCacheRule = EventCacheRule; type cache_StoreCacheRule = StoreCacheRule; declare namespace cache { export type { cache_Cache as Cache, cache_CacheRule as CacheRule, cache_EventCacheRule as EventCacheRule, cache_StoreCacheRule as StoreCacheRule }; } /** * Options for responding to an HTTP request. * Same interface for web and server — sources implement the handler. */ interface RespondOptions { /** Response body. Objects are JSON-serialized by source. */ body?: unknown; /** HTTP status code (default: 200). Server-only, ignored by web sources. */ status?: number; /** HTTP response headers. Server-only, ignored by web sources. */ headers?: Record; } /** * Standardized response function available on env for every step. * Idempotent: first call wins, subsequent calls are no-ops. * Created by sources via createRespond(), consumed by any step. */ type RespondFn = (options?: RespondOptions) => void; /** * Creates an idempotent respond function. * The sender callback is source-specific (Express wraps res, Fetch wraps Response, etc.). * * @param sender - Platform-specific function that actually sends the response * @returns Idempotent respond function (first call wins) */ declare function createRespond(sender: (options: RespondOptions) => void): RespondFn; /** * Metadata managed by the runtime. Do not overwrite from step code. * The _ prefix signals "runtime-managed." */ interface IngestMeta { /** Number of steps this data has passed through. */ hops: number; /** Ordered list of step IDs visited. path[0] is always the source ID. */ path: string[]; /** Current chain context, e.g., "destination.ga4.before" or "source.web.next". */ chainPath?: string; } /** * Mutable shared context that accumulates knowledge as data flows through the graph. * * Event = strict schema (analytics data). * Ingest = wild west (pipeline context). * * Any step can read and write arbitrary keys. The `_meta` section is * managed by the runtime — increment hops and append to path before each step. */ interface Ingest { [key: string]: unknown; _meta: IngestMeta; } /** Create a fresh Ingest for a new pipeline invocation. */ declare function createIngest(sourceId: string): Ingest; /** * FlowState is the canonical observation record emitted at each hop in a * walkerOS pipeline. Telemetry helpers populate one of these per (step, * phase) tuple and pass it to a user-supplied emit callback. The shape is * stable across step kinds (source, transformer, collector, destination, * store) so a single observer can correlate work across the pipeline. * * Optional fields are populated only when meaningful for the (step, phase) * pair, or when the telemetry options explicitly opt in (e.g. trace level * for inEvent/outEvent). */ type FlowStatePhase = 'init' | 'in' | 'out' | 'error' | 'skip' | 'flush'; type FlowStepType = 'source' | 'transformer' | 'collector' | 'destination' | 'store'; interface FlowStateBatch { size: number; index: number; } interface FlowState { /** The flow this state belongs to. */ flowId: string; /** * Runtime that produced this state: `web` (browser bundle) or `server` * (Node runtime). Mirrors the originating flow's `config.platform`. * Optional: emitters may omit it; populated when the runtime is known. */ platform?: 'web' | 'server'; /** Step identifier, e.g. 'destination.gtag', 'transformer.consent', 'collector.push'. */ stepId: string; stepType: FlowStepType; phase: FlowStatePhase; /** W3C span-id of the originating WalkerOS.Event. Sourced from event.id; never synthesized. */ eventId: string; /** ISO 8601 timestamp. */ timestamp: string; /** Milliseconds since the runtime's startedAt origin. Monotonic. */ elapsedMs: number; /** Wall-clock duration of this step, if measured (typically only on 'out'). */ durationMs?: number; /** Inbound walker event for this hop. Only populated when level === 'trace' or includeIn === true. */ inEvent?: unknown; /** Outbound walker event/payload for this hop. Only populated when level === 'trace' or includeOut === true. */ outEvent?: unknown; /** Error info when phase === 'error'. */ error?: { name?: string; message: string; }; /** The mapping rule that matched, when one matched. */ mappingKey?: string; /** Contract rule that matched, if any. */ contractRule?: string; /** Consent gate snapshot at hop time. */ consent?: Record; /** Consent state actually applied (after policy resolution). */ consentApplied?: Record; /** W3C 16-hex span-id of the child branch for `many` fan-out. */ branchId?: string; /** For phase === 'flush', the batch size + entry index. */ batch?: FlowStateBatch; /** Discriminator when phase === 'skip'. */ skipReason?: 'consent' | 'cache_hit' | 'sampled_out' | 'disabled' | 'unknown'; /** Free-form metadata: store key/value, cached: true, etc. */ meta?: Record; } /** * Pipeline observation channel. Observers receive a FlowState record per * step phase (init, in, out, error, skip, flush) and run synchronously in * the collector's emit loop. They must not throw; emitStep swallows * thrown values defensively so a slow or buggy observer cannot crash the * pipeline. Observers must not perform synchronous IO. */ type ObserverFn = (state: FlowState) => void; /** Identifies which kind of step a stepId belongs to. */ type StepKind = 'collector' | 'source' | 'transformer' | 'destination' | 'store'; /** * Build a stepId for use as a key in `Status.dropped` / * `Status.connectionErrors` (and future status maps). The collector-level * stepId is the literal "collector" (no id). Source/transformer/destination/ * store ids take the form `"."`, e.g. `"destination.ga4"`. * * The dot separator mirrors the vocabulary already used in collector * log messages ("collector.queue overflow", "destination.dlq overflow"). */ declare function stepId(kind: 'collector'): 'collector'; declare function stepId(kind: 'source' | 'transformer' | 'destination' | 'store', id: string): string; /** * Drop counters at a single step. Each buffer is optional: a step kind * may have only `queue` (collector), only `dlq`, both (destinations * today), or neither. Counts are monotonic. */ interface DroppedCounters { queue?: number; dlq?: number; } /** * Circuit-breaker state for a single step (keyed by `stepId()` in * `Status.breakers`). Tracks consecutive transport failures so a step whose * transport is down can be skipped (gated) until a cooldown elapses, instead * of every event hammering a known-broken writer. * * - `closed`: healthy; events pass through. `consecutiveFailures` accrues on * transport failures and resets to 0 on any success. * - `open`: tripped; events are skipped until `openUntil`. The first event at * or after `openUntil` transitions to `half-open` and becomes the probe. * - `half-open`: a single probe event is allowed through; `probing` marks that * the probe slot is taken so concurrent events still skip. A probe success * closes the breaker; a probe failure re-opens it with a fresh `openUntil`. * * `consecutiveFailures` is CONSECUTIVE, not cumulative: a single success * resets it, so only an unbroken run reaching the threshold opens the breaker. */ interface BreakerState { state: 'closed' | 'open' | 'half-open'; consecutiveFailures: number; /** Epoch ms after which an open breaker admits a single probe. */ openUntil?: number; /** True while a half-open probe is in flight (probe slot taken). */ probing?: boolean; } /** * Core collector configuration interface */ interface Config$6 { /** Whether to run collector automatically */ run?: boolean; /** Static global properties even on a new run */ globalsStatic: Properties; /** Static session data even on a new run */ sessionStatic: Partial; /** Logger configuration */ logger?: Config$3; /** * Maximum number of events retained in `collector.queue` for late-registered * destination backfill. Overflow drops oldest (FIFO). Default 1000. */ queueMax?: number; } /** * Initialization configuration that extends Config with initial state */ interface InitConfig extends Partial { /** Initial consent state */ consent?: Consent; /** Initial user data */ user?: User; /** Initial global properties */ globals?: Properties; /** Source configurations */ sources?: InitSources; /** Destination configurations */ destinations?: InitDestinations; /** Transformer configurations */ transformers?: InitTransformers; /** Store configurations */ stores?: InitStores; /** Initial custom properties */ custom?: Properties; /** Hooks for pipeline observation and interception */ hooks?: Functions; } interface SessionData extends Properties { isStart: boolean; storage: boolean; id?: string; start?: number; marketing?: true; updated?: number; isNew?: boolean; device?: string; count?: number; runs?: number; } interface Status { startedAt: number; in: number; out: number; failed: number; sources: Record; destinations: Record; /** * Monotonic counts of events dropped due to buffer caps, keyed by * stepId. See `stepId()` for key construction. * * Examples: * - `dropped["collector"]?.queue`: collector replay buffer drops * - `dropped["destination.ga4"]?.queue`: ga4's consent-denied buffer drops * - `dropped["destination.ga4"]?.dlq`: ga4's dead-letter queue drops */ dropped: Record; /** * Per-step circuit-breaker state, keyed by stepId. See `stepId()` for key * construction; keyed step-agnostically (NOT embedded in * `DestinationStatus`) so the breaker can guard any step kind, though * destinations are the primary use today. A breaker is created lazily on * first accounting and stays inert unless its step is configured with a * `breaker` (presence-gated): existing flows never trip a breaker. * * A runtime status field, not drift-guarded (it is observed, never authored * in a flow config). * * Example: * - `breakers["destination.bigquery"]`: bigquery's consecutive-failure gate. */ breakers: Record; /** * Monotonic counts of out-of-band connection-level errors reported by a * step via `context.reportError(err)` with no event (an orphan error from * an EventEmitter SDK object's `'error'` handler), keyed by stepId. See * `stepId()` for key construction; mirrors `dropped`. * * Distinct from `failed`: `failed` counts events lost in-band (a push that * threw, a DLQ'd entry). `connectionErrors` counts connection faults that * did not lose a specific event at the moment they fired. Operators read * both: a rising `connectionErrors` with flat `failed` means a writer is * flapping but events are still landing; both rising means the fault is * now dropping events. * * Example: * - `connectionErrors["destination.bigquery"]`: BigQuery stream writer * `'error'` events reported between pushes. */ connectionErrors: Record; } interface SourceStatus { count: number; lastAt?: number; duration: number; } interface DestinationStatus { count: number; failed: number; lastAt?: number; duration: number; /** Current size of the destination's queuePush buffer (point-in-time). */ queuePushSize: number; /** Current size of the destination's DLQ (point-in-time). */ dlqSize: number; /** * Number of events buffered in batch scheduler windows but not yet * delivered to `pushBatch`. Incremented on enqueue, decremented on * flush (whether the flush succeeds or fails). Operators read this * to spot batches that never drain. */ inFlightBatch?: number; } interface Sources { [id: string]: Instance$2; } interface Destinations$1 { [id: string]: Instance$5; } interface Transformers$1 { [id: string]: Instance$4; } interface Stores$1 { [id: string]: Instance$1; } type CommandType = 'action' | 'config' | 'consent' | 'context' | 'destination' | 'elb' | 'globals' | 'hook' | 'init' | 'link' | 'run' | 'user' | 'walker' | string; /** * Options passed to collector.push() from sources. * NOT a Context - just push metadata. */ interface PushOptions { id?: string; ingest?: Ingest; respond?: RespondFn; mapping?: Config$7; preChain?: string[]; include?: string[]; exclude?: string[]; } /** * Push function signature - handles events only */ interface PushFn$1 { (event: DeepPartialEvent, options?: PushOptions): Promise; } /** * Command function signature - handles walker commands only */ interface CommandFn { (command: 'config', config: Partial): Promise; (command: 'consent', consent: Consent): Promise; (command: 'destination', init: Init$3): Promise; (command: 'hook', init: { name: K; fn: Functions[K]; }): Promise; (command: 'on', init: { type: Types$2; rules: SingleOrArray; }): Promise; (command: 'user', user: User): Promise; (command: 'run', runState?: { consent?: Consent; user?: User; globals?: Properties; custom?: Properties; }): Promise; (command: string, data?: unknown): Promise; } /** * Per-cascade tracking for the bounded recursion guard (see `Instance.cascade`). * `counts` maps a subscriber identity object to per-cell-type delivery counts * within one top-level command's cascade. A pair is stopped once its count * exceeds the guard's bound; the non-convergence error logs once per pair on the * crossing transition. */ interface Cascade { counts: WeakMap>; } interface Instance$6 { push: PushFn$1; command: CommandFn; allowed: boolean; config: Config$6; consent: Consent; custom: Properties; sources: Sources; destinations: Destinations$1; transformers: Transformers$1; stores: Stores$1; globals: Properties; hooks: Functions; /** * First-class observation channel. The runtime self-emits FlowState * records at canonical step sites (collector.push, destination.push, * destination.init, destination.pushBatch, destination consent skip, * transformer.push, store.get/set/delete, store cache HIT/MISS). * Observers run synchronously inside emitStep; thrown values are * swallowed. Subscribers add/remove via the standard Set API. */ observers: Set; logger: Instance$3; on: OnConfig; queue: Events; round: number; /** Run-scoped W3C trace id, minted on each run and stamped onto events. */ trace?: string; /** Per-run emission sequence; reset on each run, incremented per stamped event. */ count: number; /** * Monotonic counter bumped on every accepted reactive-state mutation * (consent, user, globals, custom). Used for per-subscriber high-water-mark * dedup. Not bumped for non-reactive config changes. */ stateVersion: number; /** * Per-cell change version: the `stateVersion` at which each state cell * (`consent`/`user`/`globals`/`custom`) last changed. Lets delivery dedup be * per-cell — a subscriber owed two cells at the same `stateVersion` receives * both, because each cell's freshness is tracked independently rather than * against the single global `stateVersion`. A missing entry reads as 0. */ cellVersion: Record; /** * Per-subscriber, per-cell high-water mark registry for exactly-once state * delivery. Keys are subscriber identity objects (a ConsentRule object, a * generic-fn, or a source instance); the inner record maps each state-cell * type (`consent`/`user`/`globals`/`custom`) to the `stateVersion` at which * that subscriber was last invoked FOR THAT CELL. A missing entry means never * delivered (sentinel "-infinity", read as -1). A subscriber is invoked for a * cell iff `stateVersion > mark[cell]` AND `allowed === true`. * * Per-cell (not a single scalar per subscriber) so a handler owed two * distinct cells at the same `stateVersion` — e.g. consent and user both * bumped before run — receives both at the run barrier instead of the first * delivery advancing one mark and swallowing the second cell's edge. */ delivery: WeakMap>; /** * Transient per-cascade tracking for the bounded recursion guard. A * top-level state command creates this when it first enters the delivery * cascade and tears it down when it returns; nested commands emitted by * reacting callbacks reuse the same structure. It counts deliveries per * `(subscriber, cell-type)` so a cyclic cascade terminates (and logs once) * instead of recursing until stack overflow. `undefined` between top-level * commands. See `on.ts` `cascadeAllow`. * * This tracker, together with `stateVersion` and `delivery`, assumes top-level * state commands are processed serially on a given collector. Concurrent, * overlapping state commands on one shared collector are not supported (web is * serial; the server per-request path is event push, not state commands). */ cascade?: Cascade; session: undefined | SessionData; status: Status; timing: number; user: User; pending: { destinations: InitDestinations; }; /** * Set true on the first `shutdown` command, guarding re-entrancy: a second * `walker shutdown` must not re-run `destroyAllSteps` and double-close * writers, destinations, or stores. Subsequent shutdown commands no-op. * Initialized to `false` by the collector factory; absence (`undefined`) * is treated as "not yet shut down", so the first shutdown still runs. */ hasShutdown?: boolean; /** * Every event type ever broadcast through `onApply` (state, lifecycle, and * arbitrary). Lets a `require:[]` gate be satisfied by the current * recorded state for events that have no backing cell, including a broadcast * that fired before the requiring step registered. */ seenEvents: Set; } type collector_BreakerState = BreakerState; type collector_Cascade = Cascade; type collector_CommandFn = CommandFn; type collector_CommandType = CommandType; type collector_DestinationStatus = DestinationStatus; type collector_DroppedCounters = DroppedCounters; type collector_InitConfig = InitConfig; type collector_PushOptions = PushOptions; type collector_SessionData = SessionData; type collector_SourceStatus = SourceStatus; type collector_Sources = Sources; type collector_Status = Status; type collector_StepKind = StepKind; declare const collector_stepId: typeof stepId; declare namespace collector { export { type collector_BreakerState as BreakerState, type collector_Cascade as Cascade, type collector_CommandFn as CommandFn, type collector_CommandType as CommandType, type Config$6 as Config, type collector_DestinationStatus as DestinationStatus, type Destinations$1 as Destinations, type collector_DroppedCounters as DroppedCounters, type collector_InitConfig as InitConfig, type Instance$6 as Instance, type PushFn$1 as PushFn, type collector_PushOptions as PushOptions, type collector_SessionData as SessionData, type collector_SourceStatus as SourceStatus, type collector_Sources as Sources, type collector_Status as Status, type collector_StepKind as StepKind, type Stores$1 as Stores, type Transformers$1 as Transformers, collector_stepId as stepId }; } /** * Base context interface for walkerOS stages. * Sources, Transformers, and Destinations extend this. */ interface Base { collector: Instance$6; logger: Instance$3; config: C; env: E; /** * Out-of-band error seam available to every step kind (source, * transformer, store, destination). A step that owns an EventEmitter SDK * object (BigQuery `StreamConnection`, a Redis client, a Kafka producer) * calls this from the object's `'error'` handler, where there is no * surrounding `await`/`tryCatchAsync` to catch into and an unhandled * `'error'` would otherwise crash the process on a detached tick. * * MUST NOT throw (it runs on a detached emitter tick; a throw inside it * would reintroduce the uncaughtException it exists to prevent). * * - With `event`: routes that event through the same per-step failure * accounting an in-band push failure uses (the destination DLQ + the * `failed` counters), so a connection error that loses a specific event * is counted and surfaced exactly like a synchronous push failure. * - Without `event` (an orphan / connection-level error, e.g. a stream * writer that errored between pushes): a contained `logger.error` plus a * bump of `Status.connectionErrors[stepId]`. It does NOT bump * `Status.failed` (no event was lost at this instant; the next push that * hits the broken writer is what gets DLQ'd and counted as failed, so * counting the orphan against `failed` would double-count). */ reportError?(err: unknown, event?: Event): void; } type context_Base = Base; declare namespace context { export type { context_Base as Base }; } /** * Shared credentials types for steps that authenticate against an external * service. A step's `Types['credentials']` points at one of these (or its own * shape); the value resolves via `$env` like any other config field. */ /** * Google-style service account credentials. The common shape for GCP-family * packages (Pub/Sub, Sheets, GCS, DataManager). `project_id` is optional * because some clients derive it from the runtime environment. */ interface ServiceAccount { client_email: string; private_key: string; project_id?: string; } /** * A credential value: either a JSON string (often a `$env` reference) or the * already-parsed object form `T`. */ type Credential = string | T; /** * Declarative store operation. Replaces `$code:` for simple fetch/stash. * key = store side, value = event side, mode = direction. */ interface State { /** Direction. 'delete' is reserved for a later release. */ mode: 'get' | 'set'; /** Store id; defaults to the in-memory `__cache` store when omitted. */ store?: string; /** Resolves against the event to the store key. */ key: Value; /** * set: resolves to the payload to store. * get: its `key`/bare-string path is the event write-target. * Optional at the type level to keep a future `delete` mode non-breaking; * validation requires it for get/set. */ value?: Value; } /** * Shared context for one-shot lifecycle hooks (setup, destroy). * No event pipeline machinery — just config, env, logger, and id. */ interface LifecycleContext { id: string; config: C; env: E; logger: Instance$3; } /** * Setup function signature. Called once via `walkeros setup .`. * Packages own idempotency and error semantics. Return value (if any) is * JSON-stringified to stdout by the CLI for scripting use. */ type SetupFn = (context: LifecycleContext) => PromiseOrValue; /** * Destroy function signature for step lifecycle cleanup. */ type DestroyFn = (context: LifecycleContext) => PromiseOrValue; /** * @deprecated Use `LifecycleContext` instead. Kept as alias for one minor cycle. */ type DestroyContext = LifecycleContext; type lifecycle_DestroyContext = DestroyContext; type lifecycle_DestroyFn = DestroyFn; type lifecycle_LifecycleContext = LifecycleContext; type lifecycle_SetupFn = SetupFn; declare namespace lifecycle { export type { lifecycle_DestroyContext as DestroyContext, lifecycle_DestroyFn as DestroyFn, lifecycle_LifecycleContext as LifecycleContext, lifecycle_SetupFn as SetupFn }; } /** * Base environment requirements interface for walkerOS destinations * * This defines the core interface that destinations can use to declare * their runtime environment requirements. Platform-specific extensions * should extend this interface. */ interface BaseEnv$3 { /** * Generic global properties that destinations may require * Platform-specific implementations can extend this interface */ [key: string]: unknown; } /** * Type bundle for destination generics. * Groups Settings, InitSettings, Mapping, Env, and Setup into a single type parameter. */ interface Types$4 { settings: S; initSettings: I; mapping: M; env: E; setup: U; credentials: C; } /** * Generic constraint for Types - ensures T has required properties for indexed access */ type TypesGeneric$3 = { settings: any; initSettings: any; mapping: any; env: any; setup: any; credentials: any; }; /** * Type extractors for consistent usage with Types bundle */ type Settings$3 = T['settings']; type InitSettings$3 = T['initSettings']; type Mapping$1 = T['mapping']; type Env$3 = T['env']; type SetupOptions$2 = T['setup']; type Credentials$2 = T['credentials']; /** * Inference helper: Extract Types from Instance */ type TypesOf$3 = I extends Instance$5 ? T : never; interface Instance$5 { config: Config$5; queuePush?: Events; queueOn?: Array<{ type: Types$2; data?: unknown; }>; dlq?: DLQ; batches?: BatchRegistry>; type?: string; env?: Env$3; setup?: SetupFn, Env$3>; init?: InitFn$2; push: PushFn; pushBatch?: PushBatchFn; on?: OnFn; destroy?: DestroyFn, Env$3>; } interface Config$5 { /** Required consent states to push events; queues events when not granted. */ consent?: Consent; /** Implementation-specific configuration passed to the init function. */ settings?: InitSettings$3; /** * Optional, strictly-typed credentials slot ($env-resolved). The package * defines the shape via `Types['credentials']`. `settings.` stays the * escape hatch for raw SDK options. */ credentials?: Credentials$2; /** Global data transformation applied to all events; result passed as context.data to push. */ data?: Value | Values; /** Event sections to flatten into context.data. */ include?: string[]; /** Runtime dependencies merged from code and config env; extensible per destination. */ env?: Env$3; /** Destination identifier; auto-generated if not provided. */ id?: string; /** Whether the destination has been initialized; prevents re-initialization. */ init?: boolean; /** Whether to load external scripts (e.g., gtag.js); destination-specific behavior. */ loadScript?: boolean; /** Logger configuration (level, handler) to override the collector's defaults. */ logger?: Config$3; /** Entity-action rules to filter, rename, transform, and batch events for this destination. */ mapping?: Rules>>; /** Pre-processing rules applied to all events before mapping; modifies events in-place. */ policy?: Policy; /** Whether to queue events when consent is not granted; defaults to true. */ queue?: boolean; /** Defer destination initialization until these collector events fire (e.g., `['consent']`). */ require?: string[]; /** * Provisioning options for `walkeros setup`. `boolean | object`. * Triggered only by explicit CLI invocation; never automatic. */ setup?: boolean | SetupOptions$2; /** Transformer chain to run after collector processing but before this destination. */ before?: Route; /** Transformer chain to run after destination push completes. Push response available at ingest._response. */ next?: Route; /** Cache configuration for deduplication (step-level: skip push on HIT). */ cache?: Cache; /** Declarative store get/set operations applied around this destination. */ state?: State | State[]; /** Completely skip this destination — no init, no push, no queuing. */ disabled?: boolean; /** * Per-destination delivery timeout in ms (default 10000); a delivery that * does not settle within this window is routed to the DLQ like a thrown push. */ timeout?: number; /** Return this value instead of calling push(). Uses !== undefined check to support falsy values. */ mock?: unknown; /** * Maximum number of consent-denied events retained in `queuePush` for * this destination. Overflow drops oldest (FIFO). Default 1000. */ queueMax?: number; /** * Maximum number of failed-push entries retained in `dlq` for this * destination. Overflow drops oldest (FIFO). Default 100. */ dlqMax?: number; /** * Enables batching for ALL of this destination's events into one shared * default buffer. A mapping rule's own `batch` splits that entity-action * into its own buffer and overrides per field (`rule ?? config ?? default`). * Batching stays off when neither is set. A bare number is treated as the * debounce `wait` window. * * - `wait`: debounce window in ms; the timer resets on every push. * - `size`: hard count cap; flush immediately when entries reach this number. Default 1000 when batching is enabled. * - `age`: time since the first entry of the current window. Forces a flush even if pushes keep arriving. Default 30000 (30s). */ batch?: number | BatchOptions; /** * Per-destination circuit breaker. Presence-gated: when unset the breaker is * inert and behavior is unchanged. After `threshold` CONSECUTIVE transport * failures (a thrown push, a timed-out push, a whole-batch throw, a * connection-level `reportError(err, event)`) the breaker opens and events * are skipped (counted, not pushed) until `cooldown` ms elapse, then a single * probe event is allowed; its success closes the breaker, its failure * re-opens it. Partial-batch row failures are breaker-neutral. A bare number * is the `threshold`. * * - `threshold`: consecutive transport failures before opening. Default 5. * - `cooldown`: ms an open breaker waits before admitting a probe. Default 30000. */ breaker?: number | BreakerOptions; } /** * Circuit-breaker tuning. Used at the destination-config layer * (`Destination.Config.breaker`). A bare number is treated as `threshold`. */ interface BreakerOptions { /** Consecutive transport failures before the breaker opens. Default 5. */ threshold?: number; /** Milliseconds an open breaker waits before admitting a probe. Default 30000. */ cooldown?: number; } /** * Batch scheduling options. Used at both the mapping-rule layer * (`Mapping.Rule.batch`) and the destination-config layer * (`Destination.Config.batch`). Same shape at both layers. */ interface BatchOptions { /** Debounce window in ms. Timer resets on every push. */ wait?: number; /** Hard count cap. Flushes immediately at this size. */ size?: number; /** Hard age cap in ms since first entry of current window. */ age?: number; } type PartialConfig$2 = Config$5> | Settings$3, Partial> | Mapping$1, Env$3, InitSettings$3, SetupOptions$2, Credentials$2>>; interface Policy { [key: string]: Value; } type Code$1 = Instance$5; type Init$3 = { code: Code$1; config?: Partial>; env?: Partial>; before?: Route; next?: Route; cache?: Cache; state?: State | State[]; }; interface InitDestinations { [key: string]: Init$3; } interface Destinations { [key: string]: Instance$5; } /** * Context provided to destination functions. * Extends base context with destination-specific properties. */ interface Context$5 extends Base, Env$3> { id: string; data?: Data; } interface PushContext extends Context$5 { ingest: Ingest; rule?: Rule>; } interface PushBatchContext extends Context$5 { ingest: Ingest; rule?: Rule>; } type InitFn$2 = (context: Context$5) => PromiseOrValue>; type PushFn = (event: Event, context: PushContext) => PromiseOrValue; /** * Per-row outcome for a single failed batch entry. * * `index` is the position into the flushed batch's `entries` array (the same * order `flushBatch` iterates), so the collector can route exactly that entry * to the DLQ. `error` is the per-row failure carried into the DLQ pair; when * omitted the collector substitutes a generic batch error. */ interface BatchFailure { index: number; error?: unknown; } /** * Partial-failure result of a `pushBatch` call. * * `failed` lists the entries (by index into the flushed batch's `entries` * array) that did NOT succeed. Every other entry is treated as delivered. */ interface BatchOutcome { failed: BatchFailure[]; } /** * Pushes a batch of events to a destination. * * Return contract (backward-compatible, additive): * - Resolve `void` (the historical contract): the WHOLE batch succeeded. The * collector counts every entry as delivered. * - Throw / reject: the WHOLE batch failed. The collector routes every entry * to the DLQ and increments `failed` by the batch size. Unchanged. * - Resolve a `BatchOutcome`: PARTIAL failure. Only the entries listed in * `outcome.failed` (by `index` into the flushed `entries` array) are routed * to the DLQ and counted as failed, each with its own `error`. The remaining * entries are counted as delivered. This lets a destination report row-level * failures without forcing already-succeeded rows onto the DLQ, which would * duplicate them on a later DLQ retry. * * Indices in `failed` must line up with the order of `batch.entries`. */ type PushBatchFn = (batch: Batch>, context: PushBatchContext) => PromiseOrValue; type PushEvent = { event: Event; mapping?: Rule; }; type PushEvents = Array>; interface BatchEntry { event: Event; ingest?: Ingest; respond?: RespondFn; rule?: Rule; data?: Data; } interface Batch { key: string; /** * Per-event entries carrying per-event ingest, respond, rule, and data. * Destinations needing per-event metadata should read this instead of * (or in addition to) `events` and `data`. */ entries: BatchEntry[]; /** Derived view: events from `entries`. Kept for back-compat. */ events: Events; /** Derived view: data from `entries`. Kept for back-compat. */ data: Array; mapping?: Rule; } interface BatchRegistry { [mappingKey: string]: { batched: Batch; /** * Marks a buffer created by `config.batch` (the destination-wide default * batch) rather than a mapping rule's own `batch`. The default buffer is * heterogeneous, so its flush reports `rule: undefined` to consumers. */ isDefault?: boolean; batchFn: () => void; /** * Force a flush of the current batch immediately. Used by shutdown * drain and by tests for deterministic flushing without timer * advancement. Resolves after the underlying `pushBatch` settles. */ flush: () => Promise; }; } type Data = Property | undefined | Array; interface Ref { type: string; data?: unknown; error?: unknown; } type Push$1 = { queuePush?: Events; error?: unknown; }; type DLQ = Array<[Event, unknown]>; /** * Typed accessor for destinations registered on a collector. * * The collector's `destinations` bag indexes to `Destination.Instance` * (defaults erase the generic). Use this helper at the call site to recover * the narrow type without casts. * * @example * type MyDestTypes = Destination.Types; * const dest = getDestination(collector, 'myDest'); * await dest.push(event, context); * * @throws Error with message `Destination not found: ` when the id is unknown. */ declare function getDestination(collector: { destinations: { [id: string]: Instance$5; }; }, id: string): Instance$5; type destination_Batch = Batch; type destination_BatchEntry = BatchEntry; type destination_BatchFailure = BatchFailure; type destination_BatchOptions = BatchOptions; type destination_BatchOutcome = BatchOutcome; type destination_BatchRegistry = BatchRegistry; type destination_BreakerOptions = BreakerOptions; type destination_DLQ = DLQ; type destination_Data = Data; type destination_Destinations = Destinations; type destination_InitDestinations = InitDestinations; type destination_Policy = Policy; type destination_PushBatchContext = PushBatchContext; type destination_PushBatchFn = PushBatchFn; type destination_PushContext = PushContext; type destination_PushEvent = PushEvent; type destination_PushEvents = PushEvents; type destination_PushFn = PushFn; type destination_Ref = Ref; declare const destination_getDestination: typeof getDestination; declare namespace destination { export { type BaseEnv$3 as BaseEnv, type destination_Batch as Batch, type destination_BatchEntry as BatchEntry, type destination_BatchFailure as BatchFailure, type destination_BatchOptions as BatchOptions, type destination_BatchOutcome as BatchOutcome, type destination_BatchRegistry as BatchRegistry, type destination_BreakerOptions as BreakerOptions, type Code$1 as Code, type Config$5 as Config, type Context$5 as Context, type Credentials$2 as Credentials, type destination_DLQ as DLQ, type destination_Data as Data, type destination_Destinations as Destinations, type Env$3 as Env, type Init$3 as Init, type destination_InitDestinations as InitDestinations, type InitFn$2 as InitFn, type InitSettings$3 as InitSettings, type Instance$5 as Instance, type Mapping$1 as Mapping, type PartialConfig$2 as PartialConfig, type destination_Policy as Policy, type Push$1 as Push, type destination_PushBatchContext as PushBatchContext, type destination_PushBatchFn as PushBatchFn, type destination_PushContext as PushContext, type destination_PushEvent as PushEvent, type destination_PushEvents as PushEvents, type destination_PushFn as PushFn, type destination_Ref as Ref, type Settings$3 as Settings, type SetupOptions$2 as SetupOptions, type Types$4 as Types, type TypesGeneric$3 as TypesGeneric, type TypesOf$3 as TypesOf, destination_getDestination as getDestination }; } interface EventFn> { (partialEvent: DeepPartialEvent): R; (event: string): R; (event: string, data: Properties): R; } interface Fn$3, Config = unknown> extends EventFn, WalkerCommands { } interface WalkerCommands, Config = unknown> { (event: 'walker config', config: Partial): R; (event: 'walker consent', consent: Consent): R; (event: 'walker destination', init: Init$3): R; (event: 'walker hook', init: { name: K; fn: Functions[K]; }): R; (event: 'walker on', init: { type: Types$2; rules: SingleOrArray; }): R; (event: 'walker user', user: User): R; (event: 'walker run', runState?: { consent?: Consent; user?: User; globals?: Properties; custom?: Properties; }): R; } type Event$1> = (partialEvent: DeepPartialEvent) => R; type PushData = DeepPartial | Consent | User | Properties; interface PushResult { ok: boolean; event?: Event; done?: Record; queued?: Record; failed?: Record; } type Layer = Array; type elb_EventFn> = EventFn; type elb_Layer = Layer; type elb_PushData = PushData; type elb_PushResult = PushResult; type elb_WalkerCommands, Config = unknown> = WalkerCommands; declare namespace elb { export type { Event$1 as Event, elb_EventFn as EventFn, Fn$3 as Fn, elb_Layer as Layer, elb_PushData as PushData, elb_PushResult as PushResult, elb_WalkerCommands as WalkerCommands }; } /** * Unified route grammar for Flow v4. A `Route` is one of: * - a transformer ID string (`"redact"`) * - a sequence of routes (`["a", "b", "c"]` — sugar for chained `.next`) * - a `RouteConfig` — a gated / dispatching node. * * `RouteConfig` is a disjoint union — set exactly one of `next`, `one`, * `many`, or neither (pure gate). The disjointness is enforced by `never` * sibling properties at the type level and `z.strictObject` at the schema * level. * * Operators: * - `next`: single continuation. * - `one`: first-match dispatch (walk entries, first whose match passes wins). * - `many`: all-match terminal fan-out (every matching entry spawns an * independent flow; main chain terminates here). Restricted to * pre-collector positions (source.next, transformer.next, transformer.before). */ type Route = string | Route[] | RouteConfig; type RouteConfig = RouteNextConfig | RouteOneConfig | RouteManyConfig | RouteGateConfig; interface RouteNextConfig { match?: MatchExpression; next: Route; one?: never; many?: never; } interface RouteOneConfig { match?: MatchExpression; one: Route[]; next?: never; many?: never; } interface RouteManyConfig { match?: MatchExpression; many: Route[]; next?: never; one?: never; } interface RouteGateConfig { match: MatchExpression; next?: never; one?: never; many?: never; } /** * Base environment interface for walkerOS transformers. * * Minimal like Destination - just an extensible object. * Transformers receive dependencies through context, not env. */ interface BaseEnv$2 { [key: string]: unknown; } /** * Type bundle for transformer generics. * Groups Settings, InitSettings, and Env into a single type parameter. * Follows the Source/Destination pattern. * * @template S - Settings configuration type * @template E - Environment type * @template I - InitSettings configuration type (user input) */ interface Types$3 { settings: S; initSettings: I; env: E; } /** * Generic constraint for Types - ensures T has required properties for indexed access. */ type TypesGeneric$2 = { settings: any; initSettings: any; env: any; }; /** * Type extractors for consistent usage with Types bundle. */ type Settings$2 = T['settings']; type InitSettings$2 = T['initSettings']; type Env$2 = T['env']; /** * Inference helper: Extract Types from Instance. */ type TypesOf$2 = I extends Instance$4 ? T : never; /** * Transformer configuration. */ interface Config$4 { settings?: InitSettings$2; env?: Env$2; id?: string; logger?: Config$3; before?: Route; next?: Route; cache?: Cache; /** Declarative store get/set operations applied around this transformer. */ state?: State | State[]; init?: boolean; disabled?: boolean; /** Return this value instead of calling push(). Global mock for all chains. */ mock?: unknown; /** Path-specific mock values keyed by chain path (e.g., "destination.ga4.before"). Takes precedence over global mock. */ chainMocks?: Record; /** * Declarative event-to-event mapping applied when this transformer step * has no `code`. Same field name as on `Destination.Config`, but the * semantic differs by position: on a destination, `mapping` produces a * vendor-shaped payload; on a transformer step, it mutates the event * itself. The collector synthesizes a push that runs * `processEventMapping` and returns the transformed event (or drops it * when a rule has `ignore: true`). * * At the transformer position, only event-mutating fields apply: * `policy`, `mapping[].policy`, `mapping[].name`, `mapping[].ignore`, * `mapping[].consent`, `include`. Vendor-payload fields (`data`, * `mapping[].data`, `silent`) are ignored at this position with a * one-time warning. */ mapping?: Config$7; } /** * Context provided to transformer functions. * Extends base context with transformer-specific properties. */ interface Context$4 extends Base, Env$2> { id: string; ingest: Ingest; } /** * Unified result type for transformer functions. * Replaces the old union return type with a structured object. * * @field event - Modified event to continue with * @field respond - Wrapped respond function for downstream transformers * @field next - Branch to a different chain (replaces BranchResult) */ interface Result$1 { event?: E; respond?: RespondFn; next?: Route; } /** * Result of running a transformer chain. * Returns the processed event (singular, fan-out array, or null if dropped) * alongside the potentially wrapped respond function. * * `stopped` signals pipeline-halt — when set, the caller MUST NOT propagate * the event further downstream (no destinations, no subsequent chains). * Used by `cache.stop: true` on pre-collector transformers so the documented * "downstream transformers and destinations are skipped" semantic holds. */ interface ChainResult { event: DeepPartialEvent | DeepPartialEvent[] | null; respond?: RespondFn; stopped?: true; } /** * The main transformer function. * * Pre-collector transformers use default E = DeepPartialEvent. * Post-collector transformers can use E = Event for type-safe access. * A transformer written for DeepPartialEvent works in both positions * because Event is a subtype of DeepPartialEvent. * * @returns Result - structured result with event, respond, next * @returns Result[] - fan-out: each Result continues independently through remaining chain * @returns void - continue with current event unchanged (passthrough) * @returns false - stop chain, cancel further processing */ type Fn$2 = (event: E, context: Context$4) => PromiseOrValue | Result$1[] | false | void>; /** * Optional initialization function. * Called once before first push. * * @param context - Transformer context * @returns void - initialization successful * @returns false - initialization failed, skip this transformer * @returns Config - return updated config */ type InitFn$1 = (context: Context$4) => PromiseOrValue>; /** * Transformer instance returned by Init function. */ interface Instance$4 { type: string; config: Config$4; push: Fn$2; init?: InitFn$1; destroy?: DestroyFn, Env$2>; } /** * Transformer initialization function. * Creates a transformer instance from context. */ type Init$2 = (context: Context$4>, Env$2, InitSettings$2>>) => Instance$4 | Promise>; /** * Configuration for initializing a transformer. * Used in collector registration. */ type InitTransformer = { /** * Initialization function. When omitted, the entry is a pass-through step: * - If `mapping` is present, the collector synthesizes a mapping-only * push using `processEventMapping`. * - Otherwise it's a named hop that only hosts a `before` / `next` / * `cache` chain. * * Validation: an entry without `code` must declare at least one of * `package`, `before`, `next`, `cache`, `state`, `mapping`. Enforced by * `validateStepEntry` in `@walkeros/core`. */ code?: Init$2; config?: Partial>; env?: Partial>; before?: Route; next?: Route; cache?: Cache; state?: State | State[]; mapping?: Config$7; }; /** * Transformers configuration for collector. * Maps transformer IDs to their initialization configurations. */ interface InitTransformers { [transformerId: string]: InitTransformer; } /** * Active transformer instances registry. */ interface Transformers { [transformerId: string]: Instance$4; } /** * Typed accessor for transformers registered on a collector. * * The collector's `transformers` bag indexes to `Transformer.Instance` * (defaults erase the generic). Use this helper at the call site to recover * the narrow type without casts. * * @example * type MyTransformerTypes = Transformer.Types; * const tx = getTransformer(collector, 'redact'); * await tx.push(event, context); * * @throws Error with message `Transformer not found: ` when the id is unknown. */ declare function getTransformer(collector: { transformers: { [id: string]: Instance$4; }; }, id: string): Instance$4; type transformer_ChainResult = ChainResult; type transformer_InitTransformer = InitTransformer; type transformer_InitTransformers = InitTransformers; type transformer_Route = Route; type transformer_RouteConfig = RouteConfig; type transformer_RouteGateConfig = RouteGateConfig; type transformer_RouteManyConfig = RouteManyConfig; type transformer_RouteNextConfig = RouteNextConfig; type transformer_RouteOneConfig = RouteOneConfig; type transformer_Transformers = Transformers; declare const transformer_getTransformer: typeof getTransformer; declare namespace transformer { export { type BaseEnv$2 as BaseEnv, type transformer_ChainResult as ChainResult, type Config$4 as Config, type Context$4 as Context, type Env$2 as Env, type Fn$2 as Fn, type Init$2 as Init, type InitFn$1 as InitFn, type InitSettings$2 as InitSettings, type transformer_InitTransformer as InitTransformer, type transformer_InitTransformers as InitTransformers, type Instance$4 as Instance, type Result$1 as Result, type transformer_Route as Route, type transformer_RouteConfig as RouteConfig, type transformer_RouteGateConfig as RouteGateConfig, type transformer_RouteManyConfig as RouteManyConfig, type transformer_RouteNextConfig as RouteNextConfig, type transformer_RouteOneConfig as RouteOneConfig, type Settings$2 as Settings, type transformer_Transformers as Transformers, type Types$3 as Types, type TypesGeneric$2 as TypesGeneric, type TypesOf$2 as TypesOf, transformer_getTransformer as getTransformer }; } /** * Structural JSON Schema type. Kept dep-free (no `ajv` import in core) * so the runtime graph of any consumer of `@walkeros/core` does not pull * AJV transitively. */ type JsonSchema = Record; /** * Entity-action keyed event validation schemas. * Wildcard fallback semantic: entity.action → entity.* → *.action → *.*. */ type ValidateEvents = Record>; /** * Flow Configuration System (v4) * * Core types for walkerOS unified configuration. * Platform-agnostic, runtime-focused. * * The Flow system enables "one config to rule them all" - a single * walkeros.config.json file that manages multiple flows * (web_prod, web_stage, server_prod, etc.) with shared configuration * and reusable variables. * * Single declaration merge: `Flow` is both the interface for one flow * and the namespace holding all related types. * * ## Connection Rules * * Sources use `next` to connect to transformers (pre-collector chain). * Sources use `before` for consent-exempt pre-source preprocessing * (decode, validate, authenticate raw input before the source.next chain). * * Destinations use `before` to connect to transformers (post-collector chain). * Destinations use `next` for post-push processing. * * Transformers use `next` to chain to other transformers. The same transformer * pool is shared by both pre-collector and post-collector chains. * * The collector is implicit - it is never referenced directly in connections. * It sits between the source chain and the destination chain automatically. * * Circular `next` references are safely handled at runtime by `walkChain()` * in the collector module (visited-set detection). * * ``` * Source → [before → Preprocessing] → [next → Transformer chain] → Collector → [before → Transformer chain] → Destination → [next → Post-push] * ``` * * @packageDocumentation */ /** * Single flow configuration. * * Represents one deployment target (e.g., web_prod, server_stage). * Platform is determined by `config.platform` ('web' | 'server'). * * Variables cascade (resolveFlowSettings): step > flow > root config. * "step" applies uniformly to source, destination, transformer, and store. */ interface Flow { /** Per-flow configuration: platform, url, settings, bundle. */ config?: Flow.Config; /** * Source configurations (data capture). * * Sources capture events from various origins: * - Browser DOM interactions (clicks, page views) * - DataLayer pushes * - HTTP requests (server-side) * - Cloud function triggers * * Key = unique source identifier (arbitrary) * Value = source reference with package and config */ sources?: Record; /** * Destination configurations (data output). * * Destinations send processed events to external services: * - Google Analytics (gtag) * - Meta Pixel (fbq) * - Custom APIs * - Data warehouses * * Key = unique destination identifier (arbitrary) * Value = destination reference with package and config */ destinations?: Record; /** * Transformer configurations (event transformation). * * Pre-collector (source.next) or post-collector (destination.before). * * Key = unique transformer identifier (referenced by source.next or destination.before) * Value = transformer reference with package and config */ transformers?: Record; /** * Store configurations (key-value storage). * * Stores provide key-value storage consumed by sources, transformers, * and destinations via env injection. Referenced using $store.storeId * prefix in env values. * * Key = unique store identifier (arbitrary) * Value = store reference with package and config */ stores?: Record; /** * Collector configuration (event processing). * * The collector is the central event processing engine. * Configuration includes consent management, global properties, * user identification, and processing rules. */ collector?: InitConfig; /** * Flow-level variables. * Override root variables; overridden by source/destination variables. */ variables?: Flow.Variables; } declare namespace Flow { /** * Complete multi-flow configuration. * Root type for walkeros.config.json files. * * If only one flow exists, it's auto-selected without --flow flag. * Convention: use "default" as the flow name for single-flow configs. * * @example * ```json * { * "version": 4, * "$schema": "https://walkeros.io/schema/flow/v4.json", * "variables": { "CURRENCY": "USD" }, * "flows": { * "default": { "config": { "platform": "web" } } * } * } * ``` */ interface Json { /** Configuration schema version. */ version: 4; /** * JSON Schema reference for IDE validation. * @example "https://walkeros.io/schema/flow/v4.json" */ $schema?: string; /** * Folders to include in the bundle output. * Copied to dist/ during bundle, available at runtime for both local and Docker execution. * * Use for credential files, configuration, or other runtime assets. * Paths are relative to the config file location. * Default: `["./shared"]` if the folder exists, otherwise `[]`. */ include?: string[]; /** * Shared variables for interpolation. * Resolution: destination/source > flow > root. * Syntax: $var.name */ variables?: Variables; /** * Data contract definition. * Entity → action keyed JSON Schema with additive inheritance. */ contract?: Contract; /** * Named flow configurations. * If only one flow exists, it's auto-selected. */ flows: Record; } /** * Per-flow configuration block. * * Groups platform identity, optional public URL, arbitrary settings bag, * and bundle (build-time) configuration. */ interface Config { /** * Platform identity for this flow. * - `web` builds to IIFE format, ES2020 target, browser platform. * - `server` builds to ESM format, Node18 target, node platform. */ platform: 'web' | 'server'; /** * Public URL where this flow is reachable (for cross-flow `$flow.X.url` references). * Set explicitly by the user; the deployment process does not auto-populate it. */ url?: string; /** * Arbitrary key-value settings consumed by the platform runtime. * * For web: typical keys include `windowCollector`, `windowElb`. * For server: reserved for future server-specific options. * * This is a free-form bag — type promotion happens later if patterns emerge. */ settings?: Settings; /** * Bundle configuration: NPM packages to include, transitive dependency * overrides, and extra trace includes for server bundles. * Consumed by the CLI bundler at build time. */ bundle?: Bundle; /** * Observability configuration. Controls whether the runtime emits * FlowState records to a remote observer, and at what verbosity. * * When omitted, the runtime defaults to `{ level: 'standard' }` for * managed deployments. When `level: 'off'`, the bundle ships no * telemetry plumbing at all. */ observe?: Observe; } /** * Observability configuration block. * * - `off` disables telemetry entirely (no hooks installed, no fetch). * - `standard` emits structural FlowState records (no inEvent/outEvent). * - `trace` emits full payloads on every hop. Use only for short debug * windows; the operator can also flip the deployment's `trace_until` * timestamp at runtime to enable trace without a redeploy. */ interface Observe { level?: 'off' | 'standard' | 'trace'; /** Deterministic sample fraction in [0, 1]. Defaults to 1. */ sample?: number; } /** * Reusable values referenced via `$var.name` (with optional deep paths). * Whole-string references preserve native type; inline interpolation requires scalars. */ type Variables = Record; /** * Free-form settings bag inside `Flow.Config.settings`. * Mirrors the package settings convention (arbitrary keys). */ type Settings = Record; /** * Bundle configuration for a flow. * * Groups all build-time bundling concerns: NPM packages to include, * transitive dependency overrides, and extra trace includes (server only). * Consumed by the CLI bundler. * * The `flow.config.bundle.external` sub-field is no longer supported * (replaced by nft tracing in @walkeros/cli@4.x). */ interface Bundle { /** NPM packages to bundle, keyed by package name. */ packages?: Record; /** * Transitive dependency version pins. * * Maps package name to version spec. Applied during bundle package install * to force transitive dependencies to a specific version. Useful for * resolving conflicts between packages that depend on incompatible * versions of a shared dependency. * * @example * ```json * { * "@amplitude/analytics-types": "2.11.1" * } * ``` */ overrides?: Record; /** * Extra paths the bundler must include in the trace output. * * Each entry is either a literal path or a glob (matched via picomatch), * resolved against the bundler's install root. Use as an escape hatch * when the file tracer cannot statically discover an asset (e.g., * dynamic require, runtime configuration files). * * Server flows only. */ traceInclude?: string[]; } /** * Single bundle package entry. */ interface BundlePackage { /** Version specifier (e.g., 'latest', '^2.0.0', '2.1.3'). */ version?: string; /** Named imports to expose from the package. */ imports?: string[]; /** Local path to package directory (takes precedence over version). */ path?: string; } /** * Inline code definition for sources/destinations/transformers/stores. * Used instead of `package` when defining inline functions. */ interface Code { /** "$code:..." function (required). */ push: string; /** Optional instance type identifier. */ type?: string; /** Optional "$code:..." init function. */ init?: string; } /** * Source reference with inline package syntax. * * References a source package and provides configuration. * The package is automatically downloaded and imported during build. * Alternatively, use `code` (string or inline Code) for inline code execution. */ interface Source { /** * Package specifier with optional version. * * Formats: * - `"@walkeros/web-source-browser"` - latest * - `"@walkeros/web-source-browser@2.0.0"` - exact * - `"@walkeros/web-source-browser@^2.0.0"` - semver range * * Optional when `code` is used for inline code execution. */ package?: string; /** * Inline code definition (object form only). * * Object: `{push, type?, init?}` for inline code definition. * For named-export selection from a package, use the `import` field with `package`. */ code?: Code; /** * Named export from `package` to import as this source's implementation. * * Requires `package` to be set. Mutually exclusive with `code`. * * - Top-level identifier only: `/^[A-Za-z_$][A-Za-z0-9_$]*$/`. No dotted paths. * - `package: "X"` alone (no `import`, no `code`) loads X's default export. * - `package: "X"` + `import: "fooFactory"` loads named export `fooFactory` from X. * * @example * ```json * { "package": "@walkeros/web-source-browser", "import": "sourceBrowser" } * ``` */ import?: string; /** * Source-specific configuration. Structure depends on the source package. * Passed to the source's initialization function. */ config?: unknown; /** * Source environment configuration. * Environment-specific settings merged with default source environment. */ env?: unknown; /** * Mark as primary source (provides main ELB). * * The primary source's ELB function is returned by `startFlow()`. * Only one source should be marked as primary per flow. * * @default false */ primary?: boolean; /** * First transformer in pre-source chain (consent-exempt). * * Runs before source.next chain. Consent-exempt because no analytics * event exists yet - these transformers handle transport-level preprocessing * (decode, validate, authenticate, normalize raw input). * Raw request data is available in context.ingest. */ before?: Route; /** * First transformer in pre-collector chain. * * Name of the transformer to execute after this source captures an event. * Creates a pre-collector transformer chain. Chain ends at the collector. * If omitted, events route directly to the collector. * Can be an array for explicit chain control (bypasses transformer.next resolution). */ next?: Route; /** Cache configuration for this source. */ cache?: Cache; /** * Source-level variables (highest priority in cascade). * Overrides flow and root variables. */ variables?: Variables; /** * Named examples for testing and documentation. * Stripped during flow resolution (not included in bundles). */ examples?: StepExamples; } /** * Destination reference with inline package syntax. * * References a destination package and provides configuration. * Structure mirrors `Flow.Source` for consistency. */ interface Destination { /** Package specifier with optional version. Optional when `code` is provided. */ package?: string; /** * Inline code definition (object form only). * * Object: `{push, type?, init?}` for inline code definition. * For named-export selection from a package, use the `import` field with `package`. */ code?: Code; /** * Named export from `package` to import as this destination's implementation. * See `Flow.Source.import` for full rules. * * @example * ```json * { "package": "@walkeros/web-destination-gtag", "import": "destinationGtag" } * ``` */ import?: string; /** * Destination-specific configuration. Typically includes: * - settings: API keys, IDs, endpoints * - mapping: Event transformation rules * - consent: Required consent states * - policy: Processing rules */ config?: unknown; /** Destination environment configuration, merged with default destination environment. */ env?: unknown; /** * First transformer in post-collector chain. * * Name of the transformer to execute before sending events to this destination. * If omitted, events are sent directly from the collector. * Can be an array for explicit chain control. */ before?: Route; /** * First transformer in post-push chain. * * Runs after destination.push completes. The push response is available * at context.ingest._response. Consent is inherited from the destination * gate - no separate consent check needed. */ next?: Route; /** Cache configuration for this destination. */ cache?: Cache; /** Destination-level variables (highest priority in cascade). */ variables?: Variables; /** * Named examples for testing and documentation. * Stripped during flow resolution. */ examples?: StepExamples; } /** * Transformer reference with inline package syntax. * * Transformers transform events in the pipeline between sources and destinations. * Alternatively, use `code` for inline code execution. */ interface Transformer { /** Package specifier with optional version. Optional when `code` is provided. */ package?: string; /** * Inline code definition (object form only). * * Object: `{push, type?, init?}` for inline code definition. * For named-export selection from a package, use the `import` field with `package`. */ code?: Code; /** * Named export from `package` to import as this transformer's implementation. * See `Flow.Source.import` for full rules. * * @example * ```json * { "package": "@walkeros/transformer-ga4", "import": "transformerGa4" } * ``` */ import?: string; /** Transformer-specific configuration. Structure depends on the package. */ config?: unknown; /** Transformer environment configuration. */ env?: unknown; /** * Pre-transformer chain. * * Runs before this transformer's push function. * Enables pre-processing or context loading before the main transform. * Uses the same chain resolution as source.next and destination.before. */ before?: Route; /** * Next transformer in chain. * * Name of the next transformer to execute after this one. * In a pre-collector chain (source.next), terminates at the collector. * In a post-collector chain (destination.before), terminates at the destination. * If omitted, the chain ends and control passes to the next pipeline stage. * Array values define an explicit chain (no walking). Circular references * are safely detected at runtime by `walkChain()`. */ next?: Route; /** Cache configuration for this transformer. */ cache?: Cache; /** Transformer-level variables (highest priority in cascade). */ variables?: Variables; /** * Named examples for testing and documentation. * Stripped during flow resolution. */ examples?: StepExamples; } /** * Store reference with inline package syntax. * * Stores provide key-value storage consumed by other components via env. * Unlike sources/transformers/destinations, stores have no chain properties * (no `next` or `before`) - they are passive infrastructure. */ interface Store { /** Package specifier with optional version. Optional when `code` is provided. */ package?: string; /** * Inline code definition (object form only). * * Object: `{push, type?, init?}` for inline code definition. * For named-export selection from a package, use the `import` field with `package`. */ code?: Code; /** * Named export from `package` to import as this store's implementation. * See `Flow.Source.import` for full rules. * * @example * ```json * { "package": "@walkeros/server-store-fs", "import": "storeFs" } * ``` */ import?: string; /** Store-specific configuration. */ config?: unknown; /** Store environment configuration. */ env?: unknown; /** * Cache configuration for this store. * * When present, the collector wraps the bare store with a cache layer * (read-through, write-through, single-flight). The cache layer may * recursively delegate to another store via `cache.store`. */ cache?: Cache; /** Store-level variables (highest priority in cascade). */ variables?: Variables; /** * Named examples for testing and documentation. * Stripped during flow resolution. */ examples?: StepExamples; } /** * Discriminator for the four step kinds in a Flow. * * Single source of truth for code that branches on step kind (bundler * codegen, validators, CLI helpers). */ type StepKind = 'Source' | 'Transformer' | 'Destination' | 'Store'; /** * Union of the four step interfaces. * * Use this where a function accepts "any step in a flow" — e.g. a * shared `validateReference` that branches on `StepKind` without * narrowing to one specific shape. */ type Step = Source | Transformer | Destination | Store; /** * Named contract map. * Each key is a contract name, each value is a contract rule. * * @example * ```json * { * "default": { "globals": { ... }, "consent": { ... } }, * "web": { "extend": "default", "events": { ... } }, * "server": { "extend": "default", "events": { ... } } * } * ``` */ type Contract = Record; /** * A single named contract rule. * * All sections are optional. Sections mirror WalkerOS.Event fields: * globals, context, custom, user, consent. * Entity-action schemas live under `events`. * * Use `extend` to inherit from another named contract (additive merge). */ interface ContractRule { /** Inherit from another named contract entry. */ extend?: string; /** Contract revision marker. */ tagging?: number; /** Human-readable note. */ description?: string; /** Entity-action keyed JSON Schemas (wildcard fallback at runtime). */ events?: ValidateEvents; /** JSON Schema for the full event. */ schema?: JsonSchema; } /** * JSON Schema object for contract rule validation. * Standard JSON Schema with description/examples annotations. * Compatible with AJV for runtime validation. */ type ContractSchema = Record; /** * Contract action entries keyed by action name. * Each value is a JSON Schema describing the expected WalkerOS.Event shape. * Use "*" as wildcard for all actions of an entity. */ type ContractActions = Record; /** * Entity-action event map used inside contracts. * Keyed by entity name, each value is an action map. * Use "*" as wildcard for all entities or all actions. */ type ContractEvents = Record; /** * Walker command names that a step example can invoke instead of pushing * its `in` as a regular event. Mirrors the `elb('walker ', ...)` * surface in `WalkerCommands` (see types/elb.ts). * * - `config` - update collector config (maps to `elb('walker config', in)`) * - `consent` - update consent state (maps to `elb('walker consent', in)`) * - `user` - update user identification (maps to `elb('walker user', in)`) * - `run` - fire run state (maps to `elb('walker run', in)`) * * Note: `walker destination`, `walker hook`, and `walker on` are * intentionally excluded - they configure wiring, not test data. */ type StepCommand = 'config' | 'consent' | 'user' | 'run'; /** One observable effect: function/method call (`[callable, ...args]`) or return value (`['return', value]`). */ type StepEffect = readonly [callable: string, ...args: unknown[]]; /** The effects a step produces, in execution order. Empty = no observable effect (filtered, passthrough). */ type StepOut = readonly StepEffect[]; /** * Named example pair for a step. * `in` is the input to the step, `out` is the expected output. * * When `command` is set, the test runner invokes * `elb('walker ', in)` instead of pushing `in` as a regular event. * When `command` is absent (default), `in` is pushed as a normal event via * `elb(event)`. */ interface StepExample { /** Human-readable title (overrides camelCase-to-spaced default heading in docs). */ title?: string; description?: string; /** * Whether this example is meant for public consumption (docs, UI, MCP default output). * Defaults to `true`. Set to `false` for test-only fixtures that should stay out of * user-facing surfaces but still run in test suites and remain available to * `flow_simulate` / CLI `--simulate`. */ public?: boolean; in?: unknown; /** Trigger metadata for sources - type and options for the trigger call. */ trigger?: { /** Which mechanism to activate (e.g., 'click', 'POST', 'load'). */ type?: string; /** Mechanism-specific options (e.g., CSS selector, threshold). */ options?: unknown; }; mapping?: unknown; out?: StepOut; /** * Invoke a walker command with `in` instead of pushing `in` as an event. * When set, the test runner calls `elb('walker ', in)`. * When absent (default), `in` is pushed as a regular event. */ command?: StepCommand; } /** Named step examples keyed by scenario name. */ type StepExamples = Record; } type AnyFunction$1

= (...args: P) => R; type Functions = { [key: string]: AnyFunction$1; }; interface Parameter

{ fn: (...args: P) => R; result?: R; } type HookFn = (params: Parameter, ReturnType>, ...args: Parameters) => ReturnType; type hooks_Functions = Functions; type hooks_HookFn = HookFn; declare namespace hooks { export type { AnyFunction$1 as AnyFunction, hooks_Functions as Functions, hooks_HookFn as HookFn }; } /** * Log levels from most to least severe */ declare enum Level { ERROR = 0, WARN = 1, INFO = 2, DEBUG = 3 } /** * Normalized error context extracted from Error objects */ interface ErrorContext { message: string; name: string; stack?: string; cause?: unknown; } /** * Context passed to log handlers * If an Error was passed, it's normalized into the error property */ interface LogContext { [key: string]: unknown; error?: ErrorContext; } /** * Log message function signature * Accepts string or Error as message, with optional context */ type LogFn = (message: string | Error, context?: unknown | Error) => void; /** * Throw function signature - logs error then throws * Returns never as it always throws */ type ThrowFn = (message: string | Error, context?: unknown) => never; /** * Default handler function (passed to custom handlers for chaining) */ type DefaultHandler = (level: Level, message: string, context: LogContext, scope: string[]) => void; /** * Custom log handler function * Receives originalHandler to allow middleware-style chaining */ type Handler = (level: Level, message: string, context: LogContext, scope: string[], originalHandler: DefaultHandler) => void; /** * Logger instance with scoping support * All logs automatically include trace path from scoping */ interface Instance$3 { /** * Log an error message (always visible unless silenced) */ error: LogFn; /** * Log a warning (degraded state, config issues, transient failures) */ warn: LogFn; /** * Log an informational message */ info: LogFn; /** * Log a debug message */ debug: LogFn; /** * Log an error message and throw an Error * Combines logging and throwing in one call */ throw: ThrowFn; /** * Output structured JSON data */ json: (data: unknown) => void; /** * Create a scoped child logger with automatic trace path * @param name - Scope name (e.g., destination type, destination key) * @returns A new logger instance with the scope applied */ scope: (name: string) => Instance$3; } /** * Logger configuration options */ interface Config$3 { /** * Minimum log level to display * @default Level.ERROR */ level?: Level | keyof typeof Level; /** * Custom log handler function * Receives originalHandler to preserve default behavior */ handler?: Handler; /** Custom handler for json() output. Default: console.log(JSON.stringify(data, null, 2)) */ jsonHandler?: (data: unknown) => void; } /** * Internal config with resolved values and scope */ interface InternalConfig { level: Level; handler?: Handler; jsonHandler?: (data: unknown) => void; scope: string[]; } /** * Logger factory function type */ type Factory = (config?: Config$3) => Instance$3; type logger_DefaultHandler = DefaultHandler; type logger_ErrorContext = ErrorContext; type logger_Factory = Factory; type logger_Handler = Handler; type logger_InternalConfig = InternalConfig; type logger_Level = Level; declare const logger_Level: typeof Level; type logger_LogContext = LogContext; type logger_LogFn = LogFn; type logger_ThrowFn = ThrowFn; declare namespace logger { export { type Config$3 as Config, type logger_DefaultHandler as DefaultHandler, type logger_ErrorContext as ErrorContext, type logger_Factory as Factory, type logger_Handler as Handler, type Instance$3 as Instance, type logger_InternalConfig as InternalConfig, logger_Level as Level, type logger_LogContext as LogContext, type logger_LogFn as LogFn, type logger_ThrowFn as ThrowFn }; } /** Collector state mapping for the `on` actions. */ type Config$2 = { config?: Array; consent?: Array; custom?: Array; globals?: Array; ready?: Array; run?: Array; session?: Array; user?: Array; }; /** Allow arbitrary string events via `(string & {})`. */ type Types$2 = keyof Config$2 | (string & {}); /** Map each event type to its expected data payload type. */ interface EventDataMap { config: Partial; consent: Consent; custom: Properties; globals: Properties; ready: void; run: void; session: SessionData | undefined; user: User; } /** Extract the data type for a specific event. */ type EventData = EventDataMap[T]; /** Union of all possible data types. */ type AnyEventData = EventDataMap[keyof EventDataMap]; /** * Context provided to every `on` callback. * Same posture as Mapping.Context: collector + logger only; * subscriptions are a collector-level concern, not a stage-level one. */ interface Context$3 { collector: Instance$6; logger: Instance$3; } /** Unified subscription callback shape. */ type Fn$1 = (data: TData, context: Context$3) => PromiseOrValue; /** Typed-data variants for readability and IntelliSense. All reduce to Fn. */ type ConsentFn = Fn$1; type GenericFn = Fn$1; type ReadyFn = Fn$1; type RunFn = Fn$1; type SessionFn = Fn$1; type UserFn = Fn$1; /** * Consent rule: a record of `{ [consentKey]: ConsentFn }`. * Only the consent action uses this shape (per-key handler dispatch). */ interface ConsentRule { [key: string]: ConsentFn; } /** Anything registerable via `walker.on(action, X)`: a typed callback or a consent rule record. */ type Subscription = ConsentRule | GenericFn | ReadyFn | RunFn | SessionFn | UserFn; interface OnConfig { config?: GenericFn[]; consent?: ConsentRule[]; custom?: GenericFn[]; globals?: GenericFn[]; ready?: ReadyFn[]; run?: RunFn[]; session?: SessionFn[]; user?: UserFn[]; [key: string]: ConsentRule[] | GenericFn[] | ReadyFn[] | RunFn[] | SessionFn[] | UserFn[] | undefined; } /** * Destination `on` handler: receives the action type and a destination context. * Already context-style; kept for compatibility with the destination interface. */ type OnFn = (type: Types$2, context: Context$5) => PromiseOrValue; type OnFnRuntime = (type: Types$2, context: Context$5) => PromiseOrValue; type on_AnyEventData = AnyEventData; type on_ConsentFn = ConsentFn; type on_ConsentRule = ConsentRule; type on_EventData = EventData; type on_EventDataMap = EventDataMap; type on_GenericFn = GenericFn; type on_OnConfig = OnConfig; type on_OnFn = OnFn; type on_OnFnRuntime = OnFnRuntime; type on_ReadyFn = ReadyFn; type on_RunFn = RunFn; type on_SessionFn = SessionFn; type on_Subscription = Subscription; type on_UserFn = UserFn; declare namespace on { export type { on_AnyEventData as AnyEventData, Config$2 as Config, on_ConsentFn as ConsentFn, on_ConsentRule as ConsentRule, Context$3 as Context, on_EventData as EventData, on_EventDataMap as EventDataMap, Fn$1 as Fn, on_GenericFn as GenericFn, on_OnConfig as OnConfig, on_OnFn as OnFn, on_OnFnRuntime as OnFnRuntime, on_ReadyFn as ReadyFn, on_RunFn as RunFn, on_SessionFn as SessionFn, on_Subscription as Subscription, Types$2 as Types, on_UserFn as UserFn }; } interface Context$2 { city?: string; country?: string; encoding?: string; hash?: string; ip?: string; language?: string; origin?: string; region?: string; userAgent?: string; [key: string]: string | undefined; } declare namespace request { export type { Context$2 as Context }; } /** * Base Env interface for dependency injection into sources. * * Sources receive all their dependencies through this environment object, * making them platform-agnostic and easily testable. */ interface BaseEnv$1 { [key: string]: unknown; push: PushFn$1; command: CommandFn; sources?: Sources; elb: Fn$3; logger: Instance$3; } /** * Type bundle for source generics. * Groups Settings, Mapping, Push, Env, InitSettings, and Setup into a single type parameter. * * @template S - Settings configuration type * @template M - Mapping configuration type * @template P - Push function signature (flexible to support HTTP handlers, etc.) * @template E - Environment dependencies type * @template I - InitSettings configuration type (user input) * @template U - Setup options type (provisioning options for `walkeros setup`) */ interface Types$1 { settings: S; initSettings: I; mapping: M; push: P; env: E; setup: U; credentials: C; } /** * Generic constraint for Types - ensures T has required properties for indexed access */ type TypesGeneric$1 = { settings: any; initSettings: any; mapping: any; push: any; env: any; setup: any; credentials: any; }; /** * Type extractors for consistent usage with Types bundle */ type Settings$1 = T['settings']; type InitSettings$1 = T['initSettings']; type Mapping = T['mapping']; type Push = T['push']; type Env$1 = T['env']; type SetupOptions$1 = T['setup']; type Credentials$1 = T['credentials']; /** * Inference helper: Extract Types from Instance */ type TypesOf$1 = I extends Instance$2 ? T : never; interface Config$1 extends Config$7> { /** Implementation-specific configuration passed to the init function. */ settings?: InitSettings$1; /** * Optional, strictly-typed credentials slot ($env-resolved). The package * defines the shape via `Types['credentials']`. `settings.` stays the * escape hatch for raw SDK options. */ credentials?: Credentials$1; /** Runtime dependencies injected by the collector (push, command, logger, etc.). */ env?: Env$1; /** Source identifier; defaults to the InitSources object key. */ id?: string; /** Logger configuration (level, handler) to override the collector's defaults. */ logger?: Config$3; /** * Respond-first acknowledgement for response-producing server sources. * * When a source produces an HTTP response (express today; future fetch / * lambda), `async: true` (the default for such sources) responds 2xx * ("accepted") before the event is delivered to the collector, so the * client is not blocked on backend delivery. `async: false` waits for * delivery to settle before responding. A 2xx means "accepted", not * "delivered". * * Browser and dataLayer sources have no HTTP response to defer and ignore * this flag. The default is per source type. */ async?: boolean; /** Mark as primary source; its push function becomes the exported `elb` from startFlow. */ primary?: boolean; /** Defer source initialization until these collector events fire (e.g., `['consent']`). */ require?: string[]; /** * Provisioning options for `walkeros setup`. `boolean | object`. * Triggered only by explicit CLI invocation; never automatic. */ setup?: boolean | SetupOptions$1; /** * Ingest metadata extraction mapping. * Extracts values from raw request objects (Express req, Lambda event, etc.) * using walkerOS mapping syntax. Extracted data flows to transformers/destinations. * * @example * ingest: { * ip: 'req.ip', * ua: 'req.headers.user-agent', * origin: 'req.headers.origin' * } */ ingest?: Data$1; /** Completely skip this source — no init, no event capture. */ disabled?: boolean; /** * Init lifecycle flag. Set by the collector to `true` after `Instance.init()` * has been called. Used together with `require` to gate `on()` delivery: * lifecycle events are queued in `Instance.queueOn` until both * `config.init === true` and `config.require` is empty/absent, then replayed. */ init?: boolean; /** Declarative store get/set operations applied around this source. */ state?: State | State[]; } type PartialConfig$1 = Config$1> | Settings$1, Partial> | Mapping, Push, Env$1, InitSettings$1, SetupOptions$1, Credentials$1>>; interface Instance$2 { type: string; config: Config$1; setup?: SetupFn, Env$1>; push: Push; destroy?: DestroyFn, Env$1>; on?(event: Types$2, context?: unknown): void | boolean | Promise; /** * Optional setup hook. Called by the collector eagerly after all source * factories have run, regardless of `config.require`. Use for prep work * such as draining a pre-init window queue or attaching DOM listeners. * The collector still gates `on()` delivery, and `Collector.push` * enforces `allowed`/consent at the destination layer. */ init?: () => void | Promise; /** * Lifecycle event queue. Populated by `onApply` when the source is not * yet started (`config.init !== true` or `config.require` non-empty). * Flushed by the collector when the source becomes started. */ queueOn?: Array<{ type: Types$2; data: unknown; }>; } /** * Per-scope environment passed to the body of `Source.Context.withScope`. * * Each call to `withScope` builds a fresh `ScopeEnv` whose `push` captures * the per-scope `ingest` and `respond`. Concurrent scopes cannot crosstalk: * each one carries its own ingest and respond all the way through the * pipeline. Server sources MUST use `withScope` per inbound request; sources * with a single logical scope (browser tab lifetime, dataLayer) may skip it * and use the factory-scope `env.push` directly. */ type ScopeEnv = Env$1 & { /** Per-scope push: captures the scope's ingest and respond for this call. */ push: PushFn$1; /** Ingest metadata extracted from the raw scope input (if config.ingest is set). */ ingest: Ingest; /** Respond function bound to this scope (undefined for scopes without a response). */ respond?: RespondFn; }; /** * Context provided to source init function. * Extends base context with source-specific properties. */ interface Context$1 extends Base>, Env$1> { id: string; /** * Bind ingest and respond to a single scope of work (e.g. one inbound * HTTP request, one queue message). Builds a fresh `Ingest` from the * raw input via `config.ingest` mapping, wires the per-scope `respond`, * and invokes `body(scopeEnv)` with a push function that captures both. * * Server sources call this once per inbound request: * * ```ts * await context.withScope(req, createRespond(sender), async (env) => { * await env.push(parsedData); * }); * ``` * * Browser sources with a single tab-lifetime scope may skip `withScope` * and use `env.push` directly. * * @param rawScope - Raw input for `config.ingest` mapping (Express req, * Lambda event, fetch Request, etc.). Pass `undefined` if no ingest * mapping applies. * @param respond - Per-scope respond function, or `undefined` if the * scope produces no response. * @param body - Async callback receiving the per-scope env. * @returns The body's return value. */ withScope: (rawScope: unknown, respond: RespondFn | undefined, body: (env: ScopeEnv) => Promise) => Promise; } type Init$1 = (context: Context$1) => Instance$2 | Promise>; type InitSource = { code: Init$1; config?: Partial>; env?: Partial>; primary?: boolean; next?: Route; before?: Route; cache?: Cache; state?: State | State[]; }; /** * Sources configuration for collector. * Maps source IDs to their initialization configurations. */ interface InitSources { [sourceId: string]: InitSource; } /** * Renderer hint for source simulation UI. * - 'browser': Source needs a real DOM (iframe with live preview) * - 'codebox': Source uses a JSON/code editor (default) */ type Renderer = 'browser' | 'codebox'; /** * Typed accessor for sources registered on a collector. * * The collector's `sources` bag indexes to `Source.Instance` (defaults erase * the generic), which collapses the source's declared `push` signature to * `Elb.Fn`. Use this helper at the call site to recover the narrow type * without casts. * * @example * type TestSourceTypes = Source.Types; * const src = getSource(collector, 'testSource'); * await src.push({ method: 'GET', path: '/api/data' }); // typed! * * @throws Error with message `Source not found: ` when the id is unknown. */ declare function getSource(collector: { sources: { [id: string]: Instance$2; }; }, id: string): Instance$2; type source_InitSource = InitSource; type source_InitSources = InitSources; type source_Mapping = Mapping; type source_Push = Push; type source_Renderer = Renderer; type source_ScopeEnv = ScopeEnv; declare const source_getSource: typeof getSource; declare namespace source { export { type BaseEnv$1 as BaseEnv, type Config$1 as Config, type Context$1 as Context, type Credentials$1 as Credentials, type Env$1 as Env, type Init$1 as Init, type InitSettings$1 as InitSettings, type source_InitSource as InitSource, type source_InitSources as InitSources, type Instance$2 as Instance, type source_Mapping as Mapping, type PartialConfig$1 as PartialConfig, type source_Push as Push, type source_Renderer as Renderer, type source_ScopeEnv as ScopeEnv, type Settings$1 as Settings, type SetupOptions$1 as SetupOptions, type Types$1 as Types, type TypesGeneric$1 as TypesGeneric, type TypesOf$1 as TypesOf, source_getSource as getSource }; } interface BaseEnv { [key: string]: unknown; } interface Types { settings: S; initSettings: I; env: E; setup: U; credentials: C; } type TypesGeneric = { settings: any; initSettings: any; env: any; setup: any; credentials: any; }; type Settings = T['settings']; type InitSettings = T['initSettings']; type Env = T['env']; type SetupOptions = T['setup']; type Credentials = T['credentials']; type TypesOf = I extends Instance$1 ? T : never; interface Config { settings?: InitSettings; /** * Optional, strictly-typed credentials slot ($env-resolved). The package * defines the shape via `Types['credentials']`. `settings.` stays the * escape hatch for raw SDK options. */ credentials?: Credentials; env?: Env; id?: string; logger?: Config$3; /** * Provisioning options for `walkeros setup`. `boolean | object`. * Triggered only by explicit CLI invocation; never automatic. */ setup?: boolean | SetupOptions; /** * Persist values as raw bytes, byte-exact, bypassing the structured codec. * Default false: values are structured `StoreValue` and pass through the * shared core serialization codec. Set true only on byte-native backends * (fs/s3/gcs) whose consumer needs the exact bytes back, e.g. serving an * asset such as walker.js. Structured-only backends (sheets) reject `file: * true` at init. One store instance is exactly one mode. */ file?: boolean; } type PartialConfig = Config> | Settings, Env, InitSettings, SetupOptions, Credentials>>; interface Context extends Base, Env> { id: string; } /** * Canonical structured value persisted by a store. Includes `null`, but * EXCLUDES `undefined`: `undefined` is the reserved "miss" sentinel returned * by `GetFn` for an absent key, so it must never be a stored value. * `Uint8Array` is the platform-neutral binary leaf (never Node `Buffer`). */ type StoreValue = string | number | boolean | null | Uint8Array | StoreValue[] | { [key: string]: StoreValue; }; type GetFn = (key: string) => T | undefined | Promise; type SetFn = (key: string, value: T, /** * Optional expiry hint in ms; honored only by TTL-native backends * (in-memory, Redis). Byte/JSON backends may ignore it. Authoritative cache * expiry lives in the cache wrapper's {value, exp} payload. */ ttl?: number) => void | Promise; type DeleteFn = (key: string) => void | Promise; interface Instance$1 { type: string; config: Config; get: GetFn; set: SetFn; delete: DeleteFn; setup?: SetupFn, Env>; destroy?: DestroyFn, Env>; } type Init = (context: Context>, Env, InitSettings>>) => Instance$1 | Promise>; type InitFn = (context: Context) => PromiseOrValue>; type InitStore = { code: Init; config?: Partial>; env?: Partial>; }; interface InitStores { [storeId: string]: InitStore; } interface Stores { [storeId: string]: Instance$1; } /** * Typed accessor for stores registered on a collector. * * The collector's `stores` bag indexes to `Store.Instance` (defaults erase * the generic). Use this helper at the call site to recover the narrow type * without casts. * * @example * type MyStoreTypes = Store.Types; * const store = getStore(collector, 'cache'); * await store.set('key', 'value'); * * @throws Error with message `Store not found: ` when the id is unknown. */ declare function getStore(collector: { stores: { [id: string]: Instance$1; }; }, id: string): Instance$1; /** * Read-site narrowing helper for store values. * * `Instance.get`/`set` stay value-agnostic at `StoreValue`, so callers * that know the concrete shape narrow here instead of threading a value type * through `Store.Types`. The single narrow `as` cast is justified: the store * channel is structurally `StoreValue`, and the caller asserts the concrete * sub-shape it stored. `undefined` is preserved as the miss sentinel. */ declare function getStoreValue(store: Instance$1, key: string): Promise; type store_BaseEnv = BaseEnv; type store_Config = Config; type store_Context = Context; type store_Credentials = Credentials; type store_DeleteFn = DeleteFn; type store_Env = Env; type store_GetFn = GetFn; type store_Init = Init; type store_InitFn = InitFn; type store_InitSettings = InitSettings; type store_InitStore = InitStore; type store_InitStores = InitStores; type store_PartialConfig = PartialConfig; type store_SetFn = SetFn; type store_Settings = Settings; type store_SetupOptions = SetupOptions; type store_StoreValue = StoreValue; type store_Stores = Stores; type store_Types = Types; type store_TypesGeneric = TypesGeneric; type store_TypesOf = TypesOf; declare const store_getStore: typeof getStore; declare const store_getStoreValue: typeof getStoreValue; declare namespace store { export { type store_BaseEnv as BaseEnv, type store_Config as Config, type store_Context as Context, type store_Credentials as Credentials, type store_DeleteFn as DeleteFn, type store_Env as Env, type store_GetFn as GetFn, type store_Init as Init, type store_InitFn as InitFn, type store_InitSettings as InitSettings, type store_InitStore as InitStore, type store_InitStores as InitStores, type Instance$1 as Instance, type store_PartialConfig as PartialConfig, type store_SetFn as SetFn, type store_Settings as Settings, type store_SetupOptions as SetupOptions, type store_StoreValue as StoreValue, type store_Stores as Stores, type store_Types as Types, type store_TypesGeneric as TypesGeneric, type store_TypesOf as TypesOf, store_getStore as getStore, store_getStoreValue as getStoreValue }; } /** * Trigger — unified interface for invoking any walkerOS step in simulation * and testing. Every package exports a `createTrigger` factory from its * examples that conforms to `Trigger.CreateFn`. * * Usage: * const { flow, trigger } = await createTrigger(initConfig); * const result = await trigger(type?, options?)(content); * * @packageDocumentation */ /** Flow access handle returned by createTrigger. */ interface FlowHandle { /** The collector instance created by startFlow. */ collector: Instance$6; /** The elb push function for direct event injection. */ elb: Fn$3; } /** What createTrigger returns — a flow handle (lazy) and a trigger function. */ interface Instance { /** Flow handle — undefined until first trigger() call, then stable. */ readonly flow: FlowHandle | undefined; trigger: Fn; } /** * Curried trigger function — always async. * * First call selects mechanism (type) and configures it (options). * Second call fires with content and returns result. * * @example * // Browser source — click trigger * trigger('click', 'button.cta')('') * * // Express source — POST request * trigger('POST')({ path: '/collect', body: { name: 'page view' } }) * * // DataLayer — default mechanism * trigger()(['event', 'purchase', { value: 25.42 }]) */ type Fn = (type?: string, options?: unknown) => (content: TContent) => Promise; /** * Factory function exported by each package's examples. * * Receives full Collector.InitConfig. Does NOT call startFlow eagerly — * startFlow is deferred to the first trigger() invocation (lazy init). * The flow property uses a getter to read the closure variable live. * createTrigger itself stays async for consistency (other packages may * need await during setup). Config is passed through UNMODIFIED — * validation is startFlow's job. * * @example * // Package exports: * export const createTrigger: Trigger.CreateFn = async (config) => { * let flow: Trigger.FlowHandle | undefined; * * const trigger: Trigger.Fn = (type?, options?) => async (content) => { * // Pre-startFlow work (e.g., inject HTML for browser source) * // ... * * // Lazy init — only on first call * if (!flow) flow = await startFlow(config); * * // Post-startFlow work (e.g., dispatch click event) * // ... * }; * * return { * get flow() { return flow; }, * trigger, * }; * }; */ type CreateFn = (config: InitConfig, options?: unknown) => Promise>; type trigger_CreateFn = CreateFn; type trigger_FlowHandle = FlowHandle; type trigger_Fn = Fn; type trigger_Instance = Instance; declare namespace trigger { export type { trigger_CreateFn as CreateFn, trigger_FlowHandle as FlowHandle, trigger_Fn as Fn, trigger_Instance as Instance }; } type AnyObject = Record; type Elb = Fn$3; type AnyFunction = (...args: unknown[]) => unknown; type SingleOrArray = T | Array; type Events = Array; type PartialEvent = Partial; type DeepPartialEvent = DeepPartial; interface Event { name: string; data: Properties; context: OrderedProperties; globals: Properties; custom: Properties; user: User; nested: Entities; consent: Consent; id: string; trigger: string; entity: string; action: string; timestamp: number; timing: number; source: Source; } interface Consent { [name: string]: boolean; } interface User extends Properties { id?: string; device?: string; session?: string; hash?: string; address?: string; email?: string; phone?: string; userAgent?: string; browser?: string; browserVersion?: string; deviceType?: string; language?: string; country?: string; region?: string; city?: string; zip?: string; timezone?: string; os?: string; osVersion?: string; screenSize?: string; ip?: string; internal?: boolean; } type SourcePlatform = 'web' | 'server' | 'app' | 'ios' | 'android' | 'terminal' | string; /** * SourceMap is the discriminated-union registry for source kinds. * Each source package augments this interface via `declare module * '@walkeros/core'` to register its own `type` literal and any * source-specific fields. Conflicting declarations cause compile errors, * intentional, to surface naming collisions early. */ interface SourceMap { collector: { type: 'collector'; }; } interface Source extends Properties { type: string; platform?: SourcePlatform; /** Deployment version of the source emitter (string). */ version?: string; /** Event-model spec version. Collector defaults to "4". */ schema?: string; /** Emission sequence within the run. */ count?: number; /** Trace id shared by every event of a run (W3C trace-id shape). */ trace?: string; /** Walker-controlled standard suggestions (sources may set). */ url?: string; referrer?: string; tool?: string; command?: string; } type PropertyType = boolean | string | number | { [key: string]: Property; }; type Property = PropertyType | Array; interface Properties { [key: string]: Property | undefined; } interface OrderedProperties { [key: string]: [Property, number] | undefined; } type Entities = Array; interface Entity { entity: string; data: Properties; nested?: Entities; context?: OrderedProperties; } type ConsentHandler = Record; type ActionHandler = AnyFunction; type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; }; type PromiseOrValue = T | Promise; type walkeros_ActionHandler = ActionHandler; type walkeros_AnyFunction = AnyFunction; type walkeros_AnyObject = AnyObject; type walkeros_Consent = Consent; type walkeros_ConsentHandler = ConsentHandler; type walkeros_DeepPartial = DeepPartial; type walkeros_DeepPartialEvent = DeepPartialEvent; type walkeros_Elb = Elb; type walkeros_Entities = Entities; type walkeros_Entity = Entity; type walkeros_Event = Event; type walkeros_Events = Events; type walkeros_OrderedProperties = OrderedProperties; type walkeros_PartialEvent = PartialEvent; type walkeros_PromiseOrValue = PromiseOrValue; type walkeros_Properties = Properties; type walkeros_Property = Property; type walkeros_PropertyType = PropertyType; type walkeros_SingleOrArray = SingleOrArray; type walkeros_Source = Source; type walkeros_SourceMap = SourceMap; type walkeros_SourcePlatform = SourcePlatform; type walkeros_User = User; declare namespace walkeros { export type { walkeros_ActionHandler as ActionHandler, walkeros_AnyFunction as AnyFunction, walkeros_AnyObject as AnyObject, walkeros_Consent as Consent, walkeros_ConsentHandler as ConsentHandler, walkeros_DeepPartial as DeepPartial, walkeros_DeepPartialEvent as DeepPartialEvent, walkeros_Elb as Elb, walkeros_Entities as Entities, walkeros_Entity as Entity, walkeros_Event as Event, walkeros_Events as Events, walkeros_OrderedProperties as OrderedProperties, walkeros_PartialEvent as PartialEvent, walkeros_PromiseOrValue as PromiseOrValue, walkeros_Properties as Properties, walkeros_Property as Property, walkeros_PropertyType as PropertyType, walkeros_SingleOrArray as SingleOrArray, walkeros_Source as Source, walkeros_SourceMap as SourceMap, walkeros_SourcePlatform as SourcePlatform, walkeros_User as User }; } /** * A recorded function call made during simulation. * Captures what a destination called on its env (e.g., window.gtag). */ interface Call { /** Dot-path of the function called: "window.gtag", "dataLayer.push" */ fn: string; /** Arguments passed to the function */ args: unknown[]; /** Unix timestamp in ms */ ts: number; } /** * Result of simulating a single step. * Same shape for source, transformer, collector, and destination. */ interface Result { /** Which step type was simulated */ step: 'source' | 'transformer' | 'destination' | 'collector'; /** Step name, e.g. "gtag", "dataLayer", "enricher" */ name: string; /** * Output events: * - source: captured pre-collector events * - transformer: [transformed event] or [] if filtered * - collector: [enriched event] (createEvent applied) * - destination: [] (destinations don't produce events) */ events: DeepPartialEvent[]; /** Intercepted env calls. Populated for destinations, empty [] for others. */ calls: Call[]; /** Execution time in ms */ duration: number; /** * Entity-action key of the matched mapping rule, e.g. "product add" or * "product *". Populated for destination simulations when a mapping rule * matched; absent when no rule matched or the step has no mapping. * Also absent when the matched rule uses batched delivery (batching * reports no per-event key) and on error results, where the key is not * available. */ mappingKey?: string; /** Error if the step threw */ error?: Error; } type simulation_Call = Call; type simulation_Result = Result; declare namespace simulation { export type { simulation_Call as Call, simulation_Result as Result }; } interface Code { lang?: string; code: string; } interface Hint { text: string; code?: Array; } type Hints = Record; type hint_Code = Code; type hint_Hint = Hint; type hint_Hints = Hints; declare namespace hint { export type { hint_Code as Code, hint_Hint as Hint, hint_Hints as Hints }; } type StorageType = 'local' | 'session' | 'cookie'; declare const Const: { readonly Utils: { readonly Storage: { readonly Local: "local"; readonly Session: "session"; readonly Cookie: "cookie"; }; }; }; type SendDataValue = Property | Properties; type SendHeaders = { [key: string]: string; }; interface SendResponse { ok: boolean; data?: unknown; error?: string; } /** * Creates a TransformerResult for dynamic chain routing. * Use this in transformer push functions to redirect the chain. */ declare function branch(event: DeepPartialEvent, next: Route): Result$1; /** * Anonymizes an IPv4 address by setting the last octet to 0. * * @param ip The IP address to anonymize. * @returns The anonymized IP address or an empty string if the IP is invalid. */ declare function anonymizeIP(ip: string): string; /** * Flow Configuration Utilities * * Functions for resolving and processing Flow configurations. * * @packageDocumentation */ /** Sentinel prefix for deferred $env resolution. Shared with CLI bundler. */ declare const ENV_MARKER_PREFIX = "__WALKEROS_ENV:"; /** Sentinel prefix for deferred $secret resolution. Shared with CLI bundler. */ declare const SECRET_MARKER_PREFIX = "__WALKEROS_SECRET:"; interface ResolveOptions { deferred?: boolean; /** * When false, unresolved `$flow.X.Y` refs (unknown flow, missing key, * empty value) trigger {@link onWarning} and the original `$flow…` string * is left in place. Cycles always throw regardless of this flag. * Default: true (strict — throws as today). */ strictFlowRefs?: boolean; /** Called for each unresolved $flow ref when {@link strictFlowRefs} is false. */ onWarning?: (message: string) => void; } /** * Walk a dot-separated path into a value. * Throws if any intermediate segment is missing or not an object. */ declare function walkPath(value: unknown, path: string, refPrefix: string): unknown; /** * Resolver callback for `$flow.X.Y` references. * * Given a sibling flow name, returns its fully resolved `Flow.Config` block * (with `$env`/`$var`/`$contract` already resolved) as `unknown` so that * {@link walkPath} can traverse it. Returns `undefined` if the flow does * not exist. Implementations are responsible for cycle detection across * recursive calls. */ type FlowConfigResolver = (flowName: string) => unknown; /** * Convert package name to valid JavaScript variable name. * Used for deterministic default import naming. * @example * packageNameToVariable('@walkeros/server-destination-api') * // → '_walkerosServerDestinationApi' */ declare function packageNameToVariable(packageName: string): string; /** * Get resolved flow for a named flow. * * Resolution pass order: * 1. `$env` / `$var` resolve per-flow in isolation (no cross-flow context). * `$var` resolves recursively (variables may reference other variables, * `$env`, `$contract`, or `$flow`); cycles are detected via a visiting set. * 2. `$flow.X.Y` resolves against pass-1 outputs of sibling flows (so `$env`/`$var` * inside the referenced flow are already resolved when `$flow` reads it). * 3. `$contract` resolves last (with `$flow` results available). * * In practice these passes are interleaved by the resolver: when `$flow.X.Y` * is encountered, the sibling flow X's `Flow.Config` block is recursively * resolved on demand (with all its own `$env`/`$var`/`$contract` references * resolved first), then the deep path is walked. Cycles are detected via a * visiting set. * * @param config - The complete Flow.Json (root multi-flow config) * @param flowName - Flow name (auto-selected if only one exists) * @param options - Resolution options * @returns Resolved {@link Flow} with $var, $env, $contract, and $flow patterns resolved * @throws Error if flow selection is required but not specified, or flow not found * @throws Error if a `$flow.X.Y` reference forms a cycle * * @example * ```typescript * import { getFlowSettings } from '@walkeros/core'; * * const config = JSON.parse(fs.readFileSync('walkeros.config.json', 'utf8')); * * // Auto-select if only one flow * const flow = getFlowSettings(config); * * // Or specify flow * const prodFlow = getFlowSettings(config, 'production'); * ``` */ declare function getFlowSettings(config: Flow.Json, flowName?: string, options?: ResolveOptions): Flow; /** * Get the platform of a flow ('web' or 'server'). * * Reads from `flow.config.platform`. * * @param flow - Resolved flow (output of {@link getFlowSettings}) * @returns "web" or "server" * @throws Error if `config.platform` is missing * * @example * ```typescript * import { getPlatform } from '@walkeros/core'; * * const platform = getPlatform(flow); * // Returns "web" or "server" * ``` */ declare function getPlatform(flow: Flow): 'web' | 'server'; /** * @interface Assign * @description Options for the assign function. * @property merge - Merge array properties instead of overriding them. * @property shallow - Create a shallow copy instead of updating the target object. * @property extend - Extend the target with new properties instead of only updating existing ones. */ interface Assign { merge?: boolean; shallow?: boolean; extend?: boolean; } /** * Merges objects with advanced options. * * @template T, U * @param target - The target object to merge into. * @param obj - The source object to merge from. * @param options - Options for merging. * @returns The merged object. */ declare function assign(target: T, obj?: U, options?: Assign): T & U; /** * Gets a value from an object by a dot-notation string. * Supports wildcards for arrays. * * @example * getByPath({ data: { id: 1 } }, "data.id") // Returns 1 * * @param event - The object to get the value from. * @param key - The dot-notation string. * @param defaultValue - The default value to return if the key is not found. * @returns The value from the object or the default value. */ declare function getByPath(event: unknown, key?: string, defaultValue?: unknown): unknown; /** * Sets a value in an object by a dot-notation string. * * @param obj - The object to set the value in. * @param key - The dot-notation string. * @param value - The value to set. * @returns A new object with the updated value. */ declare function setByPath(obj: T, key: string, value: unknown): T; /** * Deletes a value in an object by a dot-notation string. * Returns a new object; the input is not mutated. No-op when the path is * absent or the target is neither an object nor an array. Numeric segments * index into arrays; a final numeric segment splices the element out so no * empty slot is left behind. */ declare function deleteByPath(obj: T, key: string): T; declare function flattenIncludeSections(event: DeepPartialEvent, sections: string[]): Record; /** * Casts a value to a specific type. * * @param value The value to cast. * @returns The casted value. */ declare function castValue(value: unknown): PropertyType; /** * Creates a deep clone of a value. * Supports primitive values, objects, arrays, dates, and regular expressions. * Handles circular references. * * @template T * @param org - The value to clone. * @param visited - A map of visited objects to handle circular references. * @returns The cloned value. */ declare function clone(org: T, visited?: WeakMap): T; /** * Checks if the required consent is granted. * * @param required - The required consent states. * @param state - The current consent states. * @param individual - Individual consent states to prioritize. * @returns The granted consent states or false if not granted. */ declare function getGrantedConsent(required: Consent | undefined, state?: Consent, individual?: Consent): false | Consent; /** * Creates a new destination instance by merging a base destination with additional configuration. * * This utility enables elegant destination configuration while avoiding config side-effects * that could occur when reusing destination objects across multiple collector instances. * * @param baseDestination - The base destination to extend * @param config - Additional configuration to merge with the base destination's config * @returns A new destination instance with merged configuration * * @example * ```typescript * // Types are inferred automatically from destinationGtag * elb('walker destination', createDestination(destinationGtag, { * settings: { ga4: { measurementId: 'G-123' } } * })); * ``` */ declare function createDestination(baseDestination: I, config: Partial>>): I; /** * Deep merges source into target, mutating target in-place. * Recurses into plain objects; everything else is a leaf (replaced). * Skips undefined source values; null overwrites. */ declare function deepMerge>(target: T, source: Record): T; /** * Creates a complete event with default values. * Used for testing and debugging. * * Models a post-collector event: `source` always carries the run-stamped * `count` and `trace`, so a generated event matches one that has been pushed * through the collector. Override via `props.source` if needed. * * @param props - Properties to override the default values. * @returns A complete event. */ declare function createEvent(props?: DeepPartialEvent): Event; /** * Creates a complete event with default values based on the event name. * Used for testing and debugging. * * @param name - The name of the event to create. * @param props - Properties to override the default values. * @returns A complete event. */ declare function getEvent(name?: string, props?: DeepPartialEvent): Event; declare function getId(length?: number, charset?: string): string; /** * W3C span_id: 8 random bytes encoded as 16 lowercase hex characters. * Reference: W3C Trace Context (W3C Recommendation, January 2020). */ declare function getSpanId(): string; /** * W3C trace_id: 16 random bytes encoded as 32 lowercase hex characters. * Shared by every event of a collector run. Reference: W3C Trace Context. */ declare function getTraceId(): string; interface MarketingParameters { [key: string]: string; } /** * Click-ID registry entry — maps a URL parameter name to a canonical platform. * * Runtime shape only; the corresponding Zod schema lives in * `@walkeros/core/dev` (schemas/marketing.ts) for dev tooling that needs * validation or JSON Schema generation. */ interface ClickIdEntry { param: string; platform: string; } /** * Default click-ID registry. * * Ordered by priority: when a URL contains multiple click IDs, the entry * appearing earlier wins as the resolved `clickId` / `platform`. All matched * raw values are still preserved on the result. * * Extend via the third argument to {@link getMarketingParameters} or the * `clickIds` field in the session source settings. */ declare const defaultClickIds: ClickIdEntry[]; /** * Extracts marketing parameters from a URL. * * - UTM and custom params are mapped to friendly names (`utm_source` → `source`). * - Known click IDs are detected case-insensitively; each raw value is stored * under its canonical lowercase param name. * - `clickId` and `platform` reference the highest-priority match (first entry * in the registry present in the URL). * - Custom `clickIds` override default platforms by `param` in place and * append new params at the end of the priority list. */ declare function getMarketingParameters(url: URL, custom?: MarketingParameters, clickIds?: ClickIdEntry[]): Properties; /** * Options for scheduling primitives ({@link debounce}, {@link throttle}). * * - `wait`: Debounce window in ms. Timer resets on every call. * - `size`: Hard call-count cap per window. Flush immediately when call * count reaches this number. Useful for batch buffers that must not * grow unbounded. * - `age`: Hard age cap in ms since the first call of the current window. * Forces a flush even if calls keep arriving and reset the debounce. * Prevents debounce starvation under sustained load. */ interface ScheduleOptions { wait?: number; size?: number; age?: number; } /** * Returned by {@link debounce}: a callable that schedules `fn` plus * deterministic `flush` / `cancel` controls. */ interface Debounced

{ (...args: P): Promise; /** Force an immediate flush with the most recent args. Resolves after `fn` settles. */ flush(): Promise; /** Cancel any pending invocation. No `fn` call, pending promises resolve to undefined. */ cancel(): void; /** Number of scheduled calls since the current window opened. */ size(): number; } /** * Creates a debounced function that delays invoking `fn` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. The debounced function comes with a `cancel` method to cancel * delayed `fn` invocations and a `flush` method to immediately invoke them. * * The second argument is either a `wait` number (legacy form) or a * {@link ScheduleOptions} object. The object form adds `size` (hard count * cap) and `age` (hard window-age cap) so the function flushes deterministically * under sustained load instead of letting the debounce reset forever. * * @template P, R * @param fn The function to debounce. * @param opts Either a wait-ms number or a {@link ScheduleOptions} object. * @param immediate Trigger the function on the leading edge, instead of the trailing. * @returns A {@link Debounced} callable with `flush`, `cancel`, and `size` methods. */ declare function debounce

(fn: (...args: P) => R, opts?: number | ScheduleOptions, immediate?: boolean): Debounced; declare function throttle

(fn: (...args: P) => R | undefined, opts?: number | ScheduleOptions): (...args: P) => R | undefined; /** * Checks if a value is an arguments object. * * @param value The value to check. * @returns True if the value is an arguments object, false otherwise. */ declare function isArguments(value: unknown): value is IArguments; /** * Checks if a value is an array. * * @param value The value to check. * @returns True if the value is an array, false otherwise. */ declare function isArray(value: unknown): value is T[]; /** * Checks if a value is a boolean. * * @param value The value to check. * @returns True if the value is a boolean, false otherwise. */ declare function isBoolean(value: unknown): value is boolean; /** * Checks if an entity is a walker command. * * @param entity The entity to check. * @returns True if the entity is a walker command, false otherwise. */ declare function isCommand(entity: string): entity is "walker"; /** * Checks if a value is defined. * * @param value The value to check. * @returns True if the value is defined, false otherwise. */ declare function isDefined(val: T | undefined): val is T; /** * Checks if a value is an element or the document. * * @param elem The value to check. * @returns True if the value is an element or the document, false otherwise. */ declare function isElementOrDocument(elem: unknown): elem is Element; /** * Checks if a value is a function. * * @param value The value to check. * @returns True if the value is a function, false otherwise. */ declare function isFunction(value: unknown): value is Function; /** * Checks if a value is a number. * * @param value The value to check. * @returns True if the value is a number, false otherwise. */ declare function isNumber(value: unknown): value is number; /** * Checks if a value is an object. * * @param value The value to check. * @returns True if the value is an object, false otherwise. */ declare function isObject(value: unknown): value is AnyObject; /** * Checks if two variables have the same type. * * @param variable The first variable. * @param type The second variable. * @returns True if the variables have the same type, false otherwise. */ declare function isSameType(variable: unknown, type: T): variable is typeof type; /** * Checks if a value is a string. * * @param value The value to check. * @returns True if the value is a string, false otherwise. */ declare function isString(value: unknown): value is string; /** * Create a logger instance * * @param config - Logger configuration * @returns Logger instance with all log methods and scoping support * * @example * ```typescript * // Basic usage * const logger = createLogger({ level: 'DEBUG' }); * logger.info('Hello world'); * * // With scoping * const destLogger = logger.scope('gtag').scope('myInstance'); * destLogger.debug('Processing event'); // DEBUG [gtag:myInstance] Processing event * * // With custom handler * const logger = createLogger({ * handler: (level, message, context, scope, originalHandler) => { * // Custom logic (e.g., send to Sentry) * originalHandler(level, message, context, scope); * } * }); * ``` * * // TODO: Consider compile-time stripping of debug logs in production builds * // e.g., if (__DEV__) { logger.debug(...) } */ declare function createLogger(config?: Config$3): Instance$3; /** * Gets the mapping for an event. * * @param event The event to get the mapping for (can be partial or full). * @param mapping The mapping rules. * @param collector Required to evaluate rule-level conditions against the unified Context. Legacy callers may omit; rule-level conditions then run with `undefined as never` (defensive). * @returns The mapping result. */ declare function getMappingEvent(event: DeepPartialEvent | PartialEvent | Event, mapping?: Rules, collector?: Instance$6): Promise; /** * Gets a value from a mapping. * * @param value The value to get the mapping from. * @param data The mapping data. * @param options The mapping options. * @returns The mapped value. */ declare function getMappingValue(value: DeepPartialEvent | unknown | undefined, data?: Data$1, context?: Partial): Promise; /** * Processes an event through mapping configuration. * * This is the unified mapping logic used by both sources and destinations. * It applies transformations in this order: * 1. Config-level policy - modifies the event itself (global rules) * 2. Mapping rules - finds matching rule based on entity-action * 3. Event-level policy - modifies the event based on specific mapping rule * 4. Data transformation - creates context data * 5. Ignore check and name override * * Sources can pass partial events, destinations pass full events. * getMappingValue works with both partial and full events. * * @param event - The event to process (can be partial or full, will be mutated by policies) * @param config - Mapping configuration (mapping, data, policy, consent) * @param collector - Collector instance for context * @returns Object with transformed event, data, mapping rule, and ignore flag */ declare function processEventMapping(event: T, config: Config$7, collector: Instance$6): Promise<{ event: T; data?: Property; mapping?: Rule; mappingKey?: string; ignore: boolean; silent: boolean; }>; /** * Resolve a user mapping rule against a package-shipped default rule. * - No extend/remove → replace (clone of override; today's behavior). * - extend → partial rule deep-merged onto base (null clears a field). * - remove → carried onto the merged rule for eval-time output stripping. * The returned rule never contains `extend`. */ declare function mergeMappingRule(base: Rule, override: Rule): Rule; /** * Environment mocking utilities for walkerOS destinations * * Provides standardized tools for intercepting function calls in environment objects, * enabling consistent testing patterns across all destinations. */ type InterceptorFn = (path: string[], args: unknown[], original?: Function) => unknown; /** * Creates a proxied environment that intercepts function calls * * Uses Proxy to wrap environment objects and capture all function calls, * allowing for call recording, mocking, or simulation. * * @param env - The environment object to wrap * @param interceptor - Function called for each intercepted call * @returns Proxied environment with interceptor applied * * @example * ```typescript * const calls: Array<{ path: string[]; args: unknown[] }> = []; * * const testEnv = mockEnv(env.push, (path, args) => { * calls.push({ path, args }); * }); * * // Use testEnv with destination * await destination.push(event, { env: testEnv }); * * // Analyze captured calls * expect(calls).toContainEqual({ * path: ['window', 'gtag'], * args: ['event', 'purchase', { value: 99.99 }] * }); * ``` */ declare function mockEnv(env: T, interceptor: InterceptorFn): T; /** * Traverses environment object and replaces values using a replacer function * * Alternative to mockEnv for environments where Proxy is not suitable. * Performs deep traversal and allows value transformation at each level. * * @param env - The environment object to traverse * @param replacer - Function to transform values during traversal * @returns New environment object with transformed values * * @example * ```typescript * const recordedCalls: APICall[] = []; * * const recordingEnv = traverseEnv(originalEnv, (value, path) => { * if (typeof value === 'function') { * return (...args: unknown[]) => { * recordedCalls.push({ * path: path.join('.'), * args: structuredClone(args) * }); * return value(...args); * }; * } * return value; * }); * ``` */ declare function traverseEnv(env: T, replacer: (value: unknown, path: string[]) => unknown): T; /** * Create a mock context for testing transformers and destinations. * * Provides sensible defaults for all required fields. Override only * what the test cares about. When context signatures change, only * this factory needs updating — not every test file. * * @example * ```typescript * // Transformer test — only specify config * const ctx = createMockContext({ config: { settings: { strict: true } } }); * const result = await transformer.push(event, ctx); * * // Destination test — specify config and custom env * const ctx = createMockContext({ config: { settings: { url } }, env: { sendWeb } }); * await destination.push(event, ctx); * * // With custom ingest data * const ctx = createMockContext({ ingest: { ...createIngest('test'), path: '/api' } }); * ``` */ declare function createMockContext(overrides?: Partial, 'config' | 'ingest'> & { config?: Config$4 | Config$5; ingest?: Ingest | (Record & { _meta: Ingest['_meta']; }); data?: unknown; rule?: unknown; }>): Context$4 & PushContext; /** * Mock logger instance for testing * Includes all logger methods as jest.fn() plus tracking of scoped loggers * Extends Instance to ensure type compatibility */ interface MockLogger extends Instance$3 { error: jest.Mock; warn: jest.Mock; info: jest.Mock; debug: jest.Mock; throw: jest.Mock; json: jest.Mock; scope: jest.Mock; /** * Array of all scoped loggers created by this logger * Useful for asserting on scoped logger calls in tests */ scopedLoggers: MockLogger[]; } /** * Create a mock logger for testing * All methods are jest.fn() that can be used for assertions * * @example * ```typescript * const mockLogger = createMockLogger(); * * // Use in code under test * someFunction(mockLogger); * * // Assert on calls * expect(mockLogger.error).toHaveBeenCalledWith('error message'); * * // Assert on scoped logger * const scoped = mockLogger.scopedLoggers[0]; * expect(scoped.debug).toHaveBeenCalledWith('debug in scope'); * ``` */ declare function createMockLogger(): MockLogger; /** * Checks if a value is a valid property type. * * @param value The value to check. * @returns True if the value is a valid property type, false otherwise. */ declare function isPropertyType(value: unknown): value is PropertyType; /** * Filters a value to only include valid property types. * * @param value The value to filter. * @returns The filtered value or undefined. */ declare function filterValues(value: unknown): Property | undefined; /** * Casts a value to a valid property type. * * @param value The value to cast. * @returns The casted value or undefined. */ declare function castToProperty(value: unknown): Property | undefined; /** * Converts a request string to a data object. * * @param parameter The request string to convert. * @returns The data object or undefined. */ declare function requestToData(parameter: unknown): AnyObject | undefined; /** * Converts a data object to a request string. * * @param data The data object to convert. * @returns The request string. */ declare function requestToParameter(data: AnyObject | PropertyType): string; /** * Transforms data to a string. * * @param data The data to transform. * @returns The transformed data. */ declare function transformData(data?: SendDataValue): string | undefined; /** * Gets the headers for a request. * * @param headers The headers to merge with the default headers. * @returns The merged headers. */ declare function getHeaders(headers?: SendHeaders): SendHeaders; /** * Normalize `config.setup` into a concrete options object, or null when disabled. * * - `false` / `undefined` → null (no setup) * - `true` → `defaults` as-is * - object → shallow merge of defaults and overrides (overrides win) */ declare function resolveSetup(value: boolean | T | undefined, defaults: T): T | null; /** * Throws an error. * * @param error The error to throw. */ declare function throwError(error: unknown): never; /** * Trims quotes and whitespaces from a string. * * @param str The string to trim. * @returns The trimmed string. */ declare function trim(str: string): string; /** * A utility function that wraps a function in a try-catch block. * * @template P, R, S * @param fn The function to wrap. * @param onError A function to call when an error is caught. * @param onFinally A function to call in the finally block. * @returns The wrapped function. */ declare function tryCatch

(fn: (...args: P) => R | undefined, onError: (err: unknown) => S, onFinally?: () => void): (...args: P) => R | S; declare function tryCatch

(fn: (...args: P) => R | undefined, onError?: undefined, onFinally?: () => void): (...args: P) => R | undefined; /** * A utility function that wraps an async function in a try-catch block. * * @template P, R, S * @param fn The async function to wrap. * @param onError A function to call when an error is caught. * @param onFinally A function to call in the finally block. * @returns The wrapped async function. */ declare function tryCatchAsync

(fn: (...args: P) => R, onError: (err: unknown) => S, onFinally?: () => void | Promise): (...args: P) => Promise; declare function tryCatchAsync

(fn: (...args: P) => R, onError?: undefined, onFinally?: () => void | Promise): (...args: P) => Promise; /** * Error subclass for invariant violations or operator-initiated aborts * that must escape the top-level boundary catches in `collector.push` * and `collector.command`. * * Standard `Error` instances are absorbed by the boundary, logged, and * counted on `collector.status.failed`. A `FatalError` rethrows so a * runtime supervisor (CLI runner, Express server, container orchestrator) * can terminate the process cleanly. * * Use sparingly. Most operational failures are recoverable and should * be plain `Error`. Reserve `FatalError` for programmer-error invariant * violations or explicit fail-stop signals. */ declare class FatalError extends Error { constructor(message: string, options?: ErrorOptions); } /** * A utility function that wraps a function with hooks. * * Pre/post hooks are user-supplied and may throw. A throwing hook must not * crash the surrounding pipeline. On failure, fall back to calling the * original function (pre-hook) or keep the original result (post-hook). * * The generic `F` preserves the exact call shape of `fn`, including named * parameters and overloaded interfaces, so call sites can assign the result * to the same interface slot without a cast. * * @template F The exact function type being wrapped. * @param fn The function to wrap. * @param name The name of the function. * @param hooks The hooks to use. * @param logger Optional logger for hook failure warnings. Falls back to * `console.warn` when not provided. * @returns The wrapped function with the same call shape as `fn`. */ declare function useHooks(fn: F, name: string, hooks: Functions, logger?: Instance$3): F; /** * Telemetry level. Off disables emission entirely. Standard projects * structural state without inEvent or outEvent payloads (unless explicitly * opted in). Trace emits full payloads on every hop. */ type TelemetryLevel = 'off' | 'standard' | 'trace'; /** * Options that shape the telemetry projection strategy. Defaults are chosen * so a caller can pass `{ flowId }` and get sensible behavior. */ interface TelemetryOptions { /** Required flow identifier; observers may use this for cross-flow correlation. */ flowId: string; /** Verbosity. Defaults to 'standard'. */ level?: TelemetryLevel; /** Force-include the inbound event regardless of level. */ includeIn?: boolean; /** Force-include the outbound event regardless of level. */ includeOut?: boolean; /** Force-include the matched mapping key (only meaningful for transformers/destinations). */ includeMappingKey?: boolean; /** * Fraction of events to emit, between 0 and 1. Deterministic by eventId: * the same eventId always falls on the same side of the threshold so * paired in/out states either both emit or both drop. */ sample?: number; } type EmitFn = (state: FlowState) => void; /** * Optional supplier form. When passed instead of static `TelemetryOptions`, * the observer evaluates the supplier on every emit so toggle-style runtime * overrides (e.g. `WALKEROS_TRACE_UNTIL`) reach the projection without * rebuilding the observer. */ type TelemetryOptionsSupplier = () => TelemetryOptions | null; /** * Build a telemetry observer that projects FlowState records according to * level/sample/include flags and forwards them to `emit`. The observer is * synchronous, never throws (a throwing emit is swallowed), and does no * IO of its own. Designed to be added to `collector.observers` so the * runtime self-emission loop drives it. * * Accepts either a static `TelemetryOptions` value or a supplier * `() => TelemetryOptions | null`. With a supplier, every emit reads the * current opts so toggles such as `WALKEROS_TRACE_UNTIL` reach the * projection without rebuilding the observer. A supplier returning `null` * suppresses the emit (telemetry off). */ declare function createTelemetryObserver(emit: EmitFn, optsOrSupplier: TelemetryOptions | TelemetryOptionsSupplier): ObserverFn; /** * Convenience export: the internal sampling predicate so callers (and * tests) can verify the deterministic bucketing without importing the * private FNV-1a helper. */ declare function isSampled(eventId: string, sample: number): boolean; /** * Runtime telemetry resolver. * * Converts a flow-side `Flow.Config.observe` block plus a runtime `traceUntil` * override into a concrete `TelemetryOptions` the collector hooks installer can * consume. Pure function of its inputs: it reads no environment. * * Resolution order (highest priority first): * 1. `traceUntil`, if a string that parses to a future ISO timestamp -> * force level=trace, sample=1, include in/out payloads. * 2. The `observe` block. * 3. A tier default of `{ level: 'standard' }`. * * The `traceUntil` value can flip between emits, so trace turns on and off as * the timestamp comes and goes. The platform-specific caller owns the value * and supplies it per emit. */ interface ResolveTelemetryInput { flowId: string; /** From `flow.config?.observe`. May be undefined. */ observe?: { level?: 'off' | 'standard' | 'trace'; sample?: number; }; /** Runtime trace override. ISO timestamp parsing to a future time forces trace. */ traceUntil?: string | null; /** Clock seam for tests. Defaults to `Date.now()`. */ now?: () => number; } /** * Returns `TelemetryOptions` ready to pass to `createTelemetryObserver`, * or `null` if telemetry is disabled (`level === 'off'` with no trace * override). Callers should skip observer installation when this returns * null. */ declare function resolveTelemetryOptions(input: ResolveTelemetryInput): TelemetryOptions | null; declare function getTraceUntil(): string | null; declare function setTraceUntil(v: string | null): void; /** * Synchronously fans out a FlowState record to every registered observer * on the collector. Each call is wrapped in try/catch so a misbehaving * observer cannot crash the runtime; observers are advisory and must not * affect pipeline outcomes. * * Iterates a snapshot of the observer set so an observer adding or removing * another observer during the emit does not re-enter or skip in the same * pass. The early return on an empty set keeps the zero-observer hot path * allocation-free. */ declare function emitStep(collector: Instance$6, state: FlowState): void; /** * Batched FlowState poster. * * Buffers FlowState records and flushes them to an HTTP endpoint either when * `batchMs` elapses since the first queued record, or when `batchSize` is * reached. Returns the emit callback that `createTelemetryObserver` consumes. * * Errors from the underlying fetch are swallowed (or routed through the * optional `onError` callback) so a transient observer outage cannot crash * the runtime. * * Uses the global `fetch` so the same primitive works in Node 18+, browsers, * and Edge runtimes. Tests may inject a stub via `opts.fetch`. */ /** * Minimum HTTP response surface the poster touches. Anything that exposes * `ok` and `status` works. Decoupling from the DOM `Response` type lets the * helper run in Edge, browser, and Node-only test environments without * requiring `lib: dom` or a polyfill. */ interface PosterResponse { ok: boolean; status: number; } /** * Minimum fetch surface the poster needs. A subset of `typeof fetch` that * lets test harnesses pass a plain async function without dragging in the * Response/Request DOM types. */ type PosterFetch = (url: string, init: { method: string; headers: Record; body: string; }) => Promise; interface BatchedPosterOptions { /** Absolute HTTP endpoint URL. POST with JSON array body. */ url: string; /** Bearer token sent in the `Authorization` header. */ token: string; /** Max time to wait before flushing the current batch. Default 50 ms. */ batchMs?: number; /** Max records per batch. When reached, flushes immediately. Default 50. */ batchSize?: number; /** Test seam. Defaults to the global `fetch`. */ fetch?: PosterFetch; /** Called when the underlying POST rejects. Defaults to swallowing. */ onError?: (err: unknown) => void; } /** * Build a batched emit callback. The returned function is synchronous, never * throws, and schedules an async flush in the background. * * Concurrency model: a single in-memory buffer plus a single pending timer. * When the timer fires (or `batchSize` is hit) the buffer is moved into a * local variable and reset, then POSTed. New records arriving during the in- * flight POST land in the next batch. */ declare function createBatchedPoster(opts: BatchedPosterOptions): (state: FlowState) => void; /** * Parses a user agent string to extract browser, OS, and device information. * * @param userAgent The user agent string to parse. * @returns An object containing the parsed user agent information. */ declare function parseUserAgent(userAgent?: string): User; /** * Gets the browser name from a user agent string. * * @param userAgent The user agent string. * @returns The browser name or undefined. */ declare function getBrowser(userAgent: string): string | undefined; /** * Gets the browser version from a user agent string. * * @param userAgent The user agent string. * @returns The browser version or undefined. */ declare function getBrowserVersion(userAgent: string): string | undefined; /** * Gets the OS name from a user agent string. * * @param userAgent The user agent string. * @returns The OS name or undefined. */ declare function getOS(userAgent: string): string | undefined; /** * Gets the OS version from a user agent string. * * @param userAgent The user agent string. * @returns The OS version or undefined. */ declare function getOSVersion(userAgent: string): string | undefined; /** * Gets the device type from a user agent string. * * @param userAgent The user agent string. * @returns The device type or undefined. */ declare function getDeviceType(userAgent: string): string | undefined; /** * Inline Code Wrapping Utilities * * Converts inline code strings to executable functions for the three mapping * callbacks: condition, fn, validate. All three share a single signature: * * (value, context) => result * * Inside the inline body, the available bindings are: * - value: unknown - the value being mapped/validated/checked * - context: Mapping.Context with these fields: * event: WalkerOS.DeepPartialEvent * mapping: Mapping.Value | Mapping.Rule * collector: Collector.Instance * logger: Logger.Instance * consent?: WalkerOS.Consent * * If the body has no explicit `return`, it is auto-wrapped with `return`. * * @packageDocumentation */ /** * Wrap inline code as a Mapping.Condition. * * @example * ```ts * const c = wrapCondition('context.consent?.marketing === true'); * c(value, context); // boolean * ``` */ declare function wrapCondition(code: string): Condition; /** * Wrap inline code as a Mapping.Fn. * * @example * ```ts * const fn = wrapFn('value.user.email.split("@")[1]'); * fn(value, context); // domain * ``` */ declare function wrapFn(code: string): Fn$4; /** * Wrap inline code as a Mapping.Validate. * * @example * ```ts * const v = wrapValidate('typeof value === "string" && value.length > 0'); * v(value, context); // boolean * ``` */ declare function wrapValidate(code: string): Validate; interface ExampleSummary { name: string; description?: string; } interface WalkerOSPackageMeta { packageName: string; version: string; description?: string; type?: string; platform?: string | string[]; } interface WalkerOSPackageInfo { packageName: string; version: string; type?: string; platform?: string | string[]; schemas: Record; examples: Record; hints?: Record; } interface WalkerOSPackage extends WalkerOSPackageInfo { description?: string; docs?: string; source?: string; hintKeys: string[]; exampleSummaries: ExampleSummary[]; } declare function fetchPackage(packageName: string, options?: { version?: string; timeout?: number; baseUrl?: string; client?: string; }): Promise; /** * @deprecated Use fetchPackage instead. * Still used by: entry.ts (validator), package-schemas.ts (MCP resource). */ declare function fetchPackageSchema(packageName: string, options?: { version?: string; timeout?: number; baseUrl?: string; client?: string; }): Promise; /** Options for {@link resolveContracts}. */ interface ResolveContractsOptions { /** * When true (default), annotation keys (`description`, `examples`, `title`, * `$comment`) are stripped from event schemas so the result is AJV-clean for * runtime validation. Set to false to keep annotations (e.g. for IntelliSense * that surfaces property descriptions). */ stripAnnotations?: boolean; } /** * Resolve all named contracts: process extend chains, expand wildcards, * strip annotations from event schemas. * * Returns a fully resolved map where each contract entry has inherited * properties merged in and wildcards expanded into concrete actions. * * By default annotations are stripped (AJV-clean). Pass * `{ stripAnnotations: false }` to preserve `description`/`examples`/`title` * on event schemas. */ declare function resolveContracts(contracts: Flow.Contract, options?: ResolveContractsOptions): Record; /** * Deep merge two JSON Schema objects with additive semantics. * - `required` arrays: union (deduplicated) * - `properties`: deep merge (child wins on conflict for scalars) * - Scalars: child overrides parent */ declare function mergeContractSchemas(parent: Record, child: Record): Record; declare function mcpResult(result: unknown, hints?: { next?: string[]; warnings?: string[]; }): { content: { type: "text"; text: string; }[]; structuredContent: Record; }; declare function mcpError(error: unknown, hint?: string): { content: { type: "text"; text: string; }[]; structuredContent: Record; isError: true; }; /** * Compiles a match expression into a closure for fast runtime evaluation. * Regex patterns are compiled once. Numeric comparisons are parsed once. * Runtime evaluation is pure function calls with short-circuit logic. */ declare function compileMatcher(expr: MatchExpression | '*' | undefined): CompiledMatcher; declare function isRouteConfigEntry(entry: unknown): boolean; /** * Pure RouteConfig array — every element is a RouteConfig object. * Used to detect the legacy first-match shape (treated as implicit `one`). */ declare function isRouteArray(next: Route): next is RouteConfig[]; /** * Resolve a Route spec against a matcher context. Returns the immediate * next transformer IDs. * * Return shape: * [] → terminate (gate failed, empty many, all matchers failed, * undefined spec). * ["x"] → continue main chain at x. * ["a","b",…] → fan-out, only produced by `many`. Main chain terminates * at this dispatch point; each branch is an independent * flow running to its own exit. * * Reachability vs prediction: `match` rules read arbitrary event fields. * `getNextSteps` is deterministic for the SUPPLIED context only. Static * analyzers without a real event must over-approximate by treating each * match as "may pass or fail" — see `flattenRouteTargets` in the CLI * validator. This function does NOT predict the path a future event will * take; it computes the path for the event you give it. */ declare function getNextSteps(spec: Route | undefined, context?: Record): string[]; interface CompiledCacheRule { match: CompiledMatcher; key: string[]; ttl: number; update?: EventCacheRule['update']; } interface CompiledCache { stop: boolean; storeId?: string; namespace?: string; rules: CompiledCacheRule[]; } interface CacheResult { status: 'HIT' | 'MISS'; key: string; value?: StoreValue; rule: CompiledCacheRule; } /** * Builds a structured context object for cache and routing operations. * Normalizes ingest (defaulting to {}) and optionally includes event. */ declare function buildCacheContext(ingest?: unknown, event?: unknown): Record; declare function compileCache(cache: Cache): CompiledCache; declare function checkCache(compiled: CompiledCache, store: Instance$1, context: Record, namespace?: string): Promise; declare function storeCache(store: Instance$1, key: string, value: unknown, ttlSeconds: number): void; declare function applyUpdate(value: unknown, update: Record | undefined, context: Record, collector: Instance$6): Promise; /** * Shared cache envelope used by BOTH cache mechanisms (the event cache in * `./cache.ts` and the store-cache wrapper in * `@walkeros/collector/store-cache-wrapper`). A cached value is wrapped in a * plain `{value, exp}` structured object, not a Buffer: the backing store * serializes it through the shared store codec (`./store/codec`), so any * structured store can persist it byte-exact, and a TTL-native tier * (in-memory `__cache`, Redis) can additionally evict via the `ttl` arg. * * The envelope owns expiry interpretation, not the store contract: * `StoreValue` carries no TTL field. The physical envelope keys are * namespaced (`__walkeros_cache_v__` / `__walkeros_cache_exp__`) so a user * value that happens to be shaped `{ value, exp }` is never mistaken for an * envelope, and conversely a wrapped envelope is unambiguous on read. */ declare const ENVELOPE_VALUE = "__walkeros_cache_v__"; declare const ENVELOPE_EXP = "__walkeros_cache_exp__"; /** A wrapped cache envelope as it is persisted into the backing store. */ type CacheEnvelope = { [ENVELOPE_VALUE]: StoreValue; [ENVELOPE_EXP]?: number; }; /** * Wrap a value in a `{value, exp}` envelope. When `ttlMs` is given, `exp` is * `now() + ttlMs`; when omitted, `exp` is left off entirely (no expiry). * * `now` is injectable so tests do not depend on ambient wall-clock time; * production callers omit it and the helper falls back to `Date.now`. */ declare function wrapCacheEnvelope(value: StoreValue, ttlMs?: number, now?: () => number): CacheEnvelope; /** * Read a stored envelope. Returns: * - `undefined` when the key is absent (`stored === undefined`). * - `{ expired: true }` when the envelope's `exp` has elapsed (caller should * best-effort purge and treat as a MISS). * - `{ value }` otherwise. * * A stored value that is not a recognizable envelope (a raw live value, e.g. * a TTL-native tier that holds the value by reference, or a legacy entry) is * returned verbatim as `{ value: stored }`, so a non-enveloped HIT degrades * gracefully rather than being dropped. */ declare function readCacheEnvelope(stored: StoreValue | undefined, now?: () => number): { value: StoreValue; } | { expired: true; } | undefined; /** * Thrown when a value cannot be serialized (e.g. a cyclic structure that * `JSON.stringify` rejects). Catchable and distinguishable from a raw * `TypeError` leaking out of the platform JSON implementation. */ declare class StoreCodecError extends Error { constructor(message: string, options?: { cause?: unknown; }); } /** * Recursive type guard: the restored value is structurally a `StoreValue`. * The single restore walk (`fromSerializableWith`) is JSON-derived plus * `Uint8Array` binary leaves, so this always holds; the guard makes the * narrowing explicit and cast-free at the public boundary. * * The guard accepts exactly what the serializer can encode. An `undefined` * object property is dropped and an `undefined` array element becomes `null` * on `JSON.stringify`, so an `undefined` nested value does NOT disqualify the * containing value (matching the serializer's runtime tolerance at the * `unknown -> StoreValue` boundary). The `StoreValue` TYPE still excludes * `undefined`; this only mirrors what survives serialization. */ declare function isStoreValue(value: unknown): value is StoreValue; /** * Serialize a `StoreValue` to its UTF-8 JSON byte payload. Throws * `StoreCodecError` if the value cannot be encoded (e.g. a cyclic structure). */ declare function serializeStoreValue(value: StoreValue): Uint8Array; /** * Restore a `StoreValue` from its UTF-8 JSON byte payload (or a JSON string). */ declare function deserializeStoreValue(raw: Uint8Array | string): StoreValue; /** * Resolve a store by id. An `undefined` id falls back to the default * in-memory `__cache` store. Returns `undefined` when the id is unknown. */ type GetStore = (id: string | undefined) => Instance$1 | undefined; /** Normalize a single State or an array of States to an array. */ declare function compileState(state: State | State[]): State[]; /** * Apply declarative store operations against an event, in array order, * sequentially. `get` reads from the store and writes the fetched value to * the event's value path; `set` writes the resolved value to the store. Each * entry is fail-open: a store or resolution error is logged and the event is * left unmutated, the chain continues. Only `FatalError` rethrows (via * `getMappingValue`). */ declare function applyState(states: State[], getStore: GetStore, event: E, collector: Instance$6): Promise; /** * Single source of truth for step-entry validation across all four kinds. * * An empty entry (no `code`, no `package`, no `import`) is a valid no-op * step for all four kinds. The bundler emits no code; the runtime skips * registration. No error is raised for empty steps. * * Error codes: * - UNKNOWN_KEY unknown top-level key on a step entry * - CONFLICT two of {code, package, import} together, or other mutually exclusive pairs * - MISSING_PACKAGE `import` set without `package` * - OBSOLETE_CODE_STRING `code` is a string (legacy named-export shape; use `import` instead) * - INVALID_IMPORT `import` is set but is not a valid JS identifier * - INVALID_CODE_SHAPE `code` is present but is neither an object nor a string */ declare const STEP_OPERATIVE_FIELDS: Record; type StepEntryErrorCode = 'UNKNOWN_KEY' | 'CONFLICT' | 'MISSING_PACKAGE' | 'OBSOLETE_CODE_STRING' | 'INVALID_IMPORT' | 'INVALID_CODE_SHAPE'; interface StepEntryValidation { ok: boolean; reason?: string; code?: StepEntryErrorCode; key?: string; } declare function validateStepEntry(entry: Record, kind: Flow.StepKind): StepEntryValidation; declare function isPathStepEntry(entry: Record, kind: Flow.StepKind): boolean; type StepOut = Flow.StepOut; /** * Format a step example's `out` as readable code for docs/app rendering. * * - Empty `out` → `// no output`. * - `['return', value]` → `return ` (no parentheses). * - `[callable, ...args]` → `callable()`. * - Primitive args render as JSON (strings quoted, numbers/booleans/null bare). * - `undefined` renders as the literal token `undefined`. * - Objects/arrays render as `JSON.stringify(v, null, 2)`. * - Functions render as `[Function]` (rare in outs; safe fallback). * * Pure function. No runtime dependencies. Used by the website * `` renderer and the app `OutputPanel` for a single source of truth. */ declare function formatOut(out: StepOut): string; /** * walkerOS reference-syntax regex constants — single source of truth. * * Rule: * - `.` = key or path (resolver walks it) * - `:` = literal value or raw-code payload (resolver uses it verbatim) * * Every tool that recognizes references (core resolver, CLI bundler, * app secrets service, explorer IntelliSense) imports these — no * inline regexes elsewhere. */ declare const REF_VAR_FULL: RegExp; declare const REF_VAR_INLINE: RegExp; declare const REF_ENV: RegExp; declare const REF_CONTRACT: RegExp; /** Whole-string `$flow.(.)?`: cross-flow value reference. */ declare const REF_FLOW: RegExp; declare const REF_STORE: RegExp; declare const REF_SECRET: RegExp; declare const REF_CODE_PREFIX = "$code:"; /** * Canonical scanner for the `$flow.` reference grammar. Walks strings, * arrays, and objects and returns every referenced flow name. The returned * set is the same instance as `into` when one is supplied, so callers can * accumulate across multiple values. */ declare function scanFlowRefs(value: unknown, into?: Set): Set; export { type BatchedPosterOptions, type BreakerState, cache as Cache, type CacheEnvelope, type CacheResult, type ClickIdEntry, collector as Collector, type CompiledCache, Const, context as Context, type Credential, type Debounced, destination as Destination, type DestroyContext, type DestroyFn, type DroppedCounters, ENV_MARKER_PREFIX, elb as Elb, type EmitFn, type ExampleSummary, FatalError, Flow, type FlowConfigResolver, type FlowState, type FlowStateBatch, type FlowStatePhase, type FlowStepType, type GetStore, hint as Hint, hooks as Hooks, type Ingest, type IngestMeta, type JsonSchema, Level, lifecycle as Lifecycle, type LifecycleContext, logger as Logger, mapping as Mapping, type MarketingParameters, matcher as Matcher, type MockLogger, type ObserverFn, on as On, type PosterFetch, type PosterResponse, REF_CODE_PREFIX, REF_CONTRACT, REF_ENV, REF_FLOW, REF_SECRET, REF_STORE, REF_VAR_FULL, REF_VAR_INLINE, request as Request, type ResolveContractsOptions, type ResolveOptions, type RespondFn, type RespondOptions, SECRET_MARKER_PREFIX, STEP_OPERATIVE_FIELDS, type ScheduleOptions, type SendDataValue, type SendHeaders, type SendResponse, type ServiceAccount, type SetupFn, simulation as Simulation, source as Source, type State, type StepEntryErrorCode, type StepEntryValidation, type StepKind, type StorageType, store as Store, StoreCodecError, type TelemetryLevel, type TelemetryOptions, type TelemetryOptionsSupplier, transformer as Transformer, trigger as Trigger, type ValidateEvents, walkeros as WalkerOS, type WalkerOSPackage, type WalkerOSPackageInfo, type WalkerOSPackageMeta, anonymizeIP, applyState, applyUpdate, assign, branch, buildCacheContext, castToProperty, castValue, checkCache, clone, compileCache, compileMatcher, compileState, createBatchedPoster, createDestination, createEvent, createIngest, createLogger, createMockContext, createMockLogger, createRespond, createTelemetryObserver, debounce, deepMerge, defaultClickIds, deleteByPath, deserializeStoreValue, emitStep, fetchPackage, fetchPackageSchema, filterValues, flattenIncludeSections, formatOut, getBrowser, getBrowserVersion, getByPath, getDeviceType, getEvent, getFlowSettings, getGrantedConsent, getHeaders, getId, getMappingEvent, getMappingValue, getMarketingParameters, getNextSteps, getOS, getOSVersion, getPlatform, getSpanId, getTraceId, getTraceUntil, isArguments, isArray, isBoolean, isCommand, isDefined, isElementOrDocument, isFunction, isNumber, isObject, isPathStepEntry, isPropertyType, isRouteArray, isRouteConfigEntry, isSameType, isSampled, isStoreValue, isString, mcpError, mcpResult, mergeContractSchemas, mergeMappingRule, mockEnv, packageNameToVariable, parseUserAgent, processEventMapping, readCacheEnvelope, requestToData, requestToParameter, resolveContracts, resolveSetup, resolveTelemetryOptions, scanFlowRefs, serializeStoreValue, setByPath, setTraceUntil, stepId, storeCache, throttle, throwError, transformData, traverseEnv, trim, tryCatch, tryCatchAsync, useHooks, validateStepEntry, walkPath, wrapCacheEnvelope, wrapCondition, wrapFn, wrapValidate };