@workflow/core 5.0.0-beta.5 → 5.0.0-beta.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- 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 +297 -0
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +673 -42
- package/dist/flushable-stream.d.ts +97 -1
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +291 -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 +19 -12
- 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-divergence.d.ts +25 -0
- package/dist/replay-divergence.d.ts.map +1 -0
- package/dist/replay-divergence.js +61 -0
- 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 +415 -29
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +686 -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 +158 -0
- package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
- package/dist/runtime/quickjs-entrypoint.js +1863 -0
- package/dist/runtime/quickjs-log-view.d.ts +129 -0
- package/dist/runtime/quickjs-log-view.d.ts.map +1 -0
- package/dist/runtime/quickjs-log-view.js +229 -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 +186 -5
- package/dist/runtime/step-executor.d.ts.map +1 -1
- package/dist/runtime/step-executor.js +768 -130
- 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 +247 -7
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +1304 -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 +3911 -489
- 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 +1885 -277
- 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 +63 -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 +80 -13
- 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 +433 -2
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +319 -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 +107 -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 +900 -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 +108 -60
- 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 +125 -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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: How the
|
|
2
|
+
title: How the directives work
|
|
3
3
|
description: Deep dive into the internals of how Workflow SDK directives transform your code.
|
|
4
4
|
type: conceptual
|
|
5
5
|
summary: Learn how the compiler transforms directive-annotated code into three execution modes.
|
|
@@ -10,16 +10,15 @@ related:
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
<Callout>
|
|
13
|
-
This
|
|
13
|
+
This advanced guide covers the internals of Workflow SDK directives. To start using Workflow SDK, see the [getting started](/docs/getting-started) guide for your framework.
|
|
14
14
|
</Callout>
|
|
15
15
|
|
|
16
|
-
Workflows use special directives to mark code for transformation by the Workflow SDK compiler.
|
|
16
|
+
Workflows use special directives to mark code for transformation by the Workflow SDK compiler. The `"use workflow"` and `"use step"` directives apply the transformations required for durable execution.
|
|
17
17
|
|
|
18
|
-
## Directives
|
|
18
|
+
## Directives overview
|
|
19
19
|
|
|
20
20
|
Workflows use two directives to mark functions for special handling:
|
|
21
21
|
|
|
22
|
-
{/* @skip-typecheck: incomplete code sample */}
|
|
23
22
|
```typescript
|
|
24
23
|
export async function handleUserSignup(email: string) {
|
|
25
24
|
"use workflow"; // [!code highlight]
|
|
@@ -44,7 +43,7 @@ async function createUser(email: string) {
|
|
|
44
43
|
|
|
45
44
|
These directives trigger the `@workflow/swc-plugin` compiler to transform your code in different ways depending on the execution context.
|
|
46
45
|
|
|
47
|
-
## The
|
|
46
|
+
## The three transformation modes
|
|
48
47
|
|
|
49
48
|
The compiler operates in three distinct modes, transforming the same source code differently for each execution context:
|
|
50
49
|
|
|
@@ -52,37 +51,47 @@ The compiler operates in three distinct modes, transforming the same source code
|
|
|
52
51
|
flowchart LR
|
|
53
52
|
A["Source Code<br/>with directives"] --> B["Step Mode"]
|
|
54
53
|
A --> C["Workflow Mode"]
|
|
55
|
-
A --> D["
|
|
56
|
-
B --> E["
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
A --> D["Detect Mode"]
|
|
55
|
+
B --> E["Step registration bundle"]
|
|
56
|
+
B --> G["Your App Code<br/>(Enables `start`)"]
|
|
57
|
+
C --> F["Workflow bundle"]
|
|
58
|
+
E --> H["Combined flow handler"]
|
|
59
|
+
F --> H
|
|
60
|
+
D --> I["Build manifest<br/>(discovery)"]
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
### Comparison
|
|
63
|
+
### Comparison table
|
|
62
64
|
|
|
63
|
-
| Mode | Used In | Purpose |
|
|
64
|
-
|
|
65
|
-
| Step | Build time |
|
|
66
|
-
| Workflow | Build time | Bundles workflow orchestrators | `.well-known/workflow/v1/flow`
|
|
67
|
-
|
|
|
65
|
+
| Mode | Used In | Purpose | Runtime role | Required? |
|
|
66
|
+
|----------|------------|--------------------------------|--------------|-----------|
|
|
67
|
+
| Step | Build time + your app code | Registers executable step functions; gives app code workflow IDs for `start()` | Imported by the combined flow handler, and applied to application code by the framework loader | Yes |
|
|
68
|
+
| Workflow | Build time | Bundles workflow orchestrators | Executed by `.well-known/workflow/v1/flow` | Yes |
|
|
69
|
+
| Detect | Build time | Discovers workflows, steps, and serialization classes without transforming code | Feeds the build's discovery phase and manifest | Yes (build-internal) |
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
<Callout type="info">
|
|
72
|
+
Earlier releases had a separate **client mode** for application code. In 5.0 it merged into step mode, which produces the same app-code behavior (workflow functions throw on direct calls and carry `workflowId` for `start()`) while also registering step functions. Build integrations that passed `mode: "client"` now pass `mode: "step"`.
|
|
73
|
+
</Callout>
|
|
70
74
|
|
|
71
|
-
## Detailed
|
|
75
|
+
## Detailed transformation examples
|
|
72
76
|
|
|
73
|
-
<Tabs items={["Step Mode", "Workflow Mode", "
|
|
77
|
+
<Tabs items={["Step Mode", "Workflow Mode", "Detect Mode"]}>
|
|
74
78
|
<Tab value="Step Mode">
|
|
75
79
|
|
|
76
|
-
**Step Mode** creates the
|
|
80
|
+
**Step Mode** creates the registration bundle that the combined flow handler imports (it is not an HTTP route), and is also the transform framework loaders apply to your application code.
|
|
77
81
|
|
|
78
82
|
**Input:**
|
|
79
83
|
|
|
80
|
-
{/* @skip-typecheck: incomplete code sample */}
|
|
81
84
|
```typescript
|
|
82
85
|
export async function createUser(email: string) {
|
|
83
86
|
"use step";
|
|
84
87
|
return { id: crypto.randomUUID(), email };
|
|
85
88
|
}
|
|
89
|
+
|
|
90
|
+
export async function handleUserSignup(email: string) {
|
|
91
|
+
"use workflow";
|
|
92
|
+
const user = await createUser(email);
|
|
93
|
+
return { userId: user.id };
|
|
94
|
+
}
|
|
86
95
|
```
|
|
87
96
|
|
|
88
97
|
**Output:**
|
|
@@ -97,18 +106,25 @@ export async function createUser(email: string) {
|
|
|
97
106
|
__wf_reg.set(__wf_id, __wf_fn); // [!code highlight]
|
|
98
107
|
__wf_fn.stepId = __wf_id; // [!code highlight]
|
|
99
108
|
})(createUser, "step//workflows/user.js//createUser"); // [!code highlight]
|
|
109
|
+
|
|
110
|
+
export async function handleUserSignup(email: string) {
|
|
111
|
+
throw new Error("You attempted to execute ..."); // [!code highlight]
|
|
112
|
+
}
|
|
113
|
+
handleUserSignup.workflowId = "workflow//workflows/user.js//handleUserSignup"; // [!code highlight]
|
|
100
114
|
```
|
|
101
115
|
|
|
102
116
|
**What happens:**
|
|
103
117
|
|
|
104
118
|
- The `"use step"` directive is removed
|
|
105
|
-
-
|
|
106
|
-
-
|
|
119
|
+
- Step function bodies are kept completely intact (no transformation)
|
|
120
|
+
- Each step function is registered with the runtime via an inline IIFE (no imports needed)
|
|
107
121
|
- Step functions run with full Node.js/Deno/Bun access
|
|
122
|
+
- Workflow function bodies are **replaced** with an error throw, and a `workflowId` property is attached. Launch workflow functions with [`start()`](/docs/api-reference/workflow-api/start) instead of calling them directly. The ID identifies the workflow to `start()`
|
|
123
|
+
- A dead-code-elimination pass removes code reachable only from the replaced workflow bodies
|
|
108
124
|
|
|
109
|
-
**Why no transformation?** Step functions execute in your main runtime with full access to Node.js APIs, file system, databases,
|
|
125
|
+
**Why no step transformation?** Step functions execute in your main runtime with full access to Node.js APIs, the file system, databases, and other resources. They run normally without special handling.
|
|
110
126
|
|
|
111
|
-
**ID
|
|
127
|
+
**ID format:** Step IDs follow the pattern `step//{filepath}//{functionName}`, where the file path is relative to your project root.
|
|
112
128
|
|
|
113
129
|
</Tab>
|
|
114
130
|
<Tab value="Workflow Mode">
|
|
@@ -117,7 +133,6 @@ export async function createUser(email: string) {
|
|
|
117
133
|
|
|
118
134
|
**Input:**
|
|
119
135
|
|
|
120
|
-
{/* @skip-typecheck: incomplete code sample */}
|
|
121
136
|
```typescript
|
|
122
137
|
export async function createUser(email: string) {
|
|
123
138
|
"use step";
|
|
@@ -149,7 +164,7 @@ handleUserSignup.workflowId = "workflow//workflows/user.js//handleUserSignup"; /
|
|
|
149
164
|
**What happens:**
|
|
150
165
|
|
|
151
166
|
- Step function bodies are **replaced** with calls to `globalThis[Symbol.for("WORKFLOW_USE_STEP")]`
|
|
152
|
-
- Workflow function bodies remain **intact
|
|
167
|
+
- Workflow function bodies remain **intact**, so they execute deterministically during replay
|
|
153
168
|
- The workflow function gets a `workflowId` property for runtime identification
|
|
154
169
|
- The `"use workflow"` directive is removed
|
|
155
170
|
|
|
@@ -157,14 +172,14 @@ handleUserSignup.workflowId = "workflow//workflows/user.js//handleUserSignup"; /
|
|
|
157
172
|
|
|
158
173
|
1. Checks if the step has already been executed (in the event log)
|
|
159
174
|
2. If yes: Returns the cached result
|
|
160
|
-
3. If no:
|
|
175
|
+
3. If no: Suspends the replay and executes the step, usually inline in the same invocation. The runtime returns the run to the queue only when the invocation's inline budget is exhausted or its timeout approaches
|
|
161
176
|
|
|
162
|
-
**ID
|
|
177
|
+
**ID format:** Workflow IDs follow the pattern `workflow//{filepath}//{functionName}`. The `workflowId` property is attached to the function so [`start()`](/docs/api-reference/workflow-api/start) works at runtime.
|
|
163
178
|
|
|
164
179
|
</Tab>
|
|
165
|
-
<Tab value="
|
|
180
|
+
<Tab value="Detect Mode">
|
|
166
181
|
|
|
167
|
-
**
|
|
182
|
+
**Detect Mode** is a lightweight, non-transforming mode used during the build's discovery phase.
|
|
168
183
|
|
|
169
184
|
**Input:**
|
|
170
185
|
|
|
@@ -181,37 +196,32 @@ export async function handleUserSignup(email: string) {
|
|
|
181
196
|
|
|
182
197
|
{/* @skip-typecheck: incomplete code sample */}
|
|
183
198
|
```typescript
|
|
199
|
+
/**__internal_workflows{"workflows":{"user.js":{"handleUserSignup":{"workflowId":"workflow//workflows/user.js//handleUserSignup"}}}}*/; // [!code highlight]
|
|
184
200
|
export async function handleUserSignup(email: string) {
|
|
185
|
-
|
|
201
|
+
"use workflow";
|
|
202
|
+
const user = await createUser(email);
|
|
203
|
+
return { userId: user.id };
|
|
186
204
|
}
|
|
187
|
-
handleUserSignup.workflowId = "workflow//workflows/user.js//handleUserSignup"; // [!code highlight]
|
|
188
205
|
```
|
|
189
206
|
|
|
190
207
|
**What happens:**
|
|
191
208
|
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
209
|
+
- The code is **not modified**. Detect mode only walks the AST
|
|
210
|
+
- Discovered workflows, steps, and custom-serialization classes are emitted as a JSON manifest comment
|
|
211
|
+
- The build uses this to decide which files feed the step and workflow bundles
|
|
195
212
|
|
|
196
|
-
**Why
|
|
197
|
-
|
|
198
|
-
The IDs are generated exactly like in workflow mode to ensure they can be directly referenced at runtime.
|
|
213
|
+
**Why a separate mode?** The build system first runs a fast regular expression pre-scan to find candidate files containing directive-like strings. It then runs detect mode on those candidates to validate them at the abstract syntax tree (AST) level. The plugin eliminates false positives, such as a directive-like string inside a template literal, because it only recognizes genuine directive statements.
|
|
199
214
|
|
|
200
215
|
<Callout type="info">
|
|
201
|
-
**
|
|
202
|
-
- Manually construct workflow IDs using the pattern `workflow//{filepath}//{functionName}`
|
|
203
|
-
- Use the workflow manifest file generated during build to lookup IDs
|
|
204
|
-
- Pass IDs directly to `start()` as strings
|
|
205
|
-
|
|
206
|
-
All framework integrations include client mode as a loader by default.
|
|
216
|
+
**Working without the app-code loader:** Frameworks apply the step-mode transform to application code by default, which is what gives `start(handleUserSignup)` its automatic IDs and type safety. If your setup can't run the loader, you can instead construct workflow IDs manually using the pattern `workflow//{filepath}//{functionName}`, look them up in the build manifest, and pass them to `start()` as strings.
|
|
207
217
|
</Callout>
|
|
208
218
|
|
|
209
219
|
</Tab>
|
|
210
220
|
</Tabs>
|
|
211
221
|
|
|
212
|
-
## Generated
|
|
222
|
+
## Generated files
|
|
213
223
|
|
|
214
|
-
When you build your application, the Workflow SDK generates
|
|
224
|
+
When you build your application, the Workflow SDK generates a combined flow handler, an internal step registration bundle, and a webhook handler. Exact filenames vary by framework.
|
|
215
225
|
|
|
216
226
|
### `flow.js`
|
|
217
227
|
|
|
@@ -222,7 +232,7 @@ Contains all workflow functions transformed in **workflow mode**. This file is i
|
|
|
222
232
|
All workflow code is bundled together and embedded as a string inside `flow.js`. When a workflow needs to execute, this bundled code is run inside a **Node.js VM** (virtual machine) to ensure:
|
|
223
233
|
|
|
224
234
|
- **Determinism**: The same inputs always produce the same outputs
|
|
225
|
-
- **Side-effect prevention**: Direct access to Node.js APIs, file system, network,
|
|
235
|
+
- **Side-effect prevention**: Direct access to Node.js APIs, the file system, the network, and other resources is blocked
|
|
226
236
|
- **Sandboxed execution**: Workflow orchestration logic is isolated from the main runtime
|
|
227
237
|
|
|
228
238
|
**Build-time validation:**
|
|
@@ -245,15 +255,21 @@ Most invalid patterns cause **build-time errors**, catching issues before deploy
|
|
|
245
255
|
**Why a VM?** Workflow functions must be deterministic to support replay. The VM sandbox prevents accidental use of non-deterministic APIs or side effects. All side effects should be performed in [step functions](/docs/foundations/workflows-and-steps#step-functions) instead.
|
|
246
256
|
</Callout>
|
|
247
257
|
|
|
248
|
-
### `
|
|
258
|
+
### `__step_registrations.js`
|
|
249
259
|
|
|
250
|
-
Contains all step functions transformed in **step mode**.
|
|
260
|
+
Contains all step functions transformed in **step mode**. The combined flow handler imports this module for its registration side effects.
|
|
251
261
|
|
|
252
262
|
**What it does:**
|
|
253
263
|
|
|
254
|
-
-
|
|
255
|
-
-
|
|
256
|
-
-
|
|
264
|
+
- Adds step functions to the runtime step registry
|
|
265
|
+
- Keeps step bodies in the full host runtime
|
|
266
|
+
- Makes registered steps available when a flow queue message includes `stepId` and `stepName`
|
|
267
|
+
|
|
268
|
+
This module must not be exposed as an HTTP endpoint.
|
|
269
|
+
|
|
270
|
+
<Callout type="info">
|
|
271
|
+
**Changed in 5.0:** In 4.x, the step bundle was served as its own HTTP route at `POST /.well-known/workflow/v1/step`, with step messages delivered on a separate `__wkf_step_*` queue topic. v5 merged both into the combined flow handler. The step bundle became a registration module imported by `flow.js`, and step messages arrive on the shared workflow queue. Use the version picker to see the old layout on the v4 version of this page.
|
|
272
|
+
</Callout>
|
|
257
273
|
|
|
258
274
|
### `webhook.js`
|
|
259
275
|
|
|
@@ -265,24 +281,24 @@ Contains webhook handling logic for delivering external data to running workflow
|
|
|
265
281
|
- Validates tokens and routes data to the correct workflow run
|
|
266
282
|
- Resumes workflow execution after webhook delivery
|
|
267
283
|
|
|
268
|
-
|
|
284
|
+
The webhook file structure varies by framework. Next.js generates `webhook/[token]/route.js` to use App Router's dynamic routing, while other frameworks generate a single `webhook.js` or `webhook.mjs` handler.
|
|
269
285
|
|
|
270
|
-
## Why
|
|
286
|
+
## Why three modes?
|
|
271
287
|
|
|
272
288
|
The multi-mode transformation enables the Workflow SDK's durable execution model:
|
|
273
289
|
|
|
274
|
-
1. **Step
|
|
275
|
-
2. **Workflow
|
|
276
|
-
3. **
|
|
290
|
+
1. **Step mode** (required): Bundles executable step functions that can access the full runtime and serves as the application-code transform that prevents direct workflow execution and enables type-safe `start()` references
|
|
291
|
+
2. **Workflow mode** (required): Creates orchestration logic that can replay from event logs
|
|
292
|
+
3. **Detect mode** (build-internal): Discovers directive-marked functions for the build without changing the code
|
|
277
293
|
|
|
278
294
|
This separation allows:
|
|
279
295
|
|
|
280
296
|
- **Deterministic replay**: Workflows can be safely replayed from event logs without re-executing side effects
|
|
281
297
|
- **Sandboxed orchestration**: Workflow logic runs in a controlled VM without direct runtime access
|
|
282
298
|
- **Stateless execution**: Your compute can scale to zero and resume from any point in the workflow
|
|
283
|
-
- **Type safety**: TypeScript
|
|
299
|
+
- **Type safety**: TypeScript supports workflow references passed to `start()`
|
|
284
300
|
|
|
285
|
-
## Determinism and
|
|
301
|
+
## Determinism and replay
|
|
286
302
|
|
|
287
303
|
A key aspect of the transformation is maintaining **deterministic replay** for workflow functions.
|
|
288
304
|
|
|
@@ -292,7 +308,7 @@ A key aspect of the transformation is maintaining **deterministic replay** for w
|
|
|
292
308
|
- No direct side effects (no API calls, no database writes, no file I/O)
|
|
293
309
|
- Can use seeded random/time APIs provided by the VM (`Math.random()`, `Date.now()`, etc.)
|
|
294
310
|
|
|
295
|
-
Because workflow functions are deterministic and have no side effects, they can be safely
|
|
311
|
+
Because workflow functions are deterministic and have no side effects, they can be safely rerun multiple times to calculate the next step. Workflow function bodies remain intact in workflow mode because they're pure orchestration logic.
|
|
296
312
|
|
|
297
313
|
**Step functions can be non-deterministic:**
|
|
298
314
|
|
|
@@ -302,7 +318,7 @@ Because workflow functions are deterministic and have no side effects, they can
|
|
|
302
318
|
|
|
303
319
|
Learn more about [Workflows and Steps](/docs/foundations/workflows-and-steps).
|
|
304
320
|
|
|
305
|
-
## ID
|
|
321
|
+
## ID generation
|
|
306
322
|
|
|
307
323
|
The compiler generates stable IDs for workflows and steps based on file paths and function names:
|
|
308
324
|
|
|
@@ -321,22 +337,22 @@ The compiler generates stable IDs for workflows and steps based on file paths an
|
|
|
321
337
|
- **Portable**: Works across different runtimes and deployments
|
|
322
338
|
|
|
323
339
|
<Callout type="info">
|
|
324
|
-
Although IDs can change when files are moved or functions are renamed, Workflow SDK
|
|
340
|
+
Although IDs can change when files are moved or functions are renamed, Workflow SDK functions assume [atomic versioning](/docs/foundations/versioning) in the World. This means changing IDs won't break old workflows from running, but will prevent runs from being upgraded and will cause your workflow/step names to change in observability across deployments.
|
|
325
341
|
</Callout>
|
|
326
342
|
|
|
327
|
-
## Framework
|
|
343
|
+
## Framework integration
|
|
328
344
|
|
|
329
|
-
These transformations are framework-agnostic
|
|
345
|
+
These transformations are framework-agnostic. They output standard JavaScript that works anywhere.
|
|
330
346
|
|
|
331
347
|
**For users**: Your framework handles all transformations automatically. See the [Getting Started](/docs/getting-started) guide for your framework.
|
|
332
348
|
|
|
333
349
|
**For framework authors**: Learn how to integrate these transformations into your framework in [Building Framework Integrations](/docs/how-it-works/framework-integrations).
|
|
334
350
|
|
|
335
|
-
## Debugging
|
|
351
|
+
## Debugging transformed code
|
|
336
352
|
|
|
337
353
|
If you need to debug transformation issues, you can inspect the generated files:
|
|
338
354
|
|
|
339
|
-
1. **
|
|
355
|
+
1. **Inspect the generated output**: Check the combined flow handler, step registration bundle, webhook handler, and emitted debug files.
|
|
340
356
|
2. **Check build logs**: Most frameworks log transformation activity during builds
|
|
341
357
|
3. **Verify directives**: Ensure `"use workflow"` and `"use step"` are the first statements in functions
|
|
342
358
|
4. **Check file locations**: Transformations only apply to files in configured source directories
|
|
@@ -7,58 +7,62 @@ prerequisites:
|
|
|
7
7
|
- /docs/how-it-works/event-sourcing
|
|
8
8
|
related:
|
|
9
9
|
- /docs/observability
|
|
10
|
-
- /
|
|
10
|
+
- /worlds/vercel
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
<Callout>
|
|
14
|
-
|
|
14
|
+
Workflow SDK automatically encrypts user data in the event log without requiring code changes. To start using workflows, see the [getting started](/docs/getting-started) guide for your framework.
|
|
15
15
|
</Callout>
|
|
16
16
|
|
|
17
|
-
Workflow SDK supports automatic end-to-end encryption of all user data before it
|
|
17
|
+
Workflow SDK supports automatic end-to-end encryption of all user data before writing it to the event log. When a `World` implementation provides encryption support, you can pass sensitive data, such as API keys, tokens, or user credentials, as workflow inputs, step arguments, and return values. The storage backend only sees ciphertext.
|
|
18
18
|
|
|
19
|
-
Encryption support varies by `World` implementation. See the [Worlds](/worlds) page to check which
|
|
19
|
+
Encryption support varies by `World` implementation. See the [Worlds](/worlds) page to check which Worlds support this feature. `World` implementations opt into encryption by providing a `getEncryptionKeyForRun()` method. The core runtime uses it automatically when present.
|
|
20
20
|
|
|
21
|
-
## What
|
|
21
|
+
## What is encrypted
|
|
22
22
|
|
|
23
23
|
All user data flowing through the event log is encrypted:
|
|
24
24
|
|
|
25
|
-
- **Workflow inputs
|
|
26
|
-
- **Workflow return values
|
|
27
|
-
- **Step inputs
|
|
28
|
-
- **Step return values
|
|
29
|
-
- **Hook metadata
|
|
30
|
-
- **Hook payloads
|
|
31
|
-
- **Stream data
|
|
25
|
+
- **Workflow inputs**: Arguments passed when starting a workflow
|
|
26
|
+
- **Workflow return values**: The final output of a workflow
|
|
27
|
+
- **Step inputs**: Arguments passed to step functions
|
|
28
|
+
- **Step return values**: The result returned by step functions
|
|
29
|
+
- **Hook metadata**: Data attached when creating a hook
|
|
30
|
+
- **Hook payloads**: Data received by hooks and webhooks
|
|
31
|
+
- **Stream data**: Each frame in a `ReadableStream` or `WritableStream`
|
|
32
32
|
|
|
33
33
|
Metadata such as workflow names, step names, entity IDs, timestamps, and lifecycle states are **not** encrypted. This allows the observability tools to display run structure and timelines without requiring decryption.
|
|
34
34
|
|
|
35
|
-
## How
|
|
35
|
+
## How it works
|
|
36
36
|
|
|
37
|
-
###
|
|
37
|
+
### Compression
|
|
38
|
+
|
|
39
|
+
Payloads are compressed before encryption. A format prefix on the stored value records the compression codec (gzip, with zstd support in the format), and the inner payload keeps its own serialization format prefix after decompression. Repetitive payloads compress heavily. AI token streams average around 80% smaller, reducing storage and network transfer. Like encryption, compression is automatic and requires no code changes.
|
|
40
|
+
|
|
41
|
+
### Key management
|
|
38
42
|
|
|
39
43
|
Each workflow run is encrypted with its own unique key, provided by the `World` implementation via `getEncryptionKeyForRun()`. How the key is generated and stored is up to the `World`.
|
|
40
44
|
|
|
41
|
-
For example, the [Vercel World](/
|
|
45
|
+
For example, the [Vercel World](/worlds/vercel) provides unique keys per run and execution environment, ensuring that a given run can only decrypt data from that run itself.
|
|
42
46
|
|
|
43
|
-
### Encryption
|
|
47
|
+
### Encryption algorithm
|
|
44
48
|
|
|
45
49
|
Data is encrypted using **AES-256-GCM** via the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API):
|
|
46
50
|
|
|
47
51
|
- A random 12-byte nonce is generated for each encryption operation
|
|
48
|
-
- The GCM authentication tag provides integrity verification
|
|
52
|
+
- The GCM authentication tag provides integrity verification and detects any ciphertext tampering
|
|
49
53
|
- The same plaintext produces different ciphertext each time due to the random nonce
|
|
50
54
|
|
|
51
|
-
## Decrypting
|
|
55
|
+
## Decrypting data
|
|
52
56
|
|
|
53
57
|
When viewing workflow runs through the observability tools, encrypted fields display as locked placeholders until you explicitly choose to decrypt them.
|
|
54
58
|
|
|
55
59
|
### Permissions
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
The `World` implementation controls decryption access. On Vercel, decryption follows the same permissions model as project environment variables. If you don't have permission to view environment variable values for a project, you can't decrypt its workflow data. Vercel records each decryption request in your [Vercel audit log](https://vercel.com/docs/audit-log), so your team can see when someone accessed workflow data and who accessed it.
|
|
58
62
|
|
|
59
|
-
### Web
|
|
63
|
+
### Web dashboard
|
|
60
64
|
|
|
61
|
-
Click the **Decrypt** button in the run detail panel to decrypt all data fields. Decryption happens entirely in the browser
|
|
65
|
+
Click the **Decrypt** button in the run detail panel to decrypt all data fields. Decryption happens entirely in the browser through the Web Crypto API. The observability server retrieves the encryption key but never sees your plaintext data.
|
|
62
66
|
|
|
63
67
|
### CLI
|
|
64
68
|
|
|
@@ -80,7 +84,7 @@ npx workflow inspect stream <stream-id> --run <run-id> --decrypt
|
|
|
80
84
|
|
|
81
85
|
Without `--decrypt`, encrypted fields display as `🔒 Encrypted` placeholders.
|
|
82
86
|
|
|
83
|
-
## Custom World
|
|
87
|
+
## Custom World implementations
|
|
84
88
|
|
|
85
89
|
The core runtime encrypts data automatically when the `World` implementation provides a `getEncryptionKeyForRun()` method. The core runtime can call this method in two forms:
|
|
86
90
|
|
|
@@ -98,15 +102,15 @@ Use `getEncryptionKeyForRun(run)` when the run entity already exists. Use `getEn
|
|
|
98
102
|
To add encryption support to a custom `World`:
|
|
99
103
|
|
|
100
104
|
1. Implement `getEncryptionKeyForRun()` on your `World` class, handling both call shapes
|
|
101
|
-
2. Return the raw 32-byte key as a `Uint8Array
|
|
105
|
+
2. Return the raw 32-byte key as a `Uint8Array`. The core runtime uses it for AES-256-GCM operations
|
|
102
106
|
3. Ensure the same key is returned for the same run ID across invocations (for decryption during replay)
|
|
103
107
|
|
|
104
108
|
```typescript
|
|
105
109
|
import type { WorkflowRun, World } from "@workflow/world";
|
|
106
110
|
|
|
107
111
|
export const getEncryptionKeyForRun: World["getEncryptionKeyForRun"] = async (
|
|
108
|
-
run,
|
|
109
|
-
context
|
|
112
|
+
run: WorkflowRun | string,
|
|
113
|
+
context?: Record<string, unknown>
|
|
110
114
|
) => {
|
|
111
115
|
const runId = typeof run === "string" ? run : run.runId;
|
|
112
116
|
const deploymentId =
|
|
@@ -127,4 +131,4 @@ async function lookupRunKey(
|
|
|
127
131
|
}
|
|
128
132
|
```
|
|
129
133
|
|
|
130
|
-
The [Vercel World](/
|
|
134
|
+
The [Vercel World](/worlds/vercel) implementation uses HKDF derivation from a deployment-scoped key, but any consistent key management scheme will work.
|