@lunora/workflow 1.0.0-alpha.9 → 1.0.0-alpha.90
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 +32 -7
- 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 +204 -129
- package/dist/index.d.ts +204 -129
- package/dist/index.mjs +1 -9
- package/dist/packem_shared/MAX_BRANCHES-Bcw3dss9.mjs +1 -0
- package/dist/packem_shared/NonRetryableError-BPu01mU8.mjs +1 -0
- package/dist/packem_shared/WorkflowsRestError-7vFcm7UK.mjs +1 -0
- package/dist/packem_shared/branch-marker-CCpWfS5k.mjs +1 -0
- package/dist/packem_shared/createRunStep-KjGNW5rm.mjs +1 -0
- package/dist/packem_shared/createWaitForEvent-D5Ohn2Pz.mjs +1 -0
- package/dist/packem_shared/createWorkflowContext-DBUnSy0_.mjs +1 -0
- package/dist/packem_shared/createWorkflowRunContext-CRTTub21.mjs +1 -0
- package/dist/packem_shared/createWorkflows-BwR_J9mp.mjs +1 -0
- package/dist/packem_shared/defineStep-D1-9eOnA.mjs +1 -0
- package/dist/packem_shared/defineWorkflow-DynRL6LP.mjs +1 -0
- package/dist/packem_shared/defineWorkflowEvent-suERPEEV.mjs +1 -0
- package/dist/packem_shared/isDuplicateInstanceError-CecnqNAa.mjs +1 -0
- package/dist/packem_shared/run-step-DJ107J5H.mjs +1 -0
- package/dist/packem_shared/types.d-zivJ8nEf.d.mts +686 -0
- package/dist/packem_shared/types.d-zivJ8nEf.d.ts +686 -0
- package/dist/packem_shared/workflow-binding-Dm9hBzx_.mjs +1 -0
- package/package.json +4 -3
- package/dist/packem_shared/MAX_BRANCHES-EO5xYS_3.mjs +0 -170
- package/dist/packem_shared/NonRetryableError-Dn2dTyBS.mjs +0 -27
- package/dist/packem_shared/WorkflowsRestError-zmjOxTR1.mjs +0 -117
- package/dist/packem_shared/createRunStep-8jOXxP2o.mjs +0 -54
- package/dist/packem_shared/createWorkflowContext-oxZ5zj3x.mjs +0 -14
- package/dist/packem_shared/createWorkflowRunContext-BDSHE8iO.mjs +0 -127
- package/dist/packem_shared/createWorkflows-wq4fs72q.mjs +0 -40
- 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-C9W6rEWv.d.mts +0 -425
- package/dist/packem_shared/types.d-C9W6rEWv.d.ts +0 -425
package/dist/index.d.ts
CHANGED
|
@@ -1,117 +1,161 @@
|
|
|
1
|
-
import { a as Workflows, L as LunoraWorkflowsOptions, S as StepArgsValidator,
|
|
2
|
-
export type { A as ArgsOf, B as BranchCompensationParams, F as FunctionReference, I as InferStepArgs, R as RunFunctionOptions,
|
|
1
|
+
import { a as Workflows, L as LunoraWorkflowsOptions, b as WorkflowEventDefinition, S as StepArgsValidator, c as StepConfig, d as StepDefinition, e as WorkflowConfig, W as WorkflowDefinition, f as WorkflowBranch, g as WorkflowInstanceStatus, h as WorkflowEventLike, i as WorkflowStepLike, j as WorkflowRunContext, k as WorkflowLogger, l as WorkflowRunFunction, m as WorkflowRunStepFunction, n as WorkflowWaitForEventFunction } from "./packem_shared/types.d-zivJ8nEf.js";
|
|
2
|
+
export type { A as ArgsOf, B as BranchCompensationParams, F as FunctionKind, o as FunctionReference, I as InferStepArgs, R as RunFunctionOptions, p as RunStepOptions, q as StepHandler, r as StepRollbackContext, s as StepRollbackHandler, t as StepRunContext, u as WaitForEventOptions, v as WorkflowBatchDeleteResult, w as WorkflowBindingLike, x as WorkflowBranchOutputs, y as WorkflowCreateBatchError, z as WorkflowCreateBatchOptions, C as WorkflowCreateBatchResult, D as WorkflowCreateOptions, E as WorkflowDelayFunctionLike, G as WorkflowHandle, H as WorkflowHandler, J as WorkflowInstanceEventLike, K as WorkflowInstanceLike, M as WorkflowInstanceSubscribeOptionsLike, N as WorkflowInstanceSubscriptionLike, O as WorkflowParallelFunction, P as WorkflowRetention, Q as WorkflowRollbackContextLike, T as WorkflowRollbackHandlerLike, U as WorkflowSpawnFunction, V as WorkflowSpawnOptions, X as WorkflowStatusResult, Y as WorkflowStepConfigLike, Z as WorkflowStepContextLike, _ as WorkflowStepRollbackOptionsLike } from "./packem_shared/types.d-zivJ8nEf.js";
|
|
3
|
+
import { Validator } from '@lunora/values';
|
|
3
4
|
import { LunoraError } from '@lunora/errors';
|
|
4
|
-
import '@lunora/values';
|
|
5
5
|
/** Wiring info for one declared workflow, emitted by codegen into the generated shard. */
|
|
6
6
|
interface WorkflowBindingSpec {
|
|
7
|
-
/** The
|
|
8
|
-
|
|
7
|
+
/** The workflow's export key — its generated class name, e.g. `OrderPipelineWorkflow`. */
|
|
8
|
+
className: string;
|
|
9
9
|
/** The `lunora/workflows.ts` export name, e.g. `orderPipeline`. */
|
|
10
10
|
exportName: string;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Build the `ctx.workflows` handle for a request: resolve every spec's
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
* Build the `ctx.workflows` handle for a request: resolve every spec's key off
|
|
14
|
+
* the invoking context's `exports` (Cloudflare) or `env` (other hosts) into the
|
|
15
|
+
* `exportName → Workflow binding` map and wrap it in {@link createWorkflows}. A
|
|
16
|
+
* spec whose workflow is absent from both is skipped
|
|
17
|
+
* here — the helpful "no workflow named …" error is raised lazily by
|
|
18
|
+
* `workflows.get(name)` when the missing workflow is actually used.
|
|
19
|
+
*/
|
|
20
|
+
declare const createWorkflowContext: (env: Record<string, unknown>, specs: ReadonlyArray<WorkflowBindingSpec>, exports?: unknown) => Workflows;
|
|
20
21
|
/**
|
|
21
|
-
* Build the `ctx.workflows` handle from a map of `lunora/workflows.ts` export
|
|
22
|
-
* name → Cloudflare `Workflow` binding. `get(name)` resolves the typed handle;
|
|
23
|
-
* an unknown name throws with the list of declared workflows.
|
|
24
|
-
*/
|
|
22
|
+
* Build the `ctx.workflows` handle from a map of `lunora/workflows.ts` export
|
|
23
|
+
* name → Cloudflare `Workflow` binding. `get(name)` resolves the typed handle;
|
|
24
|
+
* an unknown name throws with the list of declared workflows.
|
|
25
|
+
*/
|
|
25
26
|
declare const createWorkflows: (options: LunoraWorkflowsOptions) => Workflows;
|
|
26
27
|
/**
|
|
27
|
-
* Declare
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* import {
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
|
|
28
|
+
* Declare an external event, its wire type, and its payload shape.
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* // lunora/events.ts
|
|
32
|
+
* import { defineWorkflowEvent } from "@lunora/workflow";
|
|
33
|
+
* import { v } from "@lunora/values";
|
|
34
|
+
*
|
|
35
|
+
* export const orderApproved = defineWorkflowEvent("order-approved", v.object({ approvedBy: v.string() }));
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Wait on it inside a workflow body — the payload is typed and validated:
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* const { approvedBy } = await ctx.waitForEvent(orderApproved, { name: "await approval", timeout: "7 days" });
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* …and send it from a mutation/action with the same definition:
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* await ctx.workflows.get("orderPipeline").sendEvent(instanceId, orderApproved, { approvedBy });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare const defineWorkflowEvent: <Payload>(type: string, payload: Validator<Payload>) => WorkflowEventDefinition<Payload>;
|
|
51
|
+
/**
|
|
52
|
+
* True when a value is usable as an event definition. The brand alone is not the
|
|
53
|
+
* test: the predicate hands the caller a `type` and a `payload.parse`, so it checks
|
|
54
|
+
* for both (and for the reserved namespace) rather than trusting a public boolean.
|
|
55
|
+
*/
|
|
56
|
+
declare const isWorkflowEventDefinition: (value: unknown) => value is WorkflowEventDefinition;
|
|
57
|
+
/**
|
|
58
|
+
* Declare a reusable durable step. Same `args` map shape a Lunora `query` /
|
|
59
|
+
* `mutation` / `action` uses, so a step reads like a function:
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* // lunora/steps.ts
|
|
63
|
+
* import { defineStep } from "@lunora/workflow";
|
|
64
|
+
* import { v } from "@lunora/values";
|
|
65
|
+
*
|
|
66
|
+
* export const fetchImage = defineStep("fetch image", {
|
|
67
|
+
* args: { imageKey: v.string() },
|
|
68
|
+
* returns: v.object({ data: v.bytes() }),
|
|
69
|
+
* handler: async (ctx, { imageKey }) => {
|
|
70
|
+
* const object = await (ctx.env.BUCKET as R2Bucket).get(imageKey);
|
|
71
|
+
* return { data: new Uint8Array(await object!.arrayBuffer()) };
|
|
72
|
+
* },
|
|
73
|
+
* rollback: async (ctx) => {
|
|
74
|
+
* await (ctx.env.BUCKET as R2Bucket).delete(`tmp/${ctx.args.imageKey}`);
|
|
75
|
+
* },
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* Then, inside a `defineWorkflow` handler:
|
|
80
|
+
*
|
|
81
|
+
* ```ts
|
|
82
|
+
* const { data } = await ctx.runStep(fetchImage, { imageKey: ctx.params.imageKey });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
54
85
|
declare const defineStep: <A extends StepArgsValidator, Result>(name: string, config: StepConfig<A, Result>) => StepDefinition<A, Result>;
|
|
55
86
|
/** True when a value is a `defineStep` result (the runtime brand check). */
|
|
56
87
|
declare const isStepDefinition: (value: unknown) => value is StepDefinition;
|
|
57
88
|
/**
|
|
58
|
-
* The generated `WorkflowEntrypoint` class name for a `lunora/workflows.ts`
|
|
59
|
-
* export: `orderPipeline` → `OrderPipelineWorkflow`.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
|
|
89
|
+
* The generated `WorkflowEntrypoint` class name for a `lunora/workflows.ts`
|
|
90
|
+
* export: `orderPipeline` → `OrderPipelineWorkflow`. It is also the workflow's
|
|
91
|
+
* key everywhere at runtime: wrangler's `exports.<Class>` declares it, the
|
|
92
|
+
* invoking context's `ctx.exports.<Class>` reaches it (see
|
|
93
|
+
* `shared/workflow-binding.ts`), so codegen, config and the runtime MUST derive
|
|
94
|
+
* it identically — always via this helper.
|
|
95
|
+
*/
|
|
63
96
|
declare const workflowClassName: (exportName: string) => string;
|
|
64
97
|
/**
|
|
65
|
-
* The
|
|
66
|
-
* `
|
|
67
|
-
*
|
|
68
|
-
|
|
69
|
-
*/
|
|
70
|
-
declare const workflowBindingName: (exportName: string) => string;
|
|
71
|
-
/**
|
|
72
|
-
* The stable workflow name wrangler registers (`workflows[].name`):
|
|
73
|
-
* `orderPipeline` → `order-pipeline`. Used as the deployed workflow's
|
|
74
|
-
* identifier when no explicit `name` override is given.
|
|
75
|
-
*/
|
|
98
|
+
* The stable workflow name wrangler registers (`exports.<Class>.name`):
|
|
99
|
+
* `orderPipeline` → `order-pipeline`. Used as the deployed workflow's
|
|
100
|
+
* identifier when no explicit `name` override is given.
|
|
101
|
+
*/
|
|
76
102
|
declare const workflowDefaultName: (exportName: string) => string;
|
|
77
103
|
/**
|
|
78
|
-
* Declare a durable workflow deployed alongside the app. Pure validation +
|
|
79
|
-
* branding: codegen discovers the export, emits the `WorkflowEntrypoint`
|
|
80
|
-
* subclass (`_generated/workflows.ts`), and wires the typed `ctx.workflows`
|
|
81
|
-
* handle; the config layer reconciles the wrangler `
|
|
82
|
-
* same definition.
|
|
83
|
-
*
|
|
84
|
-
* ```ts
|
|
85
|
-
* // lunora/workflows.ts
|
|
86
|
-
* import { defineWorkflow } from "@lunora/workflow";
|
|
87
|
-
* import { api } from "./_generated/api";
|
|
88
|
-
*
|
|
89
|
-
* export const orderPipeline = defineWorkflow
|
|
90
|
-
* handler: async (ctx) => {
|
|
91
|
-
* const order = await ctx.step.do("load", () => ctx.run(api.orders.get, { id: ctx.params.orderId }));
|
|
92
|
-
* await ctx.step.sleep("cool-off", "1 minute");
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* })
|
|
97
|
-
*
|
|
98
|
-
|
|
104
|
+
* Declare a durable workflow deployed alongside the app. Pure validation +
|
|
105
|
+
* branding: codegen discovers the export, emits the `WorkflowEntrypoint`
|
|
106
|
+
* subclass (`_generated/workflows.ts`), and wires the typed `ctx.workflows`
|
|
107
|
+
* handle; the config layer reconciles the wrangler `exports.<Class>` entry from
|
|
108
|
+
* the same definition.
|
|
109
|
+
*
|
|
110
|
+
* ```ts
|
|
111
|
+
* // lunora/workflows.ts
|
|
112
|
+
* import { defineWorkflow } from "@lunora/workflow";
|
|
113
|
+
* import { api } from "./_generated/api";
|
|
114
|
+
*
|
|
115
|
+
* export const orderPipeline = defineWorkflow<{ orderId: string }>({
|
|
116
|
+
* handler: async (ctx) => {
|
|
117
|
+
* const order = await ctx.step.do("load", () => ctx.run(api.orders.get, { id: ctx.params.orderId }));
|
|
118
|
+
* await ctx.step.sleep("cool-off", "1 minute");
|
|
119
|
+
* // A raw `step.do` retries its callback in place, so a WRITE made through
|
|
120
|
+
* // it needs an explicit dedup id (or use `ctx.runStep`, which pins one).
|
|
121
|
+
* await ctx.step.do("charge", () =>
|
|
122
|
+
* ctx.run(api.payments.charge, { orderId: ctx.params.orderId }, { dedupId: `charge:${ctx.params.orderId}` }),
|
|
123
|
+
* );
|
|
124
|
+
* return order;
|
|
125
|
+
* },
|
|
126
|
+
* // Deploy settings, written into the wrangler `exports.<Class>` entry.
|
|
127
|
+
* schedules: ["0 * * * *"],
|
|
128
|
+
* limits: { steps: 25_000 },
|
|
129
|
+
* defaultRetention: { successRetention: "3 days", errorRetention: "30 days" },
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
99
133
|
declare const defineWorkflow: <Params = Record<string, unknown>, Output = unknown>(config: WorkflowConfig<Params, Output>) => WorkflowDefinition<Params, Output>;
|
|
100
134
|
/** True when a value is a `defineWorkflow` result (the runtime brand check). */
|
|
101
135
|
declare const isWorkflowDefinition: (value: unknown) => value is WorkflowDefinition;
|
|
102
136
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
*
|
|
114
|
-
|
|
137
|
+
* Whether a `WorkflowBinding.create()` rejection is a duplicate-instance-id
|
|
138
|
+
* error — the idempotency signal that a *previous* attempt's create already
|
|
139
|
+
* applied — as opposed to a transient or config failure (Workflows service
|
|
140
|
+
* error, instance-creation quota, bad params).
|
|
141
|
+
*
|
|
142
|
+
* Every other failure MUST surface, so the caller retries or fails visibly
|
|
143
|
+
* rather than silently reporting success for work that never started.
|
|
144
|
+
*/
|
|
145
|
+
declare const isDuplicateInstanceError: (error: unknown) => boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Throw from a workflow step (or handler) to fail the instance immediately
|
|
148
|
+
* **without** retrying — the portable mirror of `cloudflare:workflows`'
|
|
149
|
+
* `NonRetryableError`. Importable from Node, so workflow code stays unit-testable.
|
|
150
|
+
*
|
|
151
|
+
* ```ts
|
|
152
|
+
* import { NonRetryableError } from "@lunora/workflow";
|
|
153
|
+
*
|
|
154
|
+
* if (order.status === "cancelled") {
|
|
155
|
+
* throw new NonRetryableError("order already cancelled — no point retrying");
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
115
159
|
declare class NonRetryableError extends Error {
|
|
116
160
|
constructor(message: string, name?: string);
|
|
117
161
|
}
|
|
@@ -120,36 +164,33 @@ declare const isNonRetryableError: (value: unknown) => value is NonRetryableErro
|
|
|
120
164
|
/** Constructor shape of `cloudflare:workflows`' native `NonRetryableError`. */
|
|
121
165
|
type NativeNonRetryableErrorConstructor = new (message: string, name?: string) => Error;
|
|
122
166
|
/**
|
|
123
|
-
* Rebuild a portable {@link NonRetryableError} as the native Cloudflare one,
|
|
124
|
-
* preserving its `name`, `message`, `cause`, and `stack`. Used at the `src/do`
|
|
125
|
-
* boundary where the native constructor is available; everywhere else the
|
|
126
|
-
* portable error is thrown unchanged (and still honored by name).
|
|
127
|
-
*/
|
|
167
|
+
* Rebuild a portable {@link NonRetryableError} as the native Cloudflare one,
|
|
168
|
+
* preserving its `name`, `message`, `cause`, and `stack`. Used at the `src/do`
|
|
169
|
+
* boundary where the native constructor is available; everywhere else the
|
|
170
|
+
* portable error is thrown unchanged (and still honored by name).
|
|
171
|
+
*/
|
|
128
172
|
declare const toNativeNonRetryableError: (error: NonRetryableError, NativeNonRetryableError: NativeNonRetryableErrorConstructor) => Error;
|
|
129
173
|
/**
|
|
130
|
-
* If `error` is a portable {@link NonRetryableError} and a native constructor is
|
|
131
|
-
* available, rethrow it as the native error; otherwise rethrow `error` as-is.
|
|
132
|
-
* Always throws — the `never` return lets callers `return convertNonRetryableError(...)`.
|
|
133
|
-
*/
|
|
174
|
+
* If `error` is a portable {@link NonRetryableError} and a native constructor is
|
|
175
|
+
* available, rethrow it as the native error; otherwise rethrow `error` as-is.
|
|
176
|
+
* Always throws — the `never` return lets callers `return convertNonRetryableError(...)`.
|
|
177
|
+
*/
|
|
134
178
|
declare const convertNonRetryableError: (error: unknown, NativeNonRetryableError: NativeNonRetryableErrorConstructor | undefined) => never;
|
|
135
179
|
/** Hard cap on branches per `ctx.parallel` call — auto-scale, never silently spawn unbounded DOs. */
|
|
136
180
|
declare const MAX_BRANCHES = 100;
|
|
137
|
-
/** The params key the parent injects so a child knows to signal completion back. Stripped before the user handler sees `ctx.params`. */
|
|
138
|
-
|
|
139
181
|
/**
|
|
140
|
-
* Build a single fan-out branch: a declared child workflow referenced by its
|
|
141
|
-
* `lunora/workflows.ts` export name, plus the params it is created with. Pass the
|
|
142
|
-
* output type as the generic argument so `ctx.parallel(...)` infers the result
|
|
143
|
-
* tuple — e.g. `branch("imageTag", { key })` typed as `branch` of `{ tags }`.
|
|
144
|
-
*/
|
|
182
|
+
* Build a single fan-out branch: a declared child workflow referenced by its
|
|
183
|
+
* `lunora/workflows.ts` export name, plus the params it is created with. Pass the
|
|
184
|
+
* output type as the generic argument so `ctx.parallel(...)` infers the result
|
|
185
|
+
* tuple — e.g. `branch("imageTag", { key })` typed as `branch` of `{ tags }`.
|
|
186
|
+
*/
|
|
145
187
|
declare const branch: <Output = unknown>(workflow: string, params?: Record<string, unknown>, options?: {
|
|
146
188
|
compensateWith?: string;
|
|
147
189
|
id?: string;
|
|
148
190
|
timeout?: number | string;
|
|
149
191
|
}) => WorkflowBranch<Output>;
|
|
150
|
-
/** Build the success outcome a completed branch reports to its parent. */
|
|
151
192
|
/** The lifecycle mutations the REST API exposes via `PATCH .../instances/{id}`. */
|
|
152
|
-
type WorkflowInstanceAction = "pause" | "resume" | "terminate";
|
|
193
|
+
type WorkflowInstanceAction = "pause" | "restart" | "resume" | "terminate";
|
|
153
194
|
/** Configuration for a {@link WorkflowsRestClient}. */
|
|
154
195
|
interface WorkflowsRestConfig {
|
|
155
196
|
/** Cloudflare account id that owns the workflow. */
|
|
@@ -194,7 +235,14 @@ interface WorkflowInstancePage {
|
|
|
194
235
|
perPage: number;
|
|
195
236
|
totalCount?: number;
|
|
196
237
|
}
|
|
197
|
-
/**
|
|
238
|
+
/**
|
|
239
|
+
* Thrown when the REST API responds non-2xx or `success: false`; carries the
|
|
240
|
+
* status plus a capped body preview, with the full body on `cause`.
|
|
241
|
+
*
|
|
242
|
+
* The preview is capped because the Cloudflare API's auth/authorization error
|
|
243
|
+
* text (and its HTML gateway pages) would otherwise ride out verbatim —
|
|
244
|
+
* `WORKFLOWS_REST_ERROR` is non-internal, so the message reaches the browser.
|
|
245
|
+
*/
|
|
198
246
|
declare class WorkflowsRestError extends LunoraError {
|
|
199
247
|
constructor(status: number, body: string);
|
|
200
248
|
}
|
|
@@ -219,16 +267,18 @@ interface WorkflowsRestClient {
|
|
|
219
267
|
}>;
|
|
220
268
|
}
|
|
221
269
|
/**
|
|
222
|
-
* Build a {@link WorkflowsRestClient}. Each call hits the account-scoped REST
|
|
223
|
-
* endpoint with the bearer token, unwraps Cloudflare's
|
|
224
|
-
* `{ success, errors, result, result_info }` envelope, and normalizes the
|
|
225
|
-
* snake_case payload into the camelCase shapes the studio renders.
|
|
226
|
-
*/
|
|
270
|
+
* Build a {@link WorkflowsRestClient}. Each call hits the account-scoped REST
|
|
271
|
+
* endpoint with the bearer token, unwraps Cloudflare's
|
|
272
|
+
* `{ success, errors, result, result_info }` envelope, and normalizes the
|
|
273
|
+
* snake_case payload into the camelCase shapes the studio renders.
|
|
274
|
+
*/
|
|
227
275
|
declare const createWorkflowsRestClient: (config: WorkflowsRestConfig) => WorkflowsRestClient;
|
|
228
276
|
interface RunContextOptions<Params> {
|
|
229
277
|
env: Record<string, unknown>;
|
|
230
278
|
event: WorkflowEventLike<Params>;
|
|
231
279
|
exportName: string;
|
|
280
|
+
/** The invoking context's `ctx.exports`, where Cloudflare exposes the workflows declared in wrangler `exports`. */
|
|
281
|
+
exports?: unknown;
|
|
232
282
|
fetchImpl?: typeof fetch;
|
|
233
283
|
/** Native `cloudflare:workflows` `NonRetryableError` — injected by `src/do`; absent in Node tests. */
|
|
234
284
|
nonRetryableErrorClass?: NativeNonRetryableErrorConstructor;
|
|
@@ -237,31 +287,56 @@ interface RunContextOptions<Params> {
|
|
|
237
287
|
/** Assemble the {@link WorkflowRunContext} passed to a `defineWorkflow` handler. */
|
|
238
288
|
declare const createWorkflowRunContext: <Params = Record<string, unknown>>(options: RunContextOptions<Params>) => WorkflowRunContext<Params>;
|
|
239
289
|
/**
|
|
240
|
-
* Validate a step's args through its validator map, prefixing any
|
|
241
|
-
* `ValidationError` with `step args
|
|
242
|
-
* offending field. Delegates to `@lunora/values`' shared {@link parseValidatorMap}
|
|
243
|
-
* — the same parser the procedure builder and HTTP routes use — so the
|
|
244
|
-
* optional-skip and error-prefix semantics stay in lockstep across the framework.
|
|
245
|
-
*/
|
|
290
|
+
* Validate a step's args through its validator map, prefixing any
|
|
291
|
+
* `ValidationError` with `step args.<key>` so the failure points at the
|
|
292
|
+
* offending field. Delegates to `@lunora/values`' shared {@link parseValidatorMap}
|
|
293
|
+
* — the same parser the procedure builder and HTTP routes use — so the
|
|
294
|
+
* optional-skip and error-prefix semantics stay in lockstep across the framework.
|
|
295
|
+
*/
|
|
246
296
|
declare const validateStepArgs: (validators: StepArgsValidator, source: Record<string, unknown>) => Record<string, unknown>;
|
|
247
297
|
/** Dependencies needed to run a step: the native step API plus the workflow's env / runner / logger. */
|
|
248
298
|
interface RunStepDeps {
|
|
299
|
+
/** The instance's `dedupNamespace(exportName, instanceId)` — the prefix of the replay-dedup ids the steps' dispatches carry (see `dedup-id.ts`). */
|
|
300
|
+
dedupNamespace: string;
|
|
249
301
|
/** The Worker environment bindings, surfaced on the step context. */
|
|
250
302
|
env: Record<string, unknown>;
|
|
251
303
|
/** Structured logger surfaced on the step context. */
|
|
252
304
|
log: WorkflowLogger;
|
|
253
305
|
/** Native `cloudflare:workflows` `NonRetryableError` constructor — injected by `src/do`; absent in Node tests. */
|
|
254
306
|
nonRetryableErrorClass?: NativeNonRetryableErrorConstructor;
|
|
255
|
-
/**
|
|
307
|
+
/**
|
|
308
|
+
* The bare Lunora function runner. Each step attempt (and each rollback)
|
|
309
|
+
* surfaces it wrapped in `waitOutDeclines`, bounded by that attempt's own
|
|
310
|
+
* timeout.
|
|
311
|
+
*/
|
|
256
312
|
run: WorkflowRunFunction;
|
|
257
313
|
/** The native Cloudflare durable-step API. */
|
|
258
314
|
step: WorkflowStepLike;
|
|
259
315
|
}
|
|
260
316
|
/**
|
|
261
|
-
* Build the `ctx.runStep` function bound to one workflow invocation. Each call
|
|
262
|
-
* runs the step through `step.do(...)`: validate args → run body → validate
|
|
263
|
-
* result (when `returns` is declared), with any portable `NonRetryableError`
|
|
264
|
-
* converted to the native one and any declared rollback forwarded to Cloudflare.
|
|
265
|
-
*/
|
|
317
|
+
* Build the `ctx.runStep` function bound to one workflow invocation. Each call
|
|
318
|
+
* runs the step through `step.do(...)`: validate args → run body → validate
|
|
319
|
+
* result (when `returns` is declared), with any portable `NonRetryableError`
|
|
320
|
+
* converted to the native one and any declared rollback forwarded to Cloudflare.
|
|
321
|
+
*/
|
|
266
322
|
declare const createRunStep: (deps: RunStepDeps) => WorkflowRunStepFunction;
|
|
267
|
-
|
|
323
|
+
/** Dependencies one workflow invocation's `ctx.waitForEvent` closes over. */
|
|
324
|
+
interface WaitForEventDeps {
|
|
325
|
+
/** Native `cloudflare:workflows` `NonRetryableError` constructor — injected by `src/do`; absent in Node tests. */
|
|
326
|
+
nonRetryableErrorClass?: NativeNonRetryableErrorConstructor;
|
|
327
|
+
/** The native Cloudflare durable-step API. */
|
|
328
|
+
step: WorkflowStepLike;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Build `ctx.waitForEvent` for one workflow invocation.
|
|
332
|
+
*
|
|
333
|
+
* Every failure here is **non-retryable**. A malformed definition or a reserved
|
|
334
|
+
* step name is a deterministic programmer error, and a payload that fails the
|
|
335
|
+
* validator has already consumed the event — replaying the wait cannot produce a
|
|
336
|
+
* different value, it can only hibernate the instance until its timeout. Each is
|
|
337
|
+
* raised through the shared {@link raiseNonRetryable}, the same classification path
|
|
338
|
+
* `ctx.runStep` uses, so the native error reaches Cloudflare and the instance fails
|
|
339
|
+
* fast.
|
|
340
|
+
*/
|
|
341
|
+
declare const createWaitForEvent: (deps: WaitForEventDeps) => WorkflowWaitForEventFunction;
|
|
342
|
+
export { type LunoraWorkflowsOptions, MAX_BRANCHES, type NativeNonRetryableErrorConstructor, NonRetryableError, type StepArgsValidator, type StepConfig, type StepDefinition, type WorkflowBindingSpec, type WorkflowBranch, type WorkflowConfig, type WorkflowDefinition, type WorkflowEventDefinition, type WorkflowEventLike, type WorkflowInstanceAction, type WorkflowInstanceDetail, type WorkflowInstancePage, type WorkflowInstanceStatus, type WorkflowInstanceSummary, type WorkflowLogger, type WorkflowRunContext, type WorkflowRunFunction, type WorkflowRunStepFunction, type WorkflowStepDetail, type WorkflowStepLike, type WorkflowWaitForEventFunction, type Workflows, type WorkflowsRestClient, type WorkflowsRestConfig, WorkflowsRestError, branch, convertNonRetryableError, createRunStep, createWaitForEvent, createWorkflowContext, createWorkflowRunContext, createWorkflows, createWorkflowsRestClient, defineStep, defineWorkflow, defineWorkflowEvent, isDuplicateInstanceError, isNonRetryableError, isStepDefinition, isWorkflowDefinition, isWorkflowEventDefinition, toNativeNonRetryableError, validateStepArgs, workflowClassName, workflowDefaultName };
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { default as createWorkflows } from './packem_shared/createWorkflows-wq4fs72q.mjs';
|
|
3
|
-
export { defineStep, isStepDefinition } from './packem_shared/defineStep-DJQtLw7g.mjs';
|
|
4
|
-
export { defineWorkflow, isWorkflowDefinition, workflowBindingName, workflowClassName, workflowDefaultName } from './packem_shared/defineWorkflow-DbUC-oCN.mjs';
|
|
5
|
-
export { NonRetryableError, convertNonRetryableError, isNonRetryableError, toNativeNonRetryableError } from './packem_shared/NonRetryableError-Dn2dTyBS.mjs';
|
|
6
|
-
export { MAX_BRANCHES, branch } from './packem_shared/MAX_BRANCHES-EO5xYS_3.mjs';
|
|
7
|
-
export { WorkflowsRestError, createWorkflowsRestClient } from './packem_shared/WorkflowsRestError-zmjOxTR1.mjs';
|
|
8
|
-
export { createWorkflowRunContext } from './packem_shared/createWorkflowRunContext-BDSHE8iO.mjs';
|
|
9
|
-
export { createRunStep, validateStepArgs } from './packem_shared/createRunStep-8jOXxP2o.mjs';
|
|
1
|
+
import{createWorkflowContext as e}from"./packem_shared/createWorkflowContext-DBUnSy0_.mjs";import{default as f}from"./packem_shared/createWorkflows-BwR_J9mp.mjs";import{defineWorkflowEvent as n,isWorkflowEventDefinition as i}from"./packem_shared/defineWorkflowEvent-suERPEEV.mjs";import{defineStep as p,isStepDefinition as s}from"./packem_shared/defineStep-D1-9eOnA.mjs";import{defineWorkflow as x,isWorkflowDefinition as w,workflowClassName as c,workflowDefaultName as k}from"./packem_shared/defineWorkflow-DynRL6LP.mjs";import{NonRetryableError as W,convertNonRetryableError as R,isNonRetryableError as N,toNativeNonRetryableError as v}from"./packem_shared/NonRetryableError-BPu01mU8.mjs";import{MAX_BRANCHES as d,branch as u}from"./packem_shared/MAX_BRANCHES-Bcw3dss9.mjs";import{WorkflowsRestError as D,createWorkflowsRestClient as S}from"./packem_shared/WorkflowsRestError-7vFcm7UK.mjs";import{createWorkflowRunContext as A}from"./packem_shared/createWorkflowRunContext-CRTTub21.mjs";import{c as h,v as B}from"./packem_shared/run-step-DJ107J5H.mjs";import{createWaitForEvent as H}from"./packem_shared/createWaitForEvent-D5Ohn2Pz.mjs";import{isDuplicateInstanceError as M}from"./packem_shared/isDuplicateInstanceError-CecnqNAa.mjs";export{d as MAX_BRANCHES,W as NonRetryableError,D as WorkflowsRestError,u as branch,R as convertNonRetryableError,h as createRunStep,H as createWaitForEvent,e as createWorkflowContext,A as createWorkflowRunContext,f as createWorkflows,S as createWorkflowsRestClient,p as defineStep,x as defineWorkflow,n as defineWorkflowEvent,M as isDuplicateInstanceError,N as isNonRetryableError,s as isStepDefinition,w as isWorkflowDefinition,i as isWorkflowEventDefinition,v as toNativeNonRetryableError,B as validateStepArgs,c as workflowClassName,k as workflowDefaultName};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as x}from"@lunora/errors";import{h as N,B as A,a as g}from"./branch-marker-CCpWfS5k.mjs";import{r as P}from"./workflow-binding-Dm9hBzx_.mjs";import{RESERVED_EVENT_TYPE_PREFIX as B}from"./defineWorkflowEvent-suERPEEV.mjs";import{NonRetryableError as m}from"./NonRetryableError-BPu01mU8.mjs";import{isDuplicateInstanceError as C}from"./isDuplicateInstanceError-CecnqNAa.mjs";const p=e=>e.toString(16).padStart(4,"0"),k=e=>{let t=8997,n=33826,a=40164,o=52210;for(let s=0;s<e.length;s+=1){t^=e.charCodeAt(s);const l=t*435,d=n*435,h=a*435+t*256,r=o*435+n*256,c=d+(l>>>16),i=h+(c>>>16),u=r+(i>>>16);t=l&65535,n=c&65535,a=i&65535,o=u&65535}return p(o)+p(a)+p(n)+p(t)},v=100,I=100,b="lunora:spawn:",O="lunora:await:",W="lunora:signal:",F="lunora:compensate:",X=17,w=(e,t="")=>e.length+t.length<=I?`${e}${t}`:`${e.slice(0,I-t.length-X)}-${k(e)}${t}`,S=`${B}branch:`,M=/^[A-Z_$][\w$]*Workflow$/u,Q=(e,t,n)=>({compensateWith:n?.compensateWith,id:n?.id,params:t,timeout:n?.timeout,workflow:e}),T=e=>e instanceof Error?{message:e.message,name:e.name}:{message:String(e),name:"Error"},H=e=>({status:"ok",value:e}),Z=e=>({error:T(e),status:"error"}),$=1048576,j=e=>{try{return String(e instanceof Error?e.message:e).slice(0,200)}catch{return"the failure itself could not be described"}},_=e=>{let t;try{t=new TextEncoder().encode(JSON.stringify(e)).length}catch(n){return{error:{message:`branch outcome cannot be serialised to JSON (${j(n)}) — the parent can never receive it. Return a plain JSON value (no cycles, no BigInt, no class instance that fails to serialise) or a reference the parent can dereference (an R2 key, a row id)`,name:"BranchOutputUnserializable"},status:"error"}}return t<=$?e:{error:{message:`branch outcome serialises to ${String(t)} bytes, over Cloudflare's ${String($)}-byte event payload limit — the parent can never receive it. Return a reference the parent can dereference (an R2 key, a row id) instead of the payload itself`,name:"BranchOutputTooLarge"},status:"error"}},E=async(e,t)=>{try{return{attached:!1,instance:await e.create(t)}}catch(n){if(!C(n))throw n;return{attached:!0,instance:await e.get(t.id)}}},D=async e=>{const{error:t,output:n,status:a}=await e.status();if(a==="complete")return H(n);if(a==="errored"||a==="terminated")return{error:t??{message:`branch instance ${a}`,name:"Error"},status:"error"}},L=e=>{if(typeof e!="object"||e===null)return;const{status:t}=e;return t==="error"||t==="ok"?e:void 0};class f extends Error{branchError;kind;plan;constructor(t,n,a){super(n.message),this.branchError=n,this.kind=a,this.plan=t}}const J=async(e,t,n)=>{for(let a=t.length-1;a>=0;a-=1){const o=t[a],s=o?.plan.item.compensateWith;if(!(o===void 0||s===void 0))try{const l=e.resolveBinding(s);await e.step.do(`${F}${o.plan.childId}`,async()=>{const d=w(o.plan.childId,"-compensate"),h={branch:o.plan.item.workflow,error:n,index:o.plan.index,output:o.output};return await E(l,{id:d,params:h}),d})}catch(l){e.log?.error(`ctx.parallel: group-saga compensation "${s}" for branch "${o.plan.item.workflow}" (#${String(o.plan.index)}) failed`,l)}}},ee=e=>async n=>{if(n.length===0)return[];if(n.length>v)throw new m(`ctx.parallel: ${String(n.length)} branches exceeds the cap of ${String(v)} — split the fan-out or raise the work into fewer child workflows`);const a=n.map((r,c)=>{const i=w(e.nextChildId(r.id));return{childId:i,eventType:`${S}${i}`,index:c,item:r}}),o=new Set;for(const r of a){if(o.has(r.childId))throw new m(`ctx.parallel: duplicate branch id "${r.childId}" — each branch in a group must resolve to a unique child instance id (check explicit \`id\` options)`);o.add(r.childId)}const s=await Promise.all(a.map(r=>e.step.do(`${b}${r.childId}`,async()=>{const c=e.resolveBinding(r.item.workflow),i={eventType:r.eventType,index:r.index,parentClassName:e.parentClassName,parentId:e.instanceId},{attached:u,instance:R}=await E(c,{id:r.childId,params:{...r.item.params,[g]:i}});if(!u)return;const y=await D(R);return y===void 0?void 0:_(y)}))),l=Array.from({length:a.length}),d=Array.from({length:a.length}),h=async(r,c)=>{let i;if(c===void 0)try{i=(await e.step.waitForEvent(`${O}${r.childId}`,{timeout:r.item.timeout,type:r.eventType})).payload}catch(u){throw new f(r,T(u),"join failed")}else i=c;if(i.status==="error")throw new f(r,i.error,"failed");d[r.index]={output:i.value,plan:r},l[r.index]=i.value};try{await Promise.all(a.map((r,c)=>h(r,L(s[c]))))}catch(r){throw r instanceof f?(await J(e,d.filter(c=>c!==void 0),r.branchError),new m(`ctx.parallel: branch "${r.plan.item.workflow}" (#${String(r.plan.index)}) ${r.kind}: ${r.branchError.message}`)):r}return l},te=e=>async(t,n,a)=>{if(N(n))throw new x("BAD_REQUEST",`@lunora/workflow: params ${A}`);const o=w(e.nextChildId(a?.id));return await e.step.do(`${b}${o}`,async()=>{const s=e.resolveBinding(t);return await E(s,{id:o,params:n}),o}),e.resolveBinding(t).get(o)},ne=e=>{if(typeof e!="object"||e===null)return;const t=e[g];if(typeof t!="object"||t===null)return;const n=t;if(!(typeof n.eventType!="string"||typeof n.parentClassName!="string"||typeof n.parentId!="string"||typeof n.index!="number")&&!(!M.test(n.parentClassName)||!n.eventType.startsWith(S)))return{eventType:n.eventType,index:n.index,parentClassName:n.parentClassName,parentId:n.parentId}},re=e=>{if(typeof e!="object"||e===null)return e;const t={...e};return Reflect.deleteProperty(t,g),t},K=async(e,t,n)=>{const a=P(e.env,e.exports,t.parentClassName,["get"]);if(a===void 0)return;const o=a.get.bind(a),s=_(n);await e.step.do(`${W}${String(t.index)}`,async()=>(await(await o(t.parentId)).sendEvent({payload:s,type:t.eventType}),t.eventType))},ae=async(e,t,n)=>{try{await K(e,t,n)}catch(a){e.log?.error(`@lunora/workflow: failed to signal branch parent "${t.parentId}" (event "${t.eventType}")`,a)}};export{v as MAX_BRANCHES,Q as branch,ee as createParallel,te as createSpawn,Z as errorOutcome,ne as extractBranchMarker,H as okOutcome,K as signalBranchParent,ae as signalBranchParentSafe,re as stripBranchMarker};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isDuplicateInstanceError as E}from"./isDuplicateInstanceError-CecnqNAa.mjs";const s="__lunoraNonRetryable";class r extends Error{constructor(e,n="NonRetryableError"){super(e),this.name=n,this[s]=!0}}const a=t=>t instanceof Error&&t[s]===!0,c=(t,e)=>{const n=new e(t.message,t.name);return t.stack!==void 0&&(n.stack=t.stack),t.cause!==void 0&&n.cause===void 0&&(n.cause=t.cause),n},i=(t,e)=>{throw e!==void 0&&a(t)?c(t,e):t},u=(t,e,n)=>{const o=new r(t);return e!==void 0&&(o.cause=e),i(o,n)};export{r as NonRetryableError,i as convertNonRetryableError,E as isDuplicateInstanceError,a as isNonRetryableError,u as raiseNonRetryable,c as toNativeNonRetryableError};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as g}from"@lunora/errors";const l=256,S=t=>t.length>l?`${t.slice(0,l)}… (truncated)`:t,h="https://api.cloudflare.com/client/v4/accounts",_=async({accountId:t,apiToken:a,fetch:e,init:n,path:r})=>{const s=await(e??globalThis.fetch.bind(globalThis))(`${h}/${encodeURIComponent(t)}${r}`,{...n,headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"}}),o=await s.text();let c;try{c=JSON.parse(o)}catch{return{ok:!1,status:s.status,text:o}}return!s.ok||typeof c!="object"||c===null||c.success===!1?{ok:!1,status:s.status,text:o}:{body:c,ok:!0}},A={complete:!0,errored:!0,paused:!0,queued:!0,rollingBack:!0,running:!0,terminated:!0,unknown:!0,waiting:!0,waitingForPause:!0},y=t=>typeof t=="string"&&Object.hasOwn(A,t)?t:"unknown",i=t=>typeof t=="string"&&t!==""?t:void 0,m=(t,a)=>typeof t=="string"?t:a,O=t=>typeof t=="boolean"?t:void 0,b=t=>Array.isArray(t)?t.length:typeof t=="number"?t:void 0,f=t=>({createdOn:i(t.created_on),endedOn:i(t.ended_on),id:m(t.id,""),startedOn:i(t.started_on),status:y(t.status)}),k=t=>({attempts:b(t.attempts),end:i(t.end),error:t.error,name:m(t.name,""),output:t.output,start:i(t.start),success:O(t.success),type:i(t.type)});class C extends g{constructor(a,e){super("WORKFLOWS_REST_ERROR",`Cloudflare Workflows REST API returned ${String(a)}: ${S(e)}`,{cause:e,name:"WorkflowsRestError",status:a})}}const I=t=>{const a=async(e,n)=>{const r=await _({accountId:t.accountId,apiToken:t.apiToken,...t.fetch===void 0?{}:{fetch:t.fetch},...n===void 0?{}:{init:n},path:`/workflows${e}`});if(!r.ok)throw new C(r.status,r.text);return r.body};return{getInstance:async({instanceId:e,workflowName:n})=>{const s=(await a(`/${encodeURIComponent(n)}/instances/${encodeURIComponent(e)}`)).result??{},o=Array.isArray(s.steps)?s.steps:[];return{...f(s),error:s.error,output:s.output,params:s.params,steps:o.map(c=>k(c))}},listInstances:async({page:e,perPage:n,status:r,workflowName:s})=>{const o=new URLSearchParams;r!==void 0&&o.set("status",r),e!==void 0&&o.set("page",String(e)),n!==void 0&&o.set("per_page",String(n));const c=o.toString()===""?"":`?${o.toString()}`,p=await a(`/${encodeURIComponent(s)}/instances${c}`),d=Array.isArray(p.result)?p.result:[],u=p.result_info??{};return{instances:d.map(R=>f(R)),page:typeof u.page=="number"?u.page:e??1,perPage:typeof u.per_page=="number"?u.per_page:n??d.length,totalCount:typeof u.total_count=="number"?u.total_count:void 0}},setInstanceStatus:async({action:e,instanceId:n,workflowName:r})=>{const o=(await a(`/${encodeURIComponent(r)}/instances/${encodeURIComponent(n)}/status`,{body:JSON.stringify({status:e}),method:"PATCH"})).result??{};return{status:y(o.status)}}}};export{C as WorkflowsRestError,I as createWorkflowsRestClient};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e="__lunoraBranch",o=n=>typeof n=="object"&&n!==null&&Object.hasOwn(n,e),a=`may not contain the reserved workflow branch-marker key ("${e}")`;export{a as B,e as a,o as h};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as p,v as o}from"./run-step-DJ107J5H.mjs";import"./defineWorkflowEvent-suERPEEV.mjs";import"./NonRetryableError-BPu01mU8.mjs";export{p as createRunStep,o as validateStepArgs};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{eventDefinitionProblem as m,RESERVED_EVENT_TYPE_PREFIX as i}from"./defineWorkflowEvent-suERPEEV.mjs";import{raiseNonRetryable as a}from"./NonRetryableError-BPu01mU8.mjs";const c=e=>async(r,t)=>{const n=m(r);if(n!==void 0)return a(`@lunora/workflow: ctx.waitForEvent ${n}`,void 0,e.nonRetryableErrorClass);if(t?.name?.startsWith(i)===!0)return a(`@lunora/workflow: ctx.waitForEvent step name "${t.name}" is reserved — the "${i}" prefix is used by the framework's own steps`,void 0,e.nonRetryableErrorClass);const s=await e.step.waitForEvent(t?.name??`event:${r.type}`,{timeout:t?.timeout,type:r.type});try{return r.payload.parse(s.payload)}catch(o){const l=o instanceof Error?o.message:String(o);return a(`@lunora/workflow: event "${r.type}" payload validation failed: ${l}`,o,e.nonRetryableErrorClass)}};export{c as createWaitForEvent};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as s}from"./workflow-binding-Dm9hBzx_.mjs";import a from"./createWorkflows-BwR_J9mp.mjs";const l=(t,c,n)=>{const o={};for(const e of c){const r=s(t,n,e.className,["create","createBatch","get"]);r!==void 0&&(o[e.exportName]=r)}return a({bindings:o})};export{l as createWorkflowContext};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as x,d as i,c as b,p as h,w as I}from"./run-step-DJ107J5H.mjs";import{LunoraError as N}from"@lunora/errors";import{decodeWire as g}from"@lunora/wire";import{r as k}from"./workflow-binding-Dm9hBzx_.mjs";import{workflowClassName as d}from"./defineWorkflow-DynRL6LP.mjs";import{raiseNonRetryable as y}from"./NonRetryableError-BPu01mU8.mjs";import{createSpawn as C,createParallel as E}from"./MAX_BRANCHES-Bcw3dss9.mjs";import{createWaitForEvent as R}from"./createWaitForEvent-D5Ohn2Pz.mjs";const $=e=>({debug:(r,...a)=>{console.debug(e,r,...a)},error:(r,...a)=>{console.error(e,r,...a)},info:(r,...a)=>{console.info(e,r,...a)},warn:(r,...a)=>{console.warn(e,r,...a)}}),H=e=>{const r=$(`[workflow:${e.exportName}]`),a=x({env:e.env,fetchImpl:e.fetchImpl,label:"@lunora/workflow"}),m=I(a),o=i(e.exportName,e.event.instanceId),f=h(m,`${o}#body`),p=n=>{const t=d(n),s=k(e.env,e.exports,t,["create","get"]);if(s===void 0)throw new N("INTERNAL",`@lunora/workflow: cannot spawn child workflow "${n}" — no "${t}" on ctx.exports or env (is it declared in lunora/workflows.ts?)`);return s},u=e.exportName.replaceAll(/\W/gu,"_");let l=0;const w=n=>{if(n!==void 0)return n;const t=`${e.event.instanceId}-${u}-c${String(l)}`;return l+=1,t},c={env:e.env,exports:e.exports,instanceId:e.event.instanceId,log:r,nextChildId:w,parentClassName:d(e.exportName),resolveBinding:p,step:e.step},v=(()=>{try{return g(e.event.payload)}catch(n){return y(`@lunora/workflow: workflow "${e.exportName}" params could not be decoded — ${n instanceof Error?n.message:String(n)}`,n,e.nonRetryableErrorClass)}})();return{env:e.env,exports:e.exports,event:e.event,...e.fetchImpl===void 0?{}:{fetchImpl:e.fetchImpl},log:r,parallel:E(c),params:v,run:f,runStep:b({dedupNamespace:o,env:e.env,log:r,nonRetryableErrorClass:e.nonRetryableErrorClass,run:a,step:e.step}),spawn:C(c),step:e.step,waitForEvent:R({nonRetryableErrorClass:e.nonRetryableErrorClass,step:e.step})}};export{H as createWorkflowRunContext};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as o}from"@lunora/errors";import{h as w,B as l}from"./branch-marker-CCpWfS5k.mjs";import{eventDefinitionProblem as f}from"./defineWorkflowEvent-suERPEEV.mjs";const c=r=>{if(w(r?.params))throw new o("BAD_REQUEST",`@lunora/workflow: params ${l}`)},i=r=>({create:async e=>(c(e),r.create(e)),createBatch:async e=>{const a="instances"in e?e.instances:[{params:e.params}];for(const t of a)c(t);return r.createBatch(e)},deleteBatch:async e=>r.deleteBatch(e),get:async e=>r.get(e),sendEvent:async(e,a,t)=>{const n=f(a);if(n!==void 0)throw new o("BAD_REQUEST",`@lunora/workflow: sendEvent ${n}`);await(await r.get(e)).sendEvent({payload:a.payload.parse(t),type:a.type})}}),E=r=>{const e=r.bindings??{};return{get:a=>{const t=e[a];if(t===void 0){const n=Object.keys(e),s=n.length===0?"no workflows are declared":`known workflows: ${n.join(", ")}`;throw new o("INTERNAL",`@lunora/workflow: no workflow named "${a}" (${s})`)}return i(t)}}};export{E as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const n=(r,e)=>{if(typeof r!="string"||r.length===0)throw new TypeError("defineStep: `name` must be a non-empty string (the durable step label)");const t=e.args;if(typeof t!="object"||t===null)throw new TypeError("defineStep: `args` must be a validator map (e.g. `{ id: v.string() }`)");if(typeof e.handler!="function")throw new TypeError("defineStep: `handler` must be a function (the step body)");if(e.rollback!==void 0&&typeof e.rollback!="function")throw new TypeError("defineStep: `rollback` must be a function when provided");return{args:e.args,config:e.config,handler:e.handler,isLunoraStep:!0,name:r,returns:e.returns,rollback:e.rollback,rollbackConfig:e.rollbackConfig}},o=r=>typeof r=="object"&&r!==null&&r.isLunoraStep===!0;export{n as defineStep,o as isStepDefinition};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const d=e=>`${e.charAt(0).toUpperCase()}${e.slice(1)}Workflow`,w=e=>e.replaceAll(/(?<=[a-z0-9])(?=[A-Z])/g,"-").toLowerCase(),f=e=>typeof e=="string"&&e.trim().length>0,a=e=>{const{defaultRetention:o,limits:r,schedules:n}=e,s=t=>typeof t=="object"&&t!==null;if(n!==void 0&&!(Array.isArray(n)&&n.length>0&&n.every(t=>f(t))))return"`schedules` must be a non-empty array of cron expression strings";const i=s(r)?r.steps:void 0;if(r!==void 0&&(!s(r)||i!==void 0&&!(Number.isInteger(i)&&i>0)))return"`limits` must be an object whose `steps` is a positive integer";const l=s(o)?[o.errorRetention,o.successRetention]:[];if(o!==void 0&&(!s(o)||l.some(t=>t!==void 0&&!f(t))))return'`defaultRetention` must be an object of duration strings (e.g. "7 days")'},u=e=>{if(typeof e.handler!="function")throw new TypeError("defineWorkflow: `handler` must be a function (the workflow body)");if(e.name!==void 0&&(typeof e.name!="string"||e.name.length===0))throw new TypeError("defineWorkflow: `name` must be a non-empty string when provided");const o=a(e);if(o!==void 0)throw new TypeError(`defineWorkflow: ${o}`);return{...e,isLunoraWorkflow:!0}},c=e=>typeof e=="object"&&e!==null&&e.isLunoraWorkflow===!0;export{u as defineWorkflow,c as isWorkflowDefinition,d as workflowClassName,w as workflowDefaultName};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o="lunora:",r=e=>{if(typeof e!="object"||e===null||e.isLunoraWorkflowEvent!==!0)return"expects a `defineWorkflowEvent` definition";const t=e;if(typeof t.type!="string"||t.type.length===0)return"event `type` must be a non-empty string";if(t.type.startsWith(o))return`event type "${t.type}" is reserved — the "${o}" prefix is used by the framework's own events`;if(typeof t.payload?.parse!="function")return"event `payload` must be a validator (e.g. `v.object({ ok: v.boolean() })`)"},i=(e,t)=>{if(typeof e!="string"||e.length===0)throw new TypeError("defineWorkflowEvent: `type` must be a non-empty string (the wire event type)");const n=r({isLunoraWorkflowEvent:!0,payload:t,type:e});if(n!==void 0)throw new TypeError(`defineWorkflowEvent: ${n}`);return{isLunoraWorkflowEvent:!0,payload:t,type:e}},f=e=>r(e)===void 0;export{o as RESERVED_EVENT_TYPE_PREFIX,i as defineWorkflowEvent,r as eventDefinitionProblem,f as isWorkflowEventDefinition};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=/already[\s_-]?exists/iu,e=s=>t.test(s instanceof Error?s.message:String(s));export{e as isDuplicateInstanceError};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as w,isLunoraError as k}from"@lunora/errors";import{decodeWire as P,encodeArgsOrThrow as x}from"@lunora/wire";import{parseValidatorMap as H}from"@lunora/values";import{RESERVED_EVENT_TYPE_PREFIX as T}from"./defineWorkflowEvent-suERPEEV.mjs";import{raiseNonRetryable as I,convertNonRetryableError as K}from"./NonRetryableError-BPu01mU8.mjs";const b=9e5,j="DISPATCH_IN_PROGRESS",F="x-lunora-dispatch-declined",J=(t,e,r)=>{if(e===void 0)return{dispose:()=>{},signal:t};const a=new AbortController,o=setTimeout(()=>{a.abort(r())},e);return{dispose:()=>{clearTimeout(o)},signal:a.signal}},m="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",R=t=>{let e="",r=0;const a=t.length-2;for(;r<a;r+=3){const n=t[r]<<16|t[r+1]<<8|t[r+2];e+=m.charAt(n>>18&63)+m.charAt(n>>12&63)+m.charAt(n>>6&63)+m.charAt(n&63)}const o=t.length-r;if(o===1){const n=t[r]<<16;e+=m.charAt(n>>18&63)+m.charAt(n>>12&63)}else if(o===2){const n=t[r]<<16|t[r+1]<<8;e+=m.charAt(n>>18&63)+m.charAt(n>>12&63)+m.charAt(n>>6&63)}return e};new TextDecoder;const $=new TextEncoder,A="=",W=t=>{for(let e=0;e<t.length;e+=1)if(t.charCodeAt(e)>255)return!1;return!0},G=t=>R($.encode(JSON.stringify(t))),V=t=>!t.startsWith(A)&&W(t)?t:`${A}${R($.encode(t))}`,B="/_lunora/scheduler/dispatch",O=3e4,X=t=>{let e=t.length;for(;e>0&&t[e-1]==="/";)e-=1;return t.slice(0,e)},D=Symbol("lunoraDispatchFailure"),M=Symbol("lunoraDispatchDecline"),z=Symbol("lunoraDispatchMessageId"),L=(t,e)=>(e!==void 0&&Object.defineProperty(t,z,{value:e}),t),Y=(t,e)=>(Object.defineProperty(t,D,{value:!0}),L(t,e)),q=(t,e,r,a)=>{const{status:o}=e;try{const n=JSON.parse(r)?.error;if(typeof n=="object"&&n!==null&&typeof n.code=="string"){const{code:l,data:d,message:c}=n,i=Y(new w(l,typeof c=="string"?c:void 0,{data:d,status:o}),a);return e.headers.get(F)==="1"&&Object.defineProperty(i,M,{value:!0}),i}}catch{}return L(new w("INTERNAL",`${t}: function dispatch failed (${String(o)}): ${r}`,{status:o}),a)},Q=new Set([400,403,404,422]),Z=new Set([j,"DISPATCH_UNAUTHENTICATED"]),C=t=>k(t)&&t[D]===!0,tt=t=>C(t)&&Q.has(t.status)&&!Z.has(t.code),et=t=>C(t)&&t[M]===!0,rt=(t,e,r)=>new w("INTERNAL",`${t}: function dispatch to "${e}" timed out after ${String(r)}ms`,{status:503}),wt=t=>{const{label:e}=t,r=globalThis.fetch,a=t.fetchImpl??(typeof r=="function"?r.bind(globalThis):void 0);return async(o,n,l={})=>{if(typeof a!="function")throw new TypeError(`${e}: no fetch implementation available — pass fetchImpl or run on a platform with global fetch`);const d=()=>t.argsAlreadyEncoded===!0?n??{}:x(e,o.__lunoraRef,n??{}),c=t.env.LUNORA_ORIGIN_URL;if(typeof c!="string"||c.length===0)throw new w("INTERNAL",`${e}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);const i=t.env.LUNORA_ADMIN_TOKEN;if(typeof i!="string"||i.length===0)throw new w("INTERNAL",`${e}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);const g=`${X(c)}${B}`,p={authorization:`Bearer ${i}`,"content-type":"application/json"};t.traceparent!==void 0&&t.traceparent.length>0&&(p.traceparent=t.traceparent),t.identity?.userId!==void 0&&(p["x-lunora-userid"]=V(t.identity.userId)),t.identity?.claims!==void 0&&(p["x-lunora-identity"]=G(t.identity.claims));const u=l.timeoutMs??O,y=J(void 0,u,()=>new DOMException(`dispatch timed out after ${String(u)}ms`,"TimeoutError")),h=f=>{throw f instanceof Error&&f.name==="TimeoutError"?rt(e,o.__lunoraRef,u):f};let s;try{try{s=await a(g,{body:JSON.stringify({args:d(),functionPath:o.__lunoraRef,id:l.dedupId,shardKey:l.shardKey}),headers:p,method:"POST",signal:y.signal})}catch(N){return h(N)}if(!s.ok){let N;try{N=await s.text()}catch(U){return h(U)}throw q(e,s,N,l.messageId)}let f;try{f=await s.text()}catch(N){return h(N)}if(f.length===0)return;let E;try{E=JSON.parse(f)}catch{throw new w("INTERNAL",`${e}: function dispatch returned a non-JSON body (${String(s.status)}): ${f}`,{status:s.status})}if(E===null||typeof E!="object"||Array.isArray(E)||!("result"in E))throw new w("INTERNAL",`${e}: function dispatch returned a JSON body that is not a { result } envelope (${String(s.status)}): ${f}`,{status:s.status});return P(E.result)}finally{y.dispose()}}},Et=(t,e)=>`${t}/${e}`,S=(t,e)=>{let r=0;return(a,o,n)=>(r+=1,t(a,o,{...n,dedupId:n?.dedupId??`${e}.${String(r)}`}))},nt=1e3,ot=3e4,st=2e3,at=1e3,ct=6e5,it={day:864e5,hour:36e5,millisecond:1,minute:6e4,second:1e3,week:6048e5},ut=/^(\d+(?:\.\d+)?)\s*([a-z]+?)s?$/iu,lt=t=>{if(t===void 0)return ct;if(typeof t=="number")return Number.isFinite(t)&&t>0?t:void 0;const e=ut.exec(t.trim()),r=e===null?void 0:it[(e[2]??"").toLowerCase()];return e===null||r===void 0?void 0:Number(e[1])*r},v=(t,e)=>{const r=lt(t?.timeout);return r===void 0?void 0:e+r-st},dt=async t=>{await new Promise(e=>{setTimeout(e,t)})},_=(t,e)=>async(r,a,o)=>{const n=async(l,d)=>{try{const c=l===void 0||e===void 0?o:{...o,timeoutMs:Math.min(O,e-Date.now())};return await t(r,a,c)}catch(c){if(!et(c))throw c;const i=Date.now(),g=l??i,p=g+b-i,u=e===void 0?Number.POSITIVE_INFINITY:e-i-at,y=Math.min(p,u);if(y<=0)throw c;await dt(Math.min(d,y));const h=Date.now();if(h>=g+b||e!==void 0&&h>=e)throw c;return n(g,Math.min(d*2,ot))}};return n(void 0,nt)},ft=(t,e)=>H(t,e,"step args"),Nt=t=>{let e=0;return async(r,a,o)=>{const n=`${t.dedupNamespace}#step${String(e)}`;e+=1;const l=o?.config??r.config,d=o?.name??r.name;if(d.startsWith(T))return I(`@lunora/workflow: ctx.runStep step name "${d}" is reserved — the "${T}" prefix is used by the framework's own steps`,void 0,t.nonRetryableErrorClass);const c=ft(r.args,a),i=async u=>{const y={attempt:u.attempt,config:u.config,env:t.env,log:t.log,run:S(_(t.run,v(u.config,Date.now())),n),step:u.step};let h;try{h=await r.handler(y,c)}catch(s){return tt(s)?I(s.message,s,t.nonRetryableErrorClass):K(s,t.nonRetryableErrorClass)}if(!r.returns)return h;try{return r.returns.parse(h)}catch(s){const f=s instanceof Error?s.message:String(s);return I(`step "${r.name}" returns validation failed: ${f}`,s,t.nonRetryableErrorClass)}},g=r.rollback,p=g?{rollback:async u=>{await g({args:c,env:t.env,error:u.error,log:t.log,output:u.output,run:S(_(t.run,v(r.rollbackConfig,Date.now())),`${n}rollback`)})},rollbackConfig:r.rollbackConfig}:void 0;return l===void 0?t.step.do(d,i,p):t.step.do(d,l,i,p)}};export{Nt as c,Et as d,wt as n,S as p,ft as v,_ as w};
|