@workflow/core 5.0.0-beta.3 → 5.0.0-beta.31

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 (268) hide show
  1. package/dist/attribute-changes.d.ts +7 -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 +22 -1
  5. package/dist/capabilities.d.ts.map +1 -1
  6. package/dist/capabilities.js +41 -4
  7. package/dist/capture-stack.d.ts +16 -0
  8. package/dist/capture-stack.d.ts.map +1 -0
  9. package/dist/capture-stack.js +21 -0
  10. package/dist/class-serialization.d.ts +32 -0
  11. package/dist/class-serialization.d.ts.map +1 -1
  12. package/dist/class-serialization.js +37 -1
  13. package/dist/classify-error.d.ts +26 -3
  14. package/dist/classify-error.d.ts.map +1 -1
  15. package/dist/classify-error.js +103 -6
  16. package/dist/context-errors.d.ts +27 -0
  17. package/dist/context-errors.d.ts.map +1 -0
  18. package/dist/context-errors.js +101 -0
  19. package/dist/context-violation-error.d.ts +97 -0
  20. package/dist/context-violation-error.d.ts.map +1 -0
  21. package/dist/context-violation-error.js +147 -0
  22. package/dist/create-hook.d.ts +42 -3
  23. package/dist/create-hook.d.ts.map +1 -1
  24. package/dist/create-hook.js +4 -3
  25. package/dist/define-hook.d.ts.map +1 -1
  26. package/dist/define-hook.js +20 -5
  27. package/dist/describe-error.d.ts +70 -0
  28. package/dist/describe-error.d.ts.map +1 -0
  29. package/dist/describe-error.js +165 -0
  30. package/dist/encryption.d.ts +22 -1
  31. package/dist/encryption.d.ts.map +1 -1
  32. package/dist/encryption.js +72 -27
  33. package/dist/events-consumer.d.ts +25 -1
  34. package/dist/events-consumer.d.ts.map +1 -1
  35. package/dist/events-consumer.js +95 -16
  36. package/dist/flushable-stream.d.ts +10 -10
  37. package/dist/flushable-stream.d.ts.map +1 -1
  38. package/dist/flushable-stream.js +26 -15
  39. package/dist/global.d.ts +35 -1
  40. package/dist/global.d.ts.map +1 -1
  41. package/dist/global.js +21 -3
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +2 -1
  45. package/dist/log-format.d.ts +25 -0
  46. package/dist/log-format.d.ts.map +1 -0
  47. package/dist/log-format.js +250 -0
  48. package/dist/logger.d.ts +29 -30
  49. package/dist/logger.d.ts.map +1 -1
  50. package/dist/logger.js +82 -32
  51. package/dist/private.d.ts +107 -2
  52. package/dist/private.d.ts.map +1 -1
  53. package/dist/private.js +80 -3
  54. package/dist/runtime/constants.d.ts +189 -0
  55. package/dist/runtime/constants.d.ts.map +1 -1
  56. package/dist/runtime/constants.js +310 -15
  57. package/dist/runtime/get-port-lazy.d.ts +25 -0
  58. package/dist/runtime/get-port-lazy.d.ts.map +1 -0
  59. package/dist/runtime/get-port-lazy.js +92 -0
  60. package/dist/runtime/get-world-lazy.d.ts +23 -0
  61. package/dist/runtime/get-world-lazy.d.ts.map +1 -0
  62. package/dist/runtime/get-world-lazy.js +46 -0
  63. package/dist/runtime/helpers.d.ts +57 -6
  64. package/dist/runtime/helpers.d.ts.map +1 -1
  65. package/dist/runtime/helpers.js +169 -32
  66. package/dist/runtime/replay-budget.d.ts +98 -0
  67. package/dist/runtime/replay-budget.d.ts.map +1 -0
  68. package/dist/runtime/replay-budget.js +192 -0
  69. package/dist/runtime/resume-hook.d.ts.map +1 -1
  70. package/dist/runtime/resume-hook.js +39 -23
  71. package/dist/runtime/run-id-time.d.ts +10 -0
  72. package/dist/runtime/run-id-time.d.ts.map +1 -0
  73. package/dist/runtime/run-id-time.js +31 -0
  74. package/dist/runtime/run.d.ts +6 -2
  75. package/dist/runtime/run.d.ts.map +1 -1
  76. package/dist/runtime/run.js +52 -10
  77. package/dist/runtime/runs.d.ts +36 -2
  78. package/dist/runtime/runs.d.ts.map +1 -1
  79. package/dist/runtime/runs.js +18 -7
  80. package/dist/runtime/start.d.ts +58 -1
  81. package/dist/runtime/start.d.ts.map +1 -1
  82. package/dist/runtime/start.js +160 -46
  83. package/dist/runtime/step-executor.d.ts +131 -0
  84. package/dist/runtime/step-executor.d.ts.map +1 -0
  85. package/dist/runtime/step-executor.js +818 -0
  86. package/dist/runtime/step-handler.d.ts.map +1 -1
  87. package/dist/runtime/step-handler.js +718 -557
  88. package/dist/runtime/step-latency.d.ts +131 -0
  89. package/dist/runtime/step-latency.d.ts.map +1 -0
  90. package/dist/runtime/step-latency.js +155 -0
  91. package/dist/runtime/step-ownership.d.ts +72 -0
  92. package/dist/runtime/step-ownership.d.ts.map +1 -0
  93. package/dist/runtime/step-ownership.js +114 -0
  94. package/dist/runtime/step-single-flight.d.ts +12 -0
  95. package/dist/runtime/step-single-flight.d.ts.map +1 -0
  96. package/dist/runtime/step-single-flight.js +69 -0
  97. package/dist/runtime/suspension-handler.d.ts +81 -7
  98. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  99. package/dist/runtime/suspension-handler.js +355 -137
  100. package/dist/runtime/wait-continuation.d.ts +84 -0
  101. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  102. package/dist/runtime/wait-continuation.js +105 -0
  103. package/dist/runtime/wait-until.d.ts +18 -0
  104. package/dist/runtime/wait-until.d.ts.map +1 -0
  105. package/dist/runtime/wait-until.js +42 -0
  106. package/dist/runtime/world-compatibility.d.ts +5 -0
  107. package/dist/runtime/world-compatibility.d.ts.map +1 -0
  108. package/dist/runtime/world-compatibility.js +12 -0
  109. package/dist/runtime/world-init.d.ts +50 -0
  110. package/dist/runtime/world-init.d.ts.map +1 -0
  111. package/dist/runtime/world-init.js +50 -0
  112. package/dist/runtime/world-target.d.ts +11 -0
  113. package/dist/runtime/world-target.d.ts.map +1 -0
  114. package/dist/runtime/world-target.js +15 -0
  115. package/dist/runtime/world.d.ts +21 -9
  116. package/dist/runtime/world.d.ts.map +1 -1
  117. package/dist/runtime/world.js +58 -83
  118. package/dist/runtime.d.ts +15 -10
  119. package/dist/runtime.d.ts.map +1 -1
  120. package/dist/runtime.js +1757 -326
  121. package/dist/schemas.d.ts +1 -1
  122. package/dist/schemas.d.ts.map +1 -1
  123. package/dist/schemas.js +1 -1
  124. package/dist/serialization/client.d.ts +17 -0
  125. package/dist/serialization/client.d.ts.map +1 -0
  126. package/dist/serialization/client.js +48 -0
  127. package/dist/serialization/codec-devalue.d.ts +14 -0
  128. package/dist/serialization/codec-devalue.d.ts.map +1 -0
  129. package/dist/serialization/codec-devalue.js +98 -0
  130. package/dist/serialization/codec.d.ts +106 -0
  131. package/dist/serialization/codec.d.ts.map +1 -0
  132. package/dist/serialization/codec.js +17 -0
  133. package/dist/serialization/compression.d.ts +104 -0
  134. package/dist/serialization/compression.d.ts.map +1 -0
  135. package/dist/serialization/compression.js +260 -0
  136. package/dist/serialization/encryption.d.ts +33 -0
  137. package/dist/serialization/encryption.d.ts.map +1 -0
  138. package/dist/serialization/encryption.js +70 -0
  139. package/dist/serialization/errors.d.ts +34 -0
  140. package/dist/serialization/errors.d.ts.map +1 -0
  141. package/dist/serialization/errors.js +59 -0
  142. package/dist/serialization/format.d.ts +60 -0
  143. package/dist/serialization/format.d.ts.map +1 -0
  144. package/dist/serialization/format.js +97 -0
  145. package/dist/serialization/index.d.ts +19 -0
  146. package/dist/serialization/index.d.ts.map +1 -0
  147. package/dist/serialization/index.js +22 -0
  148. package/dist/serialization/reducers/class.d.ts +11 -0
  149. package/dist/serialization/reducers/class.d.ts.map +1 -0
  150. package/dist/serialization/reducers/class.js +68 -0
  151. package/dist/serialization/reducers/common.d.ts +16 -0
  152. package/dist/serialization/reducers/common.d.ts.map +1 -0
  153. package/dist/serialization/reducers/common.js +417 -0
  154. package/dist/serialization/reducers/step-function.d.ts +35 -0
  155. package/dist/serialization/reducers/step-function.d.ts.map +1 -0
  156. package/dist/serialization/reducers/step-function.js +88 -0
  157. package/dist/serialization/step.d.ts +17 -0
  158. package/dist/serialization/step.d.ts.map +1 -0
  159. package/dist/serialization/step.js +48 -0
  160. package/dist/serialization/types.d.ts +253 -0
  161. package/dist/serialization/types.d.ts.map +1 -0
  162. package/dist/serialization/types.js +25 -0
  163. package/dist/serialization/workflow.d.ts +29 -0
  164. package/dist/serialization/workflow.d.ts.map +1 -0
  165. package/dist/serialization/workflow.js +54 -0
  166. package/dist/serialization-format.d.ts +16 -0
  167. package/dist/serialization-format.d.ts.map +1 -1
  168. package/dist/serialization-format.js +213 -50
  169. package/dist/serialization.d.ts +322 -214
  170. package/dist/serialization.d.ts.map +1 -1
  171. package/dist/serialization.js +1575 -664
  172. package/dist/set-attributes.d.ts +18 -0
  173. package/dist/set-attributes.d.ts.map +1 -0
  174. package/dist/set-attributes.js +61 -0
  175. package/dist/sleep.d.ts.map +1 -1
  176. package/dist/sleep.js +3 -2
  177. package/dist/source-map.d.ts +5 -0
  178. package/dist/source-map.d.ts.map +1 -1
  179. package/dist/source-map.js +102 -10
  180. package/dist/step/context-storage.d.ts +53 -0
  181. package/dist/step/context-storage.d.ts.map +1 -1
  182. package/dist/step/context-storage.js +1 -1
  183. package/dist/step/get-closure-vars.d.ts.map +1 -1
  184. package/dist/step/get-closure-vars.js +3 -2
  185. package/dist/step/get-step-metadata.d.ts.map +1 -1
  186. package/dist/step/get-step-metadata.js +3 -2
  187. package/dist/step/get-workflow-metadata.d.ts.map +1 -1
  188. package/dist/step/get-workflow-metadata.js +3 -2
  189. package/dist/step/writable-stream.d.ts.map +1 -1
  190. package/dist/step/writable-stream.js +58 -6
  191. package/dist/step-hydration-cache.d.ts +148 -0
  192. package/dist/step-hydration-cache.d.ts.map +1 -0
  193. package/dist/step-hydration-cache.js +171 -0
  194. package/dist/step.d.ts.map +1 -1
  195. package/dist/step.js +144 -25
  196. package/dist/symbols.d.ts +28 -0
  197. package/dist/symbols.d.ts.map +1 -1
  198. package/dist/symbols.js +29 -1
  199. package/dist/telemetry/semantic-conventions.d.ts +98 -2
  200. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  201. package/dist/telemetry/semantic-conventions.js +66 -1
  202. package/dist/telemetry.d.ts +68 -0
  203. package/dist/telemetry.d.ts.map +1 -1
  204. package/dist/telemetry.js +106 -4
  205. package/dist/types.d.ts +6 -0
  206. package/dist/types.d.ts.map +1 -1
  207. package/dist/types.js +23 -1
  208. package/dist/util.d.ts +16 -6
  209. package/dist/util.d.ts.map +1 -1
  210. package/dist/util.js +25 -16
  211. package/dist/version.d.ts +1 -1
  212. package/dist/version.d.ts.map +1 -1
  213. package/dist/version.js +2 -2
  214. package/dist/vm/index.d.ts.map +1 -1
  215. package/dist/vm/index.js +3 -2
  216. package/dist/vm/script-cache.d.ts +28 -0
  217. package/dist/vm/script-cache.d.ts.map +1 -0
  218. package/dist/vm/script-cache.js +140 -0
  219. package/dist/workflow/abort-controller.d.ts +65 -0
  220. package/dist/workflow/abort-controller.d.ts.map +1 -0
  221. package/dist/workflow/abort-controller.js +277 -0
  222. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  223. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  224. package/dist/workflow/attribute-dispatcher.js +48 -0
  225. package/dist/workflow/create-hook.d.ts.map +1 -1
  226. package/dist/workflow/create-hook.js +25 -3
  227. package/dist/workflow/define-hook.d.ts +1 -1
  228. package/dist/workflow/define-hook.d.ts.map +1 -1
  229. package/dist/workflow/define-hook.js +8 -4
  230. package/dist/workflow/get-workflow-metadata.d.ts.map +1 -1
  231. package/dist/workflow/get-workflow-metadata.js +14 -3
  232. package/dist/workflow/hook.d.ts.map +1 -1
  233. package/dist/workflow/hook.js +207 -33
  234. package/dist/workflow/index.d.ts +1 -0
  235. package/dist/workflow/index.d.ts.map +1 -1
  236. package/dist/workflow/index.js +5 -3
  237. package/dist/workflow/set-attributes.d.ts +77 -0
  238. package/dist/workflow/set-attributes.d.ts.map +1 -0
  239. package/dist/workflow/set-attributes.js +65 -0
  240. package/dist/workflow/sleep.d.ts.map +1 -1
  241. package/dist/workflow/sleep.js +45 -8
  242. package/dist/workflow/world-init-stub.d.ts +15 -0
  243. package/dist/workflow/world-init-stub.d.ts.map +1 -0
  244. package/dist/workflow/world-init-stub.js +15 -0
  245. package/dist/workflow.d.ts +17 -1
  246. package/dist/workflow.d.ts.map +1 -1
  247. package/dist/workflow.js +190 -56
  248. package/docs/api-reference/create-hook.mdx +38 -0
  249. package/docs/api-reference/create-webhook.mdx +1 -0
  250. package/docs/api-reference/fetch.mdx +5 -0
  251. package/docs/api-reference/index.mdx +3 -0
  252. package/docs/api-reference/set-attributes.mdx +65 -0
  253. package/docs/foundations/cancellation.mdx +459 -0
  254. package/docs/foundations/errors-and-retries.mdx +7 -3
  255. package/docs/foundations/hooks.mdx +29 -0
  256. package/docs/foundations/idempotency.mdx +236 -11
  257. package/docs/foundations/index.mdx +1 -23
  258. package/docs/foundations/meta.json +3 -1
  259. package/docs/foundations/serialization.mdx +77 -41
  260. package/docs/foundations/starting-workflows.mdx +5 -1
  261. package/docs/foundations/streaming.mdx +14 -23
  262. package/docs/foundations/versioning.mdx +263 -0
  263. package/docs/how-it-works/cancellation.mdx +287 -0
  264. package/docs/how-it-works/code-transform.mdx +2 -2
  265. package/docs/how-it-works/encryption.mdx +2 -2
  266. package/docs/how-it-works/event-sourcing.mdx +2 -2
  267. package/docs/how-it-works/meta.json +2 -1
  268. package/package.json +32 -11
@@ -0,0 +1,131 @@
1
+ import type { Event } from '@workflow/world';
2
+ /**
3
+ * Client-side latency measurement (TTFS / STSO) threaded from the
4
+ * orchestrator's inline execution path into `executeStep`.
5
+ *
6
+ * TTFS (time-to-first-step) measures run creation → the first step's body
7
+ * beginning to execute. STSO (step-to-step overhead) measures the previous
8
+ * step's terminal event → the next step's body beginning to execute. Both are
9
+ * attached to the step's terminal event so a backend can emit latency metrics
10
+ * from the event write alone, without extra event-log queries.
11
+ *
12
+ * Eligibility is decided by the orchestrator (which owns the event log) via
13
+ * {@link computeStepLatencyTracking}; the final values are computed by
14
+ * `executeStep` right before user code runs via
15
+ * {@link computeStepLatencyEventData}.
16
+ */
17
+ export interface StepLatencyTracking {
18
+ /**
19
+ * Epoch ms of run creation (from the run-id ULID, falling back to the run
20
+ * snapshot's `createdAt`). Present only when the step qualifies for TTFS.
21
+ */
22
+ ttfsAnchorMs?: number;
23
+ /**
24
+ * Wall-clock ms this invocation spent committing `hook_created` events
25
+ * before the first step (fire-and-forget `createHook()` ahead of the first
26
+ * step commits in the same suspension batch). Subtracted from TTFS so the
27
+ * metric reflects runtime overhead rather than the user's hook writes.
28
+ */
29
+ preStepBlockingMs?: number;
30
+ /**
31
+ * Epoch ms the first pre-step `attr_set` write began (its client-stamped
32
+ * `occurredAt`, falling back to `createdAt`). When present, the TTFS
33
+ * measurement ENDS here instead of at the step's code start: a
34
+ * workflow-body `setAttributes` before the first step
35
+ * resolves through an extra replay (see the `hasAttributeEvents` branch in
36
+ * runtime.ts), so everything from this write until the step body runs is
37
+ * the duration of the setAttributes call — which is subtracted by ending
38
+ * the measurement at the point where the step would otherwise have been
39
+ * scheduled.
40
+ */
41
+ preStepAttrStartMs?: number;
42
+ /**
43
+ * Epoch ms the previous step's terminal event was recorded (its
44
+ * client-stamped `occurredAt`, falling back to `createdAt`). Present only
45
+ * when the step qualifies for STSO.
46
+ */
47
+ prevStepEndMs?: number;
48
+ /** Number of unique terminal steps already in the event log. */
49
+ stepCount?: number;
50
+ /** Number of events already in the event log. */
51
+ eventCount?: number;
52
+ /** Whether turbo mode is active for this invocation. */
53
+ turbo: boolean;
54
+ }
55
+ /** Latency telemetry attached to a step's terminal event's `eventData`. */
56
+ export interface StepLatencyEventData {
57
+ ttfs?: number;
58
+ stso?: number;
59
+ stepCount?: number;
60
+ eventCount?: number;
61
+ optimizations?: string[];
62
+ }
63
+ /**
64
+ * Decide, from the orchestrator's view of the event log, whether the inline
65
+ * step batch about to execute qualifies for TTFS and/or STSO measurement.
66
+ * Returns undefined when neither applies. Called once per batch; the result
67
+ * is passed to the batch's first step only, so a parallel first batch emits a
68
+ * single sample rather than one per sibling.
69
+ */
70
+ export declare function computeStepLatencyTracking(params: {
71
+ /** The orchestrator's current in-memory event log (ascending order). */
72
+ events: Event[];
73
+ /**
74
+ * Whether this invocation's initial event load contained nothing beyond
75
+ * run_created/run_started/attr_set. Pre-existing hook events were written
76
+ * by an earlier invocation, so the time they added (including the queue
77
+ * hop back to this invocation) is unmeasurable and disqualifies TTFS.
78
+ * attr_set is permitted: a redelivery can land after a committed pre-step
79
+ * attr_set, and the detour it marks is subtracted via `preStepAttrStartMs`
80
+ * regardless of which invocation wrote it.
81
+ */
82
+ invocationStartedClean: boolean;
83
+ /** Epoch ms of run creation, if recoverable. Absent disqualifies TTFS. */
84
+ runCreatedAtMs: number | undefined;
85
+ /** See {@link StepLatencyTracking.preStepBlockingMs}. */
86
+ preStepBlockingMs: number;
87
+ /**
88
+ * The accumulator's value as of the suspension that wrote the run's first
89
+ * attr_set (its hook phase runs before its attr writes). When the
90
+ * measurement ends at the attr write, only hook time from before that
91
+ * point may be subtracted — later hook writes fall outside the measured
92
+ * window. Undefined when no attr suspension happened in this invocation
93
+ * (e.g. the attr_set was loaded from a redelivery's snapshot, where no
94
+ * same-invocation hook time precedes it).
95
+ */
96
+ preStepBlockingBeforeAttrMs: number | undefined;
97
+ /**
98
+ * Whether the suspension that scheduled this batch also created waits.
99
+ * Those `wait_created` writes are not in `events` yet (they were committed
100
+ * by this very suspension pass), so they must be reported separately. A
101
+ * wait disqualifies both measurements.
102
+ */
103
+ suspensionHasWaits: boolean;
104
+ /**
105
+ * Whether the suspension that scheduled this batch also created hooks
106
+ * (also not in `events` yet). Hooks keep TTFS eligible — their measured
107
+ * write time is subtracted via `preStepBlockingMs` — but disqualify STSO,
108
+ * which is only meaningful for a pure back-to-back step gap.
109
+ */
110
+ suspensionCreatedHooks: boolean;
111
+ /** Whether turbo mode is active for this invocation. */
112
+ turbo: boolean;
113
+ }): StepLatencyTracking | undefined;
114
+ /**
115
+ * Compute the latency telemetry to attach to the step's terminal event.
116
+ * Called by `executeStep` with the wall-clock timestamp taken immediately
117
+ * before user step code runs. Returns undefined when there is nothing to
118
+ * report (no tracking, or a retry attempt — retries measure neither TTFS nor
119
+ * STSO).
120
+ */
121
+ export declare function computeStepLatencyEventData(params: {
122
+ tracking: StepLatencyTracking | undefined;
123
+ /** `Date.now()` taken immediately before user step code began executing. */
124
+ stepCodeStartedAtMs: number;
125
+ attempt: number;
126
+ /** Whether this step was started lazily (no separate step_created write). */
127
+ lazyStepStart: boolean;
128
+ /** Whether the body ran optimistically, without awaiting step_started. */
129
+ optimisticStart: boolean;
130
+ }): StepLatencyEventData | undefined;
131
+ //# sourceMappingURL=step-latency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-latency.d.ts","sourceRoot":"","sources":["../../src/runtime/step-latency.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,2EAA2E;AAC3E,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAkCD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,wEAAwE;IACxE,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB;;;;;;;;OAQG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC,0EAA0E;IAC1E,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,yDAAyD;IACzD,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;;;;;OAQG;IACH,2BAA2B,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD;;;;;OAKG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAC5B;;;;;OAKG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC,wDAAwD;IACxD,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,mBAAmB,GAAG,SAAS,CA4ElC;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,QAAQ,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC1C,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,aAAa,EAAE,OAAO,CAAC;IACvB,0EAA0E;IAC1E,eAAe,EAAE,OAAO,CAAC;CAC1B,GAAG,oBAAoB,GAAG,SAAS,CAiDnC"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Event types that disqualify TTFS when present in the event log at the time
3
+ * the run's first step batch is scheduled:
4
+ *
5
+ * - Any step event means this is not the run's first step execution.
6
+ * - `hook_received` / `wait_created` / `wait_completed` mean the run's path to
7
+ * the first step depended on user-driven timing (a webhook arriving, a
8
+ * sleep elapsing), so the measurement would not reflect runtime overhead.
9
+ *
10
+ * Deliberately absent, with their cost subtracted instead:
11
+ *
12
+ * - `hook_created`: a fire-and-forget `createHook()` before the first step
13
+ * commits in the same invocation, whose measured duration is subtracted via
14
+ * {@link StepLatencyTracking.preStepBlockingMs}.
15
+ * - `attr_set` (workflow-body `setAttributes`): resolves through
16
+ * an extra replay before steps run. Subtracted by ending the measurement at
17
+ * the first attr write's timestamp instead — see
18
+ * {@link StepLatencyTracking.preStepAttrStartMs}.
19
+ */
20
+ const TTFS_DISQUALIFYING_EVENT_TYPES = new Set([
21
+ 'step_created',
22
+ 'step_started',
23
+ 'step_completed',
24
+ 'step_failed',
25
+ 'step_retrying',
26
+ 'hook_received',
27
+ 'wait_created',
28
+ 'wait_completed',
29
+ ]);
30
+ /**
31
+ * Decide, from the orchestrator's view of the event log, whether the inline
32
+ * step batch about to execute qualifies for TTFS and/or STSO measurement.
33
+ * Returns undefined when neither applies. Called once per batch; the result
34
+ * is passed to the batch's first step only, so a parallel first batch emits a
35
+ * single sample rather than one per sibling.
36
+ */
37
+ export function computeStepLatencyTracking(params) {
38
+ const { events } = params;
39
+ let ttfsEligible = params.invocationStartedClean &&
40
+ params.runCreatedAtMs !== undefined &&
41
+ !params.suspensionHasWaits;
42
+ let preStepAttrStartMs;
43
+ if (ttfsEligible) {
44
+ for (const event of events) {
45
+ if (TTFS_DISQUALIFYING_EVENT_TYPES.has(event.eventType)) {
46
+ ttfsEligible = false;
47
+ break;
48
+ }
49
+ if (event.eventType === 'attr_set') {
50
+ const attrStartMs = +(event.occurredAt ?? event.createdAt);
51
+ preStepAttrStartMs =
52
+ preStepAttrStartMs === undefined
53
+ ? attrStartMs
54
+ : Math.min(preStepAttrStartMs, attrStartMs);
55
+ }
56
+ }
57
+ }
58
+ // STSO: the two steps ran back-to-back — the newest known event is the
59
+ // previous step's terminal event, with nothing (hook_received, waits,
60
+ // attr_set, ...) in between and this suspension scheduling nothing but
61
+ // steps.
62
+ let prevStepEndMs;
63
+ let stepCount;
64
+ let eventCount;
65
+ const lastEvent = events[events.length - 1];
66
+ if (!params.suspensionHasWaits &&
67
+ !params.suspensionCreatedHooks &&
68
+ lastEvent &&
69
+ (lastEvent.eventType === 'step_completed' ||
70
+ lastEvent.eventType === 'step_failed')) {
71
+ prevStepEndMs = +(lastEvent.occurredAt ?? lastEvent.createdAt);
72
+ const terminalStepIds = new Set();
73
+ for (const event of events) {
74
+ if ((event.eventType === 'step_completed' ||
75
+ event.eventType === 'step_failed') &&
76
+ event.correlationId !== undefined) {
77
+ terminalStepIds.add(event.correlationId);
78
+ }
79
+ }
80
+ stepCount = terminalStepIds.size;
81
+ eventCount = events.length;
82
+ }
83
+ if (!ttfsEligible && prevStepEndMs === undefined) {
84
+ return undefined;
85
+ }
86
+ return {
87
+ ...(ttfsEligible
88
+ ? {
89
+ ttfsAnchorMs: params.runCreatedAtMs,
90
+ // When the measurement ends at the first attr write, only hook
91
+ // time from before that point is inside the measured window.
92
+ preStepBlockingMs: preStepAttrStartMs !== undefined
93
+ ? (params.preStepBlockingBeforeAttrMs ?? 0)
94
+ : params.preStepBlockingMs,
95
+ ...(preStepAttrStartMs !== undefined ? { preStepAttrStartMs } : {}),
96
+ }
97
+ : {}),
98
+ ...(prevStepEndMs !== undefined
99
+ ? { prevStepEndMs, stepCount, eventCount }
100
+ : {}),
101
+ turbo: params.turbo,
102
+ };
103
+ }
104
+ /**
105
+ * Compute the latency telemetry to attach to the step's terminal event.
106
+ * Called by `executeStep` with the wall-clock timestamp taken immediately
107
+ * before user step code runs. Returns undefined when there is nothing to
108
+ * report (no tracking, or a retry attempt — retries measure neither TTFS nor
109
+ * STSO).
110
+ */
111
+ export function computeStepLatencyEventData(params) {
112
+ const { tracking } = params;
113
+ if (!tracking || params.attempt !== 1) {
114
+ return undefined;
115
+ }
116
+ // Clamp at 0: cross-invocation timestamps can come from another machine's
117
+ // clock, so small skews must not produce negative durations.
118
+ //
119
+ // A pre-step setAttributes detour ends the measurement at the first attr
120
+ // write instead of the step's code start — the remainder is the duration
121
+ // of the setAttributes call (resolved via an extra replay), which is
122
+ // subtracted rather than disqualifying the sample. In that case
123
+ // `tracking.preStepBlockingMs` already holds only the hook time from
124
+ // BEFORE the attr write — hook writes after the window closed are excluded
125
+ // by computeStepLatencyTracking (see preStepBlockingBeforeAttrMs).
126
+ const ttfsEndMs = tracking.preStepAttrStartMs ?? params.stepCodeStartedAtMs;
127
+ const ttfs = tracking.ttfsAnchorMs !== undefined
128
+ ? Math.max(0, ttfsEndMs - tracking.ttfsAnchorMs - (tracking.preStepBlockingMs ?? 0))
129
+ : undefined;
130
+ const stso = tracking.prevStepEndMs !== undefined
131
+ ? Math.max(0, params.stepCodeStartedAtMs - tracking.prevStepEndMs)
132
+ : undefined;
133
+ if (ttfs === undefined && stso === undefined) {
134
+ return undefined;
135
+ }
136
+ const optimizations = [];
137
+ if (tracking.turbo)
138
+ optimizations.push('turbo');
139
+ if (params.lazyStepStart)
140
+ optimizations.push('lazyStepStart');
141
+ if (params.optimisticStart)
142
+ optimizations.push('optimisticStart');
143
+ return {
144
+ ...(ttfs !== undefined ? { ttfs } : {}),
145
+ ...(stso !== undefined ? { stso } : {}),
146
+ ...(stso !== undefined && tracking.stepCount !== undefined
147
+ ? { stepCount: tracking.stepCount }
148
+ : {}),
149
+ ...(stso !== undefined && tracking.eventCount !== undefined
150
+ ? { eventCount: tracking.eventCount }
151
+ : {}),
152
+ optimizations,
153
+ };
154
+ }
155
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1sYXRlbmN5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvc3RlcC1sYXRlbmN5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlFQTs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsTUFBTSw4QkFBOEIsR0FBb0MsSUFBSSxHQUFHLENBQzdFO0lBQ0UsY0FBYztJQUNkLGNBQWM7SUFDZCxnQkFBZ0I7SUFDaEIsYUFBYTtJQUNiLGVBQWU7SUFDZixlQUFlO0lBQ2YsY0FBYztJQUNkLGdCQUFnQjtDQUNqQixDQUNGLENBQUM7QUFFRjs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsMEJBQTBCLENBQUMsTUEyQzFDO0lBQ0MsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUUxQixJQUFJLFlBQVksR0FDZCxNQUFNLENBQUMsc0JBQXNCO1FBQzdCLE1BQU0sQ0FBQyxjQUFjLEtBQUssU0FBUztRQUNuQyxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQztJQUM3QixJQUFJLGtCQUFzQyxDQUFDO0lBQzNDLElBQUksWUFBWSxFQUFFLENBQUM7UUFDakIsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUMzQixJQUFJLDhCQUE4QixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztnQkFDeEQsWUFBWSxHQUFHLEtBQUssQ0FBQztnQkFDckIsTUFBTTtZQUNSLENBQUM7WUFDRCxJQUFJLEtBQUssQ0FBQyxTQUFTLEtBQUssVUFBVSxFQUFFLENBQUM7Z0JBQ25DLE1BQU0sV0FBVyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsVUFBVSxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDM0Qsa0JBQWtCO29CQUNoQixrQkFBa0IsS0FBSyxTQUFTO3dCQUM5QixDQUFDLENBQUMsV0FBVzt3QkFDYixDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcs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O1lBQ3hELENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxRQUFRLENBQUMsU0FBUyxFQUFFO1lBQ25DLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDUCxHQUFHLENBQUMsSUFBSSxLQUFLLFNBQVMsSUFBSSxRQUFRLENBQUMsVUFBVSxLQUFLLFNBQVM7WUFDekQsQ0FBQyxDQUFDLEVBQUUsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVLEVBQUU7WUFDckMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNQLGFBQWE7S0FDZCxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRXZlbnQgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuXG4vKipcbiAqIENsaWVudC1zaWRlIGxhdGVuY3kgbWVhc3VyZW1lbnQgKFRURlMgLyBTVFNPKSB0aHJlYWRlZCBmcm9tIHRoZVxuICogb3JjaGVzdHJhdG9yJ3MgaW5saW5lIGV4ZWN1dGlvbiBwYXRoIGludG8gYGV4ZWN1dGVTdGVwYC5cbiAqXG4gKiBUVEZTICh0aW1lLXRvLWZpcnN0LXN0ZXApIG1lYXN1cmVzIHJ1biBjcmVhdGlvbiDihpIgdGhlIGZpcnN0IHN0ZXAncyBib2R5XG4gKiBiZWdpbm5pbmcgdG8gZXhlY3V0ZS4gU1RTTyAoc3RlcC10by1zdGVwIG92ZXJoZWFkKSBtZWFzdXJlcyB0aGUgcHJldmlvdXNcbiAqIHN0ZXAncyB0ZXJtaW5hbCBldmVudCDihpIgdGhlIG5leHQgc3RlcCdzIGJvZHkgYmVnaW5uaW5nIHRvIGV4ZWN1dGUuIEJvdGggYXJlXG4gKiBhdHRhY2hlZCB0byB0aGUgc3RlcCdzIHRlcm1pbmFsIGV2ZW50IHNvIGEgYmFja2VuZCBjYW4gZW1pdCBsYXRlbmN5IG1ldHJpY3NcbiAqIGZyb20gdGhlIGV2ZW50IHdyaXRlIGFsb25lLCB3aXRob3V0IGV4dHJhIGV2ZW50LWxvZyBxdWVyaWVzLlxuICpcbiAqIEVsaWdpYmlsaXR5IGlzIGRlY2lkZWQgYnkgdGhlIG9yY2hlc3RyYXRvciAod2hpY2ggb3ducyB0aGUgZXZlbnQgbG9nKSB2aWFcbiAqIHtAbGluayBjb21wdXRlU3RlcExhdGVuY3lUcmFja2luZ307IHRoZSBmaW5hbCB2YWx1ZXMgYXJlIGNvbXB1dGVkIGJ5XG4gKiBgZXhlY3V0ZVN0ZXBgIHJpZ2h0IGJlZm9yZSB1c2VyIGNvZGUgcnVucyB2aWFcbiAqIHtAbGluayBjb21wdXRlU3RlcExhdGVuY3lFdmVudERhdGF9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0ZXBMYXRlbmN5VHJhY2tpbmcge1xuICAvKipcbiAgICogRXBvY2ggbXMgb2YgcnVuIGNyZWF0aW9uIChmcm9tIHRoZSBydW4taWQgVUxJRCwgZmFsbGluZyBiYWNrIHRvIHRoZSBydW5cbiAgICogc25hcHNob3QncyBgY3JlYXRlZEF0YCkuIFByZXNlbnQgb25seSB3aGVuIHRoZSBzdGVwIHF1YWxpZmllcyBmb3IgVFRGUy5cbiAgICovXG4gIHR0ZnNBbmNob3JNcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFdhbGwtY2xvY2sgbXMgdGhpcyBpbnZvY2F0aW9uIHNwZW50IGNvbW1pdHRpbmcgYGhvb2tfY3JlYXRlZGAgZXZlbnRzXG4gICAqIGJlZm9yZSB0aGUgZmlyc3Qgc3RlcCAoZmlyZS1hbmQtZm9yZ2V0IGBjcmVhdGVIb29rKClgIGFoZWFkIG9mIHRoZSBmaXJzdFxuICAgKiBzdGVwIGNvbW1pdHMgaW4gdGhlIHNhbWUgc3VzcGVuc2lvbiBiYXRjaCkuIFN1YnRyYWN0ZWQgZnJvbSBUVEZTIHNvIHRoZVxuICAgKiBtZXRyaWMgcmVmbGVjdHMgcnVudGltZSBvdmVyaGVhZCByYXRoZXIgdGhhbiB0aGUgdXNlcidzIGhvb2sgd3JpdGVzLlxuICAgKi9cbiAgcHJlU3RlcEJsb2NraW5nTXM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBFcG9jaCBtcyB0aGUgZmlyc3QgcHJlLXN0ZXAgYGF0dHJfc2V0YCB3cml0ZSBiZWdhbiAoaXRzIGNsaWVudC1zdGFtcGVkXG4gICAqIGBvY2N1cnJlZEF0YCwgZmFsbGluZyBiYWNrIHRvIGBjcmVhdGVkQXRgKS4gV2hlbiBwcmVzZW50LCB0aGUgVFRGU1xuICAgKiBtZWFzdXJlbWVudCBFTkRTIGhlcmUgaW5zdGVhZCBvZiBhdCB0aGUgc3RlcCdzIGNvZGUgc3RhcnQ6IGFcbiAgICogd29ya2Zsb3ctYm9keSBgc2V0QXR0cmlidXRlc2AgYmVmb3JlIHRoZSBmaXJzdCBzdGVwXG4gICAqIHJlc29sdmVzIHRocm91Z2ggYW4gZXh0cmEgcmVwbGF5IChzZWUgdGhlIGBoYXNBdHRyaWJ1dGVFdmVudHNgIGJyYW5jaCBpblxuICAgKiBydW50aW1lLnRzKSwgc28gZXZlcnl0aGluZyBmcm9tIHRoaXMgd3JpdGUgdW50aWwgdGhlIHN0ZXAgYm9keSBydW5zIGlzXG4gICAqIHRoZSBkdXJhdGlvbiBvZiB0aGUgc2V0QXR0cmlidXRlcyBjYWxsIOKAlCB3aGljaCBpcyBzdWJ0cmFjdGVkIGJ5IGVuZGluZ1xuICAgKiB0aGUgbWVhc3VyZW1lbnQgYXQgdGhlIHBvaW50IHdoZXJlIHRoZSBzdGVwIHdvdWxkIG90aGVyd2lzZSBoYXZlIGJlZW5cbiAgICogc2NoZWR1bGVkLlxuICAgKi9cbiAgcHJlU3RlcEF0dHJTdGFydE1zPzogbnVtYmVyO1xuICAvKipcbiAgICogRXBvY2ggbXMgdGhlIHByZXZpb3VzIHN0ZXAncyB0ZXJtaW5hbCBldmVudCB3YXMgcmVjb3JkZWQgKGl0c1xuICAgKiBjbGllbnQtc3RhbXBlZCBgb2NjdXJyZWRBdGAsIGZhbGxpbmcgYmFjayB0byBgY3JlYXRlZEF0YCkuIFByZXNlbnQgb25seVxuICAgKiB3aGVuIHRoZSBzdGVwIHF1YWxpZmllcyBmb3IgU1RTTy5cbiAgICovXG4gIHByZXZTdGVwRW5kTXM/OiBudW1iZXI7XG4gIC8qKiBOdW1iZXIgb2YgdW5pcXVlIHRlcm1pbmFsIHN0ZXBzIGFscmVhZHkgaW4gdGhlIGV2ZW50IGxvZy4gKi9cbiAgc3RlcENvdW50PzogbnVtYmVyO1xuICAvKiogTnVtYmVyIG9mIGV2ZW50cyBhbHJlYWR5IGluIHRoZSBldmVudCBsb2cuICovXG4gIGV2ZW50Q291bnQ/OiBudW1iZXI7XG4gIC8qKiBXaGV0aGVyIHR1cmJvIG1vZGUgaXMgYWN0aXZlIGZvciB0aGlzIGludm9jYXRpb24uICovXG4gIHR1cmJvOiBib29sZWFuO1xufVxuXG4vKiogTGF0ZW5jeSB0ZWxlbWV0cnkgYXR0YWNoZWQgdG8gYSBzdGVwJ3MgdGVybWluYWwgZXZlbnQncyBgZXZlbnREYXRhYC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RlcExhdGVuY3lFdmVudERhdGEge1xuICB0dGZzPzogbnVtYmVyO1xuICBzdHNvPzogbnVtYmVyO1xuICBzdGVwQ291bnQ/OiBudW1iZXI7XG4gIGV2ZW50Q291bnQ/OiBudW1iZXI7XG4gIG9wdGltaXphdGlvbnM/OiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBFdmVudCB0eXBlcyB0aGF0IGRpc3F1YWxpZnkgVFRGUyB3aGVuIHByZXNlbnQgaW4gdGhlIGV2ZW50IGxvZyBhdCB0aGUgdGltZVxuICogdGhlIHJ1bidzIGZpcnN0IHN0ZXAgYmF0Y2ggaXMgc2NoZWR1bGVkOlxuICpcbiAqIC0gQW55IHN0ZXAgZXZlbnQgbWVhbnMgdGhpcyBpcyBub3QgdGhlIHJ1bidzIGZpcnN0IHN0ZXAgZXhlY3V0aW9uLlxuICogLSBgaG9va19yZWNlaXZlZGAgLyBgd2FpdF9jcmVhdGVkYCAvIGB3YWl0X2NvbXBsZXRlZGAgbWVhbiB0aGUgcnVuJ3MgcGF0aCB0b1xuICogICB0aGUgZmlyc3Qgc3RlcCBkZXBlbmRlZCBvbiB1c2VyLWRyaXZlbiB0aW1pbmcgKGEgd2ViaG9vayBhcnJpdmluZywgYVxuICogICBzbGVlcCBlbGFwc2luZyksIHNvIHRoZSBtZWFzdXJlbWVudCB3b3VsZCBub3QgcmVmbGVjdCBydW50aW1lIG92ZXJoZWFkLlxuICpcbiAqIERlbGliZXJhdGVseSBhYnNlbnQsIHdpdGggdGhlaXIgY29zdCBzdWJ0cmFjdGVkIGluc3RlYWQ6XG4gKlxuICogLSBgaG9va19jcmVhdGVkYDogYSBmaXJlLWFuZC1mb3JnZXQgYGNyZWF0ZUhvb2soKWAgYmVmb3JlIHRoZSBmaXJzdCBzdGVwXG4gKiAgIGNvbW1pdHMgaW4gdGhlIHNhbWUgaW52b2NhdGlvbiwgd2hvc2UgbWVhc3VyZWQgZHVyYXRpb24gaXMgc3VidHJhY3RlZCB2aWFcbiAqICAge0BsaW5rIFN0ZXBMYXRlbmN5VHJhY2tpbmcucHJlU3RlcEJsb2NraW5nTXN9LlxuICogLSBgYXR0cl9zZXRgICh3b3JrZmxvdy1ib2R5IGBzZXRBdHRyaWJ1dGVzYCk6IHJlc29sdmVzIHRocm91Z2hcbiAqICAgYW4gZXh0cmEgcmVwbGF5IGJlZm9yZSBzdGVwcyBydW4uIFN1YnRyYWN0ZWQgYnkgZW5kaW5nIHRoZSBtZWFzdXJlbWVudCBhdFxuICogICB0aGUgZmlyc3QgYXR0ciB3cml0ZSdzIHRpbWVzdGFtcCBpbnN0ZWFkIOKAlCBzZWVcbiAqICAge0BsaW5rIFN0ZXBMYXRlbmN5VHJhY2tpbmcucHJlU3RlcEF0dHJTdGFydE1zfS5cbiAqL1xuY29uc3QgVFRGU19ESVNRVUFMSUZZSU5HX0VWRU5UX1RZUEVTOiBSZWFkb25seVNldDxFdmVudFsnZXZlbnRUeXBlJ10+ID0gbmV3IFNldChcbiAgW1xuICAgICdzdGVwX2NyZWF0ZWQnLFxuICAgICdzdGVwX3N0YXJ0ZWQnLFxuICAgICdzdGVwX2NvbXBsZXRlZCcsXG4gICAgJ3N0ZXBfZmFpbGVkJyxcbiAgICAnc3RlcF9yZXRyeWluZycsXG4gICAgJ2hvb2tfcmVjZWl2ZWQnLFxuICAgICd3YWl0X2NyZWF0ZWQnLFxuICAgICd3YWl0X2NvbXBsZXRlZCcsXG4gIF1cbik7XG5cbi8qKlxuICogRGVjaWRlLCBmcm9tIHRoZSBvcmNoZXN0cmF0b3IncyB2aWV3IG9mIHRoZSBldmVudCBsb2csIHdoZXRoZXIgdGhlIGlubGluZVxuICogc3RlcCBiYXRjaCBhYm91dCB0byBleGVjdXRlIHF1YWxpZmllcyBmb3IgVFRGUyBhbmQvb3IgU1RTTyBtZWFzdXJlbWVudC5cbiAqIFJldHVybnMgdW5kZWZpbmVkIHdoZW4gbmVpdGhlciBhcHBsaWVzLiBDYWxsZWQgb25jZSBwZXIgYmF0Y2g7IHRoZSByZXN1bHRcbiAqIGlzIHBhc3NlZCB0byB0aGUgYmF0Y2gncyBmaXJzdCBzdGVwIG9ubHksIHNvIGEgcGFyYWxsZWwgZmlyc3QgYmF0Y2ggZW1pdHMgYVxuICogc2luZ2xlIHNhbXBsZSByYXRoZXIgdGhhbiBvbmUgcGVyIHNpYmxpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wdXRlU3RlcExhdGVuY3lUcmFja2luZyhwYXJhbXM6IHtcbiAgLyoqIFRoZSBvcmNoZXN0cmF0b3IncyBjdXJyZW50IGluLW1lbW9yeSBldmVudCBsb2cgKGFzY2VuZGluZyBvcmRlcikuICovXG4gIGV2ZW50czogRXZlbnRbXTtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhpcyBpbnZvY2F0aW9uJ3MgaW5pdGlhbCBldmVudCBsb2FkIGNvbnRhaW5lZCBub3RoaW5nIGJleW9uZFxuICAgKiBydW5fY3JlYXRlZC9ydW5fc3RhcnRlZC9hdHRyX3NldC4gUHJlLWV4aXN0aW5nIGhvb2sgZXZlbnRzIHdlcmUgd3JpdHRlblxuICAgKiBieSBhbiBlYXJsaWVyIGludm9jYXRpb24sIHNvIHRoZSB0aW1lIHRoZXkgYWRkZWQgKGluY2x1ZGluZyB0aGUgcXVldWVcbiAgICogaG9wIGJhY2sgdG8gdGhpcyBpbnZvY2F0aW9uKSBpcyB1bm1lYXN1cmFibGUgYW5kIGRpc3F1YWxpZmllcyBUVEZTLlxuICAgKiBhdHRyX3NldCBpcyBwZXJtaXR0ZWQ6IGEgcmVkZWxpdmVyeSBjYW4gbGFuZCBhZnRlciBhIGNvbW1pdHRlZCBwcmUtc3RlcFxuICAgKiBhdHRyX3NldCwgYW5kIHRoZSBkZXRvdXIgaXQgbWFya3MgaXMgc3VidHJhY3RlZCB2aWEgYHByZVN0ZXBBdHRyU3RhcnRNc2BcbiAgICogcmVnYXJkbGVzcyBvZiB3aGljaCBpbnZvY2F0aW9uIHdyb3RlIGl0LlxuICAgKi9cbiAgaW52b2NhdGlvblN0YXJ0ZWRDbGVhbjogYm9vbGVhbjtcbiAgLyoqIEVwb2NoIG1zIG9mIHJ1biBjcmVhdGlvbiwgaWYgcmVjb3ZlcmFibGUuIEFic2VudCBkaXNxdWFsaWZpZXMgVFRGUy4gKi9cbiAgcnVuQ3JlYXRlZEF0TXM6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgLyoqIFNlZSB7QGxpbmsgU3RlcExhdGVuY3lUcmFja2luZy5wcmVTdGVwQmxvY2tpbmdNc30uICovXG4gIHByZVN0ZXBCbG9ja2luZ01zOiBudW1iZXI7XG4gIC8qKlxuICAgKiBUaGUgYWNjdW11bGF0b3IncyB2YWx1ZSBhcyBvZiB0aGUgc3VzcGVuc2lvbiB0aGF0IHdyb3RlIHRoZSBydW4ncyBmaXJzdFxuICAgKiBhdHRyX3NldCAoaXRzIGhvb2sgcGhhc2UgcnVucyBiZWZvcmUgaXRzIGF0dHIgd3JpdGVzKS4gV2hlbiB0aGVcbiAgICogbWVhc3VyZW1lbnQgZW5kcyBhdCB0aGUgYXR0ciB3cml0ZSwgb25seSBob29rIHRpbWUgZnJvbSBiZWZvcmUgdGhhdFxuICAgKiBwb2ludCBtYXkgYmUgc3VidHJhY3RlZCDigJQgbGF0ZXIgaG9vayB3cml0ZXMgZmFsbCBvdXRzaWRlIHRoZSBtZWFzdXJlZFxuICAgKiB3aW5kb3cuIFVuZGVmaW5lZCB3aGVuIG5vIGF0dHIgc3VzcGVuc2lvbiBoYXBwZW5lZCBpbiB0aGlzIGludm9jYXRpb25cbiAgICogKGUuZy4gdGhlIGF0dHJfc2V0IHdhcyBsb2FkZWQgZnJvbSBhIHJlZGVsaXZlcnkncyBzbmFwc2hvdCwgd2hlcmUgbm9cbiAgICogc2FtZS1pbnZvY2F0aW9uIGhvb2sgdGltZSBwcmVjZWRlcyBpdCkuXG4gICAqL1xuICBwcmVTdGVwQmxvY2tpbmdCZWZvcmVBdHRyTXM6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHN1c3BlbnNpb24gdGhhdCBzY2hlZHVsZWQgdGhpcyBiYXRjaCBhbHNvIGNyZWF0ZWQgd2FpdHMuXG4gICAqIFRob3NlIGB3YWl0X2NyZWF0ZWRgIHdyaXRlcyBhcmUgbm90IGluIGBldmVudHNgIHlldCAodGhleSB3ZXJlIGNvbW1pdHRlZFxuICAgKiBieSB0aGlzIHZlcnkgc3VzcGVuc2lvbiBwYXNzKSwgc28gdGhleSBtdXN0IGJlIHJlcG9ydGVkIHNlcGFyYXRlbHkuIEFcbiAgICogd2FpdCBkaXNxdWFsaWZpZXMgYm90aCBtZWFzdXJlbWVudHMuXG4gICAqL1xuICBzdXNwZW5zaW9uSGFzV2FpdHM6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBzdXNwZW5zaW9uIHRoYXQgc2NoZWR1bGVkIHRoaXMgYmF0Y2ggYWxzbyBjcmVhdGVkIGhvb2tzXG4gICAqIChhbHNvIG5vdCBpbiBgZXZlbnRzYCB5ZXQpLiBIb29rcyBrZWVwIFRURlMgZWxpZ2libGUg4oCUIHRoZWlyIG1lYXN1cmVkXG4gICAqIHdyaXRlIHRpbWUgaXMgc3VidHJhY3RlZCB2aWEgYHByZVN0ZXBCbG9ja2luZ01zYCDigJQgYnV0IGRpc3F1YWxpZnkgU1RTTyxcbiAgICogd2hpY2ggaXMgb25seSBtZWFuaW5nZnVsIGZvciBhIHB1cmUgYmFjay10by1iYWNrIHN0ZXAgZ2FwLlxuICAgKi9cbiAgc3VzcGVuc2lvbkNyZWF0ZWRIb29rczogYm9vbGVhbjtcbiAgLyoqIFdoZXRoZXIgdHVyYm8gbW9kZSBpcyBhY3RpdmUgZm9yIHRoaXMgaW52b2NhdGlvbi4gKi9cbiAgdHVyYm86IGJvb2xlYW47XG59KTogU3RlcExhdGVuY3lUcmFja2luZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHsgZXZlbnRzIH0gPSBwYXJhbXM7XG5cbiAgbGV0IHR0ZnNFbGlnaWJsZSA9XG4gICAgcGFyYW1zLmludm9jYXRpb25TdGFydGVkQ2xlYW4gJiZcbiAgICBwYXJhbXMucnVuQ3JlYXRlZEF0TXMgIT09IHVuZGVmaW5lZCAmJlxuICAgICFwYXJhbXMuc3VzcGVuc2lvbkhhc1dhaXRzO1xuICBsZXQgcHJlU3RlcEF0dHJTdGFydE1zOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIGlmICh0dGZzRWxpZ2libGUpIHtcbiAgICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgICAgaWYgKFRURlNfRElTUVVBTElGWUlOR19FVkVOVF9UWVBFUy5oYXMoZXZlbnQuZXZlbnRUeXBlKSkge1xuICAgICAgICB0dGZzRWxpZ2libGUgPSBmYWxzZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoZXZlbnQuZXZlbnRUeXBlID09PSAnYXR0cl9zZXQnKSB7XG4gICAgICAgIGNvbnN0IGF0dHJTdGFydE1zID0gKyhldmVudC5vY2N1cnJlZEF0ID8/IGV2ZW50LmNyZWF0ZWRBdCk7XG4gICAgICAgIHByZVN0ZXBBdHRyU3RhcnRNcyA9XG4gICAgICAgICAgcHJlU3RlcEF0dHJTdGFydE1zID09PSB1bmRlZmluZWRcbiAgICAgICAgICAgID8gYXR0clN0YXJ0TXNcbiAgICAgICAgICAgIDogTWF0aC5taW4ocHJlU3RlcEF0dHJTdGFydE1zLCBhdHRyU3RhcnRNcyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gU1RTTzogdGhlIHR3byBzdGVwcyByYW4gYmFjay10by1iYWNrIOKAlCB0aGUgbmV3ZXN0IGtub3duIGV2ZW50IGlzIHRoZVxuICAvLyBwcmV2aW91cyBzdGVwJ3MgdGVybWluYWwgZXZlbnQsIHdpdGggbm90aGluZyAoaG9va19yZWNlaXZlZCwgd2FpdHMsXG4gIC8vIGF0dHJfc2V0LCAuLi4pIGluIGJldHdlZW4gYW5kIHRoaXMgc3VzcGVuc2lvbiBzY2hlZHVsaW5nIG5vdGhpbmcgYnV0XG4gIC8vIHN0ZXBzLlxuICBsZXQgcHJldlN0ZXBFbmRNczogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBsZXQgc3RlcENvdW50OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIGxldCBldmVudENvdW50OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIGNvbnN0IGxhc3RFdmVudCA9IGV2ZW50c1tldmVudHMubGVuZ3RoIC0gMV07XG4gIGlmIChcbiAgICAhcGFyYW1zLnN1c3BlbnNpb25IYXNXYWl0cyAmJlxuICAgICFwYXJhbXMuc3VzcGVuc2lvbkNyZWF0ZWRIb29rcyAmJlxuICAgIGxhc3RFdmVudCAmJlxuICAgIChsYXN0RXZlbnQuZXZlbnRUeXBlID09PSAnc3RlcF9jb21wbGV0ZWQnIHx8XG4gICAgICBsYXN0RXZlbnQuZXZlbnRUeXBlID09PSAnc3RlcF9mYWlsZWQnKVxuICApIHtcbiAgICBwcmV2U3RlcEVuZE1zID0gKyhsYXN0RXZlbnQub2NjdXJyZWRBdCA/PyBsYXN0RXZlbnQuY3JlYXRlZEF0KTtcbiAgICBjb25zdCB0ZXJtaW5hbFN0ZXBJZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgICAgaWYgKFxuICAgICAgICAoZXZlbnQuZXZlbnRUeXBlID09PSAnc3RlcF9jb21wbGV0ZWQnIHx8XG4gICAgICAgICAgZXZlbnQuZXZlbnRUeXBlID09PSAnc3RlcF9mYWlsZWQnKSAmJlxuICAgICAgICBldmVudC5jb3JyZWxhdGlvbklkICE9PSB1bmRlZmluZWRcbiAgICAgICkge1xuICAgICAgICB0ZXJtaW5hbFN0ZXBJZHMuYWRkKGV2ZW50LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgfVxuICAgIH1cbiAgICBzdGVwQ291bnQgPSB0ZXJtaW5hbFN0ZXBJZHMuc2l6ZTtcbiAgICBldmVudENvdW50ID0gZXZlbnRzLmxlbmd0aDtcbiAgfVxuXG4gIGlmICghdHRmc0VsaWdpYmxlICYmIHByZXZTdGVwRW5kTXMgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIC4uLih0dGZzRWxpZ2libGVcbiAgICAgID8ge1xuICAgICAgICAgIHR0ZnNBbmNob3JNczogcGFyYW1zLnJ1bkNyZWF0ZWRBdE1zLFxuICAgICAgICAgIC8vIFdoZW4gdGhlIG1lYXN1cmVtZW50IGVuZHMgYXQgdGhlIGZpcnN0IGF0dHIgd3JpdGUsIG9ubHkgaG9va1xuICAgICAgICAgIC8vIHRpbWUgZnJvbSBiZWZvcmUgdGhhdCBwb2ludCBpcyBpbnNpZGUgdGhlIG1lYXN1cmVkIHdpbmRvdy5cbiAgICAgICAgICBwcmVTdGVwQmxvY2tpbmdNczpcbiAgICAgICAgICAgIHByZVN0ZXBBdHRyU3RhcnRNcyAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgID8gKHBhcmFtcy5wcmVTdGVwQmxvY2tpbmdCZWZvcmVBdHRyTXMgPz8gMClcbiAgICAgICAgICAgICAgOiBwYXJhbXMucHJlU3RlcEJsb2NraW5nTXMsXG4gICAgICAgICAgLi4uKHByZVN0ZXBBdHRyU3RhcnRNcyAhPT0gdW5kZWZpbmVkID8geyBwcmVTdGVwQXR0clN0YXJ0TXMgfSA6IHt9KSxcbiAgICAgICAgfVxuICAgICAgOiB7fSksXG4gICAgLi4uKHByZXZTdGVwRW5kTXMgIT09IHVuZGVmaW5lZFxuICAgICAgPyB7IHByZXZTdGVwRW5kTXMsIHN0ZXBDb3VudCwgZXZlbnRDb3VudCB9XG4gICAgICA6IHt9KSxcbiAgICB0dXJibzogcGFyYW1zLnR1cmJvLFxuICB9O1xufVxuXG4vKipcbiAqIENvbXB1dGUgdGhlIGxhdGVuY3kgdGVsZW1ldHJ5IHRvIGF0dGFjaCB0byB0aGUgc3RlcCdzIHRlcm1pbmFsIGV2ZW50LlxuICogQ2FsbGVkIGJ5IGBleGVjdXRlU3RlcGAgd2l0aCB0aGUgd2FsbC1jbG9jayB0aW1lc3RhbXAgdGFrZW4gaW1tZWRpYXRlbHlcbiAqIGJlZm9yZSB1c2VyIHN0ZXAgY29kZSBydW5zLiBSZXR1cm5zIHVuZGVmaW5lZCB3aGVuIHRoZXJlIGlzIG5vdGhpbmcgdG9cbiAqIHJlcG9ydCAobm8gdHJhY2tpbmcsIG9yIGEgcmV0cnkgYXR0ZW1wdCDigJQgcmV0cmllcyBtZWFzdXJlIG5laXRoZXIgVFRGUyBub3JcbiAqIFNUU08pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZVN0ZXBMYXRlbmN5RXZlbnREYXRhKHBhcmFtczoge1xuICB0cmFja2luZzogU3RlcExhdGVuY3lUcmFja2luZyB8IHVuZGVmaW5lZDtcbiAgLyoqIGBEYXRlLm5vdygpYCB0YWtlbiBpbW1lZGlhdGVseSBiZWZvcmUgdXNlciBzdGVwIGNvZGUgYmVnYW4gZXhlY3V0aW5nLiAqL1xuICBzdGVwQ29kZVN0YXJ0ZWRBdE1zOiBudW1iZXI7XG4gIGF0dGVtcHQ6IG51bWJlcjtcbiAgLyoqIFdoZXRoZXIgdGhpcyBzdGVwIHdhcyBzdGFydGVkIGxhemlseSAobm8gc2VwYXJhdGUgc3RlcF9jcmVhdGVkIHdyaXRlKS4gKi9cbiAgbGF6eVN0ZXBTdGFydDogYm9vbGVhbjtcbiAgLyoqIFdoZXRoZXIgdGhlIGJvZHkgcmFuIG9wdGltaXN0aWNhbGx5LCB3aXRob3V0IGF3YWl0aW5nIHN0ZXBfc3RhcnRlZC4gKi9cbiAgb3B0aW1pc3RpY1N0YXJ0OiBib29sZWFuO1xufSk6IFN0ZXBMYXRlbmN5RXZlbnREYXRhIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgeyB0cmFja2luZyB9ID0gcGFyYW1zO1xuICBpZiAoIXRyYWNraW5nIHx8IHBhcmFtcy5hdHRlbXB0ICE9PSAxKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIENsYW1wIGF0IDA6IGNyb3NzLWludm9jYXRpb24gdGltZXN0YW1wcyBjYW4gY29tZSBmcm9tIGFub3RoZXIgbWFjaGluZSdzXG4gIC8vIGNsb2NrLCBzbyBzbWFsbCBza2V3cyBtdXN0IG5vdCBwcm9kdWNlIG5lZ2F0aXZlIGR1cmF0aW9ucy5cbiAgLy9cbiAgLy8gQSBwcmUtc3RlcCBzZXRBdHRyaWJ1dGVzIGRldG91ciBlbmRzIHRoZSBtZWFzdXJlbWVudCBhdCB0aGUgZmlyc3QgYXR0clxuICAvLyB3cml0ZSBpbnN0ZWFkIG9mIHRoZSBzdGVwJ3MgY29kZSBzdGFydCDigJQgdGhlIHJlbWFpbmRlciBpcyB0aGUgZHVyYXRpb25cbiAgLy8gb2YgdGhlIHNldEF0dHJpYnV0ZXMgY2FsbCAocmVzb2x2ZWQgdmlhIGFuIGV4dHJhIHJlcGxheSksIHdoaWNoIGlzXG4gIC8vIHN1YnRyYWN0ZWQgcmF0aGVyIHRoYW4gZGlzcXVhbGlmeWluZyB0aGUgc2FtcGxlLiBJbiB0aGF0IGNhc2VcbiAgLy8gYHRyYWNraW5nLnByZVN0ZXBCbG9ja2luZ01zYCBhbHJlYWR5IGhvbGRzIG9ubHkgdGhlIGhvb2sgdGltZSBmcm9tXG4gIC8vIEJFRk9SRSB0aGUgYXR0ciB3cml0ZSDigJQgaG9vayB3cml0ZXMgYWZ0ZXIgdGhlIHdpbmRvdyBjbG9zZWQgYXJlIGV4Y2x1ZGVkXG4gIC8vIGJ5IGNvbXB1dGVTdGVwTGF0ZW5jeVRyYWNraW5nIChzZWUgcHJlU3RlcEJsb2NraW5nQmVmb3JlQXR0ck1zKS5cbiAgY29uc3QgdHRmc0VuZE1zID0gdHJhY2tpbmcucHJlU3RlcEF0dHJTdGFydE1zID8/IHBhcmFtcy5zdGVwQ29kZVN0YXJ0ZWRBdE1zO1xuICBjb25zdCB0dGZzID1cbiAgICB0cmFja2luZy50dGZzQW5jaG9yTXMgIT09IHVuZGVmaW5lZFxuICAgICAgPyBNYXRoLm1heChcbiAgICAgICAgICAwLFxuICAgICAgICAgIHR0ZnNFbmRNcyAtIHRyYWNraW5nLnR0ZnNBbmNob3JNcyAtICh0cmFja2luZy5wcmVTdGVwQmxvY2tpbmdNcyA/PyAwKVxuICAgICAgICApXG4gICAgICA6IHVuZGVmaW5lZDtcbiAgY29uc3Qgc3RzbyA9XG4gICAgdHJhY2tpbmcucHJldlN0ZXBFbmRNcyAhPT0gdW5kZWZpbmVkXG4gICAgICA/IE1hdGgubWF4KDAsIHBhcmFtcy5zdGVwQ29kZVN0YXJ0ZWRBdE1zIC0gdHJhY2tpbmcucHJldlN0ZXBFbmRNcylcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gIGlmICh0dGZzID09PSB1bmRlZmluZWQgJiYgc3RzbyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGNvbnN0IG9wdGltaXphdGlvbnM6IHN0cmluZ1tdID0gW107XG4gIGlmICh0cmFja2luZy50dXJibykgb3B0aW1pemF0aW9ucy5wdXNoKCd0dXJibycpO1xuICBpZiAocGFyYW1zLmxhenlTdGVwU3RhcnQpIG9wdGltaXphdGlvbnMucHVzaCgnbGF6eVN0ZXBTdGFydCcpO1xuICBpZiAocGFyYW1zLm9wdGltaXN0aWNTdGFydCkgb3B0aW1pemF0aW9ucy5wdXNoKCdvcHRpbWlzdGljU3RhcnQnKTtcblxuICByZXR1cm4ge1xuICAgIC4uLih0dGZzICE9PSB1bmRlZmluZWQgPyB7IHR0ZnMgfSA6IHt9KSxcbiAgICAuLi4oc3RzbyAhPT0gdW5kZWZpbmVkID8geyBzdHNvIH0gOiB7fSksXG4gICAgLi4uKHN0c28gIT09IHVuZGVmaW5lZCAmJiB0cmFja2luZy5zdGVwQ291bnQgIT09IHVuZGVmaW5lZFxuICAgICAgPyB7IHN0ZXBDb3VudDogdHJhY2tpbmcuc3RlcENvdW50IH1cbiAgICAgIDoge30pLFxuICAgIC4uLihzdHNvICE9PSB1bmRlZmluZWQgJiYgdHJhY2tpbmcuZXZlbnRDb3VudCAhPT0gdW5kZWZpbmVkXG4gICAgICA/IHsgZXZlbnRDb3VudDogdHJhY2tpbmcuZXZlbnRDb3VudCB9XG4gICAgICA6IHt9KSxcbiAgICBvcHRpbWl6YXRpb25zLFxuICB9O1xufVxuIl19
@@ -0,0 +1,72 @@
1
+ import type { Event } from '@workflow/world';
2
+ import type { StepInvocationQueueItem } from '../global.js';
3
+ /**
4
+ * Inline step ownership helpers for the pending-step dispatch decision table
5
+ * in runtime.ts (workflow#2780). Ownership state itself is derived per-replay
6
+ * from the event log by the step consumer in step.ts and surfaced on
7
+ * StepInvocationQueueItem; these functions interpret that state at dispatch
8
+ * time.
9
+ */
10
+ /**
11
+ * Whether inline step ownership is active for a pending step: created,
12
+ * latest `step_started` carries an owner stamp, and no `step_retrying` has
13
+ * been observed (from `step_retrying` on, the step is queue-owned by its
14
+ * delayed retry handoff / replay requeue, so ownership is permanently
15
+ * lapsed for the correlation ID).
16
+ */
17
+ export declare function isStepOwnershipActive(step: StepInvocationQueueItem): boolean;
18
+ /**
19
+ * Seconds left on an owned step's liveness lease, anchored at its latest
20
+ * `step_started`. 0 means the lease has expired (or the start timestamp is
21
+ * missing — the degraded mode for worlds whose events lack usable
22
+ * timestamps), in which case dispatch falls back to the immediate enqueue.
23
+ *
24
+ * The result is clamped to the configured lease: `lastStartedAt` is the
25
+ * server-stamped event `createdAt` while `nowMs` is the local clock, so a
26
+ * client running behind the server would otherwise compute a remainder
27
+ * LONGER than the lease itself — and with the lease tuned to the 900s cap,
28
+ * a `delaySeconds` above the queue's per-message maximum, which SQS-backed
29
+ * worlds reject outright (the wake replay's enqueue would throw and ride
30
+ * the redelivery loop). The clamp makes skew strictly harmless; remaining
31
+ * time can never legitimately exceed the full lease anyway.
32
+ */
33
+ export declare function stepLeaseRemainingSeconds(step: StepInvocationQueueItem, nowMs: number): number;
34
+ /**
35
+ * Idempotency key for the delayed backstop wake of an inline-owned step.
36
+ *
37
+ * The key is scoped to the current OWNERSHIP EPOCH — the timestamp of the
38
+ * latest `step_started` — not just the correlation ID. Within one epoch,
39
+ * every wake replay derives the same key, so fan-out stays capped at one
40
+ * pending backstop per step. But when owner recovery re-stamps the step
41
+ * (queue redelivery of the owning message → new `step_started` → new
42
+ * `lastStartedAt`), the key CHANGES. This is load-bearing for liveness:
43
+ * queues dedupe an idempotency key for the lifetime of the original
44
+ * message — including while a delivery of it is in flight — so a backstop
45
+ * that fires during a refreshed lease and tries to re-arm under a fixed key
46
+ * would dedupe against ITSELF and be dropped, leaving no escape hatch if
47
+ * the recovered owner later dies without further redeliveries. The epoch
48
+ * suffix gives the re-arm a fresh key. Pending backstops are bounded by the
49
+ * number of ownership epochs, i.e. the queue's redelivery budget for the
50
+ * owning message.
51
+ *
52
+ * The epoch value comes from the persisted event's `createdAt`, so every
53
+ * replayer derives the same key. Callers only build backstops when the
54
+ * lease has time remaining, which requires `lastStartedAt` to be set.
55
+ *
56
+ * The key must also never be the step message's own `idempotencyKey`
57
+ * (the bare correlation ID): the owner's retry handoff enqueues the step
58
+ * under that key with a short backoff, and a pending backstop sharing it
59
+ * would absorb the retry — turning a 1s backoff into a full-lease stall.
60
+ */
61
+ export declare function backstopIdempotencyKey(step: StepInvocationQueueItem): string;
62
+ /**
63
+ * Whether any of the given pending correlation IDs is inline-owned by
64
+ * `messageId` per the raw event log: its LATEST `step_started` carries
65
+ * `ownerMessageId === messageId` and no `step_retrying` follows it. Used by
66
+ * the background-step fast path, which sees raw events (not the replay's
67
+ * queueItems), to decide whether to fall through to the main loop so this
68
+ * invocation can recover a step it owns instead of returning and leaving it
69
+ * to the delayed backstop.
70
+ */
71
+ export declare function hasPendingStepOwnedByMessage(events: Event[], pendingCorrelationIds: Set<string | undefined>, messageId: string): boolean;
72
+ //# sourceMappingURL=step-ownership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-ownership.d.ts","sourceRoot":"","sources":["../../src/runtime/step-ownership.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAG5D;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAM5E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,uBAAuB,EAC7B,KAAK,EAAE,MAAM,GACZ,MAAM,CAKR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAE5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,KAAK,EAAE,EACf,qBAAqB,EAAE,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,EAC9C,SAAS,EAAE,MAAM,GAChB,OAAO,CAgCT"}
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1vd25lcnNoaXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9zdGVwLW93bmVyc2hpcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVoRTs7Ozs7O0dBTUc7QUFFSDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBQUMsSUFBNkI7SUFDakUsT0FBTyxDQUNMLElBQUksQ0FBQyxlQUFlLEtBQUssSUFBSTtRQUM3QixJQUFJLENBQUMsY0FBYyxLQUFLLFNBQVM7UUFDakMsSUFBSSxDQUFDLFdBQVcsS0FBSyxJQUFJLENBQzFCLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLFVBQVUseUJBQXlCLENBQ3ZDLElBQTZCLEVBQzdCLEtBQWE7SUFFYixJQUFJLElBQUksQ0FBQyxhQUFhLEtBQUssU0FBUztRQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQy9DLE1BQU0sWUFBWSxHQUFHLDhCQUE4QixFQUFFLENBQUM7SUFDdEQsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLGFBQWEsR0FBRyxZQUFZLEdBQUcsSUFBSSxHQUFHLEtBQUssQ0FBQztJQUNyRSxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM1RSxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMEJHO0FBQ0gsTUFBTSxVQUFVLHNCQUFzQixDQUFDLElBQTZCO0lBQ2xFLE9BQU8sR0FBRyxJQUFJLENBQUMsYUFBYSxhQUFhLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztBQUNoRSxDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLFVBQVUsNEJBQTRCLENBQzFDLE1BQWUsRUFDZixxQkFBOEMsRUFDOUMsU0FBaUI7SUFFakIseUVBQXlFO0lBQ3pFLHlFQUF5RTtJQUN6RSwwRUFBMEU7SUFDMUUsMENBQTBDO0lBQzFDLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUE4QixDQUFDO0lBQzFELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDdEMsS0FBSyxNQUFNLENBQUMsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsQ0FBQyxhQUFhLEtBQUssU0FBUztZQUFFLFNBQVM7UUFDNUMsSUFBSSxDQUFDLENBQUMsU0FBUyxLQUFLLGNBQWMsRUFBRSxDQUFDO1lBQ25DLE1BQU0sS0FBSyxHQUNULFdBQVcsSUFBSSxDQUFDO2dCQUNoQixDQUFDLENBQUMsU0FBUztnQkFDWCxnQkFBZ0IsSUFBSSxDQUFDLENBQUMsU0FBUztnQkFDL0IsT0FBTyxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQWMsS0FBSyxRQUFRO2dCQUM1QyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxjQUFjO2dCQUM1QixDQUFDLENBQUMsU0FBUyxDQUFDO1lBQ2hCLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMxQyxDQUFDO2FBQU0sSUFBSSxDQUFDLENBQUMsU0FBUyxLQUFLLGVBQWUsRUFBRSxDQUFDO1lBQzNDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ25DLENBQUM7SUFDSCxDQUFDO0lBQ0QsS0FBSyxNQUFNLEVBQUUsSUFBSSxxQkFBcUIsRUFBRSxDQUFDO1FBQ3ZDLElBQ0UsRUFBRSxLQUFLLFNBQVM7WUFDaEIsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNwQixXQUFXLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLFNBQVMsRUFDakMsQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEV2ZW50IH0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB0eXBlIHsgU3RlcEludm9jYXRpb25RdWV1ZUl0ZW0gfSBmcm9tICcuLi9nbG9iYWwuanMnO1xuaW1wb3J0IHsgZ2V0SW5saW5lT3duZXJzaGlwTGVhc2VTZWNvbmRzIH0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xuXG4vKipcbiAqIElubGluZSBzdGVwIG93bmVyc2hpcCBoZWxwZXJzIGZvciB0aGUgcGVuZGluZy1zdGVwIGRpc3BhdGNoIGRlY2lzaW9uIHRhYmxlXG4gKiBpbiBydW50aW1lLnRzICh3b3JrZmxvdyMyNzgwKS4gT3duZXJzaGlwIHN0YXRlIGl0c2VsZiBpcyBkZXJpdmVkIHBlci1yZXBsYXlcbiAqIGZyb20gdGhlIGV2ZW50IGxvZyBieSB0aGUgc3RlcCBjb25zdW1lciBpbiBzdGVwLnRzIGFuZCBzdXJmYWNlZCBvblxuICogU3RlcEludm9jYXRpb25RdWV1ZUl0ZW07IHRoZXNlIGZ1bmN0aW9ucyBpbnRlcnByZXQgdGhhdCBzdGF0ZSBhdCBkaXNwYXRjaFxuICogdGltZS5cbiAqL1xuXG4vKipcbiAqIFdoZXRoZXIgaW5saW5lIHN0ZXAgb3duZXJzaGlwIGlzIGFjdGl2ZSBmb3IgYSBwZW5kaW5nIHN0ZXA6IGNyZWF0ZWQsXG4gKiBsYXRlc3QgYHN0ZXBfc3RhcnRlZGAgY2FycmllcyBhbiBvd25lciBzdGFtcCwgYW5kIG5vIGBzdGVwX3JldHJ5aW5nYCBoYXNcbiAqIGJlZW4gb2JzZXJ2ZWQgKGZyb20gYHN0ZXBfcmV0cnlpbmdgIG9uLCB0aGUgc3RlcCBpcyBxdWV1ZS1vd25lZCBieSBpdHNcbiAqIGRlbGF5ZWQgcmV0cnkgaGFuZG9mZiAvIHJlcGxheSByZXF1ZXVlLCBzbyBvd25lcnNoaXAgaXMgcGVybWFuZW50bHlcbiAqIGxhcHNlZCBmb3IgdGhlIGNvcnJlbGF0aW9uIElEKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3RlcE93bmVyc2hpcEFjdGl2ZShzdGVwOiBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSk6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIHN0ZXAuaGFzQ3JlYXRlZEV2ZW50ID09PSB0cnVlICYmXG4gICAgc3RlcC5vd25lck1lc3NhZ2VJZCAhPT0gdW5kZWZpbmVkICYmXG4gICAgc3RlcC5zYXdSZXRyeWluZyAhPT0gdHJ1ZVxuICApO1xufVxuXG4vKipcbiAqIFNlY29uZHMgbGVmdCBvbiBhbiBvd25lZCBzdGVwJ3MgbGl2ZW5lc3MgbGVhc2UsIGFuY2hvcmVkIGF0IGl0cyBsYXRlc3RcbiAqIGBzdGVwX3N0YXJ0ZWRgLiAwIG1lYW5zIHRoZSBsZWFzZSBoYXMgZXhwaXJlZCAob3IgdGhlIHN0YXJ0IHRpbWVzdGFtcCBpc1xuICogbWlzc2luZyDigJQgdGhlIGRlZ3JhZGVkIG1vZGUgZm9yIHdvcmxkcyB3aG9zZSBldmVudHMgbGFjayB1c2FibGVcbiAqIHRpbWVzdGFtcHMpLCBpbiB3aGljaCBjYXNlIGRpc3BhdGNoIGZhbGxzIGJhY2sgdG8gdGhlIGltbWVkaWF0ZSBlbnF1ZXVlLlxuICpcbiAqIFRoZSByZXN1bHQgaXMgY2xhbXBlZCB0byB0aGUgY29uZmlndXJlZCBsZWFzZTogYGxhc3RTdGFydGVkQXRgIGlzIHRoZVxuICogc2VydmVyLXN0YW1wZWQgZXZlbnQgYGNyZWF0ZWRBdGAgd2hpbGUgYG5vd01zYCBpcyB0aGUgbG9jYWwgY2xvY2ssIHNvIGFcbiAqIGNsaWVudCBydW5uaW5nIGJlaGluZCB0aGUgc2VydmVyIHdvdWxkIG90aGVyd2lzZSBjb21wdXRlIGEgcmVtYWluZGVyXG4gKiBMT05HRVIgdGhhbiB0aGUgbGVhc2UgaXRzZWxmIOKAlCBhbmQgd2l0aCB0aGUgbGVhc2UgdHVuZWQgdG8gdGhlIDkwMHMgY2FwLFxuICogYSBgZGVsYXlTZWNvbmRzYCBhYm92ZSB0aGUgcXVldWUncyBwZXItbWVzc2FnZSBtYXhpbXVtLCB3aGljaCBTUVMtYmFja2VkXG4gKiB3b3JsZHMgcmVqZWN0IG91dHJpZ2h0ICh0aGUgd2FrZSByZXBsYXkncyBlbnF1ZXVlIHdvdWxkIHRocm93IGFuZCByaWRlXG4gKiB0aGUgcmVkZWxpdmVyeSBsb29wKS4gVGhlIGNsYW1wIG1ha2VzIHNrZXcgc3RyaWN0bHkgaGFybWxlc3M7IHJlbWFpbmluZ1xuICogdGltZSBjYW4gbmV2ZXIgbGVnaXRpbWF0ZWx5IGV4Y2VlZCB0aGUgZnVsbCBsZWFzZSBhbnl3YXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdGVwTGVhc2VSZW1haW5pbmdTZWNvbmRzKFxuICBzdGVwOiBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSxcbiAgbm93TXM6IG51bWJlclxuKTogbnVtYmVyIHtcbiAgaWYgKHN0ZXAubGFzdFN0YXJ0ZWRBdCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gMDtcbiAgY29uc3QgbGVhc2VTZWNvbmRzID0gZ2V0SW5saW5lT3duZXJzaGlwTGVhc2VTZWNvbmRzKCk7XG4gIGNvbnN0IHJlbWFpbmluZ01zID0gc3RlcC5sYXN0U3RhcnRlZEF0ICsgbGVhc2VTZWNvbmRzICogMTAwMCAtIG5vd01zO1xuICByZXR1cm4gTWF0aC5taW4obGVhc2VTZWNvbmRzLCBNYXRoLm1heCgwLCBNYXRoLmNlaWwocmVtYWluaW5nTXMgLyAxMDAwKSkpO1xufVxuXG4vKipcbiAqIElkZW1wb3RlbmN5IGtleSBmb3IgdGhlIGRlbGF5ZWQgYmFja3N0b3Agd2FrZSBvZiBhbiBpbmxpbmUtb3duZWQgc3RlcC5cbiAqXG4gKiBUaGUga2V5IGlzIHNjb3BlZCB0byB0aGUgY3VycmVudCBPV05FUlNISVAgRVBPQ0gg4oCUIHRoZSB0aW1lc3RhbXAgb2YgdGhlXG4gKiBsYXRlc3QgYHN0ZXBfc3RhcnRlZGAg4oCUIG5vdCBqdXN0IHRoZSBjb3JyZWxhdGlvbiBJRC4gV2l0aGluIG9uZSBlcG9jaCxcbiAqIGV2ZXJ5IHdha2UgcmVwbGF5IGRlcml2ZXMgdGhlIHNhbWUga2V5LCBzbyBmYW4tb3V0IHN0YXlzIGNhcHBlZCBhdCBvbmVcbiAqIHBlbmRpbmcgYmFja3N0b3AgcGVyIHN0ZXAuIEJ1dCB3aGVuIG93bmVyIHJlY292ZXJ5IHJlLXN0YW1wcyB0aGUgc3RlcFxuICogKHF1ZXVlIHJlZGVsaXZlcnkgb2YgdGhlIG93bmluZyBtZXNzYWdlIOKGkiBuZXcgYHN0ZXBfc3RhcnRlZGAg4oaSIG5ld1xuICogYGxhc3RTdGFydGVkQXRgKSwgdGhlIGtleSBDSEFOR0VTLiBUaGlzIGlzIGxvYWQtYmVhcmluZyBmb3IgbGl2ZW5lc3M6XG4gKiBxdWV1ZXMgZGVkdXBlIGFuIGlkZW1wb3RlbmN5IGtleSBmb3IgdGhlIGxpZmV0aW1lIG9mIHRoZSBvcmlnaW5hbFxuICogbWVzc2FnZSDigJQgaW5jbHVkaW5nIHdoaWxlIGEgZGVsaXZlcnkgb2YgaXQgaXMgaW4gZmxpZ2h0IOKAlCBzbyBhIGJhY2tzdG9wXG4gKiB0aGF0IGZpcmVzIGR1cmluZyBhIHJlZnJlc2hlZCBsZWFzZSBhbmQgdHJpZXMgdG8gcmUtYXJtIHVuZGVyIGEgZml4ZWQga2V5XG4gKiB3b3VsZCBkZWR1cGUgYWdhaW5zdCBJVFNFTEYgYW5kIGJlIGRyb3BwZWQsIGxlYXZpbmcgbm8gZXNjYXBlIGhhdGNoIGlmXG4gKiB0aGUgcmVjb3ZlcmVkIG93bmVyIGxhdGVyIGRpZXMgd2l0aG91dCBmdXJ0aGVyIHJlZGVsaXZlcmllcy4gVGhlIGVwb2NoXG4gKiBzdWZmaXggZ2l2ZXMgdGhlIHJlLWFybSBhIGZyZXNoIGtleS4gUGVuZGluZyBiYWNrc3RvcHMgYXJlIGJvdW5kZWQgYnkgdGhlXG4gKiBudW1iZXIgb2Ygb3duZXJzaGlwIGVwb2NocywgaS5lLiB0aGUgcXVldWUncyByZWRlbGl2ZXJ5IGJ1ZGdldCBmb3IgdGhlXG4gKiBvd25pbmcgbWVzc2FnZS5cbiAqXG4gKiBUaGUgZXBvY2ggdmFsdWUgY29tZXMgZnJvbSB0aGUgcGVyc2lzdGVkIGV2ZW50J3MgYGNyZWF0ZWRBdGAsIHNvIGV2ZXJ5XG4gKiByZXBsYXllciBkZXJpdmVzIHRoZSBzYW1lIGtleS4gQ2FsbGVycyBvbmx5IGJ1aWxkIGJhY2tzdG9wcyB3aGVuIHRoZVxuICogbGVhc2UgaGFzIHRpbWUgcmVtYWluaW5nLCB3aGljaCByZXF1aXJlcyBgbGFzdFN0YXJ0ZWRBdGAgdG8gYmUgc2V0LlxuICpcbiAqIFRoZSBrZXkgbXVzdCBhbHNvIG5ldmVyIGJlIHRoZSBzdGVwIG1lc3NhZ2UncyBvd24gYGlkZW1wb3RlbmN5S2V5YFxuICogKHRoZSBiYXJlIGNvcnJlbGF0aW9uIElEKTogdGhlIG93bmVyJ3MgcmV0cnkgaGFuZG9mZiBlbnF1ZXVlcyB0aGUgc3RlcFxuICogdW5kZXIgdGhhdCBrZXkgd2l0aCBhIHNob3J0IGJhY2tvZmYsIGFuZCBhIHBlbmRpbmcgYmFja3N0b3Agc2hhcmluZyBpdFxuICogd291bGQgYWJzb3JiIHRoZSByZXRyeSDigJQgdHVybmluZyBhIDFzIGJhY2tvZmYgaW50byBhIGZ1bGwtbGVhc2Ugc3RhbGwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBiYWNrc3RvcElkZW1wb3RlbmN5S2V5KHN0ZXA6IFN0ZXBJbnZvY2F0aW9uUXVldWVJdGVtKTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke3N0ZXAuY29ycmVsYXRpb25JZH06YmFja3N0b3A6JHtzdGVwLmxhc3RTdGFydGVkQXR9YDtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGFueSBvZiB0aGUgZ2l2ZW4gcGVuZGluZyBjb3JyZWxhdGlvbiBJRHMgaXMgaW5saW5lLW93bmVkIGJ5XG4gKiBgbWVzc2FnZUlkYCBwZXIgdGhlIHJhdyBldmVudCBsb2c6IGl0cyBMQVRFU1QgYHN0ZXBfc3RhcnRlZGAgY2Fycmllc1xuICogYG93bmVyTWVzc2FnZUlkID09PSBtZXNzYWdlSWRgIGFuZCBubyBgc3RlcF9yZXRyeWluZ2AgZm9sbG93cyBpdC4gVXNlZCBieVxuICogdGhlIGJhY2tncm91bmQtc3RlcCBmYXN0IHBhdGgsIHdoaWNoIHNlZXMgcmF3IGV2ZW50cyAobm90IHRoZSByZXBsYXknc1xuICogcXVldWVJdGVtcyksIHRvIGRlY2lkZSB3aGV0aGVyIHRvIGZhbGwgdGhyb3VnaCB0byB0aGUgbWFpbiBsb29wIHNvIHRoaXNcbiAqIGludm9jYXRpb24gY2FuIHJlY292ZXIgYSBzdGVwIGl0IG93bnMgaW5zdGVhZCBvZiByZXR1cm5pbmcgYW5kIGxlYXZpbmcgaXRcbiAqIHRvIHRoZSBkZWxheWVkIGJhY2tzdG9wLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzUGVuZGluZ1N0ZXBPd25lZEJ5TWVzc2FnZShcbiAgZXZlbnRzOiBFdmVudFtdLFxuICBwZW5kaW5nQ29ycmVsYXRpb25JZHM6IFNldDxzdHJpbmcgfCB1bmRlZmluZWQ+LFxuICBtZXNzYWdlSWQ6IHN0cmluZ1xuKTogYm9vbGVhbiB7XG4gIC8vIExhdGVzdC13aW5zIHNjYW46IGV2ZW50cyBhcmUgaW4gbG9nIG9yZGVyLCBzbyBsYXRlciBlbnRyaWVzIG92ZXJ3cml0ZS5cbiAgLy8gQSBzdGVwX3JldHJ5aW5nIGxhcHNlcyBvd25lcnNoaXAgcGVybWFuZW50bHkgKG1hdGNoaW5nIHRoZSBzYXdSZXRyeWluZ1xuICAvLyBzZW1hbnRpY3Mgb2YgdGhlIHJlcGxheSBjb25zdW1lciBpbiBzdGVwLnRzKSDigJQgZnJvbSB0aGF0IHBvaW50IHRoZSBzdGVwXG4gIC8vIGlzIHF1ZXVlLW93bmVkLCB3aGF0ZXZlciBzdGFydHMgZm9sbG93LlxuICBjb25zdCBsYXRlc3RPd25lciA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+KCk7XG4gIGNvbnN0IHNhd1JldHJ5aW5nID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGZvciAoY29uc3QgZSBvZiBldmVudHMpIHtcbiAgICBpZiAoZS5jb3JyZWxhdGlvbklkID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgIGlmIChlLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfc3RhcnRlZCcpIHtcbiAgICAgIGNvbnN0IG93bmVyID1cbiAgICAgICAgJ2V2ZW50RGF0YScgaW4gZSAmJlxuICAgICAgICBlLmV2ZW50RGF0YSAmJlxuICAgICAgICAnb3duZXJNZXNzYWdlSWQnIGluIGUuZXZlbnREYXRhICYmXG4gICAgICAgIHR5cGVvZiBlLmV2ZW50RGF0YS5vd25lck1lc3NhZ2VJZCA9PT0gJ3N0cmluZydcbiAgICAgICAgICA/IGUuZXZlbnREYXRhLm93bmVyTWVzc2FnZUlkXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICBsYXRlc3RPd25lci5zZXQoZS5jb3JyZWxhdGlvbklkLCBvd25lcik7XG4gICAgfSBlbHNlIGlmIChlLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfcmV0cnlpbmcnKSB7XG4gICAgICBzYXdSZXRyeWluZy5hZGQoZS5jb3JyZWxhdGlvbklkKTtcbiAgICB9XG4gIH1cbiAgZm9yIChjb25zdCBpZCBvZiBwZW5kaW5nQ29ycmVsYXRpb25JZHMpIHtcbiAgICBpZiAoXG4gICAgICBpZCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAhc2F3UmV0cnlpbmcuaGFzKGlkKSAmJlxuICAgICAgbGF0ZXN0T3duZXIuZ2V0KGlkKSA9PT0gbWVzc2FnZUlkXG4gICAgKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuIl19
@@ -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":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAgC9D;;;;;;;;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,69 @@
1
+ import { runtimeLogger } from '../logger.js';
2
+ /**
3
+ * In-process single-flight for step body execution, keyed by
4
+ * `runId:correlationId`.
5
+ *
6
+ * This is a required companion to inline step ownership (see
7
+ * `isInlineOwnershipEnabled` in constants.ts): the ownership lease is a
8
+ * *death proof* only on platforms with a bounded invocation lifetime. On
9
+ * worlds without an invocation kill bound (world-local's single process,
10
+ * self-hosted deployments) a delayed backstop can fire while the owning
11
+ * execution is still mid-body — in the same process. This map absorbs that
12
+ * race: the loser awaits the winner's settlement and then acks WITHOUT
13
+ * executing. On Vercel Fluid compute it also absorbs same-instance races
14
+ * between an owner redelivery and a backstop.
15
+ *
16
+ * The loser must not ack-and-skip early (before the winner settles): a crash
17
+ * after an early ack would consume the loser's queue message while the
18
+ * winner's outcome is still unknown, potentially orphaning the step with no
19
+ * message left to drive it. Awaiting settlement first keeps the at-least-once
20
+ * envelope intact — if the loser's own invocation hits its deadline while
21
+ * waiting, its message redelivers and re-checks, degrading gracefully to
22
+ * polling.
23
+ *
24
+ * Cross-instance duplicates (two separate processes racing the same step)
25
+ * are out of scope here — that is what the ownership lease bounds on
26
+ * platforms where it is a death proof, and the documented residual risk on
27
+ * multi-instance self-hosted worlds (mitigate by raising
28
+ * `WORKFLOW_INLINE_OWNERSHIP_LEASE_SECONDS`).
29
+ */
30
+ const inFlightSteps = new Map();
31
+ /**
32
+ * Run `execute` unless an execution for the same run + step correlation ID is
33
+ * already in flight in this process. The winner's result is returned to the
34
+ * winner; a loser awaits the winner's settlement (success OR failure) and
35
+ * then returns `{ type: 'skipped' }` so its caller acks without running the
36
+ * body. A winner failure is not propagated to the loser — the winner's own
37
+ * queue message redelivers and drives the retry, so exactly one message
38
+ * keeps owning the outcome.
39
+ */
40
+ export async function runStepSingleFlight(runId, correlationId, execute) {
41
+ const key = `${runId}:${correlationId}`;
42
+ const existing = inFlightSteps.get(key);
43
+ if (existing) {
44
+ // warn (always printed, unlike debug/info): the single-flight is
45
+ // absorbing what would have been a duplicate execution — typically a
46
+ // delayed backstop or retry message landing in the same process while
47
+ // the owner is still mid-body. Rare by design; a burst of these means
48
+ // leases are expiring under live executions (raise
49
+ // WORKFLOW_INLINE_OWNERSHIP_LEASE_SECONDS).
50
+ runtimeLogger.warn('Step execution already in flight in this process; awaiting its settlement instead of executing again', { workflowRunId: runId, stepId: correlationId });
51
+ try {
52
+ await existing;
53
+ }
54
+ catch {
55
+ // The winner failed (typically a transient world error). Its own queue
56
+ // message redelivers and retries; this loser still just skips.
57
+ }
58
+ return { type: 'skipped' };
59
+ }
60
+ const promise = execute();
61
+ inFlightSteps.set(key, promise);
62
+ try {
63
+ return await promise;
64
+ }
65
+ finally {
66
+ inFlightSteps.delete(key);
67
+ }
68
+ }
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1zaW5nbGUtZmxpZ2h0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvc3RlcC1zaW5nbGUtZmxpZ2h0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFHN0M7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJCRztBQUNILE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxFQUF3QyxDQUFDO0FBRXRFOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxtQkFBbUIsQ0FDdkMsS0FBYSxFQUNiLGFBQXFCLEVBQ3JCLE9BQTJDO0lBRTNDLE1BQU0sR0FBRyxHQUFHLEdBQUcsS0FBSyxJQUFJLGFBQWEsRUFBRSxDQUFDO0lBQ3hDLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDeEMsSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUNiLGlFQUFpRTtRQUNqRSxxRUFBcUU7UUFDckUsc0VBQXNFO1FBQ3RFLHNFQUFzRTtRQUN0RSxtREFBbUQ7UUFDbkQsNENBQTRDO1FBQzVDLGFBQWEsQ0FBQyxJQUFJLENBQ2hCLHNHQUFzRyxFQUN0RyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxDQUNoRCxDQUFDO1FBQ0YsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLENBQUM7UUFDakIsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLHVFQUF1RTtZQUN2RSwrREFBK0Q7UUFDakUsQ0FBQztRQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLE9BQU8sRUFBRSxDQUFDO0lBQzFCLGFBQWEsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ2hDLElBQUksQ0FBQztRQUNILE9BQU8sTUFBTSxPQUFPLENBQUM7SUFDdkIsQ0FBQztZQUFTLENBQUM7UUFDVCxhQUFhLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzVCLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgdHlwZSB7IFN0ZXBFeGVjdXRpb25SZXN1bHQgfSBmcm9tICcuL3N0ZXAtZXhlY3V0b3IuanMnO1xuXG4vKipcbiAqIEluLXByb2Nlc3Mgc2luZ2xlLWZsaWdodCBmb3Igc3RlcCBib2R5IGV4ZWN1dGlvbiwga2V5ZWQgYnlcbiAqIGBydW5JZDpjb3JyZWxhdGlvbklkYC5cbiAqXG4gKiBUaGlzIGlzIGEgcmVxdWlyZWQgY29tcGFuaW9uIHRvIGlubGluZSBzdGVwIG93bmVyc2hpcCAoc2VlXG4gKiBgaXNJbmxpbmVPd25lcnNoaXBFbmFibGVkYCBpbiBjb25zdGFudHMudHMpOiB0aGUgb3duZXJzaGlwIGxlYXNlIGlzIGFcbiAqICpkZWF0aCBwcm9vZiogb25seSBvbiBwbGF0Zm9ybXMgd2l0aCBhIGJvdW5kZWQgaW52b2NhdGlvbiBsaWZldGltZS4gT25cbiAqIHdvcmxkcyB3aXRob3V0IGFuIGludm9jYXRpb24ga2lsbCBib3VuZCAod29ybGQtbG9jYWwncyBzaW5nbGUgcHJvY2VzcyxcbiAqIHNlbGYtaG9zdGVkIGRlcGxveW1lbnRzKSBhIGRlbGF5ZWQgYmFja3N0b3AgY2FuIGZpcmUgd2hpbGUgdGhlIG93bmluZ1xuICogZXhlY3V0aW9uIGlzIHN0aWxsIG1pZC1ib2R5IOKAlCBpbiB0aGUgc2FtZSBwcm9jZXNzLiBUaGlzIG1hcCBhYnNvcmJzIHRoYXRcbiAqIHJhY2U6IHRoZSBsb3NlciBhd2FpdHMgdGhlIHdpbm5lcidzIHNldHRsZW1lbnQgYW5kIHRoZW4gYWNrcyBXSVRIT1VUXG4gKiBleGVjdXRpbmcuIE9uIFZlcmNlbCBGbHVpZCBjb21wdXRlIGl0IGFsc28gYWJzb3JicyBzYW1lLWluc3RhbmNlIHJhY2VzXG4gKiBiZXR3ZWVuIGFuIG93bmVyIHJlZGVsaXZlcnkgYW5kIGEgYmFja3N0b3AuXG4gKlxuICogVGhlIGxvc2VyIG11c3Qgbm90IGFjay1hbmQtc2tpcCBlYXJseSAoYmVmb3JlIHRoZSB3aW5uZXIgc2V0dGxlcyk6IGEgY3Jhc2hcbiAqIGFmdGVyIGFuIGVhcmx5IGFjayB3b3VsZCBjb25zdW1lIHRoZSBsb3NlcidzIHF1ZXVlIG1lc3NhZ2Ugd2hpbGUgdGhlXG4gKiB3aW5uZXIncyBvdXRjb21lIGlzIHN0aWxsIHVua25vd24sIHBvdGVudGlhbGx5IG9ycGhhbmluZyB0aGUgc3RlcCB3aXRoIG5vXG4gKiBtZXNzYWdlIGxlZnQgdG8gZHJpdmUgaXQuIEF3YWl0aW5nIHNldHRsZW1lbnQgZmlyc3Qga2VlcHMgdGhlIGF0LWxlYXN0LW9uY2VcbiAqIGVudmVsb3BlIGludGFjdCDigJQgaWYgdGhlIGxvc2VyJ3Mgb3duIGludm9jYXRpb24gaGl0cyBpdHMgZGVhZGxpbmUgd2hpbGVcbiAqIHdhaXRpbmcsIGl0cyBtZXNzYWdlIHJlZGVsaXZlcnMgYW5kIHJlLWNoZWNrcywgZGVncmFkaW5nIGdyYWNlZnVsbHkgdG9cbiAqIHBvbGxpbmcuXG4gKlxuICogQ3Jvc3MtaW5zdGFuY2UgZHVwbGljYXRlcyAodHdvIHNlcGFyYXRlIHByb2Nlc3NlcyByYWNpbmcgdGhlIHNhbWUgc3RlcClcbiAqIGFyZSBvdXQgb2Ygc2NvcGUgaGVyZSDigJQgdGhhdCBpcyB3aGF0IHRoZSBvd25lcnNoaXAgbGVhc2UgYm91bmRzIG9uXG4gKiBwbGF0Zm9ybXMgd2hlcmUgaXQgaXMgYSBkZWF0aCBwcm9vZiwgYW5kIHRoZSBkb2N1bWVudGVkIHJlc2lkdWFsIHJpc2sgb25cbiAqIG11bHRpLWluc3RhbmNlIHNlbGYtaG9zdGVkIHdvcmxkcyAobWl0aWdhdGUgYnkgcmFpc2luZ1xuICogYFdPUktGTE9XX0lOTElORV9PV05FUlNISVBfTEVBU0VfU0VDT05EU2ApLlxuICovXG5jb25zdCBpbkZsaWdodFN0ZXBzID0gbmV3IE1hcDxzdHJpbmcsIFByb21pc2U8U3RlcEV4ZWN1dGlvblJlc3VsdD4+KCk7XG5cbi8qKlxuICogUnVuIGBleGVjdXRlYCB1bmxlc3MgYW4gZXhlY3V0aW9uIGZvciB0aGUgc2FtZSBydW4gKyBzdGVwIGNvcnJlbGF0aW9uIElEIGlzXG4gKiBhbHJlYWR5IGluIGZsaWdodCBpbiB0aGlzIHByb2Nlc3MuIFRoZSB3aW5uZXIncyByZXN1bHQgaXMgcmV0dXJuZWQgdG8gdGhlXG4gKiB3aW5uZXI7IGEgbG9zZXIgYXdhaXRzIHRoZSB3aW5uZXIncyBzZXR0bGVtZW50IChzdWNjZXNzIE9SIGZhaWx1cmUpIGFuZFxuICogdGhlbiByZXR1cm5zIGB7IHR5cGU6ICdza2lwcGVkJyB9YCBzbyBpdHMgY2FsbGVyIGFja3Mgd2l0aG91dCBydW5uaW5nIHRoZVxuICogYm9keS4gQSB3aW5uZXIgZmFpbHVyZSBpcyBub3QgcHJvcGFnYXRlZCB0byB0aGUgbG9zZXIg4oCUIHRoZSB3aW5uZXIncyBvd25cbiAqIHF1ZXVlIG1lc3NhZ2UgcmVkZWxpdmVycyBhbmQgZHJpdmVzIHRoZSByZXRyeSwgc28gZXhhY3RseSBvbmUgbWVzc2FnZVxuICoga2VlcHMgb3duaW5nIHRoZSBvdXRjb21lLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuU3RlcFNpbmdsZUZsaWdodChcbiAgcnVuSWQ6IHN0cmluZyxcbiAgY29ycmVsYXRpb25JZDogc3RyaW5nLFxuICBleGVjdXRlOiAoKSA9PiBQcm9taXNlPFN0ZXBFeGVjdXRpb25SZXN1bHQ+XG4pOiBQcm9taXNlPFN0ZXBFeGVjdXRpb25SZXN1bHQ+IHtcbiAgY29uc3Qga2V5ID0gYCR7cnVuSWR9OiR7Y29ycmVsYXRpb25JZH1gO1xuICBjb25zdCBleGlzdGluZyA9IGluRmxpZ2h0U3RlcHMuZ2V0KGtleSk7XG4gIGlmIChleGlzdGluZykge1xuICAgIC8vIHdhcm4gKGFsd2F5cyBwcmludGVkLCB1bmxpa2UgZGVidWcvaW5mbyk6IHRoZSBzaW5nbGUtZmxpZ2h0IGlzXG4gICAgLy8gYWJzb3JiaW5nIHdoYXQgd291bGQgaGF2ZSBiZWVuIGEgZHVwbGljYXRlIGV4ZWN1dGlvbiDigJQgdHlwaWNhbGx5IGFcbiAgICAvLyBkZWxheWVkIGJhY2tzdG9wIG9yIHJldHJ5IG1lc3NhZ2UgbGFuZGluZyBpbiB0aGUgc2FtZSBwcm9jZXNzIHdoaWxlXG4gICAgLy8gdGhlIG93bmVyIGlzIHN0aWxsIG1pZC1ib2R5LiBSYXJlIGJ5IGRlc2lnbjsgYSBidXJzdCBvZiB0aGVzZSBtZWFuc1xuICAgIC8vIGxlYXNlcyBhcmUgZXhwaXJpbmcgdW5kZXIgbGl2ZSBleGVjdXRpb25zIChyYWlzZVxuICAgIC8vIFdPUktGTE9XX0lOTElORV9PV05FUlNISVBfTEVBU0VfU0VDT05EUykuXG4gICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgJ1N0ZXAgZXhlY3V0aW9uIGFscmVhZHkgaW4gZmxpZ2h0IGluIHRoaXMgcHJvY2VzczsgYXdhaXRpbmcgaXRzIHNldHRsZW1lbnQgaW5zdGVhZCBvZiBleGVjdXRpbmcgYWdhaW4nLFxuICAgICAgeyB3b3JrZmxvd1J1bklkOiBydW5JZCwgc3RlcElkOiBjb3JyZWxhdGlvbklkIH1cbiAgICApO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBleGlzdGluZztcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIFRoZSB3aW5uZXIgZmFpbGVkICh0eXBpY2FsbHkgYSB0cmFuc2llbnQgd29ybGQgZXJyb3IpLiBJdHMgb3duIHF1ZXVlXG4gICAgICAvLyBtZXNzYWdlIHJlZGVsaXZlcnMgYW5kIHJldHJpZXM7IHRoaXMgbG9zZXIgc3RpbGwganVzdCBza2lwcy5cbiAgICB9XG4gICAgcmV0dXJuIHsgdHlwZTogJ3NraXBwZWQnIH07XG4gIH1cblxuICBjb25zdCBwcm9taXNlID0gZXhlY3V0ZSgpO1xuICBpbkZsaWdodFN0ZXBzLnNldChrZXksIHByb21pc2UpO1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBwcm9taXNlO1xuICB9IGZpbmFsbHkge1xuICAgIGluRmxpZ2h0U3RlcHMuZGVsZXRlKGtleSk7XG4gIH1cbn1cbiJdfQ==