@voltro/workflow 0.81.0 → 0.82.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.
@@ -72,6 +72,8 @@ export declare const purgeClusterState: (fixture: ClusterEngineFixture) => Promi
72
72
  */
73
73
  export declare const runClusterEngineSuite: (fixture: ClusterEngineFixture) => void;
74
74
 
75
+ export declare const runJournalEncryptionSuite: (fixture: ClusterEngineFixture) => void;
76
+
75
77
  /**
76
78
  * Runner-storage backend for `@effect/cluster.SingleRunner`.
77
79
  *
@@ -1,11 +1,12 @@
1
- import { F as e, R as t, S as n, g as r, v as i } from "./primitives-BJBn8tiH.js";
2
- import { r as a } from "./src-D_GRCNhv.js";
3
- import { i as o, p as s } from "./cluster-D7VuRhM0.js";
4
- import { Cron as c, Deferred as l, Effect as u, Fiber as d, Layer as f, Schema as p } from "effect";
5
- import { SqlClient as m } from "@effect/sql";
6
- import { beforeAll as h, describe as g, expect as _, test as v } from "vitest";
1
+ import { F as e, R as t, S as n, g as r, v as i } from "./primitives-Btjhjm8P.js";
2
+ import { E as a, a as o } from "./journalEncryption--n5VDdYO.js";
3
+ import { C as s, r as c, w as l } from "./src-BAN5Xovf.js";
4
+ import { t as u, u as d } from "./cluster-MboOAwcv.js";
5
+ import { Cause as f, Cron as p, Deferred as m, Effect as h, Fiber as g, Layer as _, Schema as v } from "effect";
6
+ import { SqlClient as y } from "@effect/sql";
7
+ import { afterEach as b, beforeAll as x, describe as S, expect as C, test as w } from "vitest";
7
8
  //#region src/clusterTestSuite.ts
8
- var y = async (e, t, n = 750) => {
9
+ var T = async (e, t, n = 750) => {
9
10
  try {
10
11
  let r = await import("node:net");
11
12
  return await new Promise((i) => {
@@ -21,140 +22,140 @@ var y = async (e, t, n = 750) => {
21
22
  } catch {
22
23
  return !1;
23
24
  }
24
- }, b = [
25
+ }, E = [
25
26
  "cluster_messages",
26
27
  "cluster_replies",
27
28
  "cluster_locks",
28
29
  "cluster_runners"
29
- ], x = async (e) => {
30
+ ], D = async (e) => {
30
31
  try {
31
- await u.runPromise(u.gen(function* () {
32
- let e = yield* m.SqlClient;
33
- for (let t of b) yield* e.unsafe(`DELETE FROM ${t}`).pipe(u.ignore);
34
- }).pipe(u.scoped, u.provide(e.sqlClientLayer)));
32
+ await h.runPromise(h.gen(function* () {
33
+ let e = yield* y.SqlClient;
34
+ for (let t of E) yield* e.unsafe(`DELETE FROM ${t}`).pipe(h.ignore);
35
+ }).pipe(h.scoped, h.provide(e.sqlClientLayer)));
35
36
  } catch {}
36
- }, S = "10 seconds", C = "30 seconds", w = (e, t) => u.gen(function* () {
37
- let n = yield* u.sync(() => Date.now() + t);
37
+ }, O = "10 seconds", k = "30 seconds", A = (e, t) => h.gen(function* () {
38
+ let n = yield* h.sync(() => Date.now() + t);
38
39
  for (; !e();) {
39
40
  if (Date.now() > n) return !1;
40
- yield* u.sleep("250 millis");
41
+ yield* h.sleep("250 millis");
41
42
  }
42
43
  return !0;
43
- }), T = (m) => {
44
- let y = `${m.name}-${Date.now()}`, b = (e, t) => s({
45
- sqlClientLayer: m.sqlClientLayer,
46
- runnerStorage: m.runnerStorage,
44
+ }), j = (a) => {
45
+ let o = `${a.name}-${Date.now()}`, s = (e, t) => d({
46
+ sqlClientLayer: a.sqlClientLayer,
47
+ runnerStorage: a.runnerStorage,
47
48
  runnerListenPort: e,
48
- ...m.dialectId ? { dialectId: m.dialectId } : {},
49
- ...m.shardLockMode ? { shardLockMode: m.shardLockMode } : {},
49
+ ...a.dialectId ? { dialectId: a.dialectId } : {},
50
+ ...a.shardLockMode ? { shardLockMode: a.shardLockMode } : {},
50
51
  ...t && t.length > 0 ? { extraShardingLayers: t } : {}
51
52
  });
52
- g(`cluster workflow engine — ${m.name}`, () => {
53
- let s = !1;
54
- h(async () => {
55
- if (s = await m.reachable(), !s) {
56
- console.warn(`[skip] cluster suite — ${m.name} not reachable`);
53
+ S(`cluster workflow engine — ${a.name}`, () => {
54
+ let l = !1;
55
+ x(async () => {
56
+ if (l = await a.reachable(), !l) {
57
+ console.warn(`[skip] cluster suite — ${a.name} not reachable`);
57
58
  return;
58
59
  }
59
- await x(m);
60
- }, 3e4), v("a two-step workflow runs end-to-end", async () => {
61
- if (!s) return;
62
- let e = `clusterTwoStep_${y}`, t = n({
60
+ await D(a);
61
+ }, 3e4), w("a two-step workflow runs end-to-end", async () => {
62
+ if (!l) return;
63
+ let e = `clusterTwoStep_${o}`, t = n({
63
64
  name: e,
64
- payload: { id: p.String },
65
- success: p.Number,
65
+ payload: { id: v.String },
66
+ success: v.Number,
66
67
  idempotencyKey: ({ id: t }) => `${e}:${t}`
67
- }), r = t.toLayer(() => u.gen(function* () {
68
+ }), r = t.toLayer(() => h.gen(function* () {
68
69
  let e = yield* i({
69
70
  name: "first",
70
- success: p.Number,
71
- execute: u.succeed(40)
71
+ success: v.Number,
72
+ execute: h.succeed(40)
72
73
  });
73
74
  return yield* i({
74
75
  name: "second",
75
- success: p.Number,
76
- execute: u.succeed(e + 2)
76
+ success: v.Number,
77
+ execute: h.succeed(e + 2)
77
78
  });
78
- })), a = await u.runPromise(u.scoped(t.execute({ id: `e2e-${y}` }).pipe(u.provide(r.pipe(f.provideMerge(b(m.runnerPort)))))));
79
- _(a).toBe(42);
80
- }, 3e4), v("idempotency-key journal — same payload returns same result", async () => {
81
- if (!s) return;
82
- let e = `clusterIdempotency_${y}`, t = 0, r = n({
79
+ })), c = await h.runPromise(h.scoped(t.execute({ id: `e2e-${o}` }).pipe(h.provide(r.pipe(_.provideMerge(s(a.runnerPort)))))));
80
+ C(c).toBe(42);
81
+ }, 3e4), w("idempotency-key journal — same payload returns same result", async () => {
82
+ if (!l) return;
83
+ let e = `clusterIdempotency_${o}`, t = 0, r = n({
83
84
  name: e,
84
- payload: { id: p.String },
85
- success: p.Number,
85
+ payload: { id: v.String },
86
+ success: v.Number,
86
87
  idempotencyKey: ({ id: t }) => `${e}:${t}`
87
- }), a = r.toLayer(() => i({
88
+ }), c = r.toLayer(() => i({
88
89
  name: "compute",
89
- success: p.Number,
90
- execute: u.sync(() => (t++, t * 100))
91
- })).pipe(f.provideMerge(b(m.runnerPort))), [o, c] = await u.runPromise(u.scoped(u.gen(function* () {
92
- return [yield* r.execute({ id: `same-${y}` }), yield* r.execute({ id: `same-${y}` })];
93
- }).pipe(u.provide(a))));
94
- _(o).toBe(c), _(t).toBe(1);
95
- }, 3e4), v("ClusterCron fires its execute on the shard owner", async () => {
96
- if (!s) return;
97
- let e = await u.runPromise(l.make()), t = 0, n = o({
98
- name: `clusterCron_${y}`,
99
- cron: c.unsafeParse("*/1 * * * * *", "UTC"),
90
+ success: v.Number,
91
+ execute: h.sync(() => (t++, t * 100))
92
+ })).pipe(_.provideMerge(s(a.runnerPort))), [u, d] = await h.runPromise(h.scoped(h.gen(function* () {
93
+ return [yield* r.execute({ id: `same-${o}` }), yield* r.execute({ id: `same-${o}` })];
94
+ }).pipe(h.provide(c))));
95
+ C(u).toBe(d), C(t).toBe(1);
96
+ }, 3e4), w("ClusterCron fires its execute on the shard owner", async () => {
97
+ if (!l) return;
98
+ let e = await h.runPromise(m.make()), t = 0, n = u({
99
+ name: `clusterCron_${o}`,
100
+ cron: p.unsafeParse("*/1 * * * * *", "UTC"),
100
101
  execute: async () => {
101
- t += 1, await u.runPromise(l.succeed(e, !0)).catch(() => {});
102
+ t += 1, await h.runPromise(m.succeed(e, !0)).catch(() => {});
102
103
  }
103
- }), r = await u.runPromise(u.scoped(u.gen(function* () {
104
- return yield* f.build(b(m.runnerPort + 1, [n])), yield* l.await(e).pipe(u.timeout("25 seconds"), u.orElseSucceed(() => !1));
104
+ }), r = await h.runPromise(h.scoped(h.gen(function* () {
105
+ return yield* _.build(s(a.runnerPort + 1, [n])), yield* m.await(e).pipe(h.timeout("25 seconds"), h.orElseSucceed(() => !1));
105
106
  })));
106
- _(r).toBe(!0), _(t).toBeGreaterThanOrEqual(1);
107
+ C(r).toBe(!0), C(t).toBeGreaterThanOrEqual(1);
107
108
  }, 35e3);
108
- let g = m.clusterResume ? v : (() => {});
109
- g("a sleeping workflow resumes on a fresh runner after the first is torn down", async () => {
110
- if (!s) return;
111
- let e = `dormancyResume_${y}`, t = [], a = [], o = [], c = () => n({
109
+ let d = a.clusterResume ? w : (() => {});
110
+ d("a sleeping workflow resumes on a fresh runner after the first is torn down", async () => {
111
+ if (!l) return;
112
+ let e = `dormancyResume_${o}`, t = [], c = [], u = [], d = () => n({
112
113
  name: e,
113
- payload: { id: p.String },
114
- success: p.String,
114
+ payload: { id: v.String },
115
+ success: v.String,
115
116
  idempotencyKey: ({ id: t }) => `${e}:${t}`
116
- }), l = (e, n) => e.toLayer(() => u.gen(function* () {
117
+ }), f = (e, n) => e.toLayer(() => h.gen(function* () {
117
118
  return yield* i({
118
119
  name: "step1",
119
- success: p.Void,
120
- execute: u.sync(() => {
120
+ success: v.Void,
121
+ execute: h.sync(() => {
121
122
  t.push(n);
122
123
  })
123
124
  }), yield* i({
124
125
  name: "armed",
125
- success: p.Void,
126
- execute: u.sync(() => {
127
- o.push(n);
126
+ success: v.Void,
127
+ execute: h.sync(() => {
128
+ u.push(n);
128
129
  })
129
130
  }), yield* r({
130
131
  name: "nap",
131
- duration: S
132
+ duration: O
132
133
  }), yield* i({
133
134
  name: "step2",
134
- success: p.Void,
135
- execute: u.sync(() => {
136
- a.push(n);
135
+ success: v.Void,
136
+ execute: h.sync(() => {
137
+ c.push(n);
137
138
  })
138
139
  }), "done";
139
- })), h = m.runnerPort + 2, g = (e) => {
140
- let t = c();
140
+ })), p = a.runnerPort + 2, m = (e) => {
141
+ let t = d();
141
142
  return {
142
143
  wf: t,
143
- layer: l(t, e).pipe(f.provideMerge(b(h)))
144
+ layer: f(t, e).pipe(_.provideMerge(s(p)))
144
145
  };
145
- }, v = { id: `resume-${y}` }, x = await u.runPromise(u.scoped(u.gen(function* () {
146
- let { wf: e, layer: t } = g("A"), n = yield* f.build(t), r = yield* u.forkDaemon(e.execute(v).pipe(u.provide(n), u.ignore));
147
- return (yield* w(() => o.length > 0, 6e4)) ? r : yield* u.die(/* @__PURE__ */ Error("runner A never journaled step1"));
146
+ }, y = { id: `resume-${o}` }, b = await h.runPromise(h.scoped(h.gen(function* () {
147
+ let { wf: e, layer: t } = m("A"), n = yield* _.build(t), r = yield* h.forkDaemon(e.execute(y).pipe(h.provide(n), h.ignore));
148
+ return (yield* A(() => u.length > 0, 6e4)) ? r : yield* h.die(/* @__PURE__ */ Error("runner A never journaled step1"));
148
149
  })));
149
- await u.runPromise(d.interrupt(x).pipe(u.ignore)), _(t).toEqual(["A"]), _(a).toEqual([]);
150
- let C = await u.runPromise(u.scoped(u.gen(function* () {
151
- let { wf: e, layer: t } = g("B"), n = yield* f.build(t);
152
- return yield* e.execute(v).pipe(u.provide(n), u.timeout("240 seconds"), u.orElseSucceed(() => "TIMEOUT"));
150
+ await h.runPromise(g.interrupt(b).pipe(h.ignore)), C(t).toEqual(["A"]), C(c).toEqual([]);
151
+ let x = await h.runPromise(h.scoped(h.gen(function* () {
152
+ let { wf: e, layer: t } = m("B"), n = yield* _.build(t);
153
+ return yield* e.execute(y).pipe(h.provide(n), h.timeout("240 seconds"), h.orElseSucceed(() => "TIMEOUT"));
153
154
  })));
154
- _(C).toBe("done"), _(t).toEqual(["A"]), _(a).toEqual(["B"]);
155
- }, 48e4), g("dormancy loop: a wake signal survives teardown and is cleared on resume", async () => {
156
- if (!s) return;
157
- let o = `dormancyLoop_${y}`, c = `wr_${o}`, l = [], h = /* @__PURE__ */ new Map(), g = a({
155
+ C(x).toBe("done"), C(t).toEqual(["A"]), C(c).toEqual(["B"]);
156
+ }, 48e4), d("dormancy loop: a wake signal survives teardown and is cleared on resume", async () => {
157
+ if (!l) return;
158
+ let u = `dormancyLoop_${o}`, d = `wr_${u}`, f = [], p = /* @__PURE__ */ new Map(), m = c({
158
159
  store: {
159
160
  insert: async (e, t) => t,
160
161
  update: async () => null,
@@ -162,50 +163,241 @@ var y = async (e, t, n = 750) => {
162
163
  },
163
164
  wakeups: {
164
165
  register: async (e, t) => {
165
- h.set(e, { wakeAt: t });
166
+ p.set(e, { wakeAt: t });
166
167
  },
167
168
  cancel: async (e) => {
168
- h.delete(e);
169
+ p.delete(e);
169
170
  }
170
171
  }
171
- }), v = () => n({
172
- name: o,
173
- payload: { id: p.String },
174
- success: p.String,
175
- idempotencyKey: ({ id: e }) => `${o}:${e}`
176
- }), x = (n, a) => n.toLayer(() => u.gen(function* () {
172
+ }), y = () => n({
173
+ name: u,
174
+ payload: { id: v.String },
175
+ success: v.String,
176
+ idempotencyKey: ({ id: e }) => `${u}:${e}`
177
+ }), b = (n, a) => n.toLayer(() => h.gen(function* () {
177
178
  return yield* i({
178
179
  name: "step1",
179
- success: p.Void,
180
- execute: u.void
180
+ success: v.Void,
181
+ execute: h.void
181
182
  }), yield* r({
182
183
  name: "nap",
183
- duration: C
184
+ duration: k
184
185
  }), yield* i({
185
186
  name: "step2",
186
- success: p.Void,
187
- execute: u.sync(() => {
188
- l.push(a);
187
+ success: v.Void,
188
+ execute: h.sync(() => {
189
+ f.push(a);
189
190
  })
190
191
  }), "done";
191
- }).pipe(u.locally(e, c), u.provideService(t, g))), S = m.runnerPort + 2, T = (e) => {
192
- let t = v();
192
+ }).pipe(h.locally(e, d), h.provideService(t, m))), x = a.runnerPort + 2, S = (e) => {
193
+ let t = y();
193
194
  return {
194
195
  wf: t,
195
- layer: x(t, e).pipe(f.provideMerge(b(S)))
196
+ layer: b(t, e).pipe(_.provideMerge(s(x)))
196
197
  };
197
- }, E = { id: `loop-${y}` }, D = await u.runPromise(u.scoped(u.gen(function* () {
198
- let { wf: e, layer: t } = T("A"), n = yield* f.build(t), r = yield* u.forkDaemon(e.execute(E).pipe(u.provide(n), u.ignore));
199
- return (yield* w(() => h.has(c), 6e4)) ? (yield* u.sleep("1 second"), r) : yield* u.die(/* @__PURE__ */ Error("workflow never registered a wakeup"));
198
+ }, w = { id: `loop-${o}` }, T = await h.runPromise(h.scoped(h.gen(function* () {
199
+ let { wf: e, layer: t } = S("A"), n = yield* _.build(t), r = yield* h.forkDaemon(e.execute(w).pipe(h.provide(n), h.ignore));
200
+ return (yield* A(() => p.has(d), 6e4)) ? (yield* h.sleep("1 second"), r) : yield* h.die(/* @__PURE__ */ Error("workflow never registered a wakeup"));
200
201
  })));
201
- await u.runPromise(d.interrupt(D).pipe(u.ignore)), _(h.has(c)).toBe(!0), _(l).toEqual([]);
202
- let O = await u.runPromise(u.scoped(u.gen(function* () {
203
- let { wf: e, layer: t } = T("B"), n = yield* f.build(t);
204
- return yield* e.execute(E).pipe(u.provide(n), u.timeout("600 seconds"), u.orElseSucceed(() => "TIMEOUT"));
202
+ await h.runPromise(g.interrupt(T).pipe(h.ignore)), C(p.has(d)).toBe(!0), C(f).toEqual([]);
203
+ let E = await h.runPromise(h.scoped(h.gen(function* () {
204
+ let { wf: e, layer: t } = S("B"), n = yield* _.build(t);
205
+ return yield* e.execute(w).pipe(h.provide(n), h.timeout("600 seconds"), h.orElseSucceed(() => "TIMEOUT"));
205
206
  })));
206
- _(O).toBe("done"), _(l).toEqual(["B"]), _(h.has(c)).toBe(!1);
207
+ C(E).toBe("done"), C(f).toEqual(["B"]), C(p.has(d)).toBe(!1);
207
208
  }, 9e5);
208
209
  });
210
+ }, M = {
211
+ encrypt: (e) => `enc:v2:c:${Buffer.from(e, "utf8").toString("base64")}`,
212
+ decrypt: (e) => Buffer.from(e.slice(9), "base64").toString("utf8")
213
+ }, N = (e) => {
214
+ let t = `${e.name}-enc-${Date.now()}`, r = () => d({
215
+ sqlClientLayer: e.sqlClientLayer,
216
+ runnerStorage: e.runnerStorage,
217
+ runnerListenPort: e.runnerPort + 7,
218
+ ...e.dialectId ? { dialectId: e.dialectId } : {}
219
+ }), c = (t) => h.runPromise(h.gen(function* () {
220
+ let e = yield* y.SqlClient, n = yield* e.unsafe("SELECT * FROM cluster_messages"), r = yield* e.unsafe("SELECT * FROM cluster_replies");
221
+ return [...n, ...r].filter((e) => JSON.stringify(e).includes(t)).length;
222
+ }).pipe(h.scoped, h.provide(e.sqlClientLayer))), u = (e, t) => {
223
+ let r = n({
224
+ name: e,
225
+ payload: {
226
+ note: v.String,
227
+ count: v.Number
228
+ },
229
+ success: v.Struct({ summary: v.String }),
230
+ idempotencyKey: ({ count: t }) => `${e}:${t}`,
231
+ encrypted: t
232
+ }), a = 0;
233
+ return {
234
+ wf: r,
235
+ handler: r.toLayer(({ note: e }) => h.gen(function* () {
236
+ return { summary: `RESULT-${yield* i({
237
+ name: "summarise",
238
+ success: v.String,
239
+ execute: h.sync(() => (a++, `STEP-${e}`))
240
+ })}` };
241
+ })),
242
+ executions: () => a
243
+ };
244
+ }, p = (e, t) => h.runPromise(h.scoped(e.wf.execute(t).pipe(h.provide(e.handler.pipe(_.provideMerge(r()))))));
245
+ S(`encrypted workflow journal — ${e.name}`, () => {
246
+ let d = !1;
247
+ x(async () => {
248
+ d = await e.reachable(), d && await D(e);
249
+ }, 3e4), b(() => a(void 0)), w("payload, step result and result are ciphertext; the unencrypted twin is found (control)", async (e) => {
250
+ d || e.skip(), a(M);
251
+ let n = u(`journalPlain_${t}`, !1), r = u(`journalSealed_${t}`, !0);
252
+ C(await p(n, {
253
+ note: "PLAINMARK",
254
+ count: 1
255
+ })).toEqual({ summary: "RESULT-STEP-PLAINMARK" }), C(await p(r, {
256
+ note: "SEALMARK",
257
+ count: 1
258
+ })).toEqual({ summary: "RESULT-STEP-SEALMARK" }), C(await c("PLAINMARK"), "the probe finds plaintext").toBeGreaterThan(0), C(await c("SEALMARK"), "no journal row carries the encrypted run in plaintext").toBe(0), C(await c("enc:v2:c:"), "and the ciphertext is there").toBeGreaterThan(0);
259
+ }, 6e4), w("a second execute replays the result from the encrypted journal without re-running the step", async (e) => {
260
+ d || e.skip(), a(M);
261
+ let n = u(`journalReplay_${t}`, !0), r = await p(n, {
262
+ note: "REPLAYMARK",
263
+ count: 7
264
+ }), i = await p(n, {
265
+ note: "REPLAYMARK",
266
+ count: 7
267
+ });
268
+ C(i).toEqual(r), C(n.executions()).toBe(1);
269
+ }, 6e4), w("a run journaled in plaintext before the declaration is still read", async (e) => {
270
+ d || e.skip();
271
+ let n = `journalBefore_${t}`, r = await p(u(n, !1), {
272
+ note: "OLDMARK",
273
+ count: 3
274
+ });
275
+ a(M);
276
+ let i = u(n, !0);
277
+ C(await p(i, {
278
+ note: "OLDMARK",
279
+ count: 3
280
+ })).toEqual(r), C(i.executions(), "answered from the plaintext journal, not re-run").toBe(0);
281
+ }, 6e4);
282
+ let m = (e, t, a) => {
283
+ class o extends v.TaggedError()("Refused", { detail: v.String }) {}
284
+ let s = n({
285
+ name: e,
286
+ payload: { note: v.String },
287
+ error: o,
288
+ idempotencyKey: ({ note: t }) => `${e}:${t}`,
289
+ encrypted: t
290
+ }), c = s.toLayer(({ note: e }) => i({
291
+ name: "call-upstream",
292
+ success: v.String,
293
+ error: o,
294
+ execute: a === "defect" ? h.die(/* @__PURE__ */ Error(`upstream rejected FAILMARK-${e}`)) : h.fail(new o({ detail: `FAILMARK-${e}` }))
295
+ }));
296
+ return h.runPromiseExit(h.scoped(s.execute({ note: e }).pipe(h.provide(c.pipe(_.provideMerge(r()))))));
297
+ };
298
+ for (let e of ["defect", "typed"]) w(`a ${e} failure of an encrypted run leaves no plaintext; the unencrypted twin does (control)`, async (n) => {
299
+ d || n.skip(), a(M);
300
+ let r = await m(`journalFailPlain_${e}_${t}`, !1, e);
301
+ C(r._tag).toBe("Failure"), C(await c(`FAILMARK-journalFailPlain_${e}`), "the probe finds plaintext").toBeGreaterThan(0);
302
+ let i = await m(`journalFailSealed_${e}_${t}`, !0, e);
303
+ C(i._tag).toBe("Failure"), C(await c(`FAILMARK-journalFailSealed_${e}`), "no journal row carries the failure in plaintext").toBe(0), C(f.pretty(i.cause)).toContain(`FAILMARK-journalFailSealed_${e}`);
304
+ }, 6e4);
305
+ w("a journaled wait value of an encrypted run is ciphertext; the unencrypted twin is found (control)", async (e) => {
306
+ d || e.skip(), a(M);
307
+ let i = (e, t) => {
308
+ let i = n({
309
+ name: e,
310
+ payload: { note: v.String },
311
+ success: v.String,
312
+ idempotencyKey: ({ note: t }) => `${e}:${t}`,
313
+ encrypted: t
314
+ }), a = i.toLayer(({ note: e }) => o({
315
+ name: "await-signal:approval",
316
+ success: v.String,
317
+ execute: h.succeed(`WAITMARK-${e}`)
318
+ }));
319
+ return h.runPromise(h.scoped(i.execute({ note: e }).pipe(h.provide(a.pipe(_.provideMerge(r()))))));
320
+ };
321
+ C(await i(`journalWaitPlain_${t}`, !1)).toBe(`WAITMARK-journalWaitPlain_${t}`), C(await c(`WAITMARK-journalWaitPlain_${t}`), "the probe finds plaintext").toBeGreaterThan(0), C(await i(`journalWaitSealed_${t}`, !0)).toBe(`WAITMARK-journalWaitSealed_${t}`), C(await c(`WAITMARK-journalWaitSealed_${t}`), "no plaintext wait value in the journal").toBe(0);
322
+ }, 6e4);
323
+ let g = (e, t, n) => h.gen(function* () {
324
+ for (let r = 0; r < 400; r++) {
325
+ let r = yield* e.poll(t);
326
+ if (n(r)) return r;
327
+ yield* h.sleep("50 millis");
328
+ }
329
+ return yield* h.dieMessage("pollUntil: never satisfied");
330
+ }), y = (e) => e?._tag;
331
+ for (let e of [!1, !0]) w(`a suspending signal's value is ${e ? "ciphertext" : "found (control)"} in the journal, and the run resumes with it`, async (i) => {
332
+ d || i.skip(), a(M);
333
+ let o = `journalSignal_${e ? "sealed" : "plain"}_${t}`, u = n({
334
+ name: o,
335
+ payload: { id: v.String },
336
+ success: v.Unknown,
337
+ idempotencyKey: ({ id: e }) => `${o}:${e}`,
338
+ encrypted: e
339
+ }), f = u.toLayer(() => s({ store: { query: () => Promise.resolve([]) } }, {
340
+ name: "approval",
341
+ schema: v.Struct({ comment: v.String }),
342
+ timeoutMs: 36e5
343
+ })), p = `SIGNALMARK-${o}`, m = await h.runPromise(h.scoped(h.gen(function* () {
344
+ let e = yield* u.executionId({ id: "one" });
345
+ return yield* u.execute({ id: "one" }, { discard: !0 }), yield* g(u, e, (e) => y(e) === "Suspended"), yield* l({
346
+ target: {
347
+ executionId: e,
348
+ workflowName: o
349
+ },
350
+ signalName: "approval",
351
+ payload: { comment: p }
352
+ }), yield* g(u, e, (e) => y(e) === "Complete");
353
+ }).pipe(h.provide(f.pipe(_.provideMerge(r()))))));
354
+ C(JSON.stringify(m.exit), "the body received the value").toContain(p);
355
+ let b = await c(p);
356
+ e ? C(b, "no plaintext signal value in the journal").toBe(0) : C(b, "the probe finds plaintext").toBeGreaterThan(0);
357
+ }, 9e4);
358
+ w("an encrypted child's defect reaches its encrypted parent as thrown, and no journal row carries it", async (e) => {
359
+ d || e.skip(), a(M);
360
+ let i = `journalChild_${t}`, o = `journalParent_${t}`, s = `CHILDMARK-${t}`, l = n({
361
+ name: i,
362
+ payload: { id: v.String },
363
+ success: v.String,
364
+ idempotencyKey: ({ id: e }) => e,
365
+ encrypted: !0
366
+ }), u = n({
367
+ name: o,
368
+ payload: { id: v.String },
369
+ success: v.String,
370
+ idempotencyKey: ({ id: e }) => e,
371
+ encrypted: !0
372
+ }), f = l.toLayer(() => h.die(/* @__PURE__ */ Error(`child failed ${s}`))), p = u.toLayer(({ id: e }) => l.execute({ id: `${e}-child` }).pipe(h.catchAllDefect((e) => h.succeed(`caught: ${e.message}`)))), m = await h.runPromise(h.scoped(u.execute({ id: "p1" }).pipe(h.provide(_.mergeAll(p, f).pipe(_.provideMerge(r()))))));
373
+ C(m).toBe(`caught: child failed ${s}`), C(await c(s)).toBe(0);
374
+ }, 6e4), w("an encrypted run that suspends on a failed step journals no plaintext", async (e) => {
375
+ d || e.skip(), a(M);
376
+ let o = `journalSuspendOnFailure_${t}`, s = `SOFMARK-${t}`, l = n({
377
+ name: o,
378
+ payload: { id: v.String },
379
+ success: v.String,
380
+ idempotencyKey: ({ id: e }) => e,
381
+ encrypted: !0,
382
+ suspendOnFailure: !0
383
+ }), u = l.toLayer(() => i({
384
+ name: "call",
385
+ success: v.String,
386
+ execute: h.die(/* @__PURE__ */ Error(`step failed ${s}`))
387
+ }));
388
+ await h.runPromise(h.scoped(h.gen(function* () {
389
+ let e = yield* l.executionId({ id: "s1" });
390
+ yield* l.execute({ id: "s1" }, { discard: !0 }), yield* g(l, e, (e) => y(e) === "Suspended");
391
+ }).pipe(h.provide(u.pipe(_.provideMerge(r())))))), C(await c(s)).toBe(0);
392
+ }, 6e4), w("without a registered cipher an encrypted run fails instead of writing plaintext", async (e) => {
393
+ d || e.skip();
394
+ let n = u(`journalNoCipher_${t}`, !0);
395
+ await C(p(n, {
396
+ note: "NOCIPHERMARK",
397
+ count: 1
398
+ })).rejects.toThrow(), C(await c("NOCIPHERMARK")).toBe(0);
399
+ }, 6e4);
400
+ });
209
401
  };
210
402
  //#endregion
211
- export { x as purgeClusterState, T as runClusterEngineSuite, y as tcpReachable };
403
+ export { D as purgeClusterState, j as runClusterEngineSuite, N as runJournalEncryptionSuite, T as tcpReachable };