/** * walkSubflowSpec — yield the structural shape of a subflow spec as a * flat ordered stream of items, with `subflowPath` already composed * for nested subflows. * * This is the public contract for traversing the structure delivered * via `StructureSubflowMountedEvent.subflowSpec`. Item shapes mirror * the corresponding Structure event payloads so consumers can route * walker items through the same handlers they use for live events. * * Walker contract (LOCKED): * 1. AUTO-RECURSE by default into nested subflows, with composed * paths (`parent/child/...`). Pass `{ recurse: false }` to walk * only one level. * 2. ENTRY-STAGE MARKER FIRST: for each subflow (top-level and * nested), yields a `{ kind: 'subflow-start', ... }` item BEFORE * any stage/edge items from that subflow. Lets consumers draw the * boundary edge from the mount node to the entry stage. * 3. COMPOSED PATHS: nested subflows get `parentPath + '/' + localId`. * Top-level mount paths are local-only (`'auth'`, NOT `'__root__/auth'`). * 4. SHAPE MIRRORING: stage/edge/loop items have the same payload * shape as Structure events, with `subflowPath` added. * 5. SOURCE DISCRIMINATOR: every walker item carries `source: 'walker'` * (Structure events do NOT). Lets consumers distinguish event vs * walker in logs/debuggers while still sharing handler code paths. * 6. STAGE-ID PREFIXING: stage IDs in nested subflows are already * prefixed by the spec (e.g. `'auth/verify/check'`). Walker * preserves this; `subflowPath` field is redundant-but-explicit. */ import type { SerializedPipelineStructure } from '../builder/types.js'; export interface WalkerOptions { /** Auto-recurse into nested subflows (default: true). When false, * nested subflow items are yielded but their internals are not * traversed. */ recurse?: boolean; } export type WalkerItem = { kind: 'subflow-start'; stageId: string; subflowPath: string; source: 'walker'; } | { kind: 'stage'; stageId: string; name: string; type: NonNullable; isPausable?: boolean; spec: SerializedPipelineStructure; subflowPath: string; source: 'walker'; } | { kind: 'edge'; from: string; to: string; edgeKind: 'next' | 'fork-branch' | 'decision-branch'; label?: string; subflowPath: string; source: 'walker'; } | { kind: 'loop'; from: string; to: string; subflowPath: string; source: 'walker'; } | { kind: 'subflow'; mountStageId: string; subflowId: string; subflowName: string; subflowSpec: SerializedPipelineStructure; subflowPath: string; source: 'walker'; }; /** * Walk a subflow spec, yielding its structure as flat ordered items. * * @example * ```ts * import { walkSubflowSpec } from 'footprintjs/trace'; * * onSubflowMounted(event) { * if (!event.subflowSpec) return; // lazy mount — no spec yet * for (const item of walkSubflowSpec(event.subflowSpec, event.subflowPath)) { * switch (item.kind) { * case 'subflow-start': break; // entry boundary * case 'stage': break; // inner stage * case 'edge': break; // inner edge * case 'loop': break; // inner loop back-edge * case 'subflow': break; // nested mount marker * } * } * } * ``` */ export declare function walkSubflowSpec(spec: SerializedPipelineStructure, subflowPath: string, options?: WalkerOptions): Generator;