@voltro/workflow 0.33.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { A as e, C as t, D as n, E as r, F as i, M as a, N as o, O as s, P as c, S as l, _ as u, a as d, b as f, c as p, d as m, f as h, g, h as _, i as v, j as y, k as b, l as x, m as S, n as C, o as w, p as T, r as E, s as D, t as O, u as k, v as A, w as j, x as M, y as N } from "./primitives-Bp98_F5L.js";
2
- import { $ as P, A as F, B as I, C as L, D as R, E as z, F as B, G as V, H, I as U, J as W, K as G, L as K, M as q, N as J, O as Y, P as X, Q as Z, R as Q, S as $, T as ee, U as te, V as ne, W as re, X as ie, Y as ae, Z as oe, _ as se, a as ce, at as le, b as ue, c as de, ct as fe, d as pe, dt as me, et as he, f as ge, ft as _e, g as ve, h as ye, i as be, it as xe, j as Se, k as Ce, l as we, lt as Te, m as Ee, mt as De, n as Oe, nt as ke, o as Ae, ot as je, p as Me, pt as Ne, q as Pe, r as Fe, rt as Ie, s as Le, st as Re, t as ze, tt as Be, u as Ve, ut as He, v as Ue, w as We, x as Ge, y as Ke, z as qe } from "./src-CP61KZ9V.js";
3
- export { J as ADMISSIONS_TABLE, ue as CANCEL_ON_WATERMARK, t as CurrentWorkflowExecutionId, j as CurrentWorkflowRunId, Ge as DEFAULT_COLD_LOOKBACK_MS, Ue as DEFAULT_DRAIN_BATCH, $ as DEFAULT_EVENT_BATCH, X as DEFAULT_LEASE_MS, e as DEFERRING_CONTROLS, L as EVENTS_TABLE, P as FlowControlKeyError, B as PAUSES_TABLE, U as PENDING_TABLE, We as WATERMARKS_TABLE, O as WorkflowFlowControlProperty, C as WorkflowMessagesProperty, r as WorkflowRunRecorder, n as WorkflowStepInterceptorTag, E as WorkflowVersionTypeId, v as WorkflowWorkerLayerTypeId, Re as _voltroWorkflowAdmissionsTable, fe as _voltroWorkflowPausesTable, Te as _voltroWorkflowPendingTable, me as _voltroWorkflowRunEventsTable, _e as _voltroWorkflowRunStepsTable, Ne as _voltroWorkflowRunsTable, He as _voltroWorkflowStartContextsTable, F as _voltroWorkflowWatermarksTable, Se as admitStart, K as allIntents, y as assertConsistentPools, ve as awaitEvent, se as awaitSignal, we as awaitSignalSuspending, de as awaitUpdate, Fe as closeWorkflowChildrenForParent, he as comparePendingOrder, Ve as completeSuspendingSignal, Be as decideAdmission, a as deferringControlsOf, Q as deleteIntent, qe as discardIntent, Ke as drainTick, I as dueIntents, d as durableClock, w as durableQueue, D as durableQueueModule, p as durableRateLimiterModule, ne as evaluateAdmission, s as getCurrentWorkflowExecutionId, b as getCurrentWorkflowRunId, x as getWorkflowFlowControl, k as getWorkflowVersionMetadata, o as hasCancelOn, c as hasFlowControl, De as inMemoryWorkflowEngineLayer, Oe as inspectWorkflow, ke as isFinishExpired, Ie as isStartExpired, m as isWorkflowWorkerLayer, q as linkExecution, ze as makeInMemoryRecorder, be as makeWorkflowRunRecorder, ge as makeWorkflowUpdateId, Y as newestEventAt, xe as nextSlotAt, H as noteIntentAttempt, te as pauseWorkflow, re as pendingSlotId, V as pendingWindow, G as persistDefer, Ce as planCancellations, le as pooledConcurrencyKey, h as processQueue, Pe as pruneAdmissions, T as queueWorker, S as rateLimit, W as readAdmissionState, ae as readPausedWorkflows, ee as readWatermark, ie as recordAdmission, oe as releaseLease, je as resolveAdmissionKeys, Me as resolveWorkflowMessageRun, Z as resumeWorkflow, Ee as sendWorkflowSignal, ye as sendWorkflowUpdate, ce as serialiseWorkflowRowForWire, _ as sleep, g as sleepUntil, u as step, A as stepIdempotencyKey, N as stepModule, pe as suspendingSignalDeferredName, z as sweepCancelOn, Ae as truncateWorkflowValue, i as validateFlowControl, f as withCompensation, M as workflow, l as workflowModule, Le as wrapWorkflowExecuteWithRunRecording, R as writeWatermark };
1
+ import { A as e, B as t, C as n, D as r, E as i, F as a, I as o, L as s, M as c, N as l, O as u, P as d, R as f, S as p, T as m, V as h, _ as g, a as _, b as v, c as y, d as b, f as x, g as S, h as C, i as w, k as T, l as E, m as D, n as O, o as k, p as A, r as j, s as M, t as N, u as P, v as F, w as I, x as L, y as R, z } from "./primitives-oLKOTbvJ.js";
2
+ import { $ as B, A as V, At as H, B as U, C as W, Ct as G, D as K, Dt as q, E as J, Et as Y, F as X, G as Z, H as Q, I as $, J as ee, K as te, L as ne, M as re, Mt as ie, N as ae, Nt as oe, O as se, Ot as ce, P as le, Q as ue, R as de, S as fe, St as pe, T as me, Tt as he, U as ge, V as _e, W as ve, X as ye, Y as be, Z as xe, _ as Se, _t as Ce, a as we, at as Te, b as Ee, bt as De, c as Oe, ct as ke, d as Ae, dt as je, et as Me, f as Ne, ft as Pe, g as Fe, gt as Ie, h as Le, ht as Re, i as ze, it as Be, j as Ve, jt as He, k as Ue, kt as We, l as Ge, lt as Ke, m as qe, mt as Je, n as Ye, nt as Xe, o as Ze, ot as Qe, p as $e, pt as et, q as tt, r as nt, rt, s as it, st as at, t as ot, tt as st, u as ct, ut as lt, v as ut, vt as dt, w as ft, wt as pt, x as mt, xt as ht, y as gt, yt as _t, z as vt } from "./src-BXObaqb-.js";
3
+ export { ue as ADMISSIONS_TABLE, $e as BUDGET_HOLDS_TABLE, qe as BudgetHoldExpired, vt as CANCEL_ON_WATERMARK, u as CurrentWorkflowExecutionId, T as CurrentWorkflowPatches, I as CurrentWorkflowReplayShape, e as CurrentWorkflowRunId, Le as DEFAULT_BUDGET_HOLD_TIMEOUT_MS, U as DEFAULT_COLD_LOOKBACK_MS, ae as DEFAULT_DRAIN_BATCH, _e as DEFAULT_EVENT_BATCH, B as DEFAULT_LEASE_MS, ze as DEFAULT_MAX_RUN_RECLAIMS, we as DEFAULT_REPLAY_SHAPE_LIMIT, X as DEFAULT_STALL_AFTER_MS, $ as DEFAULT_STALL_EVENT_LOOKBACK, ne as DEFAULT_STALL_RUN_PAGE, o as DEFERRING_CONTROLS, Q as EVENTS_TABLE, dt as FlowControlKeyError, Me as PAUSES_TABLE, st as PENDING_TABLE, ge as WATERMARKS_TABLE, N as WorkflowFlowControlProperty, O as WorkflowMessagesProperty, c as WorkflowRunRecorder, l as WorkflowStepInterceptorTag, j as WorkflowVersionTypeId, w as WorkflowWorkerLayerTypeId, Fe as _voltroBudgetHoldsTable, Y as _voltroWorkflowAdmissionsTable, q as _voltroWorkflowPausesTable, ce as _voltroWorkflowPendingTable, H as _voltroWorkflowRunEventsTable, He as _voltroWorkflowRunStepsTable, ie as _voltroWorkflowRunsTable, We as _voltroWorkflowStartContextsTable, be as _voltroWorkflowWatermarksTable, ye as admitStart, Xe as allIntents, s as assertConsistentPools, Ve as awaitEvent, re as awaitSignal, ft as awaitSignalSuspending, Ne as awaitUpdate, Se as budgetHoldGeneration, ut as budgetHoldKey, gt as budgetHoldSignalName, nt as closeWorkflowChildrenForParent, _t as comparePendingOrder, me as completeSuspendingSignal, De as decideAdmission, f as deferringControlsOf, rt as deleteIntent, Be as discardIntent, le as drainTick, Te as dueIntents, _ as durableClock, k as durableQueue, M as durableQueueModule, y as durableRateLimiterModule, Qe as evaluateAdmission, d as getCurrentWorkflowExecutionId, a as getCurrentWorkflowRunId, E as getWorkflowFlowControl, P as getWorkflowVersionMetadata, z as hasCancelOn, t as hasFlowControl, Ee as heldBudgets, oe as inMemoryWorkflowEngineLayer, Ye as inspectWorkflow, ht as isFinishExpired, pe as isStartExpired, b as isWorkflowWorkerLayer, xe as linkExecution, ot as makeInMemoryRecorder, m as makeReplayShapeTracker, Ze as makeWorkflowRunRecorder, K as makeWorkflowUpdateId, tt as newestEventAt, G as nextSlotAt, i as nondeterminismEventPayload, it as normaliseWorkflowPatches, at as noteIntentAttempt, x as patch, ke as pauseWorkflow, mt as pendingBudgetHolds, Ke as pendingSlotId, lt as pendingWindow, je as persistDefer, ee as planCancellations, pt as pooledConcurrencyKey, A as processQueue, Pe as pruneAdmissions, D as queueWorker, C as rateLimit, et as readAdmissionState, Je as readPausedWorkflows, ve as readWatermark, Re as recordAdmission, fe as releaseBudgetHolds, Ie as releaseLease, r as reportNondeterminism, he as resolveAdmissionKeys, Oe as resolveRunGuardTuning, se as resolveWorkflowMessageRun, Ce as resumeWorkflow, Ue as sendWorkflowSignal, V as sendWorkflowUpdate, Ge as serialiseWorkflowRowForWire, S as sleep, g as sleepUntil, F as step, R as stepIdempotencyKey, v as stepModule, W as suspendForBudget, J as suspendingSignalDeferredName, Z as sweepCancelOn, de as sweepStalledRuns, ct as truncateWorkflowValue, h as validateFlowControl, L as withCompensation, p as workflow, n as workflowModule, Ae as wrapWorkflowExecuteWithRunRecording, te as writeWatermark };
@@ -1,16 +1,16 @@
1
1
  import { Activity as e, Activity as t, DurableClock as n, DurableClock as r, DurableQueue as i, DurableQueue as a, DurableRateLimiter as o, DurableRateLimiter as s, Workflow as c, Workflow as l } from "@effect/workflow";
2
- import { Cause as u, Context as d, Duration as f, Effect as p, Exit as m, FiberRef as h, Option as g, Schedule as _, Schema as v } from "effect";
2
+ import { Cause as u, Context as d, Duration as f, Effect as p, Exit as m, FiberRef as h, Option as ee, Schedule as g, Schema as _ } from "effect";
3
3
  //#region src/flowControl.ts
4
- var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0 || e.concurrency !== void 0 || e.throttle !== void 0 || e.rateLimit !== void 0 || e.batch !== void 0 || e.timeouts?.startMs !== void 0 || e.timeouts?.finishMs !== void 0), b = (e) => e?.cancelOn !== void 0 && e.cancelOn.length > 0, x = [
4
+ var v = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0 || e.concurrency !== void 0 || e.throttle !== void 0 || e.rateLimit !== void 0 || e.batch !== void 0 || e.timeouts?.startMs !== void 0 || e.timeouts?.finishMs !== void 0), y = (e) => e?.cancelOn !== void 0 && e.cancelOn.length > 0, b = [
5
5
  "debounce",
6
6
  "batch",
7
7
  "throttle",
8
8
  "concurrency"
9
- ], S = (e) => {
9
+ ], x = (e) => {
10
10
  if (e === void 0) return [];
11
11
  let t = [];
12
12
  return e.debounce !== void 0 && t.push("debounce"), e.batch !== void 0 && t.push("batch"), e.throttle !== void 0 && t.push("throttle"), e.concurrency !== void 0 && t.push("concurrency"), t;
13
- }, C = (e, t, n) => {
13
+ }, S = (e, t, n) => {
14
14
  let r;
15
15
  try {
16
16
  r = f.toMillis(f.decode(e));
@@ -19,26 +19,26 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
19
19
  }
20
20
  if (!Number.isFinite(r) || r <= 0) throw Error(`workflow '${n}': ${t} must be a positive finite duration, got ${String(e)}`);
21
21
  return r;
22
- }, w = (e, t, n) => {
22
+ }, C = (e, t, n) => {
23
23
  if (!Number.isInteger(e) || e <= 0) throw Error(`workflow '${n}': ${t} must be a positive integer, got ${String(e)}`);
24
24
  return e;
25
- }, T = (e, t, n) => {
25
+ }, w = (e, t, n) => {
26
26
  if (typeof e != "function") throw Error(`workflow '${n}': ${t} must be a function of the payload`);
27
27
  return e;
28
- }, E = (e) => {
28
+ }, T = (e) => {
29
29
  let t = e?.ast?.propertySignatures;
30
30
  if (!Array.isArray(t)) return !1;
31
31
  let n = t.find((e) => e.name === "items");
32
32
  return n !== void 0 && n.type?._tag === "TupleType";
33
- }, D = (e) => {
33
+ }, E = (e) => {
34
34
  let { workflowName: t, control: n } = e;
35
35
  if (n === void 0) return;
36
36
  let r = { workflowName: t };
37
37
  if (n.debounce !== void 0) {
38
- let e = n.debounce, i = C(e.period, "debounce.period", t), a = e.timeout === void 0 ? void 0 : C(e.timeout, "debounce.timeout", t);
38
+ let e = n.debounce, i = S(e.period, "debounce.period", t), a = e.timeout === void 0 ? void 0 : S(e.timeout, "debounce.timeout", t);
39
39
  if (a !== void 0 && a < i) throw Error(`workflow '${t}': debounce.timeout (${a}ms) is shorter than debounce.period (${i}ms), so the burst can never be collapsed — the run would be admitted before the quiet period could ever elapse. Raise the timeout or lower the period.`);
40
40
  r.debounce = {
41
- key: T(e.key, "debounce.key", t),
41
+ key: w(e.key, "debounce.key", t),
42
42
  periodMs: i,
43
43
  ...a === void 0 ? {} : { timeoutMs: a }
44
44
  };
@@ -47,7 +47,7 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
47
47
  let e = n.singleton;
48
48
  if (e.mode !== "skip" && e.mode !== "cancel") throw Error(`workflow '${t}': singleton.mode must be 'skip' or 'cancel'. There is no default — 'skip' discards the incoming request and 'cancel' discards the running one, and choosing for you would silently throw away work either way.`);
49
49
  r.singleton = {
50
- key: T(e.key, "singleton.key", t),
50
+ key: w(e.key, "singleton.key", t),
51
51
  mode: e.mode
52
52
  };
53
53
  }
@@ -55,34 +55,34 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
55
55
  let e = n.concurrency;
56
56
  if (e.pool !== void 0 && (typeof e.pool != "string" || e.pool.trim() === "")) throw Error(`workflow '${t}': concurrency.pool must be a non-empty name — it is the identity other workflows declare to share this budget, and an empty one would silently merge every empty-named pool in the deployment into one.`);
57
57
  r.concurrency = {
58
- limit: w(e.limit, "concurrency.limit", t),
59
- ...e.key === void 0 ? {} : { key: T(e.key, "concurrency.key", t) },
58
+ limit: C(e.limit, "concurrency.limit", t),
59
+ ...e.key === void 0 ? {} : { key: w(e.key, "concurrency.key", t) },
60
60
  ...e.pool === void 0 ? {} : { pool: e.pool.trim() }
61
61
  };
62
62
  }
63
63
  if (n.throttle !== void 0) {
64
64
  let e = n.throttle;
65
65
  r.throttle = {
66
- limit: w(e.limit, "throttle.limit", t),
67
- periodMs: C(e.period, "throttle.period", t),
68
- ...e.key === void 0 ? {} : { key: T(e.key, "throttle.key", t) }
66
+ limit: C(e.limit, "throttle.limit", t),
67
+ periodMs: S(e.period, "throttle.period", t),
68
+ ...e.key === void 0 ? {} : { key: w(e.key, "throttle.key", t) }
69
69
  };
70
70
  }
71
71
  if (n.rateLimit !== void 0) {
72
72
  let e = n.rateLimit;
73
73
  r.rateLimit = {
74
- limit: w(e.limit, "rateLimit.limit", t),
75
- periodMs: C(e.period, "rateLimit.period", t),
76
- ...e.key === void 0 ? {} : { key: T(e.key, "rateLimit.key", t) }
74
+ limit: C(e.limit, "rateLimit.limit", t),
75
+ periodMs: S(e.period, "rateLimit.period", t),
76
+ ...e.key === void 0 ? {} : { key: w(e.key, "rateLimit.key", t) }
77
77
  };
78
78
  }
79
79
  if (n.batch !== void 0) {
80
80
  let i = n.batch;
81
- if (e.payloadSchema !== void 0 && !E(e.payloadSchema)) throw Error(`workflow '${t}': batch is declared, so the workflow's own \`payload\` must be the BATCH shape — \`Schema.Struct({ items: Schema.Array(Item) })\` — while callers start it with a SINGLE item. Declare the item's schema as \`batch.item\`. Checked here rather than at admission because a decode failure on the batching replica is a failure nobody is watching.`);
81
+ if (e.payloadSchema !== void 0 && !T(e.payloadSchema)) throw Error(`workflow '${t}': batch is declared, so the workflow's own \`payload\` must be the BATCH shape — \`Schema.Struct({ items: Schema.Array(Item) })\` — while callers start it with a SINGLE item. Declare the item's schema as \`batch.item\`. Checked here rather than at admission because a decode failure on the batching replica is a failure nobody is watching.`);
82
82
  r.batch = {
83
- ...i.key === void 0 ? {} : { key: T(i.key, "batch.key", t) },
84
- maxSize: w(i.maxSize, "batch.maxSize", t),
85
- timeoutMs: C(i.timeout, "batch.timeout", t),
83
+ ...i.key === void 0 ? {} : { key: w(i.key, "batch.key", t) },
84
+ maxSize: C(i.maxSize, "batch.maxSize", t),
85
+ timeoutMs: S(i.timeout, "batch.timeout", t),
86
86
  ...i.item === void 0 ? {} : { item: i.item }
87
87
  };
88
88
  }
@@ -91,7 +91,7 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
91
91
  r.priority = n.priority;
92
92
  }
93
93
  if (n.timeouts !== void 0) {
94
- let e = n.timeouts, i = e.start === void 0 ? void 0 : C(e.start, "timeouts.start", t), a = e.finish === void 0 ? void 0 : C(e.finish, "timeouts.finish", t);
94
+ let e = n.timeouts, i = e.start === void 0 ? void 0 : S(e.start, "timeouts.start", t), a = e.finish === void 0 ? void 0 : S(e.finish, "timeouts.finish", t);
95
95
  (i !== void 0 || a !== void 0) && (r.timeouts = {
96
96
  ...i === void 0 ? {} : { startMs: i },
97
97
  ...a === void 0 ? {} : { finishMs: a }
@@ -111,7 +111,7 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
111
111
  if (typeof e?.event != "string" || e.event.length === 0) throw Error(`workflow '${t}': ${r}.event must be a non-empty event name, exactly as ctx.events.publish writes it.`);
112
112
  if (e.schema === void 0 || typeof e.schema.ast != "object") throw Error(`workflow '${t}': ${r}.schema must be a Schema for the event payload. It is decoded before \`match\` runs, so the predicate reads the domain type rather than raw JSON.`);
113
113
  if (typeof e.match != "function") throw Error(`workflow '${t}': ${r}.match is required. Omitting it would mean "cancel every live run of this workflow whenever '${e.event}' is published" — write \`match: () => true\` if that is what you mean, so it is visible in review.`);
114
- let i = e.within === void 0 ? void 0 : C(e.within, `${r}.within`, t);
114
+ let i = e.within === void 0 ? void 0 : S(e.within, `${r}.within`, t);
115
115
  return {
116
116
  event: e.event,
117
117
  schema: e.schema,
@@ -122,9 +122,9 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
122
122
  });
123
123
  e.length > 0 && (r.cancelOn = e);
124
124
  }
125
- if (r.timeouts?.startMs !== void 0 && S(r).length === 0) throw Error(`workflow '${t}': timeouts.start bounds how long a run may sit in the ADMISSION queue, but this workflow declares no control that can defer one (debounce, batch, throttle, concurrency). It would never fire. Use timeouts.finish to bound the run itself.`);
125
+ if (r.timeouts?.startMs !== void 0 && x(r).length === 0) throw Error(`workflow '${t}': timeouts.start bounds how long a run may sit in the ADMISSION queue, but this workflow declares no control that can defer one (debounce, batch, throttle, concurrency). It would never fire. Use timeouts.finish to bound the run itself.`);
126
126
  return r;
127
- }, ee = (e) => {
127
+ }, D = (e) => {
128
128
  let t = /* @__PURE__ */ new Map();
129
129
  for (let n of e) {
130
130
  let e = n?.concurrency;
@@ -137,99 +137,143 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
137
137
  else if (r.limit !== e.limit) throw Error(`concurrency pool '${e.pool}': '${n.workflowName}' declares limit ${e.limit}, but ${r.workflows.map((e) => `'${e}'`).join(", ")} declare${r.workflows.length === 1 ? "s" : ""} limit ${r.limit}. A pool is ONE budget — every member must declare the same number, or the enforced limit would depend on which workflow's start arrived first. Align the limits, or give the workflows different pool names if they were never meant to share.`);
138
138
  else r.workflows.push(n.workflowName);
139
139
  }
140
- }, O = class extends d.Tag("@voltro/WorkflowRunRecorder")() {}, k = h.unsafeMake(void 0), A = h.unsafeMake(void 0), j = h.unsafeMake(void 0), M = () => h.get(k), N = () => h.get(A), P = class extends d.Tag("@voltro/WorkflowStepInterceptor")() {}, F = (e) => {
140
+ }, O = class extends d.Tag("@voltro/WorkflowRunRecorder")() {}, k = h.unsafeMake(void 0), A = h.unsafeMake(void 0), j = h.unsafeMake(void 0), M = h.unsafeMake([]), N = () => h.get(k), P = () => h.get(A), F = class extends d.Tag("@voltro/WorkflowStepInterceptor")() {}, I = (e) => {
141
+ let t = /* @__PURE__ */ new Map();
142
+ for (let n of e) t.set(n.stepName, (t.get(n.stepName) ?? 0) + 1);
143
+ let n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set(), i = (e) => r.has(e) ? !1 : (r.add(e), !0);
144
+ return {
145
+ reach: (e) => {
146
+ let r = (n.get(e) ?? 0) + 1;
147
+ n.set(e, r);
148
+ let a = t.get(e) ?? 0;
149
+ if (a !== 0 && !(r <= a) && i(`extra:${e}`)) return {
150
+ kind: "extra-step-occurrence",
151
+ stepName: e,
152
+ recorded: a,
153
+ reached: r,
154
+ detail: `step '${e}' was reached ${r} time(s) on this attempt but this run only ever recorded ${a} — the body may have changed how often it runs this step (a loop bound), so the journal replays a result for an iteration the code no longer means.`
155
+ };
156
+ },
157
+ settle: () => {
158
+ let e = [];
159
+ for (let [r, a] of t) (n.get(r) ?? 0) > 0 || i(`unreached:${r}`) && e.push({
160
+ kind: "unreached-step",
161
+ stepName: r,
162
+ recorded: a,
163
+ reached: 0,
164
+ detail: `step '${r}' ran on an earlier attempt of this run but the current code never reaches it — the step was renamed, removed, or moved behind a branch, so its journaled result is orphaned and any step that replaced it executed fresh.`
165
+ });
166
+ return e;
167
+ }
168
+ };
169
+ }, L = h.unsafeMake(void 0), R = (e) => ({
170
+ kind: e.kind,
171
+ stepName: e.stepName,
172
+ recorded: e.recorded,
173
+ reached: e.reached,
174
+ detail: e.detail
175
+ }), z = (e) => p.gen(function* () {
176
+ if (e.length === 0) return;
177
+ let t = yield* h.get(k), n = yield* p.serviceOption(O);
178
+ if (t === void 0 || n._tag !== "Some") return;
179
+ let r = n.value;
180
+ for (let n of e) yield* p.promise(() => r.recordEvent({
181
+ runId: t,
182
+ eventType: "nondeterminism-suspected",
183
+ payload: R(n)
184
+ }).then(() => void 0).catch(() => void 0));
185
+ }), B = (e) => {
141
186
  if (typeof e != "object" || !e) return;
142
187
  let t = e.retryAfterMillis;
143
188
  if (typeof t == "number" && Number.isFinite(t) && t >= 0) return f.millis(t);
144
189
  let n = e.retryAfter;
145
190
  if (typeof n == "number" && Number.isFinite(n) && n >= 0) return f.seconds(n);
146
- }, I = (e) => f.decode(e), L = (e) => typeof e == "object" && e && "_tag" in e ? String(e._tag) : void 0, R = (e) => e !== void 0 && (e.maxAttempts ?? 3) > 1, z = (e) => {
191
+ }, V = (e) => f.decode(e), H = (e) => typeof e == "object" && e && "_tag" in e ? String(e._tag) : void 0, U = (e) => e !== void 0 && (e.maxAttempts ?? 3) > 1, W = (e) => {
147
192
  if (e.retryable) return e.retryable;
148
193
  if (e.retryableErrors && e.retryableErrors.length > 0) {
149
194
  let t = new Set(e.retryableErrors);
150
195
  return (e) => {
151
- let n = L(e);
196
+ let n = H(e);
152
197
  return n !== void 0 && t.has(n);
153
198
  };
154
199
  }
155
200
  return () => !0;
156
- }, B = (e) => {
157
- let t = e.baseDelay ?? "200 millis", n = e.strategy ?? "exponential", r = e.maxAttempts ?? 3, i = n === "linear" ? _.linear(I(e.step ?? t)) : n === "fixed" ? _.spaced(I(t)) : _.exponential(I(t), e.factor ?? 2);
201
+ }, G = (e) => {
202
+ let t = e.baseDelay ?? "200 millis", n = e.strategy ?? "exponential", r = e.maxAttempts ?? 3, i = n === "linear" ? g.linear(V(e.step ?? t)) : n === "fixed" ? g.spaced(V(t)) : g.exponential(V(t), e.factor ?? 2);
158
203
  if (e.maxDelay !== void 0) {
159
- let t = I(e.maxDelay);
160
- i = _.modifyDelay(i, (e, n) => f.min(n, t));
204
+ let t = V(e.maxDelay);
205
+ i = g.modifyDelay(i, (e, n) => f.min(n, t));
161
206
  }
162
- (e.jitter ?? !0) === !0 && (i = _.jittered(i));
163
- let a = _.intersect(i, _.recurs(Math.max(0, r - 1)));
164
- return e.maxElapsed !== void 0 && (a = _.upTo(I(e.maxElapsed))(a)), a;
165
- }, V = (e, t) => {
166
- let n = f.toMillis(I(e.baseDelay ?? "200 millis")), r = e.strategy ?? "exponential", i = r === "fixed" ? n : r === "linear" ? n + f.toMillis(I(e.step ?? e.baseDelay ?? "200 millis")) * (t - 1) : n * (e.factor ?? 2) ** (t - 1);
167
- return e.maxDelay !== void 0 && (i = Math.min(i, f.toMillis(I(e.maxDelay)))), (e.jitter ?? !0) === !0 && (i *= Math.random()), i;
168
- }, H = (e, t, n, r) => p.gen(function* () {
169
- let i = t.maxAttempts ?? 3, a = t.maxElapsed === void 0 ? Infinity : f.toMillis(I(t.maxElapsed)), o = yield* p.sync(() => Date.now()), s = 0;
207
+ (e.jitter ?? !0) === !0 && (i = g.jittered(i));
208
+ let a = g.intersect(i, g.recurs(Math.max(0, r - 1)));
209
+ return e.maxElapsed !== void 0 && (a = g.upTo(V(e.maxElapsed))(a)), a;
210
+ }, K = (e, t) => {
211
+ let n = f.toMillis(V(e.baseDelay ?? "200 millis")), r = e.strategy ?? "exponential", i = r === "fixed" ? n : r === "linear" ? n + f.toMillis(V(e.step ?? e.baseDelay ?? "200 millis")) * (t - 1) : n * (e.factor ?? 2) ** (t - 1);
212
+ return e.maxDelay !== void 0 && (i = Math.min(i, f.toMillis(V(e.maxDelay)))), (e.jitter ?? !0) === !0 && (i *= Math.random()), i;
213
+ }, q = (e, t, n, r) => p.gen(function* () {
214
+ let i = t.maxAttempts ?? 3, a = t.maxElapsed === void 0 ? Infinity : f.toMillis(V(t.maxElapsed)), o = yield* p.sync(() => Date.now()), s = 0;
170
215
  for (;;) {
171
216
  let c = yield* p.exit(e);
172
217
  if (m.isSuccess(c)) return c.value;
173
- let l = c.cause, d = u.failureOption(l), h = g.isSome(d) ? d.value : u.squash(l);
218
+ let l = c.cause, d = u.failureOption(l), h = ee.isSome(d) ? d.value : u.squash(l);
174
219
  s += 1;
175
- let _ = (yield* p.sync(() => Date.now())) - o;
176
- if (s >= i || !n(h) || _ >= a) return yield* p.failCause(l);
220
+ let g = (yield* p.sync(() => Date.now())) - o;
221
+ if (s >= i || !n(h) || g >= a) return yield* p.failCause(l);
177
222
  r?.(h);
178
- let v = F(h), y = v === void 0 ? V(t, s) : f.toMillis(v);
179
- yield* p.sleep(f.millis(y));
223
+ let _ = B(h), v = _ === void 0 ? K(t, s) : f.toMillis(_);
224
+ yield* p.sleep(f.millis(v));
180
225
  }
181
- }), U = (e, t, n) => {
182
- if (!R(t)) return e;
183
- let r = z(t);
184
- if (t.respectRetryAfter === !0) return H(e, t, r, n);
185
- let i = B(t), a = n ? p.tapError(e, (e) => p.sync(() => {
226
+ }), J = (e, t, n) => {
227
+ if (!U(t)) return e;
228
+ let r = W(t);
229
+ if (t.respectRetryAfter === !0) return q(e, t, r, n);
230
+ let i = G(t), a = n ? p.tapError(e, (e) => p.sync(() => {
186
231
  r(e) && n(e);
187
232
  })) : e;
188
233
  return p.retry(a, {
189
234
  schedule: i,
190
235
  while: r
191
236
  });
192
- }, W = Symbol.for("voltro.workflow.workerLayer"), G = Symbol.for("voltro.workflow.version"), K = "__voltroWorkflowMessages", q = "__voltroWorkflowFlowControl", J = (e) => typeof e == "object" && !!e && e[W] === !0, Y = (e) => typeof e == "object" && e && e[G] !== void 0 ? e[G] : {
237
+ }, Y = Symbol.for("voltro.workflow.workerLayer"), X = Symbol.for("voltro.workflow.version"), Z = "__voltroWorkflowMessages", Q = "__voltroWorkflowFlowControl", te = (e) => typeof e == "object" && !!e && e[Y] === !0, ne = (e) => typeof e == "object" && e && e[X] !== void 0 ? e[X] : {
193
238
  version: "1",
194
239
  compatibleWith: ["1"],
195
240
  patches: []
196
- }, X = ((e) => {
241
+ }, re = ((e) => {
197
242
  let t = c.make(e), n = e.suspendOnFailure === !0 ? t.annotate(c.SuspendOnFailure, !0) : t, r = String(e.version ?? "1"), i = {
198
243
  version: r,
199
244
  compatibleWith: (e.compatibleWith ?? [r]).map(String),
200
245
  patches: [...e.patches ?? []]
201
246
  }, a = {
202
247
  signals: { ...e.messages?.signals ?? {} },
203
- updates: { ...e.messages?.updates ?? {} },
204
- queries: { ...e.messages?.queries ?? {} }
248
+ updates: { ...e.messages?.updates ?? {} }
205
249
  };
206
- Object.defineProperty(n, G, {
250
+ Object.defineProperty(n, X, {
207
251
  value: i,
208
252
  enumerable: !1
209
- }), Object.defineProperty(n, K, {
253
+ }), Object.defineProperty(n, Z, {
210
254
  value: a,
211
255
  enumerable: !1
212
256
  });
213
- let o = D({
257
+ let o = E({
214
258
  workflowName: e.name,
215
259
  payloadSchema: e.payload,
216
260
  control: e
217
261
  });
218
- return o !== void 0 && Object.defineProperty(n, q, {
262
+ return o !== void 0 && Object.defineProperty(n, Q, {
219
263
  value: o,
220
264
  enumerable: !1
221
265
  }), n;
222
- }), Z = (e) => {
266
+ }), ie = (e) => {
223
267
  if (typeof e != "object" || !e) return;
224
- let t = e[q];
268
+ let t = e[Q];
225
269
  return t === void 0 ? void 0 : t;
226
- }, Q = i.make, te = i.process, ne = ((...e) => {
270
+ }, ae = i.make, oe = i.process, se = ((...e) => {
227
271
  let t = i.worker(...e);
228
- return Object.defineProperty(t, W, {
272
+ return Object.defineProperty(t, Y, {
229
273
  value: !0,
230
274
  enumerable: !1
231
275
  }), t;
232
- }), re = o.rateLimit, $ = (e) => p.gen(function* () {
276
+ }), ce = o.rateLimit, $ = (e) => p.gen(function* () {
233
277
  let t = yield* k, r = yield* p.serviceOption(O), i = f.toMillis(f.decode(e.duration));
234
278
  if (t !== void 0 && r._tag === "Some") {
235
279
  let a = r.value, o = new Date(Date.now() + i).toISOString(), s = yield* j;
@@ -256,18 +300,18 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
256
300
  return;
257
301
  }
258
302
  yield* n.sleep(e);
259
- }), ie = (t) => p.gen(function* () {
303
+ }), le = (t) => p.gen(function* () {
260
304
  let n = (yield* e.make({
261
305
  name: `sleepUntil:${t.name}`,
262
- success: v.Number,
306
+ success: _.Number,
263
307
  execute: p.sync(() => t.until instanceof Date ? t.until.getTime() : t.until)
264
308
  })) - Date.now();
265
309
  n <= 0 || (yield* $({
266
310
  name: t.name,
267
311
  duration: `${n} millis`
268
312
  }));
269
- }), ae = (t, n, r, i) => p.gen(function* () {
270
- let a = yield* k, o = yield* e.CurrentAttempt, s = yield* p.serviceOption(O), c = yield* p.serviceOption(P), l = c._tag === "Some" ? c.value.interceptor(n, {
313
+ }), ue = (t, n, r, i) => p.gen(function* () {
314
+ let a = yield* k, o = yield* e.CurrentAttempt, s = yield* p.serviceOption(O), c = yield* p.serviceOption(F), l = c._tag === "Some" ? c.value.interceptor(n, {
271
315
  runId: a ?? "unrecorded",
272
316
  stepName: t,
273
317
  attempt: o
@@ -288,7 +332,7 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
288
332
  }
289
333
  }
290
334
  let m = Date.now();
291
- return yield* U(l, i).pipe(p.tap((e) => d && f ? p.promise(async () => {
335
+ return yield* J(l, i).pipe(p.tap((e) => d && f ? p.promise(async () => {
292
336
  try {
293
337
  await f.endStepSuccess({
294
338
  stepRecordId: d,
@@ -312,12 +356,23 @@ var y = (e) => e !== void 0 && (e.debounce !== void 0 || e.singleton !== void 0
312
356
  });
313
357
  } catch {}
314
358
  }) : p.void));
315
- }), oe = (t) => {
359
+ }), de = (e) => p.gen(function* () {
360
+ let t = yield* h.get(L);
361
+ if (t === void 0) return;
362
+ let n = t.reach(e);
363
+ n !== void 0 && (yield* z([n]));
364
+ }), fe = (e, t) => {
365
+ let n = e;
366
+ return {
367
+ ...e,
368
+ commit: () => p.zipRight(de(t), n)
369
+ };
370
+ }, pe = (t) => {
316
371
  let { input: n, retry: r, ...i } = t;
317
- return e.make({
372
+ return fe(e.make({
318
373
  ...i,
319
- execute: ae(i.name, i.execute, n, r)
320
- });
321
- }, se = c.withCompensation, ce = e.idempotencyKey;
374
+ execute: ue(i.name, i.execute, n, r)
375
+ }), i.name);
376
+ }, me = (e) => p.map(h.get(M), (t) => t.includes(e)), he = c.withCompensation, ge = e.idempotencyKey;
322
377
  //#endregion
323
- export { x as A, A as C, P as D, O as E, D as F, S as M, b as N, N as O, y as P, l as S, j as T, oe as _, r as a, se as b, s as c, J as d, te as f, ie as g, $ as h, W as i, ee as j, M as k, Z as l, re as m, K as n, Q as o, ne as p, G as r, a as s, q as t, Y as u, ce as v, k as w, X as x, t as y };
378
+ export { k as A, v as B, l as C, z as D, R as E, N as F, b as I, D as L, O as M, F as N, A as O, P, x as R, re as S, I as T, E as V, le as _, r as a, t as b, s as c, te as d, me as f, $ as g, ce as h, Y as i, j, M as k, ie as l, se as m, Z as n, ae as o, oe as p, X as r, a as s, Q as t, ne as u, pe as v, L as w, he as x, ge as y, y as z };
@@ -3,6 +3,7 @@ import { DurableQueue as durableQueueModule } from '@effect/workflow';
3
3
  import { DurableRateLimiter as durableRateLimiterModule } from '@effect/workflow';
4
4
  import { Duration } from 'effect';
5
5
  import { Effect } from 'effect';
6
+ import { FiberRef } from 'effect';
6
7
  import { Schema } from 'effect';
7
8
  import { Activity as stepModule } from '@effect/workflow';
8
9
  import { Workflow as workflowModule } from '@effect/workflow';
@@ -24,6 +25,16 @@ import { Workflow as workflowModule } from '@effect/workflow';
24
25
  */
25
26
  export declare const assertConsistentPools: (controls: ReadonlyArray<ResolvedFlowControl | undefined>) => void;
26
27
 
28
+ /**
29
+ * The tracker for the CURRENT body entry, or `undefined` when there is nothing
30
+ * to compare against.
31
+ *
32
+ * Installed by `wrapWorkflowExecuteWithRunRecording` ONLY on a re-entry (a run
33
+ * whose row already exists). A first entry has no prior shape, so the whole
34
+ * mechanism costs one `FiberRef` read per step and nothing else.
35
+ */
36
+ export declare const CurrentWorkflowReplayShape: FiberRef.FiberRef<ReplayShapeTracker | undefined>;
37
+
27
38
  /** The DECODED payload type. Mirrors `Workflow.make`'s own `idempotencyKey`
28
39
  * parameter, so the two never disagree about what a payload is. */
29
40
  declare type DecodedPayload<P> = P extends Schema.Struct.Fields ? Schema.Struct.Type<P> : P extends {
@@ -84,6 +95,34 @@ export declare const hasFlowControl: (control: ResolvedFlowControl | undefined)
84
95
 
85
96
  export declare const isWorkflowWorkerLayer: (value: unknown) => value is WorkflowWorkerLayerBrand;
86
97
 
98
+ /**
99
+ * Build a tracker from the step rows this run recorded on EARLIER body entries.
100
+ *
101
+ * Pass the rows as they are: one row per step ATTEMPT, so a step that retried
102
+ * three times contributes three. Counting rows rather than distinct names is
103
+ * what makes the per-name sequence rule work, and the asymmetry is deliberate —
104
+ * only reaching a name MORE often than recorded is a finding. Fewer is normal
105
+ * (a crash mid-step records two rows for one logical reach).
106
+ */
107
+ export declare const makeReplayShapeTracker: (recordedRows: ReadonlyArray<RecordedStepShape>) => ReplayShapeTracker;
108
+
109
+ /** The `nondeterminism-suspected` event body. Kept here so the two emit sites
110
+ * (the step wrapper, and the run wrapper's `settle`) cannot drift. */
111
+ export declare const nondeterminismEventPayload: (finding: NondeterminismFinding) => Record<string, unknown>;
112
+
113
+ export declare interface NondeterminismFinding {
114
+ readonly kind: NondeterminismKind;
115
+ readonly stepName: string;
116
+ /** How many rows this run recorded for `stepName` on EARLIER body entries. */
117
+ readonly recorded: number;
118
+ /** How many times the CURRENT body entry reached it. */
119
+ readonly reached: number;
120
+ /** One sentence an operator can act on, without opening the code. */
121
+ readonly detail: string;
122
+ }
123
+
124
+ export declare type NondeterminismKind = 'unreached-step' | 'extra-step-occurrence';
125
+
87
126
  declare type NormaliseWorkflowMessages<M extends WorkflowMessageSchemas | undefined> = {
88
127
  readonly signals: M extends {
89
128
  readonly signals: infer Signals;
@@ -91,11 +130,60 @@ declare type NormaliseWorkflowMessages<M extends WorkflowMessageSchemas | undefi
91
130
  readonly updates: M extends {
92
131
  readonly updates: infer Updates;
93
132
  } ? NonNullable<Updates> & Readonly<Record<string, WorkflowMessagePairSchemas>> : {};
94
- readonly queries: M extends {
95
- readonly queries: infer Queries;
96
- } ? NonNullable<Queries> & Readonly<Record<string, WorkflowMessagePairSchemas>> : {};
97
133
  };
98
134
 
135
+ /**
136
+ * Is a named change marker in effect for the run currently executing?
137
+ *
138
+ * This is the escape valve for the versioning trap. `compatibleWith` is
139
+ * all-or-nothing: leave an old version out and every in-flight run on it is
140
+ * terminally failed; leave it in and the old runs replay against the new body
141
+ * with no detection. `patch` is the third option — the body itself branches, so
142
+ * runs that started BEFORE the change keep taking the old path to completion
143
+ * while new runs take the new one.
144
+ *
145
+ * ```ts
146
+ * export const Charge = workflow({
147
+ * name: 'billing.charge',
148
+ * payload: { orderId: Schema.String },
149
+ * idempotencyKey: ({ orderId }) => `billing.charge:${orderId}`,
150
+ * patches: ['split-tax-calculation'], // ← declare it
151
+ * })
152
+ *
153
+ * // inside the body:
154
+ * if (yield* patch('split-tax-calculation')) {
155
+ * const net = yield* step({ name: 'net-total', execute })
156
+ * const tax = yield* step({ name: 'tax', execute })
157
+ * return net + tax
158
+ * }
159
+ * return yield* step({ name: 'total', execute }) // the pre-patch path
160
+ * ```
161
+ *
162
+ * ── The answer is pinned to the RUN, not to the code ────────────────────────
163
+ *
164
+ * `patches` is stamped onto `_voltro_workflow_runs.workflowPatches` when the
165
+ * run starts and read back from that row on every resume. So a run started
166
+ * before you added the marker answers `false` for the rest of its life,
167
+ * however many times it replays and whatever the deployed code says — which is
168
+ * the property that makes the branch deterministic across a redeploy.
169
+ *
170
+ * Under `@effect/workflow` the naive implementation does the opposite: an
171
+ * activity that is ABSENT from an old run's journal EXECUTES on replay (the
172
+ * journal is keyed name/attempt), so a marker journaled by an activity would
173
+ * answer `true` for exactly the old runs it must answer `false` for. Reading
174
+ * the run row sidesteps that entirely.
175
+ *
176
+ * ── Retiring a patch ───────────────────────────────────────────────────────
177
+ *
178
+ * Once no run predating the marker can still be in flight, delete the old
179
+ * branch and the entry from `patches`. Runs that stamped it keep the marker on
180
+ * their row for the audit trail; `patch()` simply stops being called.
181
+ *
182
+ * Outside a recorded workflow body (a unit test, a bare `step()` call) this is
183
+ * `false` — the pre-patch branch, which is the safe direction.
184
+ */
185
+ export declare const patch: (id: string) => Effect.Effect<boolean>;
186
+
99
187
  /** The SCHEMA a payload input denotes — `Fields` lifted into a `Struct`. */
100
188
  declare type PayloadSchemaOf<P> = P extends Schema.Struct.Fields ? Schema.Struct<P> : P;
101
189
 
@@ -114,6 +202,39 @@ export declare const queueWorker: typeof durableQueueModule.worker;
114
202
  /** Durable rate limiter activity. Delays through the workflow clock. */
115
203
  export declare const rateLimit: typeof durableRateLimiterModule.rateLimit;
116
204
 
205
+ /** The slice of a `_voltro_workflow_run_steps` row this needs. */
206
+ export declare interface RecordedStepShape {
207
+ readonly stepName: string;
208
+ }
209
+
210
+ export declare interface ReplayShapeTracker {
211
+ /**
212
+ * The body reached `stepName`. Returns a finding the FIRST time that reach
213
+ * is anomalous, `undefined` otherwise — so a step in a hot loop reports once
214
+ * rather than once per iteration.
215
+ */
216
+ readonly reach: (stepName: string) => NondeterminismFinding | undefined;
217
+ /**
218
+ * The body ran to a COMPLETE outcome. Returns the set-membership findings —
219
+ * recorded names the body never reached.
220
+ *
221
+ * Call this ONLY on success/failure, never on a suspend: a suspended body
222
+ * stopped partway through on purpose, so everything after the suspension
223
+ * point is legitimately unreached.
224
+ */
225
+ readonly settle: () => ReadonlyArray<NondeterminismFinding>;
226
+ }
227
+
228
+ /**
229
+ * Emit findings from INSIDE the workflow body, where the run id and the
230
+ * recorder are only reachable through the fiber context.
231
+ *
232
+ * Best-effort in the strongest sense: no recorder, no run id, or a rejecting
233
+ * write all resolve to "nothing happened". A tripwire that can break the run it
234
+ * is watching is not a tripwire.
235
+ */
236
+ export declare const reportNondeterminism: (findings: ReadonlyArray<NondeterminismFinding>) => Effect.Effect<void>;
237
+
117
238
  /** One resolved `cancelOn` entry. The schema is kept (not pre-compiled into a
118
239
  * decoder) so the sweeper can report a decode failure naming the event, which
119
240
  * is the difference between "the predicate said no" and "we could not read the
@@ -742,16 +863,24 @@ export declare interface WorkflowMessagesCarrier<M extends WorkflowMessagesMetad
742
863
  readonly [WorkflowMessagesProperty]: M;
743
864
  }
744
865
 
866
+ /**
867
+ * The message channels a workflow declares.
868
+ *
869
+ * TWO, not three. `queries` used to sit here as a third channel and there was
870
+ * never a send path for it — no `sendWorkflowQuery`, no `awaitQuery`, nothing
871
+ * to receive one. It was normalised into metadata, projected into the generated
872
+ * rpcGroup and carried on the client's `WorkflowState`, so a user got a fully
873
+ * typed record they could not invoke from anywhere. Signals (fire-and-forget)
874
+ * and updates (synchronous, with a result) are the channels that exist.
875
+ */
745
876
  export declare interface WorkflowMessageSchemas {
746
877
  readonly signals?: Readonly<Record<string, Schema.Schema.Any>>;
747
878
  readonly updates?: Readonly<Record<string, WorkflowMessagePairSchemas>>;
748
- readonly queries?: Readonly<Record<string, WorkflowMessagePairSchemas>>;
749
879
  }
750
880
 
751
881
  export declare interface WorkflowMessagesMetadata {
752
882
  readonly signals: Readonly<Record<string, Schema.Schema.Any>>;
753
883
  readonly updates: Readonly<Record<string, WorkflowMessagePairSchemas>>;
754
- readonly queries: Readonly<Record<string, WorkflowMessagePairSchemas>>;
755
884
  }
756
885
 
757
886
  export declare const WorkflowMessagesProperty = "__voltroWorkflowMessages";
@@ -841,6 +970,17 @@ export declare interface WorkflowVersionMetadata {
841
970
  export declare interface WorkflowVersionOptions {
842
971
  readonly version?: string | number;
843
972
  readonly compatibleWith?: ReadonlyArray<string | number>;
973
+ /**
974
+ * Named change markers this workflow's body may branch on, via
975
+ * {@link patch}. Declaring one here is what makes `yield* patch('id')`
976
+ * answer `true` for runs started from now on and `false` for runs that were
977
+ * already in flight — see {@link patch} for the semantics and the worked
978
+ * example.
979
+ *
980
+ * The declared set is stamped onto `_voltro_workflow_runs.workflowPatches`
981
+ * at run start and read back from THERE on every resume, so the answer is
982
+ * pinned to the run and cannot change under a redeploy.
983
+ */
844
984
  readonly patches?: ReadonlyArray<string>;
845
985
  /**
846
986
  * When `true`, a workflow whose top-level body FAILS does not become a
@@ -1,2 +1,2 @@
1
- import { A as e, F as t, M as n, N as r, P as i, S as a, _ as o, a as s, b as c, c as l, d as u, f as d, g as f, h as p, i as m, j as h, l as g, m as _, n as v, o as y, p as b, r as x, s as S, t as C, u as w, v as T, x as E, y as D } from "./primitives-Bp98_F5L.js";
2
- export { e as DEFERRING_CONTROLS, C as WorkflowFlowControlProperty, v as WorkflowMessagesProperty, x as WorkflowVersionTypeId, m as WorkflowWorkerLayerTypeId, h as assertConsistentPools, n as deferringControlsOf, s as durableClock, y as durableQueue, S as durableQueueModule, l as durableRateLimiterModule, g as getWorkflowFlowControl, w as getWorkflowVersionMetadata, r as hasCancelOn, i as hasFlowControl, u as isWorkflowWorkerLayer, d as processQueue, b as queueWorker, _ as rateLimit, p as sleep, f as sleepUntil, o as step, T as stepIdempotencyKey, D as stepModule, t as validateFlowControl, c as withCompensation, E as workflow, a as workflowModule };
1
+ import { B as e, C as t, D as n, E as r, I as i, L as a, R as o, S as s, T as c, V as l, _ as u, a as d, b as f, c as p, d as m, f as h, g, h as _, i as v, l as y, m as b, n as x, o as S, p as C, r as w, s as T, t as E, u as D, v as O, w as k, x as A, y as j, z as M } from "./primitives-oLKOTbvJ.js";
2
+ export { k as CurrentWorkflowReplayShape, i as DEFERRING_CONTROLS, E as WorkflowFlowControlProperty, x as WorkflowMessagesProperty, w as WorkflowVersionTypeId, v as WorkflowWorkerLayerTypeId, a as assertConsistentPools, o as deferringControlsOf, d as durableClock, S as durableQueue, T as durableQueueModule, p as durableRateLimiterModule, y as getWorkflowFlowControl, D as getWorkflowVersionMetadata, M as hasCancelOn, e as hasFlowControl, m as isWorkflowWorkerLayer, c as makeReplayShapeTracker, r as nondeterminismEventPayload, h as patch, C as processQueue, b as queueWorker, _ as rateLimit, n as reportNondeterminism, g as sleep, u as sleepUntil, O as step, j as stepIdempotencyKey, f as stepModule, l as validateFlowControl, A as withCompensation, s as workflow, t as workflowModule };