@voltro/workflow 0.85.0 → 0.87.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 (103) hide show
  1. package/CHANGELOG.md +5987 -0
  2. package/THIRD-PARTY-NOTICES.md +1122 -31
  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 +111 -27
  16. package/dist/cluster.js +12 -2
  17. package/dist/clusterCron.js +19 -0
  18. package/dist/clusterDiagnostics.js +20 -0
  19. package/dist/clusterDiagnosticsSql.js +145 -0
  20. package/dist/clusterLayer.js +145 -0
  21. package/dist/clusterMigrationGate.js +61 -0
  22. package/dist/clusterRunnerLayer.js +31 -0
  23. package/dist/clusterShardGroups.js +33 -0
  24. package/dist/clusterTestSuite.d.ts +23 -0
  25. package/dist/clusterTestSuite.js +209 -179
  26. package/dist/controlMonitor.js +13 -0
  27. package/dist/controlRequest.js +367 -0
  28. package/dist/executionRefusal.js +162 -0
  29. package/dist/failureHandoff.js +183 -0
  30. package/dist/failureMessage.js +12 -0
  31. package/dist/failureRecovery.js +50 -0
  32. package/dist/failureReportStore.js +60 -0
  33. package/dist/flowControl.js +142 -0
  34. package/dist/forwardStartReceipts.js +41 -0
  35. package/dist/inMemoryLayer.js +7 -0
  36. package/dist/inMemoryRecorder.js +56 -0
  37. package/dist/index.d.ts +129 -30
  38. package/dist/index.js +50 -5
  39. package/dist/inspectWorkflow.js +101 -0
  40. package/dist/{journalEncryption-DTyhUzaS.js → journalEncryption.js} +30 -37
  41. package/dist/journalRoutingGuard.js +50 -0
  42. package/dist/journalRoutingLayout.js +47 -0
  43. package/dist/journalRoutingLock.js +39 -0
  44. package/dist/journalRoutingMaintenance.js +24 -0
  45. package/dist/journalRoutingMessageStorage.js +32 -0
  46. package/dist/journalRoutingNamespace.js +23 -0
  47. package/dist/journalRoutingRuntime.js +33 -0
  48. package/dist/journalRoutingSharding.js +28 -0
  49. package/dist/journalRoutingState.js +93 -0
  50. package/dist/journalRoutingTable.js +11 -0
  51. package/dist/journalRoutingTransaction.js +16 -0
  52. package/dist/messages.js +92 -0
  53. package/dist/nondeterminism.js +51 -0
  54. package/dist/parentClosure.js +141 -0
  55. package/dist/parentClosureRecovery.js +54 -0
  56. package/dist/pendingSubmission.js +85 -0
  57. package/dist/prepareSubmissionDispatch.js +17 -0
  58. package/dist/preparedExecution.js +14 -0
  59. package/dist/primitives.js +225 -2
  60. package/dist/queuedCancellationRequest.js +364 -0
  61. package/dist/queuedControl.js +21 -0
  62. package/dist/recorder.js +11 -0
  63. package/dist/residentExecutionEvidence.js +64 -0
  64. package/dist/retryPolicy.js +57 -0
  65. package/dist/runEventsTable.js +17 -0
  66. package/dist/runGeneration.js +345 -0
  67. package/dist/runRecording.js +615 -0
  68. package/dist/runStepsTable.js +28 -0
  69. package/dist/runnerStorageGuard.js +29 -0
  70. package/dist/runsTable.js +42 -0
  71. package/dist/scheduleDeclaration.js +44 -0
  72. package/dist/signalHint.js +23 -0
  73. package/dist/signals.js +70 -0
  74. package/dist/signalsSuspending.js +57 -0
  75. package/dist/sqliteWorkflowOwnership.js +26 -0
  76. package/dist/stalenessSweep.js +191 -0
  77. package/dist/startContextsTable.js +20 -0
  78. package/dist/startReceipt.js +143 -0
  79. package/dist/submissionRecovery.js +122 -0
  80. package/dist/submissionRejection.js +10 -0
  81. package/dist/submissionRetry.js +71 -0
  82. package/dist/suspensionUnavailable.js +9 -0
  83. package/dist/updates.js +87 -0
  84. package/dist/watermarkTable.js +9 -0
  85. package/dist/webCrypto.js +17 -0
  86. package/dist/workflowDelivery.js +24 -0
  87. package/dist/workflowExecutorRouting.js +33 -0
  88. package/dist/workflowJournal.js +124 -0
  89. package/dist/workflowJournalReset.js +111 -0
  90. package/dist/workflowReadSelections.js +12 -0
  91. package/dist/workflowRestartDispatch.js +35 -0
  92. package/dist/workflowRestartObservation.js +60 -0
  93. package/dist/workflowRestartPreparation.js +109 -0
  94. package/dist/workflowRestartReservation.js +427 -0
  95. package/dist/workflowResumeDispatch.js +30 -0
  96. package/dist/workflowRuntimeReadiness.js +12 -0
  97. package/dist/workflowShardRelocation.js +58 -0
  98. package/dist/workflowShardRelocationSql.js +72 -0
  99. package/package.json +4 -4
  100. package/dist/cluster-F_bhqVP7.js +0 -679
  101. package/dist/primitives-DX04WTWh.js +0 -507
  102. package/dist/src-C2NEyUM8.js +0 -3925
  103. package/dist/workflowReadSelections-CZAUjP7f.js +0 -2096
@@ -0,0 +1,75 @@
1
+ import { Result as e, Schema as t } from "effect";
2
+ //#region src/cancelOnPlan.ts
3
+ var n = (e) => {
4
+ let t = e instanceof Error ? e.message : String(e);
5
+ return t.length > 400 ? `${t.slice(0, 400)}…` : t;
6
+ }, r = (r) => {
7
+ let i = [], a = [], o = [], s = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), l = r.payloadSchema === void 0 ? (t) => e.succeed(t) : (i) => {
8
+ let a = t.decodeUnknownResult(r.payloadSchema)(i);
9
+ return e.isSuccess(a) ? e.succeed(a.success) : e.fail(n(a.failure));
10
+ }, u = r.runs.map((e) => ({
11
+ run: e,
12
+ decoded: l(e.payload)
13
+ })), d = r.intents.map((e) => ({
14
+ intent: e,
15
+ decoded: l(e.payload)
16
+ }));
17
+ for (let l of r.entries) for (let f of r.events) {
18
+ if (f.name !== l.event) continue;
19
+ let p = t.decodeUnknownResult(l.schema)(f.payload);
20
+ if (e.isFailure(p)) {
21
+ o.push({
22
+ kind: "event-decode",
23
+ workflowName: r.workflowName,
24
+ event: l.event,
25
+ subject: f.id,
26
+ detail: n(p.failure)
27
+ });
28
+ continue;
29
+ }
30
+ let m = p.success, h = (e) => e.getTime() > f.occurredAt.getTime() ? !1 : l.withinMs === void 0 || f.occurredAt.getTime() - e.getTime() <= l.withinMs, g = (t, i) => {
31
+ if (e.isFailure(t)) return o.push({
32
+ kind: "payload-decode",
33
+ workflowName: r.workflowName,
34
+ event: l.event,
35
+ subject: i,
36
+ detail: t.failure
37
+ }), !1;
38
+ try {
39
+ return l.match(m, t.success) === !0;
40
+ } catch (e) {
41
+ return o.push({
42
+ kind: "match-threw",
43
+ workflowName: r.workflowName,
44
+ event: l.event,
45
+ subject: i,
46
+ detail: n(e)
47
+ }), !1;
48
+ }
49
+ };
50
+ for (let { run: e, decoded: t } of u) s.has(e.runId) || h(e.startedAt) && g(t, e.runId) && (s.add(e.runId), i.push({
51
+ runId: e.runId,
52
+ executionId: e.executionId,
53
+ reason: l.reason,
54
+ event: l.event,
55
+ eventId: f.id
56
+ }));
57
+ for (let { intent: e, decoded: t } of d) c.has(e.intentId) || h(e.firstSeenAt) && g(t, e.intentId) && (c.add(e.intentId), a.push({
58
+ intentId: e.intentId,
59
+ reason: l.reason,
60
+ event: l.event,
61
+ eventId: f.id
62
+ }));
63
+ }
64
+ return {
65
+ cancels: i,
66
+ discards: a,
67
+ problems: o
68
+ };
69
+ }, i = (e) => {
70
+ let t;
71
+ for (let n of e) (t === void 0 || n.occurredAt.getTime() > t.getTime()) && (t = n.occurredAt);
72
+ return t;
73
+ };
74
+ //#endregion
75
+ export { i as newestEventAt, r as planCancellations };
@@ -0,0 +1,188 @@
1
+ import { newestEventAt as e, planCancellations as t } from "./cancelOnPlan.js";
2
+ import { and as n, eq as r, gte as i } from "@voltro/database";
3
+ //#region src/cancelOnSweep.ts
4
+ var a = "_voltro_workflow_watermarks", o = "_voltro_workflow_events", s = "cancelOn", c = 36e5, l = 500, u = 2e3, d = (e) => {
5
+ if (e instanceof Date) return e;
6
+ if (typeof e == "number") return new Date(e);
7
+ if (typeof e == "string") {
8
+ let t = new Date(e);
9
+ if (!Number.isNaN(t.getTime())) return t;
10
+ }
11
+ }, f = (e) => e instanceof Error ? e.message : String(e), p = async (e, t) => d((await e.query({
12
+ table: a,
13
+ predicate: r("id", t),
14
+ order: [],
15
+ take: 1,
16
+ skip: void 0,
17
+ projection: void 0
18
+ }))[0]?.positionAt), m = async (e, t, n) => {
19
+ await e.upsert(a, {
20
+ id: t,
21
+ positionAt: n,
22
+ updatedAt: /* @__PURE__ */ new Date()
23
+ }, {
24
+ conflictColumns: ["id"],
25
+ update: (e) => {
26
+ let t = d(e.positionAt);
27
+ return t !== void 0 && t.getTime() >= n.getTime() ? {
28
+ positionAt: t,
29
+ updatedAt: /* @__PURE__ */ new Date()
30
+ } : {
31
+ positionAt: n,
32
+ updatedAt: /* @__PURE__ */ new Date()
33
+ };
34
+ }
35
+ });
36
+ }, h = async (e, t, i) => {
37
+ let a = async (a) => e.query({
38
+ table: "_voltro_workflow_runs",
39
+ predicate: n(r("tag", t), r("status", a)),
40
+ order: [{
41
+ column: "startedAt",
42
+ direction: "asc"
43
+ }],
44
+ take: i,
45
+ skip: void 0,
46
+ projection: void 0
47
+ });
48
+ return [...await a("running"), ...await a("suspended")].flatMap((e) => {
49
+ let t = e, n = d(t.startedAt);
50
+ return typeof t.id != "string" || typeof t.executionId != "string" || n === void 0 ? [] : [{
51
+ runId: t.id,
52
+ executionId: t.executionId,
53
+ payload: t.payload,
54
+ startedAt: n
55
+ }];
56
+ });
57
+ }, g = async (e, t, n) => (await e.query({
58
+ table: "_voltro_workflow_pending",
59
+ predicate: r("workflowName", t),
60
+ order: [{
61
+ column: "firstSeenAt",
62
+ direction: "asc"
63
+ }],
64
+ take: n,
65
+ skip: void 0,
66
+ projection: void 0
67
+ })).flatMap((e) => {
68
+ let t = e, n = d(t.firstSeenAt);
69
+ return typeof t.id != "string" || n === void 0 ? [] : [{
70
+ intentId: t.id,
71
+ payload: t.payload,
72
+ firstSeenAt: n
73
+ }];
74
+ }), _ = async (n, r) => {
75
+ let a = r.workflows.filter((e) => e.entries.length > 0);
76
+ if (a.length === 0) return {
77
+ examined: !1,
78
+ events: 0,
79
+ cancelled: 0,
80
+ discarded: 0,
81
+ catchingUp: !1,
82
+ sawFullRunPage: !1,
83
+ problems: [],
84
+ failures: [],
85
+ watermark: void 0
86
+ };
87
+ let c = n.now?.() ?? Date.now(), l = r.batch ?? 500, u = r.coldLookbackMs ?? 36e5, _ = /* @__PURE__ */ new Set();
88
+ for (let e of a) for (let t of e.entries) _.add(t.event);
89
+ let v = await p(n.store, s), y = v ?? new Date(c - u);
90
+ v === void 0 && (await m(n.store, s, y), v = y);
91
+ let b = await n.store.query({
92
+ table: o,
93
+ predicate: i("occurredAt", y),
94
+ order: [{
95
+ column: "occurredAt",
96
+ direction: "asc"
97
+ }],
98
+ take: l,
99
+ skip: void 0,
100
+ projection: void 0
101
+ }), x = [];
102
+ for (let e of b) {
103
+ let t = e, n = d(t.occurredAt);
104
+ typeof t.id == "string" && typeof t.name == "string" && n !== void 0 && _.has(t.name) && x.push({
105
+ id: t.id,
106
+ name: t.name,
107
+ payload: t.payload,
108
+ occurredAt: n
109
+ });
110
+ }
111
+ let S = [], C = [], w = 0, T = 0, E = !1, D = !1, O = r.runPage ?? 2e3;
112
+ if (x.length > 0) for (let e of a) {
113
+ let r = x.filter((t) => e.entries.some((e) => e.event === t.name));
114
+ if (r.length === 0) continue;
115
+ let i = [], a = [];
116
+ try {
117
+ i = await h(n.store, e.workflowName, O), a = await g(n.store, e.workflowName, O), (i.length >= O || a.length >= O) && (E = !0);
118
+ } catch (t) {
119
+ C.push({
120
+ subject: e.workflowName,
121
+ detail: f(t)
122
+ }), D = !0;
123
+ continue;
124
+ }
125
+ let o = t({
126
+ workflowName: e.workflowName,
127
+ entries: e.entries,
128
+ payloadSchema: e.payloadSchema,
129
+ events: r,
130
+ runs: i,
131
+ intents: a
132
+ });
133
+ S.push(...o.problems);
134
+ for (let t of o.cancels) try {
135
+ await n.cancelRun({
136
+ ...t,
137
+ workflowName: e.workflowName
138
+ }), w += 1, n.log?.info("workflow.cancelOn: run cancelled", {
139
+ workflow: e.workflowName,
140
+ runId: t.runId,
141
+ event: t.event,
142
+ eventId: t.eventId
143
+ });
144
+ } catch (e) {
145
+ C.push({
146
+ subject: t.runId,
147
+ detail: f(e)
148
+ }), D = !0;
149
+ }
150
+ for (let t of o.discards) try {
151
+ await n.discardIntent({
152
+ ...t,
153
+ workflowName: e.workflowName
154
+ }), T += 1;
155
+ } catch (e) {
156
+ C.push({
157
+ subject: t.intentId,
158
+ detail: f(e)
159
+ }), D = !0;
160
+ }
161
+ }
162
+ let k = e(x), A = v;
163
+ if (D) n.log?.warn("workflow.cancelOn: holding the watermark — evaluation or delivery remains incomplete", { failures: C.length });
164
+ else if (k !== void 0) try {
165
+ await m(n.store, s, k), A = k;
166
+ } catch (e) {
167
+ C.push({
168
+ subject: s,
169
+ detail: f(e)
170
+ });
171
+ }
172
+ return S.length > 0 && n.log?.warn("workflow.cancelOn: some events could not be evaluated", {
173
+ count: S.length,
174
+ first: S[0]
175
+ }), {
176
+ examined: !0,
177
+ events: x.length,
178
+ cancelled: w,
179
+ discarded: T,
180
+ catchingUp: b.length >= l,
181
+ sawFullRunPage: E,
182
+ problems: S,
183
+ failures: C,
184
+ watermark: A
185
+ };
186
+ };
187
+ //#endregion
188
+ export { s as CANCEL_ON_WATERMARK, c as DEFAULT_COLD_LOOKBACK_MS, l as DEFAULT_EVENT_BATCH, u as DEFAULT_RUN_PAGE, o as EVENTS_TABLE, a as WATERMARKS_TABLE, p as readWatermark, _ as sweepCancelOn, m as writeWatermark };
@@ -0,0 +1,50 @@
1
+ import { readAdmissionSubmission as e } from "./admissionSubmission.js";
2
+ import { readWorkflowStartReceipt as t, settlePendingStartReceipts as n } from "./startReceipt.js";
3
+ import { PENDING_TABLE as r, toPendingIntent as i } from "./admissionStore.js";
4
+ import { eq as a } from "@voltro/database";
5
+ //#region src/cancelPendingStart.ts
6
+ var o = async (o, s) => {
7
+ if (!Number.isFinite(s.now) || !Number.isFinite(new Date(s.now).getTime())) throw Error("Queued cancellation requires a valid timestamp");
8
+ let c = await t(o, s.receiptId);
9
+ if (c === void 0 || c.workflowName !== s.workflowName || c.tenantId !== s.tenantId) throw Error("Queued cancellation receipt is missing or belongs to another workflow or tenant");
10
+ if (c.terminal !== null) return {
11
+ kind: "terminal",
12
+ outcome: c.terminal
13
+ };
14
+ if (c.submissionId !== null) {
15
+ let t = await e(o, c.submissionId);
16
+ if (t === void 0 || !t.receiptsBound || t.workflowName !== c.workflowName || t.tenantId !== c.tenantId || !t.intentIds.includes(c.pendingId)) throw Error("Queued cancellation receipt has no matching submission");
17
+ return {
18
+ kind: "submitted",
19
+ submissionId: t.id
20
+ };
21
+ }
22
+ let [l] = await o.query({
23
+ table: r,
24
+ predicate: a("id", c.pendingId),
25
+ lock: "update",
26
+ order: [],
27
+ take: 1,
28
+ skip: void 0,
29
+ projection: void 0
30
+ });
31
+ if (l === void 0) throw Error("Queued cancellation has no pending input or submission");
32
+ let u = i(l);
33
+ if (u.workflowName !== c.workflowName || u.tenantId !== c.tenantId || u.deadLetteredAt !== void 0) throw Error("Queued cancellation input has contradictory ownership or is dead-lettered");
34
+ let d = {
35
+ kind: "cancelled",
36
+ at: s.now
37
+ };
38
+ if (await n(o, {
39
+ pendingId: c.pendingId,
40
+ workflowName: c.workflowName,
41
+ tenantId: c.tenantId,
42
+ terminal: d
43
+ }), !await o.delete("_voltro_workflow_pending", c.pendingId)) throw Error("Queued cancellation lost its pending input");
44
+ return {
45
+ kind: "terminal",
46
+ outcome: d
47
+ };
48
+ };
49
+ //#endregion
50
+ export { o as cancelPendingWorkflowStartInTransaction };