workflow 4.4.0 → 4.5.0
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/docs/api-reference/index.mdx +24 -0
- package/docs/api-reference/meta.json +8 -0
- package/docs/api-reference/vitest/index.mdx +0 -6
- package/docs/api-reference/workflow/create-hook.mdx +32 -0
- package/docs/api-reference/workflow/create-webhook.mdx +1 -0
- package/docs/api-reference/workflow-api/index.mdx +6 -8
- package/docs/api-reference/workflow-errors/meta.json +5 -0
- package/docs/api-reference/workflow-serde/index.mdx +0 -1
- package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +1 -2
- package/docs/api-reference/workflow-serde/workflow-serialize.mdx +1 -2
- package/docs/deploying/world/vercel-world.mdx +2 -0
- package/docs/errors/index.mdx +3 -0
- package/docs/foundations/hooks.mdx +29 -0
- package/docs/foundations/streaming.mdx +7 -1
- package/docs/foundations/versioning.mdx +1 -1
- package/docs/how-it-works/encryption.mdx +2 -2
- package/docs/how-it-works/event-sourcing.mdx +2 -2
- package/docs/v4/api-reference/workflow-astro/index.mdx +18 -0
- package/docs/v4/api-reference/workflow-astro/meta.json +4 -0
- package/docs/v4/api-reference/workflow-astro/workflow.mdx +37 -0
- package/docs/v4/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
- package/docs/v4/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
- package/docs/v4/api-reference/workflow-errors/workflow-error.mdx +52 -0
- package/docs/v4/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
- package/docs/v4/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
- package/docs/v4/api-reference/workflow-nest/configure-workflow-controller.mdx +33 -0
- package/docs/v4/api-reference/workflow-nest/index.mdx +31 -0
- package/docs/v4/api-reference/workflow-nest/meta.json +9 -0
- package/docs/v4/api-reference/workflow-nest/nest-local-builder.mdx +63 -0
- package/docs/v4/api-reference/workflow-nest/workflow-controller.mdx +40 -0
- package/docs/v4/api-reference/workflow-nest/workflow-module.mdx +73 -0
- package/docs/v4/api-reference/workflow-nitro/index.mdx +57 -0
- package/docs/v4/api-reference/workflow-nuxt/index.mdx +47 -0
- package/docs/v4/api-reference/workflow-observability/hydrate-data.mdx +35 -0
- package/docs/v4/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
- package/docs/v4/api-reference/workflow-observability/index.mdx +64 -0
- package/docs/v4/api-reference/workflow-observability/meta.json +11 -0
- package/docs/v4/api-reference/workflow-observability/observability-revivers.mdx +50 -0
- package/docs/v4/api-reference/workflow-observability/parse-class-name.mdx +41 -0
- package/docs/v4/api-reference/workflow-observability/parse-step-name.mdx +40 -0
- package/docs/v4/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
- package/docs/v4/api-reference/workflow-runtime/create-world.mdx +43 -0
- package/docs/v4/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
- package/docs/v4/api-reference/workflow-runtime/get-world.mdx +124 -0
- package/docs/v4/api-reference/workflow-runtime/health-check.mdx +50 -0
- package/docs/v4/api-reference/workflow-runtime/index.mdx +46 -0
- package/docs/v4/api-reference/workflow-runtime/meta.json +13 -0
- package/docs/v4/api-reference/workflow-runtime/set-world.mdx +49 -0
- package/docs/v4/api-reference/workflow-runtime/step-entrypoint.mdx +39 -0
- package/docs/v4/api-reference/workflow-runtime/workflow-entrypoint.mdx +42 -0
- package/docs/{api-reference/workflow-api → v4/api-reference/workflow-runtime}/world/index.mdx +5 -8
- package/docs/v4/api-reference/workflow-runtime/world/meta.json +4 -0
- package/docs/v4/api-reference/workflow-runtime/world/queue.mdx +86 -0
- package/docs/{api-reference/workflow-api → v4/api-reference/workflow-runtime}/world/storage.mdx +4 -4
- package/docs/v4/api-reference/workflow-runtime/world/streams.mdx +216 -0
- package/docs/v4/api-reference/workflow-sveltekit/index.mdx +18 -0
- package/docs/v4/api-reference/workflow-sveltekit/meta.json +4 -0
- package/docs/v4/api-reference/workflow-sveltekit/workflow-plugin.mdx +34 -0
- package/docs/v4/api-reference/workflow-vite/index.mdx +18 -0
- package/docs/v4/api-reference/workflow-vite/meta.json +4 -0
- package/docs/v4/api-reference/workflow-vite/workflow.mdx +47 -0
- package/docs/v4/errors/step-executed-multiple-times.mdx +23 -0
- package/docs/v5/api-reference/workflow-astro/index.mdx +18 -0
- package/docs/v5/api-reference/workflow-astro/meta.json +4 -0
- package/docs/v5/api-reference/workflow-astro/workflow.mdx +45 -0
- package/docs/v5/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
- package/docs/v5/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
- package/docs/v5/api-reference/workflow-errors/workflow-error.mdx +52 -0
- package/docs/v5/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
- package/docs/v5/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
- package/docs/v5/api-reference/workflow-nest/configure-workflow-controller.mdx +33 -0
- package/docs/v5/api-reference/workflow-nest/index.mdx +31 -0
- package/docs/v5/api-reference/workflow-nest/meta.json +9 -0
- package/docs/v5/api-reference/workflow-nest/nest-local-builder.mdx +64 -0
- package/docs/v5/api-reference/workflow-nest/workflow-controller.mdx +40 -0
- package/docs/v5/api-reference/workflow-nest/workflow-module.mdx +74 -0
- package/docs/v5/api-reference/workflow-nitro/index.mdx +59 -0
- package/docs/v5/api-reference/workflow-nuxt/index.mdx +47 -0
- package/docs/v5/api-reference/workflow-observability/hydrate-data.mdx +35 -0
- package/docs/v5/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
- package/docs/v5/api-reference/workflow-observability/index.mdx +64 -0
- package/docs/v5/api-reference/workflow-observability/meta.json +11 -0
- package/docs/v5/api-reference/workflow-observability/observability-revivers.mdx +50 -0
- package/docs/v5/api-reference/workflow-observability/parse-class-name.mdx +41 -0
- package/docs/v5/api-reference/workflow-observability/parse-step-name.mdx +40 -0
- package/docs/v5/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
- package/docs/v5/api-reference/workflow-runtime/create-world.mdx +39 -0
- package/docs/v5/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
- package/docs/{api-reference/workflow-api → v5/api-reference/workflow-runtime}/get-world.mdx +7 -10
- package/docs/v5/api-reference/workflow-runtime/health-check.mdx +50 -0
- package/docs/v5/api-reference/workflow-runtime/index.mdx +43 -0
- package/docs/v5/api-reference/workflow-runtime/meta.json +12 -0
- package/docs/v5/api-reference/workflow-runtime/set-world.mdx +49 -0
- package/docs/v5/api-reference/workflow-runtime/workflow-entrypoint.mdx +42 -0
- package/docs/v5/api-reference/workflow-runtime/world/index.mdx +55 -0
- package/docs/v5/api-reference/workflow-runtime/world/meta.json +4 -0
- package/docs/{api-reference/workflow-api → v5/api-reference/workflow-runtime}/world/queue.mdx +2 -2
- package/docs/v5/api-reference/workflow-runtime/world/storage.mdx +409 -0
- package/docs/{api-reference/workflow-api → v5/api-reference/workflow-runtime}/world/streams.mdx +2 -2
- package/docs/v5/api-reference/workflow-sveltekit/index.mdx +18 -0
- package/docs/v5/api-reference/workflow-sveltekit/meta.json +4 -0
- package/docs/v5/api-reference/workflow-sveltekit/workflow-plugin.mdx +42 -0
- package/docs/v5/api-reference/workflow-vite/index.mdx +18 -0
- package/docs/v5/api-reference/workflow-vite/meta.json +4 -0
- package/docs/v5/api-reference/workflow-vite/workflow.mdx +48 -0
- package/docs/v5/errors/index.mdx +3 -0
- package/docs/v5/errors/step-executed-multiple-times.mdx +23 -0
- package/package.json +10 -10
- package/docs/api-reference/workflow-api/world/meta.json +0 -4
- package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
|
@@ -17,9 +17,33 @@ All the functions and primitives that come with Workflow SDK by package.
|
|
|
17
17
|
<Card title="workflow/api" href="/docs/api-reference/workflow-api">
|
|
18
18
|
API reference for runtime functions from the `workflow/api` package.
|
|
19
19
|
</Card>
|
|
20
|
+
<Card title="workflow/runtime" href="/docs/api-reference/workflow-runtime">
|
|
21
|
+
Runtime functions for resolving the World instance and the low-level World SDK.
|
|
22
|
+
</Card>
|
|
23
|
+
<Card title="workflow/observability" href="/docs/api-reference/workflow-observability">
|
|
24
|
+
Utilities to hydrate step I/O, parse display names, and decrypt workflow data.
|
|
25
|
+
</Card>
|
|
20
26
|
<Card title="workflow/next" href="/docs/api-reference/workflow-next">
|
|
21
27
|
Next.js integration for Workflow SDK that automatically configures bundling and runtime support.
|
|
22
28
|
</Card>
|
|
29
|
+
<Card title="workflow/nitro" href="/docs/api-reference/workflow-nitro">
|
|
30
|
+
Nitro module for workflow bundling and runtime support.
|
|
31
|
+
</Card>
|
|
32
|
+
<Card title="workflow/nuxt" href="/docs/api-reference/workflow-nuxt">
|
|
33
|
+
Nuxt module for workflow bundling and runtime support.
|
|
34
|
+
</Card>
|
|
35
|
+
<Card title="workflow/sveltekit" href="/docs/api-reference/workflow-sveltekit">
|
|
36
|
+
SvelteKit Vite plugin for workflow bundling and runtime support.
|
|
37
|
+
</Card>
|
|
38
|
+
<Card title="workflow/astro" href="/docs/api-reference/workflow-astro">
|
|
39
|
+
Astro integration for workflow bundling and runtime support.
|
|
40
|
+
</Card>
|
|
41
|
+
<Card title="workflow/vite" href="/docs/api-reference/workflow-vite">
|
|
42
|
+
Standalone Vite plugin for workflow bundling and runtime support.
|
|
43
|
+
</Card>
|
|
44
|
+
<Card title="workflow/nest" href="/docs/api-reference/workflow-nest">
|
|
45
|
+
NestJS module for workflow bundling and runtime support.
|
|
46
|
+
</Card>
|
|
23
47
|
<Card title="workflow/errors" href="/docs/api-reference/workflow-errors">
|
|
24
48
|
Semantic error types for handling workflow storage backend failures.
|
|
25
49
|
</Card>
|
|
@@ -4,7 +4,15 @@
|
|
|
4
4
|
"workflow-globals",
|
|
5
5
|
"workflow",
|
|
6
6
|
"workflow-api",
|
|
7
|
+
"workflow-runtime",
|
|
8
|
+
"workflow-observability",
|
|
7
9
|
"workflow-next",
|
|
10
|
+
"workflow-nitro",
|
|
11
|
+
"workflow-nuxt",
|
|
12
|
+
"workflow-sveltekit",
|
|
13
|
+
"workflow-astro",
|
|
14
|
+
"workflow-vite",
|
|
15
|
+
"workflow-nest",
|
|
8
16
|
"workflow-errors",
|
|
9
17
|
"workflow-serde",
|
|
10
18
|
"workflow-ai",
|
|
@@ -11,7 +11,6 @@ The `@workflow/vitest` package provides a Vitest plugin and test helpers for run
|
|
|
11
11
|
|
|
12
12
|
Returns a Vite plugin array that handles SWC transforms, bundle building, and in-process handler registration automatically.
|
|
13
13
|
|
|
14
|
-
{/* @skip-typecheck - @workflow/vitest not available in docs-typecheck */}
|
|
15
14
|
|
|
16
15
|
```typescript
|
|
17
16
|
import { defineConfig } from "vitest/config";
|
|
@@ -24,7 +23,6 @@ export default defineConfig({
|
|
|
24
23
|
|
|
25
24
|
Pass a [`WorkflowTestOptions`](#workflowtestoptions) object when your project uses a non-standard layout — for example, a monorepo where `workflows/` does not live at the Vitest config's directory, or when the default `.workflow-data` / `.workflow-vitest` output locations need to move. The plugin forwards these paths to `buildWorkflowTests()` and `setupWorkflowTests()` through Vitest's per-project provided context, so each Vitest workspace project stays isolated.
|
|
26
25
|
|
|
27
|
-
{/* @skip-typecheck - @workflow/vitest not available in docs-typecheck */}
|
|
28
26
|
|
|
29
27
|
```typescript
|
|
30
28
|
import { defineConfig } from "vitest/config";
|
|
@@ -54,7 +52,6 @@ export default defineConfig({
|
|
|
54
52
|
|
|
55
53
|
Builds workflow and step bundles to disk. Called automatically by the `workflow()` plugin in `globalSetup`. Use directly only for [manual setup](/docs/testing#manual-setup).
|
|
56
54
|
|
|
57
|
-
{/* @skip-typecheck - @workflow/vitest not available in docs-typecheck */}
|
|
58
55
|
|
|
59
56
|
```typescript
|
|
60
57
|
import { buildWorkflowTests } from "@workflow/vitest";
|
|
@@ -76,7 +73,6 @@ Sets up an in-process workflow runtime in each test worker. Imports pre-built bu
|
|
|
76
73
|
|
|
77
74
|
Called automatically by the `workflow()` plugin in `setupFiles`. Use directly only for [manual setup](/docs/testing#manual-setup).
|
|
78
75
|
|
|
79
|
-
{/* @skip-typecheck - @workflow/vitest not available in docs-typecheck */}
|
|
80
76
|
|
|
81
77
|
```typescript
|
|
82
78
|
import { beforeAll, afterAll } from "vitest";
|
|
@@ -118,7 +114,6 @@ Tears down the workflow test world. Clears the global world and closes the Local
|
|
|
118
114
|
|
|
119
115
|
Polls the event log until the workflow has a pending `sleep()` call — one with a `wait_created` event but no corresponding `wait_completed` event. Returns the correlation ID of the pending sleep, which can be passed to [`wakeUp()`](/docs/api-reference/workflow-api/get-run) to target a specific sleep.
|
|
120
116
|
|
|
121
|
-
{/* @skip-typecheck - @workflow/vitest not available in docs-typecheck */}
|
|
122
117
|
|
|
123
118
|
```typescript
|
|
124
119
|
import { waitForSleep } from "@workflow/vitest"; // [!code highlight]
|
|
@@ -147,7 +142,6 @@ await getRun(run.runId).wakeUp({ correlationIds: [sleepId] }); // [!code highlig
|
|
|
147
142
|
|
|
148
143
|
Polls the hook list and event log until a hook matching the optional `token` filter exists that hasn't been received yet. Returns the matching hook object.
|
|
149
144
|
|
|
150
|
-
{/* @skip-typecheck - @workflow/vitest not available in docs-typecheck */}
|
|
151
145
|
|
|
152
146
|
```typescript
|
|
153
147
|
import { waitForHook } from "@workflow/vitest"; // [!code highlight]
|
|
@@ -65,6 +65,8 @@ export default Hook;`}
|
|
|
65
65
|
|
|
66
66
|
The returned `Hook` object also implements `AsyncIterable<T>`, which allows you to iterate over incoming payloads using `for await...of` syntax.
|
|
67
67
|
|
|
68
|
+
Use `hook.getConflict()` to check whether the hook token is already claimed by another active hook, without waiting for hook payload data. Calling `createHook()` on its own does not register the hook — registration is only committed when the workflow suspends. Awaiting `hook.getConflict()` suspends the workflow to commit the registration, then resolves with `null` once `hook_created` is recorded, or with `{ runId }` identifying the conflicting run if another active hook already owns the same token.
|
|
69
|
+
|
|
68
70
|
## Examples
|
|
69
71
|
|
|
70
72
|
### Basic Usage
|
|
@@ -112,6 +114,36 @@ export async function slackBotWorkflow(channelId: string) {
|
|
|
112
114
|
}
|
|
113
115
|
```
|
|
114
116
|
|
|
117
|
+
### Detecting Token Conflicts
|
|
118
|
+
|
|
119
|
+
Use `hook.getConflict()` when the workflow needs to claim a hook token before doing other work, but does not need a payload yet:
|
|
120
|
+
|
|
121
|
+
```typescript lineNumbers
|
|
122
|
+
import { createHook } from "workflow";
|
|
123
|
+
|
|
124
|
+
declare function chargeOrder(orderId: string): Promise<void>; // @setup
|
|
125
|
+
|
|
126
|
+
async function processOrder(orderId: string) {
|
|
127
|
+
"use workflow";
|
|
128
|
+
|
|
129
|
+
using hook = createHook({ // [!code highlight]
|
|
130
|
+
token: `order:${orderId}` // [!code highlight]
|
|
131
|
+
}); // [!code highlight]
|
|
132
|
+
|
|
133
|
+
const conflict = await hook.getConflict(); // [!code highlight]
|
|
134
|
+
if (conflict) { // [!code highlight]
|
|
135
|
+
// Another active workflow run already owns this token.
|
|
136
|
+
return { dedupedTo: conflict.runId };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
await chargeOrder(orderId);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Because `createHook()` alone does not suspend the workflow, awaiting `hook.getConflict()` is what actually suspends the run and commits the hook registration. It only waits for registration — to receive payload data from a future `resumeHook()` call, await the hook itself or iterate it with `for await...of`.
|
|
144
|
+
|
|
145
|
+
On a conflict, the resolved value is `{ runId }` identifying the run that currently owns the token. To act on the owner — inspect its status, wait for its result, or cancel it — pass `conflict.runId` to [`getRun()`](/docs/api-reference/workflow-api/get-run) inside a step. See [Idempotency](/docs/foundations/idempotency) for these strategies in context.
|
|
146
|
+
|
|
115
147
|
### Waiting for Multiple Payloads
|
|
116
148
|
|
|
117
149
|
You can also wait for multiple payloads by using the `for await...of` syntax.
|
|
@@ -55,6 +55,7 @@ The returned `Webhook` object has:
|
|
|
55
55
|
|
|
56
56
|
- `url`: The HTTP endpoint URL that external systems can call
|
|
57
57
|
- `token`: The unique token identifying this webhook
|
|
58
|
+
- `getConflict()`: A promise that resolves with `{ runId }` identifying the conflicting run if another active hook already owns this token, or `null` once the webhook endpoint has been registered
|
|
58
59
|
- Implements `AsyncIterable<RequestWithResponse>` for handling multiple requests
|
|
59
60
|
|
|
60
61
|
The `RequestWithResponse` type extends the standard `Request` interface with a `respondWith(response: Response)` method for sending custom responses back to the caller.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "workflow/api"
|
|
3
|
-
description: Runtime functions to inspect runs, start workflows, and
|
|
3
|
+
description: Runtime functions to inspect runs, start workflows, and manage hooks.
|
|
4
4
|
type: overview
|
|
5
5
|
summary: Explore runtime functions for starting workflows, inspecting runs, and managing hooks.
|
|
6
6
|
---
|
|
@@ -9,7 +9,7 @@ API reference for runtime functions from the `workflow/api` package.
|
|
|
9
9
|
|
|
10
10
|
## Functions
|
|
11
11
|
|
|
12
|
-
The API package is for access and introspection of workflow data to inspect runs, start new runs,
|
|
12
|
+
The API package is for access and introspection of workflow data to inspect runs, start new runs, and manage hooks.
|
|
13
13
|
|
|
14
14
|
<Cards>
|
|
15
15
|
<Card href="/docs/api-reference/workflow-api/start" title="start()">
|
|
@@ -27,10 +27,8 @@ The API package is for access and introspection of workflow data to inspect runs
|
|
|
27
27
|
<Card href="/docs/api-reference/workflow-api/get-run" title="getRun()">
|
|
28
28
|
Get workflow run status and metadata without waiting for completion.
|
|
29
29
|
</Card>
|
|
30
|
-
<Card href="/docs/api-reference/workflow-api/get-world" title="getWorld()">
|
|
31
|
-
Get direct access to workflow storage, queuing, and streaming backends.
|
|
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>
|
|
36
30
|
</Cards>
|
|
31
|
+
|
|
32
|
+
<Callout type="info">
|
|
33
|
+
Looking for `getWorld()` and the World SDK? They are exported from `workflow/runtime` — see the [`workflow/runtime` reference](/docs/api-reference/workflow-runtime).
|
|
34
|
+
</Callout>
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "workflow/errors",
|
|
3
3
|
"pages": [
|
|
4
|
+
"workflow-error",
|
|
4
5
|
"hook-not-found-error",
|
|
6
|
+
"hook-conflict-error",
|
|
5
7
|
"step-not-registered-error",
|
|
6
8
|
"workflow-not-registered-error",
|
|
7
9
|
"workflow-run-not-found-error",
|
|
8
10
|
"workflow-run-failed-error",
|
|
9
11
|
"workflow-run-cancelled-error",
|
|
12
|
+
"workflow-run-not-completed-error",
|
|
13
|
+
"workflow-runtime-error",
|
|
10
14
|
"workflow-world-error",
|
|
11
15
|
"throttle-error",
|
|
12
16
|
"entity-conflict-error",
|
|
13
17
|
"run-expired-error",
|
|
18
|
+
"run-not-supported-error",
|
|
14
19
|
"too-early-error"
|
|
15
20
|
]
|
|
16
21
|
}
|
|
@@ -6,7 +6,6 @@ A symbol used to define custom deserialization for user-defined class instances.
|
|
|
6
6
|
|
|
7
7
|
## Usage
|
|
8
8
|
|
|
9
|
-
{/* @expect-error:2351 */}
|
|
10
9
|
|
|
11
10
|
```typescript lineNumbers
|
|
12
11
|
import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde";
|
|
@@ -26,7 +25,7 @@ class Point {
|
|
|
26
25
|
|
|
27
26
|
## API Signature
|
|
28
27
|
|
|
29
|
-
{/* @skip-typecheck */}
|
|
28
|
+
{/* @skip-typecheck: type-only signature snippet, not compilable code */}
|
|
30
29
|
|
|
31
30
|
```typescript
|
|
32
31
|
static [WORKFLOW_DESERIALIZE](data: SerializableData): T
|
|
@@ -6,7 +6,6 @@ A symbol used to define custom serialization for user-defined class instances. T
|
|
|
6
6
|
|
|
7
7
|
## Usage
|
|
8
8
|
|
|
9
|
-
{/* @expect-error:2351 */}
|
|
10
9
|
|
|
11
10
|
```typescript lineNumbers
|
|
12
11
|
import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde";
|
|
@@ -26,7 +25,7 @@ class Point {
|
|
|
26
25
|
|
|
27
26
|
## API Signature
|
|
28
27
|
|
|
29
|
-
{/* @skip-typecheck */}
|
|
28
|
+
{/* @skip-typecheck: type-only signature snippet, not compilable code */}
|
|
30
29
|
|
|
31
30
|
```typescript
|
|
32
31
|
static [WORKFLOW_SERIALIZE](instance: T): SerializableData
|
|
@@ -48,6 +48,8 @@ For self-hosted deployments, use the [Postgres World](/worlds/postgres). For loc
|
|
|
48
48
|
|
|
49
49
|
- **Data residency** - The Vercel World is currently deployed in the `iad1` region. This means independently of the deployment location of your application, the data for your workflows will be stored in the `iad1` region.
|
|
50
50
|
|
|
51
|
+
- **Stream routes need `supportsCancellation`** - Routes that pipe `run.getReadable()` back to a client keep running — and billing — until the function's max duration, even after the client disconnects. Set [`supportsCancellation`](https://vercel.com/docs/functions/request-cancellation) in `vercel.json` for those routes so client aborts tear the invocation down. See [Streaming — Resuming Streams from a Specific Point](/docs/foundations/streaming#resuming-streams-from-a-specific-point).
|
|
52
|
+
|
|
51
53
|
## Observability
|
|
52
54
|
|
|
53
55
|
Workflow observability is built into the Vercel dashboard on your project page. It respects your existing authentication and project permission settings.
|
package/docs/errors/index.mdx
CHANGED
|
@@ -43,6 +43,9 @@ Fix common mistakes when creating and executing workflows in the **Workflow SDK*
|
|
|
43
43
|
<Card href="/docs/errors/step-not-registered" title="step-not-registered">
|
|
44
44
|
Resolve step not registered errors caused by deployment mismatches.
|
|
45
45
|
</Card>
|
|
46
|
+
<Card href="/docs/errors/step-executed-multiple-times" title="Step executed multiple times">
|
|
47
|
+
Diagnose duplicate step_started events from function crashes, timeouts, or OOMs.
|
|
48
|
+
</Card>
|
|
46
49
|
<Card href="/docs/errors/workflow-not-registered" title="workflow-not-registered">
|
|
47
50
|
Resolve workflow not registered errors caused by deployment mismatches.
|
|
48
51
|
</Card>
|
|
@@ -85,6 +85,35 @@ The key points:
|
|
|
85
85
|
- You need the hook's `token` to resume it
|
|
86
86
|
- The workflow will resume execution right where it left off
|
|
87
87
|
|
|
88
|
+
### Checking for Token Conflicts
|
|
89
|
+
|
|
90
|
+
Sometimes you need to know that a hook token has been claimed, but you do not want to wait for external data yet. Await `hook.getConflict()` for that:
|
|
91
|
+
|
|
92
|
+
```typescript lineNumbers
|
|
93
|
+
import { createHook } from "workflow";
|
|
94
|
+
|
|
95
|
+
declare function processOrder(orderId: string): Promise<void>; // @setup
|
|
96
|
+
|
|
97
|
+
export async function orderWorkflow(orderId: string) {
|
|
98
|
+
"use workflow";
|
|
99
|
+
|
|
100
|
+
using hook = createHook({
|
|
101
|
+
token: `order:${orderId}`
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const conflict = await hook.getConflict(); // [!code highlight]
|
|
105
|
+
if (conflict) { // [!code highlight]
|
|
106
|
+
// Another active run already owns this token.
|
|
107
|
+
return { dedupedTo: conflict.runId };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// The hook token is registered and reserved here.
|
|
111
|
+
await processOrder(orderId);
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Calling `createHook()` on its own does not register the hook — registration is only committed when the workflow suspends. Awaiting `hook.getConflict()` suspends the workflow to commit the hook registration, then resolves with `null` once the hook is registered and ready to receive payloads, or with `{ runId }` identifying the run that owns the token if another active hook already claimed it (see [`HookConflictError`](/docs/errors/hook-conflict)). For `hook_conflict` events persisted by older worlds that did not record the owning run's ID, `getConflict()` rejects with `HookConflictError` instead of resolving with an incomplete handle. To act on the owner — inspect its status, wait for its result, or cancel it — pass `conflict.runId` to [`getRun()`](/docs/api-reference/workflow-api/get-run) inside a step. See [Idempotency](/docs/foundations/idempotency) for these strategies.
|
|
116
|
+
|
|
88
117
|
### Custom Tokens for Deterministic Hooks
|
|
89
118
|
|
|
90
119
|
By default, hooks generate a random token. However, you often want to use a **custom token** that external systems can reconstruct. This is especially useful for long-running workflows where the same workflow instance should handle multiple events.
|
|
@@ -87,6 +87,12 @@ export async function GET(
|
|
|
87
87
|
|
|
88
88
|
This allows clients to reconnect and continue receiving data from where they left off, rather than restarting from the beginning.
|
|
89
89
|
|
|
90
|
+
<Callout type="warn">
|
|
91
|
+
**Vercel: long-lived stream routes need `supportsCancellation`**
|
|
92
|
+
|
|
93
|
+
When a route like the one above pipes `run.getReadable()` out to a client on Vercel, the function keeps running — and billing — until the function's configured max duration, even after the client disconnects. Set [`supportsCancellation`](https://vercel.com/docs/functions/request-cancellation) in `vercel.json` for routes that stream workflow output so Vercel forwards the client abort signal and tears the invocation down when the client goes away.
|
|
94
|
+
</Callout>
|
|
95
|
+
|
|
90
96
|
`startIndex` also supports **negative values** to read relative to the end of the stream. For example, `startIndex: -5` starts 5 chunks before the current end. This is useful when you want to show the most recent output without reading the entire stream history.
|
|
91
97
|
|
|
92
98
|
On an active (not-yet-closed) stream, the negative index resolves relative to the chunk count at connection time; any chunks written afterward are still delivered normally.
|
|
@@ -593,7 +599,7 @@ Stream errors don't trigger automatic retries for the producer step. Design your
|
|
|
593
599
|
- [`sleep()` API Reference](/docs/api-reference/workflow/sleep) - Pause workflow execution for a duration
|
|
594
600
|
- [`start()` API Reference](/docs/api-reference/workflow-api/start) - Start workflows and access the `Run` object
|
|
595
601
|
- [`getRun()` API Reference](/docs/api-reference/workflow-api/get-run) - Retrieve runs and their streams later
|
|
596
|
-
- [world.streams](/docs/api-reference/workflow-
|
|
602
|
+
- [world.streams](/docs/api-reference/workflow-runtime/world/streams) - Low-level stream read/write/close via World SDK
|
|
597
603
|
- [DurableAgent](/docs/api-reference/workflow-ai/durable-agent) - AI agents with built-in streaming support
|
|
598
604
|
- [Errors and Retries](/docs/foundations/errors-and-retries) - Understanding error handling and retry behavior
|
|
599
605
|
- [Serialization](/docs/foundations/serialization) - Understanding what data types can be passed in workflows
|
|
@@ -93,7 +93,7 @@ npx workflow cancel \
|
|
|
93
93
|
--backend vercel
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
The `--workflowName` filter expects the generated workflow ID, not only the exported function's short name. Use the `workflowName` value from `workflow inspect runs`, and use [`parseWorkflowName()`](/docs/api-reference/workflow-
|
|
96
|
+
The `--workflowName` filter expects the generated workflow ID, not only the exported function's short name. Use the `workflowName` value from `workflow inspect runs`, and use [`parseWorkflowName()`](/docs/api-reference/workflow-observability/parse-workflow-name) when you need display-friendly names.
|
|
97
97
|
|
|
98
98
|
In the [observability UI](/docs/observability), use **Rerun on latest** to enqueue the workflow again with the same inputs against the latest deployment.
|
|
99
99
|
|
|
@@ -105,8 +105,8 @@ To add encryption support to a custom `World`:
|
|
|
105
105
|
import type { WorkflowRun, World } from "@workflow/world";
|
|
106
106
|
|
|
107
107
|
export const getEncryptionKeyForRun: World["getEncryptionKeyForRun"] = async (
|
|
108
|
-
run,
|
|
109
|
-
context
|
|
108
|
+
run: WorkflowRun | string,
|
|
109
|
+
context?: Record<string, unknown>
|
|
110
110
|
) => {
|
|
111
111
|
const runId = typeof run === "string" ? run : run.runId;
|
|
112
112
|
const deploymentId =
|
|
@@ -127,7 +127,7 @@ flowchart TD
|
|
|
127
127
|
|
|
128
128
|
Unlike other entities, hooks don't have a `status` field—the states above are conceptual. An "active" hook is one that exists in storage, while "disposed" means the hook has been deleted. When a `hook_disposed` event is created, the hook record is removed rather than updated.
|
|
129
129
|
|
|
130
|
-
While a hook is active, its token is reserved and cannot be used by other workflows. If a workflow attempts to create a hook with a token that is already in use by another active hook, a `hook_conflict` event is recorded instead of `hook_created`. Current worlds include the token and the run ID that currently owns it, though older persisted events or world implementations may only include the token. This causes the hook's promise to reject with a `HookConflictError`, which you can detect with `HookConflictError.is(error)`. See the [hook-conflict error](/docs/errors/hook-conflict) documentation for more details.
|
|
130
|
+
While a hook is active, its token is reserved and cannot be used by other workflows. If a workflow attempts to create a hook with a token that is already in use by another active hook, a `hook_conflict` event is recorded instead of `hook_created`. Current worlds include the token and the run ID that currently owns it, though older persisted events or world implementations may only include the token. This causes `hook.getConflict()` to resolve with the conflicting run and the hook's payload promise to reject with a `HookConflictError`, which you can detect with `HookConflictError.is(error)`. See the [hook-conflict error](/docs/errors/hook-conflict) documentation for more details.
|
|
131
131
|
|
|
132
132
|
When a hook is disposed (either explicitly or when its workflow completes), the token is released and can be claimed by future workflows. Hooks are automatically disposed when a workflow reaches a terminal state (`completed`, `failed`, or `cancelled`). The `hook_disposed` event is only needed for explicit disposal before workflow completion.
|
|
133
133
|
|
|
@@ -188,7 +188,7 @@ Events are categorized by the entity type they affect. Each event contains metad
|
|
|
188
188
|
| Event | Description |
|
|
189
189
|
|-------|-------------|
|
|
190
190
|
| `hook_created` | Creates a new hook in `active` state. Contains the hook token and optional metadata. |
|
|
191
|
-
| `hook_conflict` | Records that hook creation failed because the token is already in use by another active hook. Contains the token and, for current worlds, the active hook owner's run ID. The hook is not created, and awaiting the hook
|
|
191
|
+
| `hook_conflict` | Records that hook creation failed because the token is already in use by another active hook. Contains the token and, for current worlds, the active hook owner's run ID. The hook is not created: `hook.getConflict()` resolves with the conflicting run, and awaiting the hook payload rejects with a `HookConflictError`. |
|
|
192
192
|
| `hook_received` | Records that a payload was delivered to the hook. The hook remains `active` and can receive more payloads. |
|
|
193
193
|
| `hook_disposed` | Deletes the hook from storage (conceptually transitioning to `disposed` state). The token is released for reuse by future workflows. |
|
|
194
194
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "workflow/astro"
|
|
3
|
+
description: Astro integration for automatic workflow bundling and route registration.
|
|
4
|
+
type: overview
|
|
5
|
+
summary: Explore the Astro integration for automatic workflow bundling and runtime support.
|
|
6
|
+
related:
|
|
7
|
+
- /docs/getting-started/astro
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Astro integration for Workflow SDK that transforms workflow code and builds the workflow bundles.
|
|
11
|
+
|
|
12
|
+
## Functions
|
|
13
|
+
|
|
14
|
+
<Cards>
|
|
15
|
+
<Card title="workflow()" href="/docs/api-reference/workflow-astro/workflow">
|
|
16
|
+
Astro integration that transforms workflow code (`"use step"`/`"use workflow"` directives)
|
|
17
|
+
</Card>
|
|
18
|
+
</Cards>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: workflow
|
|
3
|
+
description: Configure Astro to transform workflow directives.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: Add the workflow integration to your Astro config to enable workflow directive transformation.
|
|
6
|
+
prerequisites:
|
|
7
|
+
- /docs/getting-started/astro
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Returns an Astro integration that transforms workflow code (`"use step"`/`"use workflow"` directives) and builds the workflow bundles.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
To enable `"use step"` and `"use workflow"` directives while developing locally or deploying to production, add `workflow()` to the `integrations` array of your Astro config.
|
|
15
|
+
|
|
16
|
+
```typescript title="astro.config.mjs" lineNumbers
|
|
17
|
+
// @ts-check
|
|
18
|
+
import { defineConfig } from "astro/config";
|
|
19
|
+
import { workflow } from "workflow/astro"; // [!code highlight]
|
|
20
|
+
|
|
21
|
+
// https://astro.build/config
|
|
22
|
+
export default defineConfig({
|
|
23
|
+
integrations: [workflow()], // [!code highlight]
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The integration registers the workflow Vite transform plugins during `astro:config:setup` and builds the workflow bundles — locally during config setup, or via the Vercel builder after `astro:build:done` when deploying to Vercel.
|
|
28
|
+
|
|
29
|
+
## API Signature
|
|
30
|
+
|
|
31
|
+
### Parameters
|
|
32
|
+
|
|
33
|
+
This function does not accept any parameters in workflow 4.x. (5.x adds an options object with a `sourcemap` setting.)
|
|
34
|
+
|
|
35
|
+
### Returns
|
|
36
|
+
|
|
37
|
+
Returns an `AstroIntegration` object to include in the `integrations` array of your Astro config.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: HookConflictError
|
|
3
|
+
description: Thrown when creating a hook with a token that is already in use by another workflow run.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: Catch HookConflictError when a hook token is already claimed by another active workflow run.
|
|
6
|
+
related:
|
|
7
|
+
- /docs/api-reference/workflow/create-hook
|
|
8
|
+
- /docs/foundations/hooks
|
|
9
|
+
- /docs/errors/hook-conflict
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
`HookConflictError` is thrown when creating a hook with a token that is already in use by another active workflow run. Hook tokens must be unique across all running workflows — see the [hook-conflict](/docs/errors/hook-conflict) error guide for resolution strategies.
|
|
13
|
+
|
|
14
|
+
```typescript lineNumbers
|
|
15
|
+
import { HookConflictError } from "workflow/errors"
|
|
16
|
+
declare function startApprovalWorkflow(token: string): Promise<void>; // @setup
|
|
17
|
+
declare const token: string; // @setup
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
await startApprovalWorkflow(token);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
if (HookConflictError.is(error)) { // [!code highlight]
|
|
23
|
+
console.error(
|
|
24
|
+
`Token "${error.token}" already in use by run ${error.conflictingRunId}`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## API Signature
|
|
31
|
+
|
|
32
|
+
### Properties
|
|
33
|
+
|
|
34
|
+
<TSDoc
|
|
35
|
+
definition={`
|
|
36
|
+
interface HookConflictError {
|
|
37
|
+
/** The hook token that conflicted. */
|
|
38
|
+
token: string;
|
|
39
|
+
/** The run ID of the workflow currently holding the token, when known. */
|
|
40
|
+
conflictingRunId?: string;
|
|
41
|
+
/** The error message. */
|
|
42
|
+
message: string;
|
|
43
|
+
}
|
|
44
|
+
export default HookConflictError;`}
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
### Static Methods
|
|
48
|
+
|
|
49
|
+
#### `HookConflictError.is(value)`
|
|
50
|
+
|
|
51
|
+
Type-safe check for `HookConflictError` instances. Preferred over `instanceof` because it works across module boundaries and VM contexts.
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { HookConflictError } from "workflow/errors"
|
|
55
|
+
declare const error: unknown; // @setup
|
|
56
|
+
|
|
57
|
+
if (HookConflictError.is(error)) {
|
|
58
|
+
// error is typed as HookConflictError
|
|
59
|
+
}
|
|
60
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: RunNotSupportedError
|
|
3
|
+
description: Thrown when a workflow run requires a newer workflow spec version than the installed SDK supports.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: Catch RunNotSupportedError when stored run data requires a newer workflow package version.
|
|
6
|
+
related:
|
|
7
|
+
- /docs/foundations/versioning
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
`RunNotSupportedError` is thrown when reading a workflow run whose data was written with a newer workflow spec version than the running SDK supports. This typically means the run was created by a newer version of the `workflow` package — upgrade the package to process it.
|
|
11
|
+
|
|
12
|
+
```typescript lineNumbers
|
|
13
|
+
import { RunNotSupportedError } from "workflow/errors"
|
|
14
|
+
declare function readRun(runId: string): Promise<unknown>; // @setup
|
|
15
|
+
declare const runId: string; // @setup
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
await readRun(runId);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (RunNotSupportedError.is(error)) { // [!code highlight]
|
|
21
|
+
console.error(
|
|
22
|
+
`Run requires spec v${error.runSpecVersion}, world supports v${error.worldSpecVersion}`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## API Signature
|
|
29
|
+
|
|
30
|
+
### Properties
|
|
31
|
+
|
|
32
|
+
<TSDoc
|
|
33
|
+
definition={`
|
|
34
|
+
interface RunNotSupportedError {
|
|
35
|
+
/** The spec version the run's stored data requires. */
|
|
36
|
+
runSpecVersion: number;
|
|
37
|
+
/** The spec version the current World supports. */
|
|
38
|
+
worldSpecVersion: number;
|
|
39
|
+
/** The error message. */
|
|
40
|
+
message: string;
|
|
41
|
+
}
|
|
42
|
+
export default RunNotSupportedError;`}
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
### Static Methods
|
|
46
|
+
|
|
47
|
+
#### `RunNotSupportedError.is(value)`
|
|
48
|
+
|
|
49
|
+
Type-safe check for `RunNotSupportedError` instances. Preferred over `instanceof` because it works across module boundaries and VM contexts.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { RunNotSupportedError } from "workflow/errors"
|
|
53
|
+
declare const error: unknown; // @setup
|
|
54
|
+
|
|
55
|
+
if (RunNotSupportedError.is(error)) {
|
|
56
|
+
// error is typed as RunNotSupportedError
|
|
57
|
+
}
|
|
58
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: WorkflowError
|
|
3
|
+
description: Base class for all workflow error types.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: All errors thrown by the Workflow SDK extend WorkflowError.
|
|
6
|
+
related:
|
|
7
|
+
- /docs/foundations/errors-and-retries
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
`WorkflowError` is the base class that all Workflow SDK error types extend, such as [`WorkflowRunFailedError`](/docs/api-reference/workflow-errors/workflow-run-failed-error) and [`HookNotFoundError`](/docs/api-reference/workflow-errors/hook-not-found-error). It extends `Error` with an optional `cause` and, for some subclasses, a link to the relevant error documentation appended to the message.
|
|
11
|
+
|
|
12
|
+
```typescript lineNumbers
|
|
13
|
+
import { WorkflowError } from "workflow/errors"
|
|
14
|
+
|
|
15
|
+
const error = new WorkflowError("something went wrong", {
|
|
16
|
+
cause: new Error("underlying cause"),
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## API Signature
|
|
21
|
+
|
|
22
|
+
### Properties
|
|
23
|
+
|
|
24
|
+
<TSDoc
|
|
25
|
+
definition={`
|
|
26
|
+
interface WorkflowError {
|
|
27
|
+
/** The error message. */
|
|
28
|
+
message: string;
|
|
29
|
+
/** The underlying cause, when provided. */
|
|
30
|
+
cause?: unknown;
|
|
31
|
+
}
|
|
32
|
+
export default WorkflowError;`}
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
### Static Methods
|
|
36
|
+
|
|
37
|
+
#### `WorkflowError.is(value)`
|
|
38
|
+
|
|
39
|
+
Type-safe check for `WorkflowError` instances. Preferred over `instanceof` because it works across module boundaries and VM contexts.
|
|
40
|
+
|
|
41
|
+
<Callout type="warn">
|
|
42
|
+
`WorkflowError.is()` matches only direct `WorkflowError` instances — not subclasses, which override the error name it checks. To handle a specific error type, use that subclass's own `.is()` method (e.g. `WorkflowRunFailedError.is(error)`).
|
|
43
|
+
</Callout>
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { WorkflowError } from "workflow/errors"
|
|
47
|
+
declare const error: unknown; // @setup
|
|
48
|
+
|
|
49
|
+
if (WorkflowError.is(error)) {
|
|
50
|
+
// error is typed as WorkflowError
|
|
51
|
+
}
|
|
52
|
+
```
|