@lunora/workflow 1.0.0-alpha.4 → 1.0.0-alpha.41
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/LICENSE.md +6 -0
- package/README.md +25 -2
- package/dist/do/index.d.mts +16 -16
- package/dist/do/index.d.ts +16 -16
- package/dist/do/index.mjs +1 -44
- package/dist/index.d.mts +170 -123
- package/dist/index.d.ts +170 -123
- package/dist/index.mjs +1 -9
- package/dist/packem_shared/MAX_BRANCHES-C05O5LY9.mjs +1 -0
- package/dist/packem_shared/NonRetryableError-9ZqDUzwT.mjs +1 -0
- package/dist/packem_shared/WorkflowsRestError-HhBsn3PQ.mjs +1 -0
- package/dist/packem_shared/branch-marker-CCpWfS5k.mjs +1 -0
- package/dist/packem_shared/createRunStep-DB1SaYfF.mjs +1 -0
- package/dist/packem_shared/createWaitForEvent-DjWsI895.mjs +1 -0
- package/dist/packem_shared/createWorkflowContext-zQR_9N-v.mjs +1 -0
- package/dist/packem_shared/createWorkflowRunContext-C83Yp2Qp.mjs +1 -0
- package/dist/packem_shared/createWorkflows-LvAyUyKq.mjs +1 -0
- package/dist/packem_shared/defineStep-D1-9eOnA.mjs +1 -0
- package/dist/packem_shared/defineWorkflow-tKaIifbZ.mjs +1 -0
- package/dist/packem_shared/defineWorkflowEvent-suERPEEV.mjs +1 -0
- package/dist/packem_shared/run-step-D7XRYstF.mjs +1 -0
- package/dist/packem_shared/types.d-C7jti0tm.d.mts +522 -0
- package/dist/packem_shared/types.d-C7jti0tm.d.ts +522 -0
- package/package.json +3 -2
- package/dist/packem_shared/MAX_BRANCHES-C9MJIFii.mjs +0 -108
- package/dist/packem_shared/NonRetryableError-Dn2dTyBS.mjs +0 -27
- package/dist/packem_shared/WorkflowsRestError-b06i7K5j.mjs +0 -118
- package/dist/packem_shared/createRunStep-8jOXxP2o.mjs +0 -54
- package/dist/packem_shared/createWorkflowContext-D6thzmlF.mjs +0 -14
- package/dist/packem_shared/createWorkflowRunContext-BsMyGuMR.mjs +0 -110
- package/dist/packem_shared/createWorkflows-BoSYVIXg.mjs +0 -23
- package/dist/packem_shared/defineStep-DJQtLw7g.mjs +0 -28
- package/dist/packem_shared/defineWorkflow-DbUC-oCN.mjs +0 -15
- package/dist/packem_shared/types.d-Fdeu2P2C.d.mts +0 -394
- package/dist/packem_shared/types.d-Fdeu2P2C.d.ts +0 -394
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
import { ValidatorMap, InferValidatorMap, Validator } from '@lunora/values';
|
|
2
|
+
/**
|
|
3
|
+
* The generated function-reference type, shared by every package that needs to
|
|
4
|
+
* infer a call's args or return from `api.<file>.<fn>`.
|
|
5
|
+
*
|
|
6
|
+
* This lives in `shared/` rather than in one package because the consumers span
|
|
7
|
+
* a dependency boundary they must not cross: `@lunora/scheduler` and
|
|
8
|
+
* `@lunora/workflow` accept a reference in `runAfter`/`runAt`/`step.run*` but
|
|
9
|
+
* cannot depend on `@lunora/client`, which is a browser package. Each of them
|
|
10
|
+
* previously hand-copied this declaration, and both copies silently rotted when
|
|
11
|
+
* the phantom carrier was renamed — the conditional matched an OPTIONAL property
|
|
12
|
+
* that no longer existed, so `ArgsOf<F>` quietly resolved to `unknown` and every
|
|
13
|
+
* `step.run(ref, args)` in the repo lost its arg checking without a single error.
|
|
14
|
+
*
|
|
15
|
+
* `shared/` is the repo's answer to exactly that shape: bundler-inlined,
|
|
16
|
+
* zero-dependency source imported by relative path, so it creates no runtime
|
|
17
|
+
* edge between the packages that inline it. Being ONE declaration, there is
|
|
18
|
+
* nothing to keep in lockstep and no drift test to write.
|
|
19
|
+
*/
|
|
20
|
+
/** The registered function kinds a {@link FunctionReference} can describe. `stream` is a query that yields multiple frames over the WS. */
|
|
21
|
+
type FunctionKind = "action" | "mutation" | "query" | "stream";
|
|
22
|
+
/**
|
|
23
|
+
* Opaque reference to a registered function emitted by `@lunora/codegen`.
|
|
24
|
+
*
|
|
25
|
+
* At runtime it carries the `<file>:<function>` identifier in `__lunoraRef`.
|
|
26
|
+
* Generated declarations decorate this with phantom type parameters so callers
|
|
27
|
+
* can infer args / return values per call site.
|
|
28
|
+
*/
|
|
29
|
+
interface FunctionReference<Kind extends FunctionKind = FunctionKind, Args = unknown, Return = unknown> {
|
|
30
|
+
/**
|
|
31
|
+
* Phantom marker carrying the `Kind`/`Args`/`Return` type parameters for
|
|
32
|
+
* inference. Never present at runtime; declared as a covariant (output)
|
|
33
|
+
* position so a concrete reference stays assignable to a widened one.
|
|
34
|
+
*/
|
|
35
|
+
readonly __lunoraPhantom?: {
|
|
36
|
+
args: Args;
|
|
37
|
+
kind: Kind;
|
|
38
|
+
returns: Return;
|
|
39
|
+
};
|
|
40
|
+
readonly __lunoraRef: string;
|
|
41
|
+
}
|
|
42
|
+
/** Extract the args type from a {@link FunctionReference}. */
|
|
43
|
+
type ArgsOf<F> = F extends FunctionReference<infer _K, infer A, infer _R> ? A : never;
|
|
44
|
+
/** A workflow instance's lifecycle status. Mirrors `WorkflowInstanceStatus`. */
|
|
45
|
+
type WorkflowInstanceStatus = "complete" | "errored" | "paused" | "queued" | "running" | "terminated" | "unknown" | "waiting" | "waitingForPause";
|
|
46
|
+
/** Result of `WorkflowInstance.status()`. Mirrors Cloudflare's `InstanceStatus`. */
|
|
47
|
+
interface WorkflowStatusResult {
|
|
48
|
+
error?: {
|
|
49
|
+
message: string;
|
|
50
|
+
name: string;
|
|
51
|
+
};
|
|
52
|
+
output?: unknown;
|
|
53
|
+
status: WorkflowInstanceStatus;
|
|
54
|
+
}
|
|
55
|
+
/** Options accepted by `Workflow.create`. Mirrors `WorkflowInstanceCreateOptions`. */
|
|
56
|
+
interface WorkflowCreateOptions<Params = Record<string, unknown>> {
|
|
57
|
+
/** Unique-within-the-workflow instance id. Generated by Cloudflare when omitted. */
|
|
58
|
+
id?: string;
|
|
59
|
+
/** The event payload the instance is triggered with — surfaced as `event.payload`. */
|
|
60
|
+
params?: Params;
|
|
61
|
+
/** Instance retention policy (defaults to the account maximum). */
|
|
62
|
+
retention?: {
|
|
63
|
+
errorRetention?: string;
|
|
64
|
+
successRetention?: string;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** A live handle to a single workflow instance. Mirrors `WorkflowInstance`. */
|
|
68
|
+
interface WorkflowInstanceLike {
|
|
69
|
+
readonly id: string;
|
|
70
|
+
pause: () => Promise<void>;
|
|
71
|
+
restart: () => Promise<void>;
|
|
72
|
+
resume: () => Promise<void>;
|
|
73
|
+
sendEvent: (event: {
|
|
74
|
+
payload: unknown;
|
|
75
|
+
type: string;
|
|
76
|
+
}) => Promise<void>;
|
|
77
|
+
status: () => Promise<WorkflowStatusResult>;
|
|
78
|
+
terminate: () => Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The subset of the Cloudflare `Workflow` binding the package consumes.
|
|
82
|
+
* `createBatch` is a non-optional method on the real binding (Cloudflare's
|
|
83
|
+
* `Workflow` class declares it unconditionally), so it is required here too —
|
|
84
|
+
* the handle never has to guard for its absence.
|
|
85
|
+
*/
|
|
86
|
+
interface WorkflowBindingLike<Params = Record<string, unknown>> {
|
|
87
|
+
create: (options?: WorkflowCreateOptions<Params>) => Promise<WorkflowInstanceLike>;
|
|
88
|
+
createBatch: (batch: ReadonlyArray<WorkflowCreateOptions<Params>>) => Promise<WorkflowInstanceLike[]>;
|
|
89
|
+
get: (id: string) => Promise<WorkflowInstanceLike>;
|
|
90
|
+
}
|
|
91
|
+
/** The `event` argument a workflow `run` receives. Mirrors `WorkflowEvent<T>`. */
|
|
92
|
+
interface WorkflowEventLike<Params = Record<string, unknown>> {
|
|
93
|
+
readonly instanceId: string;
|
|
94
|
+
readonly payload: Readonly<Params>;
|
|
95
|
+
readonly timestamp: Date;
|
|
96
|
+
readonly workflowName: string;
|
|
97
|
+
}
|
|
98
|
+
/** Per-step durability config. Mirrors the `WorkflowStepConfig.retries` shape. */
|
|
99
|
+
interface WorkflowStepConfigLike {
|
|
100
|
+
retries?: {
|
|
101
|
+
backoff?: "constant" | "exponential" | "linear";
|
|
102
|
+
delay?: number | string;
|
|
103
|
+
limit: number;
|
|
104
|
+
};
|
|
105
|
+
timeout?: number | string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The per-attempt info Cloudflare passes a `step.do` callback. Mirrors
|
|
109
|
+
* `WorkflowStepContext` — `attempt` is the 1-based retry counter (`> 1` on
|
|
110
|
+
* retries) and `step` carries the durable step's name + invocation count.
|
|
111
|
+
*/
|
|
112
|
+
interface WorkflowStepContextLike {
|
|
113
|
+
/** 1-based attempt counter — `> 1` means this is a retry. */
|
|
114
|
+
attempt: number;
|
|
115
|
+
/** The resolved per-step config for this invocation. */
|
|
116
|
+
config: WorkflowStepConfigLike;
|
|
117
|
+
/** The durable step's identity. */
|
|
118
|
+
step: {
|
|
119
|
+
count: number;
|
|
120
|
+
name: string;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** The context a rollback handler receives. Mirrors `WorkflowRollbackContext` (`{ ctx, error, output, stepName }`). */
|
|
124
|
+
interface WorkflowRollbackContextLike<T = unknown> {
|
|
125
|
+
/** The per-attempt step context (`attempt` / `config` / `step`) for the rolled-back step. */
|
|
126
|
+
ctx: WorkflowStepContextLike;
|
|
127
|
+
/** The error that triggered the rollback. */
|
|
128
|
+
error: Error;
|
|
129
|
+
/** The step's output if it completed before a later step failed, else `undefined`. */
|
|
130
|
+
output: T | undefined;
|
|
131
|
+
/** The durable step's name. */
|
|
132
|
+
stepName: string;
|
|
133
|
+
}
|
|
134
|
+
/** A native step rollback handler. Mirrors `WorkflowRollbackHandler`. */
|
|
135
|
+
type WorkflowRollbackHandlerLike<T = unknown> = (context: WorkflowRollbackContextLike<T>) => Promise<void>;
|
|
136
|
+
/** Native rollback options accepted by `step.do`. Mirrors the Cloudflare rollback-options shape. */
|
|
137
|
+
interface WorkflowStepRollbackOptionsLike<T = unknown> {
|
|
138
|
+
rollback?: WorkflowRollbackHandlerLike<T>;
|
|
139
|
+
rollbackConfig?: WorkflowStepConfigLike;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The durable step API Cloudflare hands the workflow body. Mirrors
|
|
143
|
+
* `WorkflowStep` — `do` memoizes + retries its callback, `sleep`/`sleepUntil`
|
|
144
|
+
* are durable delays, and `waitForEvent` hibernates until an external event.
|
|
145
|
+
* `do`'s two overloads mirror Cloudflare's: an optional leading `config` and an
|
|
146
|
+
* optional trailing `rollback` (compensation run when a later step fails).
|
|
147
|
+
*
|
|
148
|
+
* Known mirror gap: Cloudflare constrains `do<T extends Rpc.Serializable<T>>` so
|
|
149
|
+
* a non-serializable step result (a function, `Map`, class instance, …) is a
|
|
150
|
+
* compile error there. `Rpc.Serializable` lives in `@cloudflare/workers-types`
|
|
151
|
+
* and is not Node-importable, so this Node-safe mirror uses a bare `<T>` and
|
|
152
|
+
* cannot enforce that — a non-serializable result type-checks here but fails at
|
|
153
|
+
* runtime on the platform. Keep step results JSON-serialisable.
|
|
154
|
+
*/
|
|
155
|
+
interface WorkflowStepLike {
|
|
156
|
+
do: {
|
|
157
|
+
<T>(name: string, callback: (context: WorkflowStepContextLike) => Promise<T>, rollback?: WorkflowStepRollbackOptionsLike<T>): Promise<T>;
|
|
158
|
+
<T>(name: string, config: WorkflowStepConfigLike, callback: (context: WorkflowStepContextLike) => Promise<T>, rollback?: WorkflowStepRollbackOptionsLike<T>): Promise<T>;
|
|
159
|
+
};
|
|
160
|
+
sleep: (name: string, duration: number | string) => Promise<void>;
|
|
161
|
+
sleepUntil: (name: string, timestamp: Date | number) => Promise<void>;
|
|
162
|
+
waitForEvent: <T = unknown>(name: string, options: {
|
|
163
|
+
timeout?: number | string;
|
|
164
|
+
type: string;
|
|
165
|
+
}) => Promise<{
|
|
166
|
+
payload: Readonly<T>;
|
|
167
|
+
type: string;
|
|
168
|
+
}>;
|
|
169
|
+
}
|
|
170
|
+
/** Minimal structured logger handed to the workflow body. */
|
|
171
|
+
interface WorkflowLogger {
|
|
172
|
+
debug: (message: string, ...rest: unknown[]) => void;
|
|
173
|
+
error: (message: string, ...rest: unknown[]) => void;
|
|
174
|
+
info: (message: string, ...rest: unknown[]) => void;
|
|
175
|
+
warn: (message: string, ...rest: unknown[]) => void;
|
|
176
|
+
}
|
|
177
|
+
/** Per-call options for {@link WorkflowRunFunction}. */
|
|
178
|
+
interface RunFunctionOptions {
|
|
179
|
+
/** Routing hint forwarded to the Worker so the call lands on the right shard. */
|
|
180
|
+
shardKey?: string;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Calls a Lunora query / mutation / action from inside a workflow and resolves
|
|
184
|
+
* with its result. Wrap it in {@link WorkflowStepLike.do} to make the call a
|
|
185
|
+
* durable, memoized, retried step:
|
|
186
|
+
*
|
|
187
|
+
* ```ts
|
|
188
|
+
* const charge = await ctx.step.do("charge", () => ctx.run(api.payments.charge, { id }));
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
type WorkflowRunFunction = <F extends FunctionReference>(function_: F, args?: ArgsOf<F>, options?: RunFunctionOptions) => Promise<unknown>;
|
|
192
|
+
/** Map of validators describing a step's args record — the same shape a Lunora function's `args` uses. Alias of `@lunora/values`' shared {@link ValidatorMap}. */
|
|
193
|
+
type StepArgsValidator = ValidatorMap;
|
|
194
|
+
/** Infer the args object type from a {@link StepArgsValidator} (optional validators → optional keys). Alias of `@lunora/values`' shared {@link InferValidatorMap}. */
|
|
195
|
+
type InferStepArgs<A extends StepArgsValidator> = InferValidatorMap<A>;
|
|
196
|
+
/**
|
|
197
|
+
* The context a {@link StepDefinition} handler receives as its first argument
|
|
198
|
+
* (the validated args are the second). Bundles the native per-attempt info
|
|
199
|
+
* (`attempt`, `config`, `step`) with the Worker `env`, the Lunora runner, and a
|
|
200
|
+
* logger.
|
|
201
|
+
*/
|
|
202
|
+
interface StepRunContext {
|
|
203
|
+
/** 1-based retry counter — `> 1` means Cloudflare is retrying the step. */
|
|
204
|
+
readonly attempt: number;
|
|
205
|
+
/** The resolved durability config for this invocation. */
|
|
206
|
+
readonly config: WorkflowStepConfigLike;
|
|
207
|
+
/** The Worker environment bindings. */
|
|
208
|
+
readonly env: Record<string, unknown>;
|
|
209
|
+
/** Structured logger surfaced in `wrangler tail` / Studio logs. */
|
|
210
|
+
readonly log: WorkflowLogger;
|
|
211
|
+
/** Invoke a Lunora query / mutation / action. */
|
|
212
|
+
readonly run: WorkflowRunFunction;
|
|
213
|
+
/** The durable step's identity (name + invocation count). */
|
|
214
|
+
readonly step: {
|
|
215
|
+
count: number;
|
|
216
|
+
name: string;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/** The work a step performs. Receives the {@link StepRunContext} and the validated args. */
|
|
220
|
+
type StepHandler<A extends StepArgsValidator, Result> = (context: StepRunContext, args: InferStepArgs<A>) => Promise<Result> | Result;
|
|
221
|
+
/** The context a step rollback handler receives — the Lunora-flavored mirror of `WorkflowRollbackContext`. */
|
|
222
|
+
interface StepRollbackContext<A extends StepArgsValidator, Result> {
|
|
223
|
+
/** The validated args the step ran with. */
|
|
224
|
+
readonly args: InferStepArgs<A>;
|
|
225
|
+
/** The Worker environment bindings. */
|
|
226
|
+
readonly env: Record<string, unknown>;
|
|
227
|
+
/** The error that triggered the rollback. */
|
|
228
|
+
readonly error: Error;
|
|
229
|
+
/** Structured logger. */
|
|
230
|
+
readonly log: WorkflowLogger;
|
|
231
|
+
/** The step's output if it completed before a later step failed, else `undefined`. */
|
|
232
|
+
readonly output: Result | undefined;
|
|
233
|
+
/** Invoke a Lunora function — e.g. to undo a write the step made. */
|
|
234
|
+
readonly run: WorkflowRunFunction;
|
|
235
|
+
}
|
|
236
|
+
/** A step compensation handler — runs when a later step fails after this one completed. */
|
|
237
|
+
type StepRollbackHandler<A extends StepArgsValidator, Result> = (context: StepRollbackContext<A, Result>) => Promise<void> | void;
|
|
238
|
+
/** Author-supplied config for {@link StepDefinition}, passed to `defineStep`. */
|
|
239
|
+
interface StepConfig<A extends StepArgsValidator, Result> {
|
|
240
|
+
/** Validators for the step's args — the same map shape a Lunora function uses. */
|
|
241
|
+
args: A;
|
|
242
|
+
/** Optional durability config (retries / timeout) applied to the step. */
|
|
243
|
+
config?: WorkflowStepConfigLike;
|
|
244
|
+
/** The work the step performs. */
|
|
245
|
+
handler: StepHandler<A, Result>;
|
|
246
|
+
/** Optional validator for the return value — validated before the result leaves the step. */
|
|
247
|
+
returns?: Validator<Result>;
|
|
248
|
+
/** Optional compensation run when a later step fails after this one completed. */
|
|
249
|
+
rollback?: StepRollbackHandler<A, Result>;
|
|
250
|
+
/** Optional durability config for the rollback step itself. */
|
|
251
|
+
rollbackConfig?: WorkflowStepConfigLike;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* A `defineStep` result — a reusable, schema-validated durable step. Run it from
|
|
255
|
+
* a workflow body with `ctx.runStep(step, args)`. The phantom generics carry the
|
|
256
|
+
* inferred args + result types to the call site.
|
|
257
|
+
*/
|
|
258
|
+
interface StepDefinition<A extends StepArgsValidator = StepArgsValidator, Result = unknown> {
|
|
259
|
+
/** Validators for the step's args. */
|
|
260
|
+
readonly args: A;
|
|
261
|
+
/** Optional per-step durability config. */
|
|
262
|
+
readonly config?: WorkflowStepConfigLike;
|
|
263
|
+
/** The step body. */
|
|
264
|
+
readonly handler: StepHandler<A, Result>;
|
|
265
|
+
/** Runtime brand check (see `isStepDefinition`). */
|
|
266
|
+
readonly isLunoraStep: true;
|
|
267
|
+
/** The durable step's name — also the `step.do(...)` label. */
|
|
268
|
+
readonly name: string;
|
|
269
|
+
/** Optional result validator. */
|
|
270
|
+
readonly returns?: Validator<Result>;
|
|
271
|
+
/** Optional compensation handler. */
|
|
272
|
+
readonly rollback?: StepRollbackHandler<A, Result>;
|
|
273
|
+
/** Optional rollback durability config. */
|
|
274
|
+
readonly rollbackConfig?: WorkflowStepConfigLike;
|
|
275
|
+
}
|
|
276
|
+
/** Per-call options for {@link WorkflowRunStepFunction}. */
|
|
277
|
+
interface RunStepOptions {
|
|
278
|
+
/** Override the step's declared durability config for this call. */
|
|
279
|
+
config?: WorkflowStepConfigLike;
|
|
280
|
+
/**
|
|
281
|
+
* Override the durable step name for this call. Cloudflare keys a durable
|
|
282
|
+
* step by name **and occurrence** (`step.count` counts the calls made under
|
|
283
|
+
* one name in a run), so reusing a name in a loop is fine and each
|
|
284
|
+
* occurrence caches independently — this is for giving a call its own
|
|
285
|
+
* addressable name, e.g. to target it with `instance.restart({ from })`.
|
|
286
|
+
* Must be deterministic across replays, like any step name.
|
|
287
|
+
*/
|
|
288
|
+
name?: string;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Run a reusable {@link StepDefinition} as a durable, memoized, retried step:
|
|
292
|
+
* validates the args before the body runs and the result after (when the step
|
|
293
|
+
* declares `returns`), and forwards any rollback handler to Cloudflare.
|
|
294
|
+
*
|
|
295
|
+
* ```ts
|
|
296
|
+
* const data = await ctx.runStep(fetchImage, { imageKey });
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
type WorkflowRunStepFunction = <A extends StepArgsValidator, Result>(step: StepDefinition<A, Result>, args: InferStepArgs<A>, options?: RunStepOptions) => Promise<Result>;
|
|
300
|
+
/**
|
|
301
|
+
* A `defineWorkflowEvent` result — the single source of truth for one external
|
|
302
|
+
* event's wire `type` and payload shape. Both ends of the exchange import the same
|
|
303
|
+
* definition (`ctx.waitForEvent(orderApproved)` inside the workflow,
|
|
304
|
+
* `workflows.get(w).sendEvent(id, orderApproved, payload)` from the caller), so
|
|
305
|
+
* there is no string to typo and no second place to update on a rename, and the
|
|
306
|
+
* payload is parsed at both ends instead of crossing as `unknown`.
|
|
307
|
+
*
|
|
308
|
+
* It does NOT make every mismatch a compile error: two definitions with the same
|
|
309
|
+
* payload shape are mutually assignable, so sending `orderRejected` where the
|
|
310
|
+
* workflow awaits `orderApproved` still type-checks (and still hibernates until
|
|
311
|
+
* the timeout). What it removes is the hand-matched literal.
|
|
312
|
+
*/
|
|
313
|
+
interface WorkflowEventDefinition<Payload = unknown> {
|
|
314
|
+
/** Runtime brand check (see `isWorkflowEventDefinition`). */
|
|
315
|
+
readonly isLunoraWorkflowEvent: true;
|
|
316
|
+
/** Validator for the event payload — parsed on send and again on receive. */
|
|
317
|
+
readonly payload: Validator<Payload>;
|
|
318
|
+
/** The wire event type Cloudflare matches `sendEvent` against `waitForEvent`. */
|
|
319
|
+
readonly type: string;
|
|
320
|
+
}
|
|
321
|
+
/** Per-call options for {@link WorkflowWaitForEventFunction}. */
|
|
322
|
+
interface WaitForEventOptions {
|
|
323
|
+
/**
|
|
324
|
+
* The durable step label, defaulting to `event:<type>`.
|
|
325
|
+
*
|
|
326
|
+
* Cloudflare identifies a memoized step by this name, so the default couples
|
|
327
|
+
* step identity to the wire type: renaming the event type also renames the
|
|
328
|
+
* step, and an instance that already recorded the wait replays into a *fresh*
|
|
329
|
+
* one that nothing will ever satisfy. Pass a stable `name` on any wait that can
|
|
330
|
+
* outlive a deploy (an approval held for days), and to tell two waits on the
|
|
331
|
+
* same event type apart in the timeline.
|
|
332
|
+
*/
|
|
333
|
+
name?: string;
|
|
334
|
+
/** How long to wait before the wait rejects. Defaults to Cloudflare's 24h. */
|
|
335
|
+
timeout?: number | string;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Hibernate until a declared event is delivered to this instance, then resolve
|
|
339
|
+
* with its validated payload. The typed wrapper over
|
|
340
|
+
* {@link WorkflowStepLike.waitForEvent}: the event's `type` comes from the
|
|
341
|
+
* definition instead of a hand-written string, and the payload is parsed through
|
|
342
|
+
* the definition's validator before the workflow resumes on it.
|
|
343
|
+
*
|
|
344
|
+
* ```ts
|
|
345
|
+
* const { approvedBy } = await ctx.waitForEvent(orderApproved, { timeout: "1 hour" });
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
type WorkflowWaitForEventFunction = <Payload>(event: WorkflowEventDefinition<Payload>, options?: WaitForEventOptions) => Promise<Payload>;
|
|
349
|
+
/**
|
|
350
|
+
* One branch of a {@link WorkflowParallelFunction} fan-out — a declared child
|
|
351
|
+
* workflow (referenced by its `lunora/workflows.ts` export name) plus the params
|
|
352
|
+
* it is created with. The phantom `Output` carries the child's result type into
|
|
353
|
+
* the `ctx.parallel(...)` result tuple. Build one with the `branch(...)` helper.
|
|
354
|
+
*/
|
|
355
|
+
interface WorkflowBranch<Output = unknown> {
|
|
356
|
+
/** Phantom marker for the branch output type — never present at runtime. */
|
|
357
|
+
readonly __output?: Output;
|
|
358
|
+
/**
|
|
359
|
+
* Optional group-saga compensation (plan 075 Phase 3): the `lunora/workflows.ts`
|
|
360
|
+
* export name of a workflow to run if a **sibling** branch in the same
|
|
361
|
+
* `ctx.parallel(...)` group fails **after** this branch has already completed.
|
|
362
|
+
* It is spawned fire-and-forget (a durable, replay-safe idempotent create) with
|
|
363
|
+
* {@link BranchCompensationParams} as its `ctx.params`. Omit for no
|
|
364
|
+
* compensation — a group where no branch sets this behaves exactly as a plain
|
|
365
|
+
* fan-out (fail-fast, no rollback).
|
|
366
|
+
*/
|
|
367
|
+
readonly compensateWith?: string;
|
|
368
|
+
/** Optional explicit child instance id (defaults to a deterministic parent-derived id). */
|
|
369
|
+
readonly id?: string;
|
|
370
|
+
/** The params the child instance is created with — surfaced as the child's `ctx.params`. */
|
|
371
|
+
readonly params?: Record<string, unknown>;
|
|
372
|
+
/** Optional wait timeout for this branch (the parent's `waitForEvent` timeout). */
|
|
373
|
+
readonly timeout?: number | string;
|
|
374
|
+
/** The `lunora/workflows.ts` export name of the child workflow to run. */
|
|
375
|
+
readonly workflow: string;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* The `ctx.params` a group-saga compensation workflow (a branch's
|
|
379
|
+
* {@link WorkflowBranch.compensateWith}) receives when a sibling's failure rolls
|
|
380
|
+
* back the group. Everything is plain-serialisable — the compensation is an
|
|
381
|
+
* ordinary declared workflow, so it can `ctx.runStep(...)` its own undo logic.
|
|
382
|
+
*/
|
|
383
|
+
interface BranchCompensationParams {
|
|
384
|
+
/** Index signature: this is a workflow `params` bag, so it is a valid `Record<string, unknown>` payload. */
|
|
385
|
+
[key: string]: unknown;
|
|
386
|
+
/** The export name of the completed branch being compensated. */
|
|
387
|
+
branch: string;
|
|
388
|
+
/** The serialised error of the sibling branch whose failure triggered the group rollback. */
|
|
389
|
+
error: {
|
|
390
|
+
message: string;
|
|
391
|
+
name: string;
|
|
392
|
+
};
|
|
393
|
+
/** Declaration-order index of the completed branch being compensated. */
|
|
394
|
+
index: number;
|
|
395
|
+
/** The completed branch's output value — what it returned before the group failed. */
|
|
396
|
+
output?: unknown;
|
|
397
|
+
}
|
|
398
|
+
/** Map a tuple of {@link WorkflowBranch}es to the tuple of their output types, preserving order. */
|
|
399
|
+
type WorkflowBranchOutputs<B extends ReadonlyArray<WorkflowBranch>> = { -readonly [K in keyof B]: B[K] extends WorkflowBranch<infer Output> ? Output : never; };
|
|
400
|
+
/**
|
|
401
|
+
* Run branches as isolated child workflow instances and resolve with their
|
|
402
|
+
* outputs in declaration order. Each branch gets its own Durable Object (own
|
|
403
|
+
* memory / CPU / retry budget); the parent hibernates while they execute. Rejects
|
|
404
|
+
* (non-retryable) on the first branch that fails.
|
|
405
|
+
*
|
|
406
|
+
* ```ts
|
|
407
|
+
* const [tags, thumb] = await ctx.parallel([
|
|
408
|
+
* branch("imageTag", { key }),
|
|
409
|
+
* branch("thumbnail", { key }),
|
|
410
|
+
* ]);
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
type WorkflowParallelFunction = <const B extends ReadonlyArray<WorkflowBranch>>(branches: B) => Promise<WorkflowBranchOutputs<B>>;
|
|
414
|
+
/** Per-call options for {@link WorkflowSpawnFunction}. */
|
|
415
|
+
interface WorkflowSpawnOptions {
|
|
416
|
+
/** Explicit child instance id (defaults to a deterministic parent-derived id). */
|
|
417
|
+
id?: string;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Fire-and-forget start of a declared child workflow from inside a workflow body
|
|
421
|
+
* — replay-safe (idempotent create), returns a live handle to the child. Use
|
|
422
|
+
* {@link WorkflowParallelFunction} instead when you need to await results.
|
|
423
|
+
*/
|
|
424
|
+
type WorkflowSpawnFunction = (workflow: string, params?: Record<string, unknown>, options?: WorkflowSpawnOptions) => Promise<WorkflowInstanceLike>;
|
|
425
|
+
/**
|
|
426
|
+
* The context object passed to a `defineWorkflow` handler. Bundles the native
|
|
427
|
+
* Cloudflare durability primitives (`step`, `event`) with the Lunora runner
|
|
428
|
+
* (`run`), the reusable-step runner (`runStep`), the fan-out primitives
|
|
429
|
+
* (`parallel` / `spawn`), the Worker `env`, and a logger.
|
|
430
|
+
*/
|
|
431
|
+
interface WorkflowRunContext<Params = Record<string, unknown>> {
|
|
432
|
+
/** The Worker environment bindings. */
|
|
433
|
+
readonly env: Record<string, unknown>;
|
|
434
|
+
/** The triggering event (id, payload, timestamp, workflow name). */
|
|
435
|
+
readonly event: WorkflowEventLike<Params>;
|
|
436
|
+
/** Structured logger surfaced in `wrangler tail` / Studio logs. */
|
|
437
|
+
readonly log: WorkflowLogger;
|
|
438
|
+
/** Run branches as isolated child workflow instances and await their outputs (declaration-ordered tuple). */
|
|
439
|
+
readonly parallel: WorkflowParallelFunction;
|
|
440
|
+
/** Convenience alias for `event.payload`. */
|
|
441
|
+
readonly params: Readonly<Params>;
|
|
442
|
+
/** Invoke a Lunora function; wrap in `step.do(...)` for durability. */
|
|
443
|
+
readonly run: WorkflowRunFunction;
|
|
444
|
+
/** Run a reusable, schema-validated {@link StepDefinition} as a durable step. */
|
|
445
|
+
readonly runStep: WorkflowRunStepFunction;
|
|
446
|
+
/** Fire-and-forget start of a declared child workflow (replay-safe; returns a live handle). */
|
|
447
|
+
readonly spawn: WorkflowSpawnFunction;
|
|
448
|
+
/** The native Cloudflare Workflows durable-step API. */
|
|
449
|
+
readonly step: WorkflowStepLike;
|
|
450
|
+
/** Hibernate until a declared external event arrives; resolves with its validated payload. */
|
|
451
|
+
readonly waitForEvent: WorkflowWaitForEventFunction;
|
|
452
|
+
}
|
|
453
|
+
/** The workflow body. Receives a {@link WorkflowRunContext}, returns the output. */
|
|
454
|
+
type WorkflowHandler<Params = Record<string, unknown>, Output = unknown> = (context: WorkflowRunContext<Params>) => Output | Promise<Output>;
|
|
455
|
+
/** Author-supplied config for `defineWorkflow`. */
|
|
456
|
+
interface WorkflowConfig<Params = Record<string, unknown>, Output = unknown> {
|
|
457
|
+
/** The workflow body — the multi-step durable program. */
|
|
458
|
+
handler: WorkflowHandler<Params, Output>;
|
|
459
|
+
/**
|
|
460
|
+
* Optional override for the deployed workflow name — the `workflows[].name`
|
|
461
|
+
* written to `wrangler.jsonc`. Defaults to a kebab-cased form of the
|
|
462
|
+
* `lunora/workflows.ts` export name (`orderPipeline` → `order-pipeline`).
|
|
463
|
+
* This does NOT change the binding name, which is always derived from the
|
|
464
|
+
* export name (`orderPipeline` → `WORKFLOW_ORDER_PIPELINE`).
|
|
465
|
+
*/
|
|
466
|
+
name?: string;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* A `defineWorkflow` result — the config plus the runtime brand codegen and the
|
|
470
|
+
* config layer use to discover it. The phantom `__params` / `__output` carry
|
|
471
|
+
* the inferred types to the generated `ctx.workflows` handle.
|
|
472
|
+
*/
|
|
473
|
+
interface WorkflowDefinition<Params = Record<string, unknown>, Output = unknown> extends WorkflowConfig<Params, Output> {
|
|
474
|
+
/** Phantom marker for the output type — never present at runtime. */
|
|
475
|
+
readonly __output?: Output;
|
|
476
|
+
/** Phantom marker for the params type — never present at runtime. */
|
|
477
|
+
readonly __params?: Params;
|
|
478
|
+
/** Runtime brand check (see `isWorkflowDefinition`). */
|
|
479
|
+
readonly isLunoraWorkflow: true;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* A typed handle to one declared workflow, addressable from `ctx.workflows`.
|
|
483
|
+
* Thin pass-through over the Cloudflare `Workflow` binding, plus the declared-event
|
|
484
|
+
* send (which the raw binding cannot type).
|
|
485
|
+
*/
|
|
486
|
+
interface WorkflowHandle<Params = Record<string, unknown>> {
|
|
487
|
+
/** Start a new instance (optionally with an id + params). */
|
|
488
|
+
create: (options?: WorkflowCreateOptions<Params>) => Promise<WorkflowInstanceLike>;
|
|
489
|
+
/** Start many instances in one batched RPC. */
|
|
490
|
+
createBatch: (batch: ReadonlyArray<WorkflowCreateOptions<Params>>) => Promise<WorkflowInstanceLike[]>;
|
|
491
|
+
/** Get a handle to an existing instance by id. */
|
|
492
|
+
get: (id: string) => Promise<WorkflowInstanceLike>;
|
|
493
|
+
/**
|
|
494
|
+
* Deliver a declared event to one instance of this workflow — the typed
|
|
495
|
+
* counterpart of the workflow body's `ctx.waitForEvent`. The wire type comes
|
|
496
|
+
* from the definition (never a hand-written string) and the payload is parsed
|
|
497
|
+
* through the definition's validator **before** the send, so a bad value fails
|
|
498
|
+
* the caller's request instead of waking the workflow on garbage.
|
|
499
|
+
*
|
|
500
|
+
* Mirrors `ctx.agents.<name>.sendEvent(id, …)`: the instance is addressed by
|
|
501
|
+
* id rather than by holding an instance handle, so the common case is one call.
|
|
502
|
+
*/
|
|
503
|
+
sendEvent: <Payload>(instanceId: string, event: WorkflowEventDefinition<Payload>, payload: Payload) => Promise<void>;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* The `ctx.workflows` surface available on `MutationCtx` and `ActionCtx`. Each
|
|
507
|
+
* declared workflow is reachable by its `lunora/workflows.ts` export name.
|
|
508
|
+
*/
|
|
509
|
+
interface Workflows {
|
|
510
|
+
/** Resolve the handle for a declared workflow by export name. */
|
|
511
|
+
get: <Params = Record<string, unknown>>(name: string) => WorkflowHandle<Params>;
|
|
512
|
+
}
|
|
513
|
+
/** Options for `createWorkflows`. */
|
|
514
|
+
interface LunoraWorkflowsOptions {
|
|
515
|
+
/**
|
|
516
|
+
* Map of `lunora/workflows.ts` export name → its Cloudflare `Workflow`
|
|
517
|
+
* binding. Codegen builds this from `env` (`{ orderPipeline:
|
|
518
|
+
* env.WORKFLOW_ORDER_PIPELINE }`); for manual wiring construct it yourself.
|
|
519
|
+
*/
|
|
520
|
+
bindings: Record<string, WorkflowBindingLike>;
|
|
521
|
+
}
|
|
522
|
+
export { ArgsOf as A, BranchCompensationParams as B, WorkflowInstanceLike as C, WorkflowParallelFunction as D, WorkflowRollbackContextLike as E, FunctionKind as F, WorkflowRollbackHandlerLike as G, WorkflowSpawnFunction as H, InferStepArgs as I, WorkflowSpawnOptions as J, WorkflowStatusResult as K, LunoraWorkflowsOptions as L, WorkflowStepConfigLike as M, WorkflowStepContextLike as N, WorkflowStepRollbackOptionsLike as O, RunFunctionOptions as R, StepArgsValidator as S, WorkflowDefinition as W, Workflows as a, WorkflowEventDefinition as b, StepConfig as c, StepDefinition as d, WorkflowConfig as e, WorkflowBranch as f, WorkflowInstanceStatus as g, WorkflowEventLike as h, WorkflowStepLike as i, WorkflowRunContext as j, WorkflowLogger as k, WorkflowRunFunction as l, WorkflowRunStepFunction as m, WorkflowWaitForEventFunction as n, FunctionReference as o, RunStepOptions as p, StepHandler as q, StepRollbackContext as r, StepRollbackHandler as s, StepRunContext as t, WaitForEventOptions as u, WorkflowBindingLike as v, WorkflowBranchOutputs as w, WorkflowCreateOptions as x, WorkflowHandle as y, WorkflowHandler as z };
|