@voltro/workflow 0.87.0 → 0.88.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.
Files changed (96) hide show
  1. package/CHANGELOG.md +169 -6
  2. package/THIRD-PARTY-NOTICES.md +3 -1346
  3. package/dist/admission.js +1 -2
  4. package/dist/admissionDrainer.js +5 -3
  5. package/dist/admissionGate.js +1 -2
  6. package/dist/admissionStore.js +1 -2
  7. package/dist/admissionSubmission.js +1 -2
  8. package/dist/admissionTables.js +4 -4
  9. package/dist/admissionTransaction.js +1 -2
  10. package/dist/awaitEvent.js +1 -2
  11. package/dist/budgetHold.js +1 -2
  12. package/dist/cancelOnPlan.js +1 -2
  13. package/dist/cancelOnSweep.js +1 -2
  14. package/dist/cancelPendingStart.js +1 -2
  15. package/dist/clusterCron.js +1 -2
  16. package/dist/clusterDiagnostics.js +1 -2
  17. package/dist/clusterDiagnosticsSql.js +1 -2
  18. package/dist/clusterLayer.js +1 -2
  19. package/dist/clusterMigrationGate.js +1 -2
  20. package/dist/clusterRunnerLayer.js +1 -2
  21. package/dist/clusterShardGroups.js +1 -2
  22. package/dist/clusterTestSuite.d.ts +22 -2
  23. package/dist/clusterTestSuite.js +170 -172
  24. package/dist/controlMonitor.js +1 -2
  25. package/dist/controlRequest.js +1 -2
  26. package/dist/executionRefusal.js +1 -2
  27. package/dist/failureHandoff.js +1 -2
  28. package/dist/failureMessage.js +1 -2
  29. package/dist/failureRecovery.js +1 -2
  30. package/dist/failureReportStore.js +1 -2
  31. package/dist/flowControl.js +1 -2
  32. package/dist/forwardStartReceipts.js +1 -2
  33. package/dist/inMemoryLayer.js +1 -2
  34. package/dist/inMemoryRecorder.js +1 -2
  35. package/dist/index.d.ts +3 -1
  36. package/dist/inspectWorkflow.js +2 -3
  37. package/dist/journalEncryption.js +1 -2
  38. package/dist/journalRoutingGuard.js +1 -2
  39. package/dist/journalRoutingLayout.js +1 -2
  40. package/dist/journalRoutingLock.js +1 -2
  41. package/dist/journalRoutingMaintenance.js +1 -2
  42. package/dist/journalRoutingMessageStorage.js +1 -2
  43. package/dist/journalRoutingNamespace.js +1 -2
  44. package/dist/journalRoutingRuntime.js +1 -2
  45. package/dist/journalRoutingSharding.js +1 -2
  46. package/dist/journalRoutingState.js +1 -2
  47. package/dist/journalRoutingTable.js +1 -2
  48. package/dist/journalRoutingTransaction.js +2 -3
  49. package/dist/messages.js +1 -2
  50. package/dist/nondeterminism.js +1 -2
  51. package/dist/parentClosure.js +1 -2
  52. package/dist/parentClosureRecovery.js +1 -2
  53. package/dist/pendingSubmission.js +1 -2
  54. package/dist/prepareSubmissionDispatch.js +1 -2
  55. package/dist/preparedExecution.js +1 -2
  56. package/dist/primitives.js +1 -2
  57. package/dist/queuedCancellationRequest.js +1 -2
  58. package/dist/queuedControl.js +1 -2
  59. package/dist/recorder.js +1 -2
  60. package/dist/residentExecutionEvidence.js +1 -2
  61. package/dist/retryPolicy.js +1 -2
  62. package/dist/runEventsTable.js +1 -2
  63. package/dist/runGeneration.js +1 -2
  64. package/dist/runRecording.js +1 -2
  65. package/dist/runStepsTable.js +1 -2
  66. package/dist/runnerStorageGuard.js +1 -2
  67. package/dist/runsTable.js +1 -2
  68. package/dist/scheduleDeclaration.js +1 -2
  69. package/dist/signalHint.js +1 -2
  70. package/dist/signals.js +1 -2
  71. package/dist/signalsSuspending.js +1 -2
  72. package/dist/sqliteWorkflowOwnership.js +1 -2
  73. package/dist/stalenessSweep.js +1 -2
  74. package/dist/startContextsTable.js +1 -2
  75. package/dist/startReceipt.js +1 -2
  76. package/dist/submissionRecovery.js +1 -2
  77. package/dist/submissionRejection.js +1 -2
  78. package/dist/submissionRetry.js +1 -2
  79. package/dist/suspensionUnavailable.js +1 -2
  80. package/dist/updates.js +1 -2
  81. package/dist/watermarkTable.js +1 -2
  82. package/dist/webCrypto.js +4 -17
  83. package/dist/workflowDelivery.js +1 -2
  84. package/dist/workflowExecutorRouting.js +1 -2
  85. package/dist/workflowJournal.js +1 -2
  86. package/dist/workflowJournalReset.js +1 -2
  87. package/dist/workflowReadSelections.js +1 -2
  88. package/dist/workflowRestartDispatch.js +1 -2
  89. package/dist/workflowRestartObservation.js +1 -2
  90. package/dist/workflowRestartPreparation.js +1 -2
  91. package/dist/workflowRestartReservation.js +4 -4
  92. package/dist/workflowResumeDispatch.js +1 -2
  93. package/dist/workflowRuntimeReadiness.js +1 -2
  94. package/dist/workflowShardRelocation.js +1 -2
  95. package/dist/workflowShardRelocationSql.js +1 -2
  96. package/package.json +5 -11
@@ -9,9 +9,8 @@ import { makeClusterCronLayer as f } from "./clusterCron.js";
9
9
  import { Cause as p, Cron as m, Deferred as h, Effect as g, Fiber as _, Layer as v, ManagedRuntime as y, Option as b, Schema as x } from "effect";
10
10
  import { SqlClient as S } from "effect/sql";
11
11
  import { EntityId as C, Sharding as w } from "effect/cluster";
12
- import { afterEach as T, beforeAll as E, describe as D, expect as O, test as k } from "vitest";
13
- //#region src/clusterTestSuite.ts
14
- var A = async (e, t, n = 750) => {
12
+ // src/clusterTestSuite.ts
13
+ var T = async (e, t, n = 750) => {
15
14
  try {
16
15
  let r = await import("node:net");
17
16
  return await new Promise((i) => {
@@ -27,27 +26,27 @@ var A = async (e, t, n = 750) => {
27
26
  } catch {
28
27
  return !1;
29
28
  }
30
- }, j = [
29
+ }, E = [
31
30
  "cluster_messages",
32
31
  "cluster_replies",
33
32
  "cluster_locks",
34
33
  "cluster_runners"
35
- ], M = async (e) => {
34
+ ], D = async (e) => {
36
35
  try {
37
36
  await g.runPromise(g.gen(function* () {
38
37
  let e = yield* S.SqlClient;
39
- for (let t of j) yield* e.unsafe(`DELETE FROM ${t}`).pipe(g.ignore);
38
+ for (let t of E) yield* e.unsafe(`DELETE FROM ${t}`).pipe(g.ignore);
40
39
  }).pipe(g.scoped, g.provide(e.sqlClientLayer)));
41
40
  } catch {}
42
- }, N = "10 seconds", P = "30 seconds", F = (e, t) => g.gen(function* () {
41
+ }, O = "10 seconds", k = "30 seconds", A = (e, t) => g.gen(function* () {
43
42
  let n = yield* g.sync(() => Date.now() + t);
44
43
  for (; !e();) {
45
44
  if (Date.now() > n) return !1;
46
45
  yield* g.sleep("250 millis");
47
46
  }
48
47
  return !0;
49
- }), I = (e) => {
50
- let t = `${e.name}-${Date.now()}`, n = (t, n) => d({
48
+ }), j = (e, t) => {
49
+ let { describe: n, test: c, expect: l, beforeAll: p } = t, b = `${e.name}-${Date.now()}`, S = (t, n) => d({
51
50
  sqlClientLayer: e.sqlClientLayer,
52
51
  runnerStorage: e.runnerStorage,
53
52
  runnerListenPort: t,
@@ -55,21 +54,21 @@ var A = async (e, t, n = 750) => {
55
54
  ...e.shardLockMode ? { shardLockMode: e.shardLockMode } : {},
56
55
  ...n && n.length > 0 ? { extraShardingLayers: n } : {}
57
56
  });
58
- D(`cluster workflow engine — ${e.name}`, () => {
59
- let c = !1;
60
- E(async () => {
61
- c = await e.reachable(), c ? await M(e) : console.warn(`[skip] cluster suite — ${e.name} not reachable`);
62
- }, 3e4), (e.runnerStorage === "sql" && e.dialectId !== "sqlite" ? k : (() => {}))("client-only submission executes on a distinct worker and never owns its shard", async (r) => {
63
- if (!c) {
64
- r.skip();
57
+ n(`cluster workflow engine — ${e.name}`, () => {
58
+ let t = !1;
59
+ p(async () => {
60
+ t = await e.reachable(), t ? await D(e) : console.warn(`[skip] cluster suite — ${e.name} not reachable`);
61
+ }, 3e4), (e.runnerStorage === "sql" && e.dialectId !== "sqlite" ? c : (() => {}))("client-only submission executes on a distinct worker and never owns its shard", async (n) => {
62
+ if (!t) {
63
+ n.skip();
65
64
  return;
66
65
  }
67
- let i = `roleClient_${t}`, a = s({
68
- name: i,
66
+ let r = `roleClient_${b}`, i = s({
67
+ name: r,
69
68
  payload: { id: x.String },
70
69
  success: x.Number,
71
- idempotencyKey: ({ id: e }) => `${i}:${e}`
72
- }), o = 0, l = 0, u = y.make(a.toLayer(() => g.sync(() => (o++, 42))).pipe(v.provideMerge(n(e.runnerPort)))), f = y.make(a.toLayer(() => g.sync(() => (l++, -1))).pipe(v.provideMerge(d({
70
+ idempotencyKey: ({ id: e }) => `${r}:${e}`
71
+ }), a = 0, o = 0, c = y.make(i.toLayer(() => g.sync(() => (a++, 42))).pipe(v.provideMerge(S(e.runnerPort)))), u = y.make(i.toLayer(() => g.sync(() => (o++, -1))).pipe(v.provideMerge(d({
73
72
  sqlClientLayer: e.sqlClientLayer,
74
73
  runnerStorage: "sql",
75
74
  runnerMode: "client",
@@ -78,24 +77,24 @@ var A = async (e, t, n = 750) => {
78
77
  ...e.shardLockMode ? { shardLockMode: e.shardLockMode } : {}
79
78
  }))));
80
79
  try {
81
- await u.runPromise(g.void), await f.runPromise(g.void);
82
- let e = await f.runPromise(a.execute({ id: "from-client" }).pipe(g.timeout("60 seconds")));
83
- O(e).toBe(42), O(o).toBe(1), O(l).toBe(0), O(await f.runPromise(g.map(w.Sharding, (e) => e.hasShardId(e.getShardId(C.make("client-probe"), "default"))))).toBe(!1), O(await f.runPromise(a.execute({ id: "from-client" }).pipe(g.timeout("60 seconds")))).toBe(42), O(o).toBe(1), O(l).toBe(0);
80
+ await c.runPromise(g.void), await u.runPromise(g.void);
81
+ let e = await u.runPromise(i.execute({ id: "from-client" }).pipe(g.timeout("60 seconds")));
82
+ l(e).toBe(42), l(a).toBe(1), l(o).toBe(0), l(await u.runPromise(g.map(w.Sharding, (e) => e.hasShardId(e.getShardId(C.make("client-probe"), "default"))))).toBe(!1), l(await u.runPromise(i.execute({ id: "from-client" }).pipe(g.timeout("60 seconds")))).toBe(42), l(a).toBe(1), l(o).toBe(0);
84
83
  } finally {
85
84
  try {
86
- await f.dispose();
87
- } finally {
88
85
  await u.dispose();
86
+ } finally {
87
+ await c.dispose();
89
88
  }
90
89
  }
91
- }, 15e4), k("a two-step workflow runs end-to-end", async () => {
92
- if (!c) return;
93
- let r = `clusterTwoStep_${t}`, i = s({
94
- name: r,
90
+ }, 15e4), c("a two-step workflow runs end-to-end", async () => {
91
+ if (!t) return;
92
+ let n = `clusterTwoStep_${b}`, r = s({
93
+ name: n,
95
94
  payload: { id: x.String },
96
95
  success: x.Number,
97
- idempotencyKey: ({ id: e }) => `${r}:${e}`
98
- }), a = i.toLayer(() => g.gen(function* () {
96
+ idempotencyKey: ({ id: e }) => `${n}:${e}`
97
+ }), i = r.toLayer(() => g.gen(function* () {
99
98
  let e = yield* o({
100
99
  name: "first",
101
100
  success: x.Number,
@@ -106,86 +105,86 @@ var A = async (e, t, n = 750) => {
106
105
  success: x.Number,
107
106
  execute: g.succeed(e + 2)
108
107
  });
109
- })), l = await g.runPromise(g.scoped(i.execute({ id: `e2e-${t}` }).pipe(g.provide(a.pipe(v.provideMerge(n(e.runnerPort)))))));
110
- O(l).toBe(42);
111
- }, 3e4), k("idempotency-key journal — same payload returns same result", async () => {
112
- if (!c) return;
113
- let r = `clusterIdempotency_${t}`, i = 0, a = s({
114
- name: r,
108
+ })), a = await g.runPromise(g.scoped(r.execute({ id: `e2e-${b}` }).pipe(g.provide(i.pipe(v.provideMerge(S(e.runnerPort)))))));
109
+ l(a).toBe(42);
110
+ }, 3e4), c("idempotency-key journal — same payload returns same result", async () => {
111
+ if (!t) return;
112
+ let n = `clusterIdempotency_${b}`, r = 0, i = s({
113
+ name: n,
115
114
  payload: { id: x.String },
116
115
  success: x.Number,
117
- idempotencyKey: ({ id: e }) => `${r}:${e}`
118
- }), l = a.toLayer(() => o({
116
+ idempotencyKey: ({ id: e }) => `${n}:${e}`
117
+ }), a = i.toLayer(() => o({
119
118
  name: "compute",
120
119
  success: x.Number,
121
- execute: g.sync(() => (i++, i * 100))
122
- })).pipe(v.provideMerge(n(e.runnerPort))), [u, d] = await g.runPromise(g.scoped(g.gen(function* () {
123
- return [yield* a.execute({ id: `same-${t}` }), yield* a.execute({ id: `same-${t}` })];
124
- }).pipe(g.provide(l))));
125
- O(u).toBe(d), O(i).toBe(1);
126
- }, 3e4), k("ClusterCron fires its execute on the shard owner", async () => {
127
- if (!c) return;
128
- let r = await g.runPromise(h.make()), i = 0, a = f({
129
- name: `clusterCron_${t}`,
120
+ execute: g.sync(() => (r++, r * 100))
121
+ })).pipe(v.provideMerge(S(e.runnerPort))), [c, u] = await g.runPromise(g.scoped(g.gen(function* () {
122
+ return [yield* i.execute({ id: `same-${b}` }), yield* i.execute({ id: `same-${b}` })];
123
+ }).pipe(g.provide(a))));
124
+ l(c).toBe(u), l(r).toBe(1);
125
+ }, 3e4), c("ClusterCron fires its execute on the shard owner", async () => {
126
+ if (!t) return;
127
+ let n = await g.runPromise(h.make()), r = 0, i = f({
128
+ name: `clusterCron_${b}`,
130
129
  cron: m.parseUnsafe("*/1 * * * * *", "UTC"),
131
130
  execute: async () => {
132
- i += 1, await g.runPromise(h.succeed(r, !0)).catch(() => {});
131
+ r += 1, await g.runPromise(h.succeed(n, !0)).catch(() => {});
133
132
  }
134
- }), o = await g.runPromise(g.scoped(g.gen(function* () {
135
- return yield* v.build(n(e.runnerPort + 1, [a])), yield* h.await(r).pipe(g.timeout("25 seconds"), g.orElseSucceed(() => !1));
133
+ }), a = await g.runPromise(g.scoped(g.gen(function* () {
134
+ return yield* v.build(S(e.runnerPort + 1, [i])), yield* h.await(n).pipe(g.timeout("25 seconds"), g.orElseSucceed(() => !1));
136
135
  })));
137
- O(o).toBe(!0), O(i).toBeGreaterThanOrEqual(1);
136
+ l(a).toBe(!0), l(r).toBeGreaterThanOrEqual(1);
138
137
  }, 35e3);
139
- let l = e.clusterResume ? k : (() => {});
140
- l("a sleeping workflow resumes on a fresh runner after the first is torn down", async () => {
141
- if (!c) return;
142
- let r = `dormancyResume_${t}`, i = [], l = [], u = [], d = () => s({
143
- name: r,
138
+ let n = e.clusterResume ? c : (() => {});
139
+ n("a sleeping workflow resumes on a fresh runner after the first is torn down", async () => {
140
+ if (!t) return;
141
+ let n = `dormancyResume_${b}`, r = [], i = [], c = [], u = () => s({
142
+ name: n,
144
143
  payload: { id: x.String },
145
144
  success: x.String,
146
- idempotencyKey: ({ id: e }) => `${r}:${e}`
147
- }), f = (e, t) => e.toLayer(() => g.gen(function* () {
145
+ idempotencyKey: ({ id: e }) => `${n}:${e}`
146
+ }), d = (e, t) => e.toLayer(() => g.gen(function* () {
148
147
  return yield* o({
149
148
  name: "step1",
150
149
  success: x.Void,
151
150
  execute: g.sync(() => {
152
- i.push(t);
151
+ r.push(t);
153
152
  })
154
153
  }), yield* o({
155
154
  name: "armed",
156
155
  success: x.Void,
157
156
  execute: g.sync(() => {
158
- u.push(t);
157
+ c.push(t);
159
158
  })
160
159
  }), yield* a({
161
160
  name: "nap",
162
- duration: N
161
+ duration: O
163
162
  }), yield* o({
164
163
  name: "step2",
165
164
  success: x.Void,
166
165
  execute: g.sync(() => {
167
- l.push(t);
166
+ i.push(t);
168
167
  })
169
168
  }), "done";
170
- })), p = e.runnerPort + 2, m = (e) => {
171
- let t = d();
169
+ })), f = e.runnerPort + 2, p = (e) => {
170
+ let t = u();
172
171
  return {
173
172
  wf: t,
174
- layer: f(t, e).pipe(v.provideMerge(n(p)))
173
+ layer: d(t, e).pipe(v.provideMerge(S(f)))
175
174
  };
176
- }, h = { id: `resume-${t}` }, y = await g.runPromise(g.scoped(g.gen(function* () {
177
- let { wf: e, layer: t } = m("A"), n = yield* v.build(t), r = yield* g.forkDetach(e.execute(h).pipe(g.provide(n), g.ignore));
178
- return (yield* F(() => u.length > 0, 6e4)) ? r : yield* g.die(/* @__PURE__ */ Error("runner A never journaled step1"));
175
+ }, m = { id: `resume-${b}` }, h = await g.runPromise(g.scoped(g.gen(function* () {
176
+ let { wf: e, layer: t } = p("A"), n = yield* v.build(t), r = yield* g.forkDetach(e.execute(m).pipe(g.provide(n), g.ignore));
177
+ return (yield* A(() => c.length > 0, 6e4)) ? r : yield* g.die(/* @__PURE__ */ Error("runner A never journaled step1"));
179
178
  })));
180
- await g.runPromise(_.interrupt(y).pipe(g.ignore)), O(i).toEqual(["A"]), O(l).toEqual([]);
181
- let b = await g.runPromise(g.scoped(g.gen(function* () {
182
- let { wf: e, layer: t } = m("B"), n = yield* v.build(t);
183
- return yield* e.execute(h).pipe(g.provide(n), g.timeout("240 seconds"), g.orElseSucceed(() => "TIMEOUT"));
179
+ await g.runPromise(_.interrupt(h).pipe(g.ignore)), l(r).toEqual(["A"]), l(i).toEqual([]);
180
+ let y = await g.runPromise(g.scoped(g.gen(function* () {
181
+ let { wf: e, layer: t } = p("B"), n = yield* v.build(t);
182
+ return yield* e.execute(m).pipe(g.provide(n), g.timeout("240 seconds"), g.orElseSucceed(() => "TIMEOUT"));
184
183
  })));
185
- O(b).toBe("done"), O(i).toEqual(["A"]), O(l).toEqual(["B"]);
186
- }, 48e4), l("dormancy loop: a wake signal survives teardown and is cleared on resume", async () => {
187
- if (!c) return;
188
- let l = `dormancyLoop_${t}`, d = `wr_${l}`, f = [], p = /* @__PURE__ */ new Map(), m = u({
184
+ l(y).toBe("done"), l(r).toEqual(["A"]), l(i).toEqual(["B"]);
185
+ }, 48e4), n("dormancy loop: a wake signal survives teardown and is cleared on resume", async () => {
186
+ if (!t) return;
187
+ let n = `dormancyLoop_${b}`, c = `wr_${n}`, d = [], f = /* @__PURE__ */ new Map(), p = u({
189
188
  store: {
190
189
  insert: async (e, t) => t,
191
190
  update: async () => null,
@@ -193,63 +192,63 @@ var A = async (e, t, n = 750) => {
193
192
  },
194
193
  wakeups: {
195
194
  register: async (e, t) => {
196
- p.set(e, { wakeAt: t });
195
+ f.set(e, { wakeAt: t });
197
196
  },
198
197
  cancel: async (e) => {
199
- p.delete(e);
198
+ f.delete(e);
200
199
  }
201
200
  }
202
- }), h = () => s({
203
- name: l,
201
+ }), m = () => s({
202
+ name: n,
204
203
  payload: { id: x.String },
205
204
  success: x.String,
206
- idempotencyKey: ({ id: e }) => `${l}:${e}`
207
- }), y = (e, t) => e.toLayer(() => g.gen(function* () {
205
+ idempotencyKey: ({ id: e }) => `${n}:${e}`
206
+ }), h = (e, t) => e.toLayer(() => g.gen(function* () {
208
207
  return yield* o({
209
208
  name: "step1",
210
209
  success: x.Void,
211
210
  execute: g.void
212
211
  }), yield* a({
213
212
  name: "nap",
214
- duration: P
213
+ duration: k
215
214
  }), yield* o({
216
215
  name: "step2",
217
216
  success: x.Void,
218
217
  execute: g.sync(() => {
219
- f.push(t);
218
+ d.push(t);
220
219
  })
221
220
  }), "done";
222
- }).pipe(g.provideService(r, d), g.provideService(i, m))), b = e.runnerPort + 2, S = (e) => {
223
- let t = h();
221
+ }).pipe(g.provideService(r, c), g.provideService(i, p))), y = e.runnerPort + 2, C = (e) => {
222
+ let t = m();
224
223
  return {
225
224
  wf: t,
226
- layer: y(t, e).pipe(v.provideMerge(n(b)))
225
+ layer: h(t, e).pipe(v.provideMerge(S(y)))
227
226
  };
228
- }, C = { id: `loop-${t}` }, w = await g.runPromise(g.scoped(g.gen(function* () {
229
- let { wf: e, layer: t } = S("A"), n = yield* v.build(t), r = yield* g.forkDetach(e.execute(C).pipe(g.provide(n), g.ignore));
230
- return (yield* F(() => p.has(d), 6e4)) ? (yield* g.sleep("1 second"), r) : yield* g.die(/* @__PURE__ */ Error("workflow never registered a wakeup"));
227
+ }, w = { id: `loop-${b}` }, T = await g.runPromise(g.scoped(g.gen(function* () {
228
+ let { wf: e, layer: t } = C("A"), n = yield* v.build(t), r = yield* g.forkDetach(e.execute(w).pipe(g.provide(n), g.ignore));
229
+ return (yield* A(() => f.has(c), 6e4)) ? (yield* g.sleep("1 second"), r) : yield* g.die(/* @__PURE__ */ Error("workflow never registered a wakeup"));
231
230
  })));
232
- await g.runPromise(_.interrupt(w).pipe(g.ignore)), O(p.has(d)).toBe(!0), O(f).toEqual([]);
233
- let T = await g.runPromise(g.scoped(g.gen(function* () {
234
- let { wf: e, layer: t } = S("B"), n = yield* v.build(t);
235
- return yield* e.execute(C).pipe(g.provide(n), g.timeout("600 seconds"), g.orElseSucceed(() => "TIMEOUT"));
231
+ await g.runPromise(_.interrupt(T).pipe(g.ignore)), l(f.has(c)).toBe(!0), l(d).toEqual([]);
232
+ let E = await g.runPromise(g.scoped(g.gen(function* () {
233
+ let { wf: e, layer: t } = C("B"), n = yield* v.build(t);
234
+ return yield* e.execute(w).pipe(g.provide(n), g.timeout("600 seconds"), g.orElseSucceed(() => "TIMEOUT"));
236
235
  })));
237
- O(T).toBe("done"), O(f).toEqual(["B"]), O(p.has(d)).toBe(!1);
236
+ l(E).toBe("done"), l(d).toEqual(["B"]), l(f.has(c)).toBe(!1);
238
237
  }, 9e5);
239
238
  });
240
- }, L = {
239
+ }, M = {
241
240
  encrypt: (e) => `enc:v2:c:${Buffer.from(e, "utf8").toString("base64")}`,
242
241
  decrypt: (e) => Buffer.from(e.slice(9), "base64").toString("utf8")
243
- }, R = (r) => {
244
- let i = `${r.name}-enc-${Date.now()}`, a = () => d({
242
+ }, N = (r, i) => {
243
+ let { describe: a, test: u, expect: f, beforeAll: m, afterEach: h } = i, _ = `${r.name}-enc-${Date.now()}`, y = () => d({
245
244
  sqlClientLayer: r.sqlClientLayer,
246
245
  runnerStorage: r.runnerStorage,
247
246
  runnerListenPort: r.runnerPort + 7,
248
247
  ...r.dialectId ? { dialectId: r.dialectId } : {}
249
- }), u = (e) => g.runPromise(g.gen(function* () {
248
+ }), C = (e) => g.runPromise(g.gen(function* () {
250
249
  let t = yield* S.SqlClient, n = yield* t.unsafe("SELECT * FROM cluster_messages"), r = yield* t.unsafe("SELECT * FROM cluster_replies"), i = (e) => JSON.stringify(e, (e, t) => typeof t == "bigint" ? String(t) : t);
251
250
  return [...n, ...r].filter((t) => i(t).includes(e)).length;
252
- }).pipe(g.provideService(S.SafeIntegers, !0), g.scoped, g.provide(r.sqlClientLayer))), f = (e, t) => {
251
+ }).pipe(g.provideService(S.SafeIntegers, !0), g.scoped, g.provide(r.sqlClientLayer))), w = (e, t) => {
253
252
  let n = s({
254
253
  name: e,
255
254
  payload: {
@@ -271,45 +270,45 @@ var A = async (e, t, n = 750) => {
271
270
  })),
272
271
  executions: () => r
273
272
  };
274
- }, m = (e, t) => g.runPromise(g.scoped(e.wf.execute(t).pipe(g.provide(e.handler.pipe(v.provideMerge(a()))))));
275
- D(`encrypted workflow journal — ${r.name}`, () => {
276
- let d = !1;
277
- E(async () => {
278
- d = await r.reachable(), d && await M(r);
279
- }, 3e4), T(() => n(void 0)), k("payload, step result and result are ciphertext; the unencrypted twin is found (control)", async (e) => {
280
- d || e.skip(), n(L);
281
- let t = f(`journalPlain_${i}`, !1), r = f(`journalSealed_${i}`, !0);
282
- O(await m(t, {
273
+ }, T = (e, t) => g.runPromise(g.scoped(e.wf.execute(t).pipe(g.provide(e.handler.pipe(v.provideMerge(y()))))));
274
+ a(`encrypted workflow journal — ${r.name}`, () => {
275
+ let i = !1;
276
+ m(async () => {
277
+ i = await r.reachable(), i && await D(r);
278
+ }, 3e4), h(() => n(void 0)), u("payload, step result and result are ciphertext; the unencrypted twin is found (control)", async (e) => {
279
+ i || e.skip(), n(M);
280
+ let t = w(`journalPlain_${_}`, !1), r = w(`journalSealed_${_}`, !0);
281
+ f(await T(t, {
283
282
  note: "PLAINMARK",
284
283
  count: 1
285
- })).toEqual({ summary: "RESULT-STEP-PLAINMARK" }), O(await m(r, {
284
+ })).toEqual({ summary: "RESULT-STEP-PLAINMARK" }), f(await T(r, {
286
285
  note: "SEALMARK",
287
286
  count: 1
288
- })).toEqual({ summary: "RESULT-STEP-SEALMARK" }), O(await u("PLAINMARK"), "the probe finds plaintext").toBeGreaterThan(0), O(await u("SEALMARK"), "no journal row carries the encrypted run in plaintext").toBe(0), O(await u("enc:v2:c:"), "and the ciphertext is there").toBeGreaterThan(0);
289
- }, 6e4), k("a second execute replays the result from the encrypted journal without re-running the step", async (e) => {
290
- d || e.skip(), n(L);
291
- let t = f(`journalReplay_${i}`, !0), r = await m(t, {
287
+ })).toEqual({ summary: "RESULT-STEP-SEALMARK" }), f(await C("PLAINMARK"), "the probe finds plaintext").toBeGreaterThan(0), f(await C("SEALMARK"), "no journal row carries the encrypted run in plaintext").toBe(0), f(await C("enc:v2:c:"), "and the ciphertext is there").toBeGreaterThan(0);
288
+ }, 6e4), u("a second execute replays the result from the encrypted journal without re-running the step", async (e) => {
289
+ i || e.skip(), n(M);
290
+ let t = w(`journalReplay_${_}`, !0), r = await T(t, {
292
291
  note: "REPLAYMARK",
293
292
  count: 7
294
- }), a = await m(t, {
293
+ }), a = await T(t, {
295
294
  note: "REPLAYMARK",
296
295
  count: 7
297
296
  });
298
- O(a).toEqual(r), O(t.executions()).toBe(1);
299
- }, 6e4), k("a run journaled in plaintext before the declaration is still read", async (e) => {
300
- d || e.skip();
301
- let t = `journalBefore_${i}`, r = await m(f(t, !1), {
297
+ f(a).toEqual(r), f(t.executions()).toBe(1);
298
+ }, 6e4), u("a run journaled in plaintext before the declaration is still read", async (e) => {
299
+ i || e.skip();
300
+ let t = `journalBefore_${_}`, r = await T(w(t, !1), {
302
301
  note: "OLDMARK",
303
302
  count: 3
304
303
  });
305
- n(L);
306
- let a = f(t, !0);
307
- O(await m(a, {
304
+ n(M);
305
+ let a = w(t, !0);
306
+ f(await T(a, {
308
307
  note: "OLDMARK",
309
308
  count: 3
310
- })).toEqual(r), O(a.executions(), "answered from the plaintext journal, not re-run").toBe(0);
309
+ })).toEqual(r), f(a.executions(), "answered from the plaintext journal, not re-run").toBe(0);
311
310
  }, 6e4);
312
- let h = (e, t, n) => {
311
+ let a = (e, t, n) => {
313
312
  class r extends x.TaggedError()("Refused", { detail: x.String }) {}
314
313
  let i = s({
315
314
  name: e,
@@ -317,23 +316,23 @@ var A = async (e, t, n = 750) => {
317
316
  error: r,
318
317
  idempotencyKey: ({ note: t }) => `${e}:${t}`,
319
318
  encrypted: t
320
- }), c = i.toLayer(({ note: e }) => o({
319
+ }), a = i.toLayer(({ note: e }) => o({
321
320
  name: "call-upstream",
322
321
  success: x.String,
323
322
  error: r,
324
323
  execute: n === "defect" ? g.die(/* @__PURE__ */ Error(`upstream rejected FAILMARK-${e}`)) : g.fail(new r({ detail: `FAILMARK-${e}` }))
325
324
  }));
326
- return g.runPromiseExit(g.scoped(i.execute({ note: e }).pipe(g.provide(c.pipe(v.provideMerge(a()))))));
325
+ return g.runPromiseExit(g.scoped(i.execute({ note: e }).pipe(g.provide(a.pipe(v.provideMerge(y()))))));
327
326
  };
328
- for (let t of ["defect", "typed"]) k(`a ${t} failure of an encrypted run leaves no plaintext; the unencrypted twin does (control)`, async (r) => {
329
- d || r.skip(), n(L);
330
- let a = await h(`journalFailPlain_${t}_${i}`, !1, t);
331
- O(a._tag).toBe("Failure"), O(await u(`FAILMARK-journalFailPlain_${t}`), "the probe finds plaintext").toBeGreaterThan(0);
332
- let o = await h(`journalFailSealed_${t}_${i}`, !0, t);
333
- O(o._tag).toBe("Failure"), O(await u(`FAILMARK-journalFailSealed_${t}`), "no journal row carries the failure in plaintext").toBe(0), O(e(p.squash(o.cause))).toContain(`FAILMARK-journalFailSealed_${t}`);
327
+ for (let t of ["defect", "typed"]) u(`a ${t} failure of an encrypted run leaves no plaintext; the unencrypted twin does (control)`, async (r) => {
328
+ i || r.skip(), n(M);
329
+ let o = await a(`journalFailPlain_${t}_${_}`, !1, t);
330
+ f(o._tag).toBe("Failure"), f(await C(`FAILMARK-journalFailPlain_${t}`), "the probe finds plaintext").toBeGreaterThan(0);
331
+ let s = await a(`journalFailSealed_${t}_${_}`, !0, t);
332
+ f(s._tag).toBe("Failure"), f(await C(`FAILMARK-journalFailSealed_${t}`), "no journal row carries the failure in plaintext").toBe(0), f(e(p.squash(s.cause))).toContain(`FAILMARK-journalFailSealed_${t}`);
334
333
  }, 6e4);
335
- k("a journaled wait value of an encrypted run is ciphertext; the unencrypted twin is found (control)", async (e) => {
336
- d || e.skip(), n(L);
334
+ u("a journaled wait value of an encrypted run is ciphertext; the unencrypted twin is found (control)", async (e) => {
335
+ i || e.skip(), n(M);
337
336
  let r = (e, n) => {
338
337
  let r = s({
339
338
  name: e,
@@ -346,88 +345,87 @@ var A = async (e, t, n = 750) => {
346
345
  success: x.String,
347
346
  execute: g.succeed(`WAITMARK-${e}`)
348
347
  }));
349
- return g.runPromise(g.scoped(r.execute({ note: e }).pipe(g.provide(i.pipe(v.provideMerge(a()))))));
348
+ return g.runPromise(g.scoped(r.execute({ note: e }).pipe(g.provide(i.pipe(v.provideMerge(y()))))));
350
349
  };
351
- O(await r(`journalWaitPlain_${i}`, !1)).toBe(`WAITMARK-journalWaitPlain_${i}`), O(await u(`WAITMARK-journalWaitPlain_${i}`), "the probe finds plaintext").toBeGreaterThan(0), O(await r(`journalWaitSealed_${i}`, !0)).toBe(`WAITMARK-journalWaitSealed_${i}`), O(await u(`WAITMARK-journalWaitSealed_${i}`), "no plaintext wait value in the journal").toBe(0);
350
+ f(await r(`journalWaitPlain_${_}`, !1)).toBe(`WAITMARK-journalWaitPlain_${_}`), f(await C(`WAITMARK-journalWaitPlain_${_}`), "the probe finds plaintext").toBeGreaterThan(0), f(await r(`journalWaitSealed_${_}`, !0)).toBe(`WAITMARK-journalWaitSealed_${_}`), f(await C(`WAITMARK-journalWaitSealed_${_}`), "no plaintext wait value in the journal").toBe(0);
352
351
  }, 6e4);
353
- let _ = (e, t, n) => g.gen(function* () {
352
+ let d = (e, t, n) => g.gen(function* () {
354
353
  for (let r = 0; r < 400; r++) {
355
354
  let r = yield* e.poll(t);
356
355
  if (n(r)) return r;
357
356
  yield* g.sleep("50 millis");
358
357
  }
359
358
  return yield* g.die(/* @__PURE__ */ Error("pollUntil: never satisfied"));
360
- }), y = (e) => b.isOption(e) && b.isSome(e) ? e.value._tag : void 0;
361
- for (let e of [!1, !0]) k(`a suspending signal's value is ${e ? "ciphertext" : "found (control)"} in the journal, and the run resumes with it`, async (t) => {
362
- d || t.skip(), n(L);
363
- let r = `journalSignal_${e ? "sealed" : "plain"}_${i}`, o = s({
359
+ }), S = (e) => b.isOption(e) && b.isSome(e) ? e.value._tag : void 0;
360
+ for (let e of [!1, !0]) u(`a suspending signal's value is ${e ? "ciphertext" : "found (control)"} in the journal, and the run resumes with it`, async (t) => {
361
+ i || t.skip(), n(M);
362
+ let r = `journalSignal_${e ? "sealed" : "plain"}_${_}`, a = s({
364
363
  name: r,
365
364
  payload: { id: x.String },
366
365
  success: x.Unknown,
367
366
  idempotencyKey: ({ id: e }) => `${r}:${e}`,
368
367
  encrypted: e
369
- }), f = o.toLayer(() => c({ store: { query: () => Promise.resolve([]) } }, {
368
+ }), o = a.toLayer(() => c({ store: { query: () => Promise.resolve([]) } }, {
370
369
  name: "approval",
371
370
  schema: x.Struct({ comment: x.String }),
372
371
  timeoutMs: 36e5
373
- })), p = `SIGNALMARK-${r}`, m = await g.runPromise(g.scoped(g.gen(function* () {
374
- let e = yield* o.executionId({ id: "one" });
375
- return yield* o.execute({ id: "one" }, { discard: !0 }), yield* _(o, e, (e) => y(e) === "Suspended"), yield* l({
372
+ })), u = `SIGNALMARK-${r}`, p = await g.runPromise(g.scoped(g.gen(function* () {
373
+ let e = yield* a.executionId({ id: "one" });
374
+ return yield* a.execute({ id: "one" }, { discard: !0 }), yield* d(a, e, (e) => S(e) === "Suspended"), yield* l({
376
375
  target: {
377
376
  executionId: e,
378
377
  workflowName: r
379
378
  },
380
379
  signalName: "approval",
381
- payload: { comment: p }
382
- }), yield* _(o, e, (e) => y(e) === "Complete");
383
- }).pipe(g.provide(f.pipe(v.provideMerge(a()))))));
384
- O(JSON.stringify(b.getOrThrow(m).exit), "the body received the value").toContain(p);
385
- let h = await u(p);
386
- e ? O(h, "no plaintext signal value in the journal").toBe(0) : O(h, "the probe finds plaintext").toBeGreaterThan(0);
380
+ payload: { comment: u }
381
+ }), yield* d(a, e, (e) => S(e) === "Complete");
382
+ }).pipe(g.provide(o.pipe(v.provideMerge(y()))))));
383
+ f(JSON.stringify(b.getOrThrow(p).exit), "the body received the value").toContain(u);
384
+ let m = await C(u);
385
+ e ? f(m, "no plaintext signal value in the journal").toBe(0) : f(m, "the probe finds plaintext").toBeGreaterThan(0);
387
386
  }, 9e4);
388
- k("an encrypted child's defect reaches its encrypted parent as thrown, and no journal row carries it", async (e) => {
389
- d || e.skip(), n(L);
390
- let t = `journalChild_${i}`, r = `journalParent_${i}`, o = `CHILDMARK-${i}`, c = s({
387
+ u("an encrypted child's defect reaches its encrypted parent as thrown, and no journal row carries it", async (e) => {
388
+ i || e.skip(), n(M);
389
+ let t = `journalChild_${_}`, r = `journalParent_${_}`, a = `CHILDMARK-${_}`, o = s({
391
390
  name: t,
392
391
  payload: { id: x.String },
393
392
  success: x.String,
394
393
  idempotencyKey: ({ id: e }) => e,
395
394
  encrypted: !0
396
- }), l = s({
395
+ }), c = s({
397
396
  name: r,
398
397
  payload: { id: x.String },
399
398
  success: x.String,
400
399
  idempotencyKey: ({ id: e }) => e,
401
400
  encrypted: !0
402
- }), f = c.toLayer(() => g.die(/* @__PURE__ */ Error(`child failed ${o}`))), p = l.toLayer(({ id: e }) => c.execute({ id: `${e}-child` }).pipe(g.catchDefect((e) => g.succeed(`caught: ${e.message}`)))), m = await g.runPromise(g.scoped(l.execute({ id: "p1" }).pipe(g.provide(v.mergeAll(p, f).pipe(v.provideMerge(a()))))));
403
- O(m).toBe(`caught: child failed ${o}`), O(await u(o)).toBe(0);
404
- }, 6e4), k("an encrypted run that suspends on a failed step journals no plaintext", async (e) => {
405
- d || e.skip(), n(L);
406
- let t = `journalSuspendOnFailure_${i}`, r = `SOFMARK-${i}`, c = s({
401
+ }), l = o.toLayer(() => g.die(/* @__PURE__ */ Error(`child failed ${a}`))), u = c.toLayer(({ id: e }) => o.execute({ id: `${e}-child` }).pipe(g.catchDefect((e) => g.succeed(`caught: ${e.message}`)))), d = await g.runPromise(g.scoped(c.execute({ id: "p1" }).pipe(g.provide(v.mergeAll(u, l).pipe(v.provideMerge(y()))))));
402
+ f(d).toBe(`caught: child failed ${a}`), f(await C(a)).toBe(0);
403
+ }, 6e4), u("an encrypted run that suspends on a failed step journals no plaintext", async (e) => {
404
+ i || e.skip(), n(M);
405
+ let t = `journalSuspendOnFailure_${_}`, r = `SOFMARK-${_}`, a = s({
407
406
  name: t,
408
407
  payload: { id: x.String },
409
408
  success: x.String,
410
409
  idempotencyKey: ({ id: e }) => e,
411
410
  encrypted: !0,
412
411
  suspendOnFailure: !0
413
- }), l = c.toLayer(() => o({
412
+ }), c = a.toLayer(() => o({
414
413
  name: "call",
415
414
  success: x.String,
416
415
  execute: g.die(/* @__PURE__ */ Error(`step failed ${r}`))
417
416
  }));
418
417
  await g.runPromise(g.scoped(g.gen(function* () {
419
- let e = yield* c.executionId({ id: "s1" });
420
- yield* c.execute({ id: "s1" }, { discard: !0 }), yield* _(c, e, (e) => y(e) === "Suspended");
421
- }).pipe(g.provide(l.pipe(v.provideMerge(a())))))), O(await u(r)).toBe(0);
422
- }, 6e4), k("without a registered cipher an encrypted run fails instead of writing plaintext", async (e) => {
423
- d || e.skip();
424
- let t = f(`journalNoCipher_${i}`, !0);
425
- await O(m(t, {
418
+ let e = yield* a.executionId({ id: "s1" });
419
+ yield* a.execute({ id: "s1" }, { discard: !0 }), yield* d(a, e, (e) => S(e) === "Suspended");
420
+ }).pipe(g.provide(c.pipe(v.provideMerge(y())))))), f(await C(r)).toBe(0);
421
+ }, 6e4), u("without a registered cipher an encrypted run fails instead of writing plaintext", async (e) => {
422
+ i || e.skip();
423
+ let t = w(`journalNoCipher_${_}`, !0);
424
+ await f(T(t, {
426
425
  note: "NOCIPHERMARK",
427
426
  count: 1
428
- })).rejects.toThrow(), O(await u("NOCIPHERMARK")).toBe(0);
427
+ })).rejects.toThrow(), f(await C("NOCIPHERMARK")).toBe(0);
429
428
  }, 6e4);
430
429
  });
431
430
  };
432
- //#endregion
433
- export { M as purgeClusterState, I as runClusterEngineSuite, R as runJournalEncryptionSuite, A as tcpReachable };
431
+ export { D as purgeClusterState, j as runClusterEngineSuite, N as runJournalEncryptionSuite, T as tcpReachable };
@@ -1,7 +1,7 @@
1
1
  import { readPendingWorkflowCancellation as e } from "./controlRequest.js";
2
2
  import { Effect as t } from "effect";
3
3
  import { WorkflowInstance as n } from "effect/workflow/WorkflowEngine";
4
- //#region src/controlMonitor.ts
4
+ // src/controlMonitor.ts
5
5
  var r = (r, i, a) => t.gen(function* () {
6
6
  let o = yield* n;
7
7
  for (;;) {
@@ -9,5 +9,4 @@ var r = (r, i, a) => t.gen(function* () {
9
9
  yield* t.sleep(1e3);
10
10
  }
11
11
  });
12
- //#endregion
13
12
  export { r as awaitWorkflowCancellation };
@@ -1,7 +1,7 @@
1
1
  import { isWorkflowEncrypted as e, sealErrorText as t, sealJournalValue as n } from "./journalEncryption.js";
2
2
  import { Schema as r } from "effect";
3
3
  import { and as i, derivedRowId as a, eq as o, gt as s, or as c } from "@voltro/database";
4
- //#region src/controlRequest.ts
4
+ // src/controlRequest.ts
5
5
  var l = "_voltro_workflow_control_requests", u = r.String.pipe(r.check(r.isMinLength(1))), d = r.Struct({
6
6
  kind: r.Literals(["confirmed", "already-terminal"]),
7
7
  status: r.Literals([
@@ -363,5 +363,4 @@ var l = "_voltro_workflow_control_requests", u = r.String.pipe(r.check(r.isMinLe
363
363
  u = r.id;
364
364
  }
365
365
  };
366
- //#endregion
367
366
  export { l as CONTROL_REQUESTS_TABLE, w as FLOW_CONTROL_FINISH_TIMEOUT, k as acceptWorkflowControlInTransaction, j as beginWorkflowControlDispatchInTransaction, A as bindWorkflowResumeJournalInTransaction, E as finishTimeoutCause, C as hasPendingWorkflowCancellation, O as hasUnsettledParentClosureControls, S as readPendingWorkflowCancellation, x as readPendingWorkflowCancellations, D as readWorkflowControlInTransaction, M as settleWorkflowControlsInTransaction, N as settleWorkflowResumesInTransaction };
@@ -6,7 +6,7 @@ import { Cause as o, Effect as s, Schema as c } from "effect";
6
6
  import { SubjectIdentity as l, publishServerError as u } from "@voltro/protocol";
7
7
  import { randomUUID as d } from "node:crypto";
8
8
  import { WorkflowInstance as f } from "effect/workflow/WorkflowEngine";
9
- //#region src/executionRefusal.ts
9
+ // src/executionRefusal.ts
10
10
  var p = (p, m) => s.gen(function* () {
11
11
  let h = yield* s.sync(() => c.decodeUnknownSync(l)(p.subject));
12
12
  if (h.tenantId !== p.failureContext.tenantId) return yield* s.die(/* @__PURE__ */ Error("Workflow refusal has inconsistent caller tenant"));
@@ -158,5 +158,4 @@ var p = (p, m) => s.gen(function* () {
158
158
  });
159
159
  }), yield* s.failCause(m.cause);
160
160
  });
161
- //#endregion
162
161
  export { p as recordWorkflowExecutionRefusal };
@@ -6,7 +6,7 @@ import { PENDING_TABLE as f, parkDelayedStart as p, retryBackoffMs as m } from "
6
6
  import { Schema as h } from "effect";
7
7
  import { and as g, eq as _, gt as v, isNull as y } from "@voltro/database";
8
8
  import { createHash as b } from "node:crypto";
9
- //#region src/failureHandoff.ts
9
+ // src/failureHandoff.ts
10
10
  var x = async (e, t, n) => {
11
11
  let r, a = t === "submissionId" ? _(t, n) : g(_(t, n), y("submissionId"), y("terminal"));
12
12
  for (;;) {
@@ -179,5 +179,4 @@ var x = async (e, t, n) => {
179
179
  executionId: c.executionId
180
180
  };
181
181
  };
182
- //#endregion
183
182
  export { j as FailureReconciliationError, A as handoffWorkflowFailureInTransaction, w as isFailureDeliveryExecution, C as isFailureDeliveryPending, S as isFailureDeliverySubmission, M as reconcileWorkflowFailureInTransaction };