@codemation/core 0.2.1 → 0.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 (63) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +2 -0
  3. package/dist/{EngineRuntimeRegistration.types-0sgV2XL2.d.ts → EngineRuntimeRegistration.types-Bjeo7Sfq.d.ts} +2 -2
  4. package/dist/{EngineWorkflowRunnerService-Dx7bJsJR.d.cts → EngineWorkflowRunnerService-Dd4yD31l.d.cts} +2 -2
  5. package/dist/{InMemoryRunDataFactory-qIYQEar7.d.cts → InMemoryRunDataFactory-OUzDmAHt.d.cts} +2 -2
  6. package/dist/{RunIntentService-BCvGdOSY.d.ts → RunIntentService-BAKikN8h.d.ts} +80 -12
  7. package/dist/{RunIntentService-CV8izV8t.d.cts → RunIntentService-Bkg4oYrM.d.cts} +74 -5
  8. package/dist/bootstrap/index.cjs +31 -31
  9. package/dist/bootstrap/index.d.cts +5 -3
  10. package/dist/bootstrap/index.d.ts +3 -3
  11. package/dist/bootstrap/index.js +2 -2
  12. package/dist/bootstrap-BD6CobHl.js +215 -0
  13. package/dist/bootstrap-BD6CobHl.js.map +1 -0
  14. package/dist/bootstrap-DwS5S7s9.cjs +240 -0
  15. package/dist/bootstrap-DwS5S7s9.cjs.map +1 -0
  16. package/dist/{index-CueSzHsf.d.ts → index-uCm9l0nw.d.ts} +64 -15
  17. package/dist/index.cjs +114 -32
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +68 -21
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +83 -2
  22. package/dist/index.js.map +1 -1
  23. package/dist/{RunIntentService-BFA48UpH.js → runtime-Cy-3FTI_.js} +1224 -94
  24. package/dist/runtime-Cy-3FTI_.js.map +1 -0
  25. package/dist/{RunIntentService-DcxXf_AM.cjs → runtime-ZJUpWmPH.cjs} +1251 -132
  26. package/dist/runtime-ZJUpWmPH.cjs.map +1 -0
  27. package/dist/testing.cjs +74 -29
  28. package/dist/testing.cjs.map +1 -1
  29. package/dist/testing.d.cts +55 -3
  30. package/dist/testing.d.ts +55 -3
  31. package/dist/testing.js +46 -3
  32. package/dist/testing.js.map +1 -1
  33. package/dist/workflowActivationPolicy-B8HzTk3o.js.map +1 -1
  34. package/dist/workflowActivationPolicy-BzyzXLa_.cjs.map +1 -1
  35. package/package.json +1 -1
  36. package/src/ai/AgentMessageConfigNormalizerFactory.ts +43 -0
  37. package/src/ai/AgentToolFactory.ts +2 -2
  38. package/src/ai/AiHost.ts +10 -9
  39. package/src/ai/NodeBackedToolConfig.ts +1 -1
  40. package/src/authoring/defineNode.types.ts +153 -10
  41. package/src/authoring/index.ts +3 -1
  42. package/src/contracts/runtimeTypes.ts +26 -0
  43. package/src/contracts/workflowTypes.ts +67 -5
  44. package/src/execution/ActivationEnqueueService.ts +8 -5
  45. package/src/execution/NodeActivationRequestInputPreparer.ts +89 -0
  46. package/src/execution/NodeExecutor.ts +38 -1
  47. package/src/execution/NodeInputContractError.ts +13 -0
  48. package/src/execution/index.ts +2 -0
  49. package/src/orchestration/RunContinuationService.ts +181 -50
  50. package/src/planning/RunQueuePlanner.ts +12 -1
  51. package/src/runtime/EngineFactory.ts +3 -0
  52. package/src/testing/ItemHarnessNode.ts +27 -0
  53. package/src/testing/ItemHarnessNodeConfig.ts +43 -0
  54. package/src/testing/RegistrarEngineTestKitFactory.ts +2 -0
  55. package/src/testing.ts +2 -0
  56. package/src/workflow/dsl/ChainCursorResolver.ts +1 -1
  57. package/src/workflow/dsl/workflowBuilderTypes.ts +8 -5
  58. package/dist/RunIntentService-BFA48UpH.js.map +0 -1
  59. package/dist/RunIntentService-DcxXf_AM.cjs.map +0 -1
  60. package/dist/bootstrap-D67Sf2BF.js +0 -1136
  61. package/dist/bootstrap-D67Sf2BF.js.map +0 -1
  62. package/dist/bootstrap-DoQHAEQJ.cjs +0 -1203
  63. package/dist/bootstrap-DoQHAEQJ.cjs.map +0 -1
@@ -24,6 +24,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  require("reflect-metadata");
25
25
  let tsyringe = require("tsyringe");
26
26
  tsyringe = __toESM(tsyringe);
27
+ let zod = require("zod");
28
+ zod = __toESM(zod);
27
29
  let node_crypto = require("node:crypto");
28
30
  node_crypto = __toESM(node_crypto);
29
31
  let node_stream_web = require("node:stream/web");
@@ -513,10 +515,11 @@ var NodeInputsByPortFactory = class {
513
515
  //#endregion
514
516
  //#region src/execution/ActivationEnqueueService.ts
515
517
  var ActivationEnqueueService = class {
516
- constructor(activationScheduler, workflowExecutionRepository, nodeEventPublisher) {
518
+ constructor(activationScheduler, workflowExecutionRepository, nodeEventPublisher, nodeActivationRequestInputPreparer) {
517
519
  this.activationScheduler = activationScheduler;
518
520
  this.workflowExecutionRepository = workflowExecutionRepository;
519
521
  this.nodeEventPublisher = nodeEventPublisher;
522
+ this.nodeActivationRequestInputPreparer = nodeActivationRequestInputPreparer;
520
523
  }
521
524
  async enqueueActivation(args) {
522
525
  const { result, queuedSnapshot } = await this.enqueueActivationWithSnapshot(args);
@@ -524,9 +527,10 @@ var ActivationEnqueueService = class {
524
527
  return result;
525
528
  }
526
529
  async enqueueActivationWithSnapshot(args) {
527
- const preparedDispatch = await this.activationScheduler.prepareDispatch(args.request);
528
- const inputsByPort = NodeInputsByPortFactory.fromRequest(args.request);
529
- const itemsIn = args.request.kind === "multi" ? args.planner.sumItemsByPort(args.request.inputsByPort) : args.request.input.length;
530
+ const preparedRequest = await this.nodeActivationRequestInputPreparer.prepare(args.request);
531
+ const preparedDispatch = await this.activationScheduler.prepareDispatch(preparedRequest);
532
+ const inputsByPort = NodeInputsByPortFactory.fromRequest(preparedRequest);
533
+ const itemsIn = preparedRequest.kind === "multi" ? args.planner.sumItemsByPort(preparedRequest.inputsByPort) : preparedRequest.input.length;
530
534
  const enqueuedAt = (/* @__PURE__ */ new Date()).toISOString();
531
535
  const pending = {
532
536
  runId: args.runId,
@@ -587,6 +591,75 @@ var ActivationEnqueueService = class {
587
591
  }
588
592
  };
589
593
 
594
+ //#endregion
595
+ //#region src/execution/NodeInputContractError.ts
596
+ var NodeInputContractError = class extends Error {
597
+ constructor(message, nodeId, activationId, cause) {
598
+ super(message);
599
+ this.nodeId = nodeId;
600
+ this.activationId = activationId;
601
+ this.cause = cause;
602
+ this.name = "NodeInputContractError";
603
+ }
604
+ };
605
+
606
+ //#endregion
607
+ //#region src/execution/NodeActivationRequestInputPreparer.ts
608
+ /**
609
+ * Maps and validates per-item inputs for {@link ItemNode} before enqueue persistence.
610
+ */
611
+ var NodeActivationRequestInputPreparer = class {
612
+ constructor(workflowNodeInstanceFactory) {
613
+ this.workflowNodeInstanceFactory = workflowNodeInstanceFactory;
614
+ }
615
+ async prepare(request) {
616
+ if (request.kind !== "single") return request;
617
+ const nodeInstance = this.workflowNodeInstanceFactory.createByType(request.ctx.config.type);
618
+ if (!this.hasExecuteOne(nodeInstance)) return request;
619
+ const inputSchema = this.resolveInputSchema(nodeInstance, request.ctx.config);
620
+ const config = request.ctx.config;
621
+ const mappedItems = [];
622
+ for (let i = 0; i < request.input.length; i++) {
623
+ const item = request.input[i];
624
+ try {
625
+ const mappedRaw = config.mapInput ? await Promise.resolve(config.mapInput({
626
+ item,
627
+ itemIndex: i,
628
+ items: request.input,
629
+ ctx: request.ctx
630
+ })) : item.json;
631
+ const parsed = inputSchema.parse(mappedRaw);
632
+ mappedItems.push({
633
+ ...item,
634
+ json: parsed
635
+ });
636
+ } catch (cause) {
637
+ const message = this.formatContractFailure(cause);
638
+ throw new NodeInputContractError(`Node ${request.nodeId} activation ${request.activationId}: input contract failed: ${message}`, request.nodeId, request.activationId, cause);
639
+ }
640
+ }
641
+ return {
642
+ ...request,
643
+ input: mappedItems
644
+ };
645
+ }
646
+ hasExecuteOne(nodeInstance) {
647
+ return typeof nodeInstance === "object" && nodeInstance !== null && typeof nodeInstance.executeOne === "function";
648
+ }
649
+ resolveInputSchema(nodeInstance, config) {
650
+ const fromInstance = nodeInstance.inputSchema;
651
+ if (fromInstance && typeof fromInstance.parse === "function") return fromInstance;
652
+ const fromConfig = config.inputSchema;
653
+ if (fromConfig && typeof fromConfig.parse === "function") return fromConfig;
654
+ return zod.z.unknown();
655
+ }
656
+ formatContractFailure(cause) {
657
+ if (cause instanceof zod.ZodError) return cause.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ");
658
+ if (cause instanceof Error) return cause.message;
659
+ return String(cause);
660
+ }
661
+ };
662
+
590
663
  //#endregion
591
664
  //#region src/execution/CredentialResolverFactory.ts
592
665
  var CredentialResolverFactory = class {
@@ -832,10 +905,32 @@ var NodeExecutor = class {
832
905
  return await multiInputNode.executeMulti(request.inputsByPort, request.ctx);
833
906
  }
834
907
  async executeSingleInputNode(request, node$1) {
908
+ if (this.hasExecuteOne(node$1)) return await this.executeItemNode(request, node$1);
835
909
  const singleInputNode = node$1;
836
910
  if (typeof singleInputNode.execute !== "function") throw new Error(`Node ${request.nodeId} does not support execute but received single-input activation`);
837
911
  return await singleInputNode.execute(request.input, request.ctx);
838
912
  }
913
+ hasExecuteOne(node$1) {
914
+ return typeof node$1 === "object" && node$1 !== null && typeof node$1.executeOne === "function";
915
+ }
916
+ async executeItemNode(request, node$1) {
917
+ const out = [];
918
+ for (let i = 0; i < request.input.length; i++) {
919
+ const item = request.input[i];
920
+ const outputJson = await Promise.resolve(node$1.executeOne({
921
+ input: item.json,
922
+ item,
923
+ itemIndex: i,
924
+ items: request.input,
925
+ ctx: request.ctx
926
+ }));
927
+ out.push({
928
+ ...item,
929
+ json: outputJson
930
+ });
931
+ }
932
+ return { main: out };
933
+ }
839
934
  };
840
935
 
841
936
  //#endregion
@@ -1650,15 +1745,15 @@ var RunContinuationService = class {
1650
1745
  finalStatus: "completed",
1651
1746
  finishedAt: completedAt
1652
1747
  });
1653
- const result$1 = {
1748
+ const result = {
1654
1749
  runId: state.runId,
1655
1750
  workflowId: state.workflowId,
1656
1751
  startedAt: state.startedAt,
1657
1752
  status: "completed",
1658
1753
  outputs: this.semantics.resolveResultOutputs(wf, state.control?.stopCondition, data.dump())
1659
1754
  };
1660
- this.waiters.resolveRunCompletion(result$1);
1661
- return result$1;
1755
+ this.waiters.resolveRunCompletion(result);
1756
+ return result;
1662
1757
  }
1663
1758
  const batchId = pendingExecution.batchId ?? "batch_1";
1664
1759
  const queue = (schedulingState?.queue ?? []).map((q) => ({
@@ -1717,15 +1812,15 @@ var RunContinuationService = class {
1717
1812
  finalStatus: "completed",
1718
1813
  finishedAt: completedAt
1719
1814
  });
1720
- const result$1 = {
1815
+ const result = {
1721
1816
  runId: state.runId,
1722
1817
  workflowId: state.workflowId,
1723
1818
  startedAt: state.startedAt,
1724
1819
  status: "completed",
1725
1820
  outputs
1726
1821
  };
1727
- this.waiters.resolveRunCompletion(result$1);
1728
- return result$1;
1822
+ this.waiters.resolveRunCompletion(result);
1823
+ return result;
1729
1824
  }
1730
1825
  if (completedActivations >= maxNodeActivations) {
1731
1826
  const message = `Run exceeded maxNodeActivations (${maxNodeActivations}) after ${completedActivations} completed node activations (next would be ${next.nodeId}).`;
@@ -1746,15 +1841,15 @@ var RunContinuationService = class {
1746
1841
  finalStatus: "failed",
1747
1842
  finishedAt: completedAt
1748
1843
  });
1749
- const result$1 = {
1844
+ const result = {
1750
1845
  runId: state.runId,
1751
1846
  workflowId: state.workflowId,
1752
1847
  startedAt: state.startedAt,
1753
1848
  status: "failed",
1754
1849
  error: { message }
1755
1850
  };
1756
- this.waiters.resolveRunCompletion(result$1);
1757
- return result$1;
1851
+ this.waiters.resolveRunCompletion(result);
1852
+ return result;
1758
1853
  }
1759
1854
  const def = topology.defsById.get(next.nodeId);
1760
1855
  if (!def || def.kind !== "node") throw new Error(`Node ${next.nodeId} is not a runnable node`);
@@ -1768,26 +1863,43 @@ var RunContinuationService = class {
1768
1863
  executionOptions: state.executionOptions,
1769
1864
  nodeDefinition: def
1770
1865
  });
1771
- const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
1772
- runId: state.runId,
1773
- workflowId: state.workflowId,
1774
- startedAt: state.startedAt,
1775
- parent: state.parent,
1776
- executionOptions: state.executionOptions,
1777
- control: state.control,
1778
- workflowSnapshot: state.workflowSnapshot,
1779
- mutableState: state.mutableState,
1780
- policySnapshot: state.policySnapshot,
1781
- pendingQueue: queue,
1782
- request,
1783
- previousNodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId,
1784
- planner,
1785
- engineCounters,
1786
- connectionInvocations: state.connectionInvocations ?? []
1787
- });
1788
- await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
1789
- await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
1790
- return result;
1866
+ try {
1867
+ const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
1868
+ runId: state.runId,
1869
+ workflowId: state.workflowId,
1870
+ startedAt: state.startedAt,
1871
+ parent: state.parent,
1872
+ executionOptions: state.executionOptions,
1873
+ control: state.control,
1874
+ workflowSnapshot: state.workflowSnapshot,
1875
+ mutableState: state.mutableState,
1876
+ policySnapshot: state.policySnapshot,
1877
+ pendingQueue: queue,
1878
+ request,
1879
+ previousNodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId,
1880
+ planner,
1881
+ engineCounters,
1882
+ connectionInvocations: state.connectionInvocations ?? []
1883
+ });
1884
+ await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
1885
+ await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
1886
+ return result;
1887
+ } catch (cause) {
1888
+ const error = cause instanceof Error ? cause : new Error(String(cause));
1889
+ return await this.terminateRunAfterActivationEnqueueRejected({
1890
+ wf,
1891
+ state,
1892
+ queue,
1893
+ nextNodeId: next.nodeId,
1894
+ request,
1895
+ completedSnapshot,
1896
+ nextNodeSnapshotsByNodeId,
1897
+ outputsByNode: data.dump(),
1898
+ engineCounters,
1899
+ error,
1900
+ completedAt
1901
+ });
1902
+ }
1791
1903
  }
1792
1904
  async resumeFromNodeError(args) {
1793
1905
  const [state, schedulingState] = await Promise.all([this.workflowExecutionRepository.load(args.runId), this.workflowExecutionRepository.loadSchedulingState(args.runId)]);
@@ -1964,15 +2076,15 @@ var RunContinuationService = class {
1964
2076
  runStatus: "completed",
1965
2077
  response: args.signal.responseItems
1966
2078
  });
1967
- const result$1 = {
2079
+ const result = {
1968
2080
  runId: args.state.runId,
1969
2081
  workflowId: args.state.workflowId,
1970
2082
  startedAt: args.state.startedAt,
1971
2083
  status: "completed",
1972
2084
  outputs: this.semantics.resolveResultOutputs(args.workflow, args.state.control?.stopCondition, data.dump())
1973
2085
  };
1974
- this.waiters.resolveRunCompletion(result$1);
1975
- return result$1;
2086
+ this.waiters.resolveRunCompletion(result);
2087
+ return result;
1976
2088
  }
1977
2089
  if (args.signal.kind === "respondNow") {
1978
2090
  const completedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
@@ -1995,7 +2107,7 @@ var RunContinuationService = class {
1995
2107
  finalStatus: "completed",
1996
2108
  finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
1997
2109
  });
1998
- const result$1 = {
2110
+ const result = {
1999
2111
  runId: args.state.runId,
2000
2112
  workflowId: args.state.workflowId,
2001
2113
  startedAt: args.state.startedAt,
@@ -2009,8 +2121,8 @@ var RunContinuationService = class {
2009
2121
  runStatus: "completed",
2010
2122
  response: args.signal.responseItems
2011
2123
  });
2012
- this.waiters.resolveRunCompletion(result$1);
2013
- return result$1;
2124
+ this.waiters.resolveRunCompletion(result);
2125
+ return result;
2014
2126
  }
2015
2127
  const batchId = args.pendingExecution.batchId ?? "batch_1";
2016
2128
  const queue = (args.schedulingState?.queue ?? []).map((entry) => ({
@@ -2046,7 +2158,7 @@ var RunContinuationService = class {
2046
2158
  finalStatus: "completed",
2047
2159
  finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
2048
2160
  });
2049
- const result$1 = {
2161
+ const result = {
2050
2162
  runId: args.state.runId,
2051
2163
  workflowId: args.state.workflowId,
2052
2164
  startedAt: args.state.startedAt,
@@ -2060,8 +2172,8 @@ var RunContinuationService = class {
2060
2172
  runStatus: "completed",
2061
2173
  response: args.signal.responseItems
2062
2174
  });
2063
- this.waiters.resolveRunCompletion(result$1);
2064
- return result$1;
2175
+ this.waiters.resolveRunCompletion(result);
2176
+ return result;
2065
2177
  }
2066
2178
  if (completedActivations >= maxNodeActivations) {
2067
2179
  const message = `Run exceeded maxNodeActivations (${maxNodeActivations}) after ${completedActivations} completed node activations (next would be ${next.nodeId}).`;
@@ -2085,7 +2197,7 @@ var RunContinuationService = class {
2085
2197
  finalStatus: "failed",
2086
2198
  finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
2087
2199
  });
2088
- const result$1 = {
2200
+ const result = {
2089
2201
  runId: args.state.runId,
2090
2202
  workflowId: args.state.workflowId,
2091
2203
  startedAt: args.state.startedAt,
@@ -2099,8 +2211,8 @@ var RunContinuationService = class {
2099
2211
  runStatus: "pending",
2100
2212
  response: args.signal.responseItems
2101
2213
  });
2102
- this.waiters.resolveRunCompletion(result$1);
2103
- return result$1;
2214
+ this.waiters.resolveRunCompletion(result);
2215
+ return result;
2104
2216
  }
2105
2217
  const nextDefinition = topology.defsById.get(next.nodeId);
2106
2218
  if (!nextDefinition || nextDefinition.kind !== "node") throw new Error(`Node ${next.nodeId} is not a runnable node`);
@@ -2126,36 +2238,63 @@ var RunContinuationService = class {
2126
2238
  executionOptions: args.state.executionOptions,
2127
2239
  nodeDefinition: nextDefinition
2128
2240
  });
2129
- const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
2130
- runId: args.state.runId,
2131
- workflowId: args.state.workflowId,
2132
- startedAt: args.state.startedAt,
2133
- parent: args.state.parent,
2134
- executionOptions: args.state.executionOptions,
2135
- control: args.state.control,
2136
- workflowSnapshot: args.state.workflowSnapshot,
2137
- mutableState: args.state.mutableState,
2138
- policySnapshot: args.state.policySnapshot,
2139
- pendingQueue: queue,
2140
- request,
2141
- previousNodeSnapshotsByNodeId: {
2142
- ...args.state.nodeSnapshotsByNodeId ?? {},
2143
- [args.args.nodeId]: completedSnapshot
2144
- },
2145
- planner,
2146
- engineCounters,
2147
- connectionInvocations: args.state.connectionInvocations ?? []
2148
- });
2149
- await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
2150
- await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
2151
- this.waiters.resolveWebhookResponse({
2152
- runId: args.state.runId,
2153
- workflowId: args.state.workflowId,
2154
- startedAt: args.state.startedAt,
2155
- runStatus: "pending",
2156
- response: args.signal.responseItems
2157
- });
2158
- return result;
2241
+ const mergedSnapshots = {
2242
+ ...args.state.nodeSnapshotsByNodeId ?? {},
2243
+ [args.args.nodeId]: completedSnapshot
2244
+ };
2245
+ try {
2246
+ const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
2247
+ runId: args.state.runId,
2248
+ workflowId: args.state.workflowId,
2249
+ startedAt: args.state.startedAt,
2250
+ parent: args.state.parent,
2251
+ executionOptions: args.state.executionOptions,
2252
+ control: args.state.control,
2253
+ workflowSnapshot: args.state.workflowSnapshot,
2254
+ mutableState: args.state.mutableState,
2255
+ policySnapshot: args.state.policySnapshot,
2256
+ pendingQueue: queue,
2257
+ request,
2258
+ previousNodeSnapshotsByNodeId: mergedSnapshots,
2259
+ planner,
2260
+ engineCounters,
2261
+ connectionInvocations: args.state.connectionInvocations ?? []
2262
+ });
2263
+ await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
2264
+ await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
2265
+ this.waiters.resolveWebhookResponse({
2266
+ runId: args.state.runId,
2267
+ workflowId: args.state.workflowId,
2268
+ startedAt: args.state.startedAt,
2269
+ runStatus: "pending",
2270
+ response: args.signal.responseItems
2271
+ });
2272
+ return result;
2273
+ } catch (cause) {
2274
+ const error = cause instanceof Error ? cause : new Error(String(cause));
2275
+ const finishedAt = completedSnapshot.finishedAt ?? completedSnapshot.updatedAt;
2276
+ const result = await this.terminateRunAfterActivationEnqueueRejected({
2277
+ wf: args.workflow,
2278
+ state: args.state,
2279
+ queue,
2280
+ nextNodeId: next.nodeId,
2281
+ request,
2282
+ completedSnapshot,
2283
+ nextNodeSnapshotsByNodeId: mergedSnapshots,
2284
+ outputsByNode: data.dump(),
2285
+ engineCounters,
2286
+ error,
2287
+ completedAt: finishedAt
2288
+ });
2289
+ this.waiters.resolveWebhookResponse({
2290
+ runId: args.state.runId,
2291
+ workflowId: args.state.workflowId,
2292
+ startedAt: args.state.startedAt,
2293
+ runStatus: "pending",
2294
+ response: args.signal.responseItems
2295
+ });
2296
+ return result;
2297
+ }
2159
2298
  }
2160
2299
  asWebhookControlSignal(error) {
2161
2300
  const candidate = error;
@@ -2213,6 +2352,66 @@ var RunContinuationService = class {
2213
2352
  engineMaxSubworkflowDepth: state.executionOptions?.maxSubworkflowDepth ?? fb.maxSubworkflowDepth
2214
2353
  };
2215
2354
  }
2355
+ /**
2356
+ * Next activation could not be enqueued (e.g. input contract / mapping failed in the preparer).
2357
+ * Marks the target node failed and terminates the run.
2358
+ */
2359
+ async terminateRunAfterActivationEnqueueRejected(args) {
2360
+ const finishedAt = args.completedAt;
2361
+ const inputsByPort = NodeInputsByPortFactory.fromRequest(args.request);
2362
+ const failedSnapshot = NodeExecutionSnapshotFactory.failed({
2363
+ previous: void 0,
2364
+ runId: args.state.runId,
2365
+ workflowId: args.state.workflowId,
2366
+ nodeId: args.nextNodeId,
2367
+ activationId: args.request.activationId,
2368
+ parent: args.state.parent,
2369
+ finishedAt,
2370
+ inputsByPort,
2371
+ error: args.error
2372
+ });
2373
+ const failedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
2374
+ state: args.state,
2375
+ engineCounters: args.engineCounters,
2376
+ status: "failed",
2377
+ queue: args.queue.map((q) => ({ ...q })),
2378
+ outputsByNode: args.outputsByNode,
2379
+ nodeSnapshotsByNodeId: {
2380
+ ...args.nextNodeSnapshotsByNodeId,
2381
+ [args.nextNodeId]: failedSnapshot
2382
+ },
2383
+ finishedAtIso: finishedAt
2384
+ });
2385
+ await this.workflowExecutionRepository.save(failedState);
2386
+ await this.nodeEventPublisher.publish("nodeCompleted", args.completedSnapshot);
2387
+ await this.nodeEventPublisher.publish("nodeFailed", failedSnapshot);
2388
+ const wfErr = this.policyErrorServices.resolveWorkflowErrorHandler(args.wf.workflowErrorHandler);
2389
+ if (wfErr) await Promise.resolve(wfErr.onError({
2390
+ runId: args.state.runId,
2391
+ workflowId: args.state.workflowId,
2392
+ workflow: args.wf,
2393
+ failedNodeId: args.nextNodeId,
2394
+ error: args.error,
2395
+ startedAt: args.state.startedAt,
2396
+ finishedAt
2397
+ }));
2398
+ await this.terminalPersistence.maybeDeleteAfterTerminalState({
2399
+ workflow: args.wf,
2400
+ state: failedState,
2401
+ finalStatus: "failed",
2402
+ finishedAt
2403
+ });
2404
+ const message = args.error.message ?? String(args.error);
2405
+ const result = {
2406
+ runId: args.state.runId,
2407
+ workflowId: args.state.workflowId,
2408
+ startedAt: args.state.startedAt,
2409
+ status: "failed",
2410
+ error: { message }
2411
+ };
2412
+ this.waiters.resolveRunCompletion(result);
2413
+ return result;
2414
+ }
2216
2415
  formatNodeLabel(args) {
2217
2416
  const tokenName = typeof args.definition?.type === "function" ? args.definition.type.name : "Node";
2218
2417
  return args.definition?.name ? `"${args.definition.name}" (${tokenName}:${args.nodeId})` : `${tokenName}:${args.nodeId}`;
@@ -3103,6 +3302,67 @@ var EngineExecutionLimitsPolicy = class {
3103
3302
  }
3104
3303
  };
3105
3304
 
3305
+ //#endregion
3306
+ //#region src/policies/storage/RunTerminalPersistenceCoordinator.ts
3307
+ var RunTerminalPersistenceCoordinator = class {
3308
+ constructor(runRepository, storageEvaluator) {
3309
+ this.runRepository = runRepository;
3310
+ this.storageEvaluator = storageEvaluator;
3311
+ }
3312
+ async maybeDeleteAfterTerminalState(args) {
3313
+ if (await this.storageEvaluator.shouldPersist(args.workflow, args.state.policySnapshot, {
3314
+ runId: args.state.runId,
3315
+ workflowId: args.state.workflowId,
3316
+ workflow: args.workflow,
3317
+ finalStatus: args.finalStatus,
3318
+ startedAt: args.state.startedAt,
3319
+ finishedAt: args.finishedAt
3320
+ })) return;
3321
+ if (!this.runRepository.deleteRun) return;
3322
+ await this.runRepository.deleteRun(args.state.runId);
3323
+ }
3324
+ };
3325
+
3326
+ //#endregion
3327
+ //#region src/policies/WorkflowPolicyErrorServices.ts
3328
+ var WorkflowPolicyErrorServices = class {
3329
+ constructor(nodeResolver) {
3330
+ this.nodeResolver = nodeResolver;
3331
+ }
3332
+ resolveNodeErrorHandler(spec) {
3333
+ if (!spec) return void 0;
3334
+ if (typeof spec === "object" && spec !== null && "handle" in spec && typeof spec.handle === "function") return spec;
3335
+ return this.nodeResolver.resolve(spec);
3336
+ }
3337
+ resolveWorkflowErrorHandler(spec) {
3338
+ if (!spec) return void 0;
3339
+ if (typeof spec === "object" && spec !== null && "onError" in spec && typeof spec.onError === "function") return spec;
3340
+ return this.nodeResolver.resolve(spec);
3341
+ }
3342
+ };
3343
+
3344
+ //#endregion
3345
+ //#region src/policies/storage/WorkflowStoragePolicyEvaluator.ts
3346
+ var WorkflowStoragePolicyEvaluator = class {
3347
+ constructor(nodeResolver) {
3348
+ this.nodeResolver = nodeResolver;
3349
+ }
3350
+ async shouldPersist(workflow, snapshot, args) {
3351
+ const spec = workflow.storagePolicy;
3352
+ if (spec === void 0) return this.modeMatches(snapshot?.storagePolicy ?? "ALL", args);
3353
+ if (typeof spec === "string") return this.modeMatches(spec, args);
3354
+ const resolver = this.nodeResolver.resolve(spec);
3355
+ return Boolean(await resolver.shouldPersist(args));
3356
+ }
3357
+ modeMatches(mode, args) {
3358
+ if (mode === "ALL") return true;
3359
+ if (mode === "NEVER") return false;
3360
+ if (mode === "SUCCESS") return args.finalStatus === "completed";
3361
+ if (mode === "ERROR") return args.finalStatus === "failed";
3362
+ return true;
3363
+ }
3364
+ };
3365
+
3106
3366
  //#endregion
3107
3367
  //#region src/runStorage/BinaryBodyBufferReader.ts
3108
3368
  var BinaryBodyBufferReader = class {
@@ -3251,6 +3511,775 @@ var RunFinishedAtFactory = class {
3251
3511
  }
3252
3512
  };
3253
3513
 
3514
+ //#endregion
3515
+ //#region src/orchestration/NodeExecutionRequestHandlerService.ts
3516
+ var NodeExecutionRequestHandlerService = class {
3517
+ constructor(workflowExecutionRepository, workflowSnapshotResolver, runDataFactory, runExecutionContextFactory, nodeStatePublisherFactory, nodeActivationRequestComposer, nodeExecutor, continuation, executionLimitsPolicy) {
3518
+ this.workflowExecutionRepository = workflowExecutionRepository;
3519
+ this.workflowSnapshotResolver = workflowSnapshotResolver;
3520
+ this.runDataFactory = runDataFactory;
3521
+ this.runExecutionContextFactory = runExecutionContextFactory;
3522
+ this.nodeStatePublisherFactory = nodeStatePublisherFactory;
3523
+ this.nodeActivationRequestComposer = nodeActivationRequestComposer;
3524
+ this.nodeExecutor = nodeExecutor;
3525
+ this.continuation = continuation;
3526
+ this.executionLimitsPolicy = executionLimitsPolicy;
3527
+ }
3528
+ async handleNodeExecutionRequest(request) {
3529
+ const [state, schedulingState] = await Promise.all([this.workflowExecutionRepository.load(request.runId), this.workflowExecutionRepository.loadSchedulingState(request.runId)]);
3530
+ if (!state) throw new Error(`Unknown runId: ${request.runId}`);
3531
+ if (state.workflowId !== request.workflowId) throw new Error(`workflowId mismatch for run ${request.runId}: ${state.workflowId} vs ${request.workflowId}`);
3532
+ const pendingExecution = schedulingState?.pending;
3533
+ if (state.status !== "pending" || !pendingExecution) return;
3534
+ if (pendingExecution.activationId !== request.activationId || pendingExecution.nodeId !== request.nodeId) return;
3535
+ const workflow = this.resolvePersistedWorkflow(state);
3536
+ if (!workflow) throw new Error(`Unknown workflowId: ${state.workflowId}`);
3537
+ const definition = workflow.nodes.find((node$1) => node$1.id === request.nodeId);
3538
+ if (!definition) throw new Error(`Unknown nodeId: ${request.nodeId}`);
3539
+ if (definition.kind !== "node") throw new Error(`Node ${request.nodeId} is not runnable`);
3540
+ const resolvedParent = request.parent ?? state.parent;
3541
+ const data = this.runDataFactory.create(state.outputsByNode);
3542
+ const limits = this.resolveEngineLimitsFromState(state);
3543
+ const persistedInput = pendingExecution.inputsByPort.in ?? request.input;
3544
+ const base = this.runExecutionContextFactory.create({
3545
+ runId: state.runId,
3546
+ workflowId: state.workflowId,
3547
+ nodeId: request.nodeId,
3548
+ parent: resolvedParent,
3549
+ subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
3550
+ engineMaxNodeActivations: limits.engineMaxNodeActivations,
3551
+ engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
3552
+ data,
3553
+ nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent)
3554
+ });
3555
+ const activationRequest = this.nodeActivationRequestComposer.createSingleFromDefinitionWithActivation({
3556
+ activationId: request.activationId,
3557
+ runId: request.runId,
3558
+ workflowId: request.workflowId,
3559
+ parent: resolvedParent,
3560
+ executionOptions: request.executionOptions ?? state.executionOptions,
3561
+ base,
3562
+ data,
3563
+ definition: {
3564
+ id: definition.id,
3565
+ config: definition.config
3566
+ },
3567
+ batchId: pendingExecution.batchId ?? "batch_1",
3568
+ input: persistedInput
3569
+ });
3570
+ await this.continuation.markNodeRunning({
3571
+ runId: activationRequest.runId,
3572
+ activationId: activationRequest.activationId,
3573
+ nodeId: activationRequest.nodeId,
3574
+ inputsByPort: pendingExecution.inputsByPort
3575
+ });
3576
+ let outputs;
3577
+ try {
3578
+ outputs = await this.nodeExecutor.execute(activationRequest);
3579
+ } catch (error) {
3580
+ await this.resumeAfterExecutionError(activationRequest, this.asError(error));
3581
+ return;
3582
+ }
3583
+ await this.resumeAfterExecutionResult(activationRequest, outputs ?? {});
3584
+ }
3585
+ resolvePersistedWorkflow(state) {
3586
+ return this.workflowSnapshotResolver.resolve({
3587
+ workflowId: state.workflowId,
3588
+ workflowSnapshot: state.workflowSnapshot
3589
+ });
3590
+ }
3591
+ resolveEngineLimitsFromState(state) {
3592
+ const fallback = this.executionLimitsPolicy.createRootExecutionOptions();
3593
+ return {
3594
+ engineMaxNodeActivations: state.executionOptions?.maxNodeActivations ?? fallback.maxNodeActivations,
3595
+ engineMaxSubworkflowDepth: state.executionOptions?.maxSubworkflowDepth ?? fallback.maxSubworkflowDepth
3596
+ };
3597
+ }
3598
+ async resumeAfterExecutionResult(request, outputs) {
3599
+ try {
3600
+ await this.continuation.resumeFromNodeResult({
3601
+ runId: request.runId,
3602
+ activationId: request.activationId,
3603
+ nodeId: request.nodeId,
3604
+ outputs
3605
+ });
3606
+ } catch (error) {
3607
+ this.rethrowUnlessIgnorableContinuationError(error);
3608
+ }
3609
+ }
3610
+ async resumeAfterExecutionError(request, error) {
3611
+ try {
3612
+ await this.continuation.resumeFromNodeError({
3613
+ runId: request.runId,
3614
+ activationId: request.activationId,
3615
+ nodeId: request.nodeId,
3616
+ error
3617
+ });
3618
+ } catch (continuationError) {
3619
+ this.rethrowUnlessIgnorableContinuationError(continuationError);
3620
+ }
3621
+ }
3622
+ asError(error) {
3623
+ return error instanceof Error ? error : new Error(String(error));
3624
+ }
3625
+ rethrowUnlessIgnorableContinuationError(error) {
3626
+ if (this.isIgnorableContinuationError(error)) return;
3627
+ throw this.asError(error);
3628
+ }
3629
+ isIgnorableContinuationError(error) {
3630
+ const message = this.asError(error).message;
3631
+ return message.includes(" is not pending") || message.includes("activationId mismatch") || message.includes("nodeId mismatch");
3632
+ }
3633
+ };
3634
+
3635
+ //#endregion
3636
+ //#region src/planning/RunQueuePlanner.ts
3637
+ var RunQueuePlanner = class {
3638
+ constructor(topology, nodeInstances) {
3639
+ this.topology = topology;
3640
+ this.nodeInstances = nodeInstances;
3641
+ }
3642
+ validateNodeKinds() {
3643
+ for (const [toNodeId, inputs] of this.topology.expectedInputsByNode.entries()) {
3644
+ if (inputs.length <= 1) {
3645
+ const only = inputs[0];
3646
+ if (only && only !== "in") {
3647
+ const inst$1 = this.nodeInstances.get(toNodeId);
3648
+ if (!this.isMultiInputNode(inst$1)) throw new Error(`Node ${toNodeId} only supports input 'in' (got '${only}').`);
3649
+ }
3650
+ continue;
3651
+ }
3652
+ const inst = this.nodeInstances.get(toNodeId);
3653
+ if (!this.isMultiInputNode(inst)) throw new Error(`Node ${toNodeId} has ${inputs.length} inbound edges. Insert a Merge node to combine branches.`);
3654
+ }
3655
+ }
3656
+ seedFromTrigger(args) {
3657
+ const queue = [];
3658
+ for (const e of this.topology.outgoingByNode.get(args.startNodeId) ?? []) {
3659
+ if (e.output !== "main") continue;
3660
+ this.enqueueEdge(queue, {
3661
+ batchId: args.batchId,
3662
+ to: e.to,
3663
+ from: {
3664
+ nodeId: args.startNodeId,
3665
+ output: "main"
3666
+ },
3667
+ items: args.items
3668
+ });
3669
+ }
3670
+ return queue;
3671
+ }
3672
+ applyOutputs(queue, args) {
3673
+ for (const e of this.topology.outgoingByNode.get(args.fromNodeId) ?? []) {
3674
+ const outItems = args.outputs[e.output] ?? [];
3675
+ this.enqueueEdge(queue, {
3676
+ batchId: args.batchId,
3677
+ to: e.to,
3678
+ from: {
3679
+ nodeId: args.fromNodeId,
3680
+ output: e.output
3681
+ },
3682
+ items: outItems
3683
+ });
3684
+ }
3685
+ }
3686
+ nextActivation(queue) {
3687
+ const readyCollect = this.resolveReadyCollect(queue);
3688
+ if (readyCollect) return readyCollect;
3689
+ const jobIdx = queue.findIndex((q) => !q.collect);
3690
+ if (jobIdx === -1) {
3691
+ if (queue.length === 0) return null;
3692
+ const sealedCollect = this.resolveSealedCollect(queue);
3693
+ if (sealedCollect) return sealedCollect;
3694
+ const stuck = queue[0];
3695
+ throw new Error(this.describeUnsatisfiedCollect(stuck));
3696
+ }
3697
+ const job = queue.splice(jobIdx, 1)[0];
3698
+ const def = this.topology.defsById.get(job.nodeId);
3699
+ if (!def || def.kind !== "node") return this.nextActivation(queue);
3700
+ return {
3701
+ kind: "single",
3702
+ nodeId: job.nodeId,
3703
+ input: job.input,
3704
+ batchId: job.batchId ?? "batch_1"
3705
+ };
3706
+ }
3707
+ sumItemsByPort(inputsByPort) {
3708
+ let n = 0;
3709
+ for (const v of Object.values(inputsByPort)) n += v?.length ?? 0;
3710
+ return n;
3711
+ }
3712
+ resolveReadyCollect(queue) {
3713
+ for (let i = 0; i < queue.length; i++) {
3714
+ const ready = this.tryDequeueCollect(queue, i);
3715
+ if (ready) return ready;
3716
+ }
3717
+ return null;
3718
+ }
3719
+ resolveSealedCollect(queue) {
3720
+ for (let i = 0; i < queue.length; i++) {
3721
+ const queueEntry = queue[i];
3722
+ if (!queueEntry.collect) continue;
3723
+ const received = queueEntry.collect.received;
3724
+ if (Object.keys(received).length === 0) continue;
3725
+ this.fillMissingCollectInputs(queueEntry);
3726
+ const ready = this.tryDequeueCollect(queue, i);
3727
+ if (ready) return ready;
3728
+ }
3729
+ return null;
3730
+ }
3731
+ tryDequeueCollect(queue, index) {
3732
+ const queueEntry = queue[index];
3733
+ if (!queueEntry.collect) return null;
3734
+ const batchId = queueEntry.batchId ?? "batch_1";
3735
+ const expected = queueEntry.collect.expectedInputs ?? [];
3736
+ const received = queueEntry.collect.received;
3737
+ for (const input of expected) if (!(input in received)) return null;
3738
+ queue.splice(index, 1);
3739
+ return {
3740
+ kind: "multi",
3741
+ nodeId: queueEntry.nodeId,
3742
+ inputsByPort: received,
3743
+ batchId
3744
+ };
3745
+ }
3746
+ fillMissingCollectInputs(queueEntry) {
3747
+ if (!queueEntry.collect) return;
3748
+ const received = queueEntry.collect.received;
3749
+ for (const input of queueEntry.collect.expectedInputs ?? []) if (!(input in received)) received[input] = [];
3750
+ }
3751
+ /**
3752
+ * Matches `CurrentStateFrontierPlanner.buildFrontierQueue`: anything that is not exactly one input
3753
+ * port named `in` participates in multi-port collect (Merge after `If` branches, etc.). Routing must
3754
+ * not depend solely on `nodeInstances.get(toNodeId)?.executeMulti`, or a Merge can be enqueued as a
3755
+ * single-input job and `NodeExecutor` will call `execute` on a multi-input-only implementation.
3756
+ */
3757
+ usesTopologyCollectMerge(toNodeId) {
3758
+ const expectedInputs = this.topology.expectedInputsByNode.get(toNodeId) ?? [];
3759
+ return expectedInputs.length !== 1 || expectedInputs[0] !== "in";
3760
+ }
3761
+ enqueueEdge(queue, args) {
3762
+ const target = this.nodeInstances.get(args.to.nodeId);
3763
+ if (!(this.usesTopologyCollectMerge(args.to.nodeId) || this.isMultiInputNode(target))) {
3764
+ if (args.items.length === 0) {
3765
+ if (this.shouldContinueAfterEmptyOutputFromSource(args.from.nodeId)) {
3766
+ queue.push({
3767
+ nodeId: args.to.nodeId,
3768
+ input: args.items,
3769
+ toInput: args.to.input,
3770
+ batchId: args.batchId,
3771
+ from: args.from
3772
+ });
3773
+ return;
3774
+ }
3775
+ this.propagateEmptyPath(queue, args.to.nodeId, args.batchId);
3776
+ return;
3777
+ }
3778
+ queue.push({
3779
+ nodeId: args.to.nodeId,
3780
+ input: args.items,
3781
+ toInput: args.to.input,
3782
+ batchId: args.batchId,
3783
+ from: args.from
3784
+ });
3785
+ return;
3786
+ }
3787
+ const expected = this.topology.expectedInputsByNode.get(args.to.nodeId) ?? [];
3788
+ let collect = queue.find((q) => q.nodeId === args.to.nodeId && (q.batchId ?? "batch_1") === args.batchId && !!q.collect);
3789
+ if (!collect) {
3790
+ collect = {
3791
+ nodeId: args.to.nodeId,
3792
+ input: [],
3793
+ batchId: args.batchId,
3794
+ collect: {
3795
+ expectedInputs: expected,
3796
+ received: {}
3797
+ }
3798
+ };
3799
+ queue.push(collect);
3800
+ }
3801
+ const received = collect.collect.received;
3802
+ received[args.to.input] = args.items;
3803
+ }
3804
+ shouldContinueAfterEmptyOutputFromSource(fromNodeId) {
3805
+ const def = this.topology.defsById.get(fromNodeId);
3806
+ if (!def) return false;
3807
+ return def.config.continueWhenEmptyOutput === true;
3808
+ }
3809
+ propagateEmptyPath(queue, nodeId, batchId) {
3810
+ for (const edge of this.topology.outgoingByNode.get(nodeId) ?? []) this.enqueueEdge(queue, {
3811
+ batchId,
3812
+ to: edge.to,
3813
+ from: {
3814
+ nodeId,
3815
+ output: edge.output
3816
+ },
3817
+ items: []
3818
+ });
3819
+ }
3820
+ isMultiInputNode(n) {
3821
+ return typeof n?.executeMulti === "function";
3822
+ }
3823
+ describeUnsatisfiedCollect(queueEntry) {
3824
+ const batchId = queueEntry.batchId ?? "batch_1";
3825
+ const expectedInputs = queueEntry.collect?.expectedInputs ?? [];
3826
+ const receivedInputs = Object.keys(queueEntry.collect?.received ?? {});
3827
+ const missingInputs = expectedInputs.filter((input) => !receivedInputs.includes(input));
3828
+ const mergeNodeLabel = this.formatNodeLabel(queueEntry.nodeId);
3829
+ const receivedSummary = this.describeReceivedInputs(queueEntry);
3830
+ const missingSummary = this.describeMissingInputs(queueEntry.nodeId, missingInputs);
3831
+ return [
3832
+ `Multi-input collect is stuck at ${mergeNodeLabel} (batchId=${batchId}).`,
3833
+ `Expected inputs: ${this.formatInputList(expectedInputs)}.`,
3834
+ `Received inputs: ${receivedSummary}.`,
3835
+ `Missing inputs: ${missingSummary}.`
3836
+ ].join(" ");
3837
+ }
3838
+ describeReceivedInputs(queueEntry) {
3839
+ const received = queueEntry.collect?.received ?? {};
3840
+ const receivedEntries = Object.entries(received);
3841
+ if (receivedEntries.length === 0) return "none";
3842
+ return receivedEntries.map(([input, items]) => `${input} (${items.length} item${items.length === 1 ? "" : "s"})`).join(", ");
3843
+ }
3844
+ describeMissingInputs(nodeId, missingInputs) {
3845
+ if (missingInputs.length === 0) return "none";
3846
+ return missingInputs.map((input) => {
3847
+ const sources = this.findSources(nodeId, input);
3848
+ if (sources.length === 0) return input;
3849
+ return `${input} from ${sources.join(" or ")}`;
3850
+ }).join(", ");
3851
+ }
3852
+ findSources(nodeId, input) {
3853
+ const matches = [];
3854
+ for (const [sourceNodeId, edges] of this.topology.outgoingByNode.entries()) for (const edge of edges) if (edge.to.nodeId === nodeId && edge.to.input === input) matches.push(this.formatNodeLabel(sourceNodeId));
3855
+ return matches;
3856
+ }
3857
+ formatInputList(inputs) {
3858
+ return inputs.length > 0 ? `[${inputs.join(", ")}]` : "[]";
3859
+ }
3860
+ formatNodeLabel(nodeId) {
3861
+ const definition = this.topology.defsById.get(nodeId);
3862
+ const instance = this.nodeInstances.get(nodeId);
3863
+ const typeName = definition?.type && typeof definition.type === "function" ? definition.type.name : instance && typeof instance === "object" && "constructor" in instance ? instance.constructor.name ?? "Node" : "Node";
3864
+ return definition?.name ? `"${definition.name}" (${typeName}:${nodeId})` : `${typeName}:${nodeId}`;
3865
+ }
3866
+ };
3867
+
3868
+ //#endregion
3869
+ //#region src/planning/EngineWorkflowPlanningFactory.ts
3870
+ var EngineWorkflowPlanningFactory = class {
3871
+ constructor(workflowNodeInstanceFactory) {
3872
+ this.workflowNodeInstanceFactory = workflowNodeInstanceFactory;
3873
+ }
3874
+ create(workflow) {
3875
+ this.validateAcyclic(workflow);
3876
+ const topology = WorkflowTopology.fromWorkflow(workflow);
3877
+ const planner = new RunQueuePlanner(topology, this.workflowNodeInstanceFactory.createNodes(workflow));
3878
+ planner.validateNodeKinds();
3879
+ return {
3880
+ topology,
3881
+ planner
3882
+ };
3883
+ }
3884
+ validateAcyclic(workflow) {
3885
+ const classifier = WorkflowExecutableNodeClassifierFactory.create(workflow);
3886
+ const outgoing = /* @__PURE__ */ new Map();
3887
+ const visitState = /* @__PURE__ */ new Map();
3888
+ for (const node$1 of workflow.nodes) if (classifier.isExecutableNodeId(node$1.id)) visitState.set(node$1.id, "unvisited");
3889
+ for (const edge of workflow.edges) {
3890
+ if (!classifier.isExecutableNodeId(edge.from.nodeId) || !classifier.isExecutableNodeId(edge.to.nodeId)) continue;
3891
+ const destinations = outgoing.get(edge.from.nodeId) ?? [];
3892
+ destinations.push(edge.to.nodeId);
3893
+ outgoing.set(edge.from.nodeId, destinations);
3894
+ }
3895
+ for (const node$1 of workflow.nodes) if (classifier.isExecutableNodeId(node$1.id) && visitState.get(node$1.id) === "unvisited") this.depthFirstSearch(node$1.id, outgoing, visitState);
3896
+ }
3897
+ depthFirstSearch(nodeId, outgoing, visitState) {
3898
+ visitState.set(nodeId, "visiting");
3899
+ for (const toNodeId of outgoing.get(nodeId) ?? []) {
3900
+ const state = visitState.get(toNodeId);
3901
+ if (state === "visiting") throw new Error(`Workflow graph contains a directed cycle (edge ${nodeId} -> ${toNodeId}).`);
3902
+ if (state === "unvisited") this.depthFirstSearch(toNodeId, outgoing, visitState);
3903
+ }
3904
+ visitState.set(nodeId, "done");
3905
+ }
3906
+ };
3907
+
3908
+ //#endregion
3909
+ //#region src/orchestration/TriggerRuntimeService.ts
3910
+ var TriggerRuntimeService = class {
3911
+ credentialResolverFactory;
3912
+ triggerCleanupHandlesByKey = /* @__PURE__ */ new Map();
3913
+ constructor(workflowRepository, workflowActivationPolicy, runIdFactory, runDataFactory, executionContextFactory, credentialResolverFactory, nodeExecutionStatePublisherFactory, nodeResolver, triggerSetupStateRepository, emitHandler, executionLimitsPolicy, diagnostics) {
3914
+ this.workflowRepository = workflowRepository;
3915
+ this.workflowActivationPolicy = workflowActivationPolicy;
3916
+ this.runIdFactory = runIdFactory;
3917
+ this.runDataFactory = runDataFactory;
3918
+ this.executionContextFactory = executionContextFactory;
3919
+ this.nodeExecutionStatePublisherFactory = nodeExecutionStatePublisherFactory;
3920
+ this.nodeResolver = nodeResolver;
3921
+ this.triggerSetupStateRepository = triggerSetupStateRepository;
3922
+ this.emitHandler = emitHandler;
3923
+ this.executionLimitsPolicy = executionLimitsPolicy;
3924
+ this.diagnostics = diagnostics;
3925
+ this.credentialResolverFactory = credentialResolverFactory;
3926
+ }
3927
+ async startTriggers() {
3928
+ for (const wf of this.workflowRepository.list()) {
3929
+ if (!this.workflowActivationPolicy.isActive(wf.id)) {
3930
+ const summaries = this.formatTriggerSummaries(wf);
3931
+ if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}) is inactive; skipping trigger setup — ${summaries.join("; ")}.`);
3932
+ continue;
3933
+ }
3934
+ await this.startTriggersForWorkflow(wf);
3935
+ }
3936
+ }
3937
+ async syncWorkflowTriggersForActivation(workflowId) {
3938
+ const wf = this.workflowRepository.get(workflowId);
3939
+ if (!wf) return;
3940
+ const summaries = this.formatTriggerSummaries(wf);
3941
+ if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}): stopping triggers — ${summaries.join("; ")}.`);
3942
+ await this.stopTriggersForWorkflow(wf);
3943
+ if (this.workflowActivationPolicy.isActive(workflowId)) {
3944
+ if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}): activation on; starting triggers — ${summaries.join("; ")}.`);
3945
+ await this.startTriggersForWorkflow(wf);
3946
+ } else this.logInfo(`Workflow "${wf.name}" (${wf.id}): activation off; triggers not started.`);
3947
+ }
3948
+ async stop() {
3949
+ for (const workflow of this.workflowRepository.list()) await this.stopTriggersForWorkflow(workflow);
3950
+ }
3951
+ async createTriggerTestItems(args) {
3952
+ const definition = args.workflow.nodes.find((node$2) => node$2.id === args.nodeId);
3953
+ if (!definition) throw new Error(`Unknown trigger nodeId: ${args.nodeId}`);
3954
+ if (definition.kind !== "trigger") throw new Error(`Node ${args.nodeId} is not a trigger`);
3955
+ const node$1 = this.nodeResolver.resolve(definition.type);
3956
+ if (!this.isTestableTriggerNode(node$1)) return;
3957
+ const data = this.runDataFactory.create();
3958
+ const runId = this.runIdFactory.makeRunId();
3959
+ const trigger = {
3960
+ workflowId: args.workflow.id,
3961
+ nodeId: definition.id
3962
+ };
3963
+ const previousState = await this.triggerSetupStateRepository.load(trigger);
3964
+ return await node$1.getTestItems({
3965
+ ...this.createExecutionContext({
3966
+ runId,
3967
+ workflowId: args.workflow.id,
3968
+ nodeId: definition.id,
3969
+ data
3970
+ }),
3971
+ trigger,
3972
+ nodeId: definition.id,
3973
+ config: definition.config,
3974
+ previousState: previousState?.state
3975
+ });
3976
+ }
3977
+ async startTriggersForWorkflow(wf) {
3978
+ for (const def of wf.nodes) {
3979
+ if (def.kind !== "trigger") continue;
3980
+ const node$1 = this.nodeResolver.resolve(def.type);
3981
+ const data = this.runDataFactory.create();
3982
+ const triggerRunId = this.runIdFactory.makeRunId();
3983
+ const trigger = {
3984
+ workflowId: wf.id,
3985
+ nodeId: def.id
3986
+ };
3987
+ await this.stopTrigger(trigger);
3988
+ const previousState = await this.triggerSetupStateRepository.load(trigger);
3989
+ let nextState;
3990
+ try {
3991
+ nextState = await node$1.setup({
3992
+ ...this.createExecutionContext({
3993
+ runId: triggerRunId,
3994
+ workflowId: wf.id,
3995
+ nodeId: def.id,
3996
+ data
3997
+ }),
3998
+ trigger,
3999
+ config: def.config,
4000
+ previousState: previousState?.state,
4001
+ registerCleanup: (cleanup) => {
4002
+ this.registerTriggerCleanupHandle(trigger, cleanup);
4003
+ },
4004
+ emit: async (items) => {
4005
+ await this.emitHandler.emit(wf, def.id, items);
4006
+ }
4007
+ });
4008
+ } catch (triggerError) {
4009
+ await this.stopTrigger(trigger);
4010
+ const message = triggerError instanceof Error ? triggerError.message : String(triggerError);
4011
+ this.logWarn(`Skipping trigger setup for workflow ${wf.id} node ${def.id}: ${message}`);
4012
+ continue;
4013
+ }
4014
+ if (nextState === void 0) await this.triggerSetupStateRepository.delete(trigger);
4015
+ else await this.triggerSetupStateRepository.save({
4016
+ trigger,
4017
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4018
+ state: nextState
4019
+ });
4020
+ }
4021
+ }
4022
+ async stopTriggersForWorkflow(workflow) {
4023
+ for (const node$1 of workflow.nodes) {
4024
+ if (node$1.kind !== "trigger") continue;
4025
+ await this.stopTrigger({
4026
+ workflowId: workflow.id,
4027
+ nodeId: node$1.id
4028
+ });
4029
+ }
4030
+ }
4031
+ createExecutionContext(args) {
4032
+ const nodeState = this.nodeExecutionStatePublisherFactory.create(args.runId, args.workflowId, void 0);
4033
+ const rootLimits = this.executionLimitsPolicy.createRootExecutionOptions();
4034
+ return this.executionContextFactory.create({
4035
+ runId: args.runId,
4036
+ workflowId: args.workflowId,
4037
+ parent: void 0,
4038
+ subworkflowDepth: rootLimits.subworkflowDepth ?? 0,
4039
+ engineMaxNodeActivations: rootLimits.maxNodeActivations,
4040
+ engineMaxSubworkflowDepth: rootLimits.maxSubworkflowDepth,
4041
+ data: args.data,
4042
+ nodeState,
4043
+ getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId)
4044
+ });
4045
+ }
4046
+ registerTriggerCleanupHandle(trigger, cleanup) {
4047
+ const key = this.toTriggerKey(trigger);
4048
+ const cleanups = this.triggerCleanupHandlesByKey.get(key) ?? [];
4049
+ cleanups.push(cleanup);
4050
+ this.triggerCleanupHandlesByKey.set(key, cleanups);
4051
+ }
4052
+ async stopTrigger(trigger) {
4053
+ const key = this.toTriggerKey(trigger);
4054
+ const cleanups = this.triggerCleanupHandlesByKey.get(key) ?? [];
4055
+ this.triggerCleanupHandlesByKey.delete(key);
4056
+ for (const cleanup of [...cleanups].reverse()) await cleanup.stop();
4057
+ }
4058
+ toTriggerKey(trigger) {
4059
+ return `${trigger.workflowId}:${trigger.nodeId}`;
4060
+ }
4061
+ formatTriggerSummaries(wf) {
4062
+ const out = [];
4063
+ for (const def of wf.nodes) {
4064
+ if (def.kind !== "trigger") continue;
4065
+ out.push(this.describeTriggerNode(def));
4066
+ }
4067
+ return out;
4068
+ }
4069
+ describeTriggerNode(def) {
4070
+ const label = def.name !== void 0 && def.name.trim().length > 0 ? def.name.trim() : String(def.id);
4071
+ const cfg = def.config;
4072
+ if (typeof cfg.endpointKey === "string" && cfg.endpointKey.trim().length > 0) return `${label} (webhook "${cfg.endpointKey.trim()}")`;
4073
+ return label;
4074
+ }
4075
+ logInfo(message) {
4076
+ if (this.diagnostics) this.diagnostics.info(message);
4077
+ }
4078
+ logWarn(message) {
4079
+ if (this.diagnostics) this.diagnostics.warn(message);
4080
+ else console.warn(`[engine] ${message}`);
4081
+ }
4082
+ isTestableTriggerNode(node$1) {
4083
+ return typeof node$1.getTestItems === "function";
4084
+ }
4085
+ };
4086
+
4087
+ //#endregion
4088
+ //#region src/orchestration/EngineWaiters.ts
4089
+ var EngineWaiters = class {
4090
+ completionWaiters = /* @__PURE__ */ new Map();
4091
+ webhookResponseWaiters = /* @__PURE__ */ new Map();
4092
+ waitForCompletion(runId) {
4093
+ return new Promise((resolve) => {
4094
+ const list = this.completionWaiters.get(runId) ?? [];
4095
+ list.push(resolve);
4096
+ this.completionWaiters.set(runId, list);
4097
+ });
4098
+ }
4099
+ waitForWebhookResponse(runId) {
4100
+ return new Promise((resolve) => {
4101
+ const list = this.webhookResponseWaiters.get(runId) ?? [];
4102
+ list.push(resolve);
4103
+ this.webhookResponseWaiters.set(runId, list);
4104
+ });
4105
+ }
4106
+ resolveRunCompletion(result) {
4107
+ if (result.status !== "completed" && result.status !== "failed") return;
4108
+ const list = this.completionWaiters.get(result.runId);
4109
+ if (!list || list.length === 0) return;
4110
+ this.completionWaiters.delete(result.runId);
4111
+ for (const r of list) r(result);
4112
+ }
4113
+ resolveWebhookResponse(result) {
4114
+ const list = this.webhookResponseWaiters.get(result.runId);
4115
+ if (!list || list.length === 0) return;
4116
+ this.webhookResponseWaiters.delete(result.runId);
4117
+ for (const resolve of list) resolve(result);
4118
+ }
4119
+ };
4120
+
4121
+ //#endregion
4122
+ //#region src/orchestration/Engine.ts
4123
+ /**
4124
+ * Runtime facade for orchestration, continuation, triggers, and webhook routing.
4125
+ * Prefer {@link import("../intents/RunIntentService").RunIntentService} for host/HTTP invocation boundaries.
4126
+ * The class token is exported from `@codemation/core/bootstrap` (not the main `@codemation/core` barrel).
4127
+ */
4128
+ var Engine = class {
4129
+ constructor(deps) {
4130
+ this.deps = deps;
4131
+ }
4132
+ loadWorkflows(workflows) {
4133
+ this.deps.tokenRegistry.registerFromWorkflows?.(workflows);
4134
+ this.deps.liveWorkflowRepository.setWorkflows(workflows);
4135
+ this.deps.webhookTriggerMatcher.onEngineWorkflowsLoaded?.();
4136
+ }
4137
+ getTokenRegistry() {
4138
+ return this.deps.tokenRegistry;
4139
+ }
4140
+ resolveWorkflowSnapshot(args) {
4141
+ return this.deps.workflowSnapshotResolver.resolve(args);
4142
+ }
4143
+ async startTriggers() {
4144
+ return await this.deps.triggerRuntime.startTriggers();
4145
+ }
4146
+ async syncWorkflowTriggersForActivation(workflowId) {
4147
+ await this.deps.triggerRuntime.syncWorkflowTriggersForActivation(workflowId);
4148
+ this.deps.webhookTriggerMatcher.reloadWebhookRoutes?.();
4149
+ }
4150
+ async start(workflows) {
4151
+ await this.stop();
4152
+ this.loadWorkflows(workflows);
4153
+ await this.startTriggers();
4154
+ }
4155
+ async stop() {
4156
+ await this.deps.triggerRuntime.stop();
4157
+ this.deps.webhookTriggerMatcher.onEngineStopped?.();
4158
+ }
4159
+ resolveWebhookTrigger(args) {
4160
+ const entry = this.deps.webhookTriggerMatcher.lookup(args.endpointPath);
4161
+ if (!entry) return { status: "notFound" };
4162
+ if (!entry.methods.includes(args.method)) return {
4163
+ status: "methodNotAllowed",
4164
+ match: entry
4165
+ };
4166
+ return {
4167
+ status: "ok",
4168
+ match: entry
4169
+ };
4170
+ }
4171
+ async createTriggerTestItems(args) {
4172
+ return await this.deps.triggerRuntime.createTriggerTestItems(args);
4173
+ }
4174
+ async runWorkflow(wf, startAt, items, parent, executionOptions, persistedStateOverrides) {
4175
+ return await this.deps.runStartService.runWorkflow(wf, startAt, items, parent, executionOptions, persistedStateOverrides);
4176
+ }
4177
+ async runWorkflowFromState(request) {
4178
+ return await this.deps.runStartService.runWorkflowFromState(request);
4179
+ }
4180
+ async markNodeRunning(args) {
4181
+ return await this.deps.runContinuationService.markNodeRunning(args);
4182
+ }
4183
+ async resumeFromNodeResult(args) {
4184
+ return await this.deps.runContinuationService.resumeFromNodeResult(args);
4185
+ }
4186
+ async resumeFromNodeError(args) {
4187
+ return await this.deps.runContinuationService.resumeFromNodeError(args);
4188
+ }
4189
+ async resumeFromStepResult(args) {
4190
+ return await this.deps.runContinuationService.resumeFromStepResult(args);
4191
+ }
4192
+ async resumeFromStepError(args) {
4193
+ return await this.deps.runContinuationService.resumeFromStepError(args);
4194
+ }
4195
+ async waitForCompletion(runId) {
4196
+ return await this.deps.runContinuationService.waitForCompletion(runId);
4197
+ }
4198
+ async waitForWebhookResponse(runId) {
4199
+ return await this.deps.runContinuationService.waitForWebhookResponse(runId);
4200
+ }
4201
+ async handleNodeExecutionRequest(request) {
4202
+ await this.deps.nodeExecutionRequestHandler.handleNodeExecutionRequest(request);
4203
+ }
4204
+ };
4205
+
4206
+ //#endregion
4207
+ //#region src/runtime/EngineFactory.ts
4208
+ /**
4209
+ * Composes the {@link Engine} graph from {@link EngineCompositionDeps}. Production wiring usually goes through
4210
+ * {@link import("../bootstrap/runtime/EngineRuntimeRegistrar").EngineRuntimeRegistrar}; this factory remains for tests and custom composition.
4211
+ * Exported from `@codemation/core/bootstrap` (not the main `@codemation/core` barrel).
4212
+ */
4213
+ var EngineFactory = class {
4214
+ create(deps) {
4215
+ const waiters = new EngineWaiters();
4216
+ const credentialResolverFactory = new CredentialResolverFactory(deps.credentialSessions);
4217
+ const nodeEventPublisher = new NodeEventPublisher(deps.eventBus);
4218
+ const nodeStatePublisherFactory = new NodeRunStateWriterFactory(deps.workflowExecutionRepository, nodeEventPublisher);
4219
+ const planningFactory = new EngineWorkflowPlanningFactory(deps.workflowNodeInstanceFactory);
4220
+ const executionLimitsPolicy = deps.executionLimitsPolicy ?? new EngineExecutionLimitsPolicy();
4221
+ const workflowSnapshotCodec = deps.workflowSnapshotCodec ?? new WorkflowSnapshotCodec(deps.tokenRegistry);
4222
+ const missingRuntimeFallbacks = deps.missingRuntimeFallbacks ?? new MissingRuntimeFallbacks();
4223
+ const workflowSnapshotResolver = new WorkflowSnapshotResolver(deps.workflowRepository, deps.tokenRegistry, workflowSnapshotCodec, missingRuntimeFallbacks);
4224
+ const semantics = new RunStateSemantics(new MissingRuntimeExecutionMarker());
4225
+ const nodeActivationRequestInputPreparer = new NodeActivationRequestInputPreparer(deps.workflowNodeInstanceFactory);
4226
+ const activationEnqueueService = new ActivationEnqueueService(deps.activationScheduler, deps.workflowExecutionRepository, nodeEventPublisher, nodeActivationRequestInputPreparer);
4227
+ const runExecutionContextFactory = new WorkflowRunExecutionContextFactory(deps.executionContextFactory, credentialResolverFactory);
4228
+ const nodeActivationRequestComposer = new NodeActivationRequestComposer(deps.activationIdFactory, credentialResolverFactory);
4229
+ const persistedRunStateTerminalBuilder = new PersistedRunStateTerminalBuilder();
4230
+ const storagePolicyEvaluator = new WorkflowStoragePolicyEvaluator(deps.nodeResolver);
4231
+ const terminalPersistence = new RunTerminalPersistenceCoordinator(deps.workflowExecutionRepository, storagePolicyEvaluator);
4232
+ const policyErrorServices = new WorkflowPolicyErrorServices(deps.nodeResolver);
4233
+ const runStartService = new RunStartService(deps.runIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, workflowSnapshotCodec, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, deps.workflowPolicyRuntimeDefaults, executionLimitsPolicy);
4234
+ const runContinuationService = new RunContinuationService(deps.activationIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, runExecutionContextFactory, workflowSnapshotResolver, planningFactory, nodeStatePublisherFactory, credentialResolverFactory, nodeActivationRequestComposer, persistedRunStateTerminalBuilder, activationEnqueueService, nodeEventPublisher, semantics, waiters, policyErrorServices, terminalPersistence, executionLimitsPolicy);
4235
+ const nodeExecutionRequestHandler = new NodeExecutionRequestHandlerService(deps.workflowExecutionRepository, workflowSnapshotResolver, deps.runDataFactory, runExecutionContextFactory, nodeStatePublisherFactory, nodeActivationRequestComposer, deps.nodeExecutor, runContinuationService, executionLimitsPolicy);
4236
+ const triggerRuntime = new TriggerRuntimeService(deps.workflowRepository, deps.workflowActivationPolicy, deps.runIdFactory, deps.runDataFactory, deps.executionContextFactory, credentialResolverFactory, nodeStatePublisherFactory, deps.nodeResolver, deps.triggerSetupStateRepository, { emit: async (workflow, triggerNodeId, items) => {
4237
+ await runStartService.runWorkflow(workflow, triggerNodeId, items, void 0);
4238
+ } }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics);
4239
+ const engine = new Engine({
4240
+ liveWorkflowRepository: deps.liveWorkflowRepository,
4241
+ tokenRegistry: deps.tokenRegistry,
4242
+ webhookTriggerMatcher: deps.webhookTriggerMatcher,
4243
+ workflowSnapshotResolver,
4244
+ triggerRuntime,
4245
+ runStartService,
4246
+ runContinuationService,
4247
+ nodeExecutionRequestHandler
4248
+ });
4249
+ deps.activationScheduler.setContinuation?.(engine);
4250
+ return engine;
4251
+ }
4252
+ };
4253
+
4254
+ //#endregion
4255
+ //#region src/runtime/EngineWorkflowRunnerService.ts
4256
+ var EngineWorkflowRunnerService = class {
4257
+ constructor(engine, workflowRepository) {
4258
+ this.engine = engine;
4259
+ this.workflowRepository = workflowRepository;
4260
+ }
4261
+ async runById(args) {
4262
+ const { workflowId, startAt, items, parent } = args;
4263
+ const wf = this.workflowRepository.get(workflowId);
4264
+ if (!wf) throw new Error(`Unknown workflowId: ${workflowId}`);
4265
+ const startNodeId = startAt ?? this.findDefaultStartNodeId(wf);
4266
+ const scheduled = await this.engine.runWorkflow(wf, startNodeId, items, parent);
4267
+ if (scheduled.status !== "pending") return scheduled;
4268
+ return await this.engine.waitForCompletion(scheduled.runId);
4269
+ }
4270
+ findDefaultStartNodeId(wf) {
4271
+ return WorkflowExecutableNodeClassifierFactory.create(wf).findDefaultExecutableStartNodeId(wf);
4272
+ }
4273
+ };
4274
+
4275
+ //#endregion
4276
+ //#region src/runtime/EngineWorkflowRunnerServiceFactory.ts
4277
+ var EngineWorkflowRunnerServiceFactory = class {
4278
+ create(engine, workflowRepository) {
4279
+ return new EngineWorkflowRunnerService(engine, workflowRepository);
4280
+ }
4281
+ };
4282
+
3254
4283
  //#endregion
3255
4284
  //#region src/runtime/InMemoryLiveWorkflowRepository.ts
3256
4285
  var InMemoryLiveWorkflowRepository = class {
@@ -3395,12 +4424,108 @@ var RunIntentService = class {
3395
4424
  };
3396
4425
 
3397
4426
  //#endregion
3398
- Object.defineProperty(exports, 'ActivationEnqueueService', {
3399
- enumerable: true,
3400
- get: function () {
3401
- return ActivationEnqueueService;
3402
- }
3403
- });
4427
+ //#region src/runtime/RunIntentServiceFactory.ts
4428
+ var RunIntentServiceFactory = class {
4429
+ create(engine, workflowRepository) {
4430
+ return new RunIntentService(engine, workflowRepository);
4431
+ }
4432
+ };
4433
+
4434
+ //#endregion
4435
+ //#region src/runtime/WorkflowRepositoryWebhookTriggerMatcher.ts
4436
+ /**
4437
+ * Resolves webhook HTTP routes from the live workflow repository (no trigger setup / registration).
4438
+ * Maintains an in-memory index keyed by user-defined endpoint path for O(1) lookups after reload.
4439
+ */
4440
+ var WorkflowRepositoryWebhookTriggerMatcher = class {
4441
+ routeByPath = /* @__PURE__ */ new Map();
4442
+ engineRoutesActive = false;
4443
+ constructor(workflowRepository, workflowActivationPolicy, diagnostics) {
4444
+ this.workflowRepository = workflowRepository;
4445
+ this.workflowActivationPolicy = workflowActivationPolicy;
4446
+ this.diagnostics = diagnostics;
4447
+ }
4448
+ onEngineWorkflowsLoaded() {
4449
+ this.engineRoutesActive = true;
4450
+ this.rebuildRouteIndex();
4451
+ }
4452
+ onEngineStopped() {
4453
+ this.engineRoutesActive = false;
4454
+ this.routeByPath.clear();
4455
+ }
4456
+ reloadWebhookRoutes() {
4457
+ if (!this.engineRoutesActive) return;
4458
+ this.rebuildRouteIndex();
4459
+ }
4460
+ lookup(endpointPath) {
4461
+ if (!this.engineRoutesActive) return;
4462
+ const normalized = this.normalizeEndpointPath(endpointPath);
4463
+ return this.routeByPath.get(normalized);
4464
+ }
4465
+ match(args) {
4466
+ const entry = this.lookup(args.endpointPath);
4467
+ if (!entry) return;
4468
+ return entry.methods.includes(args.method) ? entry : void 0;
4469
+ }
4470
+ rebuildRouteIndex() {
4471
+ this.routeByPath.clear();
4472
+ for (const workflow of this.workflowRepository.list()) {
4473
+ if (!this.workflowActivationPolicy.isActive(workflow.id)) {
4474
+ if (workflow.nodes.filter((n) => n.kind === "trigger").length > 0) {
4475
+ const paths = this.collectWebhookEndpointPaths(workflow);
4476
+ if (paths.length > 0) this.diagnostics?.info?.(`Workflow "${workflow.name}" (${workflow.id}) is inactive; webhook routes not registered: ${paths.map((p) => `"${p}"`).join(", ")}`);
4477
+ else this.diagnostics?.info?.(`Workflow "${workflow.name}" (${workflow.id}) is inactive; no repository webhook routes for its triggers (other trigger kinds are unchanged).`);
4478
+ }
4479
+ continue;
4480
+ }
4481
+ for (const def of workflow.nodes) {
4482
+ const match = this.tryMatchFromTriggerNode(workflow, def);
4483
+ if (!match) continue;
4484
+ const key = this.normalizeEndpointPath(match.endpointPath);
4485
+ const existing = this.routeByPath.get(key);
4486
+ if (existing) this.diagnostics?.warn(`Duplicate webhook endpoint path "${key}" (workflows "${existing.workflowId}" and "${match.workflowId}"); using "${match.workflowId}".`);
4487
+ this.routeByPath.set(key, match);
4488
+ }
4489
+ }
4490
+ }
4491
+ collectWebhookEndpointPaths(workflow) {
4492
+ const paths = [];
4493
+ for (const def of workflow.nodes) {
4494
+ if (def.kind !== "trigger") continue;
4495
+ const match = this.tryMatchFromTriggerNode(workflow, def);
4496
+ if (match) paths.push(match.endpointPath);
4497
+ }
4498
+ return paths;
4499
+ }
4500
+ tryMatchFromTriggerNode(workflow, def) {
4501
+ if (def.kind !== "trigger") return;
4502
+ const config = def.config;
4503
+ if (typeof config.endpointKey !== "string" || config.endpointKey.length === 0) return;
4504
+ if (!Array.isArray(config.methods) || config.methods.length === 0) return;
4505
+ const methods = config.methods;
4506
+ const parseJsonBody = typeof config.parseJsonBody === "function" ? config.parseJsonBody.bind(config) : void 0;
4507
+ return {
4508
+ endpointPath: config.endpointKey,
4509
+ workflowId: workflow.id,
4510
+ nodeId: def.id,
4511
+ methods: [...methods],
4512
+ parseJsonBody
4513
+ };
4514
+ }
4515
+ normalizeEndpointPath(endpointPath) {
4516
+ return endpointPath.trim();
4517
+ }
4518
+ };
4519
+
4520
+ //#endregion
4521
+ //#region src/runtime/WorkflowRepositoryWebhookTriggerMatcherFactory.ts
4522
+ var WorkflowRepositoryWebhookTriggerMatcherFactory = class {
4523
+ create(workflowRepository, workflowActivationPolicy, diagnostics) {
4524
+ return new WorkflowRepositoryWebhookTriggerMatcher(workflowRepository, workflowActivationPolicy, diagnostics);
4525
+ }
4526
+ };
4527
+
4528
+ //#endregion
3404
4529
  Object.defineProperty(exports, 'ConfigDrivenOffloadPolicy', {
3405
4530
  enumerable: true,
3406
4531
  get: function () {
@@ -3455,12 +4580,36 @@ Object.defineProperty(exports, 'ENGINE_EXECUTION_LIMITS_DEFAULTS', {
3455
4580
  return ENGINE_EXECUTION_LIMITS_DEFAULTS;
3456
4581
  }
3457
4582
  });
4583
+ Object.defineProperty(exports, 'Engine', {
4584
+ enumerable: true,
4585
+ get: function () {
4586
+ return Engine;
4587
+ }
4588
+ });
3458
4589
  Object.defineProperty(exports, 'EngineExecutionLimitsPolicy', {
3459
4590
  enumerable: true,
3460
4591
  get: function () {
3461
4592
  return EngineExecutionLimitsPolicy;
3462
4593
  }
3463
4594
  });
4595
+ Object.defineProperty(exports, 'EngineFactory', {
4596
+ enumerable: true,
4597
+ get: function () {
4598
+ return EngineFactory;
4599
+ }
4600
+ });
4601
+ Object.defineProperty(exports, 'EngineWorkflowRunnerService', {
4602
+ enumerable: true,
4603
+ get: function () {
4604
+ return EngineWorkflowRunnerService;
4605
+ }
4606
+ });
4607
+ Object.defineProperty(exports, 'EngineWorkflowRunnerServiceFactory', {
4608
+ enumerable: true,
4609
+ get: function () {
4610
+ return EngineWorkflowRunnerServiceFactory;
4611
+ }
4612
+ });
3464
4613
  Object.defineProperty(exports, 'HintOnlyOffloadPolicy', {
3465
4614
  enumerable: true,
3466
4615
  get: function () {
@@ -3515,30 +4664,12 @@ Object.defineProperty(exports, 'LocalOnlyScheduler', {
3515
4664
  return LocalOnlyScheduler;
3516
4665
  }
3517
4666
  });
3518
- Object.defineProperty(exports, 'MissingRuntimeExecutionMarker', {
3519
- enumerable: true,
3520
- get: function () {
3521
- return MissingRuntimeExecutionMarker;
3522
- }
3523
- });
3524
- Object.defineProperty(exports, 'MissingRuntimeFallbacks', {
3525
- enumerable: true,
3526
- get: function () {
3527
- return MissingRuntimeFallbacks;
3528
- }
3529
- });
3530
4667
  Object.defineProperty(exports, 'MissingRuntimeTriggerToken', {
3531
4668
  enumerable: true,
3532
4669
  get: function () {
3533
4670
  return MissingRuntimeTriggerToken;
3534
4671
  }
3535
4672
  });
3536
- Object.defineProperty(exports, 'NodeActivationRequestComposer', {
3537
- enumerable: true,
3538
- get: function () {
3539
- return NodeActivationRequestComposer;
3540
- }
3541
- });
3542
4673
  Object.defineProperty(exports, 'NodeEventPublisher', {
3543
4674
  enumerable: true,
3544
4675
  get: function () {
@@ -3569,18 +4700,6 @@ Object.defineProperty(exports, 'NodeInstanceFactoryFactory', {
3569
4700
  return NodeInstanceFactoryFactory;
3570
4701
  }
3571
4702
  });
3572
- Object.defineProperty(exports, 'NodeRunStateWriterFactory', {
3573
- enumerable: true,
3574
- get: function () {
3575
- return NodeRunStateWriterFactory;
3576
- }
3577
- });
3578
- Object.defineProperty(exports, 'PersistedRunStateTerminalBuilder', {
3579
- enumerable: true,
3580
- get: function () {
3581
- return PersistedRunStateTerminalBuilder;
3582
- }
3583
- });
3584
4703
  Object.defineProperty(exports, 'PersistedRuntimeTypeMetadataStore', {
3585
4704
  enumerable: true,
3586
4705
  get: function () {
@@ -3599,12 +4718,6 @@ Object.defineProperty(exports, 'PersistedWorkflowTokenRegistry', {
3599
4718
  return PersistedWorkflowTokenRegistry;
3600
4719
  }
3601
4720
  });
3602
- Object.defineProperty(exports, 'RunContinuationService', {
3603
- enumerable: true,
3604
- get: function () {
3605
- return RunContinuationService;
3606
- }
3607
- });
3608
4721
  Object.defineProperty(exports, 'RunFinishedAtFactory', {
3609
4722
  enumerable: true,
3610
4723
  get: function () {
@@ -3617,22 +4730,22 @@ Object.defineProperty(exports, 'RunIntentService', {
3617
4730
  return RunIntentService;
3618
4731
  }
3619
4732
  });
3620
- Object.defineProperty(exports, 'RunPolicySnapshotFactory', {
4733
+ Object.defineProperty(exports, 'RunIntentServiceFactory', {
3621
4734
  enumerable: true,
3622
4735
  get: function () {
3623
- return RunPolicySnapshotFactory;
4736
+ return RunIntentServiceFactory;
3624
4737
  }
3625
4738
  });
3626
- Object.defineProperty(exports, 'RunStartService', {
4739
+ Object.defineProperty(exports, 'RunPolicySnapshotFactory', {
3627
4740
  enumerable: true,
3628
4741
  get: function () {
3629
- return RunStartService;
4742
+ return RunPolicySnapshotFactory;
3630
4743
  }
3631
4744
  });
3632
- Object.defineProperty(exports, 'RunStateSemantics', {
4745
+ Object.defineProperty(exports, 'RunTerminalPersistenceCoordinator', {
3633
4746
  enumerable: true,
3634
4747
  get: function () {
3635
- return RunStateSemantics;
4748
+ return RunTerminalPersistenceCoordinator;
3636
4749
  }
3637
4750
  });
3638
4751
  Object.defineProperty(exports, 'StackTraceCallSitePathResolver', {
@@ -3659,28 +4772,34 @@ Object.defineProperty(exports, 'WorkflowExecutableNodeClassifierFactory', {
3659
4772
  return WorkflowExecutableNodeClassifierFactory;
3660
4773
  }
3661
4774
  });
3662
- Object.defineProperty(exports, 'WorkflowRunExecutionContextFactory', {
4775
+ Object.defineProperty(exports, 'WorkflowPolicyErrorServices', {
3663
4776
  enumerable: true,
3664
4777
  get: function () {
3665
- return WorkflowRunExecutionContextFactory;
4778
+ return WorkflowPolicyErrorServices;
3666
4779
  }
3667
4780
  });
3668
- Object.defineProperty(exports, 'WorkflowSnapshotCodec', {
4781
+ Object.defineProperty(exports, 'WorkflowRepositoryWebhookTriggerMatcher', {
3669
4782
  enumerable: true,
3670
4783
  get: function () {
3671
- return WorkflowSnapshotCodec;
4784
+ return WorkflowRepositoryWebhookTriggerMatcher;
3672
4785
  }
3673
4786
  });
3674
- Object.defineProperty(exports, 'WorkflowSnapshotResolver', {
4787
+ Object.defineProperty(exports, 'WorkflowRepositoryWebhookTriggerMatcherFactory', {
3675
4788
  enumerable: true,
3676
4789
  get: function () {
3677
- return WorkflowSnapshotResolver;
4790
+ return WorkflowRepositoryWebhookTriggerMatcherFactory;
4791
+ }
4792
+ });
4793
+ Object.defineProperty(exports, 'WorkflowSnapshotCodec', {
4794
+ enumerable: true,
4795
+ get: function () {
4796
+ return WorkflowSnapshotCodec;
3678
4797
  }
3679
4798
  });
3680
- Object.defineProperty(exports, 'WorkflowTopology', {
4799
+ Object.defineProperty(exports, 'WorkflowStoragePolicyEvaluator', {
3681
4800
  enumerable: true,
3682
4801
  get: function () {
3683
- return WorkflowTopology;
4802
+ return WorkflowStoragePolicyEvaluator;
3684
4803
  }
3685
4804
  });
3686
4805
  Object.defineProperty(exports, '__toESM', {
@@ -3713,4 +4832,4 @@ Object.defineProperty(exports, 'tool', {
3713
4832
  return tool;
3714
4833
  }
3715
4834
  });
3716
- //# sourceMappingURL=RunIntentService-DcxXf_AM.cjs.map
4835
+ //# sourceMappingURL=runtime-ZJUpWmPH.cjs.map