@voltro/protocol 0.75.0 → 0.76.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.
- package/CHANGELOG.md +404 -0
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/index.d.ts +100 -3
- package/dist/index.js +243 -210
- package/dist/rest.js +1 -1
- package/dist/{scopes-Dj7KCJab.js → scopes-D2dnEr4U.js} +51 -48
- package/dist/session.js +1 -1
- package/package.json +6 -6
package/dist/rest.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as e, L as t } from "./scopes-
|
|
1
|
+
import { I as e, L as t } from "./scopes-D2dnEr4U.js";
|
|
2
2
|
import { C as n, S as r, T as i, _ as a, a as o, c as s, d as c, f as l, i as u, l as d, n as f, o as p, r as m, s as h, t as g, u as _, v, w as y } from "./restFormat-ChSVyufA.js";
|
|
3
3
|
import { Effect as b, ParseResult as x, Schema as S } from "effect";
|
|
4
4
|
import * as C from "effect/SchemaAST";
|
|
@@ -63,7 +63,7 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
63
63
|
tenantId: n.Null,
|
|
64
64
|
scopes: c,
|
|
65
65
|
metadata: n.optional(s)
|
|
66
|
-
}),
|
|
66
|
+
}), m = n.Union(l, u, d, f, p), h = n.Union(l.omit("scopes"), u.omit("scopes"), d.omit("scopes"), f, p.omit("scopes")), ee = (e) => {
|
|
67
67
|
if (e.type === "anonymous") return e;
|
|
68
68
|
let { scopes: t, ...n } = e;
|
|
69
69
|
return n;
|
|
@@ -72,32 +72,35 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
72
72
|
id: null,
|
|
73
73
|
tenantId: e,
|
|
74
74
|
...t === void 0 ? {} : { credentialRejected: t }
|
|
75
|
-
}),
|
|
75
|
+
}), v = (e, t = ["admin:full"]) => ({
|
|
76
76
|
type: "system",
|
|
77
77
|
id: e,
|
|
78
78
|
tenantId: null,
|
|
79
79
|
scopes: t
|
|
80
|
-
}),
|
|
80
|
+
}), y = (e) => {
|
|
81
81
|
if (e.type === "system") return null;
|
|
82
82
|
if (e.type === "serviceAccount" && e.auditActorId !== void 0) return e.auditActorId;
|
|
83
83
|
if (e.type !== "apiKey") return e.id;
|
|
84
84
|
let t = e.metadata?.userId;
|
|
85
85
|
return typeof t == "string" && t !== "" ? t : e.id;
|
|
86
|
-
},
|
|
86
|
+
}, te = (e, t) => {
|
|
87
87
|
let n = e;
|
|
88
88
|
return {
|
|
89
89
|
type: "serviceAccount",
|
|
90
90
|
id: e.id ?? "system",
|
|
91
91
|
tenantId: t,
|
|
92
|
-
auditActorId:
|
|
92
|
+
auditActorId: y(e),
|
|
93
93
|
scopes: g(e),
|
|
94
94
|
...n.metadata === void 0 ? {} : { metadata: n.metadata }
|
|
95
95
|
};
|
|
96
|
-
},
|
|
96
|
+
}, ne = (e) => e.type === "system", b = "impersonation", x = (e) => e.metadata?.impersonation ?? null, S = class extends e.Tag("@voltro/Subject")() {}, C = class extends e.Tag("@voltro/ConnectionInfo")() {}, w = class extends n.TaggedError()("Unauthenticated", { reason: n.optional(n.String) }) {}, T = class extends r.Tag()("@voltro/AuthMiddleware", {
|
|
97
|
+
provides: S,
|
|
98
|
+
failure: w
|
|
99
|
+
}) {}, re = class extends r.Tag()("@voltro/ConnectionInfoMiddleware", { provides: C }) {}, ie = (e) => typeof e.mountRoutes == "function", ae = (e) => Array.isArray(e) ? {
|
|
97
100
|
kind: "grant",
|
|
98
101
|
scopes: e
|
|
99
|
-
} : e,
|
|
100
|
-
if (t.kind === "vetoed") throw new
|
|
102
|
+
} : e, E = (e, t) => {
|
|
103
|
+
if (t.kind === "vetoed") throw new w({ reason: `${t.code}: ${t.message}` });
|
|
101
104
|
if (e.type === "anonymous") return {
|
|
102
105
|
subject: e,
|
|
103
106
|
removed: []
|
|
@@ -125,13 +128,13 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
125
128
|
},
|
|
126
129
|
removed: i
|
|
127
130
|
};
|
|
128
|
-
},
|
|
131
|
+
}, oe = 3e4, se = 1e4, D = (e) => `${e.type}\u0000${e.tenantId ?? ""}\u0000${e.id ?? ""}`, ce = () => {
|
|
129
132
|
if (typeof process > "u") return;
|
|
130
133
|
let e = process.env.VOLTRO_AUTH_SCOPE_CACHE_TTL_MS;
|
|
131
134
|
if (e === void 0 || e === "") return;
|
|
132
135
|
let t = Number(e);
|
|
133
136
|
return Number.isFinite(t) && t >= 0 ? t : void 0;
|
|
134
|
-
},
|
|
137
|
+
}, O = (e = {}) => {
|
|
135
138
|
let t = e.ttlMs ?? ce() ?? 3e4, n = e.maxEntries ?? 1e4, r = e.now ?? Date.now, i = /* @__PURE__ */ new Map(), a = () => {
|
|
136
139
|
if (i.size <= n) return;
|
|
137
140
|
let e = r();
|
|
@@ -200,40 +203,40 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
200
203
|
}
|
|
201
204
|
return e;
|
|
202
205
|
}
|
|
203
|
-
},
|
|
206
|
+
}, k = (e, t) => {
|
|
204
207
|
let n = ue(t);
|
|
205
208
|
if (n === void 0) return e;
|
|
206
209
|
let r = e.filter((e) => e.claimsBearerPrefix !== void 0 && e.claimsBearerPrefix !== "" && n.startsWith(e.claimsBearerPrefix));
|
|
207
210
|
if (r.length === 0) return e;
|
|
208
211
|
let i = new Set(r);
|
|
209
212
|
return [...r, ...e.filter((e) => !i.has(e))];
|
|
210
|
-
},
|
|
213
|
+
}, A = (e, t) => {
|
|
211
214
|
let n = t?.resolveScopes, r = t?.subjectGuards ?? [];
|
|
212
215
|
if (t?.memberships === void 0 != (t?.tenantSelection === void 0)) throw Error("composeAuthStrategies: `memberships` and `tenantSelection` come together — a tenant selection is verified against the memberships and read from the store; configure both or neither.");
|
|
213
216
|
let i = t?.memberships !== void 0 && t.tenantSelection !== void 0 ? {
|
|
214
217
|
memberships: t.memberships,
|
|
215
218
|
store: t.tenantSelection
|
|
216
|
-
} : void 0, a = n !== void 0 || r.length > 0, o = !a || t?.scopeCache === !1 ? null : t?.scopeCache !== void 0 && le(t.scopeCache) ? t.scopeCache :
|
|
219
|
+
} : void 0, a = n !== void 0 || r.length > 0, o = !a || t?.scopeCache === !1 ? null : t?.scopeCache !== void 0 && le(t.scopeCache) ? t.scopeCache : O(t?.scopeCache ?? {});
|
|
217
220
|
return async (s) => {
|
|
218
221
|
let c = t?.getStore?.(), l = c === void 0 ? s : {
|
|
219
222
|
...s,
|
|
220
223
|
store: c
|
|
221
224
|
}, u;
|
|
222
|
-
for (let s of
|
|
225
|
+
for (let s of k(e, l.headers)) {
|
|
223
226
|
let e = await s.resolve(l);
|
|
224
227
|
if (e.kind === "matched") {
|
|
225
228
|
let c = i === void 0 ? e.subject : await de(e.subject, l, i, (e) => (t?.onStrategyFailed?.({
|
|
226
229
|
strategyId: s.id,
|
|
227
230
|
reason: e
|
|
228
|
-
}), new
|
|
231
|
+
}), new w({ reason: e }))), u = c;
|
|
229
232
|
if (a) {
|
|
230
233
|
let e = async () => {
|
|
231
234
|
let e = n === void 0 ? {
|
|
232
235
|
kind: "grant",
|
|
233
236
|
scopes: []
|
|
234
|
-
} :
|
|
237
|
+
} : ae(await n(c, l));
|
|
235
238
|
if (e.kind === "unavailable" || r.length === 0) return e;
|
|
236
|
-
let t =
|
|
239
|
+
let t = E(c, e).subject, i = {
|
|
237
240
|
origin: "request",
|
|
238
241
|
headers: l.headers,
|
|
239
242
|
clientId: l.clientId,
|
|
@@ -251,22 +254,22 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
251
254
|
}, { decision: i, fresh: a } = o === null ? {
|
|
252
255
|
decision: await e(),
|
|
253
256
|
fresh: !0
|
|
254
|
-
} : await o.resolve(
|
|
257
|
+
} : await o.resolve(D(c), e);
|
|
255
258
|
if (i.kind === "vetoed") {
|
|
256
259
|
let e = `${i.code}: ${i.message}`;
|
|
257
260
|
throw t?.onStrategyFailed?.({
|
|
258
261
|
strategyId: s.id,
|
|
259
262
|
reason: e
|
|
260
|
-
}), new
|
|
263
|
+
}), new w({ reason: e });
|
|
261
264
|
}
|
|
262
265
|
if (i.kind === "unavailable") {
|
|
263
266
|
let e = `scope resolution unavailable: ${i.reason}`;
|
|
264
267
|
throw t?.onStrategyFailed?.({
|
|
265
268
|
strategyId: s.id,
|
|
266
269
|
reason: e
|
|
267
|
-
}), new
|
|
270
|
+
}), new w({ reason: e });
|
|
268
271
|
}
|
|
269
|
-
let d =
|
|
272
|
+
let d = E(c, i);
|
|
270
273
|
a && d.removed.length > 0 && t?.onScopesNarrowed?.({
|
|
271
274
|
strategyId: s.id,
|
|
272
275
|
subjectType: c.type,
|
|
@@ -295,14 +298,14 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
295
298
|
credentialRejected: u
|
|
296
299
|
} : e };
|
|
297
300
|
}
|
|
298
|
-
if (u !== void 0) throw new
|
|
301
|
+
if (u !== void 0) throw new w({ reason: `credential rejected: ${u}` });
|
|
299
302
|
if (t?.anonymousTenantId !== void 0) return { subject: _(t.anonymousTenantId) };
|
|
300
303
|
let d = l.headers["x-tenant"] ?? null;
|
|
301
|
-
if (d === null && t?.anonymousTenantRequired === !0) throw new
|
|
304
|
+
if (d === null && t?.anonymousTenantRequired === !0) throw new w({ reason: "tenant required (x-tenant header missing)" });
|
|
302
305
|
return { subject: _(d) };
|
|
303
306
|
};
|
|
304
|
-
},
|
|
305
|
-
if (e.type === "anonymous") throw new
|
|
307
|
+
}, j = (e, t) => {
|
|
308
|
+
if (e.type === "anonymous") throw new w(t === void 0 ? {} : { reason: t });
|
|
306
309
|
}, M = "admin:full", N = "apikeys:issue:self", P = "apikeys:issue:org", F = "apikeys:issue:other", I = "devices:manage", L = class extends n.TaggedError()("ScopeError", {
|
|
307
310
|
required: n.String,
|
|
308
311
|
message: n.String
|
|
@@ -317,13 +320,13 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
317
320
|
}, H = (e, t) => {
|
|
318
321
|
let n = V(e);
|
|
319
322
|
return n.includes("admin:full") || n.includes(t);
|
|
320
|
-
},
|
|
323
|
+
}, fe = (e, t) => {
|
|
321
324
|
let n = R(e);
|
|
322
325
|
return n.includes("admin:full") || n.includes(t);
|
|
323
|
-
},
|
|
326
|
+
}, pe = (e, n) => H(e, n) ? t.void : t.fail(new L({
|
|
324
327
|
required: n,
|
|
325
328
|
message: `missing required scope '${n}'`
|
|
326
|
-
})),
|
|
329
|
+
})), U = (e, t) => {
|
|
327
330
|
let n;
|
|
328
331
|
try {
|
|
329
332
|
n = typeof e.action == "function" ? e.action(t) : e.action;
|
|
@@ -338,9 +341,9 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
338
341
|
message: "policy action selector returned no action"
|
|
339
342
|
});
|
|
340
343
|
return n;
|
|
341
|
-
},
|
|
342
|
-
|
|
343
|
-
},
|
|
344
|
+
}, 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, me = (e) => ({ open: e }), q = (e) => typeof e == "string" ? [e] : e, J, he = (e) => {
|
|
345
|
+
J = e;
|
|
346
|
+
}, ge = (e) => J === void 0 ? e.filter((e) => (e.guards ?? []).some((e) => !W(e) && e.resource !== void 0)).map((e) => e.tag) : [], _e = (e) => [
|
|
344
347
|
`${e.length} procedure${e.length === 1 ? "" : "s"} declare a per-resource guard that nothing enforces:`,
|
|
345
348
|
...e.slice(0, 10).map((e) => ` ${e}`),
|
|
346
349
|
...e.length > 10 ? [` … and ${e.length - 10} more`] : [],
|
|
@@ -354,33 +357,33 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
354
357
|
" • setResourceScopeResolver((req) => Effect<boolean>) — answers \"does this",
|
|
355
358
|
" subject hold `req.scope` on `req.resource`\" from your own tables.",
|
|
356
359
|
" • Drop the `resource` extractor if a global scope check is what you meant."
|
|
357
|
-
].join("\n"),
|
|
358
|
-
|
|
359
|
-
},
|
|
360
|
+
].join("\n"), ve = () => J, Y, ye = (e) => {
|
|
361
|
+
Y = e;
|
|
362
|
+
}, X = () => Y, Z = (e) => new L({
|
|
360
363
|
required: "access-decision",
|
|
361
364
|
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>'\`.`
|
|
362
365
|
}), Q = (e, t) => {
|
|
363
366
|
let n = e.credentialRejected;
|
|
364
|
-
return n === void 0 ? t : new
|
|
367
|
+
return n === void 0 ? t : new w({ reason: `${n} — the request carried a credential and it was REJECTED, so this caller resolved to anonymous. The guard then refused (${t.message}); the scope is not the problem. Re-authenticate and retry.` });
|
|
365
368
|
}, $ = (e, t, n) => {
|
|
366
369
|
if (!t || t.length === 0) return n?.defaultDeny === !0 ? Z(n.procedure) : null;
|
|
367
370
|
for (let n of t) {
|
|
368
|
-
if (
|
|
369
|
-
if (
|
|
371
|
+
if (G(n)) continue;
|
|
372
|
+
if (K(n)) {
|
|
370
373
|
if (e.id !== null && e.id !== void 0) continue;
|
|
371
374
|
return Q(e, new L({
|
|
372
375
|
required: "authenticated",
|
|
373
376
|
message: "this procedure requires an authenticated caller"
|
|
374
377
|
}));
|
|
375
378
|
}
|
|
376
|
-
if (
|
|
379
|
+
if (W(n)) {
|
|
377
380
|
if (H(e, "admin:full")) continue;
|
|
378
381
|
return Q(e, new L({
|
|
379
382
|
required: `${n.resourceType}:${n.action}`,
|
|
380
383
|
message: `relationship guard '${n.action}' on '${n.resourceType}' cannot be checked synchronously`
|
|
381
384
|
}));
|
|
382
385
|
}
|
|
383
|
-
let t =
|
|
386
|
+
let t = q(n.scope);
|
|
384
387
|
if (t.length === 0) continue;
|
|
385
388
|
let r = t.filter((t) => H(e, t));
|
|
386
389
|
if (!((n.mode ?? "all") === "any" ? r.length > 0 : r.length === t.length)) {
|
|
@@ -395,7 +398,7 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
395
398
|
}, be = (e, n, r) => {
|
|
396
399
|
let i;
|
|
397
400
|
try {
|
|
398
|
-
i =
|
|
401
|
+
i = U(n, r);
|
|
399
402
|
} catch (e) {
|
|
400
403
|
return t.succeed(e);
|
|
401
404
|
}
|
|
@@ -404,7 +407,7 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
404
407
|
message: e
|
|
405
408
|
});
|
|
406
409
|
if (H(e, "admin:full")) return t.succeed(null);
|
|
407
|
-
let o =
|
|
410
|
+
let o = Y;
|
|
408
411
|
if (o === void 0) return t.succeed(a(`no policy resolver registered — cannot authorize '${i}' on '${n.resourceType}'`));
|
|
409
412
|
let s = n.resource(r);
|
|
410
413
|
return s === void 0 || s === "" ? t.succeed(a(`input does not identify a '${n.resourceType}' to authorize`)) : t.suspend(() => o({
|
|
@@ -415,23 +418,23 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
415
418
|
})).pipe(t.catchAllCause(() => t.succeed(!1)), t.map((e) => e ? null : a(`no '${i}' relation on ${n.resourceType}:${s}`)));
|
|
416
419
|
}, xe = (e, n, r, i) => {
|
|
417
420
|
if (!n || n.length === 0) return t.succeed($(e, n, i));
|
|
418
|
-
let a =
|
|
419
|
-
return !n.some(
|
|
421
|
+
let a = J;
|
|
422
|
+
return !n.some(W) && (!a || !n.some((e) => e.resource !== void 0)) ? t.succeed($(e, n, i)) : t.gen(function* () {
|
|
420
423
|
for (let i of n) {
|
|
421
|
-
if (
|
|
422
|
-
if (
|
|
424
|
+
if (G(i)) continue;
|
|
425
|
+
if (K(i)) {
|
|
423
426
|
if (e.id !== null && e.id !== void 0) continue;
|
|
424
427
|
return Q(e, new L({
|
|
425
428
|
required: "authenticated",
|
|
426
429
|
message: "this procedure requires an authenticated caller"
|
|
427
430
|
}));
|
|
428
431
|
}
|
|
429
|
-
if (
|
|
432
|
+
if (W(i)) {
|
|
430
433
|
let t = yield* be(e, i, r);
|
|
431
434
|
if (t) return t;
|
|
432
435
|
continue;
|
|
433
436
|
}
|
|
434
|
-
let n =
|
|
437
|
+
let n = q(i.scope);
|
|
435
438
|
if (n.length === 0) continue;
|
|
436
439
|
let o = i.resource ? i.resource(r) : void 0, s = [];
|
|
437
440
|
for (let r of n) {
|
|
@@ -461,4 +464,4 @@ var i = (e) => e.type === "user" || e.type === "apiKey" || e.type === "serviceAc
|
|
|
461
464
|
});
|
|
462
465
|
};
|
|
463
466
|
//#endregion
|
|
464
|
-
export { o as $,
|
|
467
|
+
export { o as $, se as A, A as B, B as C, T as D, R as E, S as F, x as G, ne as H, w as I, ee as J, D as K, _ as L, b as M, m as N, C as O, h as P, i as Q, E as R, U as S, he as T, O as U, ie as V, k as W, te as X, v as Y, a as Z, G as _, I as a, me as b, $ as c, ge as d, X as f, K as g, fe as h, N as i, oe as j, re as k, xe as l, H as m, P as n, L as o, ve as p, y as q, F as r, _e as s, M as t, V as u, W as v, ye as w, pe as x, Z as y, j as z };
|
package/dist/session.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as e, J as t, P as n } from "./scopes-
|
|
1
|
+
import { E as e, J as t, P as n } from "./scopes-D2dnEr4U.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";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.76.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",
|
|
@@ -65,14 +65,14 @@
|
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@effect/experimental": "^0.61.1",
|
|
67
67
|
"@effect/sql": "^0.52.1",
|
|
68
|
-
"@voltro/database": "0.
|
|
69
|
-
"@voltro/logger": "0.
|
|
70
|
-
"jose": "^6.2.
|
|
68
|
+
"@voltro/database": "0.76.0",
|
|
69
|
+
"@voltro/logger": "0.76.0",
|
|
70
|
+
"jose": "^6.2.12"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
|
-
"@effect/platform": "^0.97.
|
|
73
|
+
"@effect/platform": "^0.97.2",
|
|
74
74
|
"@effect/rpc": "^0.76.2",
|
|
75
|
-
"effect": "^3.22.
|
|
75
|
+
"effect": "^3.22.2"
|
|
76
76
|
},
|
|
77
77
|
"publishConfig": {
|
|
78
78
|
"access": "public"
|