@voltro/protocol 0.86.0 → 0.87.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 +5321 -0
- package/THIRD-PARTY-NOTICES.md +1130 -11
- package/dist/apiRoleEndpoints.js +108 -0
- package/dist/apiRoleObservation.js +68 -0
- package/dist/apikey.d.ts +10 -0
- package/dist/auth.js +39 -19
- package/dist/canonicalJson.js +14 -0
- package/dist/errorSchema.js +24 -0
- package/dist/event.js +51 -45
- package/dist/formCapture.js +12 -0
- package/dist/httpStreamMaxDuration.js +9 -0
- package/dist/idempotency.js +88 -33
- package/dist/idempotencyInput.js +123 -0
- package/dist/index.d.ts +876 -124
- package/dist/index.js +50 -38
- package/dist/inspect.d.ts +1 -1
- package/dist/jwt.d.ts +10 -0
- package/dist/jwt.js +1 -1
- package/dist/plugin.js +43 -17
- package/dist/pluginAccountMerge.js +88 -0
- package/dist/pluginPrivacy.js +166 -0
- package/dist/procedure.js +114 -96
- package/dist/publicApi.js +190 -209
- package/dist/queryOptionalSources.js +14 -0
- package/dist/rest.d.ts +227 -64
- package/dist/rest.js +295 -192
- package/dist/restReceipt.js +43 -0
- package/dist/revalidate.js +13 -0
- package/dist/scopes.js +71 -38
- package/dist/secretWindows.js +71 -0
- package/dist/session.d.ts +89 -6
- package/dist/session.js +55 -54
- package/dist/ssrfPolicy.js +30 -0
- package/dist/webSocketGateway.js +7 -1
- package/package.json +5 -3
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
//#region src/apiRoleEndpoints.ts
|
|
2
|
+
var e = (e, t) => {
|
|
3
|
+
if (!e || typeof e != "object" || Array.isArray(e) || ![Object.prototype, null].includes(Object.getPrototypeOf(e))) throw Error("Invalid role endpoint object");
|
|
4
|
+
let n = Object.create(null);
|
|
5
|
+
for (let r of Reflect.ownKeys(e)) {
|
|
6
|
+
let i = Object.getOwnPropertyDescriptor(e, r);
|
|
7
|
+
if (typeof r != "string" || !t.includes(r) || !i.enumerable || !("value" in i)) throw Error("Invalid role endpoint field");
|
|
8
|
+
n[r] = i.value;
|
|
9
|
+
}
|
|
10
|
+
return n;
|
|
11
|
+
}, t = (e, t, n = !1) => {
|
|
12
|
+
if (!Array.isArray(e) || e.length < +!n || e.length > t || Reflect.ownKeys(e).length !== e.length + 1) throw Error("Invalid role endpoint list");
|
|
13
|
+
let r = [];
|
|
14
|
+
for (let t = 0; t < e.length; t++) {
|
|
15
|
+
let n = Object.getOwnPropertyDescriptor(e, String(t));
|
|
16
|
+
if (!n?.enumerable || !("value" in n)) throw Error("Invalid role endpoint list item");
|
|
17
|
+
r.push(n.value);
|
|
18
|
+
}
|
|
19
|
+
return r;
|
|
20
|
+
}, n = /^(?:[A-Za-z][A-Za-z0-9_-]*\.)*[A-Za-z][A-Za-z0-9_-]*$/, r = /^(?:[A-Za-z_][A-Za-z0-9_-]*\.)*[A-Za-z_][A-Za-z0-9_-]*$/, i = [
|
|
21
|
+
"rpc",
|
|
22
|
+
"subscriptions",
|
|
23
|
+
"events",
|
|
24
|
+
"presence",
|
|
25
|
+
"workflows",
|
|
26
|
+
"schedules",
|
|
27
|
+
"directors",
|
|
28
|
+
"drainers",
|
|
29
|
+
"reapers",
|
|
30
|
+
"retention",
|
|
31
|
+
"rest",
|
|
32
|
+
"webhooks",
|
|
33
|
+
"inspect",
|
|
34
|
+
"cdc"
|
|
35
|
+
], a = (r) => {
|
|
36
|
+
let a = e(r, [
|
|
37
|
+
"version",
|
|
38
|
+
"transport",
|
|
39
|
+
"roles"
|
|
40
|
+
]);
|
|
41
|
+
if (a.version !== 1 || a.transport !== "compose-nginx" && a.transport !== "kubernetes-nginx") throw Error("Unknown role endpoint protocol");
|
|
42
|
+
let o = /* @__PURE__ */ new Set(), s = t(a.roles, 32, !0).map((r) => {
|
|
43
|
+
let a = e(r, [
|
|
44
|
+
"role",
|
|
45
|
+
"routes",
|
|
46
|
+
"workloads",
|
|
47
|
+
"httpPath",
|
|
48
|
+
"webSocketPath"
|
|
49
|
+
]), s = a.role;
|
|
50
|
+
if (typeof s != "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(s) || o.has(s)) throw Error("Invalid or duplicate endpoint role");
|
|
51
|
+
o.add(s);
|
|
52
|
+
let c = t(a.workloads, 14).map((e) => {
|
|
53
|
+
if (typeof e != "string" || !i.includes(e)) throw Error("Unknown endpoint workload");
|
|
54
|
+
return e;
|
|
55
|
+
});
|
|
56
|
+
if (new Set(c).size !== c.length) throw Error("Duplicate endpoint workload");
|
|
57
|
+
let l = a.routes === null ? null : t(a.routes, 128).map((e) => {
|
|
58
|
+
if (typeof e != "string" || e.length > 191 || !n.test(e.endsWith(".*") ? e.slice(0, -2) : e)) throw Error("Invalid endpoint tag filter");
|
|
59
|
+
return e;
|
|
60
|
+
});
|
|
61
|
+
if (l && new Set(l).size !== l.length) throw Error("Duplicate endpoint tag filter");
|
|
62
|
+
let u = "/_voltro/roles/" + s;
|
|
63
|
+
if (a.webSocketPath !== u + "/ws" || a.httpPath !== (c.includes("rpc") ? u + "/rpc" : null)) throw Error("Role endpoints must use canonical same-origin paths");
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
role: s,
|
|
66
|
+
routes: l && Object.freeze(l),
|
|
67
|
+
workloads: Object.freeze(c),
|
|
68
|
+
httpPath: a.httpPath,
|
|
69
|
+
webSocketPath: a.webSocketPath
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
return Object.freeze({
|
|
73
|
+
version: 1,
|
|
74
|
+
transport: a.transport,
|
|
75
|
+
roles: Object.freeze(s)
|
|
76
|
+
});
|
|
77
|
+
}, o = (e, t, n) => {
|
|
78
|
+
if (t.length > 191 || !r.test(t) || ![
|
|
79
|
+
"rpc",
|
|
80
|
+
"subscriptions",
|
|
81
|
+
"events"
|
|
82
|
+
].includes(n)) throw Error("Invalid role endpoint request");
|
|
83
|
+
let i, a = -1, o = !1;
|
|
84
|
+
for (let r of e.roles) {
|
|
85
|
+
if (!r.workloads.includes(n)) continue;
|
|
86
|
+
let e = r.routes === null ? 0 : Math.max(-1, ...r.routes.map((e) => e.endsWith(".*") ? t.startsWith(e.slice(0, -1)) ? e.length : -1 : e === t ? 1024 + e.length : -1));
|
|
87
|
+
e > a ? (i = r, a = e, o = !1) : e >= 0 && e === a && (o = !0);
|
|
88
|
+
}
|
|
89
|
+
if (!i || o) throw Error(o ? "Ambiguous role endpoint" : "No role endpoint owns this tag and workload");
|
|
90
|
+
return i;
|
|
91
|
+
}, s = (e) => {
|
|
92
|
+
if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/.test(e)) throw Error("Invalid role proxy API name");
|
|
93
|
+
return `/_voltro/role-api/api-${e}/ws`;
|
|
94
|
+
}, c = (e, t, n) => {
|
|
95
|
+
if (!/^[a-z][a-z0-9-]{0,63}$/.test(t.role) || !["http", "websocket"].includes(n)) throw Error("Invalid role transport");
|
|
96
|
+
let r = new URL(e);
|
|
97
|
+
if (![
|
|
98
|
+
"http:",
|
|
99
|
+
"https:",
|
|
100
|
+
"ws:",
|
|
101
|
+
"wss:"
|
|
102
|
+
].includes(r.protocol) || r.username || r.password) throw Error("Invalid role endpoint origin");
|
|
103
|
+
let i = n === "http" ? t.httpPath : t.webSocketPath;
|
|
104
|
+
if (!i || i !== "/_voltro/roles/" + t.role + (n === "http" ? "/rpc" : "/ws")) throw Error("Missing or noncanonical role transport");
|
|
105
|
+
return r.protocol = n === "http" ? r.protocol === "https:" || r.protocol === "wss:" ? "https:" : "http:" : r.protocol === "https:" || r.protocol === "wss:" ? "wss:" : "ws:", r.pathname = (/^\/_voltro\/role-api\/api-[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}\/ws$/.test(r.pathname) ? r.pathname.slice(0, -3) : "") + i, r.search = "", r.hash = "", r.toString();
|
|
106
|
+
};
|
|
107
|
+
//#endregion
|
|
108
|
+
export { c as apiRoleEndpointUrl, s as apiRoleProxyBasePath, a as captureApiRoleEndpoints, o as selectApiRoleEndpoint };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { API_WORKLOADS as e } from "./plugin.js";
|
|
2
|
+
import { Schema as t } from "effect";
|
|
3
|
+
//#region src/apiRoleObservation.ts
|
|
4
|
+
var n = t.Literals(e), r = t.Number.pipe(t.check(t.isFinite()), t.check(t.isGreaterThanOrEqualTo(0))), i = r.pipe(t.check(t.isInt())), a = i.pipe(t.check(t.isLessThanOrEqualTo(864e13))), o = t.Struct({
|
|
5
|
+
workload: n,
|
|
6
|
+
seconds: r
|
|
7
|
+
}), s = t.Struct({
|
|
8
|
+
replicaId: t.NonEmptyString,
|
|
9
|
+
startedAt: a,
|
|
10
|
+
role: t.NonEmptyString,
|
|
11
|
+
workloads: t.Array(n),
|
|
12
|
+
capturedAt: a,
|
|
13
|
+
publisher: t.Struct({
|
|
14
|
+
ready: t.Boolean,
|
|
15
|
+
stopped: t.Boolean,
|
|
16
|
+
pendingBuckets: i,
|
|
17
|
+
droppedBuckets: i,
|
|
18
|
+
rejectedSegments: i,
|
|
19
|
+
writeFailures: i,
|
|
20
|
+
observationErrors: i
|
|
21
|
+
}),
|
|
22
|
+
currentMeasuredSeconds: t.Array(t.Struct({
|
|
23
|
+
role: t.NonEmptyString,
|
|
24
|
+
workload: n,
|
|
25
|
+
seconds: r
|
|
26
|
+
})),
|
|
27
|
+
history: t.Struct({
|
|
28
|
+
state: t.Literals([
|
|
29
|
+
"pending",
|
|
30
|
+
"available",
|
|
31
|
+
"unavailable"
|
|
32
|
+
]),
|
|
33
|
+
measuredSeconds: t.Array(o),
|
|
34
|
+
assessment: t.NullOr(t.Struct({
|
|
35
|
+
from: a,
|
|
36
|
+
until: a,
|
|
37
|
+
complete: t.Boolean,
|
|
38
|
+
missingBuckets: i.pipe(t.check(t.isLessThanOrEqualTo(288))),
|
|
39
|
+
incompleteWorkloads: t.Array(n),
|
|
40
|
+
reason: t.Literals([
|
|
41
|
+
"invalid-observation",
|
|
42
|
+
"incomplete",
|
|
43
|
+
"idle",
|
|
44
|
+
"observed"
|
|
45
|
+
]),
|
|
46
|
+
totals: t.Array(t.Struct({
|
|
47
|
+
workload: n,
|
|
48
|
+
seconds: r,
|
|
49
|
+
share: r.pipe(t.check(t.isLessThanOrEqualTo(1)))
|
|
50
|
+
})),
|
|
51
|
+
splitCandidates: t.Array(n)
|
|
52
|
+
}))
|
|
53
|
+
})
|
|
54
|
+
}).pipe(t.check(t.makeFilter((e) => {
|
|
55
|
+
let t = (e) => new Set(e).size === e.length, n = (n) => t(n) && n.every((t) => e.workloads.some((e) => e === t));
|
|
56
|
+
if (!e.workloads.length || !t(e.workloads) || e.startedAt > e.capturedAt || !n(e.currentMeasuredSeconds.map((e) => e.workload)) || e.currentMeasuredSeconds.some((t) => t.role !== e.role) || !n(e.history.measuredSeconds.map((e) => e.workload))) return !1;
|
|
57
|
+
let r = e.history.assessment;
|
|
58
|
+
if (e.history.state !== "available") return r === null && e.history.measuredSeconds.length === 0;
|
|
59
|
+
if (!r || r.until - r.from !== 864e5 || r.until % 3e5 != 0 || r.until > e.capturedAt || !n(r.incompleteWorkloads) || !n(r.splitCandidates) || !n(r.totals.map((e) => e.workload))) return !1;
|
|
60
|
+
if (!r.complete) return r.totals.length === 0 && r.splitCandidates.length === 0 && ["incomplete", "invalid-observation"].includes(r.reason);
|
|
61
|
+
if (r.from < e.startedAt || r.missingBuckets !== 0 || r.incompleteWorkloads.length !== 0 || r.totals.length !== e.workloads.length) return !1;
|
|
62
|
+
let i = r.totals.reduce((e, t) => e + t.seconds, 0);
|
|
63
|
+
if (i > 86400 || r.reason !== (i === 0 ? "idle" : "observed") || r.totals.some((e) => Math.abs(e.share - (i === 0 ? 0 : e.seconds / i)) > 1e-9)) return !1;
|
|
64
|
+
let a = r.totals.filter((e) => e.share > .3).map((e) => e.workload), o = a.length >= 2 ? a : [];
|
|
65
|
+
return o.length === r.splitCandidates.length && o.every((e) => r.splitCandidates.includes(e));
|
|
66
|
+
}, { message: "Inconsistent API role observation" })));
|
|
67
|
+
//#endregion
|
|
68
|
+
export { s as ApiRoleObservationSchema };
|
package/dist/apikey.d.ts
CHANGED
|
@@ -129,6 +129,13 @@ declare interface AuthStrategy {
|
|
|
129
129
|
declare interface AuthStrategyInput {
|
|
130
130
|
readonly headers: Readonly<Record<string, string | undefined>>;
|
|
131
131
|
readonly clientId: number;
|
|
132
|
+
/** HTTP request target, supplied by REST transports. Request selectors may
|
|
133
|
+
* read an explicit tenant hint here; it is never authentication or authority.
|
|
134
|
+
* Absent for connection transports and non-HTTP callers. */
|
|
135
|
+
readonly http?: {
|
|
136
|
+
readonly path: string;
|
|
137
|
+
readonly query: string;
|
|
138
|
+
};
|
|
132
139
|
/**
|
|
133
140
|
* The app's DataStore, for a strategy that must READ to identify the caller.
|
|
134
141
|
*
|
|
@@ -196,6 +203,9 @@ declare type StrategyResolution = {
|
|
|
196
203
|
|
|
197
204
|
declare const Subject: Schema.Union<readonly [Schema.Struct<{
|
|
198
205
|
readonly type: Schema.Literal<"user">;
|
|
206
|
+
/** A guest has a stable identity but has not linked a registered account.
|
|
207
|
+
* This identity mark survives session signing; it never grants authority. */
|
|
208
|
+
readonly kind: Schema.optional<Schema.Literal<"guest">>;
|
|
199
209
|
readonly id: Schema.String;
|
|
200
210
|
readonly tenantId: Schema.String;
|
|
201
211
|
readonly scopes: Schema.optional<Schema.$Array<Schema.String>>;
|
package/dist/auth.js
CHANGED
|
@@ -4,6 +4,7 @@ import { RpcMiddleware as s } from "effect/rpc";
|
|
|
4
4
|
//#region src/auth.ts
|
|
5
5
|
var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.Struct({
|
|
6
6
|
type: a.Literal("user"),
|
|
7
|
+
kind: a.optional(a.Literal("guest")),
|
|
7
8
|
id: a.String,
|
|
8
9
|
tenantId: a.String,
|
|
9
10
|
scopes: l,
|
|
@@ -103,7 +104,7 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
103
104
|
let n = F.get(e);
|
|
104
105
|
if (n === void 0) return await t?.(e), e;
|
|
105
106
|
let r = await n.resolve();
|
|
106
|
-
if (r.type !== e.type || r.id !== e.id || r.tenantId !== e.tenantId || e.type === "service" && (r.type !== "service" || r.service !== e.service)) throw new M({ reason: "
|
|
107
|
+
if (r.type !== e.type || r.id !== e.id || r.tenantId !== e.tenantId || e.type === "service" && (r.type !== "service" || r.service !== e.service) || e.type === "user" && (r.type !== "user" || r.kind !== e.kind) || e.type === "serviceAccount" && (r.type !== "serviceAccount" || r.auditActorId !== e.auditActorId)) throw new M({ reason: "request identity or tenant changed; authenticate again" });
|
|
107
108
|
return F.set(r, {
|
|
108
109
|
current: r,
|
|
109
110
|
resolve: n.resolve
|
|
@@ -140,14 +141,33 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
140
141
|
},
|
|
141
142
|
removed: i
|
|
142
143
|
};
|
|
143
|
-
}, H =
|
|
144
|
+
}, H = async (e, t, n) => {
|
|
145
|
+
let r = n?.resolveScopes, i = B(r === void 0 ? [] : await r(e, t));
|
|
146
|
+
if (i.kind === "unavailable") return {
|
|
147
|
+
kind: "unavailable",
|
|
148
|
+
reason: i.reason
|
|
149
|
+
};
|
|
150
|
+
let a = V(e, i).subject;
|
|
151
|
+
if (a.type !== "anonymous") for (let e of n?.subjectGuards ?? []) {
|
|
152
|
+
let n = await e(a, t);
|
|
153
|
+
if (!n.ok) return {
|
|
154
|
+
kind: "vetoed",
|
|
155
|
+
code: n.code,
|
|
156
|
+
message: n.message
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
kind: "resolved",
|
|
161
|
+
subject: a
|
|
162
|
+
};
|
|
163
|
+
}, U = 3e4, W = 1e4, G = (e) => `${e.type}\u0000${e.tenantId ?? ""}\u0000${e.id ?? ""}`, K = () => {
|
|
144
164
|
if (typeof process > "u") return;
|
|
145
165
|
let e = process.env.VOLTRO_AUTH_SCOPE_CACHE_TTL_MS;
|
|
146
166
|
if (e === void 0 || e === "") return;
|
|
147
167
|
let t = Number(e);
|
|
148
168
|
return Number.isFinite(t) && t >= 0 ? t : void 0;
|
|
149
|
-
},
|
|
150
|
-
let t = e.ttlMs ??
|
|
169
|
+
}, q = (e = {}) => {
|
|
170
|
+
let t = e.ttlMs ?? K() ?? 3e4, n = e.maxEntries ?? 1e4, r = e.now ?? Date.now, i = /* @__PURE__ */ new Map(), a = () => {
|
|
151
171
|
if (i.size <= n) return;
|
|
152
172
|
let e = r();
|
|
153
173
|
for (let [t, n] of i) n.freshUntil <= e && i.delete(t);
|
|
@@ -183,10 +203,10 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
183
203
|
};
|
|
184
204
|
}
|
|
185
205
|
};
|
|
186
|
-
},
|
|
206
|
+
}, J = (e) => typeof e.resolve == "function", Y = (e) => {
|
|
187
207
|
let t = e.authorization ?? e.Authorization;
|
|
188
208
|
if (t !== void 0) return /^Bearer\s+(.+)$/i.exec(t.trim())?.[1]?.trim();
|
|
189
|
-
},
|
|
209
|
+
}, X = async (e, i, a, o) => {
|
|
190
210
|
let s;
|
|
191
211
|
try {
|
|
192
212
|
s = await a.source(e, i);
|
|
@@ -207,7 +227,7 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
207
227
|
} catch (e) {
|
|
208
228
|
throw e instanceof t ? o(e.reason) : e;
|
|
209
229
|
}
|
|
210
|
-
},
|
|
230
|
+
}, Z = async (e, i, a, o) => {
|
|
211
231
|
if (!n(e)) return e;
|
|
212
232
|
let s = {
|
|
213
233
|
type: e.type,
|
|
@@ -236,14 +256,14 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
236
256
|
}
|
|
237
257
|
return e;
|
|
238
258
|
}
|
|
239
|
-
},
|
|
240
|
-
let n =
|
|
259
|
+
}, Q = (e, t) => {
|
|
260
|
+
let n = Y(t);
|
|
241
261
|
if (n === void 0) return e;
|
|
242
262
|
let r = e.filter((e) => e.claimsBearerPrefix !== void 0 && e.claimsBearerPrefix !== "" && n.startsWith(e.claimsBearerPrefix));
|
|
243
263
|
if (r.length === 0) return e;
|
|
244
264
|
let i = new Set(r);
|
|
245
265
|
return [...r, ...e.filter((e) => !i.has(e))];
|
|
246
|
-
},
|
|
266
|
+
}, $ = (e, t) => {
|
|
247
267
|
if (e === "refuse") throw new M({ reason: "anonymous callers are refused" });
|
|
248
268
|
if (e === "no-tenant") return "";
|
|
249
269
|
if (e === "header") {
|
|
@@ -251,24 +271,24 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
251
271
|
return t;
|
|
252
272
|
}
|
|
253
273
|
return "tenantId" in e ? e.tenantId : t !== void 0 && t !== "" ? t : e.headerOrTenant;
|
|
254
|
-
},
|
|
274
|
+
}, ee = (t, n) => {
|
|
255
275
|
let r = n?.resolveScopes, i = n?.subjectGuards ?? [], a = n?.tenantSelection !== void 0 || n?.requestedTenant !== void 0;
|
|
256
276
|
if (n?.memberships !== void 0 !== a) throw Error("composeAuthStrategies: memberships and tenant selection come together; `memberships` requires `tenantSelection` or `requestedTenant`; each tenant selector requires `memberships` to authorize its target.");
|
|
257
277
|
let o = n?.memberships !== void 0 && n.tenantSelection !== void 0 ? {
|
|
258
278
|
memberships: n.memberships,
|
|
259
279
|
store: n.tenantSelection
|
|
260
|
-
} : void 0, s = r !== void 0 || i.length > 0, c = !s || n?.scopeCache === !1 ? null : n?.scopeCache !== void 0 &&
|
|
280
|
+
} : void 0, s = r !== void 0 || i.length > 0, c = !s || n?.scopeCache === !1 ? null : n?.scopeCache !== void 0 && J(n.scopeCache) ? n.scopeCache : q(n?.scopeCache ?? {}), l = async (a) => {
|
|
261
281
|
let l = n?.getStore?.(), u = l === void 0 ? a : {
|
|
262
282
|
...a,
|
|
263
283
|
store: l
|
|
264
284
|
}, d;
|
|
265
|
-
for (let a of
|
|
285
|
+
for (let a of Q(t, u.headers)) {
|
|
266
286
|
let t = await a.resolve(u);
|
|
267
287
|
if (t.kind === "matched") {
|
|
268
288
|
let l = (e) => (n?.onStrategyFailed?.({
|
|
269
289
|
strategyId: a.id,
|
|
270
290
|
reason: e
|
|
271
|
-
}), new M({ reason: e })), d = n?.requestedTenant === void 0 || n.memberships === void 0 ? void 0 : await
|
|
291
|
+
}), new M({ reason: e })), d = n?.requestedTenant === void 0 || n.memberships === void 0 ? void 0 : await X(t.subject, u, {
|
|
272
292
|
source: n.requestedTenant,
|
|
273
293
|
memberships: n.memberships
|
|
274
294
|
}, (t) => (n?.onStrategyFailed?.({
|
|
@@ -279,7 +299,7 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
279
299
|
...t.subject,
|
|
280
300
|
scopes: []
|
|
281
301
|
} };
|
|
282
|
-
let f = d ?? (o === void 0 ? t.subject : await
|
|
302
|
+
let f = d ?? (o === void 0 ? t.subject : await Z(t.subject, u, o, l)), p = f;
|
|
283
303
|
if (s) {
|
|
284
304
|
let e = async () => {
|
|
285
305
|
let e = r === void 0 ? {
|
|
@@ -305,7 +325,7 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
305
325
|
}, { decision: t, fresh: o } = c === null ? {
|
|
306
326
|
decision: await e(),
|
|
307
327
|
fresh: !0
|
|
308
|
-
} : await c.resolve(
|
|
328
|
+
} : await c.resolve(G(f), e);
|
|
309
329
|
if (t.kind === "vetoed") {
|
|
310
330
|
let e = `${t.code}: ${t.message}`;
|
|
311
331
|
throw n?.onStrategyFailed?.({
|
|
@@ -350,7 +370,7 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
350
370
|
} : e };
|
|
351
371
|
}
|
|
352
372
|
if (d !== void 0) throw new M({ reason: `credential rejected: ${d}` });
|
|
353
|
-
return { subject: b(
|
|
373
|
+
return { subject: b($(n?.anonymous ?? "no-tenant", u.headers["x-tenant"])) };
|
|
354
374
|
};
|
|
355
375
|
return async (e) => {
|
|
356
376
|
let t = {
|
|
@@ -362,8 +382,8 @@ var c = a.Record(a.String, a.Unknown), l = a.optional(a.Array(a.String)), u = a.
|
|
|
362
382
|
subject: r
|
|
363
383
|
};
|
|
364
384
|
};
|
|
365
|
-
},
|
|
385
|
+
}, te = (e, t) => {
|
|
366
386
|
if (e.type === "anonymous") throw new M(t === void 0 ? {} : { reason: t });
|
|
367
387
|
};
|
|
368
388
|
//#endregion
|
|
369
|
-
export { N as AuthMiddleware, j as ConnectionInfo, P as ConnectionInfoMiddleware,
|
|
389
|
+
export { N as AuthMiddleware, j as ConnectionInfo, P as ConnectionInfoMiddleware, W as DEFAULT_SCOPE_CACHE_MAX_ENTRIES, U as DEFAULT_SCOPE_CACHE_TTL_MS, O as IMPERSONATION_METADATA_KEY, g as Subject, _ as SubjectIdentity, A as SubjectService, M as Unauthenticated, b as anonymousSubject, V as applyScopeDecision, te as assertAuthenticated, I as bindSubjectAuthority, ee as composeAuthStrategies, L as currentSubjectAuthority, z as hasCallbackRoutes, w as isMachineSubject, C as isServiceSubject, D as isSystemSubject, q as makeScopeCache, Q as orderByBearerPrefix, k as rawImpersonationMark, R as reauthorizeSubject, H as resolveIdentityAuthority, G as scopeCacheKey, S as serviceSubject, T as subjectAuditActorId, v as subjectIdentity, x as systemSubject, E as tenantScopedSubject };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/canonicalJson.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
let t = (e) => {
|
|
4
|
+
if (Array.isArray(e)) return e.map(t);
|
|
5
|
+
if (typeof e == "object" && e) {
|
|
6
|
+
let n = e;
|
|
7
|
+
return Object.fromEntries(Object.keys(n).sort().map((e) => [e, t(n[e])]));
|
|
8
|
+
}
|
|
9
|
+
return e;
|
|
10
|
+
};
|
|
11
|
+
return JSON.stringify(t(e) ?? null);
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { e as canonicalJson };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Schema as e } from "effect";
|
|
2
|
+
import * as t from "effect/SchemaAST";
|
|
3
|
+
//#region src/errorSchema.ts
|
|
4
|
+
var n = (e) => {
|
|
5
|
+
let n = /* @__PURE__ */ new Set();
|
|
6
|
+
if (e === void 0) return n;
|
|
7
|
+
let r = (e) => {
|
|
8
|
+
if (t.isUnion(e)) for (let t of e.types) r(t);
|
|
9
|
+
else if (e.encoding !== void 0 && r(t.toEncoded(e)), t.isObjects(e)) {
|
|
10
|
+
let r = e.propertySignatures.find((e) => e.name === "_tag");
|
|
11
|
+
r !== void 0 && t.isLiteral(r.type) && typeof r.type.literal == "string" && n.add(r.type.literal);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
return r(e.ast), n;
|
|
15
|
+
}, r = (r, i) => {
|
|
16
|
+
if (r === void 0) return;
|
|
17
|
+
let a = t.isUnion(r.ast) ? r.ast.types : [r.ast];
|
|
18
|
+
for (let t of a) {
|
|
19
|
+
let r = e.make(t);
|
|
20
|
+
if (n(r).has(i)) return r;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { n as declaredErrorTags, r as errorMemberSchema };
|
package/dist/event.js
CHANGED
|
@@ -3,10 +3,15 @@ import { Unauthenticated as t } from "./auth.js";
|
|
|
3
3
|
import { NoSuchResource as n, ScopeError as r, declaresResourceGuard as i, isOpenAccess as a, openAccessSpec as o } from "./scopes.js";
|
|
4
4
|
import { strictInput as s } from "./strictInput.js";
|
|
5
5
|
import { hasEnforcedGuard as c } from "./procedure.js";
|
|
6
|
-
import {
|
|
7
|
-
import { Rpc as
|
|
6
|
+
import { Context as l, Schema as u } from "effect";
|
|
7
|
+
import { Rpc as d } from "effect/rpc";
|
|
8
8
|
//#region src/event.ts
|
|
9
|
-
var
|
|
9
|
+
var f = 7500, p = (e) => typeof e == "object" && !!e && e.kind === "event", m = (e) => {
|
|
10
|
+
if (e.clientPolicy !== void 0) {
|
|
11
|
+
if (!/^[A-Za-z][A-Za-z0-9_.:-]{0,255}$/.test(e.clientPolicy)) throw Error("defineEvent: invalid client policy ID");
|
|
12
|
+
if (e.openAccess !== void 0 || !c(e.guards)) throw Error("defineEvent: a client policy requires explicit enforced guards");
|
|
13
|
+
if (e.webhook !== void 0) throw Error("defineEvent: private client policies do not authorize webhook recipients");
|
|
14
|
+
}
|
|
10
15
|
if (e.name.length === 0) throw Error("defineEvent: `name` must not be empty");
|
|
11
16
|
if (/\s/.test(e.name)) throw Error(`defineEvent("${e.name}"): \`name\` must not contain whitespace.\n The name is used as a broker subject segment. NATS refuses a subject with
|
|
12
17
|
whitespace and delivers nothing — silently, and only on that broker, so an
|
|
@@ -39,66 +44,67 @@ var d = 7500, f = (e) => typeof e == "object" && !!e && e.kind === "event", p =
|
|
|
39
44
|
openAccess: e.openAccess,
|
|
40
45
|
rewind: e.rewind,
|
|
41
46
|
webhook: e.webhook,
|
|
42
|
-
delivery: e.delivery
|
|
47
|
+
delivery: e.delivery,
|
|
48
|
+
...e.clientPolicy === void 0 ? {} : { clientPolicy: e.clientPolicy }
|
|
43
49
|
};
|
|
44
|
-
},
|
|
45
|
-
_tag:
|
|
46
|
-
origin:
|
|
47
|
-
n:
|
|
48
|
-
emittedAt:
|
|
50
|
+
}, h = (e) => u.Struct({
|
|
51
|
+
_tag: u.Literal("event"),
|
|
52
|
+
origin: u.String,
|
|
53
|
+
n: u.Number,
|
|
54
|
+
emittedAt: u.Number,
|
|
49
55
|
payload: e
|
|
50
|
-
}),
|
|
51
|
-
_tag:
|
|
52
|
-
missed:
|
|
53
|
-
reason:
|
|
54
|
-
}),
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
]),
|
|
59
|
-
origin:
|
|
60
|
-
n:
|
|
61
|
-
}),
|
|
56
|
+
}), g = u.Struct({
|
|
57
|
+
_tag: u.Literal("gap"),
|
|
58
|
+
missed: u.Number,
|
|
59
|
+
reason: u.Literals(["buffer", "resume"])
|
|
60
|
+
}), _ = u.Struct({ _tag: u.Literal("attached") }), v = (e) => u.Union([
|
|
61
|
+
_,
|
|
62
|
+
h(e),
|
|
63
|
+
g
|
|
64
|
+
]), y = u.Struct({
|
|
65
|
+
origin: u.String,
|
|
66
|
+
n: u.Number
|
|
67
|
+
}), b = (e) => u.Struct({
|
|
62
68
|
key: e,
|
|
63
|
-
resume:
|
|
64
|
-
}),
|
|
65
|
-
let f = o.guards !== void 0 && o.guards.some((e) => !a(e)) ?
|
|
69
|
+
resume: u.optional(u.Array(y))
|
|
70
|
+
}), x = l.Service("@voltro/protocol/EventRpcWorkload"), S = (o, l) => {
|
|
71
|
+
let f = o.guards !== void 0 && o.guards.some((e) => !a(e)) ? u.Union([
|
|
66
72
|
r,
|
|
67
73
|
t,
|
|
68
74
|
e
|
|
69
|
-
]) :
|
|
70
|
-
return
|
|
71
|
-
payload: s(
|
|
72
|
-
success:
|
|
75
|
+
]) : u.Union([t, e]), p = i(o.guards) ? u.Union([f, n]) : f, m = l && l.length > 0 ? u.Union([p, ...l]) : p;
|
|
76
|
+
return d.make(o.name, {
|
|
77
|
+
payload: s(b(o.key), o.name, c(o.guards)),
|
|
78
|
+
success: v(o.payload),
|
|
73
79
|
error: m,
|
|
74
80
|
stream: !0
|
|
75
|
-
});
|
|
76
|
-
},
|
|
77
|
-
event:
|
|
78
|
-
message:
|
|
79
|
-
}) {},
|
|
80
|
-
event:
|
|
81
|
-
message:
|
|
82
|
-
}) {},
|
|
83
|
-
event:
|
|
84
|
-
bytes:
|
|
85
|
-
limit:
|
|
86
|
-
}) {},
|
|
81
|
+
}).annotate(x, !0);
|
|
82
|
+
}, C = class extends u.TaggedError()("EventPayloadInvalid", {
|
|
83
|
+
event: u.String,
|
|
84
|
+
message: u.String
|
|
85
|
+
}) {}, w = class extends u.TaggedError()("EventKeyInvalid", {
|
|
86
|
+
event: u.String,
|
|
87
|
+
message: u.String
|
|
88
|
+
}) {}, T = class extends u.TaggedError()("EventPayloadTooLarge", {
|
|
89
|
+
event: u.String,
|
|
90
|
+
bytes: u.Number,
|
|
91
|
+
limit: u.Number
|
|
92
|
+
}) {}, E = (e) => {
|
|
87
93
|
if (typeof e != "object" || !e) return JSON.stringify(e) ?? "null";
|
|
88
94
|
let t = Object.entries(e), n = 0;
|
|
89
95
|
for (let e of t) e[1] !== void 0 && (t[n++] = e);
|
|
90
96
|
return t.length = n, t.sort(([e], [t]) => e < t ? -1 : +(e > t)), JSON.stringify(t);
|
|
91
|
-
},
|
|
97
|
+
}, D = "\0", O = (e, t, n) => [
|
|
92
98
|
e ?? "~",
|
|
93
99
|
t,
|
|
94
|
-
|
|
95
|
-
].join("\0"),
|
|
100
|
+
E(n)
|
|
101
|
+
].join("\0"), k = (e) => {
|
|
96
102
|
let [t = "~", n = "", r = ""] = e.split("\0");
|
|
97
103
|
return {
|
|
98
104
|
tenantId: t === "~" ? null : t,
|
|
99
105
|
event: n,
|
|
100
106
|
key: r
|
|
101
107
|
};
|
|
102
|
-
},
|
|
108
|
+
}, A = (e) => e.split("\0").join(" · ");
|
|
103
109
|
//#endregion
|
|
104
|
-
export {
|
|
110
|
+
export { D as EVENT_ROUTE_SEP, w as EventKeyInvalid, C as EventPayloadInvalid, T as EventPayloadTooLarge, x as EventRpcWorkload, f as MAX_EVENT_ENVELOPE_BYTES, m as defineEvent, E as encodeEventKey, _ as eventAttached, h as eventEnvelope, g as eventGap, y as eventResumePoint, O as eventRoute, v as eventStreamEvent, b as eventSubscribeInput, S as eventToRpc, A as formatEventRoute, p as isEventDescriptor, k as parseEventRoute };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/formCapture.ts
|
|
2
|
+
var e = "__voltro_capture", t = "voltro:form-source", n = (e) => typeof e == "string" && e.length === 261 && /^1(?:\.[a-f0-9]{64}){4}$/.test(e) ? e : void 0, r = (e, t) => {
|
|
3
|
+
let r = n(e + "." + t);
|
|
4
|
+
if (r === void 0) throw Error("Native form source unavailable");
|
|
5
|
+
return r;
|
|
6
|
+
}, i = (e = globalThis.document) => {
|
|
7
|
+
if (e === void 0) return;
|
|
8
|
+
let r = e.querySelectorAll(`meta[name="${t}"]`);
|
|
9
|
+
return r.length === 1 ? n(r[0].getAttribute("content")) : void 0;
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { e as FORM_CAPTURE_FIELD, t as FORM_CAPTURE_META_NAME, r as encodeNativeFormCapture, n as formCaptureSource, i as readFormCaptureSource };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/httpStreamMaxDuration.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (e !== void 0) {
|
|
4
|
+
if (typeof e != "number" || !Number.isSafeInteger(e) || e < 1 || e > 2147483647) throw RangeError("SSE maxDurationMs must be an integer between 1 and 2147483647.");
|
|
5
|
+
return e;
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { e as validateHttpStreamMaxDuration };
|