@voltro/workflow 0.84.0 → 0.86.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 (89) hide show
  1. package/CHANGELOG.md +1215 -0
  2. package/THIRD-PARTY-NOTICES.md +5 -151
  3. package/dist/admission.js +140 -0
  4. package/dist/admissionDrainer.js +705 -0
  5. package/dist/admissionGate.js +115 -0
  6. package/dist/admissionStore.js +347 -0
  7. package/dist/admissionSubmission.js +297 -0
  8. package/dist/admissionTables.js +137 -0
  9. package/dist/admissionTransaction.js +21 -0
  10. package/dist/awaitEvent.js +82 -0
  11. package/dist/budgetHold.js +136 -0
  12. package/dist/cancelOnPlan.js +75 -0
  13. package/dist/cancelOnSweep.js +188 -0
  14. package/dist/cancelPendingStart.js +50 -0
  15. package/dist/cluster.d.ts +304 -280
  16. package/dist/cluster.js +8 -2
  17. package/dist/clusterCron.js +11 -0
  18. package/dist/clusterDiagnostics.js +20 -0
  19. package/dist/clusterDiagnosticsSql.js +145 -0
  20. package/dist/clusterLayer.js +110 -0
  21. package/dist/clusterMigrationGate.js +61 -0
  22. package/dist/clusterRunnerLayer.js +21 -0
  23. package/dist/clusterTestSuite.d.ts +11 -11
  24. package/dist/clusterTestSuite.js +257 -257
  25. package/dist/controlMonitor.js +13 -0
  26. package/dist/controlRequest.js +367 -0
  27. package/dist/executionRefusal.js +162 -0
  28. package/dist/failureHandoff.js +183 -0
  29. package/dist/failureMessage.js +12 -0
  30. package/dist/failureRecovery.js +50 -0
  31. package/dist/failureReportStore.js +60 -0
  32. package/dist/flowControl.js +142 -0
  33. package/dist/forwardStartReceipts.js +41 -0
  34. package/dist/inMemoryLayer.js +7 -0
  35. package/dist/inMemoryRecorder.js +56 -0
  36. package/dist/index.d.ts +456 -360
  37. package/dist/index.js +49 -5
  38. package/dist/inspectWorkflow.js +101 -0
  39. package/dist/journalEncryption.js +147 -0
  40. package/dist/messages.js +92 -0
  41. package/dist/nondeterminism.js +51 -0
  42. package/dist/parentClosure.js +141 -0
  43. package/dist/parentClosureRecovery.js +54 -0
  44. package/dist/pendingSubmission.js +85 -0
  45. package/dist/prepareSubmissionDispatch.js +17 -0
  46. package/dist/preparedExecution.js +14 -0
  47. package/dist/primitives.d.ts +56 -31
  48. package/dist/primitives.js +225 -2
  49. package/dist/queuedCancellationRequest.js +364 -0
  50. package/dist/queuedControl.js +21 -0
  51. package/dist/recorder.js +11 -0
  52. package/dist/residentExecutionEvidence.js +64 -0
  53. package/dist/retryPolicy.js +57 -0
  54. package/dist/runEventsTable.js +17 -0
  55. package/dist/runGeneration.js +345 -0
  56. package/dist/runRecording.js +615 -0
  57. package/dist/runStepsTable.js +28 -0
  58. package/dist/runnerStorageGuard.js +29 -0
  59. package/dist/runsTable.js +42 -0
  60. package/dist/scheduleDeclaration.js +44 -0
  61. package/dist/signalHint.js +23 -0
  62. package/dist/signals.js +70 -0
  63. package/dist/signalsSuspending.js +57 -0
  64. package/dist/sqliteWorkflowOwnership.js +26 -0
  65. package/dist/stalenessSweep.js +191 -0
  66. package/dist/startContextsTable.js +20 -0
  67. package/dist/startReceipt.js +143 -0
  68. package/dist/submissionRecovery.js +122 -0
  69. package/dist/submissionRejection.js +10 -0
  70. package/dist/submissionRetry.js +71 -0
  71. package/dist/suspensionUnavailable.js +9 -0
  72. package/dist/updates.js +87 -0
  73. package/dist/watermarkTable.js +9 -0
  74. package/dist/webCrypto.js +17 -0
  75. package/dist/workflowDelivery.js +24 -0
  76. package/dist/workflowJournal.js +124 -0
  77. package/dist/workflowJournalReset.js +111 -0
  78. package/dist/workflowReadSelections.js +12 -0
  79. package/dist/workflowRestartDispatch.js +29 -0
  80. package/dist/workflowRestartObservation.js +60 -0
  81. package/dist/workflowRestartPreparation.js +109 -0
  82. package/dist/workflowRestartReservation.js +426 -0
  83. package/dist/workflowResumeDispatch.js +29 -0
  84. package/package.json +6 -9
  85. package/dist/cluster-i3frC3Da.js +0 -646
  86. package/dist/clusterDiagnostics-CGUtnJkX.js +0 -2084
  87. package/dist/journalEncryption--n5VDdYO.js +0 -148
  88. package/dist/primitives-Btjhjm8P.js +0 -483
  89. package/dist/src-DP-lKqaG.js +0 -3867
@@ -0,0 +1,13 @@
1
+ import { readPendingWorkflowCancellation as e } from "./controlRequest.js";
2
+ import { Effect as t } from "effect";
3
+ import { WorkflowInstance as n } from "effect/workflow/WorkflowEngine";
4
+ //#region src/controlMonitor.ts
5
+ var r = (r, i, a) => t.gen(function* () {
6
+ let o = yield* n;
7
+ for (;;) {
8
+ if (yield* t.tryPromise(() => e(i, r)).pipe(t.catch(() => t.sync(() => (a(), !1))))) return o.interrupted = !0, yield* t.interrupt;
9
+ yield* t.sleep(1e3);
10
+ }
11
+ });
12
+ //#endregion
13
+ export { r as awaitWorkflowCancellation };
@@ -0,0 +1,367 @@
1
+ import { isWorkflowEncrypted as e, sealErrorText as t, sealJournalValue as n } from "./journalEncryption.js";
2
+ import { Schema as r } from "effect";
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
5
+ var l = "_voltro_workflow_control_requests", u = r.String.pipe(r.check(r.isMinLength(1))), d = r.Struct({
6
+ kind: r.Literals(["confirmed", "already-terminal"]),
7
+ status: r.Literals([
8
+ "succeeded",
9
+ "failed",
10
+ "cancelled"
11
+ ]),
12
+ completedAt: r.Number.pipe(r.check(r.isFinite())),
13
+ output: r.Unknown,
14
+ errorTag: r.NullOr(r.String),
15
+ errorMessage: r.NullOr(r.String)
16
+ }), f = r.Struct({
17
+ kind: r.Literal("confirmed"),
18
+ status: r.Literal("running"),
19
+ enteredAt: r.Number.pipe(r.check(r.isFinite())),
20
+ generation: u
21
+ }), p = r.Union([d, f]), m = r.Struct({
22
+ reason: r.NonEmptyString,
23
+ detail: r.optional(r.Record(r.String, r.Unknown))
24
+ }), h = r.Struct({ tenantId: r.NullOr(r.String) }), g = r.Struct({
25
+ requestId: r.String.pipe(r.check(r.isPattern(/^[1-9]\d*$/))),
26
+ replyId: r.String.pipe(r.check(r.isPattern(/^[1-9]\d*$/))),
27
+ restartToken: r.NullOr(r.NonEmptyString)
28
+ }), _ = r.Struct({
29
+ id: u,
30
+ runId: u,
31
+ workflowName: u,
32
+ executionId: u,
33
+ generation: u,
34
+ operation: r.Literals([
35
+ "cancel",
36
+ "terminate",
37
+ "resume"
38
+ ]),
39
+ requestedAt: r.Number.pipe(r.check(r.isFinite())),
40
+ owner: r.NullOr(h),
41
+ cause: r.optional(r.NullOr(m)),
42
+ dispatchAttempts: r.Number.pipe(r.check(r.isInt()), r.check(r.isGreaterThanOrEqualTo(0))),
43
+ resumeJournal: r.NullOr(g),
44
+ result: r.NullOr(p)
45
+ }), v = r.Struct({
46
+ ..._.fields,
47
+ requestedAt: r.Date
48
+ }), y = (e) => {
49
+ let t = r.decodeUnknownSync(v)(e);
50
+ return r.decodeUnknownSync(_)({
51
+ ...t,
52
+ requestedAt: t.requestedAt.getTime()
53
+ });
54
+ }, b = async (e, t, n, r) => {
55
+ if (await e.update("_voltro_workflow_control_requests", t.id, { result: n }) === null) throw Error("Workflow control request disappeared during settlement");
56
+ await e.insert("_voltro_workflow_run_events", {
57
+ id: a("wfev", JSON.stringify(["control-settled", t.id])),
58
+ runId: t.runId,
59
+ eventType: "control-settled",
60
+ occurredAt: new Date(r),
61
+ stepName: null,
62
+ attempt: null,
63
+ payload: {
64
+ requestId: t.id,
65
+ operation: t.operation,
66
+ workflowName: t.workflowName,
67
+ executionId: t.executionId,
68
+ generation: t.generation,
69
+ cause: t.cause ?? null,
70
+ kind: n.kind,
71
+ status: n.status,
72
+ ..."generation" in n ? { enteredGeneration: n.generation } : {}
73
+ }
74
+ });
75
+ }, x = async (e, t) => {
76
+ let n = [], r;
77
+ for (;;) {
78
+ let a = await e({
79
+ table: l,
80
+ predicate: i(o("runId", t.runId), o("workflowName", t.workflowName), o("executionId", t.executionId), o("generation", t.generation), c(o("operation", "cancel"), o("operation", "terminate")), ...r === void 0 ? [] : [s("id", r)]),
81
+ order: [{
82
+ column: "id",
83
+ direction: "asc"
84
+ }],
85
+ take: 100,
86
+ skip: void 0,
87
+ projection: void 0
88
+ });
89
+ for (let e of a) {
90
+ let t = y(e);
91
+ t.result === null && n.push(t);
92
+ }
93
+ if (a.length < 100) return n;
94
+ r = y(a[a.length - 1]).id;
95
+ }
96
+ }, S = async (e, t) => (await x(e, t)).length > 0, C = (e, t) => S((t) => e.query({
97
+ ...t,
98
+ lock: "update"
99
+ }), t), w = {
100
+ source: "flow-control",
101
+ timeout: "finish"
102
+ }, T = r.Struct({
103
+ reason: r.NonEmptyString,
104
+ detail: r.Struct({
105
+ source: r.Literal("flow-control"),
106
+ timeout: r.Literal("finish"),
107
+ onFailure: r.NullOr(r.NonEmptyString)
108
+ })
109
+ }), E = (e) => {
110
+ let t = r.decodeUnknownOption(T)(e.cause);
111
+ return t._tag === "Some" ? t.value : void 0;
112
+ }, D = async (e, t) => {
113
+ let [n] = await e.query({
114
+ table: l,
115
+ predicate: o("id", t),
116
+ lock: "update",
117
+ order: [],
118
+ take: 1,
119
+ skip: void 0,
120
+ projection: void 0
121
+ });
122
+ if (n !== void 0) return y(n);
123
+ }, O = async (e, t) => {
124
+ let n;
125
+ for (;;) {
126
+ let r = await e.query({
127
+ table: l,
128
+ predicate: i(o("parentClosureId", t), ...n === void 0 ? [] : [s("id", n)]),
129
+ lock: "update",
130
+ order: [{
131
+ column: "id",
132
+ direction: "asc"
133
+ }],
134
+ take: 100,
135
+ skip: void 0,
136
+ projection: void 0
137
+ });
138
+ for (let e of r) {
139
+ let r = y(e);
140
+ if (r.cause?.reason !== "parent-close" || r.cause.detail?.closureId !== t || r.operation === "resume") throw Error("Parent closure control has contradictory ownership");
141
+ if (r.result === null) return !0;
142
+ n = r.id;
143
+ }
144
+ if (r.length < 100) return !1;
145
+ }
146
+ }, k = async (e, t) => {
147
+ let n = r.decodeUnknownSync(_)({
148
+ ...t,
149
+ owner: null,
150
+ cause: t.cause ?? null,
151
+ dispatchAttempts: 0,
152
+ resumeJournal: null,
153
+ result: null
154
+ }), i = await D(e, n.id);
155
+ if (i !== void 0) {
156
+ if (i.runId !== n.runId || i.workflowName !== n.workflowName || i.executionId !== n.executionId || i.generation !== n.generation || i.operation !== n.operation) throw Error("Workflow control identity belongs to a different target or operation");
157
+ return i;
158
+ }
159
+ let a = new Date(n.requestedAt);
160
+ if (!Number.isFinite(a.getTime())) throw Error("Workflow control timestamp is outside the supported date range");
161
+ let [s] = await e.query({
162
+ table: "_voltro_workflow_runs",
163
+ predicate: o("id", n.runId),
164
+ lock: "update",
165
+ order: [],
166
+ take: 1,
167
+ skip: void 0,
168
+ projection: void 0
169
+ });
170
+ if (s !== void 0 && (s.tag !== n.workflowName || s.executionId !== n.executionId)) throw Error("Workflow control target does not match its resident run");
171
+ let c = r.decodeUnknownOption(h)(s?.runnerGeneration === n.generation ? s.subject : void 0), u = {
172
+ ...n,
173
+ owner: c._tag === "Some" ? c.value : null
174
+ }, d = s !== void 0 && s.runnerGeneration === n.generation && (s.status === "succeeded" || s.status === "failed" || s.status === "cancelled") ? {
175
+ ...u,
176
+ result: r.decodeUnknownSync(p)({
177
+ kind: "already-terminal",
178
+ status: s.status,
179
+ completedAt: r.decodeUnknownSync(r.Date)(s.completedAt).getTime(),
180
+ output: s.output,
181
+ errorTag: s.errorTag,
182
+ errorMessage: s.errorMessage
183
+ })
184
+ } : u, f = d.cause?.reason === "parent-close" ? r.decodeUnknownSync(r.NonEmptyString)(d.cause.detail?.closureId) : null;
185
+ return await e.insert(l, {
186
+ ...d,
187
+ requestedAt: a,
188
+ parentClosureId: f
189
+ }), d.result !== null && await b(e, d, d.result, n.requestedAt), d;
190
+ }, A = async (e, t, n) => {
191
+ let i = await D(e, t);
192
+ if (i === void 0) throw Error("Workflow control request is missing");
193
+ if (i.operation !== "resume") throw Error("Only resume controls can bind a suspension journal");
194
+ if (i.result !== null) return {
195
+ kind: "settled",
196
+ request: i
197
+ };
198
+ let [a] = await e.query({
199
+ table: "_voltro_workflow_runs",
200
+ predicate: o("id", i.runId),
201
+ lock: "update",
202
+ order: [],
203
+ take: 1,
204
+ skip: void 0,
205
+ projection: void 0
206
+ });
207
+ if (a === void 0) return {
208
+ kind: "unknown",
209
+ request: i
210
+ };
211
+ if (a.tag !== i.workflowName || a.executionId !== i.executionId) throw Error("Workflow control target does not match its resident run");
212
+ if (a.runnerGeneration !== i.generation) return {
213
+ kind: "superseded",
214
+ request: i
215
+ };
216
+ if (a.status !== "suspended" || a.runnerEnteredAt !== null) return {
217
+ kind: "not-suspended",
218
+ request: i
219
+ };
220
+ let s = r.decodeUnknownSync(r.NullOr(r.Struct({
221
+ requestId: g.fields.requestId,
222
+ restartToken: g.fields.restartToken
223
+ })))(a.engineDelivery);
224
+ if (s === null) return {
225
+ kind: "unknown",
226
+ request: i
227
+ };
228
+ if (i.resumeJournal !== null) {
229
+ if (i.resumeJournal.requestId !== s.requestId || i.resumeJournal.restartToken !== s.restartToken) throw Error("Resume journal binding does not match its resident delivery");
230
+ return {
231
+ kind: "bound",
232
+ request: i
233
+ };
234
+ }
235
+ if (i.dispatchAttempts !== 0) return {
236
+ kind: "unknown",
237
+ request: i
238
+ };
239
+ let c = await n({
240
+ workflowName: i.workflowName,
241
+ executionId: i.executionId,
242
+ ...s
243
+ });
244
+ if (c === void 0) return {
245
+ kind: "waiting-journal",
246
+ request: i
247
+ };
248
+ let l = r.decodeUnknownSync(g)(c);
249
+ if (l.requestId !== s.requestId || l.restartToken !== s.restartToken) throw Error("Observed suspension belongs to another engine delivery");
250
+ if (await e.update("_voltro_workflow_control_requests", i.id, { resumeJournal: l }) === null) throw Error("Workflow control request disappeared during suspension binding");
251
+ return {
252
+ kind: "bound",
253
+ request: {
254
+ ...i,
255
+ resumeJournal: l
256
+ }
257
+ };
258
+ }, j = async (e, t) => {
259
+ let n = await D(e, t);
260
+ if (n === void 0) throw Error("Workflow control request is missing");
261
+ if (n.result !== null) return {
262
+ kind: "settled",
263
+ request: n
264
+ };
265
+ let [r] = await e.query({
266
+ table: "_voltro_workflow_runs",
267
+ predicate: o("id", n.runId),
268
+ lock: "update",
269
+ order: [],
270
+ take: 1,
271
+ skip: void 0,
272
+ projection: void 0
273
+ });
274
+ if (r === void 0) return {
275
+ kind: "unknown",
276
+ request: n
277
+ };
278
+ if (r.tag !== n.workflowName || r.executionId !== n.executionId) throw Error("Workflow control target does not match its resident run");
279
+ if (r.runnerGeneration !== n.generation) return {
280
+ kind: "superseded",
281
+ request: n
282
+ };
283
+ if (r.status === "succeeded" || r.status === "failed" || r.status === "cancelled") return {
284
+ kind: "already-terminal",
285
+ request: n,
286
+ run: r
287
+ };
288
+ if (r.status !== "running" && r.status !== "suspended") throw Error("Workflow control target has an invalid resident status");
289
+ let i = n.dispatchAttempts + 1;
290
+ if (!Number.isSafeInteger(i)) throw Error("Workflow control attempt counter exhausted");
291
+ if (await e.update("_voltro_workflow_control_requests", n.id, { dispatchAttempts: i }) === null) throw Error("Workflow control request disappeared before dispatch");
292
+ return {
293
+ kind: "dispatch",
294
+ request: {
295
+ ...n,
296
+ dispatchAttempts: i
297
+ }
298
+ };
299
+ }, M = async (a, c) => {
300
+ let u = c.owner, d;
301
+ for (;;) {
302
+ let f = await a.query({
303
+ table: l,
304
+ predicate: i(o("runId", u.runId), o("workflowName", u.workflowName), o("executionId", u.executionId), o("generation", u.generation), ...d === void 0 ? [] : [s("id", d)]),
305
+ lock: "update",
306
+ order: [{
307
+ column: "id",
308
+ direction: "asc"
309
+ }],
310
+ take: 100,
311
+ skip: void 0,
312
+ projection: void 0
313
+ });
314
+ for (let i of f) {
315
+ if (typeof i.id != "string") throw Error("Workflow control request has an invalid identity");
316
+ let o = await D(a, i.id);
317
+ if (o === void 0) throw Error("Workflow control request disappeared during completion");
318
+ if (o.result !== null) continue;
319
+ let s = c.outcome;
320
+ await b(a, o, r.decodeUnknownSync(p)({
321
+ kind: s.status === "cancelled" && o.operation !== "resume" ? "confirmed" : "already-terminal",
322
+ status: s.status,
323
+ completedAt: c.now,
324
+ output: s.status === "succeeded" ? e(u.workflowName) ? n(s.output, `workflow '${u.workflowName}' result`) : s.output : null,
325
+ errorTag: s.status === "failed" ? s.errorTag : null,
326
+ errorMessage: s.status === "failed" ? t(u.workflowName, s.errorMessage) : null
327
+ }), c.now);
328
+ }
329
+ if (f.length < 100) return;
330
+ let m = f[f.length - 1];
331
+ if (typeof m.id != "string") throw Error("Workflow control cursor has an invalid identity");
332
+ d = m.id;
333
+ }
334
+ }, N = async (e, t, n, a) => {
335
+ let c = r.decodeUnknownSync(f)({
336
+ kind: "confirmed",
337
+ status: "running",
338
+ generation: n,
339
+ enteredAt: a
340
+ }), u;
341
+ for (;;) {
342
+ let n = await e.query({
343
+ table: l,
344
+ predicate: i(o("runId", t.runId), o("workflowName", t.workflowName), o("executionId", t.executionId), o("generation", t.generation), o("operation", "resume"), ...u === void 0 ? [] : [s("id", u)]),
345
+ lock: "update",
346
+ order: [{
347
+ column: "id",
348
+ direction: "asc"
349
+ }],
350
+ take: 100,
351
+ skip: void 0,
352
+ projection: void 0
353
+ });
354
+ for (let t of n) {
355
+ if (typeof t.id != "string") throw Error("Workflow control request has an invalid identity");
356
+ let n = await D(e, t.id);
357
+ if (n === void 0) throw Error("Workflow control request disappeared during resume");
358
+ n.result === null && await b(e, n, c, a);
359
+ }
360
+ if (n.length < 100) return;
361
+ let r = n[n.length - 1];
362
+ if (typeof r.id != "string") throw Error("Workflow control cursor has an invalid identity");
363
+ u = r.id;
364
+ }
365
+ };
366
+ //#endregion
367
+ 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 };
@@ -0,0 +1,162 @@
1
+ import { isWorkflowEncrypted as e, loggableCause as t } from "./journalEncryption.js";
2
+ import { CurrentWorkflowDelivery as n } from "./workflowDelivery.js";
3
+ import { completeWorkflowRunGenerationInTransaction as r, enterWorkflowRunGenerationInTransaction as i } from "./runGeneration.js";
4
+ import { serialiseWorkflowRowForWire as a } from "./runRecording.js";
5
+ import { Cause as o, Effect as s, Schema as c } from "effect";
6
+ import { SubjectIdentity as l, publishServerError as u } from "@voltro/protocol";
7
+ import { randomUUID as d } from "node:crypto";
8
+ import { WorkflowInstance as f } from "effect/workflow/WorkflowEngine";
9
+ //#region src/executionRefusal.ts
10
+ var p = (p, m) => s.gen(function* () {
11
+ let h = yield* s.sync(() => c.decodeUnknownSync(l)(p.subject));
12
+ if (h.tenantId !== p.failureContext.tenantId) return yield* s.die(/* @__PURE__ */ Error("Workflow refusal has inconsistent caller tenant"));
13
+ let g = `wfrg_${d()}`, _ = yield* s.serviceOption(n), v = Date.now(), y = o.findErrorOption(m.cause), b = y._tag === "Some" ? y.value : o.squash(m.cause), x = b && typeof b == "object" && "_tag" in b ? String(b._tag) : null, S = b && typeof b == "object" && "message" in b ? String(b.message) : String(b), C = yield* s.promise(() => p.transaction(async (e) => {
14
+ let t = await i(e, {
15
+ workflowName: p.name,
16
+ executionId: m.executionId,
17
+ generation: g,
18
+ now: v,
19
+ delivery: _._tag === "Some" ? _.value : null,
20
+ initialRow: {
21
+ id: p.makeId?.("wr") ?? `wr_${d()}`,
22
+ payload: p.encodePayload === void 0 ? m.payload : p.encodePayload(m.payload),
23
+ status: "running",
24
+ subject: p.subject,
25
+ source: p.source ?? null,
26
+ traceId: p.traceId ?? null,
27
+ workflowVersion: p.workflowVersion ?? null,
28
+ workflowPatches: p.workflowPatches ?? null,
29
+ output: null,
30
+ errorTag: null,
31
+ errorMessage: null,
32
+ cancelled: !1,
33
+ startedAt: new Date(v),
34
+ completedAt: null,
35
+ durationMs: null,
36
+ parentExecutionId: p.parentExecutionId ?? null,
37
+ parentGeneration: p.parentGeneration ?? null,
38
+ parentClosePolicy: p.parentClosePolicy ?? null
39
+ }
40
+ }), n = c.decodeUnknownSync(l)(t.row.subject);
41
+ if (n.type !== h.type || n.id !== h.id || n.tenantId !== h.tenantId || h.type === "service" && (n.type !== "service" || n.service !== h.service)) throw Error("Workflow refusal belongs to a different recorded caller");
42
+ if (t.kind === "cancelled" || t.kind === "already-cancelled") return t;
43
+ if (typeof t.row.id != "string") throw Error("Workflow refusal has no allocated run identity");
44
+ let a = await r(e, {
45
+ owner: {
46
+ runId: t.row.id,
47
+ workflowName: p.name,
48
+ executionId: m.executionId,
49
+ generation: g
50
+ },
51
+ now: v,
52
+ durationMs: 0,
53
+ outcome: {
54
+ status: "failed",
55
+ errorTag: x,
56
+ errorMessage: S,
57
+ ...p.failureContext
58
+ }
59
+ });
60
+ if (a.kind !== "committed") throw Error("Workflow refusal lost its resident generation");
61
+ return {
62
+ ...a,
63
+ created: t.kind === "created",
64
+ restartEvent: t.restartEvent
65
+ };
66
+ }));
67
+ if (C.kind === "already-cancelled") {
68
+ let e = yield* f;
69
+ return e.interrupted = !0, yield* s.interrupt;
70
+ }
71
+ let w = (e) => {
72
+ try {
73
+ p.log?.warn(e, {
74
+ workflow: p.name,
75
+ executionId: m.executionId
76
+ });
77
+ } catch {}
78
+ };
79
+ yield* s.sync(() => {
80
+ try {
81
+ p.emit?.("workflowRuns", {
82
+ op: C.kind === "committed" && C.created ? "insert" : "update",
83
+ row: a(C.row)
84
+ }), C.restartEvent !== void 0 && p.emit?.("workflowEvents", {
85
+ op: "insert",
86
+ row: a(C.restartEvent)
87
+ }), C.terminalEvent !== void 0 && p.emit?.("workflowEvents", {
88
+ op: "insert",
89
+ row: a(C.terminalEvent)
90
+ });
91
+ } catch {
92
+ w("workflow refusal observer failed after terminal commit");
93
+ }
94
+ });
95
+ let T = C.kind === "cancelled" ? "cancelled" : "failed", E = String(C.row.id);
96
+ if (yield* s.tryPromise({
97
+ try: async () => {
98
+ await p.wakeups?.cancel(E, h.tenantId ?? void 0);
99
+ },
100
+ catch: (e) => e
101
+ }).pipe(s.catch(() => s.sync(() => w("workflow refusal wakeup observer failed after terminal commit")))), yield* s.tryPromise({
102
+ try: async () => {
103
+ await p.onParentClose?.({
104
+ workflowName: p.name,
105
+ executionId: m.executionId,
106
+ runId: E,
107
+ status: T
108
+ });
109
+ },
110
+ catch: (e) => e
111
+ }).pipe(s.catch(() => s.sync(() => w("workflow refusal parent observer failed after terminal commit")))), yield* s.tryPromise({
112
+ try: async () => {
113
+ await p.onTerminal?.({
114
+ workflowName: p.name,
115
+ executionId: m.executionId,
116
+ runId: E,
117
+ status: T,
118
+ ...T === "failed" ? {
119
+ payload: m.payload,
120
+ errorTag: x,
121
+ errorMessage: S
122
+ } : {}
123
+ });
124
+ },
125
+ catch: (e) => e
126
+ }).pipe(s.catch(() => s.sync(() => w("workflow refusal terminal observer failed after commit")))), yield* s.sync(() => {
127
+ try {
128
+ p.recordRun?.({
129
+ name: p.name,
130
+ status: T,
131
+ durationMs: 0
132
+ });
133
+ } catch {
134
+ w("workflow refusal metrics observer failed after terminal commit");
135
+ }
136
+ }), C.kind === "cancelled") {
137
+ let e = yield* f;
138
+ return e.interrupted = !0, yield* s.interrupt;
139
+ }
140
+ return yield* s.sync(() => {
141
+ try {
142
+ p.log?.warn("workflow execution refused before application body", {
143
+ workflow: p.name,
144
+ executionId: m.executionId,
145
+ cause: t(p.name, b)
146
+ });
147
+ } catch {}
148
+ u({
149
+ error: b,
150
+ source: "workflow",
151
+ name: p.name,
152
+ contentSensitive: e(p.name),
153
+ ...p.traceId ? { traceId: p.traceId } : {},
154
+ fields: {
155
+ executionId: m.executionId,
156
+ runId: C.row.id
157
+ }
158
+ });
159
+ }), yield* s.failCause(m.cause);
160
+ });
161
+ //#endregion
162
+ export { p as recordWorkflowExecutionRefusal };