workflow 4.2.1 → 5.0.0-beta.1

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.
@@ -1,7 +1,5 @@
1
1
  export type { Event, StartOptions, StopSleepOptions, StopSleepResult, WorkflowReadableStreamOptions, WorkflowRun, } from '@workflow/core/runtime';
2
- export declare class Run {
3
- constructor();
4
- }
2
+ export { Run } from '@workflow/core/runtime/run';
5
3
  export declare const getRun: () => never;
6
4
  export declare const getHookByToken: () => never;
7
5
  export declare const resumeHook: () => never;
@@ -1 +1 @@
1
- {"version":3,"file":"api-workflow.d.ts","sourceRoot":"","sources":["../src/api-workflow.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,KAAK,EACL,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,6BAA6B,EAC7B,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAQhC,qBAAa,GAAG;;CAIf;AACD,eAAO,MAAM,MAAM,aAA+B,CAAC;AACnD,eAAO,MAAM,cAAc,aAAuC,CAAC;AACnE,eAAO,MAAM,UAAU,aAAmC,CAAC;AAC3D,eAAO,MAAM,aAAa,aAAsC,CAAC;AACjE,eAAO,MAAM,OAAO,aAAgC,CAAC;AACrD,eAAO,MAAM,KAAK,aAA8B,CAAC"}
1
+ {"version":3,"file":"api-workflow.d.ts","sourceRoot":"","sources":["../src/api-workflow.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,KAAK,EACL,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,6BAA6B,EAC7B,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,GAAG,EAAE,MAAM,4BAA4B,CAAC;AAQjD,eAAO,MAAM,MAAM,aAA+B,CAAC;AACnD,eAAO,MAAM,cAAc,aAAuC,CAAC;AACnE,eAAO,MAAM,UAAU,aAAmC,CAAC;AAC3D,eAAO,MAAM,aAAa,aAAsC,CAAC;AACjE,eAAO,MAAM,OAAO,aAAgC,CAAC;AACrD,eAAO,MAAM,KAAK,aAA8B,CAAC"}
@@ -1,15 +1,11 @@
1
+ export { Run } from '@workflow/core/runtime/run';
1
2
  const workflowStub = (item) => {
2
3
  throw new Error(`The workflow environment doesn't allow this runtime usage of ${item}. Move this call to a step function ("use step") or call it outside the workflow context.`);
3
4
  };
4
- export class Run {
5
- constructor() {
6
- workflowStub('Run');
7
- }
8
- }
9
5
  export const getRun = () => workflowStub('getRun');
10
6
  export const getHookByToken = () => workflowStub('getHookByToken');
11
7
  export const resumeHook = () => workflowStub('resumeHook');
12
8
  export const resumeWebhook = () => workflowStub('resumeWebhook');
13
9
  export const runStep = () => workflowStub('runStep');
14
10
  export const start = () => workflowStub('start');
15
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLXdvcmtmbG93LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2FwaS13b3JrZmxvdy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFTQSxNQUFNLFlBQVksR0FBRyxDQUFDLElBQVksRUFBRSxFQUFFO0lBQ3BDLE1BQU0sSUFBSSxLQUFLLENBQ2IsZ0VBQWdFLElBQUksMkZBQTJGLENBQ2hLLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRixNQUFNLE9BQU8sR0FBRztJQUNkO1FBQ0UsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RCLENBQUM7Q0FDRjtBQUNELE1BQU0sQ0FBQyxNQUFNLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDbkQsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBQ25FLE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUFDLENBQUM7QUFDM0QsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUNqRSxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQ3JELE1BQU0sQ0FBQyxNQUFNLEtBQUssR0FBRyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMifQ==
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLXdvcmtmbG93LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2FwaS13b3JrZmxvdy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFTQSxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFakQsTUFBTSxZQUFZLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRTtJQUNwQyxNQUFNLElBQUksS0FBSyxDQUNiLGdFQUFnRSxJQUFJLDJGQUEyRixDQUNoSyxDQUFDO0FBQ0osQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUNuRCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFDbkUsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUMzRCxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBQ2pFLE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUM7QUFDckQsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyJ9
@@ -9,7 +9,7 @@
9
9
  * import { getWorld } from 'workflow/api';
10
10
  * import { hydrateResourceIO, observabilityRevivers } from 'workflow/observability';
11
11
  *
12
- * const world = getWorld();
12
+ * const world = await getWorld();
13
13
  * const step = await world.steps.get(runId, stepId, { resolveData: 'all' });
14
14
  * const hydrated = hydrateResourceIO(step, observabilityRevivers);
15
15
  * // hydrated.input and hydrated.output are now plain JS objects
@@ -9,7 +9,7 @@
9
9
  * import { getWorld } from 'workflow/api';
10
10
  * import { hydrateResourceIO, observabilityRevivers } from 'workflow/observability';
11
11
  *
12
- * const world = getWorld();
12
+ * const world = await getWorld();
13
13
  * const step = await world.steps.get(runId, stepId, { resolveData: 'all' });
14
14
  * const hydrated = hydrateResourceIO(step, observabilityRevivers);
15
15
  * // hydrated.input and hydrated.output are now plain JS objects
@@ -13,6 +13,7 @@ You may want to use this function when you need to:
13
13
 
14
14
  * Log workflow run IDs
15
15
  * Access timing information of a workflow
16
+ * Detect whether encryption is enabled for the current run
16
17
 
17
18
  <Callout>
18
19
  If you need to access step context, take a look at [`getStepMetadata`](/docs/api-reference/workflow/get-step-metadata).
@@ -29,6 +30,32 @@ async function testWorkflow() {
29
30
  }
30
31
  ```
31
32
 
33
+ ### Detecting Encryption
34
+
35
+ The `features` object indicates which capabilities are active for the current run. Library authors can use `features.encryption` to control whether sensitive data is included in step return values, which are serialized to the event log:
36
+
37
+ ```typescript lineNumbers
38
+ import { getWorkflowMetadata } from "workflow"
39
+
40
+ declare function getUserProfile(userId: string): Promise<{ name: string; ssn: string }>; // @setup
41
+
42
+ async function fetchUserProfile(userId: string) {
43
+ "use step"
44
+
45
+ const { features } = getWorkflowMetadata() // [!code highlight]
46
+ const profile = await getUserProfile(userId)
47
+
48
+ if (!features.encryption) { // [!code highlight]
49
+ // Omit sensitive fields from the return value,
50
+ // since it will be stored unencrypted in the event log
51
+ const { ssn, ...safe } = profile
52
+ return safe
53
+ }
54
+
55
+ return profile
56
+ }
57
+ ```
58
+
32
59
  ## API Signature
33
60
 
34
61
  ### Parameters
@@ -1,20 +1,20 @@
1
1
  ---
2
2
  title: getWorld
3
- description: Access the World instance for low-level storage, queuing, and streaming operations.
3
+ description: Async function that resolves the World instance for low-level storage, queuing, and streaming operations.
4
4
  type: reference
5
- summary: Use getWorld to access low-level workflow storage, queuing, and streaming backends directly.
5
+ summary: Async function that resolves the World instance for low-level workflow storage, queuing, and streaming backends.
6
6
  prerequisites:
7
7
  - /docs/deploying
8
8
  ---
9
9
 
10
- Retrieves the World instance for direct access to workflow storage, queuing, and streaming backends. This function returns a `World` which provides low-level access to manage workflow runs, steps, events, and hooks.
10
+ Retrieves the World instance for direct access to workflow storage, queuing, and streaming backends. This async function returns a `Promise<World>` which provides low-level access to manage workflow runs, steps, events, and hooks.
11
11
 
12
12
  Use this function when you need direct access to the underlying workflow infrastructure, such as listing all runs, querying events, or implementing custom workflow management logic.
13
13
 
14
14
  ```typescript lineNumbers
15
15
  import { getWorld } from "workflow/runtime";
16
16
 
17
- const world = getWorld(); // [!code highlight]
17
+ const world = await getWorld(); // [!code highlight]
18
18
  ```
19
19
 
20
20
  ## API Signature
@@ -25,7 +25,7 @@ This function does not accept any parameters.
25
25
 
26
26
  ### Returns
27
27
 
28
- Returns a `World` object:
28
+ Returns a `Promise<World>` object:
29
29
 
30
30
  <TSDoc
31
31
  definition={`
@@ -79,7 +79,7 @@ export async function GET(req: Request) {
79
79
  const cursor = url.searchParams.get("cursor") ?? undefined;
80
80
 
81
81
  try {
82
- const world = getWorld(); // [!code highlight]
82
+ const world = await getWorld(); // [!code highlight]
83
83
  const runs = await world.runs.list({
84
84
  pagination: { cursor },
85
85
  resolveData: "none",
@@ -28,7 +28,7 @@ The API package is for access and introspection of workflow data to inspect runs
28
28
  Get workflow run status and metadata without waiting for completion.
29
29
  </Card>
30
30
  <Card href="/docs/api-reference/workflow-api/get-world" title="getWorld()">
31
- Get direct access to workflow storage, queuing, and streaming backends.
31
+ Async: resolve the World instance for storage, queuing, and streaming backends.
32
32
  </Card>
33
33
  <Card href="/docs/api-reference/workflow-api/world" title="World SDK">
34
34
  Low-level API for inspecting runs, steps, events, hooks, streams, and queues.
@@ -2,7 +2,7 @@
2
2
  title: World SDK
3
3
  description: Low-level API for inspecting and managing workflow runs, steps, events, hooks, streams, and queues.
4
4
  type: overview
5
- summary: Access workflow infrastructure directly via getWorld() for building observability dashboards, admin tools, and custom integrations.
5
+ summary: Access workflow infrastructure via await getWorld() for building observability dashboards, admin tools, and custom integrations.
6
6
  prerequisites:
7
7
  - /docs/api-reference/workflow-api/get-world
8
8
  keywords:
@@ -19,7 +19,7 @@ The World SDK provides direct access to workflow infrastructure — runs, steps,
19
19
  ```typescript lineNumbers
20
20
  import { getWorld } from "workflow/runtime";
21
21
 
22
- const world = getWorld(); // [!code highlight]
22
+ const world = await getWorld(); // [!code highlight]
23
23
  ```
24
24
 
25
25
  ## Interfaces
@@ -147,7 +147,7 @@ const hydrated = hydrateResourceIOWithKey(step, key); // [!code highlight]
147
147
  import { getWorld } from "workflow/runtime";
148
148
  import { parseStepName, parseWorkflowName } from "workflow/observability"; // [!code highlight]
149
149
 
150
- const world = getWorld();
150
+ const world = await getWorld();
151
151
  const run = await world.runs.get(runId, { resolveData: "none" });
152
152
  console.log("Workflow:", parseWorkflowName(run.workflowName)?.shortName); // [!code highlight]
153
153
 
@@ -28,7 +28,7 @@ Queue methods live directly on the `world` object (not nested). They dispatch in
28
28
  ```typescript lineNumbers
29
29
  import { getWorld } from "workflow/runtime";
30
30
 
31
- const world = getWorld(); // [!code highlight]
31
+ const world = await getWorld(); // [!code highlight]
32
32
  // Queue methods are called directly on world — e.g. world.queue()
33
33
  ```
34
34
 
@@ -37,7 +37,7 @@ The World storage interface exposes four sub-interfaces for querying workflow da
37
37
  ```typescript lineNumbers
38
38
  import { getWorld } from "workflow/runtime";
39
39
 
40
- const world = getWorld(); // [!code highlight]
40
+ const world = await getWorld(); // [!code highlight]
41
41
  ```
42
42
 
43
43
  ---
@@ -304,7 +304,7 @@ const result = await world.hooks.list({ // [!code highlight]
304
304
  ```typescript lineNumbers
305
305
  import { getWorld } from "workflow/runtime";
306
306
 
307
- const world = getWorld();
307
+ const world = await getWorld();
308
308
  let cursor: string | undefined;
309
309
 
310
310
  const runs = await world.runs.list({ // [!code highlight]
@@ -319,7 +319,7 @@ cursor = runs.cursor; // pass to next call for pagination
319
319
  ```typescript lineNumbers
320
320
  import { getWorld } from "workflow/runtime";
321
321
 
322
- const world = getWorld();
322
+ const world = await getWorld();
323
323
 
324
324
  // Full data (default) — includes serialized input/output
325
325
  const run = await world.runs.get(runId); // [!code highlight]
@@ -336,7 +336,7 @@ const lightweight = await world.runs.get(runId, { // [!code highlight]
336
336
  import { getWorld } from "workflow/runtime";
337
337
  import { parseStepName } from "workflow/observability"; // [!code highlight]
338
338
 
339
- const world = getWorld();
339
+ const world = await getWorld();
340
340
  const steps = await world.steps.list({ // [!code highlight]
341
341
  runId,
342
342
  resolveData: "none",
@@ -358,7 +358,7 @@ const progress = steps.data.map((step) => {
358
358
  import { getWorld } from "workflow/runtime";
359
359
  import { hydrateResourceIO, observabilityRevivers } from "workflow/observability"; // [!code highlight]
360
360
 
361
- const world = getWorld();
361
+ const world = await getWorld();
362
362
  const step = await world.steps.get(runId, stepId); // [!code highlight]
363
363
  const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
364
364
  console.log(hydrated.input, hydrated.output);
@@ -369,7 +369,7 @@ console.log(hydrated.input, hydrated.output);
369
369
  ```typescript lineNumbers
370
370
  import { getWorld } from "workflow/runtime";
371
371
 
372
- const world = getWorld();
372
+ const world = await getWorld();
373
373
  await world.events.create(runId, { // [!code highlight]
374
374
  eventType: "run_cancelled", // [!code highlight]
375
375
  }); // [!code highlight]
@@ -380,7 +380,7 @@ await world.events.create(runId, { // [!code highlight]
380
380
  ```typescript lineNumbers
381
381
  import { getWorld } from "workflow/runtime";
382
382
 
383
- const world = getWorld();
383
+ const world = await getWorld();
384
384
  const hook = await world.hooks.getByToken(token); // [!code highlight]
385
385
  console.log(hook.runId, hook.metadata); // [!code highlight]
386
386
  ```
@@ -390,7 +390,7 @@ console.log(hook.runId, hook.metadata); // [!code highlight]
390
390
  ```typescript lineNumbers
391
391
  import { getWorld } from "workflow/runtime";
392
392
 
393
- const world = getWorld();
393
+ const world = await getWorld();
394
394
  const events = await world.events.list({ runId }); // [!code highlight]
395
395
 
396
396
  for (const event of events.data) {
@@ -2,26 +2,26 @@
2
2
  title: Streams
3
3
  description: Read, write, and manage real-time data streams for workflow runs.
4
4
  type: reference
5
- summary: "Methods: writeToStream(), writeToStreamMulti(), readFromStream(), closeStream(), listStreamsByRunId(), getStreamChunks(), getStreamInfo(). Stream methods live directly on the world object."
5
+ summary: "Methods: streams.write(), streams.writeMulti(), streams.get(), streams.close(), streams.list(), streams.getChunks(), streams.getInfo(). Stream methods live on world.streams."
6
6
  prerequisites:
7
7
  - /docs/api-reference/workflow-api/get-world
8
8
  related:
9
9
  - /docs/foundations/streaming
10
10
  - /docs/api-reference/workflow/get-writable
11
11
  keywords:
12
- - writeToStream
13
- - writeToStreamMulti
14
- - readFromStream
15
- - closeStream
16
- - listStreamsByRunId
17
- - getStreamChunks
18
- - getStreamInfo
12
+ - streams.write
13
+ - streams.writeMulti
14
+ - streams.get
15
+ - streams.close
16
+ - streams.list
17
+ - streams.getChunks
18
+ - streams.getInfo
19
19
  - Streamer interface
20
20
  - real-time streaming
21
21
  - stream lifecycle
22
22
  ---
23
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.
24
+ Stream methods live on `world.streams` (the `streams` sub-object of the `World` instance returned by `await getWorld()`). Use them to write chunks, read streams, and manage stream lifecycle outside of the standard `getWritable()` pattern.
25
25
 
26
26
  <Callout type="info">
27
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.
@@ -32,82 +32,83 @@ Stream methods live directly on the `world` object returned by `getWorld()`. Use
32
32
  ```typescript lineNumbers
33
33
  import { getWorld } from "workflow/runtime";
34
34
 
35
- const world = getWorld(); // [!code highlight]
36
- // Stream methods are called directly on world — e.g. world.writeToStream()
35
+ const world = await getWorld(); // [!code highlight]
36
+ // Stream methods are called on world.streams — e.g. world.streams.write()
37
37
  ```
38
38
 
39
39
  ## Methods
40
40
 
41
- ### writeToStream()
41
+ ### write()
42
42
 
43
43
  Write a data chunk to a named stream.
44
44
 
45
45
  ```typescript lineNumbers
46
- await world.writeToStream("default", runId, chunk); // [!code highlight]
46
+ await world.streams.write(runId, "default", chunk); // [!code highlight]
47
47
  ```
48
48
 
49
49
  **Parameters:**
50
50
 
51
51
  | Parameter | Type | Description |
52
52
  |-----------|------|-------------|
53
- | `name` | `string` | The stream name |
54
53
  | `runId` | `string` | The workflow run ID |
54
+ | `name` | `string` | The stream name |
55
55
  | `chunk` | `string \| Uint8Array` | Data to write |
56
56
 
57
- ### writeToStreamMulti()
57
+ ### writeMulti()
58
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.
59
+ Write multiple chunks in a single operation. Optional optimization — not all World implementations support it. Falls back to sequential `write()` calls if unavailable.
60
60
 
61
61
  ```typescript lineNumbers
62
- await world.writeToStreamMulti?.("default", runId, [chunk1, chunk2]); // [!code highlight]
62
+ await world.streams.writeMulti?.(runId, "default", [chunk1, chunk2]); // [!code highlight]
63
63
  ```
64
64
 
65
65
  **Parameters:**
66
66
 
67
67
  | Parameter | Type | Description |
68
68
  |-----------|------|-------------|
69
- | `name` | `string` | The stream name |
70
69
  | `runId` | `string` | The workflow run ID |
70
+ | `name` | `string` | The stream name |
71
71
  | `chunks` | `(string \| Uint8Array)[]` | Chunks to write, in order |
72
72
 
73
- ### readFromStream()
73
+ ### get()
74
74
 
75
75
  Read data from a named stream as a live `ReadableStream` that waits for new chunks in real time.
76
76
 
77
77
  ```typescript lineNumbers
78
- const readable = await world.readFromStream("default"); // [!code highlight]
78
+ const readable = await world.streams.get(runId, "default"); // [!code highlight]
79
79
  ```
80
80
 
81
81
  **Parameters:**
82
82
 
83
83
  | Parameter | Type | Description |
84
84
  |-----------|------|-------------|
85
+ | `runId` | `string` | The workflow run ID |
85
86
  | `name` | `string` | The stream name |
86
87
  | `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
 
88
89
  **Returns:** `ReadableStream<Uint8Array>`
89
90
 
90
- ### closeStream()
91
+ ### close()
91
92
 
92
93
  Close a stream when done writing.
93
94
 
94
95
  ```typescript lineNumbers
95
- await world.closeStream("default", runId); // [!code highlight]
96
+ await world.streams.close(runId, "default"); // [!code highlight]
96
97
  ```
97
98
 
98
99
  **Parameters:**
99
100
 
100
101
  | Parameter | Type | Description |
101
102
  |-----------|------|-------------|
102
- | `name` | `string` | The stream name |
103
103
  | `runId` | `string` | The workflow run ID |
104
+ | `name` | `string` | The stream name |
104
105
 
105
- ### listStreamsByRunId()
106
+ ### list()
106
107
 
107
108
  List all stream names associated with a workflow run.
108
109
 
109
110
  ```typescript lineNumbers
110
- const streamNames = await world.listStreamsByRunId(runId); // [!code highlight]
111
+ const streamNames = await world.streams.list(runId); // [!code highlight]
111
112
  ```
112
113
 
113
114
  **Parameters:**
@@ -118,12 +119,12 @@ const streamNames = await world.listStreamsByRunId(runId); // [!code highlight]
118
119
 
119
120
  **Returns:** `string[]`
120
121
 
121
- ### getStreamChunks()
122
+ ### getChunks()
122
123
 
123
- Fetch stream chunks with cursor-based pagination. Unlike `readFromStream()` (which returns a live `ReadableStream`), this returns a snapshot of currently available chunks.
124
+ Fetch stream chunks with cursor-based pagination. Unlike `get()` (which returns a live `ReadableStream`), this returns a snapshot of currently available chunks.
124
125
 
125
126
  ```typescript lineNumbers
126
- const result = await world.getStreamChunks("default", runId, { // [!code highlight]
127
+ const result = await world.streams.getChunks(runId, "default", { // [!code highlight]
127
128
  limit: 50,
128
129
  }); // [!code highlight]
129
130
  // result.data: StreamChunk[], result.cursor, result.hasMore, result.done
@@ -133,8 +134,8 @@ const result = await world.getStreamChunks("default", runId, { // [!code highlig
133
134
 
134
135
  | Parameter | Type | Description |
135
136
  |-----------|------|-------------|
136
- | `name` | `string` | The stream name |
137
137
  | `runId` | `string` | The workflow run ID |
138
+ | `name` | `string` | The stream name |
138
139
  | `options.limit` | `number` | Max chunks per page (default: 100, max: 1000) |
139
140
  | `options.cursor` | `string` | Cursor from a previous response |
140
141
 
@@ -147,12 +148,12 @@ const result = await world.getStreamChunks("default", runId, { // [!code highlig
147
148
  | `hasMore` | `boolean` | Whether more pages of already-written chunks exist |
148
149
  | `done` | `boolean` | Whether the stream is fully closed. When `false`, new chunks may appear in future requests even after `hasMore` is `false`. |
149
150
 
150
- ### getStreamInfo()
151
+ ### getInfo()
151
152
 
152
153
  Retrieve lightweight metadata about a stream without fetching chunks.
153
154
 
154
155
  ```typescript lineNumbers
155
- const info = await world.getStreamInfo("default", runId); // [!code highlight]
156
+ const info = await world.streams.getInfo(runId, "default"); // [!code highlight]
156
157
  // info.tailIndex: last chunk index (-1 if empty), info.done: whether stream is closed
157
158
  ```
158
159
 
@@ -160,8 +161,8 @@ const info = await world.getStreamInfo("default", runId); // [!code highlight]
160
161
 
161
162
  | Parameter | Type | Description |
162
163
  |-----------|------|-------------|
163
- | `name` | `string` | The stream name |
164
164
  | `runId` | `string` | The workflow run ID |
165
+ | `name` | `string` | The stream name |
165
166
 
166
167
  **Returns:** `StreamInfoResponse`
167
168
 
@@ -181,8 +182,9 @@ import { getWorld } from "workflow/runtime";
181
182
  export async function GET(req: Request) {
182
183
  const url = new URL(req.url);
183
184
  const streamName = url.searchParams.get("name") ?? "default";
184
- const world = getWorld();
185
- const readable = await world.readFromStream(streamName); // [!code highlight]
185
+ const runId = url.searchParams.get("runId")!;
186
+ const world = await getWorld();
187
+ const readable = await world.streams.get(runId, streamName); // [!code highlight]
186
188
 
187
189
  return new Response(readable, {
188
190
  headers: { "Content-Type": "application/octet-stream" },
@@ -195,11 +197,11 @@ export async function GET(req: Request) {
195
197
  ```typescript lineNumbers
196
198
  import { getWorld } from "workflow/runtime";
197
199
 
198
- const world = getWorld();
200
+ const world = await getWorld();
199
201
  let cursor: string | undefined;
200
202
 
201
203
  do {
202
- const result = await world.getStreamChunks("default", runId, { cursor }); // [!code highlight]
204
+ const result = await world.streams.getChunks(runId, "default", { cursor }); // [!code highlight]
203
205
  for (const chunk of result.data) {
204
206
  console.log(`Chunk ${chunk.index}:`, chunk.data);
205
207
  }
@@ -166,54 +166,56 @@ The Streamer interface enables real-time data streaming:
166
166
  {/* @skip-typecheck - interface definition, not runnable code */}
167
167
  ```typescript
168
168
  interface Streamer {
169
- writeToStream(
170
- name: string,
171
- runId: string,
172
- chunk: string | Uint8Array
173
- ): Promise<void>;
174
-
175
- writeToStreamMulti?(
176
- name: string,
177
- runId: string,
178
- chunks: (string | Uint8Array)[]
179
- ): Promise<void>;
180
-
181
- closeStream(
182
- name: string,
183
- runId: string
184
- ): Promise<void>;
185
-
186
- readFromStream(
187
- name: string,
188
- startIndex?: number
189
- ): Promise<ReadableStream<Uint8Array>>;
190
-
191
- listStreamsByRunId(runId: string): Promise<string[]>;
192
-
193
- /** Paginated snapshot of stream chunks. */
194
- getStreamChunks(
195
- name: string,
196
- runId: string,
197
- options?: { limit?: number; cursor?: string }
198
- ): Promise<{
199
- data: { index: number; data: Uint8Array }[];
200
- cursor: string | null;
201
- hasMore: boolean;
202
- done: boolean;
203
- }>;
204
-
205
- /** Lightweight metadata: tail index and completion flag. */
206
- getStreamInfo(
207
- name: string,
208
- runId: string
209
- ): Promise<{ tailIndex: number; done: boolean }>;
169
+ streamFlushIntervalMs?: number;
170
+
171
+ streams: {
172
+ write(
173
+ runId: string,
174
+ name: string,
175
+ chunk: string | Uint8Array
176
+ ): Promise<void>;
177
+
178
+ writeMulti?(
179
+ runId: string,
180
+ name: string,
181
+ chunks: (string | Uint8Array)[]
182
+ ): Promise<void>;
183
+
184
+ close(runId: string, name: string): Promise<void>;
185
+
186
+ get(
187
+ runId: string,
188
+ name: string,
189
+ startIndex?: number
190
+ ): Promise<ReadableStream<Uint8Array>>;
191
+
192
+ list(runId: string): Promise<string[]>;
193
+
194
+ /** Paginated snapshot of stream chunks. */
195
+ getChunks(
196
+ runId: string,
197
+ name: string,
198
+ options?: { limit?: number; cursor?: string }
199
+ ): Promise<{
200
+ data: { index: number; data: Uint8Array }[];
201
+ cursor: string | null;
202
+ hasMore: boolean;
203
+ done: boolean;
204
+ }>;
205
+
206
+ /** Lightweight metadata: tail index and completion flag. */
207
+ getInfo(
208
+ runId: string,
209
+ name: string
210
+ ): Promise<{ tailIndex: number; done: boolean }>;
211
+ };
210
212
  }
211
213
  ```
212
214
 
213
215
  Streams are identified by a combination of `runId` and `name`. Each workflow run can have multiple named streams.
214
- `writeToStreamMulti()` is an optional optimization for batching multiple writes.
216
+ `writeMulti()` is an optional optimization for batching multiple writes.
215
217
 
216
- `getStreamChunks` returns a paginated snapshot of currently available chunks (unlike `readFromStream` which returns a live `ReadableStream` that waits for new chunks). `getStreamInfo` returns the tail index (last chunk index, 0-based, or `-1` when empty) and whether the stream is complete — useful for resolving negative `startIndex` values into absolute positions.
218
+ `getChunks` returns a paginated snapshot of currently available chunks (unlike `get` which returns a live `ReadableStream` that waits for new chunks). `getInfo` returns the tail index (last chunk index, 0-based, or `-1` when empty) and whether the stream is complete — useful for resolving negative `startIndex` values into absolute positions.
217
219
 
218
220
  ## Reference Implementations
219
221
 
@@ -53,7 +53,8 @@ Create an `instrumentation.ts` file in your project root:
53
53
  export async function register() {
54
54
  if (process.env.NEXT_RUNTIME !== "edge") {
55
55
  const { getWorld } = await import("workflow/runtime");
56
- await getWorld().start?.();
56
+ const world = await getWorld();
57
+ await world.start?.();
57
58
  }
58
59
  }
59
60
  ```
@@ -73,7 +74,8 @@ import type { ServerInit } from "@sveltejs/kit";
73
74
 
74
75
  export const init: ServerInit = async () => {
75
76
  const { getWorld } = await import("workflow/runtime");
76
- await getWorld().start?.();
77
+ const world = await getWorld();
78
+ await world.start?.();
77
79
  };
78
80
  ```
79
81
 
@@ -92,7 +94,8 @@ import { defineNitroPlugin } from "nitro/~internal/runtime/plugin";
92
94
 
93
95
  export default defineNitroPlugin(async () => {
94
96
  const { getWorld } = await import("workflow/runtime");
95
- await getWorld().start?.();
97
+ const world = await getWorld();
98
+ await world.start?.();
96
99
  });
97
100
  ```
98
101
 
@@ -168,7 +171,8 @@ For higher worker concurrency, Graphile Worker recommends setting `maxPoolSize`
168
171
 
169
172
  ### Programmatic configuration
170
173
 
171
- {/* @skip-typecheck: incomplete code sample */}
174
+ {/*@skip-typecheck: incomplete code sample*/}
175
+
172
176
  ```typescript title="workflow.config.ts" lineNumbers
173
177
  import { createWorld } from "@workflow/world-postgres";
174
178
 
@@ -200,6 +204,7 @@ Deploy your application to any cloud that supports long-running servers:
200
204
  - Platform-as-a-Service providers (Railway, Render, Fly.io, etc.)
201
205
 
202
206
  Ensure your deployment has:
207
+
203
208
  1. Network access to your PostgreSQL database
204
209
  2. Environment variables configured correctly
205
210
  3. The `start()` function called on server initialization
@@ -275,12 +275,36 @@ Build error occurred
275
275
  Error: Cannot find module 'next/dist/lib/server-external-packages.json'
276
276
  ```
277
277
 
278
- Upgrade to `workflow@4.2.0` or later:
278
+ Upgrade to `workflow@4.0.1-beta.26` or later:
279
279
 
280
280
  ```package-install
281
281
  workflow@latest
282
282
  ```
283
283
 
284
+ ### Turborepo caching
285
+
286
+ If you're using [Turborepo](https://turbo.build/repo) in a monorepo, you need to include the generated Workflow routes in your cache outputs. The Workflow SDK generates route handlers at `app/.well-known/workflow/` (or `src/app/.well-known/workflow/` if your project uses the `src` directory) during the build process, and these files must be cached alongside your Next.js build output.
287
+
288
+ Add the following to your `turbo.json`:
289
+
290
+ ```jsonc title="turbo.json"
291
+ {
292
+ "tasks": {
293
+ "build": {
294
+ "outputs": [
295
+ ".next/**",
296
+ "!.next/cache/**",
297
+ // Include whichever path matches your project layout
298
+ "app/.well-known/workflow/**",
299
+ "src/app/.well-known/workflow/**"
300
+ ]
301
+ }
302
+ }
303
+ }
304
+ ```
305
+
306
+ Without this configuration, you may experience intermittent issues where workflows fail to register properly on cache hits, while working correctly on cache misses.
307
+
284
308
  ### `start()` says it received an invalid workflow function
285
309
 
286
310
  If you see this error:
@@ -89,20 +89,21 @@ export async function createUser(email: string) {
89
89
 
90
90
  {/* @skip-typecheck: incomplete code sample */}
91
91
  ```typescript
92
- import { registerStepFunction } from "workflow/internal/private"; // [!code highlight]
93
-
94
92
  export async function createUser(email: string) {
95
93
  return { id: crypto.randomUUID(), email };
96
94
  }
97
-
98
- registerStepFunction("step//workflows/user.js//createUser", createUser); // [!code highlight]
95
+ (function(__wf_fn, __wf_id) { // [!code highlight]
96
+ var __wf_sym = Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = new Map()); // [!code highlight]
97
+ __wf_reg.set(__wf_id, __wf_fn); // [!code highlight]
98
+ __wf_fn.stepId = __wf_id; // [!code highlight]
99
+ })(createUser, "step//workflows/user.js//createUser"); // [!code highlight]
99
100
  ```
100
101
 
101
102
  **What happens:**
102
103
 
103
104
  - The `"use step"` directive is removed
104
105
  - The function body is kept completely intact (no transformation)
105
- - The function is registered with the runtime using `registerStepFunction()`
106
+ - The function is registered with the runtime via an inline IIFE (no imports needed)
106
107
  - Step functions run with full Node.js/Deno/Bun access
107
108
 
108
109
  **Why no transformation?** Step functions execute in your main runtime with full access to Node.js APIs, file system, databases, etc. They don't need any special handling—they just run normally.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workflow",
3
- "version": "4.2.1",
3
+ "version": "5.0.0-beta.1",
4
4
  "description": "Workflow SDK - Build durable, resilient, and observable workflows",
5
5
  "main": "dist/typescript-plugin.cjs",
6
6
  "type": "module",
@@ -40,7 +40,6 @@
40
40
  "./errors": "./dist/internal/errors.js",
41
41
  "./internal/errors": "./dist/internal/errors.js",
42
42
  "./internal/builtins": "./dist/internal/builtins.js",
43
- "./internal/private": "./dist/internal/private.js",
44
43
  "./internal/class-serialization": "./dist/internal/class-serialization.js",
45
44
  "./next": "./dist/next.cjs",
46
45
  "./nitro": "./dist/nitro.js",
@@ -57,23 +56,23 @@
57
56
  },
58
57
  "dependencies": {
59
58
  "ms": "2.1.3",
60
- "@workflow/astro": "4.0.1",
61
- "@workflow/cli": "4.2.1",
62
- "@workflow/core": "4.2.1",
63
- "@workflow/errors": "4.1.0",
64
- "@workflow/typescript-plugin": "4.0.1",
65
- "@workflow/utils": "4.1.0",
66
- "@workflow/next": "4.0.2",
67
- "@workflow/nest": "0.0.1",
68
- "@workflow/nitro": "4.0.2",
69
- "@workflow/nuxt": "4.0.2",
70
- "@workflow/sveltekit": "4.0.1",
71
- "@workflow/rollup": "4.0.1"
59
+ "@workflow/astro": "5.0.0-beta.1",
60
+ "@workflow/cli": "5.0.0-beta.1",
61
+ "@workflow/core": "5.0.0-beta.1",
62
+ "@workflow/errors": "5.0.0-beta.0",
63
+ "@workflow/typescript-plugin": "5.0.0-beta.1",
64
+ "@workflow/utils": "5.0.0-beta.0",
65
+ "@workflow/next": "5.0.0-beta.1",
66
+ "@workflow/nest": "5.0.0-beta.1",
67
+ "@workflow/nitro": "5.0.0-beta.1",
68
+ "@workflow/nuxt": "5.0.0-beta.1",
69
+ "@workflow/sveltekit": "5.0.0-beta.1",
70
+ "@workflow/rollup": "5.0.0-beta.1"
72
71
  },
73
72
  "devDependencies": {
74
73
  "@types/ms": "2.1.0",
75
74
  "@types/node": "22.19.0",
76
- "@workflow/tsconfig": "4.0.1"
75
+ "@workflow/tsconfig": "5.0.0-beta.0"
77
76
  },
78
77
  "peerDependencies": {
79
78
  "@opentelemetry/api": "1"
@@ -1,6 +0,0 @@
1
- /**
2
- * This is the "private" API of the workflow runtime that referenced by the compiler's output
3
- * but not meant to be document and used directly in user code.
4
- */
5
- export * from '@workflow/core/private';
6
- //# sourceMappingURL=private.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"private.d.ts","sourceRoot":"","sources":["../../src/internal/private.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,wBAAwB,CAAC"}
@@ -1,6 +0,0 @@
1
- /**
2
- * This is the "private" API of the workflow runtime that referenced by the compiler's output
3
- * but not meant to be document and used directly in user code.
4
- */
5
- export * from '@workflow/core/private';
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJpdmF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbnRlcm5hbC9wcml2YXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILGNBQWMsd0JBQXdCLENBQUMifQ==