@voltro/runtime 0.86.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 (70) hide show
  1. package/CHANGELOG.md +5321 -0
  2. package/README.md +43 -0
  3. package/THIRD-PARTY-NOTICES.md +860 -221
  4. package/dist/analyticsSink.js +8 -14
  5. package/dist/apiKeys.js +82 -78
  6. package/dist/apiRoleBucketSampler.js +64 -0
  7. package/dist/apiRoleWorkloadHistory.js +56 -0
  8. package/dist/apiRoleWorkloadMetrics.js +78 -0
  9. package/dist/apiRoleWorkloadStorage.js +95 -0
  10. package/dist/approvals.js +67 -74
  11. package/dist/authMiddlewareLayer.js +7 -6
  12. package/dist/bindEvent.js +48 -28
  13. package/dist/bootListener.js +106 -39
  14. package/dist/bootStoreCodec.js +38 -37
  15. package/dist/circuitBreaker.js +1 -72
  16. package/dist/composeAnalytics.js +31 -10
  17. package/dist/computedQueryCache.js +231 -0
  18. package/dist/connectionsFacade.js +32 -30
  19. package/dist/coordinatedSchedule.js +84 -78
  20. package/dist/dataStore.js +154 -121
  21. package/dist/declaredTablesGuard.js +2 -1
  22. package/dist/dispatcher.js +403 -328
  23. package/dist/effectStore.js +2 -2
  24. package/dist/engineClients.js +24 -0
  25. package/dist/externalizedTasks.js +19 -6
  26. package/dist/fieldCipher.js +109 -40
  27. package/dist/fieldKeyRegistry.js +295 -0
  28. package/dist/fieldKeyRekey.js +286 -0
  29. package/dist/fieldKeyScan.js +136 -0
  30. package/dist/fieldKeyring.js +77 -0
  31. package/dist/hot.d.ts +56 -0
  32. package/dist/hot.js +3 -0
  33. package/dist/hotDataStore.js +148 -0
  34. package/dist/hotDataStoreSnapshot.js +98 -0
  35. package/dist/hotDataStoreTables.js +18 -0
  36. package/dist/http-range.d.ts +53 -0
  37. package/dist/http-range.js +52 -0
  38. package/dist/httpClientSsrf.js +12 -37
  39. package/dist/httpClientTracing.js +12 -9
  40. package/dist/httpCompression.js +17 -17
  41. package/dist/httpInputStream.js +82 -0
  42. package/dist/httpRouteMounts.js +1 -0
  43. package/dist/idempotencyStore.js +92 -52
  44. package/dist/index.d.ts +1164 -451
  45. package/dist/index.js +143 -132
  46. package/dist/kvFacade.js +23 -17
  47. package/dist/memoryQueryJoins.js +16 -16
  48. package/dist/memorySetOperations.js +43 -0
  49. package/dist/metrics.js +38 -24
  50. package/dist/outbox.js +1 -1
  51. package/dist/readRecorder.js +35 -34
  52. package/dist/readScopePredicate.js +12 -0
  53. package/dist/replicatedDataStore.js +22 -4
  54. package/dist/rowFilter.js +56 -39
  55. package/dist/rpcConnections.js +8 -8
  56. package/dist/rpcServer.js +522 -449
  57. package/dist/rpcWorkloadAdmission.js +50 -0
  58. package/dist/rywPositionStore.js +82 -47
  59. package/dist/scheduler.js +6 -1
  60. package/dist/servePipeline.js +215 -146
  61. package/dist/setReadScopes.js +28 -0
  62. package/dist/snapshotValueCodec.js +46 -0
  63. package/dist/sourceResolution.js +34 -24
  64. package/dist/storeMiddleware.js +211 -209
  65. package/dist/subscriber.js +1 -0
  66. package/dist/tenantScope.js +8 -20
  67. package/dist/traceparent.js +8 -19
  68. package/dist/webSocketGatewayRuntime.js +111 -71
  69. package/dist/workflowRuntime.js +9 -9
  70. package/package.json +19 -7
@@ -0,0 +1,43 @@
1
+ import { decimalEqualityKey as e, getTable as t } from "@voltro/database";
2
+ //#region src/memorySetOperations.ts
3
+ var n = (e, t = !1) => e == null ? ["null"] : e instanceof Date ? t ? ["string", e.toISOString()] : ["date", e.getTime()] : typeof e == "bigint" ? ["bigint", e.toString()] : typeof e == "number" ? t && !Number.isFinite(e) ? ["null"] : ["number", Number.isFinite(e) ? e : String(e)] : typeof e == "object" ? e instanceof ArrayBuffer ? ["bytes", [...new Uint8Array(e)]] : ArrayBuffer.isView(e) ? ["bytes", [...new Uint8Array(e.buffer, e.byteOffset, e.byteLength)]] : Array.isArray(e) ? ["array", e.map((e) => n(e, t))] : ["object", Object.entries(e).filter(([, e]) => e !== void 0).sort(([e], [t]) => e < t ? -1 : +(e > t)).map(([e, r]) => [e, n(r, t)])] : [typeof e, e], r = (t, r, i) => JSON.stringify(r.map((r) => {
4
+ let a = t[r], o = a == null || i[r]?.type !== "decimal" ? null : e(a);
5
+ return o === null ? n(a, i[r]?.type === "json") : ["decimal", o];
6
+ })), i = (e, n) => {
7
+ if (e.setOp) return i(e.setOp.queries[0], n);
8
+ let r = (e.sourceTable ?? t(e.table))?.fields ?? {}, a = { ...r }, o = e.alias ?? e.table;
9
+ for (let [e, t] of Object.entries(r)) a[`${o}.${e}`] = t;
10
+ for (let n of e.joins ?? []) {
11
+ let e = (n.sourceTable ?? t(n.table))?.fields ?? {};
12
+ for (let [t, r] of Object.entries(e)) a[`${n.alias}.${t}`] = r;
13
+ }
14
+ if (e.aggregations?.length) return Object.fromEntries(e.aggregations.map((e) => {
15
+ let t = e.column === void 0 ? { type: "unknown" } : a[e.column] ?? { type: "unknown" }, n = e.op === "count" || e.op === "count-distinct" || e.op === "window-row-number" || e.op === "window-rank" || e.op === "window-dense-rank", r = e.op === "avg" || e.op === "window-avg-over";
16
+ return [e.alias, n ? { type: "integer" } : r && t.type !== "decimal" ? { type: "real" } : t];
17
+ }));
18
+ if (e.joinedProjection) return Object.fromEntries(e.joinedProjection.map((e) => [e.outputKey, a[e.source] ?? { type: "unknown" }]));
19
+ let s = e.projection ?? (Object.keys(r).length > 0 ? Object.keys(r) : [...new Set(n.flatMap((e) => Object.keys(e)))]);
20
+ return Object.fromEntries(s.map((e) => [e, a[e] ?? { type: "unknown" }]));
21
+ }, a = (e, t) => {
22
+ let n = e.setOp;
23
+ if (!n || n.queries.length < 2) throw Error("A set operation requires at least two inputs");
24
+ let a = n.queries.map((e) => ({
25
+ rows: t(e),
26
+ query: e
27
+ })), o = a.map((e) => i(e.query, e.rows)), s = o[0], c = Object.keys(s), l = a.map((e, t) => {
28
+ let n = Object.keys(o[t]);
29
+ if (n.length !== c.length) throw Error("Set operation inputs must have the same column count");
30
+ return e.rows.map((e) => Object.fromEntries(c.map((t, r) => [t, e[n[r]] ?? null])));
31
+ });
32
+ if (n.kind === "union-all") return l.flat();
33
+ let u = (e) => new Map(e.map((e) => [r(e, c, s), e]));
34
+ if (n.kind === "union") return [...u(l.flat()).values()];
35
+ let d = u(l[0]);
36
+ for (let e of l.slice(1)) {
37
+ let t = u(e);
38
+ for (let e of d.keys()) (n.kind === "intersect" ? !t.has(e) : t.has(e)) && d.delete(e);
39
+ }
40
+ return [...d.values()];
41
+ };
42
+ //#endregion
43
+ export { i as memoryOutputColumns, r as memoryRowKey, a as memorySetRows };
package/dist/metrics.js CHANGED
@@ -17,7 +17,7 @@ var r = n.exponentialBoundaries({
17
17
  }), u = n.counter("voltro_plugin_hook_errors_total", { description: "Plugin interceptor invocations that errored." }), d = n.counter("voltro_subscription_deliveries_total", { description: "Total subscription deliveries (snapshot + delta)." }), f = n.histogram("voltro_subscription_delivery_seconds", {
18
18
  boundaries: r,
19
19
  description: "Subscription delivery produce→push latency in seconds."
20
- }), ee = n.gauge("voltro_subscriptions_active", { description: "Currently-open subscriptions." }), p = n.counter("voltro_schedule_runs_total", { description: "Schedule firings by name + outcome." }), m = n.histogram("voltro_schedule_duration_seconds", {
20
+ }), p = n.gauge("voltro_subscriptions_active", { description: "Currently-open subscriptions." }), m = n.counter("voltro_schedule_runs_total", { description: "Schedule firings by name + outcome." }), ee = n.histogram("voltro_schedule_duration_seconds", {
21
21
  boundaries: r,
22
22
  description: "Schedule handler duration in seconds."
23
23
  }), h = n.gauge("voltro_schedule_last_success_timestamp_seconds", { description: "UNIX time of the last successful firing, per schedule." }), g = n.gauge("voltro_schedule_queued", { description: "Firings waiting for their turn under onOverlap: 'queue', per schedule, on THIS replica." }), _ = n.histogram("voltro_schedule_queue_wait_seconds", {
@@ -36,11 +36,11 @@ var r = n.exponentialBoundaries({
36
36
  O.clear();
37
37
  }, j = () => O.size, M = (e) => {
38
38
  t.runSync(n.update(k(w, `p:${e}`, [["event", e]]), 1));
39
- }, te = (e, r = 1) => {
39
+ }, N = (e, r = 1) => {
40
40
  r <= 0 || t.runSync(n.update(k(T, `d:${e}`, [["event", e]]), r));
41
- }, N = (e, r, i = 1) => {
41
+ }, P = (e, r, i = 1) => {
42
42
  i <= 0 || t.runSync(n.update(k(E, `x:${r}:${e}`, [["event", e], ["reason", r]]), i));
43
- }, P = (e, r) => {
43
+ }, te = (e, r) => {
44
44
  r !== 0 && t.runSync(n.update(k(D, `s:${e}`, [["event", e]]), r));
45
45
  }, F = (e) => {
46
46
  let r = e.durationMs / 1e3, d = e.kind === "rpc" ? t.andThen(n.update(i, 1).pipe(t.provideService(n.CurrentMetricAttributes, {
@@ -51,8 +51,22 @@ var r = n.exponentialBoundaries({
51
51
  status: e.status
52
52
  })), n.update(c, r).pipe(t.provideService(n.CurrentMetricAttributes, { route: e.tag }))) : t.andThen(n.update(l, r).pipe(t.provideService(n.CurrentMetricAttributes, { hook: e.tag })), e.status === "error" ? n.update(u, 1).pipe(t.provideService(n.CurrentMetricAttributes, { hook: e.tag })) : t.void);
53
53
  t.runSync(d);
54
- }, I = (e) => e.startsWith("subscription.") ? e.slice(13) : e, L = (e) => {
55
- let r = I(e.label);
54
+ }, I = n.counter("voltro_field_decrypts_total", { description: "Opens of sealed field values, by key id, location (table:column) and outcome." }), L = /* @__PURE__ */ new Map(), R = (e, r, i) => {
55
+ let a = `${e}|${r}`, o = L.get(a) ?? L.set(a, {
56
+ key: e,
57
+ location: r,
58
+ ok: 0,
59
+ failed: 0
60
+ }).get(a);
61
+ o[i] += 1, t.runSync(n.update(k(I, `field|${a}|${i}`, [
62
+ ["key", e],
63
+ ["location", r],
64
+ ["outcome", i]
65
+ ]), 1));
66
+ }, z = () => [...L.values()].map((e) => ({ ...e })).sort((e, t) => e.location.localeCompare(t.location) || e.key.localeCompare(t.key)), B = () => {
67
+ L.clear();
68
+ }, V = (e) => e.startsWith("subscription.") ? e.slice(13) : e, H = (e) => {
69
+ let r = V(e.label);
56
70
  t.runSync(t.andThen(n.update(d, 1).pipe(t.provideService(n.CurrentMetricAttributes, {
57
71
  tag: r,
58
72
  kind: e.kind
@@ -60,42 +74,42 @@ var r = n.exponentialBoundaries({
60
74
  tag: r,
61
75
  kind: e.kind
62
76
  }))));
63
- }, R = /* @__PURE__ */ new Map(), z = (e, r) => {
64
- let i = I(e), a = Math.max(0, (R.get(i) ?? 0) + r);
65
- a === 0 ? R.delete(i) : R.set(i, a), t.runSync(n.update(ee, a).pipe(t.provideService(n.CurrentMetricAttributes, { tag: i })));
66
- }, B = (e) => {
67
- let r = n.update(p, 1).pipe(t.provideService(n.CurrentMetricAttributes, {
77
+ }, U = /* @__PURE__ */ new Map(), W = (e, r) => {
78
+ let i = V(e), a = Math.max(0, (U.get(i) ?? 0) + r);
79
+ a === 0 ? U.delete(i) : U.set(i, a), t.runSync(n.update(p, a).pipe(t.provideService(n.CurrentMetricAttributes, { tag: i })));
80
+ }, G = (e) => {
81
+ let r = n.update(m, 1).pipe(t.provideService(n.CurrentMetricAttributes, {
68
82
  schedule: e.name,
69
83
  status: e.status
70
- })), i = n.update(m, e.durationMs / 1e3).pipe(t.provideService(n.CurrentMetricAttributes, { schedule: e.name })), a = e.status === "succeeded" && e.completedAtSec !== void 0 ? n.update(h, e.completedAtSec).pipe(t.provideService(n.CurrentMetricAttributes, { schedule: e.name })) : t.void;
84
+ })), i = n.update(ee, e.durationMs / 1e3).pipe(t.provideService(n.CurrentMetricAttributes, { schedule: e.name })), a = e.status === "succeeded" && e.completedAtSec !== void 0 ? n.update(h, e.completedAtSec).pipe(t.provideService(n.CurrentMetricAttributes, { schedule: e.name })) : t.void;
71
85
  t.runSync(t.andThen(r, t.andThen(i, a)));
72
- }, V = /* @__PURE__ */ new Map(), H = (e, r) => {
73
- let i = Math.max(0, (V.get(e) ?? 0) + r);
74
- i === 0 ? V.delete(e) : V.set(e, i), t.runSync(n.update(g, i).pipe(t.provideService(n.CurrentMetricAttributes, { schedule: e })));
75
- }, U = (e, r) => {
86
+ }, K = /* @__PURE__ */ new Map(), q = (e, r) => {
87
+ let i = Math.max(0, (K.get(e) ?? 0) + r);
88
+ i === 0 ? K.delete(e) : K.set(e, i), t.runSync(n.update(g, i).pipe(t.provideService(n.CurrentMetricAttributes, { schedule: e })));
89
+ }, J = (e, r) => {
76
90
  t.runSync(n.update(_, r / 1e3).pipe(t.provideService(n.CurrentMetricAttributes, { schedule: e })));
77
- }, W = (e, r) => {
91
+ }, Y = (e, r) => {
78
92
  t.runSync(n.update(v, 1).pipe(t.provideService(n.CurrentMetricAttributes, {
79
93
  schedule: e,
80
94
  outcome: r
81
95
  })));
82
- }, G = (e, r) => {
96
+ }, X = (e, r) => {
83
97
  t.runSync(n.update(y, 1).pipe(t.provideService(n.CurrentMetricAttributes, {
84
98
  schedule: e,
85
99
  outcome: r
86
100
  })));
87
- }, K = (e, r = 1) => {
101
+ }, Z = (e, r = 1) => {
88
102
  r <= 0 || t.runSync(n.update(b, r).pipe(t.provideService(n.CurrentMetricAttributes, { schedule: e })));
89
- }, q = (e) => {
103
+ }, Q = (e) => {
90
104
  let r = n.update(x, 1).pipe(t.provideService(n.CurrentMetricAttributes, {
91
105
  workflow: e.name,
92
106
  status: e.status
93
107
  })), i = n.update(S, e.durationMs / 1e3).pipe(t.provideService(n.CurrentMetricAttributes, { workflow: e.name })), a = e.status === "succeeded" && e.completedAtSec !== void 0 ? n.update(C, e.completedAtSec).pipe(t.provideService(n.CurrentMetricAttributes, { workflow: e.name })) : t.void;
94
108
  t.runSync(t.andThen(r, t.andThen(i, a)));
95
- }, J = (e, t) => n.counter(e, t === void 0 ? {} : { description: t }), Y = (e, t) => n.gauge(e, t === void 0 ? {} : { description: t }), X = (e, t = r, i) => n.histogram(e, {
109
+ }, ne = (e, t) => n.counter(e, t === void 0 ? {} : { description: t }), re = (e, t) => n.gauge(e, t === void 0 ? {} : { description: t }), ie = (e, t = r, i) => n.histogram(e, {
96
110
  boundaries: t,
97
111
  ...i === void 0 ? {} : { description: i }
98
- }), { exponentialBoundaries: Z, linearBoundaries: Q } = n, $ = n.snapshot.pipe(t.map((e) => e.map((e) => {
112
+ }), { exponentialBoundaries: ae, linearBoundaries: oe } = n, $ = n.snapshot.pipe(t.map((e) => e.map((e) => {
99
113
  let t = e.id, n = { ...e.attributes ?? {} }, r = e.description === void 0 ? {} : { description: e.description };
100
114
  switch (e.type) {
101
115
  case "Histogram": return {
@@ -156,6 +170,6 @@ var r = n.exponentialBoundaries({
156
170
  let n = e();
157
171
  for (let e of n) t.push(e);
158
172
  return t;
159
- })), ne = () => t.runSync($);
173
+ })), se = () => t.runSync($);
160
174
  //#endregion
161
- export { J as counter, j as eventMetricTagCacheSizeForTests, Z as exponentialBoundaries, Y as gauge, X as histogramMetric, Q as linearBoundaries, te as recordEventDelivered, N as recordEventDropped, M as recordEventPublished, P as recordEventSubscribers, K as recordExternalMissed, G as recordExternalTrigger, F as recordSample, W as recordScheduleQueueRecovery, U as recordScheduleQueueWait, H as recordScheduleQueued, B as recordScheduleRun, z as recordSubscriptionActive, L as recordSubscriptionDelivery, q as recordWorkflowRun, A as resetEventMetricTagCacheForTests, $ as snapshotMetrics, ne as snapshotMetricsSync };
175
+ export { ne as counter, j as eventMetricTagCacheSizeForTests, ae as exponentialBoundaries, z as fieldDecryptSnapshot, re as gauge, ie as histogramMetric, oe as linearBoundaries, N as recordEventDelivered, P as recordEventDropped, M as recordEventPublished, te as recordEventSubscribers, Z as recordExternalMissed, X as recordExternalTrigger, R as recordFieldDecrypt, F as recordSample, Y as recordScheduleQueueRecovery, J as recordScheduleQueueWait, q as recordScheduleQueued, G as recordScheduleRun, W as recordSubscriptionActive, H as recordSubscriptionDelivery, Q as recordWorkflowRun, A as resetEventMetricTagCacheForTests, B as resetFieldDecryptCountsForTests, $ as snapshotMetrics, se as snapshotMetricsSync };
package/dist/outbox.js CHANGED
@@ -285,7 +285,7 @@ var m = p({ scope: "voltro:outbox" }), h = "_voltro_outbox", g = {
285
285
  subjectId: t.subjectId ?? null,
286
286
  tenantId: t.tenantId ?? null,
287
287
  traceId: t.traceId ?? null
288
- }, a = o.handler(i), c = e.isEffect(a) ? a : await a, d = e.isEffect(c) ? await (r.runEffect ? r.runEffect(c, i) : e.runPromise(c)) : c;
288
+ }, a = r.measureSync ? r.measureSync(() => o.handler(i)) : o.handler(i), c = e.isEffect(a) ? a : await a, d = e.isEffect(c) ? await (r.runEffect ? r.runEffect(c, i) : e.runPromise(c)) : c;
289
289
  await k(r.store, {
290
290
  outboxRow: t,
291
291
  attempt: s,
@@ -1,22 +1,23 @@
1
1
  import { classifyRead as e } from "./readClassification.js";
2
- import { Effect as t } from "effect";
3
- import { AsyncLocalStorage as n } from "node:async_hooks";
2
+ import { noteCacheRead as t } from "./computedQueryCache.js";
3
+ import { Effect as n } from "effect";
4
+ import { AsyncLocalStorage as r } from "node:async_hooks";
4
5
  //#region src/readRecorder.ts
5
- var r = new n(), i, a = /* @__PURE__ */ new Set(), o = (e) => {
6
- i = e, a.clear();
7
- }, s = () => i !== void 0, c = (e, t) => {
8
- if (i === void 0) return;
9
- let n = new Set(t), o = a.has(e) || n.size === 0;
10
- r.enterWith({
6
+ var i = new r(), a, o = /* @__PURE__ */ new Set(), s = (e) => {
7
+ a = e, o.clear();
8
+ }, c = () => a !== void 0, l = (e, t) => {
9
+ if (a === void 0) return;
10
+ let n = new Set(t), r = o.has(e) || n.size === 0;
11
+ i.enterWith({
11
12
  procedure: e,
12
13
  declared: n,
13
14
  composed: /* @__PURE__ */ new Set(),
14
15
  restricting: /* @__PURE__ */ new Set(),
15
16
  depth: { n: 0 },
16
- ...o ? { muted: !0 } : {}
17
+ ...r ? { muted: !0 } : {}
17
18
  });
18
- }, l = async (e, t, n = []) => {
19
- let i = {
19
+ }, u = async (e, t, n = []) => {
20
+ let r = {
20
21
  procedure: e,
21
22
  declared: new Set(n),
22
23
  composed: /* @__PURE__ */ new Set(),
@@ -24,12 +25,12 @@ var r = new n(), i, a = /* @__PURE__ */ new Set(), o = (e) => {
24
25
  depth: { n: 0 }
25
26
  };
26
27
  return {
27
- result: await r.run(i, t),
28
- composed: i.composed,
29
- restricting: i.restricting
28
+ result: await i.run(r, t),
29
+ composed: r.composed,
30
+ restricting: r.restricting
30
31
  };
31
- }, u = async (e) => {
32
- let t = r.getStore();
32
+ }, d = async (e) => {
33
+ let t = i.getStore();
33
34
  if (t === void 0) return e();
34
35
  t.depth.n += 1;
35
36
  try {
@@ -37,30 +38,30 @@ var r = new n(), i, a = /* @__PURE__ */ new Set(), o = (e) => {
37
38
  } finally {
38
39
  --t.depth.n;
39
40
  }
40
- }, d = (e) => t.suspend(() => {
41
- let n = r.getStore();
42
- return n === void 0 ? e : t.acquireUseRelease(t.sync(() => {
43
- n.depth.n += 1;
44
- }), () => e, () => t.sync(() => {
45
- --n.depth.n;
41
+ }, f = (e) => n.suspend(() => {
42
+ let t = i.getStore();
43
+ return t === void 0 ? e : n.acquireUseRelease(n.sync(() => {
44
+ t.depth.n += 1;
45
+ }), () => e, () => n.sync(() => {
46
+ --t.depth.n;
46
47
  }));
47
- }), f = (t) => {
48
- let n = r.getStore();
48
+ }), p = (t) => {
49
+ let n = i.getStore();
49
50
  if (n === void 0 || n.muted === !0) return;
50
- let { composed: o, restricting: s } = e(t, n.depth.n > 0);
51
- for (let e of o) n.composed.add(e);
51
+ let { composed: r, restricting: s } = e(t, n.depth.n > 0);
52
+ for (let e of r) n.composed.add(e);
52
53
  for (let e of s) n.composed.has(e) || n.restricting.add(e);
53
- if (i === void 0 || a.has(n.procedure)) return;
54
- let c = m(n.procedure, n.composed, n.declared, n.restricting);
55
- c !== void 0 && (a.add(n.procedure), i(c));
56
- }, p = (e) => new Proxy(e, { get(e, t) {
57
- let n = Reflect.get(e, t, e);
58
- return typeof n == "function" && t !== "query" ? n.bind(e) : t !== "query" || typeof n != "function" ? n : (t) => (f(t), n.call(e, t));
59
- } }), m = (e, t, n, r) => {
54
+ if (a === void 0 || o.has(n.procedure)) return;
55
+ let c = h(n.procedure, n.composed, n.declared, n.restricting);
56
+ c !== void 0 && (o.add(n.procedure), a(c));
57
+ }, m = (e) => new Proxy(e, { get(e, n) {
58
+ let r = Reflect.get(e, n, e);
59
+ return typeof r == "function" && n !== "query" ? r.bind(e) : n !== "query" || typeof r != "function" ? r : (n) => (p(n), t(n), r.call(e, n));
60
+ } }), h = (e, t, n, r) => {
60
61
  let i = [...t], a = 0;
61
62
  for (let e of i) n.has(e) || (i[a++] = e);
62
63
  if (i.length = a, i.sort(), i.length !== 0) return `${e}: read ${i.map((e) => `\`${e}\``).join(", ")} without declaring ${i.length === 1 ? "it" : "them"} in \`source:\`.\n A write to ${i.length === 1 ? "that table" : "those tables"} will not re-run this query, so an open view keeps\n showing what it showed before. The write itself is fine, which is why nothing else reports this.
63
64
  Observed on this boot — a branch that did not run contributes nothing, so this names what WAS\n read and never claims the declaration is otherwise complete.` + (r.size > 0 ? `\n Not counted (read only to narrow the result): ${[...r].sort().map((e) => `\`${e}\``).join(", ")}.` : "");
64
65
  };
65
66
  //#endregion
66
- export { c as enterReadRecording, f as noteRead, s as readRecordingActive, l as recordReads, p as recordingStore, u as restrictingReads, d as restrictingReadsEffect, o as setSourceGapSink, m as sourceGapReport };
67
+ export { l as enterReadRecording, p as noteRead, c as readRecordingActive, u as recordReads, m as recordingStore, d as restrictingReads, f as restrictingReadsEffect, s as setSourceGapSink, h as sourceGapReport };
@@ -0,0 +1,12 @@
1
+ import { and as e } from "@voltro/database";
2
+ //#region src/readScopePredicate.ts
3
+ var t = (t, n) => {
4
+ let r = t.setOp === void 0 ? t.alias ?? ((t.joins?.length ?? 0) > 0 ? t.table : void 0) : void 0, i = n((e) => r === void 0 ? e : `${r}.${e}`);
5
+ return {
6
+ ...t,
7
+ ...r === void 0 ? {} : { alias: r },
8
+ predicate: t.predicate ? e(t.predicate, i) : i
9
+ };
10
+ };
11
+ //#endregion
12
+ export { t as addReadScopePredicate };
@@ -11,6 +11,7 @@ var s = a({ scope: "voltro:replication" }), c = new o(), l = (e, t) => c.run(e,
11
11
  a(e);
12
12
  }), r.asVoid(i.interrupt(o));
13
13
  })), d = () => c.getStore(), f = class {
14
+ integrityQuery;
14
15
  primary;
15
16
  replicas;
16
17
  adapter;
@@ -22,8 +23,9 @@ var s = a({ scope: "voltro:replication" }), c = new o(), l = (e, t) => c.run(e,
22
23
  health;
23
24
  recordRouting;
24
25
  now;
26
+ closing;
25
27
  constructor(r) {
26
- this.primary = r.primary, this.replicas = r.replicas, this.adapter = r.replicationAdapter, this.policy = r.rywPolicy ?? "fallback", this.rywTtlMs = r.rywTtlMs ?? 3e4, this.rywMaxWaitMs = r.rywMaxWaitMs ?? 500, this.now = r.now ?? Date.now, this.rywStore = r.rywStore ?? n({ now: this.now }), this.selector = r.replicaSelector ?? e(), this.health = r.replicaHealth ?? t({ now: this.now }), r.recordRouting !== void 0 && (this.recordRouting = r.recordRouting);
28
+ this.primary = r.primary, r.primary.integrityQuery !== void 0 && (this.integrityQuery = r.primary.integrityQuery.bind(r.primary)), this.replicas = r.replicas, this.adapter = r.replicationAdapter, this.policy = r.rywPolicy ?? "fallback", this.rywTtlMs = r.rywTtlMs ?? 3e4, this.rywMaxWaitMs = r.rywMaxWaitMs ?? 500, this.now = r.now ?? Date.now, this.rywStore = r.rywStore ?? n({ now: this.now }), this.selector = r.replicaSelector ?? e(), this.health = r.replicaHealth ?? t({ now: this.now }), r.recordRouting !== void 0 && (this.recordRouting = r.recordRouting);
27
29
  }
28
30
  async query(e) {
29
31
  let t = c.getStore(), n = t?.subjectKey ?? "anon:bg";
@@ -166,9 +168,9 @@ var s = a({ scope: "voltro:replication" }), c = new o(), l = (e, t) => c.run(e,
166
168
  let n = await this.primary.insert(e, t);
167
169
  return await this.stampPostWrite(), n;
168
170
  }
169
- async insertMany(e, t) {
170
- let n = await this.primary.insertMany(e, t);
171
- return await this.stampPostWrite(), n;
171
+ async insertMany(e, t, n) {
172
+ let r = await this.primary.insertMany(e, t, n);
173
+ return await this.stampPostWrite(), r;
172
174
  }
173
175
  async patchJson(e, t, n, r, i) {
174
176
  let a = await this.primary.patchJson(e, t, n, r, i);
@@ -218,6 +220,22 @@ var s = a({ scope: "voltro:replication" }), c = new o(), l = (e, t) => c.run(e,
218
220
  get changeScope() {
219
221
  return this.primary.changeScope ?? "local";
220
222
  }
223
+ close(e) {
224
+ return this.closing ??= (async () => {
225
+ let t = [];
226
+ try {
227
+ await this.rywStore.close?.();
228
+ } catch (e) {
229
+ t.push(e);
230
+ }
231
+ for (let n of /* @__PURE__ */ new Set([this.primary, ...this.replicas])) try {
232
+ await n.close?.(e);
233
+ } catch (e) {
234
+ t.push(e);
235
+ }
236
+ if (t.length > 0) throw AggregateError(t, "Read replica shutdown failed");
237
+ })();
238
+ }
221
239
  async stampPostWrite() {
222
240
  if (this.replicas.length === 0) return;
223
241
  let e = c.getStore()?.subjectKey ?? "anon:bg";
package/dist/rowFilter.js CHANGED
@@ -1,65 +1,82 @@
1
1
  import { restrictingReadsEffect as e } from "./readRecorder.js";
2
- import { Effect as t, Schedule as n, Schema as r } from "effect";
3
- import { and as i } from "@voltro/database";
4
- import { currentSubjectAuthority as a, isMachineSubject as o } from "@voltro/protocol";
5
- import { createLogger as s } from "@voltro/logger";
2
+ import { mapSetReadScopes as t } from "./setReadScopes.js";
3
+ import { Effect as n, Schedule as r, Schema as i } from "effect";
4
+ import { and as a } from "@voltro/database";
5
+ import { currentSubjectAuthority as o, isMachineSubject as s } from "@voltro/protocol";
6
+ import { createLogger as c } from "@voltro/logger";
6
7
  //#region src/rowFilter.ts
7
- var c = class extends r.TaggedError()("RowFilterUnavailable", { cause: r.String }) {}, l = class extends r.TaggedError()("RowFilterDeclarationViolated", {
8
- table: r.String,
9
- declared: r.Array(r.String)
8
+ var l = class extends i.TaggedError()("RowFilterUnavailable", { cause: i.String }) {}, u = class extends i.TaggedError()("RowFilterDeclarationViolated", {
9
+ table: i.String,
10
+ declared: i.Array(i.String)
10
11
  }) {
11
12
  get message() {
12
13
  return `row filter narrowed '${this.table}', which its declaration does not name (declared: ${this.declared.join(", ") || "none"})`;
13
14
  }
14
- }, u = n.max([n.exponential("20 millis"), n.recurs(2)]), d = Symbol.for("@voltro/runtime/rowFilter"), f = globalThis, p = f[d] ?? (f[d] = {}), m = (e) => {
15
- p.filter = e;
16
- }, h = () => p.filter, g = () => p.filter !== void 0, _ = () => void 0, v = s({ scope: "voltro:row-filter" }), y = /* @__PURE__ */ new Set(), b = (e, t) => {
17
- y.has(e) || (y.add(e), v.info("row filter: RESOLVED on a live read path", {
15
+ }, d = r.max([r.exponential("20 millis"), r.recurs(2)]), f = Symbol.for("@voltro/runtime/rowFilter"), p = globalThis, m = p[f] ?? (p[f] = {}), h = (e) => {
16
+ m.filter = e;
17
+ }, g = () => m.filter, _ = () => m.filter !== void 0, v = () => void 0, y = c({ scope: "voltro:row-filter" }), b = /* @__PURE__ */ new Set(), x = (e, t) => {
18
+ b.has(e) || (b.add(e), y.info("row filter: RESOLVED on a live read path", {
18
19
  arm: e,
19
20
  ...t === void 0 ? {} : { constrains: t },
20
- armsSeen: [...y].sort().join(",")
21
+ armsSeen: [...b].sort().join(",")
21
22
  }));
22
- }, x = () => [...y].sort(), S = () => {
23
- y.clear();
24
- }, C = (e, n) => t.tap(w(h(), e, n), () => t.sync(() => {
25
- let e = h();
26
- e !== void 0 && b("request", e.tables?.length);
27
- })), w = (n, r, i) => {
28
- if (n === void 0 || o(r)) return t.succeed(_);
29
- let a = n.retry ?? u, s = e(n.load(r)), d = a === !1 ? s : t.retry(s, a), f = n.tables, p = f === void 0 ? void 0 : new Set(f);
30
- return d.pipe(t.map((e) => p === void 0 ? (t) => n.predicate(e, t) : (t) => {
31
- let r = n.predicate(e, t);
32
- if (r !== void 0 && !p.has(t)) throw new l({
33
- table: t,
23
+ }, S = () => [...b].sort(), C = () => {
24
+ b.clear();
25
+ }, w = (e, t) => n.tap(T(g(), e, t), () => n.sync(() => {
26
+ let e = g();
27
+ e !== void 0 && x("request", e.tables?.length);
28
+ })), T = (t, r, i) => {
29
+ if (t === void 0 || s(r)) return n.succeed(v);
30
+ let a = t.retry ?? d, o = e(t.load(r)), c = a === !1 ? o : n.retry(o, a), f = t.tables, p = f === void 0 ? void 0 : new Set(f);
31
+ return c.pipe(n.map((e) => p === void 0 ? (n) => t.predicate(e, n) : (n) => {
32
+ let r = t.predicate(e, n);
33
+ if (r !== void 0 && !p.has(n)) throw new u({
34
+ table: n,
34
35
  declared: f ?? []
35
36
  });
36
37
  return r;
37
- }), t.catch((e) => t.suspend(() => (i?.(e), n.onLoadError === "deny" ? t.succeed(T) : t.fail(new c({ cause: String(e) }))))));
38
- }, T = () => ({
38
+ }), n.catch((e) => n.suspend(() => (i?.(e), t.onLoadError === "deny" ? n.succeed(E) : n.fail(new l({ cause: String(e) }))))));
39
+ }, E = () => ({
39
40
  column: "id",
40
41
  op: "isNull"
41
- }), E = (e) => {
42
- let t = h();
42
+ }), D = (e) => {
43
+ let t = g();
43
44
  if (t === void 0) return !1;
44
45
  let n = t.tables;
45
46
  if (n === void 0) return !0;
46
47
  let r = new Set(n);
47
48
  return e.some((e) => r.has(e));
48
- }, D = (e, t, n) => {
49
+ }, O = (e, t, n) => {
49
50
  let r = e(t);
50
- return r === void 0 ? n : n ? i(n, r) : r;
51
- }, O = (e, t) => {
52
- let n = D(e, t.table, t.predicate);
53
- return n === t.predicate ? t : {
54
- ...t,
55
- predicate: n
56
- };
51
+ return r === void 0 ? n : n ? a(n, r) : r;
57
52
  }, k = (e, n) => {
58
- if (h() !== void 0) return async () => {
59
- let r = await t.runPromise(t.result(C(a(e), n)));
53
+ let r = n;
54
+ if (r.setOp !== void 0) {
55
+ let i = {
56
+ ...r,
57
+ table: n.table,
58
+ predicate: n.predicate,
59
+ order: r.order ?? [],
60
+ projection: r.projection,
61
+ take: r.take,
62
+ skip: r.skip
63
+ }, a = t(i, (t) => k(e, t));
64
+ return {
65
+ ...n,
66
+ setOp: a.setOp
67
+ };
68
+ }
69
+ let i = O(e, n.table, n.predicate);
70
+ return i === n.predicate ? n : {
71
+ ...n,
72
+ predicate: i
73
+ };
74
+ }, A = (e, t) => {
75
+ if (g() !== void 0) return async () => {
76
+ let r = await n.runPromise(n.result(w(o(e), t)));
60
77
  if (r._tag === "Failure") throw r.failure;
61
78
  return r.success;
62
79
  };
63
80
  };
64
81
  //#endregion
65
- export { u as DEFAULT_ROW_FILTER_RETRY, _ as NO_ROW_FILTER, l as RowFilterDeclarationViolated, c as RowFilterUnavailable, D as applyRowFilter, O as applyRowFilterToDescriptor, h as getRowFilter, k as makeDefaultRefilter, b as noteRowFilterResolved, S as resetRowFilterResolvedArms, C as resolveRowFilterScope, w as resolveRowFilterScopeFor, E as rowFilterMayNarrow, g as rowFilterRegistered, x as rowFilterResolvedArms, m as setRowFilter };
82
+ export { d as DEFAULT_ROW_FILTER_RETRY, v as NO_ROW_FILTER, u as RowFilterDeclarationViolated, l as RowFilterUnavailable, O as applyRowFilter, k as applyRowFilterToDescriptor, g as getRowFilter, A as makeDefaultRefilter, x as noteRowFilterResolved, C as resetRowFilterResolvedArms, w as resolveRowFilterScope, T as resolveRowFilterScopeFor, D as rowFilterMayNarrow, _ as rowFilterRegistered, S as rowFilterResolvedArms, h as setRowFilter };
@@ -1,15 +1,15 @@
1
1
  import { interruptConnectionStreams as e, unbindConnection as t } from "./connectionCredentials.js";
2
2
  import { Effect as n, Layer as r, Queue as i } from "effect";
3
3
  import { randomUUID as a } from "node:crypto";
4
- import { Headers as o } from "effect/http";
5
- import { RpcServer as s } from "effect/rpc";
4
+ import { RpcServer as o } from "effect/rpc";
5
+ import { Headers as s } from "effect/http";
6
6
  //#region src/rpcConnections.ts
7
7
  var c = Symbol.for("@voltro/runtime/rpcConnections"), l = globalThis, u = l[c] ??= {
8
8
  nextId: 1,
9
9
  entries: /* @__PURE__ */ new Map(),
10
10
  addressMark: a()
11
11
  }, d = "x-voltro-client-address", f = (e) => `${u.addressMark} ${e}`, p = (e, t) => {
12
- let n = o.remove(e.headers, d), r = t === void 0 ? n : o.set(n, d, f(t)), i = Object.create(e);
12
+ let n = s.remove(e.headers, d), r = t === void 0 ? n : s.set(n, d, f(t)), i = Object.create(e);
13
13
  return Object.defineProperty(i, "headers", {
14
14
  value: r,
15
15
  configurable: !0
@@ -21,8 +21,8 @@ var c = Symbol.for("@voltro/runtime/rpcConnections"), l = globalThis, u = l[c] ?
21
21
  remoteAddr: n,
22
22
  headers: r.length === e.length ? e : r
23
23
  };
24
- }, h = (e) => u.entries.get(e)?.connection, g = (o, c) => r.effect(s.Protocol, n.gen(function* () {
25
- let r = yield* s.Protocol, o = yield* i.make(), l = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = (e, t) => {
24
+ }, h = (e) => u.entries.get(e)?.connection, g = (s, c) => r.effect(o.Protocol, n.gen(function* () {
25
+ let r = yield* o.Protocol, s = yield* i.make(), l = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = (e, t) => {
26
26
  let n = l.get(e);
27
27
  if (n !== void 0) return t !== void 0 && n.connection.remoteAddr === void 0 && (n.connection = Object.freeze({
28
28
  ...n.connection,
@@ -48,10 +48,10 @@ var c = Symbol.for("@voltro/runtime/rpcConnections"), l = globalThis, u = l[c] ?
48
48
  for (let e of l.keys()) p(e);
49
49
  })), yield* n.forkScoped(n.gen(function* () {
50
50
  let e = yield* i.take(r.disconnects), t = p(e);
51
- t !== void 0 && (yield* i.offer(o, t));
51
+ t !== void 0 && (yield* i.offer(s, t));
52
52
  }).pipe(n.forever)), {
53
53
  ...r,
54
- disconnects: o,
54
+ disconnects: s,
55
55
  run: (e) => r.run((t, i) => n.gen(function* () {
56
56
  if (!(yield* r.clientIds).has(t)) return;
57
57
  if (i._tag !== "Request") {
@@ -78,6 +78,6 @@ var c = Symbol.for("@voltro/runtime/rpcConnections"), l = globalThis, u = l[c] ?
78
78
  return n;
79
79
  })
80
80
  };
81
- })).pipe(r.provide(o));
81
+ })).pipe(r.provide(s));
82
82
  //#endregion
83
83
  export { d as RPC_CLIENT_ADDRESS_HEADER, h as getRpcConnection, f as stampRpcClientAddress, m as takeRpcClientAddress, p as withRpcClientAddress, g as withRpcConnectionIdentity };