workflow 5.0.0-beta.36 → 5.0.0-beta.38

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.
package/README.md CHANGED
@@ -28,22 +28,6 @@ The Workflow SDK community can be found on [GitHub Discussions](https://github.c
28
28
 
29
29
  Contributions to Workflow SDK are welcome and highly appreciated. Please use GitHub [issues](https://github.com/vercel/workflow/issues) and [discussions](https://github.com/vercel/workflow/discussions) to collaborate with the team and wider community.
30
30
 
31
- ## Author list
32
-
33
- Workflow SDK was built by engineers at [Vercel](https://vercel.com) and the [Open Source Community](https://github.com/vercel/workflow/graphs/contributors).
34
-
35
- The initial core contributing engineers are:
36
-
37
- - Adrian Lam ([@adriandlam](https://github.com/adriandlam))
38
- - Dillon Mulroy ([@dmmulroy](https://github.com/dmmulroy))
39
- - Gal Schlezinger ([@Schniz](https://github.com/Schniz))
40
- - JJ Kasper ([@ijjk](https://github.com/ijjk))
41
- - Nathan Rajlich ([@TooTallNate](https://github.com/TooTallNate))
42
- - Peter Wielander ([@VaguelySerious](https://github.com/VaguelySerious))
43
- - Pranay Prakash ([@pranaygp](https://github.com/pranaygp))
44
-
45
- The Workflow SDK logo was designed by Cecilio Ruiz [@ceciliorz](https://x.com/ceciliorz)
46
-
47
31
  ---
48
32
 
49
33
  ## Security
package/dist/runtime.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import '@workflow/core/runtime/world-init';
2
- export { createWorld, getWorld, getWorldHandlers, type HealthCheckEndpoint, type HealthCheckOptions, type HealthCheckResult, healthCheck, setWorld, workflowEntrypoint, } from '@workflow/core/runtime';
2
+ export { createWorld, getWorld, getWorldHandlers, type HealthCheckOptions, type HealthCheckResult, healthCheck, setWorld, workflowEntrypoint, } from '@workflow/core/runtime';
3
3
  //# sourceMappingURL=runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,mCAAmC,CAAC;AAE3C,OAAO,EACL,WAAW,EACX,QAAQ,EACR,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,WAAW,EACX,QAAQ,EACR,kBAAkB,GACnB,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,mCAAmC,CAAC;AAE3C,OAAO,EACL,WAAW,EACX,QAAQ,EACR,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,WAAW,EACX,QAAQ,EACR,kBAAkB,GACnB,MAAM,wBAAwB,CAAC"}
package/dist/runtime.js CHANGED
@@ -2,4 +2,4 @@
2
2
  // through stream helpers, so register getWorld before exporting runtime APIs.
3
3
  import '@workflow/core/runtime/world-init';
4
4
  export { createWorld, getWorld, getWorldHandlers, healthCheck, setWorld, workflowEntrypoint, } from '@workflow/core/runtime';
5
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDZFQUE2RTtBQUM3RSw4RUFBOEU7QUFDOUUsT0FBTyxtQ0FBbUMsQ0FBQztBQUUzQyxPQUFPLEVBQ0wsV0FBVyxFQUNYLFFBQVEsRUFDUixnQkFBZ0IsRUFJaEIsV0FBVyxFQUNYLFFBQVEsRUFDUixrQkFBa0IsR0FDbkIsTUFBTSx3QkFBd0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEhvc3Qtc2lkZSBzaWRlIGVmZmVjdDogcnVudGltZS1vbmx5IGltcG9ydHMgY2FuIHN0aWxsIHJlYWNoIGdldFdvcmxkTGF6eSgpXG4vLyB0aHJvdWdoIHN0cmVhbSBoZWxwZXJzLCBzbyByZWdpc3RlciBnZXRXb3JsZCBiZWZvcmUgZXhwb3J0aW5nIHJ1bnRpbWUgQVBJcy5cbmltcG9ydCAnQHdvcmtmbG93L2NvcmUvcnVudGltZS93b3JsZC1pbml0JztcblxuZXhwb3J0IHtcbiAgY3JlYXRlV29ybGQsXG4gIGdldFdvcmxkLFxuICBnZXRXb3JsZEhhbmRsZXJzLFxuICB0eXBlIEhlYWx0aENoZWNrRW5kcG9pbnQsXG4gIHR5cGUgSGVhbHRoQ2hlY2tPcHRpb25zLFxuICB0eXBlIEhlYWx0aENoZWNrUmVzdWx0LFxuICBoZWFsdGhDaGVjayxcbiAgc2V0V29ybGQsXG4gIHdvcmtmbG93RW50cnlwb2ludCxcbn0gZnJvbSAnQHdvcmtmbG93L2NvcmUvcnVudGltZSc7XG4iXX0=
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDZFQUE2RTtBQUM3RSw4RUFBOEU7QUFDOUUsT0FBTyxtQ0FBbUMsQ0FBQztBQUUzQyxPQUFPLEVBQ0wsV0FBVyxFQUNYLFFBQVEsRUFDUixnQkFBZ0IsRUFHaEIsV0FBVyxFQUNYLFFBQVEsRUFDUixrQkFBa0IsR0FDbkIsTUFBTSx3QkFBd0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEhvc3Qtc2lkZSBzaWRlIGVmZmVjdDogcnVudGltZS1vbmx5IGltcG9ydHMgY2FuIHN0aWxsIHJlYWNoIGdldFdvcmxkTGF6eSgpXG4vLyB0aHJvdWdoIHN0cmVhbSBoZWxwZXJzLCBzbyByZWdpc3RlciBnZXRXb3JsZCBiZWZvcmUgZXhwb3J0aW5nIHJ1bnRpbWUgQVBJcy5cbmltcG9ydCAnQHdvcmtmbG93L2NvcmUvcnVudGltZS93b3JsZC1pbml0JztcblxuZXhwb3J0IHtcbiAgY3JlYXRlV29ybGQsXG4gIGdldFdvcmxkLFxuICBnZXRXb3JsZEhhbmRsZXJzLFxuICB0eXBlIEhlYWx0aENoZWNrT3B0aW9ucyxcbiAgdHlwZSBIZWFsdGhDaGVja1Jlc3VsdCxcbiAgaGVhbHRoQ2hlY2ssXG4gIHNldFdvcmxkLFxuICB3b3JrZmxvd0VudHJ5cG9pbnQsXG59IGZyb20gJ0B3b3JrZmxvdy9jb3JlL3J1bnRpbWUnO1xuIl19
package/docs/ai/index.mdx CHANGED
@@ -382,7 +382,7 @@ export async function checkBaggageAllowance(
382
382
 
383
383
  With `"use step"`:
384
384
 
385
- - The tool execution runs in a separate step with full Node.js access. In production, each step is executed in a separate worker process, which scales automatically with your workload.
385
+ - The tool execution runs as a durable step with full Node.js access. The combined runtime may execute it inline in the flow request or resume it through the workflow queue, and can scale queued work with your workload.
386
386
  - Failed tool calls are automatically retried (up to 3 times by default). See [Errors and Retries](/docs/foundations/errors-and-retries) for more details.
387
387
  - Each tool execution appears as a discrete step in observability tools. See [Observability](/docs/observability) for more details.
388
388
  </Step>
@@ -59,7 +59,3 @@ Validation errors throw [`FatalError`](/docs/api-reference/workflow/fatal-error)
59
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
60
 
61
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.
62
-
63
- <Callout>
64
- This function was previously exported as `experimental_setAttributes`. The old name still works as a deprecated alias — update imports to `setAttributes`.
65
- </Callout>
@@ -26,7 +26,7 @@ These APIs are available but are **seeded or fixed** to ensure deterministic beh
26
26
  | [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) / `Date.now()` / `new Date()` | Returns a fixed timestamp that advances with the workflow's logical clock |
27
27
  | [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) | Seeded — produces deterministic output for a given workflow run |
28
28
  | [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) | Seeded — produces deterministic UUIDs for a given workflow run |
29
- | [`crypto.subtle.digest()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest) | Passes through to the real implementation (SHA-256, etc. are deterministic by nature) |
29
+ | [`crypto.subtle.digest()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest) | Computed synchronously via `node:crypto` (values are byte-identical to WebCrypto), so the promise settles at a deterministic point during replay |
30
30
 
31
31
  <Callout type="info">
32
32
  You can safely use `Math.random()`, `Date.now()`, and `crypto.randomUUID()` in workflow functions. The framework ensures these return the same values across replays.
@@ -100,3 +100,6 @@ The following are **not available** in workflow functions. Move this logic to [s
100
100
  - **Global `fetch`**: Use [`import { fetch } from "workflow"`](/docs/api-reference/workflow/fetch) instead. See [fetch-in-workflow](/docs/errors/fetch-in-workflow).
101
101
  - **Timers**: `setTimeout`, `setInterval`, `setImmediate`, and their `clear*` counterparts. Use [`sleep()`](/docs/api-reference/workflow/sleep) instead. See [timeout-in-workflow](/docs/errors/timeout-in-workflow).
102
102
  - **`Buffer`**: Node.js-specific API. Use `Uint8Array` with `toBase64()` / `fromBase64()` / `toHex()` / `fromHex()` for binary data encoding, or `atob()` / `btoa()` for string-based base64.
103
+ - **`WeakRef` and `FinalizationRegistry`**: garbage-collection timing is not deterministic, so observing it would make workflow code impossible to replay. (`WeakMap` and `WeakSet` remain available — they do not expose GC state.)
104
+ - **`Atomics.waitAsync`**: a wall-clock timer, which cannot be replayed. Use [`sleep()`](/docs/api-reference/workflow/sleep) instead.
105
+ - **Async `WebAssembly` compilation** (`compile`, `instantiate`, `compileStreaming`, `instantiateStreaming`): resolves on compile-thread timing. The synchronous `new WebAssembly.Module()` and `new WebAssembly.Instance()` constructors remain available.
@@ -13,7 +13,7 @@ Performs an end-to-end health check of a deployment's workflow infrastructure by
13
13
  import { getWorld, healthCheck } from "workflow/runtime";
14
14
 
15
15
  const world = await getWorld();
16
- const result = await healthCheck(world, "workflow"); // [!code highlight]
16
+ const result = await healthCheck(world); // [!code highlight]
17
17
 
18
18
  if (!result.healthy) {
19
19
  console.error("Workflow infrastructure unhealthy:", result.error);
@@ -27,8 +27,7 @@ if (!result.healthy) {
27
27
  | Parameter | Type | Description |
28
28
  |-----------|------|-------------|
29
29
  | `world` | `World` | The World instance to send the health check through |
30
- | `endpoint` | `"workflow" \| "step"` | Which endpoint to check |
31
- | `options` | `HealthCheckOptions & { namespace?: string }` | Optional configuration |
30
+ | `options` | `HealthCheckOptions` | Optional configuration |
32
31
 
33
32
  Where `HealthCheckOptions` is:
34
33
 
@@ -36,6 +35,7 @@ Where `HealthCheckOptions` is:
36
35
  |--------|------|-------------|
37
36
  | `timeout` | `number` | Milliseconds to wait for the health check response. Default: `30000`. |
38
37
  | `deploymentId` | `string` | Deployment to target. Falls back to `process.env.VERCEL_DEPLOYMENT_ID`. |
38
+ | `namespace` | `string` | Queue namespace of the target deployment. Falls back to `WORKFLOW_QUEUE_NAMESPACE`. |
39
39
 
40
40
  ### Returns
41
41
 
@@ -43,7 +43,7 @@ Returns a `Promise<HealthCheckResult>`:
43
43
 
44
44
  | Property | Type | Description |
45
45
  |----------|------|-------------|
46
- | `healthy` | `boolean` | Whether the endpoint processed the health check message |
46
+ | `healthy` | `boolean` | Whether the combined workflow endpoint processed the health check message |
47
47
  | `error` | `string \| undefined` | Error message when the check failed |
48
48
  | `latencyMs` | `number \| undefined` | Round-trip latency when the check succeeded |
49
49
  | `specVersion` | `number \| undefined` | Workflow spec version of the responding deployment |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Queue
3
- description: Low-level queue interface for dispatching workflow and step invocations.
3
+ description: Low-level queue interface for dispatching workflow invocations.
4
4
  type: reference
5
5
  summary: "Methods: getDeploymentId(), queue(), createQueueHandler(). Internal queue dispatch — normally handled by the SDK."
6
6
  prerequisites:
@@ -17,10 +17,10 @@ keywords:
17
17
  - queue dispatch
18
18
  ---
19
19
 
20
- Queue methods live directly on the `world` object (not nested). They dispatch internal workflow and step invocations to the queue backend.
20
+ Queue methods live directly on the `world` object (not nested). They dispatch internal workflow invocations, including queued step work, to the queue backend.
21
21
 
22
22
  <Callout type="warn">
23
- These methods are used internally by the Workflow SDK to dispatch execution. You do not need to call them in normal operations — use [`start()`](/docs/api-reference/workflow-api/start) to trigger workflows instead. Direct queue access is only needed if you programmatically create a run via `world.events.create()` with a `run_created` event and need to kick off its initial execution, or for debugging resumption of a flow or step route.
23
+ These methods are used internally by the Workflow SDK to dispatch execution. You do not need to call them in normal operations — use [`start()`](/docs/api-reference/workflow-api/start) to trigger workflows instead. Direct queue access is only needed if you programmatically create a run via `world.events.create()` with a `run_created` event and need to kick off its initial execution, or for debugging flow resumption.
24
24
  </Callout>
25
25
 
26
26
  ## Import
@@ -46,7 +46,7 @@ const deploymentId = await world.getDeploymentId(); // [!code highlight]
46
46
 
47
47
  ### queue()
48
48
 
49
- Dispatch a message to a named queue. The message payload is an internal SDK type (`WorkflowInvokePayload`, `StepInvokePayload`, or `HealthCheckPayload`).
49
+ Dispatch a message to a named queue. The message payload is an internal SDK type (`WorkflowInvokePayload` or `HealthCheckPayload`). Queued steps use `WorkflowInvokePayload` with `stepId` and `stepName`.
50
50
 
51
51
  ```typescript lineNumbers
52
52
  const { messageId } = await world.queue(queueName, payload, opts); // [!code highlight]
@@ -42,6 +42,17 @@ Accepted values:
42
42
  - Set `1` to expose the workflow manifest at `/.well-known/workflow/v1/manifest.json`.
43
43
  - Useful for e2e tests and tools that need to discover workflows over HTTP.
44
44
 
45
+ ## Discovery
46
+
47
+ ### `WORKFLOW_DISCOVER_NODE_MODULES`
48
+
49
+ - Framework option: `discoverWorkflowsInNodeModules` where supported
50
+ - Default: enabled
51
+ - Controls whether workflow discovery descends into `node_modules`. By default, dependencies that declare a `workflow`/`@workflow/*` dependency can ship `"use workflow"`/`"use step"` files that are discovered and compiled into your app's bundles.
52
+ - Set `0` or `false` to opt out — imports from your application code that resolve into `node_modules` are not followed, so the build never reads, scans, or descends into dependency file graphs. This skips the cost of scanning `node_modules` and stops third-party workflow/step/serde code from being discovered. Useful when a dependency ships workflow code you don't want compiled into your app, or trips discovery with directive strings you don't intend to run.
53
+ - The SDK's own runtime serde classes (e.g. `Run`) stay registered — they are reached through a seeded entry point, and imports *within* `node_modules` are still followed.
54
+ - Explicit framework config wins over this environment variable.
55
+
45
56
  ## Development diagnostics
46
57
 
47
58
  ### `WORKFLOW_DEV_HMR_LOGS`
@@ -49,3 +60,11 @@ Accepted values:
49
60
  - Default: disabled
50
61
  - Set `1` to log workflow rebuild activity during `next dev`.
51
62
  - Useful for diagnosing watch and HMR issues.
63
+
64
+ ### `WORKFLOW_DEV_WATCH_IGNORED_PATHS`
65
+
66
+ - Default: unset
67
+ - Dev-mode only (`next dev`). Comma-separated list of path fragments the file watcher should never watch, in addition to the built-in ignores and your project's `.gitignore`.
68
+ - Each entry is matched as a substring of the absolute path (e.g. `/fixtures/,/generated/`).
69
+ - The watcher already respects `.gitignore` (walking from the app directory up to the workspace root). Use this variable only for large directories you cannot or do not want to add to `.gitignore`.
70
+ - Useful when a project has thousands of non-ignored directories and `next dev` fails with `EMFILE: too many open files, watch`.
@@ -115,6 +115,14 @@ For example, a workflow can run a 10-minute inline step even with `WORKFLOW_REPL
115
115
  - Debug log filter with wildcards and negation.
116
116
  - Examples: `workflow:*`, `workflow:*,-workflow:telemetry:*`.
117
117
 
118
+ ## Transport
119
+
120
+ ### `WORKFLOW_H2_MULTIPLEX`
121
+
122
+ - Default: enabled
123
+ - On the Vercel World, lets concurrent event-log requests share one HTTP/2 connection instead of one connection per in-flight request.
124
+ - Set `0` to send one event request per connection.
125
+
118
126
  ## Queue namespace
119
127
 
120
128
  ### `WORKFLOW_QUEUE_NAMESPACE`
@@ -130,9 +138,9 @@ These variables are primarily for tests, debugging, or unusual deployments.
130
138
 
131
139
  ### `WORKFLOW_STREAM_FLUSH_INTERVAL_MS`
132
140
 
133
- - Default: `10`
134
- - Stream write buffering interval.
135
- - Also available as `streamFlushIntervalMs` on Worlds that expose it.
141
+ - Default: `0` (dispatch the first chunk of an idle stream immediately)
142
+ - Group-commit window for the *leading* chunk of an idle stream. `0` sends it at once; a positive value holds it up to that many milliseconds to collect a group — an opt-in trade of first-chunk latency for larger batches, useful for slow-but-steady producers. Chunks arriving while a request is already in flight always coalesce into the next group regardless of this setting.
143
+ - Also available as `streamFlushIntervalMs` on Worlds that expose it (the env var, when set, takes precedence over the World option).
136
144
 
137
145
  ### `WORKFLOW_STREAM_MAX_INFLIGHT_CHUNKS`
138
146
 
@@ -149,6 +157,11 @@ These variables are primarily for tests, debugging, or unusual deployments.
149
157
  - Default: `1048576` (1 MiB)
150
158
  - Wire limit: maximum cumulative bytes in a single coalesced multi-write, so large chunks don't produce a request body that platform limits reject. A single chunk larger than this is still sent on its own.
151
159
 
160
+ ### `WORKFLOW_STREAM_MAX_BUFFERED_BYTES`
161
+
162
+ - Default: `8388608` (8 MiB)
163
+ - Flow-control bound: maximum cumulative bytes accepted into the stream writer's group-commit buffer before `write()` applies backpressure. The byte-denominated counterpart of `WORKFLOW_STREAM_MAX_INFLIGHT_CHUNKS`; distinct from `WORKFLOW_STREAM_MAX_BYTES_PER_BATCH`, which only splits how much goes out in one request.
164
+
152
165
  ### `WORKFLOW_FRAMED_STREAM_MAX_RECONNECTS`
153
166
 
154
167
  - Default: `50`
@@ -21,6 +21,12 @@ A [World](/docs/deploying) stores workflow state and delivers queue messages.
21
21
 
22
22
  Outside Vercel, Workflow defaults to the Local World. On Vercel, leave `WORKFLOW_TARGET_WORLD` unset for the normal case; Workflow detects the Vercel deployment and selects the Vercel World automatically.
23
23
 
24
+ The World is selected when your app **runs**, from the environment of the process serving it, so changing `WORKFLOW_TARGET_WORLD` takes effect on the next start without a rebuild. Detection keys off `VERCEL_DEPLOYMENT_ID`, which Vercel sets in every deployed function and nothing else sets: with it, the Vercel World; without it, the Local World.
25
+
26
+ Broader signals are deliberately ignored. `vercel env pull` writes `VERCEL=1` into `.env.local`, so a dev server or a production server started on your own machine sees it while running against a writable filesystem — where the Local World is the right choice. Set `WORKFLOW_TARGET_WORLD=vercel` explicitly if you want such a process to talk to the Vercel World; starting a run then fails with an error naming the missing `VERCEL_DEPLOYMENT_ID`.
27
+
28
+ A deployment that pins `WORKFLOW_TARGET_WORLD=local` warns at startup and fails on its first write, because a Vercel deployment's filesystem is read-only.
29
+
24
30
  Set `WORKFLOW_TARGET_WORLD` only when you want to use a custom or self-hosted World:
25
31
 
26
32
  - `local` - alias for `@workflow/world-local`.
@@ -95,8 +101,8 @@ The Local World is the default outside Vercel and is intended for development.
95
101
  ### `streamFlushIntervalMs`
96
102
 
97
103
  - Environment variable fallback: `WORKFLOW_STREAM_FLUSH_INTERVAL_MS`
98
- - Default: `10`
99
- - Flush interval for buffered stream writes. The World option wins when set.
104
+ - Default: `0` (dispatch the leading chunk of an idle stream immediately)
105
+ - Group-commit window for the leading chunk of an idle stream; a positive value trades first-chunk latency for larger groups. The `WORKFLOW_STREAM_FLUSH_INTERVAL_MS` environment variable, when set, overrides this option; otherwise the World option governs, including the very first chunk.
100
106
 
101
107
  ## Postgres World
102
108
 
@@ -128,6 +134,14 @@ The Postgres World is a self-hosted durable backend for long-running server proc
128
134
  - Number of concurrent workers polling for jobs.
129
135
  - Also bounds concurrent parent-to-child workflow return-value polls.
130
136
 
137
+ ### `applicationManagedShutdown`
138
+
139
+ - Environment variable: `WORKFLOW_POSTGRES_APPLICATION_MANAGED_SHUTDOWN` (`1` enables)
140
+ - Default: `false`
141
+ - Whether the application coordinates shutdown instead of Graphile Worker responding automatically.
142
+ - Set to `true` only when the application awaits `world.close()` before closing its workflow HTTP server and caller-owned pool.
143
+ - Prevents Graphile Worker's default handler from terminating the process before the application's remaining cleanup finishes.
144
+
131
145
  ### `maxPoolSize`
132
146
 
133
147
  - Environment variable: `WORKFLOW_POSTGRES_MAX_POOL_SIZE`
@@ -143,8 +157,8 @@ The Postgres World is a self-hosted durable backend for long-running server proc
143
157
  ### `streamFlushIntervalMs`
144
158
 
145
159
  - Environment variable fallback: `WORKFLOW_STREAM_FLUSH_INTERVAL_MS`
146
- - Default: `10`
147
- - Flush interval for buffered stream writes. The World option wins when set.
160
+ - Default: `0` (dispatch the leading chunk of an idle stream immediately)
161
+ - Group-commit window for the leading chunk of an idle stream; a positive value trades first-chunk latency for larger groups. The `WORKFLOW_STREAM_FLUSH_INTERVAL_MS` environment variable, when set, overrides this option; otherwise the World option governs, including the very first chunk.
148
162
 
149
163
  ## Vercel World
150
164
 
@@ -2,11 +2,11 @@
2
2
  title: Publishing Libraries
3
3
  description: Structure and publish npm packages that export workflow functions for consumers to use with Workflow SDK.
4
4
  type: guide
5
- summary: Learn how to build, export, and test npm packages that ship workflow and step functions — including package.json exports, re-exporting for stable workflow IDs, keeping step I/O clean, and integration testing.
5
+ summary: Learn how to build, export, and test npm packages that ship workflow and step functions — including package.json exports, re-exporting so the consumer's compiler discovers your workflows, keeping step I/O clean, and integration testing.
6
6
  ---
7
7
 
8
8
  <CopyPrompt
9
- text="Package these workflow functions as a publishable npm library. Give the package a dedicated workflows entry point (for example `exports[&quot;./workflows&quot;]`) that ships the workflow and step source for the consumer's compiler to process. Keep every workflow and step input and output serializable, and read credentials from environment variables inside steps instead of accepting client instances. Document the consumer re-export requirement: consumers create a file in their `workflows/` directory containing `export * from &quot;<pkg>/workflows&quot;` so their build assigns stable workflow IDs and replay can resolve functions after cold starts. Add an integration test that runs a library workflow end to end from a consumer-style setup. Verify the build, stable IDs across deployments, and replay safety."
9
+ text="Package these workflow functions as a publishable npm library. Give the package a dedicated workflows entry point (for example `exports[&quot;./workflows&quot;]`) that ships the workflow and step source for the consumer's compiler to process. Keep every workflow and step input and output serializable, and read credentials from environment variables inside steps instead of accepting client instances. Document the consumer re-export requirement: consumers create a file in their `workflows/` directory containing `export * from &quot;<pkg>/workflows&quot;` so their build discovers and compiles the library's workflow and step files and replay can resolve them after cold starts. Add an integration test that runs a library workflow end to end from a consumer-style setup. Verify the build, that the library's workflows and steps show up as compiled entries, and replay safety."
10
10
  />
11
11
 
12
12
  import { File, Folder, Files } from "fumadocs-ui/components/files";
@@ -114,31 +114,35 @@ export default defineConfig({
114
114
  });
115
115
  ```
116
116
 
117
- ## Re-Exporting for Workflow ID Stability
117
+ ## Re-Exporting for Compiler Discovery
118
118
 
119
- Workflow SDK's compiler assigns each workflow function a stable ID based on its position in the source file that the build system processes. When a consumer imports a pre-built workflow from an npm package, the compiler never sees the original source it only sees the compiled output. This means workflow IDs won't match between the library's development environment and the consumer's app.
119
+ The workflow compiler only transforms files it discovers, and discovery starts from the consumer's `workflows/` directory and follows imports out from there. A library's workflow functions are not on that graph by default, so nothing compiles them and the runtime has no definition to run.
120
120
 
121
- The fix is a **re-export file**. The consumer creates a file in their `workflows/` directory that re-exports the library's workflows. The build system then processes this file and assigns stable IDs.
121
+ The fix is a **re-export file**. The consumer creates a file in their `workflows/` directory that re-exports the library's workflows, which pulls the library's source onto the discovery graph and gives its entry point an address the runtime can resolve.
122
122
 
123
123
  ### Consumer Setup
124
124
 
125
125
  ```typescript lineNumbers
126
126
  // workflows/media.ts (in the consumer's project)
127
- // Re-export library workflows so the build system assigns stable IDs
127
+ // Re-export library workflows so the compiler discovers and transforms them
128
128
  export * from "@acme/media/workflows"; // [!code highlight]
129
129
  ```
130
130
 
131
- This one-line file is all that's needed. The workflow compiler transforms this file, discovers the workflow and step functions from the library, and assigns IDs that are stable across deployments.
131
+ This one-line file is all that's needed. The compiler follows the re-export into the package, transforms the workflow and step functions it finds, and registers them under IDs the runtime can resolve.
132
132
 
133
133
  ### Why This Is Necessary
134
134
 
135
- Without re-exporting, the workflow runtime cannot match a running workflow to its function definition. When a workflow run is replayed after a cold start, the runtime looks up functions by their compiler-assigned IDs. If the IDs don't exist (because the compiler never processed the library's source), replay fails.
135
+ Without re-exporting, the workflow runtime cannot match a running workflow to its function definition. When a run is replayed after a cold start, the runtime looks up functions by their compiler-assigned IDs. If those functions were never compiled, the IDs don't exist and replay fails.
136
136
 
137
- The re-export pattern ensures:
137
+ Point the re-export at the package's dedicated workflows entry point rather than a deep path into `dist/`. Files reachable through the package's `exports` map get an ID of the form `name/subpath@version`; a deep, non-exported file falls back to a path-based ID instead.
138
138
 
139
- 1. **Stable IDs** — the compiler assigns IDs based on the consumer's source tree
140
- 2. **Replay safety** IDs persist across deployments and cold starts
141
- 3. **Version upgrades** — re-exported IDs remain stable as long as the consumer's file doesn't change
139
+ <Callout type="info">
140
+ **IDs for code you ship embed your package version.** A step in `@acme/media` version `1.4.0` gets the ID `step//@acme/media/workflows@1.4.0//transcode`, so publishing `1.5.0` renames every workflow and step the package ships.
141
+
142
+ That is safe on worlds with deployment pinning, such as Vercel, because runs are pinned to the deployment that started them. A run records its deployment ID and every resume targets that same deployment, so after a consumer upgrades, new runs execute the new version while runs already in flight keep replaying against the old one. Consumers do not need to drain anything before upgrading.
143
+
144
+ The re-export file does not change any of this. An ID is derived from where the file lives, not from how it was imported, so a package file keeps its `name@version` ID whether or not a consumer re-exports it.
145
+ </Callout>
142
146
 
143
147
  ## Keeping Step I/O Clean
144
148
 
@@ -252,7 +256,7 @@ Some libraries want to be useful to consumers who *aren't* using Workflow SDK at
252
256
  Two rules for isomorphic packages:
253
257
 
254
258
  1. **Any runtime reference to the `workflow` package must be loaded via dynamic `import("workflow")` inside a try/catch.** A static top-level import makes the module fail to load for consumers who haven't installed workflow.
255
- 2. **The `"use workflow"` and `"use step"` directives are safe to keep in your library source.** When a consumer compiles your code with the Workflow SDK toolchain (via the [re-export pattern](#re-exporting-for-workflow-id-stability) above), the SWC plugin transforms them into durable-execution glue. When they're not compiled — plain Node, plain tests, a consumer without the runtime — they are just string expression statements and run as no-ops.
259
+ 2. **The `"use workflow"` and `"use step"` directives are safe to keep in your library source.** When a consumer compiles your code with the Workflow SDK toolchain (via the [re-export pattern](#re-exporting-for-compiler-discovery) above), the SWC plugin transforms them into durable-execution glue. When they're not compiled — plain Node, plain tests, a consumer without the runtime — they are just string expression statements and run as no-ops.
256
260
  </Callout>
257
261
 
258
262
  ### Optional peer dependency
@@ -160,7 +160,7 @@ async function sendOnboardingEmail(user: { id: string; email: string}) {
160
160
 
161
161
  Taking a look at this code:
162
162
 
163
- * Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
163
+ * Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
164
164
  * If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
165
165
  * Steps can throw a `FatalError` if an error is intentional and should not be retried.
166
166
 
@@ -185,7 +185,7 @@ async function sendOnboardingEmail(user: { id: string; email: string }) {
185
185
 
186
186
  Taking a look at this code:
187
187
 
188
- - Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
188
+ - Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
189
189
  - If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
190
190
  - Steps can throw a `FatalError` if an error is intentional and should not be retried.
191
191
 
@@ -174,7 +174,7 @@ async function sendOnboardingEmail(user: { id: string; email: string }) {
174
174
  ```
175
175
  Taking a look at this code:
176
176
 
177
- - Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
177
+ - Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
178
178
  - If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
179
179
  - Steps can throw a `FatalError` if an error is intentional and should not be retried.
180
180
 
@@ -170,7 +170,7 @@ async function sendOnboardingEmail(user: { id: string; email: string }) {
170
170
 
171
171
  Taking a look at this code:
172
172
 
173
- - Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
173
+ - Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
174
174
  - If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
175
175
  - Steps can throw a `FatalError` if an error is intentional and should not be retried.
176
176
 
@@ -289,7 +289,7 @@ async function sendOnboardingEmail(user: { id: string; email: string }) {
289
289
 
290
290
  Taking a look at this code:
291
291
 
292
- - Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
292
+ - Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
293
293
  - If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
294
294
  - Steps can throw a `FatalError` if an error is intentional and should not be retried.
295
295
 
@@ -192,7 +192,7 @@ async function sendOnboardingEmail(user: { id: string; email: string}) {
192
192
 
193
193
  Taking a look at this code:
194
194
 
195
- * Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
195
+ * Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
196
196
  * If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
197
197
  * Steps can throw a `FatalError` if an error is intentional and should not be retried.
198
198
 
@@ -172,7 +172,7 @@ async function sendOnboardingEmail(user: { id: string; email: string }) {
172
172
 
173
173
  Taking a look at this code:
174
174
 
175
- - Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
175
+ - Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
176
176
  - If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
177
177
  - Steps can throw a `FatalError` if an error is intentional and should not be retried.
178
178
 
@@ -149,7 +149,7 @@ async function sendOnboardingEmail(user: { id: string; email: string }) {
149
149
 
150
150
  Taking a look at this code:
151
151
 
152
- - Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
152
+ - Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
153
153
  - If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
154
154
  - Steps can throw a `FatalError` if an error is intentional and should not be retried.
155
155
 
@@ -157,7 +157,7 @@ async function sendOnboardingEmail(user: { id: string; email: string}) {
157
157
 
158
158
  Taking a look at this code:
159
159
 
160
- * Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
160
+ * Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
161
161
  * If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
162
162
  * Steps can throw a `FatalError` if an error is intentional and should not be retried.
163
163
 
@@ -155,7 +155,7 @@ async function sendOnboardingEmail(user: { id: string; email: string}) {
155
155
 
156
156
  Taking a look at this code:
157
157
 
158
- * Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
158
+ * Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
159
159
  * If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
160
160
  * Steps can throw a `FatalError` if an error is intentional and should not be retried.
161
161
 
@@ -160,7 +160,7 @@ async function sendOnboardingEmail(user: { id: string; email: string}) {
160
160
 
161
161
  Taking a look at this code:
162
162
 
163
- * Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
163
+ * Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
164
164
  * If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
165
165
  * Steps can throw a `FatalError` if an error is intentional and should not be retried.
166
166
 
@@ -176,12 +176,12 @@ The step's `ops` array is awaited via `waitUntil(Promise.all(ops))` after the st
176
176
 
177
177
  ### Abort Errors Are Wrapped in FatalError
178
178
 
179
- When a step throws due to an abort — whether from `fetch` throwing `AbortError`, `signal.throwIfAborted()`, or any other abort-induced error — the step handler wraps the error in `FatalError` before recording it in the event log. This ensures:
179
+ When a step throws due to an abort — whether from `fetch` throwing `AbortError`, `signal.throwIfAborted()`, or any other abort-induced error — the step executor wraps the error in `FatalError` before recording it in the event log. This ensures:
180
180
 
181
181
  - **No retries**: An abort is intentional cancellation, not a transient failure. Retrying would just abort again.
182
182
  - **Immediate propagation**: The error bubbles up to the workflow as a `FatalError`, which the workflow can catch with `FatalError.is(err)`.
183
183
 
184
- The wrapping happens at the step handler level (`runtime/step-handler.ts`), during error hydration. When the step's thrown error is an `AbortError` (checked via `err.name === 'AbortError'`), it is treated as fatal regardless of the step's `maxRetries` configuration.
184
+ The wrapping happens in `runtime/step-executor.ts` during error hydration. When the step's thrown error is an `AbortError` (checked via `err.name === 'AbortError'`), it is treated as fatal regardless of the step's `maxRetries` configuration.
185
185
 
186
186
  ### abort() in the Workflow
187
187
 
@@ -53,18 +53,20 @@ flowchart LR
53
53
  A["Source Code<br/>with directives"] --> B["Step Mode"]
54
54
  A --> C["Workflow Mode"]
55
55
  A --> D["Client Mode"]
56
- B --> E["step.js<br/>(Step Execution)"]
57
- C --> F["flow.js<br/>(Workflow Execution)"]
56
+ B --> E["Step registration bundle"]
57
+ C --> F["Workflow bundle"]
58
+ E --> H["Combined flow handler"]
59
+ F --> H
58
60
  D --> G["Your App Code<br/>(Enables `start`)"]
59
61
  ```
60
62
 
61
63
  ### Comparison Table
62
64
 
63
- | Mode | Used In | Purpose | Output API Route | Required? |
64
- |----------|------------|--------------------------------|------------------------------------|-----------|
65
- | Step | Build time | Bundles step handlers | `.well-known/workflow/v1/step` | Yes |
66
- | Workflow | Build time | Bundles workflow orchestrators | `.well-known/workflow/v1/flow` | Yes |
67
- | Client | Build/Runtime | Provides workflow IDs and types to `start` | Your application code | Optional* |
65
+ | Mode | Used In | Purpose | Runtime role | Required? |
66
+ |----------|------------|--------------------------------|--------------|-----------|
67
+ | Step | Build time | Registers executable step functions | Imported by the combined flow handler | Yes |
68
+ | Workflow | Build time | Bundles workflow orchestrators | Executed by `.well-known/workflow/v1/flow` | Yes |
69
+ | Client | Build/Runtime | Provides workflow IDs and types to `start` | Your application code | Optional* |
68
70
 
69
71
  \* Client mode is **recommended** for better developer experience—it provides automatic ID generation and type safety. Without it, you must manually construct workflow IDs or use the build manifest.
70
72
 
@@ -73,7 +75,7 @@ flowchart LR
73
75
  <Tabs items={["Step Mode", "Workflow Mode", "Client Mode"]}>
74
76
  <Tab value="Step Mode">
75
77
 
76
- **Step Mode** creates the step execution bundle served at `/.well-known/workflow/v1/step`.
78
+ **Step Mode** creates a registration bundle that the combined flow handler imports. It is not an HTTP route.
77
79
 
78
80
  **Input:**
79
81
 
@@ -211,7 +213,7 @@ The IDs are generated exactly like in workflow mode to ensure they can be direct
211
213
 
212
214
  ## Generated Files
213
215
 
214
- When you build your application, the Workflow SDK generates three handler files in `.well-known/workflow/v1/`:
216
+ When you build your application, the Workflow SDK generates a combined flow handler, an internal step registration bundle, and a webhook handler. Exact filenames vary by framework.
215
217
 
216
218
  ### `flow.js`
217
219
 
@@ -245,15 +247,17 @@ Most invalid patterns cause **build-time errors**, catching issues before deploy
245
247
  **Why a VM?** Workflow functions must be deterministic to support replay. The VM sandbox prevents accidental use of non-deterministic APIs or side effects. All side effects should be performed in [step functions](/docs/foundations/workflows-and-steps#step-functions) instead.
246
248
  </Callout>
247
249
 
248
- ### `step.js`
250
+ ### `__step_registrations.js`
249
251
 
250
- Contains all step functions transformed in **step mode**. This file is imported by your framework to handle step execution requests at `POST /.well-known/workflow/v1/step`.
252
+ Contains all step functions transformed in **step mode**. The combined flow handler imports this module for its registration side effects.
251
253
 
252
254
  **What it does:**
253
255
 
254
- - Exports a `POST` handler that accepts Web standard `Request` objects
255
- - Executes individual steps with full runtime access
256
- - Returns step results to the orchestration layer
256
+ - Adds step functions to the runtime step registry
257
+ - Keeps step bodies in the full host runtime
258
+ - Makes registered steps available when a flow queue message includes `stepId` and `stepName`
259
+
260
+ This module must not be exposed as an HTTP endpoint.
257
261
 
258
262
  ### `webhook.js`
259
263
 
@@ -336,7 +340,7 @@ These transformations are framework-agnostic—they output standard JavaScript t
336
340
 
337
341
  If you need to debug transformation issues, you can inspect the generated files:
338
342
 
339
- 1. **Look in `.well-known/workflow/v1/`**: Check the generated `flow.js`, `step.js`,`webhook.js`, and other emitted debug files.
343
+ 1. **Inspect the generated output**: Check the combined flow handler, step registration bundle, webhook handler, and emitted debug files.
340
344
  2. **Check build logs**: Most frameworks log transformation activity during builds
341
345
  3. **Verify directives**: Ensure `"use workflow"` and `"use step"` are the first statements in functions
342
346
  4. **Check file locations**: Transformations only apply to files in configured source directories
@@ -2,7 +2,7 @@
2
2
  title: Framework Integrations
3
3
  description: Guide for framework authors to integrate Workflow SDK with custom frameworks or runtimes.
4
4
  type: guide
5
- summary: Build a custom framework integration using the Workflow SDK compiler and runtime.
5
+ summary: Build a custom framework integration using the Workflow SDK compiler and combined runtime handler.
6
6
  prerequisites:
7
7
  - /docs/foundations/workflows-and-steps
8
8
  related:
@@ -10,55 +10,45 @@ related:
10
10
  ---
11
11
 
12
12
  <Callout>
13
- **For users:** If you just want to use Workflow SDK with an existing framework, check out the [Getting Started](/docs/getting-started) guide instead. This page is for framework authors who want to integrate Workflow SDK with their framework or runtime.
13
+ **For users:** If you just want to use Workflow SDK with an existing framework, see [Getting Started](/docs/getting-started). This page is for framework authors.
14
14
  </Callout>
15
15
 
16
- This guide walks you through building a framework integration for Workflow SDK using Bun as a concrete example. The same principles apply to any JavaScript runtime (Node.js, Deno, Cloudflare Workers, etc.).
16
+ This guide uses Bun as a concrete example, but the same build and routing model applies to other JavaScript frameworks and runtimes.
17
17
 
18
18
  <Callout type="info">
19
- **Prerequisites:** Before building a framework integration, we recommend reading [How the Directives Work](/docs/how-it-works/code-transform) to understand the transformation system that powers Workflow SDK.
19
+ Read [How the Directives Work](/docs/how-it-works/code-transform) first if you are not familiar with the three compiler modes.
20
20
  </Callout>
21
21
 
22
- ## What You'll Build
22
+ ## Integration shape
23
23
 
24
- A framework integration has two main components:
24
+ A framework integration has two responsibilities:
25
25
 
26
- 1. **Build-time**: Generate workflow handler files (`flow.js`, `step.js`, `webhook.js`)
27
- 2. **Runtime**: Expose these handlers as HTTP endpoints in your application server
26
+ 1. **Build time:** transform workflow and step code, register the steps, and generate the combined flow handler.
27
+ 2. **Runtime:** expose the generated flow and webhook handlers as HTTP routes.
28
28
 
29
29
  ```mermaid
30
30
  flowchart TD
31
- A["Source Code<br/>'use workflow'"] --> B["Workflow Builder"]
32
- B --> C["SWC Transform"]
33
- C --> D["Step Mode"]
34
- C --> E["Workflow Mode"]
35
- C --> F["Client Mode"]
36
- D --> G["Generated Handlers<br/>step.js"]
37
- E --> H["Generated Handlers<br/>flow.js"]
38
- B --> L["Generated Handlers<br/>webhook.js"]
39
- F --> I["Used by framework loader"]
40
- G --> J["HTTP Server<br/>(Your Runtime)"]
41
- H --> J
42
- L --> J
31
+ A["Source code<br/>'use workflow' / 'use step'"] --> B["Workflow builder"]
32
+ B --> C["Workflow-mode bundle"]
33
+ B --> D["Step registration bundle"]
34
+ D --> E["Combined flow handler"]
35
+ C --> E
36
+ B --> F["Webhook handler"]
37
+ E --> G["POST /.well-known/workflow/v1/flow"]
38
+ F --> H["/.well-known/workflow/v1/webhook/:token"]
43
39
 
44
40
  style B fill:#a78bfa,stroke:#8b5cf6,color:#000
45
- style I fill:#a78bfa,stroke:#8b5cf6,color:#000
46
- style J fill:#a78bfa,stroke:#8b5cf6,color:#000
41
+ style G fill:#a78bfa,stroke:#8b5cf6,color:#000
42
+ style H fill:#a78bfa,stroke:#8b5cf6,color:#000
47
43
  ```
48
44
 
49
- The purple boxes are what you implement—everything else is provided by Workflow SDK.
45
+ Steps do not have their own HTTP route. A queued step invocation contains `stepId` and `stepName` and is delivered to the flow handler on the workflow queue. The handler executes the registered step in the full host runtime, then replays the workflow in its sandboxed VM.
50
46
 
51
- ## Example: Bun Integration
47
+ ## Example: Bun integration
52
48
 
53
- Let's build a complete integration for Bun. Bun is unique because it serves as both a runtime (needs code transformations) and a framework (provides `Bun.serve()` for HTTP routing).
49
+ ### 1. Generate the bundles
54
50
 
55
- <Callout type="info">
56
- A working example can be [found here](https://github.com/vercel/workflow-examples/tree/main/custom-adapter). For a production-ready reference, see the [Next.js integration](https://github.com/vercel/workflow/tree/main/packages/next).
57
- </Callout>
58
-
59
- ### Step 1: Generate Handler Files
60
-
61
- Use the `workflow` CLI to generate the handler bundles. The CLI scans your `workflows/` directory and creates `flow.js`, `step.js`, and `webhook.js`.
51
+ The standalone CLI scans `workflows/` and creates the combined flow handler, an internal step registration module, and the webhook handler.
62
52
 
63
53
  ```json title="package.json"
64
54
  {
@@ -68,21 +58,19 @@ Use the `workflow` CLI to generate the handler bundles. The CLI scans your `work
68
58
  }
69
59
  ```
70
60
 
71
- <Callout>
72
- **For production integrations:** Instead of using the CLI, extend the `BaseBuilder` class directly in your framework plugin. This gives you control over file watching, custom output paths, and framework-specific hooks. See the [Next.js plugin](https://github.com/vercel/workflow/tree/main/packages/next) for an example.
73
- </Callout>
74
-
75
- **What gets generated:**
61
+ The default output is:
76
62
 
77
- - `/.well-known/workflow/v1/flow.js` - Handles workflow execution (workflow mode transform)
78
- - `/.well-known/workflow/v1/step.js` - Handles step execution (step mode transform)
79
- - `/.well-known/workflow/v1/webhook.js` - Handles webhook delivery
63
+ - `/.well-known/workflow/v1/flow.mjs` the combined workflow and step queue consumer
64
+ - `/.well-known/workflow/v1/__step_registrations.mjs` an internal module imported by `flow.mjs`; do not route to it
65
+ - `/.well-known/workflow/v1/webhook.mjs` webhook delivery
80
66
 
81
- Each file exports a `POST` function that accepts Web standard `Request` objects.
67
+ <Callout>
68
+ Production integrations should extend `BaseBuilder` from `@workflow/builders` so they can participate in the framework's build, watch, and routing lifecycle.
69
+ </Callout>
82
70
 
83
- ### Step 2: Add Client Mode Transform (Optional)
71
+ ### 2. Add the client transform
84
72
 
85
- Client mode transforms your application code to provide better DX. Add a Bun plugin to apply this transformation at runtime:
73
+ Client mode gives application code the workflow IDs used by `start()` and prevents accidental direct workflow execution.
86
74
 
87
75
  {/* @skip-typecheck: incomplete code sample */}
88
76
  ```typescript title="workflow-plugin.ts" lineNumbers
@@ -94,8 +82,6 @@ plugin({
94
82
  setup(build) {
95
83
  build.onLoad({ filter: /\.(ts|tsx|js|jsx)$/ }, async (args) => {
96
84
  const source = await Bun.file(args.path).text();
97
-
98
- // Optimization: Skip files that do not have any directives
99
85
  if (!source.match(/(use step|use workflow)/)) {
100
86
  return { contents: source };
101
87
  }
@@ -105,7 +91,7 @@ plugin({
105
91
  jsc: {
106
92
  experimental: {
107
93
  plugins: [
108
- [require.resolve("@workflow/swc-plugin"), { mode: "client" }], // [!code highlight]
94
+ [require.resolve("@workflow/swc-plugin"), { mode: "client" }],
109
95
  ],
110
96
  },
111
97
  },
@@ -123,23 +109,14 @@ Activate the plugin in `bunfig.toml`:
123
109
  preload = ["./workflow-plugin.ts"]
124
110
  ```
125
111
 
126
- **What this does:**
127
-
128
- - Attaches workflow IDs to functions for use with `start()`
129
- - Provides TypeScript type safety
130
- - Prevents accidental direct execution of workflows
131
-
132
- **Why optional?** Without client mode, you can still use workflows by manually constructing IDs or referencing the build manifest.
133
-
134
- ### Step 3: Expose HTTP Endpoints
112
+ ### 3. Expose the HTTP routes
135
113
 
136
- Wire up the generated handlers to HTTP endpoints using `Bun.serve()`:
114
+ Only the combined flow handler and webhook handler are routable:
137
115
 
138
116
  {/* @skip-typecheck: incomplete code sample */}
139
117
  ```typescript title="server.ts" lineNumbers
140
- import flow from "./.well-known/workflow/v1/flow.js";
141
- import step from "./.well-known/workflow/v1/step.js";
142
- import * as webhook from "./.well-known/workflow/v1/webhook.js";
118
+ import * as flow from "./.well-known/workflow/v1/flow.mjs";
119
+ import * as webhook from "./.well-known/workflow/v1/webhook.mjs";
143
120
 
144
121
  import { start } from "workflow/api";
145
122
  import { handleUserSignup } from "./workflows/user-signup.js";
@@ -148,23 +125,14 @@ const server = Bun.serve({
148
125
  port: process.env.PORT,
149
126
  routes: {
150
127
  "/.well-known/workflow/v1/flow": {
151
- POST: (req) => flow.POST(req),
128
+ POST: flow.POST,
152
129
  },
153
- "/.well-known/workflow/v1/step": {
154
- POST: (req) => step.POST(req),
155
- },
156
- // webhook exports handlers for GET, POST, DELETE, etc.
157
130
  "/.well-known/workflow/v1/webhook/:token": webhook,
158
-
159
- // Example: Start a workflow
160
131
  "/": {
161
- GET: async (req) => {
132
+ GET: async () => {
162
133
  const email = `test-${crypto.randomUUID()}@test.com`;
163
134
  const run = await start(handleUserSignup, [email]);
164
- return Response.json({
165
- message: "User signup workflow started",
166
- runId: run.runId,
167
- });
135
+ return Response.json({ runId: run.runId });
168
136
  },
169
137
  },
170
138
  },
@@ -173,222 +141,90 @@ const server = Bun.serve({
173
141
  console.log(`Server listening on http://localhost:${server.port}`);
174
142
  ```
175
143
 
176
- **That's it!** Your Bun integration is complete.
177
-
178
- ## Understanding the Endpoints
179
-
180
- Your integration must expose three HTTP endpoints. The generated handlers manage all protocol details—you just route requests.
144
+ ## Runtime routes
181
145
 
182
- ### Workflow Endpoint
146
+ ### Combined flow endpoint
183
147
 
184
148
  **Route:** `POST /.well-known/workflow/v1/flow`
185
149
 
186
- Executes workflow orchestration logic. The workflow function is "rendered" multiple times during execution—each time it progresses until it encounters the next step.
150
+ The handler consumes every workflow queue message. Depending on the payload and event log, it can:
187
151
 
188
- **Called when:**
152
+ - start or replay workflow orchestration in the sandboxed VM;
153
+ - execute a queued step in the host runtime;
154
+ - continue replay inline after a step completes;
155
+ - resume a run after a hook, webhook, sleep, retry, or recovery event.
189
156
 
190
- - Starting a new workflow
191
- - Resuming after a step completes
192
- - Resuming after a webhook or hook triggers
193
- - Recovering from failures
157
+ ### Webhook endpoint
194
158
 
195
- ### Step Endpoint
159
+ **Route:** `/.well-known/workflow/v1/webhook/:token`
196
160
 
197
- **Route:** `POST /.well-known/workflow/v1/step`
161
+ This handler delivers data to [`createWebhook()`](/docs/api-reference/workflow/create-webhook). Its generated file structure varies by framework; for example, Next.js uses `webhook/[token]/route.js`.
198
162
 
199
- Executes individual atomic operations within workflows. Each step runs exactly once per execution (unless retried due to failure). Steps have full runtime access (Node.js APIs, file system, databases, etc.).
163
+ ## Building with `BaseBuilder`
200
164
 
201
- ### Webhook Endpoint
165
+ Use `createCombinedBundle()` so the flow bundle imports the generated step registrations. Calling `createWorkflowsBundle()` and `createStepsBundle()` independently does not create a complete runtime route.
202
166
 
203
- **Route:** `POST /.well-known/workflow/v1/webhook/:token`
204
-
205
- Delivers webhook data to running workflows via [`createWebhook()`](/docs/api-reference/workflow/create-webhook). The `:token` parameter identifies which workflow run should receive the data.
206
-
207
- <Callout type="info">
208
- The webhook file structure varies by framework. Next.js generates `webhook/[token]/route.js` to leverage App Router's dynamic routing, while other frameworks generate a single `webhook.js` handler.
209
- </Callout>
210
-
211
- ## Adapting to Other Frameworks
212
-
213
- The Bun example demonstrates the core pattern. To adapt for your framework:
214
-
215
- ### Build-Time
216
-
217
- **Option 1: Use the CLI** (simplest)
218
-
219
- ```bash
220
- workflow build
221
- ```
222
-
223
- This will default to scanning the `./workflows` top-level directory for workflow files, and will output bundled files directly into your working directory.
224
-
225
- **Option 2: Extend `BaseBuilder`** (recommended)
226
-
227
- {/* @skip-typecheck: @workflow/cli internal module */}
228
- ```typescript lineNumbers
229
- import { BaseBuilder } from "@workflow/cli/dist/lib/builders/base-builder";
167
+ {/* @skip-typecheck: incomplete framework adapter */}
168
+ ```typescript title="my-framework-builder.ts" lineNumbers
169
+ import { join } from "node:path";
170
+ import { BaseBuilder } from "@workflow/builders";
230
171
 
231
172
  class MyFrameworkBuilder extends BaseBuilder {
232
- constructor(options) {
233
- super({
234
- dirs: ["workflows"],
235
- workingDir: options.rootDir,
236
- watch: options.dev,
237
- });
238
- }
239
-
240
173
  override async build(): Promise<void> {
241
174
  const inputFiles = await this.getInputFiles();
175
+ const tsconfigPath = await this.findTsConfigPath();
176
+ const outputDir = join(this.config.workingDir, ".workflow");
242
177
 
243
- await this.createWorkflowsBundle({
244
- outfile: "/path/to/.well-known/workflow/v1/flow.js",
245
- format: "esm",
178
+ await this.createCombinedBundle({
246
179
  inputFiles,
247
- });
248
-
249
- await this.createStepsBundle({
250
- outfile: "/path/to/.well-known/workflow/v1/step.js",
180
+ stepsOutfile: join(outputDir, "__step_registrations.mjs"),
181
+ flowOutfile: join(outputDir, "flow.mjs"),
182
+ tsconfigPath,
251
183
  format: "esm",
252
- inputFiles,
253
184
  });
254
185
 
255
186
  await this.createWebhookBundle({
256
- outfile: "/path/to/.well-known/workflow/v1/webhook.js",
187
+ outfile: join(outputDir, "webhook.mjs"),
257
188
  });
258
189
  }
259
190
  }
260
191
  ```
261
192
 
262
- If your framework supports virtual server routes and dev mode watching, make sure to adapt accordingly. Please open a PR to the Workflow SDK if the base builder class is missing necessary functionality.
263
-
264
- ### Monorepos and Workspace Imports
265
-
266
- If your framework integration lives in a subdirectory and your workflows import code from sibling workspace packages, pass `projectRoot` to `BaseBuilder`. Use the smallest directory that contains every workspace package imported by your workflows.
267
-
268
- {/* @skip-typecheck: @workflow/cli internal module */}
269
- ```typescript title="my-framework-builder.ts" lineNumbers
270
- import { BaseBuilder } from "@workflow/cli/dist/lib/builders/base-builder";
193
+ If workflows import sibling workspace packages, set `projectRoot` to the smallest directory containing all imported packages.
271
194
 
272
- class MyFrameworkBuilder extends BaseBuilder {
273
- constructor(options: {
274
- rootDir: string;
275
- workspaceRoot?: string;
276
- dev: boolean;
277
- }) {
278
- super({
279
- dirs: ["workflows"],
280
- workingDir: options.rootDir,
281
- projectRoot: options.workspaceRoot ?? options.rootDir, // [!code highlight]
282
- watch: options.dev,
283
- });
284
- }
285
-
286
- override async build(): Promise<void> {
287
- const inputFiles = await this.getInputFiles();
288
- // ...
289
- }
290
- }
291
- ```
292
-
293
- Hook into your framework's build:
294
-
295
- {/* @skip-typecheck: incomplete code sample */}
296
- ```typescript title="pseudocode.ts" lineNumbers
297
- framework.hooks.hook("build:before", async () => {
298
- await new MyFrameworkBuilder(framework).build();
195
+ {/* @skip-typecheck: partial constructor configuration */}
196
+ ```typescript
197
+ super({
198
+ dirs: ["workflows"],
199
+ workingDir: options.rootDir,
200
+ projectRoot: options.workspaceRoot ?? options.rootDir,
201
+ watch: options.dev,
299
202
  });
300
203
  ```
301
204
 
302
- ### Runtime (Client Mode)
303
-
304
- Add a loader/plugin for your bundler:
305
-
306
- **Rollup/Vite:**
307
-
308
- ```typescript lineNumbers
309
- export function workflowPlugin() {
310
- return {
311
- name: "workflow-client-transform",
312
- async transform(code, id) {
313
- if (!code.match(/(use step|use workflow)/)) return null;
205
+ Your integration can expose physical files, virtual modules, or framework-native routes. In every case, the step registration module is a dependency of the flow handler, not a route of its own.
314
206
 
315
- const result = await transform(code, {
316
- filename: id,
317
- jsc: {
318
- experimental: {
319
- plugins: [[require.resolve("@workflow/swc-plugin"), { mode: "client" }]], // [!code highlight]
320
- },
321
- },
322
- });
207
+ ## Vercel queue configuration
323
208
 
324
- return { code: result.code, map: result.map };
325
- },
326
- };
327
- }
328
- ```
209
+ On Vercel, configure the flow function as the sole queue consumer. `getWorkflowQueueTrigger()` handles the optional queue namespace and `WORKFLOW_SEQUENTIAL_REPLAYS=1` behavior.
329
210
 
330
- **Webpack:**
211
+ ```typescript
212
+ import { getWorkflowQueueTrigger } from "@workflow/builders";
331
213
 
332
- ```javascript lineNumbers
333
- module.exports = {
334
- module: {
335
- rules: [
336
- {
337
- test: /\.(ts|tsx|js|jsx)$/,
338
- use: "workflow-client-loader", // Similar implementation
339
- },
340
- ],
341
- },
214
+ const flowConfig = {
215
+ maxDuration: "max",
216
+ experimentalTriggers: [getWorkflowQueueTrigger()],
342
217
  };
343
218
  ```
344
219
 
345
- ### HTTP Server
346
-
347
- Route the three endpoints to the generated handlers. The exact implementation depends on your framework's routing API.
348
-
349
- In the bun example above, we left routing to the user. Essentially, the user has to serve routes like this:
220
+ The generated trigger listens to one topic family:
350
221
 
351
- {/* @skip-typecheck: incomplete code sample */}
352
- ```typescript title="server.ts" lineNumbers
353
- import flow from "./.well-known/workflow/v1/flow.js";
354
- import step from "./.well-known/workflow/v1/step.js";
355
- import * as webhook from "./.well-known/workflow/v1/webhook.js";
356
-
357
- // Expose the 3 generated routes
358
- const server = Bun.serve({
359
- routes: {
360
- "/.well-known/workflow/v1/flow": {
361
- POST: (req) => flow.POST(req),
362
- },
363
- "/.well-known/workflow/v1/step": {
364
- POST: (req) => step.POST(req),
365
- },
366
- // webhook exports handlers for GET, POST, DELETE, etc.
367
- "/.well-known/workflow/v1/webhook/:token": webhook,
368
- },
369
- });
370
- ```
371
-
372
- Production framework integrations should handle this routing in the plugin instead of leaving it to the user, and this depends on each framework's unique implementaiton.
373
- Check the Workflow SDK source code for examples of production framework implementations.
374
- In the future, the Workflow SDK will emit more routes under the `.well-known/workflow` namespace.
375
-
376
- ## Security
377
-
378
- The workflow and step handler endpoints are invoked by the world's queuing infrastructure, not by end users. How they're secured depends on which world you're deploying to.
379
-
380
- ### Vercel (`@workflow/world-vercel`)
381
-
382
- On Vercel, workflow handler functions are not accessible through public endpoints. Handlers use the same [consumer function security](https://vercel.com/docs/queues/concepts#consumer-function-security) mechanism that secures [Vercel Queues](https://vercel.com/docs/queues) consumers.
383
-
384
- During the build step, the Workflow SDK automatically configures each handler as a queue consumer by writing `experimentalTriggers` to the function's `.vc-config.json`:
385
-
386
- ```json title=".vc-config.json (generated by Workflow SDK)"
222
+ ```json title=".vc-config.json (excerpt)"
387
223
  {
388
224
  "experimentalTriggers": [
389
225
  {
390
226
  "type": "queue/v2beta",
391
- "topic": "__wkf_step_*",
227
+ "topic": "__wkf_workflow_*",
392
228
  "consumer": "default",
393
229
  "retryAfterSeconds": 5,
394
230
  "initialDelaySeconds": 0
@@ -397,110 +233,28 @@ During the build step, the Workflow SDK automatically configures each handler as
397
233
  }
398
234
  ```
399
235
 
236
+ Both orchestration messages and step messages use this topic family. A step message is distinguished by its payload, not by a second topic or function.
400
237
 
401
- Two queue topics are created per deployment:
402
-
403
- | Handler | Topic | Description |
404
- | --- | --- | --- |
405
- | `step.func` | `__wkf_step_*` | Step execution (long-running, `maxDuration: max`) |
406
- | `flow.func` | `__wkf_workflow_*` | Workflow orchestration (`maxDuration: 60`) |
407
-
408
- If you're building a framework integration that targets Vercel, you should write these triggers into the `.vc-config.json` for each generated function. Use `getWorkflowQueueTrigger()` for flow functions so `WORKFLOW_SEQUENTIAL_REPLAYS=1` is reflected in the generated trigger configuration (it also accepts a `namespace` option, matching `createWorkflowQueueTrigger`); `STEP_QUEUE_TRIGGER` is exported for step functions:
409
-
410
- ```typescript
411
- import { getWorkflowQueueTrigger, STEP_QUEUE_TRIGGER } from "@workflow/builders";
412
-
413
- const flowTriggers = [getWorkflowQueueTrigger()];
414
- const stepTriggers = [STEP_QUEUE_TRIGGER];
415
- ```
416
-
417
- If your integration constructs the flow trigger object itself instead of calling `getWorkflowQueueTrigger()`, it must add `maxConcurrency: 1` to that trigger when sequential replays are enabled at build time (`WORKFLOW_SEQUENTIAL_REPLAYS=1` — the exported `isSequentialReplaysEnabled()` helper implements this check). The runtime half of the feature (per-run queue topics) activates from the environment variable alone — without the trigger half, those per-run topics are not serialized and the setting only adds queue-topic cardinality.
418
-
238
+ If you construct the trigger yourself, add `maxConcurrency: 1` when `WORKFLOW_SEQUENTIAL_REPLAYS=1`. The exported `isSequentialReplaysEnabled()` helper implements that build-time check.
419
239
 
420
- ### Custom implementations
421
-
422
- For self-hosted or non-Vercel deployments, you are responsible for securing the handler endpoints:
423
-
424
- - **Framework middleware** — Add authentication (API keys, JWT, OIDC) in front of the `/.well-known/workflow/v1/*` routes
425
- - **Network-level security** — Deploy handlers behind a VPC, private network, or firewall rules so only your queue infrastructure can reach them
426
- - **Rate limiting** — Add request validation and rate limiting to prevent abuse
427
-
428
- Learn more about [building custom Worlds](/worlds/building-a-world).
429
-
430
- ## Testing Your Integration
431
-
432
- ### 1. Test Build Output
433
-
434
- Create a test workflow:
435
-
436
- ```typescript title="workflows/test.ts" lineNumbers
437
- import { sleep, createWebhook } from "workflow";
438
-
439
- export async function handleUserSignup(email: string) {
440
- "use workflow";
441
-
442
- const user = await createUser(email);
443
- await sendWelcomeEmail(user);
444
-
445
- await sleep("5s");
446
-
447
- const webhook = createWebhook();
448
- await sendOnboardingEmail(user, webhook.url);
449
-
450
- await webhook;
451
- console.log("Webhook Resolved");
452
-
453
- return { userId: user.id, status: "onboarded" };
454
- }
455
-
456
- async function createUser(email: string) {
457
- "use step";
458
-
459
- console.log(`Creating a new user with email: ${email}`);
460
-
461
- return { id: crypto.randomUUID(), email };
462
- }
463
-
464
- async function sendWelcomeEmail(user: { id: string; email: string }) {
465
- "use step";
466
-
467
- console.log(`Sending welcome email to user: ${user.id}`);
468
- }
469
-
470
- async function sendOnboardingEmail(user: { id: string; email: string }, callback: string) {
471
- "use step";
472
-
473
- console.log(`Sending onboarding email to user: ${user.id}`);
474
-
475
- console.log(`Click this link to resolve the webhook: ${callback}`);
476
- }
240
+ ## Security
477
241
 
478
- ```
242
+ On Vercel, the flow handler uses [queue consumer security](https://vercel.com/docs/queues/concepts#consumer-function-security). For self-hosted worlds, protect the flow and webhook routes with the authentication, network controls, and rate limits appropriate to your queue transport.
479
243
 
480
- Run your build and verify:
244
+ ## Testing an integration
481
245
 
482
- - `.well-known/workflow/v1/flow.js` exists
483
- - `.well-known/workflow/v1/step.js` exists
484
- - `.well-known/workflow/v1/webhook.js` exists
246
+ After a build, verify that:
485
247
 
486
- ### 2. Test HTTP Endpoints
248
+ - the flow handler exists and imports or embeds the step registration bundle;
249
+ - the webhook handler exists;
250
+ - no step HTTP route or step queue trigger is generated;
251
+ - the flow function has the workflow queue trigger and the required maximum duration;
252
+ - starting a workflow executes a real step and resumes the workflow.
487
253
 
488
- Start your server and verify routes respond:
254
+ The flow route exposes a lightweight direct health mode:
489
255
 
490
256
  ```bash
491
- curl -X POST http://localhost:3000/.well-known/workflow/v1/flow
492
- curl -X POST http://localhost:3000/.well-known/workflow/v1/step
493
- curl -X POST http://localhost:3000/.well-known/workflow/v1/webhook/test
257
+ curl -X POST "http://localhost:3000/.well-known/workflow/v1/flow?__health"
494
258
  ```
495
259
 
496
- (Should respond but not trigger meaningful code without authentication/proper workflow run)
497
-
498
- ### 3. Run a Workflow End-to-End
499
-
500
- ```typescript
501
- import { start } from "workflow/api";
502
- import { handleUserSignup } from "./workflows/test";
503
-
504
- const run = await start(handleUserSignup, ["test@example.com"]);
505
- console.log("Workflow started:", run.runId);
506
- ```
260
+ For an end-to-end queue check, use [`healthCheck()`](/docs/api-reference/workflow-runtime/health-check).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workflow",
3
- "version": "5.0.0-beta.36",
3
+ "version": "5.0.0-beta.38",
4
4
  "description": "Workflow SDK - Build durable, resilient, and observable workflows",
5
5
  "main": "dist/typescript-plugin.cjs",
6
6
  "type": "module",
@@ -59,18 +59,18 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "ms": "2.1.3",
62
- "@workflow/astro": "5.0.0-beta.36",
63
- "@workflow/cli": "5.0.0-beta.36",
64
- "@workflow/core": "5.0.0-beta.36",
62
+ "@workflow/astro": "5.0.0-beta.38",
63
+ "@workflow/cli": "5.0.0-beta.38",
64
+ "@workflow/core": "5.0.0-beta.38",
65
+ "@workflow/errors": "5.0.0-beta.14",
65
66
  "@workflow/typescript-plugin": "5.0.0-beta.5",
66
- "@workflow/errors": "5.0.0-beta.12",
67
- "@workflow/utils": "5.0.0-beta.6",
68
- "@workflow/next": "5.0.0-beta.36",
69
- "@workflow/nest": "5.0.0-beta.36",
70
- "@workflow/nitro": "5.0.0-beta.36",
71
- "@workflow/nuxt": "5.0.0-beta.36",
72
- "@workflow/sveltekit": "5.0.0-beta.36",
73
- "@workflow/rollup": "5.0.0-beta.36"
67
+ "@workflow/utils": "5.0.0-beta.8",
68
+ "@workflow/next": "5.0.0-beta.38",
69
+ "@workflow/nest": "5.0.0-beta.38",
70
+ "@workflow/nitro": "5.0.0-beta.38",
71
+ "@workflow/nuxt": "5.0.0-beta.38",
72
+ "@workflow/sveltekit": "5.0.0-beta.38",
73
+ "@workflow/rollup": "5.0.0-beta.38"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@types/ms": "2.1.0",