@voltro/runtime 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 (184) hide show
  1. package/CHANGELOG.md +5987 -0
  2. package/README.md +43 -0
  3. package/THIRD-PARTY-NOTICES.md +864 -253
  4. package/dist/aggregate.js +42 -0
  5. package/dist/aggregateExtrema.js +80 -0
  6. package/dist/aggregateIvm.js +115 -0
  7. package/dist/analyticsMirror.js +228 -0
  8. package/dist/analyticsSink.js +32 -0
  9. package/dist/apiKeyUsage.js +33 -0
  10. package/dist/apiKeys.js +227 -0
  11. package/dist/apiKeysWiring.js +114 -0
  12. package/dist/apiRoleBucketSampler.js +64 -0
  13. package/dist/apiRoleWorkloadHistory.js +56 -0
  14. package/dist/apiRoleWorkloadMetrics.js +78 -0
  15. package/dist/apiRoleWorkloadStorage.js +95 -0
  16. package/dist/approvalBuiltins.js +10 -0
  17. package/dist/approvals.js +262 -0
  18. package/dist/authMiddlewareLayer.js +48 -0
  19. package/dist/bindEvent.js +92 -0
  20. package/dist/bootListener.js +143 -0
  21. package/dist/bootRefusal.js +7 -0
  22. package/dist/bootStoreCodec.js +71 -0
  23. package/dist/businessRules.js +67 -0
  24. package/dist/changeClaimsTable.js +12 -0
  25. package/dist/circuitBreaker.js +1 -0
  26. package/dist/columnOnUpdate.js +23 -0
  27. package/dist/composeAnalytics.js +129 -0
  28. package/dist/computedQuery.js +4 -0
  29. package/dist/computedQueryCache.js +231 -0
  30. package/dist/connectionBuiltins.js +81 -0
  31. package/dist/connectionCredentials.js +66 -0
  32. package/dist/connectionState.js +34 -0
  33. package/dist/connectionVault.js +410 -0
  34. package/dist/connectionsFacade.js +56 -0
  35. package/dist/coordinatedSchedule.js +145 -0
  36. package/dist/crdtHistory.js +138 -0
  37. package/dist/crdtMerge.js +179 -0
  38. package/dist/crdtVersionsTable.js +25 -0
  39. package/dist/credentialBound.js +12 -0
  40. package/dist/crud.js +72 -0
  41. package/dist/dataStore.js +712 -0
  42. package/dist/dataloader.js +61 -0
  43. package/dist/declaredTablesGuard.js +49 -0
  44. package/dist/defineExecutor.js +4 -0
  45. package/dist/dependencyGraph.js +32 -0
  46. package/dist/devices.js +228 -0
  47. package/dist/devicesWiring.js +168 -0
  48. package/dist/dialectReplicationAdapter.js +29 -0
  49. package/dist/dispatcher.js +522 -0
  50. package/dist/effectStore.js +71 -0
  51. package/dist/engineClients.js +24 -0
  52. package/dist/eventBus.js +260 -0
  53. package/dist/eventPublish.js +49 -0
  54. package/dist/events.js +193 -0
  55. package/dist/expectation.js +52 -0
  56. package/dist/expectationEvaluator.js +308 -0
  57. package/dist/experiment.js +96 -0
  58. package/dist/experimentEvaluator.js +245 -0
  59. package/dist/externalizedTasks.js +38 -0
  60. package/dist/fieldCipher.js +130 -0
  61. package/dist/fieldKeyRegistry.js +295 -0
  62. package/dist/fieldKeyRekey.js +286 -0
  63. package/dist/fieldKeyScan.js +136 -0
  64. package/dist/fieldKeyring.js +77 -0
  65. package/dist/fingerprint.js +21 -0
  66. package/dist/finops.js +42 -0
  67. package/dist/finopsAccountant.js +216 -0
  68. package/dist/handlerBody.js +8 -0
  69. package/dist/healthProbes.js +55 -0
  70. package/dist/hot.d.ts +56 -0
  71. package/dist/hot.js +3 -0
  72. package/dist/hotDataStore.js +148 -0
  73. package/dist/hotDataStoreSnapshot.js +98 -0
  74. package/dist/hotDataStoreTables.js +18 -0
  75. package/dist/http-range.d.ts +53 -0
  76. package/dist/http-range.js +52 -0
  77. package/dist/httpClientSsrf.js +24 -0
  78. package/dist/httpClientTracing.js +14 -0
  79. package/dist/httpCompression.js +76 -0
  80. package/dist/httpInputStream.js +82 -0
  81. package/dist/httpKeepAlive.js +12 -0
  82. package/dist/httpRouteMounts.js +48 -0
  83. package/dist/idempotencyStore.js +110 -0
  84. package/dist/idleDetector.js +21 -0
  85. package/dist/index.d.ts +1249 -517
  86. package/dist/index.js +155 -15292
  87. package/dist/insertRequiredColumns.js +19 -0
  88. package/dist/inspectWorkflow.js +1 -0
  89. package/dist/instanceMembership.js +98 -0
  90. package/dist/ivm.js +125 -0
  91. package/dist/kvDataStore.js +86 -0
  92. package/dist/kvFacade.js +38 -0
  93. package/dist/matcher.js +304 -0
  94. package/dist/memoryColumnDefaults.js +11 -0
  95. package/dist/memoryQueryJoins.js +114 -0
  96. package/dist/memorySetOperations.js +43 -0
  97. package/dist/metrics.js +175 -0
  98. package/dist/observability.js +123 -0
  99. package/dist/observedGraph.js +52 -0
  100. package/dist/originGuard.js +116 -0
  101. package/dist/outbox.js +352 -0
  102. package/dist/pluginRefRules.js +65 -0
  103. package/dist/policyGuardResolver.js +55 -0
  104. package/dist/preview.js +62 -0
  105. package/dist/projectedRows.js +12 -0
  106. package/dist/provenance.js +63 -0
  107. package/dist/rangeIndex.js +89 -0
  108. package/dist/rawReadScope.js +17 -0
  109. package/dist/reaction.js +85 -0
  110. package/dist/reactiveConfig.js +11 -0
  111. package/dist/readClassification.js +57 -0
  112. package/dist/readRecorder.js +67 -0
  113. package/dist/readScopePredicate.js +12 -0
  114. package/dist/rebac.js +104 -0
  115. package/dist/rebacInterceptor.js +81 -0
  116. package/dist/registry.js +29 -0
  117. package/dist/relevantFields.js +65 -0
  118. package/dist/replicaHealth.js +42 -0
  119. package/dist/replicaLocality.js +44 -0
  120. package/dist/replicaObservations.js +121 -0
  121. package/dist/replicaSelection.js +32 -0
  122. package/dist/replicatedDataStore.js +257 -0
  123. package/dist/requestLoader.js +7 -0
  124. package/dist/resumeCensus.js +28 -0
  125. package/dist/revalidation.js +22 -0
  126. package/dist/rowFilter.js +82 -0
  127. package/dist/rowStateBytes.js +45 -0
  128. package/dist/rpcBodyCap.js +63 -0
  129. package/dist/rpcConnections.js +83 -0
  130. package/dist/rpcDefectDiagnostics.js +15 -0
  131. package/dist/rpcServer.js +1065 -0
  132. package/dist/rpcWorkloadAdmission.js +50 -0
  133. package/dist/runAsSystem.js +23 -0
  134. package/dist/rywPositionStore.js +119 -0
  135. package/dist/schedule.js +23 -0
  136. package/dist/scheduleBackfillRequests.js +151 -0
  137. package/dist/scheduleClaimsTable.js +11 -0
  138. package/dist/scheduleRunsTable.js +37 -0
  139. package/dist/scheduler.js +840 -0
  140. package/dist/schemaRegistry.js +65 -0
  141. package/dist/secretsResolver.js +35 -0
  142. package/dist/securityHeaders.js +33 -0
  143. package/dist/servePipeline.js +374 -0
  144. package/dist/serverOnlyAudit.js +66 -0
  145. package/dist/serverTracer.js +15 -0
  146. package/dist/serviceCredentials.js +40 -0
  147. package/dist/setReadScopes.js +28 -0
  148. package/dist/singleNodeOrchestrator.js +91 -0
  149. package/dist/snapshotValueCodec.js +46 -0
  150. package/dist/sourceResolution.js +52 -0
  151. package/dist/storeMiddleware.js +882 -0
  152. package/dist/storeQuery.js +204 -0
  153. package/dist/storeRead.js +10 -0
  154. package/dist/subscriber.js +8 -0
  155. package/dist/subscriptionOutbox.js +139 -0
  156. package/dist/subscriptionRegistry.js +82 -0
  157. package/dist/subscriptionResume.js +132 -0
  158. package/dist/subscriptionSocketMetrics.js +65 -0
  159. package/dist/systemSubject.js +5 -0
  160. package/dist/tenantScope.js +11 -0
  161. package/dist/tenantSelection.js +27 -0
  162. package/dist/timeline.js +105 -0
  163. package/dist/traceContext.js +5 -0
  164. package/dist/traceSink.js +63 -0
  165. package/dist/traceSpansTable.js +29 -0
  166. package/dist/traceparent.js +23 -0
  167. package/dist/transactionSubject.js +12 -0
  168. package/dist/trustedProxy.js +155 -0
  169. package/dist/undo.js +129 -0
  170. package/dist/undoBuiltins.js +69 -0
  171. package/dist/undoCapture.js +74 -0
  172. package/dist/undoLogTable.js +16 -0
  173. package/dist/upsertBinding.js +20 -0
  174. package/dist/wakeOrchestrator.js +34 -0
  175. package/dist/wakeRegistry.js +71 -0
  176. package/dist/wakeRouter.js +63 -0
  177. package/dist/wakeSupervisor.js +62 -0
  178. package/dist/wakeupsTable.js +12 -0
  179. package/dist/webSocketGatewayRuntime.js +154 -0
  180. package/dist/webhookVerification.js +18 -0
  181. package/dist/wireColumnStrip.js +84 -0
  182. package/dist/workflowReadBuiltins.js +87 -0
  183. package/dist/workflowRuntime.js +708 -0
  184. package/package.json +19 -7
@@ -0,0 +1,840 @@
1
+ import { settleHandlerBody as e } from "./handlerBody.js";
2
+ import { recordExternalMissed as t, recordExternalTrigger as n, recordScheduleQueueRecovery as r, recordScheduleQueueWait as i, recordScheduleQueued as a, recordScheduleRun as o } from "./metrics.js";
3
+ import { newTraceId as s } from "./traceparent.js";
4
+ import { SYSTEM_SUBJECT as c } from "./systemSubject.js";
5
+ import { DEFAULT_MAX_RUNTIME_MS as l, compileCron as u, cronOccurrences as d } from "./schedule.js";
6
+ import { acceptScheduleBackfillRequest as f, executeScheduleBackfillRequest as p, interruptOwnedScheduleBackfills as ee, interruptStaleScheduleBackfills as m, readScheduleBackfillRequest as h } from "./scheduleBackfillRequests.js";
7
+ import { registerWakeup as te } from "./wakeRegistry.js";
8
+ import { Cron as g, Effect as ne } from "effect";
9
+ import { and as _, eq as v, extractDbCause as y, lt as re } from "@voltro/database";
10
+ import { randomUUID as ie } from "node:crypto";
11
+ import { publishServerError as ae } from "@voltro/protocol";
12
+ //#region src/scheduler.ts
13
+ var b = c, x = "default", S = {
14
+ kind: "single",
15
+ tryClaim: async () => !0
16
+ }, C = "_voltro_schedule_claims", oe = 6e4, w = 64, T = (e) => Math.max((e ?? 6e4) * 64, 6e4), E = (e, t, n) => {
17
+ let r = async (t) => (await e.query({
18
+ table: C,
19
+ order: [],
20
+ predicate: v("id", t),
21
+ projection: ["id"],
22
+ skip: void 0,
23
+ take: 1
24
+ })).length > 0, i = /* @__PURE__ */ new Map(), a = async (t, n) => {
25
+ let r = Date.now();
26
+ if (!(r - (i.get(t) ?? 0) < n)) {
27
+ i.set(t, r);
28
+ try {
29
+ await e.deleteMany(C, { where: _(v("scheduleName", t), re("claimedAt", new Date(r - n))) });
30
+ } catch {}
31
+ }
32
+ };
33
+ return {
34
+ kind: "advisoryLock",
35
+ tryClaim: async (i, o, s) => {
36
+ let c = o.toISOString(), l = o.getUTCMilliseconds() === 0 ? c.slice(0, 19) : c.slice(0, 23), u = `${i}@${l}`;
37
+ try {
38
+ if (await r(u)) return !1;
39
+ } catch {}
40
+ try {
41
+ return await e.insert(C, {
42
+ id: u,
43
+ scheduleName: i,
44
+ bucket: l,
45
+ claimedBy: t,
46
+ claimedAt: /* @__PURE__ */ new Date()
47
+ }), await a(i, T(s)), !0;
48
+ } catch (e) {
49
+ try {
50
+ if (await r(u)) return !1;
51
+ } catch {}
52
+ return n?.warn("schedule: advisoryLock claim failed without a winning row — claims table may be unmigrated/unreachable; schedule will NOT fire until fixed", {
53
+ schedule: i,
54
+ reason: e?.message ?? String(e)
55
+ }), !1;
56
+ }
57
+ }
58
+ };
59
+ }, se = 3e5, ce = 3e5, le = 6e4, ue = 864e5, D = 200, de = /* @__PURE__ */ new Set([
60
+ "succeeded",
61
+ "failed",
62
+ "skipped",
63
+ "missed"
64
+ ]), O = "_voltro_schedule_runs", fe = 3e4, k = 3, pe = 1e3, me = (e, t) => Math.max(e * 2, t * k * 2), A = (e, t, n) => {
65
+ let r = n.heartbeatMs * k, i = e.heartbeatAt == null ? NaN : new Date(e.heartbeatAt).getTime();
66
+ if (Number.isFinite(i)) return t - i < r;
67
+ let a = e.firedAt == null ? NaN : new Date(e.firedAt).getTime();
68
+ return Number.isFinite(a) ? t - a < n.maxRuntimeMs + r : !1;
69
+ }, j = async (c, x) => {
70
+ let { store: S, coordinator: C, buildContext: oe, replicaId: w, log: T, onRunEvent: de, interceptFire: k } = x, j = x.runHeartbeatMs !== void 0 && x.runHeartbeatMs > 0 ? x.runHeartbeatMs : fe, _e = x.queueAdoptionWindowMs !== void 0 && x.queueAdoptionWindowMs > 0 ? x.queueAdoptionWindowMs : void 0, N = x.dormancy === "sleep", ve = x.dormancyTenantId ?? "default", P = /* @__PURE__ */ new Map(), F = /* @__PURE__ */ new Set(), ye = /* @__PURE__ */ new Map(), I = !1, be = `${w}:${ie()}`, L, R, z = !1, B = () => {
71
+ I || z || L !== void 0 || (L = setTimeout(() => {
72
+ L = void 0, z = !0, R = m(S).then(() => {}, (e) => T.warn("schedule backfill recovery unavailable", { reason: M(e) })).finally(() => {
73
+ z = !1, I || B();
74
+ });
75
+ }, 1e4), L.unref?.());
76
+ }, V = new Map(c.map((e) => [e.name, e])), H = (e, t) => {
77
+ de?.(e, ge(t));
78
+ }, U = async (e, t, n, r, i, a) => {
79
+ try {
80
+ let o = `sr_${ie()}`, s = await S.insert(O, {
81
+ id: o,
82
+ name: e.name,
83
+ status: r,
84
+ trigger: i,
85
+ scheduledAt: t,
86
+ firedAt: n,
87
+ completedAt: null,
88
+ durationMs: null,
89
+ errorTag: null,
90
+ errorMessage: null,
91
+ coordinationOutcome: a,
92
+ replicaId: w,
93
+ heartbeatAt: r === "running" ? n : r === "queued" ? /* @__PURE__ */ new Date() : null,
94
+ result: null
95
+ }), c = s.id ?? o;
96
+ return H("insert", s), c;
97
+ } catch (t) {
98
+ T.warn("schedule: failed to record run start", {
99
+ name: e.name,
100
+ reason: M(t)
101
+ });
102
+ return;
103
+ }
104
+ }, xe = async (e, t) => {
105
+ try {
106
+ let n = await S.update(O, e, t);
107
+ if (n) {
108
+ H("update", n);
109
+ return;
110
+ }
111
+ T.warn("schedule: run row did not transition — it stays `running` and will suppress this schedule", {
112
+ runId: e,
113
+ status: t.status
114
+ });
115
+ } catch (t) {
116
+ T.warn("schedule: failed to record run finish", {
117
+ runId: e,
118
+ reason: M(t)
119
+ });
120
+ }
121
+ }, W = async (e) => {
122
+ try {
123
+ let t = await S.query({
124
+ table: O,
125
+ predicate: { and: [{
126
+ _tag: "leaf",
127
+ column: "status",
128
+ op: "eq",
129
+ value: "running"
130
+ }, {
131
+ _tag: "leaf",
132
+ column: "name",
133
+ op: "eq",
134
+ value: e.name
135
+ }] },
136
+ order: [{
137
+ column: "firedAt",
138
+ direction: "desc"
139
+ }],
140
+ take: 200,
141
+ skip: void 0,
142
+ projection: void 0
143
+ }), n = Date.now(), r = {
144
+ heartbeatMs: j,
145
+ maxRuntimeMs: e.maxRuntimeMs ?? 18e5
146
+ }, i = t.find((e) => A(e, n, r));
147
+ if (i === void 0) return;
148
+ let a = i.heartbeatAt ?? i.firedAt;
149
+ return {
150
+ replicaId: i.replicaId ?? null,
151
+ lastSeenMs: a == null ? NaN : n - new Date(a).getTime()
152
+ };
153
+ } catch (t) {
154
+ T.warn("schedule: cluster-running check failed", {
155
+ name: e.name,
156
+ reason: M(t)
157
+ });
158
+ return;
159
+ }
160
+ }, Se = async (e, t) => {
161
+ try {
162
+ await S.update(O, e, { heartbeatAt: /* @__PURE__ */ new Date() });
163
+ } catch (n) {
164
+ t.yes || (t.yes = !0, T.warn("schedule: heartbeat write failed — a peer may read this run as dead and fire alongside it", {
165
+ runId: e,
166
+ reason: M(n)
167
+ }));
168
+ }
169
+ }, Ce = (e, t) => t === void 0 ? e === "external" || C.kind !== "single" : t !== "single", G = /* @__PURE__ */ new Set(), K = 0, we = (e, t) => new Promise((n) => {
170
+ if (K !== t) {
171
+ n();
172
+ return;
173
+ }
174
+ let r, i = !1, a = () => {
175
+ i || (i = !0, G.delete(o), r !== void 0 && clearTimeout(r), n());
176
+ }, o = () => {
177
+ a();
178
+ };
179
+ G.add(o), r = setTimeout(a, e), r.unref?.();
180
+ }), Te = x.onChange?.((e) => {
181
+ if (e.table === O) {
182
+ K += 1;
183
+ for (let e of [...G]) e();
184
+ }
185
+ }), Ee = async (e, t) => await S.updateMany(O, {
186
+ status: "running",
187
+ firedAt: t,
188
+ heartbeatAt: t,
189
+ replicaId: w
190
+ }, { where: _(v("id", e), v("status", "queued")) }) > 0, De = (e, t) => {
191
+ try {
192
+ let n = u(e), r = g.next(n, t), i = g.next(n, r).getTime() - r.getTime();
193
+ return i > 0 ? i : j;
194
+ } catch {
195
+ return j;
196
+ }
197
+ }, Oe = async (e, t, n) => {
198
+ let r = await S.query({
199
+ table: O,
200
+ predicate: _(v("name", e.name), v("status", "queued"), re("scheduledAt", t)),
201
+ order: [{
202
+ column: "scheduledAt",
203
+ direction: "asc"
204
+ }],
205
+ take: 200,
206
+ skip: void 0,
207
+ projection: void 0
208
+ }), i = Date.now(), a = {
209
+ heartbeatMs: j,
210
+ maxRuntimeMs: e.maxRuntimeMs ?? 18e5
211
+ };
212
+ for (let t of r) {
213
+ if (t.id === n) continue;
214
+ let r = new Date(t.scheduledAt);
215
+ if (A(t, i, a)) return {
216
+ kind: "blocked",
217
+ behind: r
218
+ };
219
+ let o = t.heartbeatAt ?? t.firedAt ?? t.scheduledAt, s = i - new Date(o).getTime();
220
+ if (s <= (_e ?? me(De(e, r), j))) return {
221
+ kind: "adopt",
222
+ runId: t.id,
223
+ scheduledAt: r,
224
+ trigger: t.trigger ?? e.trigger ?? x.defaultTrigger
225
+ };
226
+ await ke(t.id, e.name, r, s);
227
+ }
228
+ return { kind: "next" };
229
+ }, ke = async (e, t, n, i, a = "the replica holding this firing stopped reporting for longer than the adoption window") => {
230
+ try {
231
+ await S.updateMany(O, {
232
+ status: "missed",
233
+ errorTag: "abandoned",
234
+ errorMessage: a,
235
+ completedAt: /* @__PURE__ */ new Date()
236
+ }, { where: _(v("id", e), v("status", "queued")) }) > 0 && (r(t, "abandoned"), T.warn("schedule: a queued firing was abandoned", {
237
+ name: t,
238
+ runId: e,
239
+ scheduledAt: n.toISOString(),
240
+ silenceMs: Math.round(i),
241
+ reason: a
242
+ }));
243
+ } catch (n) {
244
+ T.warn("schedule: writing off an abandoned queued firing failed", {
245
+ name: t,
246
+ runId: e,
247
+ reason: M(n)
248
+ });
249
+ }
250
+ }, Ae = async (e) => {
251
+ try {
252
+ let t = await S.query({
253
+ table: O,
254
+ predicate: v("id", e),
255
+ order: [],
256
+ take: 1,
257
+ skip: void 0,
258
+ projection: void 0
259
+ });
260
+ t[0] !== void 0 && H("update", t[0]);
261
+ } catch {}
262
+ }, je = async (e, t, n, a) => {
263
+ let o = { yes: !1 }, s = !1, c = setInterval(() => {
264
+ Se(n, o);
265
+ }, j);
266
+ c.unref?.();
267
+ try {
268
+ for (;;) {
269
+ if (I) return;
270
+ let o = K;
271
+ try {
272
+ let o = await W(e);
273
+ if (o === void 0) {
274
+ let o = await Oe(e, t, n);
275
+ if (o.kind === "next") {
276
+ let r = /* @__PURE__ */ new Date();
277
+ if (!await Ee(n, r)) {
278
+ T.warn("schedule: queued firing lost its row before its turn", {
279
+ name: e.name,
280
+ runId: n,
281
+ scheduledAt: t.toISOString()
282
+ });
283
+ return;
284
+ }
285
+ return await Ae(n), i(e.name, Date.now() - a), r;
286
+ }
287
+ if (o.kind === "adopt") {
288
+ let t = /* @__PURE__ */ new Date();
289
+ await Ee(o.runId, t) && (T.info("schedule: adopted a queued firing from a replica that stopped reporting", {
290
+ name: e.name,
291
+ runId: o.runId,
292
+ scheduledAt: o.scheduledAt.toISOString()
293
+ }), r(e.name, "adopted"), await Ae(o.runId), await q(e, o.scheduledAt, o.trigger, "wonLock", {
294
+ runId: o.runId,
295
+ firedAt: t
296
+ }));
297
+ continue;
298
+ }
299
+ s || (s = !0, T.info("schedule: queued behind an earlier firing", {
300
+ name: e.name,
301
+ scheduledAt: t.toISOString(),
302
+ behind: o.behind.toISOString()
303
+ }));
304
+ } else s || (s = !0, T.info("schedule: queued behind a run in flight", {
305
+ name: e.name,
306
+ scheduledAt: t.toISOString(),
307
+ heldBy: o.replicaId ?? "unknown"
308
+ }));
309
+ } catch (t) {
310
+ T.warn("schedule: queue turn check failed", {
311
+ name: e.name,
312
+ reason: M(t)
313
+ });
314
+ }
315
+ await we(pe, o);
316
+ }
317
+ } finally {
318
+ clearInterval(c);
319
+ }
320
+ }, Me = async (e, t, n, r, i) => {
321
+ let o = Date.now(), s = await U(e, t, null, "queued", n, r);
322
+ if (s === void 0) return T.warn("schedule: could not record the queued firing — running it without the fleet-wide turn, which may overlap a run elsewhere", { name: e.name }), q(e, t, n, r, void 0, i);
323
+ i?.(s), a(e.name, 1);
324
+ let c;
325
+ try {
326
+ c = await je(e, t, s, o);
327
+ } finally {
328
+ a(e.name, -1);
329
+ }
330
+ return c === void 0 ? s : q(e, t, n, r, {
331
+ runId: s,
332
+ firedAt: c
333
+ });
334
+ }, q = async (t, n, r, i, a, c) => {
335
+ let l = a?.firedAt ?? /* @__PURE__ */ new Date(), u = a?.runId ?? await U(t, n, l, "running", r, i);
336
+ c?.(u);
337
+ let d = Date.now(), f, p, ee = { yes: !1 }, m = new AbortController();
338
+ try {
339
+ let i = new Promise((e, n) => {
340
+ f = setTimeout(() => {
341
+ n(/* @__PURE__ */ Error(`schedule "${t.name}" exceeded maxRuntimeMs=${t.maxRuntimeMs}`)), m.abort();
342
+ }, t.maxRuntimeMs);
343
+ });
344
+ i.catch(() => {}), u !== void 0 && (p = setInterval(() => {
345
+ Se(u, ee);
346
+ }, j), p.unref?.());
347
+ let a = {
348
+ scheduledAt: n,
349
+ firedAt: l,
350
+ runId: u ?? "unrecorded",
351
+ trigger: r,
352
+ app: oe({
353
+ traceId: s(),
354
+ scheduleName: t.name,
355
+ trigger: r,
356
+ runId: u,
357
+ subject: b
358
+ })
359
+ }, c = async () => {
360
+ if (t.workflow !== void 0) {
361
+ let e = a.app.workflows;
362
+ if (e === void 0) throw Error(`schedule "${t.name}" targets workflow "${t.workflow.name}" but no workflows runtime is configured`);
363
+ let n = typeof t.workflow.payload == "function" ? await t.workflow.payload(a) : t.workflow.payload ?? {};
364
+ await e.start(t.workflow.name, n);
365
+ }
366
+ if (t.handler !== void 0) {
367
+ let n = t.handler, r = x.measureSync ? x.measureSync(() => n(a)) : n(a);
368
+ await e(r, (e) => x.runEffect ? x.runEffect(e, m.signal) : ne.runPromise(e, { signal: m.signal }));
369
+ }
370
+ }, h = k ? k(c, {
371
+ name: t.name,
372
+ scheduledAt: n,
373
+ firedAt: l,
374
+ runId: u ?? "unrecorded",
375
+ trigger: r
376
+ }) : c();
377
+ await Promise.race([h, i]), u && await xe(u, {
378
+ status: "succeeded",
379
+ completedAt: /* @__PURE__ */ new Date(),
380
+ durationMs: Date.now() - d
381
+ }), T.info("schedule: fired", {
382
+ name: t.name,
383
+ durationMs: Date.now() - d
384
+ }), o({
385
+ name: t.name,
386
+ status: "succeeded",
387
+ durationMs: Date.now() - d,
388
+ completedAtSec: Date.now() / 1e3
389
+ });
390
+ } catch (e) {
391
+ let n = M(e).includes("exceeded maxRuntimeMs"), r = y(e).dbMessage, i = typeof r == "string" && r !== "" ? `${M(e)} — ${r}` : M(e);
392
+ u && await xe(u, {
393
+ status: "failed",
394
+ errorTag: n ? "timeout" : he(e),
395
+ errorMessage: i,
396
+ completedAt: /* @__PURE__ */ new Date(),
397
+ durationMs: Date.now() - d
398
+ });
399
+ let a = {
400
+ name: t.name,
401
+ reason: M(e),
402
+ timeout: n,
403
+ ...y(e)
404
+ };
405
+ T.error ? T.error("schedule: handler failed", a) : T.warn("schedule: handler failed", a), o({
406
+ name: t.name,
407
+ status: "failed",
408
+ durationMs: Date.now() - d
409
+ }), ae({
410
+ error: e,
411
+ source: "schedule",
412
+ name: t.name,
413
+ fields: {
414
+ timeout: n,
415
+ ...u ? { runId: u } : {}
416
+ }
417
+ });
418
+ } finally {
419
+ f && clearTimeout(f), p && clearInterval(p);
420
+ }
421
+ return u;
422
+ }, J = async (e, t, n, r, i) => {
423
+ if (n !== "manual" && e.onOverlap === "queue" && !Ce(n, r)) {
424
+ let a = (ye.get(e.name) ?? Promise.resolve()).then(() => Ne(e, t, n, r, i));
425
+ return ye.set(e.name, a.catch(() => {})), a;
426
+ }
427
+ if (n !== "manual" && e.onOverlap === "skip") {
428
+ let a = F.has(e.name), o = a ? void 0 : await W(e);
429
+ if (a || o !== void 0) {
430
+ let s = await U(e, t, null, "skipped", n, r ?? "single");
431
+ return i?.(s), T.info("schedule: overlap skip", {
432
+ name: e.name,
433
+ scope: a ? "local" : "cluster",
434
+ ...o === void 0 ? {} : {
435
+ heldBy: o.replicaId ?? "unknown",
436
+ lastSeenMs: Number.isFinite(o.lastSeenMs) ? Math.round(o.lastSeenMs) : null
437
+ }
438
+ }), s;
439
+ }
440
+ }
441
+ return Ne(e, t, n, r, i);
442
+ }, Ne = async (e, t, n, r, i) => {
443
+ let a;
444
+ if (r !== void 0) a = r;
445
+ else if (n === "manual") a = "single";
446
+ else if (n === "external") a = "external";
447
+ else {
448
+ if (!await C.tryClaim(e.name, t)) {
449
+ T.debug?.("schedule: lost coordination claim", {
450
+ name: e.name,
451
+ coordinator: C.kind
452
+ });
453
+ return;
454
+ }
455
+ a = C.kind === "single" ? "single" : "wonLock";
456
+ }
457
+ F.add(e.name);
458
+ try {
459
+ return n !== "manual" && e.onOverlap === "queue" && Ce(n, r) ? await Me(e, t, n, a, i) : await q(e, t, n, a, void 0, i);
460
+ } finally {
461
+ F.delete(e.name);
462
+ }
463
+ }, Y = async (e) => {
464
+ try {
465
+ let t = g.next(u(e), /* @__PURE__ */ new Date());
466
+ await te(S, {
467
+ tenantId: ve,
468
+ kind: "schedule",
469
+ refId: e.name,
470
+ wakeAt: t
471
+ });
472
+ } catch (t) {
473
+ T.warn("schedule: wakeup register failed", {
474
+ name: e.name,
475
+ reason: M(t)
476
+ });
477
+ }
478
+ }, Pe = 2147483647, Fe = (e) => {
479
+ if (I) return;
480
+ let t = u(e), n = g.next(t, /* @__PURE__ */ new Date()), r = () => {
481
+ if (I) return;
482
+ let t = n.getTime() - Date.now();
483
+ if (t > Pe) {
484
+ let t = setTimeout(r, Pe);
485
+ P.set(e.name, t);
486
+ return;
487
+ }
488
+ let i = setTimeout(() => {
489
+ J(e, n, e.trigger ?? x.defaultTrigger).catch((t) => T.warn("schedule: fire rejected", {
490
+ name: e.name,
491
+ reason: M(t)
492
+ })).finally(() => Fe(e));
493
+ }, Math.max(0, t));
494
+ P.set(e.name, i);
495
+ };
496
+ r();
497
+ }, Ie = async () => {
498
+ if (V.size !== 0) try {
499
+ let e = await S.query({
500
+ table: O,
501
+ predicate: v("status", "queued"),
502
+ order: [{
503
+ column: "scheduledAt",
504
+ direction: "asc"
505
+ }],
506
+ take: 500,
507
+ skip: void 0,
508
+ projection: void 0
509
+ }), t = Date.now(), n = {
510
+ heartbeatMs: j,
511
+ maxRuntimeMs: l
512
+ };
513
+ for (let r of e) {
514
+ if (V.has(r.name) || A(r, t, n)) continue;
515
+ let e = r.heartbeatAt ?? r.firedAt ?? r.scheduledAt;
516
+ await ke(r.id, r.name, new Date(r.scheduledAt), t - new Date(e).getTime(), "no schedule of this name is declared any more, so nothing can take this firing");
517
+ }
518
+ } catch (e) {
519
+ T.warn("schedule: orphaned-waiter sweep failed", { reason: M(e) });
520
+ }
521
+ }, Le = async (e) => {
522
+ if (e.backfill === "skip") return;
523
+ let t;
524
+ try {
525
+ let n = (await S.query({
526
+ table: O,
527
+ order: [{
528
+ column: "scheduledAt",
529
+ direction: "desc"
530
+ }],
531
+ predicate: v("name", e.name),
532
+ projection: void 0,
533
+ skip: void 0,
534
+ take: 1
535
+ }))[0];
536
+ n && (t = new Date(n.scheduledAt));
537
+ } catch (t) {
538
+ T.warn("schedule: backfill lookup failed", {
539
+ name: e.name,
540
+ reason: M(t)
541
+ });
542
+ return;
543
+ }
544
+ if (!t) return;
545
+ let n = u(e), r = [], i = g.next(n, t), a = Date.now();
546
+ for (; i.getTime() < a && r.length < 1e3;) r.push(i), i = g.next(n, i);
547
+ if (r.length !== 0) {
548
+ if (T.info("schedule: backfill", {
549
+ name: e.name,
550
+ missed: r.length,
551
+ policy: e.backfill
552
+ }), e.backfill === "latest") {
553
+ for (let t of r.slice(0, -1)) {
554
+ let n = !0;
555
+ try {
556
+ n = await C.tryClaim(e.name, t);
557
+ } catch {
558
+ n = !0;
559
+ }
560
+ n && await U(e, t, null, "missed", e.trigger ?? x.defaultTrigger, C.kind === "single" ? "single" : "wonLock");
561
+ }
562
+ let t = r[r.length - 1];
563
+ await J(e, t, e.trigger ?? x.defaultTrigger);
564
+ } else for (let t of r) await J(e, t, e.trigger ?? x.defaultTrigger);
565
+ }
566
+ }, Re = c.filter((e) => (e.trigger ?? x.defaultTrigger) === "external" && e.cron.trim().split(/\s+/).length === 6);
567
+ if (Re.length > 0) throw Error(`startScheduler: ${Re.map((e) => `"${e.name}" ("${e.cron}")`).join(", ")} use a six-field (seconds) cron and resolve to trigger: 'external' via scheduling.trigger — no platform scheduler can express sub-minute cadence, so nothing would ever fire them.
568
+ Give each a five-field expression, or set trigger: 'self' on it.`);
569
+ let X = c.filter((e) => (e.trigger ?? x.defaultTrigger) === "self");
570
+ T.info("scheduler: starting", {
571
+ total: c.length,
572
+ self: X.length,
573
+ external: c.length - X.length,
574
+ coordinator: C.kind
575
+ }), await Ie();
576
+ let ze = x.externalTriggerSkewMs !== void 0 && x.externalTriggerSkewMs > 0 ? x.externalTriggerSkewMs : se, Be = C.kind === "advisoryLock" ? C : E(S, w, T), Ve = (e, t, n) => {
577
+ try {
578
+ let r = u(e), i = g.next(r, new Date(t.getTime() - n)), a, o = 0;
579
+ for (; i.getTime() <= t.getTime() && o++ < 1e3;) a = i, i = g.next(r, i);
580
+ return a;
581
+ } catch {
582
+ return;
583
+ }
584
+ }, He = (e, t) => Math.min(ze, De(e, t)), Z = (e) => e == null ? null : e instanceof Date ? e : new Date(String(e)), Ue = async (e, t) => {
585
+ try {
586
+ return (await S.query({
587
+ table: O,
588
+ order: [],
589
+ predicate: _(v("name", e), v("scheduledAt", t)),
590
+ projection: ["id"],
591
+ skip: void 0,
592
+ take: 1
593
+ }))[0]?.id;
594
+ } catch {
595
+ return;
596
+ }
597
+ }, We = async (e) => {
598
+ let t = (await S.query({
599
+ table: O,
600
+ order: [],
601
+ predicate: v("id", e),
602
+ projection: void 0,
603
+ skip: void 0,
604
+ take: 1
605
+ }))[0];
606
+ if (t !== void 0) return {
607
+ runId: String(t.id),
608
+ name: String(t.name),
609
+ status: String(t.status),
610
+ trigger: String(t.trigger),
611
+ scheduledAt: Z(t.scheduledAt),
612
+ firedAt: Z(t.firedAt),
613
+ completedAt: Z(t.completedAt),
614
+ durationMs: typeof t.durationMs == "number" ? t.durationMs : null,
615
+ errorTag: t.errorTag === null || t.errorTag === void 0 ? null : String(t.errorTag),
616
+ errorMessage: t.errorMessage === null || t.errorMessage === void 0 ? null : String(t.errorMessage)
617
+ };
618
+ }, Ge = c.filter((e) => (e.trigger ?? x.defaultTrigger) === "external"), Q = x.externalMissedPolicy ?? "record", Ke = x.externalReconcileMs !== void 0 && x.externalReconcileMs > 0 ? x.externalReconcileMs : ce, $, qe = async (e) => {
619
+ try {
620
+ let t = (await S.query({
621
+ table: O,
622
+ predicate: v("name", e),
623
+ order: [{
624
+ column: "scheduledAt",
625
+ direction: "desc"
626
+ }],
627
+ projection: ["scheduledAt"],
628
+ skip: void 0,
629
+ take: 1
630
+ }))[0]?.scheduledAt;
631
+ return t === void 0 ? void 0 : Z(t) ?? void 0;
632
+ } catch {
633
+ return;
634
+ }
635
+ }, Je = async () => {
636
+ let e = Date.now();
637
+ for (let n of Ge) try {
638
+ let r = new Date(e - He(n, new Date(e))), i = await qe(n.name) ?? /* @__PURE__ */ new Date(e - ue);
639
+ if (i.getTime() >= r.getTime()) continue;
640
+ let a = d(n, i, r, D);
641
+ if (a.length === 0) continue;
642
+ a.length > D && T.warn("schedule: more unfired occurrences than one reconciliation records", {
643
+ name: n.name,
644
+ cap: D,
645
+ since: i.toISOString()
646
+ });
647
+ let o = 0;
648
+ for (let e of a.slice(0, D)) await Be.tryClaim(n.name, e) && (Q === "record-and-run" ? await J(n, e, "external", "external") : await U(n, e, null, "missed", "external", "external"), o += 1);
649
+ o > 0 && (t(n.name, o), T.warn("schedule: occurrences were never triggered by the external scheduler", {
650
+ name: n.name,
651
+ count: o,
652
+ since: i.toISOString(),
653
+ policy: Q
654
+ }));
655
+ } catch (e) {
656
+ T.warn("schedule: external reconciliation failed", {
657
+ name: n.name,
658
+ reason: e?.message ?? String(e)
659
+ });
660
+ }
661
+ }, Ye = () => {
662
+ I || ($ = setTimeout(() => {
663
+ Je().finally(Ye);
664
+ }, Ke), $.unref?.());
665
+ };
666
+ Ge.length > 0 && Q !== "off" && Ye();
667
+ let Xe = async (e, t) => {
668
+ if (I) throw Error("scheduler stopped");
669
+ let n = V.get(e);
670
+ if (!n) return {
671
+ kind: "unknownSchedule",
672
+ name: e
673
+ };
674
+ let r = n.trigger ?? x.defaultTrigger;
675
+ if (r !== "external") return {
676
+ kind: "notExternal",
677
+ name: e,
678
+ trigger: r
679
+ };
680
+ let i = /* @__PURE__ */ new Date();
681
+ if (t.getTime() > i.getTime() + 6e4) return T.warn("schedule: external trigger states a future time — refused, so the real firing is not turned into a duplicate", {
682
+ name: e,
683
+ arrivalAt: t.toISOString(),
684
+ now: i.toISOString()
685
+ }), {
686
+ kind: "ahead",
687
+ arrivalAt: t,
688
+ now: i,
689
+ toleranceMs: le
690
+ };
691
+ let a = He(n, t), o = Ve(n, t, a);
692
+ if (o === void 0) return T.warn("schedule: external trigger matched no occurrence — the deployed cadence and the declared one disagree", {
693
+ name: e,
694
+ arrivalAt: t.toISOString(),
695
+ cron: n.cron,
696
+ timezone: n.timezone,
697
+ skewMs: a
698
+ }), {
699
+ kind: "noOccurrence",
700
+ arrivalAt: t,
701
+ skewMs: a,
702
+ cron: n.cron,
703
+ timezone: n.timezone
704
+ };
705
+ if (!await Be.tryClaim(n.name, o)) return T.debug?.("schedule: external trigger deduplicated", {
706
+ name: e,
707
+ scheduledAt: o.toISOString()
708
+ }), {
709
+ kind: "duplicate",
710
+ runId: await Ue(n.name, o),
711
+ scheduledAt: o
712
+ };
713
+ let s = () => {}, c = new Promise((e) => {
714
+ s = e;
715
+ }), l = !1, u = (e) => {
716
+ l || (l = !0, s(e));
717
+ };
718
+ return J(n, o, "external", "external", u).then((e) => u(e)).catch((t) => {
719
+ T.warn("schedule: external firing failed to start", {
720
+ name: e,
721
+ reason: t?.message ?? String(t)
722
+ }), u(void 0);
723
+ }), N && await Y(n), {
724
+ kind: "accepted",
725
+ runId: await c,
726
+ scheduledAt: o
727
+ };
728
+ }, Ze = (x.armSelf ?? !0) && !N;
729
+ if (N) {
730
+ T.info("scheduler: sleep mode — registering wakeups, not arming timers", { count: X.length });
731
+ for (let e of X) await Y(e);
732
+ } else if (Ze) {
733
+ for (let e of X) await Le(e);
734
+ for (let e of X) Fe(e);
735
+ }
736
+ return {
737
+ isRunning: () => !I,
738
+ triggerExternal: async (e, t) => {
739
+ let r = await Xe(e, t);
740
+ return n(e, r.kind), r;
741
+ },
742
+ runStatus: We,
743
+ startNow: async (e, t) => {
744
+ let n = V.get(e);
745
+ if (!n) throw Error(`scheduler.startNow: unknown schedule "${e}"`);
746
+ if (I) throw Error("scheduler stopped");
747
+ let r = await new Promise((e, r) => {
748
+ J(n, /* @__PURE__ */ new Date(), t, void 0, e).then(e, r);
749
+ });
750
+ return N && await Y(n), r;
751
+ },
752
+ fireNow: async (e, t) => {
753
+ let n = V.get(e);
754
+ if (!n) throw Error(`scheduler.fireNow: unknown schedule "${e}"`);
755
+ let r = await J(n, /* @__PURE__ */ new Date(), t);
756
+ return N && await Y(n), r;
757
+ },
758
+ fireFromCluster: async (e) => {
759
+ let t = V.get(e);
760
+ if (!t) throw Error(`scheduler.fireFromCluster: unknown schedule "${e}"`);
761
+ let n = await J(t, /* @__PURE__ */ new Date(), "self", "cluster");
762
+ return N && await Y(t), n;
763
+ },
764
+ backfillRequest: async (e) => (await m(S), B(), h(S, e)),
765
+ startBackfillRange: async (e, t, n, r) => {
766
+ if (I) throw Error("scheduler stopped");
767
+ let i = V.get(e);
768
+ if (!i) throw Error(`Unknown schedule "${e}"`);
769
+ if (!Number.isInteger(r.cap) || r.cap < 1 || r.cap > 1e4) throw Error("Invalid backfill cap");
770
+ if (!(t.getTime() < n.getTime())) throw Error("Invalid backfill range");
771
+ let a = d(i, t, n, r.cap);
772
+ if (a.length > r.cap) throw Error("Backfill occurrence limit exceeded");
773
+ await m(S), B();
774
+ let o = await f(S, {
775
+ id: r.requestId,
776
+ name: e,
777
+ from: t,
778
+ to: n,
779
+ occurrences: a
780
+ });
781
+ return p(S, r.requestId, be, async (e) => {
782
+ if (I) throw Error("Scheduler stopped during backfill");
783
+ let t = await J(i, e, "manual");
784
+ if (!t) throw Error("Backfill firing has no recorded run ID");
785
+ let n = await We(t);
786
+ if (!n || ![
787
+ "succeeded",
788
+ "failed",
789
+ "skipped",
790
+ "missed"
791
+ ].includes(n.status)) throw Error("Backfill firing has no terminal recorded outcome");
792
+ switch (n.status) {
793
+ case "succeeded":
794
+ case "failed":
795
+ case "skipped":
796
+ case "missed": return {
797
+ runId: t,
798
+ status: n.status
799
+ };
800
+ default: throw Error("Backfill firing is still running");
801
+ }
802
+ }).catch((e) => T.error?.("schedule backfill execution unavailable", {
803
+ requestId: r.requestId,
804
+ reason: M(e)
805
+ })), o.request;
806
+ },
807
+ backfillRange: async (e, t, n, r) => {
808
+ let i = V.get(e);
809
+ if (!i) throw Error(`scheduler.backfillRange: unknown schedule "${e}"`);
810
+ if (!(t.getTime() < n.getTime())) throw Error(`scheduler.backfillRange("${e}"): 'from' (${t.toISOString()}) must be before 'to' (${n.toISOString()})`);
811
+ let a = d(i, t, n, r.cap);
812
+ if (a.length > r.cap) throw Error(`scheduler.backfillRange("${e}"): more than ${r.cap} occurrences in ${t.toISOString()}..${n.toISOString()} — narrow the range or raise the cap`);
813
+ let o = [], s = 0;
814
+ for (let e of a) {
815
+ let t = await J(i, e, "manual");
816
+ o.push(t ?? null), t != null && s++;
817
+ }
818
+ return {
819
+ occurrences: a.length,
820
+ fired: s,
821
+ runIds: o
822
+ };
823
+ },
824
+ shutdown: async () => {
825
+ I = !0;
826
+ let e = L !== void 0 || R !== void 0;
827
+ clearTimeout(L), await R, e && await ee(S, be), $ && clearTimeout($);
828
+ for (let e of P.values()) clearTimeout(e);
829
+ P.clear();
830
+ for (let e of [...G]) e();
831
+ G.clear(), Te?.(), T.info("scheduler: stopped");
832
+ }
833
+ };
834
+ }, M = (e) => e?.message ?? String(e), he = (e) => e && typeof e == "object" && "_tag" in e ? String(e._tag) : null, ge = (e) => {
835
+ let t = {};
836
+ for (let [n, r] of Object.entries(e)) t[n] = r instanceof Date ? r.toISOString() : r;
837
+ return t;
838
+ };
839
+ //#endregion
840
+ export { w as CLAIM_RETENTION_BUCKETS, oe as DEFAULT_CLAIM_BUCKET_MS, ce as DEFAULT_EXTERNAL_RECONCILE_MS, se as DEFAULT_EXTERNAL_TRIGGER_SKEW_MS, fe as DEFAULT_SCHEDULE_HEARTBEAT_MS, x as DORMANCY_WAKEUP_TENANT, le as EXTERNAL_TRIGGER_AHEAD_TOLERANCE_MS, b as SCHEDULE_SUBJECT, de as TERMINAL_RUN_STATUSES, T as claimGraceMs, E as makeAdvisoryLockCoordinator, A as peerRunIsAlive, S as singleCoordinator, j as startScheduler };