workflow 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 (256) hide show
  1. package/README.md +68 -23
  2. package/dist/api-workflow.d.ts +1 -1
  3. package/dist/api-workflow.d.ts.map +1 -1
  4. package/dist/api-workflow.js +1 -1
  5. package/dist/api.d.ts +3 -3
  6. package/dist/api.d.ts.map +1 -1
  7. package/dist/api.js +5 -7
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +6 -1
  11. package/dist/internal/builtins.d.ts +20 -3
  12. package/dist/internal/builtins.d.ts.map +1 -1
  13. package/dist/internal/builtins.js +68 -4
  14. package/dist/internal/errors.d.ts +1 -1
  15. package/dist/internal/errors.d.ts.map +1 -1
  16. package/dist/internal/errors.js +2 -2
  17. package/dist/nest-builder.d.ts +2 -0
  18. package/dist/nest-builder.d.ts.map +1 -0
  19. package/dist/nest-builder.js +2 -0
  20. package/dist/nest-vercel-builder.d.ts +2 -0
  21. package/dist/nest-vercel-builder.d.ts.map +1 -0
  22. package/dist/nest-vercel-builder.js +2 -0
  23. package/dist/observability.d.ts +1 -1
  24. package/dist/observability.js +2 -2
  25. package/dist/runtime.d.ts +2 -1
  26. package/dist/runtime.d.ts.map +1 -1
  27. package/dist/runtime.js +4 -1
  28. package/docs/ai/chat-session-modeling.mdx +29 -26
  29. package/docs/ai/defining-tools.mdx +6 -7
  30. package/docs/ai/human-in-the-loop.mdx +11 -11
  31. package/docs/ai/index.mdx +50 -45
  32. package/docs/ai/message-queueing.mdx +16 -16
  33. package/docs/ai/meta.json +1 -0
  34. package/docs/ai/resumable-streams.mdx +40 -28
  35. package/docs/ai/sleep-and-delays.mdx +10 -10
  36. package/docs/ai/streaming-updates-from-tools.mdx +6 -6
  37. package/docs/api-reference/index.mdx +24 -0
  38. package/docs/api-reference/meta.json +8 -0
  39. package/docs/api-reference/vitest/index.mdx +9 -15
  40. package/docs/api-reference/workflow/create-hook.mdx +89 -10
  41. package/docs/api-reference/workflow/create-webhook.mdx +16 -15
  42. package/docs/api-reference/workflow/define-hook.mdx +35 -33
  43. package/docs/api-reference/workflow/fatal-error.mdx +30 -8
  44. package/docs/api-reference/workflow/fetch.mdx +14 -10
  45. package/docs/api-reference/workflow/get-step-metadata.mdx +2 -2
  46. package/docs/api-reference/workflow/get-workflow-metadata.mdx +3 -3
  47. package/docs/api-reference/workflow/get-writable.mdx +7 -7
  48. package/docs/api-reference/workflow/index.mdx +4 -1
  49. package/docs/api-reference/workflow/retryable-error.mdx +1 -1
  50. package/docs/api-reference/workflow/set-attributes.mdx +61 -0
  51. package/docs/api-reference/workflow/sleep.mdx +4 -4
  52. package/docs/api-reference/workflow-ai/durable-agent.mdx +48 -86
  53. package/docs/api-reference/workflow-ai/index.mdx +3 -3
  54. package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +67 -24
  55. package/docs/api-reference/workflow-api/get-hook-by-token.mdx +26 -12
  56. package/docs/api-reference/workflow-api/get-run.mdx +43 -8
  57. package/docs/api-reference/workflow-api/index.mdx +6 -10
  58. package/docs/api-reference/workflow-api/resume-hook.mdx +73 -12
  59. package/docs/api-reference/workflow-api/resume-webhook.mdx +11 -9
  60. package/docs/api-reference/workflow-api/start.mdx +60 -13
  61. package/docs/api-reference/workflow-astro/index.mdx +18 -0
  62. package/docs/api-reference/workflow-astro/meta.json +4 -0
  63. package/docs/api-reference/workflow-astro/workflow.mdx +45 -0
  64. package/docs/api-reference/workflow-errors/entity-conflict-error.mdx +4 -4
  65. package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
  66. package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +8 -8
  67. package/docs/api-reference/workflow-errors/index.mdx +88 -0
  68. package/docs/api-reference/workflow-errors/meta.json +6 -0
  69. package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +68 -0
  70. package/docs/api-reference/workflow-errors/run-expired-error.mdx +2 -2
  71. package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
  72. package/docs/api-reference/workflow-errors/step-not-registered-error.mdx +5 -5
  73. package/docs/api-reference/workflow-errors/throttle-error.mdx +2 -2
  74. package/docs/api-reference/workflow-errors/too-early-error.mdx +2 -2
  75. package/docs/api-reference/workflow-errors/workflow-error.mdx +52 -0
  76. package/docs/api-reference/workflow-errors/workflow-not-registered-error.mdx +5 -6
  77. package/docs/api-reference/workflow-errors/workflow-run-cancelled-error.mdx +6 -6
  78. package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +5 -5
  79. package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
  80. package/docs/api-reference/workflow-errors/workflow-run-not-found-error.mdx +4 -4
  81. package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
  82. package/docs/api-reference/workflow-errors/workflow-world-error.mdx +8 -8
  83. package/docs/api-reference/workflow-globals.mdx +14 -10
  84. package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +33 -0
  85. package/docs/api-reference/workflow-nest/index.mdx +31 -0
  86. package/docs/api-reference/workflow-nest/meta.json +9 -0
  87. package/docs/api-reference/workflow-nest/nest-local-builder.mdx +64 -0
  88. package/docs/api-reference/workflow-nest/workflow-controller.mdx +40 -0
  89. package/docs/api-reference/workflow-nest/workflow-module.mdx +74 -0
  90. package/docs/api-reference/workflow-next/with-workflow.mdx +39 -17
  91. package/docs/api-reference/workflow-nitro/index.mdx +60 -0
  92. package/docs/api-reference/workflow-nuxt/index.mdx +48 -0
  93. package/docs/api-reference/workflow-observability/hydrate-data.mdx +35 -0
  94. package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
  95. package/docs/api-reference/workflow-observability/index.mdx +62 -0
  96. package/docs/api-reference/workflow-observability/meta.json +11 -0
  97. package/docs/api-reference/workflow-observability/observability-revivers.mdx +50 -0
  98. package/docs/api-reference/workflow-observability/parse-class-name.mdx +41 -0
  99. package/docs/api-reference/workflow-observability/parse-step-name.mdx +40 -0
  100. package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
  101. package/docs/api-reference/workflow-runtime/create-world.mdx +39 -0
  102. package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
  103. package/docs/api-reference/{workflow-api → workflow-runtime}/get-world.mdx +11 -14
  104. package/docs/api-reference/workflow-runtime/health-check.mdx +50 -0
  105. package/docs/api-reference/workflow-runtime/index.mdx +41 -0
  106. package/docs/api-reference/workflow-runtime/meta.json +12 -0
  107. package/docs/api-reference/workflow-runtime/set-world.mdx +51 -0
  108. package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +43 -0
  109. package/docs/api-reference/workflow-runtime/world/analytics.mdx +315 -0
  110. package/docs/api-reference/workflow-runtime/world/index.mdx +60 -0
  111. package/docs/api-reference/workflow-runtime/world/meta.json +4 -0
  112. package/docs/api-reference/workflow-runtime/world/queue.mdx +88 -0
  113. package/docs/api-reference/{workflow-api → workflow-runtime}/world/storage.mdx +98 -34
  114. package/docs/api-reference/{workflow-api → workflow-runtime}/world/streams.mdx +8 -8
  115. package/docs/api-reference/workflow-serde/index.mdx +1 -2
  116. package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +3 -4
  117. package/docs/api-reference/workflow-serde/workflow-serialize.mdx +8 -8
  118. package/docs/api-reference/workflow-sveltekit/index.mdx +18 -0
  119. package/docs/api-reference/workflow-sveltekit/meta.json +4 -0
  120. package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +42 -0
  121. package/docs/api-reference/workflow-vite/index.mdx +18 -0
  122. package/docs/api-reference/workflow-vite/meta.json +4 -0
  123. package/docs/api-reference/workflow-vite/workflow.mdx +48 -0
  124. package/docs/changelog/attributes-mvp.mdx +380 -0
  125. package/docs/changelog/batched-event-writes.mdx +79 -0
  126. package/docs/changelog/eager-processing.mdx +110 -436
  127. package/docs/changelog/index.mdx +4 -2
  128. package/docs/changelog/lazy-event-creation.md +127 -0
  129. package/docs/changelog/lazy-hook-resume.mdx +78 -0
  130. package/docs/changelog/meta.json +11 -1
  131. package/docs/changelog/resilient-resume.mdx +32 -0
  132. package/docs/changelog/resilient-start.mdx +33 -285
  133. package/docs/changelog/step-message-ownership.mdx +360 -0
  134. package/docs/changelog/turbo-mode.md +87 -0
  135. package/docs/comparisons/index.mdx +66 -0
  136. package/docs/comparisons/meta.json +11 -0
  137. package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +55 -0
  138. package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +111 -0
  139. package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +71 -0
  140. package/docs/comparisons/workflow-sdk-vs-inngest.mdx +102 -0
  141. package/docs/comparisons/workflow-sdk-vs-temporal.mdx +123 -0
  142. package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +104 -0
  143. package/docs/configuration/build-and-diagnostics.mdx +70 -0
  144. package/docs/configuration/cli-and-web-ui.mdx +241 -0
  145. package/docs/configuration/framework-options.mdx +165 -0
  146. package/docs/configuration/index.mdx +32 -0
  147. package/docs/configuration/meta.json +12 -0
  148. package/docs/configuration/runtime-tuning.mdx +376 -0
  149. package/docs/configuration/worlds.mdx +313 -0
  150. package/docs/cookbook/advanced/child-workflows.mdx +211 -264
  151. package/docs/cookbook/advanced/meta.json +6 -1
  152. package/docs/cookbook/advanced/publishing-libraries.mdx +65 -56
  153. package/docs/cookbook/advanced/serializable-steps.mdx +28 -20
  154. package/docs/cookbook/advanced/upgrading-workflows.mdx +199 -0
  155. package/docs/cookbook/agent-patterns/agent-cancellation.mdx +27 -19
  156. package/docs/cookbook/agent-patterns/durable-agent.mdx +14 -142
  157. package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +30 -22
  158. package/docs/cookbook/common-patterns/batching.mdx +18 -14
  159. package/docs/cookbook/common-patterns/idempotency.mdx +41 -53
  160. package/docs/cookbook/common-patterns/rate-limiting.mdx +8 -4
  161. package/docs/cookbook/common-patterns/saga.mdx +23 -19
  162. package/docs/cookbook/common-patterns/scheduling.mdx +34 -22
  163. package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +29 -25
  164. package/docs/cookbook/common-patterns/timeouts.mdx +26 -21
  165. package/docs/cookbook/common-patterns/webhooks.mdx +10 -6
  166. package/docs/cookbook/common-patterns/workflow-composition.mdx +30 -27
  167. package/docs/cookbook/index.mdx +22 -21
  168. package/docs/cookbook/integrations/ai-sdk.mdx +85 -47
  169. package/docs/cookbook/integrations/chat-sdk.mdx +50 -33
  170. package/docs/cookbook/integrations/sandbox.mdx +62 -45
  171. package/docs/deploying.mdx +95 -0
  172. package/docs/errors/abort-signal-timeout-in-workflow.mdx +16 -12
  173. package/docs/errors/corrupted-event-log.mdx +29 -18
  174. package/docs/errors/deployment-mismatch.mdx +71 -0
  175. package/docs/errors/fetch-in-workflow.mdx +11 -7
  176. package/docs/errors/hook-conflict.mdx +69 -13
  177. package/docs/errors/index.mdx +2 -36
  178. package/docs/errors/node-js-module-in-workflow.mdx +9 -5
  179. package/docs/errors/replay-divergence.mdx +27 -0
  180. package/docs/errors/run-expired.mdx +85 -0
  181. package/docs/errors/runtime-decryption-failed.mdx +77 -0
  182. package/docs/errors/serialization-failed.mdx +44 -12
  183. package/docs/errors/start-invalid-workflow-function.mdx +9 -5
  184. package/docs/errors/step-executed-multiple-times.mdx +23 -0
  185. package/docs/errors/step-not-registered.mdx +6 -6
  186. package/docs/errors/timeout-in-workflow.mdx +12 -8
  187. package/docs/errors/webhook-invalid-respond-with-value.mdx +18 -18
  188. package/docs/errors/webhook-response-not-sent.mdx +20 -16
  189. package/docs/errors/workflow-not-registered.mdx +5 -5
  190. package/docs/foundations/cancellation.mdx +31 -32
  191. package/docs/foundations/errors-and-retries.mdx +42 -11
  192. package/docs/foundations/hooks.mdx +64 -35
  193. package/docs/foundations/idempotency.mdx +244 -12
  194. package/docs/foundations/index.mdx +1 -23
  195. package/docs/foundations/meta.json +2 -1
  196. package/docs/foundations/serialization.mdx +21 -22
  197. package/docs/foundations/starting-workflows.mdx +106 -30
  198. package/docs/foundations/streaming.mdx +107 -59
  199. package/docs/foundations/versioning.mdx +263 -0
  200. package/docs/foundations/workflows-and-steps.mdx +9 -9
  201. package/docs/getting-started/astro.mdx +22 -18
  202. package/docs/getting-started/express.mdx +15 -11
  203. package/docs/getting-started/fastify.mdx +15 -11
  204. package/docs/getting-started/hono.mdx +15 -11
  205. package/docs/getting-started/index.mdx +10 -3
  206. package/docs/getting-started/meta.json +3 -1
  207. package/docs/getting-started/nestjs.mdx +87 -20
  208. package/docs/getting-started/next.mdx +22 -16
  209. package/docs/getting-started/nitro.mdx +22 -18
  210. package/docs/getting-started/nuxt.mdx +15 -11
  211. package/docs/getting-started/python.mdx +135 -40
  212. package/docs/getting-started/react-router/index.mdx +33 -0
  213. package/docs/getting-started/react-router/meta.json +5 -0
  214. package/docs/getting-started/react-router/v7.mdx +237 -0
  215. package/docs/getting-started/react-router/v8.mdx +232 -0
  216. package/docs/getting-started/sveltekit.mdx +20 -16
  217. package/docs/getting-started/tanstack-start.mdx +17 -13
  218. package/docs/getting-started/vite.mdx +15 -11
  219. package/docs/how-it-works/cancellation.mdx +63 -63
  220. package/docs/how-it-works/code-transform.mdx +83 -67
  221. package/docs/how-it-works/encryption.mdx +30 -26
  222. package/docs/how-it-works/event-sourcing.mdx +98 -34
  223. package/docs/how-it-works/framework-integrations.mdx +96 -337
  224. package/docs/how-it-works/understanding-directives.mdx +22 -22
  225. package/docs/internal/index.mdx +6 -4
  226. package/docs/internal/meta.json +6 -1
  227. package/docs/internal/nitro-native-build.mdx +38 -0
  228. package/docs/internal/nitro-web-ui.mdx +24 -0
  229. package/docs/internal/serializable-abort-controller.mdx +7 -7
  230. package/docs/meta.json +3 -2
  231. package/docs/observability/attributes.mdx +134 -0
  232. package/docs/observability/index.mdx +32 -10
  233. package/docs/observability/meta.json +1 -1
  234. package/docs/observability/retention.mdx +93 -0
  235. package/docs/observability/tracing.mdx +124 -0
  236. package/docs/testing/index.mdx +36 -36
  237. package/docs/testing/server-based.mdx +10 -10
  238. package/docs/whats-new.mdx +186 -0
  239. package/package.json +17 -14
  240. package/docs/api-reference/workflow-api/world/index.mdx +0 -58
  241. package/docs/api-reference/workflow-api/world/meta.json +0 -4
  242. package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
  243. package/docs/api-reference/workflow-api/world/queue.mdx +0 -86
  244. package/docs/deploying/building-a-world.mdx +0 -251
  245. package/docs/deploying/index.mdx +0 -95
  246. package/docs/deploying/meta.json +0 -4
  247. package/docs/deploying/world/local-world.mdx +0 -84
  248. package/docs/deploying/world/meta.json +0 -4
  249. package/docs/deploying/world/postgres-world.mdx +0 -224
  250. package/docs/deploying/world/vercel-world.mdx +0 -179
  251. package/docs/migration-guides/index.mdx +0 -34
  252. package/docs/migration-guides/meta.json +0 -9
  253. package/docs/migration-guides/migrating-from-aws-step-functions.mdx +0 -363
  254. package/docs/migration-guides/migrating-from-inngest.mdx +0 -314
  255. package/docs/migration-guides/migrating-from-temporal.mdx +0 -318
  256. package/docs/migration-guides/migrating-from-trigger-dev.mdx +0 -337
@@ -14,7 +14,7 @@ Creates a webhook that can be used to suspend and resume a workflow run upon rec
14
14
  Webhooks provide a way for external systems to send HTTP requests directly to your workflow. Unlike hooks which accept arbitrary payloads, webhooks work with standard HTTP `Request` objects and can return HTTP `Response` objects.
15
15
 
16
16
  <Callout type="warn">
17
- `createWebhook()` creates a public endpoint at `/.well-known/workflow/v1/webhook/:token`, and the token in that URL is the only authorization performed for incoming requests resuming that webhook. This is convenient for prototypes and simple resume links because it avoids creating another route, but if you need stronger security, prefer [`createHook()`](/docs/api-reference/workflow/create-hook) behind your own route and authorize the request before calling [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) to avoid unauthenticated workflow resumptions.
17
+ `createWebhook()` creates a public endpoint at `/.well-known/workflow/v1/webhook/:token`, and the token in that URL is the only authorization performed for incoming requests resuming that webhook. This is convenient for prototypes and basic resume links because it avoids creating another route, but if you need stronger security, prefer [`createHook()`](/docs/api-reference/workflow/create-hook) behind your own route and authorize the request before calling [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) to avoid unauthenticated workflow resumptions.
18
18
  </Callout>
19
19
 
20
20
  ```ts lineNumbers
@@ -31,7 +31,7 @@ export async function webhookWorkflow() {
31
31
  }
32
32
  ```
33
33
 
34
- ## API Signature
34
+ ## API signature
35
35
 
36
36
  ### Parameters
37
37
 
@@ -55,6 +55,7 @@ The returned `Webhook` object has:
55
55
 
56
56
  - `url`: The HTTP endpoint URL that external systems can call
57
57
  - `token`: The unique token identifying this webhook
58
+ - `getConflict()`: A promise that resolves with the conflicting run if another active hook already owns this token, or `null` once the webhook endpoint has been registered
58
59
  - Implements `AsyncIterable<T>` for handling multiple requests, where `T` is `Request` (default) or `RequestWithResponse` (manual mode)
59
60
 
60
61
  When using `createWebhook({ respondWith: 'manual' })`, the resolved request type is `RequestWithResponse`, which extends the standard `Request` interface with a `respondWith(response: Response): Promise<void>` method for sending custom responses back to the caller.
@@ -62,22 +63,22 @@ When using `createWebhook({ respondWith: 'manual' })`, the resolved request type
62
63
  <Callout type="info">
63
64
  Use the simplest option that satisfies the prompt:
64
65
 
65
- - `createWebhook()` generated callback URL, and the default `202 Accepted` response is fine
66
- - `createWebhook({ respondWith: 'manual' })` generated callback URL, but you must send a custom body, status, or headers
67
- - `createHook()` + `resumeHook()` the app resumes from server-side code with a deterministic business token instead of a generated callback URL
66
+ - `createWebhook()`: generated callback URL, and the default `202 Accepted` response is fine
67
+ - `createWebhook({ respondWith: 'manual' })`: generated callback URL, but you must send a custom body, status, or headers
68
+ - `createHook()` + `resumeHook()`: the app resumes from server-side code with a deterministic business token instead of a generated callback URL
68
69
  </Callout>
69
70
 
70
71
  <details>
71
72
  <summary>Common wrong turns</summary>
72
73
 
73
- - Do not use `respondWith: 'manual'` just because the flow has a callback URL.
74
+ - A callback URL alone does not require `respondWith: 'manual'`.
74
75
  - Do not use `RequestWithResponse` unless you chose manual mode.
75
76
  - Do not invent a custom callback route when `webhook.url` is the intended callback surface.
76
77
  </details>
77
78
 
78
79
  ## Examples
79
80
 
80
- ### Basic Usage
81
+ ### Basic usage
81
82
 
82
83
  Create a webhook that receives HTTP requests and logs the request details:
83
84
 
@@ -100,11 +101,11 @@ export async function basicWebhookWorkflow() {
100
101
  }
101
102
  ```
102
103
 
103
- ### Responding to Webhook Requests (Manual Mode)
104
+ ### Responding to webhook requests (manual mode)
104
105
 
105
106
  Use this section only when the caller requires a non-default HTTP response. If `202 Accepted` is acceptable, use `createWebhook()` without `respondWith: "manual"`.
106
107
 
107
- Pass `{ respondWith: "manual" }` to get a `RequestWithResponse` object with a `respondWith()` method. Note that `respondWith()` must be called from within a step function:
108
+ Pass `{ respondWith: "manual" }` to get a `RequestWithResponse` object with a `respondWith()` method. Call `respondWith()` from within a step function:
108
109
 
109
110
  ```typescript lineNumbers
110
111
  import { createWebhook, type RequestWithResponse } from "workflow"
@@ -142,7 +143,7 @@ async function processData(data: any): Promise<void> {
142
143
  }
143
144
  ```
144
145
 
145
- ### Waiting for Multiple Requests
146
+ ### Waiting for multiple requests
146
147
 
147
148
  You can also wait for multiple requests by using the `for await...of` syntax.
148
149
 
@@ -181,9 +182,9 @@ export async function eventCollectorWorkflow() {
181
182
  }
182
183
  ```
183
184
 
184
- ## Related Functions
185
+ ## Related functions
185
186
 
186
- - [`createHook()`](/docs/api-reference/workflow/create-hook) Use when the app resumes from server-side code with a deterministic business token.
187
- - [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) Pairs with `createHook()` for deterministic server-side resume.
188
- - [`defineHook()`](/docs/api-reference/workflow/define-hook) Type-safe hook helper.
189
- - [`resumeWebhook()`](/docs/api-reference/workflow-api/resume-webhook) Low-level runtime API. Most integrations should call `webhook.url` directly instead of adding a custom callback route.
187
+ - [`createHook()`](/docs/api-reference/workflow/create-hook): Use when the app resumes from server-side code with a deterministic business token.
188
+ - [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook): Pairs with `createHook()` for deterministic server-side resume.
189
+ - [`defineHook()`](/docs/api-reference/workflow/define-hook): Type-safe hook helper.
190
+ - [`resumeWebhook()`](/docs/api-reference/workflow-api/resume-webhook): Low-level runtime API. Most integrations should call `webhook.url` directly instead of adding a custom callback route.
@@ -33,7 +33,7 @@ export async function nameWorkflow() {
33
33
  }
34
34
  ```
35
35
 
36
- ## API Signature
36
+ ## API signature
37
37
 
38
38
  ### Parameters
39
39
 
@@ -46,27 +46,24 @@ showSections={['parameters']}
46
46
 
47
47
  ### Returns
48
48
 
49
+ `defineHook()` returns a `TypedHook<TInput, TOutput>`:
50
+
49
51
  <TSDoc
50
52
  definition={`
51
- interface DefineHook<T> {
52
- /**
53
-
54
- * Creates a new hook with the defined payload type.
55
- */
56
- create: (options?: HookOptions) => Hook<T>;
57
-
58
- /**
59
-
60
- * Resumes a hook by sending a payload with the defined type.
61
- */
62
- resume: (token: string, payload: T) => Promise<HookEntity | null>;
53
+ interface TypedHook<TInput, TOutput> {
54
+ /** Creates the hook. Call inside a "use workflow" function. */
55
+ create(options?: HookOptions): Hook<TOutput>;
56
+ /** Resumes the hook from runtime code. Resolves to the resumed hook; throws HookNotFoundError if the token does not match an active hook. */
57
+ resume(token: string, payload: TInput): Promise<HookEntity>;
63
58
  }
64
- export default DefineHook;`}
59
+ export default TypedHook;`}
65
60
  />
66
61
 
62
+ `create()` is called inside a `"use workflow"` function to create the hook; `resume()` is called from runtime code (an API route or server action). When a `schema` is provided, `resume()` accepts the raw input type (`TInput`) and the workflow receives the validated and possibly transformed output type (`TOutput`); without a schema, `TOutput` defaults to `TInput`. `resume()` throws [`HookNotFoundError`](/docs/api-reference/workflow-errors/hook-not-found-error) if the token does not match an active hook. It does not return `null`.
63
+
67
64
  ## Examples
68
65
 
69
- ### Basic Type-Safe Hook Definition
66
+ ### Basic type-safe hook definition
70
67
 
71
68
  By defining the hook once with a specific payload type, you can reuse it in multiple workflows and API routes with automatic type safety.
72
69
 
@@ -91,30 +88,35 @@ export async function workflowWithApproval() {
91
88
  }
92
89
  ```
93
90
 
94
- ### Resuming with Type Safety
91
+ ### Resuming with type safety
95
92
 
96
- Hooks can be resumed using the same defined hook and a token. By using the same hook, you can ensure that the payload matches the defined type when resuming a hook.
93
+ Hooks can be resumed using the same defined hook and a token. By using the same hook, you can ensure that the payload matches the defined type when resuming a hook. `resume()` resolves to the resumed hook and throws [`HookNotFoundError`](/docs/api-reference/workflow-errors/hook-not-found-error) if the token does not match an active hook.
97
94
 
98
95
  ```typescript lineNumbers
96
+ import { HookNotFoundError } from "workflow/errors";
97
+
99
98
  // Use the same defined hook to resume
100
99
  export async function POST(request: Request) {
101
100
  const { token, approved, comment } = await request.json();
102
101
 
103
- // Type-safe resumption - TypeScript ensures the payload matches
104
- const result = await approvalHook.resume(token, { // [!code highlight]
105
- approved, // [!code highlight]
106
- comment, // [!code highlight]
107
- }); // [!code highlight]
108
-
109
- if (!result) {
110
- return Response.json({ error: "Hook not found" }, { status: 404 });
102
+ try {
103
+ // Type-safe resumption - TypeScript ensures the payload matches
104
+ const hook = await approvalHook.resume(token, { // [!code highlight]
105
+ approved, // [!code highlight]
106
+ comment, // [!code highlight]
107
+ }); // [!code highlight]
108
+
109
+ return Response.json({ success: true, runId: hook.runId });
110
+ } catch (error) {
111
+ if (HookNotFoundError.is(error)) { // [!code highlight]
112
+ return Response.json({ error: "Hook not found" }, { status: 404 });
113
+ }
114
+ throw error;
111
115
  }
112
-
113
- return Response.json({ success: true, runId: result.runId });
114
116
  }
115
117
  ```
116
118
 
117
- ### Validate and Transform with Schema
119
+ ### Validate and transform with schema
118
120
 
119
121
  You can provide runtime validation and transformation of hook payloads using the `schema` option. This option accepts any validator that conforms to the [Standard Schema v1](https://standardschema.dev) specification.
120
122
 
@@ -172,7 +174,7 @@ export async function POST(request: Request) {
172
174
  }
173
175
  ```
174
176
 
175
- #### Using Other Standard Schema Libraries
177
+ #### Using other Standard Schema libraries
176
178
 
177
179
  The same pattern works with any Standard Schema v1 compliant library. Here's an example with [Valibot](https://valibot.dev):
178
180
 
@@ -188,7 +190,7 @@ export const approvalHook = defineHook({
188
190
  });
189
191
  ```
190
192
 
191
- ### Customizing Tokens
193
+ ### Customizing tokens
192
194
 
193
195
  Tokens are used to identify a specific hook and for resuming a hook. You can customize the token to be more specific to a use case.
194
196
 
@@ -209,7 +211,7 @@ export async function slackBotWorkflow(channelId: string) {
209
211
  }
210
212
  ```
211
213
 
212
- ## Related Functions
214
+ ## Related functions
213
215
 
214
- * [`createHook()`](/docs/api-reference/workflow/create-hook) - Create a hook in a workflow.
215
- * [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) - Resume a hook with a payload.
216
+ - [`createHook()`](/docs/api-reference/workflow/create-hook): Create a hook in a workflow.
217
+ - [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook): Resume a hook with a payload.
@@ -27,18 +27,40 @@ async function fallibleStep() {
27
27
  }
28
28
  ```
29
29
 
30
- ## API Signature
30
+ ## API signature
31
31
 
32
- ### Parameters
32
+ ### Constructor
33
+
34
+ `new FatalError(message)`
35
+
36
+ | Parameter | Type | Description |
37
+ | --------- | -------- | ------------------ |
38
+ | `message` | `string` | The error message. |
39
+
40
+ ### Properties
33
41
 
34
42
  <TSDoc
35
43
  definition={`
36
- interface Error {
37
- /**
38
-
39
- * The error message.
40
- */
44
+ interface FatalError {
45
+ /** The error message. */
41
46
  message: string;
47
+ /** Always true. Marks the error as non-retryable. */
48
+ fatal: boolean;
42
49
  }
43
- export default Error;`}
50
+ export default FatalError;`}
44
51
  />
52
+
53
+ ### Static methods
54
+
55
+ #### `FatalError.is(value)`
56
+
57
+ Type-safe check for `FatalError` instances. Preferred over `instanceof` because it works across module boundaries and VM contexts.
58
+
59
+ ```typescript
60
+ import { FatalError } from "workflow"
61
+ declare const error: unknown; // @setup
62
+
63
+ if (FatalError.is(error)) {
64
+ // error is typed as FatalError
65
+ }
66
+ ```
@@ -7,12 +7,17 @@ prerequisites:
7
7
  - /docs/foundations/workflows-and-steps
8
8
  related:
9
9
  - /docs/errors/fetch-in-workflow
10
+ - /docs/foundations/idempotency
10
11
  ---
11
12
 
12
13
  Makes HTTP requests from within a workflow. This is a special step function that wraps the standard `fetch` API, automatically handling serialization and providing retry semantics.
13
14
 
14
15
  This is useful when you need to call external APIs or services from within your workflow.
15
16
 
17
+ <Callout type="warn">
18
+ Because workflow `fetch()` has retry semantics, use idempotency keys when the request mutates an external system, such as creating a charge, sending an email, or enqueueing work. See [Idempotency](/docs/foundations/idempotency).
19
+ </Callout>
20
+
16
21
  <Callout>
17
22
  `fetch` is a *special* type of step function provided and should be called directly inside workflow functions.
18
23
  </Callout>
@@ -29,7 +34,7 @@ async function apiWorkflow() {
29
34
  }
30
35
  ```
31
36
 
32
- ## API Signature
37
+ ## API signature
33
38
 
34
39
  ### Parameters
35
40
 
@@ -55,9 +60,9 @@ showSections={['returns']}
55
60
 
56
61
  ## Examples
57
62
 
58
- ### Basic Usage
63
+ ### Basic usage
59
64
 
60
- Here's a simple example of how you can use `fetch` inside your workflow.
65
+ Here's an example of how you can use `fetch` inside your workflow.
61
66
 
62
67
  ```typescript lineNumbers
63
68
  import { fetch } from "workflow"
@@ -82,13 +87,13 @@ async function apiWorkflow() {
82
87
  }
83
88
  ```
84
89
 
85
- We call `fetch()` with a URL and optional request options, just like the standard fetch API. The workflow runtime automatically handles the response serialization.
90
+ We call `fetch()` with a URL and optional request options, like the standard fetch API. The workflow runtime automatically handles the response serialization.
86
91
 
87
- This API is provided as a convenience to easily use `fetch` in workflow, but often, you might want to extend and implement your own fetch for more powerful error handing and retry logic.
92
+ This API lets you use `fetch` in a workflow. You can also implement a custom fetch for different error handling and retry logic.
88
93
 
89
- ### Customizing Fetch Behavior
94
+ ### Customizing fetch behavior
90
95
 
91
- Here's an example of a custom fetch wrapper that provides more sophisticated error handling with custom retry logic:
96
+ The following custom fetch wrapper provides more advanced error handling with custom retry logic. Call `globalThis.fetch` inside your own `"use step"` function because calling the workflow `fetch` imported from `workflow` would nest a step inside a step:
92
97
 
93
98
  ```typescript lineNumbers
94
99
  import { FatalError, RetryableError } from "workflow"
@@ -99,7 +104,7 @@ export async function customFetch(
99
104
  ) {
100
105
  "use step"
101
106
 
102
- const response = await fetch(url, init)
107
+ const response = await globalThis.fetch(url, init)
103
108
 
104
109
  // Handle client errors (4xx) - don't retry
105
110
  if (response.status >= 400 && response.status < 500) {
@@ -140,7 +145,6 @@ export async function customFetch(
140
145
 
141
146
  This example demonstrates:
142
147
 
143
- - Setting custom `maxRetries` to 5 retries (6 total attempts including the initial attempt).
144
148
  - Throwing [`FatalError`](/docs/api-reference/workflow/fatal-error) for client errors (400-499) to prevent retries.
145
149
  - Handling 429 rate limiting by reading the `Retry-After` header and using [`RetryableError`](/docs/api-reference/workflow/retryable-error).
146
- - Allowing automatic retries for server errors (5xx).
150
+ - Allowing automatic retries for server errors (5xx) by throwing a plain `Error`.
@@ -34,7 +34,7 @@ async function logStepId() {
34
34
  }
35
35
  ```
36
36
 
37
- ### Example: Use `stepId` as an idempotency key
37
+ ### Example: use `stepId` as an idempotency key
38
38
 
39
39
  ```typescript lineNumbers
40
40
  import { getStepMetadata } from "workflow";
@@ -61,7 +61,7 @@ async function chargeUser(userId: string, amount: number) {
61
61
  <a href="/docs/foundations/idempotency">Idempotency</a> guide.
62
62
  </Callout>
63
63
 
64
- ## API Signature
64
+ ## API signature
65
65
 
66
66
  ### Parameters
67
67
 
@@ -30,7 +30,7 @@ async function testWorkflow() {
30
30
  }
31
31
  ```
32
32
 
33
- ### Detecting Workflow Runtime
33
+ ### Detecting workflow runtime
34
34
 
35
35
  You can use `getWorkflowMetadata` to detect whether your code is running inside a workflow context. This is useful when building shared utilities that need to behave differently inside and outside of workflows.
36
36
 
@@ -64,7 +64,7 @@ function log(message: string) {
64
64
  }
65
65
  ```
66
66
 
67
- ### Detecting Encryption
67
+ ### Detecting encryption
68
68
 
69
69
  The `features` object indicates which capabilities are active for the current run. Library authors can use `features.encryption` to control whether sensitive data is included in step return values, which are serialized to the event log:
70
70
 
@@ -90,7 +90,7 @@ async function fetchUserProfile(userId: string) {
90
90
  }
91
91
  ```
92
92
 
93
- ## API Signature
93
+ ## API signature
94
94
 
95
95
  ### Parameters
96
96
 
@@ -47,7 +47,7 @@ async function writeToStream(writable: WritableStream) {
47
47
  }
48
48
  ```
49
49
 
50
- ## API Signature
50
+ ## API signature
51
51
 
52
52
  ### Parameters
53
53
 
@@ -69,7 +69,7 @@ export default getWritable;`}
69
69
 
70
70
  Returns a `WritableStream<W>` where `W` is the type of data you plan to write to the stream.
71
71
 
72
- ## Good to Know
72
+ ## Good to know
73
73
 
74
74
  - **Workflow functions can only obtain the stream** - Call `getWritable()` in a workflow to get the stream reference, but you cannot call methods like `getWriter()`, `write()`, or `close()` directly in the workflow context.
75
75
  - **Step functions can interact with streams** - Steps can receive the stream as an argument or call `getWritable()` directly, and they can freely interact with it (write, close, etc.).
@@ -81,9 +81,9 @@ Returns a `WritableStream<W>` where `W` is the type of data you plan to write to
81
81
 
82
82
  ## Examples
83
83
 
84
- ### Basic Text Streaming
84
+ ### Basic text streaming
85
85
 
86
- Here's a simple example streaming text data:
86
+ This example streams text data:
87
87
 
88
88
  ```typescript lineNumbers
89
89
  import { sleep, getWritable } from "workflow";
@@ -118,7 +118,7 @@ async function stepCloseOutputStream(writable: WritableStream) {
118
118
  }
119
119
  ```
120
120
 
121
- ### Calling `getWritable()` Inside Steps
121
+ ### Calling `getWritable()` inside steps
122
122
 
123
123
  You can also call `getWritable()` directly inside step functions without passing it as a parameter:
124
124
 
@@ -157,7 +157,7 @@ async function stepCloseOutputStreamInside() {
157
157
  }
158
158
  ```
159
159
 
160
- ### Using Namespaced Streams in Steps
160
+ ### Using namespaced streams in steps
161
161
 
162
162
  You can also use namespaced streams when calling `getWritable()` from steps:
163
163
 
@@ -201,7 +201,7 @@ async function closeStreams() {
201
201
  }
202
202
  ```
203
203
 
204
- ### Advanced Chat Streaming
204
+ ### Advanced chat streaming
205
205
 
206
206
  Here's a more complex example showing how you might stream AI chat responses:
207
207
 
@@ -47,9 +47,12 @@ Workflow SDK contains the following functions you can use inside your workflow f
47
47
  <Card href="/docs/api-reference/workflow/get-writable" title="getWritable()">
48
48
  Access the current workflow run's default stream.
49
49
  </Card>
50
+ <Card href="/docs/api-reference/workflow/set-attributes" title="setAttributes()">
51
+ Attach string metadata to the current workflow run.
52
+ </Card>
50
53
  </Cards>
51
54
 
52
- ## Error Classes
55
+ ## Error classes
53
56
 
54
57
  Workflow SDK includes error classes that can be thrown in a workflow or step to change the error exit strategy of a workflow.
55
58
 
@@ -31,7 +31,7 @@ async function retryStep() {
31
31
  The difference between `Error` and `RetryableError` may not be entirely obvious, since when both are thrown, they both retry. The difference is that `RetryableError` has an additional configurable `retryAfter` parameter.
32
32
  </Callout>
33
33
 
34
- ## API Signature
34
+ ## API signature
35
35
 
36
36
  ### Parameters
37
37
 
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: setAttributes
3
+ description: Attach string metadata to workflow run for observability.
4
+ type: reference
5
+ summary: Use setAttributes inside a workflow or step function to set run attributes.
6
+ prerequisites:
7
+ - /docs/foundations/workflows-and-steps
8
+ related:
9
+ - /docs/observability/attributes
10
+ - /docs/api-reference/workflow/fatal-error
11
+ ---
12
+
13
+ Attaches string metadata to the current workflow run.
14
+
15
+ ```typescript lineNumbers
16
+ import { setAttributes } from "workflow"
17
+
18
+ export async function orderWorkflow(orderId: string) {
19
+ "use workflow"
20
+
21
+ await setAttributes({
22
+ phase: "received",
23
+ orderId,
24
+ })
25
+ }
26
+ ```
27
+
28
+ ## API signature
29
+
30
+ ### Parameters
31
+
32
+ <TSDoc
33
+ definition={`
34
+ import { setAttributes } from "workflow";
35
+ export default setAttributes;`}
36
+ showSections={['parameters']}
37
+ />
38
+
39
+ ## Usage
40
+
41
+ Call `setAttributes` from a `"use workflow"` function or a `"use step"` function. Calling it from plain application code is not supported because there is no active workflow run.
42
+
43
+ Attribute values must be strings. Pass `undefined` to remove an attribute:
44
+
45
+ ```typescript lineNumbers
46
+ import { setAttributes } from "workflow"
47
+
48
+ export async function cleanupAttributes() {
49
+ "use workflow"
50
+
51
+ await setAttributes({ staleKey: undefined })
52
+ }
53
+ ```
54
+
55
+ Attribute keys must be 1-256 characters, values must be strings up to 256 bytes, and each run can have up to 64 attributes. Keys that start with `$` are reserved for framework and library code.
56
+
57
+ Validation errors throw [`FatalError`](/docs/api-reference/workflow/fatal-error) and fail the run before an attribute write is attempted.
58
+
59
+ Calls from both workflow and step bodies append a native `attr_set` event, which the World materializes onto `run.attributes`. Workflow-originated events record a workflow writer; step-originated events record the originating step ID and attempt.
60
+
61
+ Native attributes require spec version 4 or later. Step-body storage errors throw from `setAttributes`; catch them inside the step if the write should be best-effort. Workflow-body writes are committed when the workflow suspends: transient storage errors are retried with the suspension, while a write the World rejects as invalid (such as exceeding the per-run attribute cap across multiple calls) fails the run with the validation error.
@@ -14,7 +14,7 @@ Suspends a workflow for a specified duration or until an end date without consum
14
14
  This is useful when you want to resume a workflow after some duration or date.
15
15
 
16
16
  <Callout>
17
- `sleep` is a *special* type of step function and should be called directly inside workflow functions.
17
+ `sleep` is a built-in workflow runtime function (backed by a timer event in the event log, not a step) and should be called directly inside workflow functions.
18
18
  </Callout>
19
19
 
20
20
  ```typescript lineNumbers
@@ -26,7 +26,7 @@ async function testWorkflow() {
26
26
  }
27
27
  ```
28
28
 
29
- ## API Signature
29
+ ## API signature
30
30
 
31
31
  ### Parameters
32
32
 
@@ -39,7 +39,7 @@ showSections={['parameters']}
39
39
 
40
40
  ## Examples
41
41
 
42
- ### Sleeping With a Duration
42
+ ### Sleeping with a duration
43
43
 
44
44
  You can specify a duration for `sleep` to suspend the workflow for a fixed amount of time.
45
45
 
@@ -52,7 +52,7 @@ async function testWorkflow() {
52
52
  }
53
53
  ```
54
54
 
55
- ### Sleeping Until an End Date
55
+ ### Sleeping until an end date
56
56
 
57
57
  You can specify a future `Date` object for `sleep` to suspend the workflow until a specific date.
58
58