@lunora/workflow 1.0.0-alpha.4 → 1.0.0-alpha.6

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.
@@ -1,5 +1,5 @@
1
1
  import { WorkflowEntrypoint, WorkflowEvent, WorkflowStep } from 'cloudflare:workers';
2
- import { W as WorkflowDefinition } from "../packem_shared/types.d-Fdeu2P2C.mjs";
2
+ import { W as WorkflowDefinition } from "../packem_shared/types.d-C9W6rEWv.mjs";
3
3
  import '@lunora/values';
4
4
  /**
5
5
  * Base class for the generated `WorkflowEntrypoint` classes. Applies a
@@ -1,5 +1,5 @@
1
1
  import { WorkflowEntrypoint, WorkflowEvent, WorkflowStep } from 'cloudflare:workers';
2
- import { W as WorkflowDefinition } from "../packem_shared/types.d-Fdeu2P2C.js";
2
+ import { W as WorkflowDefinition } from "../packem_shared/types.d-C9W6rEWv.js";
3
3
  import '@lunora/values';
4
4
  /**
5
5
  * Base class for the generated `WorkflowEntrypoint` classes. Applies a
package/dist/do/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { WorkflowEntrypoint } from 'cloudflare:workers';
2
2
  import { NonRetryableError } from 'cloudflare:workflows';
3
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';
4
+ import { stripBranchMarker, signalBranchParent, extractBranchMarker, errorOutcome, okOutcome } from '../packem_shared/MAX_BRANCHES-D6cQabJ1.mjs';
5
+ import { createWorkflowRunContext } from '../packem_shared/createWorkflowRunContext-C09mSbgk.mjs';
6
6
 
7
7
  class LunoraWorkflow extends WorkflowEntrypoint {
8
8
  /** The `lunora/workflows.ts` export name, for log correlation. */
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
- import { a as Workflows, L as LunoraWorkflowsOptions, S as StepArgsValidator, b as StepConfig, c as StepDefinition, d as WorkflowConfig, W as WorkflowDefinition, e as WorkflowBranch, f as WorkflowInstanceStatus, g as WorkflowEventLike, h as WorkflowStepLike, i as WorkflowRunContext, j as WorkflowLogger, k as WorkflowRunFunction, l as WorkflowRunStepFunction } from "./packem_shared/types.d-Fdeu2P2C.mjs";
2
- export type { A as ArgsOf, F as FunctionReference, I as InferStepArgs, R as RunFunctionOptions, m as RunStepOptions, n as StepHandler, o as StepRollbackContext, p as StepRollbackHandler, q as StepRunContext, r as WorkflowBindingLike, s as WorkflowBranchOutputs, t as WorkflowCreateOptions, u as WorkflowHandle, v as WorkflowHandler, w as WorkflowInstanceLike, x as WorkflowParallelFunction, y as WorkflowRollbackContextLike, z as WorkflowRollbackHandlerLike, B as WorkflowSpawnFunction, C as WorkflowSpawnOptions, D as WorkflowStatusResult, E as WorkflowStepConfigLike, G as WorkflowStepContextLike, H as WorkflowStepRollbackOptionsLike } from "./packem_shared/types.d-Fdeu2P2C.mjs";
1
+ import { a as Workflows, L as LunoraWorkflowsOptions, S as StepArgsValidator, b as StepConfig, c as StepDefinition, d as WorkflowConfig, W as WorkflowDefinition, e as WorkflowBranch, f as WorkflowInstanceStatus, g as WorkflowEventLike, h as WorkflowStepLike, i as WorkflowRunContext, j as WorkflowLogger, k as WorkflowRunFunction, l as WorkflowRunStepFunction } from "./packem_shared/types.d-C9W6rEWv.mjs";
2
+ export type { A as ArgsOf, B as BranchCompensationParams, F as FunctionReference, I as InferStepArgs, R as RunFunctionOptions, m as RunStepOptions, n as StepHandler, o as StepRollbackContext, p as StepRollbackHandler, q as StepRunContext, r as WorkflowBindingLike, s as WorkflowBranchOutputs, t as WorkflowCreateOptions, u as WorkflowHandle, v as WorkflowHandler, w as WorkflowInstanceLike, x as WorkflowParallelFunction, y as WorkflowRollbackContextLike, z as WorkflowRollbackHandlerLike, C as WorkflowSpawnFunction, D as WorkflowSpawnOptions, E as WorkflowStatusResult, G as WorkflowStepConfigLike, H as WorkflowStepContextLike, J as WorkflowStepRollbackOptionsLike } from "./packem_shared/types.d-C9W6rEWv.mjs";
3
+ import { LunoraError } from '@lunora/errors';
3
4
  import '@lunora/values';
4
5
  /** Wiring info for one declared workflow, emitted by codegen into the generated shard. */
5
6
  interface WorkflowBindingSpec {
@@ -142,6 +143,7 @@ declare const MAX_BRANCHES = 100;
142
143
  * tuple — e.g. `branch("imageTag", { key })` typed as `branch` of `{ tags }`.
143
144
  */
144
145
  declare const branch: <Output = unknown>(workflow: string, params?: Record<string, unknown>, options?: {
146
+ compensateWith?: string;
145
147
  id?: string;
146
148
  timeout?: number | string;
147
149
  }) => WorkflowBranch<Output>;
@@ -193,8 +195,7 @@ interface WorkflowInstancePage {
193
195
  totalCount?: number;
194
196
  }
195
197
  /** 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 Error {
197
- readonly status: number;
198
+ declare class WorkflowsRestError extends LunoraError {
198
199
  constructor(status: number, body: string);
199
200
  }
200
201
  /** The observe client: list instances, read one instance's steps, and (with Edit scope) mutate its status. */
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { a as Workflows, L as LunoraWorkflowsOptions, S as StepArgsValidator, b as StepConfig, c as StepDefinition, d as WorkflowConfig, W as WorkflowDefinition, e as WorkflowBranch, f as WorkflowInstanceStatus, g as WorkflowEventLike, h as WorkflowStepLike, i as WorkflowRunContext, j as WorkflowLogger, k as WorkflowRunFunction, l as WorkflowRunStepFunction } from "./packem_shared/types.d-Fdeu2P2C.js";
2
- export type { A as ArgsOf, F as FunctionReference, I as InferStepArgs, R as RunFunctionOptions, m as RunStepOptions, n as StepHandler, o as StepRollbackContext, p as StepRollbackHandler, q as StepRunContext, r as WorkflowBindingLike, s as WorkflowBranchOutputs, t as WorkflowCreateOptions, u as WorkflowHandle, v as WorkflowHandler, w as WorkflowInstanceLike, x as WorkflowParallelFunction, y as WorkflowRollbackContextLike, z as WorkflowRollbackHandlerLike, B as WorkflowSpawnFunction, C as WorkflowSpawnOptions, D as WorkflowStatusResult, E as WorkflowStepConfigLike, G as WorkflowStepContextLike, H as WorkflowStepRollbackOptionsLike } from "./packem_shared/types.d-Fdeu2P2C.js";
1
+ import { a as Workflows, L as LunoraWorkflowsOptions, S as StepArgsValidator, b as StepConfig, c as StepDefinition, d as WorkflowConfig, W as WorkflowDefinition, e as WorkflowBranch, f as WorkflowInstanceStatus, g as WorkflowEventLike, h as WorkflowStepLike, i as WorkflowRunContext, j as WorkflowLogger, k as WorkflowRunFunction, l as WorkflowRunStepFunction } from "./packem_shared/types.d-C9W6rEWv.js";
2
+ export type { A as ArgsOf, B as BranchCompensationParams, F as FunctionReference, I as InferStepArgs, R as RunFunctionOptions, m as RunStepOptions, n as StepHandler, o as StepRollbackContext, p as StepRollbackHandler, q as StepRunContext, r as WorkflowBindingLike, s as WorkflowBranchOutputs, t as WorkflowCreateOptions, u as WorkflowHandle, v as WorkflowHandler, w as WorkflowInstanceLike, x as WorkflowParallelFunction, y as WorkflowRollbackContextLike, z as WorkflowRollbackHandlerLike, C as WorkflowSpawnFunction, D as WorkflowSpawnOptions, E as WorkflowStatusResult, G as WorkflowStepConfigLike, H as WorkflowStepContextLike, J as WorkflowStepRollbackOptionsLike } from "./packem_shared/types.d-C9W6rEWv.js";
3
+ import { LunoraError } from '@lunora/errors';
3
4
  import '@lunora/values';
4
5
  /** Wiring info for one declared workflow, emitted by codegen into the generated shard. */
5
6
  interface WorkflowBindingSpec {
@@ -142,6 +143,7 @@ declare const MAX_BRANCHES = 100;
142
143
  * tuple — e.g. `branch("imageTag", { key })` typed as `branch` of `{ tags }`.
143
144
  */
144
145
  declare const branch: <Output = unknown>(workflow: string, params?: Record<string, unknown>, options?: {
146
+ compensateWith?: string;
145
147
  id?: string;
146
148
  timeout?: number | string;
147
149
  }) => WorkflowBranch<Output>;
@@ -193,8 +195,7 @@ interface WorkflowInstancePage {
193
195
  totalCount?: number;
194
196
  }
195
197
  /** 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 Error {
197
- readonly status: number;
198
+ declare class WorkflowsRestError extends LunoraError {
198
199
  constructor(status: number, body: string);
199
200
  }
200
201
  /** The observe client: list instances, read one instance's steps, and (with Edit scope) mutate its status. */
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- export { createWorkflowContext } from './packem_shared/createWorkflowContext-D6thzmlF.mjs';
2
- export { default as createWorkflows } from './packem_shared/createWorkflows-BoSYVIXg.mjs';
1
+ export { createWorkflowContext } from './packem_shared/createWorkflowContext-DfSgBq5I.mjs';
2
+ export { default as createWorkflows } from './packem_shared/createWorkflows-BC1Mwjwe.mjs';
3
3
  export { defineStep, isStepDefinition } from './packem_shared/defineStep-DJQtLw7g.mjs';
4
4
  export { defineWorkflow, isWorkflowDefinition, workflowBindingName, workflowClassName, workflowDefaultName } from './packem_shared/defineWorkflow-DbUC-oCN.mjs';
5
5
  export { NonRetryableError, convertNonRetryableError, isNonRetryableError, toNativeNonRetryableError } from './packem_shared/NonRetryableError-Dn2dTyBS.mjs';
6
- export { MAX_BRANCHES, branch } from './packem_shared/MAX_BRANCHES-C9MJIFii.mjs';
7
- export { WorkflowsRestError, createWorkflowsRestClient } from './packem_shared/WorkflowsRestError-b06i7K5j.mjs';
8
- export { createWorkflowRunContext } from './packem_shared/createWorkflowRunContext-BsMyGuMR.mjs';
6
+ export { MAX_BRANCHES, branch } from './packem_shared/MAX_BRANCHES-D6cQabJ1.mjs';
7
+ export { WorkflowsRestError, createWorkflowsRestClient } from './packem_shared/WorkflowsRestError-zmjOxTR1.mjs';
8
+ export { createWorkflowRunContext } from './packem_shared/createWorkflowRunContext-C09mSbgk.mjs';
9
9
  export { createRunStep, validateStepArgs } from './packem_shared/createRunStep-8jOXxP2o.mjs';
@@ -5,9 +5,10 @@ const BRANCH_MARKER_KEY = "__lunoraBranch";
5
5
  const SPAWN_STEP_PREFIX = "lunora:spawn:";
6
6
  const AWAIT_STEP_PREFIX = "lunora:await:";
7
7
  const SIGNAL_STEP_PREFIX = "lunora:signal:";
8
+ const COMPENSATE_STEP_PREFIX = "lunora:compensate:";
8
9
  const BRANCH_EVENT_PREFIX = "lunora:branch:";
9
10
  const branch = (workflow, params, options) => {
10
- return { id: options?.id, params, timeout: options?.timeout, workflow };
11
+ return { compensateWith: options?.compensateWith, id: options?.id, params, timeout: options?.timeout, workflow };
11
12
  };
12
13
  const serializeError = (error) => {
13
14
  if (error instanceof Error) {
@@ -21,6 +22,26 @@ const okOutcome = (value) => {
21
22
  const errorOutcome = (error) => {
22
23
  return { error: serializeError(error), status: "error" };
23
24
  };
25
+ const compensateCompleted = async (deps, completed, error) => {
26
+ for (let cursor = completed.length - 1; cursor >= 0; cursor -= 1) {
27
+ const done = completed[cursor];
28
+ const compensateWith = done?.plan.item.compensateWith;
29
+ if (done === void 0 || compensateWith === void 0) {
30
+ continue;
31
+ }
32
+ await deps.step.do(`${COMPENSATE_STEP_PREFIX}${done.plan.childId}`, async () => {
33
+ const compensateId = `${done.plan.childId}:compensate`;
34
+ const compensationParams = {
35
+ branch: done.plan.item.workflow,
36
+ error,
37
+ index: done.plan.index,
38
+ output: done.output
39
+ };
40
+ await deps.resolveBinding(compensateWith).create({ id: compensateId, params: compensationParams });
41
+ return compensateId;
42
+ });
43
+ }
44
+ };
24
45
  const createParallel = (deps) => {
25
46
  const run = async (branches) => {
26
47
  if (branches.length === 0) {
@@ -46,6 +67,7 @@ const createParallel = (deps) => {
46
67
  )
47
68
  );
48
69
  const results = [];
70
+ const completed = [];
49
71
  for (const plan of planned) {
50
72
  const event = await deps.step.waitForEvent(`${AWAIT_STEP_PREFIX}${plan.childId}`, {
51
73
  timeout: plan.item.timeout,
@@ -53,8 +75,10 @@ const createParallel = (deps) => {
53
75
  });
54
76
  const outcome = event.payload;
55
77
  if (outcome.status === "error") {
78
+ await compensateCompleted(deps, completed, outcome.error);
56
79
  throw new NonRetryableError(`ctx.parallel: branch "${plan.item.workflow}" (#${String(plan.index)}) failed: ${outcome.error.message}`);
57
80
  }
81
+ completed.push({ output: outcome.value, plan });
58
82
  results.push(outcome.value);
59
83
  }
60
84
  return results;
@@ -1,3 +1,5 @@
1
+ import { LunoraError } from '@lunora/errors';
2
+
1
3
  const API_BASE = "https://api.cloudflare.com/client/v4/accounts";
2
4
  const KNOWN_STATUSES = {
3
5
  complete: true,
@@ -41,12 +43,9 @@ const toStep = (raw) => {
41
43
  type: asString(raw["type"])
42
44
  };
43
45
  };
44
- class WorkflowsRestError extends Error {
45
- status;
46
+ class WorkflowsRestError extends LunoraError {
46
47
  constructor(status, body) {
47
- super(`Cloudflare Workflows REST API returned ${String(status)}: ${body}`);
48
- this.name = "WorkflowsRestError";
49
- this.status = status;
48
+ super("WORKFLOWS_REST_ERROR", `Cloudflare Workflows REST API returned ${String(status)}: ${body}`, { name: "WorkflowsRestError", status });
50
49
  }
51
50
  }
52
51
  const createWorkflowsRestClient = (config) => {
@@ -1,4 +1,4 @@
1
- import createWorkflows from './createWorkflows-BoSYVIXg.mjs';
1
+ import createWorkflows from './createWorkflows-BC1Mwjwe.mjs';
2
2
 
3
3
  const createWorkflowContext = (env, specs) => {
4
4
  const bindings = {};
@@ -1,5 +1,6 @@
1
+ import { LunoraError } from '@lunora/errors';
1
2
  import { workflowBindingName } from './defineWorkflow-DbUC-oCN.mjs';
2
- import { createSpawn, createParallel } from './MAX_BRANCHES-C9MJIFii.mjs';
3
+ import { createSpawn, createParallel } from './MAX_BRANCHES-D6cQabJ1.mjs';
3
4
  import { createRunStep } from './createRunStep-8jOXxP2o.mjs';
4
5
 
5
6
  const createDispatchLogger = (prefix) => {
@@ -37,11 +38,11 @@ const createDispatchRunner = (options) => {
37
38
  }
38
39
  const origin = options.env.LUNORA_ORIGIN_URL;
39
40
  if (typeof origin !== "string" || origin.length === 0) {
40
- throw new Error(`${label}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);
41
+ throw new LunoraError("INTERNAL", `${label}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);
41
42
  }
42
43
  const token = options.env.LUNORA_ADMIN_TOKEN;
43
44
  if (typeof token !== "string" || token.length === 0) {
44
- throw new Error(`${label}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);
45
+ throw new LunoraError("INTERNAL", `${label}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);
45
46
  }
46
47
  const url = `${trimTrailingSlashes(origin)}${SCHEDULER_DISPATCH_PATH}`;
47
48
  const response = await fetchImpl(url, {
@@ -50,7 +51,7 @@ const createDispatchRunner = (options) => {
50
51
  method: "POST"
51
52
  });
52
53
  if (!response.ok) {
53
- throw new Error(`${label}: function dispatch failed (${String(response.status)}): ${await response.text()}`);
54
+ throw new LunoraError("INTERNAL", `${label}: function dispatch failed (${String(response.status)}): ${await response.text()}`);
54
55
  }
55
56
  const text = await response.text();
56
57
  if (text.length === 0) {
@@ -71,7 +72,8 @@ const createWorkflowRunContext = (options) => {
71
72
  const bindingName = workflowBindingName(workflow);
72
73
  const binding = options.env[bindingName];
73
74
  if (!binding || typeof binding.create !== "function" || typeof binding.get !== "function") {
74
- throw new Error(
75
+ throw new LunoraError(
76
+ "INTERNAL",
75
77
  `@lunora/workflow: cannot spawn child workflow "${workflow}" — no Workflow binding "${bindingName}" on env (is it declared in lunora/workflows.ts?)`
76
78
  );
77
79
  }
@@ -1,3 +1,5 @@
1
+ import { LunoraError } from '@lunora/errors';
2
+
1
3
  const handleFor = (binding) => {
2
4
  return {
3
5
  create: async (options) => binding.create(options),
@@ -13,7 +15,7 @@ const createWorkflows = (options) => {
13
15
  if (binding === void 0) {
14
16
  const known = Object.keys(bindings);
15
17
  const suffix = known.length === 0 ? "no workflows are declared" : `known workflows: ${known.join(", ")}`;
16
- throw new Error(`@lunora/workflow: no workflow named "${name}" (${suffix})`);
18
+ throw new LunoraError("INTERNAL", `@lunora/workflow: no workflow named "${name}" (${suffix})`);
17
19
  }
18
20
  return handleFor(binding);
19
21
  }
@@ -272,6 +272,16 @@ type WorkflowRunStepFunction = <A extends StepArgsValidator, Result>(step: StepD
272
272
  interface WorkflowBranch<Output = unknown> {
273
273
  /** Phantom marker for the branch output type — never present at runtime. */
274
274
  readonly __output?: Output;
275
+ /**
276
+ * Optional group-saga compensation (plan 075 Phase 3): the `lunora/workflows.ts`
277
+ * export name of a workflow to run if a **sibling** branch in the same
278
+ * `ctx.parallel(...)` group fails **after** this branch has already completed.
279
+ * It is spawned fire-and-forget (a durable, replay-safe idempotent create) with
280
+ * {@link BranchCompensationParams} as its `ctx.params`. Omit for no
281
+ * compensation — a group where no branch sets this behaves exactly as a plain
282
+ * fan-out (fail-fast, no rollback).
283
+ */
284
+ readonly compensateWith?: string;
275
285
  /** Optional explicit child instance id (defaults to a deterministic parent-derived id). */
276
286
  readonly id?: string;
277
287
  /** The params the child instance is created with — surfaced as the child's `ctx.params`. */
@@ -281,6 +291,27 @@ interface WorkflowBranch<Output = unknown> {
281
291
  /** The `lunora/workflows.ts` export name of the child workflow to run. */
282
292
  readonly workflow: string;
283
293
  }
294
+ /**
295
+ * The `ctx.params` a group-saga compensation workflow (a branch's
296
+ * {@link WorkflowBranch.compensateWith}) receives when a sibling's failure rolls
297
+ * back the group. Everything is plain-serialisable — the compensation is an
298
+ * ordinary declared workflow, so it can `ctx.runStep(...)` its own undo logic.
299
+ */
300
+ interface BranchCompensationParams {
301
+ /** Index signature: this is a workflow `params` bag, so it is a valid `Record&lt;string, unknown>` payload. */
302
+ [key: string]: unknown;
303
+ /** The export name of the completed branch being compensated. */
304
+ branch: string;
305
+ /** The serialised error of the sibling branch whose failure triggered the group rollback. */
306
+ error: {
307
+ message: string;
308
+ name: string;
309
+ };
310
+ /** Declaration-order index of the completed branch being compensated. */
311
+ index: number;
312
+ /** The completed branch's output value — what it returned before the group failed. */
313
+ output?: unknown;
314
+ }
284
315
  /** Map a tuple of {@link WorkflowBranch}es to the tuple of their output types, preserving order. */
285
316
  type WorkflowBranchOutputs<B extends ReadonlyArray<WorkflowBranch>> = { -readonly [K in keyof B]: B[K] extends WorkflowBranch<infer Output> ? Output : never };
286
317
  /**
@@ -391,4 +422,4 @@ interface LunoraWorkflowsOptions {
391
422
  */
392
423
  bindings: Record<string, WorkflowBindingLike>;
393
424
  }
394
- export { ArgsOf as A, WorkflowSpawnFunction as B, WorkflowSpawnOptions as C, WorkflowStatusResult as D, WorkflowStepConfigLike as E, FunctionReference as F, WorkflowStepContextLike as G, WorkflowStepRollbackOptionsLike as H, InferStepArgs as I, LunoraWorkflowsOptions as L, RunFunctionOptions as R, StepArgsValidator as S, WorkflowDefinition as W, Workflows as a, StepConfig as b, StepDefinition as c, WorkflowConfig as d, WorkflowBranch as e, WorkflowInstanceStatus as f, WorkflowEventLike as g, WorkflowStepLike as h, WorkflowRunContext as i, WorkflowLogger as j, WorkflowRunFunction as k, WorkflowRunStepFunction as l, RunStepOptions as m, StepHandler as n, StepRollbackContext as o, StepRollbackHandler as p, StepRunContext as q, WorkflowBindingLike as r, WorkflowBranchOutputs as s, WorkflowCreateOptions as t, WorkflowHandle as u, WorkflowHandler as v, WorkflowInstanceLike as w, WorkflowParallelFunction as x, WorkflowRollbackContextLike as y, WorkflowRollbackHandlerLike as z };
425
+ export { ArgsOf as A, BranchCompensationParams as B, WorkflowSpawnFunction as C, WorkflowSpawnOptions as D, WorkflowStatusResult as E, FunctionReference as F, WorkflowStepConfigLike as G, WorkflowStepContextLike as H, InferStepArgs as I, WorkflowStepRollbackOptionsLike as J, LunoraWorkflowsOptions as L, RunFunctionOptions as R, StepArgsValidator as S, WorkflowDefinition as W, Workflows as a, StepConfig as b, StepDefinition as c, WorkflowConfig as d, WorkflowBranch as e, WorkflowInstanceStatus as f, WorkflowEventLike as g, WorkflowStepLike as h, WorkflowRunContext as i, WorkflowLogger as j, WorkflowRunFunction as k, WorkflowRunStepFunction as l, RunStepOptions as m, StepHandler as n, StepRollbackContext as o, StepRollbackHandler as p, StepRunContext as q, WorkflowBindingLike as r, WorkflowBranchOutputs as s, WorkflowCreateOptions as t, WorkflowHandle as u, WorkflowHandler as v, WorkflowInstanceLike as w, WorkflowParallelFunction as x, WorkflowRollbackContextLike as y, WorkflowRollbackHandlerLike as z };
@@ -272,6 +272,16 @@ type WorkflowRunStepFunction = <A extends StepArgsValidator, Result>(step: StepD
272
272
  interface WorkflowBranch<Output = unknown> {
273
273
  /** Phantom marker for the branch output type — never present at runtime. */
274
274
  readonly __output?: Output;
275
+ /**
276
+ * Optional group-saga compensation (plan 075 Phase 3): the `lunora/workflows.ts`
277
+ * export name of a workflow to run if a **sibling** branch in the same
278
+ * `ctx.parallel(...)` group fails **after** this branch has already completed.
279
+ * It is spawned fire-and-forget (a durable, replay-safe idempotent create) with
280
+ * {@link BranchCompensationParams} as its `ctx.params`. Omit for no
281
+ * compensation — a group where no branch sets this behaves exactly as a plain
282
+ * fan-out (fail-fast, no rollback).
283
+ */
284
+ readonly compensateWith?: string;
275
285
  /** Optional explicit child instance id (defaults to a deterministic parent-derived id). */
276
286
  readonly id?: string;
277
287
  /** The params the child instance is created with — surfaced as the child's `ctx.params`. */
@@ -281,6 +291,27 @@ interface WorkflowBranch<Output = unknown> {
281
291
  /** The `lunora/workflows.ts` export name of the child workflow to run. */
282
292
  readonly workflow: string;
283
293
  }
294
+ /**
295
+ * The `ctx.params` a group-saga compensation workflow (a branch's
296
+ * {@link WorkflowBranch.compensateWith}) receives when a sibling's failure rolls
297
+ * back the group. Everything is plain-serialisable — the compensation is an
298
+ * ordinary declared workflow, so it can `ctx.runStep(...)` its own undo logic.
299
+ */
300
+ interface BranchCompensationParams {
301
+ /** Index signature: this is a workflow `params` bag, so it is a valid `Record&lt;string, unknown>` payload. */
302
+ [key: string]: unknown;
303
+ /** The export name of the completed branch being compensated. */
304
+ branch: string;
305
+ /** The serialised error of the sibling branch whose failure triggered the group rollback. */
306
+ error: {
307
+ message: string;
308
+ name: string;
309
+ };
310
+ /** Declaration-order index of the completed branch being compensated. */
311
+ index: number;
312
+ /** The completed branch's output value — what it returned before the group failed. */
313
+ output?: unknown;
314
+ }
284
315
  /** Map a tuple of {@link WorkflowBranch}es to the tuple of their output types, preserving order. */
285
316
  type WorkflowBranchOutputs<B extends ReadonlyArray<WorkflowBranch>> = { -readonly [K in keyof B]: B[K] extends WorkflowBranch<infer Output> ? Output : never };
286
317
  /**
@@ -391,4 +422,4 @@ interface LunoraWorkflowsOptions {
391
422
  */
392
423
  bindings: Record<string, WorkflowBindingLike>;
393
424
  }
394
- export { ArgsOf as A, WorkflowSpawnFunction as B, WorkflowSpawnOptions as C, WorkflowStatusResult as D, WorkflowStepConfigLike as E, FunctionReference as F, WorkflowStepContextLike as G, WorkflowStepRollbackOptionsLike as H, InferStepArgs as I, LunoraWorkflowsOptions as L, RunFunctionOptions as R, StepArgsValidator as S, WorkflowDefinition as W, Workflows as a, StepConfig as b, StepDefinition as c, WorkflowConfig as d, WorkflowBranch as e, WorkflowInstanceStatus as f, WorkflowEventLike as g, WorkflowStepLike as h, WorkflowRunContext as i, WorkflowLogger as j, WorkflowRunFunction as k, WorkflowRunStepFunction as l, RunStepOptions as m, StepHandler as n, StepRollbackContext as o, StepRollbackHandler as p, StepRunContext as q, WorkflowBindingLike as r, WorkflowBranchOutputs as s, WorkflowCreateOptions as t, WorkflowHandle as u, WorkflowHandler as v, WorkflowInstanceLike as w, WorkflowParallelFunction as x, WorkflowRollbackContextLike as y, WorkflowRollbackHandlerLike as z };
425
+ export { ArgsOf as A, BranchCompensationParams as B, WorkflowSpawnFunction as C, WorkflowSpawnOptions as D, WorkflowStatusResult as E, FunctionReference as F, WorkflowStepConfigLike as G, WorkflowStepContextLike as H, InferStepArgs as I, WorkflowStepRollbackOptionsLike as J, LunoraWorkflowsOptions as L, RunFunctionOptions as R, StepArgsValidator as S, WorkflowDefinition as W, Workflows as a, StepConfig as b, StepDefinition as c, WorkflowConfig as d, WorkflowBranch as e, WorkflowInstanceStatus as f, WorkflowEventLike as g, WorkflowStepLike as h, WorkflowRunContext as i, WorkflowLogger as j, WorkflowRunFunction as k, WorkflowRunStepFunction as l, RunStepOptions as m, StepHandler as n, StepRollbackContext as o, StepRollbackHandler as p, StepRunContext as q, WorkflowBindingLike as r, WorkflowBranchOutputs as s, WorkflowCreateOptions as t, WorkflowHandle as u, WorkflowHandler as v, WorkflowInstanceLike as w, WorkflowParallelFunction as x, WorkflowRollbackContextLike as y, WorkflowRollbackHandlerLike as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/workflow",
3
- "version": "1.0.0-alpha.4",
3
+ "version": "1.0.0-alpha.6",
4
4
  "description": "Durable workflows for Lunora: defineWorkflow over Cloudflare Workflows, generated WorkflowEntrypoint classes, and the ctx.workflows surface",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -48,7 +48,8 @@
48
48
  "access": "public"
49
49
  },
50
50
  "dependencies": {
51
- "@lunora/values": "1.0.0-alpha.3"
51
+ "@lunora/errors": "1.0.0-alpha.1",
52
+ "@lunora/values": "1.0.0-alpha.4"
52
53
  },
53
54
  "engines": {
54
55
  "node": "^22.15.0 || >=24.11.0"