@voltro/protocol 0.1.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/dist/index.js ADDED
@@ -0,0 +1,396 @@
1
+ import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as ee, r as te, s, t as ne, u as re } from "./auth-DCE6m7Bo.js";
2
+ import { a as ie, c as ae, d as oe, f as se, i as ce, l as le, n as ue, o as de, r as fe, s as pe, t as me, u as he } from "./serverErrorBus-C1KVL0dr.js";
3
+ import { Context as ge, Layer as _e, Schema as c } from "effect";
4
+ import { Rpc as l } from "@effect/rpc";
5
+ //#region src/rowPatch.ts
6
+ var ve = c.Union(c.String, c.Number), u = c.Record({
7
+ key: c.String,
8
+ value: c.Unknown
9
+ }).pipe(c.filter((e) => "id" in e, { message: () => "patch row must carry an id" })), d = c.Union(c.Struct({
10
+ op: c.Literal("add"),
11
+ path: c.String,
12
+ value: u
13
+ }), c.Struct({
14
+ op: c.Literal("replace"),
15
+ path: c.String,
16
+ value: u
17
+ }), c.Struct({
18
+ op: c.Literal("remove"),
19
+ path: c.String
20
+ })), f = c.Struct({
21
+ ops: c.Array(d),
22
+ order: c.Array(ve)
23
+ }), p = (e) => `/${String(e).replace(/~/g, "~0").replace(/\//g, "~1")}`, ye = (e) => (e.startsWith("/") ? e.slice(1) : e).replace(/~1/g, "/").replace(/~0/g, "~"), m = (e) => {
24
+ let t = Object.keys(e).sort(), n = {};
25
+ for (let r of t) n[r] = e[r];
26
+ return JSON.stringify(n);
27
+ }, be = (e, t) => m(e) === m(t), xe = (e, t) => {
28
+ let n = /* @__PURE__ */ new Map();
29
+ for (let t of e) n.set(t.id, t);
30
+ let r = [], i = [], a = /* @__PURE__ */ new Set();
31
+ for (let e of t) {
32
+ i.push(e.id), a.add(e.id);
33
+ let t = n.get(e.id);
34
+ t === void 0 ? r.push({
35
+ op: "add",
36
+ path: p(e.id),
37
+ value: e
38
+ }) : be(t, e) || r.push({
39
+ op: "replace",
40
+ path: p(e.id),
41
+ value: e
42
+ });
43
+ }
44
+ for (let t of e) a.has(t.id) || r.push({
45
+ op: "remove",
46
+ path: p(t.id)
47
+ });
48
+ return {
49
+ ops: r,
50
+ order: i
51
+ };
52
+ }, Se = (e) => e.every((e) => {
53
+ let t = e.id;
54
+ return typeof t == "string" || typeof t == "number";
55
+ }), Ce = (e, t) => {
56
+ let n = /* @__PURE__ */ new Map();
57
+ for (let t of e) n.set(t.id, t);
58
+ for (let e of t.ops) (e.op === "add" || e.op === "replace") && n.set(e.value.id, e.value);
59
+ let r = [];
60
+ for (let e of t.order) {
61
+ let t = n.get(e);
62
+ t !== void 0 && r.push(t);
63
+ }
64
+ return r;
65
+ }, h = (e) => c.Union(c.Struct({
66
+ _tag: c.Literal("snapshot"),
67
+ revision: c.Number,
68
+ data: e,
69
+ computed: c.optional(c.Boolean)
70
+ }), c.Struct({
71
+ _tag: c.Literal("delta"),
72
+ revision: c.Number,
73
+ emittedAt: c.Number,
74
+ patch: f
75
+ }), c.Struct({
76
+ _tag: c.Literal("error"),
77
+ error: c.Unknown,
78
+ revision: c.optional(c.Number)
79
+ })), g = (e) => ({
80
+ kind: "query",
81
+ name: e.name,
82
+ input: e.input,
83
+ output: e.output,
84
+ error: e.error ?? c.Never,
85
+ source: e.source,
86
+ cache: e.cache,
87
+ publicApi: e.publicApi,
88
+ exposeAsTool: e.exposeAsTool
89
+ }), _ = (e) => ({
90
+ kind: "mutation",
91
+ name: e.name,
92
+ input: e.input,
93
+ output: e.output,
94
+ error: e.error ?? c.Never,
95
+ target: e.target,
96
+ publicApi: e.publicApi,
97
+ exposeAsTool: e.exposeAsTool
98
+ }), v = (e) => ({
99
+ kind: "action",
100
+ name: e.name,
101
+ input: e.input,
102
+ output: e.output,
103
+ error: e.error ?? c.Never,
104
+ publicApi: e.publicApi,
105
+ exposeAsTool: e.exposeAsTool
106
+ }), we = (e) => ({
107
+ kind: "stream",
108
+ name: e.name,
109
+ input: e.input,
110
+ element: e.element,
111
+ error: e.error ?? c.Never
112
+ }), y = (e, t) => t && t.length > 0 ? c.Union(e, ...t) : e, b = (e, t) => l.make(e.name, {
113
+ payload: e.input,
114
+ success: h(e.output),
115
+ error: y(e.error, t),
116
+ stream: !0
117
+ }), x = (e, t) => l.make(e.name, {
118
+ payload: e.input,
119
+ success: e.output,
120
+ error: y(e.error, t)
121
+ }), S = (e, t) => l.make(e.name, {
122
+ payload: e.input,
123
+ success: e.output,
124
+ error: y(e.error, t)
125
+ }), C = (e, t) => l.make(e.name, {
126
+ payload: e.input,
127
+ success: e.element,
128
+ error: y(e.error, t),
129
+ stream: !0
130
+ }), Te = (e) => {
131
+ switch (e.kind) {
132
+ case "query": return b(e);
133
+ case "mutation": return x(e);
134
+ case "action": return S(e);
135
+ case "stream": return C(e);
136
+ }
137
+ }, Ee = (e) => {
138
+ let t = e.input, n = t === void 0 ? {} : { input: t }, r = e.output, i = r === void 0 ? {} : { output: r };
139
+ if (e.kind === "query") return {
140
+ kind: "query",
141
+ source: e.source,
142
+ ...n,
143
+ ...i
144
+ };
145
+ if (e.kind === "action") return {
146
+ kind: "action",
147
+ ...n,
148
+ ...i
149
+ };
150
+ if (e.kind === "stream") return {
151
+ kind: "stream",
152
+ ...n,
153
+ ...i
154
+ };
155
+ let a = e.target;
156
+ if (a === void 0) return {
157
+ kind: "mutation",
158
+ ...n,
159
+ ...i
160
+ };
161
+ let o = Array.isArray(a) ? a : [a];
162
+ return {
163
+ kind: "mutation",
164
+ ...n,
165
+ ...i,
166
+ targets: o.map((e) => ({
167
+ table: e.table,
168
+ op: e.op,
169
+ ..."order" in e && e.order !== void 0 ? { order: e.order } : {},
170
+ ..."shape" in e && e.shape !== void 0 ? { shape: e.shape } : {},
171
+ ..."identify" in e && e.identify !== void 0 ? { identify: e.identify } : {}
172
+ }))
173
+ };
174
+ }, w = (e) => e, T = (e) => e, E = (e) => {
175
+ if (e.length !== 0) return (t, n) => e.reduceRight((e, t) => t(e, n), t);
176
+ }, D = (e, t) => {
177
+ let n = ge.GenericTag(e);
178
+ return {
179
+ Tag: n,
180
+ Live: _e.succeed(n, t)
181
+ };
182
+ }, De = (e, t, n) => {
183
+ if (!t) return { ok: !0 };
184
+ let r = O(n);
185
+ if (!r) return {
186
+ ok: !1,
187
+ reason: `cannot parse runningVersion "${n}"`
188
+ };
189
+ let i = t.trim();
190
+ if (i === "*" || i === "") return { ok: !0 };
191
+ let a = i.split(/\s+/).filter((e) => e.length > 0);
192
+ for (let i of a) if (!Oe(i, r)) return {
193
+ ok: !1,
194
+ reason: `plugin "${e}" requires framework ${t}, running ${n}`
195
+ };
196
+ return { ok: !0 };
197
+ }, O = (e) => {
198
+ let t = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9a-zA-Z.-]+))?$/.exec(e.trim());
199
+ return t ? {
200
+ major: Number(t[1]),
201
+ minor: Number(t[2]),
202
+ patch: Number(t[3]),
203
+ pre: t[4] ?? ""
204
+ } : null;
205
+ }, k = (e, t) => e.major === t.major ? e.minor === t.minor ? e.patch === t.patch ? e.pre && !t.pre ? -1 : !e.pre && t.pre ? 1 : e.pre && t.pre ? e.pre < t.pre ? -1 : +(e.pre > t.pre) : 0 : e.patch - t.patch : e.minor - t.minor : e.major - t.major, Oe = (e, t) => {
206
+ if (e === "*") return !0;
207
+ if (e.startsWith("^")) {
208
+ let n = O(e.slice(1));
209
+ return !n || t.major !== n.major ? !1 : k(t, n) >= 0;
210
+ }
211
+ if (e.startsWith("~")) {
212
+ let n = O(e.slice(1));
213
+ return !n || t.major !== n.major || t.minor !== n.minor ? !1 : k(t, n) >= 0;
214
+ }
215
+ let n = /^(>=|<=|>|<)(.+)$/.exec(e);
216
+ if (n) {
217
+ let e = n[1], r = O(n[2]);
218
+ if (!r) return !1;
219
+ let i = k(t, r);
220
+ if (e === ">=") return i >= 0;
221
+ if (e === "<=") return i <= 0;
222
+ if (e === ">") return i > 0;
223
+ if (e === "<") return i < 0;
224
+ }
225
+ let r = O(e);
226
+ return r ? k(t, r) === 0 : !1;
227
+ }, A = c.Literal("running", "succeeded", "failed", "cancelled", "suspended"), j = c.Literal("cancel", "terminate", "abandon"), ke = c.Struct({
228
+ id: c.String,
229
+ workflowName: c.String,
230
+ executionId: c.String,
231
+ status: c.Literal("running")
232
+ }), M = c.Struct({
233
+ id: c.String,
234
+ tag: c.String,
235
+ executionId: c.String,
236
+ status: A,
237
+ payload: c.Unknown,
238
+ workflowVersion: c.NullOr(c.String),
239
+ workflowPatches: c.NullOr(c.Unknown),
240
+ output: c.NullOr(c.Unknown),
241
+ subject: c.NullOr(c.Unknown),
242
+ source: c.NullOr(c.String),
243
+ errorTag: c.NullOr(c.String),
244
+ errorMessage: c.NullOr(c.String),
245
+ cancelled: c.Boolean,
246
+ startedAt: c.Date,
247
+ completedAt: c.NullOr(c.Date),
248
+ durationMs: c.NullOr(c.Number),
249
+ traceId: c.NullOr(c.String),
250
+ parentExecutionId: c.NullOr(c.String),
251
+ parentClosePolicy: c.NullOr(j)
252
+ }), N = c.Struct({
253
+ tag: c.optional(c.String),
254
+ status: c.optional(A),
255
+ limit: c.optional(c.Number)
256
+ }), P = c.Struct({
257
+ id: c.String,
258
+ runId: c.String,
259
+ stepName: c.String,
260
+ attempt: c.Number,
261
+ status: c.Literal("running", "succeeded", "failed"),
262
+ input: c.NullOr(c.Unknown),
263
+ retryPolicy: c.NullOr(c.Unknown),
264
+ output: c.NullOr(c.Unknown),
265
+ errorTag: c.NullOr(c.String),
266
+ errorMessage: c.NullOr(c.String),
267
+ errorCause: c.NullOr(c.Unknown),
268
+ startedAt: c.Date,
269
+ completedAt: c.NullOr(c.Date),
270
+ durationMs: c.NullOr(c.Number)
271
+ }), F = c.Struct({
272
+ id: c.String,
273
+ runId: c.String,
274
+ eventType: c.String,
275
+ payload: c.NullOr(c.Unknown),
276
+ occurredAt: c.Date,
277
+ stepName: c.NullOr(c.String),
278
+ attempt: c.NullOr(c.Number)
279
+ }), I = c.Struct({
280
+ id: c.String,
281
+ name: c.String,
282
+ payload: c.Unknown,
283
+ source: c.String,
284
+ subject: c.NullOr(c.Unknown),
285
+ traceId: c.NullOr(c.String),
286
+ occurredAt: c.Date
287
+ }), L = c.Struct({
288
+ id: c.String,
289
+ eventId: c.String,
290
+ eventName: c.String,
291
+ triggerId: c.String,
292
+ workflowName: c.String,
293
+ executionId: c.NullOr(c.String),
294
+ status: c.Literal("starting", "started", "skipped", "failed"),
295
+ idempotencyKey: c.String,
296
+ skipped: c.Boolean,
297
+ errorMessage: c.NullOr(c.String),
298
+ createdAt: c.Date,
299
+ completedAt: c.NullOr(c.Date)
300
+ }), R = c.Struct({ id: c.String }), z = c.Struct({ runId: c.String }), B = c.Struct({
301
+ name: c.optional(c.String),
302
+ limit: c.optional(c.Number)
303
+ }), V = c.Struct({ eventId: c.String }), H = c.Struct({
304
+ workflowName: c.String,
305
+ executionId: c.String
306
+ }), U = c.Struct({
307
+ id: c.String,
308
+ signalName: c.String,
309
+ payload: c.optional(c.Unknown)
310
+ }), W = c.Struct({
311
+ id: c.String,
312
+ updateName: c.String,
313
+ payload: c.optional(c.Unknown),
314
+ timeoutMs: c.optional(c.Number)
315
+ }), G = c.Struct({
316
+ eventId: c.String,
317
+ updateId: c.String,
318
+ completedEventId: c.String,
319
+ result: c.Unknown
320
+ }), Ae = g({
321
+ name: "__voltro.workflow.run",
322
+ source: "_voltro_workflow_runs",
323
+ input: R,
324
+ output: c.Array(M)
325
+ }), je = g({
326
+ name: "__voltro.workflow.runs",
327
+ source: "_voltro_workflow_runs",
328
+ input: N,
329
+ output: c.Array(M)
330
+ }), Me = g({
331
+ name: "__voltro.workflow.run.steps",
332
+ source: "_voltro_workflow_run_steps",
333
+ input: z,
334
+ output: c.Array(P)
335
+ }), Ne = g({
336
+ name: "__voltro.workflow.run.events",
337
+ source: "_voltro_workflow_run_events",
338
+ input: z,
339
+ output: c.Array(F)
340
+ }), Pe = g({
341
+ name: "__voltro.workflow.domainEvents",
342
+ source: "_voltro_workflow_events",
343
+ input: B,
344
+ output: c.Array(I)
345
+ }), Fe = g({
346
+ name: "__voltro.workflow.event.deliveries",
347
+ source: "_voltro_workflow_event_deliveries",
348
+ input: V,
349
+ output: c.Array(L)
350
+ }), Ie = v({
351
+ name: "__voltro.workflow.cancel",
352
+ input: H,
353
+ output: c.Struct({ ok: c.Boolean })
354
+ }), Le = v({
355
+ name: "__voltro.workflow.resume",
356
+ input: H,
357
+ output: c.Struct({ ok: c.Boolean })
358
+ }), Re = v({
359
+ name: "__voltro.workflow.signal",
360
+ input: U,
361
+ output: c.Struct({ eventId: c.String })
362
+ }), ze = v({
363
+ name: "__voltro.workflow.update",
364
+ input: W,
365
+ output: G
366
+ }), K = "__voltro.undo.log", q = "__voltro.undo.apply", J = "__voltro.undo.redo", Y = c.Struct({
367
+ id: c.String,
368
+ tag: c.String,
369
+ label: c.NullOr(c.String),
370
+ undone: c.Boolean,
371
+ crossesAction: c.Boolean,
372
+ createdAt: c.String
373
+ }), X = class extends c.TaggedError()("UndoNotFound", { invocationId: c.String }) {}, Z = class extends c.TaggedError()("UndoForbidden", { invocationId: c.String }) {}, Q = class extends c.TaggedError()("UndoConflict", {
374
+ invocationId: c.String,
375
+ reason: c.Literal("conflict", "action")
376
+ }) {}, $ = c.Union(X, Z, Q), Be = g({
377
+ name: K,
378
+ source: "_voltro_undo_log",
379
+ input: c.Struct({ limit: c.optional(c.Number) }),
380
+ output: c.Array(Y)
381
+ }), Ve = _({
382
+ name: q,
383
+ input: c.Struct({ invocationId: c.String }),
384
+ output: c.Struct({ ok: c.Boolean }),
385
+ error: $
386
+ }), He = _({
387
+ name: J,
388
+ input: c.Struct({ invocationId: c.String }),
389
+ output: c.Struct({ ok: c.Boolean }),
390
+ error: $
391
+ }), Ue = (e) => {
392
+ let t = e instanceof Date ? e.getTime() : typeof e == "number" ? e : typeof e == "string" ? new Date(e).getTime() : 0;
393
+ return Number.isNaN(t) ? 0 : t;
394
+ }, We = 1;
395
+ //#endregion
396
+ export { ae as ADMIN_SCOPE, ne as AuthMiddleware, o as ConnectionInfo, te as ConnectionInfoMiddleware, We as PROTOCOL_VERSION, le as ScopeError, i as Subject, e as SubjectService, q as UNDO_APPLY_TAG, K as UNDO_LOG_TAG, J as UNDO_REDO_TAG, ee as Unauthenticated, Q as UndoConflict, Z as UndoForbidden, Y as UndoLogEntry, X as UndoNotFound, H as WorkflowControlInputSchema, I as WorkflowDomainEventRowSchema, B as WorkflowDomainEventsInputSchema, V as WorkflowEventDeliveriesInputSchema, L as WorkflowEventDeliveryRowSchema, j as WorkflowParentClosePolicySchema, F as WorkflowRunEventRowSchema, ke as WorkflowRunHandleSchema, R as WorkflowRunRefSchema, M as WorkflowRunRowSchema, A as WorkflowRunStatusSchema, P as WorkflowRunStepRowSchema, z as WorkflowRunTableRefSchema, N as WorkflowRunsInputSchema, U as WorkflowSignalInputSchema, W as WorkflowUpdateInputSchema, G as WorkflowUpdateResultSchema, S as actionToRpc, s as anonymousSubject, Ce as applyRowPatch, t as assertAuthenticated, fe as beginIdempotent, De as checkFrameworkCompat, a as composeAuthStrategies, E as composeRpcInterceptors, v as defineAction, _ as defineMutation, w as definePlugin, T as definePluginRoute, D as definePluginService, g as defineQuery, we as defineStream, xe as diffRows, ce as failIdempotent, ie as finishIdempotent, re as hasCallbackRoutes, he as hasScope, p as idToPath, de as idempotencyScope, Se as isIdKeyed, n as isSystemSubject, pe as memoryIdempotencyStore, x as mutationToRpc, Ee as normalizeDescriptor, ye as pathToId, me as publishServerError, b as queryToRpc, oe as requireScope, d as rowPatchOpSchema, f as rowPatchSchema, C as streamToRpc, se as subjectScopes, ue as subscribeServerErrors, h as subscriptionEvent, r as systemSubject, Te as toRpc, Ue as tsMs, Ve as undoApplyDescriptor, Be as undoLogQueryDescriptor, He as undoRedoDescriptor, Ie as workflowCancelDescriptor, Pe as workflowDomainEventsQueryDescriptor, Fe as workflowEventDeliveriesQueryDescriptor, Le as workflowResumeDescriptor, Ne as workflowRunEventsQueryDescriptor, Ae as workflowRunQueryDescriptor, Me as workflowRunStepsQueryDescriptor, je as workflowRunsQueryDescriptor, Re as workflowSignalDescriptor, ze as workflowUpdateDescriptor };
package/dist/jwt.d.ts ADDED
@@ -0,0 +1,230 @@
1
+ import { Schema } from 'effect';
2
+
3
+ /** Pluggable auth strategy. Strategies are SYNC-fast on no-match
4
+ * (cookie-name lookup) and cache any JWKS / DB roundtrips on match
5
+ * so steady-state verification stays CPU-local. */
6
+ declare interface AuthStrategy {
7
+ /** Stable id (`'voltro-password'`, `'workos'`, `'kinde'`, …). Used
8
+ * in logs + `Subject.metadata.provider`. */
9
+ readonly id: string;
10
+ readonly resolve: (input: AuthStrategyInput) => Promise<StrategyResolution> | StrategyResolution;
11
+ }
12
+
13
+ /** Per-call input the framework hands every strategy. */
14
+ declare interface AuthStrategyInput {
15
+ readonly headers: Readonly<Record<string, string | undefined>>;
16
+ readonly clientId: number;
17
+ }
18
+
19
+ /**
20
+ * Fetch (and per-URL cache) an OIDC discovery document — the
21
+ * `.well-known/openid-configuration` an IdP publishes so consumers can
22
+ * resolve `jwks_uri` without hard-coding it. One shared cached fetcher for
23
+ * every `@voltro/plugin-auth-*` adapter that does OIDC discovery, so the
24
+ * `Map<url, Promise>` lives once at this layer instead of being re-rolled per
25
+ * adapter. Successful lookups are cached for the process lifetime; FAILED
26
+ * lookups are evicted so the next call retries (transient DNS / 5xx). Pure
27
+ * `fetch` — browser-safe, no Node deps.
28
+ */
29
+ export declare const discoverOidc: (url: string) => Promise<OidcDiscoveryDocument>;
30
+
31
+ /** Pull a JWT from either `Authorization: Bearer …` or the named cookie.
32
+ * Returns undefined when neither is present (strategy returns `skip`). */
33
+ export declare const extractBearerOrCookie: (headers: Readonly<Record<string, string | undefined>>, cookieName: string | null) => string | undefined;
34
+
35
+ /**
36
+ * JWKS-backed verification (asymmetric: ES256/RS256/PS256/EdDSA) — the
37
+ * default for hosted IdPs that publish a JWKS endpoint. Tokens are
38
+ * verified against the fetched public keys; HMAC algorithms are rejected.
39
+ */
40
+ export declare interface JwtBearerJwksConfig extends JwtBearerStrategyBase {
41
+ /** JWKS endpoint URL. Plugin sets the provider-specific default. */
42
+ readonly jwksUrl: string;
43
+ readonly jwtSecret?: never;
44
+ /** JWT algorithm allowlist. Defaults to `['ES256', 'RS256']`. Plugins
45
+ * override when their IdP signs with PS256/EdDSA. */
46
+ readonly algorithms?: ReadonlyArray<'ES256' | 'RS256' | 'PS256' | 'EdDSA'>;
47
+ }
48
+
49
+ /**
50
+ * Shared-secret verification (symmetric HMAC: HS256/384/512) — for IdPs
51
+ * that sign tokens with a shared secret and expose no JWKS, e.g. legacy /
52
+ * self-hosted Supabase (`JWT_SECRET`). The secret is a SERVER-side value
53
+ * and must never reach the browser bundle.
54
+ */
55
+ export declare interface JwtBearerSecretConfig extends JwtBearerStrategyBase {
56
+ /** Shared HMAC secret the IdP signs its tokens with. */
57
+ readonly jwtSecret: string;
58
+ readonly jwksUrl?: never;
59
+ /** JWT algorithm allowlist. Defaults to `['HS256']`. */
60
+ readonly algorithms?: ReadonlyArray<'HS256' | 'HS384' | 'HS512'>;
61
+ }
62
+
63
+ export declare const jwtBearerStrategy: (config: JwtBearerStrategyConfig) => AuthStrategy;
64
+
65
+ declare interface JwtBearerStrategyBase {
66
+ /** Stable id — `'workos' | 'kinde' | 'clerk' | …`. Used in logs and
67
+ * stamped onto `Subject.metadata.provider`. */
68
+ readonly id: string;
69
+ /** Expected issuer claim(s). Passed straight to the verifier. */
70
+ readonly issuer?: string | ReadonlyArray<string>;
71
+ /** Expected audience claim(s). */
72
+ readonly audience?: string | ReadonlyArray<string>;
73
+ /** Cookie name when the JWT travels as a cookie. Pass `null` to
74
+ * disable cookie fallback (header-only mode). */
75
+ readonly cookieName?: string | null;
76
+ /** Map verified JWT claims to a Voltro tenantId. Most IdPs put an
77
+ * org reference somewhere in the claims; plugins wire it here.
78
+ * Returning `null` is treated as `failed` — the strategy IS the
79
+ * request's owner but it can't satisfy the tenant invariant. */
80
+ readonly tenantIdFromClaims: (claims: Record<string, unknown>) => string | null;
81
+ /** Override how the Subject's `id` is derived from the claims.
82
+ * Defaults to `claims.sub`. Plugins set this when an IdP uses a
83
+ * custom subject identifier. */
84
+ readonly subjectIdFromClaims?: (claims: Record<string, unknown>) => string;
85
+ /**
86
+ * Map verified JWT claims to the subject's permission scopes. The
87
+ * returned list lands on `Subject.scopes`, so `requireScope` /
88
+ * `hasScope` (`@voltro/protocol`) gate handlers off the IdP's claims
89
+ * with NO second lookup. Typical shapes: a space-delimited OAuth
90
+ * `scope` string (`(c) => String(c.scope ?? '').split(' ').filter(Boolean)`),
91
+ * an Auth0 `permissions` array, a Kinde `roles[].key` list. Omitted →
92
+ * `Subject.scopes` stays undefined (the unchanged default; a
93
+ * handler-side scope gate then denies). Return `[]` to grant none.
94
+ */
95
+ readonly scopesFromClaims?: (claims: Record<string, unknown>) => ReadonlyArray<string>;
96
+ }
97
+
98
+ /** JWT-based strategy config — verified EITHER via a JWKS endpoint
99
+ * (`jwksUrl`, asymmetric) OR a shared HMAC secret (`jwtSecret`,
100
+ * symmetric). The two are mutually exclusive. */
101
+ export declare type JwtBearerStrategyConfig = JwtBearerJwksConfig | JwtBearerSecretConfig;
102
+
103
+ /** Thrown by `verifyJwt` on signature mismatch / expiry / claim
104
+ * mismatch / unsupported algorithm. Strategies catch + downgrade
105
+ * to `StrategyResolution.failed`. */
106
+ export declare class JwtVerifyError extends Error {
107
+ readonly code: 'signature_mismatch' | 'expired' | 'not_yet_valid' | 'issuer_mismatch' | 'audience_mismatch' | 'unsupported_algorithm' | 'malformed' | 'jwks_unreachable' | 'other';
108
+ constructor(message: string, code: 'signature_mismatch' | 'expired' | 'not_yet_valid' | 'issuer_mismatch' | 'audience_mismatch' | 'unsupported_algorithm' | 'malformed' | 'jwks_unreachable' | 'other');
109
+ }
110
+
111
+ /** The subset of an OIDC discovery document the framework reads. Providers
112
+ * ship many more fields; only `jwks_uri` is load-bearing for verification. */
113
+ export declare interface OidcDiscoveryDocument {
114
+ readonly issuer: string;
115
+ readonly jwks_uri: string;
116
+ readonly [key: string]: unknown;
117
+ }
118
+
119
+ /**
120
+ * Read a nested claim by dot-path (`'app_metadata.tenant_id'`,
121
+ * `'https://acme/tenant'`, `'org.id'`). Every IdP adapter that resolves a
122
+ * tenant / scope from a NESTED claim needs the same safe walk — this is the
123
+ * one shared implementation so they don't each re-derive it (and subtly
124
+ * diverge on the null-guard). Pure + browser-safe: no IO, no deps.
125
+ *
126
+ * A path with no `.` is a plain top-level key lookup. Any missing / non-object
127
+ * segment short-circuits to `undefined` (never throws on `null`/primitive
128
+ * intermediates). The returned value is untyped — callers narrow it.
129
+ */
130
+ export declare const readClaimPath: (claims: Record<string, unknown>, path: string) => unknown;
131
+
132
+ /**
133
+ * Read a cookie value by name from a `Cookie:` header string.
134
+ * Returns undefined if the cookie isn't present.
135
+ */
136
+ export declare const readCookie: (header: string | undefined, name: string) => string | undefined;
137
+
138
+ /** Test-only: clear the cache. Lets tests + dev-mode hot-reload skip
139
+ * the per-process global cache between runs. */
140
+ export declare const _resetJwksCache: () => void;
141
+
142
+ /** Test-only: clear the OIDC discovery-document cache between runs. */
143
+ export declare const _resetOidcDiscoveryCache: () => void;
144
+
145
+ /** A strategy's verdict on a request.
146
+ * - `matched`: this strategy claims the request; here's the Subject.
147
+ * - `skip`: not my request (e.g. cookie absent); try next strategy.
148
+ * - `failed`: this IS my request BUT validation failed (signature
149
+ * mismatch, expired JWT). Composer bails to anonymous + logs;
150
+ * silently falling through would mask attacks. */
151
+ declare type StrategyResolution = {
152
+ readonly kind: 'matched';
153
+ readonly subject: Subject;
154
+ } | {
155
+ readonly kind: 'skip';
156
+ } | {
157
+ readonly kind: 'failed';
158
+ readonly reason: string;
159
+ };
160
+
161
+ declare const Subject: Schema.Union<[Schema.Struct<{
162
+ type: Schema.Literal<["user"]>;
163
+ id: typeof Schema.String;
164
+ tenantId: typeof Schema.String;
165
+ scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
166
+ metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
167
+ }>, Schema.Struct<{
168
+ type: Schema.Literal<["apiKey"]>;
169
+ id: typeof Schema.String;
170
+ tenantId: typeof Schema.String;
171
+ scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
172
+ metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
173
+ }>, Schema.Struct<{
174
+ type: Schema.Literal<["serviceAccount"]>;
175
+ id: typeof Schema.String;
176
+ tenantId: typeof Schema.String;
177
+ scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
178
+ metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
179
+ }>, Schema.Struct<{
180
+ type: Schema.Literal<["anonymous"]>;
181
+ id: typeof Schema.Null;
182
+ tenantId: Schema.NullOr<typeof Schema.String>;
183
+ }>, Schema.Struct<{
184
+ type: Schema.Literal<["system"]>;
185
+ id: typeof Schema.String;
186
+ tenantId: typeof Schema.Null;
187
+ scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
188
+ metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
189
+ }>]>;
190
+
191
+ declare type Subject = typeof Subject.Type;
192
+
193
+ /** Verify a JWT against a remote JWKS. Returns the decoded claims on
194
+ * success. Throws `JwtVerifyError` on any verification failure. */
195
+ export declare const verifyJwt: (jwt: string, jwksUrl: string, options?: VerifyJwtOptions) => Promise<Record<string, unknown>>;
196
+
197
+ export declare interface VerifyJwtOptions {
198
+ /** Expected `iss` claim. String or list of acceptable issuers. */
199
+ readonly issuer?: string | ReadonlyArray<string>;
200
+ /** Expected `aud` claim. Most IdPs set audience = your `clientId`. */
201
+ readonly audience?: string | ReadonlyArray<string>;
202
+ /** Clock skew tolerance in seconds. Default: 60s. */
203
+ readonly clockToleranceS?: number;
204
+ /** Algorithm allowlist. Default: ['ES256', 'RS256']. */
205
+ readonly algorithms?: ReadonlyArray<'ES256' | 'RS256' | 'PS256' | 'EdDSA'>;
206
+ /** Override the per-JWKS cache TTL. Default 1h. */
207
+ readonly jwksCacheTtlMs?: number;
208
+ }
209
+
210
+ /** Verify a JWT against a shared HMAC secret (HS256/384/512). For IdPs
211
+ * that sign tokens SYMMETRICALLY and expose no JWKS endpoint — e.g.
212
+ * legacy / self-hosted Supabase (the project's `JWT_SECRET`). The
213
+ * asymmetric `verifyJwt` (JWKS) intentionally rejects HMAC algorithms;
214
+ * this is its symmetric counterpart. The secret is a server-side value
215
+ * — it must never reach the browser bundle. Returns the decoded claims
216
+ * on success; throws `JwtVerifyError` (same shape as `verifyJwt`). */
217
+ export declare const verifyJwtWithSecret: (jwt: string, secret: string, options?: VerifyJwtWithSecretOptions) => Promise<Record<string, unknown>>;
218
+
219
+ export declare interface VerifyJwtWithSecretOptions {
220
+ /** Expected `iss` claim. String or list of acceptable issuers. */
221
+ readonly issuer?: string | ReadonlyArray<string>;
222
+ /** Expected `aud` claim. */
223
+ readonly audience?: string | ReadonlyArray<string>;
224
+ /** Clock skew tolerance in seconds. Default: 60s. */
225
+ readonly clockToleranceS?: number;
226
+ /** Algorithm allowlist. Default: ['HS256']. */
227
+ readonly algorithms?: ReadonlyArray<'HS256' | 'HS384' | 'HS512'>;
228
+ }
229
+
230
+ export { }