@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,50 @@
1
+ import { Context as e, Option as t } from "effect";
2
+ import { EventRpcWorkload as n } from "@voltro/protocol";
3
+ import { RpcGroup as r, RpcSchema as i } from "effect/rpc";
4
+ //#region src/rpcWorkloadAdmission.ts
5
+ var a = (e) => {
6
+ if (e === void 0) return;
7
+ if (!e || typeof e != "object" || Array.isArray(e) || ![Object.prototype, null].includes(Object.getPrototypeOf(e))) throw Error("Invalid RPC workload admission");
8
+ let t = /* @__PURE__ */ new Map();
9
+ for (let n of Reflect.ownKeys(e)) {
10
+ let r = Object.getOwnPropertyDescriptor(e, n);
11
+ if (typeof n != "string" || ![
12
+ "rpc",
13
+ "subscriptions",
14
+ "events",
15
+ "routes"
16
+ ].includes(n) || !r.enumerable || !("value" in r)) throw Error("RPC workload admission requires own data");
17
+ t.set(n, r.value);
18
+ }
19
+ let n = t.get("rpc"), r = t.get("subscriptions"), i = t.get("routes");
20
+ if (typeof n != "boolean" || typeof r != "boolean") throw Error("RPC workload admission requires explicit modes");
21
+ let a = t.get("events");
22
+ if (a !== void 0 && typeof a != "boolean") throw Error("Invalid event workload admission");
23
+ let o;
24
+ if (i !== void 0) {
25
+ if (!Array.isArray(i) || i.length > 4096 || Reflect.ownKeys(i).length !== i.length + 1) throw Error("Invalid RPC workload route filters");
26
+ let e = [];
27
+ for (let t = 0; t < i.length; t++) {
28
+ let n = Object.getOwnPropertyDescriptor(i, String(t));
29
+ if (!n?.enumerable || !("value" in n) || typeof n.value != "string" || n.value.length > 191 || !/^(?:[A-Za-z][A-Za-z0-9_-]*\.)*[A-Za-z][A-Za-z0-9_-]*(?:\.\*)?$/.test(n.value)) throw Error("Invalid RPC workload tag filter");
30
+ e.push(n.value);
31
+ }
32
+ if (new Set(e).size !== e.length) throw Error("Duplicate RPC workload tag filter");
33
+ o = Object.freeze(e);
34
+ }
35
+ return Object.freeze({
36
+ rpc: n,
37
+ subscriptions: r,
38
+ ...a === void 0 ? {} : { events: a },
39
+ ...o === void 0 ? {} : { routes: o }
40
+ });
41
+ }, o = (a, o, s) => {
42
+ if (!o) return a;
43
+ let c = [...a.requests.values()].filter((r) => {
44
+ let a = r, c = t.isSome(e.getOption(a.annotations, n)), l = o.events ?? o.subscriptions;
45
+ return (c ? l && (s === "websocket" || o.rpc) : s === "http" ? o.rpc : i.isStreamSchema(a.successSchema) ? o.subscriptions : o.rpc) && (o.routes === void 0 || o.routes.some((e) => e.endsWith(".*") ? r._tag.startsWith(e.slice(0, -1)) : r._tag === e));
46
+ });
47
+ return r.make(...c).annotateMerge(a.annotations);
48
+ };
49
+ //#endregion
50
+ export { a as captureRpcWorkloadAdmission, o as selectRpcWorkloadGroup };
@@ -1,6 +1,7 @@
1
- import { createLogger as e } from "@voltro/logger";
1
+ import { Effect as e } from "effect";
2
+ import { createLogger as t } from "@voltro/logger";
2
3
  //#region src/rywPositionStore.ts
3
- var t = e({ scope: "voltro:ryw" }), n = (e = {}) => {
4
+ var n = t({ scope: "voltro:ryw" }), r = (e = {}) => {
4
5
  let t = e.now ?? Date.now, n = /* @__PURE__ */ new Map();
5
6
  return {
6
7
  get(e) {
@@ -20,65 +21,99 @@ var t = e({ scope: "voltro:ryw" }), n = (e = {}) => {
20
21
  return n.size;
21
22
  }
22
23
  };
23
- }, r = (e, t) => e === null ? t === void 0 ? "anon:bg" : `anon:${t}` : `subject:${e}`, i = (e) => {
24
- let n = e.now ?? Date.now, r = e.keyPrefix ?? "voltro:ryw", i = e.channel ?? `${r}:bus`, a = e.onError ?? ((e, n) => {
25
- t.warn("redis operation failed", {
26
- op: n,
27
- error: String(e)
28
- });
29
- }), o = `${process.pid ?? 0}:${Math.random() * 1e9 | 0}:${n()}`, s = /* @__PURE__ */ new Map(), c = (e) => {
30
- if (e.senderId !== o) {
31
- if (e.op === "set") {
32
- if (e.position === void 0 || e.expiresAt === void 0) return;
33
- s.set(e.subjectKey, {
34
- position: e.position,
35
- expiresAt: e.expiresAt
36
- });
37
- } else s.delete(e.subjectKey);
24
+ }, i = (e, t) => e === null ? t === void 0 ? "anon:bg" : `anon:${t}` : `subject:${e}`, a = (t) => e.gen(function* () {
25
+ let r = yield* e.context(), i = e.runPromiseWith(r), a = t.now ?? Date.now, s = t.keyPrefix.trim();
26
+ if (s.length === 0) throw Error("RYW keyPrefix must name an application/environment namespace");
27
+ let c = t.channel ?? `${s}:bus`;
28
+ if (c.trim().length === 0) throw Error("RYW channel must not be empty");
29
+ let l = t.onError ?? ((e, t) => {
30
+ n.warn("redis operation failed", { op: t });
31
+ }), u = (e, t) => {
32
+ try {
33
+ l(e, t);
34
+ } catch {
35
+ n.warn("redis error observer failed", { op: t });
38
36
  }
39
- };
40
- e.subscriber.on("message", (e, t) => {
41
- if (e === i) try {
42
- let e = JSON.parse(t);
43
- c(e);
37
+ }, d = `${process.pid}:${Math.random()}:${a()}`, f = /* @__PURE__ */ new Map(), p = !1, m = Promise.resolve(), h, g = yield* t.pubsub.subscribe(c, (e) => {
38
+ if (!p) try {
39
+ let t = o(e);
40
+ if (t.senderId === d) return;
41
+ t.op === "delete" ? f.delete(t.subjectKey) : t.expiresAt > a() ? f.set(t.subjectKey, {
42
+ position: t.position,
43
+ expiresAt: t.expiresAt
44
+ }) : f.delete(t.subjectKey);
44
45
  } catch (e) {
45
- a(e, "parse");
46
+ u(e, "parse");
46
47
  }
47
- }), e.subscriber.subscribe(i).catch((e) => a(e, "subscribe"));
48
- let l = (t) => {
49
- let n = JSON.stringify(t);
50
- e.client.publish(i, n).catch((e) => a(e, t.op));
51
- }, u = (e) => `${r}:${e}`;
48
+ }).pipe(e.onError(() => t.pubsub.close)), _ = (e, n) => {
49
+ m = m.then(async () => {
50
+ try {
51
+ await n(), await i(t.pubsub.publish(c, JSON.stringify(e)));
52
+ } catch (t) {
53
+ u(t, e.op);
54
+ }
55
+ });
56
+ }, v = () => {
57
+ if (p) throw Error("RYW consumer is closed");
58
+ };
52
59
  return {
53
60
  get(e) {
54
- let t = s.get(e);
61
+ let t = f.get(e);
55
62
  if (t !== void 0) {
56
- if (t.expiresAt <= n()) s.delete(e);
63
+ if (t.expiresAt <= a()) f.delete(e);
57
64
  else return t;
58
65
  }
59
66
  },
60
- set(t, r) {
61
- s.set(t, r);
62
- let i = r.expiresAt - n();
63
- i > 0 && e.client.psetex(u(t), i, JSON.stringify(r)).catch((e) => a(e, "set")), l({
64
- senderId: o,
67
+ set(e, n) {
68
+ v();
69
+ let r = { ...n };
70
+ f.set(e, r), _({
71
+ senderId: d,
65
72
  op: "set",
66
- subjectKey: t,
67
- position: r.position,
68
- expiresAt: r.expiresAt
73
+ subjectKey: e,
74
+ ...r
75
+ }, () => {
76
+ let n = r.expiresAt - a();
77
+ return n > 0 ? t.client.psetex(`${s}:${e}`, n, JSON.stringify(r)) : t.client.del([`${s}:${e}`]);
69
78
  });
70
79
  },
71
- delete(t) {
72
- s.delete(t), e.client.del(u(t)).catch((e) => a(e, "delete")), l({
73
- senderId: o,
80
+ delete(e) {
81
+ v(), f.delete(e), _({
82
+ senderId: d,
74
83
  op: "delete",
75
- subjectKey: t
76
- });
84
+ subjectKey: e
85
+ }, () => t.client.del([`${s}:${e}`]));
77
86
  },
78
- size() {
79
- return s.size;
80
- }
87
+ size: () => f.size,
88
+ close: () => h ??= (async () => {
89
+ p = !0, await m;
90
+ try {
91
+ await i(g);
92
+ } finally {
93
+ try {
94
+ await i(t.pubsub.close);
95
+ } finally {
96
+ f.clear();
97
+ }
98
+ }
99
+ })()
100
+ };
101
+ }), o = (e) => {
102
+ let t = JSON.parse(e);
103
+ if (typeof t != "object" || !t || !("senderId" in t) || typeof t.senderId != "string" || !("subjectKey" in t) || typeof t.subjectKey != "string" || !("op" in t) || t.op !== "set" && t.op !== "delete") throw Error("Invalid RYW message");
104
+ if (t.op === "delete") return {
105
+ senderId: t.senderId,
106
+ subjectKey: t.subjectKey,
107
+ op: "delete"
108
+ };
109
+ if (!("position" in t) || typeof t.position != "string" || !("expiresAt" in t) || typeof t.expiresAt != "number" || !Number.isFinite(t.expiresAt)) throw Error("Invalid RYW position");
110
+ return {
111
+ senderId: t.senderId,
112
+ subjectKey: t.subjectKey,
113
+ op: "set",
114
+ position: t.position,
115
+ expiresAt: t.expiresAt
81
116
  };
82
117
  };
83
118
  //#endregion
84
- export { r as buildSubjectKey, n as memoryRywPositionStore, i as redisRywPositionStore };
119
+ export { i as buildSubjectKey, r as memoryRywPositionStore, a as redisRywPositionStore };
package/dist/scheduler.js CHANGED
@@ -363,7 +363,10 @@ var b = c, x = "default", S = {
363
363
  let n = typeof t.workflow.payload == "function" ? await t.workflow.payload(a) : t.workflow.payload ?? {};
364
364
  await e.start(t.workflow.name, n);
365
365
  }
366
- t.handler !== void 0 && await e(t.handler(a), (e) => x.runEffect ? x.runEffect(e, m.signal) : ne.runPromise(e, { signal: m.signal }));
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
+ }
367
370
  }, h = k ? k(c, {
368
371
  name: t.name,
369
372
  scheduledAt: n,
@@ -662,6 +665,7 @@ Give each a five-field expression, or set trigger: 'self' on it.`);
662
665
  };
663
666
  Ge.length > 0 && Q !== "off" && Ye();
664
667
  let Xe = async (e, t) => {
668
+ if (I) throw Error("scheduler stopped");
665
669
  let n = V.get(e);
666
670
  if (!n) return {
667
671
  kind: "unknownSchedule",
@@ -730,6 +734,7 @@ Give each a five-field expression, or set trigger: 'self' on it.`);
730
734
  for (let e of X) Fe(e);
731
735
  }
732
736
  return {
737
+ isRunning: () => !I,
733
738
  triggerExternal: async (e, t) => {
734
739
  let r = await Xe(e, t);
735
740
  return n(e, r.kind), r;