@voltro/runtime 0.85.0 → 0.86.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 (160) hide show
  1. package/CHANGELOG.md +666 -0
  2. package/THIRD-PARTY-NOTICES.md +5 -33
  3. package/dist/aggregate.js +42 -0
  4. package/dist/aggregateExtrema.js +80 -0
  5. package/dist/aggregateIvm.js +115 -0
  6. package/dist/analyticsMirror.js +228 -0
  7. package/dist/analyticsSink.js +38 -0
  8. package/dist/apiKeyUsage.js +33 -0
  9. package/dist/apiKeys.js +223 -0
  10. package/dist/apiKeysWiring.js +114 -0
  11. package/dist/approvalBuiltins.js +10 -0
  12. package/dist/approvals.js +269 -0
  13. package/dist/authMiddlewareLayer.js +47 -0
  14. package/dist/bindEvent.js +72 -0
  15. package/dist/bootListener.js +76 -0
  16. package/dist/bootRefusal.js +7 -0
  17. package/dist/bootStoreCodec.js +70 -0
  18. package/dist/businessRules.js +67 -0
  19. package/dist/changeClaimsTable.js +12 -0
  20. package/dist/circuitBreaker.js +72 -0
  21. package/dist/columnOnUpdate.js +23 -0
  22. package/dist/composeAnalytics.js +108 -0
  23. package/dist/computedQuery.js +4 -0
  24. package/dist/connectionBuiltins.js +81 -0
  25. package/dist/connectionCredentials.js +66 -0
  26. package/dist/connectionState.js +34 -0
  27. package/dist/connectionVault.js +410 -0
  28. package/dist/connectionsFacade.js +54 -0
  29. package/dist/coordinatedSchedule.js +139 -0
  30. package/dist/crdtHistory.js +138 -0
  31. package/dist/crdtMerge.js +179 -0
  32. package/dist/crdtVersionsTable.js +25 -0
  33. package/dist/credentialBound.js +12 -0
  34. package/dist/crud.js +72 -0
  35. package/dist/dataStore.js +679 -0
  36. package/dist/dataloader.js +61 -0
  37. package/dist/declaredTablesGuard.js +48 -0
  38. package/dist/defineExecutor.js +4 -0
  39. package/dist/dependencyGraph.js +32 -0
  40. package/dist/devices.js +228 -0
  41. package/dist/devicesWiring.js +168 -0
  42. package/dist/dialectReplicationAdapter.js +29 -0
  43. package/dist/dispatcher.js +447 -0
  44. package/dist/effectStore.js +71 -0
  45. package/dist/eventBus.js +260 -0
  46. package/dist/eventPublish.js +49 -0
  47. package/dist/events.js +193 -0
  48. package/dist/expectation.js +52 -0
  49. package/dist/expectationEvaluator.js +308 -0
  50. package/dist/experiment.js +96 -0
  51. package/dist/experimentEvaluator.js +245 -0
  52. package/dist/externalizedTasks.js +25 -0
  53. package/dist/fieldCipher.js +61 -0
  54. package/dist/fingerprint.js +21 -0
  55. package/dist/finops.js +42 -0
  56. package/dist/finopsAccountant.js +216 -0
  57. package/dist/handlerBody.js +8 -0
  58. package/dist/healthProbes.js +55 -0
  59. package/dist/httpClientSsrf.js +49 -0
  60. package/dist/httpClientTracing.js +11 -0
  61. package/dist/httpCompression.js +76 -0
  62. package/dist/httpKeepAlive.js +12 -0
  63. package/dist/httpRouteMounts.js +47 -0
  64. package/dist/idempotencyStore.js +70 -0
  65. package/dist/idleDetector.js +21 -0
  66. package/dist/index.d.ts +88 -69
  67. package/dist/index.js +144 -15292
  68. package/dist/insertRequiredColumns.js +19 -0
  69. package/dist/inspectWorkflow.js +1 -0
  70. package/dist/instanceMembership.js +98 -0
  71. package/dist/ivm.js +125 -0
  72. package/dist/kvDataStore.js +86 -0
  73. package/dist/kvFacade.js +32 -0
  74. package/dist/matcher.js +304 -0
  75. package/dist/memoryColumnDefaults.js +11 -0
  76. package/dist/memoryQueryJoins.js +114 -0
  77. package/dist/metrics.js +161 -0
  78. package/dist/observability.js +123 -0
  79. package/dist/observedGraph.js +52 -0
  80. package/dist/originGuard.js +116 -0
  81. package/dist/outbox.js +352 -0
  82. package/dist/pluginRefRules.js +65 -0
  83. package/dist/policyGuardResolver.js +55 -0
  84. package/dist/preview.js +62 -0
  85. package/dist/projectedRows.js +12 -0
  86. package/dist/provenance.js +63 -0
  87. package/dist/rangeIndex.js +89 -0
  88. package/dist/rawReadScope.js +17 -0
  89. package/dist/reaction.js +85 -0
  90. package/dist/reactiveConfig.js +11 -0
  91. package/dist/readClassification.js +57 -0
  92. package/dist/readRecorder.js +66 -0
  93. package/dist/rebac.js +104 -0
  94. package/dist/rebacInterceptor.js +81 -0
  95. package/dist/registry.js +29 -0
  96. package/dist/relevantFields.js +65 -0
  97. package/dist/replicaHealth.js +42 -0
  98. package/dist/replicaLocality.js +44 -0
  99. package/dist/replicaObservations.js +121 -0
  100. package/dist/replicaSelection.js +32 -0
  101. package/dist/replicatedDataStore.js +239 -0
  102. package/dist/requestLoader.js +7 -0
  103. package/dist/resumeCensus.js +28 -0
  104. package/dist/revalidation.js +22 -0
  105. package/dist/rowFilter.js +65 -0
  106. package/dist/rowStateBytes.js +45 -0
  107. package/dist/rpcBodyCap.js +63 -0
  108. package/dist/rpcConnections.js +83 -0
  109. package/dist/rpcDefectDiagnostics.js +15 -0
  110. package/dist/rpcServer.js +992 -0
  111. package/dist/runAsSystem.js +23 -0
  112. package/dist/rywPositionStore.js +84 -0
  113. package/dist/schedule.js +23 -0
  114. package/dist/scheduleBackfillRequests.js +151 -0
  115. package/dist/scheduleClaimsTable.js +11 -0
  116. package/dist/scheduleRunsTable.js +37 -0
  117. package/dist/scheduler.js +835 -0
  118. package/dist/schemaRegistry.js +65 -0
  119. package/dist/secretsResolver.js +35 -0
  120. package/dist/securityHeaders.js +33 -0
  121. package/dist/servePipeline.js +305 -0
  122. package/dist/serverOnlyAudit.js +66 -0
  123. package/dist/serverTracer.js +15 -0
  124. package/dist/serviceCredentials.js +40 -0
  125. package/dist/singleNodeOrchestrator.js +91 -0
  126. package/dist/sourceResolution.js +42 -0
  127. package/dist/storeMiddleware.js +880 -0
  128. package/dist/storeQuery.js +204 -0
  129. package/dist/storeRead.js +10 -0
  130. package/dist/subscriber.js +7 -0
  131. package/dist/subscriptionOutbox.js +139 -0
  132. package/dist/subscriptionRegistry.js +82 -0
  133. package/dist/subscriptionResume.js +132 -0
  134. package/dist/subscriptionSocketMetrics.js +65 -0
  135. package/dist/systemSubject.js +5 -0
  136. package/dist/tenantScope.js +23 -0
  137. package/dist/tenantSelection.js +27 -0
  138. package/dist/timeline.js +105 -0
  139. package/dist/traceContext.js +5 -0
  140. package/dist/traceSink.js +63 -0
  141. package/dist/traceSpansTable.js +29 -0
  142. package/dist/traceparent.js +34 -0
  143. package/dist/transactionSubject.js +12 -0
  144. package/dist/trustedProxy.js +155 -0
  145. package/dist/undo.js +129 -0
  146. package/dist/undoBuiltins.js +69 -0
  147. package/dist/undoCapture.js +74 -0
  148. package/dist/undoLogTable.js +16 -0
  149. package/dist/upsertBinding.js +20 -0
  150. package/dist/wakeOrchestrator.js +34 -0
  151. package/dist/wakeRegistry.js +71 -0
  152. package/dist/wakeRouter.js +63 -0
  153. package/dist/wakeSupervisor.js +62 -0
  154. package/dist/wakeupsTable.js +12 -0
  155. package/dist/webSocketGatewayRuntime.js +114 -0
  156. package/dist/webhookVerification.js +18 -0
  157. package/dist/wireColumnStrip.js +84 -0
  158. package/dist/workflowReadBuiltins.js +87 -0
  159. package/dist/workflowRuntime.js +708 -0
  160. package/package.json +7 -7
@@ -0,0 +1,61 @@
1
+ import { BOUND_ENCRYPTED_PREFIX as e, ENCRYPTED_PREFIX as t, decodeFieldValue as n, encodeFieldValue as r, isEncrypted as i } from "@voltro/database";
2
+ import { createCipheriv as a, createDecipheriv as o, randomBytes as s, scryptSync as c } from "node:crypto";
3
+ //#region src/fieldCipher.ts
4
+ var l = (e) => /^[0-9a-f]{64}$/i.test(e) ? Buffer.from(e, "hex") : c(e, "voltro:field-encryption:v1", 32), u = (e, t) => {
5
+ let n = e === "r" ? t?.row : e === "c" ? t?.column : void 0;
6
+ if (n === void 0) throw Error(e === "r" || e === "c" ? `field cipher: ciphertext is bound to its ${e === "r" ? "row" : "column"} and was read without that binding` : "field cipher: malformed ciphertext");
7
+ return Buffer.from(n, "utf8");
8
+ }, d = (n) => {
9
+ if (n.length !== 32) throw Error(`field cipher key must be 32 bytes, got ${n.length}`);
10
+ return {
11
+ encrypt: (r, i) => {
12
+ let o = s(12), c = a("aes-256-gcm", n, o), l = i === void 0 ? void 0 : i.row === void 0 ? "c" : "r";
13
+ l !== void 0 && c.setAAD(u(l, i));
14
+ let d = Buffer.concat([c.update(r, "utf8"), c.final()]), f = c.getAuthTag(), p = `${o.toString("base64")}:${f.toString("base64")}:${d.toString("base64")}`;
15
+ return l === void 0 ? `${t}${p}` : `${e}${l}:${p}`;
16
+ },
17
+ decrypt: (r, i) => {
18
+ let a = r.startsWith(e), s = r.slice(a ? e.length : t.length).split(":"), c = a ? s.shift() ?? "" : void 0, [l, d, f] = s;
19
+ if (!l || !d || f === void 0) throw Error("field cipher: malformed ciphertext");
20
+ let p = o("aes-256-gcm", n, Buffer.from(l, "base64"));
21
+ return c !== void 0 && p.setAAD(u(c, i)), p.setAuthTag(Buffer.from(d, "base64")), Buffer.concat([p.update(Buffer.from(f, "base64")), p.final()]).toString("utf8");
22
+ }
23
+ };
24
+ }, f = (e, t = []) => {
25
+ let n = d(l(e)), r = t.filter((t) => t.trim() !== "" && t !== e).map((e) => d(l(e)));
26
+ if (r.length === 0) return n;
27
+ let i = (e, t, n) => {
28
+ try {
29
+ return e.decrypt(t, n), !0;
30
+ } catch {
31
+ return !1;
32
+ }
33
+ };
34
+ return {
35
+ encrypt: n.encrypt,
36
+ decrypt: (e, t) => {
37
+ try {
38
+ return n.decrypt(e, t);
39
+ } catch (n) {
40
+ for (let n of r) try {
41
+ return n.decrypt(e, t);
42
+ } catch {}
43
+ throw n;
44
+ }
45
+ },
46
+ sealedWithPreviousKey: (e, t) => !i(n, e, t) && r.some((n) => i(n, e, t))
47
+ };
48
+ }, p, m = (e) => {
49
+ p = e;
50
+ }, h = () => p, g = "no field cipher registered — set VOLTRO_FIELD_ENCRYPTION_KEY (`voltro secret generate field-encryption`; `voltro dev` mints one), or call setFieldCipher.", _ = (e, t) => {
51
+ let n = h();
52
+ if (!n) throw Error(`encryptField: ${g}`);
53
+ return r(n, e, t);
54
+ }, v = (e, t) => {
55
+ if (!i(e)) return e;
56
+ let r = h();
57
+ if (!r) throw Error(`decryptField: ${g}`);
58
+ return n(r, e, void 0, t);
59
+ };
60
+ //#endregion
61
+ export { v as decryptField, l as deriveKey, _ as encryptField, h as getFieldCipher, d as makeAesCipher, f as makeFieldCipher, m as setFieldCipher };
@@ -0,0 +1,21 @@
1
+ import { createHash as e } from "node:crypto";
2
+ //#region src/fingerprint.ts
3
+ var t = (e) => {
4
+ if (e == null) return null;
5
+ if (Array.isArray(e)) return e.map(t);
6
+ if (typeof e == "object") {
7
+ let n = e, r = Object.keys(n).sort(), i = {};
8
+ for (let e of r) i[e] = t(n[e]);
9
+ return i;
10
+ }
11
+ return e;
12
+ }, n = (n, r, i) => {
13
+ let a = t({
14
+ table: n,
15
+ predicate: r,
16
+ indexHint: i ?? null
17
+ });
18
+ return e("sha256").update(JSON.stringify(a)).digest("hex").slice(0, 16);
19
+ };
20
+ //#endregion
21
+ export { t as canonicalize, n as fingerprintFor };
package/dist/finops.js ADDED
@@ -0,0 +1,42 @@
1
+ import { Context as e, Effect as t } from "effect";
2
+ //#region src/finops.ts
3
+ var n = /* @__PURE__ */ new Set([
4
+ "info",
5
+ "warn",
6
+ "critical"
7
+ ]), r = /* @__PURE__ */ new Set(["observe", "suspend"]), i = (e, t) => /* @__PURE__ */ Error(`defineCostBudget(${JSON.stringify(e)}): ${t}`), a = (e) => {
8
+ let t = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/.exec(e.trim());
9
+ if (t === null) return null;
10
+ let n = Number(t[1]);
11
+ if (!(Number.isFinite(n) && n > 0)) return null;
12
+ let r = t[2];
13
+ return n * (r === "ms" ? 1 : r === "s" ? 1e3 : r === "m" ? 6e4 : r === "h" ? 36e5 : 864e5);
14
+ }, o = (e) => {
15
+ let t = e.name;
16
+ if (typeof t != "string" || t.length === 0) throw Error("defineCostBudget: a non-empty `name` is required");
17
+ if (!(typeof e.limit == "number" && Number.isFinite(e.limit) && e.limit > 0)) throw i(t, "a positive, finite `limit` is required");
18
+ if (e.unit !== void 0 && (typeof e.unit != "string" || e.unit.length === 0)) throw i(t, "unit, when present, must be a non-empty string");
19
+ let o = e.warnAt ?? .8;
20
+ if (!(typeof o == "number" && o >= 0 && o <= 1)) throw i(t, "warnAt, when present, must be in [0, 1]");
21
+ let s = null;
22
+ if (e.window !== void 0 && (s = a(e.window), s === null)) throw i(t, `window must be an interval like '1h' / '24h' (got ${JSON.stringify(e.window)})`);
23
+ let c = e.severity ?? "warn";
24
+ if (!n.has(c)) throw i(t, `severity must be one of info | warn | critical (got ${JSON.stringify(c)})`);
25
+ let l = e.onExceeded ?? "observe";
26
+ if (!r.has(l)) throw i(t, `onExceeded must be observe | suspend (got ${JSON.stringify(e.onExceeded)})`);
27
+ return {
28
+ _voltroCostBudget: !0,
29
+ name: t,
30
+ limit: e.limit,
31
+ unit: e.unit ?? null,
32
+ warnAt: o,
33
+ windowMs: s,
34
+ severity: c,
35
+ onExceeded: l,
36
+ ...e.description === void 0 ? {} : { description: e.description }
37
+ };
38
+ }, s = (e) => typeof e == "object" && !!e && e._voltroCostBudget === !0, c = class extends e.Service()("@voltro/CostRegistry") {}, l = (e, n) => t.gen(function* () {
39
+ return (yield* c).budget(e.name, n);
40
+ });
41
+ //#endregion
42
+ export { c as CostRegistry, o as defineCostBudget, s as isCostBudgetDefinition, l as useCostBudget };
@@ -0,0 +1,216 @@
1
+ //#region src/finopsAccountant.ts
2
+ var e = class {
3
+ total = 0;
4
+ byUnit = /* @__PURE__ */ new Map();
5
+ bySubscription = /* @__PURE__ */ new Map();
6
+ lastUpdatedAt = null;
7
+ add(e, t, n) {
8
+ this.total += t, this.byUnit.set(e.unit, (this.byUnit.get(e.unit) ?? 0) + t);
9
+ let r = e.subscriptionId;
10
+ r != null && r.length > 0 && this.bySubscription.set(r, (this.bySubscription.get(r) ?? 0) + t), this.lastUpdatedAt = e.at ?? n;
11
+ }
12
+ state(e) {
13
+ return {
14
+ tenantId: e,
15
+ total: this.total,
16
+ byUnit: Object.fromEntries(this.byUnit),
17
+ bySubscription: Object.fromEntries(this.bySubscription),
18
+ lastUpdatedAt: this.lastUpdatedAt
19
+ };
20
+ }
21
+ }, t = {
22
+ ok: 0,
23
+ warn: 1,
24
+ exceeded: 2
25
+ }, n = class {
26
+ def;
27
+ tenantId;
28
+ spent = 0;
29
+ windowStart = null;
30
+ status = "ok";
31
+ since = null;
32
+ lastUpdatedAt = null;
33
+ lastCause = null;
34
+ constructor(e, t) {
35
+ this.def = e, this.tenantId = t;
36
+ }
37
+ get warnThreshold() {
38
+ return this.def.warnAt * this.def.limit;
39
+ }
40
+ statusOf(e) {
41
+ return e >= this.def.limit ? "exceeded" : e >= this.warnThreshold ? "warn" : "ok";
42
+ }
43
+ rollWindow(e) {
44
+ if (this.def.windowMs === null) return null;
45
+ if (this.windowStart === null) return this.windowStart = e, null;
46
+ let t = e - this.windowStart;
47
+ return t < this.def.windowMs ? null : (this.windowStart = e - t % this.def.windowMs, this.spent = 0, this.settle("ok", e, null));
48
+ }
49
+ settle(e, n, r) {
50
+ let i = this.status;
51
+ return e === i ? null : (this.status = e, this.since = n, t[e] > t[i] ? (this.lastCause = r, {
52
+ kind: e === "exceeded" ? "exceeded" : "warn",
53
+ state: this.state(),
54
+ cause: r
55
+ }) : {
56
+ kind: "recovered",
57
+ state: this.state(),
58
+ cause: null
59
+ });
60
+ }
61
+ apply(e, t, n) {
62
+ let i = [], a = this.rollWindow(n);
63
+ a !== null && i.push(a), this.spent += t, this.lastUpdatedAt = e.at ?? n;
64
+ let o = this.settle(this.statusOf(this.spent), n, r(e));
65
+ return o !== null && i.push(o), i;
66
+ }
67
+ tick(e) {
68
+ return this.rollWindow(e);
69
+ }
70
+ reset(e) {
71
+ return this.spent = 0, this.windowStart = this.def.windowMs === null ? null : e, this.lastUpdatedAt = e, this.settle("ok", e, null);
72
+ }
73
+ state() {
74
+ return {
75
+ budget: this.def.name,
76
+ tenantId: this.tenantId,
77
+ status: this.status,
78
+ severity: this.def.severity,
79
+ onExceeded: this.def.onExceeded,
80
+ spent: this.spent,
81
+ limit: this.def.limit,
82
+ warnThreshold: this.warnThreshold,
83
+ unit: this.def.unit,
84
+ windowStartedAt: this.windowStart,
85
+ since: this.since,
86
+ lastUpdatedAt: this.lastUpdatedAt,
87
+ lastCause: this.lastCause,
88
+ ...this.def.description === void 0 ? {} : { description: this.def.description }
89
+ };
90
+ }
91
+ }, r = (e) => ({
92
+ unit: e.unit,
93
+ subscriptionId: e.subscriptionId ?? null,
94
+ procedure: e.procedure ?? null,
95
+ traceId: e.traceId ?? null
96
+ }), i = (e) => Number.isFinite(e) && e > 0 ? e : 0, a = class {
97
+ now;
98
+ attribution = /* @__PURE__ */ new Map();
99
+ counters = /* @__PURE__ */ new Map();
100
+ budgetsByName = /* @__PURE__ */ new Map();
101
+ totalBudgets = [];
102
+ unitBudgets = /* @__PURE__ */ new Map();
103
+ constructor(e, t = {}) {
104
+ this.now = t.now ?? Date.now;
105
+ for (let t of e) {
106
+ if (this.budgetsByName.has(t.name)) throw Error(`cost budget: duplicate name '${t.name}' — names must be unique across all cost budgets`);
107
+ if (this.budgetsByName.set(t.name, t), this.counters.set(t.name, /* @__PURE__ */ new Map()), t.unit === null) this.totalBudgets.push(t);
108
+ else {
109
+ let e = this.unitBudgets.get(t.unit) ?? [];
110
+ e.push(t), this.unitBudgets.set(t.unit, e);
111
+ }
112
+ }
113
+ }
114
+ counterFor(e, t) {
115
+ let r = this.counters.get(e.name), i = r.get(t);
116
+ return i === void 0 && (i = new n(e, t), r.set(t, i)), i;
117
+ }
118
+ record(t) {
119
+ let n = i(t.amount);
120
+ if (n === 0) return [];
121
+ let r = t.at ?? this.now(), a = this.attribution.get(t.tenantId);
122
+ a === void 0 && (a = new e(), this.attribution.set(t.tenantId, a)), a.add(t, n, r);
123
+ let o = this.unitBudgets.get(t.unit);
124
+ if (this.totalBudgets.length === 0 && o === void 0) return [];
125
+ let s = [];
126
+ for (let e of this.totalBudgets) s.push(...this.counterFor(e, t.tenantId).apply(t, n, r));
127
+ if (o !== void 0) for (let e of o) s.push(...this.counterFor(e, t.tenantId).apply(t, n, r));
128
+ return s;
129
+ }
130
+ tick() {
131
+ let e = this.now(), t = [];
132
+ for (let n of this.budgetsByName.values()) if (n.windowMs !== null) for (let r of this.counters.get(n.name).values()) {
133
+ let n = r.tick(e);
134
+ n !== null && t.push(n);
135
+ }
136
+ return t;
137
+ }
138
+ reset(e) {
139
+ let t = this.now(), n = [], r = (e) => {
140
+ this.attribution.delete(e);
141
+ for (let r of this.counters.values()) {
142
+ let i = r.get(e);
143
+ if (i !== void 0) {
144
+ let e = i.reset(t);
145
+ e !== null && n.push(e);
146
+ }
147
+ }
148
+ };
149
+ if (e === void 0) for (let e of /* @__PURE__ */ new Set([...this.attribution.keys(), ...this.allCounterTenants()])) r(e);
150
+ else r(e);
151
+ return n;
152
+ }
153
+ allCounterTenants() {
154
+ let e = /* @__PURE__ */ new Set();
155
+ for (let t of this.counters.values()) for (let n of t.keys()) e.add(n);
156
+ return e;
157
+ }
158
+ attributionSnapshot() {
159
+ let e = Array(this.attribution.size), t = 0;
160
+ return this.attribution.forEach((n, r) => {
161
+ e[t++] = n.state(r);
162
+ }), e;
163
+ }
164
+ tenantState(e) {
165
+ return this.attribution.get(e)?.state(e) ?? null;
166
+ }
167
+ budgetStates() {
168
+ let e = [];
169
+ for (let t of this.counters.values()) for (let n of t.values()) e.push(n.state());
170
+ return e;
171
+ }
172
+ budgetState(e, t) {
173
+ return this.counters.get(e)?.get(t)?.state() ?? null;
174
+ }
175
+ breaches() {
176
+ return this.budgetStates().filter((e) => e.status !== "ok");
177
+ }
178
+ }, o = (e) => {
179
+ let t = e.now ?? Date.now, n = e.log, r = /* @__PURE__ */ new Set(), i = e.discovered.map((e) => e.definition), o = new a(i, {
180
+ now: t,
181
+ ...n === void 0 ? {} : { log: n }
182
+ }), s = i.some((e) => e.windowMs !== null), c = (e) => {
183
+ for (let t of e) for (let e of r) try {
184
+ e(t);
185
+ } catch (e) {
186
+ n.warn("finops: budget signal listener threw", { budget: t.state.budget }, e);
187
+ }
188
+ }, l = (e) => {
189
+ try {
190
+ c(o.record(e));
191
+ } catch (t) {
192
+ n.warn("finops: cost record failed", { unit: e.unit }, t);
193
+ }
194
+ }, u = () => {
195
+ s && c(o.tick());
196
+ }, d = null;
197
+ return s && (d = setInterval(u, e.tickIntervalMs ?? 3e4), d.unref?.()), {
198
+ registry: {
199
+ attribution: () => o.attributionSnapshot(),
200
+ tenant: (e) => o.tenantState(e),
201
+ budgets: () => o.budgetStates(),
202
+ budget: (e, t) => o.budgetState(e, t),
203
+ breaches: () => o.breaches(),
204
+ subscribe: (e) => (r.add(e), () => r.delete(e))
205
+ },
206
+ record: l,
207
+ reset: (e) => c(o.reset(e)),
208
+ detach: () => {
209
+ d !== null && clearInterval(d), r.clear();
210
+ },
211
+ registered: i.map((e) => e.name),
212
+ runTick: u
213
+ };
214
+ };
215
+ //#endregion
216
+ export { a as CostAccountant, o as attachFinops };
@@ -0,0 +1,8 @@
1
+ import { Effect as e } from "effect";
2
+ //#region src/handlerBody.ts
3
+ function t(t, n) {
4
+ if (e.isEffect(t)) return n ? n(t) : e.runPromise(t);
5
+ if (t instanceof Promise) return t;
6
+ }
7
+ //#endregion
8
+ export { t as settleHandlerBody };
@@ -0,0 +1,55 @@
1
+ //#region src/healthProbes.ts
2
+ var e = "/internal", t = (t, n) => ({
3
+ path: (t?.path ?? e).replace(/\/+$/, "") || e,
4
+ liveness: t?.liveness ?? (() => !0),
5
+ readiness: t?.readiness ?? n
6
+ }), n = (e, t) => {
7
+ if (!t.startsWith(`${e.path}/`)) return;
8
+ let n = t.slice(e.path.length + 1);
9
+ return n === "liveness" || n === "readiness" || n === "startup" ? n : void 0;
10
+ }, r = async (e, t, n) => {
11
+ if (t === "liveness") try {
12
+ return await e.liveness() ? {
13
+ status: 200,
14
+ body: "ok",
15
+ contentType: "text/plain"
16
+ } : {
17
+ status: 503,
18
+ body: "not-live",
19
+ contentType: "text/plain"
20
+ };
21
+ } catch {
22
+ return {
23
+ status: 503,
24
+ body: "not-live",
25
+ contentType: "text/plain"
26
+ };
27
+ }
28
+ if (t === "startup" && n !== void 0) {
29
+ let e = n();
30
+ return {
31
+ status: e.ready ? 200 : 503,
32
+ body: JSON.stringify(e),
33
+ contentType: "application/json"
34
+ };
35
+ }
36
+ try {
37
+ return await e.readiness() ? {
38
+ status: 200,
39
+ body: "ready",
40
+ contentType: "text/plain"
41
+ } : {
42
+ status: 503,
43
+ body: "not-ready",
44
+ contentType: "text/plain"
45
+ };
46
+ } catch {
47
+ return {
48
+ status: 503,
49
+ body: "not-ready",
50
+ contentType: "text/plain"
51
+ };
52
+ }
53
+ };
54
+ //#endregion
55
+ export { r as answerProbe, n as probeFor, t as resolveHealth };
@@ -0,0 +1,49 @@
1
+ import { Effect as e, Layer as t } from "effect";
2
+ import { HttpClient as n, HttpClientError as r } from "effect/http";
3
+ //#region src/httpClientSsrf.ts
4
+ var i = class extends Error {
5
+ url;
6
+ reason;
7
+ _tag = "SsrfBlockedError";
8
+ constructor(e, t) {
9
+ super(`SSRF: blocked outbound request to ${e} — ${t}. If this target is intentional, add its host to \`http.allowHosts\` in app.config.ts.`), this.url = e, this.reason = t, this.name = "SsrfBlockedError";
10
+ }
11
+ }, a = (e, t) => e === 0 || e === 10 || e === 127 || e === 100 && t >= 64 && t <= 127 || e === 169 && t === 254 || e === 172 && t >= 16 && t <= 31 || e === 192 && t === 168 || e === 198 && (t === 18 || t === 19) || e >= 224, o = (e) => e === "::" || e === "::1" || e.startsWith("fc") || e.startsWith("fd") || e.startsWith("fe80") || e.startsWith("::ffff:"), s = (e, t, n) => n.some((n) => {
12
+ let r = n.trim().toLowerCase();
13
+ if (r === "") return !1;
14
+ let i = t === "" ? e : `${e}:${t}`;
15
+ return r === e || r === i ? !0 : r.startsWith("*.") ? e.endsWith(r.slice(1)) : !1;
16
+ }), c = (e, t = {}) => {
17
+ let n;
18
+ try {
19
+ n = new URL(e);
20
+ } catch {
21
+ return "malformed url";
22
+ }
23
+ if (n.protocol !== "http:" && n.protocol !== "https:") return `blocked scheme "${n.protocol}"`;
24
+ let r = n.hostname.replace(/^\[|\]$/g, "").toLowerCase();
25
+ if (s(r, n.port, t.allowHosts ?? [])) return null;
26
+ if (r === "localhost" || r.endsWith(".localhost") || r.endsWith(".internal") || r.endsWith(".local")) return `blocked host "${r}"`;
27
+ let i = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(r);
28
+ if (i) {
29
+ let e = Number(i[1]), t = Number(i[2]);
30
+ return e > 255 || t > 255 || Number(i[3]) > 255 || Number(i[4]) > 255 ? "malformed ipv4 literal" : a(e, t) ? `blocked private/reserved address ${r}` : null;
31
+ }
32
+ if (r.includes(":")) {
33
+ let e = /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.exec(r);
34
+ return e ? c(`${n.protocol}//${e[1]}`, t) : o(r) ? `blocked private/reserved address ${r}` : null;
35
+ }
36
+ return null;
37
+ }, l = (a = {}) => t.effect(n.HttpClient, e.map(n.HttpClient, (t) => {
38
+ let o = n.transform(t, (t, n) => e.suspend(() => {
39
+ let o = c(n.url, a);
40
+ return o === null ? t : e.fail(new r.HttpClientError({ reason: new r.TransportError({
41
+ request: n,
42
+ cause: new i(n.url, o),
43
+ description: `SSRF policy: ${o}`
44
+ }) }));
45
+ }));
46
+ return n.followRedirects(o, a.maxRedirects ?? 5);
47
+ }));
48
+ //#endregion
49
+ export { i as SsrfBlockedError, l as ssrfGuardHttpClientLayer, c as ssrfReason };
@@ -0,0 +1,11 @@
1
+ import { formatTraceparent as e } from "./traceparent.js";
2
+ import { Effect as t, Layer as n } from "effect";
3
+ import { HttpClient as r, HttpClientRequest as i } from "effect/http";
4
+ //#region src/httpClientTracing.ts
5
+ var a = n.effect(r.HttpClient, t.map(r.HttpClient, (n) => n.pipe(r.mapRequestEffect((n) => t.currentSpan.pipe(t.map((t) => n.headers.traceparent === void 0 ? i.setHeader(n, "traceparent", e({
6
+ traceId: t.traceId,
7
+ spanId: t.spanId,
8
+ sampled: t.sampled
9
+ })) : n), t.catch(() => t.succeed(n)))))));
10
+ //#endregion
11
+ export { a as tracingHttpClientLayer };
@@ -0,0 +1,76 @@
1
+ import { brotliCompressSync as e, constants as t, gzipSync as n } from "node:zlib";
2
+ //#region src/httpCompression.ts
3
+ var r = 1024, i = [
4
+ "text/",
5
+ "application/json",
6
+ "application/javascript",
7
+ "application/xml",
8
+ "image/svg+xml",
9
+ "application/rss+xml"
10
+ ], a = (e) => {
11
+ if (e === void 0) return !1;
12
+ let t = e.split(";")[0].trim().toLowerCase();
13
+ return i.some((e) => t === e || t.startsWith(e));
14
+ }, o = (e) => {
15
+ if (e === void 0 || e === "") return;
16
+ let t = /* @__PURE__ */ new Map();
17
+ for (let n of e.split(",")) {
18
+ let [e, ...r] = n.trim().split(";");
19
+ if (e === void 0 || e === "") continue;
20
+ let i = 1;
21
+ for (let e of r) {
22
+ let [t, n] = e.trim().split("=");
23
+ t === "q" && n !== void 0 && (i = Number(n));
24
+ }
25
+ t.set(e.trim().toLowerCase(), Number.isFinite(i) ? i : 1);
26
+ }
27
+ let n = (e) => {
28
+ let n = t.get(e);
29
+ if (n !== void 0) return n > 0;
30
+ let r = t.get("*");
31
+ return r !== void 0 && r > 0;
32
+ };
33
+ if (n("br")) return "br";
34
+ if (n("gzip")) return "gzip";
35
+ }, s = (r, i) => i === "br" ? new Uint8Array(e(r, { params: {
36
+ [t.BROTLI_PARAM_QUALITY]: 4,
37
+ [t.BROTLI_PARAM_SIZE_HINT]: r.length
38
+ } })) : new Uint8Array(n(r, { level: 6 })), c = (e) => {
39
+ let t = e.options?.enabled ?? !0, n = e.options?.minBytes ?? 1024, r = a(e.contentType), i = r ? { vary: "Accept-Encoding" } : {};
40
+ if (!t || !r || e.body.length < n) return {
41
+ bytes: e.body,
42
+ headers: i,
43
+ compressed: !1
44
+ };
45
+ let c = o(e.acceptEncoding);
46
+ if (c === void 0) return {
47
+ bytes: e.body,
48
+ headers: i,
49
+ compressed: !1
50
+ };
51
+ let l = s(e.body, c);
52
+ return l.length >= e.body.length ? {
53
+ bytes: e.body,
54
+ headers: i,
55
+ compressed: !1
56
+ } : {
57
+ bytes: l,
58
+ headers: {
59
+ ...i,
60
+ "content-encoding": c
61
+ },
62
+ compressed: !0
63
+ };
64
+ }, l = (e, t) => {
65
+ let n = {}, r = [], i = (e) => {
66
+ for (let t of String(e).split(",")) {
67
+ let e = t.trim();
68
+ e !== "" && !r.some((t) => t.toLowerCase() === e.toLowerCase()) && r.push(e);
69
+ }
70
+ };
71
+ for (let [t, r] of Object.entries(e)) t.toLowerCase() === "vary" ? i(Array.isArray(r) ? r.join(",") : r) : n[t] = r;
72
+ for (let [e, r] of Object.entries(t)) e.toLowerCase() === "vary" ? i(r) : n[e] = r;
73
+ return r.length > 0 && (n.vary = r.join(", ")), n;
74
+ };
75
+ //#endregion
76
+ export { r as DEFAULT_COMPRESSION_MIN_BYTES, a as isCompressibleContentType, c as maybeCompress, l as mergeCompressionHeaders, o as negotiateEncoding };
@@ -0,0 +1,12 @@
1
+ //#region src/httpKeepAlive.ts
2
+ var e = 72e3, t = 5e3, n = (e) => typeof e == "number" && Number.isFinite(e) && e > 0 ? Math.floor(e) : void 0, r = (e) => {
3
+ let r = n(e?.http?.keepAliveTimeoutMs) ?? 72e3, i = n(e?.http?.headersTimeoutMs);
4
+ return {
5
+ keepAliveTimeoutMs: r,
6
+ headersTimeoutMs: i !== void 0 && i > r ? i : r + t
7
+ };
8
+ }, i = (e, t) => {
9
+ e.keepAliveTimeout = t.keepAliveTimeoutMs, e.headersTimeout = t.headersTimeoutMs;
10
+ };
11
+ //#endregion
12
+ export { e as DEFAULT_KEEP_ALIVE_MS, t as HEADERS_TIMEOUT_MARGIN_MS, i as applyKeepAlive, r as resolveKeepAlive };
@@ -0,0 +1,47 @@
1
+ import { FindMyWay as e } from "effect/http";
2
+ import { routeAcceptsPath as t } from "@voltro/protocol/rest";
3
+ //#region src/httpRouteMounts.ts
4
+ var n = (e) => e.split("/").map((e) => e.startsWith(":") ? ":param" : e).join("/"), r = (e) => {
5
+ if (e.some((e) => e.method === "*")) return ["*"];
6
+ let t = /* @__PURE__ */ new Set();
7
+ for (let n of e) t.add(n.method === "HEAD" ? "GET" : n.method);
8
+ return [...t];
9
+ }, i = (e) => {
10
+ let t = /* @__PURE__ */ new Map();
11
+ for (let r of e) {
12
+ let e = n(r.path), i = t.get(e);
13
+ i ? i.push(r) : t.set(e, [r]);
14
+ }
15
+ let i = [];
16
+ t.forEach((e, t) => {
17
+ i.push({
18
+ mountPath: t,
19
+ routes: e,
20
+ methods: r(e)
21
+ });
22
+ });
23
+ let a = /* @__PURE__ */ new Set();
24
+ for (let e of i) e.methods.includes("*") && e.routes.some((e) => e.method === "*" && e.match !== "exact") && a.add(e.mountPath);
25
+ let o = (e) => {
26
+ if (e !== "/" && a.has("/")) return !0;
27
+ for (let t = e.indexOf("/"); t !== -1; t = e.indexOf("/", t + 1)) if (a.has(e.slice(0, t))) return !0;
28
+ return !1;
29
+ };
30
+ for (let e = 0; e < i.length; e++) {
31
+ let t = i[e];
32
+ !t.methods.includes("*") && o(t.mountPath) && (i[e] = {
33
+ ...t,
34
+ methods: ["*"]
35
+ });
36
+ }
37
+ return i;
38
+ }, a = (n) => {
39
+ let r = e.make(), i = /* @__PURE__ */ new Set();
40
+ for (let e of n) for (let t of [e.mountPath, `${e.mountPath}/*`]) i.has(t.toLowerCase()) || (i.add(t.toLowerCase()), r.on("GET", t, e));
41
+ return (e) => {
42
+ let n = r.find("GET", e)?.handler;
43
+ return n !== void 0 && n.routes.some((n) => t(n, e)) ? n : void 0;
44
+ };
45
+ }, o = (e) => a(e.filter((e) => !e.methods.includes("*") && (e.routes.length > 1 || e.routes[0]?.answersOtherMethods === !0)));
46
+ //#endregion
47
+ export { a as makeHttpRouteGroupFinder, o as makeUnmatchedGroupFinder, i as planHttpRouteMounts };
@@ -0,0 +1,70 @@
1
+ import { and as e, eq as t, generateId as n, lte as r } from "@voltro/database";
2
+ import { freshFor as i, tsMs as a } from "@voltro/protocol";
3
+ //#region src/idempotencyStore.ts
4
+ var o = "_voltro_idempotency", s = (e) => {
5
+ if (e == null) return null;
6
+ let t = typeof e == "string" ? JSON.parse(e) : e;
7
+ return t && typeof t == "object" && "status" in t ? t : null;
8
+ }, c = (e) => ({
9
+ scope: e.scope,
10
+ key: e.key,
11
+ status: e.status === "completed" ? "completed" : "in_flight",
12
+ response: s(e.response),
13
+ createdAt: a(e.createdAt)
14
+ }), l = async (n, r, i) => (await n.query({
15
+ table: o,
16
+ predicate: e(t("scope", r), t("key", i)),
17
+ order: [],
18
+ take: 1,
19
+ skip: void 0,
20
+ projection: void 0
21
+ }))[0] ?? null, u = (a) => ({
22
+ get: async (e, t) => {
23
+ let n = await l(a, e, t);
24
+ return n ? c(n) : null;
25
+ },
26
+ claim: async (s, u, d, f, p) => {
27
+ for (let l = 0; l < 2; l++) {
28
+ let l = n({
29
+ kind: "typeid",
30
+ prefix: "idem"
31
+ }, o), m = await a.insertIgnore(o, {
32
+ id: l,
33
+ scope: s,
34
+ key: u,
35
+ status: "in_flight",
36
+ response: null,
37
+ createdAt: new Date(d)
38
+ }, { conflictColumns: ["scope", "key"] });
39
+ if (m.id === l) return "claimed";
40
+ let h = c(m), g = i(h.status, f, p);
41
+ if (d - h.createdAt < g) return h;
42
+ await a.deleteMany(o, { where: e(t("id", m.id), r("createdAt", new Date(d - g))) });
43
+ }
44
+ let m = await l(a, s, u);
45
+ return m ? c(m) : {
46
+ scope: s,
47
+ key: u,
48
+ status: "in_flight",
49
+ response: null,
50
+ createdAt: d
51
+ };
52
+ },
53
+ complete: async (e, t, n, r) => {
54
+ let i = await l(a, e, t);
55
+ i && await a.update(o, i.id, {
56
+ status: "completed",
57
+ response: n
58
+ });
59
+ },
60
+ renew: async (e, t, n) => {
61
+ let r = await l(a, e, t);
62
+ r !== null && r.status === "in_flight" && await a.update(o, r.id, { createdAt: new Date(n) });
63
+ },
64
+ release: async (e, t) => {
65
+ let n = await l(a, e, t);
66
+ n && await a.delete(o, n.id);
67
+ }
68
+ });
69
+ //#endregion
70
+ export { u as dataStoreIdempotencyStore };