workflow 4.2.0-beta.74 → 4.2.0-beta.76

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
@@ -5,7 +5,7 @@
5
5
  <img alt="Workflow SDK logo" src="https://useworkflow.dev/workflow-circle-symbol-light.svg" height="128">
6
6
  </picture>
7
7
  </a>
8
- <h1>Workflow Development Kit</h1>
8
+ <h1>Workflow SDK</h1>
9
9
 
10
10
  <a href="https://vercel.com"><img alt="Vercel logo" src="https://img.shields.io/badge/MADE%20BY%20Vercel-000000.svg?style=for-the-badge&logo=Vercel&labelColor=000"></a>
11
11
  <a href="https://www.npmjs.com/package/workflow"><img alt="NPM version" src="https://img.shields.io/npm/v/workflow?style=for-the-badge&labelColor=000000"></a>
@@ -16,7 +16,7 @@
16
16
 
17
17
  ## Getting Started
18
18
 
19
- The **Workflow Development Kit** lets you easily add durability, reliability, and observability to async JavaScript. Build apps and AI agents that can suspend, resume, and maintain state with ease.
19
+ The **Workflow SDK** lets you easily add durability, reliability, and observability to async JavaScript. Build apps and AI agents that can suspend, resume, and maintain state with ease.
20
20
 
21
21
  Visit [https://useworkflow.dev](https://useworkflow.dev) to view the full documentation.
22
22
 
@@ -13,6 +13,10 @@ Creates a webhook that can be used to suspend and resume a workflow run upon rec
13
13
 
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
+ <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.
18
+ </Callout>
19
+
16
20
  ```ts lineNumbers
17
21
  import { createWebhook } from "workflow"
18
22
 
@@ -14,7 +14,7 @@ Use this function when you need direct access to the underlying workflow infrast
14
14
  ```typescript lineNumbers
15
15
  import { getWorld } from "workflow/runtime";
16
16
 
17
- const world = getWorld();
17
+ const world = getWorld(); // [!code highlight]
18
18
  ```
19
19
 
20
20
  ## API Signature
@@ -34,167 +34,37 @@ export default World;`}
34
34
  showSections={["returns"]}
35
35
  />
36
36
 
37
- ## Examples
37
+ ## World SDK
38
38
 
39
- ### List Workflow Runs
39
+ The World object provides access to several entity interfaces. See the [World SDK](/docs/api-reference/workflow-api/world) reference for complete documentation:
40
40
 
41
- List all workflow runs with pagination:
41
+ <Cards>
42
+ <Card href="/docs/api-reference/workflow-api/world/storage" title="Storage">
43
+ Query runs, steps, hooks, and the underlying event log.
44
+ </Card>
45
+ <Card href="/docs/api-reference/workflow-api/world/streams" title="Streams">
46
+ Read, write, and manage data streams.
47
+ </Card>
48
+ <Card href="/docs/api-reference/workflow-api/world/queue" title="Queue">
49
+ Low-level queue dispatch (internal SDK infrastructure).
50
+ </Card>
51
+ <Card href="/docs/api-reference/workflow-api/world/observability" title="Observability">
52
+ Hydrate step I/O, parse display names, decrypt data.
53
+ </Card>
54
+ </Cards>
42
55
 
43
- ```typescript lineNumbers
44
- import { getWorld } from "workflow/runtime";
45
-
46
- export async function GET(req: Request) {
47
- const url = new URL(req.url);
48
- const cursor = url.searchParams.get("cursor") ?? undefined;
49
-
50
- try {
51
- const world = getWorld(); // [!code highlight]
52
- const runs = await world.runs.list({
53
- pagination: { cursor },
54
- });
55
-
56
- return Response.json(runs);
57
- } catch (error) {
58
- return Response.json(
59
- { error: "Failed to list workflow runs" },
60
- { status: 500 }
61
- );
62
- }
63
- }
64
- ```
65
-
66
- ### Cancel a Workflow Run
67
-
68
- Cancel a running workflow:
69
-
70
- ```typescript lineNumbers
71
- import { getWorld } from "workflow/runtime";
56
+ ## Data Hydration
72
57
 
73
- export async function POST(req: Request) {
74
- const { runId } = await req.json();
75
-
76
- if (!runId) {
77
- return Response.json({ error: "No runId provided" }, { status: 400 });
78
- }
79
-
80
- try {
81
- const world = getWorld(); // [!code highlight]
82
- const run = await world.runs.cancel(runId); // [!code highlight]
83
-
84
- return Response.json({ status: run.status });
85
- } catch (error) {
86
- return Response.json(
87
- { error: "Failed to cancel workflow run" },
88
- { status: 500 }
89
- );
90
- }
91
- }
92
- ```
93
-
94
- ### List Steps for a Run (Without Data)
95
-
96
- List steps for a workflow run with `resolveData: 'none'` to efficiently get step metadata without fetching serialized input/output. Use `parseStepName` to extract user-friendly display names:
58
+ Step and run data is serialized using the [devalue](https://github.com/Rich-Harris/devalue) format. Use `workflow/observability` to hydrate it for display:
97
59
 
98
60
  ```typescript lineNumbers
99
- import { getWorld } from "workflow/runtime";
100
- import { parseStepName } from "@workflow/utils/parse-name"; // [!code highlight]
101
-
102
- export async function GET(req: Request) {
103
- const url = new URL(req.url);
104
- const runId = url.searchParams.get("runId");
105
-
106
- if (!runId) {
107
- return Response.json({ error: "No runId provided" }, { status: 400 });
108
- }
109
-
110
- try {
111
- const world = getWorld(); // [!code highlight]
112
- const steps = await world.steps.list({ // [!code highlight]
113
- runId, // [!code highlight]
114
- resolveData: "none", // Skip fetching input/output for performance // [!code highlight]
115
- }); // [!code highlight]
116
-
117
- // Map steps to a progress view using parseStepName for display
118
- const progress = steps.data.map((step) => {
119
- const parsed = parseStepName(step.stepName); // [!code highlight]
120
- return {
121
- stepId: step.stepId,
122
- // Use shortName for UI display (e.g., "fetchUserData") // [!code highlight]
123
- displayName: parsed?.shortName ?? step.stepName, // [!code highlight]
124
- // Module info available for debugging // [!code highlight]
125
- module: parsed?.moduleSpecifier, // [!code highlight]
126
- status: step.status,
127
- startedAt: step.startedAt,
128
- completedAt: step.completedAt,
129
- };
130
- });
131
-
132
- return Response.json({ progress, cursor: steps.cursor });
133
- } catch (error) {
134
- return Response.json(
135
- { error: "Failed to list steps" },
136
- { status: 500 }
137
- );
138
- }
139
- }
140
- ```
61
+ import { hydrateResourceIO, observabilityRevivers } from "workflow/observability"; // [!code highlight]
141
62
 
142
- ### Get Step with Hydrated Input/Output
143
-
144
- Retrieve a step with its serialized data and hydrate it for display. This example shows how to decrypt and deserialize step input/output:
145
-
146
- ```typescript lineNumbers
147
- import { getWorld } from "workflow/runtime";
148
- import { parseStepName } from "@workflow/utils/parse-name"; // [!code highlight]
149
- import { // [!code highlight]
150
- hydrateResourceIO, // [!code highlight]
151
- observabilityRevivers, // [!code highlight]
152
- } from "@workflow/core/serialization-format"; // [!code highlight]
153
-
154
- export async function GET(req: Request) {
155
- const url = new URL(req.url);
156
- const runId = url.searchParams.get("runId");
157
- const stepId = url.searchParams.get("stepId");
158
-
159
- if (!runId || !stepId) {
160
- return Response.json({ error: "runId and stepId required" }, { status: 400 });
161
- }
162
-
163
- try {
164
- const world = getWorld(); // [!code highlight]
165
- // Fetch step with data (default resolveData behavior) // [!code highlight]
166
- const step = await world.steps.get(runId, stepId); // [!code highlight]
167
-
168
- // Hydrate serialized input/output for display // [!code highlight]
169
- const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
170
-
171
- // Parse the stepName for user-friendly display
172
- const parsed = parseStepName(step.stepName);
173
-
174
- return Response.json({
175
- stepId: hydrated.stepId,
176
- displayName: parsed?.shortName ?? step.stepName, // [!code highlight]
177
- module: parsed?.moduleSpecifier, // [!code highlight]
178
- status: hydrated.status,
179
- attempt: hydrated.attempt,
180
- // Hydrated input/output ready for rendering // [!code highlight]
181
- input: hydrated.input, // [!code highlight]
182
- output: hydrated.output, // [!code highlight]
183
- });
184
- } catch (error) {
185
- return Response.json(
186
- { error: "Step not found" },
187
- { status: 404 }
188
- );
189
- }
190
- }
63
+ const step = await world.steps.get(runId, stepId);
64
+ const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
191
65
  ```
192
66
 
193
- <Callout type="info">
194
- The `stepName` field contains a machine-readable identifier like `step//./src/workflows/order//processPayment`.
195
- Use `parseStepName()` from `@workflow/utils/parse-name` to extract the `shortName` (e.g., `"processPayment"`)
196
- and `moduleSpecifier` for display in your UI.
197
- </Callout>
67
+ See [Observability Utilities](/docs/api-reference/workflow-api/world/observability) for the full hydration, parsing, and encryption API.
198
68
 
199
69
  ## Related Functions
200
70
 
@@ -30,4 +30,7 @@ The API package is for access and introspection of workflow data to inspect runs
30
30
  <Card href="/docs/api-reference/workflow-api/get-world" title="getWorld()">
31
31
  Get direct access to workflow storage, queuing, and streaming backends.
32
32
  </Card>
33
+ <Card href="/docs/api-reference/workflow-api/world" title="World SDK">
34
+ Low-level API for inspecting runs, steps, events, hooks, streams, and queues.
35
+ </Card>
33
36
  </Cards>
@@ -0,0 +1,58 @@
1
+ ---
2
+ title: World SDK
3
+ description: Low-level API for inspecting and managing workflow runs, steps, events, hooks, streams, and queues.
4
+ type: overview
5
+ summary: Access workflow infrastructure directly via getWorld() for building observability dashboards, admin tools, and custom integrations.
6
+ prerequisites:
7
+ - /docs/api-reference/workflow-api/get-world
8
+ keywords:
9
+ - getWorld
10
+ - World SDK
11
+ - workflow runtime
12
+ - observability dashboard
13
+ - admin panel
14
+ - workflow management
15
+ ---
16
+
17
+ The World SDK provides direct access to workflow infrastructure — runs, steps, events, hooks, streams, and queues. Use it to build observability dashboards, admin panels, debugging tools, and custom workflow management logic.
18
+
19
+ ```typescript lineNumbers
20
+ import { getWorld } from "workflow/runtime";
21
+
22
+ const world = getWorld(); // [!code highlight]
23
+ ```
24
+
25
+ ## Interfaces
26
+
27
+ <Cards>
28
+ <Card href="/docs/api-reference/workflow-api/world/storage" title="Storage">
29
+ Query runs, steps, hooks, and the underlying event log.
30
+ </Card>
31
+ <Card href="/docs/api-reference/workflow-api/world/streams" title="Streams">
32
+ Read, write, and manage real-time data streams for workflow runs.
33
+ </Card>
34
+ <Card href="/docs/api-reference/workflow-api/world/queue" title="Queue">
35
+ Low-level queue dispatch (internal SDK infrastructure).
36
+ </Card>
37
+ <Card href="/docs/api-reference/workflow-api/world/observability" title="Observability Utilities">
38
+ Hydrate step I/O, parse display names, and decrypt workflow data.
39
+ </Card>
40
+ </Cards>
41
+
42
+ <Callout type="info">
43
+ The World SDK is the low-level foundation that higher-level functions like [`getRun()`](/docs/api-reference/workflow-api/get-run) and [`start()`](/docs/api-reference/workflow-api/start) are built on. Use it when you need capabilities beyond what those functions provide.
44
+ </Callout>
45
+
46
+ ## Data Hydration
47
+
48
+ Step input/output data is serialized using the [devalue](https://github.com/Rich-Harris/devalue) format. To display this data in your UI, use the hydration utilities from `workflow/observability`:
49
+
50
+ ```typescript lineNumbers
51
+ import { hydrateResourceIO, observabilityRevivers } from "workflow/observability"; // [!code highlight]
52
+
53
+ const step = await world.steps.get(runId, stepId);
54
+ const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
55
+ console.log(hydrated.input, hydrated.output);
56
+ ```
57
+
58
+ See [Observability Utilities](/docs/api-reference/workflow-api/world/observability) for the full API.
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "World SDK",
3
+ "pages": ["storage", "streams", "queue", "observability"]
4
+ }
@@ -0,0 +1,164 @@
1
+ ---
2
+ title: Observability Utilities
3
+ description: Hydrate step I/O, parse display names, and decrypt workflow data using workflow/observability.
4
+ type: reference
5
+ summary: "Functions: hydrateResourceIO(), parseStepName(), parseWorkflowName(), parseClassName(), getEncryptionKeyForRun(), hydrateResourceIOWithKey()."
6
+ prerequisites:
7
+ - /docs/api-reference/workflow-api/get-world
8
+ related:
9
+ - /docs/api-reference/workflow-api/world/storage
10
+ keywords:
11
+ - workflow/observability
12
+ - hydrateResourceIO
13
+ - observabilityRevivers
14
+ - parseStepName
15
+ - parseWorkflowName
16
+ - parseClassName
17
+ - getEncryptionKeyForRun
18
+ - hydrateResourceIOWithKey
19
+ - data hydration
20
+ - devalue deserialization
21
+ - encryption decryption
22
+ - display name parsing
23
+ ---
24
+
25
+ The `workflow/observability` module provides utilities for working with workflow data in observability and debugging tools. It includes functions to hydrate serialized step I/O, parse machine-readable names into display-friendly formats, and decrypt encrypted workflow data.
26
+
27
+ ## Import
28
+
29
+ ```typescript lineNumbers
30
+ import { // [!code highlight]
31
+ hydrateResourceIO, // [!code highlight]
32
+ observabilityRevivers, // [!code highlight]
33
+ parseStepName, // [!code highlight]
34
+ parseWorkflowName, // [!code highlight]
35
+ parseClassName, // [!code highlight]
36
+ } from "workflow/observability"; // [!code highlight]
37
+ ```
38
+
39
+ ## Data Hydration
40
+
41
+ ### hydrateResourceIO()
42
+
43
+ Deserialize step or run data that was serialized using the [devalue](https://github.com/Rich-Harris/devalue) format. Required to display step input/output in your UI.
44
+
45
+ ```typescript lineNumbers
46
+ import { hydrateResourceIO, observabilityRevivers } from "workflow/observability"; // [!code highlight]
47
+
48
+ const step = await world.steps.get(runId, stepId);
49
+ const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
50
+ console.log(hydrated.input, hydrated.output);
51
+ ```
52
+
53
+ **Parameters:**
54
+
55
+ | Parameter | Type | Description |
56
+ |-----------|------|-------------|
57
+ | `resource` | `Step \| WorkflowRun` | The step or run with serialized data |
58
+ | `revivers` | `Revivers` | Reviver functions for deserialization. Use `observabilityRevivers` for standard use. |
59
+
60
+ **Returns:** The resource with hydrated `input` and `output` fields.
61
+
62
+ ### observabilityRevivers
63
+
64
+ A set of reviver functions that handle standard workflow serialization types (Date, Map, Set, Error, etc.).
65
+
66
+ ## Name Parsing
67
+
68
+ Workflow and step names are stored as machine-readable identifiers. These utilities extract display-friendly names. All return `{ shortName: string, moduleSpecifier: string } | null`.
69
+
70
+ ### parseStepName()
71
+
72
+ ```typescript lineNumbers
73
+ import { parseStepName } from "workflow/observability"; // [!code highlight]
74
+
75
+ const parsed = parseStepName("step//./src/workflows/order//processPayment"); // [!code highlight]
76
+ // parsed?.shortName → "processPayment"
77
+ // parsed?.moduleSpecifier → "./src/workflows/order"
78
+ ```
79
+
80
+ ### parseWorkflowName()
81
+
82
+ ```typescript lineNumbers
83
+ import { parseWorkflowName } from "workflow/observability"; // [!code highlight]
84
+
85
+ const parsed = parseWorkflowName("workflow//./src/workflows/order//processOrder"); // [!code highlight]
86
+ // parsed?.shortName → "processOrder"
87
+ ```
88
+
89
+ ### parseClassName()
90
+
91
+ ```typescript lineNumbers
92
+ import { parseClassName } from "workflow/observability"; // [!code highlight]
93
+
94
+ const parsed = parseClassName("class//./src/models//User"); // [!code highlight]
95
+ // parsed?.shortName → "User"
96
+ ```
97
+
98
+ ## Encryption
99
+
100
+ For workflows with encrypted step data, decrypt before hydrating.
101
+
102
+ ### getEncryptionKeyForRun()
103
+
104
+ Retrieve the encryption key used for a specific workflow run.
105
+
106
+ {/* @expect-error:2305 */}
107
+ ```typescript lineNumbers
108
+ import { getEncryptionKeyForRun } from "workflow/observability"; // [!code highlight]
109
+
110
+ const key = await getEncryptionKeyForRun(runId); // [!code highlight]
111
+ ```
112
+
113
+ **Parameters:**
114
+
115
+ | Parameter | Type | Description |
116
+ |-----------|------|-------------|
117
+ | `runId` | `string` | The workflow run ID |
118
+
119
+ **Returns:** Encryption key for the run
120
+
121
+ ### hydrateResourceIOWithKey()
122
+
123
+ Hydrate step or run data using a decryption key. Use this instead of `hydrateResourceIO()` when data is encrypted.
124
+
125
+ {/* @expect-error:2305,2724 */}
126
+ ```typescript lineNumbers
127
+ import { getEncryptionKeyForRun, hydrateResourceIOWithKey } from "workflow/observability"; // [!code highlight]
128
+
129
+ const key = await getEncryptionKeyForRun(runId); // [!code highlight]
130
+ const hydrated = hydrateResourceIOWithKey(step, key); // [!code highlight]
131
+ ```
132
+
133
+ **Parameters:**
134
+
135
+ | Parameter | Type | Description |
136
+ |-----------|------|-------------|
137
+ | `resource` | `Step \| WorkflowRun` | The step or run with encrypted serialized data |
138
+ | `key` | `EncryptionKey` | The encryption key from `getEncryptionKeyForRun()` |
139
+
140
+ **Returns:** The resource with decrypted and hydrated `input` and `output` fields.
141
+
142
+ ## Examples
143
+
144
+ ### Parse Display Names for a Run's Steps
145
+
146
+ ```typescript lineNumbers
147
+ import { getWorld } from "workflow/runtime";
148
+ import { parseStepName, parseWorkflowName } from "workflow/observability"; // [!code highlight]
149
+
150
+ const world = getWorld();
151
+ const run = await world.runs.get(runId, { resolveData: "none" });
152
+ console.log("Workflow:", parseWorkflowName(run.workflowName)?.shortName); // [!code highlight]
153
+
154
+ const steps = await world.steps.list({ runId, resolveData: "none" });
155
+ for (const step of steps.data) {
156
+ const parsed = parseStepName(step.stepName); // [!code highlight]
157
+ console.log(` ${parsed?.shortName}: ${step.status}`); // [!code highlight]
158
+ }
159
+ ```
160
+
161
+ ## Related
162
+
163
+ - [Storage](/docs/api-reference/workflow-api/world/storage) — Query runs, steps, hooks, and events
164
+ - [Serialization](/docs/foundations/serialization) — How workflow data is serialized
@@ -0,0 +1,86 @@
1
+ ---
2
+ title: Queue
3
+ description: Low-level queue interface for dispatching workflow and step invocations.
4
+ type: reference
5
+ summary: "Methods: getDeploymentId(), queue(), createQueueHandler(). Internal queue dispatch — normally handled by the SDK."
6
+ prerequisites:
7
+ - /docs/api-reference/workflow-api/get-world
8
+ related:
9
+ - /docs/api-reference/workflow-api/start
10
+ - /docs/foundations/starting-workflows
11
+ keywords:
12
+ - world.queue
13
+ - getDeploymentId
14
+ - queue
15
+ - createQueueHandler
16
+ - ValidQueueName
17
+ - queue dispatch
18
+ ---
19
+
20
+ Queue methods live directly on the `world` object (not nested). They dispatch internal workflow and step invocations to the queue backend.
21
+
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.
24
+ </Callout>
25
+
26
+ ## Import
27
+
28
+ ```typescript lineNumbers
29
+ import { getWorld } from "workflow/runtime";
30
+
31
+ const world = getWorld(); // [!code highlight]
32
+ // Queue methods are called directly on world — e.g. world.queue()
33
+ ```
34
+
35
+ ## Methods
36
+
37
+ ### getDeploymentId()
38
+
39
+ Get the current deployment ID. Used internally for routing queue messages to the correct deployment.
40
+
41
+ ```typescript lineNumbers
42
+ const deploymentId = await world.getDeploymentId(); // [!code highlight]
43
+ ```
44
+
45
+ **Returns:** `string` — The current deployment ID
46
+
47
+ ### queue()
48
+
49
+ Dispatch a message to a named queue. The message payload is an internal SDK type (`WorkflowInvokePayload`, `StepInvokePayload`, or `HealthCheckPayload`).
50
+
51
+ ```typescript lineNumbers
52
+ const { messageId } = await world.queue(queueName, payload, opts); // [!code highlight]
53
+ ```
54
+
55
+ **Parameters:**
56
+
57
+ | Parameter | Type | Description |
58
+ |-----------|------|-------------|
59
+ | `queueName` | `ValidQueueName` | The queue name (branded string) |
60
+ | `message` | `QueuePayload` | Internal SDK payload |
61
+ | `opts` | `QueueOptions` | Optional — `deploymentId`, `idempotencyKey`, `delaySeconds`, `headers` |
62
+
63
+ **Returns:** `{ messageId: MessageId | null }`
64
+
65
+ ### createQueueHandler()
66
+
67
+ Create an HTTP handler that processes messages from a queue. Used to set up the queue consumer endpoint.
68
+
69
+ ```typescript lineNumbers
70
+ const handler = world.createQueueHandler(prefix, callback); // [!code highlight]
71
+ ```
72
+
73
+ **Parameters:**
74
+
75
+ | Parameter | Type | Description |
76
+ |-----------|------|-------------|
77
+ | `prefix` | `QueuePrefix` | Queue name prefix to match |
78
+ | `callback` | `(message, meta) => Promise<void \| { timeoutSeconds: number }>` | Handler called for each message. `meta` contains `attempt`, `queueName`, `messageId`, `requestId`. |
79
+
80
+ **Returns:** `(req: Request) => Promise<Response>`
81
+
82
+ ## Related
83
+
84
+ - [start()](/docs/api-reference/workflow-api/start) — The standard way to start workflow runs
85
+ - [Starting Workflows](/docs/foundations/starting-workflows) — Core concepts for workflow invocation
86
+ - [Storage](/docs/api-reference/workflow-api/world/storage) — Create events that trigger queue dispatch