flowcraft 2.2.0 → 2.3.1

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.
Files changed (147) hide show
  1. package/README.md +40 -34
  2. package/dist/analysis.d.ts +3 -1
  3. package/dist/chunk-33NO4PUJ.js +74 -0
  4. package/dist/chunk-33NO4PUJ.js.map +1 -0
  5. package/dist/chunk-BC4G7OM6.js +42 -0
  6. package/dist/chunk-BC4G7OM6.js.map +1 -0
  7. package/dist/chunk-BCRWXTWX.js +21 -0
  8. package/dist/chunk-BCRWXTWX.js.map +1 -0
  9. package/dist/chunk-BN4MV36K.js +25 -0
  10. package/dist/chunk-BN4MV36K.js.map +1 -0
  11. package/dist/{chunk-ZCHFZBGL.js → chunk-C4HYIJI3.js} +120 -5
  12. package/dist/chunk-C4HYIJI3.js.map +1 -0
  13. package/dist/chunk-CD3Q4N6V.js +13 -0
  14. package/dist/chunk-CD3Q4N6V.js.map +1 -0
  15. package/dist/chunk-CD4FUZOJ.js +114 -0
  16. package/dist/chunk-CD4FUZOJ.js.map +1 -0
  17. package/dist/chunk-DL7KVYZF.js +39 -0
  18. package/dist/chunk-DL7KVYZF.js.map +1 -0
  19. package/dist/chunk-FRKO3WX4.js +32 -0
  20. package/dist/chunk-FRKO3WX4.js.map +1 -0
  21. package/dist/chunk-G53CSLBF.js +54 -0
  22. package/dist/chunk-G53CSLBF.js.map +1 -0
  23. package/dist/chunk-G5BGBPFP.js +172 -0
  24. package/dist/chunk-G5BGBPFP.js.map +1 -0
  25. package/dist/chunk-HAZ26F3P.js +98 -0
  26. package/dist/chunk-HAZ26F3P.js.map +1 -0
  27. package/dist/chunk-HKX7WQLS.js +446 -0
  28. package/dist/chunk-HKX7WQLS.js.map +1 -0
  29. package/dist/{chunk-U5V5O5MN.js → chunk-LNK7LZER.js} +5 -3
  30. package/dist/chunk-LNK7LZER.js.map +1 -0
  31. package/dist/chunk-MCGK3FXQ.js +143 -0
  32. package/dist/chunk-MCGK3FXQ.js.map +1 -0
  33. package/dist/chunk-MKNZBKSR.js +90 -0
  34. package/dist/chunk-MKNZBKSR.js.map +1 -0
  35. package/dist/chunk-MUYLRTSR.js +82 -0
  36. package/dist/chunk-MUYLRTSR.js.map +1 -0
  37. package/dist/chunk-NVJ3ZO3P.js +3 -0
  38. package/dist/{chunk-HMR2GEGE.js.map → chunk-NVJ3ZO3P.js.map} +1 -1
  39. package/dist/chunk-NVLZFLYM.js +3 -0
  40. package/dist/chunk-NVLZFLYM.js.map +1 -0
  41. package/dist/chunk-ONH7PIJZ.js +300 -0
  42. package/dist/chunk-ONH7PIJZ.js.map +1 -0
  43. package/dist/chunk-QNYXQKFW.js +25 -0
  44. package/dist/chunk-QNYXQKFW.js.map +1 -0
  45. package/dist/chunk-RM677CNU.js +52 -0
  46. package/dist/chunk-RM677CNU.js.map +1 -0
  47. package/dist/chunk-WWGFIYKW.js +47 -0
  48. package/dist/chunk-WWGFIYKW.js.map +1 -0
  49. package/dist/chunk-XNRIM27H.js +76 -0
  50. package/dist/chunk-XNRIM27H.js.map +1 -0
  51. package/dist/{chunk-QLGJUDQF.js → chunk-ZNL7ZXPR.js} +26 -11
  52. package/dist/chunk-ZNL7ZXPR.js.map +1 -0
  53. package/dist/container-factory.d.ts +17 -0
  54. package/dist/container-factory.js +13 -0
  55. package/dist/container-factory.js.map +1 -0
  56. package/dist/container.d.ts +23 -0
  57. package/dist/container.js +3 -0
  58. package/dist/container.js.map +1 -0
  59. package/dist/context.d.ts +3 -1
  60. package/dist/errors.d.ts +18 -17
  61. package/dist/errors.js +1 -1
  62. package/dist/evaluator.d.ts +3 -1
  63. package/dist/flow.d.ts +12 -2
  64. package/dist/flow.js +2 -2
  65. package/dist/index.d.ts +7 -8
  66. package/dist/index.js +26 -14
  67. package/dist/linter.d.ts +3 -1
  68. package/dist/logger.d.ts +3 -1
  69. package/dist/node.d.ts +3 -1
  70. package/dist/node.js +1 -1
  71. package/dist/nodes/batch-gather.d.ts +9 -0
  72. package/dist/nodes/batch-gather.js +4 -0
  73. package/dist/nodes/batch-gather.js.map +1 -0
  74. package/dist/nodes/batch-scatter.d.ts +9 -0
  75. package/dist/nodes/batch-scatter.js +4 -0
  76. package/dist/nodes/batch-scatter.js.map +1 -0
  77. package/dist/nodes/subflow.d.ts +9 -0
  78. package/dist/nodes/subflow.js +10 -0
  79. package/dist/nodes/subflow.js.map +1 -0
  80. package/dist/nodes/wait.d.ts +9 -0
  81. package/dist/nodes/wait.js +4 -0
  82. package/dist/nodes/wait.js.map +1 -0
  83. package/dist/runtime/adapter.d.ts +3 -5
  84. package/dist/runtime/adapter.js +19 -9
  85. package/dist/runtime/execution-context.d.ts +3 -0
  86. package/dist/runtime/execution-context.js +6 -0
  87. package/dist/runtime/execution-context.js.map +1 -0
  88. package/dist/runtime/executors.d.ts +3 -26
  89. package/dist/runtime/executors.js +2 -2
  90. package/dist/runtime/index.d.ts +5 -7
  91. package/dist/runtime/index.js +21 -10
  92. package/dist/runtime/node-executor-factory.d.ts +12 -0
  93. package/dist/runtime/node-executor-factory.js +6 -0
  94. package/dist/runtime/node-executor-factory.js.map +1 -0
  95. package/dist/runtime/orchestrator.d.ts +9 -0
  96. package/dist/runtime/orchestrator.js +8 -0
  97. package/dist/runtime/orchestrator.js.map +1 -0
  98. package/dist/runtime/orchestrators/step-by-step.d.ts +16 -0
  99. package/dist/runtime/orchestrators/step-by-step.js +5 -0
  100. package/dist/runtime/orchestrators/step-by-step.js.map +1 -0
  101. package/dist/runtime/orchestrators/utils.d.ts +35 -0
  102. package/dist/runtime/orchestrators/utils.js +4 -0
  103. package/dist/runtime/orchestrators/utils.js.map +1 -0
  104. package/dist/runtime/runtime.d.ts +3 -41
  105. package/dist/runtime/runtime.js +18 -8
  106. package/dist/runtime/state.d.ts +3 -21
  107. package/dist/runtime/state.js +2 -1
  108. package/dist/runtime/traverser.d.ts +3 -26
  109. package/dist/runtime/traverser.js +1 -2
  110. package/dist/runtime/types.d.ts +3 -16
  111. package/dist/runtime/types.js +1 -1
  112. package/dist/runtime/workflow-logic-handler.d.ts +17 -0
  113. package/dist/runtime/workflow-logic-handler.js +5 -0
  114. package/dist/runtime/workflow-logic-handler.js.map +1 -0
  115. package/dist/sanitizer.d.ts +3 -1
  116. package/dist/serializer.d.ts +3 -1
  117. package/dist/testing/event-logger.d.ts +63 -0
  118. package/dist/testing/event-logger.js +3 -0
  119. package/dist/testing/event-logger.js.map +1 -0
  120. package/dist/testing/index.d.ts +6 -0
  121. package/dist/testing/index.js +31 -0
  122. package/dist/testing/index.js.map +1 -0
  123. package/dist/testing/run-with-trace.d.ts +38 -0
  124. package/dist/testing/run-with-trace.js +29 -0
  125. package/dist/testing/run-with-trace.js.map +1 -0
  126. package/dist/testing/stepper.d.ts +79 -0
  127. package/dist/testing/stepper.js +11 -0
  128. package/dist/testing/stepper.js.map +1 -0
  129. package/dist/types-ezHUBdpL.d.ts +564 -0
  130. package/dist/types.d.ts +3 -1
  131. package/package.json +55 -51
  132. package/LICENSE +0 -21
  133. package/dist/chunk-5ZXV3R5D.js +0 -28
  134. package/dist/chunk-5ZXV3R5D.js.map +0 -1
  135. package/dist/chunk-GEKDR2SS.js +0 -201
  136. package/dist/chunk-GEKDR2SS.js.map +0 -1
  137. package/dist/chunk-HMR2GEGE.js +0 -3
  138. package/dist/chunk-M2FRTT2K.js +0 -144
  139. package/dist/chunk-M2FRTT2K.js.map +0 -1
  140. package/dist/chunk-OTS5YJ3S.js +0 -494
  141. package/dist/chunk-OTS5YJ3S.js.map +0 -1
  142. package/dist/chunk-QLGJUDQF.js.map +0 -1
  143. package/dist/chunk-U5V5O5MN.js.map +0 -1
  144. package/dist/chunk-VSGQDLBF.js +0 -61
  145. package/dist/chunk-VSGQDLBF.js.map +0 -1
  146. package/dist/chunk-ZCHFZBGL.js.map +0 -1
  147. package/dist/types-CsTeXTiA.d.ts +0 -222
package/README.md CHANGED
@@ -8,15 +8,15 @@ Build complex, multi-step processes with a lightweight, composable, and type-saf
8
8
 
9
9
  ## Key Features
10
10
 
11
- - **Zero Dependencies**: Lightweight and dependency-free, ensuring a small footprint and easy integration.
12
- - **Declarative Workflows**: Define workflows as serializable objects with nodes and edges.
13
- - **Unopinionated Logic**: Nodes can be simple functions or structured classes, supporting any logic.
14
- - **Progressive Scalability**: Run in-memory or scale to distributed systems using the same blueprint.
15
- - **Resilient Execution**: Built-in support for retries, fallbacks, timeouts, and graceful cancellation.
16
- - **Advanced Patterns**: Includes batch processing and loop constructs for complex workflows.
17
- - **Extensibility**: Pluggable loggers, evaluators, serializers, and middleware for custom behavior.
18
- - **Static Analysis**: Tools to detect cycles, validate blueprints, and generate visual diagrams.
19
- - **Type-Safe API**: Fully typed with TypeScript for a robust developer experience.
11
+ - **Zero Dependencies**: Lightweight and dependency-free, ensuring easy integration in any runtime.
12
+ - **Declarative Workflows**: Define workflows as [serializable](https://flowcraft.js.org/guide/core-concepts#workflow-blueprint) objects with [nodes and edges](https://flowcraft.js.org/guide/core-concepts#nodes-edges).
13
+ - **Unopinionated Logic**: Nodes can be simple [functions](https://flowcraft.js.org/guide/core-concepts#function-based-nodes) or structured [classes](https://flowcraft.js.org/guide/core-concepts#class-based-nodes), supporting any logic.
14
+ - **Progressive Scalability**: Run [in-memory](https://flowcraft.js.org/guide/programmatic) or scale to [distributed systems](https://flowcraft.js.org/guide/distributed-execution) using the same blueprint.
15
+ - **Resilient Execution**: Built-in support for [retries](https://flowcraft.js.org/guide/error-handling#retries), [fallbacks](https://flowcraft.js.org/guide/error-handling#fallbacks), [timeouts](https://flowcraft.js.org/guide/core-concepts#config), and [cancellation](https://flowcraft.js.org/guide/core-concepts#cancellation).
16
+ - **Advanced Patterns**: Includes [batches](https://flowcraft.js.org/guide/batches), [loops](https://flowcraft.js.org/guide/loops), [subflows](https://flowcraft.js.org/guide/subflows), and [HITL](https://flowcraft.js.org/guide/hitl) constructs for complex workflows.
17
+ - **Extensibility**: Pluggable [loggers](https://flowcraft.js.org/guide/loggers), [evaluators](https://flowcraft.js.org/guide/evaluators), [serializers](https://flowcraft.js.org/guide/serializers), and [middleware](https://flowcraft.js.org/guide/middleware) for custom behavior.
18
+ - **Static Analysis**: Tools to [detect cycles](https://flowcraft.js.org/guide/static-analysis#detecting-cycles), [validate blueprints](https://flowcraft.js.org/guide/static-analysis#linting-a-blueprint), and [generate visual diagrams](https://flowcraft.js.org/guide/visualizing-workflows#generatemermaid).
19
+ - **Type-Safe API**: [Fully typed](https://flowcraft.js.org/guide/core-concepts#context) with TypeScript for a robust developer experience.
20
20
 
21
21
  ## Installation
22
22
 
@@ -32,21 +32,27 @@ Define and run a simple workflow in a few lines of code.
32
32
  ```typescript
33
33
  import { createFlow, FlowRuntime } from 'flowcraft'
34
34
 
35
- // 1. Define the workflow structure using the fluent API
35
+ // 1. Define your functions for the nodes
36
+ async function startNode({ context }: NodeContext) {
37
+ const output = await context.get('value')
38
+ return { output }
39
+ }
40
+ async function doubleNode({ input }: NodeContext) {
41
+ return { output: input * 2 }
42
+ }
43
+
44
+ // 2. Define the workflow structure
36
45
  const flow = createFlow('simple-workflow')
37
- .node('start', async () => ({ output: 42 }))
38
- .node('double', async ({ input }) => ({ output: input * 2 }))
46
+ .node('start', startNode)
47
+ .node('double', doubleNode)
39
48
  .edge('start', 'double')
40
- .toBlueprint()
41
49
 
42
- // 2. Create a runtime with the node implementations
43
- const runtime = new FlowRuntime({
44
- registry: flow.getFunctionRegistry(),
45
- })
50
+ // 3. Initialize the runtime
51
+ const runtime = new FlowRuntime()
46
52
 
47
- // 3. Execute the workflow
53
+ // 4. Execute the workflow
48
54
  async function run() {
49
- const result = await runtime.run(flow)
55
+ const result = await runtime.run(blueprint, { value: 42 })
50
56
  console.log(result.context) // { start: 42, double: 84 }
51
57
  console.log(result.status) // 'completed'
52
58
  }
@@ -56,18 +62,18 @@ run()
56
62
 
57
63
  ## Core Concepts
58
64
 
59
- - **Blueprint**: A serializable object that represents the structure of your workflow. It contains all the nodes and edges and can be stored as JSON or YAML. This is the single source of truth for a workflow's logic.
60
- - **Node**: A single unit of work. Node logic can be implemented as a simple async function or a structured class that extends `BaseNode` for more complex lifecycle management.
61
- - **Edge**: A connection between two nodes that defines the direction of the flow. Edges can be conditional, allowing you to create branching logic based on the output or `action` of a source node.
62
- - **Runtime**: The `FlowRuntime` is the engine that interprets a blueprint and executes its nodes in the correct order. It manages state, handles resiliency, and coordinates the entire process.
63
- - **Context**: An object that holds the state of a single workflow execution. The outputs of completed nodes are stored in the context and can be accessed by subsequent nodes.
65
+ - **Blueprint**: A serializable object that represents the structure of your workflow. It contains all the nodes and edges and can be stored as JSON or YAML. This is the single source of truth for a workflow's logic.
66
+ - **Node**: A single unit of work. Node logic can be implemented as a simple async function or a structured class that extends `BaseNode` for more complex lifecycle management.
67
+ - **Edge**: A connection between two nodes that defines the direction of the flow. Edges can be conditional, allowing you to create branching logic based on the output or `action` of a source node.
68
+ - **Runtime**: The `FlowRuntime` is the engine that interprets a blueprint and executes its nodes in the correct order. It manages state, handles resiliency, and coordinates the entire process.
69
+ - **Context**: An object that holds the state of a single workflow execution. The outputs of completed nodes are stored in the context and can be accessed by subsequent nodes.
64
70
 
65
71
  ## Resiliency and Error Handling
66
72
 
67
73
  Design robust workflows with built-in resiliency features.
68
74
 
69
- - **Retries**: Configure the `maxRetries` property on a node to automatically retry it on failure.
70
- - **Fallbacks**: Specify a `fallback` node ID in a node's configuration. If the node fails all its retry attempts, the fallback node will be executed instead, preventing the entire workflow from failing.
75
+ - **Retries**: Configure the `maxRetries` property on a node to automatically retry it on failure.
76
+ - **Fallbacks**: Specify a `fallback` node ID in a node's configuration. If the node fails all its retry attempts, the fallback node will be executed instead, preventing the entire workflow from failing.
71
77
 
72
78
  For more granular control, you can implement a node using the `BaseNode` class, which provides `prep`, `exec`, `post`, `fallback`, and `recover` lifecycle methods.
73
79
 
@@ -75,19 +81,19 @@ For more granular control, you can implement a node using the `BaseNode` class,
75
81
 
76
82
  Flowcraft includes tools to help you validate and visualize your workflows.
77
83
 
78
- - **Linter (`lintBlueprint`)**: Statically analyze a blueprint to find common errors, such as orphan nodes, invalid edges, or nodes with missing implementations.
79
- - **Analysis (`analyzeBlueprint`)**: Programmatically inspect a blueprint to detect cycles, find start/terminal nodes, and get other graph metrics.
80
- - **Diagram Generation (`generateMermaid`)**: Automatically generate a [Mermaid](https://mermaid-js.github.io/mermaid/#/) syntax string from a blueprint to easily visualize your workflow's structure.
84
+ - **Linter (`lintBlueprint`)**: Statically analyze a blueprint to find common errors, such as orphan nodes, invalid edges, or nodes with missing implementations.
85
+ - **Analysis (`analyzeBlueprint`)**: Programmatically inspect a blueprint to detect cycles, find start/terminal nodes, and get other graph metrics.
86
+ - **Diagram Generation (`generateMermaid`)**: Automatically generate a [Mermaid](https://mermaid-js.github.io/mermaid/#/) syntax string from a blueprint to easily visualize your workflow's structure.
81
87
 
82
88
  ## Extensibility and Customization
83
89
 
84
90
  The `FlowRuntime` can be configured with pluggable components to tailor its behavior to your specific needs:
85
91
 
86
- - **Logger**: Provide a custom `ILogger` implementation (e.g., Pino, Winston) to integrate with your existing logging infrastructure.
87
- - **Serializer**: Replace the default `JsonSerializer` with a more robust one (e.g., `superjson`) to handle complex data types like `Date`, `Map`, and `Set` in the workflow context.
88
- - **Evaluator**: Swap the default `PropertyEvaluator` for a more powerful expression engine (like `jsep` or `govaluate`) to enable complex logic in edge conditions. For trusted environments, an `UnsafeEvaluator` is also available.
89
- - **Middleware**: Wrap node execution with custom logic for cross-cutting concerns like distributed tracing, performance monitoring, or advanced authorization.
90
- - **Event Bus**: An event emitter for monitoring workflow and node lifecycle events (`workflow:start`, `node:finish`, etc.).
92
+ - **Logger**: Provide a custom `ILogger` implementation (e.g., Pino, Winston) to integrate with your existing logging infrastructure.
93
+ - **Serializer**: Replace the default `JsonSerializer` with a more robust one (e.g., `superjson`) to handle complex data types like `Date`, `Map`, and `Set` in the workflow context.
94
+ - **Evaluator**: Swap the default `PropertyEvaluator` for a more powerful expression engine (like `jsep` or `govaluate`) to enable complex logic in edge conditions. For trusted environments, an `UnsafeEvaluator` is also available.
95
+ - **Middleware**: Wrap node execution with custom logic for cross-cutting concerns like distributed tracing, performance monitoring, or advanced authorization.
96
+ - **Event Bus**: An event emitter for monitoring workflow and node lifecycle events (`workflow:start`, `node:finish`, etc.).
91
97
 
92
98
  ## Distributed Execution
93
99
 
@@ -1,4 +1,6 @@
1
- import { W as WorkflowBlueprint } from './types-CsTeXTiA.js';
1
+ import { g as WorkflowBlueprint } from './types-ezHUBdpL.js';
2
+ import './errors.js';
3
+ import './container.js';
2
4
 
3
5
  /**
4
6
  * A list of cycles found in the graph. Each cycle is an array of node IDs.
@@ -0,0 +1,74 @@
1
+ import { executeBatch, processResults } from './chunk-HAZ26F3P.js';
2
+ import { ExecutionContext } from './chunk-FRKO3WX4.js';
3
+ import { FlowcraftError } from './chunk-BCRWXTWX.js';
4
+
5
+ // src/runtime/orchestrator.ts
6
+ var DefaultOrchestrator = class {
7
+ async run(context, traverser) {
8
+ const hardwareConcurrency = globalThis.navigator?.hardwareConcurrency || 4;
9
+ const maxConcurrency = context.concurrency ?? Math.min(hardwareConcurrency, 10);
10
+ try {
11
+ context.signal?.throwIfAborted();
12
+ } catch (error) {
13
+ if (error instanceof DOMException && error.name === "AbortError") {
14
+ throw new FlowcraftError("Workflow cancelled", { isFatal: false });
15
+ }
16
+ throw error;
17
+ }
18
+ let iterations = 0;
19
+ const maxIterations = 1e4;
20
+ while (traverser.hasMoreWork()) {
21
+ if (++iterations > maxIterations) {
22
+ throw new Error("Traversal exceeded maximum iterations, possible infinite loop");
23
+ }
24
+ try {
25
+ context.signal?.throwIfAborted();
26
+ } catch (error) {
27
+ if (error instanceof DOMException && error.name === "AbortError") {
28
+ throw new FlowcraftError("Workflow cancelled", { isFatal: false });
29
+ }
30
+ throw error;
31
+ }
32
+ const readyNodes = traverser.getReadyNodes();
33
+ const dynamicBlueprint = traverser.getDynamicBlueprint();
34
+ const updatedContext = new ExecutionContext(
35
+ dynamicBlueprint,
36
+ context.state,
37
+ context.nodeRegistry,
38
+ context.executionId,
39
+ context.runtime,
40
+ context.services,
41
+ context.signal,
42
+ context.concurrency
43
+ );
44
+ const settledResults = await executeBatch(
45
+ readyNodes,
46
+ dynamicBlueprint,
47
+ context.state,
48
+ (nodeId) => context.runtime.getExecutorForNode(nodeId, updatedContext),
49
+ context.runtime,
50
+ maxConcurrency
51
+ );
52
+ await processResults(
53
+ settledResults,
54
+ traverser,
55
+ context.state,
56
+ context.runtime,
57
+ context.blueprint,
58
+ context.executionId
59
+ );
60
+ if (context.state.isAwaiting()) {
61
+ break;
62
+ }
63
+ }
64
+ const isTraversalComplete = !traverser.hasMoreWork();
65
+ const status = context.state.getStatus(isTraversalComplete);
66
+ const result = await context.state.toResult(context.services.serializer);
67
+ result.status = status;
68
+ return result;
69
+ }
70
+ };
71
+
72
+ export { DefaultOrchestrator };
73
+ //# sourceMappingURL=chunk-33NO4PUJ.js.map
74
+ //# sourceMappingURL=chunk-33NO4PUJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/orchestrator.ts"],"names":[],"mappings":";;;;;AAOO,IAAM,sBAAN,MAAmD;AAAA,EACzD,MAAM,GAAA,CAAI,OAAA,EAAqC,SAAA,EAAyD;AACvG,IAAA,MAAM,mBAAA,GAAsB,UAAA,CAAW,SAAA,EAAW,mBAAA,IAAuB,CAAA;AACzE,IAAA,MAAM,iBAAiB,OAAA,CAAQ,WAAA,IAAe,IAAA,CAAK,GAAA,CAAI,qBAAqB,EAAE,CAAA;AAE9E,IAAA,IAAI;AACH,MAAA,OAAA,CAAQ,QAAQ,cAAA,EAAe;AAAA,IAChC,SAAS,KAAA,EAAO;AACf,MAAA,IAAI,KAAA,YAAiB,YAAA,IAAgB,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc;AACjE,QAAA,MAAM,IAAI,cAAA,CAAe,oBAAA,EAAsB,EAAE,OAAA,EAAS,OAAO,CAAA;AAAA,MAClE;AACA,MAAA,MAAM,KAAA;AAAA,IACP;AAEA,IAAA,IAAI,UAAA,GAAa,CAAA;AACjB,IAAA,MAAM,aAAA,GAAgB,GAAA;AAEtB,IAAA,OAAO,SAAA,CAAU,aAAY,EAAG;AAC/B,MAAA,IAAI,EAAE,aAAa,aAAA,EAAe;AACjC,QAAA,MAAM,IAAI,MAAM,+DAA+D,CAAA;AAAA,MAChF;AAEA,MAAA,IAAI;AACH,QAAA,OAAA,CAAQ,QAAQ,cAAA,EAAe;AAAA,MAChC,SAAS,KAAA,EAAO;AACf,QAAA,IAAI,KAAA,YAAiB,YAAA,IAAgB,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc;AACjE,UAAA,MAAM,IAAI,cAAA,CAAe,oBAAA,EAAsB,EAAE,OAAA,EAAS,OAAO,CAAA;AAAA,QAClE;AACA,QAAA,MAAM,KAAA;AAAA,MACP;AAEA,MAAA,MAAM,UAAA,GAAa,UAAU,aAAA,EAAc;AAC3C,MAAA,MAAM,gBAAA,GAAmB,UAAU,mBAAA,EAAoB;AACvD,MAAA,MAAM,iBAAiB,IAAI,gBAAA;AAAA,QAC1B,gBAAA;AAAA,QACA,OAAA,CAAQ,KAAA;AAAA,QACR,OAAA,CAAQ,YAAA;AAAA,QACR,OAAA,CAAQ,WAAA;AAAA,QACR,OAAA,CAAQ,OAAA;AAAA,QACR,OAAA,CAAQ,QAAA;AAAA,QACR,OAAA,CAAQ,MAAA;AAAA,QACR,OAAA,CAAQ;AAAA,OACT;AACA,MAAA,MAAM,iBAAiB,MAAM,YAAA;AAAA,QAC5B,UAAA;AAAA,QACA,gBAAA;AAAA,QACA,OAAA,CAAQ,KAAA;AAAA,QACR,CAAC,MAAA,KAAmB,OAAA,CAAQ,OAAA,CAAQ,kBAAA,CAAmB,QAAQ,cAAc,CAAA;AAAA,QAC7E,OAAA,CAAQ,OAAA;AAAA,QACR;AAAA,OACD;AAEA,MAAA,MAAM,cAAA;AAAA,QACL,cAAA;AAAA,QACA,SAAA;AAAA,QACA,OAAA,CAAQ,KAAA;AAAA,QACR,OAAA,CAAQ,OAAA;AAAA,QACR,OAAA,CAAQ,SAAA;AAAA,QACR,OAAA,CAAQ;AAAA,OACT;AAEA,MAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,UAAA,EAAW,EAAG;AAC/B,QAAA;AAAA,MACD;AAAA,IACD;AAEA,IAAA,MAAM,mBAAA,GAAsB,CAAC,SAAA,CAAU,WAAA,EAAY;AACnD,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAU,mBAAmB,CAAA;AAC1D,IAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,MAAM,QAAA,CAAS,OAAA,CAAQ,SAAS,UAAU,CAAA;AACvE,IAAA,MAAA,CAAO,MAAA,GAAS,MAAA;AAChB,IAAA,OAAO,MAAA;AAAA,EACR;AACD","file":"chunk-33NO4PUJ.js","sourcesContent":["import { FlowcraftError } from '../errors'\nimport type { WorkflowResult } from '../types'\nimport { ExecutionContext } from './execution-context'\nimport { executeBatch, processResults } from './orchestrators/utils'\nimport type { GraphTraverser } from './traverser'\nimport type { IOrchestrator } from './types'\n\nexport class DefaultOrchestrator implements IOrchestrator {\n\tasync run(context: ExecutionContext<any, any>, traverser: GraphTraverser): Promise<WorkflowResult<any>> {\n\t\tconst hardwareConcurrency = globalThis.navigator?.hardwareConcurrency || 4\n\t\tconst maxConcurrency = context.concurrency ?? Math.min(hardwareConcurrency, 10)\n\n\t\ttry {\n\t\t\tcontext.signal?.throwIfAborted()\n\t\t} catch (error) {\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow new FlowcraftError('Workflow cancelled', { isFatal: false })\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\n\t\tlet iterations = 0\n\t\tconst maxIterations = 10000\n\n\t\twhile (traverser.hasMoreWork()) {\n\t\t\tif (++iterations > maxIterations) {\n\t\t\t\tthrow new Error('Traversal exceeded maximum iterations, possible infinite loop')\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcontext.signal?.throwIfAborted()\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\t\tthrow new FlowcraftError('Workflow cancelled', { isFatal: false })\n\t\t\t\t}\n\t\t\t\tthrow error\n\t\t\t}\n\n\t\t\tconst readyNodes = traverser.getReadyNodes()\n\t\t\tconst dynamicBlueprint = traverser.getDynamicBlueprint()\n\t\t\tconst updatedContext = new ExecutionContext(\n\t\t\t\tdynamicBlueprint,\n\t\t\t\tcontext.state,\n\t\t\t\tcontext.nodeRegistry,\n\t\t\t\tcontext.executionId,\n\t\t\t\tcontext.runtime,\n\t\t\t\tcontext.services,\n\t\t\t\tcontext.signal,\n\t\t\t\tcontext.concurrency,\n\t\t\t)\n\t\t\tconst settledResults = await executeBatch(\n\t\t\t\treadyNodes,\n\t\t\t\tdynamicBlueprint,\n\t\t\t\tcontext.state,\n\t\t\t\t(nodeId: string) => context.runtime.getExecutorForNode(nodeId, updatedContext),\n\t\t\t\tcontext.runtime,\n\t\t\t\tmaxConcurrency,\n\t\t\t)\n\n\t\t\tawait processResults(\n\t\t\t\tsettledResults,\n\t\t\t\ttraverser,\n\t\t\t\tcontext.state,\n\t\t\t\tcontext.runtime,\n\t\t\t\tcontext.blueprint,\n\t\t\t\tcontext.executionId,\n\t\t\t)\n\n\t\t\tif (context.state.isAwaiting()) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tconst isTraversalComplete = !traverser.hasMoreWork()\n\t\tconst status = context.state.getStatus(isTraversalComplete)\n\t\tconst result = await context.state.toResult(context.services.serializer)\n\t\tresult.status = status\n\t\treturn result\n\t}\n}\n"]}
@@ -0,0 +1,42 @@
1
+ import { BaseNode } from './chunk-LNK7LZER.js';
2
+
3
+ // src/nodes/batch-gather.ts
4
+ var BatchGatherNode = class extends BaseNode {
5
+ async exec(_prepResult, context) {
6
+ const { gatherNodeId, outputKey } = this.params || {};
7
+ const hasMore = await context.context.get(`${gatherNodeId}_hasMore`) || false;
8
+ const dynamicNodes = [];
9
+ let results = [];
10
+ if (hasMore) {
11
+ const newScatterId = `${gatherNodeId}_scatter_next`;
12
+ dynamicNodes.push({
13
+ id: newScatterId,
14
+ uses: "batch-scatter",
15
+ inputs: context.input,
16
+ params: { ...this.params, gatherNodeId }
17
+ });
18
+ } else {
19
+ const allWorkerIds = await context.context.get(`${gatherNodeId}_allWorkerIds`) || [];
20
+ results = [];
21
+ for (const workerId of allWorkerIds) {
22
+ const result = await context.context.get(`_outputs.${workerId}`);
23
+ if (result !== void 0) results.push(result);
24
+ }
25
+ await context.context.set(outputKey, results);
26
+ const parentBatchId = gatherNodeId.replace("_gather", "");
27
+ await context.dependencies.runtime.services.eventBus.emit({
28
+ type: "batch:finish",
29
+ payload: {
30
+ batchId: parentBatchId,
31
+ gatherNodeId,
32
+ results
33
+ }
34
+ });
35
+ }
36
+ return { dynamicNodes, output: results };
37
+ }
38
+ };
39
+
40
+ export { BatchGatherNode };
41
+ //# sourceMappingURL=chunk-BC4G7OM6.js.map
42
+ //# sourceMappingURL=chunk-BC4G7OM6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/nodes/batch-gather.ts"],"names":[],"mappings":";;;AAGO,IAAM,eAAA,GAAN,cAA8B,QAAA,CAAS;AAAA,EAC7C,MAAM,IAAA,CAAK,WAAA,EAAkB,OAAA,EAAyE;AACrG,IAAA,MAAM,EAAE,YAAA,EAAc,SAAA,EAAU,GAAK,IAAA,CAAK,UAAkB,EAAC;AAC7D,IAAA,MAAM,OAAA,GAAW,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA,EAAG,YAAY,UAAU,CAAA,IAAM,KAAA;AAC1E,IAAA,MAAM,eAAsB,EAAC;AAC7B,IAAA,IAAI,UAAiB,EAAC;AACtB,IAAA,IAAI,OAAA,EAAS;AAEZ,MAAA,MAAM,YAAA,GAAe,GAAG,YAAY,CAAA,aAAA,CAAA;AACpC,MAAA,YAAA,CAAa,IAAA,CAAK;AAAA,QACjB,EAAA,EAAI,YAAA;AAAA,QACJ,IAAA,EAAM,eAAA;AAAA,QACN,QAAQ,OAAA,CAAQ,KAAA;AAAA,QAChB,MAAA,EAAQ,EAAE,GAAG,IAAA,CAAK,QAAQ,YAAA;AAAa,OACvC,CAAA;AAAA,IACF,CAAA,MAAO;AAEN,MAAA,MAAM,YAAA,GAAiB,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA,EAAG,YAAY,CAAA,aAAA,CAAe,CAAA,IAAmB,EAAC;AACnG,MAAA,OAAA,GAAU,EAAC;AACX,MAAA,KAAA,MAAW,YAAY,YAAA,EAAc;AACpC,QAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,QAAQ,GAAA,CAAI,CAAA,SAAA,EAAY,QAAQ,CAAA,CAAS,CAAA;AACtE,QAAA,IAAI,MAAA,KAAW,MAAA,EAAW,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA;AAAA,MAC9C;AACA,MAAA,MAAM,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,SAAA,EAAkB,OAAO,CAAA;AAEnD,MAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA;AACxD,MAAA,MAAM,OAAA,CAAQ,YAAA,CAAa,OAAA,CAAQ,QAAA,CAAS,SAAS,IAAA,CAAK;AAAA,QACzD,IAAA,EAAM,cAAA;AAAA,QACN,OAAA,EAAS;AAAA,UACR,OAAA,EAAS,aAAA;AAAA,UACT,YAAA;AAAA,UACA;AAAA;AACD,OACA,CAAA;AAAA,IACF;AACA,IAAA,OAAO,EAAE,YAAA,EAAc,MAAA,EAAQ,OAAA,EAAQ;AAAA,EACxC;AACD","file":"chunk-BC4G7OM6.js","sourcesContent":["import { BaseNode } from '../node'\nimport type { NodeContext, NodeResult } from '../types'\n\nexport class BatchGatherNode extends BaseNode {\n\tasync exec(_prepResult: any, context: NodeContext<any, any, any>): Promise<Omit<NodeResult, 'error'>> {\n\t\tconst { gatherNodeId, outputKey } = (this.params as any) || {}\n\t\tconst hasMore = (await context.context.get(`${gatherNodeId}_hasMore`)) || false\n\t\tconst dynamicNodes: any[] = []\n\t\tlet results: any[] = []\n\t\tif (hasMore) {\n\t\t\t// create a new scatter node for the next chunk\n\t\t\tconst newScatterId = `${gatherNodeId}_scatter_next`\n\t\t\tdynamicNodes.push({\n\t\t\t\tid: newScatterId,\n\t\t\t\tuses: 'batch-scatter',\n\t\t\t\tinputs: context.input,\n\t\t\t\tparams: { ...this.params, gatherNodeId },\n\t\t\t})\n\t\t} else {\n\t\t\t// collect results from all chunks into outputKey\n\t\t\tconst allWorkerIds = ((await context.context.get(`${gatherNodeId}_allWorkerIds`)) as string[]) || []\n\t\t\tresults = []\n\t\t\tfor (const workerId of allWorkerIds) {\n\t\t\t\tconst result = await context.context.get(`_outputs.${workerId}` as any)\n\t\t\t\tif (result !== undefined) results.push(result)\n\t\t\t}\n\t\t\tawait context.context.set(outputKey as any, results)\n\n\t\t\tconst parentBatchId = gatherNodeId.replace('_gather', '')\n\t\t\tawait context.dependencies.runtime.services.eventBus.emit({\n\t\t\t\ttype: 'batch:finish',\n\t\t\t\tpayload: {\n\t\t\t\t\tbatchId: parentBatchId,\n\t\t\t\t\tgatherNodeId,\n\t\t\t\t\tresults,\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\treturn { dynamicNodes, output: results }\n\t}\n}\n"]}
@@ -0,0 +1,21 @@
1
+ // src/errors.ts
2
+ var FlowcraftError = class extends Error {
3
+ message;
4
+ nodeId;
5
+ blueprintId;
6
+ executionId;
7
+ isFatal;
8
+ constructor(message, options = {}) {
9
+ super(message, { cause: options.cause });
10
+ this.name = "FlowcraftError";
11
+ this.message = message;
12
+ this.nodeId = options.nodeId;
13
+ this.blueprintId = options.blueprintId;
14
+ this.executionId = options.executionId;
15
+ this.isFatal = options.isFatal ?? false;
16
+ }
17
+ };
18
+
19
+ export { FlowcraftError };
20
+ //# sourceMappingURL=chunk-BCRWXTWX.js.map
21
+ //# sourceMappingURL=chunk-BCRWXTWX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":";AAIO,IAAM,cAAA,GAAN,cAA6B,KAAA,CAAM;AAAA,EACzB,OAAA;AAAA,EACA,MAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EAEhB,WAAA,CACC,OAAA,EACA,OAAA,GAMI,EAAC,EACJ;AAED,IAAA,KAAA,CAAM,OAAA,EAAS,EAAE,KAAA,EAAO,OAAA,CAAQ,OAAO,CAAA;AACvC,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAEf,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,cAAc,OAAA,CAAQ,WAAA;AAC3B,IAAA,IAAA,CAAK,cAAc,OAAA,CAAQ,WAAA;AAC3B,IAAA,IAAA,CAAK,OAAA,GAAU,QAAQ,OAAA,IAAW,KAAA;AAAA,EACnC;AACD","file":"chunk-BCRWXTWX.js","sourcesContent":["/**\n * A single, comprehensive error class for the framework.\n * Use this for all errors to ensure consistent structure and easy debugging.\n */\nexport class FlowcraftError extends Error {\n\tpublic readonly message: string\n\tpublic readonly nodeId?: string\n\tpublic readonly blueprintId?: string\n\tpublic readonly executionId?: string\n\tpublic readonly isFatal: boolean\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions: {\n\t\t\tcause?: Error\n\t\t\tnodeId?: string\n\t\t\tblueprintId?: string\n\t\t\texecutionId?: string\n\t\t\tisFatal?: boolean\n\t\t} = {},\n\t) {\n\t\t// Pass the cause to the parent Error constructor for proper chaining\n\t\tsuper(message, { cause: options.cause })\n\t\tthis.name = 'FlowcraftError'\n\t\tthis.message = message\n\n\t\tthis.nodeId = options.nodeId\n\t\tthis.blueprintId = options.blueprintId\n\t\tthis.executionId = options.executionId\n\t\tthis.isFatal = options.isFatal ?? false\n\t}\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { InMemoryEventLogger } from './chunk-MUYLRTSR.js';
2
+ import { FlowRuntime } from './chunk-HKX7WQLS.js';
3
+
4
+ // src/testing/run-with-trace.ts
5
+ async function runWithTrace(runtime, blueprint, initialState = {}, options = {}) {
6
+ const eventLogger = new InMemoryEventLogger();
7
+ const testRuntime = new FlowRuntime({
8
+ ...runtime.options,
9
+ eventBus: eventLogger
10
+ });
11
+ try {
12
+ const result = await testRuntime.run(blueprint, initialState, options);
13
+ if (process.env.DEBUG) {
14
+ eventLogger.printLog(`Successful Trace: ${blueprint.id}`);
15
+ }
16
+ return result;
17
+ } catch (error) {
18
+ eventLogger.printLog(`Failing Test Trace: ${blueprint.id}`);
19
+ throw error;
20
+ }
21
+ }
22
+
23
+ export { runWithTrace };
24
+ //# sourceMappingURL=chunk-BN4MV36K.js.map
25
+ //# sourceMappingURL=chunk-BN4MV36K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing/run-with-trace.ts"],"names":[],"mappings":";;;;AA+BA,eAAsB,YAAA,CACrB,SACA,SAAA,EACA,YAAA,GAA2C,EAAC,EAC5C,OAAA,GAII,EAAC,EACJ;AACD,EAAA,MAAM,WAAA,GAAc,IAAI,mBAAA,EAAoB;AAC5C,EAAA,MAAM,WAAA,GAAc,IAAI,WAAA,CAAY;AAAA,IACnC,GAAG,OAAA,CAAQ,OAAA;AAAA,IACX,QAAA,EAAU;AAAA,GACV,CAAA;AAED,EAAA,IAAI;AACH,IAAA,MAAM,SAAS,MAAM,WAAA,CAAY,GAAA,CAAI,SAAA,EAAW,cAAc,OAAO,CAAA;AACrE,IAAA,IAAI,OAAA,CAAQ,IAAI,KAAA,EAAO;AACtB,MAAA,WAAA,CAAY,QAAA,CAAS,CAAA,kBAAA,EAAqB,SAAA,CAAU,EAAE,CAAA,CAAE,CAAA;AAAA,IACzD;AACA,IAAA,OAAO,MAAA;AAAA,EACR,SAAS,KAAA,EAAO;AACf,IAAA,WAAA,CAAY,QAAA,CAAS,CAAA,oBAAA,EAAuB,SAAA,CAAU,EAAE,CAAA,CAAE,CAAA;AAC1D,IAAA,MAAM,KAAA;AAAA,EACP;AACD","file":"chunk-BN4MV36K.js","sourcesContent":["import { FlowRuntime } from '../runtime'\nimport type { WorkflowBlueprint } from '../types'\nimport { InMemoryEventLogger } from './event-logger'\n\n/**\n * A test helper that executes a workflow and automatically prints a detailed\n * execution trace to the console if the workflow fails.\n *\n * @example\n * // In your test file (e.g., my-workflow.test.ts)\n * it('should process data correctly', async () => {\n * const flow = createFlow('my-flow')\n * .node('a', async () => ({ output: 1 }))\n * .node('b', async ({ input }) => ({ output: input + 1 })) // Bug: returns { output: 3 }\n * .edge('a', 'b')\n *\n * const runtime = new FlowRuntime({})\n *\n * // If this test fails, a full, human-readable trace of the execution\n * // (inputs, outputs, context changes) is printed to the console.\n * const result = await runWithTrace(runtime, flow.toBlueprint())\n *\n * expect(result.context.b).toBe(2)\n * })\n *\n * @param runtime The original FlowRuntime instance (its options will be used).\n * @param blueprint The WorkflowBlueprint to execute.\n * @param initialState The initial state for the workflow run.\n * @param options Additional options for the run.\n * @returns The WorkflowResult if successful.\n */\nexport async function runWithTrace<TContext extends Record<string, any>>(\n\truntime: FlowRuntime<TContext, any>,\n\tblueprint: WorkflowBlueprint,\n\tinitialState: Partial<TContext> | string = {},\n\toptions: {\n\t\tfunctionRegistry?: Map<string, any>\n\t\tstrict?: boolean\n\t\tsignal?: AbortSignal\n\t} = {},\n) {\n\tconst eventLogger = new InMemoryEventLogger()\n\tconst testRuntime = new FlowRuntime({\n\t\t...runtime.options,\n\t\teventBus: eventLogger,\n\t})\n\n\ttry {\n\t\tconst result = await testRuntime.run(blueprint, initialState, options)\n\t\tif (process.env.DEBUG) {\n\t\t\teventLogger.printLog(`Successful Trace: ${blueprint.id}`)\n\t\t}\n\t\treturn result\n\t} catch (error) {\n\t\teventLogger.printLog(`Failing Test Trace: ${blueprint.id}`)\n\t\tthrow error\n\t}\n}\n"]}
@@ -1,6 +1,7 @@
1
- import { isNodeClass } from './chunk-U5V5O5MN.js';
1
+ import { isNodeClass } from './chunk-LNK7LZER.js';
2
2
 
3
3
  // src/flow.ts
4
+ var hashCounter = 0;
4
5
  function _hashFunction(fn) {
5
6
  const source = fn.toString();
6
7
  let hash = 0;
@@ -9,19 +10,21 @@ function _hashFunction(fn) {
9
10
  hash = (hash << 5) - hash + char;
10
11
  hash = hash & hash;
11
12
  }
12
- return Math.abs(hash).toString(16);
13
+ return (Math.abs(hash) + hashCounter++).toString(16);
13
14
  }
14
15
  var Flow = class {
15
16
  blueprint;
16
17
  functionRegistry;
17
18
  loopControllerIds;
18
19
  loopDefinitions;
20
+ batchDefinitions;
19
21
  cycleEntryPoints;
20
22
  constructor(id) {
21
23
  this.blueprint = { id, nodes: [], edges: [] };
22
24
  this.functionRegistry = /* @__PURE__ */ new Map();
23
25
  this.loopControllerIds = /* @__PURE__ */ new Map();
24
26
  this.loopDefinitions = [];
27
+ this.batchDefinitions = [];
25
28
  this.cycleEntryPoints = /* @__PURE__ */ new Map();
26
29
  }
27
30
  node(id, implementation, options) {
@@ -56,6 +59,7 @@ var Flow = class {
56
59
  const { inputKey, outputKey } = options;
57
60
  const scatterId = `${id}_scatter`;
58
61
  const gatherId = `${id}_gather`;
62
+ this.batchDefinitions.push({ id, scatterId, gatherId });
59
63
  let workerUsesKey;
60
64
  if (isNodeClass(worker)) {
61
65
  workerUsesKey = worker.name && worker.name !== "BaseNode" ? worker.name : `class_batch_worker_${_hashFunction(worker)}`;
@@ -82,6 +86,16 @@ var Flow = class {
82
86
  this.edge(scatterId, gatherId);
83
87
  return this;
84
88
  }
89
+ /**
90
+ * Creates a wait node that pauses workflow execution for external input.
91
+ * @param id A unique identifier for the wait node.
92
+ * @param options Optional configuration for the wait node.
93
+ */
94
+ wait(id, options) {
95
+ const nodeDef = { id, uses: "wait", ...options };
96
+ this.blueprint.nodes?.push(nodeDef);
97
+ return this;
98
+ }
85
99
  /**
86
100
  * Creates a loop pattern in the workflow graph.
87
101
  * @param id A unique identifier for the loop construct.
@@ -94,7 +108,7 @@ var Flow = class {
94
108
  const { startNodeId, endNodeId, condition } = options;
95
109
  const controllerId = `${id}-loop`;
96
110
  this.loopControllerIds.set(id, controllerId);
97
- this.loopDefinitions.push({ id, startNodeId, endNodeId });
111
+ this.loopDefinitions.push({ id, startNodeId, endNodeId, condition });
98
112
  this.blueprint.nodes?.push({
99
113
  id: controllerId,
100
114
  uses: "loop-controller",
@@ -131,6 +145,35 @@ var Flow = class {
131
145
  if (!this.blueprint.nodes || this.blueprint.nodes.length === 0) {
132
146
  throw new Error("Cannot build a blueprint with no nodes.");
133
147
  }
148
+ const finalEdges = [];
149
+ const processedOriginalEdges = /* @__PURE__ */ new Set();
150
+ const allOriginalEdges = this.blueprint.edges || [];
151
+ for (const loopDef of this.loopDefinitions) {
152
+ const controllerId = this.getLoopControllerId(loopDef.id);
153
+ const edgesToRewire = allOriginalEdges.filter((e) => e.source === loopDef.endNodeId && e.target !== controllerId);
154
+ for (const edge of edgesToRewire) {
155
+ finalEdges.push({ ...edge, source: controllerId, action: edge.action || "break" });
156
+ processedOriginalEdges.add(edge);
157
+ }
158
+ }
159
+ for (const batchDef of this.batchDefinitions) {
160
+ const incomingEdges = allOriginalEdges.filter((e) => e.target === batchDef.id);
161
+ for (const edge of incomingEdges) {
162
+ finalEdges.push({ ...edge, target: batchDef.scatterId });
163
+ processedOriginalEdges.add(edge);
164
+ }
165
+ const outgoingEdges = allOriginalEdges.filter((e) => e.source === batchDef.id);
166
+ for (const edge of outgoingEdges) {
167
+ finalEdges.push({ ...edge, source: batchDef.gatherId });
168
+ processedOriginalEdges.add(edge);
169
+ }
170
+ }
171
+ for (const edge of allOriginalEdges) {
172
+ if (!processedOriginalEdges.has(edge)) {
173
+ finalEdges.push(edge);
174
+ }
175
+ }
176
+ this.blueprint.edges = finalEdges;
134
177
  for (const loopDef of this.loopDefinitions) {
135
178
  const startNode = this.blueprint.nodes?.find((n) => n.id === loopDef.startNodeId);
136
179
  const endNode = this.blueprint.nodes?.find((n) => n.id === loopDef.endNodeId);
@@ -154,11 +197,83 @@ var Flow = class {
154
197
  getFunctionRegistry() {
155
198
  return this.functionRegistry;
156
199
  }
200
+ toGraphRepresentation() {
201
+ const blueprint = this.toBlueprint();
202
+ const uiNodes = [];
203
+ const uiEdges = [];
204
+ const ignoredNodeIds = /* @__PURE__ */ new Set();
205
+ for (const loopDef of this.loopDefinitions) {
206
+ const controllerId = this.loopControllerIds.get(loopDef.id);
207
+ if (!controllerId) continue;
208
+ ignoredNodeIds.add(controllerId);
209
+ uiEdges.push({
210
+ source: loopDef.endNodeId,
211
+ target: loopDef.startNodeId,
212
+ data: {
213
+ isLoopback: true,
214
+ condition: loopDef.condition,
215
+ label: `continue if: ${loopDef.condition}`
216
+ }
217
+ });
218
+ const breakEdges = blueprint.edges.filter((edge) => edge.source === controllerId && edge.action === "break");
219
+ for (const breakEdge of breakEdges) {
220
+ uiEdges.push({
221
+ ...breakEdge,
222
+ source: loopDef.endNodeId
223
+ });
224
+ }
225
+ }
226
+ const scatterNodes = blueprint.nodes.filter((n) => n.uses === "batch-scatter");
227
+ for (const scatterNode of scatterNodes) {
228
+ const gatherNodeId = scatterNode.params?.gatherNodeId;
229
+ if (!gatherNodeId) continue;
230
+ ignoredNodeIds.add(scatterNode.id);
231
+ ignoredNodeIds.add(gatherNodeId);
232
+ const batchId = scatterNode.id.replace("_scatter", "");
233
+ const gatherNode = blueprint.nodes.find((n) => n.id === gatherNodeId);
234
+ uiNodes.push({
235
+ id: batchId,
236
+ uses: scatterNode.params?.workerUsesKey,
237
+ type: "batch-worker",
238
+ data: {
239
+ label: `Batch: ${batchId}`,
240
+ isBatchPlaceholder: true,
241
+ workerUsesKey: scatterNode.params?.workerUsesKey,
242
+ inputKey: scatterNode.inputs,
243
+ outputKey: gatherNode?.params?.outputKey
244
+ }
245
+ });
246
+ const incomingEdges = blueprint.edges.filter((e) => e.target === scatterNode.id);
247
+ for (const edge of incomingEdges) {
248
+ uiEdges.push({ ...edge, target: batchId });
249
+ }
250
+ const outgoingEdges = blueprint.edges.filter((e) => e.source === gatherNodeId);
251
+ for (const edge of outgoingEdges) {
252
+ uiEdges.push({ ...edge, source: batchId });
253
+ }
254
+ }
255
+ for (const node of blueprint.nodes) {
256
+ if (!ignoredNodeIds.has(node.id)) {
257
+ uiNodes.push(node);
258
+ }
259
+ }
260
+ for (const edge of blueprint.edges) {
261
+ if (!ignoredNodeIds.has(edge.source) && !ignoredNodeIds.has(edge.target)) {
262
+ const alreadyAdded = uiEdges.some(
263
+ (e) => e.source === edge.source && e.target === edge.target && e.action === edge.action
264
+ );
265
+ if (!alreadyAdded) {
266
+ uiEdges.push(edge);
267
+ }
268
+ }
269
+ }
270
+ return { nodes: uiNodes, edges: uiEdges };
271
+ }
157
272
  };
158
273
  function createFlow(id) {
159
274
  return new Flow(id);
160
275
  }
161
276
 
162
277
  export { Flow, createFlow };
163
- //# sourceMappingURL=chunk-ZCHFZBGL.js.map
164
- //# sourceMappingURL=chunk-ZCHFZBGL.js.map
278
+ //# sourceMappingURL=chunk-C4HYIJI3.js.map
279
+ //# sourceMappingURL=chunk-C4HYIJI3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/flow.ts"],"names":[],"mappings":";;;AAMA,IAAI,WAAA,GAAc,CAAA;AAClB,SAAS,cAAc,EAAA,EAAwF;AAC9G,EAAA,MAAM,MAAA,GAAS,GAAG,QAAA,EAAS;AAC3B,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACvC,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,UAAA,CAAW,CAAC,CAAA;AAChC,IAAA,IAAA,GAAA,CAAQ,IAAA,IAAQ,KAAK,IAAA,GAAO,IAAA;AAC5B,IAAA,IAAA,GAAO,IAAA,GAAO,IAAA;AAAA,EACf;AAEA,EAAA,OAAA,CAAQ,KAAK,GAAA,CAAI,IAAI,CAAA,GAAI,WAAA,EAAA,EAAe,SAAS,EAAE,CAAA;AACpD;AAKO,IAAM,OAAN,MAGL;AAAA,EACO,SAAA;AAAA,EACA,gBAAA;AAAA,EACA,iBAAA;AAAA,EACA,eAAA;AAAA,EAMA,gBAAA;AAAA,EAKA,gBAAA;AAAA,EAER,YAAY,EAAA,EAAY;AACvB,IAAA,IAAA,CAAK,SAAA,GAAY,EAAE,EAAA,EAAI,KAAA,EAAO,EAAC,EAAG,KAAA,EAAO,EAAC,EAAE;AAC5C,IAAA,IAAA,CAAK,gBAAA,uBAAuB,GAAA,EAAI;AAChC,IAAA,IAAA,CAAK,iBAAA,uBAAwB,GAAA,EAAI;AACjC,IAAA,IAAA,CAAK,kBAAkB,EAAC;AACxB,IAAA,IAAA,CAAK,mBAAmB,EAAC;AACzB,IAAA,IAAA,CAAK,gBAAA,uBAAuB,GAAA,EAAI;AAAA,EACjC;AAAA,EAEA,IAAA,CACC,EAAA,EACA,cAAA,EAGA,OAAA,EACO;AACP,IAAA,IAAI,OAAA;AAEJ,IAAA,IAAI,WAAA,CAAY,cAAc,CAAA,EAAG;AAChC,MAAA,OAAA,GACC,cAAA,CAAe,IAAA,IAAQ,cAAA,CAAe,IAAA,KAAS,UAAA,GAC5C,eAAe,IAAA,GACf,CAAA,MAAA,EAAS,aAAA,CAAc,cAAc,CAAC,CAAA,CAAA;AAC1C,MAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,OAAA,EAAS,cAAc,CAAA;AAAA,IAClD,CAAA,MAAO;AACN,MAAA,OAAA,GAAU,CAAA,GAAA,EAAM,aAAA,CAAc,cAAc,CAAC,CAAA,CAAA;AAC7C,MAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,OAAA,EAAS,cAAyC,CAAA;AAAA,IAC7E;AAEA,IAAA,MAAM,UAA0B,EAAE,EAAA,EAAI,IAAA,EAAM,OAAA,EAAS,GAAG,OAAA,EAAQ;AAChE,IAAA,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,IAAA,CAAK,OAAO,CAAA;AAClC,IAAA,OAAO,IAAA;AAAA,EACR;AAAA,EAEA,IAAA,CAAK,MAAA,EAAgB,MAAA,EAAgB,OAAA,EAA2D;AAC/F,IAAA,MAAM,OAAA,GAA0B,EAAE,MAAA,EAAQ,MAAA,EAAQ,GAAG,OAAA,EAAQ;AAC7D,IAAA,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,IAAA,CAAK,OAAO,CAAA;AAClC,IAAA,OAAO,IAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,KAAA,CACC,EAAA,EACA,MAAA,EAGA,OAAA,EAQyE;AACzE,IAAA,MAAM,EAAE,QAAA,EAAU,SAAA,EAAU,GAAI,OAAA;AAChC,IAAA,MAAM,SAAA,GAAY,GAAG,EAAE,CAAA,QAAA,CAAA;AACvB,IAAA,MAAM,QAAA,GAAW,GAAG,EAAE,CAAA,OAAA,CAAA;AAEtB,IAAA,IAAA,CAAK,iBAAiB,IAAA,CAAK,EAAE,EAAA,EAAI,SAAA,EAAW,UAAU,CAAA;AAGtD,IAAA,IAAI,aAAA;AACJ,IAAA,IAAI,WAAA,CAAY,MAAM,CAAA,EAAG;AACxB,MAAA,aAAA,GACC,MAAA,CAAO,IAAA,IAAQ,MAAA,CAAO,IAAA,KAAS,UAAA,GAAa,OAAO,IAAA,GAAO,CAAA,mBAAA,EAAsB,aAAA,CAAc,MAAM,CAAC,CAAA,CAAA;AACtG,MAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,aAAA,EAAe,MAAM,CAAA;AAAA,IAChD,CAAA,MAAO;AACN,MAAA,aAAA,GAAgB,CAAA,gBAAA,EAAmB,aAAA,CAAc,MAAM,CAAC,CAAA,CAAA;AACxD,MAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,aAAA,EAAe,MAAiC,CAAA;AAAA,IAC3E;AAGA,IAAA,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,CAAK;AAAA,MAC1B,EAAA,EAAI,SAAA;AAAA,MACJ,IAAA,EAAM,eAAA;AAAA;AAAA,MACN,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,EAAE,aAAA,EAAe,SAAA,EAAgC,cAAc,QAAA,EAAU,SAAA,EAAW,QAAQ,SAAA;AAAU,KAC9G,CAAA;AAGD,IAAA,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,CAAK;AAAA,MAC1B,EAAA,EAAI,QAAA;AAAA,MACJ,IAAA,EAAM,cAAA;AAAA;AAAA,MACN,MAAA,EAAQ,EAAE,SAAA,EAAW,YAAA,EAAc,QAAA,EAAS;AAAA,MAC5C,MAAA,EAAQ,EAAE,YAAA,EAAc,KAAA;AAAM;AAAA,KAC9B,CAAA;AAGD,IAAA,IAAA,CAAK,IAAA,CAAK,WAAW,QAAQ,CAAA;AAE7B,IAAA,OAAO,IAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAA,CAAK,IAAY,OAAA,EAAqD;AACrE,IAAA,MAAM,UAA0B,EAAE,EAAA,EAAI,IAAA,EAAM,MAAA,EAAQ,GAAG,OAAA,EAAQ;AAC/D,IAAA,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,IAAA,CAAK,OAAO,CAAA;AAClC,IAAA,OAAO,IAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,IAAA,CACC,IACA,OAAA,EAQO;AACP,IAAA,MAAM,EAAE,WAAA,EAAa,SAAA,EAAW,SAAA,EAAU,GAAI,OAAA;AAC9C,IAAA,MAAM,YAAA,GAAe,GAAG,EAAE,CAAA,KAAA,CAAA;AAE1B,IAAA,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,EAAA,EAAI,YAAY,CAAA;AAE3C,IAAA,IAAA,CAAK,gBAAgB,IAAA,CAAK,EAAE,IAAI,WAAA,EAAa,SAAA,EAAW,WAAW,CAAA;AAGnE,IAAA,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,CAAK;AAAA,MAC1B,EAAA,EAAI,YAAA;AAAA,MACJ,IAAA,EAAM,iBAAA;AAAA;AAAA,MACN,MAAA,EAAQ,EAAE,SAAA,EAAU;AAAA,MACpB,MAAA,EAAQ,EAAE,YAAA,EAAc,KAAA;AAAM;AAAA,KAC9B,CAAA;AAED,IAAA,IAAA,CAAK,IAAA,CAAK,WAAW,YAAY,CAAA;AAEjC,IAAA,IAAA,CAAK,IAAA,CAAK,cAAc,WAAA,EAAa;AAAA,MACpC,MAAA,EAAQ,UAAA;AAAA,MACR,SAAA,EAAW,WAAW,SAAS,CAAA;AAAA;AAAA,KAC/B,CAAA;AAED,IAAA,OAAO,IAAA;AAAA,EACR;AAAA,EAEA,oBAAoB,EAAA,EAAoB;AACvC,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,EAAE,CAAA;AAClD,IAAA,IAAI,CAAC,YAAA,EAAc;AAClB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,EAAE,CAAA,iEAAA,CAAmE,CAAA;AAAA,IACvG;AACA,IAAA,OAAO,YAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,MAAA,EAAsB;AACxC,IAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,MAAA,EAAQ,MAAM,CAAA;AACxC,IAAA,OAAO,IAAA;AAAA,EACR;AAAA,EAEA,WAAA,GAAiC;AAChC,IAAA,IAAI,CAAC,KAAK,SAAA,CAAU,KAAA,IAAS,KAAK,SAAA,CAAU,KAAA,CAAM,WAAW,CAAA,EAAG;AAC/D,MAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,IAC1D;AAEA,IAAA,MAAM,aAA+B,EAAC;AACtC,IAAA,MAAM,sBAAA,uBAA6B,GAAA,EAAoB;AACvD,IAAA,MAAM,gBAAA,GAAmB,IAAA,CAAK,SAAA,CAAU,KAAA,IAAS,EAAC;AAGlD,IAAA,KAAA,MAAW,OAAA,IAAW,KAAK,eAAA,EAAiB;AAC3C,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,mBAAA,CAAoB,OAAA,CAAQ,EAAE,CAAA;AACxD,MAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,KAAW,OAAA,CAAQ,SAAA,IAAa,CAAA,CAAE,MAAA,KAAW,YAAY,CAAA;AAChH,MAAA,KAAA,MAAW,QAAQ,aAAA,EAAe;AACjC,QAAA,UAAA,CAAW,IAAA,CAAK,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,cAAc,MAAA,EAAQ,IAAA,CAAK,MAAA,IAAU,OAAA,EAAS,CAAA;AACjF,QAAA,sBAAA,CAAuB,IAAI,IAAI,CAAA;AAAA,MAChC;AAAA,IACD;AAGA,IAAA,KAAA,MAAW,QAAA,IAAY,KAAK,gBAAA,EAAkB;AAC7C,MAAA,MAAM,aAAA,GAAgB,iBAAiB,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,SAAS,EAAE,CAAA;AAC7E,MAAA,KAAA,MAAW,QAAQ,aAAA,EAAe;AACjC,QAAA,UAAA,CAAW,KAAK,EAAE,GAAG,MAAM,MAAA,EAAQ,QAAA,CAAS,WAAW,CAAA;AACvD,QAAA,sBAAA,CAAuB,IAAI,IAAI,CAAA;AAAA,MAChC;AAEA,MAAA,MAAM,aAAA,GAAgB,iBAAiB,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,SAAS,EAAE,CAAA;AAC7E,MAAA,KAAA,MAAW,QAAQ,aAAA,EAAe;AACjC,QAAA,UAAA,CAAW,KAAK,EAAE,GAAG,MAAM,MAAA,EAAQ,QAAA,CAAS,UAAU,CAAA;AACtD,QAAA,sBAAA,CAAuB,IAAI,IAAI,CAAA;AAAA,MAChC;AAAA,IACD;AAGA,IAAA,KAAA,MAAW,QAAQ,gBAAA,EAAkB;AACpC,MAAA,IAAI,CAAC,sBAAA,CAAuB,GAAA,CAAI,IAAI,CAAA,EAAG;AACtC,QAAA,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,MACrB;AAAA,IACD;AACA,IAAA,IAAA,CAAK,UAAU,KAAA,GAAQ,UAAA;AAEvB,IAAA,KAAA,MAAW,OAAA,IAAW,KAAK,eAAA,EAAiB;AAC3C,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,OAAA,CAAQ,WAAW,CAAA;AAChF,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,OAAA,CAAQ,SAAS,CAAA;AAE5E,MAAA,IAAI,CAAC,SAAA,EAAW;AACf,QAAA,MAAM,IAAI,MAAM,CAAA,MAAA,EAAS,OAAA,CAAQ,EAAE,CAAA,sCAAA,EAAyC,OAAA,CAAQ,WAAW,CAAA,EAAA,CAAI,CAAA;AAAA,MACpG;AACA,MAAA,IAAI,CAAC,OAAA,EAAS;AACb,QAAA,MAAM,IAAI,MAAM,CAAA,MAAA,EAAS,OAAA,CAAQ,EAAE,CAAA,oCAAA,EAAuC,OAAA,CAAQ,SAAS,CAAA,EAAA,CAAI,CAAA;AAAA,MAChG;AAEA,MAAA,SAAA,CAAU,SAAS,EAAE,GAAG,SAAA,CAAU,MAAA,EAAQ,cAAc,KAAA,EAAM;AAC9D,MAAA,OAAA,CAAQ,SAAS,EAAE,GAAG,OAAA,CAAQ,MAAA,EAAQ,cAAc,KAAA,EAAM;AAAA,IAC3D;AAEA,IAAA,IAAI,IAAA,CAAK,gBAAA,CAAiB,IAAA,GAAO,CAAA,EAAG;AACnC,MAAA,IAAA,CAAK,UAAU,QAAA,GAAW;AAAA,QACzB,GAAG,KAAK,SAAA,CAAU,QAAA;AAAA,QAClB,kBAAkB,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,gBAAA,CAAiB,MAAM;AAAA,OAC1D;AAAA,IACD;AAEA,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EACb;AAAA,EAEA,mBAAA,GAAsB;AACrB,IAAA,OAAO,IAAA,CAAK,gBAAA;AAAA,EACb;AAAA,EAEA,qBAAA,GAAiC;AAChC,IAAA,MAAM,SAAA,GAAY,KAAK,WAAA,EAAY;AACnC,IAAA,MAAM,UAA4B,EAAC;AACnC,IAAA,MAAM,UAA4B,EAAC;AAEnC,IAAA,MAAM,cAAA,uBAAqB,GAAA,EAAY;AAGvC,IAAA,KAAA,MAAW,OAAA,IAAW,KAAK,eAAA,EAAiB;AAC3C,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,QAAQ,EAAE,CAAA;AAC1D,MAAA,IAAI,CAAC,YAAA,EAAc;AAEnB,MAAA,cAAA,CAAe,IAAI,YAAY,CAAA;AAG/B,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACZ,QAAQ,OAAA,CAAQ,SAAA;AAAA,QAChB,QAAQ,OAAA,CAAQ,WAAA;AAAA,QAChB,IAAA,EAAM;AAAA,UACL,UAAA,EAAY,IAAA;AAAA,UACZ,WAAW,OAAA,CAAQ,SAAA;AAAA,UACnB,KAAA,EAAO,CAAA,aAAA,EAAgB,OAAA,CAAQ,SAAS,CAAA;AAAA;AACzC,OACA,CAAA;AAGD,MAAA,MAAM,UAAA,GAAa,SAAA,CAAU,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,KAAW,YAAA,IAAgB,IAAA,CAAK,MAAA,KAAW,OAAO,CAAA;AAC3G,MAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AACnC,QAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,UACZ,GAAG,SAAA;AAAA,UACH,QAAQ,OAAA,CAAQ;AAAA,SAChB,CAAA;AAAA,MACF;AAAA,IACD;AAGA,IAAA,MAAM,YAAA,GAAe,UAAU,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,eAAe,CAAA;AAC7E,IAAA,KAAA,MAAW,eAAe,YAAA,EAAc;AACvC,MAAA,MAAM,YAAA,GAAe,YAAY,MAAA,EAAQ,YAAA;AACzC,MAAA,IAAI,CAAC,YAAA,EAAc;AAEnB,MAAA,cAAA,CAAe,GAAA,CAAI,YAAY,EAAE,CAAA;AACjC,MAAA,cAAA,CAAe,IAAI,YAAY,CAAA;AAG/B,MAAA,MAAM,OAAA,GAAU,WAAA,CAAY,EAAA,CAAG,OAAA,CAAQ,YAAY,EAAE,CAAA;AACrD,MAAA,MAAM,UAAA,GAAa,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,YAAY,CAAA;AAEpE,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACZ,EAAA,EAAI,OAAA;AAAA,QACJ,IAAA,EAAM,YAAY,MAAA,EAAQ,aAAA;AAAA,QAC1B,IAAA,EAAM,cAAA;AAAA,QACN,IAAA,EAAM;AAAA,UACL,KAAA,EAAO,UAAU,OAAO,CAAA,CAAA;AAAA,UACxB,kBAAA,EAAoB,IAAA;AAAA,UACpB,aAAA,EAAe,YAAY,MAAA,EAAQ,aAAA;AAAA,UACnC,UAAU,WAAA,CAAY,MAAA;AAAA,UACtB,SAAA,EAAW,YAAY,MAAA,EAAQ;AAAA;AAChC,OACA,CAAA;AAGD,MAAA,MAAM,aAAA,GAAgB,UAAU,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,KAAW,WAAA,CAAY,EAAE,CAAA;AAC/E,MAAA,KAAA,MAAW,QAAQ,aAAA,EAAe;AACjC,QAAA,OAAA,CAAQ,KAAK,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,SAAS,CAAA;AAAA,MAC1C;AAGA,MAAA,MAAM,aAAA,GAAgB,UAAU,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,YAAY,CAAA;AAC7E,MAAA,KAAA,MAAW,QAAQ,aAAA,EAAe;AACjC,QAAA,OAAA,CAAQ,KAAK,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,SAAS,CAAA;AAAA,MAC1C;AAAA,IACD;AAEA,IAAA,KAAA,MAAW,IAAA,IAAQ,UAAU,KAAA,EAAO;AACnC,MAAA,IAAI,CAAC,cAAA,CAAe,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG;AACjC,QAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,MAClB;AAAA,IACD;AAEA,IAAA,KAAA,MAAW,IAAA,IAAQ,UAAU,KAAA,EAAO;AACnC,MAAA,IAAI,CAAC,cAAA,CAAe,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA,IAAK,CAAC,cAAA,CAAe,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA,EAAG;AACzE,QAAA,MAAM,eAAe,OAAA,CAAQ,IAAA;AAAA,UAC5B,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,KAAW,IAAA,CAAK,MAAA,IAAU,CAAA,CAAE,MAAA,KAAW,IAAA,CAAK,MAAA,IAAU,CAAA,CAAE,MAAA,KAAW,IAAA,CAAK;AAAA,SAClF;AACA,QAAA,IAAI,CAAC,YAAA,EAAc;AAClB,UAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,QAClB;AAAA,MACD;AAAA,IACD;AAEA,IAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,OAAA,EAAQ;AAAA,EACzC;AACD;AAKO,SAAS,WAGd,EAAA,EAA2C;AAC5C,EAAA,OAAO,IAAI,KAAK,EAAE,CAAA;AACnB","file":"chunk-C4HYIJI3.js","sourcesContent":["import { isNodeClass } from './node'\nimport type { EdgeDefinition, NodeClass, NodeDefinition, NodeFunction, UIGraph, WorkflowBlueprint } from './types'\n\n/**\n * Generates a deterministic hash for a function based on its source code and a unique counter.\n */\nlet hashCounter = 0\nfunction _hashFunction(fn: NodeFunction<any, any, any, any, any> | NodeClass<any, any, any, any, any>): string {\n\tconst source = fn.toString()\n\tlet hash = 0\n\tfor (let i = 0; i < source.length; i++) {\n\t\tconst char = source.charCodeAt(i)\n\t\thash = (hash << 5) - hash + char\n\t\thash = hash & hash // Convert to 32-bit integer\n\t}\n\t// Add counter to ensure uniqueness even for identical functions\n\treturn (Math.abs(hash) + hashCounter++).toString(16)\n}\n\n/**\n * A fluent API for programmatically constructing a WorkflowBlueprint.\n */\nexport class Flow<\n\tTContext extends Record<string, any> = Record<string, any>,\n\tTDependencies extends Record<string, any> = Record<string, any>,\n> {\n\tprivate blueprint: Partial<WorkflowBlueprint>\n\tprivate functionRegistry: Map<string, NodeFunction | NodeClass>\n\tprivate loopControllerIds: Map<string, string>\n\tprivate loopDefinitions: Array<{\n\t\tid: string\n\t\tstartNodeId: string\n\t\tendNodeId: string\n\t\tcondition: string\n\t}>\n\tprivate batchDefinitions: Array<{\n\t\tid: string\n\t\tscatterId: string\n\t\tgatherId: string\n\t}>\n\tprivate cycleEntryPoints: Map<string, string>\n\n\tconstructor(id: string) {\n\t\tthis.blueprint = { id, nodes: [], edges: [] }\n\t\tthis.functionRegistry = new Map()\n\t\tthis.loopControllerIds = new Map()\n\t\tthis.loopDefinitions = []\n\t\tthis.batchDefinitions = []\n\t\tthis.cycleEntryPoints = new Map()\n\t}\n\n\tnode<TInput = any, TOutput = any, TAction extends string = string>(\n\t\tid: string,\n\t\timplementation:\n\t\t\t| NodeFunction<TContext, TDependencies, TInput, TOutput, TAction>\n\t\t\t| NodeClass<TContext, TDependencies, TInput, TOutput, TAction>,\n\t\toptions?: Omit<NodeDefinition, 'id' | 'uses'>,\n\t): this {\n\t\tlet usesKey: string\n\n\t\tif (isNodeClass(implementation)) {\n\t\t\tusesKey =\n\t\t\t\timplementation.name && implementation.name !== 'BaseNode'\n\t\t\t\t\t? implementation.name\n\t\t\t\t\t: `class_${_hashFunction(implementation)}`\n\t\t\tthis.functionRegistry.set(usesKey, implementation)\n\t\t} else {\n\t\t\tusesKey = `fn_${_hashFunction(implementation)}`\n\t\t\tthis.functionRegistry.set(usesKey, implementation as unknown as NodeFunction)\n\t\t}\n\n\t\tconst nodeDef: NodeDefinition = { id, uses: usesKey, ...options }\n\t\tthis.blueprint.nodes?.push(nodeDef)\n\t\treturn this\n\t}\n\n\tedge(source: string, target: string, options?: Omit<EdgeDefinition, 'source' | 'target'>): this {\n\t\tconst edgeDef: EdgeDefinition = { source, target, ...options }\n\t\tthis.blueprint.edges?.push(edgeDef)\n\t\treturn this\n\t}\n\n\t/**\n\t * Creates a batch processing pattern.\n\t * It takes an input array, runs a worker node on each item in parallel, and gathers the results.\n\t * This method augments the Flow's TContext with a new key for the output array.\n\t *\n\t * @param id The base ID for this batch operation.\n\t * @param worker The node implementation to run on each item.\n\t * @param options Configuration for the batch operation.\n\t * @returns The Flow instance with an updated context type for chaining.\n\t */\n\tbatch<TWorkerInput, TWorkerOutput, TWorkerAction extends string, TOutputKey extends string>(\n\t\tid: string,\n\t\tworker:\n\t\t\t| NodeFunction<TContext, TDependencies, TWorkerInput, TWorkerOutput, TWorkerAction>\n\t\t\t| NodeClass<TContext, TDependencies, TWorkerInput, TWorkerOutput, TWorkerAction>,\n\t\toptions: {\n\t\t\t/** The key in the context that holds the input array for the batch. */\n\t\t\tinputKey: keyof TContext\n\t\t\t/** The key in the context where the array of results will be stored. */\n\t\t\toutputKey: TOutputKey\n\t\t\t/** The number of items to process in each chunk to limit memory usage. */\n\t\t\tchunkSize?: number\n\t\t},\n\t): Flow<TContext & { [K in TOutputKey]: TWorkerOutput[] }, TDependencies> {\n\t\tconst { inputKey, outputKey } = options\n\t\tconst scatterId = `${id}_scatter`\n\t\tconst gatherId = `${id}_gather`\n\n\t\tthis.batchDefinitions.push({ id, scatterId, gatherId })\n\n\t\t// register worker implementation under a unique key.\n\t\tlet workerUsesKey: string\n\t\tif (isNodeClass(worker)) {\n\t\t\tworkerUsesKey =\n\t\t\t\tworker.name && worker.name !== 'BaseNode' ? worker.name : `class_batch_worker_${_hashFunction(worker)}`\n\t\t\tthis.functionRegistry.set(workerUsesKey, worker)\n\t\t} else {\n\t\t\tworkerUsesKey = `fn_batch_worker_${_hashFunction(worker)}`\n\t\t\tthis.functionRegistry.set(workerUsesKey, worker as unknown as NodeFunction)\n\t\t}\n\n\t\t// scatter node: takes an array and dynamically schedules worker nodes\n\t\tthis.blueprint.nodes?.push({\n\t\t\tid: scatterId,\n\t\t\tuses: 'batch-scatter', // built-in\n\t\t\tinputs: inputKey as string,\n\t\t\tparams: { workerUsesKey, outputKey: outputKey as string, gatherNodeId: gatherId, chunkSize: options.chunkSize },\n\t\t})\n\n\t\t// gather node: waits for all workers to finish and collects the results\n\t\tthis.blueprint.nodes?.push({\n\t\t\tid: gatherId,\n\t\t\tuses: 'batch-gather', // built-in\n\t\t\tparams: { outputKey, gatherNodeId: gatherId },\n\t\t\tconfig: { joinStrategy: 'all' }, // important: must wait for all scattered jobs\n\t\t})\n\n\t\t// edge to connect scatter and gather nodes, orchestrator will manage dynamic workers\n\t\tthis.edge(scatterId, gatherId)\n\n\t\treturn this as unknown as Flow<TContext & { [K in TOutputKey]: TWorkerOutput[] }, TDependencies>\n\t}\n\n\t/**\n\t * Creates a wait node that pauses workflow execution for external input.\n\t * @param id A unique identifier for the wait node.\n\t * @param options Optional configuration for the wait node.\n\t */\n\twait(id: string, options?: Omit<NodeDefinition, 'id' | 'uses'>): this {\n\t\tconst nodeDef: NodeDefinition = { id, uses: 'wait', ...options }\n\t\tthis.blueprint.nodes?.push(nodeDef)\n\t\treturn this\n\t}\n\n\t/**\n\t * Creates a loop pattern in the workflow graph.\n\t * @param id A unique identifier for the loop construct.\n\t * @param options Defines the start, end, and continuation condition of the loop.\n\t * @param options.startNodeId The ID of the first node inside the loop body.\n\t * @param options.endNodeId The ID of the last node inside the loop body.\n\t * @param options.condition An expression that, if true, causes the loop to run again.\n\t */\n\tloop(\n\t\tid: string,\n\t\toptions: {\n\t\t\t/** The ID of the first node inside the loop body. */\n\t\t\tstartNodeId: string\n\t\t\t/** The ID of the last node inside the loop body. */\n\t\t\tendNodeId: string\n\t\t\t/** An expression that, if true, causes the loop to run again. */\n\t\t\tcondition: string\n\t\t},\n\t): this {\n\t\tconst { startNodeId, endNodeId, condition } = options\n\t\tconst controllerId = `${id}-loop`\n\n\t\tthis.loopControllerIds.set(id, controllerId)\n\n\t\tthis.loopDefinitions.push({ id, startNodeId, endNodeId, condition })\n\n\t\t// controller node: evaluates the loop condition\n\t\tthis.blueprint.nodes?.push({\n\t\t\tid: controllerId,\n\t\t\tuses: 'loop-controller', // built-in\n\t\t\tparams: { condition },\n\t\t\tconfig: { joinStrategy: 'any' }, // to allow re-execution on each loop iteration\n\t\t})\n\n\t\tthis.edge(endNodeId, controllerId)\n\n\t\tthis.edge(controllerId, startNodeId, {\n\t\t\taction: 'continue',\n\t\t\ttransform: `context.${endNodeId}`, // pass the end node's value to the start node\n\t\t})\n\n\t\treturn this\n\t}\n\n\tgetLoopControllerId(id: string): string {\n\t\tconst controllerId = this.loopControllerIds.get(id)\n\t\tif (!controllerId) {\n\t\t\tthrow new Error(`Loop with id '${id}' not found. Ensure you have defined it using the .loop() method.`)\n\t\t}\n\t\treturn controllerId\n\t}\n\n\t/**\n\t * Sets the preferred entry point for a cycle in non-DAG workflows.\n\t * This helps remove ambiguity when the runtime needs to choose a starting node for cycles.\n\t * @param nodeId The ID of the node to use as the entry point for cycles containing this node.\n\t */\n\tsetCycleEntryPoint(nodeId: string): this {\n\t\tthis.cycleEntryPoints.set(nodeId, nodeId)\n\t\treturn this\n\t}\n\n\ttoBlueprint(): WorkflowBlueprint {\n\t\tif (!this.blueprint.nodes || this.blueprint.nodes.length === 0) {\n\t\t\tthrow new Error('Cannot build a blueprint with no nodes.')\n\t\t}\n\n\t\tconst finalEdges: EdgeDefinition[] = []\n\t\tconst processedOriginalEdges = new Set<EdgeDefinition>()\n\t\tconst allOriginalEdges = this.blueprint.edges || []\n\n\t\t// loop edge re-wiring\n\t\tfor (const loopDef of this.loopDefinitions) {\n\t\t\tconst controllerId = this.getLoopControllerId(loopDef.id)\n\t\t\tconst edgesToRewire = allOriginalEdges.filter((e) => e.source === loopDef.endNodeId && e.target !== controllerId)\n\t\t\tfor (const edge of edgesToRewire) {\n\t\t\t\tfinalEdges.push({ ...edge, source: controllerId, action: edge.action || 'break' })\n\t\t\t\tprocessedOriginalEdges.add(edge)\n\t\t\t}\n\t\t}\n\n\t\t// batch edge re-wiring\n\t\tfor (const batchDef of this.batchDefinitions) {\n\t\t\tconst incomingEdges = allOriginalEdges.filter((e) => e.target === batchDef.id)\n\t\t\tfor (const edge of incomingEdges) {\n\t\t\t\tfinalEdges.push({ ...edge, target: batchDef.scatterId })\n\t\t\t\tprocessedOriginalEdges.add(edge)\n\t\t\t}\n\n\t\t\tconst outgoingEdges = allOriginalEdges.filter((e) => e.source === batchDef.id)\n\t\t\tfor (const edge of outgoingEdges) {\n\t\t\t\tfinalEdges.push({ ...edge, source: batchDef.gatherId })\n\t\t\t\tprocessedOriginalEdges.add(edge)\n\t\t\t}\n\t\t}\n\n\t\t// all remaining edges\n\t\tfor (const edge of allOriginalEdges) {\n\t\t\tif (!processedOriginalEdges.has(edge)) {\n\t\t\t\tfinalEdges.push(edge)\n\t\t\t}\n\t\t}\n\t\tthis.blueprint.edges = finalEdges\n\n\t\tfor (const loopDef of this.loopDefinitions) {\n\t\t\tconst startNode = this.blueprint.nodes?.find((n) => n.id === loopDef.startNodeId)\n\t\t\tconst endNode = this.blueprint.nodes?.find((n) => n.id === loopDef.endNodeId)\n\n\t\t\tif (!startNode) {\n\t\t\t\tthrow new Error(`Loop '${loopDef.id}' references non-existent start node '${loopDef.startNodeId}'.`)\n\t\t\t}\n\t\t\tif (!endNode) {\n\t\t\t\tthrow new Error(`Loop '${loopDef.id}' references non-existent end node '${loopDef.endNodeId}'.`)\n\t\t\t}\n\n\t\t\tstartNode.config = { ...startNode.config, joinStrategy: 'any' }\n\t\t\tendNode.config = { ...endNode.config, joinStrategy: 'any' }\n\t\t}\n\n\t\tif (this.cycleEntryPoints.size > 0) {\n\t\t\tthis.blueprint.metadata = {\n\t\t\t\t...this.blueprint.metadata,\n\t\t\t\tcycleEntryPoints: Array.from(this.cycleEntryPoints.keys()),\n\t\t\t}\n\t\t}\n\n\t\treturn this.blueprint as WorkflowBlueprint\n\t}\n\n\tgetFunctionRegistry() {\n\t\treturn this.functionRegistry\n\t}\n\n\ttoGraphRepresentation(): UIGraph {\n\t\tconst blueprint = this.toBlueprint()\n\t\tconst uiNodes: UIGraph['nodes'] = []\n\t\tconst uiEdges: UIGraph['edges'] = []\n\n\t\tconst ignoredNodeIds = new Set<string>()\n\n\t\t// replace loop-controllers with direct, cyclical edges\n\t\tfor (const loopDef of this.loopDefinitions) {\n\t\t\tconst controllerId = this.loopControllerIds.get(loopDef.id)\n\t\t\tif (!controllerId) continue\n\n\t\t\tignoredNodeIds.add(controllerId)\n\n\t\t\t// direct edge from the end of loop to start\n\t\t\tuiEdges.push({\n\t\t\t\tsource: loopDef.endNodeId,\n\t\t\t\ttarget: loopDef.startNodeId,\n\t\t\t\tdata: {\n\t\t\t\t\tisLoopback: true,\n\t\t\t\t\tcondition: loopDef.condition,\n\t\t\t\t\tlabel: `continue if: ${loopDef.condition}`,\n\t\t\t\t},\n\t\t\t})\n\n\t\t\t// re-wire any 'break' edges\n\t\t\tconst breakEdges = blueprint.edges.filter((edge) => edge.source === controllerId && edge.action === 'break')\n\t\t\tfor (const breakEdge of breakEdges) {\n\t\t\t\tuiEdges.push({\n\t\t\t\t\t...breakEdge,\n\t\t\t\t\tsource: loopDef.endNodeId,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// replace scatter/gather pairs with a single representative \"worker\" node\n\t\tconst scatterNodes = blueprint.nodes.filter((n) => n.uses === 'batch-scatter')\n\t\tfor (const scatterNode of scatterNodes) {\n\t\t\tconst gatherNodeId = scatterNode.params?.gatherNodeId\n\t\t\tif (!gatherNodeId) continue\n\n\t\t\tignoredNodeIds.add(scatterNode.id)\n\t\t\tignoredNodeIds.add(gatherNodeId)\n\n\t\t\t// single node to represent parallel work\n\t\t\tconst batchId = scatterNode.id.replace('_scatter', '')\n\t\t\tconst gatherNode = blueprint.nodes.find((n) => n.id === gatherNodeId)\n\n\t\t\tuiNodes.push({\n\t\t\t\tid: batchId,\n\t\t\t\tuses: scatterNode.params?.workerUsesKey,\n\t\t\t\ttype: 'batch-worker',\n\t\t\t\tdata: {\n\t\t\t\t\tlabel: `Batch: ${batchId}`,\n\t\t\t\t\tisBatchPlaceholder: true,\n\t\t\t\t\tworkerUsesKey: scatterNode.params?.workerUsesKey,\n\t\t\t\t\tinputKey: scatterNode.inputs,\n\t\t\t\t\toutputKey: gatherNode?.params?.outputKey,\n\t\t\t\t},\n\t\t\t})\n\n\t\t\t// re-wire incoming edges\n\t\t\tconst incomingEdges = blueprint.edges.filter((e) => e.target === scatterNode.id)\n\t\t\tfor (const edge of incomingEdges) {\n\t\t\t\tuiEdges.push({ ...edge, target: batchId })\n\t\t\t}\n\n\t\t\t// re-wire outgoing edges\n\t\t\tconst outgoingEdges = blueprint.edges.filter((e) => e.source === gatherNodeId)\n\t\t\tfor (const edge of outgoingEdges) {\n\t\t\t\tuiEdges.push({ ...edge, source: batchId })\n\t\t\t}\n\t\t}\n\n\t\tfor (const node of blueprint.nodes) {\n\t\t\tif (!ignoredNodeIds.has(node.id)) {\n\t\t\t\tuiNodes.push(node)\n\t\t\t}\n\t\t}\n\n\t\tfor (const edge of blueprint.edges) {\n\t\t\tif (!ignoredNodeIds.has(edge.source) && !ignoredNodeIds.has(edge.target)) {\n\t\t\t\tconst alreadyAdded = uiEdges.some(\n\t\t\t\t\t(e) => e.source === edge.source && e.target === edge.target && e.action === edge.action,\n\t\t\t\t)\n\t\t\t\tif (!alreadyAdded) {\n\t\t\t\t\tuiEdges.push(edge)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { nodes: uiNodes, edges: uiEdges }\n\t}\n}\n\n/**\n * Helper function to create a new Flow builder instance.\n */\nexport function createFlow<\n\tTContext extends Record<string, any> = Record<string, any>,\n\tTDependencies extends Record<string, any> = Record<string, any>,\n>(id: string): Flow<TContext, TDependencies> {\n\treturn new Flow(id)\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { BaseNode } from './chunk-LNK7LZER.js';
2
+
3
+ // src/nodes/wait.ts
4
+ var WaitNode = class extends BaseNode {
5
+ async exec(_prepResult, context) {
6
+ context.dependencies.workflowState.markAsAwaiting(this.nodeId ?? "");
7
+ return { output: void 0 };
8
+ }
9
+ };
10
+
11
+ export { WaitNode };
12
+ //# sourceMappingURL=chunk-CD3Q4N6V.js.map
13
+ //# sourceMappingURL=chunk-CD3Q4N6V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/nodes/wait.ts"],"names":[],"mappings":";;;AAGO,IAAM,QAAA,GAAN,cAAuB,QAAA,CAAS;AAAA,EACtC,MAAM,IAAA,CACL,WAAA,EACA,OAAA,EACqC;AACrC,IAAA,OAAA,CAAQ,YAAA,CAAa,aAAA,CAAc,cAAA,CAAe,IAAA,CAAK,UAAU,EAAE,CAAA;AACnE,IAAA,OAAO,EAAE,QAAQ,MAAA,EAAU;AAAA,EAC5B;AACD","file":"chunk-CD3Q4N6V.js","sourcesContent":["import { BaseNode } from '../node'\nimport type { NodeContext, NodeResult } from '../types'\n\nexport class WaitNode extends BaseNode {\n\tasync exec(\n\t\t_prepResult: any,\n\t\tcontext: NodeContext<Record<string, any>, any, any>,\n\t): Promise<Omit<NodeResult, 'error'>> {\n\t\tcontext.dependencies.workflowState.markAsAwaiting(this.nodeId ?? '')\n\t\treturn { output: undefined }\n\t}\n}\n"]}