@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
@@ -0,0 +1,94 @@
1
+ import { API_ROLE_BUCKET_MS as e, API_ROLE_WINDOW_MS as t, assessApiRoleWorkloadWindow as n } from "./apiRoleWorkloadHistory.js";
2
+ // src/apiRoleWorkloadStorage.ts
3
+ var r = "_voltro_api_role_workload_buckets", i = 16384, a = (e) => e instanceof Date ? e.getTime() : typeof e == "number" ? e : NaN, o = async (e, t) => {
4
+ let a = Object.keys(t.workloads);
5
+ if (n({
6
+ now: Math.max(864e5, t.until),
7
+ replicaId: t.replicaId,
8
+ startedAt: t.startedAt,
9
+ role: t.role,
10
+ requiredWorkloads: a,
11
+ buckets: [t]
12
+ }).reason === "invalid-observation" || !t.replicaId || t.replicaId.length > 191 || t.role.length > 2080) throw Error("Invalid API role history bucket");
13
+ let o = JSON.stringify({
14
+ version: 1,
15
+ continuous: t.continuous,
16
+ workloads: t.workloads
17
+ });
18
+ if (new TextEncoder().encode(o).byteLength > i) throw Error("API role history payload too large");
19
+ await e.upsert(r, {
20
+ replicaId: t.replicaId,
21
+ startedAt: new Date(t.startedAt),
22
+ role: t.role,
23
+ bucketFrom: new Date(t.from),
24
+ bucketUntil: new Date(t.until),
25
+ payload: o
26
+ }, { conflictColumns: [
27
+ "replicaId",
28
+ "startedAt",
29
+ "bucketFrom"
30
+ ] });
31
+ }, s = async (o, s) => {
32
+ let c = n({
33
+ ...s,
34
+ buckets: []
35
+ }), l = (await o.query({
36
+ table: r,
37
+ predicate: { and: [
38
+ {
39
+ column: "replicaId",
40
+ op: "eq",
41
+ value: s.replicaId
42
+ },
43
+ {
44
+ column: "startedAt",
45
+ op: "eq",
46
+ value: new Date(s.startedAt)
47
+ },
48
+ {
49
+ column: "role",
50
+ op: "eq",
51
+ value: s.role
52
+ },
53
+ {
54
+ column: "bucketFrom",
55
+ op: "gte",
56
+ value: new Date(c.from)
57
+ },
58
+ {
59
+ column: "bucketFrom",
60
+ op: "lt",
61
+ value: new Date(c.until)
62
+ }
63
+ ] },
64
+ order: [{
65
+ column: "bucketFrom",
66
+ direction: "asc"
67
+ }],
68
+ take: t / e + 1,
69
+ skip: void 0,
70
+ projection: void 0
71
+ })).map((e) => {
72
+ if (typeof e.payload != "string" || new TextEncoder().encode(e.payload).byteLength > i) throw Error("Invalid API role history payload");
73
+ let t = JSON.parse(e.payload);
74
+ if (!t || t.version !== 1 || typeof t.continuous != "boolean" || !t.workloads || typeof t.workloads != "object" || Array.isArray(t.workloads)) throw Error("Invalid API role history payload");
75
+ return {
76
+ replicaId: String(e.replicaId),
77
+ startedAt: a(e.startedAt),
78
+ role: String(e.role),
79
+ from: a(e.bucketFrom),
80
+ until: a(e.bucketUntil),
81
+ continuous: t.continuous,
82
+ workloads: t.workloads
83
+ };
84
+ }), u = n({
85
+ ...s,
86
+ buckets: l
87
+ });
88
+ if (u.reason === "invalid-observation") throw Error("Invalid API role history observations");
89
+ return {
90
+ buckets: l,
91
+ assessment: u
92
+ };
93
+ };
94
+ export { r as API_ROLE_WORKLOAD_BUCKETS_TABLE, s as readApiRoleWorkloadWindow, o as writeApiRoleWorkloadBucket };
@@ -1,10 +1,9 @@
1
1
  import { decideApproval as e, pendingApprovalsFor as t } from "./approvals.js";
2
- //#region src/approvalBuiltins.ts
2
+ // src/approvalBuiltins.ts
3
3
  var n = (e) => e.request?.subject ?? null, r = async (e, r) => t(r.store, n(r), { limit: e.limit ?? 50 }), i = async (t, r) => e(r.store, {
4
4
  approvalId: t.approvalId,
5
5
  decision: t.decision,
6
6
  approver: n(r),
7
7
  ...t.note === void 0 ? {} : { note: t.note }
8
8
  });
9
- //#endregion
10
9
  export { r as approvalsPendingExecutor, i as decideApprovalInvocation };
package/dist/approvals.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { Effect as e } from "effect";
2
2
  import { and as t, eq as n, generateId as r, id as i, inSet as a, registerRetention as o, retentionTtlMsFromEnv as s, table as c, text as l, timestamp as u } from "@voltro/database";
3
3
  import { createHash as d, randomUUID as f } from "node:crypto";
4
- import { ApprovalExpired as p, ApprovalForbidden as m, ApprovalNotFound as h, ApprovalNotPending as g, ApprovalRejected as _, ApprovalRequired as v, ApprovalSelfApproval as y, ApprovalUnavailable as b, checkGuardsEffect as x, isAuthenticatedGuard as S, isPolicyGuard as C, resolvePolicyAction as w } from "@voltro/protocol";
5
- //#region src/approvals.ts
6
- var T = "_voltro_approvals", E = 864e5, D = c(T, {
4
+ import { ApprovalExpired as p, ApprovalForbidden as m, ApprovalNotFound as h, ApprovalNotPending as g, ApprovalRejected as _, ApprovalRequired as v, ApprovalSelfApproval as y, ApprovalUnavailable as b, canonicalJson as x, checkGuardsEffect as S, isAuthenticatedGuard as C, isPolicyGuard as w, isUpgradedGuard as T, resolvePolicyAction as E, upgradedGuardShapeError as D } from "@voltro/protocol";
5
+ // src/approvals.ts
6
+ var O = "_voltro_approvals", k = 864e5, A = c(O, {
7
7
  id: i({ prefix: "apv" }),
8
8
  intentKey: l().maxLength(191),
9
9
  procedure: l(),
@@ -22,24 +22,28 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
22
22
  requestedAt: u().default("now"),
23
23
  expiresAt: u(),
24
24
  consumedAt: u().nullable()
25
- }).index(["status", "expiresAt"]).index(["requestedBy"]), O = () => {
25
+ }).index(["status", "expiresAt"]).index(["requestedBy"]), j = () => {
26
26
  o({
27
27
  source: "framework",
28
- table: T,
28
+ table: O,
29
29
  timeColumn: "requestedAt",
30
30
  ttlMs: s(process.env.VOLTRO_APPROVALS_TTL_HOURS, 720)
31
31
  });
32
- }, k = (e, t) => e.map((e) => S(e) ? { kind: "authenticated" } : C(e) ? {
33
- kind: "policy",
34
- action: w(e, t),
35
- resourceType: e.resourceType,
36
- resource: e.resource(t) ?? null
37
- } : {
38
- kind: "scope",
39
- scope: typeof e.scope == "string" ? [e.scope] : [...e.scope],
40
- mode: e.mode ?? "all",
41
- resource: e.resource?.(t) ?? null
42
- }), A = (e) => e.map((e) => e.kind === "authenticated" ? { authenticated: !0 } : e.kind === "policy" ? {
32
+ }, M = (e, t) => e.map((e) => {
33
+ let n = D(e);
34
+ if (n) throw n;
35
+ return C(e) ? { kind: "authenticated" } : T(e) ? { kind: "upgraded" } : w(e) ? {
36
+ kind: "policy",
37
+ action: E(e, t),
38
+ resourceType: e.resourceType,
39
+ resource: e.resource(t) ?? null
40
+ } : {
41
+ kind: "scope",
42
+ scope: typeof e.scope == "string" ? [e.scope] : [...e.scope],
43
+ mode: e.mode ?? "all",
44
+ resource: e.resource?.(t) ?? null
45
+ };
46
+ }), N = (e) => e.map((e) => e.kind === "authenticated" ? { authenticated: !0 } : e.kind === "upgraded" ? { upgraded: !0 } : e.kind === "policy" ? {
43
47
  action: e.action,
44
48
  resourceType: e.resourceType,
45
49
  resource: () => e.resource ?? void 0
@@ -47,18 +51,7 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
47
51
  scope: e.scope,
48
52
  mode: e.mode,
49
53
  ...e.resource === null ? {} : { resource: () => e.resource ?? void 0 }
50
- }), j = (e) => e.flatMap((e) => e.kind === "policy" ? [`${e.resourceType}:${e.action}`] : e.kind === "authenticated" ? ["authenticated"] : [...e.scope]), M = (e) => {
51
- let t = (e) => {
52
- if (Array.isArray(e)) return e.map(t);
53
- if (typeof e == "object" && e) {
54
- let n = e, r = Object.create(null);
55
- for (let e of Object.keys(n).sort()) r[e] = t(n[e]);
56
- return r;
57
- }
58
- return e;
59
- };
60
- return JSON.stringify(t(e) ?? null);
61
- }, N = (e) => {
54
+ }), P = (e) => e.flatMap((e) => e.kind === "policy" ? [`${e.resourceType}:${e.action}`] : e.kind === "authenticated" ? ["authenticated"] : e.kind === "upgraded" ? ["upgraded"] : [...e.scope]), F = (e) => {
62
55
  let t = [
63
56
  e.procedure,
64
57
  e.requestedBy ?? "",
@@ -67,48 +60,48 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
67
60
  e.nonce ?? ""
68
61
  ].map((e) => `${e.length}:${e}`).join("");
69
62
  return d("sha256").update(t, "utf8").digest("hex");
70
- }, P = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : (/* @__PURE__ */ new Date(0)).toISOString(), F = (e) => e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : 0, I = (e) => {
63
+ }, I = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : (/* @__PURE__ */ new Date(0)).toISOString(), L = (e) => e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : 0, R = (e) => {
71
64
  try {
72
65
  let t = JSON.parse(String(e ?? "[]"));
73
66
  return Array.isArray(t) ? t : [];
74
67
  } catch {
75
68
  return [];
76
69
  }
77
- }, L = async (e, t) => (await e.query({
70
+ }, z = async (e, t) => (await e.query({
78
71
  table: "_voltro_approvals",
79
72
  predicate: n("intentKey", t),
80
73
  order: []
81
- }))[0] ?? null, R = async (e, t) => (await e.query({
74
+ }))[0] ?? null, B = async (e, t) => (await e.query({
82
75
  table: "_voltro_approvals",
83
76
  predicate: n("id", t),
84
77
  order: []
85
- }))[0] ?? null, z = async (e, t, n) => {
78
+ }))[0] ?? null, V = async (e, t, n) => {
86
79
  let r = String(t.intentKey ?? ""), i = r.includes("#") ? r : `${r}#${String(t.id)}`;
87
- await e.update(T, String(t.id), {
80
+ await e.update(O, String(t.id), {
88
81
  ...n,
89
82
  intentKey: i
90
83
  });
91
- }, B = (e) => {
84
+ }, H = (e) => {
92
85
  let t = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/.exec(e.trim());
93
86
  if (t === null) return null;
94
87
  let n = Number(t[1]);
95
88
  if (!(Number.isFinite(n) && n > 0)) return null;
96
89
  let r = t[2];
97
90
  return n * (r === "ms" ? 1 : r === "s" ? 1e3 : r === "m" ? 6e4 : r === "h" ? 36e5 : 864e5);
98
- }, V = (e) => {
91
+ }, U = (e) => {
99
92
  let i = e.store, a = e.now ?? Date.now, o = e.defaultExpiryMs ?? 864e5;
100
- O();
93
+ j();
101
94
  let s = (e) => {
102
95
  if (e.expiresIn === void 0) return o;
103
- let t = B(e.expiresIn);
96
+ let t = H(e.expiresIn);
104
97
  if (t === null) throw Error(`requiresApproval.expiresIn must be an interval like '4h' / '30m' (got ${JSON.stringify(e.expiresIn)})`);
105
98
  return t;
106
99
  }, c = async (e, t, n) => {
107
- let o = k(e.policy.approvers, e.input), c = r({
100
+ let o = M(e.policy.approvers, e.input), c = r({
108
101
  kind: "typeid",
109
102
  prefix: "apv"
110
- }, T), l = a();
111
- await i.insertIgnore(T, {
103
+ }, O), l = a();
104
+ await i.insertIgnore(O, {
112
105
  id: c,
113
106
  intentKey: t,
114
107
  procedure: e.procedure,
@@ -117,7 +110,7 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
117
110
  tenantId: e.subject?.tenantId ?? null,
118
111
  payload: n,
119
112
  approverGuards: JSON.stringify(o),
120
- approverScopes: JSON.stringify(j(o)),
113
+ approverScopes: JSON.stringify(P(o)),
121
114
  reason: e.policy.reason ?? null,
122
115
  status: "pending",
123
116
  decidedBy: null,
@@ -128,7 +121,7 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
128
121
  expiresAt: new Date(l + s(e.policy)),
129
122
  consumedAt: null
130
123
  }, { conflictColumns: ["intentKey"] });
131
- let u = await L(i, t);
124
+ let u = await z(i, t);
132
125
  if (u === null) throw new b({
133
126
  procedure: e.procedure,
134
127
  message: "the approval intent was written and could not be read back"
@@ -137,27 +130,27 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
137
130
  }, l = (e, t) => new v({
138
131
  approvalId: String(e.id),
139
132
  procedure: String(e.procedure),
140
- expiresAt: P(e.expiresAt),
141
- requiredScopes: j(I(e.approverGuards)),
133
+ expiresAt: I(e.expiresAt),
134
+ requiredScopes: P(R(e.approverGuards)),
142
135
  reason: e.reason ?? null,
143
136
  created: t
144
137
  });
145
138
  return { admit: async (e) => {
146
- let r = M(e.input), o = N({
139
+ let r = x(e.input), o = F({
147
140
  procedure: e.procedure,
148
141
  requestedBy: e.subject?.id ?? null,
149
142
  tenantId: e.subject?.tenantId ?? null,
150
143
  payload: r,
151
144
  nonce: e.nonce
152
- }), s = await L(i, o);
145
+ }), s = await z(i, o);
153
146
  if (s === null) throw l(await c(e, o, r), !0);
154
- let u = String(s.status ?? "pending"), d = F(s.expiresAt);
155
- if ((u === "pending" || u === "approved") && a() > d) throw await z(i, s, { status: "expired" }), new p({
147
+ let u = String(s.status ?? "pending"), d = L(s.expiresAt);
148
+ if ((u === "pending" || u === "approved") && a() > d) throw await V(i, s, { status: "expired" }), new p({
156
149
  approvalId: String(s.id),
157
- expiredAt: P(s.expiresAt)
150
+ expiredAt: I(s.expiresAt)
158
151
  });
159
152
  if (u === "pending") throw l(s, !1);
160
- if (u === "rejected") throw await z(i, s, {}), new _({
153
+ if (u === "rejected") throw await V(i, s, {}), new _({
161
154
  approvalId: String(s.id),
162
155
  decidedBy: s.decidedBy ?? null,
163
156
  note: s.note ?? null
@@ -168,17 +161,17 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
168
161
  consumedAt: new Date(a()),
169
162
  intentKey: `${o}#${String(s.id)}`
170
163
  }, { where: t(n("id", String(s.id)), n("status", "approved")) }) === 1) return;
171
- throw s = await L(i, o), s === null ? l(await c(e, o, r), !0) : l(s, !1);
164
+ throw s = await z(i, o), s === null ? l(await c(e, o, r), !0) : l(s, !1);
172
165
  }
173
- throw await z(i, s, {}), l(await c(e, o, r), !0);
166
+ throw await V(i, s, {}), l(await c(e, o, r), !0);
174
167
  } };
175
- }, H, U = (e) => {
176
- H = e;
177
- }, W = () => H, G = () => {
178
- H = void 0;
179
- }, K = async (e) => {
168
+ }, W, G = (e) => {
169
+ W = e;
170
+ }, K = () => W, q = () => {
171
+ W = void 0;
172
+ }, J = async (e) => {
180
173
  if (e.policy === void 0) return;
181
- let t = W();
174
+ let t = K();
182
175
  if (t === void 0) throw new b({
183
176
  procedure: e.procedure,
184
177
  message: `${e.procedure} declares \`requiresApproval\` and no approvals gate is installed on this boot path, so the framework cannot record the intent or verify a decision. Refusing the call rather than running it unapproved.`
@@ -191,17 +184,17 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
191
184
  input: e.input,
192
185
  ...e.traceId === void 0 ? {} : { traceId: e.traceId }
193
186
  });
194
- }, q = async (r, i) => {
195
- let a = i.now ?? Date.now, o = await R(r, i.approvalId);
187
+ }, Y = async (r, i) => {
188
+ let a = i.now ?? Date.now, o = await B(r, i.approvalId);
196
189
  if (o === null) throw new h({ approvalId: i.approvalId });
197
190
  let s = String(o.status ?? "pending");
198
191
  if (s !== "pending") throw new g({
199
192
  approvalId: i.approvalId,
200
193
  status: s
201
194
  });
202
- if (a() > F(o.expiresAt)) throw await z(r, o, { status: "expired" }), new p({
195
+ if (a() > L(o.expiresAt)) throw await V(r, o, { status: "expired" }), new p({
203
196
  approvalId: i.approvalId,
204
- expiredAt: P(o.expiresAt)
197
+ expiredAt: I(o.expiresAt)
205
198
  });
206
199
  let c = i.approver?.id ?? null;
207
200
  if (c === null) throw new m({
@@ -213,7 +206,7 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
213
206
  approvalId: i.approvalId,
214
207
  subjectId: c
215
208
  });
216
- let l = A(I(o.approverGuards)), u = await e.runPromise(x(i.approver, l, JSON.parse(String(o.payload ?? "null"))));
209
+ let l = N(R(o.approverGuards)), u = await e.runPromise(S(i.approver, l, JSON.parse(String(o.payload ?? "null"))));
217
210
  if (u) throw new m({
218
211
  approvalId: i.approvalId,
219
212
  required: "_tag" in u && u._tag === "ScopeError" ? u.required : null,
@@ -226,7 +219,7 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
226
219
  decidedAt: new Date(a()),
227
220
  note: i.note ?? null
228
221
  }, { where: t(n("id", i.approvalId), n("status", "pending")) }) !== 1) {
229
- let e = await R(r, i.approvalId);
222
+ let e = await B(r, i.approvalId);
230
223
  throw new g({
231
224
  approvalId: i.approvalId,
232
225
  status: String(e?.status ?? "unknown")
@@ -236,34 +229,33 @@ var T = "_voltro_approvals", E = 864e5, D = c(T, {
236
229
  approvalId: i.approvalId,
237
230
  status: d
238
231
  };
239
- }, J = async (t, n, r) => {
232
+ }, X = async (t, n, r) => {
240
233
  let i = n?.id ?? null;
241
234
  if (i === null) return [];
242
235
  let o = r?.now ?? Date.now, s = await t.query({
243
- table: T,
236
+ table: O,
244
237
  predicate: a("status", ["pending", "approved"]),
245
238
  order: []
246
239
  }), c = [];
247
240
  for (let t of s) {
248
- if (o() > F(t.expiresAt)) continue;
249
- let r = I(t.approverGuards), a = (t.requestedBy ?? null) === i, s = a ? "requested" : null;
250
- a || await e.runPromise(x(n, A(r), JSON.parse(String(t.payload ?? "null")))) === null && String(t.status) === "pending" && (s = "to-decide"), s !== null && c.push({
241
+ if (o() > L(t.expiresAt)) continue;
242
+ let r = R(t.approverGuards), a = (t.requestedBy ?? null) === i, s = a ? "requested" : null;
243
+ a || await e.runPromise(S(n, N(r), JSON.parse(String(t.payload ?? "null")))) === null && String(t.status) === "pending" && (s = "to-decide"), s !== null && c.push({
251
244
  id: String(t.id),
252
245
  procedure: String(t.procedure),
253
246
  kind: String(t.kind) === "action" ? "action" : "mutation",
254
247
  requestedBy: t.requestedBy ?? null,
255
248
  status: String(t.status ?? "pending"),
256
249
  reason: t.reason ?? null,
257
- requiredScopes: j(r),
258
- requestedAt: P(t.requestedAt),
259
- expiresAt: P(t.expiresAt),
250
+ requiredScopes: P(r),
251
+ requestedAt: I(t.requestedAt),
252
+ expiresAt: I(t.expiresAt),
260
253
  decidedBy: t.decidedBy ?? null,
261
- decidedAt: t.decidedAt == null ? null : P(t.decidedAt),
254
+ decidedAt: t.decidedAt == null ? null : I(t.decidedAt),
262
255
  note: t.note ?? null,
263
256
  relation: s
264
257
  });
265
258
  }
266
259
  return c.sort((e, t) => t.requestedAt.localeCompare(e.requestedAt)).slice(0, r?.limit ?? 50);
267
- }, Y = () => f();
268
- //#endregion
269
- export { T as APPROVALS_TABLE, E as DEFAULT_APPROVAL_EXPIRY_MS, D as _voltroApprovalsTable, N as approvalIntentKey, Y as approvalNonce, M as canonicalJson, G as clearApprovalGate, q as decideApproval, K as enforceApproval, W as getApprovalGate, U as installApprovalGate, V as makeApprovalGate, B as parseApprovalInterval, J as pendingApprovalsFor, A as rehydrateGuards, j as scopeStringsOf, k as serializeGuards };
260
+ }, Z = () => f();
261
+ export { O as APPROVALS_TABLE, k as DEFAULT_APPROVAL_EXPIRY_MS, A as _voltroApprovalsTable, F as approvalIntentKey, Z as approvalNonce, x as canonicalJson, q as clearApprovalGate, Y as decideApproval, J as enforceApproval, K as getApprovalGate, G as installApprovalGate, U as makeApprovalGate, H as parseApprovalInterval, X as pendingApprovalsFor, N as rehydrateGuards, P as scopeStringsOf, M as serializeGuards };
@@ -3,7 +3,7 @@ import { Context as r, Effect as i, Layer as a, Option as o, Schema as s } from
3
3
  import { AuthMiddleware as c, ConnectionInfo as l, ConnectionInfoMiddleware as u, RequestedTenantRefused as d, SubjectService as f, Unauthenticated as p } from "@voltro/protocol";
4
4
  import { Rpc as m } from "effect/rpc";
5
5
  import { sessionExpiryFromHeaders as h } from "@voltro/protocol/session";
6
- //#region src/authMiddlewareLayer.ts
6
+ // src/authMiddlewareLayer.ts
7
7
  var g = class extends r.Service()("@voltro/runtime/VerifiedCredentialLifetime") {}, _ = (e) => {
8
8
  for (let t of e.requests.values()) if (m.isRpc(t) && [...t.middlewares].some((e) => e.key === c.key || e.key === u.key)) throw Error("withRpcAuthMiddleware requires a group without AuthMiddleware or ConnectionInfoMiddleware; apply the shared pair once");
9
9
  return e.middleware(u).middleware(c);
@@ -33,15 +33,15 @@ var g = class extends r.Service()("@voltro/runtime/VerifiedCredentialLifetime")
33
33
  return a.mergeAll(a.succeed(c, _), a.succeed(u, u.of((n, r) => i.gen(function* () {
34
34
  let { headers: n, client: a, rpc: s } = r, l = yield* i.serviceOption(g), u = o.filter(l, (e) => e.request === r);
35
35
  if (o.isNone(u) && m.has(r) && [...s.middlewares].some((e) => e.key === c.key)) throw Error("RPC authentication must run before ConnectionInfoMiddleware; compose the group with withRpcAuthMiddleware");
36
- let d = o.isSome(u) ? u.value.credentialExpiresAt : t(a.id) ?? h(e(a.id, n)), f = n["idempotency-key"], p = n["voltro-resume-from"], _ = n["voltro-reconcile"], v = p !== void 0 && /^\d+$/.test(p) ? Number(p) : void 0;
36
+ let d = o.isSome(u) ? u.value.credentialExpiresAt : t(a.id) ?? h(e(a.id, n)), f = e(a.id, n).cookie, p = n["idempotency-key"], _ = n["voltro-resume-from"], v = n["voltro-reconcile"], y = _ !== void 0 && /^\d+$/.test(_) ? Number(_) : void 0;
37
37
  return {
38
38
  clientId: a.id,
39
- ...f ? { idempotencyKey: f } : {},
39
+ ...f === void 0 ? {} : { cookieHeader: f },
40
+ ...p ? { idempotencyKey: p } : {},
40
41
  ...d === void 0 ? {} : { credentialExpiresAt: d },
41
- ...v !== void 0 && Number.isSafeInteger(v) ? { resumeFrom: v } : {},
42
- ..._ !== void 0 && /^[a-zA-Z0-9_-]{1,128}$/.test(_) ? { reconcile: _ } : {}
42
+ ...y !== void 0 && Number.isSafeInteger(y) ? { resumeFrom: y } : {},
43
+ ...v !== void 0 && /^[a-zA-Z0-9_-]{1,128}$/.test(v) ? { reconcile: v } : {}
43
44
  };
44
45
  }).pipe(i.flatMap((e) => i.provideService(n, l, e))))));
45
- };
46
- //#endregion
47
- export { v as makeAuthMiddlewareLayers, _ as withRpcAuthMiddleware };
46
+ }, y = (e) => a.succeed(u, u.of((t, { headers: n, client: r }) => i.sync(() => (e(n, r.id), { clientId: r.id })).pipe(i.flatMap((e) => i.provideService(t, l, e)))));
47
+ export { v as makeAuthMiddlewareLayers, y as observeConnectionHeaders, _ as withRpcAuthMiddleware };
package/dist/bindEvent.js CHANGED
@@ -2,9 +2,9 @@ import { recordEventDelivered as e, recordEventDropped as t } from "./metrics.js
2
2
  import { registerConnectionStream as n } from "./connectionCredentials.js";
3
3
  import { boundByCredential as r } from "./credentialBound.js";
4
4
  import { Effect as i, Queue as a, Stream as o } from "effect";
5
- import { ConnectionInfo as s, SubjectService as c, checkGuardsEffect as l, isOpenAccess as u, recheckGuardsEffect as d } from "@voltro/protocol";
6
- //#region src/bindEvent.ts
7
- var f = 64, p = 1, m = (e) => e.kind === "gap" ? {
5
+ import { ConnectionInfo as s, ScopeError as c, SubjectService as l, checkGuardsEffect as u, isOpenAccess as d, recheckGuardsEffect as f } from "@voltro/protocol";
6
+ // src/bindEvent.ts
7
+ var p = 64, m = 1, h = (e) => e.kind === "gap" ? {
8
8
  _tag: "gap",
9
9
  missed: e.missed,
10
10
  reason: e.reason
@@ -14,49 +14,69 @@ var f = 64, p = 1, m = (e) => e.kind === "gap" ? {
14
14
  n: e.envelope.n,
15
15
  emittedAt: e.envelope.emittedAt,
16
16
  payload: e.envelope.payload
17
- }, h = (e) => {
17
+ }, g = (e) => {
18
18
  let t = new Map(e ?? []);
19
19
  return (e, n = 0) => {
20
20
  let r = t.get(e.origin) ?? 0;
21
21
  return t.set(e.origin, Math.max(r, e.n)), r === 0 && n === 0 ? 0 : Math.max(0, e.n - r - 1);
22
22
  };
23
- }, g = (f) => o.unwrap(i.gen(function* () {
24
- let p = yield* c, g = yield* s, _ = p.tenantId ?? null, v = f.guards === void 0 ? void 0 : f.guards.filter((e) => !u(e));
25
- if (v !== void 0 && v.length > 0 || p.type === "service") {
26
- let e = yield* l(p, v ?? [], f.key);
23
+ }, _ = (p) => o.unwrap(i.gen(function* () {
24
+ let m = yield* l, _ = yield* s, v = m.tenantId ?? null, y = p.guards === void 0 ? void 0 : p.guards.filter((e) => !d(e));
25
+ if (y !== void 0 && y.length > 0 || m.type === "service") {
26
+ let e = yield* u(m, y ?? [], p.key);
27
27
  if (e) return yield* i.fail(e);
28
28
  }
29
- let y = f.bus.deliveryFor(f.event) === "latest", b = yield* a.sliding(f.queueSize ?? (y ? 1 : 64)), x = /* @__PURE__ */ new Map(), S = f.bus.subscribe({
30
- tenantId: _,
31
- event: f.event,
32
- key: f.key,
33
- options: f.options,
29
+ let b = p.clientPolicy, x = () => new c({
30
+ required: p.requiredClientPolicy ?? "event:client-policy",
31
+ message: "event client access denied"
32
+ });
33
+ if (p.requiredClientPolicy !== void 0 && (!b || b.id !== p.requiredClientPolicy) || b !== void 0 && p.requiredClientPolicy === void 0) return yield* i.fail(x());
34
+ let S = () => ({
35
+ subject: structuredClone(m),
36
+ event: p.event,
37
+ key: structuredClone(p.key)
38
+ }), C = () => b === void 0 ? i.succeed(!0) : i.suspend(() => b.admit(S())).pipe(i.catch(() => i.succeed(!1)), i.catchDefect(() => i.succeed(!1)), i.map((e) => e === !0)), w = b?.monitor === void 0 ? void 0 : yield* i.suspend(() => b.monitor(S())).pipe(i.catch(() => i.fail(x())), i.catchDefect(() => i.fail(x())));
39
+ if (!(yield* C())) return yield* i.fail(x());
40
+ let T = p.bus.deliveryFor(p.event) === "latest", E = yield* a.sliding(p.queueSize ?? (T ? 1 : 64)), D = /* @__PURE__ */ new Map(), O = p.bus.subscribe({
41
+ tenantId: v,
42
+ event: p.event,
43
+ key: p.key,
44
+ options: p.options,
34
45
  onAttach: (e) => {
35
- x = e;
46
+ D = e;
36
47
  },
37
48
  listener: (e) => {
38
- i.runSync(a.offer(b, e));
49
+ i.runSync(a.offer(E, e));
39
50
  }
40
51
  });
41
52
  if (yield* i.addFinalizer(() => i.sync(() => {
42
- S();
43
- })), g.clientId !== void 0) {
44
- let e = n(g.clientId, () => {
45
- i.runPromise(a.shutdown(b));
53
+ O();
54
+ })), _.clientId !== void 0) {
55
+ let e = n(_.clientId, () => {
56
+ i.runPromise(a.shutdown(E));
46
57
  });
47
58
  yield* i.addFinalizer(() => i.sync(() => {
48
59
  e();
49
60
  }));
50
61
  }
51
- let C = y ? () => 0 : h(x), w = () => d(p, v, f.key), T = o.fromQueue(b).pipe(o.flatMap((e) => o.unwrap(w().pipe(i.map((t) => t ? o.fail(t) : E(e))))));
52
- function E(n) {
62
+ let k = T ? () => 0 : g(D), A = () => f(m, y, p.key), j = o.fromQueue(E).pipe(o.flatMap((e) => o.unwrap(A().pipe(i.map((t) => t ? o.fail(t) : M(e))))), o.ensuring(a.shutdown(E)));
63
+ function M(e) {
64
+ if (b === void 0) return N(e);
65
+ let t = e.kind === "gap" ? C().pipe(i.map((e) => e ? "allow" : "deny")) : i.suspend(() => b.deliver({
66
+ ...S(),
67
+ payload: structuredClone(e.envelope.payload),
68
+ emittedAt: e.envelope.emittedAt
69
+ })).pipe(i.catch(() => i.succeed("deny")), i.catchDefect(() => i.succeed("deny")));
70
+ return o.unwrap(t.pipe(i.map((t) => t === "allow" ? N(e) : t === "drop" && e.kind !== "gap" ? (k(e.envelope, e.prior), o.empty) : o.fail(x()))));
71
+ }
72
+ function N(n) {
53
73
  return o.suspend(() => {
54
- if (n.kind === "gap") return o.make(m(n));
55
- let r = C(n.envelope, n.prior);
56
- e(f.event);
57
- let i = m(n);
74
+ if (n.kind === "gap") return o.make(h(n));
75
+ let r = k(n.envelope, n.prior);
76
+ e(p.event);
77
+ let i = h(n);
58
78
  if (r === 0) return o.make(i);
59
- t(f.event, "buffer", r);
79
+ t(p.event, "buffer", r);
60
80
  let a = {
61
81
  _tag: "gap",
62
82
  missed: r,
@@ -65,8 +85,7 @@ var f = 64, p = 1, m = (e) => e.kind === "gap" ? {
65
85
  return o.fromIterable([a, i]);
66
86
  });
67
87
  }
68
- let D = { _tag: "attached" };
69
- return r(o.concat(o.fromIterable([D]), T), g.credentialExpiresAt, o.fromIterable([D]));
88
+ let P = { _tag: "attached" }, F = o.concat(o.fromIterable([P]), j), I = w === void 0 ? F : F.pipe(o.interruptWhen(w.pipe(i.catch(() => i.void), i.catchDefect(() => i.void), i.flatMap(() => i.fail(x())))));
89
+ return r(I, _.credentialExpiresAt, o.fromIterable([P]));
70
90
  }));
71
- //#endregion
72
- export { f as EVENT_CLIENT_QUEUE_SIZE, p as EVENT_LATEST_QUEUE_SIZE, g as bindEvent, h as makeBufferGapDetector };
91
+ export { p as EVENT_CLIENT_QUEUE_SIZE, m as EVENT_LATEST_QUEUE_SIZE, _ as bindEvent, g as makeBufferGapDetector };
@@ -0,0 +1,10 @@
1
+ export declare const BOOT_REFUSAL_NAME = "VoltroBootRefusal";
2
+
3
+ /** An error the boot path raised on purpose. The launcher prints its message
4
+ * once and exits 1 instead of degrading to a fallback path or printing a
5
+ * stack. */
6
+ export declare const bootRefusal: (message: string) => Error;
7
+
8
+ export declare const isBootRefusal: (error: unknown) => boolean;
9
+
10
+ export { }
@@ -1,7 +1,6 @@
1
- //#region src/bootRefusal.ts
1
+ // src/bootRefusal.ts
2
2
  var e = "VoltroBootRefusal", t = (t) => {
3
3
  let n = Error(t);
4
4
  return n.name = e, n;
5
5
  }, n = (e) => typeof e == "object" && !!e && e.name === "VoltroBootRefusal";
6
- //#endregion
7
6
  export { e as BOOT_REFUSAL_NAME, t as bootRefusal, n as isBootRefusal };