ai-workflows 2.1.3 → 2.4.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +14 -1
- package/README.md +2 -0
- package/dist/barrier.d.ts +6 -0
- package/dist/barrier.d.ts.map +1 -1
- package/dist/barrier.js +45 -7
- package/dist/barrier.js.map +1 -1
- package/dist/cascade-context.d.ts.map +1 -1
- package/dist/cascade-context.js +25 -25
- package/dist/cascade-context.js.map +1 -1
- package/dist/cascade-executor.d.ts.map +1 -1
- package/dist/cascade-executor.js +1 -1
- package/dist/cascade-executor.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +23 -7
- package/dist/context.js.map +1 -1
- package/dist/cron-parser.d.ts +65 -0
- package/dist/cron-parser.d.ts.map +1 -0
- package/dist/cron-parser.js +294 -0
- package/dist/cron-parser.js.map +1 -0
- package/dist/cron-scheduler.d.ts +117 -0
- package/dist/cron-scheduler.d.ts.map +1 -0
- package/dist/cron-scheduler.js +176 -0
- package/dist/cron-scheduler.js.map +1 -0
- package/dist/database-context.d.ts +184 -0
- package/dist/database-context.d.ts.map +1 -0
- package/dist/database-context.js +428 -0
- package/dist/database-context.js.map +1 -0
- package/dist/digital-objects-adapter.d.ts +159 -0
- package/dist/digital-objects-adapter.d.ts.map +1 -0
- package/dist/digital-objects-adapter.js +229 -0
- package/dist/digital-objects-adapter.js.map +1 -0
- package/dist/durable-execution-cloudflare.d.ts +427 -0
- package/dist/durable-execution-cloudflare.d.ts.map +1 -0
- package/dist/durable-execution-cloudflare.js +510 -0
- package/dist/durable-execution-cloudflare.js.map +1 -0
- package/dist/durable-execution.d.ts +482 -0
- package/dist/durable-execution.d.ts.map +1 -0
- package/dist/durable-execution.js +594 -0
- package/dist/durable-execution.js.map +1 -0
- package/dist/durable-workflow.d.ts +176 -0
- package/dist/durable-workflow.d.ts.map +1 -0
- package/dist/durable-workflow.js +552 -0
- package/dist/durable-workflow.js.map +1 -0
- package/dist/graph/topological-sort.d.ts.map +1 -1
- package/dist/graph/topological-sort.js +5 -5
- package/dist/graph/topological-sort.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +101 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +115 -0
- package/dist/logger.js.map +1 -0
- package/dist/on.d.ts.map +1 -1
- package/dist/on.js +3 -3
- package/dist/on.js.map +1 -1
- package/dist/runtime.d.ts +169 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +275 -0
- package/dist/runtime.js.map +1 -0
- package/dist/send.d.ts.map +1 -1
- package/dist/send.js +4 -3
- package/dist/send.js.map +1 -1
- package/dist/telemetry.d.ts +150 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +388 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/timer-registry.d.ts +25 -0
- package/dist/timer-registry.d.ts.map +1 -1
- package/dist/timer-registry.js +42 -8
- package/dist/timer-registry.js.map +1 -1
- package/dist/types.d.ts +17 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/worker/durable-step.d.ts +481 -0
- package/dist/worker/durable-step.d.ts.map +1 -0
- package/dist/worker/durable-step.js +606 -0
- package/dist/worker/durable-step.js.map +1 -0
- package/dist/worker/index.d.ts +106 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +124 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/state-adapter.d.ts +230 -0
- package/dist/worker/state-adapter.d.ts.map +1 -0
- package/dist/worker/state-adapter.js +409 -0
- package/dist/worker/state-adapter.js.map +1 -0
- package/dist/worker/topological-executor.d.ts +282 -0
- package/dist/worker/topological-executor.d.ts.map +1 -0
- package/dist/worker/topological-executor.js +396 -0
- package/dist/worker/topological-executor.js.map +1 -0
- package/dist/worker/workflow-builder.d.ts +286 -0
- package/dist/worker/workflow-builder.d.ts.map +1 -0
- package/dist/worker/workflow-builder.js +565 -0
- package/dist/worker/workflow-builder.js.map +1 -0
- package/dist/worker.d.ts +800 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +2428 -0
- package/dist/worker.js.map +1 -0
- package/dist/workflow-builder.d.ts +287 -0
- package/dist/workflow-builder.d.ts.map +1 -0
- package/dist/workflow-builder.js +762 -0
- package/dist/workflow-builder.js.map +1 -0
- package/dist/workflow.d.ts +14 -30
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +132 -292
- package/dist/workflow.js.map +1 -1
- package/examples/01-ecommerce-order-pipeline.ts +358 -0
- package/examples/02-content-moderation-cascade.ts +454 -0
- package/examples/03-scheduled-reporting-dependencies.ts +479 -0
- package/examples/04-database-persistence.ts +518 -0
- package/examples/README.md +173 -0
- package/package.json +30 -13
- package/src/__tests__/digital-objects-adapter.test.ts +274 -0
- package/src/__tests__/durable-workflow.test.ts +297 -0
- package/src/barrier.ts +48 -7
- package/src/cascade-context.ts +36 -29
- package/src/cascade-executor.ts +3 -2
- package/src/context.ts +41 -12
- package/src/cron-parser.ts +347 -0
- package/src/cron-scheduler.ts +239 -0
- package/src/database-context.ts +658 -0
- package/src/digital-objects-adapter.ts +351 -0
- package/src/durable-execution-cloudflare.ts +855 -0
- package/src/durable-execution.ts +1042 -0
- package/src/durable-workflow.ts +717 -0
- package/src/graph/topological-sort.ts +6 -8
- package/src/index.ts +69 -0
- package/src/logger.ts +148 -0
- package/src/on.ts +8 -9
- package/src/runtime.ts +436 -0
- package/src/send.ts +4 -5
- package/src/telemetry.ts +577 -0
- package/src/timer-registry.ts +44 -10
- package/src/types.ts +32 -17
- package/src/worker/durable-step.ts +976 -0
- package/src/worker/index.ts +216 -0
- package/src/worker/state-adapter.ts +589 -0
- package/src/worker/topological-executor.ts +625 -0
- package/src/worker/workflow-builder.ts +871 -0
- package/src/worker.ts +2906 -0
- package/src/workflow-builder.ts +1068 -0
- package/src/workflow.ts +188 -351
- package/test/barrier-join.test.ts +32 -24
- package/test/cascade-executor.test.ts +9 -16
- package/test/cron-parser.test.ts +314 -0
- package/test/cron-scheduler.test.ts +291 -0
- package/test/database-context.test.ts +770 -0
- package/test/db-provider-adapter.test.ts +862 -0
- package/test/durable-execution-cloudflare.test.ts +606 -0
- package/test/durable-execution-in-process.test.ts +286 -0
- package/test/durable-execution.test.ts +247 -0
- package/test/e2e/workflow-scenarios.e2e.test.ts +1039 -0
- package/test/integration.test.ts +442 -0
- package/test/rpc-surface.test.ts +946 -0
- package/test/runtime.test.ts +262 -0
- package/test/schedule-timer-cleanup.test.ts +30 -21
- package/test/send-race-conditions.test.ts +30 -40
- package/test/worker/durable-cascade.test.ts +1117 -0
- package/test/worker/durable-step.test.ts +723 -0
- package/test/worker/topological-executor.test.ts +1240 -0
- package/test/worker/workflow-builder.test.ts +1067 -0
- package/test/worker.test.ts +608 -0
- package/test/workflow-builder.test.ts +1670 -0
- package/test/workflow-cron.test.ts +256 -0
- package/test/workflow-state-adapter.test.ts +923 -0
- package/test/workflow.test.ts +25 -22
- package/tsconfig.json +3 -1
- package/vitest.config.ts +38 -1
- package/vitest.workers.config.ts +44 -0
- package/wrangler.jsonc +22 -0
- package/.turbo/turbo-test.log +0 -169
- package/LICENSE +0 -21
- package/src/context.js +0 -83
- package/src/every.js +0 -267
- package/src/index.js +0 -71
- package/src/on.js +0 -79
- package/src/send.js +0 -111
- package/src/types.js +0 -4
- package/src/workflow.js +0 -455
- package/test/context.test.js +0 -116
- package/test/every.test.js +0 -282
- package/test/on.test.js +0 -80
- package/test/send.test.js +0 -89
- package/test/workflow.test.js +0 -224
- package/vitest.config.js +0 -7
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare Workflows adapter for {@link DurableExecutionAdapter}.
|
|
3
|
+
*
|
|
4
|
+
* Bridges the backend-agnostic port defined in `./durable-execution.ts` to
|
|
5
|
+
* Cloudflare's class-based {@link https://developers.cloudflare.com/workflows/ Workflows runtime}.
|
|
6
|
+
* CF Workflows is the production default per
|
|
7
|
+
* {@link ../../docs/adr/0004-durable-execution-cf-workflows-default.md ADR-0004}:
|
|
8
|
+
* the recently expanded limits (25K steps default-configurable, 50K concurrent
|
|
9
|
+
* instances, 365-day max sleep, 1 GB persisted state) plus zero per-step
|
|
10
|
+
* billing make it the cost-optimal backend for cascade-heavy workloads.
|
|
11
|
+
*
|
|
12
|
+
* ## How the bridge works
|
|
13
|
+
*
|
|
14
|
+
* CF Workflows uses a class-based dispatch model — users author a
|
|
15
|
+
* {@link WorkflowEntrypointLike} subclass with `async run(event, step)`, and
|
|
16
|
+
* the runtime instantiates it for each invocation. Our port's
|
|
17
|
+
* `run(name, fn, input)` is callback-shaped. The adapter resolves the
|
|
18
|
+
* impedance mismatch with two complementary surfaces:
|
|
19
|
+
*
|
|
20
|
+
* 1. **Workflow-function registry.** Callers register named workflow bodies
|
|
21
|
+
* against the adapter via {@link CloudflareWorkflowsDurableExecution.register}
|
|
22
|
+
* (or implicitly the first time {@link CloudflareWorkflowsDurableExecution.run}
|
|
23
|
+
* is called with that name). The registry is a plain {@link Map}
|
|
24
|
+
* maintained on the adapter instance.
|
|
25
|
+
*
|
|
26
|
+
* 2. **`createWorkflowEntrypoint(adapter)`.** Returns a
|
|
27
|
+
* {@link WorkflowEntrypointLike} subclass whose `run(event, step)`
|
|
28
|
+
* reads the workflow name from `event.payload.__wfName`, looks the body
|
|
29
|
+
* up in the registry, and invokes it with a {@link WorkflowContext} that
|
|
30
|
+
* delegates each port primitive to the CF `step` argument. Users export
|
|
31
|
+
* this class from their worker module and wire it through `wrangler.jsonc`:
|
|
32
|
+
*
|
|
33
|
+
* ```jsonc
|
|
34
|
+
* "workflows": [{
|
|
35
|
+
* "name": "cascade",
|
|
36
|
+
* "binding": "WORKFLOW",
|
|
37
|
+
* "class_name": "MyWorkflowEntrypoint"
|
|
38
|
+
* }]
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* The adapter's `run()` triggers a workflow by calling `binding.create({
|
|
42
|
+
* params: { __wfName, __wfInput } })` against the supplied
|
|
43
|
+
* {@link WorkflowsBindingLike}. By default it polls
|
|
44
|
+
* `instance.status()` until completion and returns the workflow output;
|
|
45
|
+
* callers that need fire-and-forget can opt out via
|
|
46
|
+
* {@link CloudflareWorkflowsDurableExecutionOptions.waitForCompletion}.
|
|
47
|
+
*
|
|
48
|
+
* ## Step / sleep / waitForEvent translation
|
|
49
|
+
*
|
|
50
|
+
* - `ctx.step(name, fn)` → `step.do(name, fn)`
|
|
51
|
+
* - `ctx.step(name, cfg, fn)` → `step.do(name, cfg, fn)`
|
|
52
|
+
* - `ctx.sleep(duration)` → `step.sleep(autoStepName, duration)`
|
|
53
|
+
* - `ctx.sleepUntil(date)` → `step.sleepUntil(autoStepName, date)`
|
|
54
|
+
* - `ctx.waitForEvent(name, t?)` → `step.waitForEvent(autoStepName, { type: name, timeout: t })`
|
|
55
|
+
*
|
|
56
|
+
* CF requires every primitive to receive a stable name; our port's `sleep` /
|
|
57
|
+
* `sleepUntil` / `waitForEvent` don't. The bridge synthesises a deterministic
|
|
58
|
+
* name from a per-context counter (`__sleep__1`, `__waitForEvent__Order.placed__1`)
|
|
59
|
+
* incremented in body order. Bodies that take the same control-flow path on
|
|
60
|
+
* replay therefore see identical names — the determinism rule applies.
|
|
61
|
+
*
|
|
62
|
+
* Callers who want full control over step naming for sleeps/waits should use
|
|
63
|
+
* {@link DurableExecutionAdapter.step} (or `ctx.step`) wrapping the desired
|
|
64
|
+
* primitive: e.g. `await ctx.step('payment-window', () => sleepUntil(deadline))`.
|
|
65
|
+
*
|
|
66
|
+
* ## Schedules
|
|
67
|
+
*
|
|
68
|
+
* CF Workflows do not support imperative cron registration through the binding;
|
|
69
|
+
* scheduled triggers are declared in `wrangler.jsonc` under `[triggers] crons`
|
|
70
|
+
* and routed to a Worker `scheduled()` handler. The adapter's
|
|
71
|
+
* {@link DurableExecutionAdapter.schedule} therefore registers the workflow
|
|
72
|
+
* body against the adapter and returns a {@link Subscription} whose `id` is
|
|
73
|
+
* the workflow name; the user's worker `scheduled()` handler must call
|
|
74
|
+
* {@link CloudflareWorkflowsDurableExecution.runSchedule} (or the adapter's
|
|
75
|
+
* `run()`) when the cron fires. {@link CloudflareWorkflowsDurableExecution.defineSchedule}
|
|
76
|
+
* is an alias for `schedule()` that emphasises the wrangler-coordinated nature
|
|
77
|
+
* of CF scheduling.
|
|
78
|
+
*
|
|
79
|
+
* ## Rules of Workflows (CF-imposed; universal)
|
|
80
|
+
*
|
|
81
|
+
* 1. **Steps must be idempotent.** CF re-executes step bodies on replay
|
|
82
|
+
* after a hibernation boundary or transient failure. Wrap external
|
|
83
|
+
* side-effects so a duplicate invocation is observably equivalent to a
|
|
84
|
+
* single one.
|
|
85
|
+
*
|
|
86
|
+
* 2. **Step names must be deterministic.** CF uses the step name as the
|
|
87
|
+
* memoization key. Random ids, timestamps, or run-specific values in
|
|
88
|
+
* step names break replay.
|
|
89
|
+
*
|
|
90
|
+
* 3. **State must flow through step returns.** Variables defined in the
|
|
91
|
+
* workflow body but outside a step DO NOT survive hibernation. Read
|
|
92
|
+
* inputs at the top of a step and return only what subsequent steps
|
|
93
|
+
* need.
|
|
94
|
+
*
|
|
95
|
+
* 4. **Workflow bodies must be deterministic.** Two replays of the same
|
|
96
|
+
* input must take the same control-flow path. Push non-determinism
|
|
97
|
+
* (clocks, randomness, network reads) into steps so CF can memoize the
|
|
98
|
+
* result.
|
|
99
|
+
*
|
|
100
|
+
* 5. **Use `step.sleep` / `step.sleepUntil` / `step.waitForEvent`.** Never
|
|
101
|
+
* `setTimeout` or polling — only the runtime knows how to suspend and
|
|
102
|
+
* resume the workflow.
|
|
103
|
+
*
|
|
104
|
+
* ## Limits
|
|
105
|
+
*
|
|
106
|
+
* Declared via {@link CloudflareWorkflowsDurableExecution.limits}:
|
|
107
|
+
*
|
|
108
|
+
* - **Steps per workflow:** 25,000 (default-configurable per Mar 2026
|
|
109
|
+
* change; see ADR-0004).
|
|
110
|
+
* - **Concurrent instances:** 50,000 per account (Apr 2026 change).
|
|
111
|
+
* - **Maximum sleep:** 365 days.
|
|
112
|
+
* - **Per-step / per-event payload:** 1 MiB (CF Workers RPC limit).
|
|
113
|
+
*
|
|
114
|
+
* @see {@link ../../docs/adr/0004-durable-execution-cf-workflows-default.md ADR-0004}
|
|
115
|
+
* @see {@link https://developers.cloudflare.com/workflows/build/workflows-api/ Workflows API}
|
|
116
|
+
* @see {@link https://developers.cloudflare.com/workflows/build/rules-of-workflows/ Rules of Workflows}
|
|
117
|
+
*
|
|
118
|
+
* @example Wiring an adapter
|
|
119
|
+
* ```ts
|
|
120
|
+
* // worker.ts
|
|
121
|
+
* import {
|
|
122
|
+
* createCloudflareWorkflowsDurableExecution,
|
|
123
|
+
* createWorkflowEntrypoint,
|
|
124
|
+
* } from 'ai-workflows/durable-execution'
|
|
125
|
+
*
|
|
126
|
+
* type Env = { WORKFLOW: import('cloudflare:workers').Workflow }
|
|
127
|
+
*
|
|
128
|
+
* const dx = createCloudflareWorkflowsDurableExecution({
|
|
129
|
+
* binding: () => env.WORKFLOW, // resolved per-request
|
|
130
|
+
* })
|
|
131
|
+
*
|
|
132
|
+
* dx.register('cascade', async (ctx) => {
|
|
133
|
+
* const plan = await ctx.step('plan', () => generatePlan(ctx.input))
|
|
134
|
+
* await ctx.sleep('1 minute')
|
|
135
|
+
* return ctx.step('write', () => writeAll(plan))
|
|
136
|
+
* })
|
|
137
|
+
*
|
|
138
|
+
* // The class wrangler binds; CF instantiates it on each run.
|
|
139
|
+
* export const MyWorkflow = createWorkflowEntrypoint(dx)
|
|
140
|
+
*
|
|
141
|
+
* export default {
|
|
142
|
+
* async fetch(req: Request, env: Env) {
|
|
143
|
+
* // Trigger from anywhere — adapter.run() goes through the binding.
|
|
144
|
+
* const result = await dx.run('cascade', undefined as never, { customerId: 'c-1' })
|
|
145
|
+
* return Response.json(result)
|
|
146
|
+
* },
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* @packageDocumentation
|
|
151
|
+
*/
|
|
152
|
+
import { type DurableExecutionAdapter, type Subscription, type WorkflowFn } from './durable-execution.js';
|
|
153
|
+
/**
|
|
154
|
+
* Minimal `WorkflowStep` shape — only the methods this adapter uses.
|
|
155
|
+
*
|
|
156
|
+
* Defined structurally so the adapter compiles in Node test environments and
|
|
157
|
+
* accepts a pure-JS fake without depending on `cloudflare:workers` at runtime.
|
|
158
|
+
* In production, callers pass the real `step` argument provided by CF to
|
|
159
|
+
* their {@link WorkflowEntrypointLike.run} method.
|
|
160
|
+
*/
|
|
161
|
+
export interface WorkflowStepLike {
|
|
162
|
+
do<T>(name: string, callback: () => Promise<T>): Promise<T>;
|
|
163
|
+
do<T>(name: string, config: WorkflowStepConfigLike, callback: () => Promise<T>): Promise<T>;
|
|
164
|
+
sleep(name: string, duration: string | number): Promise<void>;
|
|
165
|
+
sleepUntil(name: string, timestamp: Date | number): Promise<void>;
|
|
166
|
+
waitForEvent<T = unknown>(name: string, options: {
|
|
167
|
+
type: string;
|
|
168
|
+
timeout?: string | number;
|
|
169
|
+
}): Promise<{
|
|
170
|
+
payload: T;
|
|
171
|
+
type: string;
|
|
172
|
+
timestamp: Date;
|
|
173
|
+
} | T>;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Minimal `WorkflowStepConfig` shape passed to `step.do(name, config, fn)`.
|
|
177
|
+
* Mirrors CF's `WorkflowStepConfig`. Compatible with our port's
|
|
178
|
+
* {@link StepConfig}.
|
|
179
|
+
*/
|
|
180
|
+
export interface WorkflowStepConfigLike {
|
|
181
|
+
retries?: {
|
|
182
|
+
limit: number;
|
|
183
|
+
delay: string | number;
|
|
184
|
+
backoff?: 'constant' | 'linear' | 'exponential';
|
|
185
|
+
};
|
|
186
|
+
timeout?: string | number;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Minimal `WorkflowEvent<T>` shape — only the fields this adapter touches.
|
|
190
|
+
* `payload` carries the `{ __wfName, __wfInput }` envelope produced by
|
|
191
|
+
* {@link CloudflareWorkflowsDurableExecution.run}.
|
|
192
|
+
*/
|
|
193
|
+
export interface WorkflowEventLike<T = unknown> {
|
|
194
|
+
readonly payload: Readonly<T>;
|
|
195
|
+
readonly timestamp?: Date;
|
|
196
|
+
readonly instanceId?: string;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Minimal `WorkflowInstance` shape — only the methods this adapter uses.
|
|
200
|
+
*
|
|
201
|
+
* Declared structurally to match CF's `WorkflowInstance` while remaining
|
|
202
|
+
* testable without `cloudflare:workers`.
|
|
203
|
+
*/
|
|
204
|
+
export interface WorkflowInstanceLike {
|
|
205
|
+
readonly id: string;
|
|
206
|
+
status(): Promise<{
|
|
207
|
+
status: 'queued' | 'running' | 'paused' | 'errored' | 'terminated' | 'complete' | 'waiting' | 'waitingForPause' | 'unknown';
|
|
208
|
+
error?: {
|
|
209
|
+
name: string;
|
|
210
|
+
message: string;
|
|
211
|
+
};
|
|
212
|
+
output?: unknown;
|
|
213
|
+
}>;
|
|
214
|
+
sendEvent?(args: {
|
|
215
|
+
type: string;
|
|
216
|
+
payload: unknown;
|
|
217
|
+
}): Promise<void>;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Minimal `Workflow` binding shape — only the methods this adapter uses.
|
|
221
|
+
*
|
|
222
|
+
* Mirrors `Workflow<PARAMS>` from `cloudflare:workers`. The adapter accepts
|
|
223
|
+
* either the binding directly or a thunk that returns it (for environments
|
|
224
|
+
* where the binding is only resolvable per-request, e.g. inside `fetch`).
|
|
225
|
+
*/
|
|
226
|
+
export interface WorkflowsBindingLike<PARAMS = unknown> {
|
|
227
|
+
create(options?: {
|
|
228
|
+
id?: string;
|
|
229
|
+
params?: PARAMS;
|
|
230
|
+
}): Promise<WorkflowInstanceLike>;
|
|
231
|
+
get(id: string): Promise<WorkflowInstanceLike>;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Base class shape `createWorkflowEntrypoint` extends. Aliased here so users
|
|
235
|
+
* (and tests) can refer to the structural type without importing
|
|
236
|
+
* `cloudflare:workers`. Real callers receive an actual `WorkflowEntrypoint`
|
|
237
|
+
* subclass; tests can stub it.
|
|
238
|
+
*/
|
|
239
|
+
export interface WorkflowEntrypointLike<Env = unknown, T = unknown> {
|
|
240
|
+
run(event: Readonly<WorkflowEventLike<T>>, step: WorkflowStepLike): Promise<unknown>;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Options for {@link createCloudflareWorkflowsDurableExecution}.
|
|
244
|
+
*/
|
|
245
|
+
export interface CloudflareWorkflowsDurableExecutionOptions {
|
|
246
|
+
/**
|
|
247
|
+
* The CF Workflows binding from a Workers environment, or a thunk that
|
|
248
|
+
* resolves the binding per-call. Use the thunk form when the binding is
|
|
249
|
+
* only available inside a request handler (e.g. `() => env.WORKFLOW`).
|
|
250
|
+
*/
|
|
251
|
+
binding: WorkflowsBindingLike | (() => WorkflowsBindingLike);
|
|
252
|
+
/**
|
|
253
|
+
* When `true` (default), {@link DurableExecutionAdapter.run} polls the
|
|
254
|
+
* created instance's status until it reaches `complete` or `errored` and
|
|
255
|
+
* returns the workflow output (or throws on `errored`/`terminated`).
|
|
256
|
+
*
|
|
257
|
+
* When `false`, `run()` returns the {@link WorkflowInstanceLike} cast to
|
|
258
|
+
* `unknown` so the caller can manage the lifecycle themselves. Useful for
|
|
259
|
+
* fire-and-forget triggers or when polling is undesirable.
|
|
260
|
+
*
|
|
261
|
+
* Default: `true`.
|
|
262
|
+
*/
|
|
263
|
+
waitForCompletion?: boolean;
|
|
264
|
+
/**
|
|
265
|
+
* Polling interval (ms) when `waitForCompletion` is `true`. Default: 250.
|
|
266
|
+
*/
|
|
267
|
+
pollIntervalMs?: number;
|
|
268
|
+
/**
|
|
269
|
+
* Maximum total wait time (ms) when `waitForCompletion` is `true`. After
|
|
270
|
+
* this elapses the adapter throws a {@link DurableStepError} with
|
|
271
|
+
* `retryable: false`. Default: 24 hours (86_400_000 ms). Set higher for
|
|
272
|
+
* long-sleeping workflows or use `waitForCompletion: false`.
|
|
273
|
+
*/
|
|
274
|
+
pollTimeoutMs?: number;
|
|
275
|
+
/**
|
|
276
|
+
* Override `setTimeout` for tests. Defaults to the global `setTimeout`.
|
|
277
|
+
* Used by the polling loop and the (no-op) schedule registry.
|
|
278
|
+
*/
|
|
279
|
+
delay?: (ms: number) => Promise<void>;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Limits the adapter knows about (per ADR-0004 / current CF docs).
|
|
283
|
+
*/
|
|
284
|
+
export interface CloudflareWorkflowsLimits {
|
|
285
|
+
/** Maximum steps per workflow (default-configurable as of Mar 2026). */
|
|
286
|
+
readonly maxSteps: 25_000;
|
|
287
|
+
/** Maximum concurrent workflow instances per account. */
|
|
288
|
+
readonly maxConcurrentInstances: 50_000;
|
|
289
|
+
/** Maximum single sleep / sleepUntil duration. */
|
|
290
|
+
readonly maxSleepDays: 365;
|
|
291
|
+
/** Per-step / per-event payload size (CF Workers RPC limit). */
|
|
292
|
+
readonly maxPayloadBytes: 1_048_576;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Internal envelope passed as the `params` to `binding.create()`. The
|
|
296
|
+
* generated {@link WorkflowEntrypointLike} reads these fields from
|
|
297
|
+
* `event.payload` to dispatch into the registered workflow body.
|
|
298
|
+
*
|
|
299
|
+
* Names are double-underscored to avoid collision with user-supplied input
|
|
300
|
+
* keys when input is itself an object literal — though we always wrap input
|
|
301
|
+
* inside `__wfInput` so this is belt-and-suspenders.
|
|
302
|
+
*/
|
|
303
|
+
export interface WorkflowEnvelope<TInput = unknown> {
|
|
304
|
+
readonly __wfName: string;
|
|
305
|
+
readonly __wfInput: TInput;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* The adapter returned by {@link createCloudflareWorkflowsDurableExecution}.
|
|
309
|
+
*
|
|
310
|
+
* Extends {@link DurableExecutionAdapter} with:
|
|
311
|
+
*
|
|
312
|
+
* - {@link CloudflareWorkflowsDurableExecution.register} — explicitly
|
|
313
|
+
* register a workflow body before triggering it.
|
|
314
|
+
* - {@link CloudflareWorkflowsDurableExecution.defineSchedule} — alias for
|
|
315
|
+
* `schedule()` whose name emphasises the wrangler-coordinated nature.
|
|
316
|
+
* - {@link CloudflareWorkflowsDurableExecution.runSchedule} — invoke a
|
|
317
|
+
* scheduled workflow from a Worker `scheduled()` handler when its cron
|
|
318
|
+
* fires.
|
|
319
|
+
* - {@link CloudflareWorkflowsDurableExecution.entrypointHandler} — bound
|
|
320
|
+
* handler used by the {@link WorkflowEntrypointLike} class to dispatch
|
|
321
|
+
* incoming events back into the registered body.
|
|
322
|
+
* - {@link CloudflareWorkflowsDurableExecution.limits} — declared CF
|
|
323
|
+
* Workflows limits (consumers can introspect to bound their own steps).
|
|
324
|
+
*/
|
|
325
|
+
export interface CloudflareWorkflowsDurableExecution extends DurableExecutionAdapter {
|
|
326
|
+
readonly kind: 'cloudflare';
|
|
327
|
+
readonly limits: CloudflareWorkflowsLimits;
|
|
328
|
+
/**
|
|
329
|
+
* Register a workflow body under `name`. Subsequent `run(name, ...)` and
|
|
330
|
+
* scheduled invocations dispatch to it. Calling `register` with an
|
|
331
|
+
* existing name replaces the previous body.
|
|
332
|
+
*/
|
|
333
|
+
register<TResult = unknown, TInput = unknown>(name: string, fn: WorkflowFn<TResult, TInput>): void;
|
|
334
|
+
/**
|
|
335
|
+
* Alias for {@link DurableExecutionAdapter.schedule}. CF Workflows have no
|
|
336
|
+
* imperative cron API; the user's wrangler config defines the schedule
|
|
337
|
+
* (`[triggers] crons = [...]`) and routes to a `scheduled()` handler that
|
|
338
|
+
* calls {@link runSchedule} when the cron fires.
|
|
339
|
+
*
|
|
340
|
+
* Returns a {@link Subscription} whose `id` equals `name`.
|
|
341
|
+
*/
|
|
342
|
+
defineSchedule<TResult = unknown>(name: string, cron: string, fn: WorkflowFn<TResult, undefined>): Subscription;
|
|
343
|
+
/**
|
|
344
|
+
* Invoke a previously registered scheduled workflow. Intended to be called
|
|
345
|
+
* from a Worker `scheduled()` handler when the cron fires. Returns the
|
|
346
|
+
* triggered instance handle (or its output if `waitForCompletion`).
|
|
347
|
+
*/
|
|
348
|
+
runSchedule(name: string): Promise<unknown>;
|
|
349
|
+
/**
|
|
350
|
+
* The dispatch handler used by the generated
|
|
351
|
+
* {@link WorkflowEntrypointLike} class. Exposed so callers can build their
|
|
352
|
+
* own entrypoint subclass (e.g. to layer custom env-handling) and forward
|
|
353
|
+
* `(event, step)` here.
|
|
354
|
+
*/
|
|
355
|
+
entrypointHandler(event: WorkflowEventLike, step: WorkflowStepLike): Promise<unknown>;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Construct a Cloudflare Workflows {@link DurableExecutionAdapter}.
|
|
359
|
+
*
|
|
360
|
+
* The adapter satisfies the full port contract by translating each call into
|
|
361
|
+
* its CF equivalent (see module docs). Step bodies execute inside CF's
|
|
362
|
+
* runtime and inherit CF's idempotency, replay, and hibernation semantics.
|
|
363
|
+
*
|
|
364
|
+
* **The adapter does not run workflow bodies in-process.** Calling `run()`
|
|
365
|
+
* triggers a CF Workflow via the supplied binding; the body runs on CF's
|
|
366
|
+
* infrastructure and the adapter polls (or returns the instance handle).
|
|
367
|
+
* For tests that need to exercise the body directly without a CF runtime,
|
|
368
|
+
* use {@link createInProcessDurableExecution} or
|
|
369
|
+
* {@link createInMemoryDurableExecution} instead.
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```ts
|
|
373
|
+
* import { createCloudflareWorkflowsDurableExecution, createWorkflowEntrypoint } from 'ai-workflows/durable-execution'
|
|
374
|
+
*
|
|
375
|
+
* type Env = { WORKFLOW: Workflow }
|
|
376
|
+
*
|
|
377
|
+
* const dx = createCloudflareWorkflowsDurableExecution({ binding: () => env.WORKFLOW })
|
|
378
|
+
* dx.register('hello', async (ctx) => `hi, ${ctx.input}`)
|
|
379
|
+
*
|
|
380
|
+
* export const HelloWorkflow = createWorkflowEntrypoint(dx)
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
export declare function createCloudflareWorkflowsDurableExecution(options: CloudflareWorkflowsDurableExecutionOptions): CloudflareWorkflowsDurableExecution;
|
|
384
|
+
/**
|
|
385
|
+
* Constructor-shape returned by {@link createWorkflowEntrypoint} when called
|
|
386
|
+
* without the optional `Base` class. Callable with `new` like a normal
|
|
387
|
+
* `WorkflowEntrypoint` subclass — CF instantiates it once per workflow run.
|
|
388
|
+
*
|
|
389
|
+
* The first constructor argument is `ctx` (an `ExecutionContext`) and the
|
|
390
|
+
* second is `env`; declared `unknown` here so this module compiles without
|
|
391
|
+
* `cloudflare:workers` types in the build environment.
|
|
392
|
+
*/
|
|
393
|
+
export type WorkflowEntrypointConstructor = new (ctx: unknown, env: unknown) => {
|
|
394
|
+
run(event: WorkflowEventLike, step: WorkflowStepLike): Promise<unknown>;
|
|
395
|
+
};
|
|
396
|
+
/**
|
|
397
|
+
* Generate a {@link WorkflowEntrypointLike} subclass bound to `adapter`.
|
|
398
|
+
*
|
|
399
|
+
* Users export the returned class from their worker module and reference it
|
|
400
|
+
* in `wrangler.jsonc` under `workflows[].class_name`. CF instantiates the
|
|
401
|
+
* class for each workflow run, calls its `run(event, step)`, and the adapter
|
|
402
|
+
* dispatches into the registered body.
|
|
403
|
+
*
|
|
404
|
+
* **Why a factory instead of a fixed export?** CF binds workflows by class
|
|
405
|
+
* name at deploy time — each binding needs its own class identity. The
|
|
406
|
+
* factory pattern lets users have multiple adapters/classes in one module
|
|
407
|
+
* (e.g. one per binding) without colliding.
|
|
408
|
+
*
|
|
409
|
+
* If `Base` is omitted, this module declares an internal abstract class with
|
|
410
|
+
* the signature CF expects. In production, callers SHOULD pass the real
|
|
411
|
+
* `WorkflowEntrypoint` from `cloudflare:workers` so CF's runtime magic (env
|
|
412
|
+
* injection, `[Rpc.__WORKFLOW_ENTRYPOINT_BRAND]`, etc.) is preserved:
|
|
413
|
+
*
|
|
414
|
+
* ```ts
|
|
415
|
+
* import { WorkflowEntrypoint } from 'cloudflare:workers'
|
|
416
|
+
* import { createCloudflareWorkflowsDurableExecution, createWorkflowEntrypoint } from 'ai-workflows/durable-execution'
|
|
417
|
+
*
|
|
418
|
+
* const dx = createCloudflareWorkflowsDurableExecution({ binding: () => env.WORKFLOW })
|
|
419
|
+
* export const MyWorkflow = createWorkflowEntrypoint(dx, WorkflowEntrypoint)
|
|
420
|
+
* ```
|
|
421
|
+
*
|
|
422
|
+
* In tests / Node environments where `cloudflare:workers` isn't available,
|
|
423
|
+
* call without `Base` and the adapter's dispatch logic is exercised against
|
|
424
|
+
* the structural fake.
|
|
425
|
+
*/
|
|
426
|
+
export declare function createWorkflowEntrypoint<Env = unknown, T = unknown>(adapter: CloudflareWorkflowsDurableExecution, Base?: WorkflowEntrypointConstructor): WorkflowEntrypointConstructor;
|
|
427
|
+
//# sourceMappingURL=durable-execution-cloudflare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"durable-execution-cloudflare.d.ts","sourceRoot":"","sources":["../src/durable-execution-cloudflare.ts"],"names":[],"mappings":"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"}
|