flowcraft 2.1.0 → 2.1.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 +51 -5
- package/dist/analysis.d.ts +1 -1
- package/dist/{chunk-CO5BTPKI.js → chunk-3XVVR2SR.js} +14 -7
- package/dist/chunk-3XVVR2SR.js.map +1 -0
- package/dist/{chunk-5ZWYSKMH.js → chunk-4A627Q6L.js} +3 -3
- package/dist/chunk-4A627Q6L.js.map +1 -0
- package/dist/chunk-M2FRTT2K.js +144 -0
- package/dist/chunk-M2FRTT2K.js.map +1 -0
- package/dist/{chunk-UMXW3TCY.js → chunk-NBIRTKZ7.js} +32 -5
- package/dist/chunk-NBIRTKZ7.js.map +1 -0
- package/dist/{chunk-5EHIPX23.js → chunk-O3XD45IL.js} +53 -19
- package/dist/chunk-O3XD45IL.js.map +1 -0
- package/dist/{chunk-5QMPFUKA.js → chunk-U5V5O5MN.js} +11 -2
- package/dist/chunk-U5V5O5MN.js.map +1 -0
- package/dist/context.d.ts +1 -1
- package/dist/evaluator.d.ts +1 -1
- package/dist/flow.d.ts +3 -3
- package/dist/flow.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/linter.d.ts +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +1 -1
- package/dist/runtime/adapter.d.ts +5 -1
- package/dist/runtime/adapter.js +5 -5
- package/dist/runtime/executors.d.ts +1 -1
- package/dist/runtime/executors.js +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +5 -5
- package/dist/runtime/runtime.d.ts +3 -2
- package/dist/runtime/runtime.js +4 -4
- package/dist/runtime/state.d.ts +1 -1
- package/dist/runtime/traverser.d.ts +2 -1
- package/dist/runtime/traverser.js +1 -1
- package/dist/runtime/types.d.ts +2 -1
- package/dist/sanitizer.d.ts +1 -1
- package/dist/serializer.d.ts +1 -1
- package/dist/{types-lG3xCzp_.d.ts → types-CQCe_nBM.d.ts} +8 -0
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-5EHIPX23.js.map +0 -1
- package/dist/chunk-5QMPFUKA.js.map +0 -1
- package/dist/chunk-5ZWYSKMH.js.map +0 -1
- package/dist/chunk-CO5BTPKI.js.map +0 -1
- package/dist/chunk-QRMUKDSP.js +0 -141
- package/dist/chunk-QRMUKDSP.js.map +0 -1
- package/dist/chunk-UMXW3TCY.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { FlowRuntime } from './chunk-
|
|
1
|
+
import { FlowRuntime } from './chunk-3XVVR2SR.js';
|
|
2
2
|
import { JsonSerializer } from './chunk-CYHZ2YVH.js';
|
|
3
|
+
import { analyzeBlueprint } from './chunk-HN72TZY5.js';
|
|
3
4
|
|
|
4
5
|
// src/runtime/adapter.ts
|
|
5
6
|
var BaseDistributedAdapter = class {
|
|
@@ -54,25 +55,36 @@ var BaseDistributedAdapter = class {
|
|
|
54
55
|
try {
|
|
55
56
|
const result = await this.runtime.executeNode(blueprint, nodeId, workerState);
|
|
56
57
|
await context.set(nodeId, result.output);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
58
|
+
const analysis = analyzeBlueprint(blueprint);
|
|
59
|
+
const isTerminalNode = analysis.terminalNodeIds.includes(nodeId);
|
|
60
|
+
if (isTerminalNode) {
|
|
61
|
+
const completedNodes = new Set(
|
|
62
|
+
Object.keys(await context.toJSON()).filter((k) => blueprint.nodes.some((n) => n.id === k))
|
|
63
|
+
);
|
|
64
|
+
const allTerminalNodesCompleted = analysis.terminalNodeIds.every((terminalId) => completedNodes.has(terminalId));
|
|
65
|
+
if (allTerminalNodesCompleted) {
|
|
66
|
+
console.log(`[Adapter] \u2705 All terminal nodes completed for Run ID: ${runId}. Declaring workflow complete.`);
|
|
67
|
+
const finalContext = await context.toJSON();
|
|
68
|
+
const finalResult = {
|
|
69
|
+
context: finalContext,
|
|
70
|
+
serializedContext: this.serializer.serialize(finalContext),
|
|
71
|
+
status: "completed"
|
|
72
|
+
};
|
|
73
|
+
await this.publishFinalResult(runId, {
|
|
74
|
+
status: "completed",
|
|
75
|
+
payload: finalResult
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
} else {
|
|
79
|
+
console.log(
|
|
80
|
+
`[Adapter] Terminal node '${nodeId}' completed for Run ID '${runId}', but other terminal nodes are still running.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
71
83
|
}
|
|
72
84
|
const nextNodes = await this.runtime.determineNextNodes(blueprint, nodeId, result, context);
|
|
73
|
-
if (nextNodes.length === 0) {
|
|
85
|
+
if (nextNodes.length === 0 && !isTerminalNode) {
|
|
74
86
|
console.log(
|
|
75
|
-
`[Adapter]
|
|
87
|
+
`[Adapter] Non-terminal node '${nodeId}' reached end of branch for Run ID '${runId}'. This branch will now terminate.`
|
|
76
88
|
);
|
|
77
89
|
return;
|
|
78
90
|
}
|
|
@@ -90,6 +102,7 @@ var BaseDistributedAdapter = class {
|
|
|
90
102
|
const reason = error.message || "Unknown execution error";
|
|
91
103
|
console.error(`[Adapter] FATAL: Job for node '${nodeId}' failed for Run ID '${runId}': ${reason}`);
|
|
92
104
|
await this.publishFinalResult(runId, { status: "failed", reason });
|
|
105
|
+
await this.writePoisonPillForSuccessors(runId, blueprint, nodeId);
|
|
93
106
|
}
|
|
94
107
|
}
|
|
95
108
|
/**
|
|
@@ -105,6 +118,12 @@ var BaseDistributedAdapter = class {
|
|
|
105
118
|
if (predecessors.length <= 1) {
|
|
106
119
|
return true;
|
|
107
120
|
}
|
|
121
|
+
const poisonKey = `flowcraft:fanin:poison:${runId}:${targetNodeId}`;
|
|
122
|
+
const isPoisoned = !await this.store.setIfNotExist(poisonKey, "poisoned", 3600);
|
|
123
|
+
if (isPoisoned) {
|
|
124
|
+
console.log(`[Adapter] Node '${targetNodeId}' is poisoned due to failed predecessor. Failing immediately.`);
|
|
125
|
+
throw new Error(`Node '${targetNodeId}' failed due to poisoned predecessor in run '${runId}'`);
|
|
126
|
+
}
|
|
108
127
|
if (joinStrategy === "any") {
|
|
109
128
|
const lockKey = `flowcraft:joinlock:${runId}:${targetNodeId}`;
|
|
110
129
|
return await this.store.setIfNotExist(lockKey, "locked", 3600);
|
|
@@ -195,8 +214,23 @@ var BaseDistributedAdapter = class {
|
|
|
195
214
|
}
|
|
196
215
|
return newFrontier;
|
|
197
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Writes a poison pill for 'all' join successors of a failed node to prevent stalling.
|
|
219
|
+
*/
|
|
220
|
+
async writePoisonPillForSuccessors(runId, blueprint, failedNodeId) {
|
|
221
|
+
const successors = blueprint.edges.filter((edge) => edge.source === failedNodeId).map((edge) => edge.target).map((targetId) => blueprint.nodes.find((node) => node.id === targetId)).filter((node) => node && (node.config?.joinStrategy || "all") === "all");
|
|
222
|
+
for (const successor of successors) {
|
|
223
|
+
if (successor) {
|
|
224
|
+
const poisonKey = `flowcraft:fanin:poison:${runId}:${successor.id}`;
|
|
225
|
+
await this.store.setIfNotExist(poisonKey, "poisoned", 3600);
|
|
226
|
+
console.log(
|
|
227
|
+
`[Adapter] Wrote poison pill for join node '${successor.id}' due to failed predecessor '${failedNodeId}'`
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
198
232
|
};
|
|
199
233
|
|
|
200
234
|
export { BaseDistributedAdapter };
|
|
201
|
-
//# sourceMappingURL=chunk-
|
|
202
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-O3XD45IL.js.map
|
|
236
|
+
//# sourceMappingURL=chunk-O3XD45IL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/adapter.ts"],"names":["nodeId"],"mappings":"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","file":"chunk-O3XD45IL.js","sourcesContent":["import { analyzeBlueprint } from '../analysis'\nimport { JsonSerializer } from '../serializer'\nimport type {\n\tIAsyncContext,\n\tISerializer,\n\tNodeResult,\n\tRuntimeOptions,\n\tWorkflowBlueprint,\n\tWorkflowResult,\n} from '../types'\nimport { FlowRuntime } from './runtime'\n\n/**\n * Defines the contract for an atomic, distributed key-value store required by\n * the adapter for coordination tasks like fan-in joins and locking.\n */\nexport interface ICoordinationStore {\n\t/** Atomically increments a key and returns the new value. Ideal for 'all' joins. */\n\tincrement: (key: string, ttlSeconds: number) => Promise<number>\n\t/** Sets a key only if it does not already exist. Ideal for 'any' joins (locking). */\n\tsetIfNotExist: (key: string, value: string, ttlSeconds: number) => Promise<boolean>\n\t/** Deletes a key. Used for cleanup. */\n\tdelete: (key: string) => Promise<void>\n}\n\n/** Configuration options for constructing a BaseDistributedAdapter. */\nexport interface AdapterOptions {\n\truntimeOptions: RuntimeOptions<any>\n\tcoordinationStore: ICoordinationStore\n}\n\n/** The data payload expected for a job in the queue. */\nexport interface JobPayload {\n\trunId: string\n\tblueprintId: string\n\tnodeId: string\n}\n\n/**\n * The base class for all distributed adapters. It handles the technology-agnostic\n * orchestration logic and leaves queue-specific implementation to subclasses.\n */\nexport abstract class BaseDistributedAdapter {\n\tprotected readonly runtime: FlowRuntime<any, any>\n\tprotected readonly store: ICoordinationStore\n\tprotected readonly serializer: ISerializer\n\n\tconstructor(options: AdapterOptions) {\n\t\tthis.runtime = new FlowRuntime(options.runtimeOptions)\n\t\tthis.store = options.coordinationStore\n\t\tthis.serializer = options.runtimeOptions.serializer || new JsonSerializer()\n\t\tconsole.log('[Adapter] BaseDistributedAdapter initialized.')\n\t}\n\n\t/**\n\t * Starts the worker, which begins listening for and processing jobs from the queue.\n\t */\n\tpublic start(): void {\n\t\tconsole.log('[Adapter] Starting worker...')\n\t\tthis.processJobs(this.handleJob.bind(this))\n\t}\n\n\t/**\n\t * Creates a technology-specific distributed context for a given workflow run.\n\t * @param runId The unique ID for the workflow execution.\n\t */\n\tprotected abstract createContext(runId: string): IAsyncContext<Record<string, any>>\n\t/**\n\t * Sets up the listener for the message queue. The implementation should call the\n\t * provided `handler` function for each new job received.\n\t * @param handler The core logic to execute for each job.\n\t */\n\tprotected abstract processJobs(handler: (job: JobPayload) => Promise<void>): void\n\n\t/**\n\t * Enqueues a new job onto the message queue.\n\t * @param job The payload for the job to be enqueued.\n\t */\n\tprotected abstract enqueueJob(job: JobPayload): Promise<void>\n\n\t/**\n\t * Publishes the final result of a completed or failed workflow run.\n\t * @param runId The unique ID of the workflow run.\n\t * @param result The final status and payload of the workflow.\n\t */\n\tprotected abstract publishFinalResult(\n\t\trunId: string,\n\t\tresult: {\n\t\t\tstatus: 'completed' | 'failed'\n\t\t\tpayload?: WorkflowResult\n\t\t\treason?: string\n\t\t},\n\t): Promise<void>\n\n\t/**\n\t * Hook called at the start of job processing. Subclasses can override this\n\t * to perform additional setup (e.g., timestamp tracking for reconciliation).\n\t */\n\tprotected async onJobStart(_runId: string, _blueprintId: string, _nodeId: string): Promise<void> {\n\t\t// default implementation does nothing\n\t}\n\n\t/**\n\t * The main handler for processing a single job from the queue.\n\t */\n\tprotected async handleJob(job: JobPayload): Promise<void> {\n\t\tconst { runId, blueprintId, nodeId } = job\n\n\t\tawait this.onJobStart(runId, blueprintId, nodeId)\n\n\t\tconst blueprint = this.runtime.options.blueprints?.[blueprintId]\n\t\tif (!blueprint) {\n\t\t\tconst reason = `Blueprint with ID '${blueprintId}' not found in the worker's runtime registry.`\n\t\t\tconsole.error(`[Adapter] FATAL: ${reason}`)\n\t\t\tawait this.publishFinalResult(runId, { status: 'failed', reason })\n\t\t\treturn\n\t\t}\n\n\t\tconst context = this.createContext(runId)\n\n\t\t// persist the blueprintId for the reconcile method to find later\n\t\tconst hasBlueprintId = await context.has('blueprintId' as any)\n\t\tif (!hasBlueprintId) {\n\t\t\tawait context.set('blueprintId' as any, blueprintId)\n\t\t}\n\t\tconst workerState = {\n\t\t\tgetContext: () => context,\n\t\t\tmarkFallbackExecuted: () => {},\n\t\t\taddError: (nodeId: string, error: Error) => {\n\t\t\t\tconsole.error(`[Adapter] Error in node ${nodeId}:`, error)\n\t\t\t},\n\t\t} as any\n\n\t\ttry {\n\t\t\tconst result: NodeResult<any, any> = await this.runtime.executeNode(blueprint, nodeId, workerState)\n\t\t\tawait context.set(nodeId as any, result.output)\n\n\t\t\tconst analysis = analyzeBlueprint(blueprint)\n\t\t\tconst isTerminalNode = analysis.terminalNodeIds.includes(nodeId)\n\n\t\t\tif (isTerminalNode) {\n\t\t\t\tconst completedNodes = new Set(\n\t\t\t\t\tObject.keys(await context.toJSON()).filter((k) => blueprint.nodes.some((n) => n.id === k)),\n\t\t\t\t)\n\t\t\t\tconst allTerminalNodesCompleted = analysis.terminalNodeIds.every((terminalId) => completedNodes.has(terminalId))\n\n\t\t\t\tif (allTerminalNodesCompleted) {\n\t\t\t\t\tconsole.log(`[Adapter] ✅ All terminal nodes completed for Run ID: ${runId}. Declaring workflow complete.`)\n\t\t\t\t\tconst finalContext = await context.toJSON()\n\t\t\t\t\tconst finalResult: WorkflowResult = {\n\t\t\t\t\t\tcontext: finalContext,\n\t\t\t\t\t\tserializedContext: this.serializer.serialize(finalContext),\n\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t}\n\t\t\t\t\tawait this.publishFinalResult(runId, {\n\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\tpayload: finalResult,\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`[Adapter] Terminal node '${nodeId}' completed for Run ID '${runId}', but other terminal nodes are still running.`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst nextNodes = await this.runtime.determineNextNodes(blueprint, nodeId, result, context)\n\n\t\t\t// stop if a branch terminates but it wasn't a terminal node\n\t\t\tif (nextNodes.length === 0 && !isTerminalNode) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`[Adapter] Non-terminal node '${nodeId}' reached end of branch for Run ID '${runId}'. This branch will now terminate.`,\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor (const { node: nextNodeDef, edge } of nextNodes) {\n\t\t\t\tawait this.runtime.applyEdgeTransform(edge, result, nextNodeDef, context)\n\t\t\t\tconst isReady = await this.isReadyForFanIn(runId, blueprint, nextNodeDef.id)\n\t\t\t\tif (isReady) {\n\t\t\t\t\tconsole.log(`[Adapter] Node '${nextNodeDef.id}' is ready. Enqueuing job.`)\n\t\t\t\t\tawait this.enqueueJob({ runId, blueprintId, nodeId: nextNodeDef.id })\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(`[Adapter] Node '${nextNodeDef.id}' is waiting for other predecessors to complete.`)\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error: any) {\n\t\t\tconst reason = error.message || 'Unknown execution error'\n\t\t\tconsole.error(`[Adapter] FATAL: Job for node '${nodeId}' failed for Run ID '${runId}': ${reason}`)\n\t\t\tawait this.publishFinalResult(runId, { status: 'failed', reason })\n\t\t\tawait this.writePoisonPillForSuccessors(runId, blueprint, nodeId)\n\t\t}\n\t}\n\n\t/**\n\t * Encapsulates the fan-in join logic using the coordination store.\n\t */\n\tprotected async isReadyForFanIn(runId: string, blueprint: WorkflowBlueprint, targetNodeId: string): Promise<boolean> {\n\t\tconst targetNode = blueprint.nodes.find((n) => n.id === targetNodeId)\n\t\tif (!targetNode) {\n\t\t\tthrow new Error(`Node '${targetNodeId}' not found in blueprint`)\n\t\t}\n\t\tconst joinStrategy = targetNode.config?.joinStrategy || 'all'\n\t\tconst predecessors = blueprint.edges.filter((e) => e.target === targetNodeId)\n\n\t\tif (predecessors.length <= 1) {\n\t\t\treturn true\n\t\t}\n\n\t\tconst poisonKey = `flowcraft:fanin:poison:${runId}:${targetNodeId}`\n\t\tconst isPoisoned = !(await this.store.setIfNotExist(poisonKey, 'poisoned', 3600))\n\t\tif (isPoisoned) {\n\t\t\tconsole.log(`[Adapter] Node '${targetNodeId}' is poisoned due to failed predecessor. Failing immediately.`)\n\t\t\tthrow new Error(`Node '${targetNodeId}' failed due to poisoned predecessor in run '${runId}'`)\n\t\t}\n\n\t\tif (joinStrategy === 'any') {\n\t\t\tconst lockKey = `flowcraft:joinlock:${runId}:${targetNodeId}`\n\t\t\treturn await this.store.setIfNotExist(lockKey, 'locked', 3600)\n\t\t} else {\n\t\t\tconst fanInKey = `flowcraft:fanin:${runId}:${targetNodeId}`\n\t\t\tconst readyCount = await this.store.increment(fanInKey, 3600)\n\t\t\tif (readyCount >= predecessors.length) {\n\t\t\t\tawait this.store.delete(fanInKey)\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Reconciles the state of a workflow run. It inspects the persisted\n\t * context to find completed nodes, determines the next set of executable\n\t * nodes (the frontier), and enqueues jobs for them if they aren't\n\t * already running. This is the core of the resume functionality.\n\t *\n\t * @param runId The unique ID of the workflow execution to reconcile.\n\t * @returns The set of node IDs that were enqueued for execution.\n\t */\n\tpublic async reconcile(runId: string): Promise<Set<string>> {\n\t\tconst context = this.createContext(runId)\n\t\tconst blueprintId = (await context.get('blueprintId' as any)) as string | undefined\n\n\t\tif (!blueprintId) {\n\t\t\tthrow new Error(`Cannot reconcile runId '${runId}': blueprintId not found in context.`)\n\t\t}\n\t\tconst blueprint = this.runtime.options.blueprints?.[blueprintId]\n\t\tif (!blueprint) {\n\t\t\tthrow new Error(`Cannot reconcile runId '${runId}': Blueprint with ID '${blueprintId}' not found.`)\n\t\t}\n\n\t\tconst state = await context.toJSON()\n\t\t// filter out internal keys\n\t\tconst completedNodes = new Set(Object.keys(state).filter((k) => blueprint.nodes.some((n) => n.id === k)))\n\n\t\tconst frontier = this.calculateResumedFrontier(blueprint, completedNodes)\n\n\t\tconst enqueuedNodes = new Set<string>()\n\t\tfor (const nodeId of frontier) {\n\t\t\tconst nodeDef = blueprint.nodes.find((n) => n.id === nodeId)\n\t\t\tconst joinStrategy = nodeDef?.config?.joinStrategy || 'all'\n\n\t\t\tlet shouldEnqueue = false\n\n\t\t\tif (joinStrategy === 'any') {\n\t\t\t\t// acquire the permanent join lock\n\t\t\t\tconst lockKey = `flowcraft:joinlock:${runId}:${nodeId}`\n\t\t\t\tif (await this.store.setIfNotExist(lockKey, 'locked-by-reconcile', 3600)) {\n\t\t\t\t\tshouldEnqueue = true\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(`[Adapter] Reconciling: Node '${nodeId}' is an 'any' join and is already locked.`, { runId })\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// 'all' joins and single-predecessor nodes use a temporary lock\n\t\t\t\tconst lockKey = `flowcraft:nodelock:${runId}:${nodeId}`\n\t\t\t\tif (await this.store.setIfNotExist(lockKey, 'locked', 120)) {\n\t\t\t\t\tshouldEnqueue = true\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(`[Adapter] Reconciling: Node '${nodeId}' is already locked.`, { runId })\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (shouldEnqueue) {\n\t\t\t\tconsole.log(`[Adapter] Reconciling: Enqueuing ready job for node '${nodeId}'`, { runId })\n\t\t\t\tawait this.enqueueJob({ runId, blueprintId: blueprint.id, nodeId })\n\t\t\t\tenqueuedNodes.add(nodeId)\n\t\t\t}\n\t\t}\n\n\t\treturn enqueuedNodes\n\t}\n\n\tprivate calculateResumedFrontier(blueprint: WorkflowBlueprint, completedNodes: Set<string>): Set<string> {\n\t\tconst newFrontier = new Set<string>()\n\t\tconst allPredecessors = new Map<string, Set<string>>()\n\t\t// (logic extracted from the GraphTraverser)\n\t\tfor (const node of blueprint.nodes) {\n\t\t\tallPredecessors.set(node.id, new Set())\n\t\t}\n\t\tfor (const edge of blueprint.edges) {\n\t\t\tallPredecessors.get(edge.target)?.add(edge.source)\n\t\t}\n\n\t\tfor (const node of blueprint.nodes) {\n\t\t\tif (completedNodes.has(node.id)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst predecessors = allPredecessors.get(node.id) ?? new Set()\n\t\t\tif (predecessors.size === 0 && !completedNodes.has(node.id)) {\n\t\t\t\tnewFrontier.add(node.id)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst joinStrategy = node.config?.joinStrategy || 'all'\n\t\t\tconst completedPredecessors = [...predecessors].filter((p) => completedNodes.has(p))\n\n\t\t\tconst isReady =\n\t\t\t\tjoinStrategy === 'any' ? completedPredecessors.length > 0 : completedPredecessors.length === predecessors.size\n\n\t\t\tif (isReady) {\n\t\t\t\tnewFrontier.add(node.id)\n\t\t\t}\n\t\t}\n\t\treturn newFrontier\n\t}\n\n\t/**\n\t * Writes a poison pill for 'all' join successors of a failed node to prevent stalling.\n\t */\n\tprivate async writePoisonPillForSuccessors(\n\t\trunId: string,\n\t\tblueprint: WorkflowBlueprint,\n\t\tfailedNodeId: string,\n\t): Promise<void> {\n\t\tconst successors = blueprint.edges\n\t\t\t.filter((edge) => edge.source === failedNodeId)\n\t\t\t.map((edge) => edge.target)\n\t\t\t.map((targetId) => blueprint.nodes.find((node) => node.id === targetId))\n\t\t\t.filter((node) => node && (node.config?.joinStrategy || 'all') === 'all')\n\n\t\tfor (const successor of successors) {\n\t\t\tif (successor) {\n\t\t\t\tconst poisonKey = `flowcraft:fanin:poison:${runId}:${successor.id}`\n\t\t\t\tawait this.store.setIfNotExist(poisonKey, 'poisoned', 3600)\n\t\t\t\tconsole.log(\n\t\t\t\t\t`[Adapter] Wrote poison pill for join node '${successor.id}' due to failed predecessor '${failedNodeId}'`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -33,8 +33,17 @@ var BaseNode = class {
|
|
|
33
33
|
async fallback(error, _context) {
|
|
34
34
|
throw error;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* An optional cleanup phase for non-retriable errors that occur outside the main `exec` method.
|
|
38
|
+
* This method is invoked in a `finally` block or equivalent construct if a fatal, unhandled exception occurs in the `prep`, `exec`, or `post` phases.
|
|
39
|
+
* Allows nodes to perform crucial cleanup, such as closing database connections or releasing locks.
|
|
40
|
+
* @param _error The error that caused the failure.
|
|
41
|
+
* @param _context The node's execution context.
|
|
42
|
+
*/
|
|
43
|
+
async recover(_error, _context) {
|
|
44
|
+
}
|
|
36
45
|
};
|
|
37
46
|
|
|
38
47
|
export { BaseNode, isNodeClass };
|
|
39
|
-
//# sourceMappingURL=chunk-
|
|
40
|
-
//# sourceMappingURL=chunk-
|
|
48
|
+
//# sourceMappingURL=chunk-U5V5O5MN.js.map
|
|
49
|
+
//# sourceMappingURL=chunk-U5V5O5MN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/node.ts"],"names":[],"mappings":";AAGO,SAAS,YAAY,IAAA,EAA8B;AACzD,EAAA,OAAO,OAAO,IAAA,KAAS,UAAA,IAAc,CAAC,CAAC,KAAK,SAAA,EAAW,IAAA;AACxD;AAOO,IAAe,WAAf,MAML;AAAA;AAAA;AAAA;AAAA,EAID,YAAsB,MAAA,EAA8B;AAA9B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrD,MAAM,KAAK,OAAA,EAAqE;AAC/E,IAAA,OAAO,OAAA,CAAQ,KAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,IAAA,CACL,UAAA,EACA,QAAA,EACwC;AACxC,IAAA,OAAO,UAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAA,CACL,KAAA,EACA,QAAA,EACuD;AAEvD,IAAA,MAAM,KAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OAAA,CAAQ,MAAA,EAAe,QAAA,EAAuE;AAAA,EAEpG;AACD","file":"chunk-U5V5O5MN.js","sourcesContent":["import type { NodeClass, NodeContext, NodeResult, RuntimeDependencies } from './types'\n\n/** A type guard to reliably distinguish a NodeClass from a NodeFunction. */\nexport function isNodeClass(impl: any): impl is NodeClass {\n\treturn typeof impl === 'function' && !!impl.prototype?.exec\n}\n\n/**\n * A structured, class-based node for complex logic with a safe, granular lifecycle.\n * This class is generic, allowing implementations to specify the exact context\n * and dependency types they expect.\n */\nexport abstract class BaseNode<\n\tTContext extends Record<string, any> = Record<string, any>,\n\tTDependencies extends RuntimeDependencies = RuntimeDependencies,\n\tTInput = any,\n\tTOutput = any,\n\tTAction extends string = string,\n> {\n\t/**\n\t * @param params Static parameters for this node instance, passed from the blueprint.\n\t */\n\tconstructor(protected params?: Record<string, any>) {}\n\n\t/**\n\t * Phase 1: Gathers and prepares data for execution. This phase is NOT retried on failure.\n\t * @param context The node's execution context.\n\t * @returns The data needed for the `exec` phase.\n\t */\n\tasync prep(context: NodeContext<TContext, TDependencies, TInput>): Promise<any> {\n\t\treturn context.input\n\t}\n\n\t/**\n\t * Phase 2: Performs the core, isolated logic. This is the ONLY phase that is retried.\n\t * @param prepResult The data returned from the `prep` phase.\n\t * @param context The node's execution context.\n\t */\n\tabstract exec(\n\t\tprepResult: any,\n\t\tcontext: NodeContext<TContext, TDependencies, TInput>,\n\t): Promise<Omit<NodeResult<TOutput, TAction>, 'error'>>\n\n\t/**\n\t * Phase 3: Processes the result and saves state. This phase is NOT retried.\n\t * @param execResult The successful result from the `exec` or `fallback` phase.\n\t * @param _context The node's execution context.\n\t */\n\tasync post(\n\t\texecResult: Omit<NodeResult<TOutput, TAction>, 'error'>,\n\t\t_context: NodeContext<TContext, TDependencies, TInput>,\n\t): Promise<NodeResult<TOutput, TAction>> {\n\t\treturn execResult\n\t}\n\n\t/**\n\t * An optional safety net that runs if all `exec` retries fail.\n\t * @param error The final error from the last `exec` attempt.\n\t * @param _context The node's execution context.\n\t */\n\tasync fallback(\n\t\terror: Error,\n\t\t_context: NodeContext<TContext, TDependencies, TInput>,\n\t): Promise<Omit<NodeResult<TOutput, TAction>, 'error'>> {\n\t\t// By default, re-throw the error, failing the node.\n\t\tthrow error\n\t}\n\n\t/**\n\t * An optional cleanup phase for non-retriable errors that occur outside the main `exec` method.\n\t * This method is invoked in a `finally` block or equivalent construct if a fatal, unhandled exception occurs in the `prep`, `exec`, or `post` phases.\n\t * Allows nodes to perform crucial cleanup, such as closing database connections or releasing locks.\n\t * @param _error The error that caused the failure.\n\t * @param _context The node's execution context.\n\t */\n\tasync recover(_error: Error, _context: NodeContext<TContext, TDependencies, TInput>): Promise<void> {\n\t\t// Default no-op implementation. Subclasses can override for cleanup.\n\t}\n}\n"]}
|
package/dist/context.d.ts
CHANGED
package/dist/evaluator.d.ts
CHANGED
package/dist/flow.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as NodeFunction, e as NodeClass, N as NodeDefinition, E as EdgeDefinition, W as WorkflowBlueprint } from './types-
|
|
1
|
+
import { d as NodeFunction, e as NodeClass, N as NodeDefinition, E as EdgeDefinition, W as WorkflowBlueprint } from './types-CQCe_nBM.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A fluent API for programmatically constructing a WorkflowBlueprint.
|
|
@@ -23,9 +23,9 @@ declare class Flow<TContext extends Record<string, any> = Record<string, any>, T
|
|
|
23
23
|
*/
|
|
24
24
|
batch<TInput = any, TOutput = any, TAction extends string = string>(id: string, worker: NodeFunction<TContext, TDependencies, TInput, TOutput, TAction> | NodeClass<TContext, TDependencies, TInput, TOutput, TAction>, options: {
|
|
25
25
|
/** The key in the context that holds the input array for the batch. */
|
|
26
|
-
inputKey:
|
|
26
|
+
inputKey: keyof TContext;
|
|
27
27
|
/** The key in the context where the array of results will be stored. */
|
|
28
|
-
outputKey:
|
|
28
|
+
outputKey: keyof TContext;
|
|
29
29
|
}): this;
|
|
30
30
|
/**
|
|
31
31
|
* Creates a loop pattern in the workflow graph.
|
package/dist/flow.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { PropertyEvaluator, UnsafeEvaluator } from './evaluator.js';
|
|
|
5
5
|
export { Flow, createFlow } from './flow.js';
|
|
6
6
|
export { LinterIssue, LinterIssueCode, LinterResult, lintBlueprint } from './linter.js';
|
|
7
7
|
export { ConsoleLogger, NullLogger } from './logger.js';
|
|
8
|
-
export { B as BaseNode, C as ContextImplementation, E as EdgeDefinition, h as IAsyncContext, k as IEvaluator, m as IEventBus, l as ILogger, n as ISerializer, I as ISyncContext, M as Middleware, e as NodeClass, a as NodeConfig, c as NodeContext, N as NodeDefinition, d as NodeFunction, f as NodeImplementation, g as NodeRegistry, b as NodeResult, R as RuntimeDependencies, j as RuntimeOptions, W as WorkflowBlueprint, o as WorkflowError, p as WorkflowResult, i as isNodeClass } from './types-
|
|
8
|
+
export { B as BaseNode, C as ContextImplementation, E as EdgeDefinition, h as IAsyncContext, k as IEvaluator, m as IEventBus, l as ILogger, n as ISerializer, I as ISyncContext, M as Middleware, e as NodeClass, a as NodeConfig, c as NodeContext, N as NodeDefinition, d as NodeFunction, f as NodeImplementation, g as NodeRegistry, b as NodeResult, R as RuntimeDependencies, j as RuntimeOptions, W as WorkflowBlueprint, o as WorkflowError, p as WorkflowResult, i as isNodeClass } from './types-CQCe_nBM.js';
|
|
9
9
|
export { AdapterOptions, BaseDistributedAdapter, ICoordinationStore, JobPayload } from './runtime/adapter.js';
|
|
10
10
|
export { BuiltInNodeExecutor, ClassNodeExecutor, ExecutionStrategy, FunctionNodeExecutor } from './runtime/executors.js';
|
|
11
11
|
export { FlowRuntime } from './runtime/runtime.js';
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import './chunk-55J6XMHW.js';
|
|
2
2
|
import './chunk-HMR2GEGE.js';
|
|
3
|
-
export { BaseDistributedAdapter } from './chunk-
|
|
4
|
-
export { FlowRuntime } from './chunk-
|
|
3
|
+
export { BaseDistributedAdapter } from './chunk-O3XD45IL.js';
|
|
4
|
+
export { FlowRuntime } from './chunk-3XVVR2SR.js';
|
|
5
5
|
export { WorkflowState } from './chunk-CSZ6EOWG.js';
|
|
6
|
-
export { GraphTraverser } from './chunk-
|
|
6
|
+
export { GraphTraverser } from './chunk-NBIRTKZ7.js';
|
|
7
7
|
export { sanitizeBlueprint } from './chunk-DSYAC4WB.js';
|
|
8
8
|
import './chunk-CYHZ2YVH.js';
|
|
9
|
-
export { BuiltInNodeExecutor, ClassNodeExecutor, FunctionNodeExecutor } from './chunk-
|
|
9
|
+
export { BuiltInNodeExecutor, ClassNodeExecutor, FunctionNodeExecutor } from './chunk-M2FRTT2K.js';
|
|
10
10
|
export { AsyncContextView, Context } from './chunk-KWQHFT7E.js';
|
|
11
11
|
export { CancelledWorkflowError, FatalNodeExecutionError, NodeExecutionError } from './chunk-5ZXV3R5D.js';
|
|
12
12
|
export { PropertyEvaluator, UnsafeEvaluator } from './chunk-PH2IYZHV.js';
|
|
13
|
-
export { Flow, createFlow } from './chunk-
|
|
14
|
-
export { BaseNode, isNodeClass } from './chunk-
|
|
13
|
+
export { Flow, createFlow } from './chunk-4A627Q6L.js';
|
|
14
|
+
export { BaseNode, isNodeClass } from './chunk-U5V5O5MN.js';
|
|
15
15
|
export { lintBlueprint } from './chunk-UETC63DP.js';
|
|
16
16
|
export { analyzeBlueprint, checkForCycles, generateMermaid } from './chunk-HN72TZY5.js';
|
|
17
17
|
export { ConsoleLogger, NullLogger } from './chunk-4PELJWF7.js';
|
package/dist/linter.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as WorkflowBlueprint, d as NodeFunction, e as NodeClass } from './types-
|
|
1
|
+
import { W as WorkflowBlueprint, d as NodeFunction, e as NodeClass } from './types-CQCe_nBM.js';
|
|
2
2
|
|
|
3
3
|
type LinterIssueCode = 'INVALID_EDGE_SOURCE' | 'INVALID_EDGE_TARGET' | 'MISSING_NODE_IMPLEMENTATION' | 'ORPHAN_NODE';
|
|
4
4
|
interface LinterIssue {
|
package/dist/logger.d.ts
CHANGED
package/dist/node.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { B as BaseNode, i as isNodeClass } from './types-
|
|
1
|
+
export { B as BaseNode, i as isNodeClass } from './types-CQCe_nBM.js';
|
package/dist/node.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { j as RuntimeOptions, n as ISerializer, h as IAsyncContext, p as WorkflowResult, W as WorkflowBlueprint } from '../types-
|
|
1
|
+
import { j as RuntimeOptions, n as ISerializer, h as IAsyncContext, p as WorkflowResult, W as WorkflowBlueprint } from '../types-CQCe_nBM.js';
|
|
2
2
|
import { FlowRuntime } from './runtime.js';
|
|
3
3
|
import './state.js';
|
|
4
4
|
import './types.js';
|
|
@@ -89,6 +89,10 @@ declare abstract class BaseDistributedAdapter {
|
|
|
89
89
|
*/
|
|
90
90
|
reconcile(runId: string): Promise<Set<string>>;
|
|
91
91
|
private calculateResumedFrontier;
|
|
92
|
+
/**
|
|
93
|
+
* Writes a poison pill for 'all' join successors of a failed node to prevent stalling.
|
|
94
|
+
*/
|
|
95
|
+
private writePoisonPillForSuccessors;
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
export { type AdapterOptions, BaseDistributedAdapter, type ICoordinationStore, type JobPayload };
|
package/dist/runtime/adapter.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export { BaseDistributedAdapter } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { BaseDistributedAdapter } from '../chunk-O3XD45IL.js';
|
|
2
|
+
import '../chunk-3XVVR2SR.js';
|
|
3
3
|
import '../chunk-CSZ6EOWG.js';
|
|
4
|
-
import '../chunk-
|
|
4
|
+
import '../chunk-NBIRTKZ7.js';
|
|
5
5
|
import '../chunk-DSYAC4WB.js';
|
|
6
6
|
import '../chunk-CYHZ2YVH.js';
|
|
7
|
-
import '../chunk-
|
|
7
|
+
import '../chunk-M2FRTT2K.js';
|
|
8
8
|
import '../chunk-KWQHFT7E.js';
|
|
9
9
|
import '../chunk-5ZXV3R5D.js';
|
|
10
10
|
import '../chunk-PH2IYZHV.js';
|
|
11
|
-
import '../chunk-
|
|
11
|
+
import '../chunk-U5V5O5MN.js';
|
|
12
12
|
import '../chunk-HN72TZY5.js';
|
|
13
13
|
import '../chunk-4PELJWF7.js';
|
|
14
14
|
//# sourceMappingURL=adapter.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as NodeDefinition, c as NodeContext, b as NodeResult, d as NodeFunction, m as IEventBus, e as NodeClass, C as ContextImplementation } from '../types-
|
|
1
|
+
import { N as NodeDefinition, c as NodeContext, b as NodeResult, d as NodeFunction, m as IEventBus, e as NodeClass, C as ContextImplementation } from '../types-CQCe_nBM.js';
|
|
2
2
|
|
|
3
3
|
interface ExecutionStrategy {
|
|
4
4
|
execute: (nodeDef: NodeDefinition, context: NodeContext<any, any, any>, executionId?: string, signal?: AbortSignal) => Promise<NodeResult<any, any>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { BuiltInNodeExecutor, ClassNodeExecutor, FunctionNodeExecutor } from '../chunk-
|
|
1
|
+
export { BuiltInNodeExecutor, ClassNodeExecutor, FunctionNodeExecutor } from '../chunk-M2FRTT2K.js';
|
|
2
2
|
import '../chunk-5ZXV3R5D.js';
|
|
3
3
|
//# sourceMappingURL=executors.js.map
|
|
4
4
|
//# sourceMappingURL=executors.js.map
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export { BuiltInNodeExecutor, ClassNodeExecutor, ExecutionStrategy, FunctionNode
|
|
|
3
3
|
export { FlowRuntime } from './runtime.js';
|
|
4
4
|
export { WorkflowState } from './state.js';
|
|
5
5
|
export { GraphTraverser } from './traverser.js';
|
|
6
|
-
import '../types-
|
|
6
|
+
import '../types-CQCe_nBM.js';
|
|
7
7
|
import './types.js';
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import '../chunk-HMR2GEGE.js';
|
|
2
|
-
export { BaseDistributedAdapter } from '../chunk-
|
|
3
|
-
export { FlowRuntime } from '../chunk-
|
|
2
|
+
export { BaseDistributedAdapter } from '../chunk-O3XD45IL.js';
|
|
3
|
+
export { FlowRuntime } from '../chunk-3XVVR2SR.js';
|
|
4
4
|
export { WorkflowState } from '../chunk-CSZ6EOWG.js';
|
|
5
|
-
export { GraphTraverser } from '../chunk-
|
|
5
|
+
export { GraphTraverser } from '../chunk-NBIRTKZ7.js';
|
|
6
6
|
import '../chunk-DSYAC4WB.js';
|
|
7
7
|
import '../chunk-CYHZ2YVH.js';
|
|
8
|
-
export { BuiltInNodeExecutor, ClassNodeExecutor, FunctionNodeExecutor } from '../chunk-
|
|
8
|
+
export { BuiltInNodeExecutor, ClassNodeExecutor, FunctionNodeExecutor } from '../chunk-M2FRTT2K.js';
|
|
9
9
|
import '../chunk-KWQHFT7E.js';
|
|
10
10
|
import '../chunk-5ZXV3R5D.js';
|
|
11
11
|
import '../chunk-PH2IYZHV.js';
|
|
12
|
-
import '../chunk-
|
|
12
|
+
import '../chunk-U5V5O5MN.js';
|
|
13
13
|
import '../chunk-HN72TZY5.js';
|
|
14
14
|
import '../chunk-4PELJWF7.js';
|
|
15
15
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { j as RuntimeOptions, W as WorkflowBlueprint, p as WorkflowResult, b as NodeResult, C as ContextImplementation, N as NodeDefinition, E as EdgeDefinition } from '../types-
|
|
1
|
+
import { d as NodeFunction, e as NodeClass, B as BaseNode, j as RuntimeOptions, W as WorkflowBlueprint, p as WorkflowResult, b as NodeResult, C as ContextImplementation, N as NodeDefinition, E as EdgeDefinition } from '../types-CQCe_nBM.js';
|
|
2
2
|
import { WorkflowState } from './state.js';
|
|
3
3
|
import { IRuntime } from './types.js';
|
|
4
4
|
|
|
5
5
|
declare class FlowRuntime<TContext extends Record<string, any>, TDependencies extends Record<string, any>> implements IRuntime<TContext, TDependencies> {
|
|
6
|
-
|
|
6
|
+
registry: Record<string, NodeFunction | NodeClass | typeof BaseNode>;
|
|
7
7
|
private blueprints;
|
|
8
8
|
private dependencies;
|
|
9
9
|
private logger;
|
|
@@ -11,6 +11,7 @@ declare class FlowRuntime<TContext extends Record<string, any>, TDependencies ex
|
|
|
11
11
|
private serializer;
|
|
12
12
|
private middleware;
|
|
13
13
|
private evaluator;
|
|
14
|
+
private analysisCache;
|
|
14
15
|
options: RuntimeOptions<TDependencies>;
|
|
15
16
|
constructor(options: RuntimeOptions<TDependencies>);
|
|
16
17
|
run(blueprint: WorkflowBlueprint, initialState?: Partial<TContext> | string, options?: {
|
package/dist/runtime/runtime.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export { FlowRuntime } from '../chunk-
|
|
1
|
+
export { FlowRuntime } from '../chunk-3XVVR2SR.js';
|
|
2
2
|
import '../chunk-CSZ6EOWG.js';
|
|
3
|
-
import '../chunk-
|
|
3
|
+
import '../chunk-NBIRTKZ7.js';
|
|
4
4
|
import '../chunk-DSYAC4WB.js';
|
|
5
5
|
import '../chunk-CYHZ2YVH.js';
|
|
6
|
-
import '../chunk-
|
|
6
|
+
import '../chunk-M2FRTT2K.js';
|
|
7
7
|
import '../chunk-KWQHFT7E.js';
|
|
8
8
|
import '../chunk-5ZXV3R5D.js';
|
|
9
9
|
import '../chunk-PH2IYZHV.js';
|
|
10
|
-
import '../chunk-
|
|
10
|
+
import '../chunk-U5V5O5MN.js';
|
|
11
11
|
import '../chunk-HN72TZY5.js';
|
|
12
12
|
import '../chunk-4PELJWF7.js';
|
|
13
13
|
//# sourceMappingURL=runtime.js.map
|
package/dist/runtime/state.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ContextImplementation, o as WorkflowError, p as WorkflowResult, n as ISerializer } from '../types-
|
|
1
|
+
import { C as ContextImplementation, o as WorkflowError, p as WorkflowResult, n as ISerializer } from '../types-CQCe_nBM.js';
|
|
2
2
|
|
|
3
3
|
declare class WorkflowState<TContext extends Record<string, any>> {
|
|
4
4
|
private _completedNodes;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as WorkflowBlueprint } from '../types-
|
|
1
|
+
import { W as WorkflowBlueprint } from '../types-CQCe_nBM.js';
|
|
2
2
|
import { WorkflowState } from './state.js';
|
|
3
3
|
import { IRuntime } from './types.js';
|
|
4
4
|
|
|
@@ -14,6 +14,7 @@ declare class GraphTraverser<TContext extends Record<string, any>, TDependencies
|
|
|
14
14
|
private dynamicBlueprint;
|
|
15
15
|
constructor(blueprint: WorkflowBlueprint, runtime: IRuntime<TContext, TDependencies>, state: WorkflowState<TContext>, functionRegistry: Map<string, any> | undefined, executionId: string, signal?: AbortSignal | undefined, concurrency?: number | undefined);
|
|
16
16
|
private isFallbackNode;
|
|
17
|
+
private getEffectiveJoinStrategy;
|
|
17
18
|
traverse(): Promise<void>;
|
|
18
19
|
private executeWithConcurrency;
|
|
19
20
|
private handleDynamicNodes;
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { R as RuntimeDependencies, j as RuntimeOptions, W as WorkflowBlueprint, b as NodeResult, C as ContextImplementation, N as NodeDefinition, E as EdgeDefinition } from '../types-
|
|
1
|
+
import { R as RuntimeDependencies, j as RuntimeOptions, W as WorkflowBlueprint, b as NodeResult, C as ContextImplementation, N as NodeDefinition, E as EdgeDefinition } from '../types-CQCe_nBM.js';
|
|
2
2
|
import { WorkflowState } from './state.js';
|
|
3
3
|
|
|
4
4
|
/** Interface for the core runtime operations used by the traverser. */
|
|
5
5
|
interface IRuntime<TContext extends Record<string, any> = Record<string, any>, TDependencies extends RuntimeDependencies = RuntimeDependencies> {
|
|
6
6
|
options: RuntimeOptions<TDependencies>;
|
|
7
|
+
registry: Record<string, any>;
|
|
7
8
|
executeNode: (blueprint: WorkflowBlueprint, nodeId: string, state: WorkflowState<TContext>, allPredecessors?: Map<string, Set<string>>, functionRegistry?: Map<string, any>, executionId?: string, signal?: AbortSignal) => Promise<NodeResult>;
|
|
8
9
|
determineNextNodes: (blueprint: WorkflowBlueprint, nodeId: string, result: NodeResult, context: ContextImplementation<TContext>) => Promise<{
|
|
9
10
|
node: NodeDefinition;
|
package/dist/sanitizer.d.ts
CHANGED
package/dist/serializer.d.ts
CHANGED
|
@@ -35,6 +35,14 @@ declare abstract class BaseNode<TContext extends Record<string, any> = Record<st
|
|
|
35
35
|
* @param _context The node's execution context.
|
|
36
36
|
*/
|
|
37
37
|
fallback(error: Error, _context: NodeContext<TContext, TDependencies, TInput>): Promise<Omit<NodeResult<TOutput, TAction>, 'error'>>;
|
|
38
|
+
/**
|
|
39
|
+
* An optional cleanup phase for non-retriable errors that occur outside the main `exec` method.
|
|
40
|
+
* This method is invoked in a `finally` block or equivalent construct if a fatal, unhandled exception occurs in the `prep`, `exec`, or `post` phases.
|
|
41
|
+
* Allows nodes to perform crucial cleanup, such as closing database connections or releasing locks.
|
|
42
|
+
* @param _error The error that caused the failure.
|
|
43
|
+
* @param _context The node's execution context.
|
|
44
|
+
*/
|
|
45
|
+
recover(_error: Error, _context: NodeContext<TContext, TDependencies, TInput>): Promise<void>;
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
/** The central, serializable representation of a workflow. */
|
package/dist/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { C as ContextImplementation, E as EdgeDefinition, h as IAsyncContext, k as IEvaluator, m as IEventBus, l as ILogger, n as ISerializer, I as ISyncContext, M as Middleware, e as NodeClass, a as NodeConfig, c as NodeContext, N as NodeDefinition, d as NodeFunction, f as NodeImplementation, g as NodeRegistry, b as NodeResult, R as RuntimeDependencies, j as RuntimeOptions, W as WorkflowBlueprint, o as WorkflowError, p as WorkflowResult } from './types-
|
|
1
|
+
export { C as ContextImplementation, E as EdgeDefinition, h as IAsyncContext, k as IEvaluator, m as IEventBus, l as ILogger, n as ISerializer, I as ISyncContext, M as Middleware, e as NodeClass, a as NodeConfig, c as NodeContext, N as NodeDefinition, d as NodeFunction, f as NodeImplementation, g as NodeRegistry, b as NodeResult, R as RuntimeDependencies, j as RuntimeOptions, W as WorkflowBlueprint, o as WorkflowError, p as WorkflowResult } from './types-CQCe_nBM.js';
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/adapter.ts"],"names":["nodeId"],"mappings":"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","file":"chunk-5EHIPX23.js","sourcesContent":["import { JsonSerializer } from '../serializer'\nimport type {\n\tIAsyncContext,\n\tISerializer,\n\tNodeResult,\n\tRuntimeOptions,\n\tWorkflowBlueprint,\n\tWorkflowResult,\n} from '../types'\nimport { FlowRuntime } from './runtime'\n\n/**\n * Defines the contract for an atomic, distributed key-value store required by\n * the adapter for coordination tasks like fan-in joins and locking.\n */\nexport interface ICoordinationStore {\n\t/** Atomically increments a key and returns the new value. Ideal for 'all' joins. */\n\tincrement: (key: string, ttlSeconds: number) => Promise<number>\n\t/** Sets a key only if it does not already exist. Ideal for 'any' joins (locking). */\n\tsetIfNotExist: (key: string, value: string, ttlSeconds: number) => Promise<boolean>\n\t/** Deletes a key. Used for cleanup. */\n\tdelete: (key: string) => Promise<void>\n}\n\n/** Configuration options for constructing a BaseDistributedAdapter. */\nexport interface AdapterOptions {\n\truntimeOptions: RuntimeOptions<any>\n\tcoordinationStore: ICoordinationStore\n}\n\n/** The data payload expected for a job in the queue. */\nexport interface JobPayload {\n\trunId: string\n\tblueprintId: string\n\tnodeId: string\n}\n\n/**\n * The base class for all distributed adapters. It handles the technology-agnostic\n * orchestration logic and leaves queue-specific implementation to subclasses.\n */\nexport abstract class BaseDistributedAdapter {\n\tprotected readonly runtime: FlowRuntime<any, any>\n\tprotected readonly store: ICoordinationStore\n\tprotected readonly serializer: ISerializer\n\n\tconstructor(options: AdapterOptions) {\n\t\tthis.runtime = new FlowRuntime(options.runtimeOptions)\n\t\tthis.store = options.coordinationStore\n\t\tthis.serializer = options.runtimeOptions.serializer || new JsonSerializer()\n\t\tconsole.log('[Adapter] BaseDistributedAdapter initialized.')\n\t}\n\n\t/**\n\t * Starts the worker, which begins listening for and processing jobs from the queue.\n\t */\n\tpublic start(): void {\n\t\tconsole.log('[Adapter] Starting worker...')\n\t\tthis.processJobs(this.handleJob.bind(this))\n\t}\n\n\t/**\n\t * Creates a technology-specific distributed context for a given workflow run.\n\t * @param runId The unique ID for the workflow execution.\n\t */\n\tprotected abstract createContext(runId: string): IAsyncContext<Record<string, any>>\n\t/**\n\t * Sets up the listener for the message queue. The implementation should call the\n\t * provided `handler` function for each new job received.\n\t * @param handler The core logic to execute for each job.\n\t */\n\tprotected abstract processJobs(handler: (job: JobPayload) => Promise<void>): void\n\n\t/**\n\t * Enqueues a new job onto the message queue.\n\t * @param job The payload for the job to be enqueued.\n\t */\n\tprotected abstract enqueueJob(job: JobPayload): Promise<void>\n\n\t/**\n\t * Publishes the final result of a completed or failed workflow run.\n\t * @param runId The unique ID of the workflow run.\n\t * @param result The final status and payload of the workflow.\n\t */\n\tprotected abstract publishFinalResult(\n\t\trunId: string,\n\t\tresult: {\n\t\t\tstatus: 'completed' | 'failed'\n\t\t\tpayload?: WorkflowResult\n\t\t\treason?: string\n\t\t},\n\t): Promise<void>\n\n\t/**\n\t * Hook called at the start of job processing. Subclasses can override this\n\t * to perform additional setup (e.g., timestamp tracking for reconciliation).\n\t */\n\tprotected async onJobStart(_runId: string, _blueprintId: string, _nodeId: string): Promise<void> {\n\t\t// default implementation does nothing\n\t}\n\n\t/**\n\t * The main handler for processing a single job from the queue.\n\t */\n\tprotected async handleJob(job: JobPayload): Promise<void> {\n\t\tconst { runId, blueprintId, nodeId } = job\n\n\t\tawait this.onJobStart(runId, blueprintId, nodeId)\n\n\t\tconst blueprint = this.runtime.options.blueprints?.[blueprintId]\n\t\tif (!blueprint) {\n\t\t\tconst reason = `Blueprint with ID '${blueprintId}' not found in the worker's runtime registry.`\n\t\t\tconsole.error(`[Adapter] FATAL: ${reason}`)\n\t\t\tawait this.publishFinalResult(runId, { status: 'failed', reason })\n\t\t\treturn\n\t\t}\n\n\t\tconst context = this.createContext(runId)\n\n\t\t// persist the blueprintId for the reconcile method to find later\n\t\tconst hasBlueprintId = await context.has('blueprintId' as any)\n\t\tif (!hasBlueprintId) {\n\t\t\tawait context.set('blueprintId' as any, blueprintId)\n\t\t}\n\t\tconst workerState = {\n\t\t\tgetContext: () => context,\n\t\t\tmarkFallbackExecuted: () => {},\n\t\t\taddError: (nodeId: string, error: Error) => {\n\t\t\t\tconsole.error(`[Adapter] Error in node ${nodeId}:`, error)\n\t\t\t},\n\t\t} as any\n\n\t\ttry {\n\t\t\tconst result: NodeResult<any, any> = await this.runtime.executeNode(blueprint, nodeId, workerState)\n\t\t\tawait context.set(nodeId as any, result.output)\n\n\t\t\tconst nodeDef = blueprint.nodes.find((n) => n.id === nodeId)\n\t\t\t// workflow is considered complete when the first 'output' node finishes.\n\t\t\tif (nodeDef?.uses === 'output') {\n\t\t\t\tconsole.log(`[Adapter] ✅ Output node '${nodeId}' finished. Declaring workflow complete for Run ID: ${runId}`)\n\t\t\t\tconst finalContext = await context.toJSON()\n\t\t\t\tconst finalResult: WorkflowResult = {\n\t\t\t\t\tcontext: finalContext,\n\t\t\t\t\tserializedContext: this.serializer.serialize(finalContext),\n\t\t\t\t\tstatus: 'completed',\n\t\t\t\t}\n\t\t\t\tawait this.publishFinalResult(runId, {\n\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\tpayload: finalResult,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst nextNodes = await this.runtime.determineNextNodes(blueprint, nodeId, result, context)\n\n\t\t\t// stop if a branch terminates but it wasn't an 'output' node\n\t\t\tif (nextNodes.length === 0) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`[Adapter] Terminal node '${nodeId}' reached for Run ID '${runId}', but it was not an 'output' node. This branch will now terminate.`,\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor (const { node: nextNodeDef, edge } of nextNodes) {\n\t\t\t\tawait this.runtime.applyEdgeTransform(edge, result, nextNodeDef, context)\n\t\t\t\tconst isReady = await this.isReadyForFanIn(runId, blueprint, nextNodeDef.id)\n\t\t\t\tif (isReady) {\n\t\t\t\t\tconsole.log(`[Adapter] Node '${nextNodeDef.id}' is ready. Enqueuing job.`)\n\t\t\t\t\tawait this.enqueueJob({ runId, blueprintId, nodeId: nextNodeDef.id })\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(`[Adapter] Node '${nextNodeDef.id}' is waiting for other predecessors to complete.`)\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error: any) {\n\t\t\tconst reason = error.message || 'Unknown execution error'\n\t\t\tconsole.error(`[Adapter] FATAL: Job for node '${nodeId}' failed for Run ID '${runId}': ${reason}`)\n\t\t\tawait this.publishFinalResult(runId, { status: 'failed', reason })\n\t\t}\n\t}\n\n\t/**\n\t * Encapsulates the fan-in join logic using the coordination store.\n\t */\n\tprotected async isReadyForFanIn(runId: string, blueprint: WorkflowBlueprint, targetNodeId: string): Promise<boolean> {\n\t\tconst targetNode = blueprint.nodes.find((n) => n.id === targetNodeId)\n\t\tif (!targetNode) {\n\t\t\tthrow new Error(`Node '${targetNodeId}' not found in blueprint`)\n\t\t}\n\t\tconst joinStrategy = targetNode.config?.joinStrategy || 'all'\n\t\tconst predecessors = blueprint.edges.filter((e) => e.target === targetNodeId)\n\n\t\tif (predecessors.length <= 1) {\n\t\t\treturn true\n\t\t}\n\n\t\tif (joinStrategy === 'any') {\n\t\t\tconst lockKey = `flowcraft:joinlock:${runId}:${targetNodeId}`\n\t\t\treturn await this.store.setIfNotExist(lockKey, 'locked', 3600)\n\t\t} else {\n\t\t\tconst fanInKey = `flowcraft:fanin:${runId}:${targetNodeId}`\n\t\t\tconst readyCount = await this.store.increment(fanInKey, 3600)\n\t\t\tif (readyCount >= predecessors.length) {\n\t\t\t\tawait this.store.delete(fanInKey)\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Reconciles the state of a workflow run. It inspects the persisted\n\t * context to find completed nodes, determines the next set of executable\n\t * nodes (the frontier), and enqueues jobs for them if they aren't\n\t * already running. This is the core of the resume functionality.\n\t *\n\t * @param runId The unique ID of the workflow execution to reconcile.\n\t * @returns The set of node IDs that were enqueued for execution.\n\t */\n\tpublic async reconcile(runId: string): Promise<Set<string>> {\n\t\tconst context = this.createContext(runId)\n\t\tconst blueprintId = (await context.get('blueprintId' as any)) as string | undefined\n\n\t\tif (!blueprintId) {\n\t\t\tthrow new Error(`Cannot reconcile runId '${runId}': blueprintId not found in context.`)\n\t\t}\n\t\tconst blueprint = this.runtime.options.blueprints?.[blueprintId]\n\t\tif (!blueprint) {\n\t\t\tthrow new Error(`Cannot reconcile runId '${runId}': Blueprint with ID '${blueprintId}' not found.`)\n\t\t}\n\n\t\tconst state = await context.toJSON()\n\t\t// filter out internal keys\n\t\tconst completedNodes = new Set(Object.keys(state).filter((k) => blueprint.nodes.some((n) => n.id === k)))\n\n\t\tconst frontier = this.calculateResumedFrontier(blueprint, completedNodes)\n\n\t\tconst enqueuedNodes = new Set<string>()\n\t\tfor (const nodeId of frontier) {\n\t\t\tconst nodeDef = blueprint.nodes.find((n) => n.id === nodeId)\n\t\t\tconst joinStrategy = nodeDef?.config?.joinStrategy || 'all'\n\n\t\t\tlet shouldEnqueue = false\n\n\t\t\tif (joinStrategy === 'any') {\n\t\t\t\t// acquire the permanent join lock\n\t\t\t\tconst lockKey = `flowcraft:joinlock:${runId}:${nodeId}`\n\t\t\t\tif (await this.store.setIfNotExist(lockKey, 'locked-by-reconcile', 3600)) {\n\t\t\t\t\tshouldEnqueue = true\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(`[Adapter] Reconciling: Node '${nodeId}' is an 'any' join and is already locked.`, { runId })\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// 'all' joins and single-predecessor nodes use a temporary lock\n\t\t\t\tconst lockKey = `flowcraft:nodelock:${runId}:${nodeId}`\n\t\t\t\tif (await this.store.setIfNotExist(lockKey, 'locked', 120)) {\n\t\t\t\t\tshouldEnqueue = true\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(`[Adapter] Reconciling: Node '${nodeId}' is already locked.`, { runId })\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (shouldEnqueue) {\n\t\t\t\tconsole.log(`[Adapter] Reconciling: Enqueuing ready job for node '${nodeId}'`, { runId })\n\t\t\t\tawait this.enqueueJob({ runId, blueprintId: blueprint.id, nodeId })\n\t\t\t\tenqueuedNodes.add(nodeId)\n\t\t\t}\n\t\t}\n\n\t\treturn enqueuedNodes\n\t}\n\n\tprivate calculateResumedFrontier(blueprint: WorkflowBlueprint, completedNodes: Set<string>): Set<string> {\n\t\tconst newFrontier = new Set<string>()\n\t\tconst allPredecessors = new Map<string, Set<string>>()\n\t\t// (logic extracted from the GraphTraverser)\n\t\tfor (const node of blueprint.nodes) {\n\t\t\tallPredecessors.set(node.id, new Set())\n\t\t}\n\t\tfor (const edge of blueprint.edges) {\n\t\t\tallPredecessors.get(edge.target)?.add(edge.source)\n\t\t}\n\n\t\tfor (const node of blueprint.nodes) {\n\t\t\tif (completedNodes.has(node.id)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst predecessors = allPredecessors.get(node.id) ?? new Set()\n\t\t\tif (predecessors.size === 0 && !completedNodes.has(node.id)) {\n\t\t\t\tnewFrontier.add(node.id)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst joinStrategy = node.config?.joinStrategy || 'all'\n\t\t\tconst completedPredecessors = [...predecessors].filter((p) => completedNodes.has(p))\n\n\t\t\tconst isReady =\n\t\t\t\tjoinStrategy === 'any' ? completedPredecessors.length > 0 : completedPredecessors.length === predecessors.size\n\n\t\t\tif (isReady) {\n\t\t\t\tnewFrontier.add(node.id)\n\t\t\t}\n\t\t}\n\t\treturn newFrontier\n\t}\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/node.ts"],"names":[],"mappings":";AAGO,SAAS,YAAY,IAAA,EAA8B;AACzD,EAAA,OAAO,OAAO,IAAA,KAAS,UAAA,IAAc,CAAC,CAAC,KAAK,SAAA,EAAW,IAAA;AACxD;AAOO,IAAe,WAAf,MAML;AAAA;AAAA;AAAA;AAAA,EAID,YAAsB,MAAA,EAA8B;AAA9B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrD,MAAM,KAAK,OAAA,EAAqE;AAC/E,IAAA,OAAO,OAAA,CAAQ,KAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,IAAA,CACL,UAAA,EACA,QAAA,EACwC;AACxC,IAAA,OAAO,UAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAA,CACL,KAAA,EACA,QAAA,EACuD;AAEvD,IAAA,MAAM,KAAA;AAAA,EACP;AACD","file":"chunk-5QMPFUKA.js","sourcesContent":["import type { NodeClass, NodeContext, NodeResult, RuntimeDependencies } from './types'\n\n/** A type guard to reliably distinguish a NodeClass from a NodeFunction. */\nexport function isNodeClass(impl: any): impl is NodeClass {\n\treturn typeof impl === 'function' && !!impl.prototype?.exec\n}\n\n/**\n * A structured, class-based node for complex logic with a safe, granular lifecycle.\n * This class is generic, allowing implementations to specify the exact context\n * and dependency types they expect.\n */\nexport abstract class BaseNode<\n\tTContext extends Record<string, any> = Record<string, any>,\n\tTDependencies extends RuntimeDependencies = RuntimeDependencies,\n\tTInput = any,\n\tTOutput = any,\n\tTAction extends string = string,\n> {\n\t/**\n\t * @param params Static parameters for this node instance, passed from the blueprint.\n\t */\n\tconstructor(protected params?: Record<string, any>) {}\n\n\t/**\n\t * Phase 1: Gathers and prepares data for execution. This phase is NOT retried on failure.\n\t * @param context The node's execution context.\n\t * @returns The data needed for the `exec` phase.\n\t */\n\tasync prep(context: NodeContext<TContext, TDependencies, TInput>): Promise<any> {\n\t\treturn context.input\n\t}\n\n\t/**\n\t * Phase 2: Performs the core, isolated logic. This is the ONLY phase that is retried.\n\t * @param prepResult The data returned from the `prep` phase.\n\t * @param context The node's execution context.\n\t */\n\tabstract exec(\n\t\tprepResult: any,\n\t\tcontext: NodeContext<TContext, TDependencies, TInput>,\n\t): Promise<Omit<NodeResult<TOutput, TAction>, 'error'>>\n\n\t/**\n\t * Phase 3: Processes the result and saves state. This phase is NOT retried.\n\t * @param execResult The successful result from the `exec` or `fallback` phase.\n\t * @param _context The node's execution context.\n\t */\n\tasync post(\n\t\texecResult: Omit<NodeResult<TOutput, TAction>, 'error'>,\n\t\t_context: NodeContext<TContext, TDependencies, TInput>,\n\t): Promise<NodeResult<TOutput, TAction>> {\n\t\treturn execResult\n\t}\n\n\t/**\n\t * An optional safety net that runs if all `exec` retries fail.\n\t * @param error The final error from the last `exec` attempt.\n\t * @param _context The node's execution context.\n\t */\n\tasync fallback(\n\t\terror: Error,\n\t\t_context: NodeContext<TContext, TDependencies, TInput>,\n\t): Promise<Omit<NodeResult<TOutput, TAction>, 'error'>> {\n\t\t// By default, re-throw the error, failing the node.\n\t\tthrow error\n\t}\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/flow.ts"],"names":[],"mappings":"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","file":"chunk-5ZWYSKMH.js","sourcesContent":["import { isNodeClass } from './node'\nimport type { EdgeDefinition, NodeClass, NodeDefinition, NodeFunction, WorkflowBlueprint } from './types'\n\n/**\n * Generates a deterministic hash for a function based on its source code.\n */\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\treturn Math.abs(hash).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}>\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}\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 * @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 * @param options.inputKey The key in the context that holds the input array for the batch.\n\t * @param options.outputKey The key in the context where the array of results will be stored.\n\t * @returns The Flow instance for chaining.\n\t */\n\tbatch<TInput = any, TOutput = any, TAction extends string = string>(\n\t\tid: string,\n\t\tworker:\n\t\t\t| NodeFunction<TContext, TDependencies, TInput, TOutput, TAction>\n\t\t\t| NodeClass<TContext, TDependencies, TInput, TOutput, TAction>,\n\t\toptions: {\n\t\t\t/** The key in the context that holds the input array for the batch. */\n\t\t\tinputKey: string\n\t\t\t/** The key in the context where the array of results will be stored. */\n\t\t\toutputKey: string\n\t\t},\n\t): this {\n\t\tconst { inputKey, outputKey } = options\n\t\tconst scatterId = `${id}_scatter`\n\t\tconst gatherId = `${id}_gather`\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,\n\t\t\tparams: { workerUsesKey, outputKey, gatherNodeId: gatherId },\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 },\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\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 })\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\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\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\treturn this.blueprint as WorkflowBlueprint\n\t}\n\n\tgetFunctionRegistry() {\n\t\treturn this.functionRegistry\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"]}
|