@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
package/LICENSE.md
CHANGED
|
@@ -103,3 +103,9 @@ Unless required by applicable law or agreed to in writing, software distributed
|
|
|
103
103
|
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
104
|
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
105
|
specific language governing permissions and limitations under the License.
|
|
106
|
+
|
|
107
|
+
<!-- DEPENDENCIES -->
|
|
108
|
+
<!-- /DEPENDENCIES -->
|
|
109
|
+
|
|
110
|
+
<!-- TYPE_DEPENDENCIES -->
|
|
111
|
+
<!-- /TYPE_DEPENDENCIES -->
|
package/README.md
CHANGED
|
@@ -85,10 +85,33 @@ The handler context bundles:
|
|
|
85
85
|
- `ctx.step` — the native Cloudflare durable-step API (`do` / `sleep` / `sleepUntil` / `waitForEvent`).
|
|
86
86
|
- `ctx.run(ref, args, opts?)` — call a Lunora query / mutation / action; wrap in `ctx.step.do(...)` for durability.
|
|
87
87
|
- `ctx.runStep(step, args, opts?)` — run a reusable, schema-validated `defineStep` as a durable step (see below).
|
|
88
|
+
- `ctx.waitForEvent(event, opts?)` — hibernate until a declared `defineWorkflowEvent` arrives; resolves with its validated payload (see below).
|
|
88
89
|
- `ctx.event` / `ctx.params` — the triggering event and its payload.
|
|
89
90
|
- `ctx.env` — the Worker bindings.
|
|
90
91
|
- `ctx.log` — a workflow-prefixed logger surfaced in `wrangler tail` / Studio.
|
|
91
92
|
|
|
93
|
+
### Declared events (`defineWorkflowEvent`)
|
|
94
|
+
|
|
95
|
+
`step.waitForEvent(name, { type })` and `instance.sendEvent({ type })` match on a bare string, and the payload crosses as `unknown` — so a typo hibernates the instance until its timeout with no error anywhere, and a changed payload shape resumes the workflow on garbage. Declare the event once and both ends import the same value:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
// lunora/events.ts
|
|
99
|
+
import { defineWorkflowEvent } from "@lunora/workflow";
|
|
100
|
+
import { v } from "@lunora/values";
|
|
101
|
+
|
|
102
|
+
export const orderApproved = defineWorkflowEvent("order-approved", v.object({ approvedBy: v.string() }));
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// inside the workflow body — typed and parsed
|
|
107
|
+
const { approvedBy } = await ctx.waitForEvent(orderApproved, { name: "await approval", timeout: "7 days" });
|
|
108
|
+
|
|
109
|
+
// from a mutation/action — validated before the send
|
|
110
|
+
await ctx.workflows.get("orderPipeline").sendEvent(instanceId, orderApproved, { approvedBy });
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Pass a stable `{ name }` on any wait that can outlive a deploy: the step is otherwise labelled `event:<type>`, so renaming the event type also renames the durable step and an instance that already recorded the wait replays into a fresh one nothing will satisfy.
|
|
114
|
+
|
|
92
115
|
### Reusable steps (`defineStep`)
|
|
93
116
|
|
|
94
117
|
A step authored inline with `ctx.step.do("name", () => …)` is fine for one-offs, but `defineStep` lets you define a step **once** — schema-validated and reusable across workflows. Args are validated (with `@lunora/values`) **before** the body runs, and the return value is validated **after** (when you declare `returns`), so a bad payload fails fast instead of corrupting later steps. Scaffold one with `vis generate lunora-step --name=chargeOrder` (appends to `lunora/steps.ts`), or write it by hand:
|
|
@@ -169,7 +192,7 @@ export const checkout = mutation.input({ orderId: v.string() }).mutation(async (
|
|
|
169
192
|
});
|
|
170
193
|
```
|
|
171
194
|
|
|
172
|
-
A handle exposes `create({ id?, params?, retention? })`, `createBatch([...])`,
|
|
195
|
+
A handle exposes `create({ id?, params?, retention? })`, `createBatch([...])`, `get(id)`, and `sendEvent(instanceId, event, payload)` — the typed delivery of a declared event (see above). `create`/`get` return the native Cloudflare instance, which exposes its own lifecycle: `status()`, `pause()`, `resume()`, `restart()`, `terminate()`, and the untyped `sendEvent({ type, payload })`.
|
|
173
196
|
|
|
174
197
|
### Runtime requirements
|
|
175
198
|
|
|
@@ -223,7 +246,7 @@ const detail = await client.getInstance({ workflowName: "order-pipeline", instan
|
|
|
223
246
|
await client.setInstanceStatus({ workflowName: "order-pipeline", instanceId: detail.id, action: "terminate" });
|
|
224
247
|
```
|
|
225
248
|
|
|
226
|
-
> This README covers the basics. For the full API, options, and guides, see the **[documentation](https://lunora.sh/docs/
|
|
249
|
+
> This README covers the basics. For the full API, options, and guides, see the **[documentation](https://lunora.sh/docs/packages/workflow)**.
|
|
227
250
|
|
|
228
251
|
## Related
|
|
229
252
|
|
package/dist/do/index.d.mts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { WorkflowEntrypoint, WorkflowEvent, WorkflowStep } from 'cloudflare:workers';
|
|
2
|
-
import { W as WorkflowDefinition } from "../packem_shared/types.d-
|
|
2
|
+
import { W as WorkflowDefinition } from "../packem_shared/types.d-C7jti0tm.mjs";
|
|
3
3
|
import '@lunora/values';
|
|
4
4
|
/**
|
|
5
|
-
* Base class for the generated `WorkflowEntrypoint` classes. Applies a
|
|
6
|
-
* `defineWorkflow` definition onto Cloudflare's `WorkflowEntrypoint`: `run`
|
|
7
|
-
* assembles the Lunora context (native `step`/`event` + the `ctx.run` function
|
|
8
|
-
* dispatcher + a logger) and invokes the user's handler.
|
|
9
|
-
*
|
|
10
|
-
* Generated subclasses stay one line of behavior:
|
|
11
|
-
*
|
|
12
|
-
* ```ts
|
|
13
|
-
* export class OrderPipelineWorkflow extends LunoraWorkflow {
|
|
14
|
-
* constructor(ctx: ExecutionContext, env: Record
|
|
15
|
-
* super(ctx, env, orderPipeline, "orderPipeline");
|
|
16
|
-
* }
|
|
17
|
-
* }
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
5
|
+
* Base class for the generated `WorkflowEntrypoint` classes. Applies a
|
|
6
|
+
* `defineWorkflow` definition onto Cloudflare's `WorkflowEntrypoint`: `run`
|
|
7
|
+
* assembles the Lunora context (native `step`/`event` + the `ctx.run` function
|
|
8
|
+
* dispatcher + a logger) and invokes the user's handler.
|
|
9
|
+
*
|
|
10
|
+
* Generated subclasses stay one line of behavior:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* export class OrderPipelineWorkflow extends LunoraWorkflow {
|
|
14
|
+
* constructor(ctx: ExecutionContext, env: Record<string, unknown>) {
|
|
15
|
+
* super(ctx, env, orderPipeline, "orderPipeline");
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
20
|
declare class LunoraWorkflow<Params = Record<string, unknown>, Output = unknown> extends WorkflowEntrypoint<Record<string, unknown>, Params> {
|
|
21
21
|
#private;
|
|
22
22
|
constructor(context: ConstructorParameters<typeof WorkflowEntrypoint>[0], env: Record<string, unknown>, definition: WorkflowDefinition<Params, Output>, exportName?: string);
|
package/dist/do/index.d.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { WorkflowEntrypoint, WorkflowEvent, WorkflowStep } from 'cloudflare:workers';
|
|
2
|
-
import { W as WorkflowDefinition } from "../packem_shared/types.d-
|
|
2
|
+
import { W as WorkflowDefinition } from "../packem_shared/types.d-C7jti0tm.js";
|
|
3
3
|
import '@lunora/values';
|
|
4
4
|
/**
|
|
5
|
-
* Base class for the generated `WorkflowEntrypoint` classes. Applies a
|
|
6
|
-
* `defineWorkflow` definition onto Cloudflare's `WorkflowEntrypoint`: `run`
|
|
7
|
-
* assembles the Lunora context (native `step`/`event` + the `ctx.run` function
|
|
8
|
-
* dispatcher + a logger) and invokes the user's handler.
|
|
9
|
-
*
|
|
10
|
-
* Generated subclasses stay one line of behavior:
|
|
11
|
-
*
|
|
12
|
-
* ```ts
|
|
13
|
-
* export class OrderPipelineWorkflow extends LunoraWorkflow {
|
|
14
|
-
* constructor(ctx: ExecutionContext, env: Record
|
|
15
|
-
* super(ctx, env, orderPipeline, "orderPipeline");
|
|
16
|
-
* }
|
|
17
|
-
* }
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
5
|
+
* Base class for the generated `WorkflowEntrypoint` classes. Applies a
|
|
6
|
+
* `defineWorkflow` definition onto Cloudflare's `WorkflowEntrypoint`: `run`
|
|
7
|
+
* assembles the Lunora context (native `step`/`event` + the `ctx.run` function
|
|
8
|
+
* dispatcher + a logger) and invokes the user's handler.
|
|
9
|
+
*
|
|
10
|
+
* Generated subclasses stay one line of behavior:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* export class OrderPipelineWorkflow extends LunoraWorkflow {
|
|
14
|
+
* constructor(ctx: ExecutionContext, env: Record<string, unknown>) {
|
|
15
|
+
* super(ctx, env, orderPipeline, "orderPipeline");
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
20
|
declare class LunoraWorkflow<Params = Record<string, unknown>, Output = unknown> extends WorkflowEntrypoint<Record<string, unknown>, Params> {
|
|
21
21
|
#private;
|
|
22
22
|
constructor(context: ConstructorParameters<typeof WorkflowEntrypoint>[0], env: Record<string, unknown>, definition: WorkflowDefinition<Params, Output>, exportName?: string);
|
package/dist/do/index.mjs
CHANGED
|
@@ -1,44 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { NonRetryableError } from 'cloudflare:workflows';
|
|
3
|
-
import { convertNonRetryableError } from '../packem_shared/NonRetryableError-Dn2dTyBS.mjs';
|
|
4
|
-
import { stripBranchMarker, signalBranchParent, extractBranchMarker, errorOutcome, okOutcome } from '../packem_shared/MAX_BRANCHES-C9MJIFii.mjs';
|
|
5
|
-
import { createWorkflowRunContext } from '../packem_shared/createWorkflowRunContext-BsMyGuMR.mjs';
|
|
6
|
-
|
|
7
|
-
class LunoraWorkflow extends WorkflowEntrypoint {
|
|
8
|
-
/** The `lunora/workflows.ts` export name, for log correlation. */
|
|
9
|
-
#lunoraName;
|
|
10
|
-
/** The `defineWorkflow` result this entrypoint runs. */
|
|
11
|
-
#definition;
|
|
12
|
-
constructor(context, env, definition, exportName) {
|
|
13
|
-
super(context, env);
|
|
14
|
-
this.#definition = definition;
|
|
15
|
-
this.#lunoraName = exportName ?? "workflow";
|
|
16
|
-
}
|
|
17
|
-
async run(event, step) {
|
|
18
|
-
const nativeStep = step;
|
|
19
|
-
const marker = extractBranchMarker(event.payload);
|
|
20
|
-
const handlerEvent = marker ? { ...event, payload: stripBranchMarker(event.payload) } : event;
|
|
21
|
-
const context = createWorkflowRunContext({
|
|
22
|
-
env: this.env,
|
|
23
|
-
event: handlerEvent,
|
|
24
|
-
exportName: this.#lunoraName,
|
|
25
|
-
nonRetryableErrorClass: NonRetryableError,
|
|
26
|
-
step: nativeStep
|
|
27
|
-
});
|
|
28
|
-
let output;
|
|
29
|
-
try {
|
|
30
|
-
output = await this.#definition.handler(context);
|
|
31
|
-
} catch (error) {
|
|
32
|
-
if (marker) {
|
|
33
|
-
await signalBranchParent({ env: this.env, step: nativeStep }, marker, errorOutcome(error));
|
|
34
|
-
}
|
|
35
|
-
return convertNonRetryableError(error, NonRetryableError);
|
|
36
|
-
}
|
|
37
|
-
if (marker) {
|
|
38
|
-
await signalBranchParent({ env: this.env, step: nativeStep }, marker, okOutcome(output));
|
|
39
|
-
}
|
|
40
|
-
return output;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export { LunoraWorkflow as default };
|
|
1
|
+
import{WorkflowEntrypoint as p}from"cloudflare:workers";import{NonRetryableError as i}from"cloudflare:workflows";import{convertNonRetryableError as m}from"../packem_shared/NonRetryableError-9ZqDUzwT.mjs";import{extractBranchMarker as f,stripBranchMarker as h,signalBranchParentSafe as l,errorOutcome as u,okOutcome as y}from"../packem_shared/MAX_BRANCHES-C05O5LY9.mjs";import{createWorkflowRunContext as d}from"../packem_shared/createWorkflowRunContext-C83Yp2Qp.mjs";class N extends p{#r;#t;constructor(t,e,o,r){super(t,e),this.#t=o,this.#r=r??"workflow"}async run(t,e){const o=e,r=f(t.payload),c=r?{...t,payload:h(t.payload)}:t,a=d({env:this.env,event:c,exportName:this.#r,nonRetryableErrorClass:i,step:o});let n;try{n=await this.#t.handler(a)}catch(s){return r&&await l({env:this.env,log:a.log,step:o},r,u(s)),m(s,i)}return r&&await l({env:this.env,log:a.log,step:o},r,y(n)),n}}export{N as default};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { a as Workflows, L as LunoraWorkflowsOptions, S as StepArgsValidator,
|
|
2
|
-
export type { A as ArgsOf, F as FunctionReference, I as InferStepArgs, R as RunFunctionOptions,
|
|
3
|
-
import '@lunora/values';
|
|
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-C7jti0tm.mjs";
|
|
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 WorkflowBindingLike, w as WorkflowBranchOutputs, x as WorkflowCreateOptions, y as WorkflowHandle, z as WorkflowHandler, C as WorkflowInstanceLike, D as WorkflowParallelFunction, E as WorkflowRollbackContextLike, G as WorkflowRollbackHandlerLike, H as WorkflowSpawnFunction, J as WorkflowSpawnOptions, K as WorkflowStatusResult, M as WorkflowStepConfigLike, N as WorkflowStepContextLike, O as WorkflowStepRollbackOptionsLike } from "./packem_shared/types.d-C7jti0tm.mjs";
|
|
3
|
+
import { Validator } from '@lunora/values';
|
|
4
|
+
import { LunoraError } from '@lunora/errors';
|
|
4
5
|
/** Wiring info for one declared workflow, emitted by codegen into the generated shard. */
|
|
5
6
|
interface WorkflowBindingSpec {
|
|
6
7
|
/** The Cloudflare `Workflow` binding name, e.g. `WORKFLOW_ORDER_PIPELINE`. */
|
|
@@ -9,108 +10,138 @@ interface WorkflowBindingSpec {
|
|
|
9
10
|
exportName: string;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
|
-
* Build the `ctx.workflows` handle for a request: resolve every spec's
|
|
13
|
-
* `env[binding]` into the `exportName → Workflow binding` map and wrap it in
|
|
14
|
-
* {@link createWorkflows}. A spec whose binding is absent from `env` is skipped
|
|
15
|
-
* here — the helpful "no workflow named …" error is raised lazily by
|
|
16
|
-
* `workflows.get(name)` when the missing workflow is actually used.
|
|
17
|
-
*/
|
|
13
|
+
* Build the `ctx.workflows` handle for a request: resolve every spec's
|
|
14
|
+
* `env[binding]` into the `exportName → Workflow binding` map and wrap it in
|
|
15
|
+
* {@link createWorkflows}. A spec whose binding is absent from `env` is skipped
|
|
16
|
+
* here — the helpful "no workflow named …" error is raised lazily by
|
|
17
|
+
* `workflows.get(name)` when the missing workflow is actually used.
|
|
18
|
+
*/
|
|
18
19
|
declare const createWorkflowContext: (env: Record<string, unknown>, specs: ReadonlyArray<WorkflowBindingSpec>) => Workflows;
|
|
19
20
|
/**
|
|
20
|
-
* Build the `ctx.workflows` handle from a map of `lunora/workflows.ts` export
|
|
21
|
-
* name → Cloudflare `Workflow` binding. `get(name)` resolves the typed handle;
|
|
22
|
-
* an unknown name throws with the list of declared workflows.
|
|
23
|
-
*/
|
|
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
|
+
*/
|
|
24
25
|
declare const createWorkflows: (options: LunoraWorkflowsOptions) => Workflows;
|
|
25
26
|
/**
|
|
26
|
-
* Declare
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* import {
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
27
|
+
* Declare an external event, its wire type, and its payload shape.
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* // lunora/events.ts
|
|
31
|
+
* import { defineWorkflowEvent } from "@lunora/workflow";
|
|
32
|
+
* import { v } from "@lunora/values";
|
|
33
|
+
*
|
|
34
|
+
* export const orderApproved = defineWorkflowEvent("order-approved", v.object({ approvedBy: v.string() }));
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* Wait on it inside a workflow body — the payload is typed and validated:
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* const { approvedBy } = await ctx.waitForEvent(orderApproved, { name: "await approval", timeout: "7 days" });
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* …and send it from a mutation/action with the same definition:
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* await ctx.workflows.get("orderPipeline").sendEvent(instanceId, orderApproved, { approvedBy });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare const defineWorkflowEvent: <Payload>(type: string, payload: Validator<Payload>) => WorkflowEventDefinition<Payload>;
|
|
50
|
+
/**
|
|
51
|
+
* True when a value is usable as an event definition. The brand alone is not the
|
|
52
|
+
* test: the predicate hands the caller a `type` and a `payload.parse`, so it checks
|
|
53
|
+
* for both (and for the reserved namespace) rather than trusting a public boolean.
|
|
54
|
+
*/
|
|
55
|
+
declare const isWorkflowEventDefinition: (value: unknown) => value is WorkflowEventDefinition;
|
|
56
|
+
/**
|
|
57
|
+
* Declare a reusable durable step. Same `args` map shape a Lunora `query` /
|
|
58
|
+
* `mutation` / `action` uses, so a step reads like a function:
|
|
59
|
+
*
|
|
60
|
+
* ```ts
|
|
61
|
+
* // lunora/steps.ts
|
|
62
|
+
* import { defineStep } from "@lunora/workflow";
|
|
63
|
+
* import { v } from "@lunora/values";
|
|
64
|
+
*
|
|
65
|
+
* export const fetchImage = defineStep("fetch image", {
|
|
66
|
+
* args: { imageKey: v.string() },
|
|
67
|
+
* returns: v.object({ data: v.bytes() }),
|
|
68
|
+
* handler: async (ctx, { imageKey }) => {
|
|
69
|
+
* const object = await (ctx.env.BUCKET as R2Bucket).get(imageKey);
|
|
70
|
+
* return { data: new Uint8Array(await object!.arrayBuffer()) };
|
|
71
|
+
* },
|
|
72
|
+
* rollback: async (ctx) => {
|
|
73
|
+
* await (ctx.env.BUCKET as R2Bucket).delete(`tmp/${ctx.args.imageKey}`);
|
|
74
|
+
* },
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* Then, inside a `defineWorkflow` handler:
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* const { data } = await ctx.runStep(fetchImage, { imageKey: ctx.params.imageKey });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
53
84
|
declare const defineStep: <A extends StepArgsValidator, Result>(name: string, config: StepConfig<A, Result>) => StepDefinition<A, Result>;
|
|
54
85
|
/** True when a value is a `defineStep` result (the runtime brand check). */
|
|
55
86
|
declare const isStepDefinition: (value: unknown) => value is StepDefinition;
|
|
56
87
|
/**
|
|
57
|
-
* The generated `WorkflowEntrypoint` class name for a `lunora/workflows.ts`
|
|
58
|
-
* export: `orderPipeline` → `OrderPipelineWorkflow`. wrangler's
|
|
59
|
-
* `workflows[].class_name` references it, so codegen and the config layer MUST
|
|
60
|
-
* derive it identically — always via this helper.
|
|
61
|
-
*/
|
|
88
|
+
* The generated `WorkflowEntrypoint` class name for a `lunora/workflows.ts`
|
|
89
|
+
* export: `orderPipeline` → `OrderPipelineWorkflow`. wrangler's
|
|
90
|
+
* `workflows[].class_name` references it, so codegen and the config layer MUST
|
|
91
|
+
* derive it identically — always via this helper.
|
|
92
|
+
*/
|
|
62
93
|
declare const workflowClassName: (exportName: string) => string;
|
|
63
94
|
/**
|
|
64
|
-
* The wrangler binding name for a workflow export: `orderPipeline` →
|
|
65
|
-
* `WORKFLOW_ORDER_PIPELINE`, `etl` → `WORKFLOW_ETL`. The `WORKFLOW_` prefix
|
|
66
|
-
* namespaces these away from `SHARD`/`SESSION`/`SCHEDULER`/`CONTAINER_*` so a
|
|
67
|
-
* workflow export can never collide with the built-in bindings.
|
|
68
|
-
*/
|
|
95
|
+
* The wrangler binding name for a workflow export: `orderPipeline` →
|
|
96
|
+
* `WORKFLOW_ORDER_PIPELINE`, `etl` → `WORKFLOW_ETL`. The `WORKFLOW_` prefix
|
|
97
|
+
* namespaces these away from `SHARD`/`SESSION`/`SCHEDULER`/`CONTAINER_*` so a
|
|
98
|
+
* workflow export can never collide with the built-in bindings.
|
|
99
|
+
*/
|
|
69
100
|
declare const workflowBindingName: (exportName: string) => string;
|
|
70
101
|
/**
|
|
71
|
-
* The stable workflow name wrangler registers (`workflows[].name`):
|
|
72
|
-
* `orderPipeline` → `order-pipeline`. Used as the deployed workflow's
|
|
73
|
-
* identifier when no explicit `name` override is given.
|
|
74
|
-
*/
|
|
102
|
+
* The stable workflow name wrangler registers (`workflows[].name`):
|
|
103
|
+
* `orderPipeline` → `order-pipeline`. Used as the deployed workflow's
|
|
104
|
+
* identifier when no explicit `name` override is given.
|
|
105
|
+
*/
|
|
75
106
|
declare const workflowDefaultName: (exportName: string) => string;
|
|
76
107
|
/**
|
|
77
|
-
* Declare a durable workflow deployed alongside the app. Pure validation +
|
|
78
|
-
* branding: codegen discovers the export, emits the `WorkflowEntrypoint`
|
|
79
|
-
* subclass (`_generated/workflows.ts`), and wires the typed `ctx.workflows`
|
|
80
|
-
* handle; the config layer reconciles the wrangler `workflows[]` entry from the
|
|
81
|
-
* same definition.
|
|
82
|
-
*
|
|
83
|
-
* ```ts
|
|
84
|
-
* // lunora/workflows.ts
|
|
85
|
-
* import { defineWorkflow } from "@lunora/workflow";
|
|
86
|
-
* import { api } from "./_generated/api";
|
|
87
|
-
*
|
|
88
|
-
* export const orderPipeline = defineWorkflow
|
|
89
|
-
* handler: async (ctx) => {
|
|
90
|
-
* const order = await ctx.step.do("load", () => ctx.run(api.orders.get, { id: ctx.params.orderId }));
|
|
91
|
-
* await ctx.step.sleep("cool-off", "1 minute");
|
|
92
|
-
* await ctx.step.do("charge", () => ctx.run(api.payments.charge, { orderId: ctx.params.orderId }));
|
|
93
|
-
* return order;
|
|
94
|
-
* },
|
|
95
|
-
* });
|
|
96
|
-
* ```
|
|
97
|
-
*/
|
|
108
|
+
* Declare a durable workflow deployed alongside the app. Pure validation +
|
|
109
|
+
* branding: codegen discovers the export, emits the `WorkflowEntrypoint`
|
|
110
|
+
* subclass (`_generated/workflows.ts`), and wires the typed `ctx.workflows`
|
|
111
|
+
* handle; the config layer reconciles the wrangler `workflows[]` entry from the
|
|
112
|
+
* same definition.
|
|
113
|
+
*
|
|
114
|
+
* ```ts
|
|
115
|
+
* // lunora/workflows.ts
|
|
116
|
+
* import { defineWorkflow } from "@lunora/workflow";
|
|
117
|
+
* import { api } from "./_generated/api";
|
|
118
|
+
*
|
|
119
|
+
* export const orderPipeline = defineWorkflow<{ orderId: string }>({
|
|
120
|
+
* handler: async (ctx) => {
|
|
121
|
+
* const order = await ctx.step.do("load", () => ctx.run(api.orders.get, { id: ctx.params.orderId }));
|
|
122
|
+
* await ctx.step.sleep("cool-off", "1 minute");
|
|
123
|
+
* await ctx.step.do("charge", () => ctx.run(api.payments.charge, { orderId: ctx.params.orderId }));
|
|
124
|
+
* return order;
|
|
125
|
+
* },
|
|
126
|
+
* });
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
98
129
|
declare const defineWorkflow: <Params = Record<string, unknown>, Output = unknown>(config: WorkflowConfig<Params, Output>) => WorkflowDefinition<Params, Output>;
|
|
99
130
|
/** True when a value is a `defineWorkflow` result (the runtime brand check). */
|
|
100
131
|
declare const isWorkflowDefinition: (value: unknown) => value is WorkflowDefinition;
|
|
101
132
|
/**
|
|
102
|
-
* Throw from a workflow step (or handler) to fail the instance immediately
|
|
103
|
-
* **without** retrying — the portable mirror of `cloudflare:workflows`'
|
|
104
|
-
* `NonRetryableError`. Importable from Node, so workflow code stays unit-testable.
|
|
105
|
-
*
|
|
106
|
-
* ```ts
|
|
107
|
-
* import { NonRetryableError } from "@lunora/workflow";
|
|
108
|
-
*
|
|
109
|
-
* if (order.status === "cancelled") {
|
|
110
|
-
* throw new NonRetryableError("order already cancelled — no point retrying");
|
|
111
|
-
* }
|
|
112
|
-
* ```
|
|
113
|
-
*/
|
|
133
|
+
* Throw from a workflow step (or handler) to fail the instance immediately
|
|
134
|
+
* **without** retrying — the portable mirror of `cloudflare:workflows`'
|
|
135
|
+
* `NonRetryableError`. Importable from Node, so workflow code stays unit-testable.
|
|
136
|
+
*
|
|
137
|
+
* ```ts
|
|
138
|
+
* import { NonRetryableError } from "@lunora/workflow";
|
|
139
|
+
*
|
|
140
|
+
* if (order.status === "cancelled") {
|
|
141
|
+
* throw new NonRetryableError("order already cancelled — no point retrying");
|
|
142
|
+
* }
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
114
145
|
declare class NonRetryableError extends Error {
|
|
115
146
|
constructor(message: string, name?: string);
|
|
116
147
|
}
|
|
@@ -119,33 +150,31 @@ declare const isNonRetryableError: (value: unknown) => value is NonRetryableErro
|
|
|
119
150
|
/** Constructor shape of `cloudflare:workflows`' native `NonRetryableError`. */
|
|
120
151
|
type NativeNonRetryableErrorConstructor = new (message: string, name?: string) => Error;
|
|
121
152
|
/**
|
|
122
|
-
* Rebuild a portable {@link NonRetryableError} as the native Cloudflare one,
|
|
123
|
-
* preserving its `name`, `message`, `cause`, and `stack`. Used at the `src/do`
|
|
124
|
-
* boundary where the native constructor is available; everywhere else the
|
|
125
|
-
* portable error is thrown unchanged (and still honored by name).
|
|
126
|
-
*/
|
|
153
|
+
* Rebuild a portable {@link NonRetryableError} as the native Cloudflare one,
|
|
154
|
+
* preserving its `name`, `message`, `cause`, and `stack`. Used at the `src/do`
|
|
155
|
+
* boundary where the native constructor is available; everywhere else the
|
|
156
|
+
* portable error is thrown unchanged (and still honored by name).
|
|
157
|
+
*/
|
|
127
158
|
declare const toNativeNonRetryableError: (error: NonRetryableError, NativeNonRetryableError: NativeNonRetryableErrorConstructor) => Error;
|
|
128
159
|
/**
|
|
129
|
-
* If `error` is a portable {@link NonRetryableError} and a native constructor is
|
|
130
|
-
* available, rethrow it as the native error; otherwise rethrow `error` as-is.
|
|
131
|
-
* Always throws — the `never` return lets callers `return convertNonRetryableError(...)`.
|
|
132
|
-
*/
|
|
160
|
+
* If `error` is a portable {@link NonRetryableError} and a native constructor is
|
|
161
|
+
* available, rethrow it as the native error; otherwise rethrow `error` as-is.
|
|
162
|
+
* Always throws — the `never` return lets callers `return convertNonRetryableError(...)`.
|
|
163
|
+
*/
|
|
133
164
|
declare const convertNonRetryableError: (error: unknown, NativeNonRetryableError: NativeNonRetryableErrorConstructor | undefined) => never;
|
|
134
165
|
/** Hard cap on branches per `ctx.parallel` call — auto-scale, never silently spawn unbounded DOs. */
|
|
135
166
|
declare const MAX_BRANCHES = 100;
|
|
136
|
-
/** The params key the parent injects so a child knows to signal completion back. Stripped before the user handler sees `ctx.params`. */
|
|
137
|
-
|
|
138
167
|
/**
|
|
139
|
-
* Build a single fan-out branch: a declared child workflow referenced by its
|
|
140
|
-
* `lunora/workflows.ts` export name, plus the params it is created with. Pass the
|
|
141
|
-
* output type as the generic argument so `ctx.parallel(...)` infers the result
|
|
142
|
-
* tuple — e.g. `branch("imageTag", { key })` typed as `branch` of `{ tags }`.
|
|
143
|
-
*/
|
|
168
|
+
* Build a single fan-out branch: a declared child workflow referenced by its
|
|
169
|
+
* `lunora/workflows.ts` export name, plus the params it is created with. Pass the
|
|
170
|
+
* output type as the generic argument so `ctx.parallel(...)` infers the result
|
|
171
|
+
* tuple — e.g. `branch("imageTag", { key })` typed as `branch` of `{ tags }`.
|
|
172
|
+
*/
|
|
144
173
|
declare const branch: <Output = unknown>(workflow: string, params?: Record<string, unknown>, options?: {
|
|
174
|
+
compensateWith?: string;
|
|
145
175
|
id?: string;
|
|
146
176
|
timeout?: number | string;
|
|
147
177
|
}) => WorkflowBranch<Output>;
|
|
148
|
-
/** Build the success outcome a completed branch reports to its parent. */
|
|
149
178
|
/** The lifecycle mutations the REST API exposes via `PATCH .../instances/{id}`. */
|
|
150
179
|
type WorkflowInstanceAction = "pause" | "resume" | "terminate";
|
|
151
180
|
/** Configuration for a {@link WorkflowsRestClient}. */
|
|
@@ -193,8 +222,7 @@ interface WorkflowInstancePage {
|
|
|
193
222
|
totalCount?: number;
|
|
194
223
|
}
|
|
195
224
|
/** Thrown when the REST API responds non-2xx or `success: false`; carries the status plus body for the caller to surface. */
|
|
196
|
-
declare class WorkflowsRestError extends
|
|
197
|
-
readonly status: number;
|
|
225
|
+
declare class WorkflowsRestError extends LunoraError {
|
|
198
226
|
constructor(status: number, body: string);
|
|
199
227
|
}
|
|
200
228
|
/** The observe client: list instances, read one instance's steps, and (with Edit scope) mutate its status. */
|
|
@@ -218,11 +246,11 @@ interface WorkflowsRestClient {
|
|
|
218
246
|
}>;
|
|
219
247
|
}
|
|
220
248
|
/**
|
|
221
|
-
* Build a {@link WorkflowsRestClient}. Each call hits the account-scoped REST
|
|
222
|
-
* endpoint with the bearer token, unwraps Cloudflare's
|
|
223
|
-
* `{ success, errors, result, result_info }` envelope, and normalizes the
|
|
224
|
-
* snake_case payload into the camelCase shapes the studio renders.
|
|
225
|
-
*/
|
|
249
|
+
* Build a {@link WorkflowsRestClient}. Each call hits the account-scoped REST
|
|
250
|
+
* endpoint with the bearer token, unwraps Cloudflare's
|
|
251
|
+
* `{ success, errors, result, result_info }` envelope, and normalizes the
|
|
252
|
+
* snake_case payload into the camelCase shapes the studio renders.
|
|
253
|
+
*/
|
|
226
254
|
declare const createWorkflowsRestClient: (config: WorkflowsRestConfig) => WorkflowsRestClient;
|
|
227
255
|
interface RunContextOptions<Params> {
|
|
228
256
|
env: Record<string, unknown>;
|
|
@@ -236,12 +264,12 @@ interface RunContextOptions<Params> {
|
|
|
236
264
|
/** Assemble the {@link WorkflowRunContext} passed to a `defineWorkflow` handler. */
|
|
237
265
|
declare const createWorkflowRunContext: <Params = Record<string, unknown>>(options: RunContextOptions<Params>) => WorkflowRunContext<Params>;
|
|
238
266
|
/**
|
|
239
|
-
* Validate a step's args through its validator map, prefixing any
|
|
240
|
-
* `ValidationError` with `step args
|
|
241
|
-
* offending field. Delegates to `@lunora/values`' shared {@link parseValidatorMap}
|
|
242
|
-
* — the same parser the procedure builder and HTTP routes use — so the
|
|
243
|
-
* optional-skip and error-prefix semantics stay in lockstep across the framework.
|
|
244
|
-
*/
|
|
267
|
+
* Validate a step's args through its validator map, prefixing any
|
|
268
|
+
* `ValidationError` with `step args.<key>` so the failure points at the
|
|
269
|
+
* offending field. Delegates to `@lunora/values`' shared {@link parseValidatorMap}
|
|
270
|
+
* — the same parser the procedure builder and HTTP routes use — so the
|
|
271
|
+
* optional-skip and error-prefix semantics stay in lockstep across the framework.
|
|
272
|
+
*/
|
|
245
273
|
declare const validateStepArgs: (validators: StepArgsValidator, source: Record<string, unknown>) => Record<string, unknown>;
|
|
246
274
|
/** Dependencies needed to run a step: the native step API plus the workflow's env / runner / logger. */
|
|
247
275
|
interface RunStepDeps {
|
|
@@ -257,10 +285,29 @@ interface RunStepDeps {
|
|
|
257
285
|
step: WorkflowStepLike;
|
|
258
286
|
}
|
|
259
287
|
/**
|
|
260
|
-
* Build the `ctx.runStep` function bound to one workflow invocation. Each call
|
|
261
|
-
* runs the step through `step.do(...)`: validate args → run body → validate
|
|
262
|
-
* result (when `returns` is declared), with any portable `NonRetryableError`
|
|
263
|
-
* converted to the native one and any declared rollback forwarded to Cloudflare.
|
|
264
|
-
*/
|
|
288
|
+
* Build the `ctx.runStep` function bound to one workflow invocation. Each call
|
|
289
|
+
* runs the step through `step.do(...)`: validate args → run body → validate
|
|
290
|
+
* result (when `returns` is declared), with any portable `NonRetryableError`
|
|
291
|
+
* converted to the native one and any declared rollback forwarded to Cloudflare.
|
|
292
|
+
*/
|
|
265
293
|
declare const createRunStep: (deps: RunStepDeps) => WorkflowRunStepFunction;
|
|
266
|
-
|
|
294
|
+
/** Dependencies one workflow invocation's `ctx.waitForEvent` closes over. */
|
|
295
|
+
interface WaitForEventDeps {
|
|
296
|
+
/** Native `cloudflare:workflows` `NonRetryableError` constructor — injected by `src/do`; absent in Node tests. */
|
|
297
|
+
nonRetryableErrorClass?: NativeNonRetryableErrorConstructor;
|
|
298
|
+
/** The native Cloudflare durable-step API. */
|
|
299
|
+
step: WorkflowStepLike;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Build `ctx.waitForEvent` for one workflow invocation.
|
|
303
|
+
*
|
|
304
|
+
* Every failure here is **non-retryable**. A malformed definition or a reserved
|
|
305
|
+
* step name is a deterministic programmer error, and a payload that fails the
|
|
306
|
+
* validator has already consumed the event — replaying the wait cannot produce a
|
|
307
|
+
* different value, it can only hibernate the instance until its timeout. Each is
|
|
308
|
+
* raised through the shared {@link raiseNonRetryable}, the same classification path
|
|
309
|
+
* `ctx.runStep` uses, so the native error reaches Cloudflare and the instance fails
|
|
310
|
+
* fast.
|
|
311
|
+
*/
|
|
312
|
+
declare const createWaitForEvent: (deps: WaitForEventDeps) => WorkflowWaitForEventFunction;
|
|
313
|
+
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, isNonRetryableError, isStepDefinition, isWorkflowDefinition, isWorkflowEventDefinition, toNativeNonRetryableError, validateStepArgs, workflowBindingName, workflowClassName, workflowDefaultName };
|