@voltro/protocol 0.70.0 → 0.71.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.
@@ -51,13 +51,68 @@ var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n,
51
51
  get message() {
52
52
  return `a request with this idempotency key is still in flight — replay the same key after ${this.retryAfterMs}ms`;
53
53
  }
54
- }, d = 1e3, f = /* @__PURE__ */ new Set(), p = (e) => {
55
- for (let t of f) try {
54
+ }, d = 1e3, f = (e) => typeof e == "object" && !!e && typeof e._tag == "string", p = 64, m = (e, t = 0) => {
55
+ if (!f(e)) return String(e);
56
+ if (t >= p) return "…";
57
+ let n = t + 1, r = (t) => m(e[t], n), i = (t) => Array.isArray(e[t]) ? e[t] : [];
58
+ switch (e._tag) {
59
+ case "Transformation": return `T(${r("from")}->${r("to")})`;
60
+ case "Refinement": return `R(${r("from")})`;
61
+ case "Suspend": return "S(…)";
62
+ case "TypeLiteral": {
63
+ let e = i("propertySignatures").map((e) => {
64
+ let t = e;
65
+ return `${String(t.name)}${t.isOptional === !0 ? "?" : ""}:${m(t.type, n)}`;
66
+ }).join(","), t = i("indexSignatures").map((e) => {
67
+ let t = e;
68
+ return `[${m(t.parameter, n)}]:${m(t.type, n)}`;
69
+ }).join(",");
70
+ return t === "" ? `{${e}}` : `{${e};${t}}`;
71
+ }
72
+ case "Union": return `U(${i("types").map((e) => m(e, n)).join("|")})`;
73
+ case "TupleType": {
74
+ let e = i("elements").map((e) => {
75
+ let t = e;
76
+ return `${m(t.type, n)}${t.isOptional === !0 ? "?" : ""}`;
77
+ }).join(","), t = i("rest").map((e) => m(e.type, n)).join(",");
78
+ return `A(${e}${t === "" ? "" : `...${t}`})`;
79
+ }
80
+ case "Declaration": return `D(${i("typeParameters").map((e) => m(e, n)).join(",")})`;
81
+ default: return String(e);
82
+ }
83
+ }, h = (e) => {
84
+ let t = 2166136261;
85
+ for (let n = 0; n < e.length; n++) t ^= e.charCodeAt(n), t = Math.imul(t, 16777619) >>> 0;
86
+ return t.toString(16).padStart(8, "0");
87
+ }, g = (e) => h([
88
+ m(e.payloadSchema?.ast),
89
+ m(e.successSchema?.ast),
90
+ m(e.errorSchema?.ast)
91
+ ].join("\0")), _ = (e) => {
92
+ let t = {}, n = e.requests, r = n instanceof Map ? n.entries() : Array.isArray(n) ? n.map((e, t) => [t, e]) : [];
93
+ for (let [, e] of r) {
94
+ if (typeof e != "object" && typeof e != "function" || e === null) continue;
95
+ let n = e;
96
+ typeof n._tag == "string" && (t[n._tag] = g(n));
97
+ }
98
+ return t;
99
+ }, v = (e, t) => {
100
+ let n = [], r = [];
101
+ for (let [i, a] of Object.entries(t)) {
102
+ let t = e[i];
103
+ t === void 0 ? r.push(i) : t !== a && n.push(i);
104
+ }
105
+ return {
106
+ differing: n.sort(),
107
+ missingHere: r.sort()
108
+ };
109
+ }, y = /* @__PURE__ */ new Set(), b = (e) => {
110
+ for (let t of y) try {
56
111
  t(e);
57
112
  } catch {}
58
- }, m = (e) => (f.add(e), () => {
59
- f.delete(e);
60
- }), h = {
113
+ }, x = (e) => (y.add(e), () => {
114
+ y.delete(e);
115
+ }), S = {
61
116
  rpc: {
62
117
  name: "rpc",
63
118
  dates: "epoch-ms",
@@ -91,16 +146,16 @@ var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n,
91
146
  naming: "camelCase",
92
147
  etag: !0
93
148
  }
94
- }, g = [
149
+ }, C = [
95
150
  "rpc",
96
151
  "standard",
97
152
  "jsonapi"
98
- ], _ = (e, t = void 0) => {
153
+ ], w = (e, t = void 0) => {
99
154
  let n = (e) => {
100
155
  if (e?.profile !== void 0) {
101
156
  if (typeof e.profile == "string") {
102
- let t = h[e.profile];
103
- if (t === void 0) throw Error(`publicApi.profile: unknown profile '${String(e.profile)}' — one of ${g.join(", ")}, or a RestFormat object`);
157
+ let t = S[e.profile];
158
+ if (t === void 0) throw Error(`publicApi.profile: unknown profile '${String(e.profile)}' — one of ${C.join(", ")}, or a RestFormat object`);
104
159
  return t;
105
160
  }
106
161
  return e.profile;
@@ -115,14 +170,14 @@ var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n,
115
170
  ...t.cursorParam === void 0 ? {} : { cursorParam: t.cursorParam },
116
171
  ...t.naming === void 0 ? {} : { naming: t.naming },
117
172
  ...t.etag === void 0 ? {} : { etag: t.etag }
118
- }, i = r(n(e) ?? h.rpc, e);
173
+ }, i = r(n(e) ?? S.rpc, e);
119
174
  return r(n(t) ?? i, t);
120
- }, v = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toLowerCase(), y = (e, t) => {
175
+ }, T = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toLowerCase(), E = (e, t) => {
121
176
  if (typeof e != "object" || !e || Array.isArray(e)) return e;
122
177
  let n = {};
123
178
  for (let [r, i] of Object.entries(e)) n[t(r)] = i;
124
179
  return n;
125
- }, b = (e) => n.getOrUndefined(t.getIdentifierAnnotation(e)), x = (n, r) => {
180
+ }, D = (e) => n.getOrUndefined(t.getIdentifierAnnotation(e)), O = (n, r) => {
126
181
  if (r.dates === "epoch-ms" && r.naming === "camelCase") return n;
127
182
  let i = /* @__PURE__ */ new Map(), a = (e) => {
128
183
  let t = i.get(e);
@@ -132,7 +187,7 @@ var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n,
132
187
  }, o = (n) => {
133
188
  switch (n._tag) {
134
189
  case "Transformation":
135
- if (r.dates === "iso" && b(n) === "DateFromNumber") {
190
+ if (r.dates === "iso" && D(n) === "DateFromNumber") {
136
191
  let r = e.DateFromString.ast;
137
192
  return new t.Transformation(r.from, r.to, r.transformation, {
138
193
  ...r.annotations,
@@ -150,43 +205,43 @@ var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n,
150
205
  case "TupleType": return new t.TupleType(n.elements.map((e) => new t.OptionalType(a(e.type), e.isOptional, e.annotations)), n.rest.map((e) => new t.Type(a(e.type), e.annotations)), n.isReadonly, n.annotations);
151
206
  case "Suspend": return new t.Suspend(() => a(n.f()), n.annotations);
152
207
  case "TypeLiteral": {
153
- let i = n.propertySignatures.map((e) => new t.PropertySignature(e.name, a(e.type), e.isOptional, e.isReadonly, e.annotations)), o = new t.TypeLiteral(i, n.indexSignatures, n.annotations);
154
- if (r.naming !== "snake_case") return o;
155
- let s = i.map((e) => typeof e.name == "string" ? v(e.name) : e.name);
156
- if (s.every((e, t) => e === i[t].name)) return o;
157
- let c = new t.TypeLiteral(i.map((e, n) => new t.PropertySignature(s[n], t.encodedAST(e.type), e.isOptional, e.isReadonly, e.annotations)), n.indexSignatures, n.annotations), l = new Map(i.map((e, t) => [String(s[t]), String(e.name)])), u = new Map(i.map((e, t) => [String(e.name), String(s[t])]));
158
- return e.transform(e.make(c), e.make(o), {
208
+ let i = n.propertySignatures.map((e) => new t.PropertySignature(e.name, a(e.type), e.isOptional, e.isReadonly, e.annotations)), o = n.indexSignatures.map((e) => new t.IndexSignature(e.parameter, a(e.type), e.isReadonly)), s = new t.TypeLiteral(i, o, n.annotations);
209
+ if (r.naming !== "snake_case") return s;
210
+ let c = i.map((e) => typeof e.name == "string" ? T(e.name) : e.name);
211
+ if (c.every((e, t) => e === i[t].name)) return s;
212
+ let l = new t.TypeLiteral(i.map((e, n) => new t.PropertySignature(c[n], t.encodedAST(e.type), e.isOptional, e.isReadonly, e.annotations)), o.map((e) => new t.IndexSignature(e.parameter, t.encodedAST(e.type), e.isReadonly)), n.annotations), u = new Map(i.map((e, t) => [String(c[t]), String(e.name)])), d = new Map(i.map((e, t) => [String(e.name), String(c[t])]));
213
+ return e.transform(e.make(l), e.make(s), {
159
214
  strict: !1,
160
- decode: (e) => y(e, (e) => l.get(e) ?? e),
161
- encode: (e) => y(e, (e) => u.get(e) ?? e)
215
+ decode: (e) => E(e, (e) => u.get(e) ?? e),
216
+ encode: (e) => E(e, (e) => d.get(e) ?? e)
162
217
  }).ast;
163
218
  }
164
219
  default: return n;
165
220
  }
166
221
  };
167
222
  return e.make(a(n.ast));
168
- }, S = (e) => `urn:voltro:error:${e}`, C = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z])([A-Z][a-z])/g, "$1 $2"), w = (e) => ({
169
- type: S(e.tag),
170
- title: C(e.tag),
223
+ }, k = (e) => `urn:voltro:error:${e}`, A = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z])([A-Z][a-z])/g, "$1 $2"), j = (e) => ({
224
+ type: k(e.tag),
225
+ title: A(e.tag),
171
226
  status: e.status,
172
227
  ...e.message.length > 0 ? { detail: e.message } : {},
173
228
  ...e.fields
174
- }), T = "application/problem+json; charset=utf-8", E = "application/vnd.api+json; charset=utf-8", D = (e, t, n) => e.encodeError === void 0 ? e.errors === "problem-details" ? e.envelope === "jsonapi" ? {
229
+ }), M = "application/problem+json; charset=utf-8", N = "application/vnd.api+json; charset=utf-8", P = (e, t, n) => e.encodeError === void 0 ? e.errors === "problem-details" ? e.envelope === "jsonapi" ? {
175
230
  body: { errors: [{
176
231
  status: String(t.status),
177
232
  code: t.tag,
178
- title: C(t.tag),
233
+ title: A(t.tag),
179
234
  ...t.message.length > 0 ? { detail: t.message } : {},
180
235
  ...Object.keys(t.fields).length > 0 ? { meta: t.fields } : {}
181
236
  }] },
182
- contentType: E
237
+ contentType: N
183
238
  } : {
184
- body: w(t),
185
- contentType: T
239
+ body: j(t),
240
+ contentType: M
186
241
  } : { body: {
187
242
  error: t.tag === "InvalidRequest" || t.tag === "InternalServerError" || t.tag === "Unauthorized" || t.tag === "Forbidden" || t.tag === "Gone" || t.tag === "MethodNotAllowed" || t.tag === "Conflict" ? t.message : t.tag,
188
243
  ...t.fields
189
- } } : e.encodeError(t, n), O = (e, t) => {
244
+ } } : e.encodeError(t, n), F = (e, t) => {
190
245
  if (typeof e != "object" || !e || Array.isArray(e)) return {
191
246
  cursor: void 0,
192
247
  rest: e
@@ -199,10 +254,10 @@ var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n,
199
254
  cursor: String(n),
200
255
  rest: e
201
256
  };
202
- }, k = (e, t, n) => {
257
+ }, I = (e, t, n) => {
203
258
  let r = new URLSearchParams(e.query);
204
259
  return r.set(n, t), `<${e.path}?${r.toString()}>; rel="next"`;
205
- }, A = (e, t) => {
260
+ }, L = (e, t) => {
206
261
  if (typeof e != "object" || !e || Array.isArray(e)) return e;
207
262
  let { id: n, ...r } = e;
208
263
  return {
@@ -210,9 +265,9 @@ var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n,
210
265
  ...n === void 0 ? {} : { id: String(n) },
211
266
  attributes: r
212
267
  };
213
- }, j = (e, t, n) => {
268
+ }, R = (e, t, n) => {
214
269
  if (e.encodeSuccess !== void 0) return e.encodeSuccess(t, n);
215
- let { cursor: r } = O(t, e.cursorField), i = e.pagination === "link-header" && r !== void 0 ? { Link: k(n, r, e.cursorParam) } : void 0, a = (e, t) => ({
270
+ let { cursor: r } = F(t, e.cursorField), i = e.pagination === "link-header" && r !== void 0 ? { Link: I(n, r, e.cursorParam) } : void 0, a = (e, t) => ({
216
271
  body: e,
217
272
  ...i ? { headers: i } : {},
218
273
  ...t ? { contentType: t } : {}
@@ -224,9 +279,9 @@ var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n,
224
279
  });
225
280
  let o = n.source ?? n.tag.split(".")[0] ?? "resource", s = Array.isArray(t) ? t : typeof t == "object" && t && Array.isArray(t.items) ? t.items : void 0;
226
281
  return a({
227
- data: s === void 0 ? A(t, o) : s.map((e) => A(e, o)),
228
- ...r === void 0 ? {} : { links: { next: k(n, r, e.cursorParam).replace(/^<|>; rel="next"$/g, "") } }
229
- }, E);
282
+ data: s === void 0 ? L(t, o) : s.map((e) => L(e, o)),
283
+ ...r === void 0 ? {} : { links: { next: I(n, r, e.cursorParam).replace(/^<|>; rel="next"$/g, "") } }
284
+ }, N);
230
285
  };
231
286
  //#endregion
232
- export { i as S, o as _, j as a, r as b, S as c, v as d, p as f, u as g, a as h, D as i, _ as l, d as m, T as n, k as o, m as p, g as r, w as s, E as t, x as u, c as v, l as x, s as y };
287
+ export { c as C, i as D, l as E, o as S, r as T, m as _, R as a, a as b, k as c, T as d, b as f, g, _ as h, P as i, w as l, v as m, M as n, I as o, x as p, C as r, j as s, N as t, O as u, h as v, s as w, u as x, d as y };
@@ -20,6 +20,7 @@ var i = n.Record({
20
20
  type: n.Literal("serviceAccount"),
21
21
  id: n.String,
22
22
  tenantId: n.String,
23
+ auditActorId: n.optionalWith(n.NullOr(n.String), { exact: !0 }),
23
24
  scopes: a,
24
25
  metadata: n.optional(i)
25
26
  }), l = n.Struct({
@@ -42,24 +43,31 @@ var i = n.Record({
42
43
  id: null,
43
44
  tenantId: e,
44
45
  ...t === void 0 ? {} : { credentialRejected: t }
45
- }), ee = (e, t = ["admin:full"]) => ({
46
+ }), g = (e, t = ["admin:full"]) => ({
46
47
  type: "system",
47
48
  id: e,
48
49
  tenantId: null,
49
50
  scopes: t
50
- }), te = (e, t) => {
51
+ }), _ = (e) => {
52
+ if (e.type === "system") return null;
53
+ if (e.type === "serviceAccount" && e.auditActorId !== void 0) return e.auditActorId;
54
+ if (e.type !== "apiKey") return e.id;
55
+ let t = e.metadata?.userId;
56
+ return typeof t == "string" && t !== "" ? t : e.id;
57
+ }, ee = (e, t) => {
51
58
  let n = e;
52
59
  return {
53
60
  type: "serviceAccount",
54
61
  id: e.id ?? "system",
55
62
  tenantId: t,
56
- scopes: n.scopes ?? ["admin:full"],
63
+ auditActorId: _(e),
64
+ scopes: m(e),
57
65
  ...n.metadata === void 0 ? {} : { metadata: n.metadata }
58
66
  };
59
- }, g = (e) => e.type === "system", _ = "impersonation", v = (e) => e.metadata?.impersonation ?? null, y = class extends e.Tag("@voltro/Subject")() {}, b = class extends e.Tag("@voltro/ConnectionInfo")() {}, x = class extends r.Tag()("@voltro/AuthMiddleware", { provides: y }) {}, S = class extends r.Tag()("@voltro/ConnectionInfoMiddleware", { provides: b }) {}, ne = (e) => typeof e.mountRoutes == "function", C = (e) => Array.isArray(e) ? {
67
+ }, te = (e) => e.type === "system", ne = "impersonation", v = (e) => e.metadata?.impersonation ?? null, y = class extends e.Tag("@voltro/Subject")() {}, b = class extends e.Tag("@voltro/ConnectionInfo")() {}, x = class extends r.Tag()("@voltro/AuthMiddleware", { provides: y }) {}, S = class extends r.Tag()("@voltro/ConnectionInfoMiddleware", { provides: b }) {}, C = (e) => typeof e.mountRoutes == "function", w = (e) => Array.isArray(e) ? {
60
68
  kind: "grant",
61
69
  scopes: e
62
- } : e, w = (e, t) => {
70
+ } : e, T = (e, t) => {
63
71
  if (t.kind === "vetoed") throw new k({ reason: `${t.code}: ${t.message}` });
64
72
  if (e.type === "anonymous") return {
65
73
  subject: e,
@@ -88,13 +96,13 @@ var i = n.Record({
88
96
  },
89
97
  removed: i
90
98
  };
91
- }, re = 3e4, ie = 1e4, T = (e) => `${e.type}\u0000${e.tenantId ?? ""}\u0000${e.id ?? ""}`, ae = () => {
99
+ }, re = 3e4, ie = 1e4, E = (e) => `${e.type}\u0000${e.tenantId ?? ""}\u0000${e.id ?? ""}`, ae = () => {
92
100
  if (typeof process > "u") return;
93
101
  let e = process.env.VOLTRO_AUTH_SCOPE_CACHE_TTL_MS;
94
102
  if (e === void 0 || e === "") return;
95
103
  let t = Number(e);
96
104
  return Number.isFinite(t) && t >= 0 ? t : void 0;
97
- }, E = (e = {}) => {
105
+ }, D = (e = {}) => {
98
106
  let t = e.ttlMs ?? ae() ?? 3e4, n = e.maxEntries ?? 1e4, r = e.now ?? Date.now, i = /* @__PURE__ */ new Map(), a = () => {
99
107
  if (i.size <= n) return;
100
108
  let e = r();
@@ -134,21 +142,21 @@ var i = n.Record({
134
142
  }, oe = (e) => typeof e.resolve == "function", se = (e) => {
135
143
  let t = e.authorization ?? e.Authorization;
136
144
  if (t !== void 0) return /^Bearer\s+(.+)$/i.exec(t.trim())?.[1]?.trim();
137
- }, D = (e, t) => {
145
+ }, O = (e, t) => {
138
146
  let n = se(t);
139
147
  if (n === void 0) return e;
140
148
  let r = e.filter((e) => e.claimsBearerPrefix !== void 0 && e.claimsBearerPrefix !== "" && n.startsWith(e.claimsBearerPrefix));
141
149
  if (r.length === 0) return e;
142
150
  let i = new Set(r);
143
151
  return [...r, ...e.filter((e) => !i.has(e))];
144
- }, O = (e, t) => {
145
- let n = t?.resolveScopes, r = t?.subjectGuards ?? [], i = n !== void 0 || r.length > 0, a = !i || t?.scopeCache === !1 ? null : t?.scopeCache !== void 0 && oe(t.scopeCache) ? t.scopeCache : E(t?.scopeCache ?? {});
152
+ }, ce = (e, t) => {
153
+ let n = t?.resolveScopes, r = t?.subjectGuards ?? [], i = n !== void 0 || r.length > 0, a = !i || t?.scopeCache === !1 ? null : t?.scopeCache !== void 0 && oe(t.scopeCache) ? t.scopeCache : D(t?.scopeCache ?? {});
146
154
  return async (o) => {
147
155
  let s = t?.getStore?.(), c = s === void 0 ? o : {
148
156
  ...o,
149
157
  store: s
150
158
  }, l;
151
- for (let o of D(e, c.headers)) {
159
+ for (let o of O(e, c.headers)) {
152
160
  let e = await o.resolve(c);
153
161
  if (e.kind === "matched") {
154
162
  let s = e.subject;
@@ -157,9 +165,9 @@ var i = n.Record({
157
165
  let t = n === void 0 ? {
158
166
  kind: "grant",
159
167
  scopes: []
160
- } : C(await n(e.subject, c));
168
+ } : w(await n(e.subject, c));
161
169
  if (t.kind === "unavailable" || r.length === 0) return t;
162
- let i = w(e.subject, t).subject, a = {
170
+ let i = T(e.subject, t).subject, a = {
163
171
  origin: "request",
164
172
  headers: c.headers,
165
173
  clientId: c.clientId,
@@ -177,7 +185,7 @@ var i = n.Record({
177
185
  }, { decision: l, fresh: u } = a === null ? {
178
186
  decision: await i(),
179
187
  fresh: !0
180
- } : await a.resolve(T(e.subject), i);
188
+ } : await a.resolve(E(e.subject), i);
181
189
  if (l.kind === "vetoed") {
182
190
  let e = `${l.code}: ${l.message}`;
183
191
  throw t?.onStrategyFailed?.({
@@ -192,7 +200,7 @@ var i = n.Record({
192
200
  reason: e
193
201
  }), new k({ reason: e });
194
202
  }
195
- let d = w(e.subject, l);
203
+ let d = T(e.subject, l);
196
204
  u && d.removed.length > 0 && t?.onScopesNarrowed?.({
197
205
  strategyId: o.id,
198
206
  subjectType: e.subject.type,
@@ -245,9 +253,24 @@ var i = n.Record({
245
253
  }, H = (e, n) => B(e, n) ? t.void : t.fail(new F({
246
254
  required: n,
247
255
  message: `missing required scope '${n}'`
248
- })), U = (e) => typeof e.action == "string" && typeof e.resourceType == "string", W = (e) => typeof e.open == "string", G = (e) => e.authenticated === !0, K = (e) => ({ open: e }), q = (e) => typeof e == "string" ? [e] : e, J, ce = (e) => {
256
+ })), U = (e, t) => {
257
+ let n;
258
+ try {
259
+ n = typeof e.action == "function" ? e.action(t) : e.action;
260
+ } catch {
261
+ throw new F({
262
+ required: e.resourceType,
263
+ message: "policy action selector failed"
264
+ });
265
+ }
266
+ if (typeof n != "string" || n.trim() === "") throw new F({
267
+ required: e.resourceType,
268
+ message: "policy action selector returned no action"
269
+ });
270
+ return n;
271
+ }, W = (e) => (typeof e.action == "string" || typeof e.action == "function") && typeof e.resourceType == "string", G = (e) => typeof e.open == "string", K = (e) => e.authenticated === !0, le = (e) => ({ open: e }), q = (e) => typeof e == "string" ? [e] : e, J, ue = (e) => {
249
272
  J = e;
250
- }, le = (e) => J === void 0 ? e.filter((e) => (e.guards ?? []).some((e) => !U(e) && e.resource !== void 0)).map((e) => e.tag) : [], ue = (e) => [
273
+ }, Y = (e) => J === void 0 ? e.filter((e) => (e.guards ?? []).some((e) => !W(e) && e.resource !== void 0)).map((e) => e.tag) : [], de = (e) => [
251
274
  `${e.length} procedure${e.length === 1 ? "" : "s"} declare a per-resource guard that nothing enforces:`,
252
275
  ...e.slice(0, 10).map((e) => ` ${e}`),
253
276
  ...e.length > 10 ? [` … and ${e.length - 10} more`] : [],
@@ -261,9 +284,9 @@ var i = n.Record({
261
284
  " • setResourceScopeResolver((req) => Effect<boolean>) — answers \"does this",
262
285
  " subject hold `req.scope` on `req.resource`\" from your own tables.",
263
286
  " • Drop the `resource` extractor if a global scope check is what you meant."
264
- ].join("\n"), de = () => J, Y, fe = (e) => {
265
- Y = e;
266
- }, X = () => Y, Z = (e) => new F({
287
+ ].join("\n"), fe = () => J, X, pe = (e) => {
288
+ X = e;
289
+ }, me = () => X, Z = (e) => new F({
267
290
  required: "access-decision",
268
291
  message: `${e ?? "this procedure"} declares no access decision: it has neither \`guards:\` nor \`openAccess:\`, and the app runs with \`security.defaultDeny\`. Add the scope(s) a caller must hold (\`guards: [{ scope: '…' }]\`), or declare it open on purpose with \`openAccess: '<why anyone may call this>'\`.`
269
292
  }), Q = (e, t) => {
@@ -272,15 +295,15 @@ var i = n.Record({
272
295
  }, $ = (e, t, n) => {
273
296
  if (!t || t.length === 0) return n?.defaultDeny === !0 ? Z(n.procedure) : null;
274
297
  for (let n of t) {
275
- if (W(n)) continue;
276
- if (G(n)) {
298
+ if (G(n)) continue;
299
+ if (K(n)) {
277
300
  if (e.id !== null && e.id !== void 0) continue;
278
301
  return Q(e, new F({
279
302
  required: "authenticated",
280
303
  message: "this procedure requires an authenticated caller"
281
304
  }));
282
305
  }
283
- if (U(n)) {
306
+ if (W(n)) {
284
307
  if (B(e, "admin:full")) continue;
285
308
  return Q(e, new F({
286
309
  required: `${n.resourceType}:${n.action}`,
@@ -299,36 +322,42 @@ var i = n.Record({
299
322
  }
300
323
  }
301
324
  return null;
302
- }, pe = (e, n, r) => {
303
- let i = (e) => new F({
304
- required: `${n.resourceType}:${n.action}`,
325
+ }, he = (e, n, r) => {
326
+ let i;
327
+ try {
328
+ i = U(n, r);
329
+ } catch (e) {
330
+ return t.succeed(e);
331
+ }
332
+ let a = (e) => new F({
333
+ required: `${n.resourceType}:${i}`,
305
334
  message: e
306
335
  });
307
336
  if (B(e, "admin:full")) return t.succeed(null);
308
- let a = Y;
309
- if (a === void 0) return t.succeed(i(`no policy resolver registered — cannot authorize '${n.action}' on '${n.resourceType}'`));
310
- let o = n.resource(r);
311
- return o === void 0 || o === "" ? t.succeed(i(`input does not identify a '${n.resourceType}' to authorize`)) : t.suspend(() => a({
337
+ let o = X;
338
+ if (o === void 0) return t.succeed(a(`no policy resolver registered — cannot authorize '${i}' on '${n.resourceType}'`));
339
+ let s = n.resource(r);
340
+ return s === void 0 || s === "" ? t.succeed(a(`input does not identify a '${n.resourceType}' to authorize`)) : t.suspend(() => o({
312
341
  subject: e,
313
- action: n.action,
342
+ action: i,
314
343
  resourceType: n.resourceType,
315
- resourceId: o
316
- })).pipe(t.catchAllCause(() => t.succeed(!1)), t.map((e) => e ? null : i(`no '${n.action}' relation on ${n.resourceType}:${o}`)));
317
- }, me = (e, n, r, i) => {
344
+ resourceId: s
345
+ })).pipe(t.catchAllCause(() => t.succeed(!1)), t.map((e) => e ? null : a(`no '${i}' relation on ${n.resourceType}:${s}`)));
346
+ }, ge = (e, n, r, i) => {
318
347
  if (!n || n.length === 0) return t.succeed($(e, n, i));
319
348
  let a = J;
320
- return !n.some(U) && (!a || !n.some((e) => e.resource !== void 0)) ? t.succeed($(e, n, i)) : t.gen(function* () {
349
+ return !n.some(W) && (!a || !n.some((e) => e.resource !== void 0)) ? t.succeed($(e, n, i)) : t.gen(function* () {
321
350
  for (let i of n) {
322
- if (W(i)) continue;
323
- if (G(i)) {
351
+ if (G(i)) continue;
352
+ if (K(i)) {
324
353
  if (e.id !== null && e.id !== void 0) continue;
325
354
  return Q(e, new F({
326
355
  required: "authenticated",
327
356
  message: "this procedure requires an authenticated caller"
328
357
  }));
329
358
  }
330
- if (U(i)) {
331
- let t = yield* pe(e, i, r);
359
+ if (W(i)) {
360
+ let t = yield* he(e, i, r);
332
361
  if (t) return t;
333
362
  continue;
334
363
  }
@@ -362,4 +391,4 @@ var i = n.Record({
362
391
  });
363
392
  };
364
393
  //#endregion
365
- export { _ as A, g as B, ce as C, S as D, b as E, h as F, p as G, D as H, w as I, ee as K, A as L, f as M, y as N, ie as O, k as P, O as R, fe as S, x as T, v as U, E as V, T as W, U as _, F as a, H as b, me as c, X as d, de as f, W as g, G as h, M as i, d as j, re as k, z as l, V as m, N as n, ue as o, B as p, te as q, P as r, $ as s, j as t, le as u, Z as v, I as w, R as x, K as y, ne as z };
394
+ export { re as A, C as B, pe as C, b as D, x as E, k as F, E as G, D as H, h as I, g as J, _ as K, T as L, d as M, f as N, S as O, y as P, A as R, R as S, I as T, O as U, te as V, v as W, ee as Y, W as _, F as a, H as b, ge as c, me as d, fe as f, G as g, K as h, M as i, ne as j, ie as k, z as l, V as m, N as n, de as o, B as p, p as q, P as r, $ as s, j as t, Y as u, Z as v, ue as w, U as x, le as y, ce as z };
package/dist/session.d.ts CHANGED
@@ -176,6 +176,9 @@ declare const SessionPayload_2: Schema.Struct<{
176
176
  id: typeof Schema.String;
177
177
  tenantId: typeof Schema.String;
178
178
  metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
179
+ auditActorId: Schema.optionalWith<Schema.NullOr<typeof Schema.String>, {
180
+ exact: true;
181
+ }>;
179
182
  }>, Schema.Struct<{
180
183
  type: Schema.Literal<["anonymous"]>;
181
184
  id: typeof Schema.Null;
@@ -274,6 +277,11 @@ declare const Subject: Schema.Union<[Schema.Struct<{
274
277
  type: Schema.Literal<["serviceAccount"]>;
275
278
  id: typeof Schema.String;
276
279
  tenantId: typeof Schema.String;
280
+ /** Application actor used for audit columns; null means machine work with
281
+ * no application actor. Identity only, never a permission grant. */
282
+ auditActorId: Schema.optionalWith<Schema.NullOr<typeof Schema.String>, {
283
+ exact: true;
284
+ }>;
277
285
  scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
278
286
  metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
279
287
  }>, Schema.Struct<{
@@ -322,6 +330,9 @@ declare const SubjectIdentity: Schema.Union<[Schema.Struct<{
322
330
  id: typeof Schema.String;
323
331
  tenantId: typeof Schema.String;
324
332
  metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
333
+ auditActorId: Schema.optionalWith<Schema.NullOr<typeof Schema.String>, {
334
+ exact: true;
335
+ }>;
325
336
  }>, Schema.Struct<{
326
337
  type: Schema.Literal<["anonymous"]>;
327
338
  id: typeof Schema.Null;
package/dist/session.js CHANGED
@@ -1,11 +1,11 @@
1
- import { G as e, M as t, w as n } from "./scopes-DVtiKKsm.js";
1
+ import { N as e, T as t, q as n } from "./scopes-CW9_LbDO.js";
2
2
  import { Schema as r } from "effect";
3
3
  import { createHmac as i, timingSafeEqual as a } from "node:crypto";
4
4
  import { createLogger as o } from "@voltro/logger";
5
5
  //#region src/session.ts
6
6
  var s = o({ scope: "@voltro/protocol:session" }), c = 2, l = r.Struct({
7
7
  v: r.Literal(2),
8
- subject: t,
8
+ subject: e,
9
9
  exp: r.Number,
10
10
  iat: r.Number,
11
11
  kid: r.optional(r.String)
@@ -38,14 +38,14 @@ var s = o({ scope: "@voltro/protocol:session" }), c = 2, l = r.Struct({
38
38
  }, C = 604800, w = .7, T = (e, t) => x(i("sha256", t).update(e).digest()), E = (e) => typeof e == "string" ? {
39
39
  kid: "k0",
40
40
  secret: e
41
- } : e, D = (t, r, i = {}) => {
41
+ } : e, D = (e, r, i = {}) => {
42
42
  let a = E(r);
43
43
  if (!a.secret) throw Error("signSession: secret must be a non-empty string");
44
- let o = n(t);
45
- if (o.length > 0) throw Error(`signSession: refusing to mint a session cookie for a ${t.type} subject carrying ${o.length} scope(s) (${o.slice(0, 5).join(", ")}). A session cookie carries IDENTITY only — authority is resolved per request, so that removing a role takes effect on the session that already exists instead of in up to 7 days. Mint the session from the identity and move the scopes into the auth.resolveScopes resolver, which runs on every request and can be invalidated the moment a role changes.`);
44
+ let o = t(e);
45
+ if (o.length > 0) throw Error(`signSession: refusing to mint a session cookie for a ${e.type} subject carrying ${o.length} scope(s) (${o.slice(0, 5).join(", ")}). A session cookie carries IDENTITY only — authority is resolved per request, so that removing a role takes effect on the session that already exists instead of in up to 7 days. Mint the session from the identity and move the scopes into the auth.resolveScopes resolver, which runs on every request and can be invalidated the moment a role changes.`);
46
46
  let s = i.ttlSeconds ?? C, c = Math.floor((i.now ?? Date.now)() / 1e3), l = {
47
47
  v: 2,
48
- subject: e(t),
48
+ subject: n(e),
49
49
  exp: c + s,
50
50
  iat: c,
51
51
  ...typeof r == "string" ? {} : { kid: a.kid }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/protocol",
3
- "version": "0.70.0",
3
+ "version": "0.71.0",
4
4
  "description": "The Voltro wire + plugin contract — defineQuery/Mutation/Action/Stream, definePlugin, sessions / JWT / API-keys, and the RPC protocol.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -48,7 +48,12 @@
48
48
  "import": "./dist/identity.js",
49
49
  "default": "./dist/identity.js"
50
50
  },
51
- "./package.json": "./package.json"
51
+ "./package.json": "./package.json",
52
+ "./inspect": {
53
+ "types": "./dist/inspect.d.ts",
54
+ "import": "./dist/inspect.js",
55
+ "default": "./dist/inspect.js"
56
+ }
52
57
  },
53
58
  "main": "./dist/index.js",
54
59
  "module": "./dist/index.js",
@@ -59,8 +64,8 @@
59
64
  },
60
65
  "dependencies": {
61
66
  "@effect/sql": "^0.52.1",
62
- "@voltro/database": "0.70.0",
63
- "@voltro/logger": "0.70.0",
67
+ "@voltro/database": "0.71.0",
68
+ "@voltro/logger": "0.71.0",
64
69
  "jose": "^6.2.10"
65
70
  },
66
71
  "peerDependencies": {