@workflow/core 5.0.0-beta.5 → 5.0.0-beta.50

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 (310) hide show
  1. package/dist/attribute-changes.d.ts +5 -0
  2. package/dist/attribute-changes.d.ts.map +1 -0
  3. package/dist/attribute-changes.js +25 -0
  4. package/dist/capabilities.d.ts +35 -2
  5. package/dist/capabilities.d.ts.map +1 -1
  6. package/dist/capabilities.js +74 -5
  7. package/dist/capture-stack.d.ts +1 -1
  8. package/dist/capture-stack.js +2 -2
  9. package/dist/class-serialization.d.ts +32 -0
  10. package/dist/class-serialization.d.ts.map +1 -1
  11. package/dist/class-serialization.js +37 -1
  12. package/dist/classify-error.d.ts +19 -3
  13. package/dist/classify-error.d.ts.map +1 -1
  14. package/dist/classify-error.js +98 -6
  15. package/dist/context-violation-error.d.ts +5 -5
  16. package/dist/context-violation-error.d.ts.map +1 -1
  17. package/dist/context-violation-error.js +8 -6
  18. package/dist/create-hook.d.ts +72 -7
  19. package/dist/create-hook.d.ts.map +1 -1
  20. package/dist/create-hook.js +1 -1
  21. package/dist/define-hook.js +2 -2
  22. package/dist/describe-error.d.ts +7 -7
  23. package/dist/describe-error.d.ts.map +1 -1
  24. package/dist/describe-error.js +97 -12
  25. package/dist/encryption.d.ts +38 -4
  26. package/dist/encryption.d.ts.map +1 -1
  27. package/dist/encryption.js +96 -14
  28. package/dist/events-consumer.d.ts +271 -0
  29. package/dist/events-consumer.d.ts.map +1 -1
  30. package/dist/events-consumer.js +646 -42
  31. package/dist/flushable-stream.d.ts +56 -1
  32. package/dist/flushable-stream.d.ts.map +1 -1
  33. package/dist/flushable-stream.js +123 -11
  34. package/dist/global.d.ts +36 -2
  35. package/dist/global.d.ts.map +1 -1
  36. package/dist/global.js +21 -6
  37. package/dist/index.d.ts +2 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +3 -2
  40. package/dist/log-format.d.ts +2 -2
  41. package/dist/log-format.js +7 -7
  42. package/dist/logger.d.ts +1 -0
  43. package/dist/logger.d.ts.map +1 -1
  44. package/dist/logger.js +10 -6
  45. package/dist/private.d.ts +226 -9
  46. package/dist/private.d.ts.map +1 -1
  47. package/dist/private.js +626 -7
  48. package/dist/replay-payload-cache.d.ts +64 -0
  49. package/dist/replay-payload-cache.d.ts.map +1 -0
  50. package/dist/replay-payload-cache.js +158 -0
  51. package/dist/runtime/compute-instance.d.ts +13 -0
  52. package/dist/runtime/compute-instance.d.ts.map +1 -0
  53. package/dist/runtime/compute-instance.js +14 -0
  54. package/dist/runtime/constants.d.ts +315 -0
  55. package/dist/runtime/constants.d.ts.map +1 -1
  56. package/dist/runtime/constants.js +502 -16
  57. package/dist/runtime/count-step-started-events.d.ts +52 -0
  58. package/dist/runtime/count-step-started-events.d.ts.map +1 -0
  59. package/dist/runtime/count-step-started-events.js +72 -0
  60. package/dist/runtime/deployment-guard.d.ts +99 -0
  61. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  62. package/dist/runtime/deployment-guard.js +154 -0
  63. package/dist/runtime/get-port-lazy.d.ts +15 -0
  64. package/dist/runtime/get-port-lazy.d.ts.map +1 -1
  65. package/dist/runtime/get-port-lazy.js +75 -6
  66. package/dist/runtime/get-world-lazy.d.ts +5 -14
  67. package/dist/runtime/get-world-lazy.d.ts.map +1 -1
  68. package/dist/runtime/get-world-lazy.js +19 -29
  69. package/dist/runtime/helpers.d.ts +341 -29
  70. package/dist/runtime/helpers.d.ts.map +1 -1
  71. package/dist/runtime/helpers.js +559 -57
  72. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  73. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  74. package/dist/runtime/quickjs-assets.generated.js +30 -0
  75. package/dist/runtime/quickjs-entrypoint.d.ts +136 -0
  76. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  77. package/dist/runtime/quickjs-entrypoint.js +1686 -0
  78. package/dist/runtime/quickjs-runtime.d.ts +244 -0
  79. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  80. package/dist/runtime/quickjs-runtime.js +2427 -0
  81. package/dist/runtime/quickjs-serde.d.ts +107 -0
  82. package/dist/runtime/quickjs-serde.d.ts.map +1 -0
  83. package/dist/runtime/quickjs-serde.js +2159 -0
  84. package/dist/runtime/replay-budget.d.ts +97 -0
  85. package/dist/runtime/replay-budget.d.ts.map +1 -0
  86. package/dist/runtime/replay-budget.js +139 -0
  87. package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
  88. package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
  89. package/dist/runtime/replay-recovery-reporter.js +64 -0
  90. package/dist/runtime/resume-hook.d.ts +91 -8
  91. package/dist/runtime/resume-hook.d.ts.map +1 -1
  92. package/dist/runtime/resume-hook.js +512 -89
  93. package/dist/runtime/resume-latency.d.ts +150 -0
  94. package/dist/runtime/resume-latency.d.ts.map +1 -0
  95. package/dist/runtime/resume-latency.js +155 -0
  96. package/dist/runtime/run-id-time.d.ts +19 -0
  97. package/dist/runtime/run-id-time.d.ts.map +1 -0
  98. package/dist/runtime/run-id-time.js +42 -0
  99. package/dist/runtime/run.d.ts +72 -7
  100. package/dist/runtime/run.d.ts.map +1 -1
  101. package/dist/runtime/run.js +280 -53
  102. package/dist/runtime/runs.d.ts +54 -3
  103. package/dist/runtime/runs.d.ts.map +1 -1
  104. package/dist/runtime/runs.js +126 -16
  105. package/dist/runtime/start.d.ts +101 -2
  106. package/dist/runtime/start.d.ts.map +1 -1
  107. package/dist/runtime/start.js +352 -61
  108. package/dist/runtime/step-executor.d.ts +205 -5
  109. package/dist/runtime/step-executor.d.ts.map +1 -1
  110. package/dist/runtime/step-executor.js +760 -127
  111. package/dist/runtime/step-latency.d.ts +220 -0
  112. package/dist/runtime/step-latency.d.ts.map +1 -0
  113. package/dist/runtime/step-latency.js +215 -0
  114. package/dist/runtime/step-ownership.d.ts +72 -0
  115. package/dist/runtime/step-ownership.d.ts.map +1 -0
  116. package/dist/runtime/step-ownership.js +114 -0
  117. package/dist/runtime/step-single-flight.d.ts +12 -0
  118. package/dist/runtime/step-single-flight.d.ts.map +1 -0
  119. package/dist/runtime/step-single-flight.js +75 -0
  120. package/dist/runtime/suspension-handler.d.ts +269 -7
  121. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  122. package/dist/runtime/suspension-handler.js +1253 -125
  123. package/dist/runtime/unserializable-step.d.ts +34 -0
  124. package/dist/runtime/unserializable-step.d.ts.map +1 -0
  125. package/dist/runtime/unserializable-step.js +52 -0
  126. package/dist/runtime/vm-mode.d.ts +44 -0
  127. package/dist/runtime/vm-mode.d.ts.map +1 -0
  128. package/dist/runtime/vm-mode.js +62 -0
  129. package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
  130. package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
  131. package/dist/runtime/vm-serde-bundle.generated.js +16 -0
  132. package/dist/runtime/wait-continuation.d.ts +106 -0
  133. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  134. package/dist/runtime/wait-continuation.js +136 -0
  135. package/dist/runtime/wait-until.d.ts +18 -0
  136. package/dist/runtime/wait-until.d.ts.map +1 -0
  137. package/dist/runtime/wait-until.js +42 -0
  138. package/dist/runtime/world-compatibility.d.ts +32 -0
  139. package/dist/runtime/world-compatibility.d.ts.map +1 -0
  140. package/dist/runtime/world-compatibility.js +44 -0
  141. package/dist/runtime/world-init.d.ts +17 -42
  142. package/dist/runtime/world-init.d.ts.map +1 -1
  143. package/dist/runtime/world-init.js +18 -43
  144. package/dist/runtime/world.d.ts +14 -2
  145. package/dist/runtime/world.d.ts.map +1 -1
  146. package/dist/runtime/world.js +75 -19
  147. package/dist/runtime.d.ts +10 -6
  148. package/dist/runtime.d.ts.map +1 -1
  149. package/dist/runtime.js +3741 -490
  150. package/dist/sealed-box.d.ts +167 -0
  151. package/dist/sealed-box.d.ts.map +1 -0
  152. package/dist/sealed-box.js +571 -0
  153. package/dist/serialization/client.d.ts +3 -3
  154. package/dist/serialization/client.d.ts.map +1 -1
  155. package/dist/serialization/client.js +8 -4
  156. package/dist/serialization/codec-devalue-vm.d.ts +16 -0
  157. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  158. package/dist/serialization/codec-devalue-vm.js +148 -0
  159. package/dist/serialization/codec-devalue.d.ts +1 -1
  160. package/dist/serialization/codec-devalue.d.ts.map +1 -1
  161. package/dist/serialization/codec-devalue.js +24 -6
  162. package/dist/serialization/codec.d.ts +37 -2
  163. package/dist/serialization/codec.d.ts.map +1 -1
  164. package/dist/serialization/codec.js +2 -2
  165. package/dist/serialization/compression.d.ts +105 -0
  166. package/dist/serialization/compression.d.ts.map +1 -0
  167. package/dist/serialization/compression.js +261 -0
  168. package/dist/serialization/encryption.d.ts +119 -17
  169. package/dist/serialization/encryption.d.ts.map +1 -1
  170. package/dist/serialization/encryption.js +152 -17
  171. package/dist/serialization/errors.d.ts +13 -0
  172. package/dist/serialization/errors.d.ts.map +1 -1
  173. package/dist/serialization/errors.js +20 -2
  174. package/dist/serialization/format.d.ts +6 -6
  175. package/dist/serialization/format.js +7 -7
  176. package/dist/serialization/hardened.d.ts +156 -0
  177. package/dist/serialization/hardened.d.ts.map +1 -0
  178. package/dist/serialization/hardened.js +538 -0
  179. package/dist/serialization/index.d.ts +10 -8
  180. package/dist/serialization/index.d.ts.map +1 -1
  181. package/dist/serialization/index.js +10 -8
  182. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  183. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  184. package/dist/serialization/reducers/class-vm.js +77 -0
  185. package/dist/serialization/reducers/class.d.ts.map +1 -1
  186. package/dist/serialization/reducers/class.js +11 -6
  187. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  188. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  189. package/dist/serialization/reducers/common-vm.js +616 -0
  190. package/dist/serialization/reducers/common.d.ts +1 -1
  191. package/dist/serialization/reducers/common.d.ts.map +1 -1
  192. package/dist/serialization/reducers/common.js +202 -62
  193. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  194. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  195. package/dist/serialization/reducers/step-function-vm.js +97 -0
  196. package/dist/serialization/reducers/step-function.d.ts.map +1 -1
  197. package/dist/serialization/reducers/step-function.js +25 -9
  198. package/dist/serialization/step.d.ts +4 -4
  199. package/dist/serialization/step.d.ts.map +1 -1
  200. package/dist/serialization/step.js +9 -5
  201. package/dist/serialization/types.d.ts +80 -1
  202. package/dist/serialization/types.d.ts.map +1 -1
  203. package/dist/serialization/types.js +15 -1
  204. package/dist/serialization/workflow-vm.d.ts +29 -0
  205. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  206. package/dist/serialization/workflow-vm.js +74 -0
  207. package/dist/serialization-format.d.ts +64 -8
  208. package/dist/serialization-format.d.ts.map +1 -1
  209. package/dist/serialization-format.js +225 -73
  210. package/dist/serialization.d.ts +262 -34
  211. package/dist/serialization.d.ts.map +1 -1
  212. package/dist/serialization.js +1879 -274
  213. package/dist/set-attributes.d.ts +13 -0
  214. package/dist/set-attributes.d.ts.map +1 -0
  215. package/dist/set-attributes.js +60 -0
  216. package/dist/source-map.d.ts +25 -0
  217. package/dist/source-map.d.ts.map +1 -1
  218. package/dist/source-map.js +154 -10
  219. package/dist/step/context-storage.d.ts +61 -2
  220. package/dist/step/context-storage.d.ts.map +1 -1
  221. package/dist/step/context-storage.js +7 -5
  222. package/dist/step/writable-stream.d.ts +3 -3
  223. package/dist/step/writable-stream.d.ts.map +1 -1
  224. package/dist/step/writable-stream.js +72 -9
  225. package/dist/step.d.ts.map +1 -1
  226. package/dist/step.js +148 -27
  227. package/dist/symbols.d.ts +50 -0
  228. package/dist/symbols.d.ts.map +1 -1
  229. package/dist/symbols.js +51 -1
  230. package/dist/telemetry/semantic-conventions.d.ts +397 -2
  231. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  232. package/dist/telemetry/semantic-conventions.js +297 -3
  233. package/dist/telemetry.d.ts +91 -0
  234. package/dist/telemetry.d.ts.map +1 -1
  235. package/dist/telemetry.js +244 -17
  236. package/dist/test-support/orchestrator-context.d.ts +25 -0
  237. package/dist/test-support/orchestrator-context.d.ts.map +1 -0
  238. package/dist/test-support/orchestrator-context.js +101 -0
  239. package/dist/types.d.ts +6 -0
  240. package/dist/types.d.ts.map +1 -1
  241. package/dist/types.js +23 -1
  242. package/dist/util.d.ts +0 -5
  243. package/dist/util.d.ts.map +1 -1
  244. package/dist/util.js +1 -15
  245. package/dist/version.d.ts +1 -1
  246. package/dist/version.d.ts.map +1 -1
  247. package/dist/version.js +2 -2
  248. package/dist/vm/index.d.ts.map +1 -1
  249. package/dist/vm/index.js +84 -14
  250. package/dist/vm/script-cache.d.ts +26 -0
  251. package/dist/vm/script-cache.d.ts.map +1 -0
  252. package/dist/vm/script-cache.js +131 -0
  253. package/dist/vm/uint8array-base64.js +1 -1
  254. package/dist/workflow/abort-controller.d.ts +2 -2
  255. package/dist/workflow/abort-controller.d.ts.map +1 -1
  256. package/dist/workflow/abort-controller.js +88 -21
  257. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  258. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  259. package/dist/workflow/attribute-dispatcher.js +45 -0
  260. package/dist/workflow/create-hook.d.ts.map +1 -1
  261. package/dist/workflow/create-hook.js +24 -3
  262. package/dist/workflow/get-workflow-metadata.js +2 -2
  263. package/dist/workflow/hook.d.ts.map +1 -1
  264. package/dist/workflow/hook.js +304 -47
  265. package/dist/workflow/index.d.ts +1 -0
  266. package/dist/workflow/index.d.ts.map +1 -1
  267. package/dist/workflow/index.js +2 -1
  268. package/dist/workflow/set-attributes.d.ts +68 -0
  269. package/dist/workflow/set-attributes.d.ts.map +1 -0
  270. package/dist/workflow/set-attributes.js +60 -0
  271. package/dist/workflow/sleep.d.ts.map +1 -1
  272. package/dist/workflow/sleep.js +58 -12
  273. package/dist/workflow/world-init-stub.d.ts +3 -3
  274. package/dist/workflow/world-init-stub.js +4 -4
  275. package/dist/workflow.d.ts +95 -3
  276. package/dist/workflow.d.ts.map +1 -1
  277. package/dist/workflow.js +895 -561
  278. package/docs/api-reference/create-hook.mdx +89 -10
  279. package/docs/api-reference/create-webhook.mdx +16 -15
  280. package/docs/api-reference/define-hook.mdx +35 -33
  281. package/docs/api-reference/fatal-error.mdx +30 -8
  282. package/docs/api-reference/fetch.mdx +14 -10
  283. package/docs/api-reference/get-step-metadata.mdx +2 -2
  284. package/docs/api-reference/get-workflow-metadata.mdx +3 -3
  285. package/docs/api-reference/get-writable.mdx +7 -7
  286. package/docs/api-reference/index.mdx +4 -1
  287. package/docs/api-reference/retryable-error.mdx +1 -1
  288. package/docs/api-reference/set-attributes.mdx +61 -0
  289. package/docs/api-reference/sleep.mdx +4 -4
  290. package/docs/foundations/cancellation.mdx +31 -32
  291. package/docs/foundations/errors-and-retries.mdx +42 -11
  292. package/docs/foundations/hooks.mdx +64 -35
  293. package/docs/foundations/idempotency.mdx +244 -12
  294. package/docs/foundations/index.mdx +1 -23
  295. package/docs/foundations/meta.json +2 -1
  296. package/docs/foundations/serialization.mdx +21 -22
  297. package/docs/foundations/starting-workflows.mdx +106 -30
  298. package/docs/foundations/streaming.mdx +107 -59
  299. package/docs/foundations/versioning.mdx +263 -0
  300. package/docs/foundations/workflows-and-steps.mdx +9 -9
  301. package/docs/how-it-works/cancellation.mdx +63 -63
  302. package/docs/how-it-works/code-transform.mdx +83 -67
  303. package/docs/how-it-works/encryption.mdx +30 -26
  304. package/docs/how-it-works/event-sourcing.mdx +98 -34
  305. package/docs/how-it-works/framework-integrations.mdx +96 -337
  306. package/docs/how-it-works/understanding-directives.mdx +22 -22
  307. package/package.json +24 -15
  308. package/dist/runtime/step-handler.d.ts +0 -2
  309. package/dist/runtime/step-handler.d.ts.map +0 -1
  310. package/dist/runtime/step-handler.js +0 -776
@@ -0,0 +1,114 @@
1
+ import { getInlineOwnershipLeaseSeconds } from './constants.js';
2
+ /**
3
+ * Inline step ownership helpers for the pending-step dispatch decision table
4
+ * in runtime.ts (workflow#2780). Ownership state itself is derived per-replay
5
+ * from the event log by the step consumer in step.ts and surfaced on
6
+ * StepInvocationQueueItem; these functions interpret that state at dispatch
7
+ * time.
8
+ */
9
+ /**
10
+ * Whether inline step ownership is active for a pending step: created,
11
+ * latest `step_started` carries an owner stamp, and no `step_retrying` has
12
+ * been observed (from `step_retrying` on, the step is queue-owned by its
13
+ * delayed retry handoff / replay requeue, so ownership is permanently
14
+ * lapsed for the correlation ID).
15
+ */
16
+ export function isStepOwnershipActive(step) {
17
+ return (step.hasCreatedEvent === true &&
18
+ step.ownerMessageId !== undefined &&
19
+ step.sawRetrying !== true);
20
+ }
21
+ /**
22
+ * Seconds left on an owned step's liveness lease, anchored at its latest
23
+ * `step_started`. 0 means the lease has expired (or the start timestamp is
24
+ * missing, the degraded mode for worlds whose events lack usable
25
+ * timestamps), in which case dispatch falls back to the immediate enqueue.
26
+ *
27
+ * The result is clamped to the configured lease: `lastStartedAt` is the
28
+ * server-stamped event `createdAt` while `nowMs` is the local clock, so a
29
+ * client running behind the server would otherwise compute a remainder
30
+ * LONGER than the lease itself, and with the lease tuned to the 900s cap,
31
+ * a `delaySeconds` above the queue's per-message maximum, which SQS-backed
32
+ * worlds reject outright (the wake replay's enqueue would throw and ride
33
+ * the redelivery loop). The clamp makes skew strictly harmless; remaining
34
+ * time can never legitimately exceed the full lease anyway.
35
+ */
36
+ export function stepLeaseRemainingSeconds(step, nowMs) {
37
+ if (step.lastStartedAt === undefined)
38
+ return 0;
39
+ const leaseSeconds = getInlineOwnershipLeaseSeconds();
40
+ const remainingMs = step.lastStartedAt + leaseSeconds * 1000 - nowMs;
41
+ return Math.min(leaseSeconds, Math.max(0, Math.ceil(remainingMs / 1000)));
42
+ }
43
+ /**
44
+ * Idempotency key for the delayed backstop wake of an inline-owned step.
45
+ *
46
+ * The key is scoped to the current OWNERSHIP EPOCH (the timestamp of the
47
+ * latest `step_started`), not just the correlation ID. Within one epoch,
48
+ * every wake replay derives the same key, so fan-out stays capped at one
49
+ * pending backstop per step. But when owner recovery re-stamps the step
50
+ * (queue redelivery of the owning message → new `step_started` → new
51
+ * `lastStartedAt`), the key CHANGES. This is load-bearing for liveness:
52
+ * queues dedupe an idempotency key for the lifetime of the original
53
+ * message (including while a delivery of it is in flight), so a backstop
54
+ * that fires during a refreshed lease and tries to re-arm under a fixed key
55
+ * would dedupe against ITSELF and be dropped, leaving no escape hatch if
56
+ * the recovered owner later dies without further redeliveries. The epoch
57
+ * suffix gives the re-arm a fresh key. Pending backstops are bounded by the
58
+ * number of ownership epochs, i.e. the queue's redelivery budget for the
59
+ * owning message.
60
+ *
61
+ * The epoch value comes from the persisted event's `createdAt`, so every
62
+ * replayer derives the same key. Callers only build backstops when the
63
+ * lease has time remaining, which requires `lastStartedAt` to be set.
64
+ *
65
+ * The key must also never be the step message's own `idempotencyKey`
66
+ * (the bare correlation ID): the owner's retry handoff enqueues the step
67
+ * under that key with a short backoff, and a pending backstop sharing it
68
+ * would absorb the retry, turning a 1s backoff into a full-lease stall.
69
+ */
70
+ export function backstopIdempotencyKey(step) {
71
+ return `${step.correlationId}:backstop:${step.lastStartedAt}`;
72
+ }
73
+ /**
74
+ * Whether any of the given pending correlation IDs is inline-owned by
75
+ * `messageId` per the raw event log: its LATEST `step_started` carries
76
+ * `ownerMessageId === messageId` and no `step_retrying` follows it. Used by
77
+ * the background-step fast path, which sees raw events (not the replay's
78
+ * queueItems), to decide whether to fall through to the main loop so this
79
+ * invocation can recover a step it owns instead of returning and leaving it
80
+ * to the delayed backstop.
81
+ */
82
+ export function hasPendingStepOwnedByMessage(events, pendingCorrelationIds, messageId) {
83
+ // Latest-wins scan: events are in log order, so later entries overwrite.
84
+ // A step_retrying lapses ownership permanently (matching the sawRetrying
85
+ // semantics of the replay consumer in step.ts): from that point the step
86
+ // is queue-owned, whatever starts follow.
87
+ const latestOwner = new Map();
88
+ const sawRetrying = new Set();
89
+ for (const e of events) {
90
+ if (e.correlationId === undefined)
91
+ continue;
92
+ if (e.eventType === 'step_started') {
93
+ const owner = 'eventData' in e &&
94
+ e.eventData &&
95
+ 'ownerMessageId' in e.eventData &&
96
+ typeof e.eventData.ownerMessageId === 'string'
97
+ ? e.eventData.ownerMessageId
98
+ : undefined;
99
+ latestOwner.set(e.correlationId, owner);
100
+ }
101
+ else if (e.eventType === 'step_retrying') {
102
+ sawRetrying.add(e.correlationId);
103
+ }
104
+ }
105
+ for (const id of pendingCorrelationIds) {
106
+ if (id !== undefined &&
107
+ !sawRetrying.has(id) &&
108
+ latestOwner.get(id) === messageId) {
109
+ return true;
110
+ }
111
+ }
112
+ return false;
113
+ }
114
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1vd25lcnNoaXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9zdGVwLW93bmVyc2hpcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVoRTs7Ozs7O0dBTUc7QUFFSDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBQUMsSUFBNkI7SUFDakUsT0FBTyxDQUNMLElBQUksQ0FBQyxlQUFlLEtBQUssSUFBSTtRQUM3QixJQUFJLENBQUMsY0FBYyxLQUFLLFNBQVM7UUFDakMsSUFBSSxDQUFDLFdBQVcsS0FBSyxJQUFJLENBQzFCLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLFVBQVUseUJBQXlCLENBQ3ZDLElBQTZCLEVBQzdCLEtBQWE7SUFFYixJQUFJLElBQUksQ0FBQyxhQUFhLEtBQUssU0FBUztRQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQy9DLE1BQU0sWUFBWSxHQUFHLDhCQUE4QixFQUFFLENBQUM7SUFDdEQsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLGFBQWEsR0FBRyxZQUFZLEdBQUcsSUFBSSxHQUFHLEtBQUssQ0FBQztJQUNyRSxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM1RSxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMEJHO0FBQ0gsTUFBTSxVQUFVLHNCQUFzQixDQUFDLElBQTZCO0lBQ2xFLE9BQU8sR0FBRyxJQUFJLENBQUMsYUFBYSxhQUFhLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztBQUNoRSxDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLFVBQVUsNEJBQTRCLENBQzFDLE1BQWUsRUFDZixxQkFBOEMsRUFDOUMsU0FBaUI7SUFFakIseUVBQXlFO0lBQ3pFLHlFQUF5RTtJQUN6RSx5RUFBeUU7SUFDekUsMENBQTBDO0lBQzFDLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUE4QixDQUFDO0lBQzFELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDdEMsS0FBSyxNQUFNLENBQUMsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsQ0FBQyxhQUFhLEtBQUssU0FBUztZQUFFLFNBQVM7UUFDNUMsSUFBSSxDQUFDLENBQUMsU0FBUyxLQUFLLGNBQWMsRUFBRSxDQUFDO1lBQ25DLE1BQU0sS0FBSyxHQUNULFdBQVcsSUFBSSxDQUFDO2dCQUNoQixDQUFDLENBQUMsU0FBUztnQkFDWCxnQkFBZ0IsSUFBSSxDQUFDLENBQUMsU0FBUztnQkFDL0IsT0FBTyxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQWMsS0FBSyxRQUFRO2dCQUM1QyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxjQUFjO2dCQUM1QixDQUFDLENBQUMsU0FBUyxDQUFDO1lBQ2hCLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMxQyxDQUFDO2FBQU0sSUFBSSxDQUFDLENBQUMsU0FBUyxLQUFLLGVBQWUsRUFBRSxDQUFDO1lBQzNDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ25DLENBQUM7SUFDSCxDQUFDO0lBQ0QsS0FBSyxNQUFNLEVBQUUsSUFBSSxxQkFBcUIsRUFBRSxDQUFDO1FBQ3ZDLElBQ0UsRUFBRSxLQUFLLFNBQVM7WUFDaEIsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNwQixXQUFXLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLFNBQVMsRUFDakMsQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEV2ZW50IH0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB0eXBlIHsgU3RlcEludm9jYXRpb25RdWV1ZUl0ZW0gfSBmcm9tICcuLi9nbG9iYWwuanMnO1xuaW1wb3J0IHsgZ2V0SW5saW5lT3duZXJzaGlwTGVhc2VTZWNvbmRzIH0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xuXG4vKipcbiAqIElubGluZSBzdGVwIG93bmVyc2hpcCBoZWxwZXJzIGZvciB0aGUgcGVuZGluZy1zdGVwIGRpc3BhdGNoIGRlY2lzaW9uIHRhYmxlXG4gKiBpbiBydW50aW1lLnRzICh3b3JrZmxvdyMyNzgwKS4gT3duZXJzaGlwIHN0YXRlIGl0c2VsZiBpcyBkZXJpdmVkIHBlci1yZXBsYXlcbiAqIGZyb20gdGhlIGV2ZW50IGxvZyBieSB0aGUgc3RlcCBjb25zdW1lciBpbiBzdGVwLnRzIGFuZCBzdXJmYWNlZCBvblxuICogU3RlcEludm9jYXRpb25RdWV1ZUl0ZW07IHRoZXNlIGZ1bmN0aW9ucyBpbnRlcnByZXQgdGhhdCBzdGF0ZSBhdCBkaXNwYXRjaFxuICogdGltZS5cbiAqL1xuXG4vKipcbiAqIFdoZXRoZXIgaW5saW5lIHN0ZXAgb3duZXJzaGlwIGlzIGFjdGl2ZSBmb3IgYSBwZW5kaW5nIHN0ZXA6IGNyZWF0ZWQsXG4gKiBsYXRlc3QgYHN0ZXBfc3RhcnRlZGAgY2FycmllcyBhbiBvd25lciBzdGFtcCwgYW5kIG5vIGBzdGVwX3JldHJ5aW5nYCBoYXNcbiAqIGJlZW4gb2JzZXJ2ZWQgKGZyb20gYHN0ZXBfcmV0cnlpbmdgIG9uLCB0aGUgc3RlcCBpcyBxdWV1ZS1vd25lZCBieSBpdHNcbiAqIGRlbGF5ZWQgcmV0cnkgaGFuZG9mZiAvIHJlcGxheSByZXF1ZXVlLCBzbyBvd25lcnNoaXAgaXMgcGVybWFuZW50bHlcbiAqIGxhcHNlZCBmb3IgdGhlIGNvcnJlbGF0aW9uIElEKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3RlcE93bmVyc2hpcEFjdGl2ZShzdGVwOiBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSk6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIHN0ZXAuaGFzQ3JlYXRlZEV2ZW50ID09PSB0cnVlICYmXG4gICAgc3RlcC5vd25lck1lc3NhZ2VJZCAhPT0gdW5kZWZpbmVkICYmXG4gICAgc3RlcC5zYXdSZXRyeWluZyAhPT0gdHJ1ZVxuICApO1xufVxuXG4vKipcbiAqIFNlY29uZHMgbGVmdCBvbiBhbiBvd25lZCBzdGVwJ3MgbGl2ZW5lc3MgbGVhc2UsIGFuY2hvcmVkIGF0IGl0cyBsYXRlc3RcbiAqIGBzdGVwX3N0YXJ0ZWRgLiAwIG1lYW5zIHRoZSBsZWFzZSBoYXMgZXhwaXJlZCAob3IgdGhlIHN0YXJ0IHRpbWVzdGFtcCBpc1xuICogbWlzc2luZywgdGhlIGRlZ3JhZGVkIG1vZGUgZm9yIHdvcmxkcyB3aG9zZSBldmVudHMgbGFjayB1c2FibGVcbiAqIHRpbWVzdGFtcHMpLCBpbiB3aGljaCBjYXNlIGRpc3BhdGNoIGZhbGxzIGJhY2sgdG8gdGhlIGltbWVkaWF0ZSBlbnF1ZXVlLlxuICpcbiAqIFRoZSByZXN1bHQgaXMgY2xhbXBlZCB0byB0aGUgY29uZmlndXJlZCBsZWFzZTogYGxhc3RTdGFydGVkQXRgIGlzIHRoZVxuICogc2VydmVyLXN0YW1wZWQgZXZlbnQgYGNyZWF0ZWRBdGAgd2hpbGUgYG5vd01zYCBpcyB0aGUgbG9jYWwgY2xvY2ssIHNvIGFcbiAqIGNsaWVudCBydW5uaW5nIGJlaGluZCB0aGUgc2VydmVyIHdvdWxkIG90aGVyd2lzZSBjb21wdXRlIGEgcmVtYWluZGVyXG4gKiBMT05HRVIgdGhhbiB0aGUgbGVhc2UgaXRzZWxmLCBhbmQgd2l0aCB0aGUgbGVhc2UgdHVuZWQgdG8gdGhlIDkwMHMgY2FwLFxuICogYSBgZGVsYXlTZWNvbmRzYCBhYm92ZSB0aGUgcXVldWUncyBwZXItbWVzc2FnZSBtYXhpbXVtLCB3aGljaCBTUVMtYmFja2VkXG4gKiB3b3JsZHMgcmVqZWN0IG91dHJpZ2h0ICh0aGUgd2FrZSByZXBsYXkncyBlbnF1ZXVlIHdvdWxkIHRocm93IGFuZCByaWRlXG4gKiB0aGUgcmVkZWxpdmVyeSBsb29wKS4gVGhlIGNsYW1wIG1ha2VzIHNrZXcgc3RyaWN0bHkgaGFybWxlc3M7IHJlbWFpbmluZ1xuICogdGltZSBjYW4gbmV2ZXIgbGVnaXRpbWF0ZWx5IGV4Y2VlZCB0aGUgZnVsbCBsZWFzZSBhbnl3YXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdGVwTGVhc2VSZW1haW5pbmdTZWNvbmRzKFxuICBzdGVwOiBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSxcbiAgbm93TXM6IG51bWJlclxuKTogbnVtYmVyIHtcbiAgaWYgKHN0ZXAubGFzdFN0YXJ0ZWRBdCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gMDtcbiAgY29uc3QgbGVhc2VTZWNvbmRzID0gZ2V0SW5saW5lT3duZXJzaGlwTGVhc2VTZWNvbmRzKCk7XG4gIGNvbnN0IHJlbWFpbmluZ01zID0gc3RlcC5sYXN0U3RhcnRlZEF0ICsgbGVhc2VTZWNvbmRzICogMTAwMCAtIG5vd01zO1xuICByZXR1cm4gTWF0aC5taW4obGVhc2VTZWNvbmRzLCBNYXRoLm1heCgwLCBNYXRoLmNlaWwocmVtYWluaW5nTXMgLyAxMDAwKSkpO1xufVxuXG4vKipcbiAqIElkZW1wb3RlbmN5IGtleSBmb3IgdGhlIGRlbGF5ZWQgYmFja3N0b3Agd2FrZSBvZiBhbiBpbmxpbmUtb3duZWQgc3RlcC5cbiAqXG4gKiBUaGUga2V5IGlzIHNjb3BlZCB0byB0aGUgY3VycmVudCBPV05FUlNISVAgRVBPQ0ggKHRoZSB0aW1lc3RhbXAgb2YgdGhlXG4gKiBsYXRlc3QgYHN0ZXBfc3RhcnRlZGApLCBub3QganVzdCB0aGUgY29ycmVsYXRpb24gSUQuIFdpdGhpbiBvbmUgZXBvY2gsXG4gKiBldmVyeSB3YWtlIHJlcGxheSBkZXJpdmVzIHRoZSBzYW1lIGtleSwgc28gZmFuLW91dCBzdGF5cyBjYXBwZWQgYXQgb25lXG4gKiBwZW5kaW5nIGJhY2tzdG9wIHBlciBzdGVwLiBCdXQgd2hlbiBvd25lciByZWNvdmVyeSByZS1zdGFtcHMgdGhlIHN0ZXBcbiAqIChxdWV1ZSByZWRlbGl2ZXJ5IG9mIHRoZSBvd25pbmcgbWVzc2FnZSDihpIgbmV3IGBzdGVwX3N0YXJ0ZWRgIOKGkiBuZXdcbiAqIGBsYXN0U3RhcnRlZEF0YCksIHRoZSBrZXkgQ0hBTkdFUy4gVGhpcyBpcyBsb2FkLWJlYXJpbmcgZm9yIGxpdmVuZXNzOlxuICogcXVldWVzIGRlZHVwZSBhbiBpZGVtcG90ZW5jeSBrZXkgZm9yIHRoZSBsaWZldGltZSBvZiB0aGUgb3JpZ2luYWxcbiAqIG1lc3NhZ2UgKGluY2x1ZGluZyB3aGlsZSBhIGRlbGl2ZXJ5IG9mIGl0IGlzIGluIGZsaWdodCksIHNvIGEgYmFja3N0b3BcbiAqIHRoYXQgZmlyZXMgZHVyaW5nIGEgcmVmcmVzaGVkIGxlYXNlIGFuZCB0cmllcyB0byByZS1hcm0gdW5kZXIgYSBmaXhlZCBrZXlcbiAqIHdvdWxkIGRlZHVwZSBhZ2FpbnN0IElUU0VMRiBhbmQgYmUgZHJvcHBlZCwgbGVhdmluZyBubyBlc2NhcGUgaGF0Y2ggaWZcbiAqIHRoZSByZWNvdmVyZWQgb3duZXIgbGF0ZXIgZGllcyB3aXRob3V0IGZ1cnRoZXIgcmVkZWxpdmVyaWVzLiBUaGUgZXBvY2hcbiAqIHN1ZmZpeCBnaXZlcyB0aGUgcmUtYXJtIGEgZnJlc2gga2V5LiBQZW5kaW5nIGJhY2tzdG9wcyBhcmUgYm91bmRlZCBieSB0aGVcbiAqIG51bWJlciBvZiBvd25lcnNoaXAgZXBvY2hzLCBpLmUuIHRoZSBxdWV1ZSdzIHJlZGVsaXZlcnkgYnVkZ2V0IGZvciB0aGVcbiAqIG93bmluZyBtZXNzYWdlLlxuICpcbiAqIFRoZSBlcG9jaCB2YWx1ZSBjb21lcyBmcm9tIHRoZSBwZXJzaXN0ZWQgZXZlbnQncyBgY3JlYXRlZEF0YCwgc28gZXZlcnlcbiAqIHJlcGxheWVyIGRlcml2ZXMgdGhlIHNhbWUga2V5LiBDYWxsZXJzIG9ubHkgYnVpbGQgYmFja3N0b3BzIHdoZW4gdGhlXG4gKiBsZWFzZSBoYXMgdGltZSByZW1haW5pbmcsIHdoaWNoIHJlcXVpcmVzIGBsYXN0U3RhcnRlZEF0YCB0byBiZSBzZXQuXG4gKlxuICogVGhlIGtleSBtdXN0IGFsc28gbmV2ZXIgYmUgdGhlIHN0ZXAgbWVzc2FnZSdzIG93biBgaWRlbXBvdGVuY3lLZXlgXG4gKiAodGhlIGJhcmUgY29ycmVsYXRpb24gSUQpOiB0aGUgb3duZXIncyByZXRyeSBoYW5kb2ZmIGVucXVldWVzIHRoZSBzdGVwXG4gKiB1bmRlciB0aGF0IGtleSB3aXRoIGEgc2hvcnQgYmFja29mZiwgYW5kIGEgcGVuZGluZyBiYWNrc3RvcCBzaGFyaW5nIGl0XG4gKiB3b3VsZCBhYnNvcmIgdGhlIHJldHJ5LCB0dXJuaW5nIGEgMXMgYmFja29mZiBpbnRvIGEgZnVsbC1sZWFzZSBzdGFsbC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJhY2tzdG9wSWRlbXBvdGVuY3lLZXkoc3RlcDogU3RlcEludm9jYXRpb25RdWV1ZUl0ZW0pOiBzdHJpbmcge1xuICByZXR1cm4gYCR7c3RlcC5jb3JyZWxhdGlvbklkfTpiYWNrc3RvcDoke3N0ZXAubGFzdFN0YXJ0ZWRBdH1gO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgYW55IG9mIHRoZSBnaXZlbiBwZW5kaW5nIGNvcnJlbGF0aW9uIElEcyBpcyBpbmxpbmUtb3duZWQgYnlcbiAqIGBtZXNzYWdlSWRgIHBlciB0aGUgcmF3IGV2ZW50IGxvZzogaXRzIExBVEVTVCBgc3RlcF9zdGFydGVkYCBjYXJyaWVzXG4gKiBgb3duZXJNZXNzYWdlSWQgPT09IG1lc3NhZ2VJZGAgYW5kIG5vIGBzdGVwX3JldHJ5aW5nYCBmb2xsb3dzIGl0LiBVc2VkIGJ5XG4gKiB0aGUgYmFja2dyb3VuZC1zdGVwIGZhc3QgcGF0aCwgd2hpY2ggc2VlcyByYXcgZXZlbnRzIChub3QgdGhlIHJlcGxheSdzXG4gKiBxdWV1ZUl0ZW1zKSwgdG8gZGVjaWRlIHdoZXRoZXIgdG8gZmFsbCB0aHJvdWdoIHRvIHRoZSBtYWluIGxvb3Agc28gdGhpc1xuICogaW52b2NhdGlvbiBjYW4gcmVjb3ZlciBhIHN0ZXAgaXQgb3ducyBpbnN0ZWFkIG9mIHJldHVybmluZyBhbmQgbGVhdmluZyBpdFxuICogdG8gdGhlIGRlbGF5ZWQgYmFja3N0b3AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNQZW5kaW5nU3RlcE93bmVkQnlNZXNzYWdlKFxuICBldmVudHM6IEV2ZW50W10sXG4gIHBlbmRpbmdDb3JyZWxhdGlvbklkczogU2V0PHN0cmluZyB8IHVuZGVmaW5lZD4sXG4gIG1lc3NhZ2VJZDogc3RyaW5nXG4pOiBib29sZWFuIHtcbiAgLy8gTGF0ZXN0LXdpbnMgc2NhbjogZXZlbnRzIGFyZSBpbiBsb2cgb3JkZXIsIHNvIGxhdGVyIGVudHJpZXMgb3ZlcndyaXRlLlxuICAvLyBBIHN0ZXBfcmV0cnlpbmcgbGFwc2VzIG93bmVyc2hpcCBwZXJtYW5lbnRseSAobWF0Y2hpbmcgdGhlIHNhd1JldHJ5aW5nXG4gIC8vIHNlbWFudGljcyBvZiB0aGUgcmVwbGF5IGNvbnN1bWVyIGluIHN0ZXAudHMpOiBmcm9tIHRoYXQgcG9pbnQgdGhlIHN0ZXBcbiAgLy8gaXMgcXVldWUtb3duZWQsIHdoYXRldmVyIHN0YXJ0cyBmb2xsb3cuXG4gIGNvbnN0IGxhdGVzdE93bmVyID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZyB8IHVuZGVmaW5lZD4oKTtcbiAgY29uc3Qgc2F3UmV0cnlpbmcgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgZm9yIChjb25zdCBlIG9mIGV2ZW50cykge1xuICAgIGlmIChlLmNvcnJlbGF0aW9uSWQgPT09IHVuZGVmaW5lZCkgY29udGludWU7XG4gICAgaWYgKGUuZXZlbnRUeXBlID09PSAnc3RlcF9zdGFydGVkJykge1xuICAgICAgY29uc3Qgb3duZXIgPVxuICAgICAgICAnZXZlbnREYXRhJyBpbiBlICYmXG4gICAgICAgIGUuZXZlbnREYXRhICYmXG4gICAgICAgICdvd25lck1lc3NhZ2VJZCcgaW4gZS5ldmVudERhdGEgJiZcbiAgICAgICAgdHlwZW9mIGUuZXZlbnREYXRhLm93bmVyTWVzc2FnZUlkID09PSAnc3RyaW5nJ1xuICAgICAgICAgID8gZS5ldmVudERhdGEub3duZXJNZXNzYWdlSWRcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgIGxhdGVzdE93bmVyLnNldChlLmNvcnJlbGF0aW9uSWQsIG93bmVyKTtcbiAgICB9IGVsc2UgaWYgKGUuZXZlbnRUeXBlID09PSAnc3RlcF9yZXRyeWluZycpIHtcbiAgICAgIHNhd1JldHJ5aW5nLmFkZChlLmNvcnJlbGF0aW9uSWQpO1xuICAgIH1cbiAgfVxuICBmb3IgKGNvbnN0IGlkIG9mIHBlbmRpbmdDb3JyZWxhdGlvbklkcykge1xuICAgIGlmIChcbiAgICAgIGlkICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICFzYXdSZXRyeWluZy5oYXMoaWQpICYmXG4gICAgICBsYXRlc3RPd25lci5nZXQoaWQpID09PSBtZXNzYWdlSWRcbiAgICApIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG4iXX0=
@@ -0,0 +1,12 @@
1
+ import type { StepExecutionResult } from './step-executor.js';
2
+ /**
3
+ * Run `execute` unless an execution for the same run + step correlation ID is
4
+ * already in flight in this process. The winner's result is returned to the
5
+ * winner; a loser awaits the winner's settlement (success OR failure) and
6
+ * then returns `{ type: 'skipped' }` so its caller acks without running the
7
+ * body. A winner failure is not propagated to the loser: the winner's own
8
+ * queue message redelivers and drives the retry, so exactly one message
9
+ * keeps owning the outcome.
10
+ */
11
+ export declare function runStepSingleFlight(runId: string, correlationId: string, execute: () => Promise<StepExecutionResult>): Promise<StepExecutionResult>;
12
+ //# sourceMappingURL=step-single-flight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-single-flight.d.ts","sourceRoot":"","sources":["../../src/runtime/step-single-flight.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAyC9D;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,GAC1C,OAAO,CAAC,mBAAmB,CAAC,CA8B9B"}
@@ -0,0 +1,75 @@
1
+ import { globalSingleton } from '@workflow/utils';
2
+ import { runtimeLogger } from '../logger.js';
3
+ /**
4
+ * In-process single-flight for step body execution, keyed by
5
+ * `runId:correlationId`.
6
+ *
7
+ * This is a required companion to inline step ownership (see
8
+ * `isInlineOwnershipEnabled` in constants.ts): the ownership lease is a
9
+ * *death proof* only on platforms with a bounded invocation lifetime. On
10
+ * worlds without an invocation kill bound (world-local's single process,
11
+ * self-hosted deployments) a delayed backstop can fire while the owning
12
+ * execution is still mid-body, in the same process. This map absorbs that
13
+ * race: the loser awaits the winner's settlement and then acks WITHOUT
14
+ * executing. On Vercel Fluid compute it also absorbs same-instance races
15
+ * between an owner redelivery and a backstop.
16
+ *
17
+ * The loser must not ack-and-skip early (before the winner settles): a crash
18
+ * after an early ack would consume the loser's queue message while the
19
+ * winner's outcome is still unknown, potentially orphaning the step with no
20
+ * message left to drive it. Awaiting settlement first keeps the at-least-once
21
+ * envelope intact: if the loser's own invocation hits its deadline while
22
+ * waiting, its message redelivers and re-checks, degrading gracefully to
23
+ * polling.
24
+ *
25
+ * Cross-instance duplicates (two separate processes racing the same step)
26
+ * are out of scope here; that is what the ownership lease bounds on
27
+ * platforms where it is a death proof, and the documented residual risk on
28
+ * multi-instance self-hosted worlds (mitigate by raising
29
+ * `WORKFLOW_INLINE_OWNERSHIP_LEASE_SECONDS`).
30
+ */
31
+ // On `globalThis` (see `globalSingleton`), not module scope: a per-copy map is
32
+ // not single-flight. Two invocations reaching this module through different
33
+ // bundler layers would each believe they were the only one in the process and
34
+ // both run the step body, degrading in-process dedup to the cross-process
35
+ // residual the doc above scopes out.
36
+ const singleFlight = globalSingleton('@workflow/core//stepSingleFlight', 1, () => ({ inFlight: new Map() }));
37
+ /**
38
+ * Run `execute` unless an execution for the same run + step correlation ID is
39
+ * already in flight in this process. The winner's result is returned to the
40
+ * winner; a loser awaits the winner's settlement (success OR failure) and
41
+ * then returns `{ type: 'skipped' }` so its caller acks without running the
42
+ * body. A winner failure is not propagated to the loser: the winner's own
43
+ * queue message redelivers and drives the retry, so exactly one message
44
+ * keeps owning the outcome.
45
+ */
46
+ export async function runStepSingleFlight(runId, correlationId, execute) {
47
+ const key = `${runId}:${correlationId}`;
48
+ const existing = singleFlight.inFlight.get(key);
49
+ if (existing) {
50
+ // warn (always printed, unlike debug/info): the single-flight is
51
+ // absorbing what would have been a duplicate execution, typically a
52
+ // delayed backstop or retry message landing in the same process while
53
+ // the owner is still mid-body. Rare by design; a burst of these means
54
+ // leases are expiring under live executions (raise
55
+ // WORKFLOW_INLINE_OWNERSHIP_LEASE_SECONDS).
56
+ runtimeLogger.warn('Step execution already in flight in this process; awaiting its settlement instead of executing again', { workflowRunId: runId, stepId: correlationId });
57
+ try {
58
+ await existing;
59
+ }
60
+ catch {
61
+ // The winner failed (typically a transient world error). Its own queue
62
+ // message redelivers and retries; this loser still skips.
63
+ }
64
+ return { type: 'skipped' };
65
+ }
66
+ const promise = execute();
67
+ singleFlight.inFlight.set(key, promise);
68
+ try {
69
+ return await promise;
70
+ }
71
+ finally {
72
+ singleFlight.inFlight.delete(key);
73
+ }
74
+ }
75
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1zaW5nbGUtZmxpZ2h0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvc3RlcC1zaW5nbGUtZmxpZ2h0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRzdDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyQkc7QUFDSCwrRUFBK0U7QUFDL0UsNEVBQTRFO0FBQzVFLDhFQUE4RTtBQUM5RSwwRUFBMEU7QUFDMUUscUNBQXFDO0FBQ3JDLE1BQU0sWUFBWSxHQUFHLGVBQWUsQ0FDbEMsa0NBQWtDLEVBQ2xDLENBQUMsRUFDRCxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLElBQUksR0FBRyxFQUF3QyxFQUFFLENBQUMsQ0FDdEUsQ0FBQztBQUVGOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxtQkFBbUIsQ0FDdkMsS0FBYSxFQUNiLGFBQXFCLEVBQ3JCLE9BQTJDO0lBRTNDLE1BQU0sR0FBRyxHQUFHLEdBQUcsS0FBSyxJQUFJLGFBQWEsRUFBRSxDQUFDO0lBQ3hDLE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2hELElBQUksUUFBUSxFQUFFLENBQUM7UUFDYixpRUFBaUU7UUFDakUsb0VBQW9FO1FBQ3BFLHNFQUFzRTtRQUN0RSxzRUFBc0U7UUFDdEUsbURBQW1EO1FBQ25ELDRDQUE0QztRQUM1QyxhQUFhLENBQUMsSUFBSSxDQUNoQixzR0FBc0csRUFDdEcsRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsQ0FDaEQsQ0FBQztRQUNGLElBQUksQ0FBQztZQUNILE1BQU0sUUFBUSxDQUFDO1FBQ2pCLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCx1RUFBdUU7WUFDdkUsMERBQTBEO1FBQzVELENBQUM7UUFDRCxPQUFPLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyxPQUFPLEVBQUUsQ0FBQztJQUMxQixZQUFZLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDeEMsSUFBSSxDQUFDO1FBQ0gsT0FBTyxNQUFNLE9BQU8sQ0FBQztJQUN2QixDQUFDO1lBQVMsQ0FBQztRQUNULFlBQVksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZ2xvYmFsU2luZ2xldG9uIH0gZnJvbSAnQHdvcmtmbG93L3V0aWxzJztcbmltcG9ydCB7IHJ1bnRpbWVMb2dnZXIgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBTdGVwRXhlY3V0aW9uUmVzdWx0IH0gZnJvbSAnLi9zdGVwLWV4ZWN1dG9yLmpzJztcblxuLyoqXG4gKiBJbi1wcm9jZXNzIHNpbmdsZS1mbGlnaHQgZm9yIHN0ZXAgYm9keSBleGVjdXRpb24sIGtleWVkIGJ5XG4gKiBgcnVuSWQ6Y29ycmVsYXRpb25JZGAuXG4gKlxuICogVGhpcyBpcyBhIHJlcXVpcmVkIGNvbXBhbmlvbiB0byBpbmxpbmUgc3RlcCBvd25lcnNoaXAgKHNlZVxuICogYGlzSW5saW5lT3duZXJzaGlwRW5hYmxlZGAgaW4gY29uc3RhbnRzLnRzKTogdGhlIG93bmVyc2hpcCBsZWFzZSBpcyBhXG4gKiAqZGVhdGggcHJvb2YqIG9ubHkgb24gcGxhdGZvcm1zIHdpdGggYSBib3VuZGVkIGludm9jYXRpb24gbGlmZXRpbWUuIE9uXG4gKiB3b3JsZHMgd2l0aG91dCBhbiBpbnZvY2F0aW9uIGtpbGwgYm91bmQgKHdvcmxkLWxvY2FsJ3Mgc2luZ2xlIHByb2Nlc3MsXG4gKiBzZWxmLWhvc3RlZCBkZXBsb3ltZW50cykgYSBkZWxheWVkIGJhY2tzdG9wIGNhbiBmaXJlIHdoaWxlIHRoZSBvd25pbmdcbiAqIGV4ZWN1dGlvbiBpcyBzdGlsbCBtaWQtYm9keSwgaW4gdGhlIHNhbWUgcHJvY2Vzcy4gVGhpcyBtYXAgYWJzb3JicyB0aGF0XG4gKiByYWNlOiB0aGUgbG9zZXIgYXdhaXRzIHRoZSB3aW5uZXIncyBzZXR0bGVtZW50IGFuZCB0aGVuIGFja3MgV0lUSE9VVFxuICogZXhlY3V0aW5nLiBPbiBWZXJjZWwgRmx1aWQgY29tcHV0ZSBpdCBhbHNvIGFic29yYnMgc2FtZS1pbnN0YW5jZSByYWNlc1xuICogYmV0d2VlbiBhbiBvd25lciByZWRlbGl2ZXJ5IGFuZCBhIGJhY2tzdG9wLlxuICpcbiAqIFRoZSBsb3NlciBtdXN0IG5vdCBhY2stYW5kLXNraXAgZWFybHkgKGJlZm9yZSB0aGUgd2lubmVyIHNldHRsZXMpOiBhIGNyYXNoXG4gKiBhZnRlciBhbiBlYXJseSBhY2sgd291bGQgY29uc3VtZSB0aGUgbG9zZXIncyBxdWV1ZSBtZXNzYWdlIHdoaWxlIHRoZVxuICogd2lubmVyJ3Mgb3V0Y29tZSBpcyBzdGlsbCB1bmtub3duLCBwb3RlbnRpYWxseSBvcnBoYW5pbmcgdGhlIHN0ZXAgd2l0aCBub1xuICogbWVzc2FnZSBsZWZ0IHRvIGRyaXZlIGl0LiBBd2FpdGluZyBzZXR0bGVtZW50IGZpcnN0IGtlZXBzIHRoZSBhdC1sZWFzdC1vbmNlXG4gKiBlbnZlbG9wZSBpbnRhY3Q6IGlmIHRoZSBsb3NlcidzIG93biBpbnZvY2F0aW9uIGhpdHMgaXRzIGRlYWRsaW5lIHdoaWxlXG4gKiB3YWl0aW5nLCBpdHMgbWVzc2FnZSByZWRlbGl2ZXJzIGFuZCByZS1jaGVja3MsIGRlZ3JhZGluZyBncmFjZWZ1bGx5IHRvXG4gKiBwb2xsaW5nLlxuICpcbiAqIENyb3NzLWluc3RhbmNlIGR1cGxpY2F0ZXMgKHR3byBzZXBhcmF0ZSBwcm9jZXNzZXMgcmFjaW5nIHRoZSBzYW1lIHN0ZXApXG4gKiBhcmUgb3V0IG9mIHNjb3BlIGhlcmU7IHRoYXQgaXMgd2hhdCB0aGUgb3duZXJzaGlwIGxlYXNlIGJvdW5kcyBvblxuICogcGxhdGZvcm1zIHdoZXJlIGl0IGlzIGEgZGVhdGggcHJvb2YsIGFuZCB0aGUgZG9jdW1lbnRlZCByZXNpZHVhbCByaXNrIG9uXG4gKiBtdWx0aS1pbnN0YW5jZSBzZWxmLWhvc3RlZCB3b3JsZHMgKG1pdGlnYXRlIGJ5IHJhaXNpbmdcbiAqIGBXT1JLRkxPV19JTkxJTkVfT1dORVJTSElQX0xFQVNFX1NFQ09ORFNgKS5cbiAqL1xuLy8gT24gYGdsb2JhbFRoaXNgIChzZWUgYGdsb2JhbFNpbmdsZXRvbmApLCBub3QgbW9kdWxlIHNjb3BlOiBhIHBlci1jb3B5IG1hcCBpc1xuLy8gbm90IHNpbmdsZS1mbGlnaHQuIFR3byBpbnZvY2F0aW9ucyByZWFjaGluZyB0aGlzIG1vZHVsZSB0aHJvdWdoIGRpZmZlcmVudFxuLy8gYnVuZGxlciBsYXllcnMgd291bGQgZWFjaCBiZWxpZXZlIHRoZXkgd2VyZSB0aGUgb25seSBvbmUgaW4gdGhlIHByb2Nlc3MgYW5kXG4vLyBib3RoIHJ1biB0aGUgc3RlcCBib2R5LCBkZWdyYWRpbmcgaW4tcHJvY2VzcyBkZWR1cCB0byB0aGUgY3Jvc3MtcHJvY2Vzc1xuLy8gcmVzaWR1YWwgdGhlIGRvYyBhYm92ZSBzY29wZXMgb3V0LlxuY29uc3Qgc2luZ2xlRmxpZ2h0ID0gZ2xvYmFsU2luZ2xldG9uKFxuICAnQHdvcmtmbG93L2NvcmUvL3N0ZXBTaW5nbGVGbGlnaHQnLFxuICAxLFxuICAoKSA9PiAoeyBpbkZsaWdodDogbmV3IE1hcDxzdHJpbmcsIFByb21pc2U8U3RlcEV4ZWN1dGlvblJlc3VsdD4+KCkgfSlcbik7XG5cbi8qKlxuICogUnVuIGBleGVjdXRlYCB1bmxlc3MgYW4gZXhlY3V0aW9uIGZvciB0aGUgc2FtZSBydW4gKyBzdGVwIGNvcnJlbGF0aW9uIElEIGlzXG4gKiBhbHJlYWR5IGluIGZsaWdodCBpbiB0aGlzIHByb2Nlc3MuIFRoZSB3aW5uZXIncyByZXN1bHQgaXMgcmV0dXJuZWQgdG8gdGhlXG4gKiB3aW5uZXI7IGEgbG9zZXIgYXdhaXRzIHRoZSB3aW5uZXIncyBzZXR0bGVtZW50IChzdWNjZXNzIE9SIGZhaWx1cmUpIGFuZFxuICogdGhlbiByZXR1cm5zIGB7IHR5cGU6ICdza2lwcGVkJyB9YCBzbyBpdHMgY2FsbGVyIGFja3Mgd2l0aG91dCBydW5uaW5nIHRoZVxuICogYm9keS4gQSB3aW5uZXIgZmFpbHVyZSBpcyBub3QgcHJvcGFnYXRlZCB0byB0aGUgbG9zZXI6IHRoZSB3aW5uZXIncyBvd25cbiAqIHF1ZXVlIG1lc3NhZ2UgcmVkZWxpdmVycyBhbmQgZHJpdmVzIHRoZSByZXRyeSwgc28gZXhhY3RseSBvbmUgbWVzc2FnZVxuICoga2VlcHMgb3duaW5nIHRoZSBvdXRjb21lLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuU3RlcFNpbmdsZUZsaWdodChcbiAgcnVuSWQ6IHN0cmluZyxcbiAgY29ycmVsYXRpb25JZDogc3RyaW5nLFxuICBleGVjdXRlOiAoKSA9PiBQcm9taXNlPFN0ZXBFeGVjdXRpb25SZXN1bHQ+XG4pOiBQcm9taXNlPFN0ZXBFeGVjdXRpb25SZXN1bHQ+IHtcbiAgY29uc3Qga2V5ID0gYCR7cnVuSWR9OiR7Y29ycmVsYXRpb25JZH1gO1xuICBjb25zdCBleGlzdGluZyA9IHNpbmdsZUZsaWdodC5pbkZsaWdodC5nZXQoa2V5KTtcbiAgaWYgKGV4aXN0aW5nKSB7XG4gICAgLy8gd2FybiAoYWx3YXlzIHByaW50ZWQsIHVubGlrZSBkZWJ1Zy9pbmZvKTogdGhlIHNpbmdsZS1mbGlnaHQgaXNcbiAgICAvLyBhYnNvcmJpbmcgd2hhdCB3b3VsZCBoYXZlIGJlZW4gYSBkdXBsaWNhdGUgZXhlY3V0aW9uLCB0eXBpY2FsbHkgYVxuICAgIC8vIGRlbGF5ZWQgYmFja3N0b3Agb3IgcmV0cnkgbWVzc2FnZSBsYW5kaW5nIGluIHRoZSBzYW1lIHByb2Nlc3Mgd2hpbGVcbiAgICAvLyB0aGUgb3duZXIgaXMgc3RpbGwgbWlkLWJvZHkuIFJhcmUgYnkgZGVzaWduOyBhIGJ1cnN0IG9mIHRoZXNlIG1lYW5zXG4gICAgLy8gbGVhc2VzIGFyZSBleHBpcmluZyB1bmRlciBsaXZlIGV4ZWN1dGlvbnMgKHJhaXNlXG4gICAgLy8gV09SS0ZMT1dfSU5MSU5FX09XTkVSU0hJUF9MRUFTRV9TRUNPTkRTKS5cbiAgICBydW50aW1lTG9nZ2VyLndhcm4oXG4gICAgICAnU3RlcCBleGVjdXRpb24gYWxyZWFkeSBpbiBmbGlnaHQgaW4gdGhpcyBwcm9jZXNzOyBhd2FpdGluZyBpdHMgc2V0dGxlbWVudCBpbnN0ZWFkIG9mIGV4ZWN1dGluZyBhZ2FpbicsXG4gICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkLCBzdGVwSWQ6IGNvcnJlbGF0aW9uSWQgfVxuICAgICk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGV4aXN0aW5nO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gVGhlIHdpbm5lciBmYWlsZWQgKHR5cGljYWxseSBhIHRyYW5zaWVudCB3b3JsZCBlcnJvcikuIEl0cyBvd24gcXVldWVcbiAgICAgIC8vIG1lc3NhZ2UgcmVkZWxpdmVycyBhbmQgcmV0cmllczsgdGhpcyBsb3NlciBzdGlsbCBza2lwcy5cbiAgICB9XG4gICAgcmV0dXJuIHsgdHlwZTogJ3NraXBwZWQnIH07XG4gIH1cblxuICBjb25zdCBwcm9taXNlID0gZXhlY3V0ZSgpO1xuICBzaW5nbGVGbGlnaHQuaW5GbGlnaHQuc2V0KGtleSwgcHJvbWlzZSk7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IHByb21pc2U7XG4gIH0gZmluYWxseSB7XG4gICAgc2luZ2xlRmxpZ2h0LmluRmxpZ2h0LmRlbGV0ZShrZXkpO1xuICB9XG59XG4iXX0=
@@ -1,12 +1,89 @@
1
1
  import type { Span } from '@opentelemetry/api';
2
- import { type WorkflowRun, type World } from '@workflow/world';
2
+ import { type SerializedData, type TraceCarrier, type ValidQueueName, type WorkflowRun, type World } from '@workflow/world';
3
3
  import type { StepInvocationQueueItem, WorkflowSuspension } from '../global.js';
4
+ import { type GuestCodeExecution } from '../serialization/hardened.js';
5
+ import { type LoadedEventLog } from './helpers.js';
6
+ import { ReplayRecoveryReporter } from './replay-recovery-reporter.js';
7
+ import type { PreclaimedInlineStart } from './step-executor.js';
4
8
  export interface SuspensionHandlerParams {
5
9
  suspension: WorkflowSuspension;
6
10
  world: World;
7
11
  run: WorkflowRun;
8
12
  span?: Span;
9
13
  requestId?: string;
14
+ /**
15
+ * The runtime's loaded event log. Every event creation this suspension makes
16
+ * names the position it was derived from, so a backend that has recorded
17
+ * events the replay did not see can report them back on the write, or, if
18
+ * it would rather refuse than report, reject it with a 412. A rejection is
19
+ * not retried here: the event's correlation id was minted by *this* replay's
20
+ * seeded sequence, so re-committing it against a corrected log would persist
21
+ * an event no correct replay produces. The caller restarts the replay
22
+ * instead.
23
+ *
24
+ * Extended in place by what those writes report back — the events on slots
25
+ * they skipped over, and (on the hook create) the inline delta since its
26
+ * cursor. Whether the log is complete afterwards is answered by
27
+ * {@link SuspensionHandlerResult.eventLogCarriedForward}.
28
+ */
29
+ eventLog?: LoadedEventLog;
30
+ /**
31
+ * Turbo mode only: a promise that resolves once the backgrounded
32
+ * `run_started` has landed (the run exists). When present, every world write
33
+ * this suspension performs (`hook_created`, `wait_created`, eager overflow
34
+ * `step_created`, …) is gated on it so the write never races ahead of the
35
+ * run's creation. The pure inline hot path defers all of its steps and writes
36
+ * nothing here, so it never awaits this barrier. `undefined` outside turbo,
37
+ * where `run_started` was already awaited up front.
38
+ */
39
+ runReadyBarrier?: Promise<unknown>;
40
+ /** One-shot telemetry reporter, activated only after replay has recovered. */
41
+ replayRecoveryReporter?: ReplayRecoveryReporter;
42
+ /**
43
+ * Resilient step dispatch: when provided (and the per-step eligibility gates
44
+ * pass, see the step ops below), each newly created non-inline step's
45
+ * `step_created` write is parallelized with its step-execution queue
46
+ * publish, and the queue message carries the serialized step input
47
+ * (`stepInput`) so the consumer can idempotently re-ensure the event if the
48
+ * direct write failed transiently. Steps queued this way are reported in
49
+ * {@link SuspensionHandlerResult.queuedStepCorrelationIds} so the caller
50
+ * skips them in its own dispatch pass. Omitted by callers that must not
51
+ * queue (terminal drain, tests); creates then behave exactly as before.
52
+ */
53
+ stepDispatch?: {
54
+ /** The unified workflow queue this run's step messages are published to. */
55
+ queueName: ValidQueueName;
56
+ /**
57
+ * Lazily resolves the trace carrier to stamp on the step messages.
58
+ * Called at most once per suspension (memoized here).
59
+ */
60
+ getTraceCarrier: () => Promise<TraceCarrier>;
61
+ };
62
+ /**
63
+ * Inline step ownership: the queue message ID of the invocation this
64
+ * suspension runs in (the queue handler's meta). When present AND the
65
+ * batched fan-out engages, the lazy-inline steps' deferred writes are
66
+ * folded into the batch as `step_created` + `step_started` pairs (the
67
+ * started row stamped with this ID, exactly like the lazy claim it
68
+ * replaces), pre-claiming the steps the caller is about to run inline. See
69
+ * {@link SuspensionHandlerResult.inlineClaims}. Callers that never
70
+ * inline-execute (terminal drain) omit it, keeping their lazy steps on the
71
+ * plain deferred path.
72
+ */
73
+ ownerMessageId?: string;
74
+ /**
75
+ * Lets the batched fan-out return before every chunk has committed: only
76
+ * the chunk carrying the pre-claimed inline pairs gates the handler's
77
+ * return (its claims are what the caller starts bodies from), while the
78
+ * trailing chunks' commits (and every chunk's in-flush step-message
79
+ * publishes) ride {@link SuspensionHandlerResult.deferredBatchWork}. A
80
+ * caller that opts in MUST await that promise before acking its delivery:
81
+ * the durability contract ("every create durable before ack") moves from
82
+ * the handler's return to that join, and nothing else re-drives a lost
83
+ * trailing chunk. Callers that don't opt in (terminal drain, default)
84
+ * keep the everything-durable-at-return behavior.
85
+ */
86
+ allowDeferredBatchWork?: boolean;
10
87
  }
11
88
  /**
12
89
  * Result of handling a suspension. Returns pending step items so the caller
@@ -19,24 +96,209 @@ export interface SuspensionHandlerResult {
19
96
  * Correlation IDs for which this suspension call actually wrote the
20
97
  * step_created event (as opposed to catching EntityConflictError because
21
98
  * a concurrent handler wrote it first). Only the handler that wrote the
22
- * step_created event should queue / inline-execute the step this
99
+ * step_created event should queue / inline-execute the step; this
23
100
  * guarantees a single owner per step, even when multiple handlers race
24
101
  * into the same batch boundary.
25
102
  */
26
103
  createdStepCorrelationIds: Set<string>;
27
- /** Timeout from waits, if any */
28
- timeoutSeconds?: number;
29
- /** Whether a hook conflict was detected (should re-invoke immediately) */
104
+ /**
105
+ * Correlation IDs of steps whose arguments failed to serialize. Each was
106
+ * finalized here as `step_created` (with a placeholder input; the real
107
+ * input is precisely what refused to serialize) followed by `step_failed`
108
+ * carrying the SerializationError, so the next replay rejects the step's
109
+ * promise and a try/catch around the step call observes the error,
110
+ * exactly like a step-body failure. No step-execution message is
111
+ * dispatched for these, so the caller MUST force an in-process replay:
112
+ * when the failed step was the only pending work, nothing else will ever
113
+ * re-invoke the run to observe the terminal event.
114
+ */
115
+ failedStepCorrelationIds: Set<string>;
116
+ /**
117
+ * Correlation IDs of steps this suspension call already published
118
+ * step-execution queue messages for, via resilient step dispatch (the
119
+ * `step_created` write parallelized with a `stepInput`-carrying queue
120
+ * publish). The caller MUST NOT dispatch these again: the message is
121
+ * already out (a duplicate would be deduped by its idempotency key, but
122
+ * costs a wasted round-trip). Empty when {@link SuspensionHandlerParams.stepDispatch}
123
+ * was not provided or no step was eligible.
124
+ */
125
+ queuedStepCorrelationIds: Set<string>;
126
+ /**
127
+ * How many events this phase's writes reported back as occupying slots they
128
+ * skipped over, already merged into the caller's `eventLog.events`. Nonzero
129
+ * means the array was reordered to restore slot order, so any index the
130
+ * caller cached into it (payload prewarm scan position) is stale.
131
+ */
132
+ reportedEventCount: number;
133
+ /**
134
+ * The steps whose `step_created` writes were intentionally deferred so the
135
+ * caller can run them inline via lazy `step_started` events (which create
136
+ * the step on the fly), saving one world round-trip per inline step. Up to
137
+ * `getMaxInlineSteps()` steps are deferred; the caller runs them inline in
138
+ * parallel and queues the rest. Empty when no step was deferred (nothing
139
+ * pending, or a `hook.getConflict()` awaiter is present so nothing is
140
+ * executed inline). The caller passes each `dehydratedInput` straight to
141
+ * `executeStep`, which sends it as the `step_started` payload. The atomic
142
+ * create-claim inside each `step_started` is the exactly-one-owner gate that
143
+ * the standalone `step_created` provided before: the loser of the race gets
144
+ * `EntityConflictError` → `skipped` and does not run the body.
145
+ */
146
+ lazyInlineSteps: Array<{
147
+ correlationId: string;
148
+ stepName: string;
149
+ dehydratedInput: SerializedData;
150
+ }>;
151
+ /**
152
+ * Pre-claimed inline starts, by correlation id: the per-step verdicts of
153
+ * the `step_created` + `step_started` pairs the batched fan-out committed
154
+ * for the lazy-inline steps. A step with an entry here is passed to
155
+ * `executeStep` as `preclaimedStart` INSTEAD of `lazyStepInput`: its
156
+ * input already rode the pair, and the claim is settled: `owned: true`
157
+ * carries the started attempt-1 entity (input re-attached) so the body
158
+ * runs straight off the batch commit with no start write of its own;
159
+ * `owned: false` lost the pair's atomic create-claim to a concurrent
160
+ * writer, and executeStep returns `skipped` without running the body,
161
+ * the same outcome as losing the lazy claim. Empty whenever the fold did
162
+ * not engage (batching off, no `ownerMessageId`, or the lone-inline case,
163
+ * which keeps the optimistic lazy path and its claim/body overlap).
164
+ *
165
+ * Crash window: the pair commits before the caller runs the body, so a
166
+ * crash between them leaves a started step stamped with this message's
167
+ * ID. Redelivery of the same message re-executes it via the owned-recovery
168
+ * path, the exact machinery the lazy claim's crash window already uses.
169
+ */
170
+ inlineClaims: Map<string, PreclaimedInlineStart>;
171
+ /**
172
+ * The highest slot the batched fan-out committed, when it ran. The batch's
173
+ * own events are not in the caller's loaded log (the next reload picks
174
+ * them up), so the caller folds this ceiling into the slot snapshot it
175
+ * hands the inline executions; otherwise every inline terminal write
176
+ * would name a pre-batch position and be answered with a skipped-slot
177
+ * report echoing the events this suspension just wrote. Under
178
+ * {@link SuspensionHandlerParams.allowDeferredBatchWork} this covers the
179
+ * chunks that had committed by the handler's return (always the pair
180
+ * chunk); a trailing chunk that commits later is echoed back on the
181
+ * terminal writes like any foreign event: reports the executor reads for
182
+ * position and discards.
183
+ *
184
+ * So the echo is only fully suppressed for a SINGLE-chunk fold. On a
185
+ * multi-chunk fan-out the bodies start off the pair chunk while trailing
186
+ * chunks are still in flight, and an inline terminal write issued in that
187
+ * window still names a position below them and still draws a report for
188
+ * their events. Bounded (trailing chunks only, large fan-outs only) and
189
+ * self-correcting on the next reload, and recorded so a report seen there
190
+ * reads as expected rather than as a bug.
191
+ */
192
+ batchCommittedSlotCeiling?: number;
193
+ /**
194
+ * The batched fan-out's deferred work, present only when the caller opted
195
+ * in via {@link SuspensionHandlerParams.allowDeferredBatchWork} and
196
+ * trailing work exists: the commits of every chunk except the pair chunk,
197
+ * plus every chunk's step-message publishes (each chained on ITS OWN
198
+ * chunk's commit, so publish-after-create holds per step). The caller
199
+ * MUST await it before acking: a rejection here is a failed suspension
200
+ * write and fails the delivery exactly as it would have at the handler's
201
+ * return. Steps whose messages this work publishes are already in
202
+ * {@link queuedStepCorrelationIds} at return time.
203
+ */
204
+ deferredBatchWork?: Promise<void>;
205
+ /**
206
+ * The soonest pending wait, if any: seconds until it elapses and the
207
+ * correlationId of the wait that produced that timeout. The
208
+ * correlationId seeds the idempotency key for the wait-continuation
209
+ * queue message so that repeated suspension passes over the same
210
+ * pending wait collapse into a single delayed continuation.
211
+ */
212
+ waitTimeout?: {
213
+ seconds: number;
214
+ correlationId: string;
215
+ };
216
+ /**
217
+ * Whether a hook create committed a `hook_conflict` — the token was already
218
+ * claimed, so this run's hook was never created and the workflow must
219
+ * observe the conflict before anything else this suspension scheduled runs.
220
+ * The caller answers it by advancing the workflow over the committed event.
221
+ */
30
222
  hasHookConflict: boolean;
223
+ /** Whether a `hook.getConflict()` awaiter needs the workflow to continue immediately */
224
+ hasAwaitedHookCreation: boolean;
225
+ /**
226
+ * Correlation ids of the hooks this suspension committed a `hook_created`
227
+ * for while a `hook.getConflict()` awaiter was waiting on it — the events
228
+ * that resolve those awaiters on the next pass. Empty exactly when
229
+ * {@link hasAwaitedHookCreation} is false.
230
+ *
231
+ * Reported by id, not just counted, so a caller that continues in this
232
+ * process can tell a continuation that got somewhere from one that is
233
+ * repeating: a workflow may create one awaited hook after another, and each
234
+ * new id is a pass that made progress, while the same id coming back means
235
+ * the pass ran over a log that still did not hold its event and continuing
236
+ * again cannot change that.
237
+ */
238
+ awaitedHookCorrelationIds: string[];
239
+ /**
240
+ * Correlation ids of the hooks whose create committed a `hook_conflict`.
241
+ * Empty exactly when {@link hasHookConflict} is false.
242
+ *
243
+ * By id for the same reason as {@link awaitedHookCorrelationIds}, and
244
+ * against the same hazard: a conflict is resolved by the `hook_conflict`
245
+ * this suspension committed, and until the workflow observes it the hook
246
+ * stays in the invocations queue and the next pass writes the create again.
247
+ * A fresh id is progress; the same id coming back is a pass that ran over a
248
+ * log which still did not hold the event, so continuing again cannot change
249
+ * that.
250
+ */
251
+ hookConflictCorrelationIds: string[];
252
+ /**
253
+ * Whether the caller's `eventLog` now holds every event this suspension
254
+ * committed, so a caller that continues in this process can replay — or
255
+ * resume a retained VM — straight off it with no read.
256
+ *
257
+ * True only when the hook create's inline delta came back complete and was
258
+ * folded in (see `hookDeltaCursor` below), and nothing else in this
259
+ * suspension wrote an event. False whenever a read is needed first: no
260
+ * delta was asked for or returned, it was truncated, or a step / wait /
261
+ * attribute / abort write landed above it and is therefore not in it.
262
+ *
263
+ * Indifferent to which event the create committed: the delta is the slice
264
+ * of the log after the caller's cursor either way, so it carries a
265
+ * `hook_conflict` exactly as it carries a `hook_created`.
266
+ */
267
+ eventLogCarriedForward: boolean;
268
+ /** Whether native workflow attribute events were written for replay. */
269
+ hasAttributeEvents: boolean;
270
+ /**
271
+ * Whether this suspension created any hook (`hook_created`) events. Unlike
272
+ * `hasHookConflict` / `hasAwaitedHookCreation`, this is true even for a plain
273
+ * fire-and-forget hook with no conflict and no awaiter. Turbo mode uses it to
274
+ * detect "a hook was created this suspension" and stop forcing optimistic
275
+ * inline start (a hook introduces later resume invocations that could race).
276
+ */
277
+ hasHookEvents: boolean;
278
+ /**
279
+ * Wall-clock ms spent committing this suspension's `hook_created` events
280
+ * (0 when it created none). The caller accumulates this across iterations
281
+ * and subtracts it from the TTFS latency measurement, so time spent
282
+ * durably creating the user's hooks doesn't count as runtime overhead.
283
+ */
284
+ hookCreationMs: number;
285
+ /** Exact number of workflow-code executions observed during serialization. */
286
+ serializationBlockerCount: number;
287
+ /** Bounded sample used only for retention diagnostics. */
288
+ serializationBlockers: SuspensionSerializationBlocker[];
289
+ }
290
+ export interface SuspensionSerializationBlocker extends GuestCodeExecution {
291
+ source: 'step_input' | 'hook_metadata' | 'hook_abort';
292
+ correlationId: string;
31
293
  }
32
294
  /**
33
295
  * Handles a workflow suspension by processing all pending operations (hooks, steps, waits).
34
- * Creates events for all operations but does NOT queue step messages returns the pending
296
+ * Creates events for all operations but does NOT queue step messages; returns the pending
35
297
  * steps so the caller can decide which to execute inline vs queue to background.
36
298
  *
37
299
  * Processing order:
38
300
  * 1. Hooks are processed first to prevent race conditions with webhook receivers
39
301
  * 2. Step events and wait events are created in parallel
40
302
  */
41
- export declare function handleSuspension({ suspension, world, run, span, requestId, }: SuspensionHandlerParams): Promise<SuspensionHandlerResult>;
303
+ export declare function handleSuspension({ suspension, world, run, span, requestId, eventLog, runReadyBarrier, replayRecoveryReporter, stepDispatch, ownerMessageId, allowDeferredBatchWork, }: SuspensionHandlerParams): Promise<SuspensionHandlerResult>;
42
304
  //# sourceMappingURL=suspension-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"suspension-handler.d.ts","sourceRoot":"","sources":["../../src/runtime/suspension-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAO/C,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,KAAK,EACX,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAEV,uBAAuB,EAEvB,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAMtB,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,4DAA4D;IAC5D,YAAY,EAAE,uBAAuB,EAAE,CAAC;IACxC;;;;;;;OAOG;IACH,yBAAyB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,iCAAiC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,KAAK,EACL,GAAG,EACH,IAAI,EACJ,SAAS,GACV,EAAE,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAyU5D"}
1
+ {"version":3,"file":"suspension-handler.d.ts","sourceRoot":"","sources":["../../src/runtime/suspension-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAU/C,OAAO,EAKL,KAAK,cAAc,EAMnB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,KAAK,EACX,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAGV,uBAAuB,EAEvB,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,8BAA8B,CAAC;AAetC,OAAO,EAIL,KAAK,cAAc,EAKpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAGhE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,8EAA8E;IAC9E,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE;QACb,4EAA4E;QAC5E,SAAS,EAAE,cAAc,CAAC;QAC1B;;;WAGG;QACH,eAAe,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;KAC9C,CAAC;IACF;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,4DAA4D;IAC5D,YAAY,EAAE,uBAAuB,EAAE,CAAC;IACxC;;;;;;;OAOG;IACH,yBAAyB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC;;;;;;;;;;OAUG;IACH,wBAAwB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtC;;;;;;;;OAQG;IACH,wBAAwB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtC;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;;OAYG;IACH,eAAe,EAAE,KAAK,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,cAAc,CAAC;KACjC,CAAC,CAAC;IACH;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACjD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD;;;;;OAKG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB,wFAAwF;IACxF,sBAAsB,EAAE,OAAO,CAAC;IAChC;;;;;;;;;;;;OAYG;IACH,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC;;;;;;;;;;;OAWG;IACH,0BAA0B,EAAE,MAAM,EAAE,CAAC;IACrC;;;;;;;;;;;;;;OAcG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC,wEAAwE;IACxE,kBAAkB,EAAE,OAAO,CAAC;IAC5B;;;;;;OAMG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,yBAAyB,EAAE,MAAM,CAAC;IAClC,0DAA0D;IAC1D,qBAAqB,EAAE,8BAA8B,EAAE,CAAC;CACzD;AAED,MAAM,WAAW,8BAA+B,SAAQ,kBAAkB;IACxE,MAAM,EAAE,YAAY,GAAG,eAAe,GAAG,YAAY,CAAC;IACtD,aAAa,EAAE,MAAM,CAAC;CACvB;AAwFD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,KAAK,EACL,GAAG,EACH,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,eAAe,EACf,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,sBAAsB,GACvB,EAAE,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA++C5D"}