@voltro/runtime 0.86.0 → 0.88.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 +5484 -0
  2. package/README.md +43 -0
  3. package/THIRD-PARTY-NOTICES.md +1511 -276
  4. package/dist/aggregate.js +1 -2
  5. package/dist/aggregateExtrema.js +1 -2
  6. package/dist/aggregateIvm.js +1 -2
  7. package/dist/analyticsMirror.js +1 -2
  8. package/dist/analyticsSink.js +9 -16
  9. package/dist/apiKeyUsage.js +1 -2
  10. package/dist/apiKeys.js +83 -80
  11. package/dist/apiKeysWiring.js +1 -2
  12. package/dist/apiRoleBucketSampler.js +63 -0
  13. package/dist/apiRoleWorkloadHistory.js +55 -0
  14. package/dist/apiRoleWorkloadMetrics.js +77 -0
  15. package/dist/apiRoleWorkloadStorage.js +94 -0
  16. package/dist/approvalBuiltins.js +1 -2
  17. package/dist/approvals.js +68 -76
  18. package/dist/authMiddlewareLayer.js +8 -8
  19. package/dist/bindEvent.js +49 -30
  20. package/dist/boot-refusal.d.ts +10 -0
  21. package/dist/{bootRefusal.js → boot-refusal.js} +1 -2
  22. package/dist/bootListener.js +203 -47
  23. package/dist/bootStoreCodec.js +39 -39
  24. package/dist/businessRules.js +1 -2
  25. package/dist/changeClaimsTable.js +1 -2
  26. package/dist/circuitBreaker.js +1 -72
  27. package/dist/columnOnUpdate.js +1 -2
  28. package/dist/composeAnalytics.js +32 -12
  29. package/dist/computedQuery.js +1 -2
  30. package/dist/computedQueryCache.js +289 -0
  31. package/dist/connectionBuiltins.js +1 -2
  32. package/dist/connectionCredentials.js +1 -2
  33. package/dist/connectionState.js +1 -2
  34. package/dist/connectionVault.js +1 -2
  35. package/dist/connectionsFacade.js +33 -32
  36. package/dist/coordinatedSchedule.js +85 -80
  37. package/dist/crdtHistory.js +1 -2
  38. package/dist/crdtMerge.js +1 -2
  39. package/dist/crdtVersionsTable.js +1 -2
  40. package/dist/credentialBound.js +1 -2
  41. package/dist/crud.js +1 -2
  42. package/dist/dataStore.js +155 -123
  43. package/dist/dataloader.js +1 -2
  44. package/dist/declaredTablesGuard.js +3 -3
  45. package/dist/defineExecutor.js +1 -2
  46. package/dist/dependencyGraph.js +1 -2
  47. package/dist/devices.js +1 -2
  48. package/dist/devicesWiring.js +1 -2
  49. package/dist/dialectReplicationAdapter.js +1 -2
  50. package/dist/dispatcher.js +404 -330
  51. package/dist/effectStore.js +3 -4
  52. package/dist/engineClients.js +23 -0
  53. package/dist/eventBus.js +1 -2
  54. package/dist/eventPublish.js +1 -2
  55. package/dist/events.js +1 -2
  56. package/dist/expectation.js +1 -2
  57. package/dist/expectationEvaluator.js +2 -3
  58. package/dist/experiment.js +1 -2
  59. package/dist/experimentEvaluator.js +1 -2
  60. package/dist/externalizedTasks.js +20 -8
  61. package/dist/fieldCipher.js +110 -42
  62. package/dist/fieldKeyRegistry.js +294 -0
  63. package/dist/fieldKeyRekey.js +285 -0
  64. package/dist/fieldKeyScan.js +135 -0
  65. package/dist/fieldKeyring.js +76 -0
  66. package/dist/fingerprint.js +1 -2
  67. package/dist/finops.js +1 -2
  68. package/dist/finopsAccountant.js +1 -2
  69. package/dist/handlerBody.js +1 -2
  70. package/dist/healthProbes.js +1 -2
  71. package/dist/hot.d.ts +56 -0
  72. package/dist/hot.js +3 -0
  73. package/dist/hotDataStore.js +147 -0
  74. package/dist/hotDataStoreSnapshot.js +97 -0
  75. package/dist/hotDataStoreTables.js +17 -0
  76. package/dist/http-range.d.ts +53 -0
  77. package/dist/http-range.js +51 -0
  78. package/dist/httpClientSsrf.js +13 -39
  79. package/dist/httpClientTracing.js +13 -11
  80. package/dist/httpCompression.js +18 -19
  81. package/dist/httpInputStream.js +81 -0
  82. package/dist/httpKeepAlive.js +1 -2
  83. package/dist/httpRouteMounts.js +2 -2
  84. package/dist/idempotencyStore.js +93 -54
  85. package/dist/idleDetector.js +1 -2
  86. package/dist/index.d.ts +1185 -452
  87. package/dist/index.js +144 -134
  88. package/dist/insertRequiredColumns.js +1 -2
  89. package/dist/instanceMembership.js +1 -2
  90. package/dist/ivm.js +1 -2
  91. package/dist/kvDataStore.js +1 -2
  92. package/dist/kvFacade.js +24 -19
  93. package/dist/matcher.js +1 -2
  94. package/dist/memoryColumnDefaults.js +1 -2
  95. package/dist/memoryQueryJoins.js +17 -18
  96. package/dist/memorySetOperations.js +42 -0
  97. package/dist/metrics.js +39 -26
  98. package/dist/observability.js +2 -3
  99. package/dist/observedGraph.js +1 -2
  100. package/dist/originGuard.js +1 -2
  101. package/dist/outbox.js +2 -3
  102. package/dist/pluginRefRules.js +1 -2
  103. package/dist/policyGuardResolver.js +1 -2
  104. package/dist/preview.js +1 -2
  105. package/dist/projectedRows.js +1 -2
  106. package/dist/provenance.js +1 -2
  107. package/dist/rangeIndex.js +1 -2
  108. package/dist/rawReadScope.js +2 -3
  109. package/dist/reaction.js +1 -2
  110. package/dist/reactiveConfig.js +1 -2
  111. package/dist/readClassification.js +1 -2
  112. package/dist/readRecorder.js +36 -36
  113. package/dist/readScopePredicate.js +11 -0
  114. package/dist/rebac.js +1 -2
  115. package/dist/rebacInterceptor.js +1 -2
  116. package/dist/registry.js +1 -2
  117. package/dist/relevantFields.js +1 -2
  118. package/dist/replicaHealth.js +1 -2
  119. package/dist/replicaLocality.js +1 -2
  120. package/dist/replicaObservations.js +1 -2
  121. package/dist/replicaSelection.js +1 -2
  122. package/dist/replicatedDataStore.js +23 -6
  123. package/dist/requestLoader.js +1 -2
  124. package/dist/resumeCensus.js +1 -2
  125. package/dist/revalidation.js +1 -2
  126. package/dist/rowFilter.js +57 -41
  127. package/dist/rowStateBytes.js +1 -2
  128. package/dist/rpcBodyCap.js +1 -2
  129. package/dist/rpcConnections.js +9 -10
  130. package/dist/rpcDefectDiagnostics.js +1 -2
  131. package/dist/rpcServer.js +523 -451
  132. package/dist/rpcWorkloadAdmission.js +49 -0
  133. package/dist/runAsSystem.js +1 -2
  134. package/dist/rywPositionStore.js +83 -49
  135. package/dist/schedule.js +1 -2
  136. package/dist/scheduleBackfillRequests.js +1 -2
  137. package/dist/scheduleClaimsTable.js +1 -2
  138. package/dist/scheduleRunsTable.js +1 -2
  139. package/dist/scheduler.js +7 -3
  140. package/dist/schemaRegistry.js +1 -2
  141. package/dist/secretsResolver.js +1 -2
  142. package/dist/securityHeaders.js +1 -2
  143. package/dist/servePipeline.js +238 -154
  144. package/dist/serverOnlyAudit.js +1 -2
  145. package/dist/serverTracer.js +1 -2
  146. package/dist/serviceCredentials.js +1 -2
  147. package/dist/setReadScopes.js +27 -0
  148. package/dist/singleNodeOrchestrator.js +1 -2
  149. package/dist/snapshotValueCodec.js +45 -0
  150. package/dist/sourceResolution.js +35 -26
  151. package/dist/storeMiddleware.js +213 -212
  152. package/dist/storeQuery.js +1 -2
  153. package/dist/storeRead.js +1 -2
  154. package/dist/subscriber.js +2 -2
  155. package/dist/subscriptionOutbox.js +1 -2
  156. package/dist/subscriptionRegistry.js +1 -2
  157. package/dist/subscriptionResume.js +1 -2
  158. package/dist/subscriptionSocketMetrics.js +1 -2
  159. package/dist/systemSubject.js +1 -2
  160. package/dist/tenantScope.js +9 -22
  161. package/dist/tenantSelection.js +1 -2
  162. package/dist/timeline.js +1 -2
  163. package/dist/traceContext.js +1 -2
  164. package/dist/traceSink.js +1 -2
  165. package/dist/traceSpansTable.js +1 -2
  166. package/dist/traceparent.js +9 -21
  167. package/dist/transactionSubject.js +1 -2
  168. package/dist/trustedProxy.js +2 -3
  169. package/dist/undo.js +1 -2
  170. package/dist/undoBuiltins.js +1 -2
  171. package/dist/undoCapture.js +1 -2
  172. package/dist/undoLogTable.js +1 -2
  173. package/dist/upsertBinding.js +1 -2
  174. package/dist/wakeOrchestrator.js +1 -2
  175. package/dist/wakeRegistry.js +1 -2
  176. package/dist/wakeRouter.js +1 -2
  177. package/dist/wakeSupervisor.js +1 -2
  178. package/dist/wakeupsTable.js +1 -2
  179. package/dist/webSocketGatewayRuntime.js +112 -73
  180. package/dist/webhookVerification.js +1 -2
  181. package/dist/wireColumnStrip.js +1 -2
  182. package/dist/workflowReadBuiltins.js +1 -2
  183. package/dist/workflowRuntime.js +10 -11
  184. package/package.json +36 -17
@@ -2,7 +2,7 @@ import { Context as e, Effect as t, Exit as n, Layer as r } from "effect";
2
2
  import { authoredError as i, describeDriverError as a, wireSafeCause as o } from "@voltro/database";
3
3
  import { StoreOperationFailed as s } from "@voltro/protocol";
4
4
  import { createLogger as c } from "@voltro/logger";
5
- //#region src/effectStore.ts
5
+ // src/effectStore.ts
6
6
  var l = c({ scope: "store" }), u = class extends e.Service()("@voltro/EffectStore") {}, d = {
7
7
  TenantScopeViolation: !0,
8
8
  TenantRowNotFound: !0,
@@ -35,7 +35,7 @@ var l = c({ scope: "store" }), u = class extends e.Service()("@voltro/EffectStor
35
35
  }, v = (e) => ({
36
36
  query: ((t) => m("query", t.table, () => e.query(t))),
37
37
  insert: (t, n) => m("insert", t, () => e.insert(t, n)),
38
- insertMany: (t, n) => m("insertMany", t, () => e.insertMany(t, n)),
38
+ insertMany: (t, n, r) => m("insertMany", t, () => e.insertMany(t, n, r)),
39
39
  patchJson: (t, n, r, i, a) => m("patchJson", t, () => e.patchJson(t, n, r, i, a)),
40
40
  update: (t, n, r) => m("update", t, () => e.update(t, n, r)),
41
41
  updateMany: (t, n, r) => m("updateMany", t, () => e.updateMany(t, n, r)),
@@ -66,6 +66,5 @@ var l = c({ scope: "store" }), u = class extends e.Service()("@voltro/EffectStor
66
66
  conflictColumns: e.conflictColumns,
67
67
  ...e.update === void 0 ? {} : { update: e.update },
68
68
  ...e.updateValues === void 0 ? {} : { updateValues: e.updateValues }
69
- }), x = (e, t, n) => e.insert(t.tableName, n), S = (e, t, n) => e.insertMany(t.tableName, n), 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
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 });
71
70
  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,23 @@
1
+ // 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
+ export { i as engineClientsSnapshot, n as parseEngineSdkHeader, r as trackEngineClient };
package/dist/eventBus.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { recordEventDropped as e, recordEventPublished as t, recordEventSubscribers as n } from "./metrics.js";
2
2
  import { eventRoute as r, parseEventRoute as i } from "@voltro/protocol";
3
3
  import { createLogger as a } from "@voltro/logger";
4
- //#region src/eventBus.ts
4
+ // src/eventBus.ts
5
5
  var o = a({ scope: "voltro:events" }), s = 64, c = 3e5, l = 1e4, u = class {
6
6
  routes = /* @__PURE__ */ new Map();
7
7
  origin;
@@ -256,5 +256,4 @@ var o = a({ scope: "voltro:events" }), s = 64, c = 3e5, l = 1e4, u = class {
256
256
  this.routes.clear();
257
257
  }
258
258
  };
259
- //#endregion
260
259
  export { u as EventBus };
@@ -1,6 +1,6 @@
1
1
  import { Context as e, Effect as t, Schema as n } from "effect";
2
2
  import { EventKeyInvalid as r, EventPayloadInvalid as i, EventPayloadTooLarge as a, MAX_EVENT_ENVELOPE_BYTES as o } from "@voltro/protocol";
3
- //#region src/eventPublish.ts
3
+ // src/eventPublish.ts
4
4
  var s = (e) => e instanceof Error ? e.message : String(e), c = (e, c, l, u) => t.gen(function* () {
5
5
  let d = n.encodeEffect(c.key), f = n.encodeEffect(c.payload), p = yield* d(l).pipe(t.mapError((e) => new r({
6
6
  event: c.name,
@@ -45,5 +45,4 @@ var s = (e) => e instanceof Error ? e.message : String(e), c = (e, c, l, u) => t
45
45
  let n;
46
46
  return Object.assign(e, { then: (r, i) => (n ??= t.runPromise(e), n.then(r, i)) });
47
47
  }, d = (e) => ({ publish: (t, n, r) => u(c(e, t, n, r)) });
48
- //#endregion
49
48
  export { l as OutboxEventPublisher, d as makeEventPublisher, c as publishEvent };
package/dist/events.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { boolean as e, eq as t, id as n, json as r, table as i, text as a, timestamp as o } from "@voltro/database";
2
- //#region src/events.ts
2
+ // src/events.ts
3
3
  var s = (e) => {
4
4
  if ("on" in e) {
5
5
  let { on: t, ...n } = e;
@@ -189,5 +189,4 @@ var s = (e) => {
189
189
  };
190
190
  } };
191
191
  };
192
- //#endregion
193
192
  export { m as _voltroWorkflowEventDeliveriesTable, p as _voltroWorkflowEventsTable, c as defineEventTrigger, l as isWorkflowEventTriggerDefinition, h as makeEventsFacade, s as triggerWorkflow };
@@ -1,5 +1,5 @@
1
1
  import { Context as e, Effect as t } from "effect";
2
- //#region src/expectation.ts
2
+ // src/expectation.ts
3
3
  var n = /* @__PURE__ */ new Set([
4
4
  "info",
5
5
  "warn",
@@ -48,5 +48,4 @@ var n = /* @__PURE__ */ new Set([
48
48
  }, a = (e) => typeof e == "object" && !!e && e._voltroExpectation === !0, o = class extends e.Service()("@voltro/ExpectationRegistry") {}, s = (e) => t.gen(function* () {
49
49
  return (yield* o).get(e.name);
50
50
  });
51
- //#endregion
52
51
  export { o as ExpectationRegistry, i as defineExpectation, a as isExpectationDefinition, s as useExpectation };
@@ -1,6 +1,6 @@
1
1
  import { AggregateMaintainer as e } from "./aggregateIvm.js";
2
2
  import { collectProjectedRows as t } from "./projectedRows.js";
3
- //#region src/expectationEvaluator.ts
3
+ // src/expectationEvaluator.ts
4
4
  var n = (e) => {
5
5
  if (e instanceof Date) return e.getTime();
6
6
  if (typeof e == "number" && Number.isFinite(e)) return e;
@@ -287,7 +287,7 @@ var n = (e) => {
287
287
  let t = e ? [] : Array(i.size), n = 0;
288
288
  return i.forEach((r) => {
289
289
  let i = r.state();
290
- (!e || i.status === "violated") && (t[n++] = i);
290
+ e && i.status !== "violated" || (t[n++] = i);
291
291
  }), t;
292
292
  };
293
293
  return {
@@ -304,5 +304,4 @@ var n = (e) => {
304
304
  runTick: d
305
305
  };
306
306
  };
307
- //#endregion
308
307
  export { u as ExpectationEvaluator, d as attachExpectations };
@@ -1,5 +1,5 @@
1
1
  import { Context as e, Effect as t } from "effect";
2
- //#region src/experiment.ts
2
+ // src/experiment.ts
3
3
  var n = "holdout", r = (e, t) => /* @__PURE__ */ Error(`defineExperiment(${JSON.stringify(e)}): ${t}`), i = (e) => {
4
4
  if (e == null) return null;
5
5
  if (typeof e == "number") return Number.isFinite(e) ? String(e) : null;
@@ -92,5 +92,4 @@ var n = "holdout", r = (e, t) => /* @__PURE__ */ Error(`defineExperiment(${JSON.
92
92
  }, l = (e) => e.holdout > 0 ? [...e.variants.map((e) => e.name), n] : e.variants.map((e) => e.name), u = class extends e.Service()("@voltro/ExperimentRegistry") {}, d = (e) => t.gen(function* () {
93
93
  return (yield* u).get(e.name);
94
94
  });
95
- //#endregion
96
95
  export { u as ExperimentRegistry, n as HOLDOUT_VARIANT, c as assignVariant, a as defineExperiment, s as hashUnitInterval, o as isExperimentDefinition, l as resultVariantNames, d as useExperiment };
@@ -1,7 +1,7 @@
1
1
  import { AggregateMaintainer as e } from "./aggregateIvm.js";
2
2
  import { collectProjectedRows as t } from "./projectedRows.js";
3
3
  import { assignVariant as n, resultVariantNames as r } from "./experiment.js";
4
- //#region src/experimentEvaluator.ts
4
+ // src/experimentEvaluator.ts
5
5
  var i = "__voltro_variant", a = "__voltro_metric", o = class {
6
6
  project;
7
7
  maintainer;
@@ -241,5 +241,4 @@ var i = "__voltro_variant", a = "__voltro_metric", o = class {
241
241
  registered: [...i.keys()]
242
242
  };
243
243
  };
244
- //#endregion
245
244
  export { f as ExperimentEvaluator, p as attachExperiments };
@@ -1,4 +1,4 @@
1
- //#region src/externalizedTasks.ts
1
+ // src/externalizedTasks.ts
2
2
  var e = 6e4, t = (e) => {
3
3
  if (!Number.isFinite(e) || e < 6e4 || e % 6e4 != 0) return;
4
4
  let t = e / 6e4;
@@ -16,10 +16,22 @@ var e = 6e4, t = (e) => {
16
16
  if (t !== void 0) return t;
17
17
  let n = /* @__PURE__ */ new Map();
18
18
  return e[r] = n, n;
19
- }, a = (e) => {
20
- i().set(e.name, e);
21
- }, o = (e) => {
22
- i().delete(e);
23
- }, s = (e) => i().get(e), c = () => [...i().keys()].sort();
24
- //#endregion
25
- export { e as MIN_EXTERNALIZABLE_INTERVAL_MS, t as cronForInterval, n as externalizationRefusal, s as externalizedTask, c as externalizedTaskNames, a as registerExternalizedTask, o as unregisterExternalizedTask };
19
+ }, a = (e) => Object.freeze({
20
+ register: (t) => {
21
+ let n = Object.freeze({
22
+ name: t.name,
23
+ intervalMs: t.intervalMs,
24
+ cron: t.cron,
25
+ run: t.run
26
+ });
27
+ if (e.has(n.name)) throw Error("Externalized task name is already registered: " + n.name);
28
+ e.set(n.name, n);
29
+ let r = !1;
30
+ return () => {
31
+ r || (r = !0, e.get(n.name) === n && e.delete(n.name));
32
+ };
33
+ },
34
+ get: (t) => e.get(t),
35
+ names: () => [...e.keys()].sort()
36
+ }), o = () => a(/* @__PURE__ */ new Map()), s = (e) => a(i()).register(e), c = (e) => i().get(e), l = () => [...i().keys()].sort();
37
+ export { e as MIN_EXTERNALIZABLE_INTERVAL_MS, t as cronForInterval, n as externalizationRefusal, c as externalizedTask, l as externalizedTaskNames, o as makeExternalizedTaskRegistry, s as registerExternalizedTask };
@@ -1,61 +1,129 @@
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) => {
1
+ import { recordFieldDecrypt as e } from "./metrics.js";
2
+ import { BOUND_ENCRYPTED_PREFIX as t, ENCRYPTED_PREFIX as n, FIELD_KEY_ID_PATTERN as r, ciphertextKeyId as i, decodeFieldValue as a, encodeFieldValue as o, isEncrypted as s } from "@voltro/database";
3
+ import { createCipheriv as c, createDecipheriv as l, createHmac as u, randomBytes as d, scryptSync as f } from "node:crypto";
4
+ // src/fieldCipher.ts
5
+ var p = (e) => /^[0-9a-f]{64}$/i.test(e) ? Buffer.from(e, "hex") : f(e, "voltro:field-encryption:v1", 32), m = (e, t) => {
5
6
  let n = e === "r" ? t?.row : e === "c" ? t?.column : void 0;
6
7
  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
8
  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}`);
9
+ }, h = (e, i) => {
10
+ if (e.length !== 32) throw Error(`field cipher key must be 32 bytes, got ${e.length}`);
11
+ if (i !== void 0 && !r.test(i)) throw Error(`field cipher: "${i}" is not a key id (a short lowercase slug)`);
12
+ let a = i === void 0 ? "" : `:${i}`;
10
13
  return {
11
14
  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}`;
15
+ let o = d(12), s = c("aes-256-gcm", e, o), l = i === void 0 ? void 0 : i.row === void 0 ? "c" : "r";
16
+ l !== void 0 && s.setAAD(m(l, i));
17
+ let u = Buffer.concat([s.update(r, "utf8"), s.final()]), f = s.getAuthTag(), p = `${o.toString("base64")}:${f.toString("base64")}:${u.toString("base64")}`;
18
+ return l === void 0 ? `${n}${p}${a}` : `${t}${l}:${p}${a}`;
16
19
  },
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");
20
+ decrypt: (i, a) => {
21
+ let o = i.startsWith(t), s = i.slice(o ? t.length : n.length).split(":"), c = o ? s.shift() ?? "" : void 0, [u, d, f, ...p] = s;
22
+ if (!u || !d || f === void 0 || p.length > 1 || p.length === 1 && !r.test(p[0])) throw Error("field cipher: malformed ciphertext");
23
+ let h = l("aes-256-gcm", e, Buffer.from(u, "base64"));
24
+ return c !== void 0 && h.setAAD(m(c, a)), h.setAuthTag(Buffer.from(d, "base64")), Buffer.concat([h.update(Buffer.from(f, "base64")), h.final()]).toString("utf8");
22
25
  }
23
26
  };
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) => {
27
+ }, g = (e) => `k${u("sha256", p(e)).update("voltro:field-key-id:v1").digest("hex").slice(0, 10)}`, _ = class extends Error {
28
+ _tag = "FieldKeyringConfigError";
29
+ constructor(e) {
30
+ super(e), this.name = "FieldKeyringConfigError";
31
+ }
32
+ }, v = (e) => e !== void 0 && typeof e.sealWith == "function" && typeof e.activate == "function", y = (t, n = {}) => {
33
+ let a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
34
+ for (let e of t.keys) {
35
+ if (!r.test(e.id)) throw new _(`field encryption: "${e.id}" is not a key id — use a short lowercase slug (letters, digits, "-", at most 16)`);
36
+ if (e.secret.trim() === "") throw new _(`field encryption: key "${e.id}" is empty`);
37
+ if (a.has(e.id)) throw new _(`field encryption: key id "${e.id}" is configured twice`);
38
+ let t = p(e.secret).toString("hex"), n = o.get(t);
39
+ if (n !== void 0) throw new _(`field encryption: keys "${n}" and "${e.id}" are the same key — a rotation needs a NEW key, and two ids for one key make every count per key wrong`);
40
+ a.set(e.id, e.secret), o.set(t, e.id);
41
+ }
42
+ if (!a.has(t.active)) throw new _(`field encryption: the active key "${t.active}" is not one of the configured keys (${[...a.keys()].join(", ") || "none"})`);
43
+ let s = new Map([...a].map(([e, t]) => [e, h(p(t), e)])), c = t.active, l = n.sealOnlyOnceActivated !== !0, u = [], d = () => {
44
+ u = [[c, s.get(c)], ...[...s].filter(([e]) => e !== c)];
45
+ };
46
+ d();
47
+ let f = (e, t, n) => {
28
48
  try {
29
49
  return e.decrypt(t, n), !0;
30
50
  } catch {
31
51
  return !1;
32
52
  }
53
+ }, m = (e, t) => {
54
+ let n = i(e), r = n === void 0 ? void 0 : s.get(n);
55
+ return r !== void 0 && f(r, e, t) ? n : u.find(([, n]) => n !== r && f(n, e, t))?.[0];
33
56
  };
34
57
  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;
58
+ get activeKeyId() {
59
+ return c;
60
+ },
61
+ requestedKeyId: t.active,
62
+ keyIds: u.map(([e]) => e),
63
+ fingerprints: Object.freeze(Object.fromEntries([...a].map(([e, t]) => [e, g(t)]))),
64
+ encrypt: (e, t) => {
65
+ if (!l) throw Error("field cipher: nothing may be sealed before the boot has checked the keys against the database (verifyFieldKeyring decides which key is active) — a write reached an .encrypted() column during boot, before that check");
66
+ return s.get(c).encrypt(e, t);
67
+ },
68
+ sealWith: (e, t, n) => {
69
+ let r = s.get(e);
70
+ if (r === void 0) throw Error(`field cipher: this keyring does not hold key "${e}"`);
71
+ return r.encrypt(t, n);
72
+ },
73
+ opensWith: (e, t, n) => {
74
+ let r = s.get(e);
75
+ return r !== void 0 && f(r, t, n);
76
+ },
77
+ activate: (e) => {
78
+ if (!s.has(e)) throw Error(`field cipher: cannot activate key "${e}", which this keyring does not hold`);
79
+ c = e, l = !0, d();
80
+ },
81
+ decrypt: (t, n) => {
82
+ let r = i(t), a = r === void 0 ? void 0 : s.get(r), o = n?.column ?? "unbound";
83
+ if (r !== void 0 && a === void 0 && u.every(([, e]) => !f(e, t, n))) throw e(r, o, "failed"), Error(`field cipher: the value is sealed under key "${r}", which this keyring does not hold (it holds ${u.map(([e]) => e).join(", ")})`);
84
+ let c;
85
+ if (a !== void 0) try {
86
+ let i = a.decrypt(t, n);
87
+ return e(r, o, "ok"), i;
88
+ } catch (e) {
89
+ c = e;
44
90
  }
91
+ for (let [r, i] of u) if (i !== a) try {
92
+ let a = i.decrypt(t, n);
93
+ return e(r, o, "ok"), a;
94
+ } catch (e) {
95
+ c ??= e;
96
+ }
97
+ throw e(r ?? "unnamed", o, "failed"), c ?? /* @__PURE__ */ Error("field cipher: malformed ciphertext");
45
98
  },
46
- sealedWithPreviousKey: (e, t) => !i(n, e, t) && r.some((n) => i(n, e, t))
99
+ keyIdOf: m,
100
+ sealedWithPreviousKey: (e, t) => {
101
+ let n = m(e, t);
102
+ return n !== void 0 && n !== c;
103
+ }
47
104
  };
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);
105
+ }, b = (e, t = []) => {
106
+ let n = p(e).toString("hex"), r = [...new Map(t.filter((e) => e.trim() !== "" && p(e).toString("hex") !== n).map((e) => [p(e).toString("hex"), e])).values()];
107
+ return y({
108
+ active: g(e),
109
+ keys: [{
110
+ id: g(e),
111
+ secret: e
112
+ }, ...r.map((e) => ({
113
+ id: g(e),
114
+ secret: e
115
+ }))]
116
+ });
117
+ }, x, S = (e) => {
118
+ x = e;
119
+ }, C = () => x, w = "no field cipher registered — set VOLTRO_FIELD_ENCRYPTION_KEY (`voltro secret generate field-encryption`; `voltro dev` mints one), or call setFieldCipher.", T = (e, t) => {
120
+ let n = C();
121
+ if (!n) throw Error(`encryptField: ${w}`);
122
+ return o(n, e, t);
123
+ }, E = (e, t) => {
124
+ if (!s(e)) return e;
125
+ let n = C();
126
+ if (!n) throw Error(`decryptField: ${w}`);
127
+ return a(n, e, void 0, t);
59
128
  };
60
- //#endregion
61
- export { v as decryptField, l as deriveKey, _ as encryptField, h as getFieldCipher, d as makeAesCipher, f as makeFieldCipher, m as setFieldCipher };
129
+ export { _ as FieldKeyringConfigError, E as decryptField, p as deriveKey, T as encryptField, g as fieldKeyIdOf, C as getFieldCipher, v as isFieldKeyring, h as makeAesCipher, b as makeFieldCipher, y as makeFieldKeyring, S as setFieldCipher };