@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
@@ -1,5 +1,6 @@
1
1
  import "reflect-metadata";
2
2
  import { container as container$1, delay, inject, injectAll, injectable, instanceCachingFactory, instancePerContainerCachingFactory, predicateAwareClassFactory, registry, singleton } from "tsyringe";
3
+ import { ZodError, z } from "zod";
3
4
  import { createHash } from "node:crypto";
4
5
  import { ReadableStream } from "node:stream/web";
5
6
 
@@ -487,10 +488,11 @@ var NodeInputsByPortFactory = class {
487
488
  //#endregion
488
489
  //#region src/execution/ActivationEnqueueService.ts
489
490
  var ActivationEnqueueService = class {
490
- constructor(activationScheduler, workflowExecutionRepository, nodeEventPublisher) {
491
+ constructor(activationScheduler, workflowExecutionRepository, nodeEventPublisher, nodeActivationRequestInputPreparer) {
491
492
  this.activationScheduler = activationScheduler;
492
493
  this.workflowExecutionRepository = workflowExecutionRepository;
493
494
  this.nodeEventPublisher = nodeEventPublisher;
495
+ this.nodeActivationRequestInputPreparer = nodeActivationRequestInputPreparer;
494
496
  }
495
497
  async enqueueActivation(args) {
496
498
  const { result, queuedSnapshot } = await this.enqueueActivationWithSnapshot(args);
@@ -498,9 +500,10 @@ var ActivationEnqueueService = class {
498
500
  return result;
499
501
  }
500
502
  async enqueueActivationWithSnapshot(args) {
501
- const preparedDispatch = await this.activationScheduler.prepareDispatch(args.request);
502
- const inputsByPort = NodeInputsByPortFactory.fromRequest(args.request);
503
- const itemsIn = args.request.kind === "multi" ? args.planner.sumItemsByPort(args.request.inputsByPort) : args.request.input.length;
503
+ const preparedRequest = await this.nodeActivationRequestInputPreparer.prepare(args.request);
504
+ const preparedDispatch = await this.activationScheduler.prepareDispatch(preparedRequest);
505
+ const inputsByPort = NodeInputsByPortFactory.fromRequest(preparedRequest);
506
+ const itemsIn = preparedRequest.kind === "multi" ? args.planner.sumItemsByPort(preparedRequest.inputsByPort) : preparedRequest.input.length;
504
507
  const enqueuedAt = (/* @__PURE__ */ new Date()).toISOString();
505
508
  const pending = {
506
509
  runId: args.runId,
@@ -561,6 +564,75 @@ var ActivationEnqueueService = class {
561
564
  }
562
565
  };
563
566
 
567
+ //#endregion
568
+ //#region src/execution/NodeInputContractError.ts
569
+ var NodeInputContractError = class extends Error {
570
+ constructor(message, nodeId, activationId, cause) {
571
+ super(message);
572
+ this.nodeId = nodeId;
573
+ this.activationId = activationId;
574
+ this.cause = cause;
575
+ this.name = "NodeInputContractError";
576
+ }
577
+ };
578
+
579
+ //#endregion
580
+ //#region src/execution/NodeActivationRequestInputPreparer.ts
581
+ /**
582
+ * Maps and validates per-item inputs for {@link ItemNode} before enqueue persistence.
583
+ */
584
+ var NodeActivationRequestInputPreparer = class {
585
+ constructor(workflowNodeInstanceFactory) {
586
+ this.workflowNodeInstanceFactory = workflowNodeInstanceFactory;
587
+ }
588
+ async prepare(request) {
589
+ if (request.kind !== "single") return request;
590
+ const nodeInstance = this.workflowNodeInstanceFactory.createByType(request.ctx.config.type);
591
+ if (!this.hasExecuteOne(nodeInstance)) return request;
592
+ const inputSchema = this.resolveInputSchema(nodeInstance, request.ctx.config);
593
+ const config = request.ctx.config;
594
+ const mappedItems = [];
595
+ for (let i = 0; i < request.input.length; i++) {
596
+ const item = request.input[i];
597
+ try {
598
+ const mappedRaw = config.mapInput ? await Promise.resolve(config.mapInput({
599
+ item,
600
+ itemIndex: i,
601
+ items: request.input,
602
+ ctx: request.ctx
603
+ })) : item.json;
604
+ const parsed = inputSchema.parse(mappedRaw);
605
+ mappedItems.push({
606
+ ...item,
607
+ json: parsed
608
+ });
609
+ } catch (cause) {
610
+ const message = this.formatContractFailure(cause);
611
+ throw new NodeInputContractError(`Node ${request.nodeId} activation ${request.activationId}: input contract failed: ${message}`, request.nodeId, request.activationId, cause);
612
+ }
613
+ }
614
+ return {
615
+ ...request,
616
+ input: mappedItems
617
+ };
618
+ }
619
+ hasExecuteOne(nodeInstance) {
620
+ return typeof nodeInstance === "object" && nodeInstance !== null && typeof nodeInstance.executeOne === "function";
621
+ }
622
+ resolveInputSchema(nodeInstance, config) {
623
+ const fromInstance = nodeInstance.inputSchema;
624
+ if (fromInstance && typeof fromInstance.parse === "function") return fromInstance;
625
+ const fromConfig = config.inputSchema;
626
+ if (fromConfig && typeof fromConfig.parse === "function") return fromConfig;
627
+ return z.unknown();
628
+ }
629
+ formatContractFailure(cause) {
630
+ if (cause instanceof ZodError) return cause.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ");
631
+ if (cause instanceof Error) return cause.message;
632
+ return String(cause);
633
+ }
634
+ };
635
+
564
636
  //#endregion
565
637
  //#region src/execution/CredentialResolverFactory.ts
566
638
  var CredentialResolverFactory = class {
@@ -806,10 +878,32 @@ var NodeExecutor = class {
806
878
  return await multiInputNode.executeMulti(request.inputsByPort, request.ctx);
807
879
  }
808
880
  async executeSingleInputNode(request, node$1) {
881
+ if (this.hasExecuteOne(node$1)) return await this.executeItemNode(request, node$1);
809
882
  const singleInputNode = node$1;
810
883
  if (typeof singleInputNode.execute !== "function") throw new Error(`Node ${request.nodeId} does not support execute but received single-input activation`);
811
884
  return await singleInputNode.execute(request.input, request.ctx);
812
885
  }
886
+ hasExecuteOne(node$1) {
887
+ return typeof node$1 === "object" && node$1 !== null && typeof node$1.executeOne === "function";
888
+ }
889
+ async executeItemNode(request, node$1) {
890
+ const out = [];
891
+ for (let i = 0; i < request.input.length; i++) {
892
+ const item = request.input[i];
893
+ const outputJson = await Promise.resolve(node$1.executeOne({
894
+ input: item.json,
895
+ item,
896
+ itemIndex: i,
897
+ items: request.input,
898
+ ctx: request.ctx
899
+ }));
900
+ out.push({
901
+ ...item,
902
+ json: outputJson
903
+ });
904
+ }
905
+ return { main: out };
906
+ }
813
907
  };
814
908
 
815
909
  //#endregion
@@ -1624,15 +1718,15 @@ var RunContinuationService = class {
1624
1718
  finalStatus: "completed",
1625
1719
  finishedAt: completedAt
1626
1720
  });
1627
- const result$1 = {
1721
+ const result = {
1628
1722
  runId: state.runId,
1629
1723
  workflowId: state.workflowId,
1630
1724
  startedAt: state.startedAt,
1631
1725
  status: "completed",
1632
1726
  outputs: this.semantics.resolveResultOutputs(wf, state.control?.stopCondition, data.dump())
1633
1727
  };
1634
- this.waiters.resolveRunCompletion(result$1);
1635
- return result$1;
1728
+ this.waiters.resolveRunCompletion(result);
1729
+ return result;
1636
1730
  }
1637
1731
  const batchId = pendingExecution.batchId ?? "batch_1";
1638
1732
  const queue = (schedulingState?.queue ?? []).map((q) => ({
@@ -1691,15 +1785,15 @@ var RunContinuationService = class {
1691
1785
  finalStatus: "completed",
1692
1786
  finishedAt: completedAt
1693
1787
  });
1694
- const result$1 = {
1788
+ const result = {
1695
1789
  runId: state.runId,
1696
1790
  workflowId: state.workflowId,
1697
1791
  startedAt: state.startedAt,
1698
1792
  status: "completed",
1699
1793
  outputs
1700
1794
  };
1701
- this.waiters.resolveRunCompletion(result$1);
1702
- return result$1;
1795
+ this.waiters.resolveRunCompletion(result);
1796
+ return result;
1703
1797
  }
1704
1798
  if (completedActivations >= maxNodeActivations) {
1705
1799
  const message = `Run exceeded maxNodeActivations (${maxNodeActivations}) after ${completedActivations} completed node activations (next would be ${next.nodeId}).`;
@@ -1720,15 +1814,15 @@ var RunContinuationService = class {
1720
1814
  finalStatus: "failed",
1721
1815
  finishedAt: completedAt
1722
1816
  });
1723
- const result$1 = {
1817
+ const result = {
1724
1818
  runId: state.runId,
1725
1819
  workflowId: state.workflowId,
1726
1820
  startedAt: state.startedAt,
1727
1821
  status: "failed",
1728
1822
  error: { message }
1729
1823
  };
1730
- this.waiters.resolveRunCompletion(result$1);
1731
- return result$1;
1824
+ this.waiters.resolveRunCompletion(result);
1825
+ return result;
1732
1826
  }
1733
1827
  const def = topology.defsById.get(next.nodeId);
1734
1828
  if (!def || def.kind !== "node") throw new Error(`Node ${next.nodeId} is not a runnable node`);
@@ -1742,26 +1836,43 @@ var RunContinuationService = class {
1742
1836
  executionOptions: state.executionOptions,
1743
1837
  nodeDefinition: def
1744
1838
  });
1745
- const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
1746
- runId: state.runId,
1747
- workflowId: state.workflowId,
1748
- startedAt: state.startedAt,
1749
- parent: state.parent,
1750
- executionOptions: state.executionOptions,
1751
- control: state.control,
1752
- workflowSnapshot: state.workflowSnapshot,
1753
- mutableState: state.mutableState,
1754
- policySnapshot: state.policySnapshot,
1755
- pendingQueue: queue,
1756
- request,
1757
- previousNodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId,
1758
- planner,
1759
- engineCounters,
1760
- connectionInvocations: state.connectionInvocations ?? []
1761
- });
1762
- await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
1763
- await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
1764
- return result;
1839
+ try {
1840
+ const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
1841
+ runId: state.runId,
1842
+ workflowId: state.workflowId,
1843
+ startedAt: state.startedAt,
1844
+ parent: state.parent,
1845
+ executionOptions: state.executionOptions,
1846
+ control: state.control,
1847
+ workflowSnapshot: state.workflowSnapshot,
1848
+ mutableState: state.mutableState,
1849
+ policySnapshot: state.policySnapshot,
1850
+ pendingQueue: queue,
1851
+ request,
1852
+ previousNodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId,
1853
+ planner,
1854
+ engineCounters,
1855
+ connectionInvocations: state.connectionInvocations ?? []
1856
+ });
1857
+ await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
1858
+ await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
1859
+ return result;
1860
+ } catch (cause) {
1861
+ const error = cause instanceof Error ? cause : new Error(String(cause));
1862
+ return await this.terminateRunAfterActivationEnqueueRejected({
1863
+ wf,
1864
+ state,
1865
+ queue,
1866
+ nextNodeId: next.nodeId,
1867
+ request,
1868
+ completedSnapshot,
1869
+ nextNodeSnapshotsByNodeId,
1870
+ outputsByNode: data.dump(),
1871
+ engineCounters,
1872
+ error,
1873
+ completedAt
1874
+ });
1875
+ }
1765
1876
  }
1766
1877
  async resumeFromNodeError(args) {
1767
1878
  const [state, schedulingState] = await Promise.all([this.workflowExecutionRepository.load(args.runId), this.workflowExecutionRepository.loadSchedulingState(args.runId)]);
@@ -1938,15 +2049,15 @@ var RunContinuationService = class {
1938
2049
  runStatus: "completed",
1939
2050
  response: args.signal.responseItems
1940
2051
  });
1941
- const result$1 = {
2052
+ const result = {
1942
2053
  runId: args.state.runId,
1943
2054
  workflowId: args.state.workflowId,
1944
2055
  startedAt: args.state.startedAt,
1945
2056
  status: "completed",
1946
2057
  outputs: this.semantics.resolveResultOutputs(args.workflow, args.state.control?.stopCondition, data.dump())
1947
2058
  };
1948
- this.waiters.resolveRunCompletion(result$1);
1949
- return result$1;
2059
+ this.waiters.resolveRunCompletion(result);
2060
+ return result;
1950
2061
  }
1951
2062
  if (args.signal.kind === "respondNow") {
1952
2063
  const completedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
@@ -1969,7 +2080,7 @@ var RunContinuationService = class {
1969
2080
  finalStatus: "completed",
1970
2081
  finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
1971
2082
  });
1972
- const result$1 = {
2083
+ const result = {
1973
2084
  runId: args.state.runId,
1974
2085
  workflowId: args.state.workflowId,
1975
2086
  startedAt: args.state.startedAt,
@@ -1983,8 +2094,8 @@ var RunContinuationService = class {
1983
2094
  runStatus: "completed",
1984
2095
  response: args.signal.responseItems
1985
2096
  });
1986
- this.waiters.resolveRunCompletion(result$1);
1987
- return result$1;
2097
+ this.waiters.resolveRunCompletion(result);
2098
+ return result;
1988
2099
  }
1989
2100
  const batchId = args.pendingExecution.batchId ?? "batch_1";
1990
2101
  const queue = (args.schedulingState?.queue ?? []).map((entry) => ({
@@ -2020,7 +2131,7 @@ var RunContinuationService = class {
2020
2131
  finalStatus: "completed",
2021
2132
  finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
2022
2133
  });
2023
- const result$1 = {
2134
+ const result = {
2024
2135
  runId: args.state.runId,
2025
2136
  workflowId: args.state.workflowId,
2026
2137
  startedAt: args.state.startedAt,
@@ -2034,8 +2145,8 @@ var RunContinuationService = class {
2034
2145
  runStatus: "completed",
2035
2146
  response: args.signal.responseItems
2036
2147
  });
2037
- this.waiters.resolveRunCompletion(result$1);
2038
- return result$1;
2148
+ this.waiters.resolveRunCompletion(result);
2149
+ return result;
2039
2150
  }
2040
2151
  if (completedActivations >= maxNodeActivations) {
2041
2152
  const message = `Run exceeded maxNodeActivations (${maxNodeActivations}) after ${completedActivations} completed node activations (next would be ${next.nodeId}).`;
@@ -2059,7 +2170,7 @@ var RunContinuationService = class {
2059
2170
  finalStatus: "failed",
2060
2171
  finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
2061
2172
  });
2062
- const result$1 = {
2173
+ const result = {
2063
2174
  runId: args.state.runId,
2064
2175
  workflowId: args.state.workflowId,
2065
2176
  startedAt: args.state.startedAt,
@@ -2073,8 +2184,8 @@ var RunContinuationService = class {
2073
2184
  runStatus: "pending",
2074
2185
  response: args.signal.responseItems
2075
2186
  });
2076
- this.waiters.resolveRunCompletion(result$1);
2077
- return result$1;
2187
+ this.waiters.resolveRunCompletion(result);
2188
+ return result;
2078
2189
  }
2079
2190
  const nextDefinition = topology.defsById.get(next.nodeId);
2080
2191
  if (!nextDefinition || nextDefinition.kind !== "node") throw new Error(`Node ${next.nodeId} is not a runnable node`);
@@ -2100,36 +2211,63 @@ var RunContinuationService = class {
2100
2211
  executionOptions: args.state.executionOptions,
2101
2212
  nodeDefinition: nextDefinition
2102
2213
  });
2103
- const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
2104
- runId: args.state.runId,
2105
- workflowId: args.state.workflowId,
2106
- startedAt: args.state.startedAt,
2107
- parent: args.state.parent,
2108
- executionOptions: args.state.executionOptions,
2109
- control: args.state.control,
2110
- workflowSnapshot: args.state.workflowSnapshot,
2111
- mutableState: args.state.mutableState,
2112
- policySnapshot: args.state.policySnapshot,
2113
- pendingQueue: queue,
2114
- request,
2115
- previousNodeSnapshotsByNodeId: {
2116
- ...args.state.nodeSnapshotsByNodeId ?? {},
2117
- [args.args.nodeId]: completedSnapshot
2118
- },
2119
- planner,
2120
- engineCounters,
2121
- connectionInvocations: args.state.connectionInvocations ?? []
2122
- });
2123
- await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
2124
- await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
2125
- this.waiters.resolveWebhookResponse({
2126
- runId: args.state.runId,
2127
- workflowId: args.state.workflowId,
2128
- startedAt: args.state.startedAt,
2129
- runStatus: "pending",
2130
- response: args.signal.responseItems
2131
- });
2132
- return result;
2214
+ const mergedSnapshots = {
2215
+ ...args.state.nodeSnapshotsByNodeId ?? {},
2216
+ [args.args.nodeId]: completedSnapshot
2217
+ };
2218
+ try {
2219
+ const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
2220
+ runId: args.state.runId,
2221
+ workflowId: args.state.workflowId,
2222
+ startedAt: args.state.startedAt,
2223
+ parent: args.state.parent,
2224
+ executionOptions: args.state.executionOptions,
2225
+ control: args.state.control,
2226
+ workflowSnapshot: args.state.workflowSnapshot,
2227
+ mutableState: args.state.mutableState,
2228
+ policySnapshot: args.state.policySnapshot,
2229
+ pendingQueue: queue,
2230
+ request,
2231
+ previousNodeSnapshotsByNodeId: mergedSnapshots,
2232
+ planner,
2233
+ engineCounters,
2234
+ connectionInvocations: args.state.connectionInvocations ?? []
2235
+ });
2236
+ await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
2237
+ await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
2238
+ this.waiters.resolveWebhookResponse({
2239
+ runId: args.state.runId,
2240
+ workflowId: args.state.workflowId,
2241
+ startedAt: args.state.startedAt,
2242
+ runStatus: "pending",
2243
+ response: args.signal.responseItems
2244
+ });
2245
+ return result;
2246
+ } catch (cause) {
2247
+ const error = cause instanceof Error ? cause : new Error(String(cause));
2248
+ const finishedAt = completedSnapshot.finishedAt ?? completedSnapshot.updatedAt;
2249
+ const result = await this.terminateRunAfterActivationEnqueueRejected({
2250
+ wf: args.workflow,
2251
+ state: args.state,
2252
+ queue,
2253
+ nextNodeId: next.nodeId,
2254
+ request,
2255
+ completedSnapshot,
2256
+ nextNodeSnapshotsByNodeId: mergedSnapshots,
2257
+ outputsByNode: data.dump(),
2258
+ engineCounters,
2259
+ error,
2260
+ completedAt: finishedAt
2261
+ });
2262
+ this.waiters.resolveWebhookResponse({
2263
+ runId: args.state.runId,
2264
+ workflowId: args.state.workflowId,
2265
+ startedAt: args.state.startedAt,
2266
+ runStatus: "pending",
2267
+ response: args.signal.responseItems
2268
+ });
2269
+ return result;
2270
+ }
2133
2271
  }
2134
2272
  asWebhookControlSignal(error) {
2135
2273
  const candidate = error;
@@ -2187,6 +2325,66 @@ var RunContinuationService = class {
2187
2325
  engineMaxSubworkflowDepth: state.executionOptions?.maxSubworkflowDepth ?? fb.maxSubworkflowDepth
2188
2326
  };
2189
2327
  }
2328
+ /**
2329
+ * Next activation could not be enqueued (e.g. input contract / mapping failed in the preparer).
2330
+ * Marks the target node failed and terminates the run.
2331
+ */
2332
+ async terminateRunAfterActivationEnqueueRejected(args) {
2333
+ const finishedAt = args.completedAt;
2334
+ const inputsByPort = NodeInputsByPortFactory.fromRequest(args.request);
2335
+ const failedSnapshot = NodeExecutionSnapshotFactory.failed({
2336
+ previous: void 0,
2337
+ runId: args.state.runId,
2338
+ workflowId: args.state.workflowId,
2339
+ nodeId: args.nextNodeId,
2340
+ activationId: args.request.activationId,
2341
+ parent: args.state.parent,
2342
+ finishedAt,
2343
+ inputsByPort,
2344
+ error: args.error
2345
+ });
2346
+ const failedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
2347
+ state: args.state,
2348
+ engineCounters: args.engineCounters,
2349
+ status: "failed",
2350
+ queue: args.queue.map((q) => ({ ...q })),
2351
+ outputsByNode: args.outputsByNode,
2352
+ nodeSnapshotsByNodeId: {
2353
+ ...args.nextNodeSnapshotsByNodeId,
2354
+ [args.nextNodeId]: failedSnapshot
2355
+ },
2356
+ finishedAtIso: finishedAt
2357
+ });
2358
+ await this.workflowExecutionRepository.save(failedState);
2359
+ await this.nodeEventPublisher.publish("nodeCompleted", args.completedSnapshot);
2360
+ await this.nodeEventPublisher.publish("nodeFailed", failedSnapshot);
2361
+ const wfErr = this.policyErrorServices.resolveWorkflowErrorHandler(args.wf.workflowErrorHandler);
2362
+ if (wfErr) await Promise.resolve(wfErr.onError({
2363
+ runId: args.state.runId,
2364
+ workflowId: args.state.workflowId,
2365
+ workflow: args.wf,
2366
+ failedNodeId: args.nextNodeId,
2367
+ error: args.error,
2368
+ startedAt: args.state.startedAt,
2369
+ finishedAt
2370
+ }));
2371
+ await this.terminalPersistence.maybeDeleteAfterTerminalState({
2372
+ workflow: args.wf,
2373
+ state: failedState,
2374
+ finalStatus: "failed",
2375
+ finishedAt
2376
+ });
2377
+ const message = args.error.message ?? String(args.error);
2378
+ const result = {
2379
+ runId: args.state.runId,
2380
+ workflowId: args.state.workflowId,
2381
+ startedAt: args.state.startedAt,
2382
+ status: "failed",
2383
+ error: { message }
2384
+ };
2385
+ this.waiters.resolveRunCompletion(result);
2386
+ return result;
2387
+ }
2190
2388
  formatNodeLabel(args) {
2191
2389
  const tokenName = typeof args.definition?.type === "function" ? args.definition.type.name : "Node";
2192
2390
  return args.definition?.name ? `"${args.definition.name}" (${tokenName}:${args.nodeId})` : `${tokenName}:${args.nodeId}`;
@@ -2361,7 +2559,7 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
2361
2559
  const expectedInputs = this.topology.expectedInputsByNode.get(nodeId) ?? [];
2362
2560
  if (expectedInputs.length !== 1 || expectedInputs[0] !== "in") {
2363
2561
  const received = {};
2364
- for (const input$1 of expectedInputs) received[input$1] = this.resolveInput(currentState, nodeId, input$1);
2562
+ for (const input$2 of expectedInputs) received[input$2] = this.resolveInput(currentState, nodeId, input$2);
2365
2563
  return [{
2366
2564
  nodeId,
2367
2565
  input: [],
@@ -2372,12 +2570,12 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
2372
2570
  }
2373
2571
  }];
2374
2572
  }
2375
- const input = expectedInputs[0] ?? "in";
2376
- const incomingEdge = incomingEdges.find((edge) => edge.input === input);
2573
+ const input$1 = expectedInputs[0] ?? "in";
2574
+ const incomingEdge = incomingEdges.find((edge) => edge.input === input$1);
2377
2575
  return [{
2378
2576
  nodeId,
2379
- input: this.resolveInput(currentState, nodeId, input),
2380
- toInput: input,
2577
+ input: this.resolveInput(currentState, nodeId, input$1),
2578
+ toInput: input$1,
2381
2579
  batchId: "batch_1",
2382
2580
  from: incomingEdge?.from
2383
2581
  }];
@@ -2393,16 +2591,16 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
2393
2591
  isNodeSatisfiedByOutputsOnly(currentState, nodeId) {
2394
2592
  return this.hasOutputs(currentState, nodeId) && !this.hasCompletedSnapshot(currentState, nodeId);
2395
2593
  }
2396
- isEdgeSatisfied(currentState, nodeId, input) {
2397
- const incomingEdge = (this.topology.incomingByNode.get(nodeId) ?? []).find((edge) => edge.input === input);
2594
+ isEdgeSatisfied(currentState, nodeId, input$1) {
2595
+ const incomingEdge = (this.topology.incomingByNode.get(nodeId) ?? []).find((edge) => edge.input === input$1);
2398
2596
  if (!incomingEdge) return false;
2399
2597
  if (!this.hasOutputPort(currentState, incomingEdge.from.nodeId, incomingEdge.from.output)) return false;
2400
2598
  if (this.usesCollect(nodeId)) return true;
2401
2599
  if (this.resolveOutputItems(currentState, incomingEdge.from.nodeId, incomingEdge.from.output).length > 0) return true;
2402
2600
  return this.shouldContinueAfterEmptyOutputFromSource(incomingEdge.from.nodeId);
2403
2601
  }
2404
- resolveInput(currentState, nodeId, input) {
2405
- const incomingEdge = (this.topology.incomingByNode.get(nodeId) ?? []).find((edge) => edge.input === input);
2602
+ resolveInput(currentState, nodeId, input$1) {
2603
+ const incomingEdge = (this.topology.incomingByNode.get(nodeId) ?? []).find((edge) => edge.input === input$1);
2406
2604
  if (!incomingEdge) return [];
2407
2605
  return this.resolveOutputItems(currentState, incomingEdge.from.nodeId, incomingEdge.from.output);
2408
2606
  }
@@ -2413,13 +2611,13 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
2413
2611
  const snapshot = currentState.nodeSnapshotsByNodeId[nodeId];
2414
2612
  return snapshot?.status === "completed" || snapshot?.status === "skipped";
2415
2613
  }
2416
- hasOutputPort(currentState, nodeId, output) {
2614
+ hasOutputPort(currentState, nodeId, output$1) {
2417
2615
  const outputs = currentState.outputsByNode[nodeId];
2418
2616
  if (!outputs) return false;
2419
- return Object.prototype.hasOwnProperty.call(outputs, output);
2617
+ return Object.prototype.hasOwnProperty.call(outputs, output$1);
2420
2618
  }
2421
- resolveOutputItems(currentState, nodeId, output) {
2422
- return currentState.outputsByNode[nodeId]?.[output] ?? [];
2619
+ resolveOutputItems(currentState, nodeId, output$1) {
2620
+ return currentState.outputsByNode[nodeId]?.[output$1] ?? [];
2423
2621
  }
2424
2622
  usesCollect(nodeId) {
2425
2623
  const expectedInputs = this.topology.expectedInputsByNode.get(nodeId) ?? [];
@@ -3077,6 +3275,67 @@ var EngineExecutionLimitsPolicy = class {
3077
3275
  }
3078
3276
  };
3079
3277
 
3278
+ //#endregion
3279
+ //#region src/policies/storage/RunTerminalPersistenceCoordinator.ts
3280
+ var RunTerminalPersistenceCoordinator = class {
3281
+ constructor(runRepository, storageEvaluator) {
3282
+ this.runRepository = runRepository;
3283
+ this.storageEvaluator = storageEvaluator;
3284
+ }
3285
+ async maybeDeleteAfterTerminalState(args) {
3286
+ if (await this.storageEvaluator.shouldPersist(args.workflow, args.state.policySnapshot, {
3287
+ runId: args.state.runId,
3288
+ workflowId: args.state.workflowId,
3289
+ workflow: args.workflow,
3290
+ finalStatus: args.finalStatus,
3291
+ startedAt: args.state.startedAt,
3292
+ finishedAt: args.finishedAt
3293
+ })) return;
3294
+ if (!this.runRepository.deleteRun) return;
3295
+ await this.runRepository.deleteRun(args.state.runId);
3296
+ }
3297
+ };
3298
+
3299
+ //#endregion
3300
+ //#region src/policies/WorkflowPolicyErrorServices.ts
3301
+ var WorkflowPolicyErrorServices = class {
3302
+ constructor(nodeResolver) {
3303
+ this.nodeResolver = nodeResolver;
3304
+ }
3305
+ resolveNodeErrorHandler(spec) {
3306
+ if (!spec) return void 0;
3307
+ if (typeof spec === "object" && spec !== null && "handle" in spec && typeof spec.handle === "function") return spec;
3308
+ return this.nodeResolver.resolve(spec);
3309
+ }
3310
+ resolveWorkflowErrorHandler(spec) {
3311
+ if (!spec) return void 0;
3312
+ if (typeof spec === "object" && spec !== null && "onError" in spec && typeof spec.onError === "function") return spec;
3313
+ return this.nodeResolver.resolve(spec);
3314
+ }
3315
+ };
3316
+
3317
+ //#endregion
3318
+ //#region src/policies/storage/WorkflowStoragePolicyEvaluator.ts
3319
+ var WorkflowStoragePolicyEvaluator = class {
3320
+ constructor(nodeResolver) {
3321
+ this.nodeResolver = nodeResolver;
3322
+ }
3323
+ async shouldPersist(workflow, snapshot, args) {
3324
+ const spec = workflow.storagePolicy;
3325
+ if (spec === void 0) return this.modeMatches(snapshot?.storagePolicy ?? "ALL", args);
3326
+ if (typeof spec === "string") return this.modeMatches(spec, args);
3327
+ const resolver = this.nodeResolver.resolve(spec);
3328
+ return Boolean(await resolver.shouldPersist(args));
3329
+ }
3330
+ modeMatches(mode, args) {
3331
+ if (mode === "ALL") return true;
3332
+ if (mode === "NEVER") return false;
3333
+ if (mode === "SUCCESS") return args.finalStatus === "completed";
3334
+ if (mode === "ERROR") return args.finalStatus === "failed";
3335
+ return true;
3336
+ }
3337
+ };
3338
+
3080
3339
  //#endregion
3081
3340
  //#region src/runStorage/BinaryBodyBufferReader.ts
3082
3341
  var BinaryBodyBufferReader = class {
@@ -3191,11 +3450,11 @@ var InMemoryRunData = class {
3191
3450
  getOutputs(nodeId) {
3192
3451
  return this.byNode.get(nodeId);
3193
3452
  }
3194
- getOutputItems(nodeId, output = "main") {
3195
- return this.byNode.get(nodeId)?.[output] ?? [];
3453
+ getOutputItems(nodeId, output$1 = "main") {
3454
+ return this.byNode.get(nodeId)?.[output$1] ?? [];
3196
3455
  }
3197
- getOutputItem(nodeId, itemIndex, output = "main") {
3198
- return this.getOutputItems(nodeId, output)[itemIndex];
3456
+ getOutputItem(nodeId, itemIndex, output$1 = "main") {
3457
+ return this.getOutputItems(nodeId, output$1)[itemIndex];
3199
3458
  }
3200
3459
  dump() {
3201
3460
  const out = {};
@@ -3225,6 +3484,775 @@ var RunFinishedAtFactory = class {
3225
3484
  }
3226
3485
  };
3227
3486
 
3487
+ //#endregion
3488
+ //#region src/orchestration/NodeExecutionRequestHandlerService.ts
3489
+ var NodeExecutionRequestHandlerService = class {
3490
+ constructor(workflowExecutionRepository, workflowSnapshotResolver, runDataFactory, runExecutionContextFactory, nodeStatePublisherFactory, nodeActivationRequestComposer, nodeExecutor, continuation, executionLimitsPolicy) {
3491
+ this.workflowExecutionRepository = workflowExecutionRepository;
3492
+ this.workflowSnapshotResolver = workflowSnapshotResolver;
3493
+ this.runDataFactory = runDataFactory;
3494
+ this.runExecutionContextFactory = runExecutionContextFactory;
3495
+ this.nodeStatePublisherFactory = nodeStatePublisherFactory;
3496
+ this.nodeActivationRequestComposer = nodeActivationRequestComposer;
3497
+ this.nodeExecutor = nodeExecutor;
3498
+ this.continuation = continuation;
3499
+ this.executionLimitsPolicy = executionLimitsPolicy;
3500
+ }
3501
+ async handleNodeExecutionRequest(request) {
3502
+ const [state, schedulingState] = await Promise.all([this.workflowExecutionRepository.load(request.runId), this.workflowExecutionRepository.loadSchedulingState(request.runId)]);
3503
+ if (!state) throw new Error(`Unknown runId: ${request.runId}`);
3504
+ if (state.workflowId !== request.workflowId) throw new Error(`workflowId mismatch for run ${request.runId}: ${state.workflowId} vs ${request.workflowId}`);
3505
+ const pendingExecution = schedulingState?.pending;
3506
+ if (state.status !== "pending" || !pendingExecution) return;
3507
+ if (pendingExecution.activationId !== request.activationId || pendingExecution.nodeId !== request.nodeId) return;
3508
+ const workflow = this.resolvePersistedWorkflow(state);
3509
+ if (!workflow) throw new Error(`Unknown workflowId: ${state.workflowId}`);
3510
+ const definition = workflow.nodes.find((node$1) => node$1.id === request.nodeId);
3511
+ if (!definition) throw new Error(`Unknown nodeId: ${request.nodeId}`);
3512
+ if (definition.kind !== "node") throw new Error(`Node ${request.nodeId} is not runnable`);
3513
+ const resolvedParent = request.parent ?? state.parent;
3514
+ const data = this.runDataFactory.create(state.outputsByNode);
3515
+ const limits = this.resolveEngineLimitsFromState(state);
3516
+ const persistedInput = pendingExecution.inputsByPort.in ?? request.input;
3517
+ const base = this.runExecutionContextFactory.create({
3518
+ runId: state.runId,
3519
+ workflowId: state.workflowId,
3520
+ nodeId: request.nodeId,
3521
+ parent: resolvedParent,
3522
+ subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
3523
+ engineMaxNodeActivations: limits.engineMaxNodeActivations,
3524
+ engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
3525
+ data,
3526
+ nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent)
3527
+ });
3528
+ const activationRequest = this.nodeActivationRequestComposer.createSingleFromDefinitionWithActivation({
3529
+ activationId: request.activationId,
3530
+ runId: request.runId,
3531
+ workflowId: request.workflowId,
3532
+ parent: resolvedParent,
3533
+ executionOptions: request.executionOptions ?? state.executionOptions,
3534
+ base,
3535
+ data,
3536
+ definition: {
3537
+ id: definition.id,
3538
+ config: definition.config
3539
+ },
3540
+ batchId: pendingExecution.batchId ?? "batch_1",
3541
+ input: persistedInput
3542
+ });
3543
+ await this.continuation.markNodeRunning({
3544
+ runId: activationRequest.runId,
3545
+ activationId: activationRequest.activationId,
3546
+ nodeId: activationRequest.nodeId,
3547
+ inputsByPort: pendingExecution.inputsByPort
3548
+ });
3549
+ let outputs;
3550
+ try {
3551
+ outputs = await this.nodeExecutor.execute(activationRequest);
3552
+ } catch (error) {
3553
+ await this.resumeAfterExecutionError(activationRequest, this.asError(error));
3554
+ return;
3555
+ }
3556
+ await this.resumeAfterExecutionResult(activationRequest, outputs ?? {});
3557
+ }
3558
+ resolvePersistedWorkflow(state) {
3559
+ return this.workflowSnapshotResolver.resolve({
3560
+ workflowId: state.workflowId,
3561
+ workflowSnapshot: state.workflowSnapshot
3562
+ });
3563
+ }
3564
+ resolveEngineLimitsFromState(state) {
3565
+ const fallback = this.executionLimitsPolicy.createRootExecutionOptions();
3566
+ return {
3567
+ engineMaxNodeActivations: state.executionOptions?.maxNodeActivations ?? fallback.maxNodeActivations,
3568
+ engineMaxSubworkflowDepth: state.executionOptions?.maxSubworkflowDepth ?? fallback.maxSubworkflowDepth
3569
+ };
3570
+ }
3571
+ async resumeAfterExecutionResult(request, outputs) {
3572
+ try {
3573
+ await this.continuation.resumeFromNodeResult({
3574
+ runId: request.runId,
3575
+ activationId: request.activationId,
3576
+ nodeId: request.nodeId,
3577
+ outputs
3578
+ });
3579
+ } catch (error) {
3580
+ this.rethrowUnlessIgnorableContinuationError(error);
3581
+ }
3582
+ }
3583
+ async resumeAfterExecutionError(request, error) {
3584
+ try {
3585
+ await this.continuation.resumeFromNodeError({
3586
+ runId: request.runId,
3587
+ activationId: request.activationId,
3588
+ nodeId: request.nodeId,
3589
+ error
3590
+ });
3591
+ } catch (continuationError) {
3592
+ this.rethrowUnlessIgnorableContinuationError(continuationError);
3593
+ }
3594
+ }
3595
+ asError(error) {
3596
+ return error instanceof Error ? error : new Error(String(error));
3597
+ }
3598
+ rethrowUnlessIgnorableContinuationError(error) {
3599
+ if (this.isIgnorableContinuationError(error)) return;
3600
+ throw this.asError(error);
3601
+ }
3602
+ isIgnorableContinuationError(error) {
3603
+ const message = this.asError(error).message;
3604
+ return message.includes(" is not pending") || message.includes("activationId mismatch") || message.includes("nodeId mismatch");
3605
+ }
3606
+ };
3607
+
3608
+ //#endregion
3609
+ //#region src/planning/RunQueuePlanner.ts
3610
+ var RunQueuePlanner = class {
3611
+ constructor(topology, nodeInstances) {
3612
+ this.topology = topology;
3613
+ this.nodeInstances = nodeInstances;
3614
+ }
3615
+ validateNodeKinds() {
3616
+ for (const [toNodeId, inputs] of this.topology.expectedInputsByNode.entries()) {
3617
+ if (inputs.length <= 1) {
3618
+ const only = inputs[0];
3619
+ if (only && only !== "in") {
3620
+ const inst$1 = this.nodeInstances.get(toNodeId);
3621
+ if (!this.isMultiInputNode(inst$1)) throw new Error(`Node ${toNodeId} only supports input 'in' (got '${only}').`);
3622
+ }
3623
+ continue;
3624
+ }
3625
+ const inst = this.nodeInstances.get(toNodeId);
3626
+ if (!this.isMultiInputNode(inst)) throw new Error(`Node ${toNodeId} has ${inputs.length} inbound edges. Insert a Merge node to combine branches.`);
3627
+ }
3628
+ }
3629
+ seedFromTrigger(args) {
3630
+ const queue = [];
3631
+ for (const e of this.topology.outgoingByNode.get(args.startNodeId) ?? []) {
3632
+ if (e.output !== "main") continue;
3633
+ this.enqueueEdge(queue, {
3634
+ batchId: args.batchId,
3635
+ to: e.to,
3636
+ from: {
3637
+ nodeId: args.startNodeId,
3638
+ output: "main"
3639
+ },
3640
+ items: args.items
3641
+ });
3642
+ }
3643
+ return queue;
3644
+ }
3645
+ applyOutputs(queue, args) {
3646
+ for (const e of this.topology.outgoingByNode.get(args.fromNodeId) ?? []) {
3647
+ const outItems = args.outputs[e.output] ?? [];
3648
+ this.enqueueEdge(queue, {
3649
+ batchId: args.batchId,
3650
+ to: e.to,
3651
+ from: {
3652
+ nodeId: args.fromNodeId,
3653
+ output: e.output
3654
+ },
3655
+ items: outItems
3656
+ });
3657
+ }
3658
+ }
3659
+ nextActivation(queue) {
3660
+ const readyCollect = this.resolveReadyCollect(queue);
3661
+ if (readyCollect) return readyCollect;
3662
+ const jobIdx = queue.findIndex((q) => !q.collect);
3663
+ if (jobIdx === -1) {
3664
+ if (queue.length === 0) return null;
3665
+ const sealedCollect = this.resolveSealedCollect(queue);
3666
+ if (sealedCollect) return sealedCollect;
3667
+ const stuck = queue[0];
3668
+ throw new Error(this.describeUnsatisfiedCollect(stuck));
3669
+ }
3670
+ const job = queue.splice(jobIdx, 1)[0];
3671
+ const def = this.topology.defsById.get(job.nodeId);
3672
+ if (!def || def.kind !== "node") return this.nextActivation(queue);
3673
+ return {
3674
+ kind: "single",
3675
+ nodeId: job.nodeId,
3676
+ input: job.input,
3677
+ batchId: job.batchId ?? "batch_1"
3678
+ };
3679
+ }
3680
+ sumItemsByPort(inputsByPort) {
3681
+ let n = 0;
3682
+ for (const v of Object.values(inputsByPort)) n += v?.length ?? 0;
3683
+ return n;
3684
+ }
3685
+ resolveReadyCollect(queue) {
3686
+ for (let i = 0; i < queue.length; i++) {
3687
+ const ready = this.tryDequeueCollect(queue, i);
3688
+ if (ready) return ready;
3689
+ }
3690
+ return null;
3691
+ }
3692
+ resolveSealedCollect(queue) {
3693
+ for (let i = 0; i < queue.length; i++) {
3694
+ const queueEntry = queue[i];
3695
+ if (!queueEntry.collect) continue;
3696
+ const received = queueEntry.collect.received;
3697
+ if (Object.keys(received).length === 0) continue;
3698
+ this.fillMissingCollectInputs(queueEntry);
3699
+ const ready = this.tryDequeueCollect(queue, i);
3700
+ if (ready) return ready;
3701
+ }
3702
+ return null;
3703
+ }
3704
+ tryDequeueCollect(queue, index) {
3705
+ const queueEntry = queue[index];
3706
+ if (!queueEntry.collect) return null;
3707
+ const batchId = queueEntry.batchId ?? "batch_1";
3708
+ const expected = queueEntry.collect.expectedInputs ?? [];
3709
+ const received = queueEntry.collect.received;
3710
+ for (const input$1 of expected) if (!(input$1 in received)) return null;
3711
+ queue.splice(index, 1);
3712
+ return {
3713
+ kind: "multi",
3714
+ nodeId: queueEntry.nodeId,
3715
+ inputsByPort: received,
3716
+ batchId
3717
+ };
3718
+ }
3719
+ fillMissingCollectInputs(queueEntry) {
3720
+ if (!queueEntry.collect) return;
3721
+ const received = queueEntry.collect.received;
3722
+ for (const input$1 of queueEntry.collect.expectedInputs ?? []) if (!(input$1 in received)) received[input$1] = [];
3723
+ }
3724
+ /**
3725
+ * Matches `CurrentStateFrontierPlanner.buildFrontierQueue`: anything that is not exactly one input
3726
+ * port named `in` participates in multi-port collect (Merge after `If` branches, etc.). Routing must
3727
+ * not depend solely on `nodeInstances.get(toNodeId)?.executeMulti`, or a Merge can be enqueued as a
3728
+ * single-input job and `NodeExecutor` will call `execute` on a multi-input-only implementation.
3729
+ */
3730
+ usesTopologyCollectMerge(toNodeId) {
3731
+ const expectedInputs = this.topology.expectedInputsByNode.get(toNodeId) ?? [];
3732
+ return expectedInputs.length !== 1 || expectedInputs[0] !== "in";
3733
+ }
3734
+ enqueueEdge(queue, args) {
3735
+ const target = this.nodeInstances.get(args.to.nodeId);
3736
+ if (!(this.usesTopologyCollectMerge(args.to.nodeId) || this.isMultiInputNode(target))) {
3737
+ if (args.items.length === 0) {
3738
+ if (this.shouldContinueAfterEmptyOutputFromSource(args.from.nodeId)) {
3739
+ queue.push({
3740
+ nodeId: args.to.nodeId,
3741
+ input: args.items,
3742
+ toInput: args.to.input,
3743
+ batchId: args.batchId,
3744
+ from: args.from
3745
+ });
3746
+ return;
3747
+ }
3748
+ this.propagateEmptyPath(queue, args.to.nodeId, args.batchId);
3749
+ return;
3750
+ }
3751
+ queue.push({
3752
+ nodeId: args.to.nodeId,
3753
+ input: args.items,
3754
+ toInput: args.to.input,
3755
+ batchId: args.batchId,
3756
+ from: args.from
3757
+ });
3758
+ return;
3759
+ }
3760
+ const expected = this.topology.expectedInputsByNode.get(args.to.nodeId) ?? [];
3761
+ let collect = queue.find((q) => q.nodeId === args.to.nodeId && (q.batchId ?? "batch_1") === args.batchId && !!q.collect);
3762
+ if (!collect) {
3763
+ collect = {
3764
+ nodeId: args.to.nodeId,
3765
+ input: [],
3766
+ batchId: args.batchId,
3767
+ collect: {
3768
+ expectedInputs: expected,
3769
+ received: {}
3770
+ }
3771
+ };
3772
+ queue.push(collect);
3773
+ }
3774
+ const received = collect.collect.received;
3775
+ received[args.to.input] = args.items;
3776
+ }
3777
+ shouldContinueAfterEmptyOutputFromSource(fromNodeId) {
3778
+ const def = this.topology.defsById.get(fromNodeId);
3779
+ if (!def) return false;
3780
+ return def.config.continueWhenEmptyOutput === true;
3781
+ }
3782
+ propagateEmptyPath(queue, nodeId, batchId) {
3783
+ for (const edge of this.topology.outgoingByNode.get(nodeId) ?? []) this.enqueueEdge(queue, {
3784
+ batchId,
3785
+ to: edge.to,
3786
+ from: {
3787
+ nodeId,
3788
+ output: edge.output
3789
+ },
3790
+ items: []
3791
+ });
3792
+ }
3793
+ isMultiInputNode(n) {
3794
+ return typeof n?.executeMulti === "function";
3795
+ }
3796
+ describeUnsatisfiedCollect(queueEntry) {
3797
+ const batchId = queueEntry.batchId ?? "batch_1";
3798
+ const expectedInputs = queueEntry.collect?.expectedInputs ?? [];
3799
+ const receivedInputs = Object.keys(queueEntry.collect?.received ?? {});
3800
+ const missingInputs = expectedInputs.filter((input$1) => !receivedInputs.includes(input$1));
3801
+ const mergeNodeLabel = this.formatNodeLabel(queueEntry.nodeId);
3802
+ const receivedSummary = this.describeReceivedInputs(queueEntry);
3803
+ const missingSummary = this.describeMissingInputs(queueEntry.nodeId, missingInputs);
3804
+ return [
3805
+ `Multi-input collect is stuck at ${mergeNodeLabel} (batchId=${batchId}).`,
3806
+ `Expected inputs: ${this.formatInputList(expectedInputs)}.`,
3807
+ `Received inputs: ${receivedSummary}.`,
3808
+ `Missing inputs: ${missingSummary}.`
3809
+ ].join(" ");
3810
+ }
3811
+ describeReceivedInputs(queueEntry) {
3812
+ const received = queueEntry.collect?.received ?? {};
3813
+ const receivedEntries = Object.entries(received);
3814
+ if (receivedEntries.length === 0) return "none";
3815
+ return receivedEntries.map(([input$1, items]) => `${input$1} (${items.length} item${items.length === 1 ? "" : "s"})`).join(", ");
3816
+ }
3817
+ describeMissingInputs(nodeId, missingInputs) {
3818
+ if (missingInputs.length === 0) return "none";
3819
+ return missingInputs.map((input$1) => {
3820
+ const sources = this.findSources(nodeId, input$1);
3821
+ if (sources.length === 0) return input$1;
3822
+ return `${input$1} from ${sources.join(" or ")}`;
3823
+ }).join(", ");
3824
+ }
3825
+ findSources(nodeId, input$1) {
3826
+ const matches = [];
3827
+ for (const [sourceNodeId, edges] of this.topology.outgoingByNode.entries()) for (const edge of edges) if (edge.to.nodeId === nodeId && edge.to.input === input$1) matches.push(this.formatNodeLabel(sourceNodeId));
3828
+ return matches;
3829
+ }
3830
+ formatInputList(inputs) {
3831
+ return inputs.length > 0 ? `[${inputs.join(", ")}]` : "[]";
3832
+ }
3833
+ formatNodeLabel(nodeId) {
3834
+ const definition = this.topology.defsById.get(nodeId);
3835
+ const instance = this.nodeInstances.get(nodeId);
3836
+ const typeName = definition?.type && typeof definition.type === "function" ? definition.type.name : instance && typeof instance === "object" && "constructor" in instance ? instance.constructor.name ?? "Node" : "Node";
3837
+ return definition?.name ? `"${definition.name}" (${typeName}:${nodeId})` : `${typeName}:${nodeId}`;
3838
+ }
3839
+ };
3840
+
3841
+ //#endregion
3842
+ //#region src/planning/EngineWorkflowPlanningFactory.ts
3843
+ var EngineWorkflowPlanningFactory = class {
3844
+ constructor(workflowNodeInstanceFactory) {
3845
+ this.workflowNodeInstanceFactory = workflowNodeInstanceFactory;
3846
+ }
3847
+ create(workflow) {
3848
+ this.validateAcyclic(workflow);
3849
+ const topology = WorkflowTopology.fromWorkflow(workflow);
3850
+ const planner = new RunQueuePlanner(topology, this.workflowNodeInstanceFactory.createNodes(workflow));
3851
+ planner.validateNodeKinds();
3852
+ return {
3853
+ topology,
3854
+ planner
3855
+ };
3856
+ }
3857
+ validateAcyclic(workflow) {
3858
+ const classifier = WorkflowExecutableNodeClassifierFactory.create(workflow);
3859
+ const outgoing = /* @__PURE__ */ new Map();
3860
+ const visitState = /* @__PURE__ */ new Map();
3861
+ for (const node$1 of workflow.nodes) if (classifier.isExecutableNodeId(node$1.id)) visitState.set(node$1.id, "unvisited");
3862
+ for (const edge of workflow.edges) {
3863
+ if (!classifier.isExecutableNodeId(edge.from.nodeId) || !classifier.isExecutableNodeId(edge.to.nodeId)) continue;
3864
+ const destinations = outgoing.get(edge.from.nodeId) ?? [];
3865
+ destinations.push(edge.to.nodeId);
3866
+ outgoing.set(edge.from.nodeId, destinations);
3867
+ }
3868
+ 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);
3869
+ }
3870
+ depthFirstSearch(nodeId, outgoing, visitState) {
3871
+ visitState.set(nodeId, "visiting");
3872
+ for (const toNodeId of outgoing.get(nodeId) ?? []) {
3873
+ const state = visitState.get(toNodeId);
3874
+ if (state === "visiting") throw new Error(`Workflow graph contains a directed cycle (edge ${nodeId} -> ${toNodeId}).`);
3875
+ if (state === "unvisited") this.depthFirstSearch(toNodeId, outgoing, visitState);
3876
+ }
3877
+ visitState.set(nodeId, "done");
3878
+ }
3879
+ };
3880
+
3881
+ //#endregion
3882
+ //#region src/orchestration/TriggerRuntimeService.ts
3883
+ var TriggerRuntimeService = class {
3884
+ credentialResolverFactory;
3885
+ triggerCleanupHandlesByKey = /* @__PURE__ */ new Map();
3886
+ constructor(workflowRepository, workflowActivationPolicy, runIdFactory, runDataFactory, executionContextFactory, credentialResolverFactory, nodeExecutionStatePublisherFactory, nodeResolver, triggerSetupStateRepository, emitHandler, executionLimitsPolicy, diagnostics) {
3887
+ this.workflowRepository = workflowRepository;
3888
+ this.workflowActivationPolicy = workflowActivationPolicy;
3889
+ this.runIdFactory = runIdFactory;
3890
+ this.runDataFactory = runDataFactory;
3891
+ this.executionContextFactory = executionContextFactory;
3892
+ this.nodeExecutionStatePublisherFactory = nodeExecutionStatePublisherFactory;
3893
+ this.nodeResolver = nodeResolver;
3894
+ this.triggerSetupStateRepository = triggerSetupStateRepository;
3895
+ this.emitHandler = emitHandler;
3896
+ this.executionLimitsPolicy = executionLimitsPolicy;
3897
+ this.diagnostics = diagnostics;
3898
+ this.credentialResolverFactory = credentialResolverFactory;
3899
+ }
3900
+ async startTriggers() {
3901
+ for (const wf of this.workflowRepository.list()) {
3902
+ if (!this.workflowActivationPolicy.isActive(wf.id)) {
3903
+ const summaries = this.formatTriggerSummaries(wf);
3904
+ if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}) is inactive; skipping trigger setup — ${summaries.join("; ")}.`);
3905
+ continue;
3906
+ }
3907
+ await this.startTriggersForWorkflow(wf);
3908
+ }
3909
+ }
3910
+ async syncWorkflowTriggersForActivation(workflowId) {
3911
+ const wf = this.workflowRepository.get(workflowId);
3912
+ if (!wf) return;
3913
+ const summaries = this.formatTriggerSummaries(wf);
3914
+ if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}): stopping triggers — ${summaries.join("; ")}.`);
3915
+ await this.stopTriggersForWorkflow(wf);
3916
+ if (this.workflowActivationPolicy.isActive(workflowId)) {
3917
+ if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}): activation on; starting triggers — ${summaries.join("; ")}.`);
3918
+ await this.startTriggersForWorkflow(wf);
3919
+ } else this.logInfo(`Workflow "${wf.name}" (${wf.id}): activation off; triggers not started.`);
3920
+ }
3921
+ async stop() {
3922
+ for (const workflow of this.workflowRepository.list()) await this.stopTriggersForWorkflow(workflow);
3923
+ }
3924
+ async createTriggerTestItems(args) {
3925
+ const definition = args.workflow.nodes.find((node$2) => node$2.id === args.nodeId);
3926
+ if (!definition) throw new Error(`Unknown trigger nodeId: ${args.nodeId}`);
3927
+ if (definition.kind !== "trigger") throw new Error(`Node ${args.nodeId} is not a trigger`);
3928
+ const node$1 = this.nodeResolver.resolve(definition.type);
3929
+ if (!this.isTestableTriggerNode(node$1)) return;
3930
+ const data = this.runDataFactory.create();
3931
+ const runId = this.runIdFactory.makeRunId();
3932
+ const trigger = {
3933
+ workflowId: args.workflow.id,
3934
+ nodeId: definition.id
3935
+ };
3936
+ const previousState = await this.triggerSetupStateRepository.load(trigger);
3937
+ return await node$1.getTestItems({
3938
+ ...this.createExecutionContext({
3939
+ runId,
3940
+ workflowId: args.workflow.id,
3941
+ nodeId: definition.id,
3942
+ data
3943
+ }),
3944
+ trigger,
3945
+ nodeId: definition.id,
3946
+ config: definition.config,
3947
+ previousState: previousState?.state
3948
+ });
3949
+ }
3950
+ async startTriggersForWorkflow(wf) {
3951
+ for (const def of wf.nodes) {
3952
+ if (def.kind !== "trigger") continue;
3953
+ const node$1 = this.nodeResolver.resolve(def.type);
3954
+ const data = this.runDataFactory.create();
3955
+ const triggerRunId = this.runIdFactory.makeRunId();
3956
+ const trigger = {
3957
+ workflowId: wf.id,
3958
+ nodeId: def.id
3959
+ };
3960
+ await this.stopTrigger(trigger);
3961
+ const previousState = await this.triggerSetupStateRepository.load(trigger);
3962
+ let nextState;
3963
+ try {
3964
+ nextState = await node$1.setup({
3965
+ ...this.createExecutionContext({
3966
+ runId: triggerRunId,
3967
+ workflowId: wf.id,
3968
+ nodeId: def.id,
3969
+ data
3970
+ }),
3971
+ trigger,
3972
+ config: def.config,
3973
+ previousState: previousState?.state,
3974
+ registerCleanup: (cleanup) => {
3975
+ this.registerTriggerCleanupHandle(trigger, cleanup);
3976
+ },
3977
+ emit: async (items) => {
3978
+ await this.emitHandler.emit(wf, def.id, items);
3979
+ }
3980
+ });
3981
+ } catch (triggerError) {
3982
+ await this.stopTrigger(trigger);
3983
+ const message = triggerError instanceof Error ? triggerError.message : String(triggerError);
3984
+ this.logWarn(`Skipping trigger setup for workflow ${wf.id} node ${def.id}: ${message}`);
3985
+ continue;
3986
+ }
3987
+ if (nextState === void 0) await this.triggerSetupStateRepository.delete(trigger);
3988
+ else await this.triggerSetupStateRepository.save({
3989
+ trigger,
3990
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3991
+ state: nextState
3992
+ });
3993
+ }
3994
+ }
3995
+ async stopTriggersForWorkflow(workflow) {
3996
+ for (const node$1 of workflow.nodes) {
3997
+ if (node$1.kind !== "trigger") continue;
3998
+ await this.stopTrigger({
3999
+ workflowId: workflow.id,
4000
+ nodeId: node$1.id
4001
+ });
4002
+ }
4003
+ }
4004
+ createExecutionContext(args) {
4005
+ const nodeState = this.nodeExecutionStatePublisherFactory.create(args.runId, args.workflowId, void 0);
4006
+ const rootLimits = this.executionLimitsPolicy.createRootExecutionOptions();
4007
+ return this.executionContextFactory.create({
4008
+ runId: args.runId,
4009
+ workflowId: args.workflowId,
4010
+ parent: void 0,
4011
+ subworkflowDepth: rootLimits.subworkflowDepth ?? 0,
4012
+ engineMaxNodeActivations: rootLimits.maxNodeActivations,
4013
+ engineMaxSubworkflowDepth: rootLimits.maxSubworkflowDepth,
4014
+ data: args.data,
4015
+ nodeState,
4016
+ getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId)
4017
+ });
4018
+ }
4019
+ registerTriggerCleanupHandle(trigger, cleanup) {
4020
+ const key = this.toTriggerKey(trigger);
4021
+ const cleanups = this.triggerCleanupHandlesByKey.get(key) ?? [];
4022
+ cleanups.push(cleanup);
4023
+ this.triggerCleanupHandlesByKey.set(key, cleanups);
4024
+ }
4025
+ async stopTrigger(trigger) {
4026
+ const key = this.toTriggerKey(trigger);
4027
+ const cleanups = this.triggerCleanupHandlesByKey.get(key) ?? [];
4028
+ this.triggerCleanupHandlesByKey.delete(key);
4029
+ for (const cleanup of [...cleanups].reverse()) await cleanup.stop();
4030
+ }
4031
+ toTriggerKey(trigger) {
4032
+ return `${trigger.workflowId}:${trigger.nodeId}`;
4033
+ }
4034
+ formatTriggerSummaries(wf) {
4035
+ const out = [];
4036
+ for (const def of wf.nodes) {
4037
+ if (def.kind !== "trigger") continue;
4038
+ out.push(this.describeTriggerNode(def));
4039
+ }
4040
+ return out;
4041
+ }
4042
+ describeTriggerNode(def) {
4043
+ const label = def.name !== void 0 && def.name.trim().length > 0 ? def.name.trim() : String(def.id);
4044
+ const cfg = def.config;
4045
+ if (typeof cfg.endpointKey === "string" && cfg.endpointKey.trim().length > 0) return `${label} (webhook "${cfg.endpointKey.trim()}")`;
4046
+ return label;
4047
+ }
4048
+ logInfo(message) {
4049
+ if (this.diagnostics) this.diagnostics.info(message);
4050
+ }
4051
+ logWarn(message) {
4052
+ if (this.diagnostics) this.diagnostics.warn(message);
4053
+ else console.warn(`[engine] ${message}`);
4054
+ }
4055
+ isTestableTriggerNode(node$1) {
4056
+ return typeof node$1.getTestItems === "function";
4057
+ }
4058
+ };
4059
+
4060
+ //#endregion
4061
+ //#region src/orchestration/EngineWaiters.ts
4062
+ var EngineWaiters = class {
4063
+ completionWaiters = /* @__PURE__ */ new Map();
4064
+ webhookResponseWaiters = /* @__PURE__ */ new Map();
4065
+ waitForCompletion(runId) {
4066
+ return new Promise((resolve) => {
4067
+ const list = this.completionWaiters.get(runId) ?? [];
4068
+ list.push(resolve);
4069
+ this.completionWaiters.set(runId, list);
4070
+ });
4071
+ }
4072
+ waitForWebhookResponse(runId) {
4073
+ return new Promise((resolve) => {
4074
+ const list = this.webhookResponseWaiters.get(runId) ?? [];
4075
+ list.push(resolve);
4076
+ this.webhookResponseWaiters.set(runId, list);
4077
+ });
4078
+ }
4079
+ resolveRunCompletion(result) {
4080
+ if (result.status !== "completed" && result.status !== "failed") return;
4081
+ const list = this.completionWaiters.get(result.runId);
4082
+ if (!list || list.length === 0) return;
4083
+ this.completionWaiters.delete(result.runId);
4084
+ for (const r of list) r(result);
4085
+ }
4086
+ resolveWebhookResponse(result) {
4087
+ const list = this.webhookResponseWaiters.get(result.runId);
4088
+ if (!list || list.length === 0) return;
4089
+ this.webhookResponseWaiters.delete(result.runId);
4090
+ for (const resolve of list) resolve(result);
4091
+ }
4092
+ };
4093
+
4094
+ //#endregion
4095
+ //#region src/orchestration/Engine.ts
4096
+ /**
4097
+ * Runtime facade for orchestration, continuation, triggers, and webhook routing.
4098
+ * Prefer {@link import("../intents/RunIntentService").RunIntentService} for host/HTTP invocation boundaries.
4099
+ * The class token is exported from `@codemation/core/bootstrap` (not the main `@codemation/core` barrel).
4100
+ */
4101
+ var Engine = class {
4102
+ constructor(deps) {
4103
+ this.deps = deps;
4104
+ }
4105
+ loadWorkflows(workflows) {
4106
+ this.deps.tokenRegistry.registerFromWorkflows?.(workflows);
4107
+ this.deps.liveWorkflowRepository.setWorkflows(workflows);
4108
+ this.deps.webhookTriggerMatcher.onEngineWorkflowsLoaded?.();
4109
+ }
4110
+ getTokenRegistry() {
4111
+ return this.deps.tokenRegistry;
4112
+ }
4113
+ resolveWorkflowSnapshot(args) {
4114
+ return this.deps.workflowSnapshotResolver.resolve(args);
4115
+ }
4116
+ async startTriggers() {
4117
+ return await this.deps.triggerRuntime.startTriggers();
4118
+ }
4119
+ async syncWorkflowTriggersForActivation(workflowId) {
4120
+ await this.deps.triggerRuntime.syncWorkflowTriggersForActivation(workflowId);
4121
+ this.deps.webhookTriggerMatcher.reloadWebhookRoutes?.();
4122
+ }
4123
+ async start(workflows) {
4124
+ await this.stop();
4125
+ this.loadWorkflows(workflows);
4126
+ await this.startTriggers();
4127
+ }
4128
+ async stop() {
4129
+ await this.deps.triggerRuntime.stop();
4130
+ this.deps.webhookTriggerMatcher.onEngineStopped?.();
4131
+ }
4132
+ resolveWebhookTrigger(args) {
4133
+ const entry = this.deps.webhookTriggerMatcher.lookup(args.endpointPath);
4134
+ if (!entry) return { status: "notFound" };
4135
+ if (!entry.methods.includes(args.method)) return {
4136
+ status: "methodNotAllowed",
4137
+ match: entry
4138
+ };
4139
+ return {
4140
+ status: "ok",
4141
+ match: entry
4142
+ };
4143
+ }
4144
+ async createTriggerTestItems(args) {
4145
+ return await this.deps.triggerRuntime.createTriggerTestItems(args);
4146
+ }
4147
+ async runWorkflow(wf, startAt, items, parent, executionOptions, persistedStateOverrides) {
4148
+ return await this.deps.runStartService.runWorkflow(wf, startAt, items, parent, executionOptions, persistedStateOverrides);
4149
+ }
4150
+ async runWorkflowFromState(request) {
4151
+ return await this.deps.runStartService.runWorkflowFromState(request);
4152
+ }
4153
+ async markNodeRunning(args) {
4154
+ return await this.deps.runContinuationService.markNodeRunning(args);
4155
+ }
4156
+ async resumeFromNodeResult(args) {
4157
+ return await this.deps.runContinuationService.resumeFromNodeResult(args);
4158
+ }
4159
+ async resumeFromNodeError(args) {
4160
+ return await this.deps.runContinuationService.resumeFromNodeError(args);
4161
+ }
4162
+ async resumeFromStepResult(args) {
4163
+ return await this.deps.runContinuationService.resumeFromStepResult(args);
4164
+ }
4165
+ async resumeFromStepError(args) {
4166
+ return await this.deps.runContinuationService.resumeFromStepError(args);
4167
+ }
4168
+ async waitForCompletion(runId) {
4169
+ return await this.deps.runContinuationService.waitForCompletion(runId);
4170
+ }
4171
+ async waitForWebhookResponse(runId) {
4172
+ return await this.deps.runContinuationService.waitForWebhookResponse(runId);
4173
+ }
4174
+ async handleNodeExecutionRequest(request) {
4175
+ await this.deps.nodeExecutionRequestHandler.handleNodeExecutionRequest(request);
4176
+ }
4177
+ };
4178
+
4179
+ //#endregion
4180
+ //#region src/runtime/EngineFactory.ts
4181
+ /**
4182
+ * Composes the {@link Engine} graph from {@link EngineCompositionDeps}. Production wiring usually goes through
4183
+ * {@link import("../bootstrap/runtime/EngineRuntimeRegistrar").EngineRuntimeRegistrar}; this factory remains for tests and custom composition.
4184
+ * Exported from `@codemation/core/bootstrap` (not the main `@codemation/core` barrel).
4185
+ */
4186
+ var EngineFactory = class {
4187
+ create(deps) {
4188
+ const waiters = new EngineWaiters();
4189
+ const credentialResolverFactory = new CredentialResolverFactory(deps.credentialSessions);
4190
+ const nodeEventPublisher = new NodeEventPublisher(deps.eventBus);
4191
+ const nodeStatePublisherFactory = new NodeRunStateWriterFactory(deps.workflowExecutionRepository, nodeEventPublisher);
4192
+ const planningFactory = new EngineWorkflowPlanningFactory(deps.workflowNodeInstanceFactory);
4193
+ const executionLimitsPolicy = deps.executionLimitsPolicy ?? new EngineExecutionLimitsPolicy();
4194
+ const workflowSnapshotCodec = deps.workflowSnapshotCodec ?? new WorkflowSnapshotCodec(deps.tokenRegistry);
4195
+ const missingRuntimeFallbacks = deps.missingRuntimeFallbacks ?? new MissingRuntimeFallbacks();
4196
+ const workflowSnapshotResolver = new WorkflowSnapshotResolver(deps.workflowRepository, deps.tokenRegistry, workflowSnapshotCodec, missingRuntimeFallbacks);
4197
+ const semantics = new RunStateSemantics(new MissingRuntimeExecutionMarker());
4198
+ const nodeActivationRequestInputPreparer = new NodeActivationRequestInputPreparer(deps.workflowNodeInstanceFactory);
4199
+ const activationEnqueueService = new ActivationEnqueueService(deps.activationScheduler, deps.workflowExecutionRepository, nodeEventPublisher, nodeActivationRequestInputPreparer);
4200
+ const runExecutionContextFactory = new WorkflowRunExecutionContextFactory(deps.executionContextFactory, credentialResolverFactory);
4201
+ const nodeActivationRequestComposer = new NodeActivationRequestComposer(deps.activationIdFactory, credentialResolverFactory);
4202
+ const persistedRunStateTerminalBuilder = new PersistedRunStateTerminalBuilder();
4203
+ const storagePolicyEvaluator = new WorkflowStoragePolicyEvaluator(deps.nodeResolver);
4204
+ const terminalPersistence = new RunTerminalPersistenceCoordinator(deps.workflowExecutionRepository, storagePolicyEvaluator);
4205
+ const policyErrorServices = new WorkflowPolicyErrorServices(deps.nodeResolver);
4206
+ const runStartService = new RunStartService(deps.runIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, workflowSnapshotCodec, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, deps.workflowPolicyRuntimeDefaults, executionLimitsPolicy);
4207
+ const runContinuationService = new RunContinuationService(deps.activationIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, runExecutionContextFactory, workflowSnapshotResolver, planningFactory, nodeStatePublisherFactory, credentialResolverFactory, nodeActivationRequestComposer, persistedRunStateTerminalBuilder, activationEnqueueService, nodeEventPublisher, semantics, waiters, policyErrorServices, terminalPersistence, executionLimitsPolicy);
4208
+ const nodeExecutionRequestHandler = new NodeExecutionRequestHandlerService(deps.workflowExecutionRepository, workflowSnapshotResolver, deps.runDataFactory, runExecutionContextFactory, nodeStatePublisherFactory, nodeActivationRequestComposer, deps.nodeExecutor, runContinuationService, executionLimitsPolicy);
4209
+ 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) => {
4210
+ await runStartService.runWorkflow(workflow, triggerNodeId, items, void 0);
4211
+ } }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics);
4212
+ const engine = new Engine({
4213
+ liveWorkflowRepository: deps.liveWorkflowRepository,
4214
+ tokenRegistry: deps.tokenRegistry,
4215
+ webhookTriggerMatcher: deps.webhookTriggerMatcher,
4216
+ workflowSnapshotResolver,
4217
+ triggerRuntime,
4218
+ runStartService,
4219
+ runContinuationService,
4220
+ nodeExecutionRequestHandler
4221
+ });
4222
+ deps.activationScheduler.setContinuation?.(engine);
4223
+ return engine;
4224
+ }
4225
+ };
4226
+
4227
+ //#endregion
4228
+ //#region src/runtime/EngineWorkflowRunnerService.ts
4229
+ var EngineWorkflowRunnerService = class {
4230
+ constructor(engine, workflowRepository) {
4231
+ this.engine = engine;
4232
+ this.workflowRepository = workflowRepository;
4233
+ }
4234
+ async runById(args) {
4235
+ const { workflowId, startAt, items, parent } = args;
4236
+ const wf = this.workflowRepository.get(workflowId);
4237
+ if (!wf) throw new Error(`Unknown workflowId: ${workflowId}`);
4238
+ const startNodeId = startAt ?? this.findDefaultStartNodeId(wf);
4239
+ const scheduled = await this.engine.runWorkflow(wf, startNodeId, items, parent);
4240
+ if (scheduled.status !== "pending") return scheduled;
4241
+ return await this.engine.waitForCompletion(scheduled.runId);
4242
+ }
4243
+ findDefaultStartNodeId(wf) {
4244
+ return WorkflowExecutableNodeClassifierFactory.create(wf).findDefaultExecutableStartNodeId(wf);
4245
+ }
4246
+ };
4247
+
4248
+ //#endregion
4249
+ //#region src/runtime/EngineWorkflowRunnerServiceFactory.ts
4250
+ var EngineWorkflowRunnerServiceFactory = class {
4251
+ create(engine, workflowRepository) {
4252
+ return new EngineWorkflowRunnerService(engine, workflowRepository);
4253
+ }
4254
+ };
4255
+
3228
4256
  //#endregion
3229
4257
  //#region src/runtime/InMemoryLiveWorkflowRepository.ts
3230
4258
  var InMemoryLiveWorkflowRepository = class {
@@ -3369,5 +4397,107 @@ var RunIntentService = class {
3369
4397
  };
3370
4398
 
3371
4399
  //#endregion
3372
- export { delay as $, NodeExecutor as A, NodeEventPublisher as B, WorkflowSnapshotResolver as C, MissingRuntimeTriggerToken as D, MissingRuntimeFallbacks as E, DefaultAsyncSleeper as F, getPersistedRuntimeTypeMetadata as G, WorkflowExecutableNodeClassifier as H, CredentialResolverFactory as I, InjectableRuntimeDecoratorComposer as J, node as K, ActivationEnqueueService as L, InProcessRetryRunnerFactory as M, InProcessRetryRunner as N, MissingRuntimeExecutionMarker as O, DefaultExecutionContextFactory as P, container$1 as Q, DefaultExecutionBinaryService as R, NodeInstanceFactory as S, PersistedWorkflowTokenRegistry as T, ConnectionNodeIdFactory as U, WorkflowExecutableNodeClassifierFactory as V, chatModel as W, StackTraceCallSitePathResolver as X, PersistedRuntimeTypeMetadataStore as Y, PersistedRuntimeTypeNameResolver as Z, WorkflowRunExecutionContextFactory as _, InMemoryBinaryStorage as a, predicateAwareClassFactory as at, NodeRunStateWriterFactory as b, LocalOnlyScheduler as c, CoreTokens as ct, DefaultDrivingScheduler as d, inject as et, ConfigDrivenOffloadPolicy as f, WorkflowTopology as g, RunContinuationService as h, InMemoryRunDataFactory as i, instancePerContainerCachingFactory as it, NodeActivationRequestComposer as j, NodeExecutorFactory as k, InlineDrivingScheduler as l, RunPolicySnapshotFactory as m, InMemoryLiveWorkflowRepository as n, injectable as nt, ENGINE_EXECUTION_LIMITS_DEFAULTS as o, registry as ot, RunStartService as p, tool as q, RunFinishedAtFactory as r, instanceCachingFactory as rt, EngineExecutionLimitsPolicy as s, singleton as st, RunIntentService as t, injectAll as tt, HintOnlyOffloadPolicy as u, RunStateSemantics as v, WorkflowSnapshotCodec as w, NodeInstanceFactoryFactory as x, PersistedRunStateTerminalBuilder as y, UnavailableBinaryStorage as z };
3373
- //# sourceMappingURL=RunIntentService-BFA48UpH.js.map
4400
+ //#region src/runtime/RunIntentServiceFactory.ts
4401
+ var RunIntentServiceFactory = class {
4402
+ create(engine, workflowRepository) {
4403
+ return new RunIntentService(engine, workflowRepository);
4404
+ }
4405
+ };
4406
+
4407
+ //#endregion
4408
+ //#region src/runtime/WorkflowRepositoryWebhookTriggerMatcher.ts
4409
+ /**
4410
+ * Resolves webhook HTTP routes from the live workflow repository (no trigger setup / registration).
4411
+ * Maintains an in-memory index keyed by user-defined endpoint path for O(1) lookups after reload.
4412
+ */
4413
+ var WorkflowRepositoryWebhookTriggerMatcher = class {
4414
+ routeByPath = /* @__PURE__ */ new Map();
4415
+ engineRoutesActive = false;
4416
+ constructor(workflowRepository, workflowActivationPolicy, diagnostics) {
4417
+ this.workflowRepository = workflowRepository;
4418
+ this.workflowActivationPolicy = workflowActivationPolicy;
4419
+ this.diagnostics = diagnostics;
4420
+ }
4421
+ onEngineWorkflowsLoaded() {
4422
+ this.engineRoutesActive = true;
4423
+ this.rebuildRouteIndex();
4424
+ }
4425
+ onEngineStopped() {
4426
+ this.engineRoutesActive = false;
4427
+ this.routeByPath.clear();
4428
+ }
4429
+ reloadWebhookRoutes() {
4430
+ if (!this.engineRoutesActive) return;
4431
+ this.rebuildRouteIndex();
4432
+ }
4433
+ lookup(endpointPath) {
4434
+ if (!this.engineRoutesActive) return;
4435
+ const normalized = this.normalizeEndpointPath(endpointPath);
4436
+ return this.routeByPath.get(normalized);
4437
+ }
4438
+ match(args) {
4439
+ const entry = this.lookup(args.endpointPath);
4440
+ if (!entry) return;
4441
+ return entry.methods.includes(args.method) ? entry : void 0;
4442
+ }
4443
+ rebuildRouteIndex() {
4444
+ this.routeByPath.clear();
4445
+ for (const workflow of this.workflowRepository.list()) {
4446
+ if (!this.workflowActivationPolicy.isActive(workflow.id)) {
4447
+ if (workflow.nodes.filter((n) => n.kind === "trigger").length > 0) {
4448
+ const paths = this.collectWebhookEndpointPaths(workflow);
4449
+ if (paths.length > 0) this.diagnostics?.info?.(`Workflow "${workflow.name}" (${workflow.id}) is inactive; webhook routes not registered: ${paths.map((p) => `"${p}"`).join(", ")}`);
4450
+ else this.diagnostics?.info?.(`Workflow "${workflow.name}" (${workflow.id}) is inactive; no repository webhook routes for its triggers (other trigger kinds are unchanged).`);
4451
+ }
4452
+ continue;
4453
+ }
4454
+ for (const def of workflow.nodes) {
4455
+ const match = this.tryMatchFromTriggerNode(workflow, def);
4456
+ if (!match) continue;
4457
+ const key = this.normalizeEndpointPath(match.endpointPath);
4458
+ const existing = this.routeByPath.get(key);
4459
+ if (existing) this.diagnostics?.warn(`Duplicate webhook endpoint path "${key}" (workflows "${existing.workflowId}" and "${match.workflowId}"); using "${match.workflowId}".`);
4460
+ this.routeByPath.set(key, match);
4461
+ }
4462
+ }
4463
+ }
4464
+ collectWebhookEndpointPaths(workflow) {
4465
+ const paths = [];
4466
+ for (const def of workflow.nodes) {
4467
+ if (def.kind !== "trigger") continue;
4468
+ const match = this.tryMatchFromTriggerNode(workflow, def);
4469
+ if (match) paths.push(match.endpointPath);
4470
+ }
4471
+ return paths;
4472
+ }
4473
+ tryMatchFromTriggerNode(workflow, def) {
4474
+ if (def.kind !== "trigger") return;
4475
+ const config = def.config;
4476
+ if (typeof config.endpointKey !== "string" || config.endpointKey.length === 0) return;
4477
+ if (!Array.isArray(config.methods) || config.methods.length === 0) return;
4478
+ const methods = config.methods;
4479
+ const parseJsonBody = typeof config.parseJsonBody === "function" ? config.parseJsonBody.bind(config) : void 0;
4480
+ return {
4481
+ endpointPath: config.endpointKey,
4482
+ workflowId: workflow.id,
4483
+ nodeId: def.id,
4484
+ methods: [...methods],
4485
+ parseJsonBody
4486
+ };
4487
+ }
4488
+ normalizeEndpointPath(endpointPath) {
4489
+ return endpointPath.trim();
4490
+ }
4491
+ };
4492
+
4493
+ //#endregion
4494
+ //#region src/runtime/WorkflowRepositoryWebhookTriggerMatcherFactory.ts
4495
+ var WorkflowRepositoryWebhookTriggerMatcherFactory = class {
4496
+ create(workflowRepository, workflowActivationPolicy, diagnostics) {
4497
+ return new WorkflowRepositoryWebhookTriggerMatcher(workflowRepository, workflowActivationPolicy, diagnostics);
4498
+ }
4499
+ };
4500
+
4501
+ //#endregion
4502
+ export { injectAll as $, NodeExecutor as A, WorkflowExecutableNodeClassifier as B, RunPolicySnapshotFactory as C, PersistedWorkflowTokenRegistry as D, WorkflowSnapshotCodec as E, CredentialResolverFactory as F, tool as G, chatModel as H, DefaultExecutionBinaryService as I, StackTraceCallSitePathResolver as J, InjectableRuntimeDecoratorComposer as K, UnavailableBinaryStorage as L, InProcessRetryRunner as M, DefaultExecutionContextFactory as N, MissingRuntimeTriggerToken as O, DefaultAsyncSleeper as P, inject as Q, NodeEventPublisher as R, ConfigDrivenOffloadPolicy as S, NodeInstanceFactory as T, getPersistedRuntimeTypeMetadata as U, ConnectionNodeIdFactory as V, node as W, container$1 as X, PersistedRuntimeTypeNameResolver as Y, delay as Z, EngineExecutionLimitsPolicy as _, InMemoryLiveWorkflowRepository as a, singleton as at, HintOnlyOffloadPolicy as b, EngineFactory as c, InMemoryRunDataFactory as d, injectable as et, InMemoryBinaryStorage as f, ENGINE_EXECUTION_LIMITS_DEFAULTS as g, RunTerminalPersistenceCoordinator as h, RunIntentService as i, registry as it, InProcessRetryRunnerFactory as j, NodeExecutorFactory as k, Engine as l, WorkflowPolicyErrorServices as m, WorkflowRepositoryWebhookTriggerMatcher as n, instancePerContainerCachingFactory as nt, EngineWorkflowRunnerServiceFactory as o, CoreTokens as ot, WorkflowStoragePolicyEvaluator as p, PersistedRuntimeTypeMetadataStore as q, RunIntentServiceFactory as r, predicateAwareClassFactory as rt, EngineWorkflowRunnerService as s, WorkflowRepositoryWebhookTriggerMatcherFactory as t, instanceCachingFactory as tt, RunFinishedAtFactory as u, LocalOnlyScheduler as v, NodeInstanceFactoryFactory as w, DefaultDrivingScheduler as x, InlineDrivingScheduler as y, WorkflowExecutableNodeClassifierFactory as z };
4503
+ //# sourceMappingURL=runtime-Cy-3FTI_.js.map