@blokjs/runner 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/dist/Blok.js +32 -3
  2. package/dist/Blok.js.map +1 -1
  3. package/dist/Configuration.d.ts +41 -5
  4. package/dist/Configuration.js +215 -92
  5. package/dist/Configuration.js.map +1 -1
  6. package/dist/ForEachNode.d.ts +59 -0
  7. package/dist/ForEachNode.js +522 -0
  8. package/dist/ForEachNode.js.map +1 -0
  9. package/dist/LoopMaxIterationsError.d.ts +11 -0
  10. package/dist/LoopMaxIterationsError.js +18 -0
  11. package/dist/LoopMaxIterationsError.js.map +1 -0
  12. package/dist/LoopNode.d.ts +36 -0
  13. package/dist/LoopNode.js +182 -0
  14. package/dist/LoopNode.js.map +1 -0
  15. package/dist/Runner.d.ts +11 -1
  16. package/dist/Runner.js +9 -2
  17. package/dist/Runner.js.map +1 -1
  18. package/dist/RunnerSteps.js +419 -112
  19. package/dist/RunnerSteps.js.map +1 -1
  20. package/dist/RuntimeAdapterNode.d.ts +2 -1
  21. package/dist/RuntimeAdapterNode.js +2 -2
  22. package/dist/RuntimeAdapterNode.js.map +1 -1
  23. package/dist/RuntimeRegistry.d.ts +23 -2
  24. package/dist/RuntimeRegistry.js +31 -2
  25. package/dist/RuntimeRegistry.js.map +1 -1
  26. package/dist/SubworkflowNode.d.ts +106 -0
  27. package/dist/SubworkflowNode.js +261 -3
  28. package/dist/SubworkflowNode.js.map +1 -1
  29. package/dist/SwitchNode.d.ts +37 -0
  30. package/dist/SwitchNode.js +153 -0
  31. package/dist/SwitchNode.js.map +1 -0
  32. package/dist/TriggerBase.d.ts +50 -0
  33. package/dist/TriggerBase.js +262 -4
  34. package/dist/TriggerBase.js.map +1 -1
  35. package/dist/TryCatchNode.d.ts +32 -0
  36. package/dist/TryCatchNode.js +207 -0
  37. package/dist/TryCatchNode.js.map +1 -0
  38. package/dist/adapters/grpc/GrpcCodec.js +2 -2
  39. package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +6 -4
  40. package/dist/adapters/grpc/GrpcRuntimeAdapter.js +6 -4
  41. package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -1
  42. package/dist/adapters/grpc/types.d.ts +7 -5
  43. package/dist/adapters/grpc/types.js.map +1 -1
  44. package/dist/adapters/transport.d.ts +12 -41
  45. package/dist/adapters/transport.js +21 -70
  46. package/dist/adapters/transport.js.map +1 -1
  47. package/dist/cache/NodeResultCache.js +7 -0
  48. package/dist/cache/NodeResultCache.js.map +1 -1
  49. package/dist/concurrency/NatsKvConcurrencyBackend.js +18 -5
  50. package/dist/concurrency/NatsKvConcurrencyBackend.js.map +1 -1
  51. package/dist/concurrency/RedisConcurrencyBackend.d.ts +64 -0
  52. package/dist/concurrency/RedisConcurrencyBackend.js +374 -0
  53. package/dist/concurrency/RedisConcurrencyBackend.js.map +1 -0
  54. package/dist/concurrency/createConcurrencyBackend.d.ts +1 -0
  55. package/dist/concurrency/createConcurrencyBackend.js +5 -1
  56. package/dist/concurrency/createConcurrencyBackend.js.map +1 -1
  57. package/dist/defineNode.d.ts +8 -0
  58. package/dist/defineNode.js +25 -5
  59. package/dist/defineNode.js.map +1 -1
  60. package/dist/graphql/GraphQLSchemaGenerator.js +1 -1
  61. package/dist/graphql/GraphQLSchemaGenerator.js.map +1 -1
  62. package/dist/index.d.ts +10 -6
  63. package/dist/index.js +13 -9
  64. package/dist/index.js.map +1 -1
  65. package/dist/marketplace/RuntimeCatalog.d.ts +6 -0
  66. package/dist/marketplace/RuntimeCatalog.js.map +1 -1
  67. package/dist/marketplace/RuntimeDiscovery.d.ts +2 -2
  68. package/dist/marketplace/RuntimeDiscovery.js +18 -6
  69. package/dist/marketplace/RuntimeDiscovery.js.map +1 -1
  70. package/dist/monitoring/ConcurrencyMetrics.d.ts +26 -0
  71. package/dist/monitoring/ConcurrencyMetrics.js +36 -4
  72. package/dist/monitoring/ConcurrencyMetrics.js.map +1 -1
  73. package/dist/monitoring/ForEachWaitMetrics.d.ts +22 -0
  74. package/dist/monitoring/ForEachWaitMetrics.js +36 -0
  75. package/dist/monitoring/ForEachWaitMetrics.js.map +1 -0
  76. package/dist/openapi/OpenAPIGenerator.js +7 -2
  77. package/dist/openapi/OpenAPIGenerator.js.map +1 -1
  78. package/dist/runtime/PrimitiveStack.d.ts +64 -0
  79. package/dist/runtime/PrimitiveStack.js +92 -0
  80. package/dist/runtime/PrimitiveStack.js.map +1 -0
  81. package/dist/scheduling/DebounceBackend.d.ts +108 -0
  82. package/dist/scheduling/DebounceBackend.js +23 -0
  83. package/dist/scheduling/DebounceBackend.js.map +1 -0
  84. package/dist/scheduling/DebounceCoordinator.d.ts +65 -12
  85. package/dist/scheduling/DebounceCoordinator.js +234 -13
  86. package/dist/scheduling/DebounceCoordinator.js.map +1 -1
  87. package/dist/scheduling/DeferredRunScheduler.d.ts +28 -0
  88. package/dist/scheduling/DeferredRunScheduler.js +105 -3
  89. package/dist/scheduling/DeferredRunScheduler.js.map +1 -1
  90. package/dist/scheduling/NatsKvDebounceBackend.d.ts +53 -0
  91. package/dist/scheduling/NatsKvDebounceBackend.js +334 -0
  92. package/dist/scheduling/NatsKvDebounceBackend.js.map +1 -0
  93. package/dist/scheduling/RedisDebounceBackend.d.ts +49 -0
  94. package/dist/scheduling/RedisDebounceBackend.js +356 -0
  95. package/dist/scheduling/RedisDebounceBackend.js.map +1 -0
  96. package/dist/scheduling/createDebounceBackend.d.ts +25 -0
  97. package/dist/scheduling/createDebounceBackend.js +39 -0
  98. package/dist/scheduling/createDebounceBackend.js.map +1 -0
  99. package/dist/security/AuditLogger.js +1 -1
  100. package/dist/security/AuditLogger.js.map +1 -1
  101. package/dist/security/AuthMiddleware.d.ts +19 -20
  102. package/dist/security/AuthMiddleware.js +35 -20
  103. package/dist/security/AuthMiddleware.js.map +1 -1
  104. package/dist/security/OAuthProvider.js +2 -2
  105. package/dist/security/OAuthProvider.js.map +1 -1
  106. package/dist/security/SecretManager.js +14 -13
  107. package/dist/security/SecretManager.js.map +1 -1
  108. package/dist/security/index.d.ts +3 -1
  109. package/dist/security/index.js +3 -1
  110. package/dist/security/index.js.map +1 -1
  111. package/dist/testing/TestHarness.d.ts +27 -12
  112. package/dist/testing/TestHarness.js +19 -3
  113. package/dist/testing/TestHarness.js.map +1 -1
  114. package/dist/testing/WorkflowTestRunner.js +0 -7
  115. package/dist/testing/WorkflowTestRunner.js.map +1 -1
  116. package/dist/tracing/InMemoryRunStore.d.ts +14 -1
  117. package/dist/tracing/InMemoryRunStore.js +95 -6
  118. package/dist/tracing/InMemoryRunStore.js.map +1 -1
  119. package/dist/tracing/PostgresRunStore.d.ts +28 -2
  120. package/dist/tracing/PostgresRunStore.js +276 -3
  121. package/dist/tracing/PostgresRunStore.js.map +1 -1
  122. package/dist/tracing/RoutingDiagnostics.d.ts +55 -0
  123. package/dist/tracing/RoutingDiagnostics.js +50 -0
  124. package/dist/tracing/RoutingDiagnostics.js.map +1 -0
  125. package/dist/tracing/RunStore.d.ts +82 -1
  126. package/dist/tracing/RunTracker.d.ts +7 -1
  127. package/dist/tracing/RunTracker.js +23 -0
  128. package/dist/tracing/RunTracker.js.map +1 -1
  129. package/dist/tracing/SqliteRunStore.d.ts +57 -2
  130. package/dist/tracing/SqliteRunStore.js +408 -48
  131. package/dist/tracing/SqliteRunStore.js.map +1 -1
  132. package/dist/tracing/TraceRouter.js +380 -18
  133. package/dist/tracing/TraceRouter.js.map +1 -1
  134. package/dist/tracing/createStore.js +14 -3
  135. package/dist/tracing/createStore.js.map +1 -1
  136. package/dist/tracing/metadataFilter.d.ts +63 -0
  137. package/dist/tracing/metadataFilter.js +224 -0
  138. package/dist/tracing/metadataFilter.js.map +1 -0
  139. package/dist/tracing/types.d.ts +331 -7
  140. package/dist/utils/envAllowlist.d.ts +35 -0
  141. package/dist/utils/envAllowlist.js +113 -0
  142. package/dist/utils/envAllowlist.js.map +1 -0
  143. package/dist/version/RuntimeVersionValidator.d.ts +38 -0
  144. package/dist/version/RuntimeVersionValidator.js +121 -0
  145. package/dist/version/RuntimeVersionValidator.js.map +1 -0
  146. package/dist/visualization/WorkflowVisualizer.js +4 -4
  147. package/dist/visualization/WorkflowVisualizer.js.map +1 -1
  148. package/dist/workflow/PersistenceHelper.d.ts +18 -10
  149. package/dist/workflow/PersistenceHelper.js +35 -9
  150. package/dist/workflow/PersistenceHelper.js.map +1 -1
  151. package/dist/workflow/WorkflowNormalizer.d.ts +19 -1
  152. package/dist/workflow/WorkflowNormalizer.js +469 -19
  153. package/dist/workflow/WorkflowNormalizer.js.map +1 -1
  154. package/dist/workflow/WorkflowRegistry.d.ts +122 -0
  155. package/dist/workflow/WorkflowRegistry.js +121 -0
  156. package/dist/workflow/WorkflowRegistry.js.map +1 -1
  157. package/dist/workflow/sampleBody.d.ts +54 -0
  158. package/dist/workflow/sampleBody.js +320 -0
  159. package/dist/workflow/sampleBody.js.map +1 -0
  160. package/package.json +3 -8
  161. package/dist/adapters/HttpRuntimeAdapter.d.ts +0 -79
  162. package/dist/adapters/HttpRuntimeAdapter.js +0 -233
  163. package/dist/adapters/HttpRuntimeAdapter.js.map +0 -1
@@ -0,0 +1,522 @@
1
+ /**
2
+ * ForEachNode — v0.5 primitive. Iterates over a collection, running a
3
+ * sub-pipeline of steps for each item. Supports sequential and parallel
4
+ * (with bounded concurrency) modes.
5
+ *
6
+ * The runtime config is read from `ctx.config[this.name]`:
7
+ * {
8
+ * in: unknown[], // resolved by the blueprint mapper before run()
9
+ * as: string, // per-iteration variable name; lands at ctx.state[as]
10
+ * mode: "sequential" | "parallel",
11
+ * concurrency: number, // parallel mode only
12
+ * steps: NodeBase[], // pre-resolved by Configuration's isFlowWithProperties path
13
+ * }
14
+ *
15
+ * Per-iteration scoping: a child ctx is built per item with
16
+ * `ctx.state[as] = item` and `ctx.state[as + "Index"] = i`. Mutations
17
+ * to state inside an iteration do NOT bleed to other iterations
18
+ * (parallel safety, plus matches the documented forEach contract).
19
+ *
20
+ * Errors in any iteration propagate to the caller. The runner's outer
21
+ * step-level catch wraps them into the standard error envelope.
22
+ *
23
+ * v0.6 wait-inside-primitives:
24
+ * - Phase 2 — sequential + wait shipped via the cursor stamps below.
25
+ * - Phase 3 — parallel + wait shipped via the pool AbortController +
26
+ * Promise.allSettled classification + cursor write. See
27
+ * `docs/c/devtools/parallel-foreach-wait-spec.mdx` for the full
28
+ * design.
29
+ */
30
+ import _ from "lodash";
31
+ import { RunCancelledError } from "./RunCancelledError";
32
+ import RunnerNode from "./RunnerNode";
33
+ import { WaitDispatchRequest } from "./WaitDispatchRequest";
34
+ import { ForEachWaitMetrics } from "./monitoring/ForEachWaitMetrics";
35
+ import { consumeRehydratedCursor, popPrimitiveFrame, pushPrimitiveFrame, readRehydratedCursor, } from "./runtime/PrimitiveStack";
36
+ import { RunTracker } from "./tracing/RunTracker";
37
+ import { applyStepOutput } from "./workflow/PersistenceHelper";
38
+ export class ForEachNode extends RunnerNode {
39
+ /**
40
+ * v0.6 marker — RunnerSteps stamps `_blokActivePrimitiveNodeRunId`
41
+ * on ctx around `step.process()` calls when this flag is true so a
42
+ * nested wait fired inside an iteration body knows which NodeRun to
43
+ * write its `iteration_context` cursor to. Static `true` (vs an
44
+ * instance method) avoids importing ForEachNode inside RunnerSteps,
45
+ * which would create a circular dependency.
46
+ */
47
+ isPrimitiveIterator = true;
48
+ async run(ctx) {
49
+ this.contentType = "application/json";
50
+ const response = { success: true, data: [], error: null };
51
+ const opts = (ctx.config?.[this.name] ?? {});
52
+ const items = Array.isArray(opts.in) ? opts.in : [];
53
+ const as = typeof opts.as === "string" && opts.as.length > 0 ? opts.as : "item";
54
+ const mode = opts.mode === "parallel" ? "parallel" : "sequential";
55
+ const concurrency = typeof opts.concurrency === "number" && opts.concurrency > 0 ? opts.concurrency : 10;
56
+ const steps = (opts.steps ?? []);
57
+ if (items.length === 0 || steps.length === 0) {
58
+ response.data = [];
59
+ applyStepOutput(ctx, this, { data: [] });
60
+ return response;
61
+ }
62
+ // v0.6 — read the resume hint that TriggerBase rehydrated.
63
+ //
64
+ // Phase 4 — cursors are now keyed by NodeRun id in a map on ctx
65
+ // (`_blokIterationCursors`). Each primitive looks itself up by
66
+ // `ctx._traceNodeId` so nested primitives (forEach > forEach,
67
+ // switch > forEach, etc.) each find their OWN cursor — not the
68
+ // previous Phase 2/3 single-slot model that lost outer cursors
69
+ // to inner overwrites. Falls back to the legacy single-slot
70
+ // `_blokIterationResume` field for first-pass compatibility with
71
+ // callers that haven't migrated yet.
72
+ const ctxAny = ctx;
73
+ const myNodeRunId = ctxAny._traceNodeId;
74
+ // Phase 4 — lookup by step NAME (not NodeRun id). Names are
75
+ // stable across dispatchDeferred re-entries; NodeRun ids change.
76
+ let resume = readRehydratedCursor(ctx, this.name);
77
+ if (resume) {
78
+ consumeRehydratedCursor(ctx, this.name);
79
+ }
80
+ if (resume === undefined) {
81
+ const legacyResume = ctxAny._blokIterationResume;
82
+ if (legacyResume !== undefined) {
83
+ resume = legacyResume;
84
+ ctxAny._blokIterationResume = undefined;
85
+ }
86
+ }
87
+ // Lazy import to avoid circular dep (Runner pulls in Configuration).
88
+ const { default: Runner } = await import("./Runner");
89
+ // Discriminate on cursor mode at the read side. Sequential cursors
90
+ // written before this PR omit the `mode` field — treated as
91
+ // "sequential" by default. Parallel cursors are written ONLY by
92
+ // the parallel branch below.
93
+ const sequentialResume = resume && (resume.mode ?? "sequential") === "sequential" ? resume : undefined;
94
+ const parallelResume = resume?.mode === "parallel" ? resume : undefined;
95
+ // Pre-populate results[] from cursor — both sequential and parallel
96
+ // resume paths use this. Sequential: contiguous slice [0..N-1].
97
+ // Parallel: sparse — only slots present in `completedResults` get
98
+ // filled; the rest stay `undefined` and get re-launched.
99
+ const results = new Array(items.length);
100
+ if (sequentialResume?.completedResults) {
101
+ const cap = Math.min(sequentialResume.completedResults.length, items.length);
102
+ for (let k = 0; k < cap; k++) {
103
+ results[k] = sequentialResume.completedResults[k];
104
+ }
105
+ }
106
+ if (parallelResume?.completedResults) {
107
+ const cap = Math.min(parallelResume.completedResults.length, items.length);
108
+ for (let k = 0; k < cap; k++) {
109
+ const slot = parallelResume.completedResults[k];
110
+ // `null` distinguishes "ran but returned undefined" (re-use
111
+ // this value, don't re-launch) from a JSON-undefined hole
112
+ // (not present — re-launch). Both deserialise to `null` in
113
+ // some JSON encoders; we normalise sparse holes via
114
+ // `Object.prototype.hasOwnProperty` against the parsed
115
+ // array.
116
+ if (Object.prototype.hasOwnProperty.call(parallelResume.completedResults, k) && slot !== undefined) {
117
+ // null sentinel survives — readers see `results[k] === null`
118
+ // meaning "ran, returned undefined" and skip re-launch.
119
+ results[k] = slot;
120
+ }
121
+ }
122
+ }
123
+ const runIteration = async (item, index, innerResumeIndex) => {
124
+ const childCtx = this.cloneCtxForIteration(ctx, as, item, index);
125
+ // v0.6 Phase 2 — pass the inner-step resume cursor on the
126
+ // child ctx. Phase 4 — propagate even the index-0 case so
127
+ // the wait-re-entry detection can distinguish a resumed
128
+ // iteration (innerResumeIndex defined) from a fresh one.
129
+ if (innerResumeIndex !== undefined) {
130
+ childCtx._blokInnerResumeIndex = innerResumeIndex;
131
+ }
132
+ const runner = new Runner(steps);
133
+ // `deep: true` — inner pipelines must not inherit the outer
134
+ // run's `lastCompletedStepIndex` cursor (PR 4 wait/resume logic)
135
+ // or every iteration's nested steps get marked "skipped (resumed
136
+ // past wait...)" and the iteration produces no output.
137
+ await runner.run(childCtx, { deep: true, stepName: this.name });
138
+ // After Runner.runSteps, `childCtx.response` is set to the last
139
+ // step's resolved data (RunnerSteps line ~349: `ctx.response =
140
+ // model.data`). So `childCtx.response` IS the iteration's
141
+ // output value, not a wrapped envelope.
142
+ return childCtx.response;
143
+ };
144
+ // v0.6 Phase 4 — push a primitive frame onto the ctx stack so the
145
+ // wait-throw site (and parallel-branch cursor writer) persists
146
+ // THIS forEach's iteration cursor to THIS forEach's NodeRun.
147
+ // Nested primitives (forEach > forEach, switch > forEach, etc.)
148
+ // each push their own frame, which is what unblocks the
149
+ // `forEach > forEach > wait` shape that the Phase 2/3 single-slot
150
+ // machinery couldn't represent.
151
+ const initialCursor = mode === "parallel"
152
+ ? {
153
+ mode: "parallel",
154
+ waitFiringIteration: 0,
155
+ innerStepIndex: 0,
156
+ completedResults: [],
157
+ cancelledIterations: [],
158
+ }
159
+ : { mode: "sequential", iteration: 0, innerStepIndex: 0, completedResults: [] };
160
+ const frame = myNodeRunId
161
+ ? { nodeRunId: myNodeRunId, cursor: initialCursor }
162
+ : undefined;
163
+ if (frame)
164
+ pushPrimitiveFrame(ctx, frame);
165
+ try {
166
+ if (mode === "sequential") {
167
+ // v0.6 Phase 2 — start at the resume iteration if present,
168
+ // else 0. Iterations before the resume index are not re-run;
169
+ // their results were rehydrated above.
170
+ const startIndex = sequentialResume?.iteration ?? 0;
171
+ for (let i = startIndex; i < items.length; i++) {
172
+ // v0.6 Phase 4 — update the frame cursor so a wait fired
173
+ // from inside this iteration body lands the right snapshot
174
+ // in `node_runs.iteration_context`. `completedResults`
175
+ // reflects results-so-far so on resume we don't re-run
176
+ // iterations that already finished before the wait.
177
+ if (frame) {
178
+ const seq = frame.cursor;
179
+ seq.iteration = i;
180
+ seq.completedResults = results.slice(0, i);
181
+ }
182
+ const innerResumeIndex = i === startIndex && sequentialResume !== undefined ? sequentialResume.innerStepIndex : undefined;
183
+ results[i] = await runIteration(items[i], i, innerResumeIndex);
184
+ }
185
+ }
186
+ else {
187
+ // === v0.6 Phase 3 — parallel forEach + wait =====================
188
+ // See `docs/c/devtools/parallel-foreach-wait-spec.mdx`. Headline
189
+ // contract: when one iteration's inner step throws
190
+ // `WaitDispatchRequest`, peer in-flight iterations are
191
+ // cancelled via a pool AbortController. Completed iterations'
192
+ // results are persisted in the cursor's `completedResults`
193
+ // sparse array; cancelled + queued iterations go in
194
+ // `cancelledIterations` for re-launch on resume.
195
+ //
196
+ // The pool AbortController is distinct from `ctx.signal` —
197
+ // tripping it MUST NOT cascade to the parent run (the parent
198
+ // is waiting, not cancelled). Each iteration's child ctx gets
199
+ // a per-iteration signal chained off BOTH the parent's signal
200
+ // (so user-cancel still cascades) AND the pool signal (so
201
+ // peer-wait cascades).
202
+ const poolController = new AbortController();
203
+ const poolSignal = poolController.signal;
204
+ // On resume in parallel mode, the work queue is the set of
205
+ // iterations that need to run: the wait-firing iter (with
206
+ // inner resume hint) + all cancelled/queued iters (from
207
+ // scratch). On a fresh pass, every iteration runs.
208
+ const queue = [];
209
+ if (parallelResume) {
210
+ const toRun = new Set();
211
+ toRun.add(parallelResume.waitFiringIteration);
212
+ for (const idx of parallelResume.cancelledIterations) {
213
+ if (idx < items.length)
214
+ toRun.add(idx);
215
+ }
216
+ // Any iterations beyond `completedResults.length` are
217
+ // trailing-not-started — also need to run.
218
+ for (let i = parallelResume.completedResults.length; i < items.length; i++) {
219
+ if (results[i] === undefined)
220
+ toRun.add(i);
221
+ }
222
+ queue.push(...Array.from(toRun).sort((a, b) => a - b));
223
+ }
224
+ else {
225
+ for (let i = 0; i < items.length; i++)
226
+ queue.push(i);
227
+ }
228
+ let queuePos = 0;
229
+ const workerCount = Math.min(concurrency, queue.length);
230
+ const launchWorker = async () => {
231
+ const outcomes = [];
232
+ while (true) {
233
+ const myQueuePos = queuePos++;
234
+ if (myQueuePos >= queue.length)
235
+ return outcomes;
236
+ const index = queue[myQueuePos];
237
+ // Skip if pool tripped before this iteration started —
238
+ // classify as cancelled without doing any work.
239
+ if (poolSignal.aborted) {
240
+ outcomes.push({ kind: "cancelled", index });
241
+ continue;
242
+ }
243
+ const innerResumeIndex = parallelResume !== undefined && index === parallelResume.waitFiringIteration
244
+ ? parallelResume.innerStepIndex
245
+ : undefined;
246
+ try {
247
+ const result = await runIterationWithPool(item(items, index), index, innerResumeIndex, poolSignal);
248
+ outcomes.push({ kind: "completed", index, result });
249
+ }
250
+ catch (err) {
251
+ if (err instanceof WaitDispatchRequest) {
252
+ // This iteration fired a wait. Trip the pool so
253
+ // peers stop accepting new iterations and exit
254
+ // their current ones at the next step boundary.
255
+ if (!poolSignal.aborted)
256
+ poolController.abort();
257
+ outcomes.push({ kind: "wait", index, throwObj: err });
258
+ }
259
+ else if (err instanceof RunCancelledError) {
260
+ // Distinguish pool-cancel from user-cancel. If
261
+ // poolSignal is aborted AND ctx.signal is NOT,
262
+ // this is a pool-induced cancellation due to a
263
+ // peer's wait — re-runnable. Otherwise it's a
264
+ // user-cancel — re-throw upstream.
265
+ const userCancel = ctx.signal?.aborted === true && !poolSignal.aborted;
266
+ if (userCancel) {
267
+ outcomes.push({ kind: "error", index, err });
268
+ }
269
+ else {
270
+ outcomes.push({ kind: "cancelled", index });
271
+ }
272
+ }
273
+ else {
274
+ // Real error. Trip the pool so peers stop
275
+ // (don't waste CPU on a doomed forEach), then
276
+ // record. Classification later: real errors
277
+ // beat waits.
278
+ if (!poolSignal.aborted)
279
+ poolController.abort();
280
+ outcomes.push({ kind: "error", index, err });
281
+ }
282
+ }
283
+ }
284
+ };
285
+ // Helper — same as `runIteration` but threads the pool signal
286
+ // through to the per-iteration child ctx (so RunnerSteps'
287
+ // between-step abort check sees pool aborts).
288
+ const runIterationWithPool = async (item_, index, innerResumeIndex, poolSig) => {
289
+ const childCtx = this.cloneCtxForIteration(ctx, as, item_, index);
290
+ const iterCtl = new AbortController();
291
+ const listenerCleanup = new AbortController();
292
+ // Chain from parent ctx.signal (user cancel cascade)
293
+ if (ctx.signal) {
294
+ if (ctx.signal.aborted)
295
+ iterCtl.abort();
296
+ else
297
+ ctx.signal.addEventListener("abort", () => {
298
+ if (!iterCtl.signal.aborted)
299
+ iterCtl.abort();
300
+ }, { once: true, signal: listenerCleanup.signal });
301
+ }
302
+ // Chain from pool signal (peer wait cascade)
303
+ if (poolSig.aborted)
304
+ iterCtl.abort();
305
+ else
306
+ poolSig.addEventListener("abort", () => {
307
+ if (!iterCtl.signal.aborted)
308
+ iterCtl.abort();
309
+ }, { once: true, signal: listenerCleanup.signal });
310
+ // Replace the inherited signal (which would be parent's)
311
+ // with the per-iteration signal that cascades both ways.
312
+ childCtx.signal = iterCtl.signal;
313
+ // Phase 4 — propagate the index-0 case too.
314
+ if (innerResumeIndex !== undefined) {
315
+ childCtx._blokInnerResumeIndex = innerResumeIndex;
316
+ }
317
+ try {
318
+ const runner = new Runner(steps);
319
+ await runner.run(childCtx, { deep: true, stepName: this.name });
320
+ return childCtx.response;
321
+ }
322
+ finally {
323
+ // Detach the per-iteration listeners from parent +
324
+ // pool signals (PR 1 A3 pattern — prevents listener
325
+ // accumulation on long-lived parents over many
326
+ // parallel forEach invocations).
327
+ listenerCleanup.abort();
328
+ }
329
+ };
330
+ // Spawn workers. Each returns its set of outcomes (one
331
+ // outcome per iteration the worker handled). `allSettled`
332
+ // gives us each worker's final state; we then flatten.
333
+ const workers = [];
334
+ for (let w = 0; w < workerCount; w++) {
335
+ workers.push(launchWorker());
336
+ }
337
+ const settled = await Promise.allSettled(workers);
338
+ // Flatten. A worker can't reject (its try/catch handles all
339
+ // errors and classifies into the outcome list). But guard
340
+ // defensively — rejection means a bug in launchWorker.
341
+ const allOutcomes = [];
342
+ for (const s of settled) {
343
+ if (s.status === "fulfilled") {
344
+ allOutcomes.push(...s.value);
345
+ }
346
+ else {
347
+ // Defensive — re-throw so the failure isn't lost.
348
+ throw s.reason;
349
+ }
350
+ }
351
+ // Classification step. Walk outcomes:
352
+ // 1. If ANY non-wait error, re-throw the first one (errors
353
+ // beat waits per the spec).
354
+ // 2. If ANY wait, identify the lowest-index wait as the
355
+ // wait-firing iteration; reclassify others as cancelled.
356
+ // 3. Else, all iterations completed — fall through to
357
+ // normal completion below.
358
+ const errors = allOutcomes.filter((o) => o.kind === "error");
359
+ if (errors.length > 0) {
360
+ // First error wins (sorted by iteration index for
361
+ // determinism, even though only one re-throws).
362
+ errors.sort((a, b) => a.index - b.index);
363
+ throw errors[0].err;
364
+ }
365
+ const waits = allOutcomes.filter((o) => o.kind === "wait");
366
+ if (waits.length > 0) {
367
+ // First-wait-wins by iteration index.
368
+ waits.sort((a, b) => a.index - b.index);
369
+ const waitFiring = waits[0];
370
+ // Demote other waits to cancelled (they were racing — only
371
+ // one resumes; the others re-run from scratch).
372
+ const cancelledFromOtherWaits = waits.slice(1).map((w) => w.index);
373
+ const completed = allOutcomes.filter((o) => o.kind === "completed");
374
+ const cancelled = allOutcomes
375
+ .filter((o) => o.kind === "cancelled")
376
+ .map((o) => o.index);
377
+ // Build the sparse completedResults array. Slot k =
378
+ // completed iteration k's return value; null = "ran but
379
+ // returned undefined"; JSON-undefined hole = "not
380
+ // present" (cancelled / queued / wait-firing). On resume,
381
+ // only present-non-undefined slots short-circuit
382
+ // re-launch.
383
+ const completedResults = new Array(items.length);
384
+ for (const c of completed) {
385
+ completedResults[c.index] = c.result === undefined ? null : c.result;
386
+ }
387
+ // Also stash the rehydrated completed iterations from the
388
+ // resume cursor — if we're already on a re-entry pass,
389
+ // those iterations don't appear in `completed` (they
390
+ // were never launched this pass) but their results are
391
+ // in `results[]` from the pre-populate above.
392
+ if (parallelResume) {
393
+ for (let k = 0; k < parallelResume.completedResults.length; k++) {
394
+ if (Object.prototype.hasOwnProperty.call(parallelResume.completedResults, k) &&
395
+ parallelResume.completedResults[k] !== undefined &&
396
+ completedResults[k] === undefined) {
397
+ completedResults[k] = parallelResume.completedResults[k];
398
+ }
399
+ }
400
+ }
401
+ const allCancelled = [...new Set([...cancelled, ...cancelledFromOtherWaits])].sort((a, b) => a - b);
402
+ const cursor = {
403
+ mode: "parallel",
404
+ waitFiringIteration: waitFiring.index,
405
+ // `throwObj.info.stepIndex` carries the inner step index
406
+ // the wait fired at — exactly what we need.
407
+ innerStepIndex: waitFiring.throwObj.info.stepIndex,
408
+ completedResults,
409
+ cancelledIterations: allCancelled,
410
+ };
411
+ // Write the cursor BEFORE re-throwing so TriggerBase's
412
+ // rehydrate (on the next resume) sees the parallel-mode
413
+ // shape. RunnerSteps may have written a sequential-shape
414
+ // cursor at the wait-throw moment (Phase 2 path); this
415
+ // write overwrites it on the same NodeRun id.
416
+ this.writeCursor(ctx, frame, cursor);
417
+ // OTel — record the cancelled count so dashboards can
418
+ // spot workflows that frequently waste work on cancel +
419
+ // re-launch.
420
+ try {
421
+ ForEachWaitMetrics.getInstance().recordCancellation({
422
+ workflowName: ctx.workflow_name ?? "unknown",
423
+ cancelledCount: allCancelled.length,
424
+ });
425
+ }
426
+ catch {
427
+ // Metrics never block.
428
+ }
429
+ // Re-throw the original wait — TriggerBase catches it,
430
+ // schedules the deferred dispatch, returns 202 to HTTP.
431
+ throw waitFiring.throwObj;
432
+ }
433
+ // No waits, no errors — every iteration completed. Populate
434
+ // `results[]` from the completed outcomes.
435
+ for (const o of allOutcomes) {
436
+ if (o.kind === "completed") {
437
+ results[o.index] = o.result;
438
+ }
439
+ }
440
+ }
441
+ response.data = results;
442
+ // Persist to ctx.state[this.name] so downstream steps can read via
443
+ // $.state[id]. Class-based RunnerNode subclasses must call
444
+ // applyStepOutput explicitly (BlokService does it implicitly via
445
+ // its `run()` method, but we own our own run() here).
446
+ applyStepOutput(ctx, this, { data: results });
447
+ return response;
448
+ }
449
+ finally {
450
+ // v0.6 Phase 4 — always pop the frame so sibling primitives
451
+ // later in the workflow don't see a stale cursor pointer, AND
452
+ // so a thrown WaitDispatchRequest unwind doesn't leave the
453
+ // stack in an inconsistent state for the outer runSteps.
454
+ if (frame)
455
+ popPrimitiveFrame(ctx);
456
+ }
457
+ }
458
+ /**
459
+ * Write the parallel cursor to the active forEach NodeRun's frame.
460
+ * Stamped from inside the parallel branch (vs. via RunnerSteps' wait-
461
+ * throw site) because the parallel cursor is built post-
462
+ * `Promise.allSettled` — the wait-throw site doesn't know which peer
463
+ * iterations got cancelled OR which completed.
464
+ *
465
+ * v0.6 Phase 4 — additionally mutates the frame's cursor in place so
466
+ * the wait-throw site (which runs AFTER this, when the throw unwinds
467
+ * back through RunnerSteps) re-persists the same parallel-shape
468
+ * cursor on outer-frame writes. Without the in-place mutation, the
469
+ * outer write would clobber this back to the initial parallel
470
+ * placeholder.
471
+ */
472
+ writeCursor(ctx, frame, cursor) {
473
+ if (!frame)
474
+ return;
475
+ // Replace the in-stack cursor so any subsequent stack walk uses
476
+ // the parallel-shape one we built (not the placeholder pushed at
477
+ // run() entry).
478
+ frame.cursor = cursor;
479
+ const primitiveNodeRunId = frame.nodeRunId;
480
+ try {
481
+ RunTracker.getInstance().getStore().updateNodeRun(primitiveNodeRunId, {
482
+ iterationContext: cursor,
483
+ });
484
+ }
485
+ catch (err) {
486
+ const msg = err instanceof Error ? err.message : String(err);
487
+ ctx.logger.logLevel("warn", `[blok][wait] forEach parallel cursor write failed: ${msg}. Resume will re-run every iteration from scratch.`);
488
+ }
489
+ }
490
+ cloneCtxForIteration(ctx, as, item, index) {
491
+ const baseState = (ctx.state ?? {});
492
+ const state = { ...baseState };
493
+ state[as] = item;
494
+ state[`${as}Index`] = index;
495
+ // Deep-clone config so per-iteration blueprint mapper resolutions
496
+ // don't bleed across iterations (same hazard the v0.4 Configuration
497
+ // deep-clone fix addressed at the workflow level).
498
+ const config = _.cloneDeep(ctx.config);
499
+ const childCtx = {
500
+ ...ctx,
501
+ state,
502
+ vars: state,
503
+ config,
504
+ response: { data: null, success: true, error: null, contentType: "application/json" },
505
+ };
506
+ // v0.5.3 — stash the iteration index on the child ctx so RunnerSteps
507
+ // can propagate it to NodeRun.iterationIndex when starting each
508
+ // inner step. Studio reads this to group sibling rows by iteration
509
+ // (5 iterations × 3 inner steps render as 5 collapsible sections,
510
+ // not 15 flat rows with duplicate names). Overrides any sentinel
511
+ // inherited from a parent iteration scope — the inner-most forEach
512
+ // owns the index its inner steps see.
513
+ childCtx._blokIterationIndex = index;
514
+ return childCtx;
515
+ }
516
+ }
517
+ // Local helper to keep the parallel branch readable when reading
518
+ // `items[index]` from inside an async lambda.
519
+ function item(items, index) {
520
+ return items[index];
521
+ }
522
+ //# sourceMappingURL=ForEachNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ForEachNode.js","sourceRoot":"","sources":["../src/ForEachNode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Thrown when a `loop` step exceeds its `maxIterations` cap. Distinct
3
+ * from generic Error so callers can `instanceof` discriminate (e.g. to
4
+ * route to a tryCatch.catch arm or surface a 500 vs a 408).
5
+ */
6
+ export declare class LoopMaxIterationsError extends Error {
7
+ readonly stepId: string;
8
+ readonly maxIterations: number;
9
+ readonly actualIterations: number;
10
+ constructor(stepId: string, maxIterations: number, actualIterations: number);
11
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Thrown when a `loop` step exceeds its `maxIterations` cap. Distinct
3
+ * from generic Error so callers can `instanceof` discriminate (e.g. to
4
+ * route to a tryCatch.catch arm or surface a 500 vs a 408).
5
+ */
6
+ export class LoopMaxIterationsError extends Error {
7
+ stepId;
8
+ maxIterations;
9
+ actualIterations;
10
+ constructor(stepId, maxIterations, actualIterations) {
11
+ super(`Loop "${stepId}" exceeded maxIterations=${maxIterations} (ran ${actualIterations} times). This is a hard safety cap to prevent infinite loops. Increase the cap if your loop legitimately runs longer, or check the \`while\` condition.`);
12
+ this.name = "LoopMaxIterationsError";
13
+ this.stepId = stepId;
14
+ this.maxIterations = maxIterations;
15
+ this.actualIterations = actualIterations;
16
+ }
17
+ }
18
+ //# sourceMappingURL=LoopMaxIterationsError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoopMaxIterationsError.js","sourceRoot":"","sources":["../src/LoopMaxIterationsError.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAChC,MAAM,CAAS;IACf,aAAa,CAAS;IACtB,gBAAgB,CAAS;IAEzC,YAAY,MAAc,EAAE,aAAqB,EAAE,gBAAwB;QAC1E,KAAK,CACJ,SAAS,MAAM,4BAA4B,aAAa,SAAS,gBAAgB,yJAAyJ,CAC1O,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC1C,CAAC;CACD"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * LoopNode — v0.5 primitive. While-loop with hard maxIterations safety
3
+ * cap. Runs a sub-pipeline as long as the `while` condition evaluates
4
+ * truthy against the live ctx. Each iteration carries forward state
5
+ * mutations (sequential by definition) so condition variables can
6
+ * advance between iterations.
7
+ *
8
+ * The runtime config is read from `ctx.config[this.name]`:
9
+ * {
10
+ * while: string, // JS expression evaluated against ctx
11
+ * maxIterations: number, // hard safety cap; throws LoopMaxIterationsError on hit
12
+ * steps: NodeBase[], // pre-resolved by Configuration's isFlowWithProperties path
13
+ * }
14
+ *
15
+ * The loop counter is exposed as `ctx.state[<stepId>Index]` (0-based)
16
+ * so the `while` expression can reference it. Each iteration's final
17
+ * step output is the loop step's overall data (the last iteration's
18
+ * `ctx.response.data`).
19
+ */
20
+ import type { Context, ResponseContext } from "@blokjs/shared";
21
+ import RunnerNode from "./RunnerNode";
22
+ export declare class LoopNode extends RunnerNode {
23
+ /**
24
+ * v0.6 marker — RunnerSteps stamps `_blokActivePrimitiveNodeRunId`
25
+ * on ctx around `step.process()` calls when this flag is true so a
26
+ * nested wait fired inside an iteration body knows which NodeRun to
27
+ * write its `iteration_context` cursor to. Mirrors ForEachNode's
28
+ * marker (Phase 2). Static `true` (vs an instance method) avoids
29
+ * importing LoopNode inside RunnerSteps, which would create a
30
+ * circular dependency.
31
+ */
32
+ readonly isPrimitiveIterator = true;
33
+ run(ctx: Context): Promise<ResponseContext>;
34
+ private evaluateCondition;
35
+ private cloneCtxForIteration;
36
+ }