@workflow/core 5.0.0-beta.4 → 5.0.0-beta.40

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 (325) 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 +33 -1
  5. package/dist/capabilities.d.ts.map +1 -1
  6. package/dist/capabilities.js +71 -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 +109 -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 +149 -0
  22. package/dist/correlation-id.d.ts +109 -0
  23. package/dist/correlation-id.d.ts.map +1 -0
  24. package/dist/correlation-id.js +139 -0
  25. package/dist/create-hook.d.ts +62 -4
  26. package/dist/create-hook.d.ts.map +1 -1
  27. package/dist/create-hook.js +4 -3
  28. package/dist/define-hook.d.ts.map +1 -1
  29. package/dist/define-hook.js +20 -5
  30. package/dist/describe-error.d.ts +70 -0
  31. package/dist/describe-error.d.ts.map +1 -0
  32. package/dist/describe-error.js +189 -0
  33. package/dist/encryption.d.ts +37 -3
  34. package/dist/encryption.d.ts.map +1 -1
  35. package/dist/encryption.js +97 -31
  36. package/dist/events-consumer.d.ts +26 -1
  37. package/dist/events-consumer.d.ts.map +1 -1
  38. package/dist/events-consumer.js +105 -18
  39. package/dist/flushable-stream.d.ts +65 -10
  40. package/dist/flushable-stream.d.ts.map +1 -1
  41. package/dist/flushable-stream.js +131 -18
  42. package/dist/global.d.ts +37 -1
  43. package/dist/global.d.ts.map +1 -1
  44. package/dist/global.js +21 -3
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +2 -1
  48. package/dist/log-format.d.ts +25 -0
  49. package/dist/log-format.d.ts.map +1 -0
  50. package/dist/log-format.js +250 -0
  51. package/dist/logger.d.ts +29 -30
  52. package/dist/logger.d.ts.map +1 -1
  53. package/dist/logger.js +82 -32
  54. package/dist/private.d.ts +178 -9
  55. package/dist/private.d.ts.map +1 -1
  56. package/dist/private.js +273 -9
  57. package/dist/replay-payload-cache.d.ts +68 -0
  58. package/dist/replay-payload-cache.d.ts.map +1 -0
  59. package/dist/replay-payload-cache.js +160 -0
  60. package/dist/runtime/compute-instance.d.ts +12 -0
  61. package/dist/runtime/compute-instance.d.ts.map +1 -0
  62. package/dist/runtime/compute-instance.js +13 -0
  63. package/dist/runtime/constants.d.ts +237 -0
  64. package/dist/runtime/constants.d.ts.map +1 -1
  65. package/dist/runtime/constants.js +405 -15
  66. package/dist/runtime/count-step-started-events.d.ts +52 -0
  67. package/dist/runtime/count-step-started-events.d.ts.map +1 -0
  68. package/dist/runtime/count-step-started-events.js +72 -0
  69. package/dist/runtime/deployment-guard.d.ts +99 -0
  70. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  71. package/dist/runtime/deployment-guard.js +154 -0
  72. package/dist/runtime/get-port-lazy.d.ts +25 -0
  73. package/dist/runtime/get-port-lazy.d.ts.map +1 -0
  74. package/dist/runtime/get-port-lazy.js +92 -0
  75. package/dist/runtime/get-world-lazy.d.ts +23 -0
  76. package/dist/runtime/get-world-lazy.d.ts.map +1 -0
  77. package/dist/runtime/get-world-lazy.js +46 -0
  78. package/dist/runtime/helpers.d.ts +219 -10
  79. package/dist/runtime/helpers.d.ts.map +1 -1
  80. package/dist/runtime/helpers.js +414 -40
  81. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  82. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  83. package/dist/runtime/quickjs-assets.generated.js +30 -0
  84. package/dist/runtime/quickjs-entrypoint.d.ts +124 -0
  85. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  86. package/dist/runtime/quickjs-entrypoint.js +1429 -0
  87. package/dist/runtime/quickjs-runtime.d.ts +193 -0
  88. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  89. package/dist/runtime/quickjs-runtime.js +1944 -0
  90. package/dist/runtime/replay-budget.d.ts +98 -0
  91. package/dist/runtime/replay-budget.d.ts.map +1 -0
  92. package/dist/runtime/replay-budget.js +192 -0
  93. package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
  94. package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
  95. package/dist/runtime/replay-recovery-reporter.js +64 -0
  96. package/dist/runtime/resume-hook.d.ts +27 -4
  97. package/dist/runtime/resume-hook.d.ts.map +1 -1
  98. package/dist/runtime/resume-hook.js +448 -76
  99. package/dist/runtime/run-id-time.d.ts +19 -0
  100. package/dist/runtime/run-id-time.d.ts.map +1 -0
  101. package/dist/runtime/run-id-time.js +42 -0
  102. package/dist/runtime/run.d.ts +8 -2
  103. package/dist/runtime/run.d.ts.map +1 -1
  104. package/dist/runtime/run.js +62 -15
  105. package/dist/runtime/runs.d.ts +54 -3
  106. package/dist/runtime/runs.d.ts.map +1 -1
  107. package/dist/runtime/runs.js +117 -10
  108. package/dist/runtime/start.d.ts +70 -1
  109. package/dist/runtime/start.d.ts.map +1 -1
  110. package/dist/runtime/start.js +312 -54
  111. package/dist/runtime/step-executor.d.ts +177 -0
  112. package/dist/runtime/step-executor.d.ts.map +1 -0
  113. package/dist/runtime/step-executor.js +949 -0
  114. package/dist/runtime/step-latency.d.ts +197 -0
  115. package/dist/runtime/step-latency.d.ts.map +1 -0
  116. package/dist/runtime/step-latency.js +207 -0
  117. package/dist/runtime/step-ownership.d.ts +72 -0
  118. package/dist/runtime/step-ownership.d.ts.map +1 -0
  119. package/dist/runtime/step-ownership.js +114 -0
  120. package/dist/runtime/step-single-flight.d.ts +12 -0
  121. package/dist/runtime/step-single-flight.d.ts.map +1 -0
  122. package/dist/runtime/step-single-flight.js +69 -0
  123. package/dist/runtime/suspension-handler.d.ts +102 -7
  124. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  125. package/dist/runtime/suspension-handler.js +439 -140
  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 +84 -0
  133. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  134. package/dist/runtime/wait-continuation.js +105 -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 +5 -0
  139. package/dist/runtime/world-compatibility.d.ts.map +1 -0
  140. package/dist/runtime/world-compatibility.js +12 -0
  141. package/dist/runtime/world-init.d.ts +50 -0
  142. package/dist/runtime/world-init.d.ts.map +1 -0
  143. package/dist/runtime/world-init.js +50 -0
  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 +101 -26
  147. package/dist/runtime.d.ts +17 -12
  148. package/dist/runtime.d.ts.map +1 -1
  149. package/dist/runtime.js +3078 -327
  150. package/dist/schemas.d.ts +1 -1
  151. package/dist/schemas.d.ts.map +1 -1
  152. package/dist/schemas.js +1 -1
  153. package/dist/sealed-box.d.ts +167 -0
  154. package/dist/sealed-box.d.ts.map +1 -0
  155. package/dist/sealed-box.js +571 -0
  156. package/dist/serialization/client.d.ts +17 -0
  157. package/dist/serialization/client.d.ts.map +1 -0
  158. package/dist/serialization/client.js +48 -0
  159. package/dist/serialization/codec-devalue-vm.d.ts +9 -0
  160. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  161. package/dist/serialization/codec-devalue-vm.js +137 -0
  162. package/dist/serialization/codec-devalue.d.ts +14 -0
  163. package/dist/serialization/codec-devalue.d.ts.map +1 -0
  164. package/dist/serialization/codec-devalue.js +105 -0
  165. package/dist/serialization/codec.d.ts +125 -0
  166. package/dist/serialization/codec.d.ts.map +1 -0
  167. package/dist/serialization/codec.js +17 -0
  168. package/dist/serialization/compression.d.ts +104 -0
  169. package/dist/serialization/compression.d.ts.map +1 -0
  170. package/dist/serialization/compression.js +260 -0
  171. package/dist/serialization/encryption.d.ts +134 -0
  172. package/dist/serialization/encryption.d.ts.map +1 -0
  173. package/dist/serialization/encryption.js +186 -0
  174. package/dist/serialization/errors.d.ts +34 -0
  175. package/dist/serialization/errors.d.ts.map +1 -0
  176. package/dist/serialization/errors.js +59 -0
  177. package/dist/serialization/format.d.ts +60 -0
  178. package/dist/serialization/format.d.ts.map +1 -0
  179. package/dist/serialization/format.js +97 -0
  180. package/dist/serialization/hardened.d.ts +155 -0
  181. package/dist/serialization/hardened.d.ts.map +1 -0
  182. package/dist/serialization/hardened.js +523 -0
  183. package/dist/serialization/index.d.ts +20 -0
  184. package/dist/serialization/index.d.ts.map +1 -0
  185. package/dist/serialization/index.js +22 -0
  186. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  187. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  188. package/dist/serialization/reducers/class-vm.js +77 -0
  189. package/dist/serialization/reducers/class.d.ts +11 -0
  190. package/dist/serialization/reducers/class.d.ts.map +1 -0
  191. package/dist/serialization/reducers/class.js +73 -0
  192. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  193. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  194. package/dist/serialization/reducers/common-vm.js +579 -0
  195. package/dist/serialization/reducers/common.d.ts +16 -0
  196. package/dist/serialization/reducers/common.d.ts.map +1 -0
  197. package/dist/serialization/reducers/common.js +478 -0
  198. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  199. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  200. package/dist/serialization/reducers/step-function-vm.js +97 -0
  201. package/dist/serialization/reducers/step-function.d.ts +35 -0
  202. package/dist/serialization/reducers/step-function.d.ts.map +1 -0
  203. package/dist/serialization/reducers/step-function.js +104 -0
  204. package/dist/serialization/step.d.ts +17 -0
  205. package/dist/serialization/step.d.ts.map +1 -0
  206. package/dist/serialization/step.js +48 -0
  207. package/dist/serialization/types.d.ts +273 -0
  208. package/dist/serialization/types.d.ts.map +1 -0
  209. package/dist/serialization/types.js +35 -0
  210. package/dist/serialization/vm-bundle-entry.d.ts +12 -0
  211. package/dist/serialization/vm-bundle-entry.d.ts.map +1 -0
  212. package/dist/serialization/vm-bundle-entry.js +58 -0
  213. package/dist/serialization/workflow-vm.d.ts +24 -0
  214. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  215. package/dist/serialization/workflow-vm.js +66 -0
  216. package/dist/serialization/workflow.d.ts +29 -0
  217. package/dist/serialization/workflow.d.ts.map +1 -0
  218. package/dist/serialization/workflow.js +54 -0
  219. package/dist/serialization-format.d.ts +60 -4
  220. package/dist/serialization-format.d.ts.map +1 -1
  221. package/dist/serialization-format.js +276 -56
  222. package/dist/serialization.d.ts +374 -221
  223. package/dist/serialization.d.ts.map +1 -1
  224. package/dist/serialization.js +2300 -783
  225. package/dist/set-attributes.d.ts +13 -0
  226. package/dist/set-attributes.d.ts.map +1 -0
  227. package/dist/set-attributes.js +60 -0
  228. package/dist/sleep.d.ts.map +1 -1
  229. package/dist/sleep.js +3 -2
  230. package/dist/source-map.d.ts +25 -0
  231. package/dist/source-map.d.ts.map +1 -1
  232. package/dist/source-map.js +148 -10
  233. package/dist/step/context-storage.d.ts +61 -2
  234. package/dist/step/context-storage.d.ts.map +1 -1
  235. package/dist/step/context-storage.js +7 -5
  236. package/dist/step/get-closure-vars.d.ts.map +1 -1
  237. package/dist/step/get-closure-vars.js +3 -2
  238. package/dist/step/get-step-metadata.d.ts.map +1 -1
  239. package/dist/step/get-step-metadata.js +3 -2
  240. package/dist/step/get-workflow-metadata.d.ts.map +1 -1
  241. package/dist/step/get-workflow-metadata.js +3 -2
  242. package/dist/step/writable-stream.d.ts.map +1 -1
  243. package/dist/step/writable-stream.js +71 -7
  244. package/dist/step.d.ts.map +1 -1
  245. package/dist/step.js +226 -30
  246. package/dist/symbols.d.ts +54 -0
  247. package/dist/symbols.d.ts.map +1 -1
  248. package/dist/symbols.js +55 -1
  249. package/dist/telemetry/semantic-conventions.d.ts +242 -2
  250. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  251. package/dist/telemetry/semantic-conventions.js +173 -1
  252. package/dist/telemetry.d.ts +73 -0
  253. package/dist/telemetry.d.ts.map +1 -1
  254. package/dist/telemetry.js +153 -16
  255. package/dist/types.d.ts +6 -0
  256. package/dist/types.d.ts.map +1 -1
  257. package/dist/types.js +23 -1
  258. package/dist/util.d.ts +16 -6
  259. package/dist/util.d.ts.map +1 -1
  260. package/dist/util.js +25 -16
  261. package/dist/version.d.ts +1 -1
  262. package/dist/version.d.ts.map +1 -1
  263. package/dist/version.js +2 -2
  264. package/dist/vm/index.d.ts.map +1 -1
  265. package/dist/vm/index.js +77 -9
  266. package/dist/vm/script-cache.d.ts +28 -0
  267. package/dist/vm/script-cache.d.ts.map +1 -0
  268. package/dist/vm/script-cache.js +140 -0
  269. package/dist/workflow/abort-controller.d.ts +65 -0
  270. package/dist/workflow/abort-controller.d.ts.map +1 -0
  271. package/dist/workflow/abort-controller.js +314 -0
  272. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  273. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  274. package/dist/workflow/attribute-dispatcher.js +48 -0
  275. package/dist/workflow/create-hook.d.ts.map +1 -1
  276. package/dist/workflow/create-hook.js +25 -3
  277. package/dist/workflow/define-hook.d.ts +1 -1
  278. package/dist/workflow/define-hook.d.ts.map +1 -1
  279. package/dist/workflow/define-hook.js +8 -4
  280. package/dist/workflow/get-workflow-metadata.d.ts.map +1 -1
  281. package/dist/workflow/get-workflow-metadata.js +14 -3
  282. package/dist/workflow/hook.d.ts.map +1 -1
  283. package/dist/workflow/hook.js +303 -37
  284. package/dist/workflow/index.d.ts +1 -0
  285. package/dist/workflow/index.d.ts.map +1 -1
  286. package/dist/workflow/index.js +5 -3
  287. package/dist/workflow/set-attributes.d.ts +68 -0
  288. package/dist/workflow/set-attributes.d.ts.map +1 -0
  289. package/dist/workflow/set-attributes.js +60 -0
  290. package/dist/workflow/sleep.d.ts.map +1 -1
  291. package/dist/workflow/sleep.js +58 -9
  292. package/dist/workflow/world-init-stub.d.ts +15 -0
  293. package/dist/workflow/world-init-stub.d.ts.map +1 -0
  294. package/dist/workflow/world-init-stub.js +15 -0
  295. package/dist/workflow.d.ts +69 -3
  296. package/dist/workflow.d.ts.map +1 -1
  297. package/dist/workflow.js +791 -554
  298. package/docs/api-reference/create-hook.mdx +79 -0
  299. package/docs/api-reference/create-webhook.mdx +1 -0
  300. package/docs/api-reference/define-hook.mdx +26 -24
  301. package/docs/api-reference/fatal-error.mdx +29 -7
  302. package/docs/api-reference/fetch.mdx +8 -4
  303. package/docs/api-reference/index.mdx +3 -0
  304. package/docs/api-reference/set-attributes.mdx +61 -0
  305. package/docs/api-reference/sleep.mdx +1 -1
  306. package/docs/foundations/cancellation.mdx +459 -0
  307. package/docs/foundations/errors-and-retries.mdx +7 -3
  308. package/docs/foundations/hooks.mdx +29 -0
  309. package/docs/foundations/idempotency.mdx +243 -11
  310. package/docs/foundations/index.mdx +1 -23
  311. package/docs/foundations/meta.json +3 -1
  312. package/docs/foundations/serialization.mdx +77 -41
  313. package/docs/foundations/starting-workflows.mdx +79 -2
  314. package/docs/foundations/streaming.mdx +14 -23
  315. package/docs/foundations/versioning.mdx +263 -0
  316. package/docs/how-it-works/cancellation.mdx +287 -0
  317. package/docs/how-it-works/code-transform.mdx +21 -17
  318. package/docs/how-it-works/encryption.mdx +5 -5
  319. package/docs/how-it-works/event-sourcing.mdx +6 -6
  320. package/docs/how-it-works/framework-integrations.mdx +96 -337
  321. package/docs/how-it-works/meta.json +2 -1
  322. package/package.json +31 -13
  323. package/dist/runtime/step-handler.d.ts +0 -2
  324. package/dist/runtime/step-handler.d.ts.map +0 -1
  325. package/dist/runtime/step-handler.js +0 -678
@@ -0,0 +1,72 @@
1
+ const ownerOf = (e) => 'eventData' in e &&
2
+ e.eventData &&
3
+ 'ownerMessageId' in e.eventData &&
4
+ typeof e.eventData.ownerMessageId === 'string'
5
+ ? e.eventData.ownerMessageId
6
+ : undefined;
7
+ /**
8
+ * Number of `step_started` events already recorded for a step, used as the
9
+ * authoritative attempt count for the maxRetries ceiling (the only bound for
10
+ * steps that time out without writing a `step_failed`).
11
+ *
12
+ * IMPORTANT: the raw (unscoped) count is NOT a reliable attempt number.
13
+ * Concurrent invocations racing on the same pending batch (stale replays,
14
+ * wake replays, a step message dispatched by a replay that lost the
15
+ * create-claim race, ...) can each write a `step_started` for the same
16
+ * logical attempt — worlds without an atomic start guard (world-local) let
17
+ * all of them through. Counting those duplicates as "attempts" made the
18
+ * maxRetries ceiling fire on healthy runs and fail them with a false
19
+ * "exceeded max retries" (see workflow#3069).
20
+ *
21
+ * Callers therefore scope the count to the starts their ceiling is actually
22
+ * about via `scope`:
23
+ * - the inline owned-recovery ceiling counts only THIS message's starts
24
+ * (`ownedBy`) — each real (re)delivery of the owning message stamps its
25
+ * `ownerMessageId` on the start it writes, while racing invocations stamp
26
+ * their own IDs (or none), so they no longer inflate the count;
27
+ * - the background-step ceiling counts the lifecycle attempt total
28
+ * (`totalAttempts`: bare starts plus the largest single owner's starts) —
29
+ * so a step that exhausted part of its budget under inline ownership
30
+ * before transitioning to queued/bare retries still trips the combined
31
+ * ceiling, while racers' one-off stamped duplicates don't accumulate, and
32
+ * throttle/too-early redeliveries (which write no start at all) stay
33
+ * excluded as before.
34
+ */
35
+ export function countStepStartedEvents(events, stepId, scope) {
36
+ if (!events) {
37
+ return 0;
38
+ }
39
+ let bare = 0;
40
+ const byOwner = new Map();
41
+ for (const e of events) {
42
+ if (e.eventType !== 'step_started' || e.correlationId !== stepId) {
43
+ continue;
44
+ }
45
+ const owner = ownerOf(e);
46
+ if (owner === undefined) {
47
+ bare++;
48
+ }
49
+ else {
50
+ byOwner.set(owner, (byOwner.get(owner) ?? 0) + 1);
51
+ }
52
+ }
53
+ if (scope === undefined) {
54
+ let total = bare;
55
+ for (const count of byOwner.values()) {
56
+ total += count;
57
+ }
58
+ return total;
59
+ }
60
+ if (scope.type === 'ownedBy') {
61
+ return byOwner.get(scope.messageId) ?? 0;
62
+ }
63
+ // totalAttempts
64
+ let maxOwner = 0;
65
+ for (const count of byOwner.values()) {
66
+ if (count > maxOwner) {
67
+ maxOwner = count;
68
+ }
69
+ }
70
+ return bare + maxOwner;
71
+ }
72
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY291bnQtc3RlcC1zdGFydGVkLWV2ZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2NvdW50LXN0ZXAtc3RhcnRlZC1ldmVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBcUJBLE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBUSxFQUFzQixFQUFFLENBQy9DLFdBQVcsSUFBSSxDQUFDO0lBQ2hCLENBQUMsQ0FBQyxTQUFTO0lBQ1gsZ0JBQWdCLElBQUksQ0FBQyxDQUFDLFNBQVM7SUFDL0IsT0FBTyxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQWMsS0FBSyxRQUFRO0lBQzVDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQWM7SUFDNUIsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUVoQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMkJHO0FBQ0gsTUFBTSxVQUFVLHNCQUFzQixDQUNwQyxNQUFrQyxFQUNsQyxNQUFjLEVBQ2QsS0FBc0I7SUFFdEIsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ1osT0FBTyxDQUFDLENBQUM7SUFDWCxDQUFDO0lBQ0QsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBQ2IsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7SUFDMUMsS0FBSyxNQUFNLENBQUMsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsQ0FBQyxTQUFTLEtBQUssY0FBYyxJQUFJLENBQUMsQ0FBQyxhQUFhLEtBQUssTUFBTSxFQUFFLENBQUM7WUFDakUsU0FBUztRQUNYLENBQUM7UUFDRCxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDekIsSUFBSSxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDeEIsSUFBSSxFQUFFLENBQUM7UUFDVCxDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNwRCxDQUFDO0lBQ0gsQ0FBQztJQUNELElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3hCLElBQUksS0FBSyxHQUFHLElBQUksQ0FBQztRQUNqQixLQUFLLE1BQU0sS0FBSyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQ3JDLEtBQUssSUFBSSxLQUFLLENBQUM7UUFDakIsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUNELElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUM3QixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBQ0QsZ0JBQWdCO0lBQ2hCLElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQztJQUNqQixLQUFLLE1BQU0sS0FBSyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBQ3JDLElBQUksS0FBSyxHQUFHLFFBQVEsRUFBRSxDQUFDO1lBQ3JCLFFBQVEsR0FBRyxLQUFLLENBQUM7UUFDbkIsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLElBQUksR0FBRyxRQUFRLENBQUM7QUFDekIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRXZlbnQgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuXG4vKipcbiAqIFNjb3BlIGZvciB7QGxpbmsgY291bnRTdGVwU3RhcnRlZEV2ZW50c306XG4gKiAtIGB7IHR5cGU6ICdvd25lZEJ5JywgbWVzc2FnZUlkIH1gIGNvdW50cyBvbmx5IHN0YXJ0cyB3aG9zZVxuICogICBgZXZlbnREYXRhLm93bmVyTWVzc2FnZUlkYCBtYXRjaGVzIOKAlCBpLmUuIGF0dGVtcHRzIHBlcmZvcm1lZCBieSB0aGF0XG4gKiAgIG93bmluZyBxdWV1ZSBtZXNzYWdlIChpbmxpbmUgbGF6eSBzdGFydHMgYW5kIG93bmVkLXJlY292ZXJ5IHJlLXN0YW1wcykuXG4gKiAtIGB7IHR5cGU6ICd0b3RhbEF0dGVtcHRzJyB9YCBlc3RpbWF0ZXMgdGhlIHN0ZXAncyBnZW51aW5lIGF0dGVtcHQgdG90YWxcbiAqICAgYWNyb3NzIGl0cyB3aG9sZSBsaWZlY3ljbGU6IHVuc3RhbXBlZCAoYmFyZSkgc3RhcnRzIOKAlCB3aGljaCBvbmx5IHJlYWxcbiAqICAgcXVldWUtZGlzcGF0Y2hlZCBiYWNrZ3JvdW5kIGRlbGl2ZXJpZXMgd3JpdGUg4oCUIHBsdXMgdGhlIHN0YXJ0cyBvZiB0aGVcbiAqICAgc2luZ2xlIG1vc3Qtc3RhcnRlZCBvd25lci4gQSBnZW51aW5lIGxpZmVjeWNsZSBoYXMgYXQgbW9zdCBvbmUgaW5saW5lXG4gKiAgIG93bmVyIHBoYXNlIChvd25lcnNoaXAgaXMgY2xhaW1lZCBhdG9taWNhbGx5IGF0IHN0ZXAgY3JlYXRpb24gYW5kXG4gKiAgIGxhcHNlcyBwZXJtYW5lbnRseSBhdCBgc3RlcF9yZXRyeWluZ2Agb3Igb24gYW55IGJhcmUgc3RhcnQpLCBzbyB0YWtpbmdcbiAqICAgdGhlIG1heCBvdmVyIG93bmVycyBjb3VudHMgdGhhdCBwaGFzZSdzIHJlYWwgYXR0ZW1wdHMgd2hpbGUgaW52b2NhdGlvbnNcbiAqICAgcmFjaW5nIG9uIHRoZSBzYW1lIGJhdGNoIOKAlCB3aGljaCBzdGFtcCB0aGVpciBvd24gb25lLW9mZiBtZXNzYWdlIElEcyDigJRcbiAqICAgY29udHJpYnV0ZSBhdCBtb3N0IHRoZWlyIHNpbmdsZSBsYXJnZXN0IGNvdW50IGluc3RlYWQgb2YgYWNjdW11bGF0aW5nLlxuICovXG5leHBvcnQgdHlwZSBTdGVwU3RhcnRTY29wZSA9XG4gIHwgeyB0eXBlOiAnb3duZWRCeSc7IG1lc3NhZ2VJZDogc3RyaW5nIH1cbiAgfCB7IHR5cGU6ICd0b3RhbEF0dGVtcHRzJyB9O1xuXG5jb25zdCBvd25lck9mID0gKGU6IEV2ZW50KTogc3RyaW5nIHwgdW5kZWZpbmVkID0+XG4gICdldmVudERhdGEnIGluIGUgJiZcbiAgZS5ldmVudERhdGEgJiZcbiAgJ293bmVyTWVzc2FnZUlkJyBpbiBlLmV2ZW50RGF0YSAmJlxuICB0eXBlb2YgZS5ldmVudERhdGEub3duZXJNZXNzYWdlSWQgPT09ICdzdHJpbmcnXG4gICAgPyBlLmV2ZW50RGF0YS5vd25lck1lc3NhZ2VJZFxuICAgIDogdW5kZWZpbmVkO1xuXG4vKipcbiAqIE51bWJlciBvZiBgc3RlcF9zdGFydGVkYCBldmVudHMgYWxyZWFkeSByZWNvcmRlZCBmb3IgYSBzdGVwLCB1c2VkIGFzIHRoZVxuICogYXV0aG9yaXRhdGl2ZSBhdHRlbXB0IGNvdW50IGZvciB0aGUgbWF4UmV0cmllcyBjZWlsaW5nICh0aGUgb25seSBib3VuZCBmb3JcbiAqIHN0ZXBzIHRoYXQgdGltZSBvdXQgd2l0aG91dCB3cml0aW5nIGEgYHN0ZXBfZmFpbGVkYCkuXG4gKlxuICogSU1QT1JUQU5UOiB0aGUgcmF3ICh1bnNjb3BlZCkgY291bnQgaXMgTk9UIGEgcmVsaWFibGUgYXR0ZW1wdCBudW1iZXIuXG4gKiBDb25jdXJyZW50IGludm9jYXRpb25zIHJhY2luZyBvbiB0aGUgc2FtZSBwZW5kaW5nIGJhdGNoIChzdGFsZSByZXBsYXlzLFxuICogd2FrZSByZXBsYXlzLCBhIHN0ZXAgbWVzc2FnZSBkaXNwYXRjaGVkIGJ5IGEgcmVwbGF5IHRoYXQgbG9zdCB0aGVcbiAqIGNyZWF0ZS1jbGFpbSByYWNlLCAuLi4pIGNhbiBlYWNoIHdyaXRlIGEgYHN0ZXBfc3RhcnRlZGAgZm9yIHRoZSBzYW1lXG4gKiBsb2dpY2FsIGF0dGVtcHQg4oCUIHdvcmxkcyB3aXRob3V0IGFuIGF0b21pYyBzdGFydCBndWFyZCAod29ybGQtbG9jYWwpIGxldFxuICogYWxsIG9mIHRoZW0gdGhyb3VnaC4gQ291bnRpbmcgdGhvc2UgZHVwbGljYXRlcyBhcyBcImF0dGVtcHRzXCIgbWFkZSB0aGVcbiAqIG1heFJldHJpZXMgY2VpbGluZyBmaXJlIG9uIGhlYWx0aHkgcnVucyBhbmQgZmFpbCB0aGVtIHdpdGggYSBmYWxzZVxuICogXCJleGNlZWRlZCBtYXggcmV0cmllc1wiIChzZWUgd29ya2Zsb3cjMzA2OSkuXG4gKlxuICogQ2FsbGVycyB0aGVyZWZvcmUgc2NvcGUgdGhlIGNvdW50IHRvIHRoZSBzdGFydHMgdGhlaXIgY2VpbGluZyBpcyBhY3R1YWxseVxuICogYWJvdXQgdmlhIGBzY29wZWA6XG4gKiAtIHRoZSBpbmxpbmUgb3duZWQtcmVjb3ZlcnkgY2VpbGluZyBjb3VudHMgb25seSBUSElTIG1lc3NhZ2UncyBzdGFydHNcbiAqICAgKGBvd25lZEJ5YCkg4oCUIGVhY2ggcmVhbCAocmUpZGVsaXZlcnkgb2YgdGhlIG93bmluZyBtZXNzYWdlIHN0YW1wcyBpdHNcbiAqICAgYG93bmVyTWVzc2FnZUlkYCBvbiB0aGUgc3RhcnQgaXQgd3JpdGVzLCB3aGlsZSByYWNpbmcgaW52b2NhdGlvbnMgc3RhbXBcbiAqICAgdGhlaXIgb3duIElEcyAob3Igbm9uZSksIHNvIHRoZXkgbm8gbG9uZ2VyIGluZmxhdGUgdGhlIGNvdW50O1xuICogLSB0aGUgYmFja2dyb3VuZC1zdGVwIGNlaWxpbmcgY291bnRzIHRoZSBsaWZlY3ljbGUgYXR0ZW1wdCB0b3RhbFxuICogICAoYHRvdGFsQXR0ZW1wdHNgOiBiYXJlIHN0YXJ0cyBwbHVzIHRoZSBsYXJnZXN0IHNpbmdsZSBvd25lcidzIHN0YXJ0cykg4oCUXG4gKiAgIHNvIGEgc3RlcCB0aGF0IGV4aGF1c3RlZCBwYXJ0IG9mIGl0cyBidWRnZXQgdW5kZXIgaW5saW5lIG93bmVyc2hpcFxuICogICBiZWZvcmUgdHJhbnNpdGlvbmluZyB0byBxdWV1ZWQvYmFyZSByZXRyaWVzIHN0aWxsIHRyaXBzIHRoZSBjb21iaW5lZFxuICogICBjZWlsaW5nLCB3aGlsZSByYWNlcnMnIG9uZS1vZmYgc3RhbXBlZCBkdXBsaWNhdGVzIGRvbid0IGFjY3VtdWxhdGUsIGFuZFxuICogICB0aHJvdHRsZS90b28tZWFybHkgcmVkZWxpdmVyaWVzICh3aGljaCB3cml0ZSBubyBzdGFydCBhdCBhbGwpIHN0YXlcbiAqICAgZXhjbHVkZWQgYXMgYmVmb3JlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY291bnRTdGVwU3RhcnRlZEV2ZW50cyhcbiAgZXZlbnRzOiBFdmVudFtdIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgc3RlcElkOiBzdHJpbmcsXG4gIHNjb3BlPzogU3RlcFN0YXJ0U2NvcGVcbik6IG51bWJlciB7XG4gIGlmICghZXZlbnRzKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cbiAgbGV0IGJhcmUgPSAwO1xuICBjb25zdCBieU93bmVyID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgZm9yIChjb25zdCBlIG9mIGV2ZW50cykge1xuICAgIGlmIChlLmV2ZW50VHlwZSAhPT0gJ3N0ZXBfc3RhcnRlZCcgfHwgZS5jb3JyZWxhdGlvbklkICE9PSBzdGVwSWQpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCBvd25lciA9IG93bmVyT2YoZSk7XG4gICAgaWYgKG93bmVyID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGJhcmUrKztcbiAgICB9IGVsc2Uge1xuICAgICAgYnlPd25lci5zZXQob3duZXIsIChieU93bmVyLmdldChvd25lcikgPz8gMCkgKyAxKTtcbiAgICB9XG4gIH1cbiAgaWYgKHNjb3BlID09PSB1bmRlZmluZWQpIHtcbiAgICBsZXQgdG90YWwgPSBiYXJlO1xuICAgIGZvciAoY29uc3QgY291bnQgb2YgYnlPd25lci52YWx1ZXMoKSkge1xuICAgICAgdG90YWwgKz0gY291bnQ7XG4gICAgfVxuICAgIHJldHVybiB0b3RhbDtcbiAgfVxuICBpZiAoc2NvcGUudHlwZSA9PT0gJ293bmVkQnknKSB7XG4gICAgcmV0dXJuIGJ5T3duZXIuZ2V0KHNjb3BlLm1lc3NhZ2VJZCkgPz8gMDtcbiAgfVxuICAvLyB0b3RhbEF0dGVtcHRzXG4gIGxldCBtYXhPd25lciA9IDA7XG4gIGZvciAoY29uc3QgY291bnQgb2YgYnlPd25lci52YWx1ZXMoKSkge1xuICAgIGlmIChjb3VudCA+IG1heE93bmVyKSB7XG4gICAgICBtYXhPd25lciA9IGNvdW50O1xuICAgIH1cbiAgfVxuICByZXR1cm4gYmFyZSArIG1heE93bmVyO1xufVxuIl19
@@ -0,0 +1,99 @@
1
+ import { type WorkflowRun, type World } from '@workflow/world';
2
+ /**
3
+ * How the guard resolved a delivery. Both non-`continue` outcomes mean the
4
+ * caller must ack the message and return without executing anything.
5
+ */
6
+ export type DeploymentAffinityOutcome =
7
+ /** The run belongs here (or this world has no deployment affinity). */
8
+ 'continue'
9
+ /** Misrouted; re-enqueued at the run's own deployment. */
10
+ | 'rerouted'
11
+ /** Misrouted and out of budget (or unroutable); `run_failed` recorded. */
12
+ | 'failed';
13
+ /**
14
+ * `spanAttributes` is present only on a misrouted delivery — mismatches are
15
+ * rare, so the presence of `workflow.deployment.pinned_id` on a span *is* the
16
+ * signal that one happened, and `recovered` separates the ones a re-route fixed
17
+ * from the ones that kept misrouting.
18
+ */
19
+ export interface DeploymentAffinityResult {
20
+ outcome: DeploymentAffinityOutcome;
21
+ spanAttributes?: Record<string, string | number | boolean>;
22
+ }
23
+ /**
24
+ * Arguments handed to a call site's re-enqueue closure. The guard owns the
25
+ * policy — counting, backoff, logging, telemetry, escalation — and the call
26
+ * site owns only the shape of the message it needs to put back on the queue.
27
+ */
28
+ export interface ReenqueueArgs {
29
+ /** The deployment to target: the one the run is pinned to. */
30
+ deploymentId: string;
31
+ /**
32
+ * The run's spec version, so the world picks the right queue transport
33
+ * (CBOR vs JSON). Undefined on legacy runs that predate the field; worlds
34
+ * then fall back to their current default.
35
+ */
36
+ specVersion: number | undefined;
37
+ deploymentMismatchRetryCount: number;
38
+ /** Backoff before the re-routed message becomes visible. */
39
+ delaySeconds: number;
40
+ }
41
+ /**
42
+ * Guards deployment affinity: a run may only execute on the deployment it is
43
+ * pinned to.
44
+ *
45
+ * A run's `deploymentId` is fixed when it starts — the deployment that called
46
+ * `start()`, or whatever `start({ deploymentId })` resolved to (an explicit id
47
+ * or `'latest'`) — and no replay or step execution may happen anywhere else:
48
+ * the bundles here may not match the run's persisted history, and any step
49
+ * dispatched from here derives the per-run encryption key from the wrong
50
+ * deployment's master key, which surfaces as a `RuntimeDecryptionError` the
51
+ * queue retry callback swallows into a blank "exceeded max retries".
52
+ *
53
+ * A misrouted delivery is not treated as permanent. Rather than failing
54
+ * immediately, re-enqueue the message *explicitly targeted* at the run's own
55
+ * deployment; that send is strictly better-addressed than the one that
56
+ * misrouted, which inherited the producing deployment's ambient id. Fail only
57
+ * once the budget (`WORKFLOW_DEPLOYMENT_MISMATCH_MAX_RETRIES`, default 3) is
58
+ * spent, mirroring how a replay divergence gets bounded recovery replays before
59
+ * being recorded as a corrupted event log.
60
+ *
61
+ * Callers must pass a run entity they already have in hand — every call site
62
+ * loads the run for other reasons — so the guard costs no extra round trip.
63
+ * (`world.getDeploymentId()` reads the ambient deployment id, e.g.
64
+ * `VERCEL_DEPLOYMENT_ID`, and does not call the backend either.)
65
+ *
66
+ * The failure is recorded **without resolving the run's encryption key**: the
67
+ * key is fetched from the pinned deployment's API, often unavailable once that
68
+ * deployment is past its retention window, so depending on it would throw here
69
+ * instead of recording the failure. The payload is written unencrypted (it
70
+ * holds only deployment ids, nothing sensitive), and the plaintext `errorCode`
71
+ * is the signal observability and the UI key off.
72
+ */
73
+ export declare function guardDeploymentAffinity({ world, run, requestId, retryCount, reenqueue, isDeploymentUnavailableError, beforeStop, }: {
74
+ world: World;
75
+ run: Pick<WorkflowRun, 'runId' | 'deploymentId' | 'specVersion'>;
76
+ requestId?: string;
77
+ /** `deploymentMismatchRetryCount` from the incoming message, if any. */
78
+ retryCount?: number;
79
+ /**
80
+ * Puts this delivery's message back on the queue, targeted at the run's own
81
+ * deployment. Omitted by callers that cannot reconstruct their message, which
82
+ * makes the guard fail-fast.
83
+ */
84
+ reenqueue?: (args: ReenqueueArgs) => Promise<void>;
85
+ /**
86
+ * Classifies a re-enqueue failure as definitive proof that the pinned
87
+ * deployment cannot receive the message. Unclassified failures are retried
88
+ * by rejecting the handler and leaving the current queue message unacked.
89
+ */
90
+ isDeploymentUnavailableError?: (error: unknown) => boolean;
91
+ /**
92
+ * Ordering barrier awaited once a mismatch is confirmed, before either
93
+ * stopping action. Under turbo the `run_started` write is backgrounded, and
94
+ * both outcomes hand the run off (to a `run_failed` here, or to the pinned
95
+ * deployment's own `run_started`) — so that write must have landed first.
96
+ */
97
+ beforeStop?: () => Promise<void>;
98
+ }): Promise<DeploymentAffinityResult>;
99
+ //# sourceMappingURL=deployment-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-guard.d.ts","sourceRoot":"","sources":["../../src/runtime/deployment-guard.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,KAAK,EACX,MAAM,iBAAiB,CAAC;AASzB;;;GAGG;AACH,MAAM,MAAM,yBAAyB;AACnC,uEAAuE;AACrE,UAAU;AACZ,0DAA0D;GACxD,UAAU;AACZ,0EAA0E;GACxE,QAAQ,CAAC;AAEb;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,yBAAyB,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;CAC5D;AAwBD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,4BAA4B,EAAE,MAAM,CAAC;IACrC,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,KAAK,EACL,GAAG,EACH,SAAS,EACT,UAAc,EACd,SAAS,EACT,4BAA4B,EAC5B,UAAU,GACX,EAAE;IACD,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,cAAc,GAAG,aAAa,CAAC,CAAC;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD;;;;OAIG;IACH,4BAA4B,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAC3D;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAoIpC"}
@@ -0,0 +1,154 @@
1
+ import { EntityConflictError, RUN_ERROR_CODES, RunExpiredError, WorkflowDeploymentMismatchError, } from '@workflow/errors';
2
+ import { SPEC_VERSION_CURRENT, SPEC_VERSION_SUPPORTS_COMPRESSION, } from '@workflow/world';
3
+ import { runtimeLogger } from '../logger.js';
4
+ import { dehydrateRunError } from '../serialization.js';
5
+ import * as Attribute from '../telemetry/semantic-conventions.js';
6
+ import { getDeploymentMismatchMaxRetries } from './constants.js';
7
+ /** Cap on the re-route backoff, in seconds. */
8
+ const MAX_REROUTE_DELAY_SECONDS = 8;
9
+ /** The common case, allocation-free. */
10
+ const CONTINUE = { outcome: 'continue' };
11
+ /**
12
+ * Builds a stopping result. `attempts` is the re-route count *including* this
13
+ * invocation's own attempt, so the span attribute reads as "attempts so far".
14
+ */
15
+ function result(outcome, pinnedDeploymentId, attempts) {
16
+ return {
17
+ outcome,
18
+ spanAttributes: {
19
+ ...Attribute.WorkflowRunPinnedDeploymentId(pinnedDeploymentId),
20
+ ...Attribute.WorkflowDeploymentMismatchRetryCount(attempts),
21
+ ...Attribute.WorkflowDeploymentMismatchRecovered(outcome === 'rerouted'),
22
+ },
23
+ };
24
+ }
25
+ /**
26
+ * Guards deployment affinity: a run may only execute on the deployment it is
27
+ * pinned to.
28
+ *
29
+ * A run's `deploymentId` is fixed when it starts — the deployment that called
30
+ * `start()`, or whatever `start({ deploymentId })` resolved to (an explicit id
31
+ * or `'latest'`) — and no replay or step execution may happen anywhere else:
32
+ * the bundles here may not match the run's persisted history, and any step
33
+ * dispatched from here derives the per-run encryption key from the wrong
34
+ * deployment's master key, which surfaces as a `RuntimeDecryptionError` the
35
+ * queue retry callback swallows into a blank "exceeded max retries".
36
+ *
37
+ * A misrouted delivery is not treated as permanent. Rather than failing
38
+ * immediately, re-enqueue the message *explicitly targeted* at the run's own
39
+ * deployment; that send is strictly better-addressed than the one that
40
+ * misrouted, which inherited the producing deployment's ambient id. Fail only
41
+ * once the budget (`WORKFLOW_DEPLOYMENT_MISMATCH_MAX_RETRIES`, default 3) is
42
+ * spent, mirroring how a replay divergence gets bounded recovery replays before
43
+ * being recorded as a corrupted event log.
44
+ *
45
+ * Callers must pass a run entity they already have in hand — every call site
46
+ * loads the run for other reasons — so the guard costs no extra round trip.
47
+ * (`world.getDeploymentId()` reads the ambient deployment id, e.g.
48
+ * `VERCEL_DEPLOYMENT_ID`, and does not call the backend either.)
49
+ *
50
+ * The failure is recorded **without resolving the run's encryption key**: the
51
+ * key is fetched from the pinned deployment's API, often unavailable once that
52
+ * deployment is past its retention window, so depending on it would throw here
53
+ * instead of recording the failure. The payload is written unencrypted (it
54
+ * holds only deployment ids, nothing sensitive), and the plaintext `errorCode`
55
+ * is the signal observability and the UI key off.
56
+ */
57
+ export async function guardDeploymentAffinity({ world, run, requestId, retryCount = 0, reenqueue, isDeploymentUnavailableError, beforeStop, }) {
58
+ // Deployment affinity is only meaningful in worlds whose deployments are
59
+ // atomic and immutable, which the World declares (world-vercel does) and
60
+ // capabilities default to unsupported. Local and self-hosted worlds report a
61
+ // synthetic deployment id (e.g. `dpl_local@<sdk-version>`) that legitimately
62
+ // differs across SDK versions within one logical environment, so guarding
63
+ // them would fail ordinary local runs after a version bump.
64
+ if (world.capabilities?.deploymentAffinity !== true) {
65
+ return CONTINUE;
66
+ }
67
+ const currentDeploymentId = await world.getDeploymentId();
68
+ if (run.deploymentId === currentDeploymentId) {
69
+ return CONTINUE;
70
+ }
71
+ await beforeStop?.();
72
+ const maxRetries = getDeploymentMismatchMaxRetries();
73
+ const logContext = {
74
+ workflowRunId: run.runId,
75
+ pinnedDeploymentId: run.deploymentId,
76
+ actualDeploymentId: currentDeploymentId,
77
+ retryCount,
78
+ maxRetries,
79
+ };
80
+ /**
81
+ * Records the terminal `run_failed`. Mirrors `recordFatalRunError`: it
82
+ * records and returns rather than throwing, so the caller acks the message
83
+ * instead of letting the queue redeliver a run that is now terminal.
84
+ */
85
+ const failRun = async (recoveryAttempts, cause) => {
86
+ const error = new WorkflowDeploymentMismatchError(run.runId, run.deploymentId, currentDeploymentId, { recoveryAttempts, cause });
87
+ try {
88
+ await world.events.create(run.runId, {
89
+ eventType: 'run_failed',
90
+ specVersion: SPEC_VERSION_CURRENT,
91
+ eventData: {
92
+ // Unencrypted (undefined key): see the note on
93
+ // `guardDeploymentAffinity`. dehydrate/hydrate are self-describing,
94
+ // so this reads back without a key.
95
+ error: await dehydrateRunError(error, run.runId, undefined, undefined, (run.specVersion ?? 0) >= SPEC_VERSION_SUPPORTS_COMPRESSION),
96
+ errorCode: RUN_ERROR_CODES.DEPLOYMENT_MISMATCH,
97
+ },
98
+ }, { requestId });
99
+ }
100
+ catch (failError) {
101
+ // Run already reached a terminal state (a concurrent writer failed it, or
102
+ // it was cancelled/expired) — still stop. Anything else is a transient
103
+ // persistence failure: rethrow so the queue redelivers and we try again.
104
+ if (!EntityConflictError.is(failError) &&
105
+ !RunExpiredError.is(failError)) {
106
+ throw failError;
107
+ }
108
+ }
109
+ return result('failed', run.deploymentId, recoveryAttempts);
110
+ };
111
+ if (reenqueue && retryCount < maxRetries) {
112
+ const attempt = retryCount + 1;
113
+ // Exponential, capped: 1s, 2s, 4s — cheap insurance against a hot
114
+ // re-enqueue loop, and time for a mid-flight routing change to settle.
115
+ const delaySeconds = Math.min(2 ** retryCount, MAX_REROUTE_DELAY_SECONDS);
116
+ try {
117
+ await reenqueue({
118
+ deploymentId: run.deploymentId,
119
+ specVersion: run.specVersion,
120
+ deploymentMismatchRetryCount: attempt,
121
+ delaySeconds,
122
+ });
123
+ runtimeLogger.warn('Workflow run received by a deployment it is not pinned to; re-routing to its own deployment', { ...logContext, attempt, delaySeconds });
124
+ return result('rerouted', run.deploymentId, attempt);
125
+ }
126
+ catch (reenqueueError) {
127
+ // A generic send failure can be transient (429, 5xx, connect/DNS). Do not
128
+ // turn one infrastructure blip into a terminal run failure: reject the
129
+ // handler so the current message remains unacked and is redelivered.
130
+ if (!isDeploymentUnavailableError?.(reenqueueError)) {
131
+ throw reenqueueError;
132
+ }
133
+ // The World explicitly classified the target as unavailable — deleted,
134
+ // aged out of its retention window, or otherwise undiscoverable. Burning
135
+ // the rest of the budget on a deployment that provably cannot be reached
136
+ // only delays the failure, so fail now.
137
+ runtimeLogger.error('Cannot re-route a misrouted workflow run to its own deployment; failing the run', {
138
+ ...logContext,
139
+ attempt,
140
+ errorMessage: reenqueueError instanceof Error
141
+ ? reenqueueError.message
142
+ : String(reenqueueError),
143
+ });
144
+ // Recovery never actually happened, so report 0 attempts and let `cause`
145
+ // explain why.
146
+ return failRun(0, reenqueueError);
147
+ }
148
+ }
149
+ runtimeLogger.error(retryCount > 0
150
+ ? 'Workflow run kept arriving at a deployment it is not pinned to after re-routing; failing the run'
151
+ : 'Workflow run received by a deployment it is not pinned to; failing the run', logContext);
152
+ return failRun(retryCount);
153
+ }
154
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudC1ndWFyZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2RlcGxveW1lbnQtZ3VhcmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixlQUFlLEVBQ2YsZUFBZSxFQUNmLCtCQUErQixHQUNoQyxNQUFNLGtCQUFrQixDQUFDO0FBQzFCLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsaUNBQWlDLEdBR2xDLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM3QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN4RCxPQUFPLEtBQUssU0FBUyxNQUFNLHNDQUFzQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRWpFLCtDQUErQztBQUMvQyxNQUFNLHlCQUF5QixHQUFHLENBQUMsQ0FBQztBQXlCcEMsd0NBQXdDO0FBQ3hDLE1BQU0sUUFBUSxHQUE2QixFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQztBQUVuRTs7O0dBR0c7QUFDSCxTQUFTLE1BQU0sQ0FDYixPQUE4QixFQUM5QixrQkFBMEIsRUFDMUIsUUFBZ0I7SUFFaEIsT0FBTztRQUNMLE9BQU87UUFDUCxjQUFjLEVBQUU7WUFDZCxHQUFHLFNBQVMsQ0FBQyw2QkFBNkIsQ0FBQyxrQkFBa0IsQ0FBQztZQUM5RCxHQUFHLFNBQVMsQ0FBQyxvQ0FBb0MsQ0FBQyxRQUFRLENBQUM7WUFDM0QsR0FBRyxTQUFTLENBQUMsbUNBQW1DLENBQUMsT0FBTyxLQUFLLFVBQVUsQ0FBQztTQUN6RTtLQUNGLENBQUM7QUFDSixDQUFDO0FBcUJEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBK0JHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSx1QkFBdUIsQ0FBQyxFQUM1QyxLQUFLLEVBQ0wsR0FBRyxFQUNILFNBQVMsRUFDVCxVQUFVLEdBQUcsQ0FBQyxFQUNkLFNBQVMsRUFDVCw0QkFBNEIsRUFDNUIsVUFBVSxHQTBCWDtJQUNDLHlFQUF5RTtJQUN6RSx5RUFBeUU7SUFDekUsNkVBQTZFO0lBQzdFLDZFQUE2RTtJQUM3RSwwRUFBMEU7SUFDMUUsNERBQTREO0lBQzVELElBQUksS0FBSyxDQUFDLFlBQVksRUFBRSxrQkFBa0IsS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUNwRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQsTUFBTSxtQkFBbUIsR0FBRyxNQUFNLEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUMxRCxJQUFJLEdBQUcsQ0FBQyxZQUFZLEtBQUssbUJBQW1CLEVBQUUsQ0FBQztRQUM3QyxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQsTUFBTSxVQUFVLEVBQUUsRUFBRSxDQUFDO0lBRXJCLE1BQU0sVUFBVSxHQUFHLCtCQUErQixFQUFFLENBQUM7SUFDckQsTUFBTSxVQUFVLEdBQUc7UUFDakIsYUFBYSxFQUFFLEdBQUcsQ0FBQyxLQUFLO1FBQ3hCLGtCQUFrQixFQUFFLEdBQUcsQ0FBQyxZQUFZO1FBQ3BDLGtCQUFrQixFQUFFLG1CQUFtQjtRQUN2QyxVQUFVO1FBQ1YsVUFBVTtLQUNYLENBQUM7SUFFRjs7OztPQUlHO0lBQ0gsTUFBTSxPQUFPLEdBQUcsS0FBSyxFQUNuQixnQkFBd0IsRUFDeEIsS0FBZSxFQUNvQixFQUFFO1FBQ3JDLE1BQU0sS0FBSyxHQUFHLElBQUksK0JBQStCLENBQy9DLEdBQUcsQ0FBQyxLQUFLLEVBQ1QsR0FBRyxDQUFDLFlBQVksRUFDaEIsbUJBQW1CLEVBQ25CLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLENBQzVCLENBQUM7UUFFRixJQUFJLENBQUM7WUFDSCxNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUN2QixHQUFHLENBQUMsS0FBSyxFQUNUO2dCQUNFLFNBQVMsRUFBRSxZQUFZO2dCQUN2QixXQUFXLEVBQUUsb0JBQW9CO2dCQUNqQyxTQUFTLEVBQUU7b0JBQ1QsK0NBQStDO29CQUMvQyxvRUFBb0U7b0JBQ3BFLG9DQUFvQztvQkFDcEMsS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQzVCLEtBQUssRUFDTCxHQUFHLENBQUMsS0FBSyxFQUNULFNBQVMsRUFDVCxTQUFTLEVBQ1QsQ0FBQyxHQUFHLENBQUMsV0FBVyxJQUFJLENBQUMsQ0FBQyxJQUFJLGlDQUFpQyxDQUM1RDtvQkFDRCxTQUFTLEVBQUUsZUFBZSxDQUFDLG1CQUFtQjtpQkFDL0M7YUFDRixFQUNELEVBQUUsU0FBUyxFQUFFLENBQ2QsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLFNBQVMsRUFBRSxDQUFDO1lBQ25CLDBFQUEwRTtZQUMxRSx1RUFBdUU7WUFDdkUseUVBQXlFO1lBQ3pFLElBQ0UsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDO2dCQUNsQyxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLEVBQzlCLENBQUM7Z0JBQ0QsTUFBTSxTQUFTLENBQUM7WUFDbEIsQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUFDLFlBQVksRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzlELENBQUMsQ0FBQztJQUVGLElBQUksU0FBUyxJQUFJLFVBQVUsR0FBRyxVQUFVLEVBQUUsQ0FBQztRQUN6QyxNQUFNLE9BQU8sR0FBRyxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBQy9CLGtFQUFrRTtRQUNsRSx1RUFBdUU7UUFDdkUsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksVUFBVSxFQUFFLHlCQUF5QixDQUFDLENBQUM7UUFDMUUsSUFBSSxDQUFDO1lBQ0gsTUFBTSxTQUFTLENBQUM7Z0JBQ2QsWUFBWSxFQUFFLEdBQUcsQ0FBQyxZQUFZO2dCQUM5QixXQUFXLEVBQUUsR0FBRyxDQUFDLFdBQVc7Z0JBQzVCLDRCQUE0QixFQUFFLE9BQU87Z0JBQ3JDLFlBQVk7YUFDYixDQUFDLENBQUM7WUFDSCxhQUFhLENBQUMsSUFBSSxDQUNoQiw2RkFBNkYsRUFDN0YsRUFBRSxHQUFHLFVBQVUsRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLENBQ3pDLENBQUM7WUFDRixPQUFPLE1BQU0sQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLFlBQVksRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN2RCxDQUFDO1FBQUMsT0FBTyxjQUFjLEVBQUUsQ0FBQztZQUN4QiwwRUFBMEU7WUFDMUUsdUVBQXVFO1lBQ3ZFLHFFQUFxRTtZQUNyRSxJQUFJLENBQUMsNEJBQTRCLEVBQUUsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO2dCQUNwRCxNQUFNLGNBQWMsQ0FBQztZQUN2QixDQUFDO1lBRUQsdUVBQXVFO1lBQ3ZFLHlFQUF5RTtZQUN6RSx5RUFBeUU7WUFDekUsd0NBQXdDO1lBQ3hDLGFBQWEsQ0FBQyxLQUFLLENBQ2pCLGlGQUFpRixFQUNqRjtnQkFDRSxHQUFHLFVBQVU7Z0JBQ2IsT0FBTztnQkFDUCxZQUFZLEVBQ1YsY0FBYyxZQUFZLEtBQUs7b0JBQzdCLENBQUMsQ0FBQyxjQUFjLENBQUMsT0FBTztvQkFDeEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUM7YUFDN0IsQ0FDRixDQUFDO1lBQ0YseUVBQXlFO1lBQ3pFLGVBQWU7WUFDZixPQUFPLE9BQU8sQ0FBQyxDQUFDLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDcEMsQ0FBQztJQUNILENBQUM7SUFFRCxhQUFhLENBQUMsS0FBSyxDQUNqQixVQUFVLEdBQUcsQ0FBQztRQUNaLENBQUMsQ0FBQyxrR0FBa0c7UUFDcEcsQ0FBQyxDQUFDLDRFQUE0RSxFQUNoRixVQUFVLENBQ1gsQ0FBQztJQUNGLE9BQU8sT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0FBQzdCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBFbnRpdHlDb25mbGljdEVycm9yLFxuICBSVU5fRVJST1JfQ09ERVMsXG4gIFJ1bkV4cGlyZWRFcnJvcixcbiAgV29ya2Zsb3dEZXBsb3ltZW50TWlzbWF0Y2hFcnJvcixcbn0gZnJvbSAnQHdvcmtmbG93L2Vycm9ycyc7XG5pbXBvcnQge1xuICBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgU1BFQ19WRVJTSU9OX1NVUFBPUlRTX0NPTVBSRVNTSU9OLFxuICB0eXBlIFdvcmtmbG93UnVuLFxuICB0eXBlIFdvcmxkLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBkZWh5ZHJhdGVSdW5FcnJvciB9IGZyb20gJy4uL3NlcmlhbGl6YXRpb24uanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQgeyBnZXREZXBsb3ltZW50TWlzbWF0Y2hNYXhSZXRyaWVzIH0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xuXG4vKiogQ2FwIG9uIHRoZSByZS1yb3V0ZSBiYWNrb2ZmLCBpbiBzZWNvbmRzLiAqL1xuY29uc3QgTUFYX1JFUk9VVEVfREVMQVlfU0VDT05EUyA9IDg7XG5cbi8qKlxuICogSG93IHRoZSBndWFyZCByZXNvbHZlZCBhIGRlbGl2ZXJ5LiBCb3RoIG5vbi1gY29udGludWVgIG91dGNvbWVzIG1lYW4gdGhlXG4gKiBjYWxsZXIgbXVzdCBhY2sgdGhlIG1lc3NhZ2UgYW5kIHJldHVybiB3aXRob3V0IGV4ZWN1dGluZyBhbnl0aGluZy5cbiAqL1xuZXhwb3J0IHR5cGUgRGVwbG95bWVudEFmZmluaXR5T3V0Y29tZSA9XG4gIC8qKiBUaGUgcnVuIGJlbG9uZ3MgaGVyZSAob3IgdGhpcyB3b3JsZCBoYXMgbm8gZGVwbG95bWVudCBhZmZpbml0eSkuICovXG4gIHwgJ2NvbnRpbnVlJ1xuICAvKiogTWlzcm91dGVkOyByZS1lbnF1ZXVlZCBhdCB0aGUgcnVuJ3Mgb3duIGRlcGxveW1lbnQuICovXG4gIHwgJ3Jlcm91dGVkJ1xuICAvKiogTWlzcm91dGVkIGFuZCBvdXQgb2YgYnVkZ2V0IChvciB1bnJvdXRhYmxlKTsgYHJ1bl9mYWlsZWRgIHJlY29yZGVkLiAqL1xuICB8ICdmYWlsZWQnO1xuXG4vKipcbiAqIGBzcGFuQXR0cmlidXRlc2AgaXMgcHJlc2VudCBvbmx5IG9uIGEgbWlzcm91dGVkIGRlbGl2ZXJ5IOKAlCBtaXNtYXRjaGVzIGFyZVxuICogcmFyZSwgc28gdGhlIHByZXNlbmNlIG9mIGB3b3JrZmxvdy5kZXBsb3ltZW50LnBpbm5lZF9pZGAgb24gYSBzcGFuICppcyogdGhlXG4gKiBzaWduYWwgdGhhdCBvbmUgaGFwcGVuZWQsIGFuZCBgcmVjb3ZlcmVkYCBzZXBhcmF0ZXMgdGhlIG9uZXMgYSByZS1yb3V0ZSBmaXhlZFxuICogZnJvbSB0aGUgb25lcyB0aGF0IGtlcHQgbWlzcm91dGluZy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZXBsb3ltZW50QWZmaW5pdHlSZXN1bHQge1xuICBvdXRjb21lOiBEZXBsb3ltZW50QWZmaW5pdHlPdXRjb21lO1xuICBzcGFuQXR0cmlidXRlcz86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4+O1xufVxuXG4vKiogVGhlIGNvbW1vbiBjYXNlLCBhbGxvY2F0aW9uLWZyZWUuICovXG5jb25zdCBDT05USU5VRTogRGVwbG95bWVudEFmZmluaXR5UmVzdWx0ID0geyBvdXRjb21lOiAnY29udGludWUnIH07XG5cbi8qKlxuICogQnVpbGRzIGEgc3RvcHBpbmcgcmVzdWx0LiBgYXR0ZW1wdHNgIGlzIHRoZSByZS1yb3V0ZSBjb3VudCAqaW5jbHVkaW5nKiB0aGlzXG4gKiBpbnZvY2F0aW9uJ3Mgb3duIGF0dGVtcHQsIHNvIHRoZSBzcGFuIGF0dHJpYnV0ZSByZWFkcyBhcyBcImF0dGVtcHRzIHNvIGZhclwiLlxuICovXG5mdW5jdGlvbiByZXN1bHQoXG4gIG91dGNvbWU6ICdyZXJvdXRlZCcgfCAnZmFpbGVkJyxcbiAgcGlubmVkRGVwbG95bWVudElkOiBzdHJpbmcsXG4gIGF0dGVtcHRzOiBudW1iZXJcbik6IERlcGxveW1lbnRBZmZpbml0eVJlc3VsdCB7XG4gIHJldHVybiB7XG4gICAgb3V0Y29tZSxcbiAgICBzcGFuQXR0cmlidXRlczoge1xuICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuUGlubmVkRGVwbG95bWVudElkKHBpbm5lZERlcGxveW1lbnRJZCksXG4gICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dEZXBsb3ltZW50TWlzbWF0Y2hSZXRyeUNvdW50KGF0dGVtcHRzKSxcbiAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd0RlcGxveW1lbnRNaXNtYXRjaFJlY292ZXJlZChvdXRjb21lID09PSAncmVyb3V0ZWQnKSxcbiAgICB9LFxuICB9O1xufVxuXG4vKipcbiAqIEFyZ3VtZW50cyBoYW5kZWQgdG8gYSBjYWxsIHNpdGUncyByZS1lbnF1ZXVlIGNsb3N1cmUuIFRoZSBndWFyZCBvd25zIHRoZVxuICogcG9saWN5IOKAlCBjb3VudGluZywgYmFja29mZiwgbG9nZ2luZywgdGVsZW1ldHJ5LCBlc2NhbGF0aW9uIOKAlCBhbmQgdGhlIGNhbGxcbiAqIHNpdGUgb3ducyBvbmx5IHRoZSBzaGFwZSBvZiB0aGUgbWVzc2FnZSBpdCBuZWVkcyB0byBwdXQgYmFjayBvbiB0aGUgcXVldWUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVlbnF1ZXVlQXJncyB7XG4gIC8qKiBUaGUgZGVwbG95bWVudCB0byB0YXJnZXQ6IHRoZSBvbmUgdGhlIHJ1biBpcyBwaW5uZWQgdG8uICovXG4gIGRlcGxveW1lbnRJZDogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHJ1bidzIHNwZWMgdmVyc2lvbiwgc28gdGhlIHdvcmxkIHBpY2tzIHRoZSByaWdodCBxdWV1ZSB0cmFuc3BvcnRcbiAgICogKENCT1IgdnMgSlNPTikuIFVuZGVmaW5lZCBvbiBsZWdhY3kgcnVucyB0aGF0IHByZWRhdGUgdGhlIGZpZWxkOyB3b3JsZHNcbiAgICogdGhlbiBmYWxsIGJhY2sgdG8gdGhlaXIgY3VycmVudCBkZWZhdWx0LlxuICAgKi9cbiAgc3BlY1ZlcnNpb246IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgZGVwbG95bWVudE1pc21hdGNoUmV0cnlDb3VudDogbnVtYmVyO1xuICAvKiogQmFja29mZiBiZWZvcmUgdGhlIHJlLXJvdXRlZCBtZXNzYWdlIGJlY29tZXMgdmlzaWJsZS4gKi9cbiAgZGVsYXlTZWNvbmRzOiBudW1iZXI7XG59XG5cbi8qKlxuICogR3VhcmRzIGRlcGxveW1lbnQgYWZmaW5pdHk6IGEgcnVuIG1heSBvbmx5IGV4ZWN1dGUgb24gdGhlIGRlcGxveW1lbnQgaXQgaXNcbiAqIHBpbm5lZCB0by5cbiAqXG4gKiBBIHJ1bidzIGBkZXBsb3ltZW50SWRgIGlzIGZpeGVkIHdoZW4gaXQgc3RhcnRzIOKAlCB0aGUgZGVwbG95bWVudCB0aGF0IGNhbGxlZFxuICogYHN0YXJ0KClgLCBvciB3aGF0ZXZlciBgc3RhcnQoeyBkZXBsb3ltZW50SWQgfSlgIHJlc29sdmVkIHRvIChhbiBleHBsaWNpdCBpZFxuICogb3IgYCdsYXRlc3QnYCkg4oCUIGFuZCBubyByZXBsYXkgb3Igc3RlcCBleGVjdXRpb24gbWF5IGhhcHBlbiBhbnl3aGVyZSBlbHNlOlxuICogdGhlIGJ1bmRsZXMgaGVyZSBtYXkgbm90IG1hdGNoIHRoZSBydW4ncyBwZXJzaXN0ZWQgaGlzdG9yeSwgYW5kIGFueSBzdGVwXG4gKiBkaXNwYXRjaGVkIGZyb20gaGVyZSBkZXJpdmVzIHRoZSBwZXItcnVuIGVuY3J5cHRpb24ga2V5IGZyb20gdGhlIHdyb25nXG4gKiBkZXBsb3ltZW50J3MgbWFzdGVyIGtleSwgd2hpY2ggc3VyZmFjZXMgYXMgYSBgUnVudGltZURlY3J5cHRpb25FcnJvcmAgdGhlXG4gKiBxdWV1ZSByZXRyeSBjYWxsYmFjayBzd2FsbG93cyBpbnRvIGEgYmxhbmsgXCJleGNlZWRlZCBtYXggcmV0cmllc1wiLlxuICpcbiAqIEEgbWlzcm91dGVkIGRlbGl2ZXJ5IGlzIG5vdCB0cmVhdGVkIGFzIHBlcm1hbmVudC4gUmF0aGVyIHRoYW4gZmFpbGluZ1xuICogaW1tZWRpYXRlbHksIHJlLWVucXVldWUgdGhlIG1lc3NhZ2UgKmV4cGxpY2l0bHkgdGFyZ2V0ZWQqIGF0IHRoZSBydW4ncyBvd25cbiAqIGRlcGxveW1lbnQ7IHRoYXQgc2VuZCBpcyBzdHJpY3RseSBiZXR0ZXItYWRkcmVzc2VkIHRoYW4gdGhlIG9uZSB0aGF0XG4gKiBtaXNyb3V0ZWQsIHdoaWNoIGluaGVyaXRlZCB0aGUgcHJvZHVjaW5nIGRlcGxveW1lbnQncyBhbWJpZW50IGlkLiBGYWlsIG9ubHlcbiAqIG9uY2UgdGhlIGJ1ZGdldCAoYFdPUktGTE9XX0RFUExPWU1FTlRfTUlTTUFUQ0hfTUFYX1JFVFJJRVNgLCBkZWZhdWx0IDMpIGlzXG4gKiBzcGVudCwgbWlycm9yaW5nIGhvdyBhIHJlcGxheSBkaXZlcmdlbmNlIGdldHMgYm91bmRlZCByZWNvdmVyeSByZXBsYXlzIGJlZm9yZVxuICogYmVpbmcgcmVjb3JkZWQgYXMgYSBjb3JydXB0ZWQgZXZlbnQgbG9nLlxuICpcbiAqIENhbGxlcnMgbXVzdCBwYXNzIGEgcnVuIGVudGl0eSB0aGV5IGFscmVhZHkgaGF2ZSBpbiBoYW5kIOKAlCBldmVyeSBjYWxsIHNpdGVcbiAqIGxvYWRzIHRoZSBydW4gZm9yIG90aGVyIHJlYXNvbnMg4oCUIHNvIHRoZSBndWFyZCBjb3N0cyBubyBleHRyYSByb3VuZCB0cmlwLlxuICogKGB3b3JsZC5nZXREZXBsb3ltZW50SWQoKWAgcmVhZHMgdGhlIGFtYmllbnQgZGVwbG95bWVudCBpZCwgZS5nLlxuICogYFZFUkNFTF9ERVBMT1lNRU5UX0lEYCwgYW5kIGRvZXMgbm90IGNhbGwgdGhlIGJhY2tlbmQgZWl0aGVyLilcbiAqXG4gKiBUaGUgZmFpbHVyZSBpcyByZWNvcmRlZCAqKndpdGhvdXQgcmVzb2x2aW5nIHRoZSBydW4ncyBlbmNyeXB0aW9uIGtleSoqOiB0aGVcbiAqIGtleSBpcyBmZXRjaGVkIGZyb20gdGhlIHBpbm5lZCBkZXBsb3ltZW50J3MgQVBJLCBvZnRlbiB1bmF2YWlsYWJsZSBvbmNlIHRoYXRcbiAqIGRlcGxveW1lbnQgaXMgcGFzdCBpdHMgcmV0ZW50aW9uIHdpbmRvdywgc28gZGVwZW5kaW5nIG9uIGl0IHdvdWxkIHRocm93IGhlcmVcbiAqIGluc3RlYWQgb2YgcmVjb3JkaW5nIHRoZSBmYWlsdXJlLiBUaGUgcGF5bG9hZCBpcyB3cml0dGVuIHVuZW5jcnlwdGVkIChpdFxuICogaG9sZHMgb25seSBkZXBsb3ltZW50IGlkcywgbm90aGluZyBzZW5zaXRpdmUpLCBhbmQgdGhlIHBsYWludGV4dCBgZXJyb3JDb2RlYFxuICogaXMgdGhlIHNpZ25hbCBvYnNlcnZhYmlsaXR5IGFuZCB0aGUgVUkga2V5IG9mZi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGd1YXJkRGVwbG95bWVudEFmZmluaXR5KHtcbiAgd29ybGQsXG4gIHJ1bixcbiAgcmVxdWVzdElkLFxuICByZXRyeUNvdW50ID0gMCxcbiAgcmVlbnF1ZXVlLFxuICBpc0RlcGxveW1lbnRVbmF2YWlsYWJsZUVycm9yLFxuICBiZWZvcmVTdG9wLFxufToge1xuICB3b3JsZDogV29ybGQ7XG4gIHJ1bjogUGljazxXb3JrZmxvd1J1biwgJ3J1bklkJyB8ICdkZXBsb3ltZW50SWQnIHwgJ3NwZWNWZXJzaW9uJz47XG4gIHJlcXVlc3RJZD86IHN0cmluZztcbiAgLyoqIGBkZXBsb3ltZW50TWlzbWF0Y2hSZXRyeUNvdW50YCBmcm9tIHRoZSBpbmNvbWluZyBtZXNzYWdlLCBpZiBhbnkuICovXG4gIHJldHJ5Q291bnQ/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBQdXRzIHRoaXMgZGVsaXZlcnkncyBtZXNzYWdlIGJhY2sgb24gdGhlIHF1ZXVlLCB0YXJnZXRlZCBhdCB0aGUgcnVuJ3Mgb3duXG4gICAqIGRlcGxveW1lbnQuIE9taXR0ZWQgYnkgY2FsbGVycyB0aGF0IGNhbm5vdCByZWNvbnN0cnVjdCB0aGVpciBtZXNzYWdlLCB3aGljaFxuICAgKiBtYWtlcyB0aGUgZ3VhcmQgZmFpbC1mYXN0LlxuICAgKi9cbiAgcmVlbnF1ZXVlPzogKGFyZ3M6IFJlZW5xdWV1ZUFyZ3MpID0+IFByb21pc2U8dm9pZD47XG4gIC8qKlxuICAgKiBDbGFzc2lmaWVzIGEgcmUtZW5xdWV1ZSBmYWlsdXJlIGFzIGRlZmluaXRpdmUgcHJvb2YgdGhhdCB0aGUgcGlubmVkXG4gICAqIGRlcGxveW1lbnQgY2Fubm90IHJlY2VpdmUgdGhlIG1lc3NhZ2UuIFVuY2xhc3NpZmllZCBmYWlsdXJlcyBhcmUgcmV0cmllZFxuICAgKiBieSByZWplY3RpbmcgdGhlIGhhbmRsZXIgYW5kIGxlYXZpbmcgdGhlIGN1cnJlbnQgcXVldWUgbWVzc2FnZSB1bmFja2VkLlxuICAgKi9cbiAgaXNEZXBsb3ltZW50VW5hdmFpbGFibGVFcnJvcj86IChlcnJvcjogdW5rbm93bikgPT4gYm9vbGVhbjtcbiAgLyoqXG4gICAqIE9yZGVyaW5nIGJhcnJpZXIgYXdhaXRlZCBvbmNlIGEgbWlzbWF0Y2ggaXMgY29uZmlybWVkLCBiZWZvcmUgZWl0aGVyXG4gICAqIHN0b3BwaW5nIGFjdGlvbi4gVW5kZXIgdHVyYm8gdGhlIGBydW5fc3RhcnRlZGAgd3JpdGUgaXMgYmFja2dyb3VuZGVkLCBhbmRcbiAgICogYm90aCBvdXRjb21lcyBoYW5kIHRoZSBydW4gb2ZmICh0byBhIGBydW5fZmFpbGVkYCBoZXJlLCBvciB0byB0aGUgcGlubmVkXG4gICAqIGRlcGxveW1lbnQncyBvd24gYHJ1bl9zdGFydGVkYCkg4oCUIHNvIHRoYXQgd3JpdGUgbXVzdCBoYXZlIGxhbmRlZCBmaXJzdC5cbiAgICovXG4gIGJlZm9yZVN0b3A/OiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xufSk6IFByb21pc2U8RGVwbG95bWVudEFmZmluaXR5UmVzdWx0PiB7XG4gIC8vIERlcGxveW1lbnQgYWZmaW5pdHkgaXMgb25seSBtZWFuaW5nZnVsIGluIHdvcmxkcyB3aG9zZSBkZXBsb3ltZW50cyBhcmVcbiAgLy8gYXRvbWljIGFuZCBpbW11dGFibGUsIHdoaWNoIHRoZSBXb3JsZCBkZWNsYXJlcyAod29ybGQtdmVyY2VsIGRvZXMpIGFuZFxuICAvLyBjYXBhYmlsaXRpZXMgZGVmYXVsdCB0byB1bnN1cHBvcnRlZC4gTG9jYWwgYW5kIHNlbGYtaG9zdGVkIHdvcmxkcyByZXBvcnQgYVxuICAvLyBzeW50aGV0aWMgZGVwbG95bWVudCBpZCAoZS5nLiBgZHBsX2xvY2FsQDxzZGstdmVyc2lvbj5gKSB0aGF0IGxlZ2l0aW1hdGVseVxuICAvLyBkaWZmZXJzIGFjcm9zcyBTREsgdmVyc2lvbnMgd2l0aGluIG9uZSBsb2dpY2FsIGVudmlyb25tZW50LCBzbyBndWFyZGluZ1xuICAvLyB0aGVtIHdvdWxkIGZhaWwgb3JkaW5hcnkgbG9jYWwgcnVucyBhZnRlciBhIHZlcnNpb24gYnVtcC5cbiAgaWYgKHdvcmxkLmNhcGFiaWxpdGllcz8uZGVwbG95bWVudEFmZmluaXR5ICE9PSB0cnVlKSB7XG4gICAgcmV0dXJuIENPTlRJTlVFO1xuICB9XG5cbiAgY29uc3QgY3VycmVudERlcGxveW1lbnRJZCA9IGF3YWl0IHdvcmxkLmdldERlcGxveW1lbnRJZCgpO1xuICBpZiAocnVuLmRlcGxveW1lbnRJZCA9PT0gY3VycmVudERlcGxveW1lbnRJZCkge1xuICAgIHJldHVybiBDT05USU5VRTtcbiAgfVxuXG4gIGF3YWl0IGJlZm9yZVN0b3A/LigpO1xuXG4gIGNvbnN0IG1heFJldHJpZXMgPSBnZXREZXBsb3ltZW50TWlzbWF0Y2hNYXhSZXRyaWVzKCk7XG4gIGNvbnN0IGxvZ0NvbnRleHQgPSB7XG4gICAgd29ya2Zsb3dSdW5JZDogcnVuLnJ1bklkLFxuICAgIHBpbm5lZERlcGxveW1lbnRJZDogcnVuLmRlcGxveW1lbnRJZCxcbiAgICBhY3R1YWxEZXBsb3ltZW50SWQ6IGN1cnJlbnREZXBsb3ltZW50SWQsXG4gICAgcmV0cnlDb3VudCxcbiAgICBtYXhSZXRyaWVzLFxuICB9O1xuXG4gIC8qKlxuICAgKiBSZWNvcmRzIHRoZSB0ZXJtaW5hbCBgcnVuX2ZhaWxlZGAuIE1pcnJvcnMgYHJlY29yZEZhdGFsUnVuRXJyb3JgOiBpdFxuICAgKiByZWNvcmRzIGFuZCByZXR1cm5zIHJhdGhlciB0aGFuIHRocm93aW5nLCBzbyB0aGUgY2FsbGVyIGFja3MgdGhlIG1lc3NhZ2VcbiAgICogaW5zdGVhZCBvZiBsZXR0aW5nIHRoZSBxdWV1ZSByZWRlbGl2ZXIgYSBydW4gdGhhdCBpcyBub3cgdGVybWluYWwuXG4gICAqL1xuICBjb25zdCBmYWlsUnVuID0gYXN5bmMgKFxuICAgIHJlY292ZXJ5QXR0ZW1wdHM6IG51bWJlcixcbiAgICBjYXVzZT86IHVua25vd25cbiAgKTogUHJvbWlzZTxEZXBsb3ltZW50QWZmaW5pdHlSZXN1bHQ+ID0+IHtcbiAgICBjb25zdCBlcnJvciA9IG5ldyBXb3JrZmxvd0RlcGxveW1lbnRNaXNtYXRjaEVycm9yKFxuICAgICAgcnVuLnJ1bklkLFxuICAgICAgcnVuLmRlcGxveW1lbnRJZCxcbiAgICAgIGN1cnJlbnREZXBsb3ltZW50SWQsXG4gICAgICB7IHJlY292ZXJ5QXR0ZW1wdHMsIGNhdXNlIH1cbiAgICApO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUoXG4gICAgICAgIHJ1bi5ydW5JZCxcbiAgICAgICAge1xuICAgICAgICAgIGV2ZW50VHlwZTogJ3J1bl9mYWlsZWQnLFxuICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgIC8vIFVuZW5jcnlwdGVkICh1bmRlZmluZWQga2V5KTogc2VlIHRoZSBub3RlIG9uXG4gICAgICAgICAgICAvLyBgZ3VhcmREZXBsb3ltZW50QWZmaW5pdHlgLiBkZWh5ZHJhdGUvaHlkcmF0ZSBhcmUgc2VsZi1kZXNjcmliaW5nLFxuICAgICAgICAgICAgLy8gc28gdGhpcyByZWFkcyBiYWNrIHdpdGhvdXQgYSBrZXkuXG4gICAgICAgICAgICBlcnJvcjogYXdhaXQgZGVoeWRyYXRlUnVuRXJyb3IoXG4gICAgICAgICAgICAgIGVycm9yLFxuICAgICAgICAgICAgICBydW4ucnVuSWQsXG4gICAgICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAocnVuLnNwZWNWZXJzaW9uID8/IDApID49IFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DT01QUkVTU0lPTlxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIGVycm9yQ29kZTogUlVOX0VSUk9SX0NPREVTLkRFUExPWU1FTlRfTUlTTUFUQ0gsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgKTtcbiAgICB9IGNhdGNoIChmYWlsRXJyb3IpIHtcbiAgICAgIC8vIFJ1biBhbHJlYWR5IHJlYWNoZWQgYSB0ZXJtaW5hbCBzdGF0ZSAoYSBjb25jdXJyZW50IHdyaXRlciBmYWlsZWQgaXQsIG9yXG4gICAgICAvLyBpdCB3YXMgY2FuY2VsbGVkL2V4cGlyZWQpIOKAlCBzdGlsbCBzdG9wLiBBbnl0aGluZyBlbHNlIGlzIGEgdHJhbnNpZW50XG4gICAgICAvLyBwZXJzaXN0ZW5jZSBmYWlsdXJlOiByZXRocm93IHNvIHRoZSBxdWV1ZSByZWRlbGl2ZXJzIGFuZCB3ZSB0cnkgYWdhaW4uXG4gICAgICBpZiAoXG4gICAgICAgICFFbnRpdHlDb25mbGljdEVycm9yLmlzKGZhaWxFcnJvcikgJiZcbiAgICAgICAgIVJ1bkV4cGlyZWRFcnJvci5pcyhmYWlsRXJyb3IpXG4gICAgICApIHtcbiAgICAgICAgdGhyb3cgZmFpbEVycm9yO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0KCdmYWlsZWQnLCBydW4uZGVwbG95bWVudElkLCByZWNvdmVyeUF0dGVtcHRzKTtcbiAgfTtcblxuICBpZiAocmVlbnF1ZXVlICYmIHJldHJ5Q291bnQgPCBtYXhSZXRyaWVzKSB7XG4gICAgY29uc3QgYXR0ZW1wdCA9IHJldHJ5Q291bnQgKyAxO1xuICAgIC8vIEV4cG9uZW50aWFsLCBjYXBwZWQ6IDFzLCAycywgNHMg4oCUIGNoZWFwIGluc3VyYW5jZSBhZ2FpbnN0IGEgaG90XG4gICAgLy8gcmUtZW5xdWV1ZSBsb29wLCBhbmQgdGltZSBmb3IgYSBtaWQtZmxpZ2h0IHJvdXRpbmcgY2hhbmdlIHRvIHNldHRsZS5cbiAgICBjb25zdCBkZWxheVNlY29uZHMgPSBNYXRoLm1pbigyICoqIHJldHJ5Q291bnQsIE1BWF9SRVJPVVRFX0RFTEFZX1NFQ09ORFMpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCByZWVucXVldWUoe1xuICAgICAgICBkZXBsb3ltZW50SWQ6IHJ1bi5kZXBsb3ltZW50SWQsXG4gICAgICAgIHNwZWNWZXJzaW9uOiBydW4uc3BlY1ZlcnNpb24sXG4gICAgICAgIGRlcGxveW1lbnRNaXNtYXRjaFJldHJ5Q291bnQ6IGF0dGVtcHQsXG4gICAgICAgIGRlbGF5U2Vjb25kcyxcbiAgICAgIH0pO1xuICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAnV29ya2Zsb3cgcnVuIHJlY2VpdmVkIGJ5IGEgZGVwbG95bWVudCBpdCBpcyBub3QgcGlubmVkIHRvOyByZS1yb3V0aW5nIHRvIGl0cyBvd24gZGVwbG95bWVudCcsXG4gICAgICAgIHsgLi4ubG9nQ29udGV4dCwgYXR0ZW1wdCwgZGVsYXlTZWNvbmRzIH1cbiAgICAgICk7XG4gICAgICByZXR1cm4gcmVzdWx0KCdyZXJvdXRlZCcsIHJ1bi5kZXBsb3ltZW50SWQsIGF0dGVtcHQpO1xuICAgIH0gY2F0Y2ggKHJlZW5xdWV1ZUVycm9yKSB7XG4gICAgICAvLyBBIGdlbmVyaWMgc2VuZCBmYWlsdXJlIGNhbiBiZSB0cmFuc2llbnQgKDQyOSwgNXh4LCBjb25uZWN0L0ROUykuIERvIG5vdFxuICAgICAgLy8gdHVybiBvbmUgaW5mcmFzdHJ1Y3R1cmUgYmxpcCBpbnRvIGEgdGVybWluYWwgcnVuIGZhaWx1cmU6IHJlamVjdCB0aGVcbiAgICAgIC8vIGhhbmRsZXIgc28gdGhlIGN1cnJlbnQgbWVzc2FnZSByZW1haW5zIHVuYWNrZWQgYW5kIGlzIHJlZGVsaXZlcmVkLlxuICAgICAgaWYgKCFpc0RlcGxveW1lbnRVbmF2YWlsYWJsZUVycm9yPy4ocmVlbnF1ZXVlRXJyb3IpKSB7XG4gICAgICAgIHRocm93IHJlZW5xdWV1ZUVycm9yO1xuICAgICAgfVxuXG4gICAgICAvLyBUaGUgV29ybGQgZXhwbGljaXRseSBjbGFzc2lmaWVkIHRoZSB0YXJnZXQgYXMgdW5hdmFpbGFibGUg4oCUIGRlbGV0ZWQsXG4gICAgICAvLyBhZ2VkIG91dCBvZiBpdHMgcmV0ZW50aW9uIHdpbmRvdywgb3Igb3RoZXJ3aXNlIHVuZGlzY292ZXJhYmxlLiBCdXJuaW5nXG4gICAgICAvLyB0aGUgcmVzdCBvZiB0aGUgYnVkZ2V0IG9uIGEgZGVwbG95bWVudCB0aGF0IHByb3ZhYmx5IGNhbm5vdCBiZSByZWFjaGVkXG4gICAgICAvLyBvbmx5IGRlbGF5cyB0aGUgZmFpbHVyZSwgc28gZmFpbCBub3cuXG4gICAgICBydW50aW1lTG9nZ2VyLmVycm9yKFxuICAgICAgICAnQ2Fubm90IHJlLXJvdXRlIGEgbWlzcm91dGVkIHdvcmtmbG93IHJ1biB0byBpdHMgb3duIGRlcGxveW1lbnQ7IGZhaWxpbmcgdGhlIHJ1bicsXG4gICAgICAgIHtcbiAgICAgICAgICAuLi5sb2dDb250ZXh0LFxuICAgICAgICAgIGF0dGVtcHQsXG4gICAgICAgICAgZXJyb3JNZXNzYWdlOlxuICAgICAgICAgICAgcmVlbnF1ZXVlRXJyb3IgaW5zdGFuY2VvZiBFcnJvclxuICAgICAgICAgICAgICA/IHJlZW5xdWV1ZUVycm9yLm1lc3NhZ2VcbiAgICAgICAgICAgICAgOiBTdHJpbmcocmVlbnF1ZXVlRXJyb3IpLFxuICAgICAgICB9XG4gICAgICApO1xuICAgICAgLy8gUmVjb3ZlcnkgbmV2ZXIgYWN0dWFsbHkgaGFwcGVuZWQsIHNvIHJlcG9ydCAwIGF0dGVtcHRzIGFuZCBsZXQgYGNhdXNlYFxuICAgICAgLy8gZXhwbGFpbiB3aHkuXG4gICAgICByZXR1cm4gZmFpbFJ1bigwLCByZWVucXVldWVFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcnVudGltZUxvZ2dlci5lcnJvcihcbiAgICByZXRyeUNvdW50ID4gMFxuICAgICAgPyAnV29ya2Zsb3cgcnVuIGtlcHQgYXJyaXZpbmcgYXQgYSBkZXBsb3ltZW50IGl0IGlzIG5vdCBwaW5uZWQgdG8gYWZ0ZXIgcmUtcm91dGluZzsgZmFpbGluZyB0aGUgcnVuJ1xuICAgICAgOiAnV29ya2Zsb3cgcnVuIHJlY2VpdmVkIGJ5IGEgZGVwbG95bWVudCBpdCBpcyBub3QgcGlubmVkIHRvOyBmYWlsaW5nIHRoZSBydW4nLFxuICAgIGxvZ0NvbnRleHRcbiAgKTtcbiAgcmV0dXJuIGZhaWxSdW4ocmV0cnlDb3VudCk7XG59XG4iXX0=
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Lazy loader for getPort that prevents bundlers (Turbopack, esbuild)
3
+ * from statically tracing @workflow/utils/get-port and its filesystem
4
+ * operations (readdir, readFile, readlink) into the flow route bundle.
5
+ *
6
+ * Uses createRequire with a dynamically constructed specifier so the
7
+ * dependency is invisible to bundler static analysis.
8
+ */
9
+ export declare function getPortLazy(): Promise<number | undefined>;
10
+ /**
11
+ * Resets the per-process port cache. Intended for tests; not used on the hot
12
+ * path. Callers must let any in-flight lookup settle (await the pending
13
+ * `getPortLazy()` call) before resetting: clearing `_inFlight` here does not
14
+ * cancel an already-scheduled resolution, so a late `.then` could otherwise
15
+ * repopulate `_cachedPort` after the reset and bleed into the next test.
16
+ */
17
+ export declare function resetPortCacheForTesting(): void;
18
+ /**
19
+ * Installs a fake port resolver and clears the cache. Test-only seam: the real
20
+ * resolver is loaded via `createRequire` with a runtime-built specifier (to
21
+ * hide it from bundlers), which also defeats module mocking, so injection is
22
+ * the only deterministic way to exercise the caching contract.
23
+ */
24
+ export declare function setPortResolverForTesting(fn: () => Promise<number | undefined>): void;
25
+ //# sourceMappingURL=get-port-lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-port-lazy.d.ts","sourceRoot":"","sources":["../../src/runtime/get-port-lazy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAuBH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA4C/D;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAI/C;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GACpC,IAAI,CAIN"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Lazy loader for getPort that prevents bundlers (Turbopack, esbuild)
3
+ * from statically tracing @workflow/utils/get-port and its filesystem
4
+ * operations (readdir, readFile, readlink) into the flow route bundle.
5
+ *
6
+ * Uses createRequire with a dynamically constructed specifier so the
7
+ * dependency is invisible to bundler static analysis.
8
+ */
9
+ import { createRequire } from 'node:module';
10
+ import { pathToFileURL } from 'node:url';
11
+ let _getPort;
12
+ // Per-process cache of the resolved port. The workflow server listens on a
13
+ // stable port for the lifetime of the process, but `getPort()` rediscovers it
14
+ // on every call by querying the OS for the process's listening sockets — on
15
+ // macOS that shells out to `lsof` (~60ms), which the runtime pays on EVERY
16
+ // workflow replay or step invocation. Since the port does not change within a
17
+ // process, resolve it once and reuse it. `_inFlight`
18
+ // dedupes concurrent first calls so discovery never runs more than once.
19
+ //
20
+ // The first concrete port is pinned for the lifetime of the process — there is
21
+ // no per-call re-resolution. This is safe because the runtime only runs inside
22
+ // the already-listening dev-server process, and `getPort()` -> `getAllPorts()`
23
+ // returns a deterministic order, so repeated calls would resolve the same port
24
+ // anyway.
25
+ let _cachedPort;
26
+ let _inFlight;
27
+ export async function getPortLazy() {
28
+ // Fast path: already resolved a concrete port for this process.
29
+ if (_cachedPort !== undefined) {
30
+ return _cachedPort;
31
+ }
32
+ // A discovery is already running — share it rather than starting a second.
33
+ if (_inFlight) {
34
+ return _inFlight;
35
+ }
36
+ if (!_getPort) {
37
+ try {
38
+ // Construct specifier at runtime to defeat bundler static analysis.
39
+ const spec = ['@workflow/utils', 'get-port'].join('/');
40
+ // Use process.cwd()-based createRequire for CJS/ESM compatibility.
41
+ // import.meta.url is unavailable in CJS re-bundled outputs.
42
+ const _require = createRequire(pathToFileURL(process.cwd() + '/package.json').href);
43
+ const mod = _require(spec);
44
+ _getPort = mod.getPort;
45
+ }
46
+ catch {
47
+ // Module not available (e.g., in a browser or minimal bundle)
48
+ _getPort = async () => undefined;
49
+ }
50
+ }
51
+ // `_getPort` is always assigned by the block above; the fallback keeps the
52
+ // type non-nullable without a non-null assertion.
53
+ const resolver = _getPort ?? (async () => undefined);
54
+ _inFlight = resolver()
55
+ .then((port) => {
56
+ // Only cache a concrete port. A transient `undefined` (e.g. the server is
57
+ // not listening yet on the very first replay) must not poison the cache —
58
+ // leaving it unset lets the next call retry discovery.
59
+ if (typeof port === 'number') {
60
+ _cachedPort = port;
61
+ }
62
+ return port;
63
+ })
64
+ .finally(() => {
65
+ _inFlight = undefined;
66
+ });
67
+ return _inFlight;
68
+ }
69
+ /**
70
+ * Resets the per-process port cache. Intended for tests; not used on the hot
71
+ * path. Callers must let any in-flight lookup settle (await the pending
72
+ * `getPortLazy()` call) before resetting: clearing `_inFlight` here does not
73
+ * cancel an already-scheduled resolution, so a late `.then` could otherwise
74
+ * repopulate `_cachedPort` after the reset and bleed into the next test.
75
+ */
76
+ export function resetPortCacheForTesting() {
77
+ _getPort = undefined;
78
+ _cachedPort = undefined;
79
+ _inFlight = undefined;
80
+ }
81
+ /**
82
+ * Installs a fake port resolver and clears the cache. Test-only seam: the real
83
+ * resolver is loaded via `createRequire` with a runtime-built specifier (to
84
+ * hide it from bundlers), which also defeats module mocking, so injection is
85
+ * the only deterministic way to exercise the caching contract.
86
+ */
87
+ export function setPortResolverForTesting(fn) {
88
+ _getPort = fn;
89
+ _cachedPort = undefined;
90
+ _inFlight = undefined;
91
+ }
92
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LXBvcnQtbGF6eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2dldC1wb3J0LWxhenkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUVILE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDNUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUV6QyxJQUFJLFFBQXlELENBQUM7QUFFOUQsMkVBQTJFO0FBQzNFLDhFQUE4RTtBQUM5RSw0RUFBNEU7QUFDNUUsMkVBQTJFO0FBQzNFLDhFQUE4RTtBQUM5RSxxREFBcUQ7QUFDckQseUVBQXlFO0FBQ3pFLEVBQUU7QUFDRiwrRUFBK0U7QUFDL0UsK0VBQStFO0FBQy9FLCtFQUErRTtBQUMvRSwrRUFBK0U7QUFDL0UsVUFBVTtBQUNWLElBQUksV0FBK0IsQ0FBQztBQUNwQyxJQUFJLFNBQWtELENBQUM7QUFFdkQsTUFBTSxDQUFDLEtBQUssVUFBVSxXQUFXO0lBQy9CLGdFQUFnRTtJQUNoRSxJQUFJLFdBQVcsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUM5QixPQUFPLFdBQVcsQ0FBQztJQUNyQixDQUFDO0lBQ0QsMkVBQTJFO0lBQzNFLElBQUksU0FBUyxFQUFFLENBQUM7UUFDZCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRUQsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2QsSUFBSSxDQUFDO1lBQ0gsb0VBQW9FO1lBQ3BFLE1BQU0sSUFBSSxHQUFHLENBQUMsaUJBQWlCLEVBQUUsVUFBVSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3ZELG1FQUFtRTtZQUNuRSw0REFBNEQ7WUFDNUQsTUFBTSxRQUFRLEdBQUcsYUFBYSxDQUM1QixhQUFhLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxHQUFHLGVBQWUsQ0FBQyxDQUFDLElBQUksQ0FDcEQsQ0FBQztZQUNGLE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMzQixRQUFRLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQztRQUN6QixDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsOERBQThEO1lBQzlELFFBQVEsR0FBRyxLQUFLLElBQUksRUFBRSxDQUFDLFNBQVMsQ0FBQztRQUNuQyxDQUFDO0lBQ0gsQ0FBQztJQUVELDJFQUEyRTtJQUMzRSxrREFBa0Q7SUFDbEQsTUFBTSxRQUFRLEdBQUcsUUFBUSxJQUFJLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNyRCxTQUFTLEdBQUcsUUFBUSxFQUFFO1NBQ25CLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1FBQ2IsMEVBQTBFO1FBQzFFLDBFQUEwRTtRQUMxRSx1REFBdUQ7UUFDdkQsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUM3QixXQUFXLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUMsQ0FBQztTQUNELE9BQU8sQ0FBQyxHQUFHLEVBQUU7UUFDWixTQUFTLEdBQUcsU0FBUyxDQUFDO0lBQ3hCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILE1BQU0sVUFBVSx3QkFBd0I7SUFDdEMsUUFBUSxHQUFHLFNBQVMsQ0FBQztJQUNyQixXQUFXLEdBQUcsU0FBUyxDQUFDO0lBQ3hCLFNBQVMsR0FBRyxTQUFTLENBQUM7QUFDeEIsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLHlCQUF5QixDQUN2QyxFQUFxQztJQUVyQyxRQUFRLEdBQUcsRUFBRSxDQUFDO0lBQ2QsV0FBVyxHQUFHLFNBQVMsQ0FBQztJQUN4QixTQUFTLEdBQUcsU0FBUyxDQUFDO0FBQ3hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIExhenkgbG9hZGVyIGZvciBnZXRQb3J0IHRoYXQgcHJldmVudHMgYnVuZGxlcnMgKFR1cmJvcGFjaywgZXNidWlsZClcbiAqIGZyb20gc3RhdGljYWxseSB0cmFjaW5nIEB3b3JrZmxvdy91dGlscy9nZXQtcG9ydCBhbmQgaXRzIGZpbGVzeXN0ZW1cbiAqIG9wZXJhdGlvbnMgKHJlYWRkaXIsIHJlYWRGaWxlLCByZWFkbGluaykgaW50byB0aGUgZmxvdyByb3V0ZSBidW5kbGUuXG4gKlxuICogVXNlcyBjcmVhdGVSZXF1aXJlIHdpdGggYSBkeW5hbWljYWxseSBjb25zdHJ1Y3RlZCBzcGVjaWZpZXIgc28gdGhlXG4gKiBkZXBlbmRlbmN5IGlzIGludmlzaWJsZSB0byBidW5kbGVyIHN0YXRpYyBhbmFseXNpcy5cbiAqL1xuXG5pbXBvcnQgeyBjcmVhdGVSZXF1aXJlIH0gZnJvbSAnbm9kZTptb2R1bGUnO1xuaW1wb3J0IHsgcGF0aFRvRmlsZVVSTCB9IGZyb20gJ25vZGU6dXJsJztcblxubGV0IF9nZXRQb3J0OiAoKCkgPT4gUHJvbWlzZTxudW1iZXIgfCB1bmRlZmluZWQ+KSB8IHVuZGVmaW5lZDtcblxuLy8gUGVyLXByb2Nlc3MgY2FjaGUgb2YgdGhlIHJlc29sdmVkIHBvcnQuIFRoZSB3b3JrZmxvdyBzZXJ2ZXIgbGlzdGVucyBvbiBhXG4vLyBzdGFibGUgcG9ydCBmb3IgdGhlIGxpZmV0aW1lIG9mIHRoZSBwcm9jZXNzLCBidXQgYGdldFBvcnQoKWAgcmVkaXNjb3ZlcnMgaXRcbi8vIG9uIGV2ZXJ5IGNhbGwgYnkgcXVlcnlpbmcgdGhlIE9TIGZvciB0aGUgcHJvY2VzcydzIGxpc3RlbmluZyBzb2NrZXRzIOKAlCBvblxuLy8gbWFjT1MgdGhhdCBzaGVsbHMgb3V0IHRvIGBsc29mYCAofjYwbXMpLCB3aGljaCB0aGUgcnVudGltZSBwYXlzIG9uIEVWRVJZXG4vLyB3b3JrZmxvdyByZXBsYXkgb3Igc3RlcCBpbnZvY2F0aW9uLiBTaW5jZSB0aGUgcG9ydCBkb2VzIG5vdCBjaGFuZ2Ugd2l0aGluIGFcbi8vIHByb2Nlc3MsIHJlc29sdmUgaXQgb25jZSBhbmQgcmV1c2UgaXQuIGBfaW5GbGlnaHRgXG4vLyBkZWR1cGVzIGNvbmN1cnJlbnQgZmlyc3QgY2FsbHMgc28gZGlzY292ZXJ5IG5ldmVyIHJ1bnMgbW9yZSB0aGFuIG9uY2UuXG4vL1xuLy8gVGhlIGZpcnN0IGNvbmNyZXRlIHBvcnQgaXMgcGlubmVkIGZvciB0aGUgbGlmZXRpbWUgb2YgdGhlIHByb2Nlc3Mg4oCUIHRoZXJlIGlzXG4vLyBubyBwZXItY2FsbCByZS1yZXNvbHV0aW9uLiBUaGlzIGlzIHNhZmUgYmVjYXVzZSB0aGUgcnVudGltZSBvbmx5IHJ1bnMgaW5zaWRlXG4vLyB0aGUgYWxyZWFkeS1saXN0ZW5pbmcgZGV2LXNlcnZlciBwcm9jZXNzLCBhbmQgYGdldFBvcnQoKWAgLT4gYGdldEFsbFBvcnRzKClgXG4vLyByZXR1cm5zIGEgZGV0ZXJtaW5pc3RpYyBvcmRlciwgc28gcmVwZWF0ZWQgY2FsbHMgd291bGQgcmVzb2x2ZSB0aGUgc2FtZSBwb3J0XG4vLyBhbnl3YXkuXG5sZXQgX2NhY2hlZFBvcnQ6IG51bWJlciB8IHVuZGVmaW5lZDtcbmxldCBfaW5GbGlnaHQ6IFByb21pc2U8bnVtYmVyIHwgdW5kZWZpbmVkPiB8IHVuZGVmaW5lZDtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldFBvcnRMYXp5KCk6IFByb21pc2U8bnVtYmVyIHwgdW5kZWZpbmVkPiB7XG4gIC8vIEZhc3QgcGF0aDogYWxyZWFkeSByZXNvbHZlZCBhIGNvbmNyZXRlIHBvcnQgZm9yIHRoaXMgcHJvY2Vzcy5cbiAgaWYgKF9jYWNoZWRQb3J0ICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gX2NhY2hlZFBvcnQ7XG4gIH1cbiAgLy8gQSBkaXNjb3ZlcnkgaXMgYWxyZWFkeSBydW5uaW5nIOKAlCBzaGFyZSBpdCByYXRoZXIgdGhhbiBzdGFydGluZyBhIHNlY29uZC5cbiAgaWYgKF9pbkZsaWdodCkge1xuICAgIHJldHVybiBfaW5GbGlnaHQ7XG4gIH1cblxuICBpZiAoIV9nZXRQb3J0KSB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIENvbnN0cnVjdCBzcGVjaWZpZXIgYXQgcnVudGltZSB0byBkZWZlYXQgYnVuZGxlciBzdGF0aWMgYW5hbHlzaXMuXG4gICAgICBjb25zdCBzcGVjID0gWydAd29ya2Zsb3cvdXRpbHMnLCAnZ2V0LXBvcnQnXS5qb2luKCcvJyk7XG4gICAgICAvLyBVc2UgcHJvY2Vzcy5jd2QoKS1iYXNlZCBjcmVhdGVSZXF1aXJlIGZvciBDSlMvRVNNIGNvbXBhdGliaWxpdHkuXG4gICAgICAvLyBpbXBvcnQubWV0YS51cmwgaXMgdW5hdmFpbGFibGUgaW4gQ0pTIHJlLWJ1bmRsZWQgb3V0cHV0cy5cbiAgICAgIGNvbnN0IF9yZXF1aXJlID0gY3JlYXRlUmVxdWlyZShcbiAgICAgICAgcGF0aFRvRmlsZVVSTChwcm9jZXNzLmN3ZCgpICsgJy9wYWNrYWdlLmpzb24nKS5ocmVmXG4gICAgICApO1xuICAgICAgY29uc3QgbW9kID0gX3JlcXVpcmUoc3BlYyk7XG4gICAgICBfZ2V0UG9ydCA9IG1vZC5nZXRQb3J0O1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gTW9kdWxlIG5vdCBhdmFpbGFibGUgKGUuZy4sIGluIGEgYnJvd3NlciBvciBtaW5pbWFsIGJ1bmRsZSlcbiAgICAgIF9nZXRQb3J0ID0gYXN5bmMgKCkgPT4gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxuXG4gIC8vIGBfZ2V0UG9ydGAgaXMgYWx3YXlzIGFzc2lnbmVkIGJ5IHRoZSBibG9jayBhYm92ZTsgdGhlIGZhbGxiYWNrIGtlZXBzIHRoZVxuICAvLyB0eXBlIG5vbi1udWxsYWJsZSB3aXRob3V0IGEgbm9uLW51bGwgYXNzZXJ0aW9uLlxuICBjb25zdCByZXNvbHZlciA9IF9nZXRQb3J0ID8/IChhc3luYyAoKSA9PiB1bmRlZmluZWQpO1xuICBfaW5GbGlnaHQgPSByZXNvbHZlcigpXG4gICAgLnRoZW4oKHBvcnQpID0+IHtcbiAgICAgIC8vIE9ubHkgY2FjaGUgYSBjb25jcmV0ZSBwb3J0LiBBIHRyYW5zaWVudCBgdW5kZWZpbmVkYCAoZS5nLiB0aGUgc2VydmVyIGlzXG4gICAgICAvLyBub3QgbGlzdGVuaW5nIHlldCBvbiB0aGUgdmVyeSBmaXJzdCByZXBsYXkpIG11c3Qgbm90IHBvaXNvbiB0aGUgY2FjaGUg4oCUXG4gICAgICAvLyBsZWF2aW5nIGl0IHVuc2V0IGxldHMgdGhlIG5leHQgY2FsbCByZXRyeSBkaXNjb3ZlcnkuXG4gICAgICBpZiAodHlwZW9mIHBvcnQgPT09ICdudW1iZXInKSB7XG4gICAgICAgIF9jYWNoZWRQb3J0ID0gcG9ydDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBwb3J0O1xuICAgIH0pXG4gICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgX2luRmxpZ2h0ID0gdW5kZWZpbmVkO1xuICAgIH0pO1xuICByZXR1cm4gX2luRmxpZ2h0O1xufVxuXG4vKipcbiAqIFJlc2V0cyB0aGUgcGVyLXByb2Nlc3MgcG9ydCBjYWNoZS4gSW50ZW5kZWQgZm9yIHRlc3RzOyBub3QgdXNlZCBvbiB0aGUgaG90XG4gKiBwYXRoLiBDYWxsZXJzIG11c3QgbGV0IGFueSBpbi1mbGlnaHQgbG9va3VwIHNldHRsZSAoYXdhaXQgdGhlIHBlbmRpbmdcbiAqIGBnZXRQb3J0TGF6eSgpYCBjYWxsKSBiZWZvcmUgcmVzZXR0aW5nOiBjbGVhcmluZyBgX2luRmxpZ2h0YCBoZXJlIGRvZXMgbm90XG4gKiBjYW5jZWwgYW4gYWxyZWFkeS1zY2hlZHVsZWQgcmVzb2x1dGlvbiwgc28gYSBsYXRlIGAudGhlbmAgY291bGQgb3RoZXJ3aXNlXG4gKiByZXBvcHVsYXRlIGBfY2FjaGVkUG9ydGAgYWZ0ZXIgdGhlIHJlc2V0IGFuZCBibGVlZCBpbnRvIHRoZSBuZXh0IHRlc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNldFBvcnRDYWNoZUZvclRlc3RpbmcoKTogdm9pZCB7XG4gIF9nZXRQb3J0ID0gdW5kZWZpbmVkO1xuICBfY2FjaGVkUG9ydCA9IHVuZGVmaW5lZDtcbiAgX2luRmxpZ2h0ID0gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEluc3RhbGxzIGEgZmFrZSBwb3J0IHJlc29sdmVyIGFuZCBjbGVhcnMgdGhlIGNhY2hlLiBUZXN0LW9ubHkgc2VhbTogdGhlIHJlYWxcbiAqIHJlc29sdmVyIGlzIGxvYWRlZCB2aWEgYGNyZWF0ZVJlcXVpcmVgIHdpdGggYSBydW50aW1lLWJ1aWx0IHNwZWNpZmllciAodG9cbiAqIGhpZGUgaXQgZnJvbSBidW5kbGVycyksIHdoaWNoIGFsc28gZGVmZWF0cyBtb2R1bGUgbW9ja2luZywgc28gaW5qZWN0aW9uIGlzXG4gKiB0aGUgb25seSBkZXRlcm1pbmlzdGljIHdheSB0byBleGVyY2lzZSB0aGUgY2FjaGluZyBjb250cmFjdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldFBvcnRSZXNvbHZlckZvclRlc3RpbmcoXG4gIGZuOiAoKSA9PiBQcm9taXNlPG51bWJlciB8IHVuZGVmaW5lZD5cbik6IHZvaWQge1xuICBfZ2V0UG9ydCA9IGZuO1xuICBfY2FjaGVkUG9ydCA9IHVuZGVmaW5lZDtcbiAgX2luRmxpZ2h0ID0gdW5kZWZpbmVkO1xufVxuIl19
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Lazy accessor for the World singleton via globalThis symbols.
3
+ *
4
+ * This module exists to break the static import chain from step-side
5
+ * modules (serialization, run, helpers, start) to world.ts. Without it,
6
+ * esbuild bundles world.ts (and its transitive deps: world-local,
7
+ * world-vercel, process.cwd(), etc.) into the step registrations bundle,
8
+ * which triggers Turbopack NFT tracing errors in the V2 combined flow route.
9
+ *
10
+ * Resolution order, in priority:
11
+ *
12
+ * 1. `globalThis[WorldCacheKey]` — populated by a successful prior
13
+ * `getWorld()` call. This is the steady-state hot path.
14
+ * 2. `globalThis[GetWorldFnKey]` — populated by the module-load side
15
+ * effect at the bottom of `./world.ts`. Fires on every server bundle
16
+ * that reaches this file via `workflow` or `workflow/api` (which import
17
+ * `./world-init.ts` for its side effect; see that file for the full
18
+ * rationale). This is the cold-start path for routes that consume host
19
+ * helpers without any prior workflow run.
20
+ */
21
+ import type { World } from '@workflow/world';
22
+ export declare function getWorldLazy(): Promise<World>;
23
+ //# sourceMappingURL=get-world-lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-world-lazy.d.ts","sourceRoot":"","sources":["../../src/runtime/get-world-lazy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAa7C,wBAAsB,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC,CAsBnD"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Lazy accessor for the World singleton via globalThis symbols.
3
+ *
4
+ * This module exists to break the static import chain from step-side
5
+ * modules (serialization, run, helpers, start) to world.ts. Without it,
6
+ * esbuild bundles world.ts (and its transitive deps: world-local,
7
+ * world-vercel, process.cwd(), etc.) into the step registrations bundle,
8
+ * which triggers Turbopack NFT tracing errors in the V2 combined flow route.
9
+ *
10
+ * Resolution order, in priority:
11
+ *
12
+ * 1. `globalThis[WorldCacheKey]` — populated by a successful prior
13
+ * `getWorld()` call. This is the steady-state hot path.
14
+ * 2. `globalThis[GetWorldFnKey]` — populated by the module-load side
15
+ * effect at the bottom of `./world.ts`. Fires on every server bundle
16
+ * that reaches this file via `workflow` or `workflow/api` (which import
17
+ * `./world-init.ts` for its side effect; see that file for the full
18
+ * rationale). This is the cold-start path for routes that consume host
19
+ * helpers without any prior workflow run.
20
+ */
21
+ import { assertWorldSupportsRuntimeProtocol } from './world-compatibility.js';
22
+ const WorldCacheKey = Symbol.for('@workflow/world//cache');
23
+ const WorldCachePromiseKey = Symbol.for('@workflow/world//cachePromise');
24
+ const GetWorldFnKey = Symbol.for('@workflow/world//getWorldFn');
25
+ export async function getWorldLazy() {
26
+ const g = globalThis;
27
+ if (g[WorldCacheKey]) {
28
+ assertWorldSupportsRuntimeProtocol(g[WorldCacheKey]);
29
+ return g[WorldCacheKey];
30
+ }
31
+ if (g[WorldCachePromiseKey]) {
32
+ g[WorldCacheKey] = await g[WorldCachePromiseKey];
33
+ assertWorldSupportsRuntimeProtocol(g[WorldCacheKey]);
34
+ return g[WorldCacheKey];
35
+ }
36
+ // world-init statically imports world.ts in host bundles, which registers
37
+ // getWorld on globalThis at module load.
38
+ const getWorldFn = g[GetWorldFnKey];
39
+ if (getWorldFn) {
40
+ const world = await getWorldFn();
41
+ assertWorldSupportsRuntimeProtocol(world);
42
+ return world;
43
+ }
44
+ throw new Error('Workflow world runtime was not initialized. Import from the host workflow entrypoints (`workflow`, `workflow/api`, or `workflow/runtime`) so @workflow/core/runtime/world-init can register getWorld before getWorldLazy() is used.');
45
+ }
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LXdvcmxkLWxhenkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9nZXQtd29ybGQtbGF6eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUdILE9BQU8sRUFBRSxrQ0FBa0MsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRTlFLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsd0JBQXdCLENBQUMsQ0FBQztBQUMzRCxNQUFNLG9CQUFvQixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsK0JBQStCLENBQUMsQ0FBQztBQUN6RSxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLDZCQUE2QixDQUFDLENBQUM7QUFRaEUsTUFBTSxDQUFDLEtBQUssVUFBVSxZQUFZO0lBQ2hDLE1BQU0sQ0FBQyxHQUFHLFVBQThCLENBQUM7SUFDekMsSUFBSSxDQUFDLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztRQUNyQixrQ0FBa0MsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztRQUNyRCxPQUFPLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBQ0QsSUFBSSxDQUFDLENBQUMsb0JBQW9CLENBQUMsRUFBRSxDQUFDO1FBQzVCLENBQUMsQ0FBQyxhQUFhLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ2pELGtDQUFrQyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO1FBQ3JELE9BQU8sQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFDRCwwRUFBMEU7SUFDMUUseUNBQXlDO0lBQ3pDLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUNwQyxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQ2YsTUFBTSxLQUFLLEdBQUcsTUFBTSxVQUFVLEVBQUUsQ0FBQztRQUNqQyxrQ0FBa0MsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMxQyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxNQUFNLElBQUksS0FBSyxDQUNiLHFPQUFxTyxDQUN0TyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTGF6eSBhY2Nlc3NvciBmb3IgdGhlIFdvcmxkIHNpbmdsZXRvbiB2aWEgZ2xvYmFsVGhpcyBzeW1ib2xzLlxuICpcbiAqIFRoaXMgbW9kdWxlIGV4aXN0cyB0byBicmVhayB0aGUgc3RhdGljIGltcG9ydCBjaGFpbiBmcm9tIHN0ZXAtc2lkZVxuICogbW9kdWxlcyAoc2VyaWFsaXphdGlvbiwgcnVuLCBoZWxwZXJzLCBzdGFydCkgdG8gd29ybGQudHMuIFdpdGhvdXQgaXQsXG4gKiBlc2J1aWxkIGJ1bmRsZXMgd29ybGQudHMgKGFuZCBpdHMgdHJhbnNpdGl2ZSBkZXBzOiB3b3JsZC1sb2NhbCxcbiAqIHdvcmxkLXZlcmNlbCwgcHJvY2Vzcy5jd2QoKSwgZXRjLikgaW50byB0aGUgc3RlcCByZWdpc3RyYXRpb25zIGJ1bmRsZSxcbiAqIHdoaWNoIHRyaWdnZXJzIFR1cmJvcGFjayBORlQgdHJhY2luZyBlcnJvcnMgaW4gdGhlIFYyIGNvbWJpbmVkIGZsb3cgcm91dGUuXG4gKlxuICogUmVzb2x1dGlvbiBvcmRlciwgaW4gcHJpb3JpdHk6XG4gKlxuICogMS4gYGdsb2JhbFRoaXNbV29ybGRDYWNoZUtleV1gIOKAlCBwb3B1bGF0ZWQgYnkgYSBzdWNjZXNzZnVsIHByaW9yXG4gKiAgICBgZ2V0V29ybGQoKWAgY2FsbC4gVGhpcyBpcyB0aGUgc3RlYWR5LXN0YXRlIGhvdCBwYXRoLlxuICogMi4gYGdsb2JhbFRoaXNbR2V0V29ybGRGbktleV1gIOKAlCBwb3B1bGF0ZWQgYnkgdGhlIG1vZHVsZS1sb2FkIHNpZGVcbiAqICAgIGVmZmVjdCBhdCB0aGUgYm90dG9tIG9mIGAuL3dvcmxkLnRzYC4gRmlyZXMgb24gZXZlcnkgc2VydmVyIGJ1bmRsZVxuICogICAgdGhhdCByZWFjaGVzIHRoaXMgZmlsZSB2aWEgYHdvcmtmbG93YCBvciBgd29ya2Zsb3cvYXBpYCAod2hpY2ggaW1wb3J0XG4gKiAgICBgLi93b3JsZC1pbml0LnRzYCBmb3IgaXRzIHNpZGUgZWZmZWN0OyBzZWUgdGhhdCBmaWxlIGZvciB0aGUgZnVsbFxuICogICAgcmF0aW9uYWxlKS4gVGhpcyBpcyB0aGUgY29sZC1zdGFydCBwYXRoIGZvciByb3V0ZXMgdGhhdCBjb25zdW1lIGhvc3RcbiAqICAgIGhlbHBlcnMgd2l0aG91dCBhbnkgcHJpb3Igd29ya2Zsb3cgcnVuLlxuICovXG5cbmltcG9ydCB0eXBlIHsgV29ybGQgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgYXNzZXJ0V29ybGRTdXBwb3J0c1J1bnRpbWVQcm90b2NvbCB9IGZyb20gJy4vd29ybGQtY29tcGF0aWJpbGl0eS5qcyc7XG5cbmNvbnN0IFdvcmxkQ2FjaGVLZXkgPSBTeW1ib2wuZm9yKCdAd29ya2Zsb3cvd29ybGQvL2NhY2hlJyk7XG5jb25zdCBXb3JsZENhY2hlUHJvbWlzZUtleSA9IFN5bWJvbC5mb3IoJ0B3b3JrZmxvdy93b3JsZC8vY2FjaGVQcm9taXNlJyk7XG5jb25zdCBHZXRXb3JsZEZuS2V5ID0gU3ltYm9sLmZvcignQHdvcmtmbG93L3dvcmxkLy9nZXRXb3JsZEZuJyk7XG5cbnR5cGUgR2xvYmFsV29ybGRDYWNoZSA9IHR5cGVvZiBnbG9iYWxUaGlzICYge1xuICBbV29ybGRDYWNoZUtleV0/OiBXb3JsZDtcbiAgW1dvcmxkQ2FjaGVQcm9taXNlS2V5XT86IFByb21pc2U8V29ybGQ+O1xuICBbR2V0V29ybGRGbktleV0/OiAoKSA9PiBQcm9taXNlPFdvcmxkPjtcbn07XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRXb3JsZExhenkoKTogUHJvbWlzZTxXb3JsZD4ge1xuICBjb25zdCBnID0gZ2xvYmFsVGhpcyBhcyBHbG9iYWxXb3JsZENhY2hlO1xuICBpZiAoZ1tXb3JsZENhY2hlS2V5XSkge1xuICAgIGFzc2VydFdvcmxkU3VwcG9ydHNSdW50aW1lUHJvdG9jb2woZ1tXb3JsZENhY2hlS2V5XSk7XG4gICAgcmV0dXJuIGdbV29ybGRDYWNoZUtleV07XG4gIH1cbiAgaWYgKGdbV29ybGRDYWNoZVByb21pc2VLZXldKSB7XG4gICAgZ1tXb3JsZENhY2hlS2V5XSA9IGF3YWl0IGdbV29ybGRDYWNoZVByb21pc2VLZXldO1xuICAgIGFzc2VydFdvcmxkU3VwcG9ydHNSdW50aW1lUHJvdG9jb2woZ1tXb3JsZENhY2hlS2V5XSk7XG4gICAgcmV0dXJuIGdbV29ybGRDYWNoZUtleV07XG4gIH1cbiAgLy8gd29ybGQtaW5pdCBzdGF0aWNhbGx5IGltcG9ydHMgd29ybGQudHMgaW4gaG9zdCBidW5kbGVzLCB3aGljaCByZWdpc3RlcnNcbiAgLy8gZ2V0V29ybGQgb24gZ2xvYmFsVGhpcyBhdCBtb2R1bGUgbG9hZC5cbiAgY29uc3QgZ2V0V29ybGRGbiA9IGdbR2V0V29ybGRGbktleV07XG4gIGlmIChnZXRXb3JsZEZuKSB7XG4gICAgY29uc3Qgd29ybGQgPSBhd2FpdCBnZXRXb3JsZEZuKCk7XG4gICAgYXNzZXJ0V29ybGRTdXBwb3J0c1J1bnRpbWVQcm90b2NvbCh3b3JsZCk7XG4gICAgcmV0dXJuIHdvcmxkO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihcbiAgICAnV29ya2Zsb3cgd29ybGQgcnVudGltZSB3YXMgbm90IGluaXRpYWxpemVkLiBJbXBvcnQgZnJvbSB0aGUgaG9zdCB3b3JrZmxvdyBlbnRyeXBvaW50cyAoYHdvcmtmbG93YCwgYHdvcmtmbG93L2FwaWAsIG9yIGB3b3JrZmxvdy9ydW50aW1lYCkgc28gQHdvcmtmbG93L2NvcmUvcnVudGltZS93b3JsZC1pbml0IGNhbiByZWdpc3RlciBnZXRXb3JsZCBiZWZvcmUgZ2V0V29ybGRMYXp5KCkgaXMgdXNlZC4nXG4gICk7XG59XG4iXX0=