@voltro/protocol 0.67.0 → 0.69.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 +437 -0
- package/dist/index.d.ts +106 -4
- package/dist/index.js +552 -497
- package/dist/rest.js +1 -1
- package/dist/{scopes-C86BDyNJ.js → scopes-DVtiKKsm.js} +25 -15
- package/dist/session.js +6 -6
- package/package.json +3 -3
package/dist/rest.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { F as e, P as t } from "./scopes-
|
|
1
|
+
import { F as e, P as t } from "./scopes-DVtiKKsm.js";
|
|
2
2
|
import { c as n, l as r, o as i, s as a, t as o } from "./serverErrorBus-BTnTpMqj.js";
|
|
3
3
|
import { Effect as s, Schema as c } from "effect";
|
|
4
4
|
//#region src/publicApi.ts
|
|
@@ -88,14 +88,14 @@ var i = n.Record({
|
|
|
88
88
|
},
|
|
89
89
|
removed: i
|
|
90
90
|
};
|
|
91
|
-
},
|
|
91
|
+
}, re = 3e4, ie = 1e4, T = (e) => `${e.type}\u0000${e.tenantId ?? ""}\u0000${e.id ?? ""}`, ae = () => {
|
|
92
92
|
if (typeof process > "u") return;
|
|
93
93
|
let e = process.env.VOLTRO_AUTH_SCOPE_CACHE_TTL_MS;
|
|
94
94
|
if (e === void 0 || e === "") return;
|
|
95
95
|
let t = Number(e);
|
|
96
96
|
return Number.isFinite(t) && t >= 0 ? t : void 0;
|
|
97
|
-
},
|
|
98
|
-
let t = e.ttlMs ??
|
|
97
|
+
}, E = (e = {}) => {
|
|
98
|
+
let t = e.ttlMs ?? ae() ?? 3e4, n = e.maxEntries ?? 1e4, r = e.now ?? Date.now, i = /* @__PURE__ */ new Map(), a = () => {
|
|
99
99
|
if (i.size <= n) return;
|
|
100
100
|
let e = r();
|
|
101
101
|
for (let [t, n] of i) n.freshUntil <= e && i.delete(t);
|
|
@@ -131,14 +131,24 @@ var i = n.Record({
|
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
};
|
|
134
|
-
},
|
|
135
|
-
let
|
|
134
|
+
}, oe = (e) => typeof e.resolve == "function", se = (e) => {
|
|
135
|
+
let t = e.authorization ?? e.Authorization;
|
|
136
|
+
if (t !== void 0) return /^Bearer\s+(.+)$/i.exec(t.trim())?.[1]?.trim();
|
|
137
|
+
}, D = (e, t) => {
|
|
138
|
+
let n = se(t);
|
|
139
|
+
if (n === void 0) return e;
|
|
140
|
+
let r = e.filter((e) => e.claimsBearerPrefix !== void 0 && e.claimsBearerPrefix !== "" && n.startsWith(e.claimsBearerPrefix));
|
|
141
|
+
if (r.length === 0) return e;
|
|
142
|
+
let i = new Set(r);
|
|
143
|
+
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 ?? {});
|
|
136
146
|
return async (o) => {
|
|
137
147
|
let s = t?.getStore?.(), c = s === void 0 ? o : {
|
|
138
148
|
...o,
|
|
139
149
|
store: s
|
|
140
150
|
}, l;
|
|
141
|
-
for (let o of e) {
|
|
151
|
+
for (let o of D(e, c.headers)) {
|
|
142
152
|
let e = await o.resolve(c);
|
|
143
153
|
if (e.kind === "matched") {
|
|
144
154
|
let s = e.subject;
|
|
@@ -167,7 +177,7 @@ var i = n.Record({
|
|
|
167
177
|
}, { decision: l, fresh: u } = a === null ? {
|
|
168
178
|
decision: await i(),
|
|
169
179
|
fresh: !0
|
|
170
|
-
} : await a.resolve(
|
|
180
|
+
} : await a.resolve(T(e.subject), i);
|
|
171
181
|
if (l.kind === "vetoed") {
|
|
172
182
|
let e = `${l.code}: ${l.message}`;
|
|
173
183
|
throw t?.onStrategyFailed?.({
|
|
@@ -235,9 +245,9 @@ var i = n.Record({
|
|
|
235
245
|
}, H = (e, n) => B(e, n) ? t.void : t.fail(new F({
|
|
236
246
|
required: n,
|
|
237
247
|
message: `missing required scope '${n}'`
|
|
238
|
-
})), 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,
|
|
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) => {
|
|
239
249
|
J = e;
|
|
240
|
-
},
|
|
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) => [
|
|
241
251
|
`${e.length} procedure${e.length === 1 ? "" : "s"} declare a per-resource guard that nothing enforces:`,
|
|
242
252
|
...e.slice(0, 10).map((e) => ` ${e}`),
|
|
243
253
|
...e.length > 10 ? [` … and ${e.length - 10} more`] : [],
|
|
@@ -251,9 +261,9 @@ var i = n.Record({
|
|
|
251
261
|
" • setResourceScopeResolver((req) => Effect<boolean>) — answers \"does this",
|
|
252
262
|
" subject hold `req.scope` on `req.resource`\" from your own tables.",
|
|
253
263
|
" • Drop the `resource` extractor if a global scope check is what you meant."
|
|
254
|
-
].join("\n"),
|
|
264
|
+
].join("\n"), de = () => J, Y, fe = (e) => {
|
|
255
265
|
Y = e;
|
|
256
|
-
},
|
|
266
|
+
}, X = () => Y, Z = (e) => new F({
|
|
257
267
|
required: "access-decision",
|
|
258
268
|
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>'\`.`
|
|
259
269
|
}), Q = (e, t) => {
|
|
@@ -289,7 +299,7 @@ var i = n.Record({
|
|
|
289
299
|
}
|
|
290
300
|
}
|
|
291
301
|
return null;
|
|
292
|
-
},
|
|
302
|
+
}, pe = (e, n, r) => {
|
|
293
303
|
let i = (e) => new F({
|
|
294
304
|
required: `${n.resourceType}:${n.action}`,
|
|
295
305
|
message: e
|
|
@@ -304,7 +314,7 @@ var i = n.Record({
|
|
|
304
314
|
resourceType: n.resourceType,
|
|
305
315
|
resourceId: o
|
|
306
316
|
})).pipe(t.catchAllCause(() => t.succeed(!1)), t.map((e) => e ? null : i(`no '${n.action}' relation on ${n.resourceType}:${o}`)));
|
|
307
|
-
},
|
|
317
|
+
}, me = (e, n, r, i) => {
|
|
308
318
|
if (!n || n.length === 0) return t.succeed($(e, n, i));
|
|
309
319
|
let a = J;
|
|
310
320
|
return !n.some(U) && (!a || !n.some((e) => e.resource !== void 0)) ? t.succeed($(e, n, i)) : t.gen(function* () {
|
|
@@ -318,7 +328,7 @@ var i = n.Record({
|
|
|
318
328
|
}));
|
|
319
329
|
}
|
|
320
330
|
if (U(i)) {
|
|
321
|
-
let t = yield*
|
|
331
|
+
let t = yield* pe(e, i, r);
|
|
322
332
|
if (t) return t;
|
|
323
333
|
continue;
|
|
324
334
|
}
|
|
@@ -352,4 +362,4 @@ var i = n.Record({
|
|
|
352
362
|
});
|
|
353
363
|
};
|
|
354
364
|
//#endregion
|
|
355
|
-
export { _ as A, g as B,
|
|
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 };
|
package/dist/session.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { G as e, M as t, w as n } from "./scopes-DVtiKKsm.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:
|
|
8
|
+
subject: t,
|
|
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 = (
|
|
41
|
+
} : e, D = (t, 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(
|
|
45
|
-
if (o.length > 0) throw Error(`signSession: refusing to mint a session cookie for a ${
|
|
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.`);
|
|
46
46
|
let s = i.ttlSeconds ?? C, c = Math.floor((i.now ?? Date.now)() / 1e3), l = {
|
|
47
47
|
v: 2,
|
|
48
|
-
subject: t
|
|
48
|
+
subject: e(t),
|
|
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.
|
|
3
|
+
"version": "0.69.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",
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@effect/sql": "^0.52.1",
|
|
62
|
-
"@voltro/database": "0.
|
|
63
|
-
"@voltro/logger": "0.
|
|
62
|
+
"@voltro/database": "0.69.0",
|
|
63
|
+
"@voltro/logger": "0.69.0",
|
|
64
64
|
"jose": "^6.2.10"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|