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 +2 -2
- package/docs/api-reference/workflow/create-webhook.mdx +4 -0
- package/docs/api-reference/workflow-api/get-world.mdx +23 -153
- package/docs/api-reference/workflow-api/index.mdx +3 -0
- package/docs/api-reference/workflow-api/world/index.mdx +58 -0
- package/docs/api-reference/workflow-api/world/meta.json +4 -0
- package/docs/api-reference/workflow-api/world/observability.mdx +164 -0
- package/docs/api-reference/workflow-api/world/queue.mdx +86 -0
- package/docs/api-reference/workflow-api/world/storage.mdx +408 -0
- package/docs/api-reference/workflow-api/world/streams.mdx +214 -0
- package/docs/foundations/hooks.mdx +4 -0
- package/docs/foundations/serialization.mdx +3 -3
- package/docs/foundations/streaming.mdx +1 -0
- package/docs/getting-started/astro.mdx +1 -1
- package/docs/getting-started/express.mdx +1 -1
- package/docs/getting-started/fastify.mdx +1 -1
- package/docs/getting-started/hono.mdx +1 -1
- package/docs/getting-started/nestjs.mdx +1 -1
- package/docs/getting-started/next.mdx +1 -1
- package/docs/getting-started/nitro.mdx +1 -1
- package/docs/getting-started/nuxt.mdx +1 -1
- package/docs/getting-started/sveltekit.mdx +1 -1
- package/docs/getting-started/vite.mdx +1 -1
- package/docs/how-it-works/understanding-directives.mdx +3 -3
- package/package.json +11 -11
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Storage
|
|
3
|
+
description: Query workflow runs, steps, hooks, and the underlying event log via the World storage interface.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: "Interfaces: world.events, world.runs, world.steps, world.hooks. Events are the source of truth; runs, steps, and hooks are materialized views."
|
|
6
|
+
prerequisites:
|
|
7
|
+
- /docs/api-reference/workflow-api/get-world
|
|
8
|
+
related:
|
|
9
|
+
- /docs/api-reference/workflow-api/get-run
|
|
10
|
+
- /docs/how-it-works/event-sourcing
|
|
11
|
+
- /docs/api-reference/workflow-api/world/observability
|
|
12
|
+
keywords:
|
|
13
|
+
- world.events
|
|
14
|
+
- world.runs
|
|
15
|
+
- world.steps
|
|
16
|
+
- world.hooks
|
|
17
|
+
- event log
|
|
18
|
+
- event sourcing
|
|
19
|
+
- materialized views
|
|
20
|
+
- WorkflowRun
|
|
21
|
+
- Step
|
|
22
|
+
- Hook
|
|
23
|
+
- Event
|
|
24
|
+
- cursor pagination
|
|
25
|
+
- resolveData
|
|
26
|
+
- run_cancelled
|
|
27
|
+
- correlation ID
|
|
28
|
+
- parseStepName
|
|
29
|
+
- parseWorkflowName
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
The World storage interface exposes four sub-interfaces for querying workflow data:
|
|
33
|
+
|
|
34
|
+
- **`world.events`** — The append-only event log. This is the source of truth for all workflow state. See [Event Sourcing](/docs/how-it-works/event-sourcing) for background.
|
|
35
|
+
- **`world.runs`**, **`world.steps`**, **`world.hooks`** — Materialized views derived from the event log, provided as convenience accessors for the most common query patterns.
|
|
36
|
+
|
|
37
|
+
```typescript lineNumbers
|
|
38
|
+
import { getWorld } from "workflow/runtime";
|
|
39
|
+
|
|
40
|
+
const world = getWorld(); // [!code highlight]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## world.events
|
|
46
|
+
|
|
47
|
+
The event log drives all workflow state. Use it for audit trails, debugging, and programmatic run cancellation.
|
|
48
|
+
|
|
49
|
+
### events.create()
|
|
50
|
+
|
|
51
|
+
Create a new event for a workflow run. Most commonly used to cancel a run.
|
|
52
|
+
|
|
53
|
+
```typescript lineNumbers
|
|
54
|
+
await world.events.create(runId, { // [!code highlight]
|
|
55
|
+
eventType: "run_cancelled", // [!code highlight]
|
|
56
|
+
}); // [!code highlight]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
| Parameter | Type | Description |
|
|
60
|
+
|-----------|------|-------------|
|
|
61
|
+
| `runId` | `string \| null` | The workflow run ID (`null` only for `run_created` events, where the server generates an ID) |
|
|
62
|
+
| `data` | `CreateEventRequest` | Event data including `eventType` |
|
|
63
|
+
| `params` | `object` | Optional parameters |
|
|
64
|
+
|
|
65
|
+
**Returns:** `EventResult` — The created event and the affected entity (run/step/hook)
|
|
66
|
+
|
|
67
|
+
### events.get()
|
|
68
|
+
|
|
69
|
+
Retrieve a single event by run ID and event ID.
|
|
70
|
+
|
|
71
|
+
```typescript lineNumbers
|
|
72
|
+
const event = await world.events.get(runId, eventId); // [!code highlight]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
| Parameter | Type | Description |
|
|
76
|
+
|-----------|------|-------------|
|
|
77
|
+
| `runId` | `string` | The workflow run ID |
|
|
78
|
+
| `eventId` | `string` | The event ID |
|
|
79
|
+
|
|
80
|
+
**Returns:** `Event`
|
|
81
|
+
|
|
82
|
+
### events.list()
|
|
83
|
+
|
|
84
|
+
List events for a run with cursor pagination.
|
|
85
|
+
|
|
86
|
+
```typescript lineNumbers
|
|
87
|
+
const result = await world.events.list({ runId, pagination: { cursor } }); // [!code highlight]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
| Parameter | Type | Description |
|
|
91
|
+
|-----------|------|-------------|
|
|
92
|
+
| `params.runId` | `string` | Filter events by run ID |
|
|
93
|
+
| `params.pagination.cursor` | `string` | Cursor for the next page |
|
|
94
|
+
|
|
95
|
+
**Returns:** `{ data: Event[], cursor?: string }`
|
|
96
|
+
|
|
97
|
+
### events.listByCorrelationId()
|
|
98
|
+
|
|
99
|
+
List events that share a correlation ID, useful for tracing related events across runs.
|
|
100
|
+
|
|
101
|
+
```typescript lineNumbers
|
|
102
|
+
const result = await world.events.listByCorrelationId({ // [!code highlight]
|
|
103
|
+
correlationId: "order-123",
|
|
104
|
+
}); // [!code highlight]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
| Parameter | Type | Description |
|
|
108
|
+
|-----------|------|-------------|
|
|
109
|
+
| `params.correlationId` | `string` | The correlation ID to filter by |
|
|
110
|
+
| `params.pagination.cursor` | `string` | Cursor for the next page |
|
|
111
|
+
|
|
112
|
+
**Returns:** `{ data: Event[], cursor?: string }`
|
|
113
|
+
|
|
114
|
+
### Event Types
|
|
115
|
+
|
|
116
|
+
| Category | Types |
|
|
117
|
+
|----------|-------|
|
|
118
|
+
| Run | `run_created`, `run_started`, `run_completed`, `run_failed`, `run_cancelled` |
|
|
119
|
+
| Step | `step_created`, `step_started`, `step_completed`, `step_failed`, `step_retrying` |
|
|
120
|
+
| Hook | `hook_created`, `hook_received`, `hook_disposed`, `hook_conflict` |
|
|
121
|
+
| Wait | `wait_created`, `wait_completed` |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## world.runs
|
|
126
|
+
|
|
127
|
+
Materialized from run events. Use it to list and inspect workflow runs.
|
|
128
|
+
|
|
129
|
+
### runs.get()
|
|
130
|
+
|
|
131
|
+
```typescript lineNumbers
|
|
132
|
+
const run = await world.runs.get(runId); // [!code highlight]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
| Parameter | Type | Description |
|
|
136
|
+
|-----------|------|-------------|
|
|
137
|
+
| `runId` | `string` | The workflow run ID |
|
|
138
|
+
| `params.resolveData` | `'all' \| 'none'` | Whether to include input/output data. Default: `'all'` |
|
|
139
|
+
|
|
140
|
+
**Returns:** `WorkflowRun` (or `WorkflowRunWithoutData` when `resolveData: 'none'`)
|
|
141
|
+
|
|
142
|
+
### runs.list()
|
|
143
|
+
|
|
144
|
+
```typescript lineNumbers
|
|
145
|
+
const result = await world.runs.list({ // [!code highlight]
|
|
146
|
+
pagination: { cursor },
|
|
147
|
+
}); // [!code highlight]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
| Parameter | Type | Description |
|
|
151
|
+
|-----------|------|-------------|
|
|
152
|
+
| `params.pagination.cursor` | `string` | Cursor for the next page |
|
|
153
|
+
| `params.resolveData` | `'all' \| 'none'` | Whether to include input/output data |
|
|
154
|
+
|
|
155
|
+
**Returns:** `{ data: WorkflowRun[], cursor?: string }`
|
|
156
|
+
|
|
157
|
+
### Cancelling Runs
|
|
158
|
+
|
|
159
|
+
To cancel a run, create a `run_cancelled` event via `world.events.create()` (see [world.events](#worldevents) above), or use the CLI or Web UI helpers.
|
|
160
|
+
|
|
161
|
+
### WorkflowRun Type
|
|
162
|
+
|
|
163
|
+
| Field | Type | Description |
|
|
164
|
+
|-------|------|-------------|
|
|
165
|
+
| `runId` | `string` | Unique run identifier |
|
|
166
|
+
| `status` | `string` | `'running'`, `'completed'`, `'failed'`, `'cancelled'` |
|
|
167
|
+
| `workflowName` | `string` | Machine-readable workflow identifier |
|
|
168
|
+
| `input` | `any` | Workflow input data (when `resolveData: 'all'`) |
|
|
169
|
+
| `output` | `any` | Workflow output data (when `resolveData: 'all'`) |
|
|
170
|
+
| `error` | `any` | Error data if the run failed |
|
|
171
|
+
| `startedAt` | `string` | ISO timestamp when the run started |
|
|
172
|
+
| `completedAt` | `string \| null` | ISO timestamp when the run completed |
|
|
173
|
+
|
|
174
|
+
<Callout type="warn">
|
|
175
|
+
`workflowName` is a machine-readable identifier like `workflow//./src/workflows/order//processOrder`. Use `parseWorkflowName()` from `workflow/observability` to extract a display-friendly name.
|
|
176
|
+
</Callout>
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## world.steps
|
|
181
|
+
|
|
182
|
+
Materialized from step events. Use it to list steps, inspect their input/output, and build progress dashboards.
|
|
183
|
+
|
|
184
|
+
### steps.get()
|
|
185
|
+
|
|
186
|
+
```typescript lineNumbers
|
|
187
|
+
const step = await world.steps.get(runId, stepId); // [!code highlight]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
| Parameter | Type | Description |
|
|
191
|
+
|-----------|------|-------------|
|
|
192
|
+
| `runId` | `string \| undefined` | The workflow run ID |
|
|
193
|
+
| `stepId` | `string` | The step ID |
|
|
194
|
+
| `params.resolveData` | `'all' \| 'none'` | Whether to include input/output data. Default: `'all'` |
|
|
195
|
+
|
|
196
|
+
**Returns:** `Step` (or `StepWithoutData` when `resolveData: 'none'`)
|
|
197
|
+
|
|
198
|
+
### steps.list()
|
|
199
|
+
|
|
200
|
+
```typescript lineNumbers
|
|
201
|
+
const result = await world.steps.list({ // [!code highlight]
|
|
202
|
+
runId,
|
|
203
|
+
pagination: { cursor },
|
|
204
|
+
}); // [!code highlight]
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
| Parameter | Type | Description |
|
|
208
|
+
|-----------|------|-------------|
|
|
209
|
+
| `params.runId` | `string` | Filter steps by run ID |
|
|
210
|
+
| `params.pagination.cursor` | `string` | Cursor for the next page |
|
|
211
|
+
| `params.resolveData` | `'all' \| 'none'` | Whether to include input/output data |
|
|
212
|
+
|
|
213
|
+
**Returns:** `{ data: Step[], cursor?: string }`
|
|
214
|
+
|
|
215
|
+
### Step Type
|
|
216
|
+
|
|
217
|
+
| Field | Type | Description |
|
|
218
|
+
|-------|------|-------------|
|
|
219
|
+
| `runId` | `string` | Parent workflow run ID |
|
|
220
|
+
| `stepId` | `string` | Unique step identifier |
|
|
221
|
+
| `stepName` | `string` | Machine-readable step identifier |
|
|
222
|
+
| `status` | `string` | `'running'`, `'completed'`, `'failed'` |
|
|
223
|
+
| `input` | `any` | Step input data (when `resolveData: 'all'`) |
|
|
224
|
+
| `output` | `any` | Step output data (when `resolveData: 'all'`) |
|
|
225
|
+
| `error` | `any` | Error data if the step failed |
|
|
226
|
+
| `attempt` | `number` | Current retry attempt number |
|
|
227
|
+
| `startedAt` | `string` | ISO timestamp when the step started |
|
|
228
|
+
| `completedAt` | `string \| null` | ISO timestamp when the step completed |
|
|
229
|
+
| `retryAfter` | `string \| null` | ISO timestamp for next retry attempt |
|
|
230
|
+
|
|
231
|
+
<Callout type="info">
|
|
232
|
+
Step I/O is serialized using the [devalue](https://github.com/Rich-Harris/devalue) format. Use `hydrateResourceIO()` from `workflow/observability` to deserialize it for display. See [Observability Utilities](/docs/api-reference/workflow-api/world/observability).
|
|
233
|
+
</Callout>
|
|
234
|
+
|
|
235
|
+
<Callout type="warn">
|
|
236
|
+
`stepName` is a machine-readable identifier like `step//./src/workflows/order//processPayment`. Use `parseStepName()` from `workflow/observability` to extract the `shortName` for UI display.
|
|
237
|
+
</Callout>
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## world.hooks
|
|
242
|
+
|
|
243
|
+
Materialized from hook events. Hooks are pause points in workflows that wait for external input. Use this interface to look up hooks by ID or token, inspect metadata, and build UIs for pending approvals.
|
|
244
|
+
|
|
245
|
+
### hooks.get()
|
|
246
|
+
|
|
247
|
+
```typescript lineNumbers
|
|
248
|
+
const hook = await world.hooks.get(hookId); // [!code highlight]
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
| Parameter | Type | Description |
|
|
252
|
+
|-----------|------|-------------|
|
|
253
|
+
| `hookId` | `string` | The hook ID |
|
|
254
|
+
|
|
255
|
+
**Returns:** `Hook`
|
|
256
|
+
|
|
257
|
+
### hooks.getByToken()
|
|
258
|
+
|
|
259
|
+
Look up a hook by its token. Useful in webhook resume flows where you receive a token in the callback URL.
|
|
260
|
+
|
|
261
|
+
```typescript lineNumbers
|
|
262
|
+
const hook = await world.hooks.getByToken(token); // [!code highlight]
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
| Parameter | Type | Description |
|
|
266
|
+
|-----------|------|-------------|
|
|
267
|
+
| `token` | `string` | The hook token |
|
|
268
|
+
|
|
269
|
+
**Returns:** `Hook`
|
|
270
|
+
|
|
271
|
+
### hooks.list()
|
|
272
|
+
|
|
273
|
+
```typescript lineNumbers
|
|
274
|
+
const result = await world.hooks.list({ // [!code highlight]
|
|
275
|
+
pagination: { cursor },
|
|
276
|
+
}); // [!code highlight]
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
| Parameter | Type | Description |
|
|
280
|
+
|-----------|------|-------------|
|
|
281
|
+
| `params.pagination.cursor` | `string` | Cursor for the next page |
|
|
282
|
+
|
|
283
|
+
**Returns:** `{ data: Hook[], cursor?: string }`
|
|
284
|
+
|
|
285
|
+
### Hook Type
|
|
286
|
+
|
|
287
|
+
| Field | Type | Description |
|
|
288
|
+
|-------|------|-------------|
|
|
289
|
+
| `runId` | `string` | Parent workflow run ID |
|
|
290
|
+
| `hookId` | `string` | Unique hook identifier |
|
|
291
|
+
| `token` | `string` | Hook token for resuming |
|
|
292
|
+
| `ownerId` | `string` | Owner (team/user) ID |
|
|
293
|
+
| `projectId` | `string` | Project ID |
|
|
294
|
+
| `environment` | `string` | Deployment environment |
|
|
295
|
+
| `metadata` | `object` | Custom metadata attached to the hook |
|
|
296
|
+
| `isWebhook` | `boolean` | Whether this is a webhook-style hook |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Examples
|
|
301
|
+
|
|
302
|
+
### List Runs with Pagination
|
|
303
|
+
|
|
304
|
+
```typescript lineNumbers
|
|
305
|
+
import { getWorld } from "workflow/runtime";
|
|
306
|
+
|
|
307
|
+
const world = getWorld();
|
|
308
|
+
let cursor: string | undefined;
|
|
309
|
+
|
|
310
|
+
const runs = await world.runs.list({ // [!code highlight]
|
|
311
|
+
pagination: { cursor },
|
|
312
|
+
}); // [!code highlight]
|
|
313
|
+
|
|
314
|
+
cursor = runs.cursor; // pass to next call for pagination
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Get a Run — Full Data vs. Metadata Only
|
|
318
|
+
|
|
319
|
+
```typescript lineNumbers
|
|
320
|
+
import { getWorld } from "workflow/runtime";
|
|
321
|
+
|
|
322
|
+
const world = getWorld();
|
|
323
|
+
|
|
324
|
+
// Full data (default) — includes serialized input/output
|
|
325
|
+
const run = await world.runs.get(runId); // [!code highlight]
|
|
326
|
+
|
|
327
|
+
// Metadata only — lighter, no I/O loaded
|
|
328
|
+
const lightweight = await world.runs.get(runId, { // [!code highlight]
|
|
329
|
+
resolveData: "none", // [!code highlight]
|
|
330
|
+
}); // [!code highlight]
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### List Steps for a Progress Dashboard
|
|
334
|
+
|
|
335
|
+
```typescript lineNumbers
|
|
336
|
+
import { getWorld } from "workflow/runtime";
|
|
337
|
+
import { parseStepName } from "workflow/observability"; // [!code highlight]
|
|
338
|
+
|
|
339
|
+
const world = getWorld();
|
|
340
|
+
const steps = await world.steps.list({ // [!code highlight]
|
|
341
|
+
runId,
|
|
342
|
+
resolveData: "none",
|
|
343
|
+
}); // [!code highlight]
|
|
344
|
+
|
|
345
|
+
const progress = steps.data.map((step) => {
|
|
346
|
+
const parsed = parseStepName(step.stepName); // [!code highlight]
|
|
347
|
+
return {
|
|
348
|
+
stepId: step.stepId,
|
|
349
|
+
displayName: parsed?.shortName ?? step.stepName, // [!code highlight]
|
|
350
|
+
status: step.status,
|
|
351
|
+
};
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Hydrate Step I/O
|
|
356
|
+
|
|
357
|
+
```typescript lineNumbers
|
|
358
|
+
import { getWorld } from "workflow/runtime";
|
|
359
|
+
import { hydrateResourceIO, observabilityRevivers } from "workflow/observability"; // [!code highlight]
|
|
360
|
+
|
|
361
|
+
const world = getWorld();
|
|
362
|
+
const step = await world.steps.get(runId, stepId); // [!code highlight]
|
|
363
|
+
const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
|
|
364
|
+
console.log(hydrated.input, hydrated.output);
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Cancel a Run
|
|
368
|
+
|
|
369
|
+
```typescript lineNumbers
|
|
370
|
+
import { getWorld } from "workflow/runtime";
|
|
371
|
+
|
|
372
|
+
const world = getWorld();
|
|
373
|
+
await world.events.create(runId, { // [!code highlight]
|
|
374
|
+
eventType: "run_cancelled", // [!code highlight]
|
|
375
|
+
}); // [!code highlight]
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Look Up Hook by Token
|
|
379
|
+
|
|
380
|
+
```typescript lineNumbers
|
|
381
|
+
import { getWorld } from "workflow/runtime";
|
|
382
|
+
|
|
383
|
+
const world = getWorld();
|
|
384
|
+
const hook = await world.hooks.getByToken(token); // [!code highlight]
|
|
385
|
+
console.log(hook.runId, hook.metadata); // [!code highlight]
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### List Events for Audit Trail
|
|
389
|
+
|
|
390
|
+
```typescript lineNumbers
|
|
391
|
+
import { getWorld } from "workflow/runtime";
|
|
392
|
+
|
|
393
|
+
const world = getWorld();
|
|
394
|
+
const events = await world.events.list({ runId }); // [!code highlight]
|
|
395
|
+
|
|
396
|
+
for (const event of events.data) {
|
|
397
|
+
console.log(event.eventType, event.createdAt);
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## Related
|
|
402
|
+
|
|
403
|
+
- [Event Sourcing](/docs/how-it-works/event-sourcing) — How the event log powers workflow replay and state
|
|
404
|
+
- [getRun()](/docs/api-reference/workflow-api/get-run) — Higher-level API for working with individual runs
|
|
405
|
+
- [Observability Utilities](/docs/api-reference/workflow-api/world/observability) — Hydrate step I/O, parse display names, decrypt data
|
|
406
|
+
- [resumeHook()](/docs/api-reference/workflow-api/resume-hook) — Resume a workflow by sending a payload to a hook
|
|
407
|
+
- [Hooks](/docs/foundations/hooks) — Core concepts for hooks and pause points
|
|
408
|
+
- [Workflows and Steps](/docs/foundations/workflows-and-steps) — Core concepts for steps
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Streams
|
|
3
|
+
description: Read, write, and manage real-time data streams for workflow runs.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: "Methods: writeToStream(), writeToStreamMulti(), readFromStream(), closeStream(), listStreamsByRunId(), getStreamChunks(), getStreamInfo(). Stream methods live directly on the world object."
|
|
6
|
+
prerequisites:
|
|
7
|
+
- /docs/api-reference/workflow-api/get-world
|
|
8
|
+
related:
|
|
9
|
+
- /docs/foundations/streaming
|
|
10
|
+
- /docs/api-reference/workflow/get-writable
|
|
11
|
+
keywords:
|
|
12
|
+
- writeToStream
|
|
13
|
+
- writeToStreamMulti
|
|
14
|
+
- readFromStream
|
|
15
|
+
- closeStream
|
|
16
|
+
- listStreamsByRunId
|
|
17
|
+
- getStreamChunks
|
|
18
|
+
- getStreamInfo
|
|
19
|
+
- Streamer interface
|
|
20
|
+
- real-time streaming
|
|
21
|
+
- stream lifecycle
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
Stream methods live directly on the `world` object returned by `getWorld()`. Use them to write chunks, read streams, and manage stream lifecycle outside of the standard `getWritable()` pattern.
|
|
25
|
+
|
|
26
|
+
<Callout type="info">
|
|
27
|
+
For most streaming use cases, use [`getWritable()`](/docs/api-reference/workflow/get-writable) inside steps. Direct stream methods are for advanced scenarios like building custom stream consumers or managing streams from outside a workflow.
|
|
28
|
+
</Callout>
|
|
29
|
+
|
|
30
|
+
## Import
|
|
31
|
+
|
|
32
|
+
```typescript lineNumbers
|
|
33
|
+
import { getWorld } from "workflow/runtime";
|
|
34
|
+
|
|
35
|
+
const world = getWorld(); // [!code highlight]
|
|
36
|
+
// Stream methods are called directly on world — e.g. world.writeToStream()
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Methods
|
|
40
|
+
|
|
41
|
+
### writeToStream()
|
|
42
|
+
|
|
43
|
+
Write a data chunk to a named stream.
|
|
44
|
+
|
|
45
|
+
```typescript lineNumbers
|
|
46
|
+
await world.writeToStream("default", runId, chunk); // [!code highlight]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Parameters:**
|
|
50
|
+
|
|
51
|
+
| Parameter | Type | Description |
|
|
52
|
+
|-----------|------|-------------|
|
|
53
|
+
| `name` | `string` | The stream name |
|
|
54
|
+
| `runId` | `string` | The workflow run ID |
|
|
55
|
+
| `chunk` | `string \| Uint8Array` | Data to write |
|
|
56
|
+
|
|
57
|
+
### writeToStreamMulti()
|
|
58
|
+
|
|
59
|
+
Write multiple chunks in a single operation. Optional optimization — not all World implementations support it. Falls back to sequential `writeToStream()` calls if unavailable.
|
|
60
|
+
|
|
61
|
+
```typescript lineNumbers
|
|
62
|
+
await world.writeToStreamMulti?.("default", runId, [chunk1, chunk2]); // [!code highlight]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Parameters:**
|
|
66
|
+
|
|
67
|
+
| Parameter | Type | Description |
|
|
68
|
+
|-----------|------|-------------|
|
|
69
|
+
| `name` | `string` | The stream name |
|
|
70
|
+
| `runId` | `string` | The workflow run ID |
|
|
71
|
+
| `chunks` | `(string \| Uint8Array)[]` | Chunks to write, in order |
|
|
72
|
+
|
|
73
|
+
### readFromStream()
|
|
74
|
+
|
|
75
|
+
Read data from a named stream as a live `ReadableStream` that waits for new chunks in real time.
|
|
76
|
+
|
|
77
|
+
```typescript lineNumbers
|
|
78
|
+
const readable = await world.readFromStream("default"); // [!code highlight]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Parameters:**
|
|
82
|
+
|
|
83
|
+
| Parameter | Type | Description |
|
|
84
|
+
|-----------|------|-------------|
|
|
85
|
+
| `name` | `string` | The stream name |
|
|
86
|
+
| `startIndex` | `number` | Optional. Positive values skip chunks from the start (0-based). Negative values read from the tail (e.g. `-3` starts 3 chunks from the end). Clamped to 0. |
|
|
87
|
+
|
|
88
|
+
**Returns:** `ReadableStream<Uint8Array>`
|
|
89
|
+
|
|
90
|
+
### closeStream()
|
|
91
|
+
|
|
92
|
+
Close a stream when done writing.
|
|
93
|
+
|
|
94
|
+
```typescript lineNumbers
|
|
95
|
+
await world.closeStream("default", runId); // [!code highlight]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Parameters:**
|
|
99
|
+
|
|
100
|
+
| Parameter | Type | Description |
|
|
101
|
+
|-----------|------|-------------|
|
|
102
|
+
| `name` | `string` | The stream name |
|
|
103
|
+
| `runId` | `string` | The workflow run ID |
|
|
104
|
+
|
|
105
|
+
### listStreamsByRunId()
|
|
106
|
+
|
|
107
|
+
List all stream names associated with a workflow run.
|
|
108
|
+
|
|
109
|
+
```typescript lineNumbers
|
|
110
|
+
const streamNames = await world.listStreamsByRunId(runId); // [!code highlight]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Parameters:**
|
|
114
|
+
|
|
115
|
+
| Parameter | Type | Description |
|
|
116
|
+
|-----------|------|-------------|
|
|
117
|
+
| `runId` | `string` | The workflow run ID |
|
|
118
|
+
|
|
119
|
+
**Returns:** `string[]`
|
|
120
|
+
|
|
121
|
+
### getStreamChunks()
|
|
122
|
+
|
|
123
|
+
Fetch stream chunks with cursor-based pagination. Unlike `readFromStream()` (which returns a live `ReadableStream`), this returns a snapshot of currently available chunks.
|
|
124
|
+
|
|
125
|
+
```typescript lineNumbers
|
|
126
|
+
const result = await world.getStreamChunks("default", runId, { // [!code highlight]
|
|
127
|
+
limit: 50,
|
|
128
|
+
}); // [!code highlight]
|
|
129
|
+
// result.data: StreamChunk[], result.cursor, result.hasMore, result.done
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Parameters:**
|
|
133
|
+
|
|
134
|
+
| Parameter | Type | Description |
|
|
135
|
+
|-----------|------|-------------|
|
|
136
|
+
| `name` | `string` | The stream name |
|
|
137
|
+
| `runId` | `string` | The workflow run ID |
|
|
138
|
+
| `options.limit` | `number` | Max chunks per page (default: 100, max: 1000) |
|
|
139
|
+
| `options.cursor` | `string` | Cursor from a previous response |
|
|
140
|
+
|
|
141
|
+
**Returns:** `StreamChunksResponse`
|
|
142
|
+
|
|
143
|
+
| Field | Type | Description |
|
|
144
|
+
|-------|------|-------------|
|
|
145
|
+
| `data` | `StreamChunk[]` | Chunks in index order. Each has `index` (0-based) and `data` (`Uint8Array`). |
|
|
146
|
+
| `cursor` | `string \| null` | Cursor for the next page |
|
|
147
|
+
| `hasMore` | `boolean` | Whether more pages of already-written chunks exist |
|
|
148
|
+
| `done` | `boolean` | Whether the stream is fully closed. When `false`, new chunks may appear in future requests even after `hasMore` is `false`. |
|
|
149
|
+
|
|
150
|
+
### getStreamInfo()
|
|
151
|
+
|
|
152
|
+
Retrieve lightweight metadata about a stream without fetching chunks.
|
|
153
|
+
|
|
154
|
+
```typescript lineNumbers
|
|
155
|
+
const info = await world.getStreamInfo("default", runId); // [!code highlight]
|
|
156
|
+
// info.tailIndex: last chunk index (-1 if empty), info.done: whether stream is closed
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Parameters:**
|
|
160
|
+
|
|
161
|
+
| Parameter | Type | Description |
|
|
162
|
+
|-----------|------|-------------|
|
|
163
|
+
| `name` | `string` | The stream name |
|
|
164
|
+
| `runId` | `string` | The workflow run ID |
|
|
165
|
+
|
|
166
|
+
**Returns:** `StreamInfoResponse`
|
|
167
|
+
|
|
168
|
+
| Field | Type | Description |
|
|
169
|
+
|-------|------|-------------|
|
|
170
|
+
| `tailIndex` | `number` | Index of the last known chunk (0-based). `-1` when no chunks have been written. |
|
|
171
|
+
| `done` | `boolean` | Whether the stream is fully complete (closed). |
|
|
172
|
+
|
|
173
|
+
## Examples
|
|
174
|
+
|
|
175
|
+
### Read a Stream as a Response
|
|
176
|
+
|
|
177
|
+
```typescript lineNumbers
|
|
178
|
+
// app/api/workflow-streams/read/route.ts
|
|
179
|
+
import { getWorld } from "workflow/runtime";
|
|
180
|
+
|
|
181
|
+
export async function GET(req: Request) {
|
|
182
|
+
const url = new URL(req.url);
|
|
183
|
+
const streamName = url.searchParams.get("name") ?? "default";
|
|
184
|
+
const world = getWorld();
|
|
185
|
+
const readable = await world.readFromStream(streamName); // [!code highlight]
|
|
186
|
+
|
|
187
|
+
return new Response(readable, {
|
|
188
|
+
headers: { "Content-Type": "application/octet-stream" },
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Paginate Through Stream Chunks
|
|
194
|
+
|
|
195
|
+
```typescript lineNumbers
|
|
196
|
+
import { getWorld } from "workflow/runtime";
|
|
197
|
+
|
|
198
|
+
const world = getWorld();
|
|
199
|
+
let cursor: string | undefined;
|
|
200
|
+
|
|
201
|
+
do {
|
|
202
|
+
const result = await world.getStreamChunks("default", runId, { cursor }); // [!code highlight]
|
|
203
|
+
for (const chunk of result.data) {
|
|
204
|
+
console.log(`Chunk ${chunk.index}:`, chunk.data);
|
|
205
|
+
}
|
|
206
|
+
cursor = result.cursor ?? undefined;
|
|
207
|
+
} while (cursor);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Related
|
|
211
|
+
|
|
212
|
+
- [Streaming](/docs/foundations/streaming) — Core concepts for streaming data from workflows
|
|
213
|
+
- [getWritable()](/docs/api-reference/workflow/get-writable) — The standard way to write to streams from within steps
|
|
214
|
+
- [Storage](/docs/api-reference/workflow-api/world/storage) — Query runs, steps, hooks, and events
|
|
@@ -221,6 +221,10 @@ While hooks are powerful, they require you to manually handle HTTP requests and
|
|
|
221
221
|
|
|
222
222
|
When using Workflow SDK, webhooks are automatically wired up at `/.well-known/workflow/v1/webhook/:token` without any additional setup.
|
|
223
223
|
|
|
224
|
+
<Callout type="warn">
|
|
225
|
+
`createWebhook()` exposes a public route at `/.well-known/workflow/v1/webhook/:token`, and the token in that URL is the only authorization performed for incoming requests. This is convenient for prototypes and a simple developer experience because you can share the webhook URL (endpoint) without 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.
|
|
226
|
+
</Callout>
|
|
227
|
+
|
|
224
228
|
<Callout type="info">
|
|
225
229
|
See the full API reference for [`createWebhook()`](/docs/api-reference/workflow/create-webhook) for all available options.
|
|
226
230
|
</Callout>
|
|
@@ -190,7 +190,7 @@ async function doublePoint(point: Point) {
|
|
|
190
190
|
### Requirements
|
|
191
191
|
|
|
192
192
|
<Callout type="warn">
|
|
193
|
-
|
|
193
|
+
`WORKFLOW_SERIALIZE` and `WORKFLOW_DESERIALIZE` must be implemented as **static** methods on the class. Defining them as instance methods is not supported.
|
|
194
194
|
</Callout>
|
|
195
195
|
|
|
196
196
|
- The data returned by `WORKFLOW_SERIALIZE` must itself be serializable (see [Supported Serializable Types](#supported-serializable-types))
|
|
@@ -205,9 +205,9 @@ The `WORKFLOW_SERIALIZE` and `WORKFLOW_DESERIALIZE` methods run inside the workf
|
|
|
205
205
|
Keep these methods simple and focused on data transformation only.
|
|
206
206
|
</Callout>
|
|
207
207
|
|
|
208
|
-
###
|
|
208
|
+
### Instance Methods as Steps
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
In practice, many classes have methods that need Node.js APIs, perform network calls, or interact with databases — operations that are not allowed in the `"use workflow"` execution context. You can make these methods workflow-compatible by adding `"use step"` to them. The SWC compiler will strip the method bodies from the workflow bundle and replace them with proxy functions that invoke the method as a step — with full Node.js runtime access. The `this` context (the class instance) is automatically serialized and deserialized across the workflow/step boundary.
|
|
211
211
|
|
|
212
212
|
This requires the class to implement `WORKFLOW_SERIALIZE` and `WORKFLOW_DESERIALIZE`, so that the instance can be passed to the step execution context.
|
|
213
213
|
|
|
@@ -593,6 +593,7 @@ Stream errors don't trigger automatic retries for the producer step. Design your
|
|
|
593
593
|
- [`sleep()` API Reference](/docs/api-reference/workflow/sleep) - Pause workflow execution for a duration
|
|
594
594
|
- [`start()` API Reference](/docs/api-reference/workflow-api/start) - Start workflows and access the `Run` object
|
|
595
595
|
- [`getRun()` API Reference](/docs/api-reference/workflow-api/get-run) - Retrieve runs and their streams later
|
|
596
|
+
- [world.streams](/docs/api-reference/workflow-api/world/streams) - Low-level stream read/write/close via World SDK
|
|
596
597
|
- [DurableAgent](/docs/api-reference/workflow-ai/durable-agent) - AI agents with built-in streaming support
|
|
597
598
|
- [Errors and Retries](/docs/foundations/errors-and-retries) - Understanding error handling and retry behavior
|
|
598
599
|
- [Serialization](/docs/foundations/serialization) - Understanding what data types can be passed in workflows
|
|
@@ -9,7 +9,7 @@ related:
|
|
|
9
9
|
- /docs/foundations/workflows-and-steps
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
This guide will walk through setting up your first workflow in an Astro app. Along the way, you'll learn more about the concepts that are fundamental to using the
|
|
12
|
+
This guide will walk through setting up your first workflow in an Astro app. Along the way, you'll learn more about the concepts that are fundamental to using the Workflow SDK in your own projects.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -9,7 +9,7 @@ related:
|
|
|
9
9
|
- /docs/foundations/workflows-and-steps
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
This guide will walk through setting up your first workflow in
|
|
12
|
+
This guide will walk through setting up your first workflow in an Express app. Along the way, you'll learn more about the concepts that are fundamental to using the Workflow SDK in your own projects.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -9,7 +9,7 @@ related:
|
|
|
9
9
|
- /docs/foundations/workflows-and-steps
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
This guide will walk through setting up your first workflow in a Fastify app. Along the way, you'll learn more about the concepts that are fundamental to using the
|
|
12
|
+
This guide will walk through setting up your first workflow in a Fastify app. Along the way, you'll learn more about the concepts that are fundamental to using the Workflow SDK in your own projects.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|