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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/dist/attribute-changes.d.ts +5 -0
  2. package/dist/attribute-changes.d.ts.map +1 -0
  3. package/dist/attribute-changes.js +25 -0
  4. package/dist/capabilities.d.ts +35 -2
  5. package/dist/capabilities.d.ts.map +1 -1
  6. package/dist/capabilities.js +74 -5
  7. package/dist/capture-stack.d.ts +1 -1
  8. package/dist/capture-stack.js +2 -2
  9. package/dist/class-serialization.d.ts +32 -0
  10. package/dist/class-serialization.d.ts.map +1 -1
  11. package/dist/class-serialization.js +37 -1
  12. package/dist/classify-error.d.ts +19 -3
  13. package/dist/classify-error.d.ts.map +1 -1
  14. package/dist/classify-error.js +98 -6
  15. package/dist/context-violation-error.d.ts +5 -5
  16. package/dist/context-violation-error.d.ts.map +1 -1
  17. package/dist/context-violation-error.js +8 -6
  18. package/dist/create-hook.d.ts +72 -7
  19. package/dist/create-hook.d.ts.map +1 -1
  20. package/dist/create-hook.js +1 -1
  21. package/dist/define-hook.js +2 -2
  22. package/dist/describe-error.d.ts +7 -7
  23. package/dist/describe-error.d.ts.map +1 -1
  24. package/dist/describe-error.js +97 -12
  25. package/dist/encryption.d.ts +38 -4
  26. package/dist/encryption.d.ts.map +1 -1
  27. package/dist/encryption.js +96 -14
  28. package/dist/events-consumer.d.ts +271 -0
  29. package/dist/events-consumer.d.ts.map +1 -1
  30. package/dist/events-consumer.js +646 -42
  31. package/dist/flushable-stream.d.ts +56 -1
  32. package/dist/flushable-stream.d.ts.map +1 -1
  33. package/dist/flushable-stream.js +123 -11
  34. package/dist/global.d.ts +36 -2
  35. package/dist/global.d.ts.map +1 -1
  36. package/dist/global.js +21 -6
  37. package/dist/index.d.ts +2 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +3 -2
  40. package/dist/log-format.d.ts +2 -2
  41. package/dist/log-format.js +7 -7
  42. package/dist/logger.d.ts +1 -0
  43. package/dist/logger.d.ts.map +1 -1
  44. package/dist/logger.js +10 -6
  45. package/dist/private.d.ts +226 -9
  46. package/dist/private.d.ts.map +1 -1
  47. package/dist/private.js +626 -7
  48. package/dist/replay-payload-cache.d.ts +64 -0
  49. package/dist/replay-payload-cache.d.ts.map +1 -0
  50. package/dist/replay-payload-cache.js +158 -0
  51. package/dist/runtime/compute-instance.d.ts +13 -0
  52. package/dist/runtime/compute-instance.d.ts.map +1 -0
  53. package/dist/runtime/compute-instance.js +14 -0
  54. package/dist/runtime/constants.d.ts +315 -0
  55. package/dist/runtime/constants.d.ts.map +1 -1
  56. package/dist/runtime/constants.js +502 -16
  57. package/dist/runtime/count-step-started-events.d.ts +52 -0
  58. package/dist/runtime/count-step-started-events.d.ts.map +1 -0
  59. package/dist/runtime/count-step-started-events.js +72 -0
  60. package/dist/runtime/deployment-guard.d.ts +99 -0
  61. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  62. package/dist/runtime/deployment-guard.js +154 -0
  63. package/dist/runtime/get-port-lazy.d.ts +15 -0
  64. package/dist/runtime/get-port-lazy.d.ts.map +1 -1
  65. package/dist/runtime/get-port-lazy.js +75 -6
  66. package/dist/runtime/get-world-lazy.d.ts +5 -14
  67. package/dist/runtime/get-world-lazy.d.ts.map +1 -1
  68. package/dist/runtime/get-world-lazy.js +19 -29
  69. package/dist/runtime/helpers.d.ts +341 -29
  70. package/dist/runtime/helpers.d.ts.map +1 -1
  71. package/dist/runtime/helpers.js +559 -57
  72. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  73. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  74. package/dist/runtime/quickjs-assets.generated.js +30 -0
  75. package/dist/runtime/quickjs-entrypoint.d.ts +136 -0
  76. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  77. package/dist/runtime/quickjs-entrypoint.js +1686 -0
  78. package/dist/runtime/quickjs-runtime.d.ts +244 -0
  79. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  80. package/dist/runtime/quickjs-runtime.js +2427 -0
  81. package/dist/runtime/quickjs-serde.d.ts +107 -0
  82. package/dist/runtime/quickjs-serde.d.ts.map +1 -0
  83. package/dist/runtime/quickjs-serde.js +2159 -0
  84. package/dist/runtime/replay-budget.d.ts +97 -0
  85. package/dist/runtime/replay-budget.d.ts.map +1 -0
  86. package/dist/runtime/replay-budget.js +139 -0
  87. package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
  88. package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
  89. package/dist/runtime/replay-recovery-reporter.js +64 -0
  90. package/dist/runtime/resume-hook.d.ts +91 -8
  91. package/dist/runtime/resume-hook.d.ts.map +1 -1
  92. package/dist/runtime/resume-hook.js +512 -89
  93. package/dist/runtime/resume-latency.d.ts +150 -0
  94. package/dist/runtime/resume-latency.d.ts.map +1 -0
  95. package/dist/runtime/resume-latency.js +155 -0
  96. package/dist/runtime/run-id-time.d.ts +19 -0
  97. package/dist/runtime/run-id-time.d.ts.map +1 -0
  98. package/dist/runtime/run-id-time.js +42 -0
  99. package/dist/runtime/run.d.ts +72 -7
  100. package/dist/runtime/run.d.ts.map +1 -1
  101. package/dist/runtime/run.js +280 -53
  102. package/dist/runtime/runs.d.ts +54 -3
  103. package/dist/runtime/runs.d.ts.map +1 -1
  104. package/dist/runtime/runs.js +126 -16
  105. package/dist/runtime/start.d.ts +101 -2
  106. package/dist/runtime/start.d.ts.map +1 -1
  107. package/dist/runtime/start.js +352 -61
  108. package/dist/runtime/step-executor.d.ts +205 -5
  109. package/dist/runtime/step-executor.d.ts.map +1 -1
  110. package/dist/runtime/step-executor.js +760 -127
  111. package/dist/runtime/step-latency.d.ts +220 -0
  112. package/dist/runtime/step-latency.d.ts.map +1 -0
  113. package/dist/runtime/step-latency.js +215 -0
  114. package/dist/runtime/step-ownership.d.ts +72 -0
  115. package/dist/runtime/step-ownership.d.ts.map +1 -0
  116. package/dist/runtime/step-ownership.js +114 -0
  117. package/dist/runtime/step-single-flight.d.ts +12 -0
  118. package/dist/runtime/step-single-flight.d.ts.map +1 -0
  119. package/dist/runtime/step-single-flight.js +75 -0
  120. package/dist/runtime/suspension-handler.d.ts +269 -7
  121. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  122. package/dist/runtime/suspension-handler.js +1253 -125
  123. package/dist/runtime/unserializable-step.d.ts +34 -0
  124. package/dist/runtime/unserializable-step.d.ts.map +1 -0
  125. package/dist/runtime/unserializable-step.js +52 -0
  126. package/dist/runtime/vm-mode.d.ts +44 -0
  127. package/dist/runtime/vm-mode.d.ts.map +1 -0
  128. package/dist/runtime/vm-mode.js +62 -0
  129. package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
  130. package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
  131. package/dist/runtime/vm-serde-bundle.generated.js +16 -0
  132. package/dist/runtime/wait-continuation.d.ts +106 -0
  133. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  134. package/dist/runtime/wait-continuation.js +136 -0
  135. package/dist/runtime/wait-until.d.ts +18 -0
  136. package/dist/runtime/wait-until.d.ts.map +1 -0
  137. package/dist/runtime/wait-until.js +42 -0
  138. package/dist/runtime/world-compatibility.d.ts +32 -0
  139. package/dist/runtime/world-compatibility.d.ts.map +1 -0
  140. package/dist/runtime/world-compatibility.js +44 -0
  141. package/dist/runtime/world-init.d.ts +17 -42
  142. package/dist/runtime/world-init.d.ts.map +1 -1
  143. package/dist/runtime/world-init.js +18 -43
  144. package/dist/runtime/world.d.ts +14 -2
  145. package/dist/runtime/world.d.ts.map +1 -1
  146. package/dist/runtime/world.js +75 -19
  147. package/dist/runtime.d.ts +10 -6
  148. package/dist/runtime.d.ts.map +1 -1
  149. package/dist/runtime.js +3741 -490
  150. package/dist/sealed-box.d.ts +167 -0
  151. package/dist/sealed-box.d.ts.map +1 -0
  152. package/dist/sealed-box.js +571 -0
  153. package/dist/serialization/client.d.ts +3 -3
  154. package/dist/serialization/client.d.ts.map +1 -1
  155. package/dist/serialization/client.js +8 -4
  156. package/dist/serialization/codec-devalue-vm.d.ts +16 -0
  157. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  158. package/dist/serialization/codec-devalue-vm.js +148 -0
  159. package/dist/serialization/codec-devalue.d.ts +1 -1
  160. package/dist/serialization/codec-devalue.d.ts.map +1 -1
  161. package/dist/serialization/codec-devalue.js +24 -6
  162. package/dist/serialization/codec.d.ts +37 -2
  163. package/dist/serialization/codec.d.ts.map +1 -1
  164. package/dist/serialization/codec.js +2 -2
  165. package/dist/serialization/compression.d.ts +105 -0
  166. package/dist/serialization/compression.d.ts.map +1 -0
  167. package/dist/serialization/compression.js +261 -0
  168. package/dist/serialization/encryption.d.ts +119 -17
  169. package/dist/serialization/encryption.d.ts.map +1 -1
  170. package/dist/serialization/encryption.js +152 -17
  171. package/dist/serialization/errors.d.ts +13 -0
  172. package/dist/serialization/errors.d.ts.map +1 -1
  173. package/dist/serialization/errors.js +20 -2
  174. package/dist/serialization/format.d.ts +6 -6
  175. package/dist/serialization/format.js +7 -7
  176. package/dist/serialization/hardened.d.ts +156 -0
  177. package/dist/serialization/hardened.d.ts.map +1 -0
  178. package/dist/serialization/hardened.js +538 -0
  179. package/dist/serialization/index.d.ts +10 -8
  180. package/dist/serialization/index.d.ts.map +1 -1
  181. package/dist/serialization/index.js +10 -8
  182. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  183. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  184. package/dist/serialization/reducers/class-vm.js +77 -0
  185. package/dist/serialization/reducers/class.d.ts.map +1 -1
  186. package/dist/serialization/reducers/class.js +11 -6
  187. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  188. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  189. package/dist/serialization/reducers/common-vm.js +616 -0
  190. package/dist/serialization/reducers/common.d.ts +1 -1
  191. package/dist/serialization/reducers/common.d.ts.map +1 -1
  192. package/dist/serialization/reducers/common.js +202 -62
  193. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  194. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  195. package/dist/serialization/reducers/step-function-vm.js +97 -0
  196. package/dist/serialization/reducers/step-function.d.ts.map +1 -1
  197. package/dist/serialization/reducers/step-function.js +25 -9
  198. package/dist/serialization/step.d.ts +4 -4
  199. package/dist/serialization/step.d.ts.map +1 -1
  200. package/dist/serialization/step.js +9 -5
  201. package/dist/serialization/types.d.ts +80 -1
  202. package/dist/serialization/types.d.ts.map +1 -1
  203. package/dist/serialization/types.js +15 -1
  204. package/dist/serialization/workflow-vm.d.ts +29 -0
  205. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  206. package/dist/serialization/workflow-vm.js +74 -0
  207. package/dist/serialization-format.d.ts +64 -8
  208. package/dist/serialization-format.d.ts.map +1 -1
  209. package/dist/serialization-format.js +225 -73
  210. package/dist/serialization.d.ts +262 -34
  211. package/dist/serialization.d.ts.map +1 -1
  212. package/dist/serialization.js +1879 -274
  213. package/dist/set-attributes.d.ts +13 -0
  214. package/dist/set-attributes.d.ts.map +1 -0
  215. package/dist/set-attributes.js +60 -0
  216. package/dist/source-map.d.ts +25 -0
  217. package/dist/source-map.d.ts.map +1 -1
  218. package/dist/source-map.js +154 -10
  219. package/dist/step/context-storage.d.ts +61 -2
  220. package/dist/step/context-storage.d.ts.map +1 -1
  221. package/dist/step/context-storage.js +7 -5
  222. package/dist/step/writable-stream.d.ts +3 -3
  223. package/dist/step/writable-stream.d.ts.map +1 -1
  224. package/dist/step/writable-stream.js +72 -9
  225. package/dist/step.d.ts.map +1 -1
  226. package/dist/step.js +148 -27
  227. package/dist/symbols.d.ts +50 -0
  228. package/dist/symbols.d.ts.map +1 -1
  229. package/dist/symbols.js +51 -1
  230. package/dist/telemetry/semantic-conventions.d.ts +397 -2
  231. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  232. package/dist/telemetry/semantic-conventions.js +297 -3
  233. package/dist/telemetry.d.ts +91 -0
  234. package/dist/telemetry.d.ts.map +1 -1
  235. package/dist/telemetry.js +244 -17
  236. package/dist/test-support/orchestrator-context.d.ts +25 -0
  237. package/dist/test-support/orchestrator-context.d.ts.map +1 -0
  238. package/dist/test-support/orchestrator-context.js +101 -0
  239. package/dist/types.d.ts +6 -0
  240. package/dist/types.d.ts.map +1 -1
  241. package/dist/types.js +23 -1
  242. package/dist/util.d.ts +0 -5
  243. package/dist/util.d.ts.map +1 -1
  244. package/dist/util.js +1 -15
  245. package/dist/version.d.ts +1 -1
  246. package/dist/version.d.ts.map +1 -1
  247. package/dist/version.js +2 -2
  248. package/dist/vm/index.d.ts.map +1 -1
  249. package/dist/vm/index.js +84 -14
  250. package/dist/vm/script-cache.d.ts +26 -0
  251. package/dist/vm/script-cache.d.ts.map +1 -0
  252. package/dist/vm/script-cache.js +131 -0
  253. package/dist/vm/uint8array-base64.js +1 -1
  254. package/dist/workflow/abort-controller.d.ts +2 -2
  255. package/dist/workflow/abort-controller.d.ts.map +1 -1
  256. package/dist/workflow/abort-controller.js +88 -21
  257. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  258. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  259. package/dist/workflow/attribute-dispatcher.js +45 -0
  260. package/dist/workflow/create-hook.d.ts.map +1 -1
  261. package/dist/workflow/create-hook.js +24 -3
  262. package/dist/workflow/get-workflow-metadata.js +2 -2
  263. package/dist/workflow/hook.d.ts.map +1 -1
  264. package/dist/workflow/hook.js +304 -47
  265. package/dist/workflow/index.d.ts +1 -0
  266. package/dist/workflow/index.d.ts.map +1 -1
  267. package/dist/workflow/index.js +2 -1
  268. package/dist/workflow/set-attributes.d.ts +68 -0
  269. package/dist/workflow/set-attributes.d.ts.map +1 -0
  270. package/dist/workflow/set-attributes.js +60 -0
  271. package/dist/workflow/sleep.d.ts.map +1 -1
  272. package/dist/workflow/sleep.js +58 -12
  273. package/dist/workflow/world-init-stub.d.ts +3 -3
  274. package/dist/workflow/world-init-stub.js +4 -4
  275. package/dist/workflow.d.ts +95 -3
  276. package/dist/workflow.d.ts.map +1 -1
  277. package/dist/workflow.js +895 -561
  278. package/docs/api-reference/create-hook.mdx +89 -10
  279. package/docs/api-reference/create-webhook.mdx +16 -15
  280. package/docs/api-reference/define-hook.mdx +35 -33
  281. package/docs/api-reference/fatal-error.mdx +30 -8
  282. package/docs/api-reference/fetch.mdx +14 -10
  283. package/docs/api-reference/get-step-metadata.mdx +2 -2
  284. package/docs/api-reference/get-workflow-metadata.mdx +3 -3
  285. package/docs/api-reference/get-writable.mdx +7 -7
  286. package/docs/api-reference/index.mdx +4 -1
  287. package/docs/api-reference/retryable-error.mdx +1 -1
  288. package/docs/api-reference/set-attributes.mdx +61 -0
  289. package/docs/api-reference/sleep.mdx +4 -4
  290. package/docs/foundations/cancellation.mdx +31 -32
  291. package/docs/foundations/errors-and-retries.mdx +42 -11
  292. package/docs/foundations/hooks.mdx +64 -35
  293. package/docs/foundations/idempotency.mdx +244 -12
  294. package/docs/foundations/index.mdx +1 -23
  295. package/docs/foundations/meta.json +2 -1
  296. package/docs/foundations/serialization.mdx +21 -22
  297. package/docs/foundations/starting-workflows.mdx +106 -30
  298. package/docs/foundations/streaming.mdx +107 -59
  299. package/docs/foundations/versioning.mdx +263 -0
  300. package/docs/foundations/workflows-and-steps.mdx +9 -9
  301. package/docs/how-it-works/cancellation.mdx +63 -63
  302. package/docs/how-it-works/code-transform.mdx +83 -67
  303. package/docs/how-it-works/encryption.mdx +30 -26
  304. package/docs/how-it-works/event-sourcing.mdx +98 -34
  305. package/docs/how-it-works/framework-integrations.mdx +96 -337
  306. package/docs/how-it-works/understanding-directives.mdx +22 -22
  307. package/package.json +24 -15
  308. package/dist/runtime/step-handler.d.ts +0 -2
  309. package/dist/runtime/step-handler.d.ts.map +0 -1
  310. package/dist/runtime/step-handler.js +0 -776
@@ -1,5 +1,5 @@
1
1
  ---
2
- title: Event Sourcing
2
+ title: Event sourcing
3
3
  description: Learn how Workflow SDK uses event sourcing internally for debugging and observability.
4
4
  type: conceptual
5
5
  summary: Understand the event log that powers workflow replay and debugging.
@@ -10,14 +10,12 @@ related:
10
10
  ---
11
11
 
12
12
  <Callout>
13
- This guide explores how the Workflow SDK uses event sourcing internally. Understanding these concepts is helpful for debugging and building observability tools, but is not required to use workflows. For getting started with workflows, see the [getting started](/docs/getting-started) guides for your framework.
13
+ Workflow SDK uses event sourcing internally for debugging and observability tools. To start using workflows, see the [getting started](/docs/getting-started) guide for your framework.
14
14
  </Callout>
15
15
 
16
16
  The Workflow SDK uses event sourcing to track all state changes in workflow executions. Every mutation creates an event that is persisted to the event log, and entity state is derived by replaying these events.
17
17
 
18
- This page explains the event sourcing model and entity lifecycles.
19
-
20
- ## Event Sourcing Overview
18
+ ## Event sourcing overview
21
19
 
22
20
  Event sourcing is a persistence pattern where state changes are stored as a sequence of events rather than by updating records in place. The current state of any entity is reconstructed by replaying its events from the beginning.
23
21
 
@@ -35,15 +33,15 @@ In the Workflow SDK, the following entity types are managed through events:
35
33
  - **Hooks**: Suspension points that can receive external data (materialized in storage)
36
34
  - **Waits**: Sleep or delay operations (materialized in storage)
37
35
 
38
- ## Entity Lifecycles
36
+ ## Entity lifecycles
39
37
 
40
- Each entity type follows a specific lifecycle defined by the events that can affect it. Events transition entities between states, and certain states are terminal—once reached, no further transitions are possible.
38
+ Each entity type follows a specific lifecycle defined by the events that can affect it. Events transition entities between states. Once an entity reaches a terminal state, no further transitions are possible.
41
39
 
42
40
  <Callout type="info">
43
41
  In the diagrams below, <span style={{color: '#8b5cf6', fontWeight: 'bold'}}>purple nodes</span> indicate terminal states that cannot be transitioned out of.
44
42
  </Callout>
45
43
 
46
- ### Run Lifecycle
44
+ ### Run lifecycle
47
45
 
48
46
  A run represents a single execution of a workflow function. Runs begin in `pending` state when created, transition to `running` when execution starts, and end in one of three terminal states.
49
47
 
@@ -67,9 +65,9 @@ flowchart TD
67
65
  - `running`: Actively executing workflow code
68
66
  - `completed`: Finished successfully with an output value
69
67
  - `failed`: Terminated due to an unrecoverable error
70
- - `cancelled`: Explicitly cancelled by the user or system
68
+ - `cancelled`: Explicitly canceled by the user or system
71
69
 
72
- ### Step Lifecycle
70
+ ### Step lifecycle
73
71
 
74
72
  A step represents a single invocation of a step function. Steps can retry on failure, either transitioning back to `pending` via `step_retrying` or being re-executed directly with another `step_started` event.
75
73
 
@@ -94,7 +92,7 @@ flowchart TD
94
92
  - `cancelled`: Reserved for future use (not currently emitted)
95
93
 
96
94
  <Callout type="info">
97
- The `step_retrying` event is optional. Steps can retry without it - the retry mechanism works regardless of whether this event is emitted. You may see back-to-back `step_started` events in logs when a step retries after a timeout or when the error is not explicitly captured. See [Errors and Retries](/docs/foundations/errors-and-retries) for more on how retries work.
95
+ The `step_retrying` event is optional. Steps can retry without it, regardless of whether the event is emitted. You may see consecutive `step_started` events when a step retries after a timeout, when the error isn't explicitly captured, or when concurrent replays each commit one. See [Duplicate events](#duplicate-events) and [Errors and retries](/docs/foundations/errors-and-retries) for more information.
98
96
  </Callout>
99
97
 
100
98
  When present, the `step_retrying` event moves a step back to `pending` state and records the error that caused the retry. This provides two benefits:
@@ -102,7 +100,7 @@ When present, the `step_retrying` event moves a step back to `pending` state and
102
100
  - **Cleaner observability**: The event log explicitly shows retry transitions rather than consecutive `step_started` events
103
101
  - **Error history**: The error that triggered the retry is preserved for debugging
104
102
 
105
- ### Hook Lifecycle
103
+ ### Hook lifecycle
106
104
 
107
105
  A hook represents a suspension point that can receive external data, created by [`createHook()`](/docs/api-reference/workflow/create-hook). Hooks enable workflows to pause and wait for external events, user interactions, or HTTP requests. Webhooks (created with [`createWebhook()`](/docs/api-reference/workflow/create-webhook)) are a higher-level abstraction built on hooks that adds automatic HTTP request/response handling.
108
106
 
@@ -121,19 +119,19 @@ flowchart TD
121
119
 
122
120
  **Hook states:**
123
121
 
124
- - `active`: Ready to receive payloads (hook exists in storage)
125
- - `disposed`: No longer accepting payloads (hook is deleted from storage)
122
+ - `active`: Ready to receive payloads
123
+ - `disposed`: No longer accepting payloads
126
124
  - `conflicted`: Hook creation failed because the token is already in use by another workflow
127
125
 
128
- Unlike other entities, hooks don't have a `status` field—the states above are conceptual. An "active" hook is one that exists in storage, while "disposed" means the hook has been deleted. When a `hook_disposed` event is created, the hook record is removed rather than updated.
126
+ Unlike other entities, hooks don't have a `status` field. The states above are conceptual. When a `hook_disposed` event is created, the hook record is removed rather than updated.
129
127
 
130
- While a hook is active, its token is reserved and cannot be used by other workflows. If a workflow attempts to create a hook with a token that is already in use by another active hook, a `hook_conflict` event is recorded instead of `hook_created`. This causes the hook's promise to reject with a `HookConflictError`, which you can detect with `HookConflictError.is(error)`. See the [hook-conflict error](/docs/errors/hook-conflict) documentation for more details.
128
+ While a hook is active, its token is reserved and cannot be used by other workflows. If a workflow attempts to create a hook with a token reserved by another run, either by an active hook or by `experimental_minRetention` after its run ended, a `hook_conflict` event is recorded instead of `hook_created`. Current Worlds include the token and the run ID that owns it, though older persisted events or World implementations may only include the token. This causes `hook.getConflict()` to resolve with the conflicting run and the hook's payload promise to reject with a `HookConflictError`, which you can detect with `HookConflictError.is(error)`. See the [hook-conflict error](/docs/errors/hook-conflict) documentation for more details.
131
129
 
132
- When a hook is disposed (either explicitly or when its workflow completes), the token is released and can be claimed by future workflows. Hooks are automatically disposed when a workflow reaches a terminal state (`completed`, `failed`, or `cancelled`). The `hook_disposed` event is only needed for explicit disposal before workflow completion.
130
+ When a workflow ends, its hooks can no longer be resumed. They are normally removed, and their tokens become available again. With `experimental_minRetention`, a hook remains readable, and its token remains unavailable until retention ends. A `hook_disposed` event removes the hook and makes its token available immediately.
133
131
 
134
- See [Hooks & Webhooks](/docs/foundations/hooks) for more on how hooks and webhooks work.
132
+ See [Hooks and webhooks](/docs/foundations/hooks) for more on how hooks and webhooks work.
135
133
 
136
- ### Wait Lifecycle
134
+ ### Wait lifecycle
137
135
 
138
136
  A wait represents a sleep operation created by [`sleep()`](/docs/api-reference/workflow/sleep). Waits track when a delay period has elapsed.
139
137
 
@@ -151,10 +149,10 @@ flowchart TD
151
149
  - `completed`: Delay period has elapsed, workflow can resume
152
150
 
153
151
  <Callout type="info">
154
- Like Runs, Steps, and Hooks, waits are materialized as entities in storage. When a `wait_created` event is processed, a wait entity is created with status `waiting`. When a `wait_completed` event is processed, the wait entity is atomically transitioned to `completed` this guarantees that a wait can only be completed exactly once, even if multiple concurrent invocations attempt to complete it simultaneously.
152
+ Like runs, steps, and hooks, waits are materialized as entities in storage. Processing a `wait_created` event creates a wait entity with the `waiting` status. Processing a `wait_completed` event atomically transitions the wait entity to `completed`. This process guarantees that a wait can only be completed once, even if multiple concurrent invocations attempt to complete it simultaneously.
155
153
  </Callout>
156
154
 
157
- ## Event Types Reference
155
+ ## Event types reference
158
156
 
159
157
  Events are categorized by the entity type they affect. Each event contains metadata including a timestamp and a `correlationId` that links the event to a specific entity:
160
158
 
@@ -163,7 +161,7 @@ Events are categorized by the entity type they affect. Each event contains metad
163
161
  - Wait events use the `waitId` as the correlation ID
164
162
  - Run events do not require a correlation ID since the `runId` itself identifies the entity
165
163
 
166
- ### Run Events
164
+ ### Run events
167
165
 
168
166
  | Event | Description |
169
167
  |-------|-------------|
@@ -173,7 +171,7 @@ Events are categorized by the entity type they affect. Each event contains metad
173
171
  | `run_failed` | Transitions the run to `failed` state with error details and optional error code. |
174
172
  | `run_cancelled` | Transitions the run to `cancelled` state. Can be triggered from `pending` or `running` states. |
175
173
 
176
- ### Step Events
174
+ ### Step events
177
175
 
178
176
  | Event | Description |
179
177
  |-------|-------------|
@@ -183,23 +181,29 @@ Events are categorized by the entity type they affect. Each event contains metad
183
181
  | `step_failed` | Transitions the step to `failed` state with error details. The step will not be retried. |
184
182
  | `step_retrying` | (Optional) Transitions the step back to `pending` state for retry. Contains the error that caused the retry and optional delay before the next attempt. When not emitted, retries appear as consecutive `step_started` events. |
185
183
 
186
- ### Hook Events
184
+ ### Hook events
187
185
 
188
186
  | Event | Description |
189
187
  |-------|-------------|
190
188
  | `hook_created` | Creates a new hook in `active` state. Contains the hook token and optional metadata. |
191
- | `hook_conflict` | Records that hook creation failed because the token is already in use by another active hook. The hook is not created, and awaiting the hook will reject with a `HookConflictError`. |
189
+ | `hook_conflict` | Records that hook creation failed because another run owns the token. Contains the token and, for current worlds, the owner's run ID. The hook is not created: `hook.getConflict()` resolves with the conflicting run, and awaiting the hook payload rejects with a `HookConflictError`. |
192
190
  | `hook_received` | Records that a payload was delivered to the hook. The hook remains `active` and can receive more payloads. |
193
191
  | `hook_disposed` | Deletes the hook from storage (conceptually transitioning to `disposed` state). The token is released for reuse by future workflows. |
194
192
 
195
- ### Wait Events
193
+ ### Wait events
196
194
 
197
195
  | Event | Description |
198
196
  |-------|-------------|
199
197
  | `wait_created` | Creates a new wait in `waiting` state. Contains the timestamp when the wait should complete. |
200
198
  | `wait_completed` | Transitions the wait to `completed` state when the delay period has elapsed. |
201
199
 
202
- ## Terminal States
200
+ ### System events
201
+
202
+ | Event | Description |
203
+ |-------|-------------|
204
+ | `noop` | Seals an abandoned log position (`specVersion` 7 and above). Only the backend writes this event; the create endpoints reject it. See [Sealed positions](#sealed-positions-noop-events). |
205
+
206
+ ## Terminal states
203
207
 
204
208
  Terminal states represent the end of an entity's lifecycle. Once an entity reaches a terminal state, no further events can transition it to another state.
205
209
 
@@ -207,7 +211,7 @@ Terminal states represent the end of an entity's lifecycle. Once an entity reach
207
211
 
208
212
  - `completed`: Workflow finished successfully
209
213
  - `failed`: Workflow encountered an unrecoverable error
210
- - `cancelled`: Workflow was explicitly cancelled
214
+ - `cancelled`: Workflow was explicitly canceled
211
215
 
212
216
  **Step terminal states:**
213
217
 
@@ -225,7 +229,59 @@ Terminal states represent the end of an entity's lifecycle. Once an entity reach
225
229
 
226
230
  Attempting to create an event that would transition an entity out of a terminal state will result in an error. This prevents inconsistent state and ensures the integrity of the event log.
227
231
 
228
- ## Event Correlation
232
+ That guard sits on the write path. Replay handles duplicates that the write path permits, such as a second `step_created` for a step that isn't terminal.
233
+
234
+ ## Duplicate events
235
+
236
+ Concurrent invocations replaying the same run share one event log. An invocation working from a stale prefix that predates another invocation's write can commit its own `step_created`, `step_started`, or `wait_created` for an entity that already has one in the log. These writes pass the terminal-state guard, so the write path commits them even when a backend validates transitions atomically with the insert.
237
+
238
+ Those duplicates are committed but inert. The outcome was decided by the first event of its kind at a lower position in the log, and every replay reads that same event at that same position, so a later copy cannot change what the workflow observes.
239
+
240
+ To prevent an inert copy from failing an otherwise healthy run, the runtime groups event types into **classes**. For each entity, it tracks which classes the current replay has consumed. If no registered consumer accepts an event and its class is already recorded for that entity, replay skips it instead of reporting a [replay divergence](/docs/errors/replay-divergence). After exhausting the recovery budget, a replay divergence ends the run with [`CORRUPTED_EVENT_LOG`](/docs/errors/corrupted-event-log).
241
+
242
+ | Class | Event types |
243
+ |-------|-------------|
244
+ | `run_started` | `run_started` |
245
+ | `step_created` | `step_created` |
246
+ | `step_started` | `step_started` |
247
+ | `step_retrying` | `step_retrying` |
248
+ | `step_terminal` | `step_completed`, `step_failed` |
249
+ | `wait_created` | `wait_created` |
250
+ | `wait_completed` | `wait_completed` |
251
+ | `hook_created` | `hook_created` |
252
+ | `hook_disposed` | `hook_disposed` |
253
+
254
+ Types that share a class are the mutually exclusive outcomes of one decision. A step either completes or fails, and the first recorded outcome counts. Classes are independent, so skipping one doesn't suppress another. A step whose result is already in the log has still recorded exactly one `step_created`, making a second one independently ignorable.
255
+
256
+ The two hook classes cover the same shape of duplicate, and replay reaches them less often because the write path resolves most hook duplicates before they reach the log: a run re-creating a hook it already owns converges on the existing `hook_created` rather than appending a second one, and a second `hook_disposed` for the same hook is refused as an idempotent no-op. A log that holds either anyway is read past like any other repeat.
257
+
258
+ The remaining event types belong to no class and are never skipped:
259
+
260
+ - `hook_received`: a hook legitimately receives many payloads under one ID, so a second `hook_received` is not a repeat of anything.
261
+ - `hook_conflict`: records a failed acquisition of a hook's token, which the same run can hit repeatedly over its lifetime as other runs take and release that token. The hook's own consumer stays registered and claims every copy it is offered, so a repeat is consumed rather than reaching the class check.
262
+ - `attr_set`: written on every [`setAttributes()`](/docs/api-reference/workflow/set-attributes) call, so a second write of the same key is a new fact rather than a repeat.
263
+ - `run_created` precedes every replay and is always consumed.
264
+ - `run_completed`, `run_failed`, and `run_cancelled` never reach the check. The runtime exits before replaying the workflow body once the log holds one of them, so no consumer ever takes one and no class is ever recorded for them.
265
+
266
+ Both kinds of skip are logged at `debug`, so neither reaches the console unless you run with `DEBUG=workflow:runtime:*`. A duplicate is a permanent part of the log. Every later replay reads it and reaches the same check, so an unconditional message would print once per replay for the life of the run without requiring action. A repeat that decides a class differently, such as a `step_failed` after a `step_completed` or the reverse, gets its own message. Unlike a recommit of the same outcome, both writers cannot be correct.
267
+
268
+ The observability UI grays out events it can identify this way and shows the reason on hover. Its set is narrower than the runtime's because it reads the log without consumer state. A consumer for an entity that is still open can legitimately claim a repeat because each step retry writes another `step_started`. The UI marks a repeat only when no consumer can remain for it: after a terminal event for the same entity or at a second `run_started`, of which the log records one per run. The UI marks nothing on a partial log view, such as one page of a paginated list or search results, because identifying the first copy requires the entire log.
269
+
270
+ ## Sealed positions (noop events)
271
+
272
+ Runs at `specVersion` 7 and above use a *sealed log*. The backend gives each write its position from a per-run sequencer **before** the write commits, so concurrent writers hold distinct positions and never race for a slot. New runs use this behavior by default. [`WORKFLOW_SEALED_LOG=0`](/docs/configuration/runtime-tuning#workflow_sealed_log) returns a deployment to the previous scheme. Every runtime reads a sealed log regardless, and a run's version is fixed at creation, so changing the setting never affects an in-flight run. However, a writer can claim a position and then stop because of a crashed process or canceled transaction. This leaves a hole that no writer will fill, and a hole looks like an event the reader failed to load.
273
+
274
+ The backend restores the dense log at read time by **sealing** these positions. Once a hole is provably abandoned, bounded by the commit time of later positions, the backend writes a `noop` event into it. Positions are assigned in order, so a committed later position proves how long the hole has been open. A `noop` occupies its position, and length-based completeness checks, cursors, and pagination all count it. It has no other effect:
275
+
276
+ - It is **never offered to any consumer** during replay. The walk steps over it in the same synchronous pass that delivers the events around it, so its presence cannot perturb delivery order, promise scheduling, or which branch of a `Promise.all` resumes first.
277
+ - It **never advances the deterministic clock**. A `noop`'s `createdAt` is the *sealer's* wall clock and can postdate events at higher positions. Allowing it to feed the replay clock would make a log containing a seal replay differently from one whose original writer filled the hole. This behavior uses the same rule and mechanism as skipped duplicates.
278
+ - Its `correlationId` is `noop_` followed by the sealed position's zero-padded digits. This deterministic format ensures that two sealers racing for the same hole create an identical event that is recognizable in the log.
279
+
280
+ A sealed position races its original writer at the same uniqueness fence as every other write. Losing that race means the real event landed first, so readers receive it instead. A live writer that gets sealed over derives a new position and commits there, using the same recovery as any other lost write race. Sealing can require a retry but cannot produce an incorrect log.
281
+
282
+ `noop` is not user-creatable: it does not exist in the create schemas, and backends reject it on every create endpoint. Only a backend's own read path writes one.
283
+
284
+ ## Event correlation
229
285
 
230
286
  Events use a `correlationId` to link related events together. For step, hook, and wait events, the correlation ID identifies the specific entity instance:
231
287
 
@@ -241,7 +297,7 @@ This correlation enables:
241
297
  - Building timelines of entity lifecycle transitions
242
298
  - Debugging by tracing the complete history of any entity
243
299
 
244
- ### Request ID Correlation
300
+ ### Request ID correlation
245
301
 
246
302
  Some `World` implementations also attach a `requestId` to events for platform-log correlation. This is different from `correlationId`:
247
303
 
@@ -260,7 +316,7 @@ On Vercel, `requestId` is the platform request ID when available. Other worlds a
260
316
 
261
317
  ## Entity IDs
262
318
 
263
- All entities in the Workflow SDK use a consistent ID format: a 4-character prefix followed by an underscore and a [ULID](https://github.com/ulid/spec) (Universally Unique Lexicographically Sortable Identifier).
319
+ All entities in the Workflow SDK use a consistent ID format: a 4-character prefix followed by an underscore and a fixed-width body. For every entity except events, that body is a [ULID](https://github.com/ulid/spec) (Universally Unique Lexicographically Sortable Identifier). An event's body is its slot number, described below.
264
320
 
265
321
  | Entity | Prefix | Example |
266
322
  |--------|--------|---------|
@@ -268,11 +324,19 @@ All entities in the Workflow SDK use a consistent ID format: a 4-character prefi
268
324
  | Step | `step_` | `step_01HXYZ123ABC456DEF789GHJ` |
269
325
  | Hook | `hook_` | `hook_01HXYZ123ABC456DEF789GHJ` |
270
326
  | Wait | `wait_` | `wait_01HXYZ123ABC456DEF789GHJ` |
271
- | Event | `evnt_` | `evnt_01HXYZ123ABC456DEF789GHJ` |
327
+ | Event | `evnt_` | `evnt_00000000000000000000000042` (slot 42) |
272
328
  | Stream | `strm_` | `strm_01HXYZ123ABC456DEF789GHJ` |
273
329
 
274
330
  **Why this format?**
275
331
 
276
- - **Prefixes enable introspection**: Given any ID, you can immediately identify what type of entity it refers to. This makes debugging, logging, and cross-referencing entities across the system straightforward.
332
+ - **Prefixes enable introspection**: Given any ID, you can immediately identify what type of entity it refers to. This helps you debug, log, and cross-reference entities across the system.
333
+
334
+ - **Fixed-width bodies enable ordering**: Unlike UUIDs, these bodies sort lexicographically in creation order, so the event log is stored and retrieved in the correct order by sorting IDs alone. Slot numbers get that from counting at a fixed width, which makes string order the same as numeric order. ULIDs get it from the timestamp in their first 48 bits, which also makes a ULID's creation time recoverable from the ID itself.
335
+
336
+ ### Event IDs
337
+
338
+ An event ID is a **slot number**: the event's 1-based position in the run's event log, zero-padded to the same width as a ULID. The world assigns it when the event is published, so two writers racing to append never claim the same position and a rejected write leaves no gap behind. Slots are dense, and unique only within a run, so an event ID identifies an event only when paired with its `runId`.
339
+
340
+ Density is what lets a reader tell a complete log from an incomplete one by its length alone. A replay that loads a log with a position missing below the highest one it can see cannot tell an event that was never written from one it failed to read, so it fails the run with [`CORRUPTED_EVENT_LOG`](/docs/errors/corrupted-event-log) rather than replay across the hole. See [`WORKFLOW_SLOT_GAP_CHECK`](/docs/configuration/runtime-tuning#workflow_slot_gap_check).
277
341
 
278
- - **ULIDs enable chronological ordering**: Unlike UUIDs, ULIDs encode a timestamp in their first 48 bits, making them lexicographically sortable by creation time. This property is essential for the event log—events are always stored and retrieved in the correct chronological order simply by sorting their IDs.
342
+ A slot ID carries no timestamp. Zero-padded decimal digits are a subset of the ULID alphabet, so a slot ID passes ULID validation and sorts correctly, but decoding its first 48 bits yields the Unix epoch instead of a creation time. Read `createdAt` on the event when you need to know when it was written, and don't decode the time from an `evnt_` ID you get back from an API, a log line, or a cursor.