@workflow/core 5.0.0-beta.5 → 5.0.0-beta.50
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/dist/attribute-changes.d.ts +5 -0
- package/dist/attribute-changes.d.ts.map +1 -0
- package/dist/attribute-changes.js +25 -0
- package/dist/capabilities.d.ts +35 -2
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +74 -5
- package/dist/capture-stack.d.ts +1 -1
- package/dist/capture-stack.js +2 -2
- package/dist/class-serialization.d.ts +32 -0
- package/dist/class-serialization.d.ts.map +1 -1
- package/dist/class-serialization.js +37 -1
- package/dist/classify-error.d.ts +19 -3
- package/dist/classify-error.d.ts.map +1 -1
- package/dist/classify-error.js +98 -6
- package/dist/context-violation-error.d.ts +5 -5
- package/dist/context-violation-error.d.ts.map +1 -1
- package/dist/context-violation-error.js +8 -6
- package/dist/create-hook.d.ts +72 -7
- package/dist/create-hook.d.ts.map +1 -1
- package/dist/create-hook.js +1 -1
- package/dist/define-hook.js +2 -2
- package/dist/describe-error.d.ts +7 -7
- package/dist/describe-error.d.ts.map +1 -1
- package/dist/describe-error.js +97 -12
- package/dist/encryption.d.ts +38 -4
- package/dist/encryption.d.ts.map +1 -1
- package/dist/encryption.js +96 -14
- package/dist/events-consumer.d.ts +271 -0
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +646 -42
- package/dist/flushable-stream.d.ts +56 -1
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +123 -11
- package/dist/global.d.ts +36 -2
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +21 -6
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/log-format.d.ts +2 -2
- package/dist/log-format.js +7 -7
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +10 -6
- package/dist/private.d.ts +226 -9
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +626 -7
- package/dist/replay-payload-cache.d.ts +64 -0
- package/dist/replay-payload-cache.d.ts.map +1 -0
- package/dist/replay-payload-cache.js +158 -0
- package/dist/runtime/compute-instance.d.ts +13 -0
- package/dist/runtime/compute-instance.d.ts.map +1 -0
- package/dist/runtime/compute-instance.js +14 -0
- package/dist/runtime/constants.d.ts +315 -0
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +502 -16
- package/dist/runtime/count-step-started-events.d.ts +52 -0
- package/dist/runtime/count-step-started-events.d.ts.map +1 -0
- package/dist/runtime/count-step-started-events.js +72 -0
- package/dist/runtime/deployment-guard.d.ts +99 -0
- package/dist/runtime/deployment-guard.d.ts.map +1 -0
- package/dist/runtime/deployment-guard.js +154 -0
- package/dist/runtime/get-port-lazy.d.ts +15 -0
- package/dist/runtime/get-port-lazy.d.ts.map +1 -1
- package/dist/runtime/get-port-lazy.js +75 -6
- package/dist/runtime/get-world-lazy.d.ts +5 -14
- package/dist/runtime/get-world-lazy.d.ts.map +1 -1
- package/dist/runtime/get-world-lazy.js +19 -29
- package/dist/runtime/helpers.d.ts +341 -29
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +559 -57
- package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
- package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
- package/dist/runtime/quickjs-assets.generated.js +30 -0
- package/dist/runtime/quickjs-entrypoint.d.ts +136 -0
- package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
- package/dist/runtime/quickjs-entrypoint.js +1686 -0
- package/dist/runtime/quickjs-runtime.d.ts +244 -0
- package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
- package/dist/runtime/quickjs-runtime.js +2427 -0
- package/dist/runtime/quickjs-serde.d.ts +107 -0
- package/dist/runtime/quickjs-serde.d.ts.map +1 -0
- package/dist/runtime/quickjs-serde.js +2159 -0
- package/dist/runtime/replay-budget.d.ts +97 -0
- package/dist/runtime/replay-budget.d.ts.map +1 -0
- package/dist/runtime/replay-budget.js +139 -0
- package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
- package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
- package/dist/runtime/replay-recovery-reporter.js +64 -0
- package/dist/runtime/resume-hook.d.ts +91 -8
- package/dist/runtime/resume-hook.d.ts.map +1 -1
- package/dist/runtime/resume-hook.js +512 -89
- package/dist/runtime/resume-latency.d.ts +150 -0
- package/dist/runtime/resume-latency.d.ts.map +1 -0
- package/dist/runtime/resume-latency.js +155 -0
- package/dist/runtime/run-id-time.d.ts +19 -0
- package/dist/runtime/run-id-time.d.ts.map +1 -0
- package/dist/runtime/run-id-time.js +42 -0
- package/dist/runtime/run.d.ts +72 -7
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +280 -53
- package/dist/runtime/runs.d.ts +54 -3
- package/dist/runtime/runs.d.ts.map +1 -1
- package/dist/runtime/runs.js +126 -16
- package/dist/runtime/start.d.ts +101 -2
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +352 -61
- package/dist/runtime/step-executor.d.ts +205 -5
- package/dist/runtime/step-executor.d.ts.map +1 -1
- package/dist/runtime/step-executor.js +760 -127
- package/dist/runtime/step-latency.d.ts +220 -0
- package/dist/runtime/step-latency.d.ts.map +1 -0
- package/dist/runtime/step-latency.js +215 -0
- package/dist/runtime/step-ownership.d.ts +72 -0
- package/dist/runtime/step-ownership.d.ts.map +1 -0
- package/dist/runtime/step-ownership.js +114 -0
- package/dist/runtime/step-single-flight.d.ts +12 -0
- package/dist/runtime/step-single-flight.d.ts.map +1 -0
- package/dist/runtime/step-single-flight.js +75 -0
- package/dist/runtime/suspension-handler.d.ts +269 -7
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +1253 -125
- package/dist/runtime/unserializable-step.d.ts +34 -0
- package/dist/runtime/unserializable-step.d.ts.map +1 -0
- package/dist/runtime/unserializable-step.js +52 -0
- package/dist/runtime/vm-mode.d.ts +44 -0
- package/dist/runtime/vm-mode.d.ts.map +1 -0
- package/dist/runtime/vm-mode.js +62 -0
- package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
- package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
- package/dist/runtime/vm-serde-bundle.generated.js +16 -0
- package/dist/runtime/wait-continuation.d.ts +106 -0
- package/dist/runtime/wait-continuation.d.ts.map +1 -0
- package/dist/runtime/wait-continuation.js +136 -0
- package/dist/runtime/wait-until.d.ts +18 -0
- package/dist/runtime/wait-until.d.ts.map +1 -0
- package/dist/runtime/wait-until.js +42 -0
- package/dist/runtime/world-compatibility.d.ts +32 -0
- package/dist/runtime/world-compatibility.d.ts.map +1 -0
- package/dist/runtime/world-compatibility.js +44 -0
- package/dist/runtime/world-init.d.ts +17 -42
- package/dist/runtime/world-init.d.ts.map +1 -1
- package/dist/runtime/world-init.js +18 -43
- package/dist/runtime/world.d.ts +14 -2
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +75 -19
- package/dist/runtime.d.ts +10 -6
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +3741 -490
- package/dist/sealed-box.d.ts +167 -0
- package/dist/sealed-box.d.ts.map +1 -0
- package/dist/sealed-box.js +571 -0
- package/dist/serialization/client.d.ts +3 -3
- package/dist/serialization/client.d.ts.map +1 -1
- package/dist/serialization/client.js +8 -4
- package/dist/serialization/codec-devalue-vm.d.ts +16 -0
- package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
- package/dist/serialization/codec-devalue-vm.js +148 -0
- package/dist/serialization/codec-devalue.d.ts +1 -1
- package/dist/serialization/codec-devalue.d.ts.map +1 -1
- package/dist/serialization/codec-devalue.js +24 -6
- package/dist/serialization/codec.d.ts +37 -2
- package/dist/serialization/codec.d.ts.map +1 -1
- package/dist/serialization/codec.js +2 -2
- package/dist/serialization/compression.d.ts +105 -0
- package/dist/serialization/compression.d.ts.map +1 -0
- package/dist/serialization/compression.js +261 -0
- package/dist/serialization/encryption.d.ts +119 -17
- package/dist/serialization/encryption.d.ts.map +1 -1
- package/dist/serialization/encryption.js +152 -17
- package/dist/serialization/errors.d.ts +13 -0
- package/dist/serialization/errors.d.ts.map +1 -1
- package/dist/serialization/errors.js +20 -2
- package/dist/serialization/format.d.ts +6 -6
- package/dist/serialization/format.js +7 -7
- package/dist/serialization/hardened.d.ts +156 -0
- package/dist/serialization/hardened.d.ts.map +1 -0
- package/dist/serialization/hardened.js +538 -0
- package/dist/serialization/index.d.ts +10 -8
- package/dist/serialization/index.d.ts.map +1 -1
- package/dist/serialization/index.js +10 -8
- package/dist/serialization/reducers/class-vm.d.ts +20 -0
- package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/class-vm.js +77 -0
- package/dist/serialization/reducers/class.d.ts.map +1 -1
- package/dist/serialization/reducers/class.js +11 -6
- package/dist/serialization/reducers/common-vm.d.ts +15 -0
- package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/common-vm.js +616 -0
- package/dist/serialization/reducers/common.d.ts +1 -1
- package/dist/serialization/reducers/common.d.ts.map +1 -1
- package/dist/serialization/reducers/common.js +202 -62
- package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
- package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/step-function-vm.js +97 -0
- package/dist/serialization/reducers/step-function.d.ts.map +1 -1
- package/dist/serialization/reducers/step-function.js +25 -9
- package/dist/serialization/step.d.ts +4 -4
- package/dist/serialization/step.d.ts.map +1 -1
- package/dist/serialization/step.js +9 -5
- package/dist/serialization/types.d.ts +80 -1
- package/dist/serialization/types.d.ts.map +1 -1
- package/dist/serialization/types.js +15 -1
- package/dist/serialization/workflow-vm.d.ts +29 -0
- package/dist/serialization/workflow-vm.d.ts.map +1 -0
- package/dist/serialization/workflow-vm.js +74 -0
- package/dist/serialization-format.d.ts +64 -8
- package/dist/serialization-format.d.ts.map +1 -1
- package/dist/serialization-format.js +225 -73
- package/dist/serialization.d.ts +262 -34
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +1879 -274
- package/dist/set-attributes.d.ts +13 -0
- package/dist/set-attributes.d.ts.map +1 -0
- package/dist/set-attributes.js +60 -0
- package/dist/source-map.d.ts +25 -0
- package/dist/source-map.d.ts.map +1 -1
- package/dist/source-map.js +154 -10
- package/dist/step/context-storage.d.ts +61 -2
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +7 -5
- package/dist/step/writable-stream.d.ts +3 -3
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +72 -9
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +148 -27
- package/dist/symbols.d.ts +50 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +51 -1
- package/dist/telemetry/semantic-conventions.d.ts +397 -2
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +297 -3
- package/dist/telemetry.d.ts +91 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +244 -17
- package/dist/test-support/orchestrator-context.d.ts +25 -0
- package/dist/test-support/orchestrator-context.d.ts.map +1 -0
- package/dist/test-support/orchestrator-context.js +101 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +23 -1
- package/dist/util.d.ts +0 -5
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +1 -15
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -2
- package/dist/vm/index.d.ts.map +1 -1
- package/dist/vm/index.js +84 -14
- package/dist/vm/script-cache.d.ts +26 -0
- package/dist/vm/script-cache.d.ts.map +1 -0
- package/dist/vm/script-cache.js +131 -0
- package/dist/vm/uint8array-base64.js +1 -1
- package/dist/workflow/abort-controller.d.ts +2 -2
- package/dist/workflow/abort-controller.d.ts.map +1 -1
- package/dist/workflow/abort-controller.js +88 -21
- package/dist/workflow/attribute-dispatcher.d.ts +6 -0
- package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
- package/dist/workflow/attribute-dispatcher.js +45 -0
- package/dist/workflow/create-hook.d.ts.map +1 -1
- package/dist/workflow/create-hook.js +24 -3
- package/dist/workflow/get-workflow-metadata.js +2 -2
- package/dist/workflow/hook.d.ts.map +1 -1
- package/dist/workflow/hook.js +304 -47
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +2 -1
- package/dist/workflow/set-attributes.d.ts +68 -0
- package/dist/workflow/set-attributes.d.ts.map +1 -0
- package/dist/workflow/set-attributes.js +60 -0
- package/dist/workflow/sleep.d.ts.map +1 -1
- package/dist/workflow/sleep.js +58 -12
- package/dist/workflow/world-init-stub.d.ts +3 -3
- package/dist/workflow/world-init-stub.js +4 -4
- package/dist/workflow.d.ts +95 -3
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +895 -561
- package/docs/api-reference/create-hook.mdx +89 -10
- package/docs/api-reference/create-webhook.mdx +16 -15
- package/docs/api-reference/define-hook.mdx +35 -33
- package/docs/api-reference/fatal-error.mdx +30 -8
- package/docs/api-reference/fetch.mdx +14 -10
- package/docs/api-reference/get-step-metadata.mdx +2 -2
- package/docs/api-reference/get-workflow-metadata.mdx +3 -3
- package/docs/api-reference/get-writable.mdx +7 -7
- package/docs/api-reference/index.mdx +4 -1
- package/docs/api-reference/retryable-error.mdx +1 -1
- package/docs/api-reference/set-attributes.mdx +61 -0
- package/docs/api-reference/sleep.mdx +4 -4
- package/docs/foundations/cancellation.mdx +31 -32
- package/docs/foundations/errors-and-retries.mdx +42 -11
- package/docs/foundations/hooks.mdx +64 -35
- package/docs/foundations/idempotency.mdx +244 -12
- package/docs/foundations/index.mdx +1 -23
- package/docs/foundations/meta.json +2 -1
- package/docs/foundations/serialization.mdx +21 -22
- package/docs/foundations/starting-workflows.mdx +106 -30
- package/docs/foundations/streaming.mdx +107 -59
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/foundations/workflows-and-steps.mdx +9 -9
- package/docs/how-it-works/cancellation.mdx +63 -63
- package/docs/how-it-works/code-transform.mdx +83 -67
- package/docs/how-it-works/encryption.mdx +30 -26
- package/docs/how-it-works/event-sourcing.mdx +98 -34
- package/docs/how-it-works/framework-integrations.mdx +96 -337
- package/docs/how-it-works/understanding-directives.mdx +22 -22
- package/package.json +24 -15
- package/dist/runtime/step-handler.d.ts +0 -2
- package/dist/runtime/step-handler.d.ts.map +0 -1
- package/dist/runtime/step-handler.js +0 -776
|
@@ -2,63 +2,53 @@
|
|
|
2
2
|
title: Framework Integrations
|
|
3
3
|
description: Guide for framework authors to integrate Workflow SDK with custom frameworks or runtimes.
|
|
4
4
|
type: guide
|
|
5
|
-
summary: Build a custom framework integration using the Workflow SDK compiler and runtime.
|
|
5
|
+
summary: Build a custom framework integration using the Workflow SDK compiler and combined runtime handler.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/foundations/workflows-and-steps
|
|
8
8
|
related:
|
|
9
|
-
- /
|
|
9
|
+
- /worlds/building-a-world
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
<Callout>
|
|
13
|
-
**For users:** If you
|
|
13
|
+
**For users:** If you want to use Workflow SDK with an existing framework, see [Getting Started](/docs/getting-started). This page is for framework authors.
|
|
14
14
|
</Callout>
|
|
15
15
|
|
|
16
|
-
This guide
|
|
16
|
+
This guide uses Bun as a concrete example, but the same build and routing model applies to other JavaScript frameworks and runtimes.
|
|
17
17
|
|
|
18
18
|
<Callout type="info">
|
|
19
|
-
|
|
19
|
+
Read [How the Directives Work](/docs/how-it-works/code-transform) first if you are not familiar with the three compiler modes.
|
|
20
20
|
</Callout>
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Integration shape
|
|
23
23
|
|
|
24
|
-
A framework integration has two
|
|
24
|
+
A framework integration has two responsibilities:
|
|
25
25
|
|
|
26
|
-
1. **Build
|
|
27
|
-
2. **Runtime
|
|
26
|
+
1. **Build time:** transform workflow and step code, register the steps, and generate the combined flow handler.
|
|
27
|
+
2. **Runtime:** expose the generated flow and webhook handlers as HTTP routes.
|
|
28
28
|
|
|
29
29
|
```mermaid
|
|
30
30
|
flowchart TD
|
|
31
|
-
A["Source
|
|
32
|
-
B --> C["
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
C -->
|
|
36
|
-
|
|
37
|
-
E -->
|
|
38
|
-
|
|
39
|
-
F --> I["Used by framework loader"]
|
|
40
|
-
G --> J["HTTP Server<br/>(Your Runtime)"]
|
|
41
|
-
H --> J
|
|
42
|
-
L --> J
|
|
31
|
+
A["Source code<br/>'use workflow' / 'use step'"] --> B["Workflow builder"]
|
|
32
|
+
B --> C["Workflow-mode bundle"]
|
|
33
|
+
B --> D["Step registration bundle"]
|
|
34
|
+
D --> E["Combined flow handler"]
|
|
35
|
+
C --> E
|
|
36
|
+
B --> F["Webhook handler"]
|
|
37
|
+
E --> G["POST /.well-known/workflow/v1/flow"]
|
|
38
|
+
F --> H["/.well-known/workflow/v1/webhook/:token"]
|
|
43
39
|
|
|
44
40
|
style B fill:#a78bfa,stroke:#8b5cf6,color:#000
|
|
45
|
-
style
|
|
46
|
-
style
|
|
41
|
+
style G fill:#a78bfa,stroke:#8b5cf6,color:#000
|
|
42
|
+
style H fill:#a78bfa,stroke:#8b5cf6,color:#000
|
|
47
43
|
```
|
|
48
44
|
|
|
49
|
-
|
|
45
|
+
Steps do not have their own HTTP route. A queued step invocation contains `stepId` and `stepName` and is delivered to the flow handler on the workflow queue. The handler executes the registered step in the full host runtime, then replays the workflow in its sandboxed VM.
|
|
50
46
|
|
|
51
|
-
## Example: Bun
|
|
47
|
+
## Example: Bun integration
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
### 1. Generate the bundles
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
A working example can be [found here](https://github.com/vercel/workflow-examples/tree/main/custom-adapter). For a production-ready reference, see the [Next.js integration](https://github.com/vercel/workflow/tree/main/packages/next).
|
|
57
|
-
</Callout>
|
|
58
|
-
|
|
59
|
-
### Step 1: Generate Handler Files
|
|
60
|
-
|
|
61
|
-
Use the `workflow` CLI to generate the handler bundles. The CLI scans your `workflows/` directory and creates `flow.js`, `step.js`, and `webhook.js`.
|
|
51
|
+
The standalone Workflow CLI scans `workflows/` and creates the combined flow handler, an internal step registration module, and the webhook handler.
|
|
62
52
|
|
|
63
53
|
```json title="package.json"
|
|
64
54
|
{
|
|
@@ -68,21 +58,19 @@ Use the `workflow` CLI to generate the handler bundles. The CLI scans your `work
|
|
|
68
58
|
}
|
|
69
59
|
```
|
|
70
60
|
|
|
71
|
-
|
|
72
|
-
**For production integrations:** Instead of using the CLI, extend the `BaseBuilder` class directly in your framework plugin. This gives you control over file watching, custom output paths, and framework-specific hooks. See the [Next.js plugin](https://github.com/vercel/workflow/tree/main/packages/next) for an example.
|
|
73
|
-
</Callout>
|
|
74
|
-
|
|
75
|
-
**What gets generated:**
|
|
61
|
+
The default output is:
|
|
76
62
|
|
|
77
|
-
- `/.well-known/workflow/v1/flow.
|
|
78
|
-
- `/.well-known/workflow/v1/
|
|
79
|
-
- `/.well-known/workflow/v1/webhook.
|
|
63
|
+
- `/.well-known/workflow/v1/flow.mjs`: the combined workflow and step queue consumer
|
|
64
|
+
- `/.well-known/workflow/v1/__step_registrations.mjs`: an internal module imported by `flow.mjs`; do not route to it
|
|
65
|
+
- `/.well-known/workflow/v1/webhook.mjs`: webhook delivery
|
|
80
66
|
|
|
81
|
-
|
|
67
|
+
<Callout>
|
|
68
|
+
Production integrations should extend `BaseBuilder` from `@workflow/builders` so they can participate in the framework's build, watch, and routing lifecycle.
|
|
69
|
+
</Callout>
|
|
82
70
|
|
|
83
|
-
###
|
|
71
|
+
### 2. Add the app-code transform
|
|
84
72
|
|
|
85
|
-
|
|
73
|
+
Applying the step-mode transform to application code gives it the workflow IDs used by `start()` and prevents accidental direct workflow execution. (Earlier releases used a separate `client` mode for this; it merged into `step` in 5.0.)
|
|
86
74
|
|
|
87
75
|
{/* @skip-typecheck: incomplete code sample */}
|
|
88
76
|
```typescript title="workflow-plugin.ts" lineNumbers
|
|
@@ -94,8 +82,6 @@ plugin({
|
|
|
94
82
|
setup(build) {
|
|
95
83
|
build.onLoad({ filter: /\.(ts|tsx|js|jsx)$/ }, async (args) => {
|
|
96
84
|
const source = await Bun.file(args.path).text();
|
|
97
|
-
|
|
98
|
-
// Optimization: Skip files that do not have any directives
|
|
99
85
|
if (!source.match(/(use step|use workflow)/)) {
|
|
100
86
|
return { contents: source };
|
|
101
87
|
}
|
|
@@ -105,7 +91,7 @@ plugin({
|
|
|
105
91
|
jsc: {
|
|
106
92
|
experimental: {
|
|
107
93
|
plugins: [
|
|
108
|
-
[require.resolve("@workflow/swc-plugin"), { mode: "
|
|
94
|
+
[require.resolve("@workflow/swc-plugin"), { mode: "step" }],
|
|
109
95
|
],
|
|
110
96
|
},
|
|
111
97
|
},
|
|
@@ -123,23 +109,14 @@ Activate the plugin in `bunfig.toml`:
|
|
|
123
109
|
preload = ["./workflow-plugin.ts"]
|
|
124
110
|
```
|
|
125
111
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
- Attaches workflow IDs to functions for use with `start()`
|
|
129
|
-
- Provides TypeScript type safety
|
|
130
|
-
- Prevents accidental direct execution of workflows
|
|
131
|
-
|
|
132
|
-
**Why optional?** Without client mode, you can still use workflows by manually constructing IDs or referencing the build manifest.
|
|
133
|
-
|
|
134
|
-
### Step 3: Expose HTTP Endpoints
|
|
112
|
+
### 3. Expose the HTTP routes
|
|
135
113
|
|
|
136
|
-
|
|
114
|
+
Only the combined flow handler and webhook handler are routable:
|
|
137
115
|
|
|
138
116
|
{/* @skip-typecheck: incomplete code sample */}
|
|
139
117
|
```typescript title="server.ts" lineNumbers
|
|
140
|
-
import flow from "./.well-known/workflow/v1/flow.
|
|
141
|
-
import
|
|
142
|
-
import * as webhook from "./.well-known/workflow/v1/webhook.js";
|
|
118
|
+
import * as flow from "./.well-known/workflow/v1/flow.mjs";
|
|
119
|
+
import * as webhook from "./.well-known/workflow/v1/webhook.mjs";
|
|
143
120
|
|
|
144
121
|
import { start } from "workflow/api";
|
|
145
122
|
import { handleUserSignup } from "./workflows/user-signup.js";
|
|
@@ -148,23 +125,14 @@ const server = Bun.serve({
|
|
|
148
125
|
port: process.env.PORT,
|
|
149
126
|
routes: {
|
|
150
127
|
"/.well-known/workflow/v1/flow": {
|
|
151
|
-
POST:
|
|
128
|
+
POST: flow.POST,
|
|
152
129
|
},
|
|
153
|
-
"/.well-known/workflow/v1/step": {
|
|
154
|
-
POST: (req) => step.POST(req),
|
|
155
|
-
},
|
|
156
|
-
// webhook exports handlers for GET, POST, DELETE, etc.
|
|
157
130
|
"/.well-known/workflow/v1/webhook/:token": webhook,
|
|
158
|
-
|
|
159
|
-
// Example: Start a workflow
|
|
160
131
|
"/": {
|
|
161
|
-
GET: async (
|
|
132
|
+
GET: async () => {
|
|
162
133
|
const email = `test-${crypto.randomUUID()}@test.com`;
|
|
163
134
|
const run = await start(handleUserSignup, [email]);
|
|
164
|
-
return Response.json({
|
|
165
|
-
message: "User signup workflow started",
|
|
166
|
-
runId: run.runId,
|
|
167
|
-
});
|
|
135
|
+
return Response.json({ runId: run.runId });
|
|
168
136
|
},
|
|
169
137
|
},
|
|
170
138
|
},
|
|
@@ -173,222 +141,90 @@ const server = Bun.serve({
|
|
|
173
141
|
console.log(`Server listening on http://localhost:${server.port}`);
|
|
174
142
|
```
|
|
175
143
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
## Understanding the Endpoints
|
|
179
|
-
|
|
180
|
-
Your integration must expose three HTTP endpoints. The generated handlers manage all protocol details—you just route requests.
|
|
144
|
+
## Runtime routes
|
|
181
145
|
|
|
182
|
-
###
|
|
146
|
+
### Combined flow endpoint
|
|
183
147
|
|
|
184
148
|
**Route:** `POST /.well-known/workflow/v1/flow`
|
|
185
149
|
|
|
186
|
-
|
|
150
|
+
The handler consumes every workflow queue message. Depending on the payload and event log, it can:
|
|
187
151
|
|
|
188
|
-
|
|
152
|
+
- Start or replay workflow orchestration in the sandboxed VM.
|
|
153
|
+
- Execute a queued step in the host runtime.
|
|
154
|
+
- Continue replay inline after a step completes.
|
|
155
|
+
- Resume a run after a hook, webhook, sleep, retry, or recovery event.
|
|
189
156
|
|
|
190
|
-
|
|
191
|
-
- Resuming after a step completes
|
|
192
|
-
- Resuming after a webhook or hook triggers
|
|
193
|
-
- Recovering from failures
|
|
157
|
+
### Webhook endpoint
|
|
194
158
|
|
|
195
|
-
|
|
159
|
+
**Route:** `/.well-known/workflow/v1/webhook/:token`
|
|
196
160
|
|
|
197
|
-
|
|
161
|
+
This handler delivers data to [`createWebhook()`](/docs/api-reference/workflow/create-webhook). Its generated file structure varies by framework; for example, Next.js uses `webhook/[token]/route.js`.
|
|
198
162
|
|
|
199
|
-
|
|
163
|
+
## Building with `BaseBuilder`
|
|
200
164
|
|
|
201
|
-
|
|
165
|
+
Use `createCombinedBundle()` so the flow bundle imports the generated step registrations. Calling `createWorkflowsBundle()` and `createStepsBundle()` independently does not create a complete runtime route.
|
|
202
166
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
<Callout type="info">
|
|
208
|
-
The webhook file structure varies by framework. Next.js generates `webhook/[token]/route.js` to leverage App Router's dynamic routing, while other frameworks generate a single `webhook.js` handler.
|
|
209
|
-
</Callout>
|
|
210
|
-
|
|
211
|
-
## Adapting to Other Frameworks
|
|
212
|
-
|
|
213
|
-
The Bun example demonstrates the core pattern. To adapt for your framework:
|
|
214
|
-
|
|
215
|
-
### Build-Time
|
|
216
|
-
|
|
217
|
-
**Option 1: Use the CLI** (simplest)
|
|
218
|
-
|
|
219
|
-
```bash
|
|
220
|
-
workflow build
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
This will default to scanning the `./workflows` top-level directory for workflow files, and will output bundled files directly into your working directory.
|
|
224
|
-
|
|
225
|
-
**Option 2: Extend `BaseBuilder`** (recommended)
|
|
226
|
-
|
|
227
|
-
{/* @skip-typecheck: @workflow/cli internal module */}
|
|
228
|
-
```typescript lineNumbers
|
|
229
|
-
import { BaseBuilder } from "@workflow/cli/dist/lib/builders/base-builder";
|
|
167
|
+
{/* @skip-typecheck: incomplete framework adapter */}
|
|
168
|
+
```typescript title="my-framework-builder.ts" lineNumbers
|
|
169
|
+
import { join } from "node:path";
|
|
170
|
+
import { BaseBuilder } from "@workflow/builders";
|
|
230
171
|
|
|
231
172
|
class MyFrameworkBuilder extends BaseBuilder {
|
|
232
|
-
constructor(options) {
|
|
233
|
-
super({
|
|
234
|
-
dirs: ["workflows"],
|
|
235
|
-
workingDir: options.rootDir,
|
|
236
|
-
watch: options.dev,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
|
|
240
173
|
override async build(): Promise<void> {
|
|
241
174
|
const inputFiles = await this.getInputFiles();
|
|
175
|
+
const tsconfigPath = await this.findTsConfigPath();
|
|
176
|
+
const outputDir = join(this.config.workingDir, ".workflow");
|
|
242
177
|
|
|
243
|
-
await this.
|
|
244
|
-
outfile: "/path/to/.well-known/workflow/v1/flow.js",
|
|
245
|
-
format: "esm",
|
|
178
|
+
await this.createCombinedBundle({
|
|
246
179
|
inputFiles,
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
outfile: "/path/to/.well-known/workflow/v1/step.js",
|
|
180
|
+
stepsOutfile: join(outputDir, "__step_registrations.mjs"),
|
|
181
|
+
flowOutfile: join(outputDir, "flow.mjs"),
|
|
182
|
+
tsconfigPath,
|
|
251
183
|
format: "esm",
|
|
252
|
-
inputFiles,
|
|
253
184
|
});
|
|
254
185
|
|
|
255
186
|
await this.createWebhookBundle({
|
|
256
|
-
outfile: "
|
|
187
|
+
outfile: join(outputDir, "webhook.mjs"),
|
|
257
188
|
});
|
|
258
189
|
}
|
|
259
190
|
}
|
|
260
191
|
```
|
|
261
192
|
|
|
262
|
-
If
|
|
263
|
-
|
|
264
|
-
### Monorepos and Workspace Imports
|
|
193
|
+
If workflows import sibling workspace packages, set `projectRoot` to the smallest directory containing all imported packages.
|
|
265
194
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
{
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
constructor(options: {
|
|
274
|
-
rootDir: string;
|
|
275
|
-
workspaceRoot?: string;
|
|
276
|
-
dev: boolean;
|
|
277
|
-
}) {
|
|
278
|
-
super({
|
|
279
|
-
dirs: ["workflows"],
|
|
280
|
-
workingDir: options.rootDir,
|
|
281
|
-
projectRoot: options.workspaceRoot ?? options.rootDir, // [!code highlight]
|
|
282
|
-
watch: options.dev,
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
override async build(): Promise<void> {
|
|
287
|
-
const inputFiles = await this.getInputFiles();
|
|
288
|
-
// ...
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
Hook into your framework's build:
|
|
294
|
-
|
|
295
|
-
{/* @skip-typecheck: incomplete code sample */}
|
|
296
|
-
```typescript title="pseudocode.ts" lineNumbers
|
|
297
|
-
framework.hooks.hook("build:before", async () => {
|
|
298
|
-
await new MyFrameworkBuilder(framework).build();
|
|
195
|
+
{/* @skip-typecheck: partial constructor configuration */}
|
|
196
|
+
```typescript
|
|
197
|
+
super({
|
|
198
|
+
dirs: ["workflows"],
|
|
199
|
+
workingDir: options.rootDir,
|
|
200
|
+
projectRoot: options.workspaceRoot ?? options.rootDir,
|
|
201
|
+
watch: options.dev,
|
|
299
202
|
});
|
|
300
203
|
```
|
|
301
204
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
Add a loader/plugin for your bundler:
|
|
305
|
-
|
|
306
|
-
**Rollup/Vite:**
|
|
205
|
+
Your integration can expose physical files, virtual modules, or framework-native routes. In every case, the step registration module is a dependency of the flow handler, not a route of its own.
|
|
307
206
|
|
|
308
|
-
|
|
309
|
-
export function workflowPlugin() {
|
|
310
|
-
return {
|
|
311
|
-
name: "workflow-client-transform",
|
|
312
|
-
async transform(code, id) {
|
|
313
|
-
if (!code.match(/(use step|use workflow)/)) return null;
|
|
207
|
+
## Vercel queue configuration
|
|
314
208
|
|
|
315
|
-
|
|
316
|
-
filename: id,
|
|
317
|
-
jsc: {
|
|
318
|
-
experimental: {
|
|
319
|
-
plugins: [[require.resolve("@workflow/swc-plugin"), { mode: "client" }]], // [!code highlight]
|
|
320
|
-
},
|
|
321
|
-
},
|
|
322
|
-
});
|
|
209
|
+
On Vercel, configure the flow function as the sole queue consumer. `getWorkflowQueueTrigger()` handles the optional queue namespace and `WORKFLOW_SEQUENTIAL_REPLAYS=1` behavior.
|
|
323
210
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
**Webpack:**
|
|
211
|
+
```typescript
|
|
212
|
+
import { getWorkflowQueueTrigger } from "@workflow/builders";
|
|
331
213
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
rules: [
|
|
336
|
-
{
|
|
337
|
-
test: /\.(ts|tsx|js|jsx)$/,
|
|
338
|
-
use: "workflow-client-loader", // Similar implementation
|
|
339
|
-
},
|
|
340
|
-
],
|
|
341
|
-
},
|
|
214
|
+
const flowConfig = {
|
|
215
|
+
maxDuration: "max",
|
|
216
|
+
experimentalTriggers: [getWorkflowQueueTrigger()],
|
|
342
217
|
};
|
|
343
218
|
```
|
|
344
219
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
Route the three endpoints to the generated handlers. The exact implementation depends on your framework's routing API.
|
|
348
|
-
|
|
349
|
-
In the bun example above, we left routing to the user. Essentially, the user has to serve routes like this:
|
|
350
|
-
|
|
351
|
-
{/* @skip-typecheck: incomplete code sample */}
|
|
352
|
-
```typescript title="server.ts" lineNumbers
|
|
353
|
-
import flow from "./.well-known/workflow/v1/flow.js";
|
|
354
|
-
import step from "./.well-known/workflow/v1/step.js";
|
|
355
|
-
import * as webhook from "./.well-known/workflow/v1/webhook.js";
|
|
220
|
+
The generated trigger listens to one topic family:
|
|
356
221
|
|
|
357
|
-
|
|
358
|
-
const server = Bun.serve({
|
|
359
|
-
routes: {
|
|
360
|
-
"/.well-known/workflow/v1/flow": {
|
|
361
|
-
POST: (req) => flow.POST(req),
|
|
362
|
-
},
|
|
363
|
-
"/.well-known/workflow/v1/step": {
|
|
364
|
-
POST: (req) => step.POST(req),
|
|
365
|
-
},
|
|
366
|
-
// webhook exports handlers for GET, POST, DELETE, etc.
|
|
367
|
-
"/.well-known/workflow/v1/webhook/:token": webhook,
|
|
368
|
-
},
|
|
369
|
-
});
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
Production framework integrations should handle this routing in the plugin instead of leaving it to the user, and this depends on each framework's unique implementaiton.
|
|
373
|
-
Check the Workflow SDK source code for examples of production framework implementations.
|
|
374
|
-
In the future, the Workflow SDK will emit more routes under the `.well-known/workflow` namespace.
|
|
375
|
-
|
|
376
|
-
## Security
|
|
377
|
-
|
|
378
|
-
The workflow and step handler endpoints are invoked by the world's queuing infrastructure, not by end users. How they're secured depends on which world you're deploying to.
|
|
379
|
-
|
|
380
|
-
### Vercel (`@workflow/world-vercel`)
|
|
381
|
-
|
|
382
|
-
On Vercel, workflow handler functions are not accessible through public endpoints. Handlers use the same [consumer function security](https://vercel.com/docs/queues/concepts#consumer-function-security) mechanism that secures [Vercel Queues](https://vercel.com/docs/queues) consumers.
|
|
383
|
-
|
|
384
|
-
During the build step, the Workflow SDK automatically configures each handler as a queue consumer by writing `experimentalTriggers` to the function's `.vc-config.json`:
|
|
385
|
-
|
|
386
|
-
```json title=".vc-config.json (generated by Workflow SDK)"
|
|
222
|
+
```json title=".vc-config.json (excerpt)"
|
|
387
223
|
{
|
|
388
224
|
"experimentalTriggers": [
|
|
389
225
|
{
|
|
390
226
|
"type": "queue/v2beta",
|
|
391
|
-
"topic": "
|
|
227
|
+
"topic": "__wkf_workflow_*",
|
|
392
228
|
"consumer": "default",
|
|
393
229
|
"retryAfterSeconds": 5,
|
|
394
230
|
"initialDelaySeconds": 0
|
|
@@ -397,105 +233,28 @@ During the build step, the Workflow SDK automatically configures each handler as
|
|
|
397
233
|
}
|
|
398
234
|
```
|
|
399
235
|
|
|
236
|
+
Both orchestration messages and step messages use this topic family. A step message is distinguished by its payload, not by a second topic or function.
|
|
400
237
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
| Handler | Topic | Description |
|
|
404
|
-
| --- | --- | --- |
|
|
405
|
-
| `step.func` | `__wkf_step_*` | Step execution (long-running, `maxDuration: max`) |
|
|
406
|
-
| `flow.func` | `__wkf_workflow_*` | Workflow orchestration (`maxDuration: 60`) |
|
|
407
|
-
|
|
408
|
-
If you're building a framework integration that targets Vercel, you should write these triggers into the `.vc-config.json` for each generated function. The `STEP_QUEUE_TRIGGER` and `WORKFLOW_QUEUE_TRIGGER` constants are exported from `@workflow/builders` for this purpose:
|
|
409
|
-
|
|
410
|
-
```typescript
|
|
411
|
-
import { STEP_QUEUE_TRIGGER, WORKFLOW_QUEUE_TRIGGER } from "@workflow/builders";
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
### Custom implementations
|
|
238
|
+
If you construct the trigger yourself, add `maxConcurrency: 1` when `WORKFLOW_SEQUENTIAL_REPLAYS=1`. The exported `isSequentialReplaysEnabled()` helper implements that build-time check.
|
|
416
239
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
- **Framework middleware** — Add authentication (API keys, JWT, OIDC) in front of the `/.well-known/workflow/v1/*` routes
|
|
420
|
-
- **Network-level security** — Deploy handlers behind a VPC, private network, or firewall rules so only your queue infrastructure can reach them
|
|
421
|
-
- **Rate limiting** — Add request validation and rate limiting to prevent abuse
|
|
422
|
-
|
|
423
|
-
Learn more about [building custom Worlds](/docs/deploying/building-a-world).
|
|
424
|
-
|
|
425
|
-
## Testing Your Integration
|
|
426
|
-
|
|
427
|
-
### 1. Test Build Output
|
|
428
|
-
|
|
429
|
-
Create a test workflow:
|
|
430
|
-
|
|
431
|
-
```typescript title="workflows/test.ts" lineNumbers
|
|
432
|
-
import { sleep, createWebhook } from "workflow";
|
|
433
|
-
|
|
434
|
-
export async function handleUserSignup(email: string) {
|
|
435
|
-
"use workflow";
|
|
436
|
-
|
|
437
|
-
const user = await createUser(email);
|
|
438
|
-
await sendWelcomeEmail(user);
|
|
439
|
-
|
|
440
|
-
await sleep("5s");
|
|
441
|
-
|
|
442
|
-
const webhook = createWebhook();
|
|
443
|
-
await sendOnboardingEmail(user, webhook.url);
|
|
444
|
-
|
|
445
|
-
await webhook;
|
|
446
|
-
console.log("Webhook Resolved");
|
|
447
|
-
|
|
448
|
-
return { userId: user.id, status: "onboarded" };
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
async function createUser(email: string) {
|
|
452
|
-
"use step";
|
|
453
|
-
|
|
454
|
-
console.log(`Creating a new user with email: ${email}`);
|
|
455
|
-
|
|
456
|
-
return { id: crypto.randomUUID(), email };
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
async function sendWelcomeEmail(user: { id: string; email: string }) {
|
|
460
|
-
"use step";
|
|
461
|
-
|
|
462
|
-
console.log(`Sending welcome email to user: ${user.id}`);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
async function sendOnboardingEmail(user: { id: string; email: string }, callback: string) {
|
|
466
|
-
"use step";
|
|
467
|
-
|
|
468
|
-
console.log(`Sending onboarding email to user: ${user.id}`);
|
|
469
|
-
|
|
470
|
-
console.log(`Click this link to resolve the webhook: ${callback}`);
|
|
471
|
-
}
|
|
240
|
+
## Security
|
|
472
241
|
|
|
473
|
-
|
|
242
|
+
On Vercel, the flow handler uses [queue consumer security](https://vercel.com/docs/queues/concepts#consumer-function-security). For self-hosted worlds, protect the flow and webhook routes with the authentication, network controls, and rate limits appropriate to your queue transport.
|
|
474
243
|
|
|
475
|
-
|
|
244
|
+
## Testing an integration
|
|
476
245
|
|
|
477
|
-
|
|
478
|
-
- `.well-known/workflow/v1/step.js` exists
|
|
479
|
-
- `.well-known/workflow/v1/webhook.js` exists
|
|
246
|
+
After a build, verify that:
|
|
480
247
|
|
|
481
|
-
|
|
248
|
+
- the flow handler exists and imports or embeds the step registration bundle;
|
|
249
|
+
- the webhook handler exists;
|
|
250
|
+
- no step HTTP route or step queue trigger is generated;
|
|
251
|
+
- the flow function has the workflow queue trigger and the required maximum duration;
|
|
252
|
+
- starting a workflow executes a real step and resumes the workflow.
|
|
482
253
|
|
|
483
|
-
|
|
254
|
+
The flow route exposes a lightweight direct health mode:
|
|
484
255
|
|
|
485
256
|
```bash
|
|
486
|
-
curl -X POST http://localhost:3000/.well-known/workflow/v1/flow
|
|
487
|
-
curl -X POST http://localhost:3000/.well-known/workflow/v1/step
|
|
488
|
-
curl -X POST http://localhost:3000/.well-known/workflow/v1/webhook/test
|
|
257
|
+
curl -X POST "http://localhost:3000/.well-known/workflow/v1/flow?__health"
|
|
489
258
|
```
|
|
490
259
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
### 3. Run a Workflow End-to-End
|
|
494
|
-
|
|
495
|
-
```typescript
|
|
496
|
-
import { start } from "workflow/api";
|
|
497
|
-
import { handleUserSignup } from "./workflows/test";
|
|
498
|
-
|
|
499
|
-
const run = await start(handleUserSignup, ["test@example.com"]);
|
|
500
|
-
console.log("Workflow started:", run.runId);
|
|
501
|
-
```
|
|
260
|
+
For an end-to-end queue check, use [`healthCheck()`](/docs/api-reference/workflow-runtime/health-check).
|