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.
- package/README.md +40 -34
- package/dist/analysis.d.ts +3 -1
- package/dist/chunk-33NO4PUJ.js +74 -0
- package/dist/chunk-33NO4PUJ.js.map +1 -0
- package/dist/chunk-BC4G7OM6.js +42 -0
- package/dist/chunk-BC4G7OM6.js.map +1 -0
- package/dist/chunk-BCRWXTWX.js +21 -0
- package/dist/chunk-BCRWXTWX.js.map +1 -0
- package/dist/chunk-BN4MV36K.js +25 -0
- package/dist/chunk-BN4MV36K.js.map +1 -0
- package/dist/{chunk-ZCHFZBGL.js → chunk-C4HYIJI3.js} +120 -5
- package/dist/chunk-C4HYIJI3.js.map +1 -0
- package/dist/chunk-CD3Q4N6V.js +13 -0
- package/dist/chunk-CD3Q4N6V.js.map +1 -0
- package/dist/chunk-CD4FUZOJ.js +114 -0
- package/dist/chunk-CD4FUZOJ.js.map +1 -0
- package/dist/chunk-DL7KVYZF.js +39 -0
- package/dist/chunk-DL7KVYZF.js.map +1 -0
- package/dist/chunk-FRKO3WX4.js +32 -0
- package/dist/chunk-FRKO3WX4.js.map +1 -0
- package/dist/chunk-G53CSLBF.js +54 -0
- package/dist/chunk-G53CSLBF.js.map +1 -0
- package/dist/chunk-G5BGBPFP.js +172 -0
- package/dist/chunk-G5BGBPFP.js.map +1 -0
- package/dist/chunk-HAZ26F3P.js +98 -0
- package/dist/chunk-HAZ26F3P.js.map +1 -0
- package/dist/chunk-HKX7WQLS.js +446 -0
- package/dist/chunk-HKX7WQLS.js.map +1 -0
- package/dist/{chunk-U5V5O5MN.js → chunk-LNK7LZER.js} +5 -3
- package/dist/chunk-LNK7LZER.js.map +1 -0
- package/dist/chunk-MCGK3FXQ.js +143 -0
- package/dist/chunk-MCGK3FXQ.js.map +1 -0
- package/dist/chunk-MKNZBKSR.js +90 -0
- package/dist/chunk-MKNZBKSR.js.map +1 -0
- package/dist/chunk-MUYLRTSR.js +82 -0
- package/dist/chunk-MUYLRTSR.js.map +1 -0
- package/dist/chunk-NVJ3ZO3P.js +3 -0
- package/dist/{chunk-HMR2GEGE.js.map → chunk-NVJ3ZO3P.js.map} +1 -1
- package/dist/chunk-NVLZFLYM.js +3 -0
- package/dist/chunk-NVLZFLYM.js.map +1 -0
- package/dist/chunk-ONH7PIJZ.js +300 -0
- package/dist/chunk-ONH7PIJZ.js.map +1 -0
- package/dist/chunk-QNYXQKFW.js +25 -0
- package/dist/chunk-QNYXQKFW.js.map +1 -0
- package/dist/chunk-RM677CNU.js +52 -0
- package/dist/chunk-RM677CNU.js.map +1 -0
- package/dist/chunk-WWGFIYKW.js +47 -0
- package/dist/chunk-WWGFIYKW.js.map +1 -0
- package/dist/chunk-XNRIM27H.js +76 -0
- package/dist/chunk-XNRIM27H.js.map +1 -0
- package/dist/{chunk-QLGJUDQF.js → chunk-ZNL7ZXPR.js} +26 -11
- package/dist/chunk-ZNL7ZXPR.js.map +1 -0
- package/dist/container-factory.d.ts +17 -0
- package/dist/container-factory.js +13 -0
- package/dist/container-factory.js.map +1 -0
- package/dist/container.d.ts +23 -0
- package/dist/container.js +3 -0
- package/dist/container.js.map +1 -0
- package/dist/context.d.ts +3 -1
- package/dist/errors.d.ts +18 -17
- package/dist/errors.js +1 -1
- package/dist/evaluator.d.ts +3 -1
- package/dist/flow.d.ts +12 -2
- package/dist/flow.js +2 -2
- package/dist/index.d.ts +7 -8
- package/dist/index.js +26 -14
- package/dist/linter.d.ts +3 -1
- package/dist/logger.d.ts +3 -1
- package/dist/node.d.ts +3 -1
- package/dist/node.js +1 -1
- package/dist/nodes/batch-gather.d.ts +9 -0
- package/dist/nodes/batch-gather.js +4 -0
- package/dist/nodes/batch-gather.js.map +1 -0
- package/dist/nodes/batch-scatter.d.ts +9 -0
- package/dist/nodes/batch-scatter.js +4 -0
- package/dist/nodes/batch-scatter.js.map +1 -0
- package/dist/nodes/subflow.d.ts +9 -0
- package/dist/nodes/subflow.js +10 -0
- package/dist/nodes/subflow.js.map +1 -0
- package/dist/nodes/wait.d.ts +9 -0
- package/dist/nodes/wait.js +4 -0
- package/dist/nodes/wait.js.map +1 -0
- package/dist/runtime/adapter.d.ts +3 -5
- package/dist/runtime/adapter.js +19 -9
- package/dist/runtime/execution-context.d.ts +3 -0
- package/dist/runtime/execution-context.js +6 -0
- package/dist/runtime/execution-context.js.map +1 -0
- package/dist/runtime/executors.d.ts +3 -26
- package/dist/runtime/executors.js +2 -2
- package/dist/runtime/index.d.ts +5 -7
- package/dist/runtime/index.js +21 -10
- package/dist/runtime/node-executor-factory.d.ts +12 -0
- package/dist/runtime/node-executor-factory.js +6 -0
- package/dist/runtime/node-executor-factory.js.map +1 -0
- package/dist/runtime/orchestrator.d.ts +9 -0
- package/dist/runtime/orchestrator.js +8 -0
- package/dist/runtime/orchestrator.js.map +1 -0
- package/dist/runtime/orchestrators/step-by-step.d.ts +16 -0
- package/dist/runtime/orchestrators/step-by-step.js +5 -0
- package/dist/runtime/orchestrators/step-by-step.js.map +1 -0
- package/dist/runtime/orchestrators/utils.d.ts +35 -0
- package/dist/runtime/orchestrators/utils.js +4 -0
- package/dist/runtime/orchestrators/utils.js.map +1 -0
- package/dist/runtime/runtime.d.ts +3 -41
- package/dist/runtime/runtime.js +18 -8
- package/dist/runtime/state.d.ts +3 -21
- package/dist/runtime/state.js +2 -1
- package/dist/runtime/traverser.d.ts +3 -26
- package/dist/runtime/traverser.js +1 -2
- package/dist/runtime/types.d.ts +3 -16
- package/dist/runtime/types.js +1 -1
- package/dist/runtime/workflow-logic-handler.d.ts +17 -0
- package/dist/runtime/workflow-logic-handler.js +5 -0
- package/dist/runtime/workflow-logic-handler.js.map +1 -0
- package/dist/sanitizer.d.ts +3 -1
- package/dist/serializer.d.ts +3 -1
- package/dist/testing/event-logger.d.ts +63 -0
- package/dist/testing/event-logger.js +3 -0
- package/dist/testing/event-logger.js.map +1 -0
- package/dist/testing/index.d.ts +6 -0
- package/dist/testing/index.js +31 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/run-with-trace.d.ts +38 -0
- package/dist/testing/run-with-trace.js +29 -0
- package/dist/testing/run-with-trace.js.map +1 -0
- package/dist/testing/stepper.d.ts +79 -0
- package/dist/testing/stepper.js +11 -0
- package/dist/testing/stepper.js.map +1 -0
- package/dist/types-ezHUBdpL.d.ts +564 -0
- package/dist/types.d.ts +3 -1
- package/package.json +55 -51
- package/LICENSE +0 -21
- package/dist/chunk-5ZXV3R5D.js +0 -28
- package/dist/chunk-5ZXV3R5D.js.map +0 -1
- package/dist/chunk-GEKDR2SS.js +0 -201
- package/dist/chunk-GEKDR2SS.js.map +0 -1
- package/dist/chunk-HMR2GEGE.js +0 -3
- package/dist/chunk-M2FRTT2K.js +0 -144
- package/dist/chunk-M2FRTT2K.js.map +0 -1
- package/dist/chunk-OTS5YJ3S.js +0 -494
- package/dist/chunk-OTS5YJ3S.js.map +0 -1
- package/dist/chunk-QLGJUDQF.js.map +0 -1
- package/dist/chunk-U5V5O5MN.js.map +0 -1
- package/dist/chunk-VSGQDLBF.js +0 -61
- package/dist/chunk-VSGQDLBF.js.map +0 -1
- package/dist/chunk-ZCHFZBGL.js.map +0 -1
- 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
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
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
|
|
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',
|
|
38
|
-
.node('double',
|
|
46
|
+
.node('start', startNode)
|
|
47
|
+
.node('double', doubleNode)
|
|
39
48
|
.edge('start', 'double')
|
|
40
|
-
.toBlueprint()
|
|
41
49
|
|
|
42
|
-
//
|
|
43
|
-
const runtime = new FlowRuntime(
|
|
44
|
-
registry: flow.getFunctionRegistry(),
|
|
45
|
-
})
|
|
50
|
+
// 3. Initialize the runtime
|
|
51
|
+
const runtime = new FlowRuntime()
|
|
46
52
|
|
|
47
|
-
//
|
|
53
|
+
// 4. Execute the workflow
|
|
48
54
|
async function run() {
|
|
49
|
-
const result = await runtime.run(
|
|
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
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
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
|
-
-
|
|
70
|
-
-
|
|
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
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
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
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
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
|
|
package/dist/analysis.d.ts
CHANGED
|
@@ -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-
|
|
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-
|
|
164
|
-
//# sourceMappingURL=chunk-
|
|
278
|
+
//# sourceMappingURL=chunk-C4HYIJI3.js.map
|
|
279
|
+
//# sourceMappingURL=chunk-C4HYIJI3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/flow.ts"],"names":[],"mappings":"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","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"]}
|