flowcraft 1.0.0-beta.12 → 1.0.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -67,7 +67,7 @@ graph LR
67
67
  ```
68
68
 
69
69
  - **Demonstrates**: `Node` chaining, passing data via `Context`, and a simple `BatchFlow`.
70
- - **[Explore the Basic example »](./sandbox/1.basic/)**
70
+ - **[Explore the Basic example »](https://github.com/gorango/flowcraft/tree/main/sandbox/1.basic/)**
71
71
 
72
72
  ### 2. Conditional Branching: Research Agent
73
73
 
@@ -81,7 +81,7 @@ graph TD
81
81
  ```
82
82
 
83
83
  - **Demonstrates**: Conditional branching with custom actions, creating loops, and building simple state machines.
84
- - **[Explore the Research Agent example »](./sandbox/2.research/)**
84
+ - **[Explore the Research Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/2.research/)**
85
85
 
86
86
  ### 3. Parallel Batch Processing: Document Translator
87
87
 
@@ -101,7 +101,7 @@ graph TD
101
101
  ```
102
102
 
103
103
  - **Demonstrates**: `ParallelBatchFlow` for high-throughput concurrent processing of I/O-bound tasks.
104
- - **[Explore the Parallel Translation example »](./sandbox/3.parallel/)**
104
+ - **[Explore the Parallel Translation example »](https://github.com/gorango/flowcraft/tree/main/sandbox/3.parallel/)**
105
105
 
106
106
  ### 4. Dynamic Graph Engine: AI Agent Runtime
107
107
 
@@ -133,7 +133,7 @@ graph TD
133
133
  - Parallel fan-in and fan-out (mid-flow branching).
134
134
  - Reusable, data-driven nodes (e.g., an LLM-powered router).
135
135
  - Complex sub-workflow composition.
136
- - **[Explore the Dynamic AI Agent example »](./sandbox/4.dag/)**
136
+ - **[Explore the Dynamic AI Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/4.dag/)**
137
137
 
138
138
  ### 5. Distributed Execution: AI Agent with BullMQ
139
139
 
@@ -144,7 +144,7 @@ This example takes the same type-safe graph definition from the previous example
144
144
  - Client-worker architecture with state serialization.
145
145
  - Mid-flight, distributed cancellation of long-running jobs.
146
146
  - How business logic (the graph) remains unchanged when the execution environment changes.
147
- - **[Explore the Distributed AI Agent example »](./sandbox/5.distributed/)**
147
+ - **[Explore the Distributed AI Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/5.distributed/)**
148
148
 
149
149
  ### 6. Advanced RAG Agent: Complex Data & Serialization
150
150
 
@@ -163,7 +163,7 @@ graph TD
163
163
  - A mix of custom, single-responsibility nodes.
164
164
  - Handling complex data types (`Map`, `Date`, custom classes) in the `Context`.
165
165
  - The necessity of robust serialization (using `superjson`) for state management.
166
- - **[Explore the RAG Agent example »](./sandbox/6.rag/)**
166
+ - **[Explore the RAG Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/6.rag/)**
167
167
 
168
168
  ## Core Concepts
169
169
 
@@ -219,6 +219,68 @@ A chainable API on the `Node` class has a set of functional helpers:
219
219
  - `.toContext(key)`: Store a node's result in the context.
220
220
  - `.withLens(lens, value)`: Applies a context mutation before the node executes
221
221
 
222
+ ### Simplified Node Base Classes
223
+
224
+ To reduce boilerplate for common patterns, Flowcraft provides specialized abstract base classes.
225
+
226
+ #### `ExecNode`
227
+
228
+ For nodes that only need to perform a core action and return a value. This is the most common pattern.
229
+
230
+ ```typescript
231
+ // 1. Define params and the node, extending ExecNode<ExecRes, TParams>
232
+ interface GreetParams { name: string }
233
+
234
+ class GreetNode extends ExecNode<string, GreetParams> {
235
+ // 2. You only need to implement the 'exec' method.
236
+ async exec({ params }: NodeArgs<void, void, GreetParams>): Promise<string> {
237
+ return `Hello, ${params.name}!`
238
+ }
239
+ }
240
+
241
+ // Usage:
242
+ const greetNode = new GreetNode().withParams({ name: 'World' })
243
+ ```
244
+
245
+ #### `PreNode`
246
+
247
+ For nodes that only modify state (e.g., in the `Context`) and don't produce an output. Their logic can be placed in the `prep` phase.
248
+
249
+ ```typescript
250
+ const COUNTER = contextKey<number>('counter')
251
+
252
+ class IncrementCounterNode extends PreNode {
253
+ // You only need to implement the 'prep' method for context mutations.
254
+ async prep({ ctx }: NodeArgs): Promise<void> {
255
+ const current = ctx.get(COUNTER) ?? 0
256
+ ctx.set(COUNTER, current + 1)
257
+ }
258
+ }
259
+ ```
260
+
261
+ #### `PostNode`
262
+
263
+ For nodes that route the workflow by returning a custom action string from their `post` method.
264
+
265
+ ```typescript
266
+ const USER_ROLE = contextKey<'admin' | 'guest'>('user_role')
267
+
268
+ type UserAction = 'grant_access' | 'deny_access'
269
+
270
+ class CheckAdminNode extends PostNode<UserAction> {
271
+ // You only need to implement the 'post' method for branching logic.
272
+ async post({ ctx }: NodeArgs): Promise<UserAction> {
273
+ const role = ctx.get(USER_ROLE)
274
+ return role === 'admin' ? 'grant_access' : 'deny_access'
275
+ }
276
+ }
277
+
278
+ // Usage in a flow:
279
+ const checkAdmin = new CheckAdminNode()
280
+ checkAdmin.next(new AdminPanelNode(), 'grant_access')
281
+ checkAdmin.next(new GuestPageNode(), 'deny_access')
282
+ ```
283
+
222
284
  ### Flow
223
285
 
224
286
  A `Flow` is a special type of `Node` that orchestrates a sequence of other nodes. It is also generic (`Flow<PrepRes, ExecRes, TParams>`) and can be configured with its own parameters and middleware. It contains the logic for traversing its own graph of operations, making it a powerful, self-contained unit of work.
@@ -252,9 +314,9 @@ To simplify the creation of common and complex patterns, the framework provides
252
314
  > [!TIP]
253
315
  > For clear, focused examples of specific, individual features (like retries, middleware, cancellation, and composition), the unit tests are an excellent resource.
254
316
 
255
- - Core workflow tests: [`src/workflow.test.ts`](src/workflow.test.ts)
256
- - Patterns tests: [`src/builder/patterns.test.ts`](src/builder/patterns.test.ts)
257
- - Graph builder tests: [`src/builder/graph.test.ts`](src/builder/graph.test.ts)
317
+ - Core workflow tests: [`src/workflow.test.ts`](https://github.com/gorango/flowcraft/tree/main/workflow.test.ts)
318
+ - Patterns tests: [`src/builder/patterns.test.ts`](https://github.com/gorango/flowcraft/tree/main/builder/patterns.test.ts)
319
+ - Graph builder tests: [`src/builder/graph.test.ts`](https://github.com/gorango/flowcraft/tree/main/builder/graph.test.ts)
258
320
 
259
321
  ## API Reference
260
322
 
@@ -294,4 +356,4 @@ A collection of functions for creating nodes and pipelines in a more functional
294
356
  The complete [Flowcraft documentation](https://flowcraft-docs.netlify.app) is available on the website.
295
357
 
296
358
  ---
297
- Licensed under the [MIT License](./LICENSE).
359
+ Licensed under the [MIT License](https://github.com/gorango/flowcraft/tree/main/LICENSE).
package/dist/index.d.ts CHANGED
@@ -318,6 +318,8 @@ interface TypedWorkflowGraph<T extends {
318
318
  type TypedNodeRegistry<TNodeMap extends NodeTypeMap, TContext = object> = {
319
319
  [K in keyof TNodeMap as string extends K ? never : number extends K ? never : K]: new (options: NodeConstructorOptions<TNodeMap[K], TContext> & TContext) => AbstractNode;
320
320
  };
321
+ type PredecessorIdMap = Map<string, string[]>;
322
+ type OriginalPredecessorIdMap = Map<string, string[]>;
321
323
  /**
322
324
  * The result of a successful `GraphBuilder.build()` call.
323
325
  */
@@ -329,7 +331,14 @@ interface BuildResult {
329
331
  /** A map of all node `id`s to their predecessor count. */
330
332
  predecessorCountMap: Map<string, number>;
331
333
  /** A map of all node `id`s to an array of their predecessor `id`s. */
332
- predecessorIdMap: Map<string, string[]>;
334
+ predecessorIdMap: PredecessorIdMap;
335
+ /**
336
+ * A map of all node `id`s to an array of their original (un-namespaced) predecessor `id`s.
337
+ * This represents the logical dependencies of the graph before flattening.
338
+ * Note: For sub-workflow nodes, their direct predecessors will be the logical terminal nodes
339
+ * from *within* that sub-workflow, reflecting the data flow.
340
+ */
341
+ originalPredecessorIdMap: OriginalPredecessorIdMap;
333
342
  }
334
343
  /**
335
344
  * Represents a node within the workflow graph.
@@ -358,8 +367,29 @@ interface WorkflowGraph {
358
367
  * This is a simpler (UNTYPED) version of the `TypedNodeRegistry` type
359
368
  */
360
369
  type NodeRegistry = Map<string, new (...args: any[]) => AbstractNode>;
370
+ /**
371
+ * An interface for an object that can resolve a sub-workflow definition by its ID.
372
+ */
373
+ interface SubWorkflowResolver {
374
+ getGraph: (id: number | string) => WorkflowGraph | undefined;
375
+ }
376
+ /**
377
+ * Options for configuring the behavior of the `GraphBuilder`.
378
+ */
361
379
  interface GraphBuilderOptions {
380
+ /**
381
+ * An array of node type names that should be treated as sub-workflows.
382
+ * When the builder encounters a node whose type is in this list, it will
383
+ * attempt to use the `subWorkflowResolver` to fetch and inline the corresponding graph.
384
+ * @example ['sub-flow', 'reusable-task-group']
385
+ */
362
386
  subWorkflowNodeTypes?: string[];
387
+ /**
388
+ * An object that provides the logic for retrieving a sub-workflow's graph definition.
389
+ * This is required if the graph contains any nodes whose types are listed in `subWorkflowNodeTypes`.
390
+ * The `getGraph` method will be called with the `workflowId` from the node's data payload.
391
+ */
392
+ subWorkflowResolver?: SubWorkflowResolver;
363
393
  }
364
394
 
365
395
  /**
@@ -571,6 +601,55 @@ declare class Node<PrepRes = any, ExecRes = any, PostRes = any, TParams extends
571
601
  */
572
602
  withLens<T>(lens: ContextLens<T>, value: T): Node<PrepRes, ExecRes, PostRes, TParams>;
573
603
  }
604
+ /**
605
+ * A simplified base class for nodes that only need to perform a core action.
606
+ * This pattern is ideal for nodes that receive their inputs via `params` and
607
+ * produce an output, without needing `prep` or complex `post` branching logic.
608
+ *
609
+ * @template ExecRes The type of data returned by the `exec` phase.
610
+ * @template TParams The type for the node's static parameters.
611
+ */
612
+ declare abstract class ExecNode<ExecRes = any, TParams extends Params = Params> extends Node<void, ExecRes, any, TParams> {
613
+ /**
614
+ * (Lifecycle) Performs the core, isolated logic of the node.
615
+ * This is the only phase that is retried on failure. It should not access the `Context` directly.
616
+ * @param args The arguments for the node, including `prepRes`.
617
+ * @returns The result of the execution.
618
+ */
619
+ abstract exec(args: NodeArgs<void, void, TParams>): Promise<ExecRes>;
620
+ }
621
+ /**
622
+ * A simplified base class for nodes that only perform a side effect, such as
623
+ * modifying the `Context` or logging. These nodes do not produce an `exec` result.
624
+ * Their logic is typically placed in the `prep` phase.
625
+ *
626
+ * @template TParams The type for the node's static parameters.
627
+ */
628
+ declare abstract class PreNode<TParams extends Params = Params> extends Node<void, void, any, TParams> {
629
+ /**
630
+ * (Lifecycle) Prepares data or performs a side effect. Runs once before `exec`.
631
+ * This is the ideal place to read from or write to the `Context`.
632
+ * @param args The arguments for the node, including `ctx` and `params`.
633
+ */
634
+ abstract prep(args: NodeArgs<void, void, TParams>): Promise<void>;
635
+ }
636
+ /**
637
+ * A simplified base class for nodes that make a branching decision.
638
+ * This pattern is ideal for routing the workflow based on data in the `Context`.
639
+ * The branching logic is placed in the `post` phase, which returns a custom action string.
640
+ *
641
+ * @template PostRes The type of the "action" string returned by the `post` phase.
642
+ * @template TParams The type for the node's static parameters.
643
+ */
644
+ declare abstract class PostNode<PostRes = any, TParams extends Params = Params> extends Node<void, void, PostRes, TParams> {
645
+ /**
646
+ * (Lifecycle) Processes results and determines the next step. Runs once after `exec`.
647
+ * This is the ideal place to write data to the `Context` and return an action.
648
+ * @param args The arguments for the node, including `execRes`.
649
+ * @returns An "action" string to determine which successor to execute next.
650
+ */
651
+ abstract post(args: NodeArgs<void, void, TParams>): Promise<PostRes>;
652
+ }
574
653
  /**
575
654
  * A special type of `Node` that orchestrates a graph of other nodes.
576
655
  * It can contain its own middleware and can be composed within other flows.
@@ -690,12 +769,11 @@ declare function createNodeRegistry<TNodeMap extends NodeTypeMap, TContext = obj
690
769
  * @template TNodeMap A `NodeTypeMap` for validating type-safe graph definitions.
691
770
  * @template TContext The shape of the dependency injection context object.
692
771
  */
693
- declare class GraphBuilder<TNodeMap extends NodeTypeMap, TContext extends {
694
- registry?: any;
695
- } = object> {
772
+ declare class GraphBuilder<TNodeMap extends NodeTypeMap, TContext extends object = object> {
696
773
  private nodeOptionsContext;
697
774
  private registry;
698
775
  private subWorkflowNodeTypes;
776
+ private subWorkflowResolver?;
699
777
  private logger;
700
778
  /**
701
779
  * @param registry A type-safe object or a `Map` where keys are node `type` strings and
@@ -710,10 +788,11 @@ declare class GraphBuilder<TNodeMap extends NodeTypeMap, TContext extends {
710
788
  /**
711
789
  * Builds a runnable `Flow` from a graph definition.
712
790
  * @param graph The `WorkflowGraph` object describing the flow.
791
+ * @param log Whether to log the graph after flattening. Defaults to `false`.
713
792
  * @returns A `BuildResult` object containing the executable `flow` and a `nodeMap`.
714
793
  */
715
- build(graph: TypedWorkflowGraph<TNodeMap>): BuildResult;
716
- build(graph: WorkflowGraph): BuildResult;
794
+ build(graph: TypedWorkflowGraph<TNodeMap>, log?: boolean): BuildResult;
795
+ build(graph: WorkflowGraph, log?: boolean): BuildResult;
717
796
  /**
718
797
  * Creates a map of each node ID to an array of its direct predecessor node IDs.
719
798
  * This is a helper for executors that need to know a node's direct inputs.
@@ -721,7 +800,7 @@ declare class GraphBuilder<TNodeMap extends NodeTypeMap, TContext extends {
721
800
  * @returns A map where each key is a node ID and the value is an array of its predecessor IDs.
722
801
  * @private
723
802
  */
724
- private _createPredecessorIdMap;
803
+ private _createPredecessorIdMaps;
725
804
  /**
726
805
  * Finds the first node where all parallel branches converge.
727
806
  * Uses a Breadth-First Search to guarantee finding the nearest convergence point.
@@ -1059,6 +1138,26 @@ declare const checkForCycles: Validator;
1059
1138
  */
1060
1139
  declare function generateMermaidGraph(flow: Flow): string;
1061
1140
 
1141
+ /**
1142
+ * Composes a chain of middleware functions around a node's execution.
1143
+ * @internal
1144
+ */
1145
+ declare function applyMiddleware<T = any>(middleware: Middleware<T>[], nodeToRun: AbstractNode): MiddlewareNext<T>;
1146
+
1147
+ /**
1148
+ * Sanitizes a raw workflow graph object by removing properties that are not
1149
+ * relevant to the execution engine, such as UI-specific data.
1150
+ *
1151
+ * @param rawGraph - The raw graph object, potentially containing extraneous properties.
1152
+ * @param rawGraph.nodes - An array of node objects.
1153
+ * @param rawGraph.edges - An array of edge objects.
1154
+ * @returns A clean, execution-focused `WorkflowGraph` object.
1155
+ */
1156
+ declare function sanitizeGraph(rawGraph: {
1157
+ nodes: any[];
1158
+ edges: any[];
1159
+ }): WorkflowGraph;
1160
+
1062
1161
  /**
1063
1162
  * An abortable `sleep` utility that pauses execution for a specified duration.
1064
1163
  * It will reject with an `AbortError` if the provided `AbortSignal` is triggered.
@@ -1067,10 +1166,4 @@ declare function generateMermaidGraph(flow: Flow): string;
1067
1166
  */
1068
1167
  declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
1069
1168
 
1070
- /**
1071
- * Composes a chain of middleware functions around a node's execution.
1072
- * @internal
1073
- */
1074
- declare function applyMiddleware<T = any>(middleware: Middleware<T>[], nodeToRun: AbstractNode): MiddlewareNext<T>;
1075
-
1076
- export { AbortError, AbstractNode, BatchFlow, type BuildResult, ConsoleLogger, type Context, type ContextFunction, type ContextKey, type ContextLens, type ContextTransform, DEFAULT_ACTION, FILTER_FAILED, FatalWorkflowError, Flow, type GraphAnalysis, GraphBuilder, type GraphBuilderOptions, type GraphEdge, type GraphNode, type IExecutor, InMemoryExecutor, type InternalRunOptions, type Logger, type Middleware, type MiddlewareNext, Node, type NodeArgs, type NodeConstructorOptions, type NodeFunction, type NodeOptions, type NodeRegistry, type NodeRunContext, type NodeTypeMap, NullLogger, ParallelBatchFlow, ParallelFlow, type Params, type RunOptions, SequenceFlow, TypedContext, type TypedGraphNode, type TypedNodeRegistry, type TypedWorkflowGraph, type ValidationError, type Validator, WorkflowError, type WorkflowGraph, analyzeGraph, applyMiddleware, checkForCycles, compose, composeContext, contextKey, contextNode, createNodeRegistry, createNodeRule, filterCollection, generateMermaidGraph, isNodeType, lens, mapCollection, mapNode, pipeline, reduceCollection, sleep, transformNode };
1169
+ export { AbortError, AbstractNode, BatchFlow, type BuildResult, ConsoleLogger, type Context, type ContextFunction, type ContextKey, type ContextLens, type ContextTransform, DEFAULT_ACTION, ExecNode, FILTER_FAILED, FatalWorkflowError, Flow, type GraphAnalysis, GraphBuilder, type GraphBuilderOptions, type GraphEdge, type GraphNode, type IExecutor, InMemoryExecutor, type InternalRunOptions, type Logger, type Middleware, type MiddlewareNext, Node, type NodeArgs, type NodeConstructorOptions, type NodeFunction, type NodeOptions, type NodeRegistry, type NodeRunContext, type NodeTypeMap, NullLogger, type OriginalPredecessorIdMap, ParallelBatchFlow, ParallelFlow, type Params, PostNode, PreNode, type PredecessorIdMap, type RunOptions, SequenceFlow, type SubWorkflowResolver, TypedContext, type TypedGraphNode, type TypedNodeRegistry, type TypedWorkflowGraph, type ValidationError, type Validator, WorkflowError, type WorkflowGraph, analyzeGraph, applyMiddleware, checkForCycles, compose, composeContext, contextKey, contextNode, createNodeRegistry, createNodeRule, filterCollection, generateMermaidGraph, isNodeType, lens, mapCollection, mapNode, pipeline, reduceCollection, sanitizeGraph, sleep, transformNode };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- var y=class extends Error{constructor(e="Workflow aborted"){super(e),this.name="AbortError"}},A=class extends Error{constructor(t,r,o,s){let a=s?`${t}: ${s.message}`:t;super(a);this.nodeName=r;this.phase=o;this.originalError=s;this.name="WorkflowError",s!=null&&s.stack&&(this.stack=`${this.stack}
2
- Caused by: ${s.stack}`)}},v=class extends A{constructor(e,t,r,o){super(e,t,r,o),this.name="FatalWorkflowError"}};var R=class{debug(){}info(){}warn(){}error(){}},W={debug:1,info:2,warn:3,error:4},B=class{minLevel;constructor(e={}){this.minLevel=e.level??"info"}log(e,t,r){if(W[e]<W[this.minLevel])return;let o=`[${e.toUpperCase()}] ${t}`;r&&Object.keys(r).length>0?(console[e]||console.log)(o,r):(console[e]||console.log)(o)}debug(e,t){this.log("debug",e,t)}info(e,t){this.log("info",e,t)}warn(e,t){this.log("warn",e,t)}error(e,t){this.log("error",e,t)}};function L(n,e){let t=r=>e._run({ctx:r.ctx,params:{...r.params,...e.params},signal:r.signal,logger:r.logger,executor:r.executor});return!n||n.length===0?t:n.reduceRight((r,o)=>s=>o(s,r),t)}var E=class{async _orch(e,t,r,o){let s=e,a,c,{logger:i,signal:p}=o;for(;s;){if(p!=null&&p.aborted)throw new y;let l={ctx:r,params:{...o.params,...s.params},signal:p,logger:i,prepRes:void 0,execRes:void 0,name:s.constructor.name,executor:o.executor};if(c=await L(t,s)(l),a=this.getNextNode(s,c,i),!a)return c;s=a}}async run(e,t,r){var c;let o=(r==null?void 0:r.logger)??new R,s={...e.params,...r==null?void 0:r.params},a={logger:o,signal:(r==null?void 0:r.signal)??((c=r==null?void 0:r.controller)==null?void 0:c.signal),params:s,executor:this};return e.startNode?(o.info(`Executor is running flow graph: ${e.constructor.name}`),this._orch(e.startNode,e.middleware,t,a)):(o.info(`Executor is running a logic-bearing flow: ${e.constructor.name}`),await L(e.middleware,e)({...a,ctx:t,prepRes:void 0,execRes:void 0,name:e.constructor.name}))}getNextNode(e,t,r){let o=e.successors.get(t),s=typeof t=="symbol"?t.toString():t;return o?r.debug(`Action '${s}' from ${e.constructor.name} leads to ${o.constructor.name}`,{action:t}):e.successors.size>0&&t!==void 0&&t!==null&&r.debug(`Flow ends: Action '${s}' from ${e.constructor.name} has no configured successor.`),o}};var T=Symbol("default"),_=Symbol("filter_failed");function ne(n){return e=>e.type===n}function ae(n){let e=n,t={nodes:new Map,allNodeIds:[],startNodeIds:[],cycles:[]};if(!e||!e.nodes||!e.nodes.length)return t;let r=e.nodes.map(i=>i.id);t.allNodeIds=r;let o=new Map;e.nodes.forEach(i=>{t.nodes.set(i.id,{...i,inDegree:0,outDegree:0}),o.set(i.id,[])}),e.edges.forEach(i=>{let p=t.nodes.get(i.source),l=t.nodes.get(i.target);p&&p.outDegree++,l&&l.inDegree++,o.has(i.source)&&o.get(i.source).push(i.target)}),t.startNodeIds=r.filter(i=>t.nodes.get(i).inDegree===0);let s=new Set,a=new Set;function c(i,p){s.add(i),a.add(i),p.push(i);let l=o.get(i)||[];for(let u of l)if(a.has(u)){let g=p.indexOf(u),m=p.slice(g);t.cycles.push([...m,u])}else s.has(u)||c(u,p);a.delete(i),p.pop()}for(let i of r)s.has(i)||c(i,[]);return t}function ie(n,e,t){return(r,o)=>{let s=[];for(let a of r.nodes.values())if(e(a)){let c=t(a);c.valid||s.push({nodeId:a.id,type:"ConnectionRuleViolation",message:c.message||`Node ${a.id} failed rule: ${n}`})}return s}}var ce=n=>{let e=new Set(n.cycles.map(t=>t.slice(0,-1).sort().join(",")));return Array.from(e).map(t=>{let r=n.cycles.find(o=>o.slice(0,-1).sort().join(",")===t);return{nodeId:r[0],type:"CycleDetected",message:`Cycle detected involving nodes: ${r.join(" -> ")}`}})};function H(n){return n===T?"":n===_?'"filter failed"':`"${n.toString().replace(/"/g,"")}"`}function Q(n,e){if(n.isParallelContainer)return` ${e}{Parallel Block}`;if(n.constructor.name==="InputMappingNode")return` ${e}(("Inputs"))`;if(n.constructor.name==="OutputMappingNode")return` ${e}(("Outputs"))`;if(n.graphData){let t=n.graphData.type,r=n.graphData.id.split(":").pop();return` ${e}["${r} (${t})"]`}return` ${e}[${n.constructor.name}]`}function M(n,e,t){if(t.has(n))return t.get(n);let r;n.isParallelContainer?r="ParallelBlock":n.graphData?r=n.graphData.id:r=n.constructor.name;let o=r.replace(/:/g,"_").replace(/\W/g,""),s=e.get(o)||0,a=`${o}_${s}`;return e.set(o,s+1),t.set(n,a),a}function K(n){if(!n.startNode)return`graph TD
3
- %% Empty Flow`;let e=new Set,t=new Set,r=new Set,o=[n.startNode],s=new Map,a=new Map;for(r.add(n.startNode),M(n.startNode,a,s);o.length>0;){let i=o.shift(),p=M(i,a,s);if(e.add(Q(i,p)),i.isParallelContainer){let l=i;for(let u of l.nodesToRun){let g=M(u,a,s);t.add(` ${p} --> ${g}`),r.has(u)||(r.add(u),o.push(u))}}for(let[l,u]of i.successors.entries()){let g=M(u,a,s),m=H(l),d=m?` ${p} -- ${m} --> ${g}`:` ${p} --> ${g}`;t.add(d),r.has(u)||(r.add(u),o.push(u))}}return["graph TD",...Array.from(e),...Array.from(t)].join(`
4
- `)}async function j(n,e){return new Promise((t,r)=>{if(e!=null&&e.aborted)return r(new y);let o=setTimeout(t,n);e==null||e.addEventListener("abort",()=>{clearTimeout(o),r(new y)})})}var F=class{id;params={};successors=new Map;graphData;withId(e){return this.id=e,this}withGraphData(e){return this.graphData=e,this}withParams(e){return this.params={...this.params,...e},this}next(e,t=T){return this.successors.set(t,e),e}},P=class n extends F{maxRetries;wait;constructor(e={}){super(),this.maxRetries=e.maxRetries??1,this.wait=e.wait??0}_wrapError(e,t){return e instanceof y||e instanceof A?e:new A(`Failed in ${t} phase for node ${this.constructor.name}`,this.constructor.name,t,e)}async prep(e){}async exec(e){}async post(e){return T}async execFallback(e){throw e.error?e.error:new Error(`Node ${this.constructor.name} failed and has no fallback implementation.`)}async _exec(e){var r,o;let t;for(let s=0;s<this.maxRetries;s++){if((r=e.signal)!=null&&r.aborted)throw new y;try{return await this.exec(e)}catch(a){let c=a;if(t=c,c instanceof v||c instanceof y||c.name==="AbortError")throw c;s<this.maxRetries-1&&(e.logger.warn(`Attempt ${s+1}/${this.maxRetries} failed for ${this.constructor.name}. Retrying...`,{error:c}),this.wait>0&&await j(this.wait,e.signal))}}if(e.logger.error(`All retries failed for ${this.constructor.name}. Executing fallback.`,{error:t}),(o=e.signal)!=null&&o.aborted)throw new y;return await this.execFallback({...e,error:t})}async _run({ctx:e,params:t,signal:r,logger:o,executor:s}){if(this instanceof w?o.debug(`Running flow: ${this.constructor.name}`,{params:t}):o.debug(`Running node: ${this.constructor.name}`,{params:t}),r!=null&&r.aborted)throw new y;let a;try{a=await this.prep({ctx:e,params:t,signal:r,logger:o,prepRes:void 0,execRes:void 0,executor:s}),o.debug(`[${this.constructor.name}] prep() result`,{prepRes:a})}catch(i){throw this._wrapError(i,"prep")}if(r!=null&&r.aborted)throw new y;let c;try{c=await this._exec({ctx:e,params:t,signal:r,logger:o,prepRes:a,execRes:void 0,executor:s}),o.debug(`[${this.constructor.name}] exec() result`,{execRes:c})}catch(i){throw this._wrapError(i,"exec")}if(r!=null&&r.aborted)throw new y;try{let i=await this.post({ctx:e,params:t,signal:r,logger:o,prepRes:a,execRes:c,executor:s}),p=typeof i=="symbol"?i.toString():i;return o.debug(`[${this.constructor.name}] post() returned action: '${p}'`),i===void 0?T:i}catch(i){throw this._wrapError(i,"post")}}async run(e,t){let r=(t==null?void 0:t.logger)??new R;return this.successors.size>0&&!(this instanceof w)&&r.warn("Node.run() called directly on a node with successors. The flow will not continue. Use a Flow to execute a sequence."),((t==null?void 0:t.executor)??new E).run(new w(this),e,{...t,params:this.params})}map(e){let t=this,r=this.maxRetries,o=this.wait;return new class extends n{constructor(){super({maxRetries:r,wait:o})}async prep(s){return t.prep(s)}async exec(s){let a=await t.exec(s);return e(a)}async post(s){return T}}}toContext(e){let t=this,r=this.maxRetries,o=this.wait;return new class extends n{constructor(){super({maxRetries:r,wait:o})}async prep(s){return t.prep(s)}async exec(s){return t.exec(s)}async post(s){return s.ctx.set(e,s.execRes),s.logger.debug(`[toContext] Set context key '${String(e.description)}'`,{value:s.execRes}),T}}}filter(e){let t=this;return new class extends n{didPass=!1;async prep(r){return t.prep(r)}async exec(r){let o=await t.exec(r);return this.didPass=await e(o),this.didPass||r.logger.debug(`[Filter] Predicate failed for node ${this.constructor.name}.`),o}async post(r){return this.didPass?T:_}}}tap(e){let t=this,r=this.maxRetries,o=this.wait;return new class extends n{constructor(){super({maxRetries:r,wait:o})}async prep(s){return t.prep(s)}async exec(s){let a=await t.exec(s);return await e(a),a}async post(s){return t.post(s)}}}withLens(e,t){let r=this,o=this.maxRetries,s=this.wait;return new class extends n{constructor(){super({maxRetries:o,wait:s})}async prep(a){return e.set(t)(a.ctx),r.prep(a)}async exec(a){return r.exec(a)}async post(a){return r.post(a)}}}},w=class extends P{startNode;middleware=[];constructor(e){super(),this.startNode=e}_wrapError(e,t){return t==="exec"?e:super._wrapError(e,t)}use(e){return this.middleware.push(e),this}start(e){return this.startNode=e,e}async exec(e){if(!(e.executor instanceof E))throw new TypeError("Programmatic sub-flow execution is only supported by the InMemoryExecutor. For other environments, use GraphBuilder to create a single, flattened workflow.");if(!this.startNode)return super.exec(e);e.logger.debug(`-- Entering sub-flow: ${this.constructor.name} --`);let t={...e.params,...this.params},r={logger:e.logger,signal:e.signal,params:t,executor:e.executor},o=await e.executor._orch(this.startNode,this.middleware,e.ctx,r);return e.logger.debug(`-- Exiting sub-flow: ${this.constructor.name} --`),o}async post({execRes:e}){return e}async run(e,t){return((t==null?void 0:t.executor)??new E).run(this,e,t)}getNodeById(e){if(!this.startNode)return;let t=[this.startNode],r=new Set([this.startNode]);for(;t.length>0;){let o=t.shift();if(o.id===e)return o;for(let s of o.successors.values())r.has(s)||(r.add(s),t.push(s))}}};var ve=n=>Symbol(n),U=class{data;constructor(e){this.data=new Map(e)}get(e){return this.data.get(e)}set(e,t){return this.data.set(e,t),this}has(e){return this.data.has(e)}entries(){return this.data.entries()}};function _e(n){return{get:e=>e.get(n),set:e=>t=>t.set(n,e),update:e=>t=>t.set(n,e(t.get(n)))}}function V(...n){return e=>n.reduce((t,r)=>r(t),e)}var $=class extends w{constructor(...e){if(e.length===0){super();return}super(e[0]);let t=e[0];for(let r=1;r<e.length;r++)t=t.next(e[r])}},G=class extends w{constructor(t){super();this.nodesToRun=t}async exec({ctx:t,params:r,signal:o,logger:s,executor:a}){if(this.nodesToRun.length===0){s.debug("[ParallelFlow] No branches to execute in parallel.");return}s.info(`[ParallelFlow] Executing ${this.nodesToRun.length} branches in parallel...`);let c=this.nodesToRun.map(p=>p._run({ctx:t,params:{...r,...p.params},signal:o,logger:s,executor:a}));(await Promise.allSettled(c)).forEach(p=>{p.status==="rejected"&&s.error("[ParallelFlow] A parallel branch failed.",{error:p.reason})})}},z=class extends w{constructor(){super()}async prep(e){return[]}async exec(e){var s;if(!this.nodeToRun)return null;let t={...this.params,...e.params},r=await this.prep(e)||[],o=Array.from(r);e.logger.info(`[BatchFlow] Starting sequential processing of ${o.length} items.`);for(let a of o){if((s=e.signal)!=null&&s.aborted)throw new y;await this.nodeToRun._run({ctx:e.ctx,params:{...t,...a},signal:e.signal,logger:e.logger,executor:e.executor})}return null}},q=class extends w{constructor(){super()}async prep(e){return[]}async exec(e){if(!this.nodeToRun)return[];let t={...this.params,...e.params},r=await this.prep(e)||[],o=Array.from(r);e.logger.info(`[ParallelBatchFlow] Starting parallel processing of ${o.length} items.`);let s=o.map(c=>this.nodeToRun._run({ctx:e.ctx,params:{...t,...c},signal:e.signal,logger:e.logger,executor:e.executor})),a=await Promise.allSettled(s);for(let c of a)c.status==="rejected"&&e.logger.error("A parallel batch item failed.",{error:c.reason});return a}};function ke(n,e){return new class extends w{async exec(){let t=n.map(r=>e(r));return Promise.all(t)}}}function Oe(n,e){return new class extends w{async exec(){let t=await Promise.all(n.map(r=>e(r)));return n.filter((r,o)=>t[o])}}}function Le(n,e,t){return new class extends w{async exec(r){var s;let o=t;for(let a of n){if((s=r.signal)!=null&&s.aborted)throw new y;o=await e(o,a)}return o}}}function ze(n){return n}var S=class extends P{mappings;constructor(e){super();let{nodeId:t,...r}=e.data;this.mappings=r}async prep({ctx:e,logger:t}){for(let[r,o]of Object.entries(this.mappings))e.has(o)?e.set(r,e.get(o)):t.warn(`[InputMapper] Input mapping failed. Key '${o}' not found in context.`)}},D=class extends P{mappings;constructor(e){super();let{nodeId:t,...r}=e.data;this.mappings=r}async prep({ctx:e,logger:t}){for(let[r,o]of Object.entries(this.mappings))e.has(o)?e.set(r,e.get(o)):t.warn(`[OutputMapper] Output mapping failed. Key '${o}' not found in context.`)}},k=class extends G{constructor(t){super(t);this.nodesToRun=t}isParallelContainer=!0},J=class{constructor(e,t={},r={},o=new R){this.nodeOptionsContext=t;this.logger=o,e instanceof Map?this.registry=e:this.registry=new Map(Object.entries(e)),this.registry.set("__internal_input_mapper__",S),this.registry.set("__internal_output_mapper__",D),this.subWorkflowNodeTypes=r.subWorkflowNodeTypes??[]}registry;subWorkflowNodeTypes;logger;_logMermaid(e){this.logger instanceof R||(this.logger.debug("[GraphBuilder] Flattened Graph"),K(e).split(`
5
- `).forEach(r=>this.logger.debug(r)))}_flattenGraph(e,t=""){let r=[],o=[],s=new Set(e.nodes.map(a=>a.id));for(let a of e.nodes){let c=`${t}${a.id}`,i=this.subWorkflowNodeTypes.includes(a.type),p=a.data&&"workflowId"in a.data,l=JSON.parse(JSON.stringify(a.data||{}));if(l.inputs){let u=l.inputs;for(let[g,m]of Object.entries(u)){let f=(Array.isArray(m)?m:[m]).map(x=>s.has(x)?`${t}${x}`:x);u[g]=Array.isArray(m)?f:f[0]}}if(i){this.logger.debug(`[GraphBuilder] Inlining sub-workflow node '${c}'...`);let u=a.data,g=u.workflowId,m=this.nodeOptionsContext.registry;if(!m||typeof m.getGraph!="function")throw new Error("GraphBuilder needs a registry with a `getGraph` method in its context to resolve sub-workflows.");let d=m.getGraph(g);if(!d)throw new Error(`Sub-workflow with ID ${g} not found in registry.`);this.logger.debug(`[GraphBuilder] -> Fetched graph for sub-workflow ID: ${g}`);let f=`${c}_input_mapper`,x=`${c}_output_mapper`;r.push({id:f,type:"__internal_input_mapper__",data:u.inputs||{}}),r.push({id:x,type:"__internal_output_mapper__",data:u.outputs||{}});let h=this._flattenGraph(d,`${c}:`),b=h.nodes.map(N=>({...N,data:{...N.data||{},isSubWorkflow:!0}}));r.push(...b),o.push(...h.edges);let I=h.nodes.map(N=>N.id).filter(N=>!h.edges.some(O=>O.target===N));for(let N of I)o.push({source:f,target:N,action:T});let C=h.nodes.map(N=>N.id).filter(N=>!h.edges.some(O=>O.source===N));for(let N of C)o.push({source:N,target:x,action:T})}else{if(p)throw new Error(`GraphBuilder Error: Node with ID '${a.id}' and type '${a.type}' contains a 'workflowId' property, but its type is not registered in the 'subWorkflowNodeTypes' option. Please add '${a.type}' to the subWorkflowNodeTypes array in the GraphBuilder constructor.`);r.push({...a,id:c,data:l})}}for(let a of e.edges){let c=e.nodes.find(m=>m.id===a.source),i=e.nodes.find(m=>m.id===a.target),p=`${t}${a.source}`,l=`${t}${a.target}`,u=this.subWorkflowNodeTypes.includes(c.type),g=this.subWorkflowNodeTypes.includes(i.type);u&&g?o.push({...a,source:`${p}_output_mapper`,target:`${l}_input_mapper`}):u?o.push({...a,source:`${p}_output_mapper`,target:l}):g?o.push({...a,source:p,target:`${l}_input_mapper`}):o.push({...a,source:p,target:l})}return{nodes:r,edges:o}}build(e){let t=this._flattenGraph(e),r=new Map,o=new Map;for(let d of t.edges)o.has(d.target)||o.set(d.target,new Set),o.get(d.target).add(d.source);let s=new Map;for(let d of t.nodes){let f=o.get(d.id);s.set(d.id,f?f.size:0)}for(let d of t.nodes){let f=this.registry.get(d.type.toString());if(!f)throw new Error(`GraphBuilder: Node type '${d.type.toString()}' not found in the registry.`);let x={...this.nodeOptionsContext,data:{...d.data,nodeId:d.id}},h=new f(x).withId(d.id).withGraphData(d);d.config&&(h instanceof P?(h.maxRetries=d.config.maxRetries??h.maxRetries,h.wait=d.config.wait??h.wait):this.logger.warn(`[GraphBuilder] Node '${d.id}' has a 'config' block in its definition, but its class '${h.constructor.name}' does not extend 'Node', so retry options cannot be applied.`)),r.set(d.id,h)}let a=new Map;for(let d of t.edges){let f=d.source,x=d.action||T,h=r.get(d.target);a.has(f)||a.set(f,new Map);let b=a.get(f);b.has(x)||b.set(x,[]),b.get(x).push(h)}for(let[d,f]of a.entries()){let x=r.get(d);for(let[h,b]of f.entries())if(b.length===1)x.next(b[0],h);else if(b.length>1){let I=new k(b);x.next(I,h);let C=this._findConvergenceNode(b,a);C&&I.next(C)}}let c=Array.from(r.keys()),i=new Set(t.edges.map(d=>d.target)),p=c.filter(d=>!i.has(d));if(p.length===0&&c.length>0)throw new Error("GraphBuilder: This graph has a cycle and no clear start node.");if(p.length===1){let d=r.get(p[0]),f=new w(d),x=this._createPredecessorIdMap(t);return this._logMermaid(f),{flow:f,nodeMap:r,predecessorCountMap:s,predecessorIdMap:x}}let l=p.map(d=>r.get(d)),u=new k(l);if(l.length>1){let d=this._findConvergenceNode(l,a);d&&u.next(d)}let g=new w(u),m=this._createPredecessorIdMap(t);return this._logMermaid(g),{flow:g,nodeMap:r,predecessorCountMap:s,predecessorIdMap:m}}_createPredecessorIdMap(e){let t=new Map;for(let r of e.edges)t.has(r.target)||t.set(r.target,[]),t.get(r.target).push(r.source);return t}_findConvergenceNode(e,t){var a;if(e.length<=1)return;let r=e.map(c=>String(c.id)),o=new Map;e.forEach(c=>o.set(String(c.id),new Set([String(c.id)])));let s=0;for(;s<r.length;){let c=r[s++],i=Array.from(((a=t.get(c))==null?void 0:a.values())??[]).flat();for(let p of i){let l=String(p.id);o.has(l)||o.set(l,new Set);let u=o.get(l),g=o.get(c);for(let m of g)u.add(m);if(u.size===e.length)return this.logger.debug(`[GraphBuilder] Found convergence node: ${l}`),p;r.includes(l)||r.push(l)}}this.logger.warn("[GraphBuilder] Parallel branches do not seem to converge.")}};function tt(n){return new class extends P{async exec({params:e}){return n(e)}}}function rt(n){return new class extends P{async exec({ctx:e,params:t}){return n(e,t)}}}function ot(...n){return new class extends P{async prep({ctx:e}){V(...n)(e)}}}function st(...n){return new $(...n)}function nt(n,e){return async t=>n(await e(t))}export{y as AbortError,F as AbstractNode,z as BatchFlow,B as ConsoleLogger,T as DEFAULT_ACTION,_ as FILTER_FAILED,v as FatalWorkflowError,w as Flow,J as GraphBuilder,E as InMemoryExecutor,P as Node,R as NullLogger,q as ParallelBatchFlow,G as ParallelFlow,$ as SequenceFlow,U as TypedContext,A as WorkflowError,ae as analyzeGraph,L as applyMiddleware,ce as checkForCycles,nt as compose,V as composeContext,ve as contextKey,rt as contextNode,ze as createNodeRegistry,ie as createNodeRule,Oe as filterCollection,K as generateMermaidGraph,ne as isNodeType,_e as lens,ke as mapCollection,tt as mapNode,st as pipeline,Le as reduceCollection,j as sleep,ot as transformNode};
1
+ var x=class extends Error{constructor(e="Workflow aborted"){super(e),this.name="AbortError"}},v=class extends Error{constructor(t,r,o,s){let a=s?`${t}: ${s.message}`:t;super(a);this.nodeName=r;this.phase=o;this.originalError=s;this.name="WorkflowError",s!=null&&s.stack&&(this.stack=`${this.stack}
2
+ Caused by: ${s.stack}`)}},C=class extends v{constructor(e,t,r,o){super(e,t,r,o),this.name="FatalWorkflowError"}};var R=class{debug(){}info(){}warn(){}error(){}},K={debug:1,info:2,warn:3,error:4},j=class{minLevel;constructor(e={}){this.minLevel=e.level??"info"}log(e,t,r){if(K[e]<K[this.minLevel])return;let o=`[${e.toUpperCase()}] ${t}`;r&&Object.keys(r).length>0?(console[e]||console.log)(o,r):(console[e]||console.log)(o)}debug(e,t){this.log("debug",e,t)}info(e,t){this.log("info",e,t)}warn(e,t){this.log("warn",e,t)}error(e,t){this.log("error",e,t)}};function S(n,e){let t=r=>e._run({ctx:r.ctx,params:{...r.params,...e.params},signal:r.signal,logger:r.logger,executor:r.executor});return!n||n.length===0?t:n.reduceRight((r,o)=>s=>o(s,r),t)}var E=class{async _orch(e,t,r,o){let s=e,a,c,{logger:i,signal:p}=o;for(;s;){if(p!=null&&p.aborted)throw new x;let l={ctx:r,params:{...o.params,...s.params},signal:p,logger:i,prepRes:void 0,execRes:void 0,name:s.constructor.name,executor:o.executor};if(c=await S(t,s)(l),a=this.getNextNode(s,c,i),!a)return c;s=a}}async run(e,t,r){var c;let o=(r==null?void 0:r.logger)??new R,s={...e.params,...r==null?void 0:r.params},a={logger:o,signal:(r==null?void 0:r.signal)??((c=r==null?void 0:r.controller)==null?void 0:c.signal),params:s,executor:this};return e.startNode?(o.info(`Executor is running flow graph: ${e.constructor.name}`),this._orch(e.startNode,e.middleware,t,a)):(o.info(`Executor is running a logic-bearing flow: ${e.constructor.name}`),await S(e.middleware,e)({...a,ctx:t,prepRes:void 0,execRes:void 0,name:e.constructor.name}))}getNextNode(e,t,r){let o=e.successors.get(t),s=typeof t=="symbol"?t.toString():t;return o?r.debug(`Action '${s}' from ${e.constructor.name} leads to ${o.constructor.name}`,{action:t}):e.successors.size>0&&t!==void 0&&t!==null&&r.debug(`Flow ends: Action '${s}' from ${e.constructor.name} has no configured successor.`),o}};var P=Symbol("default"),M=Symbol("filter_failed");function le(n){return e=>e.type===n}function me(n){let e=n,t={nodes:new Map,allNodeIds:[],startNodeIds:[],cycles:[]};if(!e||!e.nodes||!e.nodes.length)return t;let r=e.nodes.map(i=>i.id);t.allNodeIds=r;let o=new Map;e.nodes.forEach(i=>{t.nodes.set(i.id,{...i,inDegree:0,outDegree:0}),o.set(i.id,[])}),e.edges.forEach(i=>{let p=t.nodes.get(i.source),l=t.nodes.get(i.target);p&&p.outDegree++,l&&l.inDegree++,o.has(i.source)&&o.get(i.source).push(i.target)}),t.startNodeIds=r.filter(i=>t.nodes.get(i).inDegree===0);let s=new Set,a=new Set;function c(i,p){s.add(i),a.add(i),p.push(i);let l=o.get(i)||[];for(let u of l)if(a.has(u)){let m=p.indexOf(u),w=p.slice(m);t.cycles.push([...w,u])}else s.has(u)||c(u,p);a.delete(i),p.pop()}for(let i of r)s.has(i)||c(i,[]);return t}function ge(n,e,t){return(r,o)=>{let s=[];for(let a of r.nodes.values())if(e(a)){let c=t(a);c.valid||s.push({nodeId:a.id,type:"ConnectionRuleViolation",message:c.message||`Node ${a.id} failed rule: ${n}`})}return s}}var fe=n=>{let e=new Set(n.cycles.map(t=>t.slice(0,-1).sort().join(",")));return Array.from(e).map(t=>{let r=n.cycles.find(o=>o.slice(0,-1).sort().join(",")===t);return{nodeId:r[0],type:"CycleDetected",message:`Cycle detected involving nodes: ${r.join(" -> ")}`}})};function re(n){return n===P?"":n===M?'"filter failed"':`"${n.toString().replace(/"/g,"")}"`}function oe(n,e){if(n.isParallelContainer)return` ${e}{Parallel Block}`;if(n.constructor.name==="InputMappingNode")return` ${e}(("Inputs"))`;if(n.constructor.name==="OutputMappingNode")return` ${e}(("Outputs"))`;if(n.graphData){let t=n.graphData.type,r=n.graphData.id.split(":").pop();return` ${e}["${r} (${t})"]`}return` ${e}[${n.constructor.name}]`}function k(n,e,t){if(t.has(n))return t.get(n);let r;n.isParallelContainer?r="ParallelBlock":n.graphData?r=n.graphData.id:n.id?r=String(n.id):r=n.constructor.name;let o=r.replace(/:/g,"_").replace(/\W/g,""),s=e.get(o)||0,a=`${o}_${s}`;return e.set(o,s+1),t.set(n,a),a}function U(n){if(!n.startNode)return`graph TD
3
+ %% Empty Flow`;let e=new Set,t=new Set,r=new Set,o=[n.startNode],s=new Map,a=new Map;for(r.add(n.startNode),k(n.startNode,a,s);o.length>0;){let i=o.shift(),p=k(i,a,s);if(e.add(oe(i,p)),i.isParallelContainer){let l=i;for(let u of l.nodesToRun){let m=k(u,a,s);t.add(` ${p} --> ${m}`),r.has(u)||(r.add(u),o.push(u))}}for(let[l,u]of i.successors.entries()){let m=k(u,a,s),w=re(l),d=w?` ${p} -- ${w} --> ${m}`:` ${p} --> ${m}`;t.add(d),r.has(u)||(r.add(u),o.push(u))}}return["graph TD",...Array.from(e),...Array.from(t)].join(`
4
+ `)}function we(n){let e=n.nodes.map(({id:r,type:o,data:s,config:a})=>({id:r,type:o,data:s,...a&&{config:a}})),t=n.edges.map(({id:r,source:o,target:s,action:a})=>({id:r,source:o,target:s,...a&&{action:a}}));return{nodes:e,edges:t}}async function B(n,e){return new Promise((t,r)=>{if(e!=null&&e.aborted)return r(new x);let o=setTimeout(t,n);e==null||e.addEventListener("abort",()=>{clearTimeout(o),r(new x)})})}var L=class{id;params={};successors=new Map;graphData;withId(e){return this.id=e,this}withGraphData(e){return this.graphData=e,this}withParams(e){return this.params={...this.params,...e},this}next(e,t=P){return this.successors.set(t,e),e}},N=class n extends L{maxRetries;wait;constructor(e={}){super(),this.maxRetries=e.maxRetries??1,this.wait=e.wait??0}_wrapError(e,t){return e instanceof x||e instanceof v?e:new v(`Failed in ${t} phase for node ${this.constructor.name}`,this.constructor.name,t,e)}async prep(e){}async exec(e){}async post(e){return P}async execFallback(e){throw e.error?e.error:new Error(`Node ${this.constructor.name} failed and has no fallback implementation.`)}async _exec(e){var r,o;let t;for(let s=0;s<this.maxRetries;s++){if((r=e.signal)!=null&&r.aborted)throw new x;try{return await this.exec(e)}catch(a){let c=a;if(t=c,c instanceof C||c instanceof x||c.name==="AbortError")throw c;s<this.maxRetries-1&&(e.logger.warn(`Attempt ${s+1}/${this.maxRetries} failed for ${this.constructor.name}. Retrying...`,{error:c}),this.wait>0&&await B(this.wait,e.signal))}}if(e.logger.error(`All retries failed for ${this.constructor.name}. Executing fallback.`,{error:t}),(o=e.signal)!=null&&o.aborted)throw new x;return await this.execFallback({...e,error:t})}async _run({ctx:e,params:t,signal:r,logger:o,executor:s}){if(this instanceof T?o.debug(`Running flow: ${this.constructor.name}`,{params:t}):o.debug(`Running node: ${this.constructor.name}`,{params:t}),r!=null&&r.aborted)throw new x;let a;try{a=await this.prep({ctx:e,params:t,signal:r,logger:o,prepRes:void 0,execRes:void 0,executor:s}),o.debug(`[${this.constructor.name}] prep() result`,{prepRes:a})}catch(i){throw this._wrapError(i,"prep")}if(r!=null&&r.aborted)throw new x;let c;try{c=await this._exec({ctx:e,params:t,signal:r,logger:o,prepRes:a,execRes:void 0,executor:s}),o.debug(`[${this.constructor.name}] exec() result`,{execRes:c})}catch(i){throw this._wrapError(i,"exec")}if(r!=null&&r.aborted)throw new x;try{let i=await this.post({ctx:e,params:t,signal:r,logger:o,prepRes:a,execRes:c,executor:s}),p=typeof i=="symbol"?i.toString():i;return o.debug(`[${this.constructor.name}] post() returned action: '${p}'`),i===void 0?P:i}catch(i){throw this._wrapError(i,"post")}}async run(e,t){let r=(t==null?void 0:t.logger)??new R;return this.successors.size>0&&!(this instanceof T)&&r.warn("Node.run() called directly on a node with successors. The flow will not continue. Use a Flow to execute a sequence."),((t==null?void 0:t.executor)??new E).run(new T(this),e,{...t,params:this.params})}map(e){let t=this,r=this.maxRetries,o=this.wait;return new class extends n{constructor(){super({maxRetries:r,wait:o})}async prep(s){return t.prep(s)}async exec(s){let a=await t.exec(s);return e(a)}async post(s){return P}}}toContext(e){let t=this,r=this.maxRetries,o=this.wait;return new class extends n{constructor(){super({maxRetries:r,wait:o})}async prep(s){return t.prep(s)}async exec(s){return t.exec(s)}async post(s){return s.ctx.set(e,s.execRes),s.logger.debug(`[toContext] Set context key '${String(e.description)}'`,{value:s.execRes}),P}}}filter(e){let t=this;return new class extends n{didPass=!1;async prep(r){return t.prep(r)}async exec(r){let o=await t.exec(r);return this.didPass=await e(o),this.didPass||r.logger.debug(`[Filter] Predicate failed for node ${this.constructor.name}.`),o}async post(r){return this.didPass?P:M}}}tap(e){let t=this,r=this.maxRetries,o=this.wait;return new class extends n{constructor(){super({maxRetries:r,wait:o})}async prep(s){return t.prep(s)}async exec(s){let a=await t.exec(s);return await e(a),a}async post(s){return t.post(s)}}}withLens(e,t){let r=this,o=this.maxRetries,s=this.wait;return new class extends n{constructor(){super({maxRetries:o,wait:s})}async prep(a){return e.set(t)(a.ctx),r.prep(a)}async exec(a){return r.exec(a)}async post(a){return r.post(a)}}}},z=class extends N{},V=class extends N{},q=class extends N{},T=class extends N{startNode;middleware=[];constructor(e){super(),this.startNode=e}_wrapError(e,t){return t==="exec"?e:super._wrapError(e,t)}use(e){return this.middleware.push(e),this}start(e){return this.startNode=e,e}async exec(e){if(!(e.executor instanceof E))throw new TypeError("Programmatic sub-flow execution is only supported by the InMemoryExecutor. For other environments, use GraphBuilder to create a single, flattened workflow.");if(!this.startNode)return super.exec(e);e.logger.debug(`-- Entering sub-flow: ${this.constructor.name} --`);let t={...e.params,...this.params},r={logger:e.logger,signal:e.signal,params:t,executor:e.executor},o=await e.executor._orch(this.startNode,this.middleware,e.ctx,r);return e.logger.debug(`-- Exiting sub-flow: ${this.constructor.name} --`),o}async post({execRes:e}){return e}async run(e,t){return((t==null?void 0:t.executor)??new E).run(this,e,t)}getNodeById(e){if(!this.startNode)return;let t=[this.startNode],r=new Set([this.startNode]);for(;t.length>0;){let o=t.shift();if(o.id===e)return o;for(let s of o.successors.values())r.has(s)||(r.add(s),t.push(s))}}};var De=n=>Symbol(n),J=class{data;constructor(e){this.data=new Map(e)}get(e){return this.data.get(e)}set(e,t){return this.data.set(e,t),this}has(e){return this.data.has(e)}entries(){return this.data.entries()}};function Ke(n){return{get:e=>e.get(n),set:e=>t=>t.set(n,e),update:e=>t=>t.set(n,e(t.get(n)))}}function H(...n){return e=>n.reduce((t,r)=>r(t),e)}var G=class extends T{constructor(...e){if(e.length===0){super();return}super(e[0]);let t=e[0];for(let r=1;r<e.length;r++)t=t.next(e[r])}},$=class extends T{constructor(t){super();this.nodesToRun=t}async exec({ctx:t,params:r,signal:o,logger:s,executor:a}){if(this.nodesToRun.length===0){s.debug("[ParallelFlow] No branches to execute in parallel.");return}s.info(`[ParallelFlow] Executing ${this.nodesToRun.length} branches in parallel...`);let c=this.nodesToRun.map(p=>p._run({ctx:t,params:{...r,...p.params},signal:o,logger:s,executor:a}));(await Promise.allSettled(c)).forEach(p=>{p.status==="rejected"&&s.error("[ParallelFlow] A parallel branch failed.",{error:p.reason})})}},Q=class extends T{constructor(){super()}async prep(e){return[]}async exec(e){var s;if(!this.nodeToRun)return null;let t={...this.params,...e.params},r=await this.prep(e)||[],o=Array.from(r);e.logger.info(`[BatchFlow] Starting sequential processing of ${o.length} items.`);for(let a of o){if((s=e.signal)!=null&&s.aborted)throw new x;await this.nodeToRun._run({ctx:e.ctx,params:{...t,...a},signal:e.signal,logger:e.logger,executor:e.executor})}return null}},X=class extends T{constructor(){super()}async prep(e){return[]}async exec(e){if(!this.nodeToRun)return[];let t={...this.params,...e.params},r=await this.prep(e)||[],o=Array.from(r);e.logger.info(`[ParallelBatchFlow] Starting parallel processing of ${o.length} items.`);let s=o.map(c=>this.nodeToRun._run({ctx:e.ctx,params:{...t,...c},signal:e.signal,logger:e.logger,executor:e.executor})),a=await Promise.allSettled(s);for(let c of a)c.status==="rejected"&&e.logger.error("A parallel batch item failed.",{error:c.reason});return a}};function ze(n,e){return new class extends T{async exec(){let t=n.map(r=>e(r));return Promise.all(t)}}}function Ve(n,e){return new class extends T{async exec(){let t=await Promise.all(n.map(r=>e(r)));return n.filter((r,o)=>t[o])}}}function qe(n,e,t){return new class extends T{async exec(r){var s;let o=t;for(let a of n){if((s=r.signal)!=null&&s.aborted)throw new x;o=await e(o,a)}return o}}}function ot(n){return n}var F=class extends N{mappings;constructor(e){super();let{nodeId:t,...r}=e.data;this.mappings=r}async prep({ctx:e,logger:t}){for(let[r,o]of Object.entries(this.mappings))e.has(o)?e.set(r,e.get(o)):t.warn(`[InputMapper] Input mapping failed. Key '${o}' not found in context.`)}},W=class extends N{mappings;constructor(e){super();let{nodeId:t,...r}=e.data;this.mappings=r}async prep({ctx:e,logger:t}){for(let[r,o]of Object.entries(this.mappings))e.has(o)?e.set(r,e.get(o)):t.warn(`[OutputMapper] Output mapping failed. Key '${o}' not found in context.`)}},D=class extends N{async exec(){}},O=class extends ${constructor(t){super(t);this.nodesToRun=t}isParallelContainer=!0},Y=class{constructor(e,t={},r={},o=new R){this.nodeOptionsContext=t;this.logger=o,e instanceof Map?this.registry=e:this.registry=new Map(Object.entries(e)),this.registry.set("__internal_input_mapper__",F),this.registry.set("__internal_output_mapper__",W),this.registry.set("__internal_sub_workflow_container__",D),this.subWorkflowNodeTypes=r.subWorkflowNodeTypes??[],this.subWorkflowResolver=r.subWorkflowResolver}registry;subWorkflowNodeTypes;subWorkflowResolver;logger;_logMermaid(e){this.logger instanceof R||(this.logger.info("[GraphBuilder] Flattened Graph"),U(e).split(`
5
+ `).forEach(r=>this.logger.info(r)))}_flattenGraph(e,t=""){let r=[],o=[],s=new Set(e.nodes.map(a=>a.id));for(let a of e.nodes){let c=`${t}${a.id}`,i=c.replace(/:/g,"_").replace(/\W/g,""),p=this.subWorkflowNodeTypes.includes(a.type),l=a.data&&"workflowId"in a.data,u=JSON.parse(JSON.stringify(a.data||{}));if(u.inputs){let m=u.inputs;for(let[w,d]of Object.entries(m)){let h=(Array.isArray(d)?d:[d]).map(g=>s.has(g)?`${t}${g}`:g);m[w]=Array.isArray(d)?h:h[0]}}if(p){if(!this.subWorkflowResolver)throw new Error("GraphBuilder: `subWorkflowResolver` must be provided in options to handle sub-workflows.");let m=a.data,w=m.workflowId,d=this.subWorkflowResolver.getGraph(w);if(!d)throw new Error(`Sub-workflow with ID ${w} not found in resolver.`);r.push({id:c,type:"__internal_sub_workflow_container__",data:{...u,originalId:a.id}});let f=`${i}_input_mapper`,h=`${i}_output_mapper`;r.push({id:f,type:"__internal_input_mapper__",data:{...m.inputs||{},originalId:a.id}}),r.push({id:h,type:"__internal_output_mapper__",data:{...m.outputs||{},originalId:a.id}});let g=this._flattenGraph(d,`${c}:`),b=g.nodes.map(y=>({...y,data:{...y.data||{},isSubWorkflow:!0}}));r.push(...b),o.push(...g.edges),o.push({source:c,target:f});let A=g.nodes.map(y=>y.id).filter(y=>!g.edges.some(I=>I.target===y));for(let y of A)o.push({source:f,target:y});let _=g.nodes.map(y=>y.id).filter(y=>!g.edges.some(I=>I.source===y));for(let y of _)o.push({source:y,target:h})}else{if(l)throw new Error(`Node with ID '${a.id}' has a 'workflowId' but its type '${a.type}' is not in 'subWorkflowNodeTypes'.`);r.push({...a,id:c,data:{...u,originalId:a.id}})}}for(let a of e.edges){let c=e.nodes.find(m=>m.id===a.source),i=`${t}${a.source}`,p=`${t}${a.target}`,l=this.subWorkflowNodeTypes.includes(c.type),u=i.replace(/:/g,"_").replace(/\W/g,"");l?o.push({...a,source:`${u}_output_mapper`,target:p}):o.push({...a,source:i,target:p})}return{nodes:r,edges:o}}build(e,t){let r=this._flattenGraph(e),o=new Map;for(let d of r.nodes){let f=this.registry.get(d.type.toString());if(!f)throw new Error(`GraphBuilder: Node type '${d.type.toString()}' not found in registry.`);let h={...this.nodeOptionsContext,data:{...d.data,nodeId:d.id}},g=new f(h).withId(d.id).withGraphData(d);d.config&&g instanceof N&&(g.maxRetries=d.config.maxRetries??g.maxRetries,g.wait=d.config.wait??g.wait),o.set(d.id,g)}let s=new Map;for(let d of r.edges){let f=d.source,h=d.action||P,g=o.get(d.target);s.has(f)||s.set(f,new Map);let b=s.get(f);b.has(h)||b.set(h,[]),b.get(h).push(g)}for(let[d,f]of s.entries()){let h=o.get(d);for(let[g,b]of f.entries())if(b.length===1)h.next(b[0],g);else if(b.length>1){let A=new O(b).withId(`${d}__parallel_container`);o.set(String(A.id),A),h.next(A,g);for(let y of b){let I=s.get(String(y.id));if(I)for(let[Z,ee]of I.entries())for(let te of ee)y.next(te,Z)}let _=this._findConvergenceNode(b,s);_&&A.next(_)}}let a=new Set(r.nodes.map(d=>d.id)),c=new Set(r.edges.map(d=>d.target)),i=[...a].filter(d=>!c.has(d));if(i.length===0&&a.size>0)throw new Error("GraphBuilder: This graph has a cycle and no clear start node.");let{predecessorIdMap:p,originalPredecessorIdMap:l}=this._createPredecessorIdMaps(r,o),u=new Map;for(let[d,f]of p.entries())u.set(d,f.length);for(let d of a)u.has(d)||u.set(d,0);let m;if(i.length===1)m=o.get(i[0]);else{let d=i.map(g=>o.get(g)),f=new O(d).withId("__root_parallel_start");o.set(String(f.id),f);let h=this._findConvergenceNode(d,s);h&&f.next(h),m=f}let w=new T(m);return t&&this._logMermaid(w),{flow:w,nodeMap:o,predecessorCountMap:u,predecessorIdMap:p,originalPredecessorIdMap:l}}_createPredecessorIdMaps(e,t){var s,a,c,i;let r=new Map,o=new Map;for(let p of e.edges){r.has(p.target)||r.set(p.target,[]),r.get(p.target).push(p.source);let l=t.get(p.source),u=t.get(p.target),m=(a=(s=l==null?void 0:l.graphData)==null?void 0:s.data)==null?void 0:a.originalId,d=((i=(c=u==null?void 0:u.graphData)==null?void 0:c.data)==null?void 0:i.originalId)??(u==null?void 0:u.id);if(m&&d){o.has(d)||o.set(d,[]);let f=o.get(d);f.includes(m)||f.push(m)}}return{predecessorIdMap:r,originalPredecessorIdMap:o}}_findConvergenceNode(e,t){var a;if(e.length<=1)return;let r=e.map(c=>String(c.id)),o=new Map;e.forEach(c=>o.set(String(c.id),new Set([String(c.id)])));let s=0;for(;s<r.length;){let c=r[s++],i=Array.from(((a=t.get(c))==null?void 0:a.values())??[]).flat();for(let p of i){let l=String(p.id);o.has(l)||o.set(l,new Set);let u=o.get(l),m=o.get(c);for(let w of m)u.add(w);if(u.size===e.length)return p;r.includes(l)||r.push(l)}}this.logger.warn("[GraphBuilder] Parallel branches do not seem to converge.")}};function lt(n){return new class extends N{async exec({params:e}){return n(e)}}}function mt(n){return new class extends N{async exec({ctx:e,params:t}){return n(e,t)}}}function gt(...n){return new class extends N{async prep({ctx:e}){H(...n)(e)}}}function ft(...n){return new G(...n)}function xt(n,e){return async t=>n(await e(t))}export{x as AbortError,L as AbstractNode,Q as BatchFlow,j as ConsoleLogger,P as DEFAULT_ACTION,z as ExecNode,M as FILTER_FAILED,C as FatalWorkflowError,T as Flow,Y as GraphBuilder,E as InMemoryExecutor,N as Node,R as NullLogger,X as ParallelBatchFlow,$ as ParallelFlow,q as PostNode,V as PreNode,G as SequenceFlow,J as TypedContext,v as WorkflowError,me as analyzeGraph,S as applyMiddleware,fe as checkForCycles,xt as compose,H as composeContext,De as contextKey,mt as contextNode,ot as createNodeRegistry,ge as createNodeRule,Ve as filterCollection,U as generateMermaidGraph,le as isNodeType,Ke as lens,ze as mapCollection,lt as mapNode,ft as pipeline,qe as reduceCollection,we as sanitizeGraph,B as sleep,gt as transformNode};
6
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/logger.ts","../src/utils/middleware.ts","../src/executors/in-memory.ts","../src/types.ts","../src/utils/analysis.ts","../src/utils/mermaid.ts","../src/utils/sleep.ts","../src/workflow.ts","../src/context.ts","../src/builder/patterns.ts","../src/builder/graph.ts","../src/functions.ts"],"sourcesContent":["/**\n * Error thrown when a workflow is gracefully aborted via an `AbortSignal`.\n * This error is caught by the execution engine to halt the flow.\n */\nexport class AbortError extends Error {\n\tconstructor(message = 'Workflow aborted') {\n\t\tsuper(message)\n\t\tthis.name = 'AbortError'\n\t}\n}\n\n/**\n * A custom error class for failures within a workflow, providing additional\n * context about where and when the error occurred.\n */\nexport class WorkflowError extends Error {\n\t/**\n\t * @param message The error message.\n\t * @param nodeName The name of the `Node` class where the error occurred.\n\t * @param phase The lifecycle phase (`'prep'`, `'exec'`, or `'post'`) where the error was thrown.\n\t * @param originalError The underlying error that was caught and wrapped.\n\t */\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly nodeName: string,\n\t\tpublic readonly phase: 'prep' | 'exec' | 'post',\n\t\tpublic readonly originalError?: Error,\n\t) {\n\t\tconst combinedMessage = originalError\n\t\t\t? `${message}: ${originalError.message}`\n\t\t\t: message\n\n\t\tsuper(combinedMessage)\n\t\tthis.name = 'WorkflowError'\n\t\tif (originalError?.stack)\n\t\t\tthis.stack = `${this.stack}\\nCaused by: ${originalError.stack}`\n\t}\n}\n\n/**\n * An error thrown by a node to indicate a non-recoverable failure.\n *\n * When an executor catches this error, it should immediately terminate the\n * entire workflow run, bypassing any remaining retries, fallbacks, or\n * subsequent nodes in the graph.\n */\nexport class FatalWorkflowError extends WorkflowError {\n\tconstructor(\n\t\tmessage: string,\n\t\tnodeName: string,\n\t\tphase: 'prep' | 'exec' | 'post',\n\t\toriginalError?: Error,\n\t) {\n\t\tsuper(message, nodeName, phase, originalError)\n\t\tthis.name = 'FatalWorkflowError'\n\t}\n}\n","/**\n * Defines the interface for a logger that can be used by the workflow engine.\n * This allows for plugging in any logging library (e.g., Pino, Winston).\n */\nexport interface Logger {\n\tdebug: (message: string, context?: object) => void\n\tinfo: (message: string, context?: object) => void\n\twarn: (message: string, context?: object) => void\n\terror: (message: string, context?: object) => void\n}\n\n/**\n * A logger implementation that performs no action (a \"no-op\" logger).\n * This is the default logger used by the framework if none is provided,\n * making Flowcraft silent out-of-the-box.\n */\nexport class NullLogger implements Logger {\n\tdebug() { /* no-op */ }\n\tinfo() { /* no-op */ }\n\twarn() { /* no-op */ }\n\terror() { /* no-op */ }\n}\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\nconst levelPriorities: Record<LogLevel, number> = {\n\tdebug: 1,\n\tinfo: 2,\n\twarn: 3,\n\terror: 4,\n}\n\n/**\n * A default logger implementation that writes messages to the `console`.\n * It supports a minimum log level to control verbosity.\n */\nexport class ConsoleLogger implements Logger {\n\tprivate minLevel: LogLevel\n\n\t/**\n\t * @param options Configuration for the logger.\n\t * @param options.level The minimum level of messages to log. Defaults to 'info'.\n\t */\n\tconstructor(options: { level?: LogLevel } = {}) {\n\t\tthis.minLevel = options.level ?? 'info'\n\t}\n\n\tprivate log(level: LogLevel, message: string, context?: object) {\n\t\tif (levelPriorities[level] < levelPriorities[this.minLevel]) {\n\t\t\treturn\n\t\t}\n\n\t\tconst fullMessage = `[${level.toUpperCase()}] ${message}`\n\t\tif (context && Object.keys(context).length > 0) {\n\t\t\tconst logMethod = console[level] || console.log\n\t\t\tlogMethod(fullMessage, context)\n\t\t}\n\t\telse {\n\t\t\tconst logMethod = console[level] || console.log\n\t\t\tlogMethod(fullMessage)\n\t\t}\n\t}\n\n\tdebug(message: string, context?: object) { this.log('debug', message, context) }\n\tinfo(message: string, context?: object) { this.log('info', message, context) }\n\twarn(message: string, context?: object) { this.log('warn', message, context) }\n\terror(message: string, context?: object) { this.log('error', message, context) }\n}\n","import type { Middleware, MiddlewareNext, NodeArgs } from '../types'\nimport type { AbstractNode } from '../workflow'\n\n/**\n * Composes a chain of middleware functions around a node's execution.\n * @internal\n */\nexport function applyMiddleware<T = any>(middleware: Middleware<T>[], nodeToRun: AbstractNode): MiddlewareNext<T> {\n\t// The final function in the chain is the actual execution of the node.\n\tconst runNode: MiddlewareNext<T> = (args: NodeArgs) => {\n\t\treturn nodeToRun._run({\n\t\t\tctx: args.ctx,\n\t\t\tparams: { ...args.params, ...nodeToRun.params },\n\t\t\tsignal: args.signal,\n\t\t\tlogger: args.logger,\n\t\t\texecutor: args.executor,\n\t\t})\n\t}\n\n\tif (!middleware || middleware.length === 0)\n\t\treturn runNode\n\n\t// Build the chain backwards, so the first middleware in the array is the outermost.\n\treturn middleware.reduceRight<MiddlewareNext<T>>(\n\t\t(next, mw) => (args: NodeArgs) => mw(args, next),\n\t\trunNode,\n\t)\n}\n","import type { Context } from '../context'\nimport type { Logger } from '../logger'\nimport type { Middleware, NodeArgs, RunOptions } from '../types'\nimport type { AbstractNode, Flow } from '../workflow'\nimport type { IExecutor, InternalRunOptions } from './types'\nimport { AbortError } from '../errors'\nimport { NullLogger } from '../logger'\nimport { applyMiddleware } from '../utils/middleware'\n\n/**\n * The default executor that runs a workflow within a single, in-memory process.\n * This class contains the core logic for traversing a workflow graph, applying middleware,\n * and handling node execution.\n */\nexport class InMemoryExecutor implements IExecutor {\n\t/**\n\t * A stateless, reusable method that orchestrates the traversal of a graph.\n\t * It is called by `run()` for top-level flows and by `Flow.exec()` for sub-flows.\n\t * @param startNode The node where the graph traversal begins.\n\t * @param flowMiddleware The middleware array from the containing flow.\n\t * @param context The shared workflow context.\n\t * @param options The internal, normalized run options.\n\t * @returns The final action from the last executed node in the graph.\n\t * @internal\n\t */\n\tpublic async _orch<T = any>(\n\t\tstartNode: AbstractNode,\n\t\tflowMiddleware: Middleware[],\n\t\tcontext: Context,\n\t\toptions: InternalRunOptions,\n\t): Promise<T> {\n\t\tlet currentNode: AbstractNode | undefined = startNode\n\t\tlet nextNode: AbstractNode | undefined\n\t\tlet action: any\n\n\t\tconst { logger, signal } = options\n\n\t\twhile (currentNode) {\n\t\t\tif (signal?.aborted)\n\t\t\t\tthrow new AbortError()\n\n\t\t\tconst nodeArgs: NodeArgs = {\n\t\t\t\tctx: context,\n\t\t\t\tparams: { ...options.params, ...currentNode.params },\n\t\t\t\tsignal,\n\t\t\t\tlogger,\n\t\t\t\tprepRes: undefined,\n\t\t\t\texecRes: undefined,\n\t\t\t\tname: currentNode.constructor.name,\n\t\t\t\texecutor: options.executor,\n\t\t\t}\n\n\t\t\tconst chain = applyMiddleware(flowMiddleware, currentNode)\n\t\t\taction = await chain(nodeArgs)\n\t\t\tnextNode = this.getNextNode(currentNode, action, logger)\n\n\t\t\tif (!nextNode)\n\t\t\t\treturn action as T\n\n\t\t\tcurrentNode = nextNode\n\t\t}\n\n\t\treturn undefined as T\n\t}\n\n\t/**\n\t * Executes a given flow with a specific context and options.\n\t * This is the main entry point for the in-memory execution engine.\n\t * @param flow The Flow instance to execute.\n\t * @param context The shared context for the workflow.\n\t * @param options Runtime options, including a logger, abort controller, or initial params.\n\t * @returns A promise that resolves with the final action of the workflow.\n\t */\n\tpublic run<T>(flow: Flow<any, T>, context: Context, options?: RunOptions): Promise<T>\n\tpublic run(flow: Flow, context: Context, options?: RunOptions): Promise<any>\n\tpublic async run<T>(flow: Flow<any, T>, context: Context, options?: RunOptions): Promise<T> {\n\t\tconst logger = options?.logger ?? new NullLogger()\n\t\tconst combinedParams = { ...flow.params, ...options?.params }\n\n\t\tconst internalOptions: InternalRunOptions = {\n\t\t\tlogger,\n\t\t\tsignal: options?.signal ?? options?.controller?.signal,\n\t\t\tparams: combinedParams,\n\t\t\texecutor: this,\n\t\t}\n\n\t\t// Handle \"logic-bearing\" flows (e.g., BatchFlow) that don't have a graph.\n\t\t// Their logic is self-contained in their `exec` method.\n\t\tif (!flow.startNode) {\n\t\t\tlogger.info(`Executor is running a logic-bearing flow: ${flow.constructor.name}`)\n\t\t\tconst chain = applyMiddleware(flow.middleware, flow)\n\t\t\treturn await chain({\n\t\t\t\t...internalOptions,\n\t\t\t\tctx: context,\n\t\t\t\tprepRes: undefined,\n\t\t\t\texecRes: undefined,\n\t\t\t\tname: flow.constructor.name,\n\t\t\t})\n\t\t}\n\n\t\tlogger.info(`Executor is running flow graph: ${flow.constructor.name}`)\n\t\t// Delegate the graph traversal to our new stateless helper.\n\t\t// Pass the flow's own middleware to be applied to its nodes.\n\t\treturn this._orch<T>(flow.startNode, flow.middleware, context, internalOptions)\n\t}\n\n\t/**\n\t * Determines the next node to execute based on the action returned by the current node.\n\t * @internal\n\t */\n\tpublic getNextNode(curr: AbstractNode, action: any, logger: Logger): AbstractNode | undefined {\n\t\tconst nextNode = curr.successors.get(action)\n\t\tconst actionDisplay = typeof action === 'symbol' ? action.toString() : action\n\n\t\tif (nextNode) {\n\t\t\tlogger.debug(`Action '${actionDisplay}' from ${curr.constructor.name} leads to ${nextNode.constructor.name}`, { action })\n\t\t}\n\t\telse if (curr.successors.size > 0 && action !== undefined && action !== null) {\n\t\t\tlogger.debug(`Flow ends: Action '${actionDisplay}' from ${curr.constructor.name} has no configured successor.`)\n\t\t}\n\t\treturn nextNode\n\t}\n}\n","import type { Context } from './context'\nimport type { IExecutor } from './executors/types'\nimport type { Logger } from './logger'\n\n/** A generic type for key-value parameters. */\nexport type Params = Record<string, any>\n\n/** The default action returned by a node for linear progression. */\nexport const DEFAULT_ACTION = Symbol('default')\n\n/** The action returned by a `.filter()` node when the predicate fails. */\nexport const FILTER_FAILED = Symbol('filter_failed')\n\n/**\n * The standard arguments object passed to a node's lifecycle methods.\n * @template PrepRes The type of the `prepRes` property.\n * @template ExecRes The type of the `execRes` property.\n * @template TParams The type for the node's static parameters.\n */\nexport interface NodeArgs<PrepRes = any, ExecRes = any, TParams extends Params = Params> {\n\t/** The shared, mutable context for the workflow run. */\n\tctx: Context\n\t/** The static parameters for the node, merged from the node and flow's `withParams`. */\n\tparams: TParams\n\t/** An `AbortController` to gracefully cancel the workflow. */\n\tcontroller?: AbortController\n\t/** An `AbortSignal` for handling cancellation. */\n\tsignal?: AbortSignal\n\t/** The logger instance for the workflow run. */\n\tlogger: Logger\n\t/** The result of the `prep` phase. */\n\tprepRes: PrepRes\n\t/** The result of the `exec` phase. */\n\texecRes: ExecRes\n\t/** The final error object, available only in `execFallback`. */\n\terror?: Error\n\t/** The name of the Node's constructor, for logging. */\n\tname?: string\n\t/** A reference to the current `IExecutor` running the flow. */\n\texecutor?: IExecutor\n}\n\n/**\n * The context object passed to a node's internal `_run` method.\n * @internal\n */\nexport interface NodeRunContext {\n\tctx: Context\n\tparams: Params\n\tsignal?: AbortSignal\n\tlogger: Logger\n\texecutor?: IExecutor\n}\n\n/** Options for configuring a `Node` instance. */\nexport interface NodeOptions {\n\t/** The total number of times the `exec` phase will be attempted. Defaults to `1`. */\n\tmaxRetries?: number\n\t/** The time in milliseconds to wait between failed `exec` attempts. Defaults to `0`. */\n\twait?: number\n}\n\n/** Options for running a top-level `Flow`. */\nexport interface RunOptions {\n\t/** An `AbortController` to gracefully cancel the workflow. */\n\tcontroller?: AbortController\n\t/** An `AbortSignal` for handling cancellation. */\n\tsignal?: AbortSignal\n\t/** A `Logger` instance to receive logs from the execution engine. */\n\tlogger?: Logger\n\t/** Top-level parameters to be merged into the context for the entire run. */\n\tparams?: Params\n\t/** A custom `IExecutor` instance to run the workflow. Defaults to `InMemoryExecutor`. */\n\texecutor?: IExecutor\n}\n\n/** The function signature for the `next` function passed to middleware. */\nexport type MiddlewareNext<T = any> = (args: NodeArgs) => Promise<T>\n/** The function signature for a middleware function. */\nexport type Middleware<T = any> = (args: NodeArgs, next: MiddlewareNext<T>) => Promise<T>\n","import type { GraphNode, NodeTypeMap, TypedGraphNode, TypedWorkflowGraph, WorkflowGraph } from '../builder/graph.types'\n\n/** The rich metadata object returned by the analyzeGraph function. */\nexport interface GraphAnalysis<T extends NodeTypeMap = any> {\n\t/** A map of all nodes, keyed by ID, augmented with their connection degrees. */\n\tnodes: Map<string, TypedGraphNode<T> & { inDegree: number, outDegree: number }>\n\t/** An array of all node IDs in the graph. */\n\tallNodeIds: string[]\n\t/** An array of node IDs that have no incoming edges. */\n\tstartNodeIds: string[]\n\t/** A list of cycles found in the graph. Each cycle is an array of node IDs. */\n\tcycles: string[][]\n}\n\n/** A standard structure for reporting a single validation error. */\nexport interface ValidationError {\n\t/** The ID of the node where the error occurred, if applicable. */\n\tnodeId?: string\n\t/** A category for the error, e.g., 'CycleDetected', 'ConnectionRuleViolation'. */\n\ttype: string\n\t/** A human-readable message explaining the validation failure. */\n\tmessage: string\n}\n\n/**\n * A function that takes a graph analysis and the original graph,\n * and returns an array of validation errors.\n */\nexport type Validator<T extends NodeTypeMap = any> = (\n\tanalysis: GraphAnalysis<T>,\n\tgraph: TypedWorkflowGraph<T>\n) => ValidationError[]\n\n/**\n * A helper function that creates a type guard for filtering nodes by their type.\n * This simplifies writing type-safe validation rules by removing the need for\n * verbose, explicit type guard syntax.\n *\n * @param type The literal string of the node type to check for.\n * @returns A type guard function that narrows the node to its specific type.\n */\nexport function isNodeType<T extends NodeTypeMap, K extends keyof T>(type: K) {\n\treturn (node: TypedGraphNode<T>): node is TypedGraphNode<T> & { type: K } => {\n\t\treturn node.type === type\n\t}\n}\n\n/**\n * Analyzes a declarative workflow graph definition to extract structural metadata.\n * This is a lightweight, static utility that does not instantiate any nodes.\n *\n * @param graph The WorkflowGraph object containing nodes and edges.\n * @returns A GraphAnalysis object containing nodes with degree counts, start nodes, and any cycles.\n */\n// (Typesafe Overload) Analyzes a declarative workflow graph, preserving strong types.\nexport function analyzeGraph<T extends NodeTypeMap>(graph: TypedWorkflowGraph<T>): GraphAnalysis<T>\n// (Untyped Overload) Analyzes a declarative workflow graph with basic types.\nexport function analyzeGraph(graph: WorkflowGraph): GraphAnalysis\n// (Implementation) Analyzes a declarative workflow graph to extract structural metadata.\nexport function analyzeGraph<T extends NodeTypeMap>(graph: TypedWorkflowGraph<T> | WorkflowGraph): GraphAnalysis<T> {\n\tconst typedGraph = graph as TypedWorkflowGraph<T> // Cast for internal consistency\n\tconst analysis: GraphAnalysis<T> = {\n\t\tnodes: new Map(),\n\t\tallNodeIds: [],\n\t\tstartNodeIds: [],\n\t\tcycles: [],\n\t}\n\n\tif (!typedGraph || !typedGraph.nodes || !typedGraph.nodes.length)\n\t\treturn analysis\n\n\tconst allNodeIds = typedGraph.nodes.map(node => node.id)\n\tanalysis.allNodeIds = allNodeIds\n\n\tconst adj: Map<string, string[]> = new Map()\n\ttypedGraph.nodes.forEach((node) => {\n\t\tanalysis.nodes.set(node.id, { ...node, inDegree: 0, outDegree: 0 })\n\t\tadj.set(node.id, [])\n\t})\n\n\ttypedGraph.edges.forEach((edge) => {\n\t\tconst source = analysis.nodes.get(edge.source)\n\t\tconst target = analysis.nodes.get(edge.target)\n\t\tif (source)\n\t\t\tsource.outDegree++\n\t\tif (target)\n\t\t\ttarget.inDegree++\n\t\tif (adj.has(edge.source))\n\t\t\tadj.get(edge.source)!.push(edge.target)\n\t})\n\n\tanalysis.startNodeIds = allNodeIds.filter(id => analysis.nodes.get(id)!.inDegree === 0)\n\n\tconst visited = new Set<string>()\n\tconst recursionStack = new Set<string>()\n\tfunction detectCycleUtil(nodeId: string, path: string[]) {\n\t\tvisited.add(nodeId)\n\t\trecursionStack.add(nodeId)\n\t\tpath.push(nodeId)\n\n\t\tconst neighbors = adj.get(nodeId) || []\n\t\tfor (const neighbor of neighbors) {\n\t\t\tif (recursionStack.has(neighbor)) {\n\t\t\t\tconst cycleStartIndex = path.indexOf(neighbor)\n\t\t\t\tconst cycle = path.slice(cycleStartIndex)\n\t\t\t\tanalysis.cycles.push([...cycle, neighbor])\n\t\t\t}\n\t\t\telse if (!visited.has(neighbor)) {\n\t\t\t\tdetectCycleUtil(neighbor, path)\n\t\t\t}\n\t\t}\n\n\t\trecursionStack.delete(nodeId)\n\t\tpath.pop()\n\t}\n\n\tfor (const nodeId of allNodeIds) {\n\t\tif (!visited.has(nodeId))\n\t\t\tdetectCycleUtil(nodeId, [])\n\t}\n\n\treturn analysis\n}\n\n/**\n * Factory for creating a generic, reusable validator that checks node properties.\n *\n * @param description A human-readable description of the rule for error messages.\n * @param filter A predicate to select which nodes this rule applies to.\n * @param check A function that validates the properties of a selected node.\n * @returns A Validator function.\n */\n// (Type-Safe Overload) Creates a validator with strong types based on a NodeTypeMap.\nexport function createNodeRule<T extends NodeTypeMap>(\n\tdescription: string,\n\tfilter: (node: TypedGraphNode<T>) => boolean,\n\tcheck: (node: TypedGraphNode<T> & { inDegree: number, outDegree: number }) => { valid: boolean, message?: string },\n): Validator<T>\n// (Untyped Overload) Creates a validator with basic types.\nexport function createNodeRule(\n\tdescription: string,\n\tfilter: (node: GraphNode) => boolean,\n\tcheck: (node: GraphNode & { inDegree: number, outDegree: number }) => { valid: boolean, message?: string },\n): Validator\n// (Implementation) Factory for creating a generic, reusable validator.\nexport function createNodeRule(\n\tdescription: string,\n\tfilter: (node: any) => boolean,\n\tcheck: (node: any) => { valid: boolean, message?: string },\n): Validator {\n\treturn (analysis: GraphAnalysis, _graph: WorkflowGraph): ValidationError[] => {\n\t\tconst errors: ValidationError[] = []\n\t\tfor (const node of analysis.nodes.values()) {\n\t\t\tif (filter(node)) {\n\t\t\t\tconst result = check(node)\n\t\t\t\tif (!result.valid) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\t\ttype: 'ConnectionRuleViolation',\n\t\t\t\t\t\tmessage: result.message || `Node ${node.id} failed rule: ${description}`,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn errors\n\t}\n}\n\n/**\n * A built-in validator that reports any cycles found in the graph.\n */\nexport const checkForCycles: Validator = (analysis) => {\n\tconst uniqueCycles = new Set(analysis.cycles.map(c => c.slice(0, -1).sort().join(',')))\n\treturn Array.from(uniqueCycles).map((cycleKey) => {\n\t\tconst representativeCycle = analysis.cycles.find(c => c.slice(0, -1).sort().join(',') === cycleKey)!\n\t\treturn {\n\t\t\tnodeId: representativeCycle[0],\n\t\t\ttype: 'CycleDetected',\n\t\t\tmessage: `Cycle detected involving nodes: ${representativeCycle.join(' -> ')}`,\n\t\t}\n\t})\n}\n","import type { AbstractNode, Flow } from '../workflow'\nimport { DEFAULT_ACTION, FILTER_FAILED } from '../types'\n\n/**\n * Converts a special action symbol to a user-friendly string for the graph label.\n * @param action The action symbol or string.\n * @returns A string label for the Mermaid edge.\n */\nfunction getActionLabel(action: string | symbol): string {\n\tif (action === DEFAULT_ACTION)\n\t\treturn ''\n\n\tif (action === FILTER_FAILED)\n\t\treturn '\"filter failed\"'\n\n\t// Sanitize labels to prevent breaking Mermaid syntax\n\tconst sanitizedAction = action.toString().replace(/\"/g, '')\n\treturn `\"${sanitizedAction}\"`\n}\n\n/**\n * Generates a descriptive label for a node to be used in the Mermaid graph.\n * @param node The node to generate a label for.\n * @param uniqueId The unique ID assigned to this node instance in the graph.\n * @returns A formatted string for the Mermaid node definition.\n */\nfunction getNodeLabel(node: AbstractNode, uniqueId: string): string {\n\tif ((node as any).isParallelContainer)\n\t\treturn ` ${uniqueId}{Parallel Block}`\n\n\tif (node.constructor.name === 'InputMappingNode')\n\t\treturn ` ${uniqueId}((\"Inputs\"))`\n\n\tif (node.constructor.name === 'OutputMappingNode')\n\t\treturn ` ${uniqueId}((\"Outputs\"))`\n\n\tif (node.graphData) {\n\t\tconst type = node.graphData.type\n\t\tconst id = node.graphData.id.split(':').pop()\n\t\treturn ` ${uniqueId}[\"${id} (${type})\"]`\n\t}\n\n\treturn ` ${uniqueId}[${node.constructor.name}]`\n}\n\n/**\n * Generates a unique, readable ID for a node instance.\n * @param node The node instance.\n * @returns A unique string ID.\n */\nfunction getUniqueNodeId(node: AbstractNode, nameCounts: Map<string, number>, idMap: Map<AbstractNode, string>): string {\n\tif (idMap.has(node))\n\t\treturn idMap.get(node)!\n\n\tlet baseName: string\n\tif ((node as any).isParallelContainer) {\n\t\tbaseName = 'ParallelBlock'\n\t}\n\telse if (node.graphData) {\n\t\tbaseName = node.graphData.id\n\t}\n\telse {\n\t\tbaseName = node.constructor.name\n\t}\n\n\t// Sanitize the name for Mermaid ID\n\tconst sanitizedBaseName = baseName.replace(/:/g, '_').replace(/\\W/g, '')\n\tconst count = nameCounts.get(sanitizedBaseName) || 0\n\tconst uniqueId = `${sanitizedBaseName}_${count}`\n\tnameCounts.set(sanitizedBaseName, count + 1)\n\tidMap.set(node, uniqueId)\n\treturn uniqueId\n}\n\n/**\n * Generates a Mermaid graph definition from a `Flow` instance.\n * ...\n */\nexport function generateMermaidGraph(flow: Flow): string {\n\tif (!flow.startNode)\n\t\treturn 'graph TD\\n %% Empty Flow'\n\n\tconst nodes = new Set<string>()\n\tconst edges = new Set<string>()\n\tconst visited = new Set<AbstractNode>()\n\tconst queue: AbstractNode[] = [flow.startNode]\n\tconst idMap = new Map<AbstractNode, string>()\n\tconst nameCounts = new Map<string, number>()\n\n\tvisited.add(flow.startNode)\n\tgetUniqueNodeId(flow.startNode, nameCounts, idMap)\n\n\twhile (queue.length > 0) {\n\t\tconst currentNode = queue.shift()!\n\t\tconst sourceId = getUniqueNodeId(currentNode, nameCounts, idMap)\n\n\t\tnodes.add(getNodeLabel(currentNode, sourceId))\n\n\t\tif ((currentNode as any).isParallelContainer) {\n\t\t\tconst container = currentNode as any as { nodesToRun: AbstractNode[] }\n\t\t\tfor (const internalNode of container.nodesToRun) {\n\t\t\t\tconst targetId = getUniqueNodeId(internalNode, nameCounts, idMap)\n\t\t\t\tedges.add(` ${sourceId} --> ${targetId}`)\n\t\t\t\tif (!visited.has(internalNode)) {\n\t\t\t\t\tvisited.add(internalNode)\n\t\t\t\t\tqueue.push(internalNode)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const [action, successorNode] of currentNode.successors.entries()) {\n\t\t\tconst targetId = getUniqueNodeId(successorNode, nameCounts, idMap)\n\t\t\tconst label = getActionLabel(action)\n\t\t\tconst edge = label\n\t\t\t\t? ` ${sourceId} -- ${label} --> ${targetId}`\n\t\t\t\t: ` ${sourceId} --> ${targetId}`\n\t\t\tedges.add(edge)\n\n\t\t\tif (!visited.has(successorNode)) {\n\t\t\t\tvisited.add(successorNode)\n\t\t\t\tqueue.push(successorNode)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst mermaidLines = [\n\t\t'graph TD',\n\t\t...Array.from(nodes),\n\t\t...Array.from(edges),\n\t]\n\n\treturn mermaidLines.join('\\n')\n}\n","import { AbortError } from '../errors'\n\n/**\n * An abortable `sleep` utility that pauses execution for a specified duration.\n * It will reject with an `AbortError` if the provided `AbortSignal` is triggered.\n * @param ms The number of milliseconds to sleep.\n * @param signal An optional `AbortSignal` to listen for cancellation.\n */\nexport async function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted)\n\t\t\treturn reject(new AbortError())\n\n\t\tconst timeoutId = setTimeout(resolve, ms)\n\t\tsignal?.addEventListener('abort', () => {\n\t\t\tclearTimeout(timeoutId)\n\t\t\treject(new AbortError())\n\t\t})\n\t})\n}\n","/* eslint-disable unused-imports/no-unused-vars */\nimport type { GraphNode } from './builder/graph.types'\nimport type { Context, ContextKey, ContextLens } from './context'\nimport type { InternalRunOptions } from './executors/types'\nimport type { Middleware, NodeArgs, NodeOptions, NodeRunContext, Params, RunOptions } from './types'\nimport { AbortError, FatalWorkflowError, WorkflowError } from './errors'\nimport { InMemoryExecutor } from './executors/in-memory'\nimport { NullLogger } from './logger'\nimport { DEFAULT_ACTION, FILTER_FAILED } from './types'\nimport { sleep } from './utils/index'\n\n/**\n * The abstract base class for all executable units in a workflow.\n * It provides the core structure for connecting nodes into a graph.\n *\n * @template TPostRes The type for the action returned by the node's `post` method.\n * @template TParams The type for the node's static parameters.\n */\nexport abstract class AbstractNode<\n\tTPostRes = any,\n\tTParams extends Params = Params,\n> {\n\t/** A unique identifier for this node instance, often set by the GraphBuilder. */\n\tpublic id?: number | string\n\t/** A key-value store for static parameters that configure the node's behavior. */\n\tpublic params: TParams = {} as TParams\n\t/** A map of successor nodes, keyed by the action that triggers the transition. */\n\tpublic successors = new Map<TPostRes | string | typeof DEFAULT_ACTION | typeof FILTER_FAILED, AbstractNode<any, any>>()\n\t/** The original graph definition for this node, if created by a GraphBuilder. */\n\tpublic graphData?: GraphNode\n\n\t/**\n\t * Sets a unique identifier for this node instance.\n\t * Primarily used by the GraphBuilder for wiring and debugging.\n\t * @param id The unique ID for the node.\n\t * @returns The node instance for chaining.\n\t */\n\twithId(id: number | string): this {\n\t\tthis.id = id\n\t\treturn this\n\t}\n\n\t/**\n\t * Attaches the original graph definition data to the node instance.\n\t * @internal\n\t * @param data The graph node definition.\n\t * @returns The node instance for chaining.\n\t */\n\twithGraphData(data: GraphNode): this {\n\t\tthis.graphData = data\n\t\treturn this\n\t}\n\n\t/**\n\t * Sets or merges static parameters for the node. These parameters are available\n\t * via `args.params` in the node's lifecycle methods.\n\t * @param params The parameters to merge into the node's existing parameters.\n\t * @returns The node instance for chaining.\n\t */\n\twithParams(params: Partial<TParams>): this {\n\t\tthis.params = { ...this.params, ...params }\n\t\treturn this\n\t}\n\n\t/**\n\t * Defines the next node in the sequence for a given action.\n\t * This is the primary method for constructing a workflow graph.\n\t *\n\t * @param node The successor node to execute next.\n\t * @param action The action from this node's `post` method that triggers\n\t * the transition. Defaults to `DEFAULT_ACTION` for linear flows.\n\t * @returns The successor node instance, allowing for further chaining.\n\t */\n\tnext<NextNode extends AbstractNode<any, any>>(\n\t\tnode: NextNode,\n\t\taction: TPostRes | string | typeof DEFAULT_ACTION | typeof FILTER_FAILED = DEFAULT_ACTION as any,\n\t): NextNode {\n\t\tthis.successors.set(action, node)\n\t\treturn node\n\t}\n\n\t/**\n\t * The internal method that executes the node's full lifecycle.\n\t * It is called by an `IExecutor`.\n\t * @internal\n\t */\n\tabstract _run(ctx: NodeRunContext): Promise<TPostRes>\n}\n\n/**\n * The fundamental building block of a workflow, representing a single unit of work.\n * It features a three-phase lifecycle, retry logic, and a fluent API for creating\n * data processing pipelines.\n *\n * @template PrepRes The type of data returned by the `prep` phase.\n * @template ExecRes The type of data returned by the `exec` phase.\n * @template PostRes The type of the action returned by the `post` phase.\n * @template TParams The type for the node's static parameters.\n */\nexport class Node<\n\tPrepRes = any,\n\tExecRes = any,\n\tPostRes = any,\n\tTParams extends Params = Params,\n> extends AbstractNode<PostRes, TParams> {\n\t/** The total number of times the `exec` phase will be attempted. */\n\tpublic maxRetries: number\n\t/** The time in milliseconds to wait between failed `exec` attempts. */\n\tpublic wait: number\n\n\t/**\n\t * @param options Configuration options for the node's behavior.\n\t * @param options.maxRetries Total number of `exec` attempts. Defaults to `1`.\n\t * @param options.wait Milliseconds to wait between failed `exec` attempts. Defaults to `0`.\n\t */\n\tconstructor(options: NodeOptions = {}) {\n\t\tsuper()\n\t\tthis.maxRetries = options.maxRetries ?? 1\n\t\tthis.wait = options.wait ?? 0\n\t}\n\n\tprotected _wrapError(e: any, phase: 'prep' | 'exec' | 'post'): Error {\n\t\tif (e instanceof AbortError || e instanceof WorkflowError)\n\t\t\treturn e\n\n\t\treturn new WorkflowError(`Failed in ${phase} phase for node ${this.constructor.name}`, this.constructor.name, phase, e as Error)\n\t}\n\n\t/**\n\t * (Lifecycle) Prepares data for execution. Runs once before `exec`.\n\t * This is the ideal place to read data from the `Context`.\n\t * @param args The arguments for the node, including `ctx` and `params`.\n\t * @returns The data required by the `exec` phase.\n\t */\n\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> { return undefined as unknown as PrepRes }\n\n\t/**\n\t * (Lifecycle) Performs the core, isolated logic of the node.\n\t * This is the only phase that is retried on failure. It should not access the `Context` directly.\n\t * @param args The arguments for the node, including `prepRes`.\n\t * @returns The result of the execution.\n\t */\n\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> { return undefined as unknown as ExecRes }\n\n\t/**\n\t * (Lifecycle) Processes results and determines the next step. Runs once after `exec` succeeds.\n\t * This is the ideal place to write data to the `Context`.\n\t * @param args The arguments for the node, including `execRes`.\n\t * @returns An \"action\" string to determine which successor to execute next. Defaults to `DEFAULT_ACTION`.\n\t */\n\tasync post(args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<PostRes> { return DEFAULT_ACTION as any }\n\n\t/**\n\t * (Lifecycle) A fallback that runs if all `exec` retries fail.\n\t * If not implemented, the final error will be re-thrown, halting the workflow.\n\t * @param args The arguments for the node, including the final `error` that caused the failure.\n\t * @returns A fallback result of type `ExecRes`, allowing the workflow to recover and continue.\n\t */\n\tasync execFallback(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\tif (args.error)\n\t\t\tthrow args.error\n\n\t\tthrow new Error(`Node ${this.constructor.name} failed and has no fallback implementation.`)\n\t}\n\n\t/**\n\t * The internal retry-aware execution logic for the `exec` phase.\n\t * @internal\n\t */\n\tasync _exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\tlet lastError: Error | undefined\n\t\tfor (let curRetry = 0; curRetry < this.maxRetries; curRetry++) {\n\t\t\tif (args.signal?.aborted)\n\t\t\t\tthrow new AbortError()\n\t\t\ttry {\n\t\t\t\treturn await this.exec(args)\n\t\t\t}\n\t\t\tcatch (e) {\n\t\t\t\tconst error = e as Error\n\t\t\t\tlastError = error\n\n\t\t\t\tif (error instanceof FatalWorkflowError)\n\t\t\t\t\tthrow error\n\n\t\t\t\tif (error instanceof AbortError || error.name === 'AbortError')\n\t\t\t\t\tthrow error\n\n\t\t\t\tif (curRetry < this.maxRetries - 1) {\n\t\t\t\t\targs.logger.warn(`Attempt ${curRetry + 1}/${this.maxRetries} failed for ${this.constructor.name}. Retrying...`, { error })\n\t\t\t\t\tif (this.wait > 0)\n\t\t\t\t\t\tawait sleep(this.wait, args.signal)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\targs.logger.error(`All retries failed for ${this.constructor.name}. Executing fallback.`, { error: lastError })\n\t\tif (args.signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\treturn await this.execFallback({ ...args, error: lastError })\n\t}\n\n\t/**\n\t * The internal method that executes the node's full lifecycle.\n\t * @internal\n\t */\n\tasync _run({ ctx, params, signal, logger, executor }: NodeRunContext): Promise<PostRes> {\n\t\tif (this instanceof Flow) {\n\t\t\tlogger.debug(`Running flow: ${this.constructor.name}`, { params })\n\t\t}\n\t\telse {\n\t\t\tlogger.debug(`Running node: ${this.constructor.name}`, { params })\n\t\t}\n\n\t\tif (signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\tlet prepRes: PrepRes\n\t\ttry {\n\t\t\tprepRes = await this.prep({ ctx, params: params as TParams, signal, logger, prepRes: undefined, execRes: undefined, executor })\n\t\t\tlogger.debug(`[${this.constructor.name}] prep() result`, { prepRes })\n\t\t}\n\t\tcatch (e) {\n\t\t\tthrow this._wrapError(e, 'prep')\n\t\t}\n\n\t\tif (signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\tlet execRes: ExecRes\n\t\ttry {\n\t\t\texecRes = await this._exec({ ctx, params: params as TParams, signal, logger, prepRes, execRes: undefined, executor })\n\t\t\tlogger.debug(`[${this.constructor.name}] exec() result`, { execRes })\n\t\t}\n\t\tcatch (e) {\n\t\t\tthrow this._wrapError(e, 'exec')\n\t\t}\n\n\t\tif (signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\ttry {\n\t\t\tconst action = await this.post({ ctx, params: params as TParams, signal, logger, prepRes, execRes, executor })\n\t\t\tconst actionDisplay = typeof action === 'symbol' ? action.toString() : action\n\t\t\tlogger.debug(`[${this.constructor.name}] post() returned action: '${actionDisplay}'`)\n\t\t\treturn action === undefined ? DEFAULT_ACTION as any : action\n\t\t}\n\t\tcatch (e) {\n\t\t\tthrow this._wrapError(e, 'post')\n\t\t}\n\t}\n\n\t/**\n\t * Runs the node as a standalone unit, independent of a larger flow.\n\t * This is useful for testing individual nodes in isolation.\n\t *\n\t * @param ctx The shared workflow context.\n\t * @param options Runtime options like a logger or abort controller.\n\t * @returns The result of the node's `post` method (its action).\n\t */\n\tasync run(ctx: Context, options?: RunOptions): Promise<PostRes> {\n\t\tconst logger = options?.logger ?? new NullLogger()\n\t\tif (this.successors.size > 0 && !(this instanceof Flow))\n\t\t\tlogger.warn('Node.run() called directly on a node with successors. The flow will not continue. Use a Flow to execute a sequence.')\n\t\tconst executor = options?.executor ?? new InMemoryExecutor()\n\t\t// Wrap the node in a Flow and pass its params via the options.\n\t\treturn executor.run(new Flow(this), ctx, { ...options, params: this.params })\n\t}\n\n\t/**\n\t * Creates a new node that transforms the result of this node's `exec` phase.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t * The new node inherits the original's `prep` method. The original `post` method\n\t * is discarded as it is incompatible with the new result type.\n\t *\n\t * @example\n\t * const fetchUserNode = new FetchUserNode() // returns { id: 1, name: 'Alice' }\n\t * const getUserNameNode = fetchUserNode.map(user => user.name) // returns 'Alice'\n\t *\n\t * @param fn A sync or async function to transform the execution result from `ExecRes` to `NewRes`.\n\t * @returns A new `Node` instance with the transformed output type.\n\t */\n\tmap<NewRes>(fn: (result: ExecRes) => NewRes | Promise<NewRes>): Node<PrepRes, NewRes, any, TParams> {\n\t\tconst originalNode = this\n\t\tconst maxRetries = this.maxRetries\n\t\tconst wait = this.wait\n\n\t\treturn new class extends Node<PrepRes, NewRes, any, TParams> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<NewRes> {\n\t\t\t\tconst originalResult = await originalNode.exec(args)\n\t\t\t\treturn fn(originalResult)\n\t\t\t}\n\n\t\t\tasync post(_args: NodeArgs<PrepRes, NewRes, TParams>): Promise<any> {\n\t\t\t\treturn DEFAULT_ACTION\n\t\t\t}\n\t\t}()\n\t}\n\n\t/**\n\t * Creates a new node that stores the result of this node's `exec` phase in the `Context`.\n\t * This is a common terminal operation for a data processing chain.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t *\n\t * @example\n\t * const USER_NAME = contextKey<string>('user_name')\n\t * const workflow = new FetchUserNode()\n\t * .map(user => user.name)\n\t * .toContext(USER_NAME)\n\t *\n\t * @param key The type-safe `ContextKey` to use for storing the result.\n\t * @returns A new `Node` instance that performs the context update in its `post` phase.\n\t */\n\ttoContext(key: ContextKey<ExecRes>): Node<PrepRes, ExecRes, any, TParams> {\n\t\tconst originalNode = this\n\t\tconst maxRetries = this.maxRetries\n\t\tconst wait = this.wait\n\n\t\treturn new class extends Node<PrepRes, ExecRes, any, TParams> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> { return originalNode.exec(args) }\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<any> {\n\t\t\t\targs.ctx.set(key, args.execRes)\n\t\t\t\targs.logger.debug(`[toContext] Set context key '${String(key.description)}'`, { value: args.execRes })\n\t\t\t\treturn DEFAULT_ACTION\n\t\t\t}\n\t\t}()\n\t}\n\n\t/**\n\t * Creates a new node that acts as a conditional gate based on the `exec` result.\n\t * If the predicate returns `true`, the node returns `DEFAULT_ACTION`.\n\t * If it returns `false`, the node returns `FILTER_FAILED`, enabling branching.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t *\n\t * @example\n\t * const checkAdminNode = new FetchUserNode().filter(user => user.isAdmin)\n\t *\n\t * checkAdminNode.next(adminOnlyNode, DEFAULT_ACTION)\n\t * checkAdminNode.next(accessDeniedNode, FILTER_FAILED)\n\t *\n\t * @param predicate A sync or async function that returns `true` or `false`.\n\t * @returns A new `Node` instance that implements the filter logic.\n\t */\n\tfilter(predicate: (result: ExecRes) => boolean | Promise<boolean>): Node<PrepRes, ExecRes, any, TParams> {\n\t\tconst originalNode = this\n\n\t\treturn new class extends Node<PrepRes, ExecRes, any, TParams> {\n\t\t\tprivate didPass = false\n\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>) { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\t\t\tconst result = await originalNode.exec(args)\n\t\t\t\tthis.didPass = await predicate(result)\n\t\t\t\tif (!this.didPass)\n\t\t\t\t\targs.logger.debug(`[Filter] Predicate failed for node ${this.constructor.name}.`)\n\n\t\t\t\treturn result\n\t\t\t}\n\n\t\t\tasync post(_args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<any> {\n\t\t\t\treturn this.didPass ? DEFAULT_ACTION : FILTER_FAILED\n\t\t\t}\n\t\t}()\n\t}\n\n\t/**\n\t * Creates a new node that performs a side effect with the `exec` result,\n\t * but passes the original result through unmodified. Ideal for logging or debugging.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t *\n\t * @example\n\t * const workflow = new FetchUserNode()\n\t * .tap(user => console.log('Fetched User:', user))\n\t * .map(user => user.id)\n\t *\n\t * @param fn A function to call with the execution result for its side effect.\n\t * @returns A new `Node` instance that wraps the original.\n\t */\n\ttap(fn: (result: ExecRes) => void | Promise<void>): Node<PrepRes, ExecRes, PostRes, TParams> {\n\t\tconst originalNode = this\n\t\tconst maxRetries = this.maxRetries\n\t\tconst wait = this.wait\n\n\t\treturn new class extends Node<PrepRes, ExecRes, PostRes, TParams> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> {\n\t\t\t\treturn originalNode.prep(args)\n\t\t\t}\n\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\t\t\tconst originalResult = await originalNode.exec(args)\n\t\t\t\tawait fn(originalResult)\n\t\t\t\treturn originalResult\n\t\t\t}\n\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<PostRes> {\n\t\t\t\treturn originalNode.post(args)\n\t\t\t}\n\t\t}()\n\t}\n\n\t/**\n\t * Creates a new node that applies a context mutation using a lens before executing.\n\t * This allows for declaratively setting or updating context as part of a fluent chain.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t *\n\t * @example\n\t * const VALUE = contextKey<number>('value')\n\t * const valueLens = lens(VALUE)\n\t *\n\t * const nodeWithLens = new SomeNode().withLens(valueLens, 42) // Sets VALUE to 42 before SomeNode runs\n\t *\n\t * @param lens The `ContextLens` to use for the operation.\n\t * @param value The value to set in the context via the lens.\n\t * @returns A new `Node` instance that applies the context change.\n\t */\n\twithLens<T>(lens: ContextLens<T>, value: T): Node<PrepRes, ExecRes, PostRes, TParams> {\n\t\tconst originalNode = this\n\t\tconst maxRetries = this.maxRetries\n\t\tconst wait = this.wait\n\n\t\treturn new class extends Node<PrepRes, ExecRes, PostRes, TParams> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> {\n\t\t\t\t// Apply the lens transformation before executing the original node's logic.\n\t\t\t\tlens.set(value)(args.ctx)\n\t\t\t\treturn originalNode.prep(args)\n\t\t\t}\n\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\t\t\treturn originalNode.exec(args)\n\t\t\t}\n\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<PostRes> {\n\t\t\t\treturn originalNode.post(args)\n\t\t\t}\n\t\t}()\n\t}\n}\n\n/**\n * A special type of `Node` that orchestrates a graph of other nodes.\n * It can contain its own middleware and can be composed within other flows.\n *\n * @template PrepRes The type of data returned by the `prep` phase.\n * @template ExecRes The type of data returned by the `exec` phase (the final action).\n * @template TParams The type for the flow's static parameters.\n */\nexport class Flow<\n\tPrepRes = any,\n\tExecRes = any,\n\tTParams extends Params = Params,\n> extends Node<PrepRes, ExecRes, ExecRes, TParams> {\n\t/** The first node to be executed in this flow's graph. */\n\tpublic startNode?: AbstractNode<any, any>\n\t/** An array of middleware functions to be applied to every node within this flow. */\n\tpublic middleware: Middleware[] = []\n\n\t/**\n\t * @param start An optional node to start the flow with.\n\t */\n\tconstructor(start?: AbstractNode<any, any>) {\n\t\tsuper()\n\t\tthis.startNode = start\n\t}\n\n\tprotected _wrapError(e: any, phase: 'prep' | 'exec' | 'post'): Error {\n\t\tif (phase === 'exec') {\n\t\t\t// Errors from a sub-flow's orchestration are already wrapped, so we pass them through.\n\t\t\treturn e\n\t\t}\n\t\treturn super._wrapError(e, phase)\n\t}\n\n\t/**\n\t * Adds a middleware function to this flow. Middleware will be executed in the\n\t * order it is added, wrapping the execution of every node within this flow.\n\t * @param fn The middleware function to add.\n\t * @returns The `Flow` instance for chaining.\n\t */\n\tpublic use(fn: Middleware): this {\n\t\tthis.middleware.push(fn)\n\t\treturn this\n\t}\n\n\t/**\n\t * Sets the starting node of the flow's graph.\n\t * @param start The node to start with.\n\t * @returns The start node instance, allowing for further chaining (`.next()`).\n\t */\n\tstart<StartNode extends AbstractNode<any, any>>(start: StartNode): StartNode {\n\t\tthis.startNode = start\n\t\treturn start\n\t}\n\n\t/**\n\t * (Lifecycle) Executes this flow's internal graph when it is used as a sub-flow\n\t * (a node within a larger flow).\n\t * @internal\n\t * @param args The arguments for the node, passed down from the parent executor.\n\t * @returns The final action returned by the last node in this flow's graph.\n\t */\n\tasync exec(args: NodeArgs<any, any, TParams>): Promise<ExecRes> {\n\t\t// For programmatic composition, a Flow node orchestrates its own graph.\n\t\t// This is a feature of the InMemoryExecutor. Distributed systems should\n\t\t// rely on pre-flattened graphs produced by the GraphBuilder.\n\t\tif (!(args.executor instanceof InMemoryExecutor)) {\n\t\t\tthrow new TypeError('Programmatic sub-flow execution is only supported by the InMemoryExecutor. For other environments, use GraphBuilder to create a single, flattened workflow.')\n\t\t}\n\n\t\tif (!this.startNode) {\n\t\t\t// This handles logic-bearing flows like BatchFlow that override exec directly.\n\t\t\treturn super.exec(args)\n\t\t}\n\n\t\targs.logger.debug(`-- Entering sub-flow: ${this.constructor.name} --`)\n\n\t\tconst combinedParams = { ...args.params, ...this.params }\n\t\tconst internalOptions: InternalRunOptions = {\n\t\t\tlogger: args.logger,\n\t\t\tsignal: args.signal,\n\t\t\tparams: combinedParams,\n\t\t\texecutor: args.executor,\n\t\t}\n\n\t\tconst finalAction = await args.executor._orch<ExecRes>(\n\t\t\tthis.startNode,\n\t\t\tthis.middleware,\n\t\t\targs.ctx,\n\t\t\tinternalOptions,\n\t\t)\n\n\t\targs.logger.debug(`-- Exiting sub-flow: ${this.constructor.name} --`)\n\t\treturn finalAction as ExecRes\n\t}\n\n\t/**\n\t * (Lifecycle) The post-execution step for a `Flow` node. It simply passes through\n\t * the final action from its internal graph execution (`execRes`).\n\t * @internal\n\t */\n\tasync post({ execRes }: NodeArgs<PrepRes, ExecRes, TParams>): Promise<ExecRes> {\n\t\treturn execRes\n\t}\n\n\t/**\n\t * Runs the entire flow as a top-level entry point.\n\t * @param ctx The shared workflow context.\n\t * @param options Runtime options like a logger, abort controller, or a custom executor.\n\t * @returns The final action returned by the last node in the flow.\n\t */\n\tasync run(ctx: Context, options?: RunOptions): Promise<ExecRes> {\n\t\tconst executor = options?.executor ?? new InMemoryExecutor()\n\t\treturn executor.run(this, ctx, options)\n\t}\n\n\t/**\n\t * Finds a node within the flow's graph by its unique ID.\n\t *\n\t * This method performs a breadth-first search starting from the `startNode`.\n\t * It is a convenient way to get a reference to a specific node instance\n\t * for debugging or dynamic modifications.\n\t *\n\t * @remarks\n\t * This performs a graph traversal on each call, which has a time complexity\n\t * proportional to the number of nodes and edges in the graph (O(V+E)). For\n\t * performance-critical applications or flows built with `GraphBuilder`,\n\t * it is more efficient to use the `nodeMap` returned by `GraphBuilder.build()`.\n\t *\n\t * @param id The unique ID of the node to find (set via `.withId()` or by the `GraphBuilder`).\n\t * @returns The `AbstractNode` instance if found, otherwise `undefined`.\n\t */\n\tpublic getNodeById(id: string | number): AbstractNode<any, any> | undefined {\n\t\tif (!this.startNode)\n\t\t\treturn undefined\n\n\t\tconst queue: AbstractNode<any, any>[] = [this.startNode]\n\t\tconst visited = new Set<AbstractNode<any, any>>([this.startNode])\n\t\twhile (queue.length > 0) {\n\t\t\tconst currentNode = queue.shift()!\n\n\t\t\tif (currentNode.id === id)\n\t\t\t\treturn currentNode\n\n\t\t\tfor (const successor of currentNode.successors.values()) {\n\t\t\t\tif (!visited.has(successor)) {\n\t\t\t\t\tvisited.add(successor)\n\t\t\t\t\tqueue.push(successor)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined\n\t}\n}\n","/**\n * A type-safe, opaque key for storing and retrieving values from the Context.\n * Using a `ContextKey` provides compile-time safety for your workflow's state.\n * @template T The type of the value this key refers to.\n */\nexport type ContextKey<T> = symbol & { __type: T }\n\n/**\n * Creates a new, unique `ContextKey` for type-safe access to the `Context`.\n * @template T The type of the value this key will hold.\n * @param description An optional description for debugging purposes (e.g., in logs or test snapshots).\n * @returns A unique `ContextKey<T>`.\n */\nexport const contextKey = <T>(description?: string): ContextKey<T> => Symbol(description) as ContextKey<T>\n\n/**\n * Defines the interface for the shared context object passed through the workflow.\n * It acts as the shared memory for all nodes in a flow. It supports both\n * type-safe `ContextKey`s and flexible `string` keys.\n */\nexport interface Context {\n\t/** Retrieves a value from the context. */\n\tget: (<T>(key: ContextKey<T>) => T | undefined) & (<T = any>(key: string) => T | undefined)\n\t/** Stores a value in the context. */\n\tset: (<T>(key: ContextKey<T>, value: T) => this) & ((key: string, value: any) => this)\n\t/** Checks if a key exists in the context. */\n\thas: ((key: ContextKey<any>) => boolean) & ((key: string) => boolean)\n\t/** Returns an iterator of all [key, value] pairs in the context. */\n\tentries: () => IterableIterator<[any, any]>\n}\n\n/**\n * The default, `Map`-based implementation of the `Context` interface.\n */\nexport class TypedContext implements Context {\n\tprivate data: Map<any, any>\n\n\t/**\n\t * @param initialData An optional iterable (like an array of `[key, value]` pairs)\n\t * to initialize the context with.\n\t */\n\tconstructor(initialData?: Iterable<readonly [ContextKey<any> | string, any]> | null) {\n\t\tthis.data = new Map<any, any>(initialData)\n\t}\n\n\tget(key: ContextKey<any> | string): any {\n\t\treturn this.data.get(key)\n\t}\n\n\tset(key: ContextKey<any> | string, value: any): this {\n\t\tthis.data.set(key, value)\n\t\treturn this\n\t}\n\n\thas(key: ContextKey<any> | string): boolean {\n\t\treturn this.data.has(key)\n\t}\n\n\tentries(): IterableIterator<[any, any]> {\n\t\treturn this.data.entries()\n\t}\n}\n\n/** A function that takes a `Context` and returns a (potentially new) `Context`. */\nexport type ContextTransform = (ctx: Context) => Context\n\n/**\n * A \"lens\" provides a way to \"focus\" on a single key in the `Context`,\n * creating reusable, type-safe functions to get, set, or update its value.\n * @template T The type of the value the lens focuses on.\n */\nexport interface ContextLens<T> {\n\t/** Retrieves the value for the key from the context. */\n\tget: (ctx: Context) => T | undefined\n\t/** Returns a `ContextTransform` function that will set the key to the provided value. */\n\tset: (value: T) => ContextTransform\n\t/** Returns a `ContextTransform` function that updates the key's value based on its current value. */\n\tupdate: (fn: (current: T | undefined) => T) => ContextTransform\n}\n\n/**\n * Creates a `ContextLens` object for a specific `ContextKey`.\n * This is the entry point for functional context manipulation.\n *\n * @example\n * const NAME = contextKey<string>('name')\n * const nameLens = lens(NAME)\n * const setNameTransform = nameLens.set('Alice') // This is a function: (ctx) => ctx.set(NAME, 'Alice')\n *\n * @param key The `ContextKey` to focus on.\n * @returns A `ContextLens<T>` object with `.get()`, `.set()`, and `.update()` methods.\n */\nexport function lens<T>(key: ContextKey<T>): ContextLens<T> {\n\treturn {\n\t\tget: (ctx: Context) => ctx.get(key),\n\t\tset: (value: T) => (ctx: Context) => ctx.set(key, value),\n\t\tupdate: (fn: (current: T | undefined) => T) => (ctx: Context) =>\n\t\t\tctx.set(key, fn(ctx.get(key))),\n\t}\n}\n\n/**\n * Composes multiple `ContextTransform` functions into a single `ContextTransform` function.\n * The transformations are applied in the order they are provided.\n *\n * @param transforms A sequence of `ContextTransform` functions.\n * @returns A single function that applies all transformations.\n */\nexport function composeContext(...transforms: ContextTransform[]): ContextTransform {\n\treturn (ctx: Context) => transforms.reduce((acc, transform) => transform(acc), ctx)\n}\n","import type { NodeFunction } from '../functions'\nimport type { NodeArgs } from '../types'\nimport type { AbstractNode } from '../workflow'\nimport { AbortError } from '../errors'\nimport { Flow } from '../workflow'\n\n/**\n * A `Flow` that creates a linear workflow from a sequence of nodes,\n * automatically chaining them in order.\n */\nexport class SequenceFlow<PrepRes = any, ExecRes = any> extends Flow<PrepRes, ExecRes> {\n\t/**\n\t * @param nodes A sequence of `Node` or `Flow` instances to be executed in order.\n\t */\n\tconstructor(...nodes: AbstractNode[]) {\n\t\tif (nodes.length === 0) {\n\t\t\tsuper()\n\t\t\treturn\n\t\t}\n\t\tsuper(nodes[0])\n\t\tlet current = nodes[0]\n\t\tfor (let i = 1; i < nodes.length; i++)\n\t\t\tcurrent = current.next(nodes[i])\n\t}\n}\n\n/**\n * A `Flow` that executes a collection of different nodes concurrently.\n * This is the core of the \"fan-out, fan-in\" pattern for structural parallelism.\n * After all parallel branches complete, the flow can proceed to a single successor.\n */\nexport class ParallelFlow extends Flow<any, void> {\n\t/**\n\t * @param nodesToRun The array of nodes to execute concurrently.\n\t */\n\tconstructor(protected nodesToRun: AbstractNode[]) {\n\t\tsuper()\n\t}\n\n\t/**\n\t * Orchestrates the parallel execution of all nodes.\n\t * @internal\n\t */\n\tasync exec({ ctx, params, signal, logger, executor }: NodeArgs): Promise<void> {\n\t\tif (this.nodesToRun.length === 0) {\n\t\t\tlogger.debug('[ParallelFlow] No branches to execute in parallel.')\n\t\t\treturn\n\t\t}\n\n\t\tlogger.info(`[ParallelFlow] Executing ${this.nodesToRun.length} branches in parallel...`)\n\t\tconst promises = this.nodesToRun.map(node =>\n\t\t\tnode._run({\n\t\t\t\tctx,\n\t\t\t\tparams: { ...params, ...node.params },\n\t\t\t\tsignal,\n\t\t\t\tlogger,\n\t\t\t\texecutor,\n\t\t\t}),\n\t\t)\n\n\t\tconst results = await Promise.allSettled(promises)\n\n\t\tresults.forEach((result) => {\n\t\t\tif (result.status === 'rejected')\n\t\t\t\tlogger.error('[ParallelFlow] A parallel branch failed.', { error: result.reason })\n\t\t})\n\t}\n}\n\n/**\n * An abstract `Flow` that processes a collection of items sequentially, one by one.\n * Subclasses must implement the `prep` method to provide the items and the\n * `nodeToRun` property to define the processing logic for each item.\n */\nexport abstract class BatchFlow<T = any> extends Flow<Iterable<T>, null> {\n\t/**\n\t * The `Node` instance that will be executed for each item in the batch.\n\t * This must be implemented by any subclass.\n\t */\n\tprotected abstract nodeToRun: AbstractNode\n\n\tconstructor() {\n\t\tsuper()\n\t}\n\n\t/**\n\t * (Abstract) Prepares the list of items to be processed.\n\t * This method is called once before the batch processing begins.\n\t * @param _args The arguments for the node, including `ctx` and `params`.\n\t * @returns An array or iterable of parameter objects, one for each item.\n\t * The `nodeToRun` will be executed once for each of these objects.\n\t */\n\tasync prep(_args: NodeArgs): Promise<Iterable<any>> {\n\t\treturn []\n\t}\n\n\t/**\n\t * Orchestrates the sequential execution of `nodeToRun` for each item.\n\t * @internal\n\t */\n\tasync exec(args: NodeArgs): Promise<null> {\n\t\tif (!this.nodeToRun)\n\t\t\treturn null\n\n\t\tconst combinedParams = { ...this.params, ...args.params }\n\t\tconst batchParamsIterable = (await this.prep(args)) || []\n\t\tconst batchParamsList = Array.from(batchParamsIterable)\n\t\targs.logger.info(`[BatchFlow] Starting sequential processing of ${batchParamsList.length} items.`)\n\n\t\tfor (const batchParams of batchParamsList) {\n\t\t\tif (args.signal?.aborted)\n\t\t\t\tthrow new AbortError()\n\n\t\t\tawait this.nodeToRun._run({\n\t\t\t\tctx: args.ctx,\n\t\t\t\tparams: { ...combinedParams, ...batchParams },\n\t\t\t\tsignal: args.signal,\n\t\t\t\tlogger: args.logger,\n\t\t\t\texecutor: args.executor,\n\t\t\t})\n\t\t}\n\t\treturn null\n\t}\n}\n\n/**\n * An abstract `Flow` that processes a collection of items concurrently.\n * Subclasses must implement the `prep` method to provide the items and the\n * `nodeToRun` property to define the processing logic for each item.\n * This provides a significant performance boost for I/O-bound tasks.\n */\nexport abstract class ParallelBatchFlow<T = any> extends Flow<Iterable<T>, PromiseSettledResult<any>[]> {\n\t/**\n\t * The `Node` instance that will be executed concurrently for each item in the batch.\n\t * This must be implemented by any subclass.\n\t */\n\tprotected abstract nodeToRun: AbstractNode\n\n\tconstructor() {\n\t\tsuper()\n\t}\n\n\t/**\n\t * (Abstract) Prepares the list of items to be processed.\n\t * This method is called once before the batch processing begins.\n\t * @param _args The arguments for the node, including `ctx` and `params`.\n\t * @returns An array or iterable of parameter objects, one for each item.\n\t * The `nodeToRun` will be executed concurrently for each of these objects.\n\t */\n\tasync prep(_args: NodeArgs): Promise<Iterable<any>> {\n\t\treturn []\n\t}\n\n\t/**\n\t * Orchestrates the parallel execution of `nodeToRun` for each item.\n\t * @internal\n\t */\n\tasync exec(args: NodeArgs<any, void>): Promise<PromiseSettledResult<any>[]> {\n\t\tif (!this.nodeToRun)\n\t\t\treturn []\n\n\t\tconst combinedParams = { ...this.params, ...args.params }\n\t\tconst batchParamsIterable = (await this.prep(args)) || []\n\t\tconst batchParamsList = Array.from(batchParamsIterable)\n\t\targs.logger.info(`[ParallelBatchFlow] Starting parallel processing of ${batchParamsList.length} items.`)\n\n\t\tconst promises = batchParamsList.map((batchParams) => {\n\t\t\treturn this.nodeToRun._run({\n\t\t\t\tctx: args.ctx,\n\t\t\t\tparams: { ...combinedParams, ...batchParams },\n\t\t\t\tsignal: args.signal,\n\t\t\t\tlogger: args.logger,\n\t\t\t\texecutor: args.executor,\n\t\t\t})\n\t\t})\n\n\t\tconst results = await Promise.allSettled(promises)\n\n\t\tfor (const result of results) {\n\t\t\tif (result.status === 'rejected') {\n\t\t\t\targs.logger.error('A parallel batch item failed.', { error: result.reason })\n\t\t\t}\n\t\t}\n\n\t\treturn results\n\t}\n}\n\n/**\n * Creates a flow that applies a mapping function to each item in a collection in parallel\n * and returns a new array containing the results.\n *\n * @example\n * const numbers = [1, 2, 3];\n * const double = (n: number) => n * 2;\n * const processingFlow = mapCollection(numbers, double);\n * // When run, processingFlow's result will be [2, 4, 6]\n *\n * @param items The initial array of items of type `T`.\n * @param fn An async or sync function that transforms an item from type `T` to type `U`.\n * @returns A `Flow` instance that, when run, will output an array of type `U[]`.\n */\nexport function mapCollection<T, U>(items: T[], fn: NodeFunction<T, U>): Flow<void, U[]> {\n\treturn new class extends Flow {\n\t\tasync exec(): Promise<U[]> {\n\t\t\t// Using Promise.all to run the mapping function on all items concurrently.\n\t\t\tconst promises = items.map(item => fn(item))\n\t\t\treturn Promise.all(promises)\n\t\t}\n\t}()\n}\n\n/**\n * Creates a flow that filters a collection based on a predicate function,\n * returning a new array containing only the items that pass the predicate.\n * The predicate is applied to all items concurrently.\n *\n * @example\n * const users = [{ id: 1, admin: true }, { id: 2, admin: false }];\n * const isAdmin = async (user: { admin: boolean }) => user.admin;\n * const adminFilterFlow = filterCollection(users, isAdmin);\n * // When run, the result will be [{ id: 1, admin: true }]\n *\n * @param items The initial array of items of type `T`.\n * @param predicate An async or sync function that returns `true` or `false` for an item.\n * @returns A `Flow` instance that, when run, will output a filtered array of type `T[]`.\n */\nexport function filterCollection<T>(items: T[], predicate: (item: T) => boolean | Promise<boolean>): Flow<void, T[]> {\n\treturn new class extends Flow {\n\t\tasync exec(): Promise<T[]> {\n\t\t\tconst results = await Promise.all(items.map(item => predicate(item)))\n\t\t\treturn items.filter((_, index) => results[index])\n\t\t}\n\t}()\n}\n\n/**\n * Creates a flow that reduces a collection to a single value by executing a\n * reducer function sequentially for each item, similar to `Array.prototype.reduce()`.\n *\n * @example\n * const numbers = [1, 2, 3, 4];\n * const sumReducer = (acc: number, val: number) => acc + val;\n * const sumFlow = reduceCollection(numbers, sumReducer, 0);\n * // When run, the result will be 10.\n *\n * @param items The array of items to be reduced.\n * @param reducer An async or sync function that processes the accumulator and the current item.\n * @param initialValue The initial value for the accumulator.\n * @returns A `Flow` instance that, when run, will output the final accumulated value of type `U`.\n */\nexport function reduceCollection<T, U>(\n\titems: T[],\n\treducer: (accumulator: U, item: T) => U | Promise<U>,\n\tinitialValue: U,\n): Flow<void, U> {\n\treturn new class extends Flow {\n\t\tasync exec(_args: NodeArgs): Promise<U> {\n\t\t\tlet accumulator = initialValue\n\t\t\tfor (const item of items) {\n\t\t\t\tif (_args.signal?.aborted) {\n\t\t\t\t\tthrow new AbortError()\n\t\t\t\t}\n\t\t\t\taccumulator = await reducer(accumulator, item)\n\t\t\t}\n\t\t\treturn accumulator\n\t\t}\n\t}()\n}\n","import type { Logger } from '../logger'\nimport type { FILTER_FAILED, NodeArgs } from '../types'\nimport type { AbstractNode } from '../workflow'\nimport type { BuildResult, GraphBuilderOptions, GraphEdge, GraphNode, NodeRegistry, NodeTypeMap, TypedNodeRegistry, TypedWorkflowGraph, WorkflowGraph } from './graph.types'\nimport { NullLogger } from '../logger'\nimport { DEFAULT_ACTION } from '../types'\nimport { generateMermaidGraph } from '../utils/mermaid'\nimport { Flow, Node } from '../workflow'\nimport { ParallelFlow } from './patterns'\n\n/**\n * A type-safe helper function for creating a `TypedNodeRegistry`.\n * This function preserves the strong typing of the registry object, enabling\n * compile-time validation of `TypedWorkflowGraph` definitions.\n *\n * @param registry The registry object, where keys are node types and values are `Node` constructors.\n * @returns The same registry object, correctly typed for use with `GraphBuilder`.\n */\nexport function createNodeRegistry<\n\tTNodeMap extends NodeTypeMap,\n\tTContext = object,\n>(registry: TypedNodeRegistry<TNodeMap, TContext>): TypedNodeRegistry<TNodeMap, TContext> {\n\treturn registry\n}\n\n/**\n * An internal node used by the GraphBuilder to handle the `inputs` mapping\n * of an inlined sub-workflow. It copies data from the parent context scope\n * to the sub-workflow's context scope.\n * @internal\n */\nclass InputMappingNode extends Node {\n\tprivate mappings: Record<string, string>\n\tconstructor(options: { data: Record<string, string> }) {\n\t\tsuper()\n\t\tconst { nodeId, ...mappings } = options.data\n\t\tthis.mappings = mappings\n\t}\n\n\tasync prep({ ctx, logger }: NodeArgs) {\n\t\tfor (const [subKey, parentKey] of Object.entries(this.mappings)) {\n\t\t\tif (ctx.has(parentKey)) {\n\t\t\t\tctx.set(subKey, ctx.get(parentKey))\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.warn(`[InputMapper] Input mapping failed. Key '${parentKey}' not found in context.`)\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * An internal node used by the GraphBuilder to handle the `outputs` mapping\n * of an inlined sub-workflow. It copies data from the sub-workflow's\n * context scope back to the parent's context scope.\n * @internal\n */\nclass OutputMappingNode extends Node {\n\tprivate mappings: Record<string, string>\n\tconstructor(options: { data: Record<string, string> }) {\n\t\tsuper()\n\t\tconst { nodeId, ...mappings } = options.data\n\t\tthis.mappings = mappings\n\t}\n\n\tasync prep({ ctx, logger }: NodeArgs) {\n\t\tfor (const [parentKey, subKey] of Object.entries(this.mappings)) {\n\t\t\tif (ctx.has(subKey)) {\n\t\t\t\tctx.set(parentKey, ctx.get(subKey))\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.warn(`[OutputMapper] Output mapping failed. Key '${subKey}' not found in context.`)\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** A private class used by the builder to represent parallel execution blocks. */\nclass ParallelBranchContainer extends ParallelFlow {\n\t/** A tag to reliably identify this node type in the visualizer. */\n\tpublic readonly isParallelContainer = true\n\tconstructor(public readonly nodesToRun: AbstractNode[]) { super(nodesToRun) }\n}\n\n/**\n * Constructs an executable `Flow` from a declarative `WorkflowGraph` definition.\n * @template TNodeMap A `NodeTypeMap` for validating type-safe graph definitions.\n * @template TContext The shape of the dependency injection context object.\n */\nexport class GraphBuilder<\n\tTNodeMap extends NodeTypeMap,\n\tTContext extends { registry?: any } = object,\n> {\n\tprivate registry: Map<string, new (...args: any[]) => AbstractNode>\n\tprivate subWorkflowNodeTypes: string[]\n\tprivate logger: Logger\n\n\t/**\n\t * @param registry A type-safe object or a `Map` where keys are node `type` strings and\n\t * values are the corresponding `Node` class constructors. For type-safety, use `createNodeRegistry`.\n\t * @param nodeOptionsContext An optional object that is passed to every node's\n\t * constructor, useful for dependency injection (e.g., passing a database client or the builder itself).\n\t */\n\t// type-safe overload\n\tconstructor(registry: TypedNodeRegistry<TNodeMap, TContext>, nodeOptionsContext?: TContext, options?: GraphBuilderOptions, logger?: Logger)\n\t// untyped overload\n\tconstructor(registry: NodeRegistry, nodeOptionsContext?: Record<string, any>, options?: GraphBuilderOptions, logger?: Logger)\n\t// handle both cases\n\tconstructor(\n\t\tregistry: TypedNodeRegistry<TNodeMap, TContext> | NodeRegistry,\n\t\tprivate nodeOptionsContext: TContext | Record<string, any> = {},\n\t\toptions: GraphBuilderOptions = {},\n\t\tlogger: Logger = new NullLogger(),\n\t) {\n\t\tthis.logger = logger\n\t\tif (registry instanceof Map) {\n\t\t\tthis.registry = registry\n\t\t}\n\t\telse {\n\t\t\tthis.registry = new Map(Object.entries(registry))\n\t\t}\n\t\tthis.registry.set('__internal_input_mapper__', InputMappingNode as any)\n\t\tthis.registry.set('__internal_output_mapper__', OutputMappingNode as any)\n\t\tthis.subWorkflowNodeTypes = options.subWorkflowNodeTypes ?? []\n\t}\n\n\tprivate _logMermaid(flow: Flow) {\n\t\tif (!(this.logger instanceof NullLogger)) {\n\t\t\tthis.logger.debug('[GraphBuilder] Flattened Graph')\n\t\t\tconst mermaid = generateMermaidGraph(flow)\n\t\t\tmermaid.split('\\n').forEach(line => this.logger.debug(line))\n\t\t}\n\t}\n\n\tprivate _flattenGraph(graph: WorkflowGraph, idPrefix = ''): WorkflowGraph {\n\t\tconst finalNodes: GraphNode[] = []\n\t\tconst finalEdges: GraphEdge[] = []\n\n\t\tconst localNodeIds = new Set(graph.nodes.map(n => n.id))\n\n\t\t// Pass 1: Recursively add all nodes, inlining sub-workflows and rewriting input paths.\n\t\tfor (const node of graph.nodes) {\n\t\t\tconst prefixedNodeId = `${idPrefix}${node.id}`\n\t\t\tconst isRegisteredSubWorkflow = this.subWorkflowNodeTypes.includes(node.type)\n\t\t\tconst hasWorkflowId = node.data && 'workflowId' in node.data\n\n\t\t\t// Create a mutable copy of node data to safely rewrite input paths.\n\t\t\tconst newNodeData = JSON.parse(JSON.stringify(node.data || {}))\n\n\t\t\tif (newNodeData.inputs) {\n\t\t\t\tconst inputs = newNodeData.inputs as Record<string, string | string[]>\n\t\t\t\tfor (const [templateKey, sourcePathOrPaths] of Object.entries(inputs)) {\n\t\t\t\t\tconst sourcePaths = Array.isArray(sourcePathOrPaths) ? sourcePathOrPaths : [sourcePathOrPaths]\n\t\t\t\t\tconst newSourcePaths = sourcePaths.map((sourcePath) => {\n\t\t\t\t\t\t// If the input source is another node within this same graph file, prefix its ID.\n\t\t\t\t\t\t// Otherwise, leave it as is (it's from a parent context or an initial value).\n\t\t\t\t\t\tif (localNodeIds.has(sourcePath))\n\t\t\t\t\t\t\treturn `${idPrefix}${sourcePath}`\n\n\t\t\t\t\t\treturn sourcePath\n\t\t\t\t\t})\n\t\t\t\t\tinputs[templateKey] = Array.isArray(sourcePathOrPaths) ? newSourcePaths : newSourcePaths[0]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isRegisteredSubWorkflow) {\n\t\t\t\tthis.logger.debug(`[GraphBuilder] Inlining sub-workflow node '${prefixedNodeId}'...`)\n\t\t\t\tconst subWorkflowData = node.data as any\n\t\t\t\tconst subWorkflowId = subWorkflowData.workflowId\n\t\t\t\tconst registry = this.nodeOptionsContext.registry as any\n\t\t\t\tif (!registry || typeof registry.getGraph !== 'function')\n\t\t\t\t\tthrow new Error('GraphBuilder needs a registry with a `getGraph` method in its context to resolve sub-workflows.')\n\n\t\t\t\tconst subGraph: WorkflowGraph | undefined = registry.getGraph(subWorkflowId)\n\t\t\t\tif (!subGraph)\n\t\t\t\t\tthrow new Error(`Sub-workflow with ID ${subWorkflowId} not found in registry.`)\n\n\t\t\t\tthis.logger.debug(`[GraphBuilder] -> Fetched graph for sub-workflow ID: ${subWorkflowId}`)\n\t\t\t\tconst inputMapperId = `${prefixedNodeId}_input_mapper`\n\t\t\t\tconst outputMapperId = `${prefixedNodeId}_output_mapper`\n\t\t\t\tfinalNodes.push({ id: inputMapperId, type: '__internal_input_mapper__', data: subWorkflowData.inputs || {} })\n\t\t\t\tfinalNodes.push({ id: outputMapperId, type: '__internal_output_mapper__', data: subWorkflowData.outputs || {} })\n\n\t\t\t\tconst inlinedSubGraph = this._flattenGraph(subGraph, `${prefixedNodeId}:`)\n\t\t\t\tconst augmentedInlinedNodes = inlinedSubGraph.nodes.map(n => ({ ...n, data: { ...(n.data || {}), isSubWorkflow: true } }))\n\t\t\t\tfinalNodes.push(...augmentedInlinedNodes)\n\t\t\t\tfinalEdges.push(...inlinedSubGraph.edges)\n\n\t\t\t\tconst subGraphStartIds = inlinedSubGraph.nodes.map(n => n.id).filter(id => !inlinedSubGraph.edges.some(e => e.target === id))\n\t\t\t\tfor (const startId of subGraphStartIds)\n\t\t\t\t\tfinalEdges.push({ source: inputMapperId, target: startId, action: DEFAULT_ACTION as any })\n\n\t\t\t\tconst subGraphTerminalIds = inlinedSubGraph.nodes.map(n => n.id).filter(id => !inlinedSubGraph.edges.some(e => e.source === id))\n\t\t\t\tfor (const terminalId of subGraphTerminalIds)\n\t\t\t\t\tfinalEdges.push({ source: terminalId, target: outputMapperId, action: DEFAULT_ACTION as any })\n\t\t\t}\n\t\t\telse if (hasWorkflowId) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`GraphBuilder Error: Node with ID '${node.id}' and type '${node.type}' contains a 'workflowId' property, `\n\t\t\t\t\t+ `but its type is not registered in the 'subWorkflowNodeTypes' option. `\n\t\t\t\t\t+ `Please add '${node.type}' to the subWorkflowNodeTypes array in the GraphBuilder constructor.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Add the normal node with its newly resolved input paths.\n\t\t\t\tfinalNodes.push({ ...node, id: prefixedNodeId, data: newNodeData })\n\t\t\t}\n\t\t}\n\n\t\t// Pass 2: Re-wire all original edges to connect to the correct nodes in the flattened graph.\n\t\tfor (const edge of graph.edges) {\n\t\t\tconst sourceNode = graph.nodes.find(n => n.id === edge.source)!\n\t\t\tconst targetNode = graph.nodes.find(n => n.id === edge.target)!\n\t\t\tconst prefixedSourceId = `${idPrefix}${edge.source}`\n\t\t\tconst prefixedTargetId = `${idPrefix}${edge.target}`\n\n\t\t\tconst isSourceSub = this.subWorkflowNodeTypes.includes(sourceNode.type)\n\t\t\tconst isTargetSub = this.subWorkflowNodeTypes.includes(targetNode.type)\n\n\t\t\tif (isSourceSub && isTargetSub)\n\t\t\t\tfinalEdges.push({ ...edge, source: `${prefixedSourceId}_output_mapper`, target: `${prefixedTargetId}_input_mapper` })\n\t\t\telse if (isSourceSub)\n\t\t\t\tfinalEdges.push({ ...edge, source: `${prefixedSourceId}_output_mapper`, target: prefixedTargetId })\n\t\t\telse if (isTargetSub)\n\t\t\t\tfinalEdges.push({ ...edge, source: prefixedSourceId, target: `${prefixedTargetId}_input_mapper` })\n\t\t\telse\n\t\t\t\tfinalEdges.push({ ...edge, source: prefixedSourceId, target: prefixedTargetId })\n\t\t}\n\t\treturn { nodes: finalNodes, edges: finalEdges }\n\t}\n\n\t/**\n\t * Builds a runnable `Flow` from a graph definition.\n\t * @param graph The `WorkflowGraph` object describing the flow.\n\t * @returns A `BuildResult` object containing the executable `flow` and a `nodeMap`.\n\t */\n\t// type-safe overload\n\tbuild(graph: TypedWorkflowGraph<TNodeMap>): BuildResult\n\t// untyped overload\n\tbuild(graph: WorkflowGraph): BuildResult\n\t// single implementation that handles both cases\n\tbuild(graph: TypedWorkflowGraph<TNodeMap> | WorkflowGraph): BuildResult {\n\t\tconst flatGraph = this._flattenGraph(graph as WorkflowGraph)\n\n\t\tconst nodeMap = new Map<string, AbstractNode>()\n\t\tconst predecessorMap = new Map<string, Set<string>>()\n\t\tfor (const edge of flatGraph.edges) {\n\t\t\tif (!predecessorMap.has(edge.target))\n\t\t\t\tpredecessorMap.set(edge.target, new Set())\n\t\t\tpredecessorMap.get(edge.target)!.add(edge.source)\n\t\t}\n\t\tconst predecessorCountMap = new Map<string, number>()\n\t\tfor (const node of flatGraph.nodes) {\n\t\t\tconst uniquePredecessors = predecessorMap.get(node.id)\n\t\t\tpredecessorCountMap.set(node.id, uniquePredecessors ? uniquePredecessors.size : 0)\n\t\t}\n\n\t\t// Pass 1: Instantiate all nodes.\n\t\tfor (const graphNode of flatGraph.nodes) {\n\t\t\tconst NodeClass = this.registry.get(graphNode.type.toString())\n\t\t\tif (!NodeClass)\n\t\t\t\tthrow new Error(`GraphBuilder: Node type '${graphNode.type.toString()}' not found in the registry.`)\n\n\t\t\tconst nodeOptions = {\n\t\t\t\t...this.nodeOptionsContext,\n\t\t\t\tdata: { ...graphNode.data, nodeId: graphNode.id },\n\t\t\t}\n\t\t\tconst executableNode = new NodeClass(nodeOptions)\n\t\t\t\t.withId(graphNode.id)\n\t\t\t\t.withGraphData(graphNode)\n\t\t\tif (graphNode.config) {\n\t\t\t\tif (executableNode instanceof Node) {\n\t\t\t\t\texecutableNode.maxRetries = graphNode.config.maxRetries ?? executableNode.maxRetries\n\t\t\t\t\texecutableNode.wait = graphNode.config.wait ?? executableNode.wait\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.logger.warn(`[GraphBuilder] Node '${graphNode.id}' has a 'config' block in its definition, but its class '${executableNode.constructor.name}' does not extend 'Node', so retry options cannot be applied.`)\n\t\t\t\t}\n\t\t\t}\n\t\t\tnodeMap.set(graphNode.id, executableNode)\n\t\t}\n\n\t\t// Pass 2: Group all edges by their source and action. This map is the source of truth for wiring.\n\t\tconst edgeGroups = new Map<string, Map<string | typeof DEFAULT_ACTION | typeof FILTER_FAILED, AbstractNode[]>>()\n\t\tfor (const edge of flatGraph.edges) {\n\t\t\tconst sourceId = edge.source\n\t\t\tconst action = edge.action || DEFAULT_ACTION\n\t\t\tconst targetNode = nodeMap.get(edge.target)!\n\n\t\t\tif (!edgeGroups.has(sourceId))\n\t\t\t\tedgeGroups.set(sourceId, new Map())\n\t\t\tconst sourceActions = edgeGroups.get(sourceId)!\n\t\t\tif (!sourceActions.has(action))\n\t\t\t\tsourceActions.set(action, [])\n\t\t\tsourceActions.get(action)!.push(targetNode)\n\t\t}\n\n\t\t// Pass 3: Wire the graph using the grouped edges, creating ParallelFlows where necessary.\n\t\tfor (const [sourceId, actions] of edgeGroups.entries()) {\n\t\t\tconst sourceNode = nodeMap.get(sourceId)!\n\t\t\tfor (const [action, successors] of actions.entries()) {\n\t\t\t\tif (successors.length === 1) {\n\t\t\t\t\t// Simple 1-to-1 connection.\n\t\t\t\t\tsourceNode.next(successors[0], action)\n\t\t\t\t}\n\t\t\t\telse if (successors.length > 1) {\n\t\t\t\t\t// Fan-out detected. Use our named container.\n\t\t\t\t\tconst parallelNode = new ParallelBranchContainer(successors)\n\t\t\t\t\tsourceNode.next(parallelNode, action)\n\n\t\t\t\t\tconst convergenceNode = this._findConvergenceNode(successors, edgeGroups)\n\t\t\t\t\tif (convergenceNode)\n\t\t\t\t\t\tparallelNode.next(convergenceNode)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Final Step: Determine the start node(s) for the entire flow.\n\t\tconst allNodeIds = Array.from(nodeMap.keys())\n\t\tconst allTargetIds = new Set(flatGraph.edges.map(e => e.target))\n\t\tconst startNodeIds = allNodeIds.filter(id => !allTargetIds.has(id))\n\n\t\tif (startNodeIds.length === 0 && allNodeIds.length > 0)\n\t\t\tthrow new Error('GraphBuilder: This graph has a cycle and no clear start node.')\n\n\t\tif (startNodeIds.length === 1) {\n\t\t\tconst startNode = nodeMap.get(startNodeIds[0])!\n\t\t\tconst flow = new Flow(startNode)\n\t\t\tconst predecessorIdMap = this._createPredecessorIdMap(flatGraph)\n\t\t\tthis._logMermaid(flow)\n\t\t\treturn { flow, nodeMap, predecessorCountMap, predecessorIdMap }\n\t\t}\n\n\t\t// Handle parallel start nodes.\n\t\tconst startNodes = startNodeIds.map(id => nodeMap.get(id)!)\n\t\tconst parallelStartNode = new ParallelBranchContainer(startNodes)\n\n\t\tif (startNodes.length > 1) {\n\t\t\tconst convergenceNode = this._findConvergenceNode(startNodes, edgeGroups)\n\t\t\tif (convergenceNode)\n\t\t\t\tparallelStartNode.next(convergenceNode)\n\t\t}\n\n\t\tconst flow = new Flow(parallelStartNode)\n\t\tconst predecessorIdMap = this._createPredecessorIdMap(flatGraph)\n\t\tthis._logMermaid(flow)\n\t\treturn { flow, nodeMap, predecessorCountMap, predecessorIdMap }\n\t}\n\n\t/**\n\t * Creates a map of each node ID to an array of its direct predecessor node IDs.\n\t * This is a helper for executors that need to know a node's direct inputs.\n\t * @param graph The flattened workflow graph.\n\t * @returns A map where each key is a node ID and the value is an array of its predecessor IDs.\n\t * @private\n\t */\n\tprivate _createPredecessorIdMap(graph: WorkflowGraph): Map<string, string[]> {\n\t\tconst map = new Map<string, string[]>()\n\t\tfor (const edge of graph.edges) {\n\t\t\tif (!map.has(edge.target))\n\t\t\t\tmap.set(edge.target, [])\n\t\t\tmap.get(edge.target)!.push(edge.source)\n\t\t}\n\t\treturn map\n\t}\n\n\t/**\n\t * Finds the first node where all parallel branches converge.\n\t * Uses a Breadth-First Search to guarantee finding the nearest convergence point.\n\t * @param parallelNodes - The set of nodes running in parallel.\n\t * @param edgeGroups - The map of all graph edges.\n\t * @returns The convergence node, or undefined if they never converge.\n\t * @private\n\t */\n\tprivate _findConvergenceNode(\n\t\tparallelNodes: AbstractNode[],\n\t\tedgeGroups: Map<string, Map<any, AbstractNode[]>>,\n\t): AbstractNode | undefined {\n\t\tif (parallelNodes.length <= 1)\n\t\t\treturn undefined\n\n\t\tconst queue: string[] = parallelNodes.map(n => String(n.id!))\n\t\t// Map<nodeId, Set<parallelNodeId>>\n\t\tconst visitedBy = new Map<string, Set<string>>()\n\t\tparallelNodes.forEach(n => visitedBy.set(String(n.id!), new Set([String(n.id!)])))\n\n\t\tlet head = 0\n\t\twhile (head < queue.length) {\n\t\t\tconst currentId = queue[head++]!\n\t\t\tconst successors = Array.from(edgeGroups.get(currentId)?.values() ?? []).flat()\n\n\t\t\tfor (const successor of successors) {\n\t\t\t\tconst successorId = String(successor.id!)\n\t\t\t\tif (!visitedBy.has(successorId))\n\t\t\t\t\tvisitedBy.set(successorId, new Set())\n\n\t\t\t\tconst visitorSet = visitedBy.get(successorId)!\n\t\t\t\tconst startingPointsVistingThisNode = visitedBy.get(currentId)!\n\n\t\t\t\tfor (const startNodeId of startingPointsVistingThisNode)\n\t\t\t\t\tvisitorSet.add(startNodeId)\n\n\t\t\t\tif (visitorSet.size === parallelNodes.length) {\n\t\t\t\t\t// This is the first node visited by paths from ALL parallel branches.\n\t\t\t\t\tthis.logger.debug(`[GraphBuilder] Found convergence node: ${successorId}`)\n\t\t\t\t\treturn successor\n\t\t\t\t}\n\n\t\t\t\tif (!queue.includes(successorId))\n\t\t\t\t\tqueue.push(successorId)\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.warn('[GraphBuilder] Parallel branches do not seem to converge.')\n\t\treturn undefined\n\t}\n}\n","import type { Context, ContextTransform } from './context'\nimport type { NodeArgs, Params } from './types'\nimport type { Flow, Node } from './workflow'\nimport { SequenceFlow } from './builder/patterns'\nimport { composeContext } from './context'\nimport { Node as BaseNode } from './workflow'\n\n/**\n * A type for a pure function that can be executed within a `Node`,\n * typically taking the node's `params` as input.\n * @template TIn The input type, corresponding to `params`.\n * @template TOut The output type, which becomes the node's `execRes`.\n */\nexport type NodeFunction<TIn = any, TOut = any> = (input: TIn) => TOut | Promise<TOut>\n\n/**\n * A type for a function that operates on the shared `Context` in addition\n * to the node's `params`.\n * @template TIn The input type, corresponding to `params`.\n * @template TOut The output type, which becomes the node's `execRes`.\n */\nexport type ContextFunction<TIn = any, TOut = any> = (ctx: Context, input: TIn) => TOut | Promise<TOut>\n\n/**\n * Creates a `Node` from a simple, pure function that transforms an input to an output.\n * The node's `params` object is passed as the input to the function.\n *\n * @example\n * const add = (n: number) => mapNode<{ value: number }, number>(params => params.value + n)\n * const add5Node = add(5) // A reusable node that adds 5 to its input parameter.\n *\n * @param fn A function that takes an input object and returns a result.\n * @returns A new `Node` instance that wraps the function.\n */\nexport function mapNode<TIn extends Params, TOut>(fn: NodeFunction<TIn, TOut>): Node<void, TOut, any, TIn> {\n\treturn new class extends BaseNode<void, TOut, any, TIn> {\n\t\tasync exec({ params }: NodeArgs<void, void, TIn>): Promise<TOut> {\n\t\t\treturn fn(params as TIn)\n\t\t}\n\t}()\n}\n\n/**\n * Creates a `Node` from a function that requires access to the shared `Context`.\n * Both the `Context` and the node's `params` are passed as arguments to the function.\n *\n * @example\n * const greeter = contextNode((ctx, params: { name: string }) => {\n * const language = ctx.get(LANGUAGE_KEY) || 'en'\n * return language === 'en' ? `Hello, ${params.name}` : `Hola, ${params.name}`\n * })\n *\n * @param fn A function that takes the context and an input object, and returns a result.\n * @returns A new `Node` instance that wraps the function.\n */\nexport function contextNode<TIn extends Params, TOut>(fn: ContextFunction<TIn, TOut>): Node<void, TOut, any, TIn> {\n\treturn new class extends BaseNode<void, TOut, any, TIn> {\n\t\tasync exec({ ctx, params }: NodeArgs<void, void, TIn>): Promise<TOut> {\n\t\t\treturn fn(ctx, params as TIn)\n\t\t}\n\t}()\n}\n\n/**\n * Creates a `Node` that declaratively applies a series of transformations to the `Context`.\n * This is a \"side-effect\" node used purely for state management; its logic runs in the `prep` phase,\n * and it does not produce an `exec` output.\n *\n * @example\n * const USER_ID = contextKey<string>('user_id')\n * const userLens = lens(USER_ID)\n * const setupUserContext = (userId: string) => transformNode(userLens.set(userId))\n *\n * @param transforms A sequence of `ContextTransform` functions (e.g., from a lens) to apply.\n * @returns A new `Node` instance that will mutate the context when executed.\n */\nexport function transformNode(...transforms: ContextTransform[]): Node {\n\treturn new class extends BaseNode {\n\t\tasync prep({ ctx }: NodeArgs) {\n\t\t\t// Apply the composed transformations directly to the mutable context.\n\t\t\tcomposeContext(...transforms)(ctx)\n\t\t}\n\t}()\n}\n\n/**\n * A functional-style alias for `SequenceFlow`. It constructs a linear workflow\n * where each node executes in the order it is provided.\n *\n * @example\n * const mathPipeline = pipeline(addNode(5), multiplyNode(2))\n *\n * @param nodes A sequence of `Node` instances to chain together.\n * @returns A `Flow` instance representing the linear sequence.\n */\nexport function pipeline(...nodes: Node[]): Flow {\n\treturn new SequenceFlow(...nodes)\n}\n\n/**\n * A classic functional composition utility. It takes two functions, `f` and `g`,\n * and returns a new function that computes `f(g(x))`.\n *\n * This is a general-purpose helper, not a `Node` builder itself, but it can be\n * used to create more complex `NodeFunction`s to pass to `mapNode`.\n *\n * @example\n * const add5 = (x: number) => x + 5\n * const multiply2 = (x: number) => x * 2\n * const add5ThenMultiply2 = compose(multiply2, add5) // equivalent to: x => (x + 5) * 2\n *\n * @param f The outer function, which receives the result of `g`.\n * @param g The inner function, which receives the initial input.\n * @returns A new `NodeFunction` that combines both operations.\n */\nexport function compose<A, B, C>(f: NodeFunction<B, C>, g: NodeFunction<A, B>): NodeFunction<A, C> {\n\treturn async (input: A) => f(await g(input))\n}\n"],"mappings":"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","names":["AbortError","message","WorkflowError","nodeName","phase","originalError","combinedMessage","FatalWorkflowError","NullLogger","levelPriorities","ConsoleLogger","options","level","message","context","fullMessage","applyMiddleware","middleware","nodeToRun","runNode","args","next","mw","InMemoryExecutor","startNode","flowMiddleware","context","options","currentNode","nextNode","action","logger","signal","AbortError","nodeArgs","applyMiddleware","flow","_a","NullLogger","combinedParams","internalOptions","curr","actionDisplay","DEFAULT_ACTION","FILTER_FAILED","isNodeType","type","node","analyzeGraph","graph","typedGraph","analysis","allNodeIds","adj","edge","source","target","id","visited","recursionStack","detectCycleUtil","nodeId","path","neighbors","neighbor","cycleStartIndex","cycle","createNodeRule","description","filter","check","_graph","errors","result","checkForCycles","uniqueCycles","c","cycleKey","representativeCycle","getActionLabel","action","DEFAULT_ACTION","FILTER_FAILED","getNodeLabel","node","uniqueId","type","id","getUniqueNodeId","nameCounts","idMap","baseName","sanitizedBaseName","count","generateMermaidGraph","flow","nodes","edges","visited","queue","currentNode","sourceId","container","internalNode","targetId","successorNode","label","edge","sleep","ms","signal","resolve","reject","AbortError","timeoutId","AbstractNode","id","data","params","node","action","DEFAULT_ACTION","Node","_Node","options","phase","AbortError","WorkflowError","args","_a","_b","lastError","curRetry","e","error","FatalWorkflowError","sleep","ctx","signal","logger","executor","Flow","prepRes","execRes","actionDisplay","NullLogger","InMemoryExecutor","fn","originalNode","maxRetries","wait","originalResult","_args","key","predicate","result","FILTER_FAILED","lens","value","start","combinedParams","internalOptions","finalAction","queue","visited","currentNode","successor","contextKey","description","TypedContext","initialData","key","value","lens","ctx","fn","composeContext","transforms","acc","transform","SequenceFlow","Flow","nodes","current","i","ParallelFlow","nodesToRun","ctx","params","signal","logger","executor","promises","node","result","BatchFlow","_args","args","_a","combinedParams","batchParamsIterable","batchParamsList","batchParams","AbortError","ParallelBatchFlow","results","mapCollection","items","fn","item","filterCollection","predicate","_","index","reduceCollection","reducer","initialValue","accumulator","createNodeRegistry","registry","InputMappingNode","Node","options","nodeId","mappings","ctx","logger","subKey","parentKey","OutputMappingNode","ParallelBranchContainer","ParallelFlow","nodesToRun","GraphBuilder","nodeOptionsContext","NullLogger","flow","generateMermaidGraph","line","graph","idPrefix","finalNodes","finalEdges","localNodeIds","n","node","prefixedNodeId","isRegisteredSubWorkflow","hasWorkflowId","newNodeData","inputs","templateKey","sourcePathOrPaths","newSourcePaths","sourcePath","subWorkflowData","subWorkflowId","subGraph","inputMapperId","outputMapperId","inlinedSubGraph","augmentedInlinedNodes","subGraphStartIds","id","e","startId","DEFAULT_ACTION","subGraphTerminalIds","terminalId","edge","sourceNode","targetNode","prefixedSourceId","prefixedTargetId","isSourceSub","isTargetSub","flatGraph","nodeMap","predecessorMap","predecessorCountMap","uniquePredecessors","graphNode","NodeClass","nodeOptions","executableNode","edgeGroups","sourceId","action","sourceActions","actions","successors","parallelNode","convergenceNode","allNodeIds","allTargetIds","startNodeIds","startNode","Flow","predecessorIdMap","startNodes","parallelStartNode","map","parallelNodes","_a","queue","visitedBy","head","currentId","successor","successorId","visitorSet","startingPointsVistingThisNode","startNodeId","mapNode","fn","Node","params","contextNode","ctx","transformNode","transforms","composeContext","pipeline","nodes","SequenceFlow","compose","f","g","input"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/logger.ts","../src/utils/middleware.ts","../src/executors/in-memory.ts","../src/types.ts","../src/utils/analysis.ts","../src/utils/mermaid.ts","../src/utils/sanitize.ts","../src/utils/sleep.ts","../src/workflow.ts","../src/context.ts","../src/builder/patterns.ts","../src/builder/graph.ts","../src/functions.ts"],"sourcesContent":["/**\n * Error thrown when a workflow is gracefully aborted via an `AbortSignal`.\n * This error is caught by the execution engine to halt the flow.\n */\nexport class AbortError extends Error {\n\tconstructor(message = 'Workflow aborted') {\n\t\tsuper(message)\n\t\tthis.name = 'AbortError'\n\t}\n}\n\n/**\n * A custom error class for failures within a workflow, providing additional\n * context about where and when the error occurred.\n */\nexport class WorkflowError extends Error {\n\t/**\n\t * @param message The error message.\n\t * @param nodeName The name of the `Node` class where the error occurred.\n\t * @param phase The lifecycle phase (`'prep'`, `'exec'`, or `'post'`) where the error was thrown.\n\t * @param originalError The underlying error that was caught and wrapped.\n\t */\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly nodeName: string,\n\t\tpublic readonly phase: 'prep' | 'exec' | 'post',\n\t\tpublic readonly originalError?: Error,\n\t) {\n\t\tconst combinedMessage = originalError\n\t\t\t? `${message}: ${originalError.message}`\n\t\t\t: message\n\n\t\tsuper(combinedMessage)\n\t\tthis.name = 'WorkflowError'\n\t\tif (originalError?.stack)\n\t\t\tthis.stack = `${this.stack}\\nCaused by: ${originalError.stack}`\n\t}\n}\n\n/**\n * An error thrown by a node to indicate a non-recoverable failure.\n *\n * When an executor catches this error, it should immediately terminate the\n * entire workflow run, bypassing any remaining retries, fallbacks, or\n * subsequent nodes in the graph.\n */\nexport class FatalWorkflowError extends WorkflowError {\n\tconstructor(\n\t\tmessage: string,\n\t\tnodeName: string,\n\t\tphase: 'prep' | 'exec' | 'post',\n\t\toriginalError?: Error,\n\t) {\n\t\tsuper(message, nodeName, phase, originalError)\n\t\tthis.name = 'FatalWorkflowError'\n\t}\n}\n","/**\n * Defines the interface for a logger that can be used by the workflow engine.\n * This allows for plugging in any logging library (e.g., Pino, Winston).\n */\nexport interface Logger {\n\tdebug: (message: string, context?: object) => void\n\tinfo: (message: string, context?: object) => void\n\twarn: (message: string, context?: object) => void\n\terror: (message: string, context?: object) => void\n}\n\n/**\n * A logger implementation that performs no action (a \"no-op\" logger).\n * This is the default logger used by the framework if none is provided,\n * making Flowcraft silent out-of-the-box.\n */\nexport class NullLogger implements Logger {\n\tdebug() { /* no-op */ }\n\tinfo() { /* no-op */ }\n\twarn() { /* no-op */ }\n\terror() { /* no-op */ }\n}\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\nconst levelPriorities: Record<LogLevel, number> = {\n\tdebug: 1,\n\tinfo: 2,\n\twarn: 3,\n\terror: 4,\n}\n\n/**\n * A default logger implementation that writes messages to the `console`.\n * It supports a minimum log level to control verbosity.\n */\nexport class ConsoleLogger implements Logger {\n\tprivate minLevel: LogLevel\n\n\t/**\n\t * @param options Configuration for the logger.\n\t * @param options.level The minimum level of messages to log. Defaults to 'info'.\n\t */\n\tconstructor(options: { level?: LogLevel } = {}) {\n\t\tthis.minLevel = options.level ?? 'info'\n\t}\n\n\tprivate log(level: LogLevel, message: string, context?: object) {\n\t\tif (levelPriorities[level] < levelPriorities[this.minLevel]) {\n\t\t\treturn\n\t\t}\n\n\t\tconst fullMessage = `[${level.toUpperCase()}] ${message}`\n\t\tif (context && Object.keys(context).length > 0) {\n\t\t\tconst logMethod = console[level] || console.log\n\t\t\tlogMethod(fullMessage, context)\n\t\t}\n\t\telse {\n\t\t\tconst logMethod = console[level] || console.log\n\t\t\tlogMethod(fullMessage)\n\t\t}\n\t}\n\n\tdebug(message: string, context?: object) { this.log('debug', message, context) }\n\tinfo(message: string, context?: object) { this.log('info', message, context) }\n\twarn(message: string, context?: object) { this.log('warn', message, context) }\n\terror(message: string, context?: object) { this.log('error', message, context) }\n}\n","import type { Middleware, MiddlewareNext, NodeArgs } from '../types'\nimport type { AbstractNode } from '../workflow'\n\n/**\n * Composes a chain of middleware functions around a node's execution.\n * @internal\n */\nexport function applyMiddleware<T = any>(middleware: Middleware<T>[], nodeToRun: AbstractNode): MiddlewareNext<T> {\n\t// The final function in the chain is the actual execution of the node.\n\tconst runNode: MiddlewareNext<T> = (args: NodeArgs) => {\n\t\treturn nodeToRun._run({\n\t\t\tctx: args.ctx,\n\t\t\tparams: { ...args.params, ...nodeToRun.params },\n\t\t\tsignal: args.signal,\n\t\t\tlogger: args.logger,\n\t\t\texecutor: args.executor,\n\t\t})\n\t}\n\n\tif (!middleware || middleware.length === 0)\n\t\treturn runNode\n\n\t// Build the chain backwards, so the first middleware in the array is the outermost.\n\treturn middleware.reduceRight<MiddlewareNext<T>>(\n\t\t(next, mw) => (args: NodeArgs) => mw(args, next),\n\t\trunNode,\n\t)\n}\n","import type { Context } from '../context'\nimport type { Logger } from '../logger'\nimport type { Middleware, NodeArgs, RunOptions } from '../types'\nimport type { AbstractNode, Flow } from '../workflow'\nimport type { IExecutor, InternalRunOptions } from './types'\nimport { AbortError } from '../errors'\nimport { NullLogger } from '../logger'\nimport { applyMiddleware } from '../utils/middleware'\n\n/**\n * The default executor that runs a workflow within a single, in-memory process.\n * This class contains the core logic for traversing a workflow graph, applying middleware,\n * and handling node execution.\n */\nexport class InMemoryExecutor implements IExecutor {\n\t/**\n\t * A stateless, reusable method that orchestrates the traversal of a graph.\n\t * It is called by `run()` for top-level flows and by `Flow.exec()` for sub-flows.\n\t * @param startNode The node where the graph traversal begins.\n\t * @param flowMiddleware The middleware array from the containing flow.\n\t * @param context The shared workflow context.\n\t * @param options The internal, normalized run options.\n\t * @returns The final action from the last executed node in the graph.\n\t * @internal\n\t */\n\tpublic async _orch<T = any>(\n\t\tstartNode: AbstractNode,\n\t\tflowMiddleware: Middleware[],\n\t\tcontext: Context,\n\t\toptions: InternalRunOptions,\n\t): Promise<T> {\n\t\tlet currentNode: AbstractNode | undefined = startNode\n\t\tlet nextNode: AbstractNode | undefined\n\t\tlet action: any\n\n\t\tconst { logger, signal } = options\n\n\t\twhile (currentNode) {\n\t\t\tif (signal?.aborted)\n\t\t\t\tthrow new AbortError()\n\n\t\t\tconst nodeArgs: NodeArgs = {\n\t\t\t\tctx: context,\n\t\t\t\tparams: { ...options.params, ...currentNode.params },\n\t\t\t\tsignal,\n\t\t\t\tlogger,\n\t\t\t\tprepRes: undefined,\n\t\t\t\texecRes: undefined,\n\t\t\t\tname: currentNode.constructor.name,\n\t\t\t\texecutor: options.executor,\n\t\t\t}\n\n\t\t\tconst chain = applyMiddleware(flowMiddleware, currentNode)\n\t\t\taction = await chain(nodeArgs)\n\t\t\tnextNode = this.getNextNode(currentNode, action, logger)\n\n\t\t\tif (!nextNode)\n\t\t\t\treturn action as T\n\n\t\t\tcurrentNode = nextNode\n\t\t}\n\n\t\treturn undefined as T\n\t}\n\n\t/**\n\t * Executes a given flow with a specific context and options.\n\t * This is the main entry point for the in-memory execution engine.\n\t * @param flow The Flow instance to execute.\n\t * @param context The shared context for the workflow.\n\t * @param options Runtime options, including a logger, abort controller, or initial params.\n\t * @returns A promise that resolves with the final action of the workflow.\n\t */\n\tpublic run<T>(flow: Flow<any, T>, context: Context, options?: RunOptions): Promise<T>\n\tpublic run(flow: Flow, context: Context, options?: RunOptions): Promise<any>\n\tpublic async run<T>(flow: Flow<any, T>, context: Context, options?: RunOptions): Promise<T> {\n\t\tconst logger = options?.logger ?? new NullLogger()\n\t\tconst combinedParams = { ...flow.params, ...options?.params }\n\n\t\tconst internalOptions: InternalRunOptions = {\n\t\t\tlogger,\n\t\t\tsignal: options?.signal ?? options?.controller?.signal,\n\t\t\tparams: combinedParams,\n\t\t\texecutor: this,\n\t\t}\n\n\t\t// Handle \"logic-bearing\" flows (e.g., BatchFlow) that don't have a graph.\n\t\t// Their logic is self-contained in their `exec` method.\n\t\tif (!flow.startNode) {\n\t\t\tlogger.info(`Executor is running a logic-bearing flow: ${flow.constructor.name}`)\n\t\t\tconst chain = applyMiddleware(flow.middleware, flow)\n\t\t\treturn await chain({\n\t\t\t\t...internalOptions,\n\t\t\t\tctx: context,\n\t\t\t\tprepRes: undefined,\n\t\t\t\texecRes: undefined,\n\t\t\t\tname: flow.constructor.name,\n\t\t\t})\n\t\t}\n\n\t\tlogger.info(`Executor is running flow graph: ${flow.constructor.name}`)\n\t\t// Delegate the graph traversal to our new stateless helper.\n\t\t// Pass the flow's own middleware to be applied to its nodes.\n\t\treturn this._orch<T>(flow.startNode, flow.middleware, context, internalOptions)\n\t}\n\n\t/**\n\t * Determines the next node to execute based on the action returned by the current node.\n\t * @internal\n\t */\n\tpublic getNextNode(curr: AbstractNode, action: any, logger: Logger): AbstractNode | undefined {\n\t\tconst nextNode = curr.successors.get(action)\n\t\tconst actionDisplay = typeof action === 'symbol' ? action.toString() : action\n\n\t\tif (nextNode) {\n\t\t\tlogger.debug(`Action '${actionDisplay}' from ${curr.constructor.name} leads to ${nextNode.constructor.name}`, { action })\n\t\t}\n\t\telse if (curr.successors.size > 0 && action !== undefined && action !== null) {\n\t\t\tlogger.debug(`Flow ends: Action '${actionDisplay}' from ${curr.constructor.name} has no configured successor.`)\n\t\t}\n\t\treturn nextNode\n\t}\n}\n","import type { Context } from './context'\nimport type { IExecutor } from './executors/types'\nimport type { Logger } from './logger'\n\n/** A generic type for key-value parameters. */\nexport type Params = Record<string, any>\n\n/** The default action returned by a node for linear progression. */\nexport const DEFAULT_ACTION = Symbol('default')\n\n/** The action returned by a `.filter()` node when the predicate fails. */\nexport const FILTER_FAILED = Symbol('filter_failed')\n\n/**\n * The standard arguments object passed to a node's lifecycle methods.\n * @template PrepRes The type of the `prepRes` property.\n * @template ExecRes The type of the `execRes` property.\n * @template TParams The type for the node's static parameters.\n */\nexport interface NodeArgs<PrepRes = any, ExecRes = any, TParams extends Params = Params> {\n\t/** The shared, mutable context for the workflow run. */\n\tctx: Context\n\t/** The static parameters for the node, merged from the node and flow's `withParams`. */\n\tparams: TParams\n\t/** An `AbortController` to gracefully cancel the workflow. */\n\tcontroller?: AbortController\n\t/** An `AbortSignal` for handling cancellation. */\n\tsignal?: AbortSignal\n\t/** The logger instance for the workflow run. */\n\tlogger: Logger\n\t/** The result of the `prep` phase. */\n\tprepRes: PrepRes\n\t/** The result of the `exec` phase. */\n\texecRes: ExecRes\n\t/** The final error object, available only in `execFallback`. */\n\terror?: Error\n\t/** The name of the Node's constructor, for logging. */\n\tname?: string\n\t/** A reference to the current `IExecutor` running the flow. */\n\texecutor?: IExecutor\n}\n\n/**\n * The context object passed to a node's internal `_run` method.\n * @internal\n */\nexport interface NodeRunContext {\n\tctx: Context\n\tparams: Params\n\tsignal?: AbortSignal\n\tlogger: Logger\n\texecutor?: IExecutor\n}\n\n/** Options for configuring a `Node` instance. */\nexport interface NodeOptions {\n\t/** The total number of times the `exec` phase will be attempted. Defaults to `1`. */\n\tmaxRetries?: number\n\t/** The time in milliseconds to wait between failed `exec` attempts. Defaults to `0`. */\n\twait?: number\n}\n\n/** Options for running a top-level `Flow`. */\nexport interface RunOptions {\n\t/** An `AbortController` to gracefully cancel the workflow. */\n\tcontroller?: AbortController\n\t/** An `AbortSignal` for handling cancellation. */\n\tsignal?: AbortSignal\n\t/** A `Logger` instance to receive logs from the execution engine. */\n\tlogger?: Logger\n\t/** Top-level parameters to be merged into the context for the entire run. */\n\tparams?: Params\n\t/** A custom `IExecutor` instance to run the workflow. Defaults to `InMemoryExecutor`. */\n\texecutor?: IExecutor\n}\n\n/** The function signature for the `next` function passed to middleware. */\nexport type MiddlewareNext<T = any> = (args: NodeArgs) => Promise<T>\n/** The function signature for a middleware function. */\nexport type Middleware<T = any> = (args: NodeArgs, next: MiddlewareNext<T>) => Promise<T>\n","import type { GraphNode, NodeTypeMap, TypedGraphNode, TypedWorkflowGraph, WorkflowGraph } from '../builder/graph.types'\n\n/** The rich metadata object returned by the analyzeGraph function. */\nexport interface GraphAnalysis<T extends NodeTypeMap = any> {\n\t/** A map of all nodes, keyed by ID, augmented with their connection degrees. */\n\tnodes: Map<string, TypedGraphNode<T> & { inDegree: number, outDegree: number }>\n\t/** An array of all node IDs in the graph. */\n\tallNodeIds: string[]\n\t/** An array of node IDs that have no incoming edges. */\n\tstartNodeIds: string[]\n\t/** A list of cycles found in the graph. Each cycle is an array of node IDs. */\n\tcycles: string[][]\n}\n\n/** A standard structure for reporting a single validation error. */\nexport interface ValidationError {\n\t/** The ID of the node where the error occurred, if applicable. */\n\tnodeId?: string\n\t/** A category for the error, e.g., 'CycleDetected', 'ConnectionRuleViolation'. */\n\ttype: string\n\t/** A human-readable message explaining the validation failure. */\n\tmessage: string\n}\n\n/**\n * A function that takes a graph analysis and the original graph,\n * and returns an array of validation errors.\n */\nexport type Validator<T extends NodeTypeMap = any> = (\n\tanalysis: GraphAnalysis<T>,\n\tgraph: TypedWorkflowGraph<T>\n) => ValidationError[]\n\n/**\n * A helper function that creates a type guard for filtering nodes by their type.\n * This simplifies writing type-safe validation rules by removing the need for\n * verbose, explicit type guard syntax.\n *\n * @param type The literal string of the node type to check for.\n * @returns A type guard function that narrows the node to its specific type.\n */\nexport function isNodeType<T extends NodeTypeMap, K extends keyof T>(type: K) {\n\treturn (node: TypedGraphNode<T>): node is TypedGraphNode<T> & { type: K } => {\n\t\treturn node.type === type\n\t}\n}\n\n/**\n * Analyzes a declarative workflow graph definition to extract structural metadata.\n * This is a lightweight, static utility that does not instantiate any nodes.\n *\n * @param graph The WorkflowGraph object containing nodes and edges.\n * @returns A GraphAnalysis object containing nodes with degree counts, start nodes, and any cycles.\n */\n// (Typesafe Overload) Analyzes a declarative workflow graph, preserving strong types.\nexport function analyzeGraph<T extends NodeTypeMap>(graph: TypedWorkflowGraph<T>): GraphAnalysis<T>\n// (Untyped Overload) Analyzes a declarative workflow graph with basic types.\nexport function analyzeGraph(graph: WorkflowGraph): GraphAnalysis\n// (Implementation) Analyzes a declarative workflow graph to extract structural metadata.\nexport function analyzeGraph<T extends NodeTypeMap>(graph: TypedWorkflowGraph<T> | WorkflowGraph): GraphAnalysis<T> {\n\tconst typedGraph = graph as TypedWorkflowGraph<T> // Cast for internal consistency\n\tconst analysis: GraphAnalysis<T> = {\n\t\tnodes: new Map(),\n\t\tallNodeIds: [],\n\t\tstartNodeIds: [],\n\t\tcycles: [],\n\t}\n\n\tif (!typedGraph || !typedGraph.nodes || !typedGraph.nodes.length)\n\t\treturn analysis\n\n\tconst allNodeIds = typedGraph.nodes.map(node => node.id)\n\tanalysis.allNodeIds = allNodeIds\n\n\tconst adj: Map<string, string[]> = new Map()\n\ttypedGraph.nodes.forEach((node) => {\n\t\tanalysis.nodes.set(node.id, { ...node, inDegree: 0, outDegree: 0 })\n\t\tadj.set(node.id, [])\n\t})\n\n\ttypedGraph.edges.forEach((edge) => {\n\t\tconst source = analysis.nodes.get(edge.source)\n\t\tconst target = analysis.nodes.get(edge.target)\n\t\tif (source)\n\t\t\tsource.outDegree++\n\t\tif (target)\n\t\t\ttarget.inDegree++\n\t\tif (adj.has(edge.source))\n\t\t\tadj.get(edge.source)!.push(edge.target)\n\t})\n\n\tanalysis.startNodeIds = allNodeIds.filter(id => analysis.nodes.get(id)!.inDegree === 0)\n\n\tconst visited = new Set<string>()\n\tconst recursionStack = new Set<string>()\n\tfunction detectCycleUtil(nodeId: string, path: string[]) {\n\t\tvisited.add(nodeId)\n\t\trecursionStack.add(nodeId)\n\t\tpath.push(nodeId)\n\n\t\tconst neighbors = adj.get(nodeId) || []\n\t\tfor (const neighbor of neighbors) {\n\t\t\tif (recursionStack.has(neighbor)) {\n\t\t\t\tconst cycleStartIndex = path.indexOf(neighbor)\n\t\t\t\tconst cycle = path.slice(cycleStartIndex)\n\t\t\t\tanalysis.cycles.push([...cycle, neighbor])\n\t\t\t}\n\t\t\telse if (!visited.has(neighbor)) {\n\t\t\t\tdetectCycleUtil(neighbor, path)\n\t\t\t}\n\t\t}\n\n\t\trecursionStack.delete(nodeId)\n\t\tpath.pop()\n\t}\n\n\tfor (const nodeId of allNodeIds) {\n\t\tif (!visited.has(nodeId))\n\t\t\tdetectCycleUtil(nodeId, [])\n\t}\n\n\treturn analysis\n}\n\n/**\n * Factory for creating a generic, reusable validator that checks node properties.\n *\n * @param description A human-readable description of the rule for error messages.\n * @param filter A predicate to select which nodes this rule applies to.\n * @param check A function that validates the properties of a selected node.\n * @returns A Validator function.\n */\n// (Type-Safe Overload) Creates a validator with strong types based on a NodeTypeMap.\nexport function createNodeRule<T extends NodeTypeMap>(\n\tdescription: string,\n\tfilter: (node: TypedGraphNode<T>) => boolean,\n\tcheck: (node: TypedGraphNode<T> & { inDegree: number, outDegree: number }) => { valid: boolean, message?: string },\n): Validator<T>\n// (Untyped Overload) Creates a validator with basic types.\nexport function createNodeRule(\n\tdescription: string,\n\tfilter: (node: GraphNode) => boolean,\n\tcheck: (node: GraphNode & { inDegree: number, outDegree: number }) => { valid: boolean, message?: string },\n): Validator\n// (Implementation) Factory for creating a generic, reusable validator.\nexport function createNodeRule(\n\tdescription: string,\n\tfilter: (node: any) => boolean,\n\tcheck: (node: any) => { valid: boolean, message?: string },\n): Validator {\n\treturn (analysis: GraphAnalysis, _graph: WorkflowGraph): ValidationError[] => {\n\t\tconst errors: ValidationError[] = []\n\t\tfor (const node of analysis.nodes.values()) {\n\t\t\tif (filter(node)) {\n\t\t\t\tconst result = check(node)\n\t\t\t\tif (!result.valid) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\t\ttype: 'ConnectionRuleViolation',\n\t\t\t\t\t\tmessage: result.message || `Node ${node.id} failed rule: ${description}`,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn errors\n\t}\n}\n\n/**\n * A built-in validator that reports any cycles found in the graph.\n */\nexport const checkForCycles: Validator = (analysis) => {\n\tconst uniqueCycles = new Set(analysis.cycles.map(c => c.slice(0, -1).sort().join(',')))\n\treturn Array.from(uniqueCycles).map((cycleKey) => {\n\t\tconst representativeCycle = analysis.cycles.find(c => c.slice(0, -1).sort().join(',') === cycleKey)!\n\t\treturn {\n\t\t\tnodeId: representativeCycle[0],\n\t\t\ttype: 'CycleDetected',\n\t\t\tmessage: `Cycle detected involving nodes: ${representativeCycle.join(' -> ')}`,\n\t\t}\n\t})\n}\n","import type { AbstractNode, Flow } from '../workflow'\nimport { DEFAULT_ACTION, FILTER_FAILED } from '../types'\n\n/**\n * Converts a special action symbol to a user-friendly string for the graph label.\n * @param action The action symbol or string.\n * @returns A string label for the Mermaid edge.\n */\nfunction getActionLabel(action: string | symbol): string {\n\tif (action === DEFAULT_ACTION)\n\t\treturn ''\n\n\tif (action === FILTER_FAILED)\n\t\treturn '\"filter failed\"'\n\n\t// Sanitize labels to prevent breaking Mermaid syntax\n\tconst sanitizedAction = action.toString().replace(/\"/g, '')\n\treturn `\"${sanitizedAction}\"`\n}\n\n/**\n * Generates a descriptive label for a node to be used in the Mermaid graph.\n * @param node The node to generate a label for.\n * @param uniqueId The unique ID assigned to this node instance in the graph.\n * @returns A formatted string for the Mermaid node definition.\n */\nfunction getNodeLabel(node: AbstractNode, uniqueId: string): string {\n\tif ((node as any).isParallelContainer)\n\t\treturn ` ${uniqueId}{Parallel Block}`\n\n\tif (node.constructor.name === 'InputMappingNode')\n\t\treturn ` ${uniqueId}((\"Inputs\"))`\n\n\tif (node.constructor.name === 'OutputMappingNode')\n\t\treturn ` ${uniqueId}((\"Outputs\"))`\n\n\tif (node.graphData) {\n\t\tconst type = node.graphData.type\n\t\tconst id = node.graphData.id.split(':').pop()\n\t\treturn ` ${uniqueId}[\"${id} (${type})\"]`\n\t}\n\n\treturn ` ${uniqueId}[${node.constructor.name}]`\n}\n\n/**\n * Generates a unique, readable ID for a node instance.\n * @param node The node instance.\n * @returns A unique string ID.\n */\nfunction getUniqueNodeId(node: AbstractNode, nameCounts: Map<string, number>, idMap: Map<AbstractNode, string>): string {\n\tif (idMap.has(node))\n\t\treturn idMap.get(node)!\n\n\tlet baseName: string\n\tif ((node as any).isParallelContainer) {\n\t\tbaseName = 'ParallelBlock'\n\t}\n\telse if (node.graphData) {\n\t\tbaseName = node.graphData.id\n\t}\n\telse if (node.id) {\n\t\tbaseName = String(node.id)\n\t}\n\telse {\n\t\tbaseName = node.constructor.name\n\t}\n\n\t// Sanitize the name for Mermaid ID\n\tconst sanitizedBaseName = baseName.replace(/:/g, '_').replace(/\\W/g, '')\n\tconst count = nameCounts.get(sanitizedBaseName) || 0\n\tconst uniqueId = `${sanitizedBaseName}_${count}`\n\tnameCounts.set(sanitizedBaseName, count + 1)\n\tidMap.set(node, uniqueId)\n\treturn uniqueId\n}\n\n/**\n * Generates a Mermaid graph definition from a `Flow` instance.\n * ...\n */\nexport function generateMermaidGraph(flow: Flow): string {\n\tif (!flow.startNode)\n\t\treturn 'graph TD\\n %% Empty Flow'\n\n\tconst nodes = new Set<string>()\n\tconst edges = new Set<string>()\n\tconst visited = new Set<AbstractNode>()\n\tconst queue: AbstractNode[] = [flow.startNode]\n\tconst idMap = new Map<AbstractNode, string>()\n\tconst nameCounts = new Map<string, number>()\n\n\tvisited.add(flow.startNode)\n\tgetUniqueNodeId(flow.startNode, nameCounts, idMap)\n\n\twhile (queue.length > 0) {\n\t\tconst currentNode = queue.shift()!\n\t\tconst sourceId = getUniqueNodeId(currentNode, nameCounts, idMap)\n\n\t\tnodes.add(getNodeLabel(currentNode, sourceId))\n\n\t\tif ((currentNode as any).isParallelContainer) {\n\t\t\tconst container = currentNode as any as { nodesToRun: AbstractNode[] }\n\t\t\tfor (const internalNode of container.nodesToRun) {\n\t\t\t\tconst targetId = getUniqueNodeId(internalNode, nameCounts, idMap)\n\t\t\t\tedges.add(` ${sourceId} --> ${targetId}`)\n\t\t\t\tif (!visited.has(internalNode)) {\n\t\t\t\t\tvisited.add(internalNode)\n\t\t\t\t\tqueue.push(internalNode)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const [action, successorNode] of currentNode.successors.entries()) {\n\t\t\tconst targetId = getUniqueNodeId(successorNode, nameCounts, idMap)\n\t\t\tconst label = getActionLabel(action)\n\t\t\tconst edge = label\n\t\t\t\t? ` ${sourceId} -- ${label} --> ${targetId}`\n\t\t\t\t: ` ${sourceId} --> ${targetId}`\n\t\t\tedges.add(edge)\n\n\t\t\tif (!visited.has(successorNode)) {\n\t\t\t\tvisited.add(successorNode)\n\t\t\t\tqueue.push(successorNode)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst mermaidLines = [\n\t\t'graph TD',\n\t\t...Array.from(nodes),\n\t\t...Array.from(edges),\n\t]\n\n\treturn mermaidLines.join('\\n')\n}\n","import type { WorkflowGraph } from '../builder/graph.types'\n\n/**\n * Sanitizes a raw workflow graph object by removing properties that are not\n * relevant to the execution engine, such as UI-specific data.\n *\n * @param rawGraph - The raw graph object, potentially containing extraneous properties.\n * @param rawGraph.nodes - An array of node objects.\n * @param rawGraph.edges - An array of edge objects.\n * @returns A clean, execution-focused `WorkflowGraph` object.\n */\nexport function sanitizeGraph(rawGraph: { nodes: any[], edges: any[] }): WorkflowGraph {\n\tconst nodes = rawGraph.nodes.map(({ id, type, data, config }) => ({\n\t\tid,\n\t\ttype,\n\t\tdata,\n\t\t...(config && { config }),\n\t}))\n\n\tconst edges = rawGraph.edges.map(({ id, source, target, action }) => ({\n\t\tid,\n\t\tsource,\n\t\ttarget,\n\t\t...(action && { action }),\n\t}))\n\n\treturn { nodes, edges }\n}\n","import { AbortError } from '../errors'\n\n/**\n * An abortable `sleep` utility that pauses execution for a specified duration.\n * It will reject with an `AbortError` if the provided `AbortSignal` is triggered.\n * @param ms The number of milliseconds to sleep.\n * @param signal An optional `AbortSignal` to listen for cancellation.\n */\nexport async function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted)\n\t\t\treturn reject(new AbortError())\n\n\t\tconst timeoutId = setTimeout(resolve, ms)\n\t\tsignal?.addEventListener('abort', () => {\n\t\t\tclearTimeout(timeoutId)\n\t\t\treject(new AbortError())\n\t\t})\n\t})\n}\n","/* eslint-disable unused-imports/no-unused-vars */\nimport type { GraphNode } from './builder/graph.types'\nimport type { Context, ContextKey, ContextLens } from './context'\nimport type { InternalRunOptions } from './executors/types'\nimport type { Middleware, NodeArgs, NodeOptions, NodeRunContext, Params, RunOptions } from './types'\nimport { AbortError, FatalWorkflowError, WorkflowError } from './errors'\nimport { InMemoryExecutor } from './executors/in-memory'\nimport { NullLogger } from './logger'\nimport { DEFAULT_ACTION, FILTER_FAILED } from './types'\nimport { sleep } from './utils/index'\n\n/**\n * The abstract base class for all executable units in a workflow.\n * It provides the core structure for connecting nodes into a graph.\n *\n * @template TPostRes The type for the action returned by the node's `post` method.\n * @template TParams The type for the node's static parameters.\n */\nexport abstract class AbstractNode<\n\tTPostRes = any,\n\tTParams extends Params = Params,\n> {\n\t/** A unique identifier for this node instance, often set by the GraphBuilder. */\n\tpublic id?: number | string\n\t/** A key-value store for static parameters that configure the node's behavior. */\n\tpublic params: TParams = {} as TParams\n\t/** A map of successor nodes, keyed by the action that triggers the transition. */\n\tpublic successors = new Map<TPostRes | string | typeof DEFAULT_ACTION | typeof FILTER_FAILED, AbstractNode<any, any>>()\n\t/** The original graph definition for this node, if created by a GraphBuilder. */\n\tpublic graphData?: GraphNode\n\n\t/**\n\t * Sets a unique identifier for this node instance.\n\t * Primarily used by the GraphBuilder for wiring and debugging.\n\t * @param id The unique ID for the node.\n\t * @returns The node instance for chaining.\n\t */\n\twithId(id: number | string): this {\n\t\tthis.id = id\n\t\treturn this\n\t}\n\n\t/**\n\t * Attaches the original graph definition data to the node instance.\n\t * @internal\n\t * @param data The graph node definition.\n\t * @returns The node instance for chaining.\n\t */\n\twithGraphData(data: GraphNode): this {\n\t\tthis.graphData = data\n\t\treturn this\n\t}\n\n\t/**\n\t * Sets or merges static parameters for the node. These parameters are available\n\t * via `args.params` in the node's lifecycle methods.\n\t * @param params The parameters to merge into the node's existing parameters.\n\t * @returns The node instance for chaining.\n\t */\n\twithParams(params: Partial<TParams>): this {\n\t\tthis.params = { ...this.params, ...params }\n\t\treturn this\n\t}\n\n\t/**\n\t * Defines the next node in the sequence for a given action.\n\t * This is the primary method for constructing a workflow graph.\n\t *\n\t * @param node The successor node to execute next.\n\t * @param action The action from this node's `post` method that triggers\n\t * the transition. Defaults to `DEFAULT_ACTION` for linear flows.\n\t * @returns The successor node instance, allowing for further chaining.\n\t */\n\tnext<NextNode extends AbstractNode<any, any>>(\n\t\tnode: NextNode,\n\t\taction: TPostRes | string | typeof DEFAULT_ACTION | typeof FILTER_FAILED = DEFAULT_ACTION as any,\n\t): NextNode {\n\t\tthis.successors.set(action, node)\n\t\treturn node\n\t}\n\n\t/**\n\t * The internal method that executes the node's full lifecycle.\n\t * It is called by an `IExecutor`.\n\t * @internal\n\t */\n\tabstract _run(ctx: NodeRunContext): Promise<TPostRes>\n}\n\n/**\n * The fundamental building block of a workflow, representing a single unit of work.\n * It features a three-phase lifecycle, retry logic, and a fluent API for creating\n * data processing pipelines.\n *\n * @template PrepRes The type of data returned by the `prep` phase.\n * @template ExecRes The type of data returned by the `exec` phase.\n * @template PostRes The type of the action returned by the `post` phase.\n * @template TParams The type for the node's static parameters.\n */\nexport class Node<\n\tPrepRes = any,\n\tExecRes = any,\n\tPostRes = any,\n\tTParams extends Params = Params,\n> extends AbstractNode<PostRes, TParams> {\n\t/** The total number of times the `exec` phase will be attempted. */\n\tpublic maxRetries: number\n\t/** The time in milliseconds to wait between failed `exec` attempts. */\n\tpublic wait: number\n\n\t/**\n\t * @param options Configuration options for the node's behavior.\n\t * @param options.maxRetries Total number of `exec` attempts. Defaults to `1`.\n\t * @param options.wait Milliseconds to wait between failed `exec` attempts. Defaults to `0`.\n\t */\n\tconstructor(options: NodeOptions = {}) {\n\t\tsuper()\n\t\tthis.maxRetries = options.maxRetries ?? 1\n\t\tthis.wait = options.wait ?? 0\n\t}\n\n\tprotected _wrapError(e: any, phase: 'prep' | 'exec' | 'post'): Error {\n\t\tif (e instanceof AbortError || e instanceof WorkflowError)\n\t\t\treturn e\n\n\t\treturn new WorkflowError(`Failed in ${phase} phase for node ${this.constructor.name}`, this.constructor.name, phase, e as Error)\n\t}\n\n\t/**\n\t * (Lifecycle) Prepares data for execution. Runs once before `exec`.\n\t * This is the ideal place to read data from the `Context`.\n\t * @param args The arguments for the node, including `ctx` and `params`.\n\t * @returns The data required by the `exec` phase.\n\t */\n\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> { return undefined as unknown as PrepRes }\n\n\t/**\n\t * (Lifecycle) Performs the core, isolated logic of the node.\n\t * This is the only phase that is retried on failure. It should not access the `Context` directly.\n\t * @param args The arguments for the node, including `prepRes`.\n\t * @returns The result of the execution.\n\t */\n\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> { return undefined as unknown as ExecRes }\n\n\t/**\n\t * (Lifecycle) Processes results and determines the next step. Runs once after `exec` succeeds.\n\t * This is the ideal place to write data to the `Context`.\n\t * @param args The arguments for the node, including `execRes`.\n\t * @returns An \"action\" string to determine which successor to execute next. Defaults to `DEFAULT_ACTION`.\n\t */\n\tasync post(args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<PostRes> { return DEFAULT_ACTION as any }\n\n\t/**\n\t * (Lifecycle) A fallback that runs if all `exec` retries fail.\n\t * If not implemented, the final error will be re-thrown, halting the workflow.\n\t * @param args The arguments for the node, including the final `error` that caused the failure.\n\t * @returns A fallback result of type `ExecRes`, allowing the workflow to recover and continue.\n\t */\n\tasync execFallback(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\tif (args.error)\n\t\t\tthrow args.error\n\n\t\tthrow new Error(`Node ${this.constructor.name} failed and has no fallback implementation.`)\n\t}\n\n\t/**\n\t * The internal retry-aware execution logic for the `exec` phase.\n\t * @internal\n\t */\n\tasync _exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\tlet lastError: Error | undefined\n\t\tfor (let curRetry = 0; curRetry < this.maxRetries; curRetry++) {\n\t\t\tif (args.signal?.aborted)\n\t\t\t\tthrow new AbortError()\n\t\t\ttry {\n\t\t\t\treturn await this.exec(args)\n\t\t\t}\n\t\t\tcatch (e) {\n\t\t\t\tconst error = e as Error\n\t\t\t\tlastError = error\n\n\t\t\t\tif (error instanceof FatalWorkflowError)\n\t\t\t\t\tthrow error\n\n\t\t\t\tif (error instanceof AbortError || error.name === 'AbortError')\n\t\t\t\t\tthrow error\n\n\t\t\t\tif (curRetry < this.maxRetries - 1) {\n\t\t\t\t\targs.logger.warn(`Attempt ${curRetry + 1}/${this.maxRetries} failed for ${this.constructor.name}. Retrying...`, { error })\n\t\t\t\t\tif (this.wait > 0)\n\t\t\t\t\t\tawait sleep(this.wait, args.signal)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\targs.logger.error(`All retries failed for ${this.constructor.name}. Executing fallback.`, { error: lastError })\n\t\tif (args.signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\treturn await this.execFallback({ ...args, error: lastError })\n\t}\n\n\t/**\n\t * The internal method that executes the node's full lifecycle.\n\t * @internal\n\t */\n\tasync _run({ ctx, params, signal, logger, executor }: NodeRunContext): Promise<PostRes> {\n\t\tif (this instanceof Flow) {\n\t\t\tlogger.debug(`Running flow: ${this.constructor.name}`, { params })\n\t\t}\n\t\telse {\n\t\t\tlogger.debug(`Running node: ${this.constructor.name}`, { params })\n\t\t}\n\n\t\tif (signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\tlet prepRes: PrepRes\n\t\ttry {\n\t\t\tprepRes = await this.prep({ ctx, params: params as TParams, signal, logger, prepRes: undefined, execRes: undefined, executor })\n\t\t\tlogger.debug(`[${this.constructor.name}] prep() result`, { prepRes })\n\t\t}\n\t\tcatch (e) {\n\t\t\tthrow this._wrapError(e, 'prep')\n\t\t}\n\n\t\tif (signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\tlet execRes: ExecRes\n\t\ttry {\n\t\t\texecRes = await this._exec({ ctx, params: params as TParams, signal, logger, prepRes, execRes: undefined, executor })\n\t\t\tlogger.debug(`[${this.constructor.name}] exec() result`, { execRes })\n\t\t}\n\t\tcatch (e) {\n\t\t\tthrow this._wrapError(e, 'exec')\n\t\t}\n\n\t\tif (signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\ttry {\n\t\t\tconst action = await this.post({ ctx, params: params as TParams, signal, logger, prepRes, execRes, executor })\n\t\t\tconst actionDisplay = typeof action === 'symbol' ? action.toString() : action\n\t\t\tlogger.debug(`[${this.constructor.name}] post() returned action: '${actionDisplay}'`)\n\t\t\treturn action === undefined ? DEFAULT_ACTION as any : action\n\t\t}\n\t\tcatch (e) {\n\t\t\tthrow this._wrapError(e, 'post')\n\t\t}\n\t}\n\n\t/**\n\t * Runs the node as a standalone unit, independent of a larger flow.\n\t * This is useful for testing individual nodes in isolation.\n\t *\n\t * @param ctx The shared workflow context.\n\t * @param options Runtime options like a logger or abort controller.\n\t * @returns The result of the node's `post` method (its action).\n\t */\n\tasync run(ctx: Context, options?: RunOptions): Promise<PostRes> {\n\t\tconst logger = options?.logger ?? new NullLogger()\n\t\tif (this.successors.size > 0 && !(this instanceof Flow))\n\t\t\tlogger.warn('Node.run() called directly on a node with successors. The flow will not continue. Use a Flow to execute a sequence.')\n\t\tconst executor = options?.executor ?? new InMemoryExecutor()\n\t\t// Wrap the node in a Flow and pass its params via the options.\n\t\treturn executor.run(new Flow(this), ctx, { ...options, params: this.params })\n\t}\n\n\t/**\n\t * Creates a new node that transforms the result of this node's `exec` phase.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t * The new node inherits the original's `prep` method. The original `post` method\n\t * is discarded as it is incompatible with the new result type.\n\t *\n\t * @example\n\t * const fetchUserNode = new FetchUserNode() // returns { id: 1, name: 'Alice' }\n\t * const getUserNameNode = fetchUserNode.map(user => user.name) // returns 'Alice'\n\t *\n\t * @param fn A sync or async function to transform the execution result from `ExecRes` to `NewRes`.\n\t * @returns A new `Node` instance with the transformed output type.\n\t */\n\tmap<NewRes>(fn: (result: ExecRes) => NewRes | Promise<NewRes>): Node<PrepRes, NewRes, any, TParams> {\n\t\tconst originalNode = this\n\t\tconst maxRetries = this.maxRetries\n\t\tconst wait = this.wait\n\n\t\treturn new class extends Node<PrepRes, NewRes, any, TParams> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<NewRes> {\n\t\t\t\tconst originalResult = await originalNode.exec(args)\n\t\t\t\treturn fn(originalResult)\n\t\t\t}\n\n\t\t\tasync post(_args: NodeArgs<PrepRes, NewRes, TParams>): Promise<any> {\n\t\t\t\treturn DEFAULT_ACTION\n\t\t\t}\n\t\t}()\n\t}\n\n\t/**\n\t * Creates a new node that stores the result of this node's `exec` phase in the `Context`.\n\t * This is a common terminal operation for a data processing chain.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t *\n\t * @example\n\t * const USER_NAME = contextKey<string>('user_name')\n\t * const workflow = new FetchUserNode()\n\t * .map(user => user.name)\n\t * .toContext(USER_NAME)\n\t *\n\t * @param key The type-safe `ContextKey` to use for storing the result.\n\t * @returns A new `Node` instance that performs the context update in its `post` phase.\n\t */\n\ttoContext(key: ContextKey<ExecRes>): Node<PrepRes, ExecRes, any, TParams> {\n\t\tconst originalNode = this\n\t\tconst maxRetries = this.maxRetries\n\t\tconst wait = this.wait\n\n\t\treturn new class extends Node<PrepRes, ExecRes, any, TParams> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> { return originalNode.exec(args) }\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<any> {\n\t\t\t\targs.ctx.set(key, args.execRes)\n\t\t\t\targs.logger.debug(`[toContext] Set context key '${String(key.description)}'`, { value: args.execRes })\n\t\t\t\treturn DEFAULT_ACTION\n\t\t\t}\n\t\t}()\n\t}\n\n\t/**\n\t * Creates a new node that acts as a conditional gate based on the `exec` result.\n\t * If the predicate returns `true`, the node returns `DEFAULT_ACTION`.\n\t * If it returns `false`, the node returns `FILTER_FAILED`, enabling branching.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t *\n\t * @example\n\t * const checkAdminNode = new FetchUserNode().filter(user => user.isAdmin)\n\t *\n\t * checkAdminNode.next(adminOnlyNode, DEFAULT_ACTION)\n\t * checkAdminNode.next(accessDeniedNode, FILTER_FAILED)\n\t *\n\t * @param predicate A sync or async function that returns `true` or `false`.\n\t * @returns A new `Node` instance that implements the filter logic.\n\t */\n\tfilter(predicate: (result: ExecRes) => boolean | Promise<boolean>): Node<PrepRes, ExecRes, any, TParams> {\n\t\tconst originalNode = this\n\n\t\treturn new class extends Node<PrepRes, ExecRes, any, TParams> {\n\t\t\tprivate didPass = false\n\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>) { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\t\t\tconst result = await originalNode.exec(args)\n\t\t\t\tthis.didPass = await predicate(result)\n\t\t\t\tif (!this.didPass)\n\t\t\t\t\targs.logger.debug(`[Filter] Predicate failed for node ${this.constructor.name}.`)\n\n\t\t\t\treturn result\n\t\t\t}\n\n\t\t\tasync post(_args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<any> {\n\t\t\t\treturn this.didPass ? DEFAULT_ACTION : FILTER_FAILED\n\t\t\t}\n\t\t}()\n\t}\n\n\t/**\n\t * Creates a new node that performs a side effect with the `exec` result,\n\t * but passes the original result through unmodified. Ideal for logging or debugging.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t *\n\t * @example\n\t * const workflow = new FetchUserNode()\n\t * .tap(user => console.log('Fetched User:', user))\n\t * .map(user => user.id)\n\t *\n\t * @param fn A function to call with the execution result for its side effect.\n\t * @returns A new `Node` instance that wraps the original.\n\t */\n\ttap(fn: (result: ExecRes) => void | Promise<void>): Node<PrepRes, ExecRes, PostRes, TParams> {\n\t\tconst originalNode = this\n\t\tconst maxRetries = this.maxRetries\n\t\tconst wait = this.wait\n\n\t\treturn new class extends Node<PrepRes, ExecRes, PostRes, TParams> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> {\n\t\t\t\treturn originalNode.prep(args)\n\t\t\t}\n\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\t\t\tconst originalResult = await originalNode.exec(args)\n\t\t\t\tawait fn(originalResult)\n\t\t\t\treturn originalResult\n\t\t\t}\n\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<PostRes> {\n\t\t\t\treturn originalNode.post(args)\n\t\t\t}\n\t\t}()\n\t}\n\n\t/**\n\t * Creates a new node that applies a context mutation using a lens before executing.\n\t * This allows for declaratively setting or updating context as part of a fluent chain.\n\t *\n\t * @remarks\n\t * This method returns a **new** `Node` instance and does not modify the original.\n\t *\n\t * @example\n\t * const VALUE = contextKey<number>('value')\n\t * const valueLens = lens(VALUE)\n\t *\n\t * const nodeWithLens = new SomeNode().withLens(valueLens, 42) // Sets VALUE to 42 before SomeNode runs\n\t *\n\t * @param lens The `ContextLens` to use for the operation.\n\t * @param value The value to set in the context via the lens.\n\t * @returns A new `Node` instance that applies the context change.\n\t */\n\twithLens<T>(lens: ContextLens<T>, value: T): Node<PrepRes, ExecRes, PostRes, TParams> {\n\t\tconst originalNode = this\n\t\tconst maxRetries = this.maxRetries\n\t\tconst wait = this.wait\n\n\t\treturn new class extends Node<PrepRes, ExecRes, PostRes, TParams> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs<void, void, TParams>): Promise<PrepRes> {\n\t\t\t\t// Apply the lens transformation before executing the original node's logic.\n\t\t\t\tlens.set(value)(args.ctx)\n\t\t\t\treturn originalNode.prep(args)\n\t\t\t}\n\n\t\t\tasync exec(args: NodeArgs<PrepRes, void, TParams>): Promise<ExecRes> {\n\t\t\t\treturn originalNode.exec(args)\n\t\t\t}\n\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes, TParams>): Promise<PostRes> {\n\t\t\t\treturn originalNode.post(args)\n\t\t\t}\n\t\t}()\n\t}\n}\n\n/**\n * A simplified base class for nodes that only need to perform a core action.\n * This pattern is ideal for nodes that receive their inputs via `params` and\n * produce an output, without needing `prep` or complex `post` branching logic.\n *\n * @template ExecRes The type of data returned by the `exec` phase.\n * @template TParams The type for the node's static parameters.\n */\nexport abstract class ExecNode<\n\tExecRes = any,\n\tTParams extends Params = Params,\n> extends Node<void, ExecRes, any, TParams> {\n\t/**\n\t * (Lifecycle) Performs the core, isolated logic of the node.\n\t * This is the only phase that is retried on failure. It should not access the `Context` directly.\n\t * @param args The arguments for the node, including `prepRes`.\n\t * @returns The result of the execution.\n\t */\n\tabstract override exec(args: NodeArgs<void, void, TParams>): Promise<ExecRes>\n}\n\n/**\n * A simplified base class for nodes that only perform a side effect, such as\n * modifying the `Context` or logging. These nodes do not produce an `exec` result.\n * Their logic is typically placed in the `prep` phase.\n *\n * @template TParams The type for the node's static parameters.\n */\nexport abstract class PreNode<\n\tTParams extends Params = Params,\n> extends Node<void, void, any, TParams> {\n\t/**\n\t * (Lifecycle) Prepares data or performs a side effect. Runs once before `exec`.\n\t * This is the ideal place to read from or write to the `Context`.\n\t * @param args The arguments for the node, including `ctx` and `params`.\n\t */\n\tabstract override prep(args: NodeArgs<void, void, TParams>): Promise<void>\n}\n\n/**\n * A simplified base class for nodes that make a branching decision.\n * This pattern is ideal for routing the workflow based on data in the `Context`.\n * The branching logic is placed in the `post` phase, which returns a custom action string.\n *\n * @template PostRes The type of the \"action\" string returned by the `post` phase.\n * @template TParams The type for the node's static parameters.\n */\nexport abstract class PostNode<\n\tPostRes = any,\n\tTParams extends Params = Params,\n> extends Node<void, void, PostRes, TParams> {\n\t/**\n\t * (Lifecycle) Processes results and determines the next step. Runs once after `exec`.\n\t * This is the ideal place to write data to the `Context` and return an action.\n\t * @param args The arguments for the node, including `execRes`.\n\t * @returns An \"action\" string to determine which successor to execute next.\n\t */\n\tabstract override post(args: NodeArgs<void, void, TParams>): Promise<PostRes>\n}\n\n/**\n * A special type of `Node` that orchestrates a graph of other nodes.\n * It can contain its own middleware and can be composed within other flows.\n *\n * @template PrepRes The type of data returned by the `prep` phase.\n * @template ExecRes The type of data returned by the `exec` phase (the final action).\n * @template TParams The type for the flow's static parameters.\n */\nexport class Flow<\n\tPrepRes = any,\n\tExecRes = any,\n\tTParams extends Params = Params,\n> extends Node<PrepRes, ExecRes, ExecRes, TParams> {\n\t/** The first node to be executed in this flow's graph. */\n\tpublic startNode?: AbstractNode<any, any>\n\t/** An array of middleware functions to be applied to every node within this flow. */\n\tpublic middleware: Middleware[] = []\n\n\t/**\n\t * @param start An optional node to start the flow with.\n\t */\n\tconstructor(start?: AbstractNode<any, any>) {\n\t\tsuper()\n\t\tthis.startNode = start\n\t}\n\n\tprotected _wrapError(e: any, phase: 'prep' | 'exec' | 'post'): Error {\n\t\tif (phase === 'exec') {\n\t\t\t// Errors from a sub-flow's orchestration are already wrapped, so we pass them through.\n\t\t\treturn e\n\t\t}\n\t\treturn super._wrapError(e, phase)\n\t}\n\n\t/**\n\t * Adds a middleware function to this flow. Middleware will be executed in the\n\t * order it is added, wrapping the execution of every node within this flow.\n\t * @param fn The middleware function to add.\n\t * @returns The `Flow` instance for chaining.\n\t */\n\tpublic use(fn: Middleware): this {\n\t\tthis.middleware.push(fn)\n\t\treturn this\n\t}\n\n\t/**\n\t * Sets the starting node of the flow's graph.\n\t * @param start The node to start with.\n\t * @returns The start node instance, allowing for further chaining (`.next()`).\n\t */\n\tstart<StartNode extends AbstractNode<any, any>>(start: StartNode): StartNode {\n\t\tthis.startNode = start\n\t\treturn start\n\t}\n\n\t/**\n\t * (Lifecycle) Executes this flow's internal graph when it is used as a sub-flow\n\t * (a node within a larger flow).\n\t * @internal\n\t * @param args The arguments for the node, passed down from the parent executor.\n\t * @returns The final action returned by the last node in this flow's graph.\n\t */\n\tasync exec(args: NodeArgs<any, any, TParams>): Promise<ExecRes> {\n\t\t// For programmatic composition, a Flow node orchestrates its own graph.\n\t\t// This is a feature of the InMemoryExecutor. Distributed systems should\n\t\t// rely on pre-flattened graphs produced by the GraphBuilder.\n\t\tif (!(args.executor instanceof InMemoryExecutor)) {\n\t\t\tthrow new TypeError('Programmatic sub-flow execution is only supported by the InMemoryExecutor. For other environments, use GraphBuilder to create a single, flattened workflow.')\n\t\t}\n\n\t\tif (!this.startNode) {\n\t\t\t// This handles logic-bearing flows like BatchFlow that override exec directly.\n\t\t\treturn super.exec(args)\n\t\t}\n\n\t\targs.logger.debug(`-- Entering sub-flow: ${this.constructor.name} --`)\n\n\t\tconst combinedParams = { ...args.params, ...this.params }\n\t\tconst internalOptions: InternalRunOptions = {\n\t\t\tlogger: args.logger,\n\t\t\tsignal: args.signal,\n\t\t\tparams: combinedParams,\n\t\t\texecutor: args.executor,\n\t\t}\n\n\t\tconst finalAction = await args.executor._orch<ExecRes>(\n\t\t\tthis.startNode,\n\t\t\tthis.middleware,\n\t\t\targs.ctx,\n\t\t\tinternalOptions,\n\t\t)\n\n\t\targs.logger.debug(`-- Exiting sub-flow: ${this.constructor.name} --`)\n\t\treturn finalAction as ExecRes\n\t}\n\n\t/**\n\t * (Lifecycle) The post-execution step for a `Flow` node. It simply passes through\n\t * the final action from its internal graph execution (`execRes`).\n\t * @internal\n\t */\n\tasync post({ execRes }: NodeArgs<PrepRes, ExecRes, TParams>): Promise<ExecRes> {\n\t\treturn execRes\n\t}\n\n\t/**\n\t * Runs the entire flow as a top-level entry point.\n\t * @param ctx The shared workflow context.\n\t * @param options Runtime options like a logger, abort controller, or a custom executor.\n\t * @returns The final action returned by the last node in the flow.\n\t */\n\tasync run(ctx: Context, options?: RunOptions): Promise<ExecRes> {\n\t\tconst executor = options?.executor ?? new InMemoryExecutor()\n\t\treturn executor.run(this, ctx, options)\n\t}\n\n\t/**\n\t * Finds a node within the flow's graph by its unique ID.\n\t *\n\t * This method performs a breadth-first search starting from the `startNode`.\n\t * It is a convenient way to get a reference to a specific node instance\n\t * for debugging or dynamic modifications.\n\t *\n\t * @remarks\n\t * This performs a graph traversal on each call, which has a time complexity\n\t * proportional to the number of nodes and edges in the graph (O(V+E)). For\n\t * performance-critical applications or flows built with `GraphBuilder`,\n\t * it is more efficient to use the `nodeMap` returned by `GraphBuilder.build()`.\n\t *\n\t * @param id The unique ID of the node to find (set via `.withId()` or by the `GraphBuilder`).\n\t * @returns The `AbstractNode` instance if found, otherwise `undefined`.\n\t */\n\tpublic getNodeById(id: string | number): AbstractNode<any, any> | undefined {\n\t\tif (!this.startNode)\n\t\t\treturn undefined\n\n\t\tconst queue: AbstractNode<any, any>[] = [this.startNode]\n\t\tconst visited = new Set<AbstractNode<any, any>>([this.startNode])\n\t\twhile (queue.length > 0) {\n\t\t\tconst currentNode = queue.shift()!\n\n\t\t\tif (currentNode.id === id)\n\t\t\t\treturn currentNode\n\n\t\t\tfor (const successor of currentNode.successors.values()) {\n\t\t\t\tif (!visited.has(successor)) {\n\t\t\t\t\tvisited.add(successor)\n\t\t\t\t\tqueue.push(successor)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined\n\t}\n}\n","/**\n * A type-safe, opaque key for storing and retrieving values from the Context.\n * Using a `ContextKey` provides compile-time safety for your workflow's state.\n * @template T The type of the value this key refers to.\n */\nexport type ContextKey<T> = symbol & { __type: T }\n\n/**\n * Creates a new, unique `ContextKey` for type-safe access to the `Context`.\n * @template T The type of the value this key will hold.\n * @param description An optional description for debugging purposes (e.g., in logs or test snapshots).\n * @returns A unique `ContextKey<T>`.\n */\nexport const contextKey = <T>(description?: string): ContextKey<T> => Symbol(description) as ContextKey<T>\n\n/**\n * Defines the interface for the shared context object passed through the workflow.\n * It acts as the shared memory for all nodes in a flow. It supports both\n * type-safe `ContextKey`s and flexible `string` keys.\n */\nexport interface Context {\n\t/** Retrieves a value from the context. */\n\tget: (<T>(key: ContextKey<T>) => T | undefined) & (<T = any>(key: string) => T | undefined)\n\t/** Stores a value in the context. */\n\tset: (<T>(key: ContextKey<T>, value: T) => this) & ((key: string, value: any) => this)\n\t/** Checks if a key exists in the context. */\n\thas: ((key: ContextKey<any>) => boolean) & ((key: string) => boolean)\n\t/** Returns an iterator of all [key, value] pairs in the context. */\n\tentries: () => IterableIterator<[any, any]>\n}\n\n/**\n * The default, `Map`-based implementation of the `Context` interface.\n */\nexport class TypedContext implements Context {\n\tprivate data: Map<any, any>\n\n\t/**\n\t * @param initialData An optional iterable (like an array of `[key, value]` pairs)\n\t * to initialize the context with.\n\t */\n\tconstructor(initialData?: Iterable<readonly [ContextKey<any> | string, any]> | null) {\n\t\tthis.data = new Map<any, any>(initialData)\n\t}\n\n\tget(key: ContextKey<any> | string): any {\n\t\treturn this.data.get(key)\n\t}\n\n\tset(key: ContextKey<any> | string, value: any): this {\n\t\tthis.data.set(key, value)\n\t\treturn this\n\t}\n\n\thas(key: ContextKey<any> | string): boolean {\n\t\treturn this.data.has(key)\n\t}\n\n\tentries(): IterableIterator<[any, any]> {\n\t\treturn this.data.entries()\n\t}\n}\n\n/** A function that takes a `Context` and returns a (potentially new) `Context`. */\nexport type ContextTransform = (ctx: Context) => Context\n\n/**\n * A \"lens\" provides a way to \"focus\" on a single key in the `Context`,\n * creating reusable, type-safe functions to get, set, or update its value.\n * @template T The type of the value the lens focuses on.\n */\nexport interface ContextLens<T> {\n\t/** Retrieves the value for the key from the context. */\n\tget: (ctx: Context) => T | undefined\n\t/** Returns a `ContextTransform` function that will set the key to the provided value. */\n\tset: (value: T) => ContextTransform\n\t/** Returns a `ContextTransform` function that updates the key's value based on its current value. */\n\tupdate: (fn: (current: T | undefined) => T) => ContextTransform\n}\n\n/**\n * Creates a `ContextLens` object for a specific `ContextKey`.\n * This is the entry point for functional context manipulation.\n *\n * @example\n * const NAME = contextKey<string>('name')\n * const nameLens = lens(NAME)\n * const setNameTransform = nameLens.set('Alice') // This is a function: (ctx) => ctx.set(NAME, 'Alice')\n *\n * @param key The `ContextKey` to focus on.\n * @returns A `ContextLens<T>` object with `.get()`, `.set()`, and `.update()` methods.\n */\nexport function lens<T>(key: ContextKey<T>): ContextLens<T> {\n\treturn {\n\t\tget: (ctx: Context) => ctx.get(key),\n\t\tset: (value: T) => (ctx: Context) => ctx.set(key, value),\n\t\tupdate: (fn: (current: T | undefined) => T) => (ctx: Context) =>\n\t\t\tctx.set(key, fn(ctx.get(key))),\n\t}\n}\n\n/**\n * Composes multiple `ContextTransform` functions into a single `ContextTransform` function.\n * The transformations are applied in the order they are provided.\n *\n * @param transforms A sequence of `ContextTransform` functions.\n * @returns A single function that applies all transformations.\n */\nexport function composeContext(...transforms: ContextTransform[]): ContextTransform {\n\treturn (ctx: Context) => transforms.reduce((acc, transform) => transform(acc), ctx)\n}\n","import type { NodeFunction } from '../functions'\nimport type { NodeArgs } from '../types'\nimport type { AbstractNode } from '../workflow'\nimport { AbortError } from '../errors'\nimport { Flow } from '../workflow'\n\n/**\n * A `Flow` that creates a linear workflow from a sequence of nodes,\n * automatically chaining them in order.\n */\nexport class SequenceFlow<PrepRes = any, ExecRes = any> extends Flow<PrepRes, ExecRes> {\n\t/**\n\t * @param nodes A sequence of `Node` or `Flow` instances to be executed in order.\n\t */\n\tconstructor(...nodes: AbstractNode[]) {\n\t\tif (nodes.length === 0) {\n\t\t\tsuper()\n\t\t\treturn\n\t\t}\n\t\tsuper(nodes[0])\n\t\tlet current = nodes[0]\n\t\tfor (let i = 1; i < nodes.length; i++)\n\t\t\tcurrent = current.next(nodes[i])\n\t}\n}\n\n/**\n * A `Flow` that executes a collection of different nodes concurrently.\n * This is the core of the \"fan-out, fan-in\" pattern for structural parallelism.\n * After all parallel branches complete, the flow can proceed to a single successor.\n */\nexport class ParallelFlow extends Flow<any, void> {\n\t/**\n\t * @param nodesToRun The array of nodes to execute concurrently.\n\t */\n\tconstructor(protected nodesToRun: AbstractNode[]) {\n\t\tsuper()\n\t}\n\n\t/**\n\t * Orchestrates the parallel execution of all nodes.\n\t * @internal\n\t */\n\tasync exec({ ctx, params, signal, logger, executor }: NodeArgs): Promise<void> {\n\t\tif (this.nodesToRun.length === 0) {\n\t\t\tlogger.debug('[ParallelFlow] No branches to execute in parallel.')\n\t\t\treturn\n\t\t}\n\n\t\tlogger.info(`[ParallelFlow] Executing ${this.nodesToRun.length} branches in parallel...`)\n\t\tconst promises = this.nodesToRun.map(node =>\n\t\t\tnode._run({\n\t\t\t\tctx,\n\t\t\t\tparams: { ...params, ...node.params },\n\t\t\t\tsignal,\n\t\t\t\tlogger,\n\t\t\t\texecutor,\n\t\t\t}),\n\t\t)\n\n\t\tconst results = await Promise.allSettled(promises)\n\n\t\tresults.forEach((result) => {\n\t\t\tif (result.status === 'rejected')\n\t\t\t\tlogger.error('[ParallelFlow] A parallel branch failed.', { error: result.reason })\n\t\t})\n\t}\n}\n\n/**\n * An abstract `Flow` that processes a collection of items sequentially, one by one.\n * Subclasses must implement the `prep` method to provide the items and the\n * `nodeToRun` property to define the processing logic for each item.\n */\nexport abstract class BatchFlow<T = any> extends Flow<Iterable<T>, null> {\n\t/**\n\t * The `Node` instance that will be executed for each item in the batch.\n\t * This must be implemented by any subclass.\n\t */\n\tprotected abstract nodeToRun: AbstractNode\n\n\tconstructor() {\n\t\tsuper()\n\t}\n\n\t/**\n\t * (Abstract) Prepares the list of items to be processed.\n\t * This method is called once before the batch processing begins.\n\t * @param _args The arguments for the node, including `ctx` and `params`.\n\t * @returns An array or iterable of parameter objects, one for each item.\n\t * The `nodeToRun` will be executed once for each of these objects.\n\t */\n\tasync prep(_args: NodeArgs): Promise<Iterable<any>> {\n\t\treturn []\n\t}\n\n\t/**\n\t * Orchestrates the sequential execution of `nodeToRun` for each item.\n\t * @internal\n\t */\n\tasync exec(args: NodeArgs): Promise<null> {\n\t\tif (!this.nodeToRun)\n\t\t\treturn null\n\n\t\tconst combinedParams = { ...this.params, ...args.params }\n\t\tconst batchParamsIterable = (await this.prep(args)) || []\n\t\tconst batchParamsList = Array.from(batchParamsIterable)\n\t\targs.logger.info(`[BatchFlow] Starting sequential processing of ${batchParamsList.length} items.`)\n\n\t\tfor (const batchParams of batchParamsList) {\n\t\t\tif (args.signal?.aborted)\n\t\t\t\tthrow new AbortError()\n\n\t\t\tawait this.nodeToRun._run({\n\t\t\t\tctx: args.ctx,\n\t\t\t\tparams: { ...combinedParams, ...batchParams },\n\t\t\t\tsignal: args.signal,\n\t\t\t\tlogger: args.logger,\n\t\t\t\texecutor: args.executor,\n\t\t\t})\n\t\t}\n\t\treturn null\n\t}\n}\n\n/**\n * An abstract `Flow` that processes a collection of items concurrently.\n * Subclasses must implement the `prep` method to provide the items and the\n * `nodeToRun` property to define the processing logic for each item.\n * This provides a significant performance boost for I/O-bound tasks.\n */\nexport abstract class ParallelBatchFlow<T = any> extends Flow<Iterable<T>, PromiseSettledResult<any>[]> {\n\t/**\n\t * The `Node` instance that will be executed concurrently for each item in the batch.\n\t * This must be implemented by any subclass.\n\t */\n\tprotected abstract nodeToRun: AbstractNode\n\n\tconstructor() {\n\t\tsuper()\n\t}\n\n\t/**\n\t * (Abstract) Prepares the list of items to be processed.\n\t * This method is called once before the batch processing begins.\n\t * @param _args The arguments for the node, including `ctx` and `params`.\n\t * @returns An array or iterable of parameter objects, one for each item.\n\t * The `nodeToRun` will be executed concurrently for each of these objects.\n\t */\n\tasync prep(_args: NodeArgs): Promise<Iterable<any>> {\n\t\treturn []\n\t}\n\n\t/**\n\t * Orchestrates the parallel execution of `nodeToRun` for each item.\n\t * @internal\n\t */\n\tasync exec(args: NodeArgs<any, void>): Promise<PromiseSettledResult<any>[]> {\n\t\tif (!this.nodeToRun)\n\t\t\treturn []\n\n\t\tconst combinedParams = { ...this.params, ...args.params }\n\t\tconst batchParamsIterable = (await this.prep(args)) || []\n\t\tconst batchParamsList = Array.from(batchParamsIterable)\n\t\targs.logger.info(`[ParallelBatchFlow] Starting parallel processing of ${batchParamsList.length} items.`)\n\n\t\tconst promises = batchParamsList.map((batchParams) => {\n\t\t\treturn this.nodeToRun._run({\n\t\t\t\tctx: args.ctx,\n\t\t\t\tparams: { ...combinedParams, ...batchParams },\n\t\t\t\tsignal: args.signal,\n\t\t\t\tlogger: args.logger,\n\t\t\t\texecutor: args.executor,\n\t\t\t})\n\t\t})\n\n\t\tconst results = await Promise.allSettled(promises)\n\n\t\tfor (const result of results) {\n\t\t\tif (result.status === 'rejected') {\n\t\t\t\targs.logger.error('A parallel batch item failed.', { error: result.reason })\n\t\t\t}\n\t\t}\n\n\t\treturn results\n\t}\n}\n\n/**\n * Creates a flow that applies a mapping function to each item in a collection in parallel\n * and returns a new array containing the results.\n *\n * @example\n * const numbers = [1, 2, 3];\n * const double = (n: number) => n * 2;\n * const processingFlow = mapCollection(numbers, double);\n * // When run, processingFlow's result will be [2, 4, 6]\n *\n * @param items The initial array of items of type `T`.\n * @param fn An async or sync function that transforms an item from type `T` to type `U`.\n * @returns A `Flow` instance that, when run, will output an array of type `U[]`.\n */\nexport function mapCollection<T, U>(items: T[], fn: NodeFunction<T, U>): Flow<void, U[]> {\n\treturn new class extends Flow {\n\t\tasync exec(): Promise<U[]> {\n\t\t\t// Using Promise.all to run the mapping function on all items concurrently.\n\t\t\tconst promises = items.map(item => fn(item))\n\t\t\treturn Promise.all(promises)\n\t\t}\n\t}()\n}\n\n/**\n * Creates a flow that filters a collection based on a predicate function,\n * returning a new array containing only the items that pass the predicate.\n * The predicate is applied to all items concurrently.\n *\n * @example\n * const users = [{ id: 1, admin: true }, { id: 2, admin: false }];\n * const isAdmin = async (user: { admin: boolean }) => user.admin;\n * const adminFilterFlow = filterCollection(users, isAdmin);\n * // When run, the result will be [{ id: 1, admin: true }]\n *\n * @param items The initial array of items of type `T`.\n * @param predicate An async or sync function that returns `true` or `false` for an item.\n * @returns A `Flow` instance that, when run, will output a filtered array of type `T[]`.\n */\nexport function filterCollection<T>(items: T[], predicate: (item: T) => boolean | Promise<boolean>): Flow<void, T[]> {\n\treturn new class extends Flow {\n\t\tasync exec(): Promise<T[]> {\n\t\t\tconst results = await Promise.all(items.map(item => predicate(item)))\n\t\t\treturn items.filter((_, index) => results[index])\n\t\t}\n\t}()\n}\n\n/**\n * Creates a flow that reduces a collection to a single value by executing a\n * reducer function sequentially for each item, similar to `Array.prototype.reduce()`.\n *\n * @example\n * const numbers = [1, 2, 3, 4];\n * const sumReducer = (acc: number, val: number) => acc + val;\n * const sumFlow = reduceCollection(numbers, sumReducer, 0);\n * // When run, the result will be 10.\n *\n * @param items The array of items to be reduced.\n * @param reducer An async or sync function that processes the accumulator and the current item.\n * @param initialValue The initial value for the accumulator.\n * @returns A `Flow` instance that, when run, will output the final accumulated value of type `U`.\n */\nexport function reduceCollection<T, U>(\n\titems: T[],\n\treducer: (accumulator: U, item: T) => U | Promise<U>,\n\tinitialValue: U,\n): Flow<void, U> {\n\treturn new class extends Flow {\n\t\tasync exec(_args: NodeArgs): Promise<U> {\n\t\t\tlet accumulator = initialValue\n\t\t\tfor (const item of items) {\n\t\t\t\tif (_args.signal?.aborted) {\n\t\t\t\t\tthrow new AbortError()\n\t\t\t\t}\n\t\t\t\taccumulator = await reducer(accumulator, item)\n\t\t\t}\n\t\t\treturn accumulator\n\t\t}\n\t}()\n}\n","import type { Logger } from '../logger'\nimport type { FILTER_FAILED, NodeArgs } from '../types'\nimport type { AbstractNode } from '../workflow'\nimport type { BuildResult, GraphBuilderOptions, GraphEdge, GraphNode, NodeRegistry, NodeTypeMap, OriginalPredecessorIdMap, PredecessorIdMap, SubWorkflowResolver, TypedNodeRegistry, TypedWorkflowGraph, WorkflowGraph } from './graph.types'\nimport { NullLogger } from '../logger'\nimport { DEFAULT_ACTION } from '../types'\nimport { generateMermaidGraph } from '../utils/mermaid'\nimport { Flow, Node } from '../workflow'\nimport { ParallelFlow } from './patterns'\n\n/**\n * A type-safe helper function for creating a `TypedNodeRegistry`.\n * This function preserves the strong typing of the registry object, enabling\n * compile-time validation of `TypedWorkflowGraph` definitions.\n *\n * @param registry The registry object, where keys are node types and values are `Node` constructors.\n * @returns The same registry object, correctly typed for use with `GraphBuilder`.\n */\nexport function createNodeRegistry<\n\tTNodeMap extends NodeTypeMap,\n\tTContext = object,\n>(registry: TypedNodeRegistry<TNodeMap, TContext>): TypedNodeRegistry<TNodeMap, TContext> {\n\treturn registry\n}\n\n/**\n * An internal node used by the GraphBuilder to handle the `inputs` mapping\n * of an inlined sub-workflow. It copies data from the parent context scope\n * to the sub-workflow's context scope.\n * @internal\n */\nclass InputMappingNode extends Node {\n\tprivate mappings: Record<string, string>\n\tconstructor(options: { data: Record<string, string> }) {\n\t\tsuper()\n\t\t// Exclude the injected nodeId from the mappings\n\t\tconst { nodeId, ...mappings } = options.data\n\t\tthis.mappings = mappings\n\t}\n\n\tasync prep({ ctx, logger }: NodeArgs) {\n\t\tfor (const [subKey, parentKey] of Object.entries(this.mappings)) {\n\t\t\tif (ctx.has(parentKey)) {\n\t\t\t\tctx.set(subKey, ctx.get(parentKey))\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.warn(`[InputMapper] Input mapping failed. Key '${parentKey}' not found in context.`)\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * An internal node used by the GraphBuilder to handle the `outputs` mapping\n * of an inlined sub-workflow. It copies data from the sub-workflow's\n * context scope back to the parent's context scope.\n * @internal\n */\nclass OutputMappingNode extends Node {\n\tprivate mappings: Record<string, string>\n\tconstructor(options: { data: Record<string, string> }) {\n\t\tsuper()\n\t\t// Exclude the injected nodeId from the mappings\n\t\tconst { nodeId, ...mappings } = options.data\n\t\tthis.mappings = mappings\n\t}\n\n\tasync prep({ ctx, logger }: NodeArgs) {\n\t\tfor (const [parentKey, subKey] of Object.entries(this.mappings)) {\n\t\t\tif (ctx.has(subKey)) {\n\t\t\t\tctx.set(parentKey, ctx.get(subKey))\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.warn(`[OutputMapper] Output mapping failed. Key '${subKey}' not found in context.`)\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * A private class used by the builder to represent the sub-workflow container itself.\n * It's a structural node that preserves the original node ID in the flattened graph.\n * @internal\n */\nclass SubWorkflowContainerNode extends Node {\n\tasync exec() {\n\t\t// This node performs no work; it just acts as a stable entry point.\n\t\t// The graph wiring ensures the InputMappingNode is executed next.\n\t}\n}\n\n/** A private class used by the builder to represent parallel execution blocks. */\nclass ParallelBranchContainer extends ParallelFlow {\n\t/** A tag to reliably identify this node type in the visualizer. */\n\tpublic readonly isParallelContainer = true\n\tconstructor(public readonly nodesToRun: AbstractNode[]) { super(nodesToRun) }\n}\n\n/**\n * Constructs an executable `Flow` from a declarative `WorkflowGraph` definition.\n * @template TNodeMap A `NodeTypeMap` for validating type-safe graph definitions.\n * @template TContext The shape of the dependency injection context object.\n */\nexport class GraphBuilder<\n\tTNodeMap extends NodeTypeMap,\n\tTContext extends object = object,\n> {\n\tprivate registry: Map<string, new (...args: any[]) => AbstractNode>\n\tprivate subWorkflowNodeTypes: string[]\n\tprivate subWorkflowResolver?: SubWorkflowResolver\n\tprivate logger: Logger\n\n\t/**\n\t * @param registry A type-safe object or a `Map` where keys are node `type` strings and\n\t * values are the corresponding `Node` class constructors. For type-safety, use `createNodeRegistry`.\n\t * @param nodeOptionsContext An optional object that is passed to every node's\n\t * constructor, useful for dependency injection (e.g., passing a database client or the builder itself).\n\t */\n\t// type-safe overload\n\tconstructor(registry: TypedNodeRegistry<TNodeMap, TContext>, nodeOptionsContext?: TContext, options?: GraphBuilderOptions, logger?: Logger)\n\t// untyped overload\n\tconstructor(registry: NodeRegistry, nodeOptionsContext?: Record<string, any>, options?: GraphBuilderOptions, logger?: Logger)\n\t// handle both cases\n\tconstructor(\n\t\tregistry: TypedNodeRegistry<TNodeMap, TContext> | NodeRegistry,\n\t\tprivate nodeOptionsContext: TContext | Record<string, any> = {},\n\t\toptions: GraphBuilderOptions = {},\n\t\tlogger: Logger = new NullLogger(),\n\t) {\n\t\tthis.logger = logger\n\t\tif (registry instanceof Map) {\n\t\t\tthis.registry = registry\n\t\t}\n\t\telse {\n\t\t\tthis.registry = new Map(Object.entries(registry))\n\t\t}\n\t\tthis.registry.set('__internal_input_mapper__', InputMappingNode as any)\n\t\tthis.registry.set('__internal_output_mapper__', OutputMappingNode as any)\n\t\tthis.registry.set('__internal_sub_workflow_container__', SubWorkflowContainerNode as any)\n\t\tthis.subWorkflowNodeTypes = options.subWorkflowNodeTypes ?? []\n\t\tthis.subWorkflowResolver = options.subWorkflowResolver\n\t}\n\n\tprivate _logMermaid(flow: Flow) {\n\t\tif (!(this.logger instanceof NullLogger)) {\n\t\t\tthis.logger.info('[GraphBuilder] Flattened Graph')\n\t\t\tconst mermaid = generateMermaidGraph(flow)\n\t\t\tmermaid.split('\\n').forEach(line => this.logger.info(line))\n\t\t}\n\t}\n\n\tprivate _flattenGraph(graph: WorkflowGraph, idPrefix = ''): WorkflowGraph {\n\t\tconst finalNodes: GraphNode[] = []\n\t\tconst finalEdges: GraphEdge[] = []\n\n\t\tconst localNodeIds = new Set(graph.nodes.map(n => n.id))\n\n\t\tfor (const node of graph.nodes) {\n\t\t\tconst prefixedNodeId = `${idPrefix}${node.id}`\n\t\t\tconst sanitizedId = prefixedNodeId.replace(/:/g, '_').replace(/\\W/g, '')\n\n\t\t\tconst isRegisteredSubWorkflow = this.subWorkflowNodeTypes.includes(node.type)\n\t\t\tconst hasWorkflowId = node.data && 'workflowId' in node.data\n\t\t\tconst newNodeData = JSON.parse(JSON.stringify(node.data || {}))\n\n\t\t\tif (newNodeData.inputs) {\n\t\t\t\tconst inputs = newNodeData.inputs as Record<string, string | string[]>\n\t\t\t\tfor (const [templateKey, sourcePathOrPaths] of Object.entries(inputs)) {\n\t\t\t\t\tconst sourcePaths = Array.isArray(sourcePathOrPaths) ? sourcePathOrPaths : [sourcePathOrPaths]\n\t\t\t\t\tconst newSourcePaths = sourcePaths.map((sourcePath) => {\n\t\t\t\t\t\tif (localNodeIds.has(sourcePath))\n\t\t\t\t\t\t\treturn `${idPrefix}${sourcePath}`\n\t\t\t\t\t\treturn sourcePath\n\t\t\t\t\t})\n\t\t\t\t\tinputs[templateKey] = Array.isArray(sourcePathOrPaths) ? newSourcePaths : newSourcePaths[0]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isRegisteredSubWorkflow) {\n\t\t\t\tif (!this.subWorkflowResolver)\n\t\t\t\t\tthrow new Error('GraphBuilder: `subWorkflowResolver` must be provided in options to handle sub-workflows.')\n\n\t\t\t\tconst subWorkflowData = node.data as any\n\t\t\t\tconst subWorkflowId = subWorkflowData.workflowId\n\t\t\t\tconst subGraph: WorkflowGraph | undefined = this.subWorkflowResolver.getGraph(subWorkflowId)\n\t\t\t\tif (!subGraph)\n\t\t\t\t\tthrow new Error(`Sub-workflow with ID ${subWorkflowId} not found in resolver.`)\n\n\t\t\t\tfinalNodes.push({\n\t\t\t\t\tid: prefixedNodeId,\n\t\t\t\t\ttype: '__internal_sub_workflow_container__',\n\t\t\t\t\tdata: { ...newNodeData, originalId: node.id },\n\t\t\t\t})\n\n\t\t\t\tconst inputMapperId = `${sanitizedId}_input_mapper`\n\t\t\t\tconst outputMapperId = `${sanitizedId}_output_mapper`\n\t\t\t\tfinalNodes.push({\n\t\t\t\t\tid: inputMapperId,\n\t\t\t\t\ttype: '__internal_input_mapper__',\n\t\t\t\t\tdata: { ...(subWorkflowData.inputs || {}), originalId: node.id },\n\t\t\t\t})\n\t\t\t\tfinalNodes.push({\n\t\t\t\t\tid: outputMapperId,\n\t\t\t\t\ttype: '__internal_output_mapper__',\n\t\t\t\t\tdata: { ...(subWorkflowData.outputs || {}), originalId: node.id },\n\t\t\t\t})\n\n\t\t\t\tconst inlinedSubGraph = this._flattenGraph(subGraph, `${prefixedNodeId}:`)\n\t\t\t\tconst augmentedInlinedNodes = inlinedSubGraph.nodes.map(n => ({\n\t\t\t\t\t...n,\n\t\t\t\t\tdata: { ...(n.data || {}), isSubWorkflow: true },\n\t\t\t\t}))\n\t\t\t\tfinalNodes.push(...augmentedInlinedNodes)\n\t\t\t\tfinalEdges.push(...inlinedSubGraph.edges)\n\n\t\t\t\tfinalEdges.push({ source: prefixedNodeId, target: inputMapperId })\n\n\t\t\t\tconst subGraphStartIds = inlinedSubGraph.nodes.map(n => n.id).filter(id => !inlinedSubGraph.edges.some(e => e.target === id))\n\t\t\t\tfor (const startId of subGraphStartIds)\n\t\t\t\t\tfinalEdges.push({ source: inputMapperId, target: startId })\n\n\t\t\t\tconst subGraphTerminalIds = inlinedSubGraph.nodes.map(n => n.id).filter(id => !inlinedSubGraph.edges.some(e => e.source === id))\n\t\t\t\tfor (const terminalId of subGraphTerminalIds)\n\t\t\t\t\tfinalEdges.push({ source: terminalId, target: outputMapperId })\n\t\t\t}\n\t\t\telse if (hasWorkflowId) {\n\t\t\t\tthrow new Error(`Node with ID '${node.id}' has a 'workflowId' but its type '${node.type}' is not in 'subWorkflowNodeTypes'.`)\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfinalNodes.push({ ...node, id: prefixedNodeId, data: { ...newNodeData, originalId: node.id } })\n\t\t\t}\n\t\t}\n\n\t\t// Pass 2: Re-wire all original edges to connect to the correct nodes in the flattened graph.\n\t\tfor (const edge of graph.edges) {\n\t\t\tconst sourceNode = graph.nodes.find(n => n.id === edge.source)!\n\t\t\tconst prefixedSourceId = `${idPrefix}${edge.source}`\n\t\t\tconst prefixedTargetId = `${idPrefix}${edge.target}`\n\n\t\t\tconst isSourceSub = this.subWorkflowNodeTypes.includes(sourceNode.type)\n\t\t\tconst sanitizedSourceId = prefixedSourceId.replace(/:/g, '_').replace(/\\W/g, '')\n\n\t\t\tif (isSourceSub) {\n\t\t\t\tfinalEdges.push({ ...edge, source: `${sanitizedSourceId}_output_mapper`, target: prefixedTargetId })\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfinalEdges.push({ ...edge, source: prefixedSourceId, target: prefixedTargetId })\n\t\t\t}\n\t\t}\n\t\treturn { nodes: finalNodes, edges: finalEdges }\n\t}\n\n\t/**\n\t * Builds a runnable `Flow` from a graph definition.\n\t * @param graph The `WorkflowGraph` object describing the flow.\n\t * @param log Whether to log the graph after flattening. Defaults to `false`.\n\t * @returns A `BuildResult` object containing the executable `flow` and a `nodeMap`.\n\t */\n\t// type-safe overload\n\tbuild(graph: TypedWorkflowGraph<TNodeMap>, log?: boolean): BuildResult\n\t// untyped overload\n\tbuild(graph: WorkflowGraph, log?: boolean): BuildResult\n\t// single implementation that handles both cases\n\tbuild(graph: TypedWorkflowGraph<TNodeMap> | WorkflowGraph, log?: boolean): BuildResult {\n\t\tconst flatGraph = this._flattenGraph(graph as WorkflowGraph)\n\t\tconst nodeMap = new Map<string, AbstractNode>()\n\n\t\t// Pass 1: Instantiate all nodes.\n\t\tfor (const graphNode of flatGraph.nodes) {\n\t\t\tconst NodeClass = this.registry.get(graphNode.type.toString())\n\t\t\tif (!NodeClass)\n\t\t\t\tthrow new Error(`GraphBuilder: Node type '${graphNode.type.toString()}' not found in registry.`)\n\n\t\t\tconst nodeOptions = {\n\t\t\t\t...this.nodeOptionsContext,\n\t\t\t\tdata: { ...graphNode.data, nodeId: graphNode.id },\n\t\t\t}\n\t\t\tconst executableNode = new NodeClass(nodeOptions).withId(graphNode.id).withGraphData(graphNode)\n\t\t\tif (graphNode.config && executableNode instanceof Node) {\n\t\t\t\texecutableNode.maxRetries = graphNode.config.maxRetries ?? executableNode.maxRetries\n\t\t\t\texecutableNode.wait = graphNode.config.wait ?? executableNode.wait\n\t\t\t}\n\t\t\tnodeMap.set(graphNode.id, executableNode)\n\t\t}\n\n\t\t// Pass 2: Group edges by source to identify fan-outs.\n\t\tconst edgeGroups = new Map<string, Map<string | typeof DEFAULT_ACTION | typeof FILTER_FAILED, AbstractNode[]>>()\n\t\tfor (const edge of flatGraph.edges) {\n\t\t\tconst sourceId = edge.source\n\t\t\tconst action = edge.action || DEFAULT_ACTION\n\t\t\tconst targetNode = nodeMap.get(edge.target)!\n\n\t\t\tif (!edgeGroups.has(sourceId))\n\t\t\t\tedgeGroups.set(sourceId, new Map())\n\t\t\tconst sourceActions = edgeGroups.get(sourceId)!\n\t\t\tif (!sourceActions.has(action))\n\t\t\t\tsourceActions.set(action, [])\n\t\t\tsourceActions.get(action)!.push(targetNode)\n\t\t}\n\n\t\t// Pass 3: Wire the graph.\n\t\tfor (const [sourceId, actions] of edgeGroups.entries()) {\n\t\t\tconst sourceNode = nodeMap.get(sourceId)!\n\t\t\tfor (const [action, successors] of actions.entries()) {\n\t\t\t\tif (successors.length === 1) {\n\t\t\t\t\tsourceNode.next(successors[0], action)\n\t\t\t\t}\n\t\t\t\telse if (successors.length > 1) {\n\t\t\t\t\tconst parallelNode = new ParallelBranchContainer(successors).withId(`${sourceId}__parallel_container`)\n\t\t\t\t\tnodeMap.set(String(parallelNode.id), parallelNode) // Add to map\n\t\t\t\t\tsourceNode.next(parallelNode, action)\n\n\t\t\t\t\t// Wire the individual branches to their own successors.\n\t\t\t\t\tfor (const branchNode of successors) {\n\t\t\t\t\t\tconst branchSuccessors = edgeGroups.get(String(branchNode.id!))\n\t\t\t\t\t\tif (branchSuccessors) {\n\t\t\t\t\t\t\tfor (const [branchAction, branchTargets] of branchSuccessors.entries()) {\n\t\t\t\t\t\t\t\tfor (const target of branchTargets)\n\t\t\t\t\t\t\t\t\tbranchNode.next(target, branchAction)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Find the convergence point and wire the container to it.\n\t\t\t\t\tconst convergenceNode = this._findConvergenceNode(successors, edgeGroups)\n\t\t\t\t\tif (convergenceNode)\n\t\t\t\t\t\tparallelNode.next(convergenceNode)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Final Step: Determine start nodes and build final result.\n\t\tconst allNodeIds = new Set(flatGraph.nodes.map(n => n.id))\n\t\tconst allTargetIds = new Set(flatGraph.edges.map(e => e.target))\n\t\tconst startNodeIds = [...allNodeIds].filter(id => !allTargetIds.has(id))\n\n\t\tif (startNodeIds.length === 0 && allNodeIds.size > 0)\n\t\t\tthrow new Error('GraphBuilder: This graph has a cycle and no clear start node.')\n\n\t\tconst { predecessorIdMap, originalPredecessorIdMap } = this._createPredecessorIdMaps(flatGraph, nodeMap)\n\t\tconst predecessorCountMap = new Map<string, number>()\n\t\tfor (const [key, val] of predecessorIdMap.entries())\n\t\t\tpredecessorCountMap.set(key, val.length)\n\t\tfor (const id of allNodeIds) {\n\t\t\tif (!predecessorCountMap.has(id))\n\t\t\t\tpredecessorCountMap.set(id, 0)\n\t\t}\n\n\t\tlet startNode: AbstractNode\n\t\tif (startNodeIds.length === 1) {\n\t\t\tstartNode = nodeMap.get(startNodeIds[0])!\n\t\t}\n\t\telse {\n\t\t\tconst startNodes = startNodeIds.map(id => nodeMap.get(id)!)\n\t\t\tconst parallelStartNode = new ParallelBranchContainer(startNodes).withId('__root_parallel_start')\n\t\t\tnodeMap.set(String(parallelStartNode.id), parallelStartNode)\n\t\t\tconst convergenceNode = this._findConvergenceNode(startNodes, edgeGroups)\n\t\t\tif (convergenceNode)\n\t\t\t\tparallelStartNode.next(convergenceNode)\n\t\t\tstartNode = parallelStartNode\n\t\t}\n\n\t\tconst flow = new Flow(startNode)\n\t\tif (log)\n\t\t\tthis._logMermaid(flow)\n\t\treturn { flow, nodeMap, predecessorCountMap, predecessorIdMap, originalPredecessorIdMap }\n\t}\n\n\t/**\n\t * Creates a map of each node ID to an array of its direct predecessor node IDs.\n\t * This is a helper for executors that need to know a node's direct inputs.\n\t * @param graph The flattened workflow graph.\n\t * @returns A map where each key is a node ID and the value is an array of its predecessor IDs.\n\t * @private\n\t */\n\tprivate _createPredecessorIdMaps(\n\t\tgraph: WorkflowGraph,\n\t\tnodeMap: Map<string, AbstractNode>,\n\t): { predecessorIdMap: PredecessorIdMap, originalPredecessorIdMap: OriginalPredecessorIdMap } {\n\t\tconst predecessorIdMap: PredecessorIdMap = new Map()\n\t\tconst originalPredecessorIdMap: OriginalPredecessorIdMap = new Map()\n\n\t\tfor (const edge of graph.edges) {\n\t\t\tif (!predecessorIdMap.has(edge.target))\n\t\t\t\tpredecessorIdMap.set(edge.target, [])\n\t\t\tpredecessorIdMap.get(edge.target)!.push(edge.source)\n\n\t\t\tconst sourceNode = nodeMap.get(edge.source)!\n\t\t\tconst targetNode = nodeMap.get(edge.target)!\n\n\t\t\tconst sourceOriginalId = sourceNode?.graphData?.data?.originalId\n\t\t\tconst targetOriginalId = targetNode?.graphData?.data?.originalId\n\t\t\tconst mapKey = targetOriginalId ?? targetNode?.id as string\n\n\t\t\tif (sourceOriginalId && mapKey) {\n\t\t\t\tif (!originalPredecessorIdMap.has(mapKey))\n\t\t\t\t\toriginalPredecessorIdMap.set(mapKey, [])\n\n\t\t\t\tconst originalPreds = originalPredecessorIdMap.get(mapKey)!\n\t\t\t\tif (!originalPreds.includes(sourceOriginalId))\n\t\t\t\t\toriginalPreds.push(sourceOriginalId)\n\t\t\t}\n\t\t}\n\t\treturn { predecessorIdMap, originalPredecessorIdMap }\n\t}\n\n\t/**\n\t * Finds the first node where all parallel branches converge.\n\t * Uses a Breadth-First Search to guarantee finding the nearest convergence point.\n\t * @param parallelNodes - The set of nodes running in parallel.\n\t * @param edgeGroups - The map of all graph edges.\n\t * @returns The convergence node, or undefined if they never converge.\n\t * @private\n\t */\n\tprivate _findConvergenceNode(\n\t\tparallelNodes: AbstractNode[],\n\t\tedgeGroups: Map<string, Map<any, AbstractNode[]>>,\n\t): AbstractNode | undefined {\n\t\tif (parallelNodes.length <= 1)\n\t\t\treturn undefined\n\n\t\tconst queue: string[] = parallelNodes.map(n => String(n.id!))\n\t\tconst visitedBy = new Map<string, Set<string>>()\n\t\tparallelNodes.forEach(n => visitedBy.set(String(n.id!), new Set([String(n.id!)])))\n\n\t\tlet head = 0\n\t\twhile (head < queue.length) {\n\t\t\tconst currentId = queue[head++]!\n\t\t\tconst successors = Array.from(edgeGroups.get(currentId)?.values() ?? []).flat()\n\n\t\t\tfor (const successor of successors) {\n\t\t\t\tconst successorId = String(successor.id!)\n\t\t\t\tif (!visitedBy.has(successorId))\n\t\t\t\t\tvisitedBy.set(successorId, new Set())\n\n\t\t\t\tconst visitorSet = visitedBy.get(successorId)!\n\t\t\t\tconst startingPointsVistingThisNode = visitedBy.get(currentId)!\n\n\t\t\t\tfor (const startNodeId of startingPointsVistingThisNode)\n\t\t\t\t\tvisitorSet.add(startNodeId)\n\n\t\t\t\tif (visitorSet.size === parallelNodes.length) {\n\t\t\t\t\treturn successor\n\t\t\t\t}\n\n\t\t\t\tif (!queue.includes(successorId))\n\t\t\t\t\tqueue.push(successorId)\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.warn('[GraphBuilder] Parallel branches do not seem to converge.')\n\t\treturn undefined\n\t}\n}\n","import type { Context, ContextTransform } from './context'\nimport type { NodeArgs, Params } from './types'\nimport type { Flow, Node } from './workflow'\nimport { SequenceFlow } from './builder/patterns'\nimport { composeContext } from './context'\nimport { Node as BaseNode } from './workflow'\n\n/**\n * A type for a pure function that can be executed within a `Node`,\n * typically taking the node's `params` as input.\n * @template TIn The input type, corresponding to `params`.\n * @template TOut The output type, which becomes the node's `execRes`.\n */\nexport type NodeFunction<TIn = any, TOut = any> = (input: TIn) => TOut | Promise<TOut>\n\n/**\n * A type for a function that operates on the shared `Context` in addition\n * to the node's `params`.\n * @template TIn The input type, corresponding to `params`.\n * @template TOut The output type, which becomes the node's `execRes`.\n */\nexport type ContextFunction<TIn = any, TOut = any> = (ctx: Context, input: TIn) => TOut | Promise<TOut>\n\n/**\n * Creates a `Node` from a simple, pure function that transforms an input to an output.\n * The node's `params` object is passed as the input to the function.\n *\n * @example\n * const add = (n: number) => mapNode<{ value: number }, number>(params => params.value + n)\n * const add5Node = add(5) // A reusable node that adds 5 to its input parameter.\n *\n * @param fn A function that takes an input object and returns a result.\n * @returns A new `Node` instance that wraps the function.\n */\nexport function mapNode<TIn extends Params, TOut>(fn: NodeFunction<TIn, TOut>): Node<void, TOut, any, TIn> {\n\treturn new class extends BaseNode<void, TOut, any, TIn> {\n\t\tasync exec({ params }: NodeArgs<void, void, TIn>): Promise<TOut> {\n\t\t\treturn fn(params as TIn)\n\t\t}\n\t}()\n}\n\n/**\n * Creates a `Node` from a function that requires access to the shared `Context`.\n * Both the `Context` and the node's `params` are passed as arguments to the function.\n *\n * @example\n * const greeter = contextNode((ctx, params: { name: string }) => {\n * const language = ctx.get(LANGUAGE_KEY) || 'en'\n * return language === 'en' ? `Hello, ${params.name}` : `Hola, ${params.name}`\n * })\n *\n * @param fn A function that takes the context and an input object, and returns a result.\n * @returns A new `Node` instance that wraps the function.\n */\nexport function contextNode<TIn extends Params, TOut>(fn: ContextFunction<TIn, TOut>): Node<void, TOut, any, TIn> {\n\treturn new class extends BaseNode<void, TOut, any, TIn> {\n\t\tasync exec({ ctx, params }: NodeArgs<void, void, TIn>): Promise<TOut> {\n\t\t\treturn fn(ctx, params as TIn)\n\t\t}\n\t}()\n}\n\n/**\n * Creates a `Node` that declaratively applies a series of transformations to the `Context`.\n * This is a \"side-effect\" node used purely for state management; its logic runs in the `prep` phase,\n * and it does not produce an `exec` output.\n *\n * @example\n * const USER_ID = contextKey<string>('user_id')\n * const userLens = lens(USER_ID)\n * const setupUserContext = (userId: string) => transformNode(userLens.set(userId))\n *\n * @param transforms A sequence of `ContextTransform` functions (e.g., from a lens) to apply.\n * @returns A new `Node` instance that will mutate the context when executed.\n */\nexport function transformNode(...transforms: ContextTransform[]): Node {\n\treturn new class extends BaseNode {\n\t\tasync prep({ ctx }: NodeArgs) {\n\t\t\t// Apply the composed transformations directly to the mutable context.\n\t\t\tcomposeContext(...transforms)(ctx)\n\t\t}\n\t}()\n}\n\n/**\n * A functional-style alias for `SequenceFlow`. It constructs a linear workflow\n * where each node executes in the order it is provided.\n *\n * @example\n * const mathPipeline = pipeline(addNode(5), multiplyNode(2))\n *\n * @param nodes A sequence of `Node` instances to chain together.\n * @returns A `Flow` instance representing the linear sequence.\n */\nexport function pipeline(...nodes: Node[]): Flow {\n\treturn new SequenceFlow(...nodes)\n}\n\n/**\n * A classic functional composition utility. It takes two functions, `f` and `g`,\n * and returns a new function that computes `f(g(x))`.\n *\n * This is a general-purpose helper, not a `Node` builder itself, but it can be\n * used to create more complex `NodeFunction`s to pass to `mapNode`.\n *\n * @example\n * const add5 = (x: number) => x + 5\n * const multiply2 = (x: number) => x * 2\n * const add5ThenMultiply2 = compose(multiply2, add5) // equivalent to: x => (x + 5) * 2\n *\n * @param f The outer function, which receives the result of `g`.\n * @param g The inner function, which receives the initial input.\n * @returns A new `NodeFunction` that combines both operations.\n */\nexport function compose<A, B, C>(f: NodeFunction<B, C>, g: NodeFunction<A, B>): NodeFunction<A, C> {\n\treturn async (input: A) => f(await g(input))\n}\n"],"mappings":"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","names":["AbortError","message","WorkflowError","nodeName","phase","originalError","combinedMessage","FatalWorkflowError","NullLogger","levelPriorities","ConsoleLogger","options","level","message","context","fullMessage","applyMiddleware","middleware","nodeToRun","runNode","args","next","mw","InMemoryExecutor","startNode","flowMiddleware","context","options","currentNode","nextNode","action","logger","signal","AbortError","nodeArgs","applyMiddleware","flow","_a","NullLogger","combinedParams","internalOptions","curr","actionDisplay","DEFAULT_ACTION","FILTER_FAILED","isNodeType","type","node","analyzeGraph","graph","typedGraph","analysis","allNodeIds","adj","edge","source","target","id","visited","recursionStack","detectCycleUtil","nodeId","path","neighbors","neighbor","cycleStartIndex","cycle","createNodeRule","description","filter","check","_graph","errors","result","checkForCycles","uniqueCycles","c","cycleKey","representativeCycle","getActionLabel","action","DEFAULT_ACTION","FILTER_FAILED","getNodeLabel","node","uniqueId","type","id","getUniqueNodeId","nameCounts","idMap","baseName","sanitizedBaseName","count","generateMermaidGraph","flow","nodes","edges","visited","queue","currentNode","sourceId","container","internalNode","targetId","successorNode","label","edge","sanitizeGraph","rawGraph","nodes","id","type","data","config","edges","source","target","action","sleep","ms","signal","resolve","reject","AbortError","timeoutId","AbstractNode","id","data","params","node","action","DEFAULT_ACTION","Node","_Node","options","phase","AbortError","WorkflowError","args","_a","_b","lastError","curRetry","e","error","FatalWorkflowError","sleep","ctx","signal","logger","executor","Flow","prepRes","execRes","actionDisplay","NullLogger","InMemoryExecutor","fn","originalNode","maxRetries","wait","originalResult","_args","key","predicate","result","FILTER_FAILED","lens","value","ExecNode","PreNode","PostNode","start","combinedParams","internalOptions","finalAction","queue","visited","currentNode","successor","contextKey","description","TypedContext","initialData","key","value","lens","ctx","fn","composeContext","transforms","acc","transform","SequenceFlow","Flow","nodes","current","i","ParallelFlow","nodesToRun","ctx","params","signal","logger","executor","promises","node","result","BatchFlow","_args","args","_a","combinedParams","batchParamsIterable","batchParamsList","batchParams","AbortError","ParallelBatchFlow","results","mapCollection","items","fn","item","filterCollection","predicate","_","index","reduceCollection","reducer","initialValue","accumulator","createNodeRegistry","registry","InputMappingNode","Node","options","nodeId","mappings","ctx","logger","subKey","parentKey","OutputMappingNode","SubWorkflowContainerNode","ParallelBranchContainer","ParallelFlow","nodesToRun","GraphBuilder","nodeOptionsContext","NullLogger","flow","generateMermaidGraph","line","graph","idPrefix","finalNodes","finalEdges","localNodeIds","n","node","prefixedNodeId","sanitizedId","isRegisteredSubWorkflow","hasWorkflowId","newNodeData","inputs","templateKey","sourcePathOrPaths","newSourcePaths","sourcePath","subWorkflowData","subWorkflowId","subGraph","inputMapperId","outputMapperId","inlinedSubGraph","augmentedInlinedNodes","subGraphStartIds","id","e","startId","subGraphTerminalIds","terminalId","edge","sourceNode","prefixedSourceId","prefixedTargetId","isSourceSub","sanitizedSourceId","log","flatGraph","nodeMap","graphNode","NodeClass","nodeOptions","executableNode","edgeGroups","sourceId","action","DEFAULT_ACTION","targetNode","sourceActions","actions","successors","parallelNode","branchNode","branchSuccessors","branchAction","branchTargets","target","convergenceNode","allNodeIds","allTargetIds","startNodeIds","predecessorIdMap","originalPredecessorIdMap","predecessorCountMap","key","val","startNode","startNodes","parallelStartNode","Flow","_a","_b","_c","_d","sourceOriginalId","mapKey","originalPreds","parallelNodes","queue","visitedBy","head","currentId","successor","successorId","visitorSet","startingPointsVistingThisNode","startNodeId","mapNode","fn","Node","params","contextNode","ctx","transformNode","transforms","composeContext","pipeline","nodes","SequenceFlow","compose","f","g","input"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "flowcraft",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.12",
4
+ "version": "1.0.0-beta.14",
5
5
  "packageManager": "pnpm@10.13.1",
6
6
  "description": "A flexible workflow framework",
7
7
  "repository": {