flowcraft 2.4.0 → 2.6.0
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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/analysis.d.ts +9 -2
- package/dist/analysis.js +1 -1
- package/dist/chunk-27STBUGG.js +44 -0
- package/dist/chunk-27STBUGG.js.map +1 -0
- package/dist/{chunk-OZZP5YI6.js → chunk-2ISKDTSN.js} +3 -3
- package/dist/{chunk-OZZP5YI6.js.map → chunk-2ISKDTSN.js.map} +1 -1
- package/dist/{chunk-OO3FF3DF.js → chunk-5BOUGXZO.js} +8 -8
- package/dist/chunk-5BOUGXZO.js.map +1 -0
- package/dist/{chunk-J3HZD5ES.js → chunk-5XPW6YEP.js} +54 -15
- package/dist/chunk-5XPW6YEP.js.map +1 -0
- package/dist/{chunk-VN2JKKAE.js → chunk-6MGLU3UU.js} +3 -3
- package/dist/{chunk-VN2JKKAE.js.map → chunk-6MGLU3UU.js.map} +1 -1
- package/dist/{chunk-7PBANEG3.js → chunk-7FIOROIR.js} +5 -11
- package/dist/chunk-7FIOROIR.js.map +1 -0
- package/dist/{chunk-G5BGBPFP.js → chunk-FBPY44WL.js} +3 -3
- package/dist/{chunk-G5BGBPFP.js.map → chunk-FBPY44WL.js.map} +1 -1
- package/dist/chunk-HNHM3FDK.js +52 -0
- package/dist/chunk-HNHM3FDK.js.map +1 -0
- package/dist/chunk-I53JB2KW.js +26 -0
- package/dist/chunk-I53JB2KW.js.map +1 -0
- package/dist/{chunk-GVF7GQXQ.js → chunk-IDTYHLDQ.js} +3 -3
- package/dist/chunk-IDTYHLDQ.js.map +1 -0
- package/dist/{chunk-EUJWJWFA.js → chunk-IKOTX22J.js} +3 -3
- package/dist/{chunk-EUJWJWFA.js.map → chunk-IKOTX22J.js.map} +1 -1
- package/dist/{chunk-GIJOZ3AN.js → chunk-JLDHCI2O.js} +5 -5
- package/dist/{chunk-GIJOZ3AN.js.map → chunk-JLDHCI2O.js.map} +1 -1
- package/dist/{chunk-KXXEA5VE.js → chunk-N4NLAIEN.js} +3 -3
- package/dist/{chunk-KXXEA5VE.js.map → chunk-N4NLAIEN.js.map} +1 -1
- package/dist/{chunk-CHG6O6JX.js → chunk-OPRR4TAO.js} +14 -12
- package/dist/chunk-OPRR4TAO.js.map +1 -0
- package/dist/{chunk-MCGK3FXQ.js → chunk-SEI4Z3MO.js} +3 -3
- package/dist/{chunk-MCGK3FXQ.js.map → chunk-SEI4Z3MO.js.map} +1 -1
- package/dist/{chunk-K6LPGUPR.js → chunk-UXIASXSG.js} +7 -7
- package/dist/chunk-UXIASXSG.js.map +1 -0
- package/dist/chunk-XDI4TJHA.js +95 -0
- package/dist/chunk-XDI4TJHA.js.map +1 -0
- package/dist/{chunk-NDWVLU7J.js → chunk-XTW36KQZ.js} +3 -3
- package/dist/{chunk-NDWVLU7J.js.map → chunk-XTW36KQZ.js.map} +1 -1
- package/dist/{chunk-233SESC2.js → chunk-ZLW4QOTS.js} +74 -3
- package/dist/chunk-ZLW4QOTS.js.map +1 -0
- package/dist/container-factory.d.ts +1 -1
- package/dist/container-factory.js +5 -5
- package/dist/context.d.ts +21 -2
- package/dist/context.js +1 -1
- package/dist/error-mapper.d.ts +15 -0
- package/dist/error-mapper.js +4 -0
- package/dist/error-mapper.js.map +1 -0
- package/dist/evaluator.d.ts +1 -1
- package/dist/flow.d.ts +5 -5
- package/dist/flow.js +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +20 -18
- package/dist/linter.d.ts +1 -1
- package/dist/linter.js +2 -2
- package/dist/logger.d.ts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/nodes/batch-gather.d.ts +1 -1
- package/dist/nodes/batch-scatter.d.ts +1 -1
- package/dist/nodes/sleep.d.ts +1 -1
- package/dist/nodes/sleep.js +1 -1
- package/dist/nodes/subflow.d.ts +1 -1
- package/dist/nodes/subflow.js +6 -6
- package/dist/nodes/wait.d.ts +1 -1
- package/dist/nodes/wait.js +1 -1
- package/dist/nodes/webhook.d.ts +13 -0
- package/dist/nodes/webhook.js +4 -0
- package/dist/nodes/webhook.js.map +1 -0
- package/dist/runtime/adapter.d.ts +13 -1
- package/dist/runtime/adapter.js +15 -14
- package/dist/runtime/execution-context.d.ts +1 -1
- package/dist/runtime/execution-context.js +3 -3
- package/dist/runtime/executors.d.ts +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +15 -14
- package/dist/runtime/node-executor-factory.d.ts +1 -1
- package/dist/runtime/orchestrator.d.ts +1 -1
- package/dist/runtime/orchestrator.js +4 -4
- package/dist/runtime/orchestrators/step-by-step.d.ts +1 -1
- package/dist/runtime/orchestrators/utils.d.ts +1 -1
- package/dist/runtime/runtime.d.ts +1 -1
- package/dist/runtime/runtime.js +14 -13
- package/dist/runtime/scheduler.d.ts +1 -1
- package/dist/runtime/state.d.ts +1 -1
- package/dist/runtime/state.js +2 -2
- package/dist/runtime/traverser.d.ts +1 -1
- package/dist/runtime/traverser.js +2 -2
- package/dist/runtime/types.d.ts +1 -1
- package/dist/runtime/workflow-logic-handler.d.ts +1 -1
- package/dist/runtime/workflow-logic-handler.js +2 -2
- package/dist/sanitizer.d.ts +1 -1
- package/dist/sdk.d.ts +29 -0
- package/dist/sdk.js +20 -0
- package/dist/sdk.js.map +1 -0
- package/dist/serializer.d.ts +1 -1
- package/dist/testing/event-logger.d.ts +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +17 -16
- package/dist/testing/run-with-trace.d.ts +1 -1
- package/dist/testing/run-with-trace.js +16 -15
- package/dist/testing/stepper.d.ts +1 -1
- package/dist/testing/stepper.js +6 -6
- package/dist/{types-DWCZW68f.d.ts → types-B-Drn84R.d.ts} +35 -3
- package/dist/types.d.ts +1 -1
- package/package.json +59 -55
- package/dist/chunk-233SESC2.js.map +0 -1
- package/dist/chunk-7PBANEG3.js.map +0 -1
- package/dist/chunk-CHG6O6JX.js.map +0 -1
- package/dist/chunk-GVF7GQXQ.js.map +0 -1
- package/dist/chunk-J3HZD5ES.js.map +0 -1
- package/dist/chunk-K6LPGUPR.js.map +0 -1
- package/dist/chunk-LJ4COM7S.js +0 -20
- package/dist/chunk-LJ4COM7S.js.map +0 -1
- package/dist/chunk-OO3FF3DF.js.map +0 -1
- package/dist/chunk-R3HQXIEL.js +0 -49
- package/dist/chunk-R3HQXIEL.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Feathers
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Build complex, multi-step processes with a lightweight, composable, and type-saf
|
|
|
11
11
|
- **Zero Dependencies**: Lightweight and dependency-free, ensuring easy integration in any runtime.
|
|
12
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
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/
|
|
14
|
+
- **Progressive Scalability**: Run [in-memory](https://flowcraft.js.org/guide/fluent) or scale to [distributed systems](https://flowcraft.js.org/guide/distributed-execution) using the same blueprint.
|
|
15
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
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
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.
|
package/dist/analysis.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as WorkflowBlueprint, z as FlowcraftEvent } from './types-B-Drn84R.js';
|
|
2
2
|
import './errors.js';
|
|
3
3
|
import './container.js';
|
|
4
4
|
|
|
@@ -36,6 +36,13 @@ declare function checkForCycles(blueprint: WorkflowBlueprint): Cycles;
|
|
|
36
36
|
* @returns Mermaid syntax string for the flowchart
|
|
37
37
|
*/
|
|
38
38
|
declare function generateMermaid(blueprint: WorkflowBlueprint): string;
|
|
39
|
+
/**
|
|
40
|
+
* Generates Mermaid diagram syntax from a WorkflowBlueprint with execution history styling
|
|
41
|
+
* @param blueprint The WorkflowBlueprint object containing nodes and edges
|
|
42
|
+
* @param events Array of FlowcraftEvent objects from the workflow execution
|
|
43
|
+
* @returns Mermaid syntax string for the flowchart with execution path highlighting
|
|
44
|
+
*/
|
|
45
|
+
declare function generateMermaidForRun(blueprint: WorkflowBlueprint, events: FlowcraftEvent[]): string;
|
|
39
46
|
/**
|
|
40
47
|
* Analyzes a workflow blueprint and returns comprehensive analysis
|
|
41
48
|
* @param blueprint The WorkflowBlueprint object containing nodes and edges
|
|
@@ -43,4 +50,4 @@ declare function generateMermaid(blueprint: WorkflowBlueprint): string;
|
|
|
43
50
|
*/
|
|
44
51
|
declare function analyzeBlueprint(blueprint: WorkflowBlueprint): BlueprintAnalysis;
|
|
45
52
|
|
|
46
|
-
export { type BlueprintAnalysis, type Cycles, analyzeBlueprint, checkForCycles, generateMermaid };
|
|
53
|
+
export { type BlueprintAnalysis, type Cycles, analyzeBlueprint, checkForCycles, generateMermaid, generateMermaidForRun };
|
package/dist/analysis.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { analyzeBlueprint, checkForCycles, generateMermaid } from './chunk-
|
|
1
|
+
export { analyzeBlueprint, checkForCycles, generateMermaid, generateMermaidForRun } from './chunk-ZLW4QOTS.js';
|
|
2
2
|
//# sourceMappingURL=analysis.js.map
|
|
3
3
|
//# sourceMappingURL=analysis.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { FlowcraftError } from './chunk-BCRWXTWX.js';
|
|
2
|
+
|
|
3
|
+
// src/error-mapper.ts
|
|
4
|
+
function createErrorMapper(manifestBlueprints) {
|
|
5
|
+
const locationMap = /* @__PURE__ */ new Map();
|
|
6
|
+
for (const blueprint of Object.values(manifestBlueprints)) {
|
|
7
|
+
for (const node of blueprint.nodes) {
|
|
8
|
+
if (node._sourceLocation) {
|
|
9
|
+
locationMap.set(node.id, node._sourceLocation);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
for (const edge of blueprint.edges) {
|
|
13
|
+
if (edge._sourceLocation) {
|
|
14
|
+
const edgeKey = `${edge.source}-${edge.target}`;
|
|
15
|
+
locationMap.set(edgeKey, edge._sourceLocation);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return function mapError(error) {
|
|
20
|
+
if (error instanceof FlowcraftError && error.nodeId) {
|
|
21
|
+
const location = locationMap.get(error.nodeId);
|
|
22
|
+
if (location) {
|
|
23
|
+
return new Error(
|
|
24
|
+
`Workflow error at ${location.file}:${location.line}:${location.column}. Original error: ${error.message}`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const nodeIdMatch = error.message.match(/nodeId[:\s]+([^\s,]+)/i);
|
|
29
|
+
if (nodeIdMatch) {
|
|
30
|
+
const nodeId = nodeIdMatch[1];
|
|
31
|
+
const location = locationMap.get(nodeId);
|
|
32
|
+
if (location) {
|
|
33
|
+
return new Error(
|
|
34
|
+
`Workflow error at ${location.file}:${location.line}:${location.column}. Original error: ${error.message}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return error;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { createErrorMapper };
|
|
43
|
+
//# sourceMappingURL=chunk-27STBUGG.js.map
|
|
44
|
+
//# sourceMappingURL=chunk-27STBUGG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/error-mapper.ts"],"names":[],"mappings":";;;AAWO,SAAS,kBAAkB,kBAAA,EAAuD;AACxF,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAA4B;AAGpD,EAAA,KAAA,MAAW,SAAA,IAAa,MAAA,CAAO,MAAA,CAAO,kBAAkB,CAAA,EAAG;AAC1D,IAAA,KAAA,MAAW,IAAA,IAAQ,UAAU,KAAA,EAAO;AACnC,MAAA,IAAI,KAAK,eAAA,EAAiB;AACzB,QAAA,WAAA,CAAY,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,IAAA,CAAK,eAAe,CAAA;AAAA,MAC9C;AAAA,IACD;AACA,IAAA,KAAA,MAAW,IAAA,IAAQ,UAAU,KAAA,EAAO;AACnC,MAAA,IAAI,KAAK,eAAA,EAAiB;AACzB,QAAA,MAAM,UAAU,CAAA,EAAG,IAAA,CAAK,MAAM,CAAA,CAAA,EAAI,KAAK,MAAM,CAAA,CAAA;AAC7C,QAAA,WAAA,CAAY,GAAA,CAAI,OAAA,EAAS,IAAA,CAAK,eAAe,CAAA;AAAA,MAC9C;AAAA,IACD;AAAA,EACD;AAEA,EAAA,OAAO,SAAS,SAAS,KAAA,EAAqB;AAC7C,IAAA,IAAI,KAAA,YAAiB,cAAA,IAAkB,KAAA,CAAM,MAAA,EAAQ;AACpD,MAAA,MAAM,QAAA,GAAW,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA;AAC7C,MAAA,IAAI,QAAA,EAAU;AACb,QAAA,OAAO,IAAI,KAAA;AAAA,UACV,CAAA,kBAAA,EAAqB,QAAA,CAAS,IAAI,CAAA,CAAA,EAAI,QAAA,CAAS,IAAI,CAAA,CAAA,EAAI,QAAA,CAAS,MAAM,CAAA,kBAAA,EAAqB,KAAA,CAAM,OAAO,CAAA;AAAA,SACzG;AAAA,MACD;AAAA,IACD;AAGA,IAAA,MAAM,WAAA,GAAc,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,wBAAwB,CAAA;AAChE,IAAA,IAAI,WAAA,EAAa;AAChB,MAAA,MAAM,MAAA,GAAS,YAAY,CAAC,CAAA;AAC5B,MAAA,MAAM,QAAA,GAAW,WAAA,CAAY,GAAA,CAAI,MAAM,CAAA;AACvC,MAAA,IAAI,QAAA,EAAU;AACb,QAAA,OAAO,IAAI,KAAA;AAAA,UACV,CAAA,kBAAA,EAAqB,QAAA,CAAS,IAAI,CAAA,CAAA,EAAI,QAAA,CAAS,IAAI,CAAA,CAAA,EAAI,QAAA,CAAS,MAAM,CAAA,kBAAA,EAAqB,KAAA,CAAM,OAAO,CAAA;AAAA,SACzG;AAAA,MACD;AAAA,IACD;AAEA,IAAA,OAAO,KAAA;AAAA,EACR,CAAA;AACD","file":"chunk-27STBUGG.js","sourcesContent":["import { FlowcraftError } from './errors'\nimport type { SourceLocation, WorkflowBlueprint } from './types'\n\n/**\n * Creates an error mapper function that enhances runtime errors with source location information.\n * The mapper looks up node IDs in the provided manifest blueprints and returns enhanced errors\n * that point to the original TypeScript source code.\n *\n * @param manifestBlueprints - The compiled blueprint manifest containing source location data\n * @returns A function that maps errors to enhanced errors with source location information\n */\nexport function createErrorMapper(manifestBlueprints: Record<string, WorkflowBlueprint>) {\n\tconst locationMap = new Map<string, SourceLocation>()\n\n\t// build a quick lookup map\n\tfor (const blueprint of Object.values(manifestBlueprints)) {\n\t\tfor (const node of blueprint.nodes) {\n\t\t\tif (node._sourceLocation) {\n\t\t\t\tlocationMap.set(node.id, node._sourceLocation)\n\t\t\t}\n\t\t}\n\t\tfor (const edge of blueprint.edges) {\n\t\t\tif (edge._sourceLocation) {\n\t\t\t\tconst edgeKey = `${edge.source}-${edge.target}`\n\t\t\t\tlocationMap.set(edgeKey, edge._sourceLocation)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn function mapError(error: Error): Error {\n\t\tif (error instanceof FlowcraftError && error.nodeId) {\n\t\t\tconst location = locationMap.get(error.nodeId)\n\t\t\tif (location) {\n\t\t\t\treturn new Error(\n\t\t\t\t\t`Workflow error at ${location.file}:${location.line}:${location.column}. Original error: ${error.message}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// try to extract nodeId from error message\n\t\tconst nodeIdMatch = error.message.match(/nodeId[:\\s]+([^\\s,]+)/i)\n\t\tif (nodeIdMatch) {\n\t\t\tconst nodeId = nodeIdMatch[1]\n\t\t\tconst location = locationMap.get(nodeId)\n\t\t\tif (location) {\n\t\t\t\treturn new Error(\n\t\t\t\t\t`Workflow error at ${location.file}:${location.line}:${location.column}. Original error: ${error.message}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\treturn error\n\t}\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DefaultOrchestrator } from './chunk-
|
|
1
|
+
import { DefaultOrchestrator } from './chunk-XTW36KQZ.js';
|
|
2
2
|
import { NullLogger } from './chunk-4PELJWF7.js';
|
|
3
3
|
import { JsonSerializer } from './chunk-CYHZ2YVH.js';
|
|
4
4
|
import { DIContainer, ServiceTokens } from './chunk-WWGFIYKW.js';
|
|
@@ -21,5 +21,5 @@ function createDefaultContainer(options = {}) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export { createDefaultContainer };
|
|
24
|
-
//# sourceMappingURL=chunk-
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
24
|
+
//# sourceMappingURL=chunk-2ISKDTSN.js.map
|
|
25
|
+
//# sourceMappingURL=chunk-2ISKDTSN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/container-factory.ts"],"names":[],"mappings":";;;;;;;AA4BO,SAAS,sBAAA,CACf,OAAA,GAA2C,EAAC,EAC9B;AACd,EAAA,MAAM,SAAA,GAAY,IAAI,WAAA,EAAY;AAElC,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,MAAA,EAAQ,QAAQ,MAAA,IAAU,IAAI,YAAY,CAAA;AAC3E,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,UAAA,EAAY,QAAQ,UAAA,IAAc,IAAI,gBAAgB,CAAA;AACvF,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,SAAA,EAAW,QAAQ,SAAA,IAAa,IAAI,mBAAmB,CAAA;AACxF,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,QAAA,EAAU,QAAQ,QAAA,IAAY,EAAE,MAAM,YAAY;AAAA,EAAC,GAAG,CAAA;AACvF,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc,EAAE,CAAA;AACrE,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,YAAA,EAAc,OAAA,CAAQ,QAAA,IAAY,EAAE,CAAA;AACrE,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,iBAAA,EAAmB,OAAA,CAAQ,UAAA,IAAc,EAAE,CAAA;AAC5E,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,YAAA,EAAc,OAAA,CAAQ,YAAA,IAAiB,EAAoB,CAAA;AAE5F,EAAA,SAAA,CAAU,gBAAgB,aAAA,CAAc,YAAA,EAAc,MAAM,IAAI,qBAAqB,CAAA;AAErF,EAAA,OAAO,SAAA;AACR","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/container-factory.ts"],"names":[],"mappings":";;;;;;;AA4BO,SAAS,sBAAA,CACf,OAAA,GAA2C,EAAC,EAC9B;AACd,EAAA,MAAM,SAAA,GAAY,IAAI,WAAA,EAAY;AAElC,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,MAAA,EAAQ,QAAQ,MAAA,IAAU,IAAI,YAAY,CAAA;AAC3E,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,UAAA,EAAY,QAAQ,UAAA,IAAc,IAAI,gBAAgB,CAAA;AACvF,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,SAAA,EAAW,QAAQ,SAAA,IAAa,IAAI,mBAAmB,CAAA;AACxF,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,QAAA,EAAU,QAAQ,QAAA,IAAY,EAAE,MAAM,YAAY;AAAA,EAAC,GAAG,CAAA;AACvF,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc,EAAE,CAAA;AACrE,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,YAAA,EAAc,OAAA,CAAQ,QAAA,IAAY,EAAE,CAAA;AACrE,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,iBAAA,EAAmB,OAAA,CAAQ,UAAA,IAAc,EAAE,CAAA;AAC5E,EAAA,SAAA,CAAU,SAAS,aAAA,CAAc,YAAA,EAAc,OAAA,CAAQ,YAAA,IAAiB,EAAoB,CAAA;AAE5F,EAAA,SAAA,CAAU,gBAAgB,aAAA,CAAc,YAAA,EAAc,MAAM,IAAI,qBAAqB,CAAA;AAErF,EAAA,OAAO,SAAA;AACR","file":"chunk-2ISKDTSN.js","sourcesContent":["import { DIContainer, ServiceTokens } from './container'\nimport { PropertyEvaluator } from './evaluator'\nimport { NullLogger } from './logger'\nimport { DefaultOrchestrator } from './runtime/orchestrator'\nimport { JsonSerializer } from './serializer'\nimport type {\n\tIEvaluator,\n\tIEventBus,\n\tILogger,\n\tISerializer,\n\tMiddleware,\n\tNodeClass,\n\tNodeFunction,\n\tRuntimeDependencies,\n\tWorkflowBlueprint,\n} from './types'\n\nexport interface ContainerOptions<TDependencies extends RuntimeDependencies = RuntimeDependencies> {\n\tlogger?: ILogger\n\tserializer?: ISerializer\n\tevaluator?: IEvaluator\n\teventBus?: IEventBus\n\tmiddleware?: Middleware[]\n\tregistry?: Record<string, NodeFunction | NodeClass>\n\tblueprints?: Record<string, WorkflowBlueprint>\n\tdependencies?: TDependencies\n}\n\nexport function createDefaultContainer<TDependencies extends RuntimeDependencies = RuntimeDependencies>(\n\toptions: ContainerOptions<TDependencies> = {},\n): DIContainer {\n\tconst container = new DIContainer()\n\n\tcontainer.register(ServiceTokens.Logger, options.logger || new NullLogger())\n\tcontainer.register(ServiceTokens.Serializer, options.serializer || new JsonSerializer())\n\tcontainer.register(ServiceTokens.Evaluator, options.evaluator || new PropertyEvaluator())\n\tcontainer.register(ServiceTokens.EventBus, options.eventBus || { emit: async () => {} })\n\tcontainer.register(ServiceTokens.Middleware, options.middleware || [])\n\tcontainer.register(ServiceTokens.NodeRegistry, options.registry || {})\n\tcontainer.register(ServiceTokens.BlueprintRegistry, options.blueprints || {})\n\tcontainer.register(ServiceTokens.Dependencies, options.dependencies || ({} as TDependencies))\n\n\tcontainer.registerFactory(ServiceTokens.Orchestrator, () => new DefaultOrchestrator())\n\n\treturn container\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AsyncContextView, Context } from './chunk-
|
|
1
|
+
import { TrackedAsyncContext, AsyncContextView, Context } from './chunk-XDI4TJHA.js';
|
|
2
2
|
import { FlowcraftError } from './chunk-BCRWXTWX.js';
|
|
3
3
|
|
|
4
4
|
// src/runtime/state.ts
|
|
@@ -11,7 +11,7 @@ var WorkflowState = class {
|
|
|
11
11
|
_awaitingNodeIds = /* @__PURE__ */ new Set();
|
|
12
12
|
_awaitingDetails = /* @__PURE__ */ new Map();
|
|
13
13
|
constructor(initialData) {
|
|
14
|
-
this.context = new AsyncContextView(new Context(initialData));
|
|
14
|
+
this.context = new TrackedAsyncContext(new AsyncContextView(new Context(initialData)));
|
|
15
15
|
if (initialData._awaitingNodeIds) {
|
|
16
16
|
this._isAwaiting = true;
|
|
17
17
|
const awaitingIds = initialData._awaitingNodeIds;
|
|
@@ -45,7 +45,7 @@ var WorkflowState = class {
|
|
|
45
45
|
...flowcraftError,
|
|
46
46
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
47
47
|
originalError: error
|
|
48
|
-
//
|
|
48
|
+
// legacy compatibility
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
clearError(nodeId) {
|
|
@@ -66,14 +66,14 @@ var WorkflowState = class {
|
|
|
66
66
|
getAnyFallbackExecuted() {
|
|
67
67
|
return this.anyFallbackExecuted;
|
|
68
68
|
}
|
|
69
|
-
markAsAwaiting(nodeId, details) {
|
|
69
|
+
async markAsAwaiting(nodeId, details) {
|
|
70
70
|
this._isAwaiting = true;
|
|
71
71
|
this._awaitingNodeIds.add(nodeId);
|
|
72
72
|
if (details) {
|
|
73
73
|
this._awaitingDetails.set(nodeId, details);
|
|
74
74
|
}
|
|
75
|
-
this.context.set("_awaitingNodeIds", Array.from(this._awaitingNodeIds));
|
|
76
|
-
this.context.set("_awaitingDetails", Object.fromEntries(this._awaitingDetails));
|
|
75
|
+
await this.context.set("_awaitingNodeIds", Array.from(this._awaitingNodeIds));
|
|
76
|
+
await this.context.set("_awaitingDetails", Object.fromEntries(this._awaitingDetails));
|
|
77
77
|
}
|
|
78
78
|
isAwaiting() {
|
|
79
79
|
return this._isAwaiting && this._awaitingNodeIds.size > 0;
|
|
@@ -124,5 +124,5 @@ var WorkflowState = class {
|
|
|
124
124
|
};
|
|
125
125
|
|
|
126
126
|
export { WorkflowState };
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
128
|
-
//# sourceMappingURL=chunk-
|
|
127
|
+
//# sourceMappingURL=chunk-5BOUGXZO.js.map
|
|
128
|
+
//# sourceMappingURL=chunk-5BOUGXZO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/state.ts"],"names":[],"mappings":"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","file":"chunk-5BOUGXZO.js","sourcesContent":["import { AsyncContextView, Context as SyncContext, TrackedAsyncContext } from '../context'\nimport { FlowcraftError } from '../errors'\nimport type { IAsyncContext, ISerializer, WorkflowError, WorkflowResult } from '../types'\n\nexport class WorkflowState<TContext extends Record<string, any>> {\n\tprivate _completedNodes = new Set<string>()\n\tprivate errors: WorkflowError[] = []\n\tprivate anyFallbackExecuted = false\n\tprivate context: IAsyncContext<TContext>\n\tprivate _isAwaiting = false\n\tprivate _awaitingNodeIds = new Set<string>()\n\tprivate _awaitingDetails = new Map<string, any>()\n\n\tconstructor(initialData: Partial<TContext>) {\n\t\tthis.context = new TrackedAsyncContext(new AsyncContextView(new SyncContext<TContext>(initialData)))\n\t\tif ((initialData as any)._awaitingNodeIds) {\n\t\t\tthis._isAwaiting = true\n\t\t\tconst awaitingIds = (initialData as any)._awaitingNodeIds\n\t\t\tif (Array.isArray(awaitingIds)) {\n\t\t\t\tfor (const id of awaitingIds) {\n\t\t\t\t\tthis._awaitingNodeIds.add(id)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif ((initialData as any)._awaitingDetails) {\n\t\t\tthis._awaitingDetails = new Map(Object.entries((initialData as any)._awaitingDetails))\n\t\t}\n\t\tfor (const key of Object.keys(initialData)) {\n\t\t\tif (key.startsWith('_outputs.')) {\n\t\t\t\tconst nodeId = key.substring('_outputs.'.length)\n\t\t\t\tthis._completedNodes.add(nodeId)\n\t\t\t}\n\t\t}\n\t}\n\n\tasync addCompletedNode(nodeId: string, output: any) {\n\t\tthis._completedNodes.add(nodeId)\n\t\tawait this.context.set(`_outputs.${nodeId}` as any, output)\n\t}\n\n\taddError(nodeId: string, error: Error) {\n\t\tconst flowcraftError = new FlowcraftError(error.message, {\n\t\t\tcause: error,\n\t\t\tnodeId,\n\t\t\tisFatal: false,\n\t\t})\n\t\tthis.errors.push({\n\t\t\t...flowcraftError,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\toriginalError: error, // legacy compatibility\n\t\t})\n\t}\n\n\tclearError(nodeId: string) {\n\t\tthis.errors = this.errors.filter((err) => err.nodeId !== nodeId)\n\t}\n\n\tmarkFallbackExecuted() {\n\t\tthis.anyFallbackExecuted = true\n\t}\n\n\tgetContext(): IAsyncContext<TContext> {\n\t\treturn this.context\n\t}\n\n\tgetCompletedNodes(): Set<string> {\n\t\treturn new Set(this._completedNodes)\n\t}\n\n\tgetErrors(): WorkflowError[] {\n\t\treturn this.errors\n\t}\n\n\tgetAnyFallbackExecuted(): boolean {\n\t\treturn this.anyFallbackExecuted\n\t}\n\n\tasync markAsAwaiting(nodeId: string, details?: any): Promise<void> {\n\t\tthis._isAwaiting = true\n\t\tthis._awaitingNodeIds.add(nodeId)\n\t\tif (details) {\n\t\t\tthis._awaitingDetails.set(nodeId, details)\n\t\t}\n\t\tawait this.context.set('_awaitingNodeIds' as any, Array.from(this._awaitingNodeIds))\n\t\tawait this.context.set('_awaitingDetails' as any, Object.fromEntries(this._awaitingDetails))\n\t}\n\n\tisAwaiting(): boolean {\n\t\treturn this._isAwaiting && this._awaitingNodeIds.size > 0\n\t}\n\n\tgetAwaitingNodeIds(): string[] {\n\t\treturn Array.from(this._awaitingNodeIds)\n\t}\n\n\tgetAwaitingDetails(nodeId: string): any {\n\t\treturn this._awaitingDetails.get(nodeId)\n\t}\n\n\tclearAwaiting(nodeId?: string): void {\n\t\tif (nodeId) {\n\t\t\tthis._awaitingNodeIds.delete(nodeId)\n\t\t\tthis._awaitingDetails.delete(nodeId)\n\t\t} else {\n\t\t\tthis._awaitingNodeIds.clear()\n\t\t\tthis._awaitingDetails.clear()\n\t\t}\n\t\tthis._isAwaiting = this._awaitingNodeIds.size > 0\n\n\t\tif (this._awaitingNodeIds.size > 0) {\n\t\t\tthis.context.set('_awaitingNodeIds' as any, Array.from(this._awaitingNodeIds))\n\t\t\tthis.context.set('_awaitingDetails' as any, Object.fromEntries(this._awaitingDetails))\n\t\t} else {\n\t\t\tthis.context.delete('_awaitingNodeIds' as any)\n\t\t\tthis.context.delete('_awaitingDetails' as any)\n\t\t}\n\t}\n\n\tgetStatus(isTraversalComplete = false): WorkflowResult['status'] {\n\t\tif (this._isAwaiting) return 'awaiting'\n\t\tif (this.anyFallbackExecuted) return 'completed'\n\t\tif (this.errors.length > 0) return 'failed'\n\t\tif (isTraversalComplete) return 'completed'\n\t\treturn 'stalled'\n\t}\n\n\tasync toResult(serializer: ISerializer): Promise<WorkflowResult<TContext>> {\n\t\tconst contextJSON = (await this.context.toJSON()) as TContext\n\t\tif (!this._isAwaiting && (contextJSON as any)._awaitingNodeIds) {\n\t\t\tdelete (contextJSON as any)._awaitingNodeIds\n\t\t\tdelete (contextJSON as any)._awaitingDetails\n\t\t}\n\t\treturn {\n\t\t\tcontext: contextJSON,\n\t\t\tserializedContext: serializer.serialize(contextJSON),\n\t\t\tstatus: this.getStatus(),\n\t\t\terrors: this.errors.length > 0 ? this.errors : undefined,\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { FlowRuntime } from './chunk-
|
|
2
|
-
import { analyzeBlueprint } from './chunk-
|
|
1
|
+
import { FlowRuntime } from './chunk-OPRR4TAO.js';
|
|
2
|
+
import { analyzeBlueprint } from './chunk-ZLW4QOTS.js';
|
|
3
3
|
import { ConsoleLogger } from './chunk-4PELJWF7.js';
|
|
4
4
|
import { JsonSerializer } from './chunk-CYHZ2YVH.js';
|
|
5
|
+
import { TrackedAsyncContext } from './chunk-XDI4TJHA.js';
|
|
5
6
|
|
|
6
7
|
// src/runtime/adapter.ts
|
|
7
8
|
var BaseDistributedAdapter = class {
|
|
@@ -10,7 +11,14 @@ var BaseDistributedAdapter = class {
|
|
|
10
11
|
serializer;
|
|
11
12
|
logger;
|
|
12
13
|
constructor(options) {
|
|
13
|
-
|
|
14
|
+
const runtimeOptions = {
|
|
15
|
+
...options.runtimeOptions,
|
|
16
|
+
dependencies: {
|
|
17
|
+
...options.runtimeOptions.dependencies,
|
|
18
|
+
adapter: this
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
this.runtime = new FlowRuntime(runtimeOptions);
|
|
14
22
|
this.store = options.coordinationStore;
|
|
15
23
|
this.serializer = options.runtimeOptions.serializer || new JsonSerializer();
|
|
16
24
|
this.logger = options.runtimeOptions.logger || new ConsoleLogger();
|
|
@@ -43,23 +51,47 @@ var BaseDistributedAdapter = class {
|
|
|
43
51
|
return;
|
|
44
52
|
}
|
|
45
53
|
const context = this.createContext(runId);
|
|
54
|
+
const storedVersion = await context.get("blueprintVersion");
|
|
55
|
+
const currentVersion = blueprint.metadata?.version || null;
|
|
56
|
+
if (storedVersion !== currentVersion) {
|
|
57
|
+
const reason = `Blueprint version mismatch: stored version '${storedVersion}', current version '${currentVersion}'. Rejecting job to prevent state corruption.`;
|
|
58
|
+
this.logger.warn(`[Adapter] Version mismatch for run ${runId}, node ${nodeId}: ${reason}`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
46
61
|
const hasBlueprintId = await context.has("blueprintId");
|
|
47
62
|
if (!hasBlueprintId) {
|
|
48
63
|
await context.set("blueprintId", blueprintId);
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
await context.set("blueprintVersion", blueprint.metadata?.version || null);
|
|
65
|
+
const blueprintKey2 = `flowcraft:blueprint:${runId}`;
|
|
66
|
+
await this.store.setIfNotExist(blueprintKey2, blueprintId, 3600);
|
|
51
67
|
}
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
const joinLockKey = `flowcraft:joinlock:${runId}:${nodeId}`;
|
|
69
|
+
const fanInKey = `flowcraft:fanin:${runId}:${nodeId}`;
|
|
70
|
+
const blueprintKey = `flowcraft:blueprint:${runId}`;
|
|
71
|
+
const heartbeatInterval = setInterval(async () => {
|
|
72
|
+
await this.store.extendTTL(joinLockKey, 3600);
|
|
73
|
+
await this.store.extendTTL(fanInKey, 3600);
|
|
74
|
+
await this.store.extendTTL(blueprintKey, 3600);
|
|
75
|
+
this.logger.debug(`[Adapter] Extended TTLs for run ${runId}, node ${nodeId}`);
|
|
76
|
+
}, 18e5);
|
|
60
77
|
try {
|
|
78
|
+
const workerState = {
|
|
79
|
+
getContext: () => context,
|
|
80
|
+
markFallbackExecuted: () => {
|
|
81
|
+
},
|
|
82
|
+
addError: (nodeId2, error) => {
|
|
83
|
+
this.logger.error(`[Adapter] Error in node ${nodeId2}:`, error);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
61
86
|
const result = await this.runtime.executeNode(blueprint, nodeId, workerState);
|
|
62
87
|
await context.set(`_outputs.${nodeId}`, result.output);
|
|
88
|
+
if (context instanceof TrackedAsyncContext) {
|
|
89
|
+
const deltas = context.getDeltas();
|
|
90
|
+
if (deltas.length > 0) {
|
|
91
|
+
await context.patch(deltas);
|
|
92
|
+
context.clearDeltas();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
63
95
|
const analysis = analyzeBlueprint(blueprint);
|
|
64
96
|
const isTerminalNode = analysis.terminalNodeIds.includes(nodeId);
|
|
65
97
|
if (isTerminalNode) {
|
|
@@ -83,6 +115,7 @@ var BaseDistributedAdapter = class {
|
|
|
83
115
|
status: "completed",
|
|
84
116
|
payload: finalResult
|
|
85
117
|
});
|
|
118
|
+
clearInterval(heartbeatInterval);
|
|
86
119
|
return;
|
|
87
120
|
} else {
|
|
88
121
|
this.logger.info(
|
|
@@ -95,6 +128,7 @@ var BaseDistributedAdapter = class {
|
|
|
95
128
|
this.logger.info(
|
|
96
129
|
`[Adapter] Non-terminal node '${nodeId}' reached end of branch for Run ID '${runId}'. This branch will now terminate.`
|
|
97
130
|
);
|
|
131
|
+
clearInterval(heartbeatInterval);
|
|
98
132
|
return;
|
|
99
133
|
}
|
|
100
134
|
for (const { node: nextNodeDef, edge } of nextNodes) {
|
|
@@ -112,6 +146,8 @@ var BaseDistributedAdapter = class {
|
|
|
112
146
|
this.logger.error(`[Adapter] FATAL: Job for node '${nodeId}' failed for Run ID '${runId}': ${reason}`);
|
|
113
147
|
await this.publishFinalResult(runId, { status: "failed", reason });
|
|
114
148
|
await this.writePoisonPillForSuccessors(runId, blueprint, nodeId);
|
|
149
|
+
} finally {
|
|
150
|
+
clearInterval(heartbeatInterval);
|
|
115
151
|
}
|
|
116
152
|
}
|
|
117
153
|
/**
|
|
@@ -180,6 +216,9 @@ var BaseDistributedAdapter = class {
|
|
|
180
216
|
}
|
|
181
217
|
}
|
|
182
218
|
const blueprint = this.runtime.options.blueprints?.[blueprintId];
|
|
219
|
+
if (blueprint && !await context.has("blueprintVersion")) {
|
|
220
|
+
await context.set("blueprintVersion", blueprint.metadata?.version || null);
|
|
221
|
+
}
|
|
183
222
|
if (!blueprint) {
|
|
184
223
|
throw new Error(`Cannot reconcile runId '${runId}': Blueprint with ID '${blueprintId}' not found.`);
|
|
185
224
|
}
|
|
@@ -279,5 +318,5 @@ var BaseDistributedAdapter = class {
|
|
|
279
318
|
};
|
|
280
319
|
|
|
281
320
|
export { BaseDistributedAdapter };
|
|
282
|
-
//# sourceMappingURL=chunk-
|
|
283
|
-
//# sourceMappingURL=chunk-
|
|
321
|
+
//# sourceMappingURL=chunk-5XPW6YEP.js.map
|
|
322
|
+
//# sourceMappingURL=chunk-5XPW6YEP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/adapter.ts"],"names":["blueprintKey","nodeId"],"mappings":";;;;;;;AAiDO,IAAe,yBAAf,MAAsC;AAAA,EACzB,OAAA;AAAA,EACA,KAAA;AAAA,EACA,UAAA;AAAA,EACA,MAAA;AAAA,EAEnB,YAAY,OAAA,EAAyB;AACpC,IAAA,MAAM,cAAA,GAAiB;AAAA,MACtB,GAAG,OAAA,CAAQ,cAAA;AAAA,MACX,YAAA,EAAc;AAAA,QACb,GAAG,QAAQ,cAAA,CAAe,YAAA;AAAA,QAC1B,OAAA,EAAS;AAAA;AACV,KACD;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,IAAI,WAAA,CAAY,cAAc,CAAA;AAC7C,IAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,iBAAA;AACrB,IAAA,IAAA,CAAK,UAAA,GAAa,OAAA,CAAQ,cAAA,CAAe,UAAA,IAAc,IAAI,cAAA,EAAe;AAC1E,IAAA,IAAA,CAAK,MAAA,GAAS,OAAA,CAAQ,cAAA,CAAe,MAAA,IAAU,IAAI,aAAA,EAAc;AACjE,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,+CAA+C,CAAA;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKO,KAAA,GAAc;AACpB,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,8BAA8B,CAAA;AAC/C,IAAA,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,EA8CA,MAAgB,UAAA,CAAW,MAAA,EAAgB,YAAA,EAAsB,OAAA,EAAgC;AAAA,EAEjG;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,UAAU,GAAA,EAAgC;AACzD,IAAA,MAAM,EAAE,KAAA,EAAO,WAAA,EAAa,MAAA,EAAO,GAAI,GAAA;AAEvC,IAAA,MAAM,IAAA,CAAK,UAAA,CAAW,KAAA,EAAO,WAAA,EAAa,MAAM,CAAA;AAEhD,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,aAAa,WAAW,CAAA;AAC/D,IAAA,IAAI,CAAC,SAAA,EAAW;AACf,MAAA,MAAM,MAAA,GAAS,sBAAsB,WAAW,CAAA,6CAAA,CAAA;AAChD,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,iBAAA,EAAoB,MAAM,CAAA,CAAE,CAAA;AAC9C,MAAA,MAAM,KAAK,kBAAA,CAAmB,KAAA,EAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,QAAQ,CAAA;AACjE,MAAA;AAAA,IACD;AAEA,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,aAAA,CAAc,KAAK,CAAA;AAExC,IAAA,MAAM,aAAA,GAAgB,MAAM,OAAA,CAAQ,GAAA,CAAI,kBAAyB,CAAA;AACjE,IAAA,MAAM,cAAA,GAAiB,SAAA,CAAU,QAAA,EAAU,OAAA,IAAW,IAAA;AACtD,IAAA,IAAI,kBAAkB,cAAA,EAAgB;AACrC,MAAA,MAAM,MAAA,GAAS,CAAA,4CAAA,EAA+C,aAAa,CAAA,oBAAA,EAAuB,cAAc,CAAA,6CAAA,CAAA;AAChH,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,mCAAA,EAAsC,KAAK,UAAU,MAAM,CAAA,EAAA,EAAK,MAAM,CAAA,CAAE,CAAA;AACzF,MAAA;AAAA,IACD;AAGA,IAAA,MAAM,cAAA,GAAiB,MAAM,OAAA,CAAQ,GAAA,CAAI,aAAoB,CAAA;AAC7D,IAAA,IAAI,CAAC,cAAA,EAAgB;AACpB,MAAA,MAAM,OAAA,CAAQ,GAAA,CAAI,aAAA,EAAsB,WAAW,CAAA;AACnD,MAAA,MAAM,QAAQ,GAAA,CAAI,kBAAA,EAA2B,SAAA,CAAU,QAAA,EAAU,WAAW,IAAI,CAAA;AAEhF,MAAA,MAAMA,aAAAA,GAAe,uBAAuB,KAAK,CAAA,CAAA;AACjD,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAcA,aAAAA,EAAc,aAAa,IAAI,CAAA;AAAA,IAC/D;AAGA,IAAA,MAAM,WAAA,GAAc,CAAA,mBAAA,EAAsB,KAAK,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AACzD,IAAA,MAAM,QAAA,GAAW,CAAA,gBAAA,EAAmB,KAAK,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AACnD,IAAA,MAAM,YAAA,GAAe,uBAAuB,KAAK,CAAA,CAAA;AACjD,IAAA,MAAM,iBAAA,GAAoB,YAAY,YAAY;AACjD,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,WAAA,EAAa,IAAI,CAAA;AAC5C,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,QAAA,EAAU,IAAI,CAAA;AACzC,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,YAAA,EAAc,IAAI,CAAA;AAC7C,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,CAAA,gCAAA,EAAmC,KAAK,CAAA,OAAA,EAAU,MAAM,CAAA,CAAE,CAAA;AAAA,IAC7E,GAAG,IAAO,CAAA;AAEV,IAAA,IAAI;AACH,MAAA,MAAM,WAAA,GAAc;AAAA,QACnB,YAAY,MAAM,OAAA;AAAA,QAClB,sBAAsB,MAAM;AAAA,QAAC,CAAA;AAAA,QAC7B,QAAA,EAAU,CAACC,OAAAA,EAAgB,KAAA,KAAiB;AAC3C,UAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,wBAAA,EAA2BA,OAAM,KAAK,KAAK,CAAA;AAAA,QAC9D;AAAA,OACD;AAEA,MAAA,MAAM,SAA+B,MAAM,IAAA,CAAK,QAAQ,WAAA,CAAY,SAAA,EAAW,QAAQ,WAAW,CAAA;AAClG,MAAA,MAAM,QAAQ,GAAA,CAAI,CAAA,SAAA,EAAY,MAAM,CAAA,CAAA,EAAW,OAAO,MAAM,CAAA;AAE5D,MAAA,IAAI,mBAAmB,mBAAA,EAAqB;AAC3C,QAAA,MAAM,MAAA,GAAS,QAAQ,SAAA,EAAU;AACjC,QAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACtB,UAAA,MAAM,OAAA,CAAQ,MAAM,MAAM,CAAA;AAC1B,UAAA,OAAA,CAAQ,WAAA,EAAY;AAAA,QACrB;AAAA,MACD;AAEA,MAAA,MAAM,QAAA,GAAW,iBAAiB,SAAS,CAAA;AAC3C,MAAA,MAAM,cAAA,GAAiB,QAAA,CAAS,eAAA,CAAgB,QAAA,CAAS,MAAM,CAAA;AAE/D,MAAA,IAAI,cAAA,EAAgB;AACnB,QAAA,MAAM,iBAAiB,MAAA,CAAO,IAAA,CAAK,MAAM,OAAA,CAAQ,QAAQ,CAAA;AACzD,QAAA,MAAM,cAAA,uBAAqB,GAAA,EAAY;AACvC,QAAA,KAAA,MAAW,OAAO,cAAA,EAAgB;AACjC,UAAA,IAAI,GAAA,CAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAChC,YAAA,cAAA,CAAe,GAAA,CAAI,GAAA,CAAI,SAAA,CAAU,WAAA,CAAY,MAAM,CAAC,CAAA;AAAA,UACrD;AAAA,QACD;AACA,QAAA,MAAM,yBAAA,GAA4B,SAAS,eAAA,CAAgB,KAAA,CAAM,CAAC,UAAA,KAAe,cAAA,CAAe,GAAA,CAAI,UAAU,CAAC,CAAA;AAE/G,QAAA,IAAI,yBAAA,EAA2B;AAC9B,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,mDAAA,EAAsD,KAAK,CAAA,8BAAA,CAAgC,CAAA;AAC5G,UAAA,MAAM,YAAA,GAAe,MAAM,OAAA,CAAQ,MAAA,EAAO;AAC1C,UAAA,MAAM,WAAA,GAA8B;AAAA,YACnC,OAAA,EAAS,YAAA;AAAA,YACT,iBAAA,EAAmB,IAAA,CAAK,UAAA,CAAW,SAAA,CAAU,YAAY,CAAA;AAAA,YACzD,MAAA,EAAQ;AAAA,WACT;AACA,UAAA,MAAM,IAAA,CAAK,mBAAmB,KAAA,EAAO;AAAA,YACpC,MAAA,EAAQ,WAAA;AAAA,YACR,OAAA,EAAS;AAAA,WACT,CAAA;AACD,UAAA,aAAA,CAAc,iBAAiB,CAAA;AAC/B,UAAA;AAAA,QACD,CAAA,MAAO;AACN,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,YACX,CAAA,yBAAA,EAA4B,MAAM,CAAA,wBAAA,EAA2B,KAAK,CAAA,8CAAA;AAAA,WACnE;AAAA,QACD;AAAA,MACD;AAEA,MAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,OAAA,CAAQ,mBAAmB,SAAA,EAAW,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,KAAK,CAAA;AAGjG,MAAA,IAAI,SAAA,CAAU,MAAA,KAAW,CAAA,IAAK,CAAC,cAAA,EAAgB;AAC9C,QAAA,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,UACX,CAAA,6BAAA,EAAgC,MAAM,CAAA,oCAAA,EAAuC,KAAK,CAAA,kCAAA;AAAA,SACnF;AACA,QAAA,aAAA,CAAc,iBAAiB,CAAA;AAC/B,QAAA;AAAA,MACD;AAEA,MAAA,KAAA,MAAW,EAAE,IAAA,EAAM,WAAA,EAAa,IAAA,MAAU,SAAA,EAAW;AACpD,QAAA,MAAM,KAAK,OAAA,CAAQ,kBAAA,CAAmB,IAAA,EAAM,MAAA,EAAQ,aAAa,OAAO,CAAA;AACxE,QAAA,MAAM,UAAU,MAAM,IAAA,CAAK,gBAAgB,KAAA,EAAO,SAAA,EAAW,YAAY,EAAE,CAAA;AAC3E,QAAA,IAAI,OAAA,EAAS;AACZ,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,gBAAA,EAAmB,WAAA,CAAY,EAAE,CAAA,0BAAA,CAA4B,CAAA;AAC9E,UAAA,MAAM,IAAA,CAAK,WAAW,EAAE,KAAA,EAAO,aAAa,MAAA,EAAQ,WAAA,CAAY,IAAI,CAAA;AAAA,QACrE,CAAA,MAAO;AACN,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,gBAAA,EAAmB,WAAA,CAAY,EAAE,CAAA,gDAAA,CAAkD,CAAA;AAAA,QACrG;AAAA,MACD;AAAA,IACD,SAAS,KAAA,EAAY;AACpB,MAAA,MAAM,MAAA,GAAS,MAAM,OAAA,IAAW,yBAAA;AAChC,MAAA,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,+BAAA,EAAkC,MAAM,wBAAwB,KAAK,CAAA,GAAA,EAAM,MAAM,CAAA,CAAE,CAAA;AACrG,MAAA,MAAM,KAAK,kBAAA,CAAmB,KAAA,EAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,QAAQ,CAAA;AACjE,MAAA,MAAM,IAAA,CAAK,4BAAA,CAA6B,KAAA,EAAO,SAAA,EAAW,MAAM,CAAA;AAAA,IACjE,CAAA,SAAE;AACD,MAAA,aAAA,CAAc,iBAAiB,CAAA;AAAA,IAChC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,eAAA,CAAgB,KAAA,EAAe,SAAA,EAA8B,YAAA,EAAwC;AACpH,IAAA,MAAM,UAAA,GAAa,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,YAAY,CAAA;AACpE,IAAA,IAAI,CAAC,UAAA,EAAY;AAChB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,YAAY,CAAA,wBAAA,CAA0B,CAAA;AAAA,IAChE;AACA,IAAA,MAAM,YAAA,GAAe,UAAA,CAAW,MAAA,EAAQ,YAAA,IAAgB,KAAA;AACxD,IAAA,MAAM,YAAA,GAAe,UAAU,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,YAAY,CAAA;AAE5E,IAAA,IAAI,YAAA,CAAa,UAAU,CAAA,EAAG;AAC7B,MAAA,OAAO,IAAA;AAAA,IACR;AAEA,IAAA,MAAM,SAAA,GAAY,CAAA,uBAAA,EAA0B,KAAK,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AACjE,IAAA,MAAM,UAAA,GAAa,MAAM,IAAA,CAAK,KAAA,CAAM,IAAI,SAAS,CAAA;AACjD,IAAA,IAAI,UAAA,EAAY;AACf,MAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,gBAAA,EAAmB,YAAY,CAAA,6DAAA,CAA+D,CAAA;AAC/G,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,YAAY,CAAA,6CAAA,EAAgD,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,IAC9F;AAEA,IAAA,IAAI,iBAAiB,KAAA,EAAO;AAC3B,MAAA,MAAM,OAAA,GAAU,CAAA,mBAAA,EAAsB,KAAK,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AAC3D,MAAA,MAAM,WAAW,MAAM,IAAA,CAAK,MAAM,aAAA,CAAc,OAAA,EAAS,UAAU,IAAI,CAAA;AACvE,MAAA,IAAI,CAAC,QAAA,EAAU;AAEd,QAAA,MAAM,SAAA,GAAY,CAAA,uBAAA,EAA0B,KAAK,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AACjE,QAAA,MAAM,WAAA,GAAc,CAAE,MAAM,IAAA,CAAK,MAAM,aAAA,CAAc,SAAA,EAAW,aAAa,IAAI,CAAA;AACjF,QAAA,IAAI,WAAA,EAAa;AAChB,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,YACX,mBAAmB,YAAY,CAAA,8DAAA;AAAA,WAChC;AACA,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,YAAY,CAAA,8CAAA,EAAiD,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,QAC/F;AACA,QAAA,OAAO,KAAA;AAAA,MACR;AACA,MAAA,OAAO,IAAA;AAAA,IACR,CAAA,MAAO;AACN,MAAA,MAAM,QAAA,GAAW,CAAA,gBAAA,EAAmB,KAAK,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AACzD,MAAA,MAAM,aAAa,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,UAAU,IAAI,CAAA;AAC5D,MAAA,IAAI,UAAA,IAAc,aAAa,MAAA,EAAQ;AACtC,QAAA,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,QAAQ,CAAA;AAChC,QAAA,OAAO,IAAA;AAAA,MACR;AACA,MAAA,OAAO,KAAA;AAAA,IACR;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAa,UAAU,KAAA,EAAqC;AAC3D,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,aAAA,CAAc,KAAK,CAAA;AACxC,IAAA,IAAI,WAAA,GAAe,MAAM,OAAA,CAAQ,GAAA,CAAI,aAAoB,CAAA;AAEzD,IAAA,IAAI,CAAC,WAAA,EAAa;AAEjB,MAAA,MAAM,YAAA,GAAe,uBAAuB,KAAK,CAAA,CAAA;AACjD,MAAA,WAAA,GAAc,MAAM,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,YAAY,CAAA;AAC/C,MAAA,IAAI,WAAA,EAAa;AAEhB,QAAA,MAAM,OAAA,CAAQ,GAAA,CAAI,aAAA,EAAsB,WAAW,CAAA;AAAA,MACpD,CAAA,MAAO;AACN,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,KAAK,CAAA,0DAAA,CAA4D,CAAA;AAAA,MAC7G;AAAA,IACD;AACA,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,aAAa,WAAW,CAAA;AAC/D,IAAA,IAAI,aAAa,CAAE,MAAM,OAAA,CAAQ,GAAA,CAAI,kBAAyB,CAAA,EAAI;AACjE,MAAA,MAAM,QAAQ,GAAA,CAAI,kBAAA,EAA2B,SAAA,CAAU,QAAA,EAAU,WAAW,IAAI,CAAA;AAAA,IACjF;AACA,IAAA,IAAI,CAAC,SAAA,EAAW;AACf,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,KAAK,CAAA,sBAAA,EAAyB,WAAW,CAAA,YAAA,CAAc,CAAA;AAAA,IACnG;AAEA,IAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,MAAA,EAAO;AACnC,IAAA,MAAM,cAAA,uBAAqB,GAAA,EAAY;AACvC,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,EAAG;AACrC,MAAA,IAAI,GAAA,CAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAChC,QAAA,cAAA,CAAe,GAAA,CAAI,GAAA,CAAI,SAAA,CAAU,WAAA,CAAY,MAAM,CAAC,CAAA;AAAA,MACrD;AAAA,IACD;AAEA,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,wBAAA,CAAyB,SAAA,EAAW,cAAc,CAAA;AAExE,IAAA,MAAM,aAAA,uBAAoB,GAAA,EAAY;AACtC,IAAA,KAAA,MAAW,UAAU,QAAA,EAAU;AAC9B,MAAA,MAAM,OAAA,GAAU,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,MAAM,CAAA;AAC3D,MAAA,MAAM,YAAA,GAAe,OAAA,EAAS,MAAA,EAAQ,YAAA,IAAgB,KAAA;AAEtD,MAAA,MAAM,SAAA,GAAY,CAAA,uBAAA,EAA0B,KAAK,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAC3D,MAAA,MAAM,UAAA,GAAa,MAAM,IAAA,CAAK,KAAA,CAAM,IAAI,SAAS,CAAA;AACjD,MAAA,IAAI,UAAA,EAAY;AACf,QAAA,IAAA,CAAK,OAAO,IAAA,CAAK,CAAA,6BAAA,EAAgC,MAAM,CAAA,wBAAA,CAAA,EAA4B,EAAE,OAAO,CAAA;AAC5F,QAAA;AAAA,MACD;AAEA,MAAA,IAAI,aAAA,GAAgB,KAAA;AAEpB,MAAA,IAAI,iBAAiB,KAAA,EAAO;AAE3B,QAAA,MAAM,OAAA,GAAU,CAAA,mBAAA,EAAsB,KAAK,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AACrD,QAAA,IAAI,MAAM,IAAA,CAAK,KAAA,CAAM,cAAc,OAAA,EAAS,qBAAA,EAAuB,IAAI,CAAA,EAAG;AACzE,UAAA,aAAA,GAAgB,IAAA;AAAA,QACjB,CAAA,MAAO;AACN,UAAA,IAAA,CAAK,OAAO,IAAA,CAAK,CAAA,6BAAA,EAAgC,MAAM,CAAA,yCAAA,CAAA,EAA6C,EAAE,OAAO,CAAA;AAAA,QAC9G;AAAA,MACD,CAAA,MAAO;AAEN,QAAA,MAAM,OAAA,GAAU,CAAA,mBAAA,EAAsB,KAAK,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AACrD,QAAA,IAAI,MAAM,IAAA,CAAK,KAAA,CAAM,cAAc,OAAA,EAAS,QAAA,EAAU,GAAG,CAAA,EAAG;AAC3D,UAAA,aAAA,GAAgB,IAAA;AAAA,QACjB,CAAA,MAAO;AACN,UAAA,IAAA,CAAK,OAAO,IAAA,CAAK,CAAA,6BAAA,EAAgC,MAAM,CAAA,oBAAA,CAAA,EAAwB,EAAE,OAAO,CAAA;AAAA,QACzF;AAAA,MACD;AAEA,MAAA,IAAI,aAAA,EAAe;AAClB,QAAA,IAAA,CAAK,OAAO,IAAA,CAAK,CAAA,qDAAA,EAAwD,MAAM,CAAA,CAAA,CAAA,EAAK,EAAE,OAAO,CAAA;AAC7F,QAAA,MAAM,IAAA,CAAK,WAAW,EAAE,KAAA,EAAO,aAAa,SAAA,CAAU,EAAA,EAAI,QAAQ,CAAA;AAClE,QAAA,aAAA,CAAc,IAAI,MAAM,CAAA;AAAA,MACzB;AAAA,IACD;AAEA,IAAA,OAAO,aAAA;AAAA,EACR;AAAA,EAEQ,wBAAA,CAAyB,WAA8B,cAAA,EAA0C;AACxG,IAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,IAAA,MAAM,eAAA,uBAAsB,GAAA,EAAyB;AAErD,IAAA,KAAA,MAAW,IAAA,IAAQ,UAAU,KAAA,EAAO;AACnC,MAAA,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,EAAA,kBAAI,IAAI,KAAK,CAAA;AAAA,IACvC;AACA,IAAA,KAAA,MAAW,IAAA,IAAQ,UAAU,KAAA,EAAO;AACnC,MAAA,eAAA,CAAgB,IAAI,IAAA,CAAK,MAAM,CAAA,EAAG,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IAClD;AAEA,IAAA,KAAA,MAAW,IAAA,IAAQ,UAAU,KAAA,EAAO;AACnC,MAAA,IAAI,cAAA,CAAe,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG;AAChC,QAAA;AAAA,MACD;AAEA,MAAA,MAAM,eAAe,eAAA,CAAgB,GAAA,CAAI,KAAK,EAAE,CAAA,wBAAS,GAAA,EAAI;AAC7D,MAAA,IAAI,YAAA,CAAa,SAAS,CAAA,IAAK,CAAC,eAAe,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG;AAC5D,QAAA,WAAA,CAAY,GAAA,CAAI,KAAK,EAAE,CAAA;AACvB,QAAA;AAAA,MACD;AAEA,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,MAAA,EAAQ,YAAA,IAAgB,KAAA;AAClD,MAAA,MAAM,qBAAA,GAAwB,CAAC,GAAG,YAAY,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,cAAA,CAAe,GAAA,CAAI,CAAC,CAAC,CAAA;AAEnF,MAAA,MAAM,OAAA,GACL,iBAAiB,KAAA,GAAQ,qBAAA,CAAsB,SAAS,CAAA,GAAI,qBAAA,CAAsB,WAAW,YAAA,CAAa,IAAA;AAE3G,MAAA,IAAI,OAAA,EAAS;AACZ,QAAA,WAAA,CAAY,GAAA,CAAI,KAAK,EAAE,CAAA;AAAA,MACxB;AAAA,IACD;AACA,IAAA,OAAO,WAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,4BAAA,CACb,KAAA,EACA,SAAA,EACA,YAAA,EACgB;AAChB,IAAA,MAAM,UAAA,GAAa,SAAA,CAAU,KAAA,CAC3B,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,KAAW,YAAY,CAAA,CAC7C,GAAA,CAAI,CAAC,IAAA,KAAS,KAAK,MAAM,CAAA,CACzB,GAAA,CAAI,CAAC,QAAA,KAAa,SAAA,CAAU,KAAA,CAAM,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,EAAA,KAAO,QAAQ,CAAC,CAAA,CACtE,MAAA,CAAO,CAAC,SAAS,IAAI,CAAA;AAEvB,IAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AACnC,MAAA,IAAI,SAAA,EAAW;AACd,QAAA,MAAM,YAAA,GAAe,SAAA,CAAU,MAAA,EAAQ,YAAA,IAAgB,KAAA;AACvD,QAAA,IAAI,iBAAiB,KAAA,EAAO;AAC3B,UAAA,MAAM,SAAA,GAAY,CAAA,uBAAA,EAA0B,KAAK,CAAA,CAAA,EAAI,UAAU,EAAE,CAAA,CAAA;AACjE,UAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,SAAA,EAAW,YAAY,IAAI,CAAA;AAC1D,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,YACX,CAAA,iDAAA,EAAoD,SAAA,CAAU,EAAE,CAAA,6BAAA,EAAgC,YAAY,CAAA,CAAA;AAAA,WAC7G;AAAA,QACD,CAAA,MAAA,IAAW,iBAAiB,KAAA,EAAO;AAClC,UAAA,MAAM,SAAA,GAAY,CAAA,uBAAA,EAA0B,KAAK,CAAA,CAAA,EAAI,UAAU,EAAE,CAAA,CAAA;AACjE,UAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,SAAA,EAAW,aAAa,IAAI,CAAA;AAC3D,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,YACX,CAAA,uDAAA,EAA0D,SAAA,CAAU,EAAE,CAAA,6BAAA,EAAgC,YAAY,CAAA,CAAA;AAAA,WACnH;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD","file":"chunk-5XPW6YEP.js","sourcesContent":["import { analyzeBlueprint } from '../analysis'\nimport { TrackedAsyncContext } from '../context'\nimport { ConsoleLogger } from '../logger'\nimport { JsonSerializer } from '../serializer'\nimport type {\n\tIAsyncContext,\n\tILogger,\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/** Extends the TTL of an existing key. Used for heartbeat mechanism in long-running jobs. */\n\textendTTL: (key: string, ttlSeconds: number) => Promise<boolean>\n\t/** Deletes a key. Used for cleanup. */\n\tdelete: (key: string) => Promise<void>\n\t/** Gets the value of a key. */\n\tget: (key: string) => Promise<string | undefined>\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\tprotected readonly logger: ILogger\n\n\tconstructor(options: AdapterOptions) {\n\t\tconst runtimeOptions = {\n\t\t\t...options.runtimeOptions,\n\t\t\tdependencies: {\n\t\t\t\t...options.runtimeOptions.dependencies,\n\t\t\t\tadapter: this,\n\t\t\t} as any,\n\t\t}\n\t\tthis.runtime = new FlowRuntime(runtimeOptions)\n\t\tthis.store = options.coordinationStore\n\t\tthis.serializer = options.runtimeOptions.serializer || new JsonSerializer()\n\t\tthis.logger = options.runtimeOptions.logger || new ConsoleLogger()\n\t\tthis.logger.info('[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\tthis.logger.info('[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 * Registers a webhook endpoint for a specific node in a workflow run.\n\t * @param runId The unique ID of the workflow run.\n\t * @param nodeId The ID of the node that will wait for the webhook.\n\t * @returns The URL and event name for the webhook.\n\t */\n\tpublic abstract registerWebhookEndpoint(runId: string, nodeId: string): Promise<{ url: string; event: string }>\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\tthis.logger.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\tconst storedVersion = await context.get('blueprintVersion' as any)\n\t\tconst currentVersion = blueprint.metadata?.version || null\n\t\tif (storedVersion !== currentVersion) {\n\t\t\tconst reason = `Blueprint version mismatch: stored version '${storedVersion}', current version '${currentVersion}'. Rejecting job to prevent state corruption.`\n\t\t\tthis.logger.warn(`[Adapter] Version mismatch for run ${runId}, node ${nodeId}: ${reason}`)\n\t\t\treturn\n\t\t}\n\n\t\t// persist the blueprintId and version 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\tawait context.set('blueprintVersion' as any, blueprint.metadata?.version || null)\n\t\t\t// also store in coordination store as fallback\n\t\t\tconst blueprintKey = `flowcraft:blueprint:${runId}`\n\t\t\tawait this.store.setIfNotExist(blueprintKey, blueprintId, 3600)\n\t\t}\n\n\t\t// heartbeat to extend TTLs of coordination keys for long-running jobs\n\t\tconst joinLockKey = `flowcraft:joinlock:${runId}:${nodeId}`\n\t\tconst fanInKey = `flowcraft:fanin:${runId}:${nodeId}`\n\t\tconst blueprintKey = `flowcraft:blueprint:${runId}`\n\t\tconst heartbeatInterval = setInterval(async () => {\n\t\t\tawait this.store.extendTTL(joinLockKey, 3600)\n\t\t\tawait this.store.extendTTL(fanInKey, 3600)\n\t\t\tawait this.store.extendTTL(blueprintKey, 3600)\n\t\t\tthis.logger.debug(`[Adapter] Extended TTLs for run ${runId}, node ${nodeId}`)\n\t\t}, 1800000) // 30 minutes\n\n\t\ttry {\n\t\t\tconst workerState = {\n\t\t\t\tgetContext: () => context,\n\t\t\t\tmarkFallbackExecuted: () => {},\n\t\t\t\taddError: (nodeId: string, error: Error) => {\n\t\t\t\t\tthis.logger.error(`[Adapter] Error in node ${nodeId}:`, error)\n\t\t\t\t},\n\t\t\t} as any\n\n\t\t\tconst result: NodeResult<any, any> = await this.runtime.executeNode(blueprint, nodeId, workerState)\n\t\t\tawait context.set(`_outputs.${nodeId}` as any, result.output)\n\n\t\t\tif (context instanceof TrackedAsyncContext) {\n\t\t\t\tconst deltas = context.getDeltas()\n\t\t\t\tif (deltas.length > 0) {\n\t\t\t\t\tawait context.patch(deltas)\n\t\t\t\t\tcontext.clearDeltas()\n\t\t\t\t}\n\t\t\t}\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 allContextKeys = Object.keys(await context.toJSON())\n\t\t\t\tconst completedNodes = new Set<string>()\n\t\t\t\tfor (const key of allContextKeys) {\n\t\t\t\t\tif (key.startsWith('_outputs.')) {\n\t\t\t\t\t\tcompletedNodes.add(key.substring('_outputs.'.length))\n\t\t\t\t\t}\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\tthis.logger.info(`[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\tclearInterval(heartbeatInterval)\n\t\t\t\t\treturn\n\t\t\t\t} else {\n\t\t\t\t\tthis.logger.info(\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, runId)\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\tthis.logger.info(\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\tclearInterval(heartbeatInterval)\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\tthis.logger.info(`[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\tthis.logger.info(`[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\tthis.logger.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} finally {\n\t\t\tclearInterval(heartbeatInterval)\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.get(poisonKey)\n\t\tif (isPoisoned) {\n\t\t\tthis.logger.info(`[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\tconst isLocked = await this.store.setIfNotExist(lockKey, 'locked', 3600)\n\t\t\tif (!isLocked) {\n\t\t\t\t// check if cancelled\n\t\t\t\tconst cancelKey = `flowcraft:fanin:cancel:${runId}:${targetNodeId}`\n\t\t\t\tconst isCancelled = !(await this.store.setIfNotExist(cancelKey, 'cancelled', 3600))\n\t\t\t\tif (isCancelled) {\n\t\t\t\t\tthis.logger.info(\n\t\t\t\t\t\t`[Adapter] Node '${targetNodeId}' is cancelled due to failed predecessor. Failing immediately.`,\n\t\t\t\t\t)\n\t\t\t\t\tthrow new Error(`Node '${targetNodeId}' failed due to cancelled predecessor in run '${runId}'`)\n\t\t\t\t}\n\t\t\t\treturn false // already locked by another predecessor\n\t\t\t}\n\t\t\treturn true\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\tlet blueprintId = (await context.get('blueprintId' as any)) as string | undefined\n\n\t\tif (!blueprintId) {\n\t\t\t// fallback to coordination store\n\t\t\tconst blueprintKey = `flowcraft:blueprint:${runId}`\n\t\t\tblueprintId = await this.store.get(blueprintKey)\n\t\t\tif (blueprintId) {\n\t\t\t\t// set it back in context for future use\n\t\t\t\tawait context.set('blueprintId' as any, blueprintId)\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Cannot reconcile runId '${runId}': blueprintId not found in context or coordination store.`)\n\t\t\t}\n\t\t}\n\t\tconst blueprint = this.runtime.options.blueprints?.[blueprintId]\n\t\tif (blueprint && !(await context.has('blueprintVersion' as any))) {\n\t\t\tawait context.set('blueprintVersion' as any, blueprint.metadata?.version || null)\n\t\t}\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\tconst completedNodes = new Set<string>()\n\t\tfor (const key of Object.keys(state)) {\n\t\t\tif (key.startsWith('_outputs.')) {\n\t\t\t\tcompletedNodes.add(key.substring('_outputs.'.length))\n\t\t\t}\n\t\t}\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\tconst poisonKey = `flowcraft:fanin:poison:${runId}:${nodeId}`\n\t\t\tconst isPoisoned = await this.store.get(poisonKey)\n\t\t\tif (isPoisoned) {\n\t\t\t\tthis.logger.info(`[Adapter] Reconciling: Node '${nodeId}' is poisoned, skipping.`, { runId })\n\t\t\t\tcontinue\n\t\t\t}\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\tthis.logger.info(`[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\tthis.logger.info(`[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\tthis.logger.info(`[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 and a cancellation pill for 'any' join successors of a failed node to prevent stalling or ambiguous states.\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)\n\n\t\tfor (const successor of successors) {\n\t\t\tif (successor) {\n\t\t\t\tconst joinStrategy = successor.config?.joinStrategy || 'all'\n\t\t\t\tif (joinStrategy === 'all') {\n\t\t\t\t\tconst poisonKey = `flowcraft:fanin:poison:${runId}:${successor.id}`\n\t\t\t\t\tawait this.store.setIfNotExist(poisonKey, 'poisoned', 3600)\n\t\t\t\t\tthis.logger.info(\n\t\t\t\t\t\t`[Adapter] Wrote poison pill for 'all' join node '${successor.id}' due to failed predecessor '${failedNodeId}'`,\n\t\t\t\t\t)\n\t\t\t\t} else if (joinStrategy === 'any') {\n\t\t\t\t\tconst cancelKey = `flowcraft:fanin:cancel:${runId}:${successor.id}`\n\t\t\t\t\tawait this.store.setIfNotExist(cancelKey, 'cancelled', 3600)\n\t\t\t\t\tthis.logger.info(\n\t\t\t\t\t\t`[Adapter] Wrote cancellation pill for 'any' join node '${successor.id}' due to failed predecessor '${failedNodeId}'`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InMemoryEventLogger } from './chunk-MUYLRTSR.js';
|
|
2
|
-
import { FlowRuntime } from './chunk-
|
|
2
|
+
import { FlowRuntime } from './chunk-OPRR4TAO.js';
|
|
3
3
|
|
|
4
4
|
// src/testing/run-with-trace.ts
|
|
5
5
|
async function runWithTrace(runtime, blueprint, initialState = {}, options = {}) {
|
|
@@ -21,5 +21,5 @@ async function runWithTrace(runtime, blueprint, initialState = {}, options = {})
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export { runWithTrace };
|
|
24
|
-
//# sourceMappingURL=chunk-
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
24
|
+
//# sourceMappingURL=chunk-6MGLU3UU.js.map
|
|
25
|
+
//# sourceMappingURL=chunk-6MGLU3UU.js.map
|
|
@@ -1 +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-
|
|
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-6MGLU3UU.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"]}
|
|
@@ -12,7 +12,7 @@ function _hashFunction(fn) {
|
|
|
12
12
|
}
|
|
13
13
|
return (Math.abs(hash) + hashCounter++).toString(16);
|
|
14
14
|
}
|
|
15
|
-
var
|
|
15
|
+
var FlowBuilder = class {
|
|
16
16
|
blueprint;
|
|
17
17
|
functionRegistry;
|
|
18
18
|
loopControllerIds;
|
|
@@ -71,17 +71,14 @@ var Flow = class {
|
|
|
71
71
|
this.blueprint.nodes?.push({
|
|
72
72
|
id: scatterId,
|
|
73
73
|
uses: "batch-scatter",
|
|
74
|
-
// built-in
|
|
75
74
|
inputs: inputKey,
|
|
76
75
|
params: { workerUsesKey, outputKey, gatherNodeId: gatherId, chunkSize: options.chunkSize }
|
|
77
76
|
});
|
|
78
77
|
this.blueprint.nodes?.push({
|
|
79
78
|
id: gatherId,
|
|
80
79
|
uses: "batch-gather",
|
|
81
|
-
// built-in
|
|
82
80
|
params: { outputKey, gatherNodeId: gatherId },
|
|
83
81
|
config: { joinStrategy: "all" }
|
|
84
|
-
// important: must wait for all scattered jobs
|
|
85
82
|
});
|
|
86
83
|
this.edge(scatterId, gatherId);
|
|
87
84
|
return this;
|
|
@@ -126,16 +123,13 @@ var Flow = class {
|
|
|
126
123
|
this.blueprint.nodes?.push({
|
|
127
124
|
id: controllerId,
|
|
128
125
|
uses: "loop-controller",
|
|
129
|
-
// built-in
|
|
130
126
|
params: { condition },
|
|
131
127
|
config: { joinStrategy: "any" }
|
|
132
|
-
// to allow re-execution on each loop iteration
|
|
133
128
|
});
|
|
134
129
|
this.edge(endNodeId, controllerId);
|
|
135
130
|
this.edge(controllerId, startNodeId, {
|
|
136
131
|
action: "continue",
|
|
137
132
|
transform: `context.${endNodeId}`
|
|
138
|
-
// pass the end node's value to the start node
|
|
139
133
|
});
|
|
140
134
|
return this;
|
|
141
135
|
}
|
|
@@ -285,9 +279,9 @@ var Flow = class {
|
|
|
285
279
|
}
|
|
286
280
|
};
|
|
287
281
|
function createFlow(id) {
|
|
288
|
-
return new
|
|
282
|
+
return new FlowBuilder(id);
|
|
289
283
|
}
|
|
290
284
|
|
|
291
|
-
export {
|
|
292
|
-
//# sourceMappingURL=chunk-
|
|
293
|
-
//# sourceMappingURL=chunk-
|
|
285
|
+
export { FlowBuilder, createFlow };
|
|
286
|
+
//# sourceMappingURL=chunk-7FIOROIR.js.map
|
|
287
|
+
//# sourceMappingURL=chunk-7FIOROIR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/flow.ts"],"names":[],"mappings":"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","file":"chunk-7FIOROIR.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 FlowBuilder<\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): FlowBuilder<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\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\tthis.blueprint.nodes?.push({\n\t\t\tid: scatterId,\n\t\t\tuses: 'batch-scatter',\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\tthis.blueprint.nodes?.push({\n\t\t\tid: gatherId,\n\t\t\tuses: 'batch-gather',\n\t\t\tparams: { outputKey, gatherNodeId: gatherId },\n\t\t\tconfig: { joinStrategy: 'all' },\n\t\t})\n\n\t\tthis.edge(scatterId, gatherId)\n\n\t\treturn this as unknown as FlowBuilder<TContext & { [K in TOutputKey]: TWorkerOutput[] }, TDependencies>\n\t}\n\n\t/**\n\t * Creates a sleep node that pauses workflow execution for a specified duration.\n\t * @param id A unique identifier for the sleep node.\n\t * @param options Configuration for the sleep duration.\n\t */\n\tsleep(\n\t\tid: string,\n\t\toptions: {\n\t\t\t/** The duration to sleep in milliseconds. */\n\t\t\tduration: number\n\t\t},\n\t): this {\n\t\tconst nodeDef: NodeDefinition = {\n\t\t\tid,\n\t\t\tuses: 'sleep',\n\t\t\tparams: { duration: options.duration },\n\t\t}\n\t\tthis.blueprint.nodes?.push(nodeDef)\n\t\treturn this\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\tthis.blueprint.nodes?.push({\n\t\t\tid: controllerId,\n\t\t\tuses: 'loop-controller',\n\t\t\tparams: { condition },\n\t\t\tconfig: { joinStrategy: 'any' },\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}`,\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): FlowBuilder<TContext, TDependencies> {\n\treturn new FlowBuilder(id)\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { analyzeBlueprint } from './chunk-
|
|
1
|
+
import { analyzeBlueprint } from './chunk-ZLW4QOTS.js';
|
|
2
2
|
|
|
3
3
|
// src/runtime/traverser.ts
|
|
4
4
|
var GraphTraverser = class _GraphTraverser {
|
|
@@ -168,5 +168,5 @@ var GraphTraverser = class _GraphTraverser {
|
|
|
168
168
|
};
|
|
169
169
|
|
|
170
170
|
export { GraphTraverser };
|
|
171
|
-
//# sourceMappingURL=chunk-
|
|
172
|
-
//# sourceMappingURL=chunk-
|
|
171
|
+
//# sourceMappingURL=chunk-FBPY44WL.js.map
|
|
172
|
+
//# sourceMappingURL=chunk-FBPY44WL.js.map
|