@voltro/protocol 0.33.0 → 0.35.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 +1968 -0
- package/dist/auth-B6YZuSBr.js +303 -0
- package/dist/index.d.ts +1082 -36
- package/dist/index.js +468 -333
- package/dist/rest.d.ts +143 -11
- package/dist/rest.js +12 -12
- package/dist/serverErrorBus-BeN9pOpY.js +43 -0
- package/dist/session.d.ts +77 -16
- package/dist/session.js +62 -49
- package/package.json +3 -2
- package/dist/auth-CXMrvPyX.js +0 -90
- package/dist/serverErrorBus-C3JTqgIc.js +0 -157
package/dist/session.js
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Schema as
|
|
3
|
-
import { createHmac as
|
|
1
|
+
import { U as e, s as t, v as n } from "./auth-B6YZuSBr.js";
|
|
2
|
+
import { Schema as r } from "effect";
|
|
3
|
+
import { createHmac as i, timingSafeEqual as a } from "node:crypto";
|
|
4
|
+
import { createLogger as o } from "@voltro/logger";
|
|
4
5
|
//#region src/session.ts
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
var s = o({ scope: "@voltro/protocol:session" }), c = 2, l = r.Struct({
|
|
7
|
+
v: r.Literal(2),
|
|
8
|
+
subject: t,
|
|
9
|
+
exp: r.Number,
|
|
10
|
+
iat: r.Number,
|
|
11
|
+
kid: r.optional(r.String)
|
|
12
|
+
}), u = "k0", d = "k-previous", f = () => {
|
|
11
13
|
throw Error("VOLTRO_SESSION_SECRET is not set. It signs and verifies session cookies, and the framework refuses to invent one at this point: a fixed fallback would be readable by anyone with the source, making every session forgeable. `voltro dev` mints a project-local value into .env.local on boot; for a deployment, generate one with `voltro secret generate session`.");
|
|
12
|
-
},
|
|
13
|
-
kid:
|
|
14
|
-
secret:
|
|
15
|
-
} },
|
|
14
|
+
}, p = () => process.env.VOLTRO_SESSION_SECRET ?? f(), m = () => g() ?? { current: {
|
|
15
|
+
kid: h(),
|
|
16
|
+
secret: p()
|
|
17
|
+
} }, h = () => process.env.VOLTRO_SESSION_KID ?? "k0", g = () => {
|
|
16
18
|
let e = process.env.VOLTRO_SESSION_SECRET;
|
|
17
19
|
if (e === void 0 || e === "") return;
|
|
18
20
|
let t = {
|
|
19
|
-
kid:
|
|
21
|
+
kid: h(),
|
|
20
22
|
secret: e
|
|
21
23
|
}, n = process.env.VOLTRO_SESSION_SECRET_PREVIOUS;
|
|
22
24
|
return n ? {
|
|
@@ -26,51 +28,54 @@ var i = t.Struct({
|
|
|
26
28
|
secret: n
|
|
27
29
|
}
|
|
28
30
|
} : { current: t };
|
|
29
|
-
},
|
|
31
|
+
}, _ = 32, v = (e = process.env) => {
|
|
30
32
|
let t = e.VOLTRO_SESSION_SECRET;
|
|
31
33
|
if (t === void 0 || t === "") throw Error("VOLTRO_SESSION_SECRET is not set — refusing to serve. It signs session cookies, and there is no fallback: a built-in one would be readable by anyone with the source. Generate one with `voltro secret generate session`. (`voltro dev` mints a project-local value automatically; a deployment needs its own.)");
|
|
32
34
|
if (t.length < 32) throw Error(`VOLTRO_SESSION_SECRET is only ${t.length} chars — too short for a session secret (need >= 32). This looks like a placeholder. Generate a real one with \`voltro secret generate session\`.`);
|
|
33
|
-
},
|
|
35
|
+
}, y = r.encodeSync(l), b = r.decodeUnknownSync(l), x = (e) => (typeof e == "string" ? Buffer.from(e, "utf8") : e).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), S = (e) => {
|
|
34
36
|
let t = e.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - e.length % 4) % 4);
|
|
35
37
|
return Buffer.from(t, "base64");
|
|
36
|
-
},
|
|
38
|
+
}, C = 3600 * 24 * 7, w = .7, T = (e, t) => x(i("sha256", t).update(e).digest()), E = (e) => typeof e == "string" ? {
|
|
37
39
|
kid: "k0",
|
|
38
40
|
secret: e
|
|
39
|
-
} : e,
|
|
40
|
-
let
|
|
41
|
-
if (!
|
|
42
|
-
let
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
} : e, D = (t, r, i = {}) => {
|
|
42
|
+
let a = E(r);
|
|
43
|
+
if (!a.secret) throw Error("signSession: secret must be a non-empty string");
|
|
44
|
+
let o = e(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
|
+
let s = i.ttlSeconds ?? C, c = Math.floor((i.now ?? Date.now)() / 1e3), l = {
|
|
47
|
+
v: 2,
|
|
48
|
+
subject: n(t),
|
|
49
|
+
exp: c + s,
|
|
50
|
+
iat: c,
|
|
51
|
+
...typeof r == "string" ? {} : { kid: a.kid }
|
|
52
|
+
}, u = x(JSON.stringify(y(l)));
|
|
53
|
+
return `${u}.${T(u, a.secret)}`;
|
|
54
|
+
}, O = (e, t, n, r) => {
|
|
55
|
+
let o = i("sha256", n).update(e).digest(), s = S(t);
|
|
56
|
+
if (s.length !== o.length || !a(s, o)) return null;
|
|
52
57
|
try {
|
|
53
|
-
let t =
|
|
54
|
-
return n.exp < Math.floor(
|
|
58
|
+
let t = S(e).toString("utf8"), n = b(JSON.parse(t));
|
|
59
|
+
return n.exp < Math.floor(r() / 1e3) ? null : n;
|
|
55
60
|
} catch {
|
|
56
61
|
return null;
|
|
57
62
|
}
|
|
58
|
-
},
|
|
63
|
+
}, k = (e, t) => {
|
|
59
64
|
if (!e || !t) return null;
|
|
60
65
|
let n = e.indexOf(".");
|
|
61
66
|
if (n <= 0 || n === e.length - 1) return null;
|
|
62
|
-
let r =
|
|
67
|
+
let r = O(e.slice(0, n), e.slice(n + 1), t, Date.now);
|
|
63
68
|
return r ? r.subject : null;
|
|
64
|
-
},
|
|
69
|
+
}, A = (e, t, n = {}) => {
|
|
65
70
|
if (!e) return null;
|
|
66
71
|
let r = e.indexOf(".");
|
|
67
72
|
if (r <= 0 || r === e.length - 1) return null;
|
|
68
73
|
let i = e.slice(0, r), a = e.slice(r + 1), o = t.previous ? [t.current, t.previous] : [t.current], s = n.now ?? Date.now;
|
|
69
74
|
for (let e of o) {
|
|
70
75
|
if (!e.secret) continue;
|
|
71
|
-
let t =
|
|
76
|
+
let t = O(i, a, e.secret, s);
|
|
72
77
|
if (!t) continue;
|
|
73
|
-
let r = n.renewFraction ??
|
|
78
|
+
let r = n.renewFraction ?? w, o = Math.floor(s() / 1e3), c = t.exp - t.iat, l = t.iat + c * r;
|
|
74
79
|
return {
|
|
75
80
|
subject: t.subject,
|
|
76
81
|
renew: o >= l,
|
|
@@ -80,14 +85,14 @@ var i = t.Struct({
|
|
|
80
85
|
};
|
|
81
86
|
}
|
|
82
87
|
return null;
|
|
83
|
-
},
|
|
84
|
-
let n = Buffer.from(e, "utf8"),
|
|
85
|
-
return n.length ===
|
|
86
|
-
},
|
|
88
|
+
}, j = (e, t) => {
|
|
89
|
+
let n = Buffer.from(e, "utf8"), r = Buffer.from(t, "utf8");
|
|
90
|
+
return n.length === r.length && a(n, r);
|
|
91
|
+
}, M = (e, t, n) => {
|
|
87
92
|
if (!t || t.length === 0) return n?.openWhenUnset === !0;
|
|
88
93
|
let r = e.authorization ?? e.Authorization;
|
|
89
|
-
return !r || !r.startsWith("Bearer ") ? !1 :
|
|
90
|
-
},
|
|
94
|
+
return !r || !r.startsWith("Bearer ") ? !1 : j(r.slice(7).trim(), t);
|
|
95
|
+
}, N = (e, t) => {
|
|
91
96
|
if (e) for (let n of e.split(";")) {
|
|
92
97
|
let e = n.indexOf("=");
|
|
93
98
|
if (e < 0 || n.slice(0, e).trim() !== t) continue;
|
|
@@ -99,18 +104,26 @@ var i = t.Struct({
|
|
|
99
104
|
return r;
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
|
-
},
|
|
107
|
+
}, P = (e, t, n = {}) => {
|
|
103
108
|
let r = [`${e}=${encodeURIComponent(t)}`];
|
|
104
109
|
if (r.push(`Path=${n.path ?? "/"}`), n.maxAgeSeconds !== void 0 && r.push(`Max-Age=${n.maxAgeSeconds}`), r.push("HttpOnly"), n.httpOnly === !1) {
|
|
105
110
|
let e = r.indexOf("HttpOnly");
|
|
106
111
|
e >= 0 && r.splice(e, 1);
|
|
107
112
|
}
|
|
108
113
|
return r.push(`SameSite=${n.sameSite ?? "Lax"}`), (n.secure ?? !0) && r.push("Secure"), n.domain && r.push(`Domain=${n.domain}`), r.join("; ");
|
|
109
|
-
},
|
|
110
|
-
let t =
|
|
114
|
+
}, F = process.env.VOLTRO_SESSION_COOKIE ?? "voltro:session", I = (e) => {
|
|
115
|
+
let t = N(e.cookie ?? e.Cookie, F);
|
|
111
116
|
if (!t) return;
|
|
112
|
-
let n =
|
|
113
|
-
if (n)
|
|
117
|
+
let n = g();
|
|
118
|
+
if (!n) {
|
|
119
|
+
R();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
return A(t, n)?.exp;
|
|
123
|
+
}, L = !1, R = () => {
|
|
124
|
+
L || (L = !0, s.error("a `voltro:session` cookie was presented but VOLTRO_SESSION_SECRET is not set — the session cannot be verified, so no credential-expiry bound is imposed and realtime subscriptions on this connection will not be cut off when the session expires. Set VOLTRO_SESSION_SECRET (`voltro secret generate session`); `voltro dev` mints one, `voltro serve` refuses to boot without one.", { cookieName: F }));
|
|
125
|
+
}, z = () => {
|
|
126
|
+
L = !1;
|
|
114
127
|
};
|
|
115
128
|
//#endregion
|
|
116
|
-
export {
|
|
129
|
+
export { d as DEFAULT_PREVIOUS_SESSION_KID, u as DEFAULT_SESSION_KID, _ as MIN_SESSION_SECRET_LENGTH, F as SESSION_COOKIE_NAME, c as SESSION_PAYLOAD_VERSION, v as assertProductionSessionSecret, P as buildSetCookie, M as checkBearer, N as readCookie, z as resetSessionSecretWarningLatch, g as resolveOptionalSessionSecrets, p as resolveSessionSecret, m as resolveSessionSecrets, I as sessionExpiryFromHeaders, D as signSession, j as timingSafeStringEqual, k as verifySession, A as verifySessionKeyed };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.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",
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@effect/sql": "^0.52.0",
|
|
57
|
-
"@voltro/database": "0.
|
|
57
|
+
"@voltro/database": "0.35.0",
|
|
58
|
+
"@voltro/logger": "0.35.0",
|
|
58
59
|
"jose": "^6.2.4"
|
|
59
60
|
},
|
|
60
61
|
"peerDependencies": {
|
package/dist/auth-CXMrvPyX.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { Context as e, Schema as t } from "effect";
|
|
2
|
-
import { RpcMiddleware as n } from "@effect/rpc";
|
|
3
|
-
//#region src/auth.ts
|
|
4
|
-
var r = t.Record({
|
|
5
|
-
key: t.String,
|
|
6
|
-
value: t.Unknown
|
|
7
|
-
}), i = t.optional(t.Array(t.String)), a = t.Struct({
|
|
8
|
-
type: t.Literal("user"),
|
|
9
|
-
id: t.String,
|
|
10
|
-
tenantId: t.String,
|
|
11
|
-
scopes: i,
|
|
12
|
-
metadata: t.optional(r)
|
|
13
|
-
}), o = t.Struct({
|
|
14
|
-
type: t.Literal("apiKey"),
|
|
15
|
-
id: t.String,
|
|
16
|
-
tenantId: t.String,
|
|
17
|
-
scopes: i,
|
|
18
|
-
metadata: t.optional(r)
|
|
19
|
-
}), s = t.Struct({
|
|
20
|
-
type: t.Literal("serviceAccount"),
|
|
21
|
-
id: t.String,
|
|
22
|
-
tenantId: t.String,
|
|
23
|
-
scopes: i,
|
|
24
|
-
metadata: t.optional(r)
|
|
25
|
-
}), c = t.Struct({
|
|
26
|
-
type: t.Literal("anonymous"),
|
|
27
|
-
id: t.Null,
|
|
28
|
-
tenantId: t.NullOr(t.String)
|
|
29
|
-
}), l = t.Struct({
|
|
30
|
-
type: t.Literal("system"),
|
|
31
|
-
id: t.String,
|
|
32
|
-
tenantId: t.Null,
|
|
33
|
-
scopes: i,
|
|
34
|
-
metadata: t.optional(r)
|
|
35
|
-
}), u = t.Union(a, o, s, c, l), d = (e) => ({
|
|
36
|
-
type: "anonymous",
|
|
37
|
-
id: null,
|
|
38
|
-
tenantId: e
|
|
39
|
-
}), f = (e, t = ["admin:full"]) => ({
|
|
40
|
-
type: "system",
|
|
41
|
-
id: e,
|
|
42
|
-
tenantId: null,
|
|
43
|
-
scopes: t
|
|
44
|
-
}), p = (e, t) => {
|
|
45
|
-
let n = e;
|
|
46
|
-
return {
|
|
47
|
-
type: "serviceAccount",
|
|
48
|
-
id: e.id ?? "system",
|
|
49
|
-
tenantId: t,
|
|
50
|
-
scopes: n.scopes ?? ["admin:full"],
|
|
51
|
-
...n.metadata === void 0 ? {} : { metadata: n.metadata }
|
|
52
|
-
};
|
|
53
|
-
}, m = (e) => e.type === "system", h = class extends e.Tag("@voltro/Subject")() {}, g = class extends e.Tag("@voltro/ConnectionInfo")() {}, _ = class extends n.Tag()("@voltro/AuthMiddleware", { provides: h }) {}, v = class extends n.Tag()("@voltro/ConnectionInfoMiddleware", { provides: g }) {}, y = (e) => typeof e.mountRoutes == "function", b = (e, t) => {
|
|
54
|
-
if (t.length === 0) return e;
|
|
55
|
-
let n = [.../* @__PURE__ */ new Set([...e.scopes ?? [], ...t])];
|
|
56
|
-
return {
|
|
57
|
-
...e,
|
|
58
|
-
scopes: n
|
|
59
|
-
};
|
|
60
|
-
}, x = (e, t) => async (n) => {
|
|
61
|
-
let r = t?.getStore?.(), i = r === void 0 ? n : {
|
|
62
|
-
...n,
|
|
63
|
-
store: r
|
|
64
|
-
};
|
|
65
|
-
for (let n of e) {
|
|
66
|
-
let e = await n.resolve(i);
|
|
67
|
-
if (e.kind === "matched") {
|
|
68
|
-
let n = t?.resolveScopes === void 0 ? e.subject : b(e.subject, await t.resolveScopes(e.subject, i));
|
|
69
|
-
return e.credentialExpiresAt === void 0 ? { subject: n } : {
|
|
70
|
-
subject: n,
|
|
71
|
-
credentialExpiresAt: e.credentialExpiresAt
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
if (e.kind === "failed") {
|
|
75
|
-
t?.onStrategyFailed?.({
|
|
76
|
-
strategyId: n.id,
|
|
77
|
-
reason: e.reason
|
|
78
|
-
});
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (t?.fallback) return { subject: await t.fallback(i) };
|
|
83
|
-
let a = i.headers["x-tenant"] ?? null;
|
|
84
|
-
if (a === null && t?.anonymousTenantRequired === !0) throw new S({ reason: "tenant required (x-tenant header missing)" });
|
|
85
|
-
return { subject: d(a) };
|
|
86
|
-
}, S = class extends t.TaggedError()("Unauthenticated", { reason: t.optional(t.String) }) {}, C = (e, t) => {
|
|
87
|
-
if (e.type === "anonymous") throw new S(t === void 0 ? {} : { reason: t });
|
|
88
|
-
};
|
|
89
|
-
//#endregion
|
|
90
|
-
export { h as a, C as c, m as d, f, u as i, x as l, g as n, S as o, p, v as r, d as s, _ as t, y as u };
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { Effect as e, Schema as t } from "effect";
|
|
2
|
-
//#region src/scopes.ts
|
|
3
|
-
var n = "admin:full", r = "apikeys:issue:self", i = "apikeys:issue:org", a = "apikeys:issue:other", o = class extends t.TaggedError()("ScopeError", {
|
|
4
|
-
required: t.String,
|
|
5
|
-
message: t.String
|
|
6
|
-
}) {}, s = (e) => "scopes" in e && e.scopes ? e.scopes : [], c = /* @__PURE__ */ new WeakMap(), l = (e, t) => {
|
|
7
|
-
typeof e == "object" && e && c.set(e, t);
|
|
8
|
-
}, u = (e) => {
|
|
9
|
-
if (typeof e == "object" && e) {
|
|
10
|
-
let t = c.get(e);
|
|
11
|
-
if (t) return t;
|
|
12
|
-
}
|
|
13
|
-
return s(e);
|
|
14
|
-
}, d = (e, t) => {
|
|
15
|
-
let n = u(e);
|
|
16
|
-
return n.includes("admin:full") || n.includes(t);
|
|
17
|
-
}, f = (e, t) => {
|
|
18
|
-
let n = s(e);
|
|
19
|
-
return n.includes("admin:full") || n.includes(t);
|
|
20
|
-
}, p = (t, n) => d(t, n) ? e.void : e.fail(new o({
|
|
21
|
-
required: n,
|
|
22
|
-
message: `missing required scope '${n}'`
|
|
23
|
-
})), m = (e) => typeof e.action == "string" && typeof e.resourceType == "string", h = (e) => typeof e == "string" ? [e] : e, g, _ = (e) => {
|
|
24
|
-
g = e;
|
|
25
|
-
}, v = (e) => g === void 0 ? e.filter((e) => (e.guards ?? []).some((e) => !m(e) && e.resource !== void 0)).map((e) => e.tag) : [], y = (e) => [
|
|
26
|
-
`${e.length} procedure${e.length === 1 ? "" : "s"} declare a per-resource guard that nothing enforces:`,
|
|
27
|
-
...e.slice(0, 10).map((e) => ` ${e}`),
|
|
28
|
-
...e.length > 10 ? [` … and ${e.length - 10} more`] : [],
|
|
29
|
-
"",
|
|
30
|
-
" `guards: [{ scope, resource }]` reads as \"may you do this to THIS resource\",",
|
|
31
|
-
" but with no resource-scope resolver registered the extractor is advisory and",
|
|
32
|
-
" the check runs against the caller's GLOBAL scopes. For an app whose",
|
|
33
|
-
" authorization is per-resource, that guard passes callers it should refuse.",
|
|
34
|
-
"",
|
|
35
|
-
" Fix it one of two ways:",
|
|
36
|
-
" • setResourceScopeResolver((req) => Effect<boolean>) — answers \"does this",
|
|
37
|
-
" subject hold `req.scope` on `req.resource`\" from your own tables.",
|
|
38
|
-
" • Drop the `resource` extractor if a global scope check is what you meant."
|
|
39
|
-
].join("\n"), b = () => g, x, S = (e) => {
|
|
40
|
-
x = e;
|
|
41
|
-
}, C = () => x, w = (e, t) => {
|
|
42
|
-
if (!t || t.length === 0) return null;
|
|
43
|
-
for (let n of t) {
|
|
44
|
-
if (m(n)) {
|
|
45
|
-
if (d(e, "admin:full")) continue;
|
|
46
|
-
return new o({
|
|
47
|
-
required: `${n.resourceType}:${n.action}`,
|
|
48
|
-
message: `relationship guard '${n.action}' on '${n.resourceType}' cannot be checked synchronously`
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
let t = h(n.scope);
|
|
52
|
-
if (t.length === 0) continue;
|
|
53
|
-
let r = t.filter((t) => d(e, t));
|
|
54
|
-
if (!((n.mode ?? "all") === "any" ? r.length > 0 : r.length === t.length)) {
|
|
55
|
-
let r = (n.mode ?? "all") === "any" ? t[0] : t.find((t) => !d(e, t));
|
|
56
|
-
return new o({
|
|
57
|
-
required: r,
|
|
58
|
-
message: (n.mode ?? "all") === "any" ? `missing all of required scopes [${t.join(", ")}]` : `missing required scope '${r}'`
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
}, T = (t, n, r) => {
|
|
64
|
-
let i = (e) => new o({
|
|
65
|
-
required: `${n.resourceType}:${n.action}`,
|
|
66
|
-
message: e
|
|
67
|
-
});
|
|
68
|
-
if (d(t, "admin:full")) return e.succeed(null);
|
|
69
|
-
let a = x;
|
|
70
|
-
if (a === void 0) return e.succeed(i(`no policy resolver registered — cannot authorize '${n.action}' on '${n.resourceType}'`));
|
|
71
|
-
let s = n.resource(r);
|
|
72
|
-
return s === void 0 || s === "" ? e.succeed(i(`input does not identify a '${n.resourceType}' to authorize`)) : e.suspend(() => a({
|
|
73
|
-
subject: t,
|
|
74
|
-
action: n.action,
|
|
75
|
-
resourceType: n.resourceType,
|
|
76
|
-
resourceId: s
|
|
77
|
-
})).pipe(e.catchAllCause(() => e.succeed(!1)), e.map((e) => e ? null : i(`no '${n.action}' relation on ${n.resourceType}:${s}`)));
|
|
78
|
-
}, E = (t, n, r) => {
|
|
79
|
-
if (!n || n.length === 0) return e.succeed(null);
|
|
80
|
-
let i = g;
|
|
81
|
-
return !n.some(m) && (!i || !n.some((e) => e.resource !== void 0)) ? e.succeed(w(t, n)) : e.gen(function* () {
|
|
82
|
-
for (let a of n) {
|
|
83
|
-
if (m(a)) {
|
|
84
|
-
let e = yield* T(t, a, r);
|
|
85
|
-
if (e) return e;
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
let n = h(a.scope);
|
|
89
|
-
if (n.length === 0) continue;
|
|
90
|
-
let s = a.resource ? a.resource(r) : void 0, c = [];
|
|
91
|
-
for (let r of n) {
|
|
92
|
-
if (d(t, r)) {
|
|
93
|
-
c.push(!0);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (s !== void 0 && i !== void 0) {
|
|
97
|
-
let n = yield* e.suspend(() => i({
|
|
98
|
-
subject: t,
|
|
99
|
-
scope: r,
|
|
100
|
-
resource: s
|
|
101
|
-
})).pipe(e.catchAllCause(() => e.succeed(!1)));
|
|
102
|
-
c.push(n);
|
|
103
|
-
} else c.push(!1);
|
|
104
|
-
}
|
|
105
|
-
let l = a.mode ?? "all";
|
|
106
|
-
if (!(l === "any" ? c.some(Boolean) : c.every(Boolean))) {
|
|
107
|
-
let e = l === "any" ? n[0] : n[n.findIndex((e, t) => !c[t])];
|
|
108
|
-
return new o({
|
|
109
|
-
required: e,
|
|
110
|
-
message: l === "any" ? `missing all of required scopes [${n.join(", ")}]` : `missing required scope '${e}'` + (s === void 0 ? "" : ` on resource '${s}'`)
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return null;
|
|
115
|
-
});
|
|
116
|
-
}, D = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, O = (e, t, n) => `${e ?? "(global)"}|${t ?? "(anon)"}|WS|${n}`, k = async (e, t, n, r, i) => {
|
|
117
|
-
let a = await e.claim(t, n, i, r);
|
|
118
|
-
return a === "claimed" ? { kind: "fresh" } : a.status === "completed" && a.response ? {
|
|
119
|
-
kind: "replay",
|
|
120
|
-
response: a.response
|
|
121
|
-
} : { kind: "conflict" };
|
|
122
|
-
}, A = (e, t, n, r, i) => e.complete(t, n, r, i), j = (e, t, n) => e.release(t, n), M = () => {
|
|
123
|
-
let e = /* @__PURE__ */ new Map(), t = (e, t) => `${e}\u0000${t}`;
|
|
124
|
-
return {
|
|
125
|
-
get: async (n, r) => e.get(t(n, r)) ?? null,
|
|
126
|
-
claim: async (n, r, i, a) => {
|
|
127
|
-
let o = e.get(t(n, r));
|
|
128
|
-
return o && i - o.createdAt < a ? o : (e.set(t(n, r), {
|
|
129
|
-
scope: n,
|
|
130
|
-
key: r,
|
|
131
|
-
status: "in_flight",
|
|
132
|
-
response: null,
|
|
133
|
-
createdAt: i
|
|
134
|
-
}), "claimed");
|
|
135
|
-
},
|
|
136
|
-
complete: async (n, r, i, a) => {
|
|
137
|
-
e.set(t(n, r), {
|
|
138
|
-
scope: n,
|
|
139
|
-
key: r,
|
|
140
|
-
status: "completed",
|
|
141
|
-
response: i,
|
|
142
|
-
createdAt: a
|
|
143
|
-
});
|
|
144
|
-
},
|
|
145
|
-
release: async (n, r) => {
|
|
146
|
-
e.delete(t(n, r));
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
}, N = /* @__PURE__ */ new Set(), P = (e) => {
|
|
150
|
-
for (let t of N) try {
|
|
151
|
-
t(e);
|
|
152
|
-
} catch {}
|
|
153
|
-
}, F = (e) => (N.add(e), () => {
|
|
154
|
-
N.delete(e);
|
|
155
|
-
});
|
|
156
|
-
//#endregion
|
|
157
|
-
export { m as C, _ as D, S as E, s as O, f as S, l as T, u as _, A as a, b, O as c, a as d, r as f, E as g, w as h, j as i, n as l, y as m, F as n, D as o, o as p, k as r, M as s, P as t, i as u, v, p as w, d as x, C as y };
|