flowcraft 2.1.1 → 2.3.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.
Files changed (162) hide show
  1. package/README.md +41 -35
  2. package/dist/analysis.d.ts +5 -2
  3. package/dist/analysis.js +1 -1
  4. package/dist/{chunk-HN72TZY5.js → chunk-233SESC2.js} +34 -23
  5. package/dist/chunk-233SESC2.js.map +1 -0
  6. package/dist/chunk-33NO4PUJ.js +74 -0
  7. package/dist/chunk-33NO4PUJ.js.map +1 -0
  8. package/dist/chunk-5KKSQWSC.js +90 -0
  9. package/dist/chunk-5KKSQWSC.js.map +1 -0
  10. package/dist/{chunk-O3XD45IL.js → chunk-6INWPSZT.js} +44 -17
  11. package/dist/chunk-6INWPSZT.js.map +1 -0
  12. package/dist/chunk-BC4G7OM6.js +42 -0
  13. package/dist/chunk-BC4G7OM6.js.map +1 -0
  14. package/dist/chunk-BCRWXTWX.js +21 -0
  15. package/dist/chunk-BCRWXTWX.js.map +1 -0
  16. package/dist/chunk-C4HYIJI3.js +279 -0
  17. package/dist/chunk-C4HYIJI3.js.map +1 -0
  18. package/dist/chunk-CD3Q4N6V.js +13 -0
  19. package/dist/chunk-CD3Q4N6V.js.map +1 -0
  20. package/dist/chunk-CD4FUZOJ.js +114 -0
  21. package/dist/chunk-CD4FUZOJ.js.map +1 -0
  22. package/dist/chunk-CY755I7I.js +25 -0
  23. package/dist/chunk-CY755I7I.js.map +1 -0
  24. package/dist/chunk-DL7KVYZF.js +39 -0
  25. package/dist/chunk-DL7KVYZF.js.map +1 -0
  26. package/dist/{chunk-UETC63DP.js → chunk-EUJWJWFA.js} +24 -4
  27. package/dist/chunk-EUJWJWFA.js.map +1 -0
  28. package/dist/chunk-FRKO3WX4.js +32 -0
  29. package/dist/chunk-FRKO3WX4.js.map +1 -0
  30. package/dist/chunk-G53CSLBF.js +54 -0
  31. package/dist/chunk-G53CSLBF.js.map +1 -0
  32. package/dist/chunk-G5BGBPFP.js +172 -0
  33. package/dist/chunk-G5BGBPFP.js.map +1 -0
  34. package/dist/chunk-HAZ26F3P.js +98 -0
  35. package/dist/chunk-HAZ26F3P.js.map +1 -0
  36. package/dist/chunk-IB2BISIC.js +446 -0
  37. package/dist/chunk-IB2BISIC.js.map +1 -0
  38. package/dist/{chunk-U5V5O5MN.js → chunk-LNK7LZER.js} +5 -3
  39. package/dist/chunk-LNK7LZER.js.map +1 -0
  40. package/dist/chunk-MCGK3FXQ.js +143 -0
  41. package/dist/chunk-MCGK3FXQ.js.map +1 -0
  42. package/dist/chunk-MUYLRTSR.js +82 -0
  43. package/dist/chunk-MUYLRTSR.js.map +1 -0
  44. package/dist/chunk-NVJ3ZO3P.js +3 -0
  45. package/dist/{chunk-HMR2GEGE.js.map → chunk-NVJ3ZO3P.js.map} +1 -1
  46. package/dist/chunk-NVLZFLYM.js +3 -0
  47. package/dist/chunk-NVLZFLYM.js.map +1 -0
  48. package/dist/chunk-ONH7PIJZ.js +300 -0
  49. package/dist/chunk-ONH7PIJZ.js.map +1 -0
  50. package/dist/chunk-QNYXQKFW.js +25 -0
  51. package/dist/chunk-QNYXQKFW.js.map +1 -0
  52. package/dist/{chunk-KWQHFT7E.js → chunk-R3HQXIEL.js} +6 -6
  53. package/dist/chunk-R3HQXIEL.js.map +1 -0
  54. package/dist/chunk-RM677CNU.js +52 -0
  55. package/dist/chunk-RM677CNU.js.map +1 -0
  56. package/dist/chunk-WWGFIYKW.js +47 -0
  57. package/dist/chunk-WWGFIYKW.js.map +1 -0
  58. package/dist/chunk-XNRIM27H.js +76 -0
  59. package/dist/chunk-XNRIM27H.js.map +1 -0
  60. package/dist/container-factory.d.ts +17 -0
  61. package/dist/container-factory.js +13 -0
  62. package/dist/container-factory.js.map +1 -0
  63. package/dist/container.d.ts +23 -0
  64. package/dist/container.js +3 -0
  65. package/dist/container.js.map +1 -0
  66. package/dist/context.d.ts +3 -1
  67. package/dist/context.js +1 -1
  68. package/dist/errors.d.ts +18 -17
  69. package/dist/errors.js +1 -1
  70. package/dist/evaluator.d.ts +3 -1
  71. package/dist/flow.d.ts +29 -8
  72. package/dist/flow.js +2 -2
  73. package/dist/index.d.ts +7 -7
  74. package/dist/index.js +27 -15
  75. package/dist/linter.d.ts +5 -3
  76. package/dist/linter.js +2 -2
  77. package/dist/logger.d.ts +3 -1
  78. package/dist/node.d.ts +3 -1
  79. package/dist/node.js +1 -1
  80. package/dist/nodes/batch-gather.d.ts +9 -0
  81. package/dist/nodes/batch-gather.js +4 -0
  82. package/dist/nodes/batch-gather.js.map +1 -0
  83. package/dist/nodes/batch-scatter.d.ts +9 -0
  84. package/dist/nodes/batch-scatter.js +4 -0
  85. package/dist/nodes/batch-scatter.js.map +1 -0
  86. package/dist/nodes/subflow.d.ts +9 -0
  87. package/dist/nodes/subflow.js +10 -0
  88. package/dist/nodes/subflow.js.map +1 -0
  89. package/dist/nodes/wait.d.ts +9 -0
  90. package/dist/nodes/wait.js +4 -0
  91. package/dist/nodes/wait.js.map +1 -0
  92. package/dist/runtime/adapter.d.ts +6 -5
  93. package/dist/runtime/adapter.js +20 -10
  94. package/dist/runtime/builtin-keys.d.ts +38 -0
  95. package/dist/runtime/builtin-keys.js +10 -0
  96. package/dist/runtime/builtin-keys.js.map +1 -0
  97. package/dist/runtime/execution-context.d.ts +3 -0
  98. package/dist/runtime/execution-context.js +6 -0
  99. package/dist/runtime/execution-context.js.map +1 -0
  100. package/dist/runtime/executors.d.ts +3 -26
  101. package/dist/runtime/executors.js +2 -2
  102. package/dist/runtime/index.d.ts +5 -6
  103. package/dist/runtime/index.js +22 -11
  104. package/dist/runtime/node-executor-factory.d.ts +12 -0
  105. package/dist/runtime/node-executor-factory.js +6 -0
  106. package/dist/runtime/node-executor-factory.js.map +1 -0
  107. package/dist/runtime/orchestrator.d.ts +9 -0
  108. package/dist/runtime/orchestrator.js +8 -0
  109. package/dist/runtime/orchestrator.js.map +1 -0
  110. package/dist/runtime/orchestrators/step-by-step.d.ts +16 -0
  111. package/dist/runtime/orchestrators/step-by-step.js +5 -0
  112. package/dist/runtime/orchestrators/step-by-step.js.map +1 -0
  113. package/dist/runtime/orchestrators/utils.d.ts +35 -0
  114. package/dist/runtime/orchestrators/utils.js +4 -0
  115. package/dist/runtime/orchestrators/utils.js.map +1 -0
  116. package/dist/runtime/runtime.d.ts +3 -35
  117. package/dist/runtime/runtime.js +19 -9
  118. package/dist/runtime/state.d.ts +3 -21
  119. package/dist/runtime/state.js +3 -2
  120. package/dist/runtime/traverser.d.ts +3 -26
  121. package/dist/runtime/traverser.js +2 -3
  122. package/dist/runtime/types.d.ts +3 -16
  123. package/dist/runtime/types.js +1 -1
  124. package/dist/runtime/workflow-logic-handler.d.ts +17 -0
  125. package/dist/runtime/workflow-logic-handler.js +5 -0
  126. package/dist/runtime/workflow-logic-handler.js.map +1 -0
  127. package/dist/sanitizer.d.ts +3 -1
  128. package/dist/serializer.d.ts +3 -1
  129. package/dist/testing/event-logger.d.ts +63 -0
  130. package/dist/testing/event-logger.js +3 -0
  131. package/dist/testing/event-logger.js.map +1 -0
  132. package/dist/testing/index.d.ts +6 -0
  133. package/dist/testing/index.js +31 -0
  134. package/dist/testing/index.js.map +1 -0
  135. package/dist/testing/run-with-trace.d.ts +38 -0
  136. package/dist/testing/run-with-trace.js +29 -0
  137. package/dist/testing/run-with-trace.js.map +1 -0
  138. package/dist/testing/stepper.d.ts +79 -0
  139. package/dist/testing/stepper.js +11 -0
  140. package/dist/testing/stepper.js.map +1 -0
  141. package/dist/types-ezHUBdpL.d.ts +564 -0
  142. package/dist/types.d.ts +3 -1
  143. package/package.json +6 -2
  144. package/dist/chunk-3XVVR2SR.js +0 -417
  145. package/dist/chunk-3XVVR2SR.js.map +0 -1
  146. package/dist/chunk-4A627Q6L.js +0 -147
  147. package/dist/chunk-4A627Q6L.js.map +0 -1
  148. package/dist/chunk-5ZXV3R5D.js +0 -28
  149. package/dist/chunk-5ZXV3R5D.js.map +0 -1
  150. package/dist/chunk-CSZ6EOWG.js +0 -61
  151. package/dist/chunk-CSZ6EOWG.js.map +0 -1
  152. package/dist/chunk-HMR2GEGE.js +0 -3
  153. package/dist/chunk-HN72TZY5.js.map +0 -1
  154. package/dist/chunk-KWQHFT7E.js.map +0 -1
  155. package/dist/chunk-M2FRTT2K.js +0 -144
  156. package/dist/chunk-M2FRTT2K.js.map +0 -1
  157. package/dist/chunk-NBIRTKZ7.js +0 -192
  158. package/dist/chunk-NBIRTKZ7.js.map +0 -1
  159. package/dist/chunk-O3XD45IL.js.map +0 -1
  160. package/dist/chunk-U5V5O5MN.js.map +0 -1
  161. package/dist/chunk-UETC63DP.js.map +0 -1
  162. package/dist/types-CQCe_nBM.d.ts +0 -214
@@ -0,0 +1,143 @@
1
+ import { AsyncContextView } from './chunk-R3HQXIEL.js';
2
+ import { FlowcraftError } from './chunk-BCRWXTWX.js';
3
+
4
+ // src/runtime/workflow-logic-handler.ts
5
+ var WorkflowLogicHandler = class {
6
+ constructor(evaluator, eventBus) {
7
+ this.evaluator = evaluator;
8
+ this.eventBus = eventBus;
9
+ }
10
+ async determineNextNodes(blueprint, completedNodeId, result, context, executionId) {
11
+ let effectiveSourceNodeId = completedNodeId;
12
+ const completedNodeDef = blueprint.nodes.find((n) => n.id === completedNodeId);
13
+ if (completedNodeDef?.uses === "loop-controller" && result.action !== "continue")
14
+ effectiveSourceNodeId = completedNodeDef.params?.endNodeId;
15
+ let directOutgoingEdges = blueprint.edges.filter((edge) => edge.source === effectiveSourceNodeId);
16
+ if (effectiveSourceNodeId !== completedNodeId)
17
+ directOutgoingEdges = directOutgoingEdges.filter((edge) => edge.target !== completedNodeId);
18
+ const nodesThisIsAFallbackFor = blueprint.nodes.filter((n) => n.config?.fallback === completedNodeId);
19
+ const inheritedOutgoingEdges = nodesThisIsAFallbackFor.flatMap(
20
+ (originalNode) => blueprint.edges.filter((edge) => edge.source === originalNode.id)
21
+ );
22
+ const allPossibleEdges = [...directOutgoingEdges, ...inheritedOutgoingEdges];
23
+ const outgoingEdges = [
24
+ ...new Map(
25
+ allPossibleEdges.map((edge) => [
26
+ `${edge.source}-${edge.target}-${edge.action || ""}-${edge.condition || ""}`,
27
+ edge
28
+ ])
29
+ ).values()
30
+ ];
31
+ const matched = [];
32
+ const evaluateEdge = async (edge) => {
33
+ if (!edge.condition) return true;
34
+ const contextData = context.type === "sync" ? context.toJSON() : await context.toJSON();
35
+ const evaluationResult = !!this.evaluator.evaluate(edge.condition, {
36
+ ...contextData,
37
+ result
38
+ });
39
+ await this.eventBus.emit({
40
+ type: "edge:evaluate",
41
+ payload: { source: edge.source, target: edge.target, condition: edge.condition, result: evaluationResult }
42
+ });
43
+ return evaluationResult;
44
+ };
45
+ if (result.action) {
46
+ const actionEdges = outgoingEdges.filter((edge) => edge.action === result.action);
47
+ for (const edge of actionEdges) {
48
+ if (await evaluateEdge(edge)) {
49
+ const targetNode = blueprint.nodes.find((n) => n.id === edge.target);
50
+ if (targetNode) matched.push({ node: targetNode, edge });
51
+ } else {
52
+ await this.eventBus.emit({
53
+ type: "node:skipped",
54
+ payload: { nodeId: completedNodeId, edge, executionId: executionId || "", blueprintId: blueprint.id }
55
+ });
56
+ }
57
+ }
58
+ }
59
+ if (matched.length === 0) {
60
+ const defaultEdges = outgoingEdges.filter((edge) => !edge.action);
61
+ for (const edge of defaultEdges) {
62
+ if (await evaluateEdge(edge)) {
63
+ const targetNode = blueprint.nodes.find((n) => n.id === edge.target);
64
+ if (targetNode) matched.push({ node: targetNode, edge });
65
+ } else {
66
+ await this.eventBus.emit({
67
+ type: "node:skipped",
68
+ payload: { nodeId: completedNodeId, edge, executionId: executionId || "", blueprintId: blueprint.id }
69
+ });
70
+ }
71
+ }
72
+ }
73
+ return matched;
74
+ }
75
+ async applyEdgeTransform(edge, sourceResult, targetNode, context, allPredecessors) {
76
+ const asyncContext = context.type === "sync" ? new AsyncContextView(context) : context;
77
+ const predecessors = allPredecessors?.get(targetNode.id);
78
+ const hasSinglePredecessor = predecessors && predecessors.size === 1;
79
+ const hasExplicitInputs = targetNode.inputs !== void 0;
80
+ const hasEdgeTransform = edge.transform !== void 0;
81
+ if (!hasExplicitInputs && !hasSinglePredecessor && !hasEdgeTransform) {
82
+ return;
83
+ }
84
+ const finalInput = edge.transform ? this.evaluator.evaluate(edge.transform, {
85
+ input: sourceResult.output,
86
+ context: await asyncContext.toJSON()
87
+ }) : sourceResult.output;
88
+ const inputKey = `_inputs.${targetNode.id}`;
89
+ await asyncContext.set(inputKey, finalInput);
90
+ await this.eventBus.emit({
91
+ type: "context:change",
92
+ payload: { sourceNode: edge.source, key: inputKey, value: finalInput }
93
+ });
94
+ if (!hasExplicitInputs) {
95
+ targetNode.inputs = inputKey;
96
+ }
97
+ }
98
+ async resolveNodeInput(nodeId, blueprint, context) {
99
+ const nodeDef = blueprint.nodes.find((n) => n.id === nodeId);
100
+ if (!nodeDef) {
101
+ throw new FlowcraftError(`Node '${nodeId}' not found in blueprint.`, {
102
+ nodeId,
103
+ blueprintId: blueprint.id,
104
+ isFatal: false
105
+ });
106
+ }
107
+ const asyncContext = context.type === "sync" ? new AsyncContextView(context) : context;
108
+ if (nodeDef.inputs) {
109
+ if (typeof nodeDef.inputs === "string") {
110
+ const key = nodeDef.inputs;
111
+ if (key.startsWith("_")) return await asyncContext.get(key);
112
+ const outputKey = `_outputs.${key}`;
113
+ if (await asyncContext.has(outputKey)) {
114
+ return await asyncContext.get(outputKey);
115
+ }
116
+ return await asyncContext.get(key);
117
+ }
118
+ if (typeof nodeDef.inputs === "object") {
119
+ const input = {};
120
+ for (const key in nodeDef.inputs) {
121
+ const contextKey = nodeDef.inputs[key];
122
+ if (contextKey.startsWith("_")) {
123
+ input[key] = await asyncContext.get(contextKey);
124
+ } else {
125
+ const outputKey = `_outputs.${contextKey}`;
126
+ if (await asyncContext.has(outputKey)) {
127
+ input[key] = await asyncContext.get(outputKey);
128
+ } else {
129
+ input[key] = await asyncContext.get(contextKey);
130
+ }
131
+ }
132
+ }
133
+ return input;
134
+ }
135
+ }
136
+ const inputKey = `_inputs.${nodeDef.id}`;
137
+ return await asyncContext.get(inputKey);
138
+ }
139
+ };
140
+
141
+ export { WorkflowLogicHandler };
142
+ //# sourceMappingURL=chunk-MCGK3FXQ.js.map
143
+ //# sourceMappingURL=chunk-MCGK3FXQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/workflow-logic-handler.ts"],"names":[],"mappings":";;;;AAYO,IAAM,uBAAN,MAA2B;AAAA,EACjC,WAAA,CACkB,WACA,QAAA,EAChB;AAFgB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EACf;AAAA,EAEH,MAAa,kBAAA,CACZ,SAAA,EACA,eAAA,EACA,MAAA,EACA,SACA,WAAA,EAC4D;AAC5D,IAAA,IAAI,qBAAA,GAAwB,eAAA;AAC5B,IAAA,MAAM,gBAAA,GAAmB,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,eAAe,CAAA;AAC7E,IAAA,IAAI,gBAAA,EAAkB,IAAA,KAAS,iBAAA,IAAqB,MAAA,CAAO,MAAA,KAAW,UAAA;AAErE,MAAA,qBAAA,GAAwB,iBAAiB,MAAA,EAAQ,SAAA;AAElD,IAAA,IAAI,mBAAA,GAAsB,UAAU,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,WAAW,qBAAqB,CAAA;AAChG,IAAA,IAAI,qBAAA,KAA0B,eAAA;AAE7B,MAAA,mBAAA,GAAsB,oBAAoB,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,WAAW,eAAe,CAAA;AAE3F,IAAA,MAAM,uBAAA,GAA0B,UAAU,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,EAAQ,QAAA,KAAa,eAAe,CAAA;AACpG,IAAA,MAAM,yBAAyB,uBAAA,CAAwB,OAAA;AAAA,MAAQ,CAAC,YAAA,KAC/D,SAAA,CAAU,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,KAAW,YAAA,CAAa,EAAE;AAAA,KACjE;AACA,IAAA,MAAM,gBAAA,GAAmB,CAAC,GAAG,mBAAA,EAAqB,GAAG,sBAAsB,CAAA;AAC3E,IAAA,MAAM,aAAA,GAAgB;AAAA,MACrB,GAAG,IAAI,GAAA;AAAA,QACN,gBAAA,CAAiB,GAAA,CAAI,CAAC,IAAA,KAAS;AAAA,UAC9B,CAAA,EAAG,IAAA,CAAK,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,IAAU,EAAE,CAAA,CAAA,EAAI,IAAA,CAAK,aAAa,EAAE,CAAA,CAAA;AAAA,UAC1E;AAAA,SACA;AAAA,QACA,MAAA;AAAO,KACV;AAEA,IAAA,MAAM,UAA4D,EAAC;AACnE,IAAA,MAAM,YAAA,GAAe,OAAO,IAAA,KAA2C;AACtE,MAAA,IAAI,CAAC,IAAA,CAAK,SAAA,EAAW,OAAO,IAAA;AAC5B,MAAA,MAAM,WAAA,GAAc,QAAQ,IAAA,KAAS,MAAA,GAAS,QAAQ,MAAA,EAAO,GAAI,MAAM,OAAA,CAAQ,MAAA,EAAO;AACtF,MAAA,MAAM,mBAAmB,CAAC,CAAC,KAAK,SAAA,CAAU,QAAA,CAAS,KAAK,SAAA,EAAW;AAAA,QAClE,GAAG,WAAA;AAAA,QACH;AAAA,OACA,CAAA;AACD,MAAA,MAAM,IAAA,CAAK,SAAS,IAAA,CAAK;AAAA,QACxB,IAAA,EAAM,eAAA;AAAA,QACN,OAAA,EAAS,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,SAAA,EAAW,IAAA,CAAK,SAAA,EAAW,MAAA,EAAQ,gBAAA;AAAiB,OACzG,CAAA;AACD,MAAA,OAAO,gBAAA;AAAA,IACR,CAAA;AAEA,IAAA,IAAI,OAAO,MAAA,EAAQ;AAClB,MAAA,MAAM,WAAA,GAAc,cAAc,MAAA,CAAO,CAAC,SAAS,IAAA,CAAK,MAAA,KAAW,OAAO,MAAM,CAAA;AAChF,MAAA,KAAA,MAAW,QAAQ,WAAA,EAAa;AAC/B,QAAA,IAAI,MAAM,YAAA,CAAa,IAAI,CAAA,EAAG;AAC7B,UAAA,MAAM,UAAA,GAAa,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,IAAA,CAAK,MAAM,CAAA;AACnE,UAAA,IAAI,YAAY,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,UAAA,EAAY,MAAM,CAAA;AAAA,QACxD,CAAA,MAAO;AACN,UAAA,MAAM,IAAA,CAAK,SAAS,IAAA,CAAK;AAAA,YACxB,IAAA,EAAM,cAAA;AAAA,YACN,OAAA,EAAS,EAAE,MAAA,EAAQ,eAAA,EAAiB,IAAA,EAAM,aAAa,WAAA,IAAe,EAAA,EAAI,WAAA,EAAa,SAAA,CAAU,EAAA;AAAG,WACpG,CAAA;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAEA,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACzB,MAAA,MAAM,eAAe,aAAA,CAAc,MAAA,CAAO,CAAC,IAAA,KAAS,CAAC,KAAK,MAAM,CAAA;AAChE,MAAA,KAAA,MAAW,QAAQ,YAAA,EAAc;AAChC,QAAA,IAAI,MAAM,YAAA,CAAa,IAAI,CAAA,EAAG;AAC7B,UAAA,MAAM,UAAA,GAAa,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,IAAA,CAAK,MAAM,CAAA;AACnE,UAAA,IAAI,YAAY,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,UAAA,EAAY,MAAM,CAAA;AAAA,QACxD,CAAA,MAAO;AACN,UAAA,MAAM,IAAA,CAAK,SAAS,IAAA,CAAK;AAAA,YACxB,IAAA,EAAM,cAAA;AAAA,YACN,OAAA,EAAS,EAAE,MAAA,EAAQ,eAAA,EAAiB,IAAA,EAAM,aAAa,WAAA,IAAe,EAAA,EAAI,WAAA,EAAa,SAAA,CAAU,EAAA;AAAG,WACpG,CAAA;AAAA,QACF;AAAA,MACD;AAAA,IACD;AACA,IAAA,OAAO,OAAA;AAAA,EACR;AAAA,EAEA,MAAa,kBAAA,CACZ,IAAA,EACA,YAAA,EACA,UAAA,EACA,SACA,eAAA,EACgB;AAChB,IAAA,MAAM,eAAe,OAAA,CAAQ,IAAA,KAAS,SAAS,IAAI,gBAAA,CAAiB,OAAO,CAAA,GAAI,OAAA;AAC/E,IAAA,MAAM,YAAA,GAAe,eAAA,EAAiB,GAAA,CAAI,UAAA,CAAW,EAAE,CAAA;AACvD,IAAA,MAAM,oBAAA,GAAuB,YAAA,IAAgB,YAAA,CAAa,IAAA,KAAS,CAAA;AACnE,IAAA,MAAM,iBAAA,GAAoB,WAAW,MAAA,KAAW,MAAA;AAChD,IAAA,MAAM,gBAAA,GAAmB,KAAK,SAAA,KAAc,MAAA;AAE5C,IAAA,IAAI,CAAC,iBAAA,IAAqB,CAAC,oBAAA,IAAwB,CAAC,gBAAA,EAAkB;AACrE,MAAA;AAAA,IACD;AAEA,IAAA,MAAM,aAAa,IAAA,CAAK,SAAA,GACrB,KAAK,SAAA,CAAU,QAAA,CAAS,KAAK,SAAA,EAAW;AAAA,MACxC,OAAO,YAAA,CAAa,MAAA;AAAA,MACpB,OAAA,EAAS,MAAM,YAAA,CAAa,MAAA;AAAO,KACnC,IACA,YAAA,CAAa,MAAA;AAChB,IAAA,MAAM,QAAA,GAAW,CAAA,QAAA,EAAW,UAAA,CAAW,EAAE,CAAA,CAAA;AACzC,IAAA,MAAM,YAAA,CAAa,GAAA,CAAI,QAAA,EAAiB,UAAU,CAAA;AAClD,IAAA,MAAM,IAAA,CAAK,SAAS,IAAA,CAAK;AAAA,MACxB,IAAA,EAAM,gBAAA;AAAA,MACN,OAAA,EAAS,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,GAAA,EAAK,QAAA,EAAU,OAAO,UAAA;AAAW,KACrE,CAAA;AACD,IAAA,IAAI,CAAC,iBAAA,EAAmB;AACvB,MAAA,UAAA,CAAW,MAAA,GAAS,QAAA;AAAA,IACrB;AAAA,EACD;AAAA,EAEA,MAAa,gBAAA,CACZ,MAAA,EACA,SAAA,EACA,OAAA,EACe;AACf,IAAA,MAAM,OAAA,GAAU,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,MAAM,CAAA;AAC3D,IAAA,IAAI,CAAC,OAAA,EAAS;AACb,MAAA,MAAM,IAAI,cAAA,CAAe,CAAA,MAAA,EAAS,MAAM,CAAA,yBAAA,CAAA,EAA6B;AAAA,QACpE,MAAA;AAAA,QACA,aAAa,SAAA,CAAU,EAAA;AAAA,QACvB,OAAA,EAAS;AAAA,OACT,CAAA;AAAA,IACF;AACA,IAAA,MAAM,eAAe,OAAA,CAAQ,IAAA,KAAS,SAAS,IAAI,gBAAA,CAAiB,OAAO,CAAA,GAAI,OAAA;AAC/E,IAAA,IAAI,QAAQ,MAAA,EAAQ;AACnB,MAAA,IAAI,OAAO,OAAA,CAAQ,MAAA,KAAW,QAAA,EAAU;AACvC,QAAA,MAAM,MAAM,OAAA,CAAQ,MAAA;AACpB,QAAA,IAAI,GAAA,CAAI,WAAW,GAAG,CAAA,SAAU,MAAM,YAAA,CAAa,IAAI,GAAU,CAAA;AACjE,QAAA,MAAM,SAAA,GAAY,YAAY,GAAG,CAAA,CAAA;AACjC,QAAA,IAAI,MAAM,YAAA,CAAa,GAAA,CAAI,SAAgB,CAAA,EAAG;AAC7C,UAAA,OAAO,MAAM,YAAA,CAAa,GAAA,CAAI,SAAgB,CAAA;AAAA,QAC/C;AACA,QAAA,OAAO,MAAM,YAAA,CAAa,GAAA,CAAI,GAAU,CAAA;AAAA,MACzC;AACA,MAAA,IAAI,OAAO,OAAA,CAAQ,MAAA,KAAW,QAAA,EAAU;AACvC,QAAA,MAAM,QAA6B,EAAC;AACpC,QAAA,KAAA,MAAW,GAAA,IAAO,QAAQ,MAAA,EAAQ;AACjC,UAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAA;AACrC,UAAA,IAAI,UAAA,CAAW,UAAA,CAAW,GAAG,CAAA,EAAG;AAC/B,YAAA,KAAA,CAAM,GAAG,CAAA,GAAI,MAAM,YAAA,CAAa,IAAI,UAAiB,CAAA;AAAA,UACtD,CAAA,MAAO;AACN,YAAA,MAAM,SAAA,GAAY,YAAY,UAAU,CAAA,CAAA;AACxC,YAAA,IAAI,MAAM,YAAA,CAAa,GAAA,CAAI,SAAgB,CAAA,EAAG;AAC7C,cAAA,KAAA,CAAM,GAAG,CAAA,GAAI,MAAM,YAAA,CAAa,IAAI,SAAgB,CAAA;AAAA,YACrD,CAAA,MAAO;AACN,cAAA,KAAA,CAAM,GAAG,CAAA,GAAI,MAAM,YAAA,CAAa,IAAI,UAAiB,CAAA;AAAA,YACtD;AAAA,UACD;AAAA,QACD;AACA,QAAA,OAAO,KAAA;AAAA,MACR;AAAA,IACD;AAEA,IAAA,MAAM,QAAA,GAAW,CAAA,QAAA,EAAW,OAAA,CAAQ,EAAE,CAAA,CAAA;AACtC,IAAA,OAAO,MAAM,YAAA,CAAa,GAAA,CAAI,QAAe,CAAA;AAAA,EAC9C;AACD","file":"chunk-MCGK3FXQ.js","sourcesContent":["import { AsyncContextView } from '../context'\nimport { FlowcraftError } from '../errors'\nimport type {\n\tContextImplementation,\n\tEdgeDefinition,\n\tIEvaluator,\n\tIEventBus,\n\tNodeDefinition,\n\tNodeResult,\n\tWorkflowBlueprint,\n} from '../types'\n\nexport class WorkflowLogicHandler {\n\tconstructor(\n\t\tprivate readonly evaluator: IEvaluator,\n\t\tprivate readonly eventBus: IEventBus,\n\t) {}\n\n\tpublic async determineNextNodes(\n\t\tblueprint: WorkflowBlueprint,\n\t\tcompletedNodeId: string,\n\t\tresult: NodeResult<any, any>,\n\t\tcontext: ContextImplementation<any>,\n\t\texecutionId?: string,\n\t): Promise<{ node: NodeDefinition; edge: EdgeDefinition }[]> {\n\t\tlet effectiveSourceNodeId = completedNodeId\n\t\tconst completedNodeDef = blueprint.nodes.find((n) => n.id === completedNodeId)\n\t\tif (completedNodeDef?.uses === 'loop-controller' && result.action !== 'continue')\n\t\t\t// act as if the loop's end node just finished\n\t\t\teffectiveSourceNodeId = completedNodeDef.params?.endNodeId\n\n\t\tlet directOutgoingEdges = blueprint.edges.filter((edge) => edge.source === effectiveSourceNodeId)\n\t\tif (effectiveSourceNodeId !== completedNodeId)\n\t\t\t// breaking from a loop, ignore the edge that leads back to the controller\n\t\t\tdirectOutgoingEdges = directOutgoingEdges.filter((edge) => edge.target !== completedNodeId)\n\n\t\tconst nodesThisIsAFallbackFor = blueprint.nodes.filter((n) => n.config?.fallback === completedNodeId)\n\t\tconst inheritedOutgoingEdges = nodesThisIsAFallbackFor.flatMap((originalNode) =>\n\t\t\tblueprint.edges.filter((edge) => edge.source === originalNode.id),\n\t\t)\n\t\tconst allPossibleEdges = [...directOutgoingEdges, ...inheritedOutgoingEdges]\n\t\tconst outgoingEdges = [\n\t\t\t...new Map(\n\t\t\t\tallPossibleEdges.map((edge) => [\n\t\t\t\t\t`${edge.source}-${edge.target}-${edge.action || ''}-${edge.condition || ''}`,\n\t\t\t\t\tedge,\n\t\t\t\t]),\n\t\t\t).values(),\n\t\t]\n\n\t\tconst matched: { node: NodeDefinition; edge: EdgeDefinition }[] = []\n\t\tconst evaluateEdge = async (edge: EdgeDefinition): Promise<boolean> => {\n\t\t\tif (!edge.condition) return true\n\t\t\tconst contextData = context.type === 'sync' ? context.toJSON() : await context.toJSON()\n\t\t\tconst evaluationResult = !!this.evaluator.evaluate(edge.condition, {\n\t\t\t\t...contextData,\n\t\t\t\tresult,\n\t\t\t})\n\t\t\tawait this.eventBus.emit({\n\t\t\t\ttype: 'edge:evaluate',\n\t\t\t\tpayload: { source: edge.source, target: edge.target, condition: edge.condition, result: evaluationResult },\n\t\t\t})\n\t\t\treturn evaluationResult\n\t\t}\n\n\t\tif (result.action) {\n\t\t\tconst actionEdges = outgoingEdges.filter((edge) => edge.action === result.action)\n\t\t\tfor (const edge of actionEdges) {\n\t\t\t\tif (await evaluateEdge(edge)) {\n\t\t\t\t\tconst targetNode = blueprint.nodes.find((n) => n.id === edge.target)\n\t\t\t\t\tif (targetNode) matched.push({ node: targetNode, edge })\n\t\t\t\t} else {\n\t\t\t\t\tawait this.eventBus.emit({\n\t\t\t\t\t\ttype: 'node:skipped',\n\t\t\t\t\t\tpayload: { nodeId: completedNodeId, edge, executionId: executionId || '', blueprintId: blueprint.id },\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (matched.length === 0) {\n\t\t\tconst defaultEdges = outgoingEdges.filter((edge) => !edge.action)\n\t\t\tfor (const edge of defaultEdges) {\n\t\t\t\tif (await evaluateEdge(edge)) {\n\t\t\t\t\tconst targetNode = blueprint.nodes.find((n) => n.id === edge.target)\n\t\t\t\t\tif (targetNode) matched.push({ node: targetNode, edge })\n\t\t\t\t} else {\n\t\t\t\t\tawait this.eventBus.emit({\n\t\t\t\t\t\ttype: 'node:skipped',\n\t\t\t\t\t\tpayload: { nodeId: completedNodeId, edge, executionId: executionId || '', blueprintId: blueprint.id },\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn matched\n\t}\n\n\tpublic async applyEdgeTransform(\n\t\tedge: EdgeDefinition,\n\t\tsourceResult: NodeResult<any, any>,\n\t\ttargetNode: NodeDefinition,\n\t\tcontext: ContextImplementation<any>,\n\t\tallPredecessors?: Map<string, Set<string>>,\n\t): Promise<void> {\n\t\tconst asyncContext = context.type === 'sync' ? new AsyncContextView(context) : context\n\t\tconst predecessors = allPredecessors?.get(targetNode.id)\n\t\tconst hasSinglePredecessor = predecessors && predecessors.size === 1\n\t\tconst hasExplicitInputs = targetNode.inputs !== undefined\n\t\tconst hasEdgeTransform = edge.transform !== undefined\n\n\t\tif (!hasExplicitInputs && !hasSinglePredecessor && !hasEdgeTransform) {\n\t\t\treturn\n\t\t}\n\n\t\tconst finalInput = edge.transform\n\t\t\t? this.evaluator.evaluate(edge.transform, {\n\t\t\t\t\tinput: sourceResult.output,\n\t\t\t\t\tcontext: await asyncContext.toJSON(),\n\t\t\t\t})\n\t\t\t: sourceResult.output\n\t\tconst inputKey = `_inputs.${targetNode.id}`\n\t\tawait asyncContext.set(inputKey as any, finalInput)\n\t\tawait this.eventBus.emit({\n\t\t\ttype: 'context:change',\n\t\t\tpayload: { sourceNode: edge.source, key: inputKey, value: finalInput },\n\t\t})\n\t\tif (!hasExplicitInputs) {\n\t\t\ttargetNode.inputs = inputKey\n\t\t}\n\t}\n\n\tpublic async resolveNodeInput(\n\t\tnodeId: string,\n\t\tblueprint: WorkflowBlueprint,\n\t\tcontext: ContextImplementation<any>,\n\t): Promise<any> {\n\t\tconst nodeDef = blueprint.nodes.find((n) => n.id === nodeId)\n\t\tif (!nodeDef) {\n\t\t\tthrow new FlowcraftError(`Node '${nodeId}' not found in blueprint.`, {\n\t\t\t\tnodeId,\n\t\t\t\tblueprintId: blueprint.id,\n\t\t\t\tisFatal: false,\n\t\t\t})\n\t\t}\n\t\tconst asyncContext = context.type === 'sync' ? new AsyncContextView(context) : context\n\t\tif (nodeDef.inputs) {\n\t\t\tif (typeof nodeDef.inputs === 'string') {\n\t\t\t\tconst key = nodeDef.inputs\n\t\t\t\tif (key.startsWith('_')) return await asyncContext.get(key as any)\n\t\t\t\tconst outputKey = `_outputs.${key}`\n\t\t\t\tif (await asyncContext.has(outputKey as any)) {\n\t\t\t\t\treturn await asyncContext.get(outputKey as any)\n\t\t\t\t}\n\t\t\t\treturn await asyncContext.get(key as any)\n\t\t\t}\n\t\t\tif (typeof nodeDef.inputs === 'object') {\n\t\t\t\tconst input: Record<string, any> = {}\n\t\t\t\tfor (const key in nodeDef.inputs) {\n\t\t\t\t\tconst contextKey = nodeDef.inputs[key]\n\t\t\t\t\tif (contextKey.startsWith('_')) {\n\t\t\t\t\t\tinput[key] = await asyncContext.get(contextKey as any)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst outputKey = `_outputs.${contextKey}`\n\t\t\t\t\t\tif (await asyncContext.has(outputKey as any)) {\n\t\t\t\t\t\t\tinput[key] = await asyncContext.get(outputKey as any)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinput[key] = await asyncContext.get(contextKey as any)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn input\n\t\t\t}\n\t\t}\n\t\t// Default to standardized input key\n\t\tconst inputKey = `_inputs.${nodeDef.id}`\n\t\treturn await asyncContext.get(inputKey as any)\n\t}\n}\n"]}
@@ -0,0 +1,82 @@
1
+ // src/testing/event-logger.ts
2
+ var InMemoryEventLogger = class {
3
+ events = [];
4
+ /**
5
+ * Clears all captured events.
6
+ */
7
+ clear() {
8
+ this.events.length = 0;
9
+ }
10
+ /**
11
+ * The `emit` method required by the IEventBus interface.
12
+ * It simply pushes the received event into the internal events array.
13
+ * @param event The FlowcraftEvent to record.
14
+ */
15
+ async emit(event) {
16
+ this.events.push(event);
17
+ }
18
+ /**
19
+ * Finds the first event of a specific type.
20
+ * @param type The event type to find (e.g., 'node:error').
21
+ * @returns The first matching event, or undefined if not found.
22
+ */
23
+ find(type) {
24
+ return this.events.find((e) => e.type === type);
25
+ }
26
+ /**
27
+ * Filters events to find all occurrences of a specific type.
28
+ * @param type The event type to filter by.
29
+ * @returns An array of matching events.
30
+ */
31
+ filter(type) {
32
+ return this.events.filter((e) => e.type === type);
33
+ }
34
+ /**
35
+ * Prints a formatted log of all captured events to the console.
36
+ * Ideal for debugging failing tests.
37
+ * @param title A title for the log output.
38
+ */
39
+ printLog(title = "Workflow Execution Trace") {
40
+ console.log(`
41
+ --- ${title} ---`);
42
+ if (this.events.length === 0) {
43
+ console.log("No events were captured.");
44
+ console.log("----------------------------------\n");
45
+ return;
46
+ }
47
+ this.events.forEach((event, index) => {
48
+ const { type, payload } = event;
49
+ console.log(`
50
+ [${index + 1}] ${type}`);
51
+ switch (type) {
52
+ case "node:start":
53
+ console.log(` - Node: "${payload.nodeId}" | Input: ${JSON.stringify(payload.input)}`);
54
+ break;
55
+ case "edge:evaluate":
56
+ console.log(` - Edge: "${payload.source}" -> "${payload.target}"`);
57
+ console.log(` - Condition: ${payload.condition || "N/A"} | Result: ${payload.result}`);
58
+ break;
59
+ case "context:change":
60
+ console.log(
61
+ ` - Node "${payload.sourceNode}" wrote to context -> Key: "${payload.key}" | Value: ${JSON.stringify(payload.value)}`
62
+ );
63
+ break;
64
+ case "node:finish":
65
+ console.log(` - Node: "${payload.nodeId}" | Result: ${JSON.stringify(payload.result)}`);
66
+ break;
67
+ case "node:error":
68
+ console.log(` - Node: "${payload.nodeId}"`);
69
+ console.error(" - Error:", payload.error);
70
+ break;
71
+ default:
72
+ console.log(` - Payload: ${JSON.stringify(payload, null, 2)}`);
73
+ }
74
+ });
75
+ console.log(`
76
+ --- End of Trace ---`);
77
+ }
78
+ };
79
+
80
+ export { InMemoryEventLogger };
81
+ //# sourceMappingURL=chunk-MUYLRTSR.js.map
82
+ //# sourceMappingURL=chunk-MUYLRTSR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing/event-logger.ts"],"names":[],"mappings":"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","file":"chunk-MUYLRTSR.js","sourcesContent":["import type { FlowcraftEvent, IEventBus } from '../types'\n\n/**\n * A test utility that implements IEventBus to capture all workflow events\n * in memory, acting as a \"flight recorder\" for behavioral testing.\n *\n * @example\n * // In your test file (e.g., resiliency.test.ts)\n * it('should retry a node on failure', async () => {\n * const eventLogger = new InMemoryEventLogger();\n * const runtime = new FlowRuntime({ eventBus: eventLogger });\n *\n * const flow = createFlow('retry-flow')\n * .node('api-call', vi.fn().mockRejectedValueOnce(new Error('fail')), {\n * config: { maxRetries: 2 },\n * });\n *\n * await runtime.run(flow.toBlueprint());\n *\n * // Assert against the captured event history to prove behavior.\n * const retryEvents = eventLogger.filter('node:retry');\n * expect(retryEvents).toHaveLength(1); // The first attempt is not a \"retry\"\n * });\n */\nexport class InMemoryEventLogger implements IEventBus {\n\tpublic readonly events: FlowcraftEvent[] = []\n\n\t/**\n\t * Clears all captured events.\n\t */\n\tpublic clear(): void {\n\t\tthis.events.length = 0\n\t}\n\n\t/**\n\t * The `emit` method required by the IEventBus interface.\n\t * It simply pushes the received event into the internal events array.\n\t * @param event The FlowcraftEvent to record.\n\t */\n\tpublic async emit(event: FlowcraftEvent): Promise<void> {\n\t\tthis.events.push(event)\n\t}\n\n\t/**\n\t * Finds the first event of a specific type.\n\t * @param type The event type to find (e.g., 'node:error').\n\t * @returns The first matching event, or undefined if not found.\n\t */\n\tpublic find<T extends FlowcraftEvent['type']>(type: T): Extract<FlowcraftEvent, { type: T }> | undefined {\n\t\treturn this.events.find((e) => e.type === type) as Extract<FlowcraftEvent, { type: T }> | undefined\n\t}\n\n\t/**\n\t * Filters events to find all occurrences of a specific type.\n\t * @param type The event type to filter by.\n\t * @returns An array of matching events.\n\t */\n\tpublic filter<T extends FlowcraftEvent['type']>(type: T): Extract<FlowcraftEvent, { type: T }>[] {\n\t\treturn this.events.filter((e) => e.type === type) as Extract<FlowcraftEvent, { type: T }>[]\n\t}\n\n\t/**\n\t * Prints a formatted log of all captured events to the console.\n\t * Ideal for debugging failing tests.\n\t * @param title A title for the log output.\n\t */\n\tpublic printLog(title = 'Workflow Execution Trace'): void {\n\t\tconsole.log(`\\n--- ${title} ---`)\n\t\tif (this.events.length === 0) {\n\t\t\tconsole.log('No events were captured.')\n\t\t\tconsole.log('----------------------------------\\n')\n\t\t\treturn\n\t\t}\n\n\t\tthis.events.forEach((event, index) => {\n\t\t\tconst { type, payload } = event\n\t\t\tconsole.log(`\\n[${index + 1}] ${type}`)\n\n\t\t\t// Custom formatting for a more intuitive trace\n\t\t\tswitch (type) {\n\t\t\t\tcase 'node:start':\n\t\t\t\t\tconsole.log(` - Node: \"${payload.nodeId}\" | Input: ${JSON.stringify(payload.input)}`)\n\t\t\t\t\tbreak\n\t\t\t\tcase 'edge:evaluate':\n\t\t\t\t\tconsole.log(` - Edge: \"${payload.source}\" -> \"${payload.target}\"`)\n\t\t\t\t\tconsole.log(` - Condition: ${payload.condition || 'N/A'} | Result: ${payload.result}`)\n\t\t\t\t\tbreak\n\t\t\t\tcase 'context:change':\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t` - Node \"${payload.sourceNode}\" wrote to context -> Key: \"${payload.key}\" | Value: ${JSON.stringify(payload.value)}`,\n\t\t\t\t\t)\n\t\t\t\t\tbreak\n\t\t\t\tcase 'node:finish':\n\t\t\t\t\tconsole.log(` - Node: \"${payload.nodeId}\" | Result: ${JSON.stringify(payload.result)}`)\n\t\t\t\t\tbreak\n\t\t\t\tcase 'node:error':\n\t\t\t\t\tconsole.log(` - Node: \"${payload.nodeId}\"`)\n\t\t\t\t\tconsole.error(' - Error:', payload.error)\n\t\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.log(` - Payload: ${JSON.stringify(payload, null, 2)}`)\n\t\t\t}\n\t\t})\n\t\tconsole.log(`\\n--- End of Trace ---`)\n\t}\n}\n"]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-NVJ3ZO3P.js.map
3
+ //# sourceMappingURL=chunk-NVJ3ZO3P.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-HMR2GEGE.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-NVJ3ZO3P.js"}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-NVLZFLYM.js.map
3
+ //# sourceMappingURL=chunk-NVLZFLYM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-NVLZFLYM.js"}
@@ -0,0 +1,300 @@
1
+ import { FlowcraftError } from './chunk-BCRWXTWX.js';
2
+
3
+ // src/runtime/executors.ts
4
+ async function withRetries(executor, maxRetries, nodeDef, context, executionId, signal, eventBus) {
5
+ let lastError;
6
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
7
+ try {
8
+ signal?.throwIfAborted();
9
+ const result = await executor();
10
+ if (attempt > 1) {
11
+ context.dependencies.logger.info(`Node execution succeeded after retry`, {
12
+ nodeId: nodeDef.id,
13
+ attempt,
14
+ executionId
15
+ });
16
+ }
17
+ return result;
18
+ } catch (error) {
19
+ lastError = error;
20
+ if (error instanceof DOMException && error.name === "AbortError") {
21
+ throw new FlowcraftError("Workflow cancelled", {
22
+ isFatal: false
23
+ });
24
+ }
25
+ if (error instanceof FlowcraftError && error.isFatal) break;
26
+ if (attempt < maxRetries) {
27
+ context.dependencies.logger.warn(`Node execution failed, retrying`, {
28
+ nodeId: nodeDef.id,
29
+ attempt,
30
+ maxRetries,
31
+ error: error instanceof Error ? error.message : String(error),
32
+ executionId
33
+ });
34
+ if (eventBus) {
35
+ await eventBus.emit({
36
+ type: "node:retry",
37
+ payload: {
38
+ nodeId: nodeDef.id,
39
+ attempt,
40
+ executionId: executionId || "",
41
+ blueprintId: context.dependencies.blueprint?.id || ""
42
+ }
43
+ });
44
+ }
45
+ } else {
46
+ context.dependencies.logger.error(`Node execution failed after all retries`, {
47
+ nodeId: nodeDef.id,
48
+ attempts: maxRetries,
49
+ error: error instanceof Error ? error.message : String(error),
50
+ executionId
51
+ });
52
+ }
53
+ }
54
+ }
55
+ throw lastError;
56
+ }
57
+ var FunctionNodeExecutor = class {
58
+ constructor(implementation, maxRetries, eventBus) {
59
+ this.implementation = implementation;
60
+ this.maxRetries = maxRetries;
61
+ this.eventBus = eventBus;
62
+ }
63
+ async execute(nodeDef, context, executionId, signal) {
64
+ return withRetries(
65
+ () => this.implementation(context),
66
+ this.maxRetries,
67
+ nodeDef,
68
+ context,
69
+ executionId,
70
+ signal,
71
+ this.eventBus
72
+ );
73
+ }
74
+ };
75
+ var ClassNodeExecutor = class {
76
+ constructor(implementation, maxRetries, eventBus) {
77
+ this.implementation = implementation;
78
+ this.maxRetries = maxRetries;
79
+ this.eventBus = eventBus;
80
+ }
81
+ async execute(nodeDef, context, executionId, signal) {
82
+ const instance = new this.implementation(nodeDef.params || {}, nodeDef.id);
83
+ let lastError;
84
+ try {
85
+ signal?.throwIfAborted();
86
+ const prepResult = await instance.prep(context);
87
+ let execResult;
88
+ try {
89
+ execResult = await withRetries(
90
+ () => instance.exec(prepResult, context),
91
+ this.maxRetries,
92
+ nodeDef,
93
+ context,
94
+ executionId,
95
+ signal,
96
+ this.eventBus
97
+ );
98
+ } catch (error) {
99
+ lastError = error instanceof Error ? error : new Error(String(error));
100
+ if (error instanceof DOMException && error.name === "AbortError") {
101
+ throw new FlowcraftError("Workflow cancelled", {
102
+ isFatal: false
103
+ });
104
+ }
105
+ if (error instanceof FlowcraftError && error.isFatal) {
106
+ throw error;
107
+ }
108
+ }
109
+ if (lastError) {
110
+ signal?.throwIfAborted();
111
+ execResult = await instance.fallback(lastError, context);
112
+ }
113
+ signal?.throwIfAborted();
114
+ if (!execResult) {
115
+ throw new Error("Execution failed after all retries");
116
+ }
117
+ return await instance.post(execResult, context);
118
+ } catch (error) {
119
+ lastError = error instanceof Error ? error : new Error(String(error));
120
+ if (error instanceof DOMException && error.name === "AbortError") {
121
+ throw new FlowcraftError("Workflow cancelled", {
122
+ isFatal: false
123
+ });
124
+ }
125
+ throw error;
126
+ } finally {
127
+ if (lastError) {
128
+ try {
129
+ await instance.recover(lastError, context);
130
+ } catch (recoverError) {
131
+ context.dependencies.logger.warn(`Recover phase failed`, {
132
+ nodeId: nodeDef.id,
133
+ originalError: lastError.message,
134
+ recoverError: recoverError instanceof Error ? recoverError.message : String(recoverError),
135
+ executionId
136
+ });
137
+ }
138
+ }
139
+ }
140
+ }
141
+ };
142
+ var NodeExecutor = class {
143
+ context;
144
+ nodeDef;
145
+ strategy;
146
+ constructor(config) {
147
+ this.context = config.context;
148
+ this.nodeDef = config.nodeDef;
149
+ this.strategy = config.strategy;
150
+ }
151
+ async execute(input) {
152
+ const asyncContext = this.context.state.getContext();
153
+ const nodeContext = {
154
+ context: asyncContext,
155
+ input,
156
+ params: this.nodeDef.params || {},
157
+ dependencies: {
158
+ ...this.context.services.dependencies,
159
+ logger: this.context.services.logger,
160
+ runtime: this.context,
161
+ workflowState: this.context.state
162
+ },
163
+ signal: this.context.signal
164
+ };
165
+ const beforeHooks = this.context.services.middleware.map((m) => m.beforeNode).filter((hook) => !!hook);
166
+ const afterHooks = this.context.services.middleware.map((m) => m.afterNode).filter((hook) => !!hook);
167
+ const aroundHooks = this.context.services.middleware.map((m) => m.aroundNode).filter((hook) => !!hook);
168
+ const coreExecution = async () => {
169
+ let result;
170
+ let error;
171
+ try {
172
+ for (const hook of beforeHooks) await hook(nodeContext.context, this.nodeDef.id);
173
+ result = await this.strategy.execute(this.nodeDef, nodeContext, this.context.executionId, this.context.signal);
174
+ return { status: "success", result };
175
+ } catch (e) {
176
+ error = e instanceof Error ? e : new Error(String(e));
177
+ const flowcraftError = error instanceof FlowcraftError ? error : new FlowcraftError(`Node '${this.nodeDef.id}' execution failed`, {
178
+ cause: error,
179
+ nodeId: this.nodeDef.id,
180
+ blueprintId: this.context.blueprint.id,
181
+ executionId: this.context.executionId,
182
+ isFatal: false
183
+ });
184
+ const fallbackNodeId = this.nodeDef.config?.fallback;
185
+ if (fallbackNodeId && !flowcraftError.isFatal) {
186
+ this.context.services.logger.warn(`Node failed, fallback required`, {
187
+ nodeId: this.nodeDef.id,
188
+ fallbackNodeId,
189
+ error: error.message,
190
+ executionId: this.context.executionId
191
+ });
192
+ await this.context.services.eventBus.emit({
193
+ type: "node:fallback",
194
+ payload: {
195
+ nodeId: this.nodeDef.id,
196
+ executionId: this.context.executionId || "",
197
+ fallback: fallbackNodeId,
198
+ blueprintId: this.context.blueprint.id
199
+ }
200
+ });
201
+ return { status: "failed_with_fallback", fallbackNodeId, error: flowcraftError };
202
+ }
203
+ return { status: "failed", error: flowcraftError };
204
+ } finally {
205
+ for (const hook of afterHooks) await hook(nodeContext.context, this.nodeDef.id, result, error);
206
+ }
207
+ };
208
+ let executionChain = coreExecution;
209
+ for (let i = aroundHooks.length - 1; i >= 0; i--) {
210
+ const hook = aroundHooks[i];
211
+ const next = executionChain;
212
+ executionChain = async () => {
213
+ let capturedResult;
214
+ const middlewareResult = await hook(nodeContext.context, this.nodeDef.id, async () => {
215
+ capturedResult = await next();
216
+ if (capturedResult.status === "success") {
217
+ return capturedResult.result;
218
+ }
219
+ throw capturedResult.error;
220
+ });
221
+ if (!capturedResult && middlewareResult) {
222
+ return { status: "success", result: middlewareResult };
223
+ }
224
+ if (!capturedResult) {
225
+ throw new Error("Middleware did not call next() and did not return a result");
226
+ }
227
+ return capturedResult;
228
+ };
229
+ }
230
+ try {
231
+ await this.context.services.eventBus.emit({
232
+ type: "node:start",
233
+ payload: {
234
+ nodeId: this.nodeDef.id,
235
+ executionId: this.context.executionId || "",
236
+ input: nodeContext.input,
237
+ blueprintId: this.context.blueprint.id
238
+ }
239
+ });
240
+ const executionResult = await executionChain();
241
+ if (executionResult.status === "success") {
242
+ await this.context.services.eventBus.emit({
243
+ type: "node:finish",
244
+ payload: {
245
+ nodeId: this.nodeDef.id,
246
+ result: executionResult.result,
247
+ executionId: this.context.executionId || "",
248
+ blueprintId: this.context.blueprint.id
249
+ }
250
+ });
251
+ } else {
252
+ await this.context.services.eventBus.emit({
253
+ type: "node:error",
254
+ payload: {
255
+ nodeId: this.nodeDef.id,
256
+ error: executionResult.error,
257
+ executionId: this.context.executionId || "",
258
+ blueprintId: this.context.blueprint.id
259
+ }
260
+ });
261
+ }
262
+ return executionResult;
263
+ } catch (error) {
264
+ const err = error instanceof Error ? error : new Error(String(error));
265
+ const flowcraftError = err instanceof FlowcraftError ? err : new FlowcraftError(`Node '${this.nodeDef.id}' failed execution.`, {
266
+ cause: err,
267
+ nodeId: this.nodeDef.id,
268
+ blueprintId: this.context.blueprint.id,
269
+ executionId: this.context.executionId,
270
+ isFatal: false
271
+ });
272
+ await this.context.services.eventBus.emit({
273
+ type: "node:error",
274
+ payload: {
275
+ nodeId: this.nodeDef.id,
276
+ error: flowcraftError,
277
+ executionId: this.context.executionId || "",
278
+ blueprintId: this.context.blueprint.id
279
+ }
280
+ });
281
+ if (error instanceof DOMException && error.name === "AbortError") {
282
+ throw new FlowcraftError("Workflow cancelled", {
283
+ executionId: this.context.executionId,
284
+ isFatal: false
285
+ });
286
+ }
287
+ throw error instanceof FlowcraftError && !error.isFatal ? error : new FlowcraftError(`Node '${this.nodeDef.id}' failed execution.`, {
288
+ cause: error,
289
+ nodeId: this.nodeDef.id,
290
+ blueprintId: this.context.blueprint.id,
291
+ executionId: this.context.executionId,
292
+ isFatal: false
293
+ });
294
+ }
295
+ }
296
+ };
297
+
298
+ export { ClassNodeExecutor, FunctionNodeExecutor, NodeExecutor };
299
+ //# sourceMappingURL=chunk-ONH7PIJZ.js.map
300
+ //# sourceMappingURL=chunk-ONH7PIJZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/executors.ts"],"names":[],"mappings":"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","file":"chunk-ONH7PIJZ.js","sourcesContent":["import { FlowcraftError } from '../errors'\nimport type { IEventBus, Middleware, NodeClass, NodeContext, NodeDefinition, NodeFunction, NodeResult } from '../types'\nimport type { ExecutionContext } from './execution-context'\n\nasync function withRetries<T>(\n\texecutor: () => Promise<T>,\n\tmaxRetries: number,\n\tnodeDef: NodeDefinition,\n\tcontext: NodeContext<any, any, any>,\n\texecutionId?: string,\n\tsignal?: AbortSignal,\n\teventBus?: IEventBus,\n): Promise<T> {\n\tlet lastError: any\n\tfor (let attempt = 1; attempt <= maxRetries; attempt++) {\n\t\ttry {\n\t\t\tsignal?.throwIfAborted()\n\t\t\tconst result = await executor()\n\t\t\tif (attempt > 1) {\n\t\t\t\tcontext.dependencies.logger.info(`Node execution succeeded after retry`, {\n\t\t\t\t\tnodeId: nodeDef.id,\n\t\t\t\t\tattempt,\n\t\t\t\t\texecutionId,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn result\n\t\t} catch (error) {\n\t\t\tlastError = error\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow new FlowcraftError('Workflow cancelled', {\n\t\t\t\t\tisFatal: false,\n\t\t\t\t})\n\t\t\t}\n\t\t\tif (error instanceof FlowcraftError && error.isFatal) break\n\t\t\tif (attempt < maxRetries) {\n\t\t\t\tcontext.dependencies.logger.warn(`Node execution failed, retrying`, {\n\t\t\t\t\tnodeId: nodeDef.id,\n\t\t\t\t\tattempt,\n\t\t\t\t\tmaxRetries,\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\texecutionId,\n\t\t\t\t})\n\t\t\t\tif (eventBus) {\n\t\t\t\t\tawait eventBus.emit({\n\t\t\t\t\t\ttype: 'node:retry',\n\t\t\t\t\t\tpayload: {\n\t\t\t\t\t\t\tnodeId: nodeDef.id,\n\t\t\t\t\t\t\tattempt,\n\t\t\t\t\t\t\texecutionId: executionId || '',\n\t\t\t\t\t\t\tblueprintId: context.dependencies.blueprint?.id || '',\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcontext.dependencies.logger.error(`Node execution failed after all retries`, {\n\t\t\t\t\tnodeId: nodeDef.id,\n\t\t\t\t\tattempts: maxRetries,\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\texecutionId,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\tthrow lastError\n}\n\nexport interface ExecutionStrategy {\n\texecute: (\n\t\tnodeDef: NodeDefinition,\n\t\tcontext: NodeContext<any, any, any>,\n\t\texecutionId?: string,\n\t\tsignal?: AbortSignal,\n\t) => Promise<NodeResult<any, any>>\n}\n\nexport class FunctionNodeExecutor implements ExecutionStrategy {\n\tconstructor(\n\t\tprivate implementation: NodeFunction,\n\t\tprivate maxRetries: number,\n\t\tprivate eventBus: IEventBus,\n\t) {}\n\n\tasync execute(\n\t\tnodeDef: NodeDefinition,\n\t\tcontext: NodeContext<any, any, any>,\n\t\texecutionId?: string,\n\t\tsignal?: AbortSignal,\n\t): Promise<NodeResult<any, any>> {\n\t\treturn withRetries(\n\t\t\t() => this.implementation(context),\n\t\t\tthis.maxRetries,\n\t\t\tnodeDef,\n\t\t\tcontext,\n\t\t\texecutionId,\n\t\t\tsignal,\n\t\t\tthis.eventBus,\n\t\t)\n\t}\n}\n\nexport class ClassNodeExecutor implements ExecutionStrategy {\n\tconstructor(\n\t\tprivate implementation: NodeClass,\n\t\tprivate maxRetries: number,\n\t\tprivate eventBus: IEventBus,\n\t) {}\n\n\tasync execute(\n\t\tnodeDef: NodeDefinition,\n\t\tcontext: NodeContext<any, any, any>,\n\t\texecutionId?: string,\n\t\tsignal?: AbortSignal,\n\t): Promise<NodeResult<any, any>> {\n\t\tconst instance = new this.implementation(nodeDef.params || {}, nodeDef.id)\n\t\tlet lastError: Error | undefined\n\t\ttry {\n\t\t\tsignal?.throwIfAborted()\n\t\t\tconst prepResult = await instance.prep(context)\n\t\t\tlet execResult: Omit<NodeResult, 'error'> | undefined\n\t\t\ttry {\n\t\t\t\texecResult = await withRetries(\n\t\t\t\t\t() => instance.exec(prepResult, context),\n\t\t\t\t\tthis.maxRetries,\n\t\t\t\t\tnodeDef,\n\t\t\t\t\tcontext,\n\t\t\t\t\texecutionId,\n\t\t\t\t\tsignal,\n\t\t\t\t\tthis.eventBus,\n\t\t\t\t)\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error instanceof Error ? error : new Error(String(error))\n\t\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\t\tthrow new FlowcraftError('Workflow cancelled', {\n\t\t\t\t\t\tisFatal: false,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tif (error instanceof FlowcraftError && error.isFatal) {\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (lastError) {\n\t\t\t\tsignal?.throwIfAborted()\n\t\t\t\texecResult = await instance.fallback(lastError, context)\n\t\t\t}\n\t\t\tsignal?.throwIfAborted()\n\t\t\tif (!execResult) {\n\t\t\t\tthrow new Error('Execution failed after all retries')\n\t\t\t}\n\t\t\treturn await instance.post(execResult, context)\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error))\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow new FlowcraftError('Workflow cancelled', {\n\t\t\t\t\tisFatal: false,\n\t\t\t\t})\n\t\t\t}\n\t\t\tthrow error\n\t\t} finally {\n\t\t\tif (lastError) {\n\t\t\t\ttry {\n\t\t\t\t\tawait instance.recover(lastError, context)\n\t\t\t\t} catch (recoverError) {\n\t\t\t\t\tcontext.dependencies.logger.warn(`Recover phase failed`, {\n\t\t\t\t\t\tnodeId: nodeDef.id,\n\t\t\t\t\t\toriginalError: lastError.message,\n\t\t\t\t\t\trecoverError: recoverError instanceof Error ? recoverError.message : String(recoverError),\n\t\t\t\t\t\texecutionId,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport type NodeExecutionResult =\n\t| { status: 'success'; result: NodeResult<any, any> }\n\t| { status: 'failed_with_fallback'; fallbackNodeId: string; error: FlowcraftError }\n\t| { status: 'failed'; error: FlowcraftError }\n\nexport interface NodeExecutorConfig<TContext extends Record<string, any>, TDependencies extends Record<string, any>> {\n\tcontext: ExecutionContext<TContext, TDependencies>\n\tnodeDef: NodeDefinition\n\tstrategy: ExecutionStrategy\n}\n\nexport class NodeExecutor<TContext extends Record<string, any>, TDependencies extends Record<string, any>> {\n\tprivate context: ExecutionContext<TContext, TDependencies>\n\tprivate nodeDef: NodeDefinition\n\tprivate strategy: ExecutionStrategy\n\n\tconstructor(config: NodeExecutorConfig<TContext, TDependencies>) {\n\t\tthis.context = config.context\n\t\tthis.nodeDef = config.nodeDef\n\t\tthis.strategy = config.strategy\n\t}\n\n\tasync execute(input: any): Promise<NodeExecutionResult> {\n\t\tconst asyncContext = this.context.state.getContext()\n\n\t\tconst nodeContext: NodeContext<TContext, TDependencies, any> = {\n\t\t\tcontext: asyncContext,\n\t\t\tinput,\n\t\t\tparams: this.nodeDef.params || {},\n\t\t\tdependencies: {\n\t\t\t\t...this.context.services.dependencies,\n\t\t\t\tlogger: this.context.services.logger,\n\t\t\t\truntime: this.context,\n\t\t\t\tworkflowState: this.context.state,\n\t\t\t},\n\t\t\tsignal: this.context.signal,\n\t\t}\n\n\t\tconst beforeHooks = this.context.services.middleware\n\t\t\t.map((m) => m.beforeNode)\n\t\t\t.filter((hook): hook is NonNullable<Middleware['beforeNode']> => !!hook)\n\t\tconst afterHooks = this.context.services.middleware\n\t\t\t.map((m) => m.afterNode)\n\t\t\t.filter((hook): hook is NonNullable<Middleware['afterNode']> => !!hook)\n\t\tconst aroundHooks = this.context.services.middleware\n\t\t\t.map((m) => m.aroundNode)\n\t\t\t.filter((hook): hook is NonNullable<Middleware['aroundNode']> => !!hook)\n\n\t\tconst coreExecution = async (): Promise<NodeExecutionResult> => {\n\t\t\tlet result: NodeResult | undefined\n\t\t\tlet error: Error | undefined\n\t\t\ttry {\n\t\t\t\tfor (const hook of beforeHooks) await hook(nodeContext.context, this.nodeDef.id)\n\t\t\t\tresult = await this.strategy.execute(this.nodeDef, nodeContext, this.context.executionId, this.context.signal)\n\t\t\t\treturn { status: 'success', result }\n\t\t\t} catch (e: any) {\n\t\t\t\terror = e instanceof Error ? e : new Error(String(e))\n\t\t\t\tconst flowcraftError =\n\t\t\t\t\terror instanceof FlowcraftError\n\t\t\t\t\t\t? error\n\t\t\t\t\t\t: new FlowcraftError(`Node '${this.nodeDef.id}' execution failed`, {\n\t\t\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\t\t\t\tblueprintId: this.context.blueprint.id,\n\t\t\t\t\t\t\t\texecutionId: this.context.executionId,\n\t\t\t\t\t\t\t\tisFatal: false,\n\t\t\t\t\t\t\t})\n\n\t\t\t\tconst fallbackNodeId = this.nodeDef.config?.fallback\n\t\t\t\tif (fallbackNodeId && !flowcraftError.isFatal) {\n\t\t\t\t\tthis.context.services.logger.warn(`Node failed, fallback required`, {\n\t\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\t\tfallbackNodeId,\n\t\t\t\t\t\terror: error.message,\n\t\t\t\t\t\texecutionId: this.context.executionId,\n\t\t\t\t\t})\n\t\t\t\t\tawait this.context.services.eventBus.emit({\n\t\t\t\t\t\ttype: 'node:fallback',\n\t\t\t\t\t\tpayload: {\n\t\t\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\t\t\texecutionId: this.context.executionId || '',\n\t\t\t\t\t\t\tfallback: fallbackNodeId,\n\t\t\t\t\t\t\tblueprintId: this.context.blueprint.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\treturn { status: 'failed_with_fallback', fallbackNodeId, error: flowcraftError }\n\t\t\t\t}\n\t\t\t\treturn { status: 'failed', error: flowcraftError }\n\t\t\t} finally {\n\t\t\t\tfor (const hook of afterHooks) await hook(nodeContext.context, this.nodeDef.id, result, error)\n\t\t\t}\n\t\t}\n\n\t\tlet executionChain: () => Promise<NodeExecutionResult> = coreExecution\n\t\tfor (let i = aroundHooks.length - 1; i >= 0; i--) {\n\t\t\tconst hook = aroundHooks[i]\n\t\t\tconst next = executionChain\n\t\t\texecutionChain = async () => {\n\t\t\t\tlet capturedResult: NodeExecutionResult | undefined\n\t\t\t\tconst middlewareResult = await hook(nodeContext.context, this.nodeDef.id, async () => {\n\t\t\t\t\tcapturedResult = await next()\n\t\t\t\t\tif (capturedResult.status === 'success') {\n\t\t\t\t\t\treturn capturedResult.result\n\t\t\t\t\t}\n\t\t\t\t\tthrow capturedResult.error\n\t\t\t\t})\n\t\t\t\tif (!capturedResult && middlewareResult) {\n\t\t\t\t\treturn { status: 'success', result: middlewareResult }\n\t\t\t\t}\n\t\t\t\tif (!capturedResult) {\n\t\t\t\t\tthrow new Error('Middleware did not call next() and did not return a result')\n\t\t\t\t}\n\t\t\t\treturn capturedResult\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.context.services.eventBus.emit({\n\t\t\t\ttype: 'node:start',\n\t\t\t\tpayload: {\n\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\texecutionId: this.context.executionId || '',\n\t\t\t\t\tinput: nodeContext.input,\n\t\t\t\t\tblueprintId: this.context.blueprint.id,\n\t\t\t\t},\n\t\t\t})\n\t\t\tconst executionResult = await executionChain()\n\t\t\tif (executionResult.status === 'success') {\n\t\t\t\tawait this.context.services.eventBus.emit({\n\t\t\t\t\ttype: 'node:finish',\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\t\tresult: executionResult.result,\n\t\t\t\t\t\texecutionId: this.context.executionId || '',\n\t\t\t\t\t\tblueprintId: this.context.blueprint.id,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tawait this.context.services.eventBus.emit({\n\t\t\t\t\ttype: 'node:error',\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\t\terror: executionResult.error,\n\t\t\t\t\t\texecutionId: this.context.executionId || '',\n\t\t\t\t\t\tblueprintId: this.context.blueprint.id,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn executionResult\n\t\t} catch (error: any) {\n\t\t\tconst err = error instanceof Error ? error : new Error(String(error))\n\t\t\tconst flowcraftError =\n\t\t\t\terr instanceof FlowcraftError\n\t\t\t\t\t? err\n\t\t\t\t\t: new FlowcraftError(`Node '${this.nodeDef.id}' failed execution.`, {\n\t\t\t\t\t\t\tcause: err,\n\t\t\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\t\t\tblueprintId: this.context.blueprint.id,\n\t\t\t\t\t\t\texecutionId: this.context.executionId,\n\t\t\t\t\t\t\tisFatal: false,\n\t\t\t\t\t\t})\n\t\t\tawait this.context.services.eventBus.emit({\n\t\t\t\ttype: 'node:error',\n\t\t\t\tpayload: {\n\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\terror: flowcraftError,\n\t\t\t\t\texecutionId: this.context.executionId || '',\n\t\t\t\t\tblueprintId: this.context.blueprint.id,\n\t\t\t\t},\n\t\t\t})\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow new FlowcraftError('Workflow cancelled', {\n\t\t\t\t\texecutionId: this.context.executionId,\n\t\t\t\t\tisFatal: false,\n\t\t\t\t})\n\t\t\t}\n\t\t\tthrow error instanceof FlowcraftError && !error.isFatal\n\t\t\t\t? error\n\t\t\t\t: new FlowcraftError(`Node '${this.nodeDef.id}' failed execution.`, {\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\tnodeId: this.nodeDef.id,\n\t\t\t\t\t\tblueprintId: this.context.blueprint.id,\n\t\t\t\t\t\texecutionId: this.context.executionId,\n\t\t\t\t\t\tisFatal: false,\n\t\t\t\t\t})\n\t\t}\n\t}\n}\n"]}