@voltro/protocol 0.69.1 → 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.
- package/CHANGELOG.md +1369 -111
- package/dist/apikey.d.ts +5 -0
- package/dist/index.d.ts +770 -23
- package/dist/index.js +615 -567
- package/dist/inspect.d.ts +100 -0
- package/dist/inspect.js +160 -0
- package/dist/jwt.d.ts +5 -0
- package/dist/rest.d.ts +464 -21
- package/dist/rest.js +408 -174
- package/dist/restFormat-ChSVyufA.js +287 -0
- package/dist/{scopes-DVtiKKsm.js → scopes-CW9_LbDO.js} +69 -40
- package/dist/session.d.ts +19 -8
- package/dist/session.js +6 -6
- package/package.json +9 -4
- package/dist/serverErrorBus-BTnTpMqj.js +0 -60
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { Schema as e } from "effect";
|
|
2
|
+
import * as t from "effect/SchemaAST";
|
|
3
|
+
import * as n from "effect/Option";
|
|
4
|
+
//#region src/idempotency.ts
|
|
5
|
+
var r = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, i = (e, t, n, r) => r === void 0 ? `${e ?? "(global)"}|${t ?? "(anon)"}|WS|${n}` : `WS-connection:${JSON.stringify([
|
|
6
|
+
e ?? null,
|
|
7
|
+
t ?? null,
|
|
8
|
+
n,
|
|
9
|
+
r
|
|
10
|
+
])}`, a = class extends e.TaggedError()("MutationConnectionRequired", { traceId: e.String }) {
|
|
11
|
+
get message() {
|
|
12
|
+
return "this mutation requires a live native WebSocket connection";
|
|
13
|
+
}
|
|
14
|
+
}, o = async (e, t, n, r, i) => {
|
|
15
|
+
let a = await e.claim(t, n, i, r);
|
|
16
|
+
return a === "claimed" ? { kind: "fresh" } : a.status === "completed" && a.response ? {
|
|
17
|
+
kind: "replay",
|
|
18
|
+
response: a.response
|
|
19
|
+
} : { kind: "conflict" };
|
|
20
|
+
}, s = (e, t, n, r, i) => e.complete(t, n, r, i), c = (e, t, n) => e.release(t, n), l = () => {
|
|
21
|
+
let e = /* @__PURE__ */ new Map(), t = (e, t) => `${e}\u0000${t}`;
|
|
22
|
+
return {
|
|
23
|
+
get: async (n, r) => e.get(t(n, r)) ?? null,
|
|
24
|
+
claim: async (n, r, i, a) => {
|
|
25
|
+
let o = e.get(t(n, r));
|
|
26
|
+
return o && i - o.createdAt < a ? o : (e.set(t(n, r), {
|
|
27
|
+
scope: n,
|
|
28
|
+
key: r,
|
|
29
|
+
status: "in_flight",
|
|
30
|
+
response: null,
|
|
31
|
+
createdAt: i
|
|
32
|
+
}), "claimed");
|
|
33
|
+
},
|
|
34
|
+
complete: async (n, r, i, a) => {
|
|
35
|
+
e.set(t(n, r), {
|
|
36
|
+
scope: n,
|
|
37
|
+
key: r,
|
|
38
|
+
status: "completed",
|
|
39
|
+
response: i,
|
|
40
|
+
createdAt: a
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
release: async (n, r) => {
|
|
44
|
+
e.delete(t(n, r));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}, u = class extends e.TaggedError()("MutationInFlight", {
|
|
48
|
+
traceId: e.String,
|
|
49
|
+
retryAfterMs: e.Number
|
|
50
|
+
}) {
|
|
51
|
+
get message() {
|
|
52
|
+
return `a request with this idempotency key is still in flight — replay the same key after ${this.retryAfterMs}ms`;
|
|
53
|
+
}
|
|
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 {
|
|
111
|
+
t(e);
|
|
112
|
+
} catch {}
|
|
113
|
+
}, x = (e) => (y.add(e), () => {
|
|
114
|
+
y.delete(e);
|
|
115
|
+
}), S = {
|
|
116
|
+
rpc: {
|
|
117
|
+
name: "rpc",
|
|
118
|
+
dates: "epoch-ms",
|
|
119
|
+
errors: "tagged",
|
|
120
|
+
envelope: "none",
|
|
121
|
+
pagination: "body-cursor",
|
|
122
|
+
cursorField: "nextCursor",
|
|
123
|
+
cursorParam: "cursor",
|
|
124
|
+
naming: "camelCase",
|
|
125
|
+
etag: !1
|
|
126
|
+
},
|
|
127
|
+
standard: {
|
|
128
|
+
name: "standard",
|
|
129
|
+
dates: "iso",
|
|
130
|
+
errors: "problem-details",
|
|
131
|
+
envelope: "none",
|
|
132
|
+
pagination: "link-header",
|
|
133
|
+
cursorField: "nextCursor",
|
|
134
|
+
cursorParam: "cursor",
|
|
135
|
+
naming: "camelCase",
|
|
136
|
+
etag: !0
|
|
137
|
+
},
|
|
138
|
+
jsonapi: {
|
|
139
|
+
name: "jsonapi",
|
|
140
|
+
dates: "iso",
|
|
141
|
+
errors: "problem-details",
|
|
142
|
+
envelope: "jsonapi",
|
|
143
|
+
pagination: "link-header",
|
|
144
|
+
cursorField: "nextCursor",
|
|
145
|
+
cursorParam: "cursor",
|
|
146
|
+
naming: "camelCase",
|
|
147
|
+
etag: !0
|
|
148
|
+
}
|
|
149
|
+
}, C = [
|
|
150
|
+
"rpc",
|
|
151
|
+
"standard",
|
|
152
|
+
"jsonapi"
|
|
153
|
+
], w = (e, t = void 0) => {
|
|
154
|
+
let n = (e) => {
|
|
155
|
+
if (e?.profile !== void 0) {
|
|
156
|
+
if (typeof e.profile == "string") {
|
|
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`);
|
|
159
|
+
return t;
|
|
160
|
+
}
|
|
161
|
+
return e.profile;
|
|
162
|
+
}
|
|
163
|
+
}, r = (e, t) => t === void 0 ? e : {
|
|
164
|
+
...e,
|
|
165
|
+
...t.dates === void 0 ? {} : { dates: t.dates },
|
|
166
|
+
...t.errors === void 0 ? {} : { errors: t.errors },
|
|
167
|
+
...t.envelope === void 0 ? {} : { envelope: t.envelope },
|
|
168
|
+
...t.pagination === void 0 ? {} : { pagination: t.pagination },
|
|
169
|
+
...t.cursorField === void 0 ? {} : { cursorField: t.cursorField },
|
|
170
|
+
...t.cursorParam === void 0 ? {} : { cursorParam: t.cursorParam },
|
|
171
|
+
...t.naming === void 0 ? {} : { naming: t.naming },
|
|
172
|
+
...t.etag === void 0 ? {} : { etag: t.etag }
|
|
173
|
+
}, i = r(n(e) ?? S.rpc, e);
|
|
174
|
+
return r(n(t) ?? i, 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) => {
|
|
176
|
+
if (typeof e != "object" || !e || Array.isArray(e)) return e;
|
|
177
|
+
let n = {};
|
|
178
|
+
for (let [r, i] of Object.entries(e)) n[t(r)] = i;
|
|
179
|
+
return n;
|
|
180
|
+
}, D = (e) => n.getOrUndefined(t.getIdentifierAnnotation(e)), O = (n, r) => {
|
|
181
|
+
if (r.dates === "epoch-ms" && r.naming === "camelCase") return n;
|
|
182
|
+
let i = /* @__PURE__ */ new Map(), a = (e) => {
|
|
183
|
+
let t = i.get(e);
|
|
184
|
+
if (t !== void 0) return t;
|
|
185
|
+
let n = o(e);
|
|
186
|
+
return i.set(e, n), n;
|
|
187
|
+
}, o = (n) => {
|
|
188
|
+
switch (n._tag) {
|
|
189
|
+
case "Transformation":
|
|
190
|
+
if (r.dates === "iso" && D(n) === "DateFromNumber") {
|
|
191
|
+
let r = e.DateFromString.ast;
|
|
192
|
+
return new t.Transformation(r.from, r.to, r.transformation, {
|
|
193
|
+
...r.annotations,
|
|
194
|
+
...n.annotations,
|
|
195
|
+
[t.IdentifierAnnotationId]: "DateFromString",
|
|
196
|
+
[t.JSONSchemaAnnotationId]: {
|
|
197
|
+
type: "string",
|
|
198
|
+
format: "date-time"
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return n;
|
|
203
|
+
case "Refinement": return new t.Refinement(a(n.from), n.filter, n.annotations);
|
|
204
|
+
case "Union": return t.Union.make(n.types.map(a), n.annotations);
|
|
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);
|
|
206
|
+
case "Suspend": return new t.Suspend(() => a(n.f()), n.annotations);
|
|
207
|
+
case "TypeLiteral": {
|
|
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), {
|
|
214
|
+
strict: !1,
|
|
215
|
+
decode: (e) => E(e, (e) => u.get(e) ?? e),
|
|
216
|
+
encode: (e) => E(e, (e) => d.get(e) ?? e)
|
|
217
|
+
}).ast;
|
|
218
|
+
}
|
|
219
|
+
default: return n;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
return e.make(a(n.ast));
|
|
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),
|
|
226
|
+
status: e.status,
|
|
227
|
+
...e.message.length > 0 ? { detail: e.message } : {},
|
|
228
|
+
...e.fields
|
|
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" ? {
|
|
230
|
+
body: { errors: [{
|
|
231
|
+
status: String(t.status),
|
|
232
|
+
code: t.tag,
|
|
233
|
+
title: A(t.tag),
|
|
234
|
+
...t.message.length > 0 ? { detail: t.message } : {},
|
|
235
|
+
...Object.keys(t.fields).length > 0 ? { meta: t.fields } : {}
|
|
236
|
+
}] },
|
|
237
|
+
contentType: N
|
|
238
|
+
} : {
|
|
239
|
+
body: j(t),
|
|
240
|
+
contentType: M
|
|
241
|
+
} : { body: {
|
|
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,
|
|
243
|
+
...t.fields
|
|
244
|
+
} } : e.encodeError(t, n), F = (e, t) => {
|
|
245
|
+
if (typeof e != "object" || !e || Array.isArray(e)) return {
|
|
246
|
+
cursor: void 0,
|
|
247
|
+
rest: e
|
|
248
|
+
};
|
|
249
|
+
let n = e[t];
|
|
250
|
+
return typeof n != "string" && typeof n != "number" ? {
|
|
251
|
+
cursor: void 0,
|
|
252
|
+
rest: e
|
|
253
|
+
} : {
|
|
254
|
+
cursor: String(n),
|
|
255
|
+
rest: e
|
|
256
|
+
};
|
|
257
|
+
}, I = (e, t, n) => {
|
|
258
|
+
let r = new URLSearchParams(e.query);
|
|
259
|
+
return r.set(n, t), `<${e.path}?${r.toString()}>; rel="next"`;
|
|
260
|
+
}, L = (e, t) => {
|
|
261
|
+
if (typeof e != "object" || !e || Array.isArray(e)) return e;
|
|
262
|
+
let { id: n, ...r } = e;
|
|
263
|
+
return {
|
|
264
|
+
type: t,
|
|
265
|
+
...n === void 0 ? {} : { id: String(n) },
|
|
266
|
+
attributes: r
|
|
267
|
+
};
|
|
268
|
+
}, R = (e, t, n) => {
|
|
269
|
+
if (e.encodeSuccess !== void 0) return e.encodeSuccess(t, n);
|
|
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) => ({
|
|
271
|
+
body: e,
|
|
272
|
+
...i ? { headers: i } : {},
|
|
273
|
+
...t ? { contentType: t } : {}
|
|
274
|
+
});
|
|
275
|
+
if (e.envelope === "none") return a(t);
|
|
276
|
+
if (e.envelope === "data") return a({
|
|
277
|
+
data: t,
|
|
278
|
+
...r !== void 0 && e.pagination === "link-header" ? { next: r } : {}
|
|
279
|
+
});
|
|
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;
|
|
281
|
+
return a({
|
|
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);
|
|
285
|
+
};
|
|
286
|
+
//#endregion
|
|
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
|
-
}),
|
|
46
|
+
}), g = (e, t = ["admin:full"]) => ({
|
|
46
47
|
type: "system",
|
|
47
48
|
id: e,
|
|
48
49
|
tenantId: null,
|
|
49
50
|
scopes: t
|
|
50
|
-
}),
|
|
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
|
-
|
|
63
|
+
auditActorId: _(e),
|
|
64
|
+
scopes: m(e),
|
|
57
65
|
...n.metadata === void 0 ? {} : { metadata: n.metadata }
|
|
58
66
|
};
|
|
59
|
-
},
|
|
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,
|
|
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,
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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 :
|
|
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
|
|
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
|
-
} :
|
|
168
|
+
} : w(await n(e.subject, c));
|
|
161
169
|
if (t.kind === "unavailable" || r.length === 0) return t;
|
|
162
|
-
let i =
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
-
},
|
|
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"),
|
|
265
|
-
|
|
266
|
-
},
|
|
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 (
|
|
276
|
-
if (
|
|
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 (
|
|
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
|
-
},
|
|
303
|
-
let i
|
|
304
|
-
|
|
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
|
|
309
|
-
if (
|
|
310
|
-
let
|
|
311
|
-
return
|
|
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:
|
|
342
|
+
action: i,
|
|
314
343
|
resourceType: n.resourceType,
|
|
315
|
-
resourceId:
|
|
316
|
-
})).pipe(t.catchAllCause(() => t.succeed(!1)), t.map((e) => e ? null :
|
|
317
|
-
},
|
|
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(
|
|
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 (
|
|
323
|
-
if (
|
|
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 (
|
|
331
|
-
let t = yield*
|
|
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 {
|
|
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
|
@@ -162,28 +162,31 @@ declare const SessionPayload_2: Schema.Struct<{
|
|
|
162
162
|
v: Schema.Literal<[2]>;
|
|
163
163
|
/** WHO, never WHAT-THEY-MAY-DO. `SubjectIdentity` has no `scopes` field. */
|
|
164
164
|
subject: Schema.Union<[Schema.Struct<{
|
|
165
|
-
id: typeof Schema.String;
|
|
166
165
|
type: Schema.Literal<["user"]>;
|
|
166
|
+
id: typeof Schema.String;
|
|
167
167
|
tenantId: typeof Schema.String;
|
|
168
168
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
169
169
|
}>, Schema.Struct<{
|
|
170
|
-
id: typeof Schema.String;
|
|
171
170
|
type: Schema.Literal<["apiKey"]>;
|
|
171
|
+
id: typeof Schema.String;
|
|
172
172
|
tenantId: typeof Schema.String;
|
|
173
173
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
174
174
|
}>, Schema.Struct<{
|
|
175
|
-
id: typeof Schema.String;
|
|
176
175
|
type: Schema.Literal<["serviceAccount"]>;
|
|
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;
|
|
182
185
|
tenantId: Schema.NullOr<typeof Schema.String>;
|
|
183
186
|
credentialRejected: Schema.optional<typeof Schema.String>;
|
|
184
187
|
}>, Schema.Struct<{
|
|
185
|
-
id: typeof Schema.String;
|
|
186
188
|
type: Schema.Literal<["system"]>;
|
|
189
|
+
id: typeof Schema.String;
|
|
187
190
|
tenantId: typeof Schema.Null;
|
|
188
191
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
189
192
|
}>]>;
|
|
@@ -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<{
|
|
@@ -308,20 +316,23 @@ declare const Subject: Schema.Union<[Schema.Struct<{
|
|
|
308
316
|
declare type Subject = typeof Subject.Type;
|
|
309
317
|
|
|
310
318
|
declare const SubjectIdentity: Schema.Union<[Schema.Struct<{
|
|
311
|
-
id: typeof Schema.String;
|
|
312
319
|
type: Schema.Literal<["user"]>;
|
|
320
|
+
id: typeof Schema.String;
|
|
313
321
|
tenantId: typeof Schema.String;
|
|
314
322
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
315
323
|
}>, Schema.Struct<{
|
|
316
|
-
id: typeof Schema.String;
|
|
317
324
|
type: Schema.Literal<["apiKey"]>;
|
|
325
|
+
id: typeof Schema.String;
|
|
318
326
|
tenantId: typeof Schema.String;
|
|
319
327
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
320
328
|
}>, Schema.Struct<{
|
|
321
|
-
id: typeof Schema.String;
|
|
322
329
|
type: Schema.Literal<["serviceAccount"]>;
|
|
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;
|
|
@@ -344,8 +355,8 @@ declare const SubjectIdentity: Schema.Union<[Schema.Struct<{
|
|
|
344
355
|
*/
|
|
345
356
|
credentialRejected: Schema.optional<typeof Schema.String>;
|
|
346
357
|
}>, Schema.Struct<{
|
|
347
|
-
id: typeof Schema.String;
|
|
348
358
|
type: Schema.Literal<["system"]>;
|
|
359
|
+
id: typeof Schema.String;
|
|
349
360
|
tenantId: typeof Schema.Null;
|
|
350
361
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
351
362
|
}>]>;
|
package/dist/session.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
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:
|
|
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 = (
|
|
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 =
|
|
45
|
-
if (o.length > 0) throw Error(`signSession: refusing to mint a session cookie for a ${
|
|
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
|
|
48
|
+
subject: n(e),
|
|
49
49
|
exp: c + s,
|
|
50
50
|
iat: c,
|
|
51
51
|
...typeof r == "string" ? {} : { kid: a.kid }
|