@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,522 @@
1
+ import { IndexedMatcher as e } from "./matcher.js";
2
+ import { canonicalize as t } from "./fingerprint.js";
3
+ import { SubscriptionRegistry as n } from "./subscriptionRegistry.js";
4
+ import { resolveReactiveConfig as r } from "./reactiveConfig.js";
5
+ import { currentRawReads as i, runWithRawReadScope as a } from "./rawReadScope.js";
6
+ import { crdtIncrementalCell as o } from "./crdtMerge.js";
7
+ import { resolveDependentTables as s } from "./dependencyGraph.js";
8
+ import { isEventRelevant as c, resolveRelevantFields as l } from "./relevantFields.js";
9
+ import { recordSubscriptionActive as u } from "./metrics.js";
10
+ import { buildSubjectKey as d } from "./rywPositionStore.js";
11
+ import { runWithRoutingContext as f } from "./replicatedDataStore.js";
12
+ import { applyRowFilterToDescriptor as p, rowFilterRegistered as m } from "./rowFilter.js";
13
+ import { createDispatchWireStrip as h, stripForbiddenForWire as g } from "./wireColumnStrip.js";
14
+ import { committedChangeBatchOf as _ } from "@voltro/database";
15
+ import { createHash as v, randomUUID as y } from "node:crypto";
16
+ import { diffRows as b, isIdKeyed as x } from "@voltro/protocol";
17
+ import { createLogger as S } from "@voltro/logger";
18
+ //#region src/dispatcher.ts
19
+ var C = /* @__PURE__ */ new Set(), w = S({ scope: "voltro:dispatcher" }), T = (e) => Array.isArray(e) ? e.length : e == null ? 0 : 1, E = (e, n) => ({
20
+ ...e,
21
+ key: `${e.key}:${v("sha256").update(JSON.stringify(t(n))).digest("base64url")}`
22
+ }), D = (e) => typeof e == "object" && !!e && (e._tag === "ScopeError" || e._tag === "Unauthenticated" || e._tag === "RequestedTenantRefused"), O = 1e3, k = 3e4, A = Object.freeze({
23
+ _tag: "QueryRecomputeFailed",
24
+ message: "The live query could not be refreshed. Retrying automatically."
25
+ }), j = class {
26
+ deps;
27
+ subscriptionRegistry;
28
+ matcher;
29
+ subscriptions = /* @__PURE__ */ new Map();
30
+ unsubscribeChange;
31
+ closed = !1;
32
+ operations = /* @__PURE__ */ new Set();
33
+ beginOperation() {
34
+ let e, t = new Promise((t) => {
35
+ e = t;
36
+ });
37
+ return this.operations.add(t), () => {
38
+ this.operations.delete(t), e();
39
+ };
40
+ }
41
+ interests = /* @__PURE__ */ new Map();
42
+ dependentByTable = /* @__PURE__ */ new Map();
43
+ computedSubs = /* @__PURE__ */ new Map();
44
+ computedByTable = /* @__PURE__ */ new Map();
45
+ reactive;
46
+ rawReadWarned = /* @__PURE__ */ new Set();
47
+ readFences = /* @__PURE__ */ new WeakMap();
48
+ changeEpoch = 0;
49
+ committedReads = /* @__PURE__ */ new WeakMap();
50
+ crdtColumnsFor(e) {
51
+ return this.deps.crdtColumnsOf?.(e) ?? C;
52
+ }
53
+ constructor(t) {
54
+ this.deps = t, this.matcher = new e(), this.subscriptionRegistry = new n(this.matcher), this.reactive = r(t.reactive);
55
+ }
56
+ measureLoop(e) {
57
+ return this.deps.measureSync ? this.deps.measureSync(e) : e();
58
+ }
59
+ retainInterest(e, t) {
60
+ if (this.closed) throw Error("Dispatcher is closed");
61
+ this.interests.set(e, t);
62
+ try {
63
+ this.unsubscribeChange ??= this.deps.store.onChange((e) => {
64
+ let t = _(e), n = t === void 0 ? void 0 : this.committedReads.get(t);
65
+ n === void 0 && (this.changeEpoch++, t !== void 0 && (n = {
66
+ epoch: this.changeEpoch,
67
+ reads: /* @__PURE__ */ new Map()
68
+ }, this.committedReads.set(t, n))), this.closed || this.handleChange(e, !1, n);
69
+ });
70
+ } catch (t) {
71
+ throw this.interests.delete(e), t;
72
+ }
73
+ }
74
+ removeInterest(e) {
75
+ let t = this.interests.get(e);
76
+ if (t === void 0) return;
77
+ this.interests.delete(e);
78
+ let n = this.computedSubs.get(e);
79
+ n?.retryTimer !== void 0 && (clearTimeout(n.retryTimer), n.retryTimer = void 0);
80
+ let r = this.subscriptions.get(e) ?? n;
81
+ this.subscriptions.delete(e), this.computedSubs.delete(e), r !== void 0 && u(r.label, -1), this.subscriptionRegistry.unsubscribe(e);
82
+ for (let n of t) for (let t of [this.dependentByTable, this.computedByTable]) {
83
+ let r = t.get(n);
84
+ r?.delete(e), r?.size === 0 && t.delete(n);
85
+ }
86
+ this.interests.size === 0 && (this.unsubscribeChange?.(), this.unsubscribeChange = void 0);
87
+ }
88
+ warnUndeclaredRawReads(e, t) {
89
+ if (t.length !== 0 && !this.rawReadWarned.has(e)) {
90
+ this.rawReadWarned.add(e);
91
+ for (let n of t) w.warn(`${e}: a raw SQL read in this live query declares no dependsOn, so no write can invalidate it — every subscriber keeps its first result until it reconnects. Declare the tables it reads: ctx.store.raw(fragment, { dependsOn: ['orders'] }) — or on the fragment itself. The read: ${n.sql}`, {
92
+ label: e,
93
+ sql: n.sql
94
+ });
95
+ }
96
+ }
97
+ async subscribe(e, t, n, r, a, o, c, h, _ = !1) {
98
+ let v = `sub_${y()}`, b = a ?? `subscription.${e.table}`, x = s(e);
99
+ this.retainInterest(v, x);
100
+ let S = this.beginOperation();
101
+ try {
102
+ if (h === void 0 && m()) throw Error(`subscription "${b}" was opened without a row-filter resolver while a row filter is registered — this would read every row the filter exists to hide. Pass the resolver from \`makeDefaultRefilter(subject)\`, or pass one returning \`NO_ROW_FILTER\` to read unfiltered deliberately.`);
103
+ let a = l(e);
104
+ e.predicate !== void 0 && this.subscriptionRegistry.subscribe(v, e.table, e.predicate, r);
105
+ let s = e.predicate !== void 0 && (e.dependentTables?.length ?? 0) === 0 && e.eager === void 0 && e.setOp === void 0 && e.ctes === void 0 && e.alias === void 0 && (e.joins?.length ?? 0) === 0 && x.size === 1 && x.has(e.table);
106
+ for (let t of x) {
107
+ if (s && t === e.table) continue;
108
+ let n = this.dependentByTable.get(t);
109
+ n === void 0 && (n = /* @__PURE__ */ new Set(), this.dependentByTable.set(t, n)), n.add(v);
110
+ }
111
+ let y = Date.now(), S = Array.from(x), C = () => this.removeInterest(v), w, T;
112
+ try {
113
+ if (w = h === void 0 ? e : p(await h(), e), this.closed) throw Error("Dispatcher is closed");
114
+ let t = _ ? await f({
115
+ subjectKey: d(n.subject.id, n.clientId),
116
+ forcePrimary: !0
117
+ }, () => this.deps.store.query(w)) : this.deps.cache !== void 0 && o !== void 0 ? await this.deps.cache.wrap(E(o, w), S, () => f({
118
+ subjectKey: d(n.subject.id, n.clientId),
119
+ forcePrimary: !0
120
+ }, () => this.deps.store.query(w))) : await this.deps.store.query(w);
121
+ if (this.closed) throw Error("Dispatcher is closed");
122
+ if (c !== void 0) {
123
+ let e = await c();
124
+ if (e) throw e;
125
+ }
126
+ if (this.closed) throw Error("Dispatcher is closed");
127
+ T = g(w.table, t, n.subject);
128
+ } catch (e) {
129
+ throw C(), e;
130
+ }
131
+ this.warnUndeclaredRawReads(b, i().filter((e) => e.dependsOn.length === 0)), this.subscriptions.set(v, {
132
+ id: v,
133
+ descriptor: w,
134
+ baseDescriptor: e,
135
+ context: n,
136
+ emit: t,
137
+ label: b,
138
+ dependentTables: x,
139
+ relevantFields: a,
140
+ lastDelivered: T,
141
+ cacheBinding: o,
142
+ readFromPrimary: _,
143
+ reauthorize: c,
144
+ refilter: h,
145
+ memoKey: void 0
146
+ }), u(b, 1), t({
147
+ _tag: "snapshot",
148
+ revision: 0,
149
+ data: T
150
+ });
151
+ let D = Date.now();
152
+ return this.deps.recordDelivery?.({
153
+ traceId: n.traceId,
154
+ parentSpanId: n.spanId,
155
+ label: b,
156
+ kind: "snapshot",
157
+ startMs: y,
158
+ endMs: D,
159
+ durationMs: D - y,
160
+ rowCount: T.length
161
+ }), () => this.removeInterest(v);
162
+ } catch (e) {
163
+ throw this.removeInterest(v), e;
164
+ } finally {
165
+ S();
166
+ }
167
+ }
168
+ revokeSubscription(e, t, n = "guards no longer satisfied") {
169
+ this.subscriptions.get(e.id) === e && (this.removeInterest(e.id), w.warn(`subscription revoked mid-stream — ${n}`, {
170
+ id: e.id,
171
+ label: e.label,
172
+ traceId: e.context.traceId
173
+ }), e.emit({
174
+ _tag: "error",
175
+ error: t
176
+ }));
177
+ }
178
+ removeComputed(e) {
179
+ return this.computedSubs.get(e.id) === e && (this.removeInterest(e.id), !0);
180
+ }
181
+ revokeComputed(e, t) {
182
+ this.removeComputed(e) && (w.warn("computed subscription revoked mid-stream — guards no longer satisfied", {
183
+ id: e.id,
184
+ label: e.label,
185
+ traceId: e.context.traceId
186
+ }), e.emit({
187
+ _tag: "error",
188
+ error: t
189
+ }));
190
+ }
191
+ async subscribeComputed(e, t, n, r) {
192
+ let o = `csub_${y()}`, s = r ?? "subscription.computed", c = i(), l = new Set(e.dependentTables);
193
+ for (let e of c) for (let t of e.dependsOn) l.add(t);
194
+ let d = Array.from(l);
195
+ this.retainInterest(o, l);
196
+ try {
197
+ this.warnUndeclaredRawReads(s, c.filter((e) => e.dependsOn.length === 0));
198
+ let r = {
199
+ id: o,
200
+ recompute: () => a(e.recompute),
201
+ tenantId: e.tenantId,
202
+ emit: t,
203
+ context: n,
204
+ label: s,
205
+ tables: d,
206
+ lastJson: M(e.value),
207
+ revision: 0,
208
+ failed: !1,
209
+ retryAttempts: 0,
210
+ retryTimer: void 0,
211
+ running: !1,
212
+ rerunRequested: !1
213
+ };
214
+ this.computedSubs.set(o, r), u(r.label, 1);
215
+ for (let e of d) {
216
+ let t = this.computedByTable.get(e);
217
+ t === void 0 && (t = /* @__PURE__ */ new Set(), this.computedByTable.set(e, t)), t.add(o);
218
+ }
219
+ let i = Date.now();
220
+ return t({
221
+ _tag: "snapshot",
222
+ revision: 0,
223
+ data: e.value
224
+ }), this.deps.recordDelivery?.({
225
+ traceId: n.traceId,
226
+ parentSpanId: n.spanId,
227
+ label: r.label,
228
+ kind: "snapshot",
229
+ startMs: i,
230
+ endMs: Date.now(),
231
+ durationMs: Date.now() - i,
232
+ rowCount: T(e.value)
233
+ }), () => {
234
+ this.removeComputed(r);
235
+ };
236
+ } catch (e) {
237
+ throw this.removeInterest(o), e;
238
+ }
239
+ }
240
+ async recomputeComputed(e) {
241
+ if (this.closed || this.computedSubs.get(e.id) !== e) return;
242
+ if (e.running) {
243
+ e.rerunRequested = !0;
244
+ return;
245
+ }
246
+ e.retryTimer !== void 0 && clearTimeout(e.retryTimer), e.retryTimer = void 0, e.running = !0;
247
+ let t = this.beginOperation();
248
+ try {
249
+ do {
250
+ e.rerunRequested = !1;
251
+ let t = Date.now(), n = await e.recompute();
252
+ if (this.computedSubs.get(e.id) !== e) return;
253
+ if (e.rerunRequested) continue;
254
+ let r = this.measureLoop(() => M(n)), i = e.failed;
255
+ if (e.failed = !1, e.retryAttempts = 0, r === e.lastJson && !i) return;
256
+ e.lastJson = r, e.revision += 1;
257
+ let a = Date.now();
258
+ this.measureLoop(() => e.emit({
259
+ _tag: "snapshot",
260
+ revision: e.revision,
261
+ data: n
262
+ })), this.deps.recordDelivery?.({
263
+ traceId: e.context.traceId,
264
+ parentSpanId: e.context.spanId,
265
+ label: e.label,
266
+ kind: "delta",
267
+ startMs: t,
268
+ endMs: a,
269
+ durationMs: a - t,
270
+ rowCount: T(n)
271
+ }), this.deps.recordCost !== void 0 && this.deps.recordCost({
272
+ tenantId: e.tenantId,
273
+ subscriptionId: e.id,
274
+ unit: "recompute",
275
+ amount: 1,
276
+ traceId: e.context.traceId
277
+ });
278
+ } while (e.rerunRequested);
279
+ } catch (t) {
280
+ if (this.computedSubs.get(e.id) !== e) return;
281
+ if (D(t)) {
282
+ this.revokeComputed(e, t);
283
+ return;
284
+ }
285
+ e.failed || (e.failed = !0, e.emit({
286
+ _tag: "error",
287
+ error: A
288
+ }), w.warn("computed recompute failed; retrying with last value marked stale", {
289
+ id: e.id,
290
+ label: e.label,
291
+ traceId: e.context.traceId
292
+ }, t));
293
+ let n = Math.min(k, O * 2 ** Math.min(e.retryAttempts, 5));
294
+ if (e.retryAttempts += 1, this.computedSubs.get(e.id) !== e) return;
295
+ e.retryTimer = setTimeout(() => {
296
+ e.retryTimer = void 0, this.recomputeComputed(e);
297
+ }, n), e.retryTimer.unref();
298
+ } finally {
299
+ e.running = !1, t();
300
+ }
301
+ }
302
+ subscriptionSnapshot() {
303
+ return this.subscriptionRegistry.snapshot();
304
+ }
305
+ matcherStats() {
306
+ return this.matcher.stats?.() ?? { perTable: [] };
307
+ }
308
+ onSubscriptionsChange(e) {
309
+ return this.subscriptionRegistry.onChange(e);
310
+ }
311
+ close() {
312
+ this.closed = !0;
313
+ for (let e of this.interests.keys()) this.removeInterest(e);
314
+ this.unsubscribeChange?.(), this.unsubscribeChange = void 0;
315
+ }
316
+ async closeAndDrain() {
317
+ try {
318
+ this.close();
319
+ } finally {
320
+ for (; this.operations.size > 0;) await Promise.all(this.operations);
321
+ }
322
+ }
323
+ async refreshAll(e) {
324
+ let t = /* @__PURE__ */ new Set();
325
+ for (let e of this.subscriptions.values()) t.add(e.descriptor.table);
326
+ for (let e of this.computedByTable.keys()) t.add(e);
327
+ if (t.size !== 0) {
328
+ w.warn("refreshing every live subscription", {
329
+ reason: e,
330
+ tables: t.size,
331
+ subscriptions: this.subscriptions.size
332
+ });
333
+ for (let e of t) await this.handleChange({
334
+ table: e,
335
+ op: "insert",
336
+ new: {},
337
+ old: void 0
338
+ }, !0);
339
+ }
340
+ }
341
+ async handleChange(e, n = !1, r) {
342
+ if (this.closed) return;
343
+ let i = this.beginOperation();
344
+ try {
345
+ n && this.changeEpoch++;
346
+ let i = this.computedByTable.get(e.table);
347
+ if (i !== void 0 && i.size > 0) for (let e of i) {
348
+ let t = this.computedSubs.get(e);
349
+ t !== void 0 && this.recomputeComputed(t);
350
+ }
351
+ let a = n || e.oversized === "tombstone" || e.oversized === "unrecovered", s = a ? [] : this.measureLoop(() => this.subscriptionRegistry.notify(e)), l = /* @__PURE__ */ new Set();
352
+ for (let e of s) l.add(e.subscriberId);
353
+ if (a) for (let [t, n] of this.subscriptions) n.descriptor.table === e.table && l.add(t);
354
+ let u = this.dependentByTable.get(e.table);
355
+ if (u !== void 0) for (let e of u) l.add(e);
356
+ if (w.trace("handleChange", {
357
+ table: e.table,
358
+ op: e.op,
359
+ matcher: s.length,
360
+ dependent: u?.size ?? 0,
361
+ triggered: l.size
362
+ }), l.size === 0) return;
363
+ let m = Date.now(), _ = 0, v = /* @__PURE__ */ new Map(), y = l.size > 1 ? h() : void 0, S = /* @__PURE__ */ new Map(), T = /* @__PURE__ */ new Map(), D = async (i) => {
364
+ let a = this.subscriptions.get(i);
365
+ if (!a) {
366
+ w.trace("missing subscription", { subscriberId: i });
367
+ return;
368
+ }
369
+ if (!n && !c(e, a.relevantFields)) {
370
+ _++;
371
+ return;
372
+ }
373
+ let s = Date.now();
374
+ try {
375
+ if (a.reauthorize !== void 0) {
376
+ let e = await a.reauthorize();
377
+ if (this.subscriptions.get(a.id) !== a) return;
378
+ if (e) {
379
+ this.revokeSubscription(a, e);
380
+ return;
381
+ }
382
+ }
383
+ let n, c;
384
+ if (a.refilter === void 0) n = a.descriptor, a.memoKey ??= JSON.stringify(t(n)), c = a.memoKey;
385
+ else {
386
+ let e;
387
+ try {
388
+ if (e = await a.refilter(), this.subscriptions.get(a.id) !== a) return;
389
+ } catch (e) {
390
+ this.revokeSubscription(a, e, "row filter unavailable");
391
+ return;
392
+ }
393
+ try {
394
+ n = p(e, a.baseDescriptor);
395
+ } catch (e) {
396
+ this.revokeSubscription(a, e, "row filter declaration violated");
397
+ return;
398
+ }
399
+ c = JSON.stringify(t(n));
400
+ }
401
+ c = `${a.readFromPrimary ? "primary" : "policy"}:${c}`;
402
+ let l = r?.epoch === this.changeEpoch ? r.reads : v, u = l.get(c);
403
+ if (u === void 0) {
404
+ let e = () => a.readFromPrimary ? f({
405
+ subjectKey: d(a.context.subject.id, a.context.clientId),
406
+ forcePrimary: !0
407
+ }, () => this.deps.store.query(n)) : this.deps.store.query(n), t = this.deps.cache;
408
+ if (t !== void 0 && a.cacheBinding !== void 0) {
409
+ let n = t.fence();
410
+ u = n.then(e, e), this.readFences.set(u, n);
411
+ } else u = e();
412
+ l.set(c, u);
413
+ }
414
+ let h = await u;
415
+ if (this.subscriptions.get(a.id) !== a) return;
416
+ if (a.reauthorize !== void 0) {
417
+ let e = await a.reauthorize();
418
+ if (this.subscriptions.get(a.id) !== a) return;
419
+ if (e) {
420
+ this.revokeSubscription(a, e);
421
+ return;
422
+ }
423
+ }
424
+ let _ = this.measureLoop(() => y?.(n.table, h, a.context.subject)), D = _?.rows ?? this.measureLoop(() => g(n.table, h, a.context.subject));
425
+ _ !== void 0 && (c = JSON.stringify([c, _.visibilityKey]));
426
+ let O = a.lastDelivered, k = T.get(c);
427
+ k === void 0 && (k = /* @__PURE__ */ new Map(), T.set(c, k));
428
+ let A = k.get(O);
429
+ if (A === void 0 && (A = !this.measureLoop(() => N(D, O)), k.set(O, A)), !A) {
430
+ w.trace("suppressed no-op delta", {
431
+ subscriberId: i,
432
+ table: e.table
433
+ });
434
+ return;
435
+ }
436
+ a.lastDelivered = D;
437
+ let j = this.readFences.get(u);
438
+ if (this.deps.cache !== void 0 && a.cacheBinding !== void 0 && j !== void 0) {
439
+ let e = this.deps.cache, t = E(a.cacheBinding, n), r = Array.from(a.dependentTables);
440
+ j.then((n) => {
441
+ e.put(t, r, h, n);
442
+ }, () => void 0);
443
+ }
444
+ if (x(O) && x(D)) {
445
+ let e = S.get(c);
446
+ e === void 0 && (e = /* @__PURE__ */ new Map(), S.set(c, e));
447
+ let t = e.get(O);
448
+ if (t === void 0) {
449
+ let n = this.deps.crdtColumnsOf?.(a.descriptor.table) ?? C;
450
+ t = this.measureLoop(() => n.size === 0 ? b(O, D) : b(O, D, { crdt: {
451
+ columns: n,
452
+ incremental: o
453
+ } })), e.set(O, t);
454
+ }
455
+ let n = t;
456
+ this.measureLoop(() => a.emit({
457
+ _tag: "delta",
458
+ revision: m,
459
+ emittedAt: m,
460
+ patch: n
461
+ }));
462
+ } else this.measureLoop(() => a.emit({
463
+ _tag: "snapshot",
464
+ revision: m,
465
+ data: D
466
+ }));
467
+ let M = Date.now();
468
+ this.deps.recordDelivery?.({
469
+ traceId: a.context.traceId,
470
+ parentSpanId: a.context.spanId,
471
+ label: a.label,
472
+ kind: "delta",
473
+ startMs: s,
474
+ endMs: M,
475
+ durationMs: M - s,
476
+ rowCount: D.length
477
+ }), this.deps.recordCost !== void 0 && this.deps.recordCost({
478
+ tenantId: a.context.subject.tenantId,
479
+ subscriptionId: a.id,
480
+ unit: "recompute",
481
+ amount: 1,
482
+ traceId: a.context.traceId
483
+ });
484
+ } catch (t) {
485
+ w.warn("reactive re-query failed; subscriber left on last snapshot", {
486
+ subscriberId: i,
487
+ label: a.label,
488
+ table: e.table,
489
+ traceId: a.context.traceId
490
+ }, t);
491
+ }
492
+ }, O = Array.from(l), k = Math.max(1, Math.min(this.reactive.deliveryConcurrency, O.length)), A = 0, j = async () => {
493
+ for (;;) {
494
+ let e = A++;
495
+ if (e >= O.length) return;
496
+ await D(O[e]);
497
+ }
498
+ }, M = (await Promise.allSettled(Array.from({ length: k }, () => j()))).find((e) => e.status === "rejected");
499
+ if (M?.status === "rejected") throw M.reason;
500
+ _ > 0 && w.trace("handleChange/prefiltered", {
501
+ table: e.table,
502
+ op: e.op,
503
+ skipped: _
504
+ });
505
+ } finally {
506
+ i();
507
+ }
508
+ }
509
+ }, M = (e) => {
510
+ try {
511
+ return JSON.stringify(e) ?? "null";
512
+ } catch {
513
+ return String(e);
514
+ }
515
+ }, N = (e, t) => {
516
+ if (e === t) return !0;
517
+ if (e.length !== t.length) return !1;
518
+ for (let n = 0; n < e.length; n++) if (JSON.stringify(e[n]) !== JSON.stringify(t[n])) return !1;
519
+ return !0;
520
+ };
521
+ //#endregion
522
+ export { j as Dispatcher, T as deliveredRowCount, E as snapshotEntryFor };
@@ -0,0 +1,71 @@
1
+ import { Context as e, Effect as t, Exit as n, Layer as r } from "effect";
2
+ import { authoredError as i, describeDriverError as a, wireSafeCause as o } from "@voltro/database";
3
+ import { StoreOperationFailed as s } from "@voltro/protocol";
4
+ import { createLogger as c } from "@voltro/logger";
5
+ //#region src/effectStore.ts
6
+ var l = c({ scope: "store" }), u = class extends e.Service()("@voltro/EffectStore") {}, d = {
7
+ TenantScopeViolation: !0,
8
+ TenantRowNotFound: !0,
9
+ ServerOnlyColumnWrite: !0,
10
+ StoreOperationFailed: !0,
11
+ TableValidationFailed: !0,
12
+ ConstraintViolation: !0
13
+ }, f = (e) => {
14
+ let t = e?._tag;
15
+ return typeof t == "string" && Object.hasOwn(d, t);
16
+ }, p = (e, t) => (n) => f(n) ? n : (l.warn("store operation failed", {
17
+ operation: e,
18
+ table: t,
19
+ detail: a(n) ?? String(n)
20
+ }), new s({
21
+ operation: e,
22
+ table: t,
23
+ cause: o(n, e)
24
+ })), m = (e, n, r) => t.tryPromise({
25
+ try: r,
26
+ catch: p(e, n)
27
+ }), h = (e) => ("descriptor" in e ? e.descriptor : e).table, g = (e, n) => t.tryPromise({
28
+ try: n,
29
+ catch: (t) => t?._tag === "NoRowFound" ? t : p("one", e)(t)
30
+ }), _ = class extends Error {
31
+ effectCause;
32
+ constructor(e) {
33
+ super("Effect program failed inside store transaction"), this.effectCause = e;
34
+ }
35
+ }, v = (e) => ({
36
+ query: ((t) => m("query", t.table, () => e.query(t))),
37
+ insert: (t, n) => m("insert", t, () => e.insert(t, n)),
38
+ insertMany: (t, n, r) => m("insertMany", t, () => e.insertMany(t, n, r)),
39
+ patchJson: (t, n, r, i, a) => m("patchJson", t, () => e.patchJson(t, n, r, i, a)),
40
+ update: (t, n, r) => m("update", t, () => e.update(t, n, r)),
41
+ updateMany: (t, n, r) => m("updateMany", t, () => e.updateMany(t, n, r)),
42
+ delete: (t, n) => m("delete", t, () => e.delete(t, n)),
43
+ deleteMany: (t, n) => m("deleteMany", t, () => e.deleteMany(t, n)),
44
+ upsert: (t, n, r) => m("upsert", t, () => e.upsert(t, n, r)),
45
+ upsertWithOutcome: (t, n, r) => m("upsertWithOutcome", t, async () => {
46
+ if (e.upsertWithOutcome === void 0) throw i("upsertWithOutcome: this store does not implement it — the framework's store wrapper does; a hand-written DataStore must add it");
47
+ return e.upsertWithOutcome(t, n, r);
48
+ }),
49
+ insertIgnore: (t, n, r) => m("insertIgnore", t, () => e.insertIgnore(t, n, r)),
50
+ insertIgnoreWithOutcome: (t, n, r) => m("insertIgnoreWithOutcome", t, async () => e.insertIgnoreWithOutcome(t, n, r)),
51
+ one: ((t) => g(h(t), () => e.one(t))),
52
+ maybeOne: ((t) => m("maybeOne", h(t), () => e.maybeOne(t))),
53
+ first: ((t) => m("first", h(t), () => e.first(t))),
54
+ hardDelete: (t, n) => m("hardDelete", t, () => e.hardDelete(t, n)),
55
+ transactional: (r) => t.flatMap(t.context(), (i) => t.callback((o) => {
56
+ let s;
57
+ e.transactional(async (e) => {
58
+ let a = await t.runPromiseExitWith(i)(r(v(e)));
59
+ if (n.isFailure(a)) throw s = a.cause, new _(a.cause);
60
+ return a.value;
61
+ }).then((e) => o(t.succeed(e)), (e) => {
62
+ e instanceof _ ? o(t.failCause(e.effectCause)) : s === void 0 ? o(t.fail(p("transactional", "<transaction>")(e))) : (l.warn("transaction rollback failed after the work did", { detail: a(e) ?? String(e) }), o(t.failCause(s)));
63
+ });
64
+ }))
65
+ }), y = (e) => r.succeed(u, v(e)), b = (e) => ({
66
+ conflictColumns: e.conflictColumns,
67
+ ...e.update === void 0 ? {} : { update: e.update },
68
+ ...e.updateValues === void 0 ? {} : { updateValues: e.updateValues }
69
+ }), x = (e, t, n) => e.insert(t.tableName, n), S = (e, t, n, r) => e.insertMany(t.tableName, n, r), C = (e, t, n, r) => e.upsert(t.tableName, n, b(r)), w = (e, t, n, r) => e.upsertWithOutcome(t.tableName, n, b(r)), T = (e, t, n, r) => e.insertIgnoreWithOutcome(t.tableName, n, { conflictColumns: r.conflictColumns });
70
+ //#endregion
71
+ export { u as EffectStore, T as insertIgnoreRowOutcomeEffect, S as insertManyRowsEffect, x as insertRowEffect, y as makeEffectStoreLayer, C as upsertRowEffect, w as upsertRowOutcomeEffect };
@@ -0,0 +1,24 @@
1
+ //#region src/engineClients.ts
2
+ var e = /* @__PURE__ */ new Map(), t = 0, n = (e) => {
3
+ let t = /^([a-z]{1,16})\/([0-9A-Za-z.+-]{1,100})(?:; surface=([0-9a-f]{64}))?$/.exec(e.trim());
4
+ return t ? {
5
+ target: t[1],
6
+ version: t[2],
7
+ surface: t[3] ?? null
8
+ } : null;
9
+ }, r = (r, i) => {
10
+ let a = r.headers["x-voltro-sdk"];
11
+ if (typeof a != "string" || e.size >= 1024) return;
12
+ let o = n(a);
13
+ if (!o) return;
14
+ let s = "client-" + String(++t);
15
+ e.set(s, Object.freeze({
16
+ id: s,
17
+ ...o,
18
+ connectedAt: Date.now()
19
+ })), i.once("close", () => {
20
+ e.delete(s);
21
+ });
22
+ }, i = () => [...e.values()];
23
+ //#endregion
24
+ export { i as engineClientsSnapshot, n as parseEngineSdkHeader, r as trackEngineClient };