flowcraft 1.0.0-beta.3 → 1.0.0-beta.5
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/dist/index.d.ts +49 -17
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -9
package/dist/index.d.ts
CHANGED
|
@@ -80,6 +80,38 @@ declare function lens<T>(key: ContextKey<T>): ContextLens<T>;
|
|
|
80
80
|
*/
|
|
81
81
|
declare function composeContext(...transforms: ContextTransform[]): ContextTransform;
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Defines the schema for all custom node types within a specific workflow application.
|
|
85
|
+
*
|
|
86
|
+
* It is a map where each key is a string identifier for a node `type`
|
|
87
|
+
* (e.g., `'llm-process'`), and the value is an object defining the expected
|
|
88
|
+
* shape of that node's `data` payload.
|
|
89
|
+
*
|
|
90
|
+
* By creating an application-specific interface that extends `NodeTypeMap`,
|
|
91
|
+
* you enable compile-time validation and autocompletion for your declarative
|
|
92
|
+
* graph definitions. This type is the central generic constraint used by
|
|
93
|
+
* `TypedWorkflowGraph`, `TypedNodeRegistry`, and `GraphBuilder` to provide a
|
|
94
|
+
* fully type-safe development experience.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* // 1. Define the data payloads for your application's nodes.
|
|
98
|
+
* interface MyAppNodeTypeMap extends NodeTypeMap {
|
|
99
|
+
* 'api-call': { url: string; retries: number };
|
|
100
|
+
* 'data-transform': { mode: 'uppercase' | 'lowercase' };
|
|
101
|
+
* 'output': { destination: string };
|
|
102
|
+
* }
|
|
103
|
+
*
|
|
104
|
+
* // 2. Use it to create a type-safe graph definition.
|
|
105
|
+
* const myGraph: TypedWorkflowGraph<MyAppNodeTypeMap> = {
|
|
106
|
+
* nodes: [
|
|
107
|
+
* // TypeScript will validate that `data` matches the 'api-call' schema.
|
|
108
|
+
* { id: 'fetch', type: 'api-call', data: { url: '/users', retries: 3 } },
|
|
109
|
+
* // TypeScript would throw an error on the following line:
|
|
110
|
+
* { id: 'bad', type: 'api-call', data: { path: '/users' } } // Missing 'url' and 'retries'
|
|
111
|
+
* ],
|
|
112
|
+
* edges: [],
|
|
113
|
+
* };
|
|
114
|
+
*/
|
|
83
115
|
interface NodeTypeMap {
|
|
84
116
|
[key: string]: Record<string, any>;
|
|
85
117
|
}
|
|
@@ -406,24 +438,24 @@ declare class Node<PrepRes = any, ExecRes = any, PostRes = any> extends Abstract
|
|
|
406
438
|
/**
|
|
407
439
|
* (Lifecycle) Prepares data for execution. Runs once before `exec`.
|
|
408
440
|
* This is the ideal place to read data from the `Context`.
|
|
409
|
-
* @param
|
|
441
|
+
* @param args The arguments for the node, including `ctx` and `params`.
|
|
410
442
|
* @returns The data required by the `exec` phase.
|
|
411
443
|
*/
|
|
412
|
-
prep(
|
|
444
|
+
prep(args: NodeArgs<void, void>): Promise<PrepRes>;
|
|
413
445
|
/**
|
|
414
446
|
* (Lifecycle) Performs the core, isolated logic of the node.
|
|
415
447
|
* This is the only phase that is retried on failure. It should not access the `Context` directly.
|
|
416
|
-
* @param
|
|
448
|
+
* @param args The arguments for the node, including `prepRes`.
|
|
417
449
|
* @returns The result of the execution.
|
|
418
450
|
*/
|
|
419
|
-
exec(
|
|
451
|
+
exec(args: NodeArgs<PrepRes, void>): Promise<ExecRes>;
|
|
420
452
|
/**
|
|
421
453
|
* (Lifecycle) Processes results and determines the next step. Runs once after `exec` succeeds.
|
|
422
454
|
* This is the ideal place to write data to the `Context`.
|
|
423
|
-
* @param
|
|
455
|
+
* @param args The arguments for the node, including `execRes`.
|
|
424
456
|
* @returns An "action" string to determine which successor to execute next. Defaults to `DEFAULT_ACTION`.
|
|
425
457
|
*/
|
|
426
|
-
post(
|
|
458
|
+
post(args: NodeArgs<PrepRes, ExecRes>): Promise<PostRes>;
|
|
427
459
|
/**
|
|
428
460
|
* (Lifecycle) A fallback that runs if all `exec` retries fail.
|
|
429
461
|
* If not implemented, the final error will be re-thrown, halting the workflow.
|
|
@@ -540,7 +572,7 @@ declare class Node<PrepRes = any, ExecRes = any, PostRes = any> extends Abstract
|
|
|
540
572
|
* A special type of `Node` that orchestrates a graph of other nodes.
|
|
541
573
|
* It can contain its own middleware and can be composed within other flows.
|
|
542
574
|
*/
|
|
543
|
-
declare class Flow extends Node<
|
|
575
|
+
declare class Flow<PrepRes = any, ExecRes = any, PostRes = ExecRes> extends Node<PrepRes, ExecRes, PostRes> {
|
|
544
576
|
/** The first node to be executed in this flow's graph. */
|
|
545
577
|
startNode?: AbstractNode;
|
|
546
578
|
/** An array of middleware functions to be applied to every node within this flow. */
|
|
@@ -570,20 +602,20 @@ declare class Flow extends Node<any, any, any> {
|
|
|
570
602
|
* @param args The arguments for the node, passed down from the parent executor.
|
|
571
603
|
* @returns The final action returned by the last node in this flow's graph.
|
|
572
604
|
*/
|
|
573
|
-
exec(args: NodeArgs<any, any>): Promise<
|
|
605
|
+
exec(args: NodeArgs<any, any>): Promise<ExecRes>;
|
|
574
606
|
/**
|
|
575
607
|
* (Lifecycle) The post-execution step for a `Flow` node. It simply passes through
|
|
576
608
|
* the final action from its internal graph execution (`execRes`).
|
|
577
609
|
* @internal
|
|
578
610
|
*/
|
|
579
|
-
post({ execRes }: NodeArgs<any,
|
|
611
|
+
post({ execRes }: NodeArgs<any, ExecRes>): Promise<PostRes>;
|
|
580
612
|
/**
|
|
581
613
|
* Runs the entire flow as a top-level entry point.
|
|
582
614
|
* @param ctx The shared workflow context.
|
|
583
615
|
* @param options Runtime options like a logger, abort controller, or a custom executor.
|
|
584
616
|
* @returns The final action returned by the last node in the flow.
|
|
585
617
|
*/
|
|
586
|
-
run(ctx: Context, options?: RunOptions): Promise<
|
|
618
|
+
run(ctx: Context, options?: RunOptions): Promise<PostRes>;
|
|
587
619
|
/**
|
|
588
620
|
* Finds a node within the flow's graph by its unique ID.
|
|
589
621
|
*
|
|
@@ -690,7 +722,7 @@ declare function compose<A, B, C>(f: NodeFunction<B, C>, g: NodeFunction<A, B>):
|
|
|
690
722
|
* A `Flow` that creates a linear workflow from a sequence of nodes,
|
|
691
723
|
* automatically chaining them in order.
|
|
692
724
|
*/
|
|
693
|
-
declare class SequenceFlow extends Flow {
|
|
725
|
+
declare class SequenceFlow<PrepRes = any, ExecRes = any, PostRes = ExecRes> extends Flow<PrepRes, ExecRes, PostRes> {
|
|
694
726
|
/**
|
|
695
727
|
* @param nodes A sequence of `Node` or `Flow` instances to be executed in order.
|
|
696
728
|
*/
|
|
@@ -701,7 +733,7 @@ declare class SequenceFlow extends Flow {
|
|
|
701
733
|
* This is the core of the "fan-out, fan-in" pattern for structural parallelism.
|
|
702
734
|
* After all parallel branches complete, the flow can proceed to a single successor.
|
|
703
735
|
*/
|
|
704
|
-
declare class ParallelFlow extends Flow {
|
|
736
|
+
declare class ParallelFlow extends Flow<any, void, void> {
|
|
705
737
|
protected nodesToRun: AbstractNode[];
|
|
706
738
|
/**
|
|
707
739
|
* @param nodesToRun The array of nodes to execute concurrently.
|
|
@@ -718,7 +750,7 @@ declare class ParallelFlow extends Flow {
|
|
|
718
750
|
* Subclasses must implement the `prep` method to provide the items and the
|
|
719
751
|
* `nodeToRun` property to define the processing logic for each item.
|
|
720
752
|
*/
|
|
721
|
-
declare abstract class BatchFlow extends Flow {
|
|
753
|
+
declare abstract class BatchFlow extends Flow<any, null, any> {
|
|
722
754
|
/**
|
|
723
755
|
* The `Node` instance that will be executed for each item in the batch.
|
|
724
756
|
* This must be implemented by any subclass.
|
|
@@ -745,7 +777,7 @@ declare abstract class BatchFlow extends Flow {
|
|
|
745
777
|
* `nodeToRun` property to define the processing logic for each item.
|
|
746
778
|
* This provides a significant performance boost for I/O-bound tasks.
|
|
747
779
|
*/
|
|
748
|
-
declare abstract class ParallelBatchFlow extends Flow {
|
|
780
|
+
declare abstract class ParallelBatchFlow extends Flow<any, PromiseSettledResult<any>[], any> {
|
|
749
781
|
/**
|
|
750
782
|
* The `Node` instance that will be executed concurrently for each item in the batch.
|
|
751
783
|
* This must be implemented by any subclass.
|
|
@@ -780,7 +812,7 @@ declare abstract class ParallelBatchFlow extends Flow {
|
|
|
780
812
|
* @param fn An async or sync function that transforms an item from type `T` to type `U`.
|
|
781
813
|
* @returns A `Flow` instance that, when run, will output an array of type `U[]`.
|
|
782
814
|
*/
|
|
783
|
-
declare function mapCollection<T, U>(items: T[], fn: NodeFunction<T, U>): Flow
|
|
815
|
+
declare function mapCollection<T, U>(items: T[], fn: NodeFunction<T, U>): Flow<void, U[], U[]>;
|
|
784
816
|
/**
|
|
785
817
|
* Creates a flow that filters a collection based on a predicate function,
|
|
786
818
|
* returning a new array containing only the items that pass the predicate.
|
|
@@ -796,7 +828,7 @@ declare function mapCollection<T, U>(items: T[], fn: NodeFunction<T, U>): Flow;
|
|
|
796
828
|
* @param predicate An async or sync function that returns `true` or `false` for an item.
|
|
797
829
|
* @returns A `Flow` instance that, when run, will output a filtered array of type `T[]`.
|
|
798
830
|
*/
|
|
799
|
-
declare function filterCollection<T>(items: T[], predicate: (item: T) => boolean | Promise<boolean>): Flow
|
|
831
|
+
declare function filterCollection<T>(items: T[], predicate: (item: T) => boolean | Promise<boolean>): Flow<void, T[], T[]>;
|
|
800
832
|
/**
|
|
801
833
|
* Creates a flow that reduces a collection to a single value by executing a
|
|
802
834
|
* reducer function sequentially for each item, similar to `Array.prototype.reduce()`.
|
|
@@ -812,7 +844,7 @@ declare function filterCollection<T>(items: T[], predicate: (item: T) => boolean
|
|
|
812
844
|
* @param initialValue The initial value for the accumulator.
|
|
813
845
|
* @returns A `Flow` instance that, when run, will output the final accumulated value of type `U`.
|
|
814
846
|
*/
|
|
815
|
-
declare function reduceCollection<T, U>(items: T[], reducer: (accumulator: U, item: T) => U | Promise<U>, initialValue: U): Flow
|
|
847
|
+
declare function reduceCollection<T, U>(items: T[], reducer: (accumulator: U, item: T) => U | Promise<U>, initialValue: U): Flow<void, U, U>;
|
|
816
848
|
|
|
817
849
|
/**
|
|
818
850
|
* A type-safe helper function for creating a `TypedNodeRegistry`.
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var h=class extends Error{constructor(e="Workflow aborted"){super(e),this.name="AbortError"}},C=class extends Error{constructor(t,r,o,n){super(t);this.nodeName=r;this.phase=o;this.originalError=n;this.name="WorkflowError",n!=null&&n.stack&&(this.stack=`${this.stack}
|
|
2
|
-
Caused by: ${n.stack}`)}};var
|
|
2
|
+
Caused by: ${n.stack}`)}};var I=class{async _orch(e,t,r,o){let n=e,a,{logger:d,signal:i,params:p,executor:l}=o;for(;n;){if(i!=null&&i.aborted)throw new h;let u=this.applyMiddleware(t,n),m={ctx:r,params:p,signal:i,logger:d,prepRes:void 0,execRes:void 0,name:n.constructor.name,executor:l};a=await u(m);let f=n;n=this.getNextNode(f,a,d)}return a}async run(e,t,r){let o=(r==null?void 0:r.logger)??new A,n=r==null?void 0:r.controller,a={...e.params,...r==null?void 0:r.params},d={logger:o,signal:n==null?void 0:n.signal,params:a,executor:this};return e.startNode?(o.info(`Executor is running flow graph: ${e.constructor.name}`),this._orch(e.startNode,e.middleware,t,d)):(o.info(`Executor is running a logic-bearing flow: ${e.constructor.name}`),await this.applyMiddleware(e.middleware,e)({...d,ctx:t,prepRes:void 0,execRes:void 0,name:e.constructor.name}))}getNextNode(e,t,r){let o=e.successors.get(t),n=typeof t=="symbol"?t.toString():t;return o?r.debug(`Action '${n}' from ${e.constructor.name} leads to ${o.constructor.name}`,{action:t}):e.successors.size>0&&t!==void 0&&t!==null&&r.info(`Flow ends: Action '${n}' from ${e.constructor.name} has no configured successor.`),o}applyMiddleware(e,t){let r=o=>t._run({ctx:o.ctx,params:{...o.params,...t.params},signal:o.signal,logger:o.logger,executor:o.executor});return!e||e.length===0?r:e.reduceRight((o,n)=>a=>n(a,o),r)}};var A=class{debug(){}info(){}warn(){}error(){}},K=class{log(e,t,r){let o=`[${e.toUpperCase()}] ${t}`;r&&Object.keys(r).length>0?console[e](o,r):console[e](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)}};var w=Symbol("default"),_=Symbol("filter_failed");function se(s){return e=>e.type===s}function ne(s){let e=s,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 n=new Set,a=new Set;function d(i,p){n.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),f=p.slice(m);t.cycles.push([...f,u])}else n.has(u)||d(u,p);a.delete(i),p.pop()}for(let i of r)n.has(i)||d(i,[]);return t}function ae(s,e,t){return(r,o)=>{let n=[];for(let a of r.nodes.values())if(e(a)){let d=t(a);d.valid||n.push({nodeId:a.id,type:"ConnectionRuleViolation",message:d.message||`Node ${a.id} failed rule: ${s}`})}return n}}var ie=s=>{let e=new Set(s.cycles.map(t=>t.slice(0,-1).sort().join(",")));return Array.from(e).map(t=>{let r=s.cycles.find(o=>o.slice(0,-1).sort().join(",")===t);return{nodeId:r[0],type:"CycleDetected",message:`Cycle detected involving nodes: ${r.join(" -> ")}`}})};function Q(s){return s===w?"":s===_?'"filter failed"':`"${s.toString().replace(/"/g,"")}"`}function X(s,e){if(s.isParallelContainer)return` ${e}{Parallel Block}`;if(s.constructor.name==="InputMappingNode")return` ${e}(("Inputs"))`;if(s.constructor.name==="OutputMappingNode")return` ${e}(("Outputs"))`;if(s.graphData){let t=s.graphData.type,r=s.graphData.id.split(":").pop();return` ${e}["${r} (${t})"]`}return` ${e}[${s.constructor.name}]`}function G(s,e,t){if(t.has(s))return t.get(s);let r;s.isParallelContainer?r="ParallelBlock":s.graphData?r=s.graphData.id:r=s.constructor.name;let o=r.replace(/:/g,"_").replace(/\W/g,""),n=e.get(o)||0,a=`${o}_${n}`;return e.set(o,n+1),t.set(s,a),a}function U(s){if(!s.startNode)return`graph TD
|
|
3
3
|
%% Empty Flow`;let e=new Set,t=new Set,r=new Set,o=[s.startNode],n=new Map,a=new Map;for(r.add(s.startNode),G(s.startNode,a,n);o.length>0;){let i=o.shift(),p=G(i,a,n);if(e.add(X(i,p)),i.isParallelContainer){let l=i;for(let u of l.nodesToRun){let m=G(u,a,n);t.add(` ${p} --> ${m}`),r.has(u)||(r.add(u),o.push(u))}}for(let[l,u]of i.successors.entries()){let m=G(u,a,n),f=Q(l),P=f?` ${p} -- ${f} --> ${m}`:` ${p} --> ${m}`;t.add(P),r.has(u)||(r.add(u),o.push(u))}}return["graph TD",...Array.from(e),...Array.from(t)].join(`
|
|
4
|
-
`)}async function
|
|
5
|
-
`).forEach(r=>this.logger.info(r)))}_flattenGraph(e,t=""){let r=[],o=[],n=new Set(e.nodes.map(a=>a.id));for(let a of e.nodes){let d=`${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[m,f]of Object.entries(u)){let
|
|
4
|
+
`)}async function j(s,e){return new Promise((t,r)=>{if(e!=null&&e.aborted)return r(new h);let o=setTimeout(t,s);e==null||e.addEventListener("abort",()=>{clearTimeout(o),r(new h)})})}var ye=s=>Symbol(s),B=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 xe(s){return{get:e=>e.get(s),set:e=>t=>t.set(s,e),update:e=>t=>t.set(s,e(t.get(s)))}}function V(...s){return e=>s.reduce((t,r)=>r(t),e)}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=w){return this.successors.set(t,e),e}},T=class s extends F{maxRetries;wait;constructor(e={}){super(),this.maxRetries=e.maxRetries??1,this.wait=e.wait??0}_wrapError(e,t){return e instanceof h||e instanceof C?e:new C(`Failed in ${t} phase for node ${this.constructor.name}`,this.constructor.name,t,e)}async prep(e){}async exec(e){}async post(e){return w}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 n=0;n<this.maxRetries;n++){if((r=e.signal)!=null&&r.aborted)throw new h;try{return await this.exec(e)}catch(a){let d=a;if(t=d,d instanceof h||d.name==="AbortError")throw d;n<this.maxRetries-1&&(e.logger.warn(`Attempt ${n+1}/${this.maxRetries} failed for ${this.constructor.name}. Retrying...`,{error:d}),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 h;return await this.execFallback({...e,error:t})}async _run({ctx:e,params:t,signal:r,logger:o,executor:n}){if(this instanceof N?o.info(`Running flow: ${this.constructor.name}`,{params:t}):o.info(`Running node: ${this.constructor.name}`,{params:t}),r!=null&&r.aborted)throw new h;let a;try{a=await this.prep({ctx:e,params:t,signal:r,logger:o,prepRes:void 0,execRes:void 0,executor:n})}catch(i){throw this._wrapError(i,"prep")}if(r!=null&&r.aborted)throw new h;let d;try{d=await this._exec({ctx:e,params:t,signal:r,logger:o,prepRes:a,execRes:void 0,executor:n})}catch(i){throw this._wrapError(i,"exec")}if(r!=null&&r.aborted)throw new h;try{let i=await this.post({ctx:e,params:t,signal:r,logger:o,prepRes:a,execRes:d,executor:n});return i===void 0?w:i}catch(i){throw this._wrapError(i,"post")}}async run(e,t){let r=(t==null?void 0:t.logger)??new A;return this.successors.size>0&&!(this instanceof N)&&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 I).run(new N(this),e,{...t,params:this.params})}map(e){let t=this,r=this.maxRetries,o=this.wait;return new class extends s{constructor(){super({maxRetries:r,wait:o})}async prep(n){return t.prep(n)}async exec(n){let a=await t.exec(n);return e(a)}async post(n){return w}}}toContext(e){let t=this,r=this.maxRetries,o=this.wait;return new class extends s{constructor(){super({maxRetries:r,wait:o})}async prep(n){return t.prep(n)}async exec(n){return t.exec(n)}async post(n){return n.ctx.set(e,n.execRes),w}}}filter(e){let t=this;return new class extends s{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.info(`[Filter] Predicate failed for node ${this.constructor.name}.`),o}async post(r){return this.didPass?w:_}}}tap(e){return this.map(async t=>(await e(t),t))}withLens(e,t){let r=this,o=this.maxRetries,n=this.wait;return new class extends s{constructor(){super({maxRetries:o,wait:n})}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)}}}},N=class extends T{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 I))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.info(`-- 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.info(`-- 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 I).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 n of o.successors.values())r.has(n)||(r.add(n),t.push(n))}}};var $=class extends N{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])}},k=class extends N{constructor(t){super();this.nodesToRun=t}async exec({ctx:t,params:r,signal:o,logger:n,executor:a}){if(this.nodesToRun.length===0){n.info("[ParallelFlow] No branches to execute in parallel.");return}n.info(`[ParallelFlow] Executing ${this.nodesToRun.length} branches in parallel...`);let d=this.nodesToRun.map(p=>p._run({ctx:t,params:{...r,...p.params},signal:o,logger:n,executor:a})),i=await Promise.allSettled(d);n.info("[ParallelFlow] \u2713 All parallel branches finished."),i.forEach(p=>{p.status==="rejected"&&n.error("[ParallelFlow] A parallel branch failed.",{error:p.reason})})}},z=class extends N{constructor(){super()}async prep(e){return[]}async exec(e){var n;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((n=e.signal)!=null&&n.aborted)throw new h;await this.nodeToRun._run({ctx:e.ctx,params:{...t,...a},signal:e.signal,logger:e.logger,executor:e.executor})}return null}},q=class extends N{constructor(){super()}async prep(e){return[]}async exec(e){if(!this.nodeToRun)return null;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 n=o.map(d=>this.nodeToRun._run({ctx:e.ctx,params:{...t,...d},signal:e.signal,logger:e.logger,executor:e.executor})),a=await Promise.allSettled(n);for(let d of a)d.status==="rejected"&&e.logger.error("A parallel batch item failed.",{error:d.reason});return a}};function ve(s,e){return new class extends N{async exec(){let t=s.map(r=>e(r));return Promise.all(t)}}}function Le(s,e){return new class extends N{async exec(){let t=await Promise.all(s.map(r=>e(r)));return s.filter((r,o)=>t[o])}}}function Se(s,e,t){return new class extends N{async exec(r){var n;let o=t;for(let a of s){if((n=r.signal)!=null&&n.aborted)throw new h;o=await e(o,a)}return o}}}function ze(s){return s}var v=class extends T{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.`)}},L=class extends T{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.`)}},M=class extends k{constructor(t){super(t);this.nodesToRun=t}isParallelContainer=!0},J=class{constructor(e,t={},r={},o=new A){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__",v),this.registry.set("__internal_output_mapper__",L),this.subWorkflowNodeTypes=r.subWorkflowNodeTypes??[]}registry;subWorkflowNodeTypes;logger;_logMermaid(e){this.logger instanceof A||(this.logger.info("[GraphBuilder] Flattened Graph"),U(e).split(`
|
|
5
|
+
`).forEach(r=>this.logger.info(r)))}_flattenGraph(e,t=""){let r=[],o=[],n=new Set(e.nodes.map(a=>a.id));for(let a of e.nodes){let d=`${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[m,f]of Object.entries(u)){let E=(Array.isArray(f)?f:[f]).map(R=>n.has(R)?`${t}${R}`:R);u[m]=Array.isArray(f)?E:E[0]}}if(i){let u=a.data,m=u.workflowId,f=this.nodeOptionsContext.registry;if(!f||typeof f.getGraph!="function")throw new Error("GraphBuilder needs a registry with a `getGraph` method in its context to resolve sub-workflows.");let P=f.getGraph(m);if(!P)throw new Error(`Sub-workflow with ID ${m} not found in registry.`);let E=`${d}_input_mapper`,R=`${d}_output_mapper`;r.push({id:E,type:"__internal_input_mapper__",data:u.inputs||{}}),r.push({id:R,type:"__internal_output_mapper__",data:u.outputs||{}});let c=this._flattenGraph(P,`${d}:`);r.push(...c.nodes),o.push(...c.edges);let y=c.nodes.map(g=>g.id).filter(g=>!c.edges.some(x=>x.target===g));for(let g of y)o.push({source:E,target:g,action:w});let b=c.nodes.map(g=>g.id).filter(g=>!c.edges.some(x=>x.source===g));for(let g of b)o.push({source:g,target:R,action:w})}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:d,data:l})}}for(let a of e.edges){let d=e.nodes.find(f=>f.id===a.source),i=e.nodes.find(f=>f.id===a.target),p=`${t}${a.source}`,l=`${t}${a.target}`,u=this.subWorkflowNodeTypes.includes(d.type),m=this.subWorkflowNodeTypes.includes(i.type);u&&m?o.push({...a,source:`${p}_output_mapper`,target:`${l}_input_mapper`}):u?o.push({...a,source:`${p}_output_mapper`,target:l}):m?o.push({...a,source:p,target:`${l}_input_mapper`}):o.push({...a,source:p,target:l})}return{nodes:r,edges:o}}build(e){var f,P,E,R;let t=this._flattenGraph(e),r=new Map,o=new Map;for(let c of t.edges)o.has(c.target)||o.set(c.target,new Set),o.get(c.target).add(c.source);let n=new Map;for(let c of t.nodes){let y=o.get(c.id);n.set(c.id,y?y.size:0)}for(let c of t.nodes){let y=this.registry.get(c.type.toString());if(!y)throw new Error(`GraphBuilder: Node type '${c.type.toString()}' not found in the registry.`);let b={...this.nodeOptionsContext,data:{...c.data,nodeId:c.id}},g=new y(b).withId(c.id).withGraphData(c);r.set(c.id,g)}let a=new Map;for(let c of t.edges){let y=c.source,b=c.action||w,g=r.get(c.target);a.has(y)||a.set(y,new Map);let x=a.get(y);x.has(b)||x.set(b,[]),x.get(b).push(g)}for(let[c,y]of a.entries()){let b=r.get(c);for(let[g,x]of y.entries())if(x.length===1)b.next(x[0],g);else if(x.length>1){let S=new M(x);b.next(S,g);let O=(P=(f=a.get(x[0].id.toString()))==null?void 0:f.get(w))==null?void 0:P[0];O&&x.slice(1).every(H=>{var D,W;return((W=(D=a.get(H.id.toString()))==null?void 0:D.get(w))==null?void 0:W[0])===O})&&S.next(O)}}let d=Array.from(r.keys()),i=new Set(t.edges.map(c=>c.target)),p=d.filter(c=>!i.has(c));if(p.length===0&&d.length>0)throw new Error("GraphBuilder: This graph has a cycle and no clear start node.");if(p.length===1){let c=r.get(p[0]),y=new N(c);return this._logMermaid(y),{flow:y,nodeMap:r,predecessorCountMap:n}}let l=p.map(c=>r.get(c)),u=new M(l);if(l.length>0){let c=(R=(E=a.get(l[0].id.toString()))==null?void 0:E.get(w))==null?void 0:R[0];c&&l.slice(1).every(b=>{var g,x;return((x=(g=a.get(b.id.toString()))==null?void 0:g.get(w))==null?void 0:x[0])===c})&&u.next(c)}let m=new N(u);return this._logMermaid(m),{flow:m,nodeMap:r,predecessorCountMap:n}}};function tt(s){return new class extends T{async exec({params:e}){return s(e)}}}function rt(s){return new class extends T{async exec({ctx:e,params:t}){return s(e,t)}}}function ot(...s){return new class extends T{async prep({ctx:e}){V(...s)(e)}}}function st(...s){return new $(...s)}function nt(s,e){return async t=>s(await e(t))}export{h as AbortError,F as AbstractNode,z as BatchFlow,K as ConsoleLogger,w as DEFAULT_ACTION,_ as FILTER_FAILED,N as Flow,J as GraphBuilder,I as InMemoryExecutor,T as Node,A as NullLogger,q as ParallelBatchFlow,k as ParallelFlow,$ as SequenceFlow,B as TypedContext,C as WorkflowError,ne as analyzeGraph,ie as checkForCycles,nt as compose,V as composeContext,ye as contextKey,rt as contextNode,ze as createNodeRegistry,ae as createNodeRule,Le as filterCollection,U as generateMermaidGraph,se as isNodeType,xe as lens,ve as mapCollection,tt as mapNode,st as pipeline,Se as reduceCollection,j as sleep,ot as transformNode};
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/executors/in-memory.ts","../src/logger.ts","../src/types.ts","../src/utils/graph.ts","../src/utils/mermaid.ts","../src/utils/sleep.ts","../src/context.ts","../src/workflow.ts","../src/builder/collection.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\tsuper(message)\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","import type { IExecutor, InternalRunOptions } from '../executor'\nimport type { AbstractNode, Context, Flow, Logger, Middleware, MiddlewareNext, NodeArgs, RunOptions } from '../workflow'\nimport { AbortError, NullLogger } from '../workflow'\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(\n\t\tstartNode: AbstractNode,\n\t\tflowMiddleware: Middleware[],\n\t\tcontext: Context,\n\t\toptions: InternalRunOptions,\n\t): Promise<any> {\n\t\tlet currentNode: AbstractNode | undefined = startNode\n\t\tlet lastAction: any\n\n\t\tconst { logger, signal, params, executor } = options\n\n\t\twhile (currentNode) {\n\t\t\tif (signal?.aborted)\n\t\t\t\tthrow new AbortError()\n\n\t\t\tconst chain = this.applyMiddleware(flowMiddleware, currentNode)\n\n\t\t\tconst nodeArgs: NodeArgs = {\n\t\t\t\tctx: context,\n\t\t\t\tparams,\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,\n\t\t\t}\n\n\t\t\tlastAction = await chain(nodeArgs)\n\n\t\t\tconst previousNode = currentNode\n\t\t\tcurrentNode = this.getNextNode(previousNode, lastAction, logger)\n\t\t}\n\n\t\treturn lastAction\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 async run(flow: Flow, context: Context, options?: RunOptions): Promise<any> {\n\t\tconst logger = options?.logger ?? new NullLogger()\n\t\tconst controller = options?.controller\n\t\tconst combinedParams = { ...flow.params, ...options?.params }\n\n\t\tconst internalOptions: InternalRunOptions = {\n\t\t\tlogger,\n\t\t\tsignal: 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 = this.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(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.info(`Flow ends: Action '${actionDisplay}' from ${curr.constructor.name} has no configured successor.`)\n\t\t}\n\t\treturn nextNode\n\t}\n\n\t/**\n\t * Composes a chain of middleware functions around a node's execution.\n\t * @internal\n\t */\n\tpublic applyMiddleware(middleware: Middleware[], nodeToRun: AbstractNode): MiddlewareNext {\n\t\t// The final function in the chain is the actual execution of the node.\n\t\tconst runNode: MiddlewareNext = (args: NodeArgs) => {\n\t\t\treturn nodeToRun._run({\n\t\t\t\tctx: args.ctx,\n\t\t\t\tparams: { ...args.params, ...nodeToRun.params },\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\tif (!middleware || middleware.length === 0)\n\t\t\treturn runNode\n\n\t\t// Build the chain backwards, so the first middleware in the array is the outermost.\n\t\treturn middleware.reduceRight<MiddlewareNext>(\n\t\t\t(next, mw) => (args: NodeArgs) => mw(args, next),\n\t\t\trunNode,\n\t\t)\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\n/**\n * A default logger implementation that writes messages to the `console`.\n * Useful for development and debugging.\n */\nexport class ConsoleLogger implements Logger {\n\tprivate log(level: 'debug' | 'info' | 'warn' | 'error', message: string, context?: object) {\n\t\tconst fullMessage = `[${level.toUpperCase()}] ${message}`\n\t\tif (context && Object.keys(context).length > 0)\n\t\t\tconsole[level](fullMessage, context)\n\t\telse\n\t\t\tconsole[level](fullMessage)\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 { Context } from './context'\nimport type { IExecutor } from './executor'\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 */\nexport interface NodeArgs<PrepRes = any, ExecRes = any> {\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: Params\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/** 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 = (args: NodeArgs) => Promise<any>\n/** The function signature for a middleware function. */\nexport type Middleware = (args: NodeArgs, next: MiddlewareNext) => Promise<any>\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","/**\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 { GraphNode } from './builder/graph.types'\nimport type { Context, ContextKey, ContextLens } from './context'\nimport type { InternalRunOptions } from './executor'\nimport type { Middleware, NodeArgs, NodeOptions, NodeRunContext, Params, RunOptions } from './types'\nimport { AbortError, 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\nexport * from './context'\nexport * from './errors'\nexport * from './executor'\nexport * from './logger'\nexport * from './types'\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 */\nexport abstract class AbstractNode {\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: Params = {}\n\t/** A map of successor nodes, keyed by the action that triggers the transition. */\n\tpublic successors = new Map<string | typeof DEFAULT_ACTION | typeof FILTER_FAILED, AbstractNode>()\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: Params): 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 string 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(node: AbstractNode, action: string | typeof DEFAULT_ACTION | typeof FILTER_FAILED = DEFAULT_ACTION): AbstractNode {\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<any>\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 */\nexport class Node<PrepRes = any, ExecRes = any, PostRes = any> extends AbstractNode {\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\t\t}\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>): 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>): 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>): 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>): Promise<ExecRes> {\n\t\tif (args.error) {\n\t\t\tthrow args.error\n\t\t}\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>): 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\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.info(`Running flow: ${this.constructor.name}`, { params })\n\t\t}\n\t\telse {\n\t\t\tlogger.info(`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, signal, logger, prepRes: undefined, execRes: undefined, executor })\n\t\t}\n\t\tcatch (e) {\n\t\t\tthrow this._wrapError(e, 'prep')\n\t\t}\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, signal, logger, prepRes, execRes: undefined, executor })\n\t\t}\n\t\tcatch (e) {\n\t\t\tthrow this._wrapError(e, 'exec')\n\t\t}\n\t\tif (signal?.aborted)\n\t\t\tthrow new AbortError()\n\t\ttry {\n\t\t\tconst action = await this.post({ ctx, params, signal, logger, prepRes, execRes, executor })\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> {\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> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs): Promise<PrepRes> { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes>): 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>): 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> {\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> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs): Promise<PrepRes> { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes>): Promise<ExecRes> { return originalNode.exec(args as any) }\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes>): Promise<any> {\n\t\t\t\targs.ctx.set(key, 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> {\n\t\tconst originalNode = this\n\n\t\treturn new class extends Node<PrepRes, ExecRes, any> {\n\t\t\tprivate didPass = false\n\n\t\t\tasync prep(args: NodeArgs) { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes>): 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.info(`[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>): 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> {\n\t\treturn this.map(async (result) => {\n\t\t\tawait fn(result)\n\t\t\treturn result\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> {\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> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs): 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>): Promise<ExecRes> {\n\t\t\t\treturn originalNode.exec(args as any)\n\t\t\t}\n\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes>): 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 */\nexport class Flow extends Node<any, any, any> {\n\t/** The first node to be executed in this flow's graph. */\n\tpublic startNode?: AbstractNode\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) {\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(start: AbstractNode): AbstractNode {\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>): Promise<any> {\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.info(`-- 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(\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.info(`-- Exiting sub-flow: ${this.constructor.name} --`)\n\t\treturn finalAction\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<any, any>): Promise<any> {\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<any> {\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 | undefined {\n\t\tif (!this.startNode) {\n\t\t\treturn undefined\n\t\t}\n\n\t\tconst queue: AbstractNode[] = [this.startNode]\n\t\tconst visited = new Set<AbstractNode>([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\t\t\t}\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","import type { NodeFunction } from '../functions'\nimport type { AbstractNode, NodeArgs } from '../workflow'\nimport { AbortError, 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 extends Flow {\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 {\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.info('[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\t\tconst results = await Promise.allSettled(promises)\n\t\tlogger.info(`[ParallelFlow] ✓ All parallel branches finished.`)\n\t\t// Check for and log any failures. A more robust implementation might\n\t\t// collect these errors and decide on a specific failure action.\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 extends Flow {\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 extends Flow {\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<any> {\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(`[ParallelBatchFlow] Starting parallel processing of ${batchParamsList.length} items.`)\n\n\t\tconst promises = batchParamsList.map(batchParams =>\n\t\t\tthis.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\t// Optionally handle rejected promises, but don't rethrow to avoid halting the whole batch.\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 {\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 {\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 {\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 { AbstractNode, FILTER_FAILED, Logger, NodeArgs } from '../workflow'\nimport type { BuildResult, GraphBuilderOptions, GraphEdge, GraphNode, NodeRegistry, NodeTypeMap, TypedNodeRegistry, TypedWorkflowGraph, WorkflowGraph } from './graph.types'\nimport { generateMermaidGraph } from '../utils/mermaid'\nimport { DEFAULT_ACTION, Flow, Node, NullLogger } from '../workflow'\nimport { ParallelFlow } from './collection'\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.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\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\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\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\tfinalNodes.push(...inlinedSubGraph.nodes)\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\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\t// Determine the single convergence point for this parallel block.\n\t\t\t\t\tconst firstBranchSuccessor = edgeGroups.get(successors[0].id!.toString())?.get(DEFAULT_ACTION)?.[0]\n\t\t\t\t\tif (firstBranchSuccessor) {\n\t\t\t\t\t\tconst allConverge = successors.slice(1).every(\n\t\t\t\t\t\t\tnode => edgeGroups.get(node.id!.toString())?.get(DEFAULT_ACTION)?.[0] === firstBranchSuccessor,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t// If all branches lead to the same next node, wire the container to it.\n\t\t\t\t\t\tif (allConverge)\n\t\t\t\t\t\t\tparallelNode.next(firstBranchSuccessor)\n\t\t\t\t\t}\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\tthis._logMermaid(flow)\n\t\t\treturn { flow, nodeMap, predecessorCountMap }\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 > 0) {\n\t\t\tconst firstSuccessor = edgeGroups.get(startNodes[0].id!.toString())?.get(DEFAULT_ACTION)?.[0]\n\t\t\tif (firstSuccessor) {\n\t\t\t\tconst allConverge = startNodes.slice(1).every(node => edgeGroups.get(node.id!.toString())?.get(DEFAULT_ACTION)?.[0] === firstSuccessor)\n\t\t\t\tif (allConverge)\n\t\t\t\t\tparallelStartNode.next(firstSuccessor)\n\t\t\t}\n\t\t}\n\n\t\tconst flow = new Flow(parallelStartNode)\n\t\tthis._logMermaid(flow)\n\t\treturn { flow, nodeMap, predecessorCountMap }\n\t}\n}\n","import type { ContextTransform } from './context'\nimport type { Context, Flow, Node, NodeArgs } from './workflow'\nimport { SequenceFlow } from './builder/collection'\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, TOut>(fn: NodeFunction<TIn, TOut>): Node<TIn, TOut> {\n\treturn new class extends BaseNode<TIn, TOut> {\n\t\tasync exec({ params }: NodeArgs<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, TOut>(fn: ContextFunction<TIn, TOut>): Node<TIn, TOut> {\n\treturn new class extends BaseNode<TIn, TOut> {\n\t\tasync exec({ ctx, params }: NodeArgs<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":"AAIO,IAAMA,EAAN,cAAyB,KAAM,CACrC,YAAYC,EAAU,mBAAoB,CACzC,MAAMA,CAAO,EACb,KAAK,KAAO,YACb,CACD,EAMaC,EAAN,cAA4B,KAAM,CAOxC,YACCD,EACgBE,EACAC,EACAC,EACf,CACD,MAAMJ,CAAO,EAJG,cAAAE,EACA,WAAAC,EACA,mBAAAC,EAGhB,KAAK,KAAO,gBACRA,GAAA,MAAAA,EAAe,QAClB,KAAK,MAAQ,GAAG,KAAK,KAAK;AAAA,aAAgBA,EAAc,KAAK,GAC/D,CACD,ECxBO,IAAMC,EAAN,KAA4C,CAWlD,MAAa,MACZC,EACAC,EACAC,EACAC,EACe,CACf,IAAIC,EAAwCJ,EACxCK,EAEE,CAAE,OAAAC,EAAQ,OAAAC,EAAQ,OAAAC,EAAQ,SAAAC,CAAS,EAAIN,EAE7C,KAAOC,GAAa,CACnB,GAAIG,GAAA,MAAAA,EAAQ,QACX,MAAM,IAAIG,EAEX,IAAMC,EAAQ,KAAK,gBAAgBV,EAAgBG,CAAW,EAExDQ,EAAqB,CAC1B,IAAKV,EACL,OAAAM,EACA,OAAAD,EACA,OAAAD,EACA,QAAS,OACT,QAAS,OACT,KAAMF,EAAY,YAAY,KAC9B,SAAAK,CACD,EAEAJ,EAAa,MAAMM,EAAMC,CAAQ,EAEjC,IAAMC,EAAeT,EACrBA,EAAc,KAAK,YAAYS,EAAcR,EAAYC,CAAM,CAChE,CAEA,OAAOD,CACR,CAUA,MAAa,IAAIS,EAAYZ,EAAkBC,EAAoC,CAClF,IAAMG,GAASH,GAAA,YAAAA,EAAS,SAAU,IAAIY,EAChCC,EAAab,GAAA,YAAAA,EAAS,WACtBc,EAAiB,CAAE,GAAGH,EAAK,OAAQ,GAAGX,GAAA,YAAAA,EAAS,MAAO,EAEtDe,EAAsC,CAC3C,OAAAZ,EACA,OAAQU,GAAA,YAAAA,EAAY,OACpB,OAAQC,EACR,SAAU,IACX,EAIA,OAAKH,EAAK,WAYVR,EAAO,KAAK,mCAAmCQ,EAAK,YAAY,IAAI,EAAE,EAG/D,KAAK,MAAMA,EAAK,UAAWA,EAAK,WAAYZ,EAASgB,CAAe,IAd1EZ,EAAO,KAAK,6CAA6CQ,EAAK,YAAY,IAAI,EAAE,EAEzE,MADO,KAAK,gBAAgBA,EAAK,WAAYA,CAAI,EACrC,CAClB,GAAGI,EACH,IAAKhB,EACL,QAAS,OACT,QAAS,OACT,KAAMY,EAAK,YAAY,IACxB,CAAC,EAOH,CAMO,YAAYK,EAAoBC,EAAad,EAA0C,CAC7F,IAAMe,EAAWF,EAAK,WAAW,IAAIC,CAAM,EACrCE,EAAgB,OAAOF,GAAW,SAAWA,EAAO,SAAS,EAAIA,EAEvE,OAAIC,EACHf,EAAO,MAAM,WAAWgB,CAAa,UAAUH,EAAK,YAAY,IAAI,aAAaE,EAAS,YAAY,IAAI,GAAI,CAAE,OAAAD,CAAO,CAAC,EAEhHD,EAAK,WAAW,KAAO,GAAKC,IAAW,QAAaA,IAAW,MACvEd,EAAO,KAAK,sBAAsBgB,CAAa,UAAUH,EAAK,YAAY,IAAI,+BAA+B,EAEvGE,CACR,CAMO,gBAAgBE,EAA0BC,EAAyC,CAEzF,IAAMC,EAA2BC,GACzBF,EAAU,KAAK,CACrB,IAAKE,EAAK,IACV,OAAQ,CAAE,GAAGA,EAAK,OAAQ,GAAGF,EAAU,MAAO,EAC9C,OAAQE,EAAK,OACb,OAAQA,EAAK,OACb,SAAUA,EAAK,QAChB,CAAC,EAGF,MAAI,CAACH,GAAcA,EAAW,SAAW,EACjCE,EAGDF,EAAW,YACjB,CAACI,EAAMC,IAAQF,GAAmBE,EAAGF,EAAMC,CAAI,EAC/CF,CACD,CACD,CACD,EC3HO,IAAMI,EAAN,KAAmC,CACzC,OAAQ,CAAc,CACtB,MAAO,CAAc,CACrB,MAAO,CAAc,CACrB,OAAQ,CAAc,CACvB,EAMaC,EAAN,KAAsC,CACpC,IAAIC,EAA4CC,EAAiBC,EAAkB,CAC1F,IAAMC,EAAc,IAAIH,EAAM,YAAY,CAAC,KAAKC,CAAO,GACnDC,GAAW,OAAO,KAAKA,CAAO,EAAE,OAAS,EAC5C,QAAQF,CAAK,EAAEG,EAAaD,CAAO,EAEnC,QAAQF,CAAK,EAAEG,CAAW,CAC5B,CAEA,MAAMF,EAAiBC,EAAkB,CAAE,KAAK,IAAI,QAASD,EAASC,CAAO,CAAE,CAC/E,KAAKD,EAAiBC,EAAkB,CAAE,KAAK,IAAI,OAAQD,EAASC,CAAO,CAAE,CAC7E,KAAKD,EAAiBC,EAAkB,CAAE,KAAK,IAAI,OAAQD,EAASC,CAAO,CAAE,CAC7E,MAAMD,EAAiBC,EAAkB,CAAE,KAAK,IAAI,QAASD,EAASC,CAAO,CAAE,CAChF,EChCO,IAAME,EAAiB,OAAO,SAAS,EAGjCC,EAAgB,OAAO,eAAe,EC8B5C,SAASC,GAAqDC,EAAS,CAC7E,OAAQC,GACAA,EAAK,OAASD,CAEvB,CAcO,SAASE,GAAoCC,EAAgE,CACnH,IAAMC,EAAaD,EACbE,EAA6B,CAClC,MAAO,IAAI,IACX,WAAY,CAAC,EACb,aAAc,CAAC,EACf,OAAQ,CAAC,CACV,EAEA,GAAI,CAACD,GAAc,CAACA,EAAW,OAAS,CAACA,EAAW,MAAM,OACzD,OAAOC,EAER,IAAMC,EAAaF,EAAW,MAAM,IAAIH,GAAQA,EAAK,EAAE,EACvDI,EAAS,WAAaC,EAEtB,IAAMC,EAA6B,IAAI,IACvCH,EAAW,MAAM,QAASH,GAAS,CAClCI,EAAS,MAAM,IAAIJ,EAAK,GAAI,CAAE,GAAGA,EAAM,SAAU,EAAG,UAAW,CAAE,CAAC,EAClEM,EAAI,IAAIN,EAAK,GAAI,CAAC,CAAC,CACpB,CAAC,EAEDG,EAAW,MAAM,QAASI,GAAS,CAClC,IAAMC,EAASJ,EAAS,MAAM,IAAIG,EAAK,MAAM,EACvCE,EAASL,EAAS,MAAM,IAAIG,EAAK,MAAM,EACzCC,GACHA,EAAO,YACJC,GACHA,EAAO,WACJH,EAAI,IAAIC,EAAK,MAAM,GACtBD,EAAI,IAAIC,EAAK,MAAM,EAAG,KAAKA,EAAK,MAAM,CACxC,CAAC,EAEDH,EAAS,aAAeC,EAAW,OAAOK,GAAMN,EAAS,MAAM,IAAIM,CAAE,EAAG,WAAa,CAAC,EAEtF,IAAMC,EAAU,IAAI,IACdC,EAAiB,IAAI,IAC3B,SAASC,EAAgBC,EAAgBC,EAAgB,CACxDJ,EAAQ,IAAIG,CAAM,EAClBF,EAAe,IAAIE,CAAM,EACzBC,EAAK,KAAKD,CAAM,EAEhB,IAAME,EAAYV,EAAI,IAAIQ,CAAM,GAAK,CAAC,EACtC,QAAWG,KAAYD,EACtB,GAAIJ,EAAe,IAAIK,CAAQ,EAAG,CACjC,IAAMC,EAAkBH,EAAK,QAAQE,CAAQ,EACvCE,EAAQJ,EAAK,MAAMG,CAAe,EACxCd,EAAS,OAAO,KAAK,CAAC,GAAGe,EAAOF,CAAQ,CAAC,CAC1C,MACUN,EAAQ,IAAIM,CAAQ,GAC7BJ,EAAgBI,EAAUF,CAAI,EAIhCH,EAAe,OAAOE,CAAM,EAC5BC,EAAK,IAAI,CACV,CAEA,QAAWD,KAAUT,EACfM,EAAQ,IAAIG,CAAM,GACtBD,EAAgBC,EAAQ,CAAC,CAAC,EAG5B,OAAOV,CACR,CAuBO,SAASgB,GACfC,EACAC,EACAC,EACY,CACZ,MAAO,CAACnB,EAAyBoB,IAA6C,CAC7E,IAAMC,EAA4B,CAAC,EACnC,QAAWzB,KAAQI,EAAS,MAAM,OAAO,EACxC,GAAIkB,EAAOtB,CAAI,EAAG,CACjB,IAAM0B,EAASH,EAAMvB,CAAI,EACpB0B,EAAO,OACXD,EAAO,KAAK,CACX,OAAQzB,EAAK,GACb,KAAM,0BACN,QAAS0B,EAAO,SAAW,QAAQ1B,EAAK,EAAE,iBAAiBqB,CAAW,EACvE,CAAC,CAEH,CAED,OAAOI,CACR,CACD,CAKO,IAAME,GAA6BvB,GAAa,CACtD,IAAMwB,EAAe,IAAI,IAAIxB,EAAS,OAAO,IAAIyB,GAAKA,EAAE,MAAM,EAAG,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,EACtF,OAAO,MAAM,KAAKD,CAAY,EAAE,IAAKE,GAAa,CACjD,IAAMC,EAAsB3B,EAAS,OAAO,KAAKyB,GAAKA,EAAE,MAAM,EAAG,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,IAAMC,CAAQ,EAClG,MAAO,CACN,OAAQC,EAAoB,CAAC,EAC7B,KAAM,gBACN,QAAS,mCAAmCA,EAAoB,KAAK,MAAM,CAAC,EAC7E,CACD,CAAC,CACF,EC7KA,SAASC,EAAeC,EAAiC,CACxD,OAAIA,IAAWC,EACP,GAEJD,IAAWE,EACP,kBAID,IADiBF,EAAO,SAAS,EAAE,QAAQ,KAAM,EAAE,CAChC,GAC3B,CAQA,SAASG,EAAaC,EAAoBC,EAA0B,CACnE,GAAKD,EAAa,oBACjB,MAAO,KAAKC,CAAQ,mBAErB,GAAID,EAAK,YAAY,OAAS,mBAC7B,MAAO,KAAKC,CAAQ,eAErB,GAAID,EAAK,YAAY,OAAS,oBAC7B,MAAO,KAAKC,CAAQ,gBAErB,GAAID,EAAK,UAAW,CACnB,IAAME,EAAOF,EAAK,UAAU,KACtBG,EAAKH,EAAK,UAAU,GAAG,MAAM,GAAG,EAAE,IAAI,EAC5C,MAAO,KAAKC,CAAQ,KAAKE,CAAE,KAAKD,CAAI,KACrC,CAEA,MAAO,KAAKD,CAAQ,IAAID,EAAK,YAAY,IAAI,GAC9C,CAOA,SAASI,EAAgBJ,EAAoBK,EAAiCC,EAA0C,CACvH,GAAIA,EAAM,IAAIN,CAAI,EACjB,OAAOM,EAAM,IAAIN,CAAI,EAEtB,IAAIO,EACCP,EAAa,oBACjBO,EAAW,gBAEHP,EAAK,UACbO,EAAWP,EAAK,UAAU,GAG1BO,EAAWP,EAAK,YAAY,KAI7B,IAAMQ,EAAoBD,EAAS,QAAQ,KAAM,GAAG,EAAE,QAAQ,MAAO,EAAE,EACjEE,EAAQJ,EAAW,IAAIG,CAAiB,GAAK,EAC7CP,EAAW,GAAGO,CAAiB,IAAIC,CAAK,GAC9C,OAAAJ,EAAW,IAAIG,EAAmBC,EAAQ,CAAC,EAC3CH,EAAM,IAAIN,EAAMC,CAAQ,EACjBA,CACR,CAMO,SAASS,EAAqBC,EAAoB,CACxD,GAAI,CAACA,EAAK,UACT,MAAO;AAAA,iBAER,IAAMC,EAAQ,IAAI,IACZC,EAAQ,IAAI,IACZC,EAAU,IAAI,IACdC,EAAwB,CAACJ,EAAK,SAAS,EACvCL,EAAQ,IAAI,IACZD,EAAa,IAAI,IAKvB,IAHAS,EAAQ,IAAIH,EAAK,SAAS,EAC1BP,EAAgBO,EAAK,UAAWN,EAAYC,CAAK,EAE1CS,EAAM,OAAS,GAAG,CACxB,IAAMC,EAAcD,EAAM,MAAM,EAC1BE,EAAWb,EAAgBY,EAAaX,EAAYC,CAAK,EAI/D,GAFAM,EAAM,IAAIb,EAAaiB,EAAaC,CAAQ,CAAC,EAExCD,EAAoB,oBAAqB,CAC7C,IAAME,EAAYF,EAClB,QAAWG,KAAgBD,EAAU,WAAY,CAChD,IAAME,EAAWhB,EAAgBe,EAAcd,EAAYC,CAAK,EAChEO,EAAM,IAAI,KAAKI,CAAQ,QAAQG,CAAQ,EAAE,EACpCN,EAAQ,IAAIK,CAAY,IAC5BL,EAAQ,IAAIK,CAAY,EACxBJ,EAAM,KAAKI,CAAY,EAEzB,CACD,CAEA,OAAW,CAACvB,EAAQyB,CAAa,IAAKL,EAAY,WAAW,QAAQ,EAAG,CACvE,IAAMI,EAAWhB,EAAgBiB,EAAehB,EAAYC,CAAK,EAC3DgB,EAAQ3B,EAAeC,CAAM,EAC7B2B,EAAOD,EACV,KAAKL,CAAQ,OAAOK,CAAK,QAAQF,CAAQ,GACzC,KAAKH,CAAQ,QAAQG,CAAQ,GAChCP,EAAM,IAAIU,CAAI,EAETT,EAAQ,IAAIO,CAAa,IAC7BP,EAAQ,IAAIO,CAAa,EACzBN,EAAM,KAAKM,CAAa,EAE1B,CACD,CAQA,MANqB,CACpB,WACA,GAAG,MAAM,KAAKT,CAAK,EACnB,GAAG,MAAM,KAAKC,CAAK,CACpB,EAEoB,KAAK;AAAA,CAAI,CAC9B,CC5HA,eAAsBW,EAAMC,EAAYC,EAAqC,CAC5E,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACvC,GAAIF,GAAA,MAAAA,EAAQ,QACX,OAAOE,EAAO,IAAIC,CAAY,EAE/B,IAAMC,EAAY,WAAWH,EAASF,CAAE,EACxCC,GAAA,MAAAA,EAAQ,iBAAiB,QAAS,IAAM,CACvC,aAAaI,CAAS,EACtBF,EAAO,IAAIC,CAAY,CACxB,EACD,CAAC,CACF,CCNO,IAAME,GAAiBC,GAAwC,OAAOA,CAAW,EAqB3EC,EAAN,KAAsC,CACpC,KAMR,YAAYC,EAAyE,CACpF,KAAK,KAAO,IAAI,IAAcA,CAAW,CAC1C,CAEA,IAAIC,EAAoC,CACvC,OAAO,KAAK,KAAK,IAAIA,CAAG,CACzB,CAEA,IAAIA,EAA+BC,EAAkB,CACpD,YAAK,KAAK,IAAID,EAAKC,CAAK,EACjB,IACR,CAEA,IAAID,EAAwC,CAC3C,OAAO,KAAK,KAAK,IAAIA,CAAG,CACzB,CAEA,SAAwC,CACvC,OAAO,KAAK,KAAK,QAAQ,CAC1B,CACD,EA+BO,SAASE,GAAQF,EAAoC,CAC3D,MAAO,CACN,IAAMG,GAAiBA,EAAI,IAAIH,CAAG,EAClC,IAAMC,GAAcE,GAAiBA,EAAI,IAAIH,EAAKC,CAAK,EACvD,OAASG,GAAuCD,GAC/CA,EAAI,IAAIH,EAAKI,EAAGD,EAAI,IAAIH,CAAG,CAAC,CAAC,CAC/B,CACD,CASO,SAASK,KAAkBC,EAAkD,CACnF,OAAQH,GAAiBG,EAAW,OAAO,CAACC,EAAKC,IAAcA,EAAUD,CAAG,EAAGJ,CAAG,CACnF,CC1FO,IAAeM,EAAf,KAA4B,CAE3B,GAEA,OAAiB,CAAC,EAElB,WAAa,IAAI,IAEjB,UAQP,OAAOC,EAA2B,CACjC,YAAK,GAAKA,EACH,IACR,CAQA,cAAcC,EAAuB,CACpC,YAAK,UAAYA,EACV,IACR,CAQA,WAAWC,EAAsB,CAChC,YAAK,OAAS,CAAE,GAAG,KAAK,OAAQ,GAAGA,CAAO,EACnC,IACR,CAWA,KAAKC,EAAoBC,EAAgEC,EAA8B,CACtH,YAAK,WAAW,IAAID,EAAQD,CAAI,EACzBA,CACR,CAQD,EAWaG,EAAN,MAAMC,UAA0DR,CAAa,CAE5E,WAEA,KAOP,YAAYS,EAAuB,CAAC,EAAG,CACtC,MAAM,EACN,KAAK,WAAaA,EAAQ,YAAc,EACxC,KAAK,KAAOA,EAAQ,MAAQ,CAC7B,CAEU,WAAW,EAAQC,EAAwC,CACpE,OAAI,aAAaC,GAAc,aAAaC,EACpC,EAED,IAAIA,EAAc,aAAaF,CAAK,mBAAmB,KAAK,YAAY,IAAI,GAAI,KAAK,YAAY,KAAMA,EAAO,CAAU,CAChI,CAQA,MAAM,KAAKG,EAA+C,CAAyC,CAQnG,MAAM,KAAKA,EAAkD,CAAyC,CAQtG,MAAM,KAAKA,EAAqD,CAAE,OAAOP,CAAsB,CAQ/F,MAAM,aAAaQ,EAAiD,CACnE,MAAIA,EAAK,MACFA,EAAK,MAEN,IAAI,MAAM,QAAQ,KAAK,YAAY,IAAI,6CAA6C,CAC3F,CAMA,MAAM,MAAMA,EAAiD,CA/J9D,IAAAC,EAAAC,EAgKE,IAAIC,EACJ,QAASC,EAAW,EAAGA,EAAW,KAAK,WAAYA,IAAY,CAC9D,IAAIH,EAAAD,EAAK,SAAL,MAAAC,EAAa,QAChB,MAAM,IAAIJ,EACX,GAAI,CACH,OAAO,MAAM,KAAK,KAAKG,CAAI,CAC5B,OACOK,EAAG,CACT,IAAMC,EAAQD,EAEd,GADAF,EAAYG,EACRA,aAAiBT,GAAcS,EAAM,OAAS,aACjD,MAAMA,EAEHF,EAAW,KAAK,WAAa,IAChCJ,EAAK,OAAO,KAAK,WAAWI,EAAW,CAAC,IAAI,KAAK,UAAU,eAAe,KAAK,YAAY,IAAI,gBAAiB,CAAE,MAAAE,CAAM,CAAC,EACrH,KAAK,KAAO,GACf,MAAMC,EAAM,KAAK,KAAMP,EAAK,MAAM,EAErC,CACD,CAEA,GADAA,EAAK,OAAO,MAAM,0BAA0B,KAAK,YAAY,IAAI,wBAAyB,CAAE,MAAOG,CAAU,CAAC,GAC1GD,EAAAF,EAAK,SAAL,MAAAE,EAAa,QAChB,MAAM,IAAIL,EACX,OAAO,MAAM,KAAK,aAAa,CAAE,GAAGG,EAAM,MAAOG,CAAU,CAAC,CAC7D,CAMA,MAAM,KAAK,CAAE,IAAAK,EAAK,OAAAnB,EAAQ,OAAAoB,EAAQ,OAAAC,EAAQ,SAAAC,CAAS,EAAqC,CAQvF,GAPI,gBAAgBC,EACnBF,EAAO,KAAK,iBAAiB,KAAK,YAAY,IAAI,GAAI,CAAE,OAAArB,CAAO,CAAC,EAGhEqB,EAAO,KAAK,iBAAiB,KAAK,YAAY,IAAI,GAAI,CAAE,OAAArB,CAAO,CAAC,EAG7DoB,GAAA,MAAAA,EAAQ,QACX,MAAM,IAAIZ,EACX,IAAIgB,EACJ,GAAI,CACHA,EAAU,MAAM,KAAK,KAAK,CAAE,IAAAL,EAAK,OAAAnB,EAAQ,OAAAoB,EAAQ,OAAAC,EAAQ,QAAS,OAAW,QAAS,OAAW,SAAAC,CAAS,CAAC,CAC5G,OACON,EAAG,CACT,MAAM,KAAK,WAAWA,EAAG,MAAM,CAChC,CACA,GAAII,GAAA,MAAAA,EAAQ,QACX,MAAM,IAAIZ,EACX,IAAIiB,EACJ,GAAI,CACHA,EAAU,MAAM,KAAK,MAAM,CAAE,IAAAN,EAAK,OAAAnB,EAAQ,OAAAoB,EAAQ,OAAAC,EAAQ,QAAAG,EAAS,QAAS,OAAW,SAAAF,CAAS,CAAC,CAClG,OACON,EAAG,CACT,MAAM,KAAK,WAAWA,EAAG,MAAM,CAChC,CACA,GAAII,GAAA,MAAAA,EAAQ,QACX,MAAM,IAAIZ,EACX,GAAI,CACH,IAAMN,EAAS,MAAM,KAAK,KAAK,CAAE,IAAAiB,EAAK,OAAAnB,EAAQ,OAAAoB,EAAQ,OAAAC,EAAQ,QAAAG,EAAS,QAAAC,EAAS,SAAAH,CAAS,CAAC,EAC1F,OAAOpB,IAAW,OAAYC,EAAwBD,CACvD,OACOc,EAAG,CACT,MAAM,KAAK,WAAWA,EAAG,MAAM,CAChC,CACD,CAUA,MAAM,IAAIG,EAAcb,EAAwC,CAC/D,IAAMe,GAASf,GAAA,YAAAA,EAAS,SAAU,IAAIoB,EACtC,OAAI,KAAK,WAAW,KAAO,GAAK,EAAE,gBAAgBH,IACjDF,EAAO,KAAK,qHAAqH,IACjHf,GAAA,YAAAA,EAAS,WAAY,IAAIqB,GAE1B,IAAI,IAAIJ,EAAK,IAAI,EAAGJ,EAAK,CAAE,GAAGb,EAAS,OAAQ,KAAK,MAAO,CAAC,CAC7E,CAiBA,IAAYsB,EAA+E,CAC1F,IAAMC,EAAe,KACfC,EAAa,KAAK,WAClBC,EAAO,KAAK,KAElB,OAAO,IAAI,cAAc1B,CAA2B,CACnD,aAAc,CAAE,MAAM,CAAE,WAAAyB,EAAY,KAAAC,CAAK,CAAC,CAAE,CAC5C,MAAM,KAAKpB,EAAkC,CAAE,OAAOkB,EAAa,KAAKlB,CAAI,CAAE,CAC9E,MAAM,KAAKA,EAA0C,CACpD,IAAMqB,EAAiB,MAAMH,EAAa,KAAKlB,CAAI,EACnD,OAAOiB,EAAGI,CAAc,CACzB,CAEA,MAAM,KAAKtB,EAAgD,CAC1D,OAAOP,CACR,CACD,CACD,CAkBA,UAAU8B,EAAuD,CAChE,IAAMJ,EAAe,KACfC,EAAa,KAAK,WAClBC,EAAO,KAAK,KAElB,OAAO,IAAI,cAAc1B,CAA4B,CACpD,aAAc,CAAE,MAAM,CAAE,WAAAyB,EAAY,KAAAC,CAAK,CAAC,CAAE,CAC5C,MAAM,KAAKpB,EAAkC,CAAE,OAAOkB,EAAa,KAAKlB,CAAI,CAAE,CAC9E,MAAM,KAAKA,EAA2C,CAAE,OAAOkB,EAAa,KAAKlB,CAAW,CAAE,CAC9F,MAAM,KAAKA,EAAgD,CAC1D,OAAAA,EAAK,IAAI,IAAIsB,EAAKtB,EAAK,OAAO,EACvBR,CACR,CACD,CACD,CAmBA,OAAO+B,EAAyF,CAC/F,IAAML,EAAe,KAErB,OAAO,IAAI,cAAcxB,CAA4B,CAC5C,QAAU,GAElB,MAAM,KAAKM,EAAgB,CAAE,OAAOkB,EAAa,KAAKlB,CAAI,CAAE,CAC5D,MAAM,KAAKA,EAA2C,CACrD,IAAMwB,EAAS,MAAMN,EAAa,KAAKlB,CAAI,EAC3C,YAAK,QAAU,MAAMuB,EAAUC,CAAM,EAChC,KAAK,SACTxB,EAAK,OAAO,KAAK,sCAAsC,KAAK,YAAY,IAAI,GAAG,EAEzEwB,CACR,CAEA,MAAM,KAAKzB,EAAiD,CAC3D,OAAO,KAAK,QAAUP,EAAiBiC,CACxC,CACD,CACD,CAiBA,IAAIR,EAAgF,CACnF,OAAO,KAAK,IAAI,MAAOO,IACtB,MAAMP,EAAGO,CAAM,EACRA,EACP,CACF,CAmBA,SAAYE,EAAsBC,EAA2C,CAC5E,IAAMT,EAAe,KACfC,EAAa,KAAK,WAClBC,EAAO,KAAK,KAElB,OAAO,IAAI,cAAc1B,CAAgC,CACxD,aAAc,CAAE,MAAM,CAAE,WAAAyB,EAAY,KAAAC,CAAK,CAAC,CAAE,CAC5C,MAAM,KAAKpB,EAAkC,CAE5C,OAAA0B,EAAK,IAAIC,CAAK,EAAE3B,EAAK,GAAG,EACjBkB,EAAa,KAAKlB,CAAI,CAC9B,CAEA,MAAM,KAAKA,EAA2C,CACrD,OAAOkB,EAAa,KAAKlB,CAAW,CACrC,CAEA,MAAM,KAAKA,EAAoD,CAC9D,OAAOkB,EAAa,KAAKlB,CAAI,CAC9B,CACD,CACD,CACD,EAMaY,EAAN,cAAmBnB,CAAoB,CAEtC,UAEA,WAA2B,CAAC,EAKnC,YAAYmC,EAAsB,CACjC,MAAM,EACN,KAAK,UAAYA,CAClB,CAEU,WAAW,EAAQhC,EAAwC,CACpE,OAAIA,IAAU,OAEN,EAED,MAAM,WAAW,EAAGA,CAAK,CACjC,CAQO,IAAIqB,EAAsB,CAChC,YAAK,WAAW,KAAKA,CAAE,EAChB,IACR,CAOA,MAAMW,EAAmC,CACxC,YAAK,UAAYA,EACVA,CACR,CASA,MAAM,KAAK5B,EAAwC,CAIlD,GAAI,EAAEA,EAAK,oBAAoBgB,GAC9B,MAAM,IAAI,UAAU,6JAA6J,EAGlL,GAAI,CAAC,KAAK,UAET,OAAO,MAAM,KAAKhB,CAAI,EAGvBA,EAAK,OAAO,KAAK,yBAAyB,KAAK,YAAY,IAAI,KAAK,EAEpE,IAAM6B,EAAiB,CAAE,GAAG7B,EAAK,OAAQ,GAAG,KAAK,MAAO,EAClD8B,EAAsC,CAC3C,OAAQ9B,EAAK,OACb,OAAQA,EAAK,OACb,OAAQ6B,EACR,SAAU7B,EAAK,QAChB,EAEM+B,EAAc,MAAM/B,EAAK,SAAS,MACvC,KAAK,UACL,KAAK,WACLA,EAAK,IACL8B,CACD,EAEA,OAAA9B,EAAK,OAAO,KAAK,wBAAwB,KAAK,YAAY,IAAI,KAAK,EAC5D+B,CACR,CAOA,MAAM,KAAK,CAAE,QAAAjB,CAAQ,EAAqC,CACzD,OAAOA,CACR,CAQA,MAAM,IAAIN,EAAcb,EAAoC,CAE3D,QADiBA,GAAA,YAAAA,EAAS,WAAY,IAAIqB,GAC1B,IAAI,KAAMR,EAAKb,CAAO,CACvC,CAkBO,YAAYR,EAA+C,CACjE,GAAI,CAAC,KAAK,UACT,OAGD,IAAM6C,EAAwB,CAAC,KAAK,SAAS,EACvCC,EAAU,IAAI,IAAkB,CAAC,KAAK,SAAS,CAAC,EACtD,KAAOD,EAAM,OAAS,GAAG,CACxB,IAAME,EAAcF,EAAM,MAAM,EAEhC,GAAIE,EAAY,KAAO/C,EACtB,OAAO+C,EAGR,QAAWC,KAAaD,EAAY,WAAW,OAAO,EAChDD,EAAQ,IAAIE,CAAS,IACzBF,EAAQ,IAAIE,CAAS,EACrBH,EAAM,KAAKG,CAAS,EAGvB,CAGD,CACD,ECxiBO,IAAMC,EAAN,cAA2BC,CAAK,CAItC,eAAeC,EAAuB,CACrC,GAAIA,EAAM,SAAW,EAAG,CACvB,MAAM,EACN,MACD,CACA,MAAMA,EAAM,CAAC,CAAC,EACd,IAAIC,EAAUD,EAAM,CAAC,EACrB,QAASE,EAAI,EAAGA,EAAIF,EAAM,OAAQE,IACjCD,EAAUA,EAAQ,KAAKD,EAAME,CAAC,CAAC,CACjC,CACD,EAOaC,EAAN,cAA2BJ,CAAK,CAItC,YAAsBK,EAA4B,CACjD,MAAM,EADe,gBAAAA,CAEtB,CAMA,MAAM,KAAK,CAAE,IAAAC,EAAK,OAAAC,EAAQ,OAAAC,EAAQ,OAAAC,EAAQ,SAAAC,CAAS,EAA4B,CAC9E,GAAI,KAAK,WAAW,SAAW,EAAG,CACjCD,EAAO,KAAK,oDAAoD,EAChE,MACD,CAEAA,EAAO,KAAK,4BAA4B,KAAK,WAAW,MAAM,0BAA0B,EACxF,IAAME,EAAW,KAAK,WAAW,IAAIC,GACpCA,EAAK,KAAK,CACT,IAAAN,EACA,OAAQ,CAAE,GAAGC,EAAQ,GAAGK,EAAK,MAAO,EACpC,OAAAJ,EACA,OAAAC,EACA,SAAAC,CACD,CAAC,CACF,EACMG,EAAU,MAAM,QAAQ,WAAWF,CAAQ,EACjDF,EAAO,KAAK,uDAAkD,EAG9DI,EAAQ,QAASC,GAAW,CACvBA,EAAO,SAAW,YACrBL,EAAO,MAAM,2CAA4C,CAAE,MAAOK,EAAO,MAAO,CAAC,CACnF,CAAC,CACF,CACD,EAOsBC,EAAf,cAAiCf,CAAK,CAO5C,aAAc,CACb,MAAM,CACP,CASA,MAAM,KAAKgB,EAAyC,CACnD,MAAO,CAAC,CACT,CAMA,MAAM,KAAKC,EAA+B,CAnG3C,IAAAC,EAoGE,GAAI,CAAC,KAAK,UACT,OAAO,KAER,IAAMC,EAAiB,CAAE,GAAG,KAAK,OAAQ,GAAGF,EAAK,MAAO,EAClDG,EAAuB,MAAM,KAAK,KAAKH,CAAI,GAAM,CAAC,EAClDI,EAAkB,MAAM,KAAKD,CAAmB,EACtDH,EAAK,OAAO,KAAK,iDAAiDI,EAAgB,MAAM,SAAS,EAEjG,QAAWC,KAAeD,EAAiB,CAC1C,IAAIH,EAAAD,EAAK,SAAL,MAAAC,EAAa,QAChB,MAAM,IAAIK,EAEX,MAAM,KAAK,UAAU,KAAK,CACzB,IAAKN,EAAK,IACV,OAAQ,CAAE,GAAGE,EAAgB,GAAGG,CAAY,EAC5C,OAAQL,EAAK,OACb,OAAQA,EAAK,OACb,SAAUA,EAAK,QAChB,CAAC,CACF,CACA,OAAO,IACR,CACD,EAQsBO,EAAf,cAAyCxB,CAAK,CAOpD,aAAc,CACb,MAAM,CACP,CASA,MAAM,KAAKgB,EAAyC,CACnD,MAAO,CAAC,CACT,CAMA,MAAM,KAAKC,EAAyC,CACnD,GAAI,CAAC,KAAK,UACT,OAAO,KAER,IAAME,EAAiB,CAAE,GAAG,KAAK,OAAQ,GAAGF,EAAK,MAAO,EAClDG,EAAuB,MAAM,KAAK,KAAKH,CAAI,GAAM,CAAC,EAClDI,EAAkB,MAAM,KAAKD,CAAmB,EACtDH,EAAK,OAAO,KAAK,uDAAuDI,EAAgB,MAAM,SAAS,EAEvG,IAAMV,EAAWU,EAAgB,IAAIC,GACpC,KAAK,UAAU,KAAK,CACnB,IAAKL,EAAK,IACV,OAAQ,CAAE,GAAGE,EAAgB,GAAGG,CAAY,EAC5C,OAAQL,EAAK,OACb,OAAQA,EAAK,OACb,SAAUA,EAAK,QAChB,CAAC,CACF,EAEMJ,EAAU,MAAM,QAAQ,WAAWF,CAAQ,EAGjD,QAAWG,KAAUD,EAChBC,EAAO,SAAW,YACrBG,EAAK,OAAO,MAAM,gCAAiC,CAAE,MAAOH,EAAO,MAAO,CAAC,EAI7E,OAAOD,CACR,CACD,EAgBO,SAASY,GAAoBC,EAAYC,EAA8B,CAC7E,OAAO,IAAI,cAAc3B,CAAK,CAC7B,MAAM,MAAqB,CAE1B,IAAMW,EAAWe,EAAM,IAAIE,GAAQD,EAAGC,CAAI,CAAC,EAC3C,OAAO,QAAQ,IAAIjB,CAAQ,CAC5B,CACD,CACD,CAiBO,SAASkB,GAAoBH,EAAYI,EAA0D,CACzG,OAAO,IAAI,cAAc9B,CAAK,CAC7B,MAAM,MAAqB,CAC1B,IAAMa,EAAU,MAAM,QAAQ,IAAIa,EAAM,IAAIE,GAAQE,EAAUF,CAAI,CAAC,CAAC,EACpE,OAAOF,EAAM,OAAO,CAACK,EAAGC,IAAUnB,EAAQmB,CAAK,CAAC,CACjD,CACD,CACD,CAiBO,SAASC,GACfP,EACAQ,EACAC,EACO,CACP,OAAO,IAAI,cAAcnC,CAAK,CAC7B,MAAM,KAAKgB,EAA6B,CAjQ1C,IAAAE,EAkQG,IAAIkB,EAAcD,EAClB,QAAWP,KAAQF,EAAO,CACzB,IAAIR,EAAAF,EAAM,SAAN,MAAAE,EAAc,QACjB,MAAM,IAAIK,EAEXa,EAAc,MAAMF,EAAQE,EAAaR,CAAI,CAC9C,CACA,OAAOQ,CACR,CACD,CACD,CC9PO,SAASC,GAGdC,EAAwF,CACzF,OAAOA,CACR,CAQA,IAAMC,EAAN,cAA+BC,CAAK,CAC3B,SACR,YAAYC,EAA2C,CACtD,MAAM,EACN,GAAM,CAAE,OAAAC,EAAQ,GAAGC,CAAS,EAAIF,EAAQ,KACxC,KAAK,SAAWE,CACjB,CAEA,MAAM,KAAK,CAAE,IAAAC,EAAK,OAAAC,CAAO,EAAa,CACrC,OAAW,CAACC,EAAQC,CAAS,IAAK,OAAO,QAAQ,KAAK,QAAQ,EACzDH,EAAI,IAAIG,CAAS,EACpBH,EAAI,IAAIE,EAAQF,EAAI,IAAIG,CAAS,CAAC,EAGlCF,EAAO,KAAK,4CAA4CE,CAAS,yBAAyB,CAG7F,CACD,EAQMC,EAAN,cAAgCR,CAAK,CAC5B,SACR,YAAYC,EAA2C,CACtD,MAAM,EACN,GAAM,CAAE,OAAAC,EAAQ,GAAGC,CAAS,EAAIF,EAAQ,KACxC,KAAK,SAAWE,CACjB,CAEA,MAAM,KAAK,CAAE,IAAAC,EAAK,OAAAC,CAAO,EAAa,CACrC,OAAW,CAACE,EAAWD,CAAM,IAAK,OAAO,QAAQ,KAAK,QAAQ,EACzDF,EAAI,IAAIE,CAAM,EACjBF,EAAI,IAAIG,EAAWH,EAAI,IAAIE,CAAM,CAAC,EAGlCD,EAAO,KAAK,8CAA8CC,CAAM,yBAAyB,CAG5F,CACD,EAGMG,EAAN,cAAsCC,CAAa,CAGlD,YAA4BC,EAA4B,CAAE,MAAMA,CAAU,EAA9C,gBAAAA,CAAgD,CAD5D,oBAAsB,EAEvC,EAOaC,EAAN,KAGL,CAgBD,YACCd,EACQe,EAAqD,CAAC,EAC9DZ,EAA+B,CAAC,EAChCI,EAAiB,IAAIS,EACpB,CAHO,wBAAAD,EAIR,KAAK,OAASR,EACVP,aAAoB,IACvB,KAAK,SAAWA,EAGhB,KAAK,SAAW,IAAI,IAAI,OAAO,QAAQA,CAAQ,CAAC,EAEjD,KAAK,SAAS,IAAI,4BAA6BC,CAAuB,EACtE,KAAK,SAAS,IAAI,6BAA8BS,CAAwB,EACxE,KAAK,qBAAuBP,EAAQ,sBAAwB,CAAC,CAC9D,CA/BQ,SACA,qBACA,OA+BA,YAAYc,EAAY,CACzB,KAAK,kBAAkBD,IAC5B,KAAK,OAAO,KAAK,gCAAgC,EACjCE,EAAqBD,CAAI,EACjC,MAAM;AAAA,CAAI,EAAE,QAAQE,GAAQ,KAAK,OAAO,KAAKA,CAAI,CAAC,EAE5D,CAEQ,cAAcC,EAAsBC,EAAW,GAAmB,CACzE,IAAMC,EAA0B,CAAC,EAC3BC,EAA0B,CAAC,EAE3BC,EAAe,IAAI,IAAIJ,EAAM,MAAM,IAAIK,GAAKA,EAAE,EAAE,CAAC,EAGvD,QAAWC,KAAQN,EAAM,MAAO,CAC/B,IAAMO,EAAiB,GAAGN,CAAQ,GAAGK,EAAK,EAAE,GACtCE,EAA0B,KAAK,qBAAqB,SAASF,EAAK,IAAI,EACtEG,EAAgBH,EAAK,MAAQ,eAAgBA,EAAK,KAGlDI,EAAc,KAAK,MAAM,KAAK,UAAUJ,EAAK,MAAQ,CAAC,CAAC,CAAC,EAE9D,GAAII,EAAY,OAAQ,CACvB,IAAMC,EAASD,EAAY,OAC3B,OAAW,CAACE,EAAaC,CAAiB,IAAK,OAAO,QAAQF,CAAM,EAAG,CAEtE,IAAMG,GADc,MAAM,QAAQD,CAAiB,EAAIA,EAAoB,CAACA,CAAiB,GAC1D,IAAKE,GAGnCX,EAAa,IAAIW,CAAU,EACvB,GAAGd,CAAQ,GAAGc,CAAU,GAEzBA,CACP,EACDJ,EAAOC,CAAW,EAAI,MAAM,QAAQC,CAAiB,EAAIC,EAAiBA,EAAe,CAAC,CAC3F,CACD,CAEA,GAAIN,EAAyB,CAC5B,IAAMQ,EAAkBV,EAAK,KACvBW,EAAgBD,EAAgB,WAChCpC,EAAW,KAAK,mBAAmB,SACzC,GAAI,CAACA,GAAY,OAAOA,EAAS,UAAa,WAC7C,MAAM,IAAI,MAAM,iGAAiG,EAElH,IAAMsC,EAAsCtC,EAAS,SAASqC,CAAa,EAC3E,GAAI,CAACC,EACJ,MAAM,IAAI,MAAM,wBAAwBD,CAAa,yBAAyB,EAE/E,IAAME,EAAgB,GAAGZ,CAAc,gBACjCa,EAAiB,GAAGb,CAAc,iBACxCL,EAAW,KAAK,CAAE,GAAIiB,EAAe,KAAM,4BAA6B,KAAMH,EAAgB,QAAU,CAAC,CAAE,CAAC,EAC5Gd,EAAW,KAAK,CAAE,GAAIkB,EAAgB,KAAM,6BAA8B,KAAMJ,EAAgB,SAAW,CAAC,CAAE,CAAC,EAE/G,IAAMK,EAAkB,KAAK,cAAcH,EAAU,GAAGX,CAAc,GAAG,EACzEL,EAAW,KAAK,GAAGmB,EAAgB,KAAK,EACxClB,EAAW,KAAK,GAAGkB,EAAgB,KAAK,EAExC,IAAMC,EAAmBD,EAAgB,MAAM,IAAIhB,GAAKA,EAAE,EAAE,EAAE,OAAOkB,GAAM,CAACF,EAAgB,MAAM,KAAKG,GAAKA,EAAE,SAAWD,CAAE,CAAC,EAC5H,QAAWE,KAAWH,EACrBnB,EAAW,KAAK,CAAE,OAAQgB,EAAe,OAAQM,EAAS,OAAQC,CAAsB,CAAC,EAE1F,IAAMC,EAAsBN,EAAgB,MAAM,IAAIhB,GAAKA,EAAE,EAAE,EAAE,OAAOkB,GAAM,CAACF,EAAgB,MAAM,KAAKG,GAAKA,EAAE,SAAWD,CAAE,CAAC,EAC/H,QAAWK,KAAcD,EACxBxB,EAAW,KAAK,CAAE,OAAQyB,EAAY,OAAQR,EAAgB,OAAQM,CAAsB,CAAC,CAC/F,KACK,IAAIjB,EACR,MAAM,IAAI,MACT,qCAAqCH,EAAK,EAAE,eAAeA,EAAK,IAAI,wHAEnDA,EAAK,IAAI,sEAC3B,EAIAJ,EAAW,KAAK,CAAE,GAAGI,EAAM,GAAIC,EAAgB,KAAMG,CAAY,CAAC,EAEpE,CAGA,QAAWmB,KAAQ7B,EAAM,MAAO,CAC/B,IAAM8B,EAAa9B,EAAM,MAAM,KAAKK,GAAKA,EAAE,KAAOwB,EAAK,MAAM,EACvDE,EAAa/B,EAAM,MAAM,KAAKK,GAAKA,EAAE,KAAOwB,EAAK,MAAM,EACvDG,EAAmB,GAAG/B,CAAQ,GAAG4B,EAAK,MAAM,GAC5CI,EAAmB,GAAGhC,CAAQ,GAAG4B,EAAK,MAAM,GAE5CK,EAAc,KAAK,qBAAqB,SAASJ,EAAW,IAAI,EAChEK,EAAc,KAAK,qBAAqB,SAASJ,EAAW,IAAI,EAElEG,GAAeC,EAClBhC,EAAW,KAAK,CAAE,GAAG0B,EAAM,OAAQ,GAAGG,CAAgB,iBAAkB,OAAQ,GAAGC,CAAgB,eAAgB,CAAC,EAC5GC,EACR/B,EAAW,KAAK,CAAE,GAAG0B,EAAM,OAAQ,GAAGG,CAAgB,iBAAkB,OAAQC,CAAiB,CAAC,EAC1FE,EACRhC,EAAW,KAAK,CAAE,GAAG0B,EAAM,OAAQG,EAAkB,OAAQ,GAAGC,CAAgB,eAAgB,CAAC,EAEjG9B,EAAW,KAAK,CAAE,GAAG0B,EAAM,OAAQG,EAAkB,OAAQC,CAAiB,CAAC,CACjF,CACA,MAAO,CAAE,MAAO/B,EAAY,MAAOC,CAAW,CAC/C,CAYA,MAAMH,EAAkE,CA1OzE,IAAAoC,EAAAC,EAAAC,EAAAC,EA2OE,IAAMC,EAAY,KAAK,cAAcxC,CAAsB,EAErDyC,EAAU,IAAI,IACdC,EAAiB,IAAI,IAC3B,QAAWb,KAAQW,EAAU,MACvBE,EAAe,IAAIb,EAAK,MAAM,GAClCa,EAAe,IAAIb,EAAK,OAAQ,IAAI,GAAK,EAC1Ca,EAAe,IAAIb,EAAK,MAAM,EAAG,IAAIA,EAAK,MAAM,EAEjD,IAAMc,EAAsB,IAAI,IAChC,QAAWrC,KAAQkC,EAAU,MAAO,CACnC,IAAMI,EAAqBF,EAAe,IAAIpC,EAAK,EAAE,EACrDqC,EAAoB,IAAIrC,EAAK,GAAIsC,EAAqBA,EAAmB,KAAO,CAAC,CAClF,CAGA,QAAWC,KAAaL,EAAU,MAAO,CACxC,IAAMM,EAAY,KAAK,SAAS,IAAID,EAAU,KAAK,SAAS,CAAC,EAC7D,GAAI,CAACC,EACJ,MAAM,IAAI,MAAM,4BAA4BD,EAAU,KAAK,SAAS,CAAC,8BAA8B,EAEpG,IAAME,EAAc,CACnB,GAAG,KAAK,mBACR,KAAM,CAAE,GAAGF,EAAU,KAAM,OAAQA,EAAU,EAAG,CACjD,EACMG,EAAiB,IAAIF,EAAUC,CAAW,EAC9C,OAAOF,EAAU,EAAE,EACnB,cAAcA,CAAS,EACzBJ,EAAQ,IAAII,EAAU,GAAIG,CAAc,CACzC,CAGA,IAAMC,EAAa,IAAI,IACvB,QAAWpB,KAAQW,EAAU,MAAO,CACnC,IAAMU,EAAWrB,EAAK,OAChBsB,EAAStB,EAAK,QAAUH,EACxBK,EAAaU,EAAQ,IAAIZ,EAAK,MAAM,EAErCoB,EAAW,IAAIC,CAAQ,GAC3BD,EAAW,IAAIC,EAAU,IAAI,GAAK,EACnC,IAAME,EAAgBH,EAAW,IAAIC,CAAQ,EACxCE,EAAc,IAAID,CAAM,GAC5BC,EAAc,IAAID,EAAQ,CAAC,CAAC,EAC7BC,EAAc,IAAID,CAAM,EAAG,KAAKpB,CAAU,CAC3C,CAGA,OAAW,CAACmB,EAAUG,CAAO,IAAKJ,EAAW,QAAQ,EAAG,CACvD,IAAMnB,EAAaW,EAAQ,IAAIS,CAAQ,EACvC,OAAW,CAACC,EAAQG,CAAU,IAAKD,EAAQ,QAAQ,EAClD,GAAIC,EAAW,SAAW,EAEzBxB,EAAW,KAAKwB,EAAW,CAAC,EAAGH,CAAM,UAE7BG,EAAW,OAAS,EAAG,CAE/B,IAAMC,EAAe,IAAIhE,EAAwB+D,CAAU,EAC3DxB,EAAW,KAAKyB,EAAcJ,CAAM,EAGpC,IAAMK,GAAuBnB,GAAAD,EAAAa,EAAW,IAAIK,EAAW,CAAC,EAAE,GAAI,SAAS,CAAC,IAA3C,YAAAlB,EAA8C,IAAIV,KAAlD,YAAAW,EAAoE,GAC7FmB,GACiBF,EAAW,MAAM,CAAC,EAAE,MACvChD,GAAK,CA1SZ,IAAA8B,EAAAC,EA0Se,QAAAA,GAAAD,EAAAa,EAAW,IAAI3C,EAAK,GAAI,SAAS,CAAC,IAAlC,YAAA8B,EAAqC,IAAIV,KAAzC,YAAAW,EAA2D,MAAOmB,EAC3E,GAGCD,EAAa,KAAKC,CAAoB,CAEzC,CAEF,CAGA,IAAMC,EAAa,MAAM,KAAKhB,EAAQ,KAAK,CAAC,EACtCiB,EAAe,IAAI,IAAIlB,EAAU,MAAM,IAAIhB,GAAKA,EAAE,MAAM,CAAC,EACzDmC,EAAeF,EAAW,OAAOlC,GAAM,CAACmC,EAAa,IAAInC,CAAE,CAAC,EAElE,GAAIoC,EAAa,SAAW,GAAKF,EAAW,OAAS,EACpD,MAAM,IAAI,MAAM,+DAA+D,EAEhF,GAAIE,EAAa,SAAW,EAAG,CAC9B,IAAMC,EAAYnB,EAAQ,IAAIkB,EAAa,CAAC,CAAC,EACvC9D,EAAO,IAAIgE,EAAKD,CAAS,EAC/B,YAAK,YAAY/D,CAAI,EACd,CAAE,KAAAA,EAAM,QAAA4C,EAAS,oBAAAE,CAAoB,CAC7C,CAGA,IAAMmB,EAAaH,EAAa,IAAIpC,GAAMkB,EAAQ,IAAIlB,CAAE,CAAE,EACpDwC,EAAoB,IAAIxE,EAAwBuE,CAAU,EAEhE,GAAIA,EAAW,OAAS,EAAG,CAC1B,IAAME,GAAiBzB,GAAAD,EAAAW,EAAW,IAAIa,EAAW,CAAC,EAAE,GAAI,SAAS,CAAC,IAA3C,YAAAxB,EAA8C,IAAIZ,KAAlD,YAAAa,EAAoE,GACvFyB,GACiBF,EAAW,MAAM,CAAC,EAAE,MAAMxD,GAAK,CA1UvD,IAAA8B,EAAAC,EA0U0D,QAAAA,GAAAD,EAAAa,EAAW,IAAI3C,EAAK,GAAI,SAAS,CAAC,IAAlC,YAAA8B,EAAqC,IAAIV,KAAzC,YAAAW,EAA2D,MAAO2B,EAAc,GAErID,EAAkB,KAAKC,CAAc,CAExC,CAEA,IAAMnE,EAAO,IAAIgE,EAAKE,CAAiB,EACvC,YAAK,YAAYlE,CAAI,EACd,CAAE,KAAAA,EAAM,QAAA4C,EAAS,oBAAAE,CAAoB,CAC7C,CACD,ECnTO,SAASsB,GAAmBC,EAA8C,CAChF,OAAO,IAAI,cAAcC,CAAoB,CAC5C,MAAM,KAAK,CAAE,OAAAC,CAAO,EAAiC,CACpD,OAAOF,EAAGE,CAAa,CACxB,CACD,CACD,CAeO,SAASC,GAAuBH,EAAiD,CACvF,OAAO,IAAI,cAAcC,CAAoB,CAC5C,MAAM,KAAK,CAAE,IAAAG,EAAK,OAAAF,CAAO,EAAiC,CACzD,OAAOF,EAAGI,EAAKF,CAAa,CAC7B,CACD,CACD,CAeO,SAASG,MAAiBC,EAAsC,CACtE,OAAO,IAAI,cAAcL,CAAS,CACjC,MAAM,KAAK,CAAE,IAAAG,CAAI,EAAa,CAE7BG,EAAe,GAAGD,CAAU,EAAEF,CAAG,CAClC,CACD,CACD,CAYO,SAASI,MAAYC,EAAqB,CAChD,OAAO,IAAIC,EAAa,GAAGD,CAAK,CACjC,CAkBO,SAASE,GAAiBC,EAAuBC,EAA2C,CAClG,MAAO,OAAOC,GAAaF,EAAE,MAAMC,EAAEC,CAAK,CAAC,CAC5C","names":["AbortError","message","WorkflowError","nodeName","phase","originalError","InMemoryExecutor","startNode","flowMiddleware","context","options","currentNode","lastAction","logger","signal","params","executor","AbortError","chain","nodeArgs","previousNode","flow","NullLogger","controller","combinedParams","internalOptions","curr","action","nextNode","actionDisplay","middleware","nodeToRun","runNode","args","next","mw","NullLogger","ConsoleLogger","level","message","context","fullMessage","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","contextKey","description","TypedContext","initialData","key","value","lens","ctx","fn","composeContext","transforms","acc","transform","AbstractNode","id","data","params","node","action","DEFAULT_ACTION","Node","_Node","options","phase","AbortError","WorkflowError","_args","args","_a","_b","lastError","curRetry","e","error","sleep","ctx","signal","logger","executor","Flow","prepRes","execRes","NullLogger","InMemoryExecutor","fn","originalNode","maxRetries","wait","originalResult","key","predicate","result","FILTER_FAILED","lens","value","start","combinedParams","internalOptions","finalAction","queue","visited","currentNode","successor","SequenceFlow","Flow","nodes","current","i","ParallelFlow","nodesToRun","ctx","params","signal","logger","executor","promises","node","results","result","BatchFlow","_args","args","_a","combinedParams","batchParamsIterable","batchParamsList","batchParams","AbortError","ParallelBatchFlow","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","subGraphStartIds","id","e","startId","DEFAULT_ACTION","subGraphTerminalIds","terminalId","edge","sourceNode","targetNode","prefixedSourceId","prefixedTargetId","isSourceSub","isTargetSub","_a","_b","_c","_d","flatGraph","nodeMap","predecessorMap","predecessorCountMap","uniquePredecessors","graphNode","NodeClass","nodeOptions","executableNode","edgeGroups","sourceId","action","sourceActions","actions","successors","parallelNode","firstBranchSuccessor","allNodeIds","allTargetIds","startNodeIds","startNode","Flow","startNodes","parallelStartNode","firstSuccessor","mapNode","fn","Node","params","contextNode","ctx","transformNode","transforms","composeContext","pipeline","nodes","SequenceFlow","compose","f","g","input"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/executors/in-memory.ts","../src/logger.ts","../src/types.ts","../src/utils/graph.ts","../src/utils/mermaid.ts","../src/utils/sleep.ts","../src/context.ts","../src/workflow.ts","../src/builder/collection.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\tsuper(message)\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","import type { IExecutor, InternalRunOptions } from '../executor'\nimport type { AbstractNode, Context, Flow, Logger, Middleware, MiddlewareNext, NodeArgs, RunOptions } from '../workflow'\nimport { AbortError, NullLogger } from '../workflow'\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(\n\t\tstartNode: AbstractNode,\n\t\tflowMiddleware: Middleware[],\n\t\tcontext: Context,\n\t\toptions: InternalRunOptions,\n\t): Promise<any> {\n\t\tlet currentNode: AbstractNode | undefined = startNode\n\t\tlet lastAction: any\n\n\t\tconst { logger, signal, params, executor } = options\n\n\t\twhile (currentNode) {\n\t\t\tif (signal?.aborted)\n\t\t\t\tthrow new AbortError()\n\n\t\t\tconst chain = this.applyMiddleware(flowMiddleware, currentNode)\n\n\t\t\tconst nodeArgs: NodeArgs = {\n\t\t\t\tctx: context,\n\t\t\t\tparams,\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,\n\t\t\t}\n\n\t\t\tlastAction = await chain(nodeArgs)\n\n\t\t\tconst previousNode = currentNode\n\t\t\tcurrentNode = this.getNextNode(previousNode, lastAction, logger)\n\t\t}\n\n\t\treturn lastAction\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 async run(flow: Flow, context: Context, options?: RunOptions): Promise<any> {\n\t\tconst logger = options?.logger ?? new NullLogger()\n\t\tconst controller = options?.controller\n\t\tconst combinedParams = { ...flow.params, ...options?.params }\n\n\t\tconst internalOptions: InternalRunOptions = {\n\t\t\tlogger,\n\t\t\tsignal: 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 = this.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(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.info(`Flow ends: Action '${actionDisplay}' from ${curr.constructor.name} has no configured successor.`)\n\t\t}\n\t\treturn nextNode\n\t}\n\n\t/**\n\t * Composes a chain of middleware functions around a node's execution.\n\t * @internal\n\t */\n\tpublic applyMiddleware(middleware: Middleware[], nodeToRun: AbstractNode): MiddlewareNext {\n\t\t// The final function in the chain is the actual execution of the node.\n\t\tconst runNode: MiddlewareNext = (args: NodeArgs) => {\n\t\t\treturn nodeToRun._run({\n\t\t\t\tctx: args.ctx,\n\t\t\t\tparams: { ...args.params, ...nodeToRun.params },\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\tif (!middleware || middleware.length === 0)\n\t\t\treturn runNode\n\n\t\t// Build the chain backwards, so the first middleware in the array is the outermost.\n\t\treturn middleware.reduceRight<MiddlewareNext>(\n\t\t\t(next, mw) => (args: NodeArgs) => mw(args, next),\n\t\t\trunNode,\n\t\t)\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\n/**\n * A default logger implementation that writes messages to the `console`.\n * Useful for development and debugging.\n */\nexport class ConsoleLogger implements Logger {\n\tprivate log(level: 'debug' | 'info' | 'warn' | 'error', message: string, context?: object) {\n\t\tconst fullMessage = `[${level.toUpperCase()}] ${message}`\n\t\tif (context && Object.keys(context).length > 0)\n\t\t\tconsole[level](fullMessage, context)\n\t\telse\n\t\t\tconsole[level](fullMessage)\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 { Context } from './context'\nimport type { IExecutor } from './executor'\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 */\nexport interface NodeArgs<PrepRes = any, ExecRes = any> {\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: Params\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/** 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 = (args: NodeArgs) => Promise<any>\n/** The function signature for a middleware function. */\nexport type Middleware = (args: NodeArgs, next: MiddlewareNext) => Promise<any>\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","/**\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","/* 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 './executor'\nimport type { Middleware, NodeArgs, NodeOptions, NodeRunContext, Params, RunOptions } from './types'\nimport { AbortError, 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\nexport * from './context'\nexport * from './errors'\nexport * from './executor'\nexport * from './logger'\nexport * from './types'\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 */\nexport abstract class AbstractNode {\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: Params = {}\n\t/** A map of successor nodes, keyed by the action that triggers the transition. */\n\tpublic successors = new Map<string | typeof DEFAULT_ACTION | typeof FILTER_FAILED, AbstractNode>()\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: Params): 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 string 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(node: AbstractNode, action: string | typeof DEFAULT_ACTION | typeof FILTER_FAILED = DEFAULT_ACTION): AbstractNode {\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<any>\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 */\nexport class Node<PrepRes = any, ExecRes = any, PostRes = any> extends AbstractNode {\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\t\t}\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>): 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>): 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>): 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>): Promise<ExecRes> {\n\t\tif (args.error) {\n\t\t\tthrow args.error\n\t\t}\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>): 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\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.info(`Running flow: ${this.constructor.name}`, { params })\n\t\t}\n\t\telse {\n\t\t\tlogger.info(`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, signal, logger, prepRes: undefined, execRes: undefined, executor })\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, signal, logger, prepRes, execRes: undefined, executor })\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, signal, logger, prepRes, execRes, executor })\n\t\t\tif (action === undefined)\n\t\t\t\treturn DEFAULT_ACTION as PostRes\n\n\t\t\treturn 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> {\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> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs): Promise<PrepRes> { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes>): 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>): 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> {\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> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs): Promise<PrepRes> { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes>): Promise<ExecRes> { return originalNode.exec(args as any) }\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes>): Promise<any> {\n\t\t\t\targs.ctx.set(key, 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> {\n\t\tconst originalNode = this\n\n\t\treturn new class extends Node<PrepRes, ExecRes, any> {\n\t\t\tprivate didPass = false\n\n\t\t\tasync prep(args: NodeArgs) { return originalNode.prep(args) }\n\t\t\tasync exec(args: NodeArgs<PrepRes>): 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.info(`[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>): 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> {\n\t\treturn this.map(async (result) => {\n\t\t\tawait fn(result)\n\t\t\treturn result\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> {\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> {\n\t\t\tconstructor() { super({ maxRetries, wait }) }\n\t\t\tasync prep(args: NodeArgs): 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>): Promise<ExecRes> {\n\t\t\t\treturn originalNode.exec(args as any)\n\t\t\t}\n\n\t\t\tasync post(args: NodeArgs<PrepRes, ExecRes>): 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 */\nexport class Flow<PrepRes = any, ExecRes = any, PostRes = ExecRes> extends Node<PrepRes, ExecRes, PostRes> {\n\t/** The first node to be executed in this flow's graph. */\n\tpublic startNode?: AbstractNode\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) {\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(start: AbstractNode): AbstractNode {\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>): 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.info(`-- 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(\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.info(`-- 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<any, ExecRes>): Promise<PostRes> {\n\t\treturn execRes as unknown as PostRes\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<PostRes> {\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 | undefined {\n\t\tif (!this.startNode) {\n\t\t\treturn undefined\n\t\t}\n\n\t\tconst queue: AbstractNode[] = [this.startNode]\n\t\tconst visited = new Set<AbstractNode>([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\t\t\t}\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","import type { NodeFunction } from '../functions'\nimport type { AbstractNode, NodeArgs } from '../workflow'\nimport { AbortError, 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, PostRes = ExecRes> extends Flow<PrepRes, ExecRes, PostRes> {\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, 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.info('[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\t\tconst results = await Promise.allSettled(promises)\n\t\tlogger.info(`[ParallelFlow] ✓ All parallel branches finished.`)\n\t\t// Check for and log any failures. A more robust implementation might\n\t\t// collect these errors and decide on a specific failure action.\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 extends Flow<any, null, any> {\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 extends Flow<any, PromiseSettledResult<any>[], 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<any> {\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(`[ParallelBatchFlow] Starting parallel processing of ${batchParamsList.length} items.`)\n\n\t\tconst promises = batchParamsList.map(batchParams =>\n\t\t\tthis.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\t// Optionally handle rejected promises, but don't rethrow to avoid halting the whole batch.\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[], 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[], 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, 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 { AbstractNode, FILTER_FAILED, Logger, NodeArgs } from '../workflow'\nimport type { BuildResult, GraphBuilderOptions, GraphEdge, GraphNode, NodeRegistry, NodeTypeMap, TypedNodeRegistry, TypedWorkflowGraph, WorkflowGraph } from './graph.types'\nimport { generateMermaidGraph } from '../utils/mermaid'\nimport { DEFAULT_ACTION, Flow, Node, NullLogger } from '../workflow'\nimport { ParallelFlow } from './collection'\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.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\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\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\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\tfinalNodes.push(...inlinedSubGraph.nodes)\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\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\t// Determine the single convergence point for this parallel block.\n\t\t\t\t\tconst firstBranchSuccessor = edgeGroups.get(successors[0].id!.toString())?.get(DEFAULT_ACTION)?.[0]\n\t\t\t\t\tif (firstBranchSuccessor) {\n\t\t\t\t\t\tconst allConverge = successors.slice(1).every(\n\t\t\t\t\t\t\tnode => edgeGroups.get(node.id!.toString())?.get(DEFAULT_ACTION)?.[0] === firstBranchSuccessor,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t// If all branches lead to the same next node, wire the container to it.\n\t\t\t\t\t\tif (allConverge)\n\t\t\t\t\t\t\tparallelNode.next(firstBranchSuccessor)\n\t\t\t\t\t}\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\tthis._logMermaid(flow)\n\t\t\treturn { flow, nodeMap, predecessorCountMap }\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 > 0) {\n\t\t\tconst firstSuccessor = edgeGroups.get(startNodes[0].id!.toString())?.get(DEFAULT_ACTION)?.[0]\n\t\t\tif (firstSuccessor) {\n\t\t\t\tconst allConverge = startNodes.slice(1).every(node => edgeGroups.get(node.id!.toString())?.get(DEFAULT_ACTION)?.[0] === firstSuccessor)\n\t\t\t\tif (allConverge)\n\t\t\t\t\tparallelStartNode.next(firstSuccessor)\n\t\t\t}\n\t\t}\n\n\t\tconst flow = new Flow(parallelStartNode)\n\t\tthis._logMermaid(flow)\n\t\treturn { flow, nodeMap, predecessorCountMap }\n\t}\n}\n","import type { ContextTransform } from './context'\nimport type { Context, Flow, Node, NodeArgs } from './workflow'\nimport { SequenceFlow } from './builder/collection'\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, TOut>(fn: NodeFunction<TIn, TOut>): Node<TIn, TOut> {\n\treturn new class extends BaseNode<TIn, TOut> {\n\t\tasync exec({ params }: NodeArgs<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, TOut>(fn: ContextFunction<TIn, TOut>): Node<TIn, TOut> {\n\treturn new class extends BaseNode<TIn, TOut> {\n\t\tasync exec({ ctx, params }: NodeArgs<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","InMemoryExecutor","startNode","flowMiddleware","context","options","currentNode","lastAction","logger","signal","params","executor","AbortError","chain","nodeArgs","previousNode","flow","NullLogger","controller","combinedParams","internalOptions","curr","action","nextNode","actionDisplay","middleware","nodeToRun","runNode","args","next","mw","NullLogger","ConsoleLogger","level","message","context","fullMessage","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","contextKey","description","TypedContext","initialData","key","value","lens","ctx","fn","composeContext","transforms","acc","transform","AbstractNode","id","data","params","node","action","DEFAULT_ACTION","Node","_Node","options","phase","AbortError","WorkflowError","args","_a","_b","lastError","curRetry","e","error","sleep","ctx","signal","logger","executor","Flow","prepRes","execRes","NullLogger","InMemoryExecutor","fn","originalNode","maxRetries","wait","originalResult","_args","key","predicate","result","FILTER_FAILED","lens","value","start","combinedParams","internalOptions","finalAction","queue","visited","currentNode","successor","SequenceFlow","Flow","nodes","current","i","ParallelFlow","nodesToRun","ctx","params","signal","logger","executor","promises","node","results","result","BatchFlow","_args","args","_a","combinedParams","batchParamsIterable","batchParamsList","batchParams","AbortError","ParallelBatchFlow","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","subGraphStartIds","id","e","startId","DEFAULT_ACTION","subGraphTerminalIds","terminalId","edge","sourceNode","targetNode","prefixedSourceId","prefixedTargetId","isSourceSub","isTargetSub","_a","_b","_c","_d","flatGraph","nodeMap","predecessorMap","predecessorCountMap","uniquePredecessors","graphNode","NodeClass","nodeOptions","executableNode","edgeGroups","sourceId","action","sourceActions","actions","successors","parallelNode","firstBranchSuccessor","allNodeIds","allTargetIds","startNodeIds","startNode","Flow","startNodes","parallelStartNode","firstSuccessor","mapNode","fn","Node","params","contextNode","ctx","transformNode","transforms","composeContext","pipeline","nodes","SequenceFlow","compose","f","g","input"]}
|
package/package.json
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowcraft",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.5",
|
|
5
5
|
"packageManager": "pnpm@10.13.1",
|
|
6
6
|
"description": "A flexible workflow framework",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/gorango/flowcraft.git"
|
|
10
|
+
},
|
|
7
11
|
"exports": {
|
|
8
12
|
".": {
|
|
9
13
|
"types": "./dist/index.d.ts",
|
|
10
14
|
"import": "./dist/index.js"
|
|
11
15
|
}
|
|
12
16
|
},
|
|
13
|
-
"engines": {
|
|
14
|
-
"node": ">=24",
|
|
15
|
-
"pnpm": ">=10"
|
|
16
|
-
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
|
-
"repository": {
|
|
21
|
-
"type": "git",
|
|
22
|
-
"url": "https://github.com/gorango/flowcraft.git"
|
|
23
|
-
},
|
|
24
20
|
"scripts": {
|
|
25
21
|
"dev": "tsup --watch --config config/tsup.config.ts",
|
|
26
22
|
"build": "tsup --config config/tsup.config.ts",
|