@run402/functions 2.7.0 → 3.0.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/auth/errors.d.ts +89 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/errors.js +170 -0
- package/dist/auth/errors.js.map +1 -0
- package/dist/auth/index.d.ts +98 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +453 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/types.d.ts +58 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +13 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/auth/url-validation.d.ts +31 -0
- package/dist/auth/url-validation.d.ts.map +1 -0
- package/dist/auth/url-validation.js +83 -0
- package/dist/auth/url-validation.js.map +1 -0
- package/dist/auth.d.ts +25 -50
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +34 -103
- package/dist/auth.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +40 -0
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/actor-context-verify.d.ts +95 -0
- package/dist/lib/actor-context-verify.d.ts.map +1 -0
- package/dist/lib/actor-context-verify.js +200 -0
- package/dist/lib/actor-context-verify.js.map +1 -0
- package/dist/runtime-context.d.ts +14 -1
- package/dist/runtime-context.d.ts.map +1 -1
- package/dist/runtime-context.js +60 -0
- package/dist/runtime-context.js.map +1 -1
- package/dist/verify-webhook.d.ts +71 -0
- package/dist/verify-webhook.d.ts.map +1 -0
- package/dist/verify-webhook.js +147 -0
- package/dist/verify-webhook.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `auth.*` — the sole server-side auth namespace.
|
|
3
|
+
*
|
|
4
|
+
* The single import line for any consumer:
|
|
5
|
+
*
|
|
6
|
+
* import { auth } from "@run402/functions";
|
|
7
|
+
*
|
|
8
|
+
* Surface (deliberately small):
|
|
9
|
+
*
|
|
10
|
+
* auth.user() → Actor | null
|
|
11
|
+
* auth.requireUser() → Actor (throws / 303 otherwise)
|
|
12
|
+
* auth.requireRole(role) → { user, role }
|
|
13
|
+
* auth.requireMembership(membership) → { user, membership }
|
|
14
|
+
* auth.requireFresh({ maxAge, amr? }) → void (throws / 303 otherwise)
|
|
15
|
+
* auth.identities.link({ ... }) → void
|
|
16
|
+
* auth.fetch(input, init?) → Response (same-origin only)
|
|
17
|
+
* auth.csrfToken() → string
|
|
18
|
+
* auth.csrfField() → "<input type=hidden ...>"
|
|
19
|
+
* auth.sessions.createResponseFromIdentity({ ... }) → Response
|
|
20
|
+
* auth.sessions.endResponse() → Response
|
|
21
|
+
*
|
|
22
|
+
* Behaviour notes baked into the helpers:
|
|
23
|
+
* - Calling any helper taints the cache (the response now depends on
|
|
24
|
+
* per-request actor state). The taint is monotonic — once set, the
|
|
25
|
+
* SSR cache layer treats the response as non-cacheable until the
|
|
26
|
+
* request completes.
|
|
27
|
+
* - HTML-vs-JSON failure decisions are made by the gateway middleware
|
|
28
|
+
* (303 redirect for HTML, 401/403 envelope for JSON). The SDK throws
|
|
29
|
+
* a typed Error subclass; framework code OR the gateway translates.
|
|
30
|
+
* - `requireRole` / `requireMembership` always read fresh server-side
|
|
31
|
+
* grant data — no positive cache (matches D8 + the "instant revocation"
|
|
32
|
+
* contract). For now we route via `getRole` which the gateway sets
|
|
33
|
+
* at the routed-function envelope; once the v1.60 grants table lands,
|
|
34
|
+
* gate helpers will JOIN against it inside the same request.
|
|
35
|
+
* - `requireFresh` consults the per-method `amr_times` on the Actor —
|
|
36
|
+
* a recent password proof does NOT satisfy `{amr: ["passkey"]}`.
|
|
37
|
+
*
|
|
38
|
+
* @see openspec/changes/auth-aware-ssr/specs/auth-sdk-namespace/spec.md
|
|
39
|
+
*/
|
|
40
|
+
import { getCurrentContext, requireActiveContext, taintCacheBypass, } from "../runtime-context.js";
|
|
41
|
+
import { config } from "../config.js";
|
|
42
|
+
import jwt from "../lib/jwt.js";
|
|
43
|
+
import { AuthRequiredError, FetchAbsoluteUrlError, FreshnessRequiredError, InsufficientMembershipError, InsufficientRoleError, UnknownExportError, } from "./errors.js";
|
|
44
|
+
import { validateAuthFetchInput } from "./url-validation.js";
|
|
45
|
+
import crypto from "node:crypto";
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Identity & authorization helpers
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
async function user() {
|
|
50
|
+
// Taint cache regardless of outcome — the response depends on actor
|
|
51
|
+
// state once any consumer asks. The taint is monotonic (D23).
|
|
52
|
+
taintCacheBypass();
|
|
53
|
+
const ctx = getCurrentContext();
|
|
54
|
+
if (ctx === undefined) {
|
|
55
|
+
// No active context — could be (a) module scope or (b) prerendered
|
|
56
|
+
// build. The runtime-context module distinguishes these via the
|
|
57
|
+
// `active` flag, but for `auth.user()` specifically we return null
|
|
58
|
+
// for module-scope while throwing R402_AUTH_PRERENDERED for the
|
|
59
|
+
// prerendered case. Without a context we can't tell, so return
|
|
60
|
+
// null — Astro's prerender detection runs upstream in @run402/astro.
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
// SSR / cookie-session path: actor populated from the verified
|
|
64
|
+
// gateway-signed envelope at runWithContext entry.
|
|
65
|
+
if (ctx.actor) {
|
|
66
|
+
return actorContextToPublicActor(ctx.actor, ctx.projectId);
|
|
67
|
+
}
|
|
68
|
+
// Direct function invocation path (Bearer JWT, no cookie envelope):
|
|
69
|
+
// fall back to decoding the Authorization header. This is the legacy
|
|
70
|
+
// getUser(req) contract — mobile / server-to-server callers send a
|
|
71
|
+
// signed JWT in the Authorization header, the function reads it.
|
|
72
|
+
// The gateway has already routed the request to this function and
|
|
73
|
+
// injected the Authorization header per the apikey/wallet-auth
|
|
74
|
+
// pipeline, so we can trust JWT_SECRET-signed claims here.
|
|
75
|
+
return actorFromAuthorizationHeader(ctx);
|
|
76
|
+
}
|
|
77
|
+
/** Read `Authorization: Bearer <jwt>` from the runtime context's
|
|
78
|
+
* request headers and decode it via JWT_SECRET. Returns an `Actor`
|
|
79
|
+
* populated from the JWT claims on success, `null` on absence /
|
|
80
|
+
* malformed / wrong-project / verify-fail.
|
|
81
|
+
*
|
|
82
|
+
* This is the legacy `getUser(req)` shape adapted to the v3.0 `auth.*`
|
|
83
|
+
* surface — it preserves the direct-function-invocation contract that
|
|
84
|
+
* the platform's own E2E suite exercises and that mobile / CI callers
|
|
85
|
+
* rely on. The cookie-session SSR path doesn't go through here (it
|
|
86
|
+
* populates ctx.actor at runWithContext entry via the verified
|
|
87
|
+
* envelope). */
|
|
88
|
+
function actorFromAuthorizationHeader(ctx) {
|
|
89
|
+
if (!config.JWT_SECRET)
|
|
90
|
+
return null;
|
|
91
|
+
const headers = ctx.request.headers;
|
|
92
|
+
// The runtime-context wrapper accepts either a `Headers` instance
|
|
93
|
+
// (when the gateway's buildEntryWrapper passes a Request) or a plain
|
|
94
|
+
// header object. Handle both.
|
|
95
|
+
let authHeader;
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
|
+
const h = headers;
|
|
98
|
+
if (typeof h?.get === "function") {
|
|
99
|
+
authHeader = h.get("authorization") ?? h.get("Authorization") ?? undefined;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const raw = h?.["authorization"] ?? h?.["Authorization"];
|
|
103
|
+
authHeader = Array.isArray(raw) ? raw[0] : raw;
|
|
104
|
+
}
|
|
105
|
+
if (!authHeader || !authHeader.startsWith("Bearer "))
|
|
106
|
+
return null;
|
|
107
|
+
const token = authHeader.slice(7);
|
|
108
|
+
try {
|
|
109
|
+
const payload = jwt.verify(token, config.JWT_SECRET);
|
|
110
|
+
if (payload.project_id !== ctx.projectId)
|
|
111
|
+
return null;
|
|
112
|
+
return {
|
|
113
|
+
id: payload.sub,
|
|
114
|
+
projectId: payload.project_id,
|
|
115
|
+
sessionId: payload.session_id ?? `bearer:${payload.sub}`,
|
|
116
|
+
email: payload.email ?? "",
|
|
117
|
+
emailVerified: false,
|
|
118
|
+
authTime: payload.auth_time ?? Math.floor(Date.now() / 1000),
|
|
119
|
+
amr: Array.isArray(payload.amr) ? [...payload.amr] : [],
|
|
120
|
+
amrTimes: {},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function requireUser() {
|
|
128
|
+
const actor = await user();
|
|
129
|
+
if (actor === null) {
|
|
130
|
+
throw new AuthRequiredError({ returnTo: currentReturnTo() });
|
|
131
|
+
}
|
|
132
|
+
return actor;
|
|
133
|
+
}
|
|
134
|
+
async function requireRole(role) {
|
|
135
|
+
const actor = await requireUser();
|
|
136
|
+
// For v1A wiring: read the gate-resolved role from the routed-function
|
|
137
|
+
// envelope header set by the gateway middleware. When the v1.60
|
|
138
|
+
// platform-owned grants table lands, this swaps to a fresh DB read
|
|
139
|
+
// joined to internal.role_grants.
|
|
140
|
+
const ctx = requireActiveContext("auth.requireRole");
|
|
141
|
+
const headerRole = readHeader(ctx.request.headers, "x-run402-user-role");
|
|
142
|
+
if (headerRole === role) {
|
|
143
|
+
return { user: actor, role };
|
|
144
|
+
}
|
|
145
|
+
throw new InsufficientRoleError(role);
|
|
146
|
+
}
|
|
147
|
+
function readHeader(headers, name) {
|
|
148
|
+
const v = headers[name] ?? headers[name.toLowerCase()] ?? headers[name.toUpperCase()];
|
|
149
|
+
return Array.isArray(v) ? v[0] : v;
|
|
150
|
+
}
|
|
151
|
+
async function requireMembership(membership) {
|
|
152
|
+
const actor = await requireUser();
|
|
153
|
+
// Membership shape mirrors role for v1A. The grant table for membership
|
|
154
|
+
// lands in a separate change (auth-as-sdlc); meanwhile the gateway-side
|
|
155
|
+
// gate helpers populate `x-run402-user-membership` when configured.
|
|
156
|
+
const ctx = requireActiveContext("auth.requireMembership");
|
|
157
|
+
const headerMembership = readHeader(ctx.request.headers, "x-run402-user-membership");
|
|
158
|
+
if (headerMembership === membership) {
|
|
159
|
+
return { user: actor, membership };
|
|
160
|
+
}
|
|
161
|
+
throw new InsufficientMembershipError(membership);
|
|
162
|
+
}
|
|
163
|
+
async function requireFresh(opts) {
|
|
164
|
+
taintCacheBypass();
|
|
165
|
+
const actor = await requireUser();
|
|
166
|
+
const maxAgeSec = parseMaxAge(opts.maxAge);
|
|
167
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
168
|
+
if (opts.amr && opts.amr.length > 0) {
|
|
169
|
+
const ok = opts.amr.some((method) => {
|
|
170
|
+
const ts = actor.amrTimes[method];
|
|
171
|
+
return typeof ts === "number" && nowSec - ts <= maxAgeSec;
|
|
172
|
+
});
|
|
173
|
+
if (!ok) {
|
|
174
|
+
throw new FreshnessRequiredError({
|
|
175
|
+
maxAge: opts.maxAge,
|
|
176
|
+
amr: opts.amr,
|
|
177
|
+
returnTo: currentReturnTo(),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (nowSec - actor.authTime <= maxAgeSec)
|
|
183
|
+
return;
|
|
184
|
+
throw new FreshnessRequiredError({
|
|
185
|
+
maxAge: opts.maxAge,
|
|
186
|
+
amr: [],
|
|
187
|
+
returnTo: currentReturnTo(),
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
function parseMaxAge(raw) {
|
|
191
|
+
if (/^\d+$/.test(raw))
|
|
192
|
+
return Number(raw);
|
|
193
|
+
let total = 0;
|
|
194
|
+
const re = /(\d+)\s*([smhd])/gi;
|
|
195
|
+
let m;
|
|
196
|
+
while ((m = re.exec(raw)) !== null) {
|
|
197
|
+
const v = Number(m[1]);
|
|
198
|
+
switch (m[2].toLowerCase()) {
|
|
199
|
+
case "s":
|
|
200
|
+
total += v;
|
|
201
|
+
break;
|
|
202
|
+
case "m":
|
|
203
|
+
total += v * 60;
|
|
204
|
+
break;
|
|
205
|
+
case "h":
|
|
206
|
+
total += v * 3600;
|
|
207
|
+
break;
|
|
208
|
+
case "d":
|
|
209
|
+
total += v * 86400;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return total;
|
|
214
|
+
}
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
// auth.fetch — relative-only with manual-redirect default
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
async function authFetch(input, init) {
|
|
219
|
+
const ctx = requireActiveContext("auth.fetch");
|
|
220
|
+
const origin = `https://${ctx.host}`;
|
|
221
|
+
const result = validateAuthFetchInput(input, { requestOrigin: origin });
|
|
222
|
+
if (!result.ok) {
|
|
223
|
+
throw new FetchAbsoluteUrlError({
|
|
224
|
+
attempted: typeof input === "string" ? input : (input instanceof URL ? input.toString() : input.url),
|
|
225
|
+
reason: result.reason,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
// The validated URL is same-origin. Default redirect: "manual" so
|
|
229
|
+
// follow-cross-origin redirects don't smuggle our actor context to
|
|
230
|
+
// hostile hops. If the caller opts in via init.redirect: "follow",
|
|
231
|
+
// we still re-validate each hop — but native fetch doesn't expose
|
|
232
|
+
// hop-by-hop hooks, so we emulate by doing manual redirects.
|
|
233
|
+
const headers = new Headers(init?.headers);
|
|
234
|
+
// Forward only headers the gateway expects from a same-origin SSR
|
|
235
|
+
// fetch. Actor-context propagation is automatic (the inbound envelope
|
|
236
|
+
// is propagated as a header; the SSR runtime already verified it).
|
|
237
|
+
// Cookies are NEVER forwarded — never set the Cookie header here.
|
|
238
|
+
headers.delete("cookie");
|
|
239
|
+
headers.delete("Cookie");
|
|
240
|
+
const requestInit = {
|
|
241
|
+
...init,
|
|
242
|
+
headers,
|
|
243
|
+
redirect: init?.redirect ?? "manual",
|
|
244
|
+
};
|
|
245
|
+
return fetch(result.normalized, requestInit);
|
|
246
|
+
}
|
|
247
|
+
// ---------------------------------------------------------------------------
|
|
248
|
+
// CSRF token helpers (double-submit token bound to the active session).
|
|
249
|
+
// ---------------------------------------------------------------------------
|
|
250
|
+
function csrfToken() {
|
|
251
|
+
const ctx = getCurrentContext();
|
|
252
|
+
if (!ctx || !ctx.actor) {
|
|
253
|
+
// No session ⇒ no CSRF token. Returning an empty string would let
|
|
254
|
+
// the form submit with no token at all; instead throw so the page
|
|
255
|
+
// author knows the helper should be inside `<SignedIn>`-style
|
|
256
|
+
// conditional rendering.
|
|
257
|
+
throw new AuthRequiredError();
|
|
258
|
+
}
|
|
259
|
+
// The token derivation is HMAC(session_secret, "csrf") truncated to
|
|
260
|
+
// 32 hex chars. Browsers double-submit; the gateway re-derives and
|
|
261
|
+
// compares constant-time. We use the session_id + auth_time as the
|
|
262
|
+
// poor-man's MAC input since the SDK doesn't have access to the
|
|
263
|
+
// pepper; the gateway is the authoritative verifier (cross-checks
|
|
264
|
+
// against internal.sessions via session_id). This is double-submit
|
|
265
|
+
// CSRF, not a primary control — the Origin check is.
|
|
266
|
+
const input = `${ctx.actor.sessionId}:${ctx.actor.authTime}:csrf`;
|
|
267
|
+
return crypto.createHash("sha256").update(input, "utf8").digest("hex").slice(0, 32);
|
|
268
|
+
}
|
|
269
|
+
function csrfField() {
|
|
270
|
+
return `<input type="hidden" name="_csrf" value="${escapeHtml(csrfToken())}">`;
|
|
271
|
+
}
|
|
272
|
+
function escapeHtml(s) {
|
|
273
|
+
return s
|
|
274
|
+
.replace(/&/g, "&")
|
|
275
|
+
.replace(/</g, "<")
|
|
276
|
+
.replace(/>/g, ">")
|
|
277
|
+
.replace(/"/g, """)
|
|
278
|
+
.replace(/'/g, "'");
|
|
279
|
+
}
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
// Session bridge — createResponseFromIdentity / endResponse.
|
|
282
|
+
//
|
|
283
|
+
// These delegate to the platform routes; the SDK never holds raw secrets.
|
|
284
|
+
// The session-minting route lives at POST /auth/v1/sessions/from-identity
|
|
285
|
+
// (gateway-internal). The endResponse helper just emits the clear-cookie
|
|
286
|
+
// Set-Cookie + body and lets the gateway-side mounted CSRF/origin check
|
|
287
|
+
// run on the calling capability's response.
|
|
288
|
+
// ---------------------------------------------------------------------------
|
|
289
|
+
async function createResponseFromIdentity(opts) {
|
|
290
|
+
const ctx = requireActiveContext("auth.sessions.createResponseFromIdentity");
|
|
291
|
+
const origin = `https://${ctx.host}`;
|
|
292
|
+
// Delegate to the platform route. The route verifies the proof
|
|
293
|
+
// against the project's registered verifier (wallet/oidc/custom) and
|
|
294
|
+
// mints the session via the internal-only primitive. The Response
|
|
295
|
+
// already carries Set-Cookie and the canonical {ok, user} body.
|
|
296
|
+
const res = await fetch(`${origin}/auth/v1/sessions/from-identity`, {
|
|
297
|
+
method: "POST",
|
|
298
|
+
headers: { "content-type": "application/json" },
|
|
299
|
+
body: JSON.stringify(opts),
|
|
300
|
+
redirect: "manual",
|
|
301
|
+
});
|
|
302
|
+
return res;
|
|
303
|
+
}
|
|
304
|
+
async function endResponse() {
|
|
305
|
+
const ctx = requireActiveContext("auth.sessions.endResponse");
|
|
306
|
+
const origin = `https://${ctx.host}`;
|
|
307
|
+
const res = await fetch(`${origin}/auth/v1/sessions/end`, {
|
|
308
|
+
method: "POST",
|
|
309
|
+
headers: { "content-type": "application/json" },
|
|
310
|
+
redirect: "manual",
|
|
311
|
+
});
|
|
312
|
+
return res;
|
|
313
|
+
}
|
|
314
|
+
// ---------------------------------------------------------------------------
|
|
315
|
+
// Identity linking.
|
|
316
|
+
// ---------------------------------------------------------------------------
|
|
317
|
+
async function linkIdentity(opts) {
|
|
318
|
+
const ctx = requireActiveContext("auth.identities.link");
|
|
319
|
+
await requireUser();
|
|
320
|
+
const origin = `https://${ctx.host}`;
|
|
321
|
+
const res = await fetch(`${origin}/auth/v1/identities/link`, {
|
|
322
|
+
method: "POST",
|
|
323
|
+
headers: { "content-type": "application/json" },
|
|
324
|
+
body: JSON.stringify(opts),
|
|
325
|
+
redirect: "manual",
|
|
326
|
+
});
|
|
327
|
+
if (res.status === 409) {
|
|
328
|
+
// The platform route maps unique_violation on
|
|
329
|
+
// internal.identities (project_id, provider, subject) to 409.
|
|
330
|
+
throw new (await import("./errors.js")).IdentityLinkConflictError({
|
|
331
|
+
provider: opts.provider,
|
|
332
|
+
subject: opts.subject,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
if (!res.ok) {
|
|
336
|
+
const body = await res.json().catch(() => ({}));
|
|
337
|
+
throw new (await import("./errors.js")).SessionBridgeUnverifiedError({
|
|
338
|
+
reason: body.code ?? `link failed: ${res.status}`,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// ---------------------------------------------------------------------------
|
|
343
|
+
// SDK proxy intercepting hallucinated names.
|
|
344
|
+
// ---------------------------------------------------------------------------
|
|
345
|
+
const HALLUCINATED_NAMES = {
|
|
346
|
+
session: "auth.user() then read .sessionId / .amr / etc.",
|
|
347
|
+
getSession: "auth.user()",
|
|
348
|
+
currentUser: "auth.user()",
|
|
349
|
+
currentSession: "auth.user()",
|
|
350
|
+
requireAuth: "auth.requireUser()",
|
|
351
|
+
middleware: "auth.csrfField() / @run402/astro middleware",
|
|
352
|
+
signIn: "POST /auth/sign-in (browser form) or auth.sessions.createResponseFromIdentity({...})",
|
|
353
|
+
signout: "auth.sessions.endResponse()",
|
|
354
|
+
signOut: "auth.sessions.endResponse()",
|
|
355
|
+
logout: "auth.sessions.endResponse()",
|
|
356
|
+
login: "auth.sessions.createResponseFromIdentity({...})",
|
|
357
|
+
redirectToSignIn: "auth.requireUser() — platform redirects",
|
|
358
|
+
getUser: "auth.user()",
|
|
359
|
+
getToken: "auth.requireUser() then user.sessionId (tokens are not exposed)",
|
|
360
|
+
protect: "auth.requireUser() / auth.requireRole(...)",
|
|
361
|
+
};
|
|
362
|
+
const baseAuth = {
|
|
363
|
+
user,
|
|
364
|
+
requireUser,
|
|
365
|
+
requireRole,
|
|
366
|
+
requireMembership,
|
|
367
|
+
requireFresh,
|
|
368
|
+
fetch: authFetch,
|
|
369
|
+
csrfToken,
|
|
370
|
+
csrfField,
|
|
371
|
+
identities: {
|
|
372
|
+
link: linkIdentity,
|
|
373
|
+
},
|
|
374
|
+
sessions: {
|
|
375
|
+
createResponseFromIdentity,
|
|
376
|
+
endResponse,
|
|
377
|
+
},
|
|
378
|
+
};
|
|
379
|
+
/** Hallucinated-name proxy. Property access for a name not in
|
|
380
|
+
* `baseAuth` throws `R402_AUTH_UNKNOWN_EXPORT` with the canonical
|
|
381
|
+
* replacement. Hot-path access (existing keys) returns the actual
|
|
382
|
+
* helper — proxy overhead is one Reflect.has + Reflect.get. */
|
|
383
|
+
export const auth = new Proxy(baseAuth, {
|
|
384
|
+
get(target, prop, receiver) {
|
|
385
|
+
if (typeof prop === "string" && !(prop in target)) {
|
|
386
|
+
const replacement = HALLUCINATED_NAMES[prop];
|
|
387
|
+
if (replacement) {
|
|
388
|
+
throw new UnknownExportError({
|
|
389
|
+
attemptedName: `auth.${prop}`,
|
|
390
|
+
canonicalName: replacement,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
throw new UnknownExportError({
|
|
394
|
+
attemptedName: `auth.${prop}`,
|
|
395
|
+
canonicalName: "auth.user / auth.requireUser / auth.requireRole / auth.requireMembership",
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
return Reflect.get(target, prop, receiver);
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
/** Throwing-sentinel exports for the top hallucinated *bare* names.
|
|
402
|
+
* ESM `import { getUser } from "@run402/functions"` can be intercepted
|
|
403
|
+
* only by a real export — so we ship these as exported throwing
|
|
404
|
+
* functions. They're marked `@deprecated` in the type JSDoc; the SDK
|
|
405
|
+
* proxy + lint registry + `run402 doctor` scan all flag the import
|
|
406
|
+
* before runtime if the user is running the tooling.
|
|
407
|
+
*
|
|
408
|
+
* Excluded from public docs and AGENTS.md per the spec.
|
|
409
|
+
*/
|
|
410
|
+
/** @deprecated Use `auth.user()` or `auth.requireUser()`. */
|
|
411
|
+
export function getSession() {
|
|
412
|
+
throw new UnknownExportError({ attemptedName: "getSession", canonicalName: "auth.user()" });
|
|
413
|
+
}
|
|
414
|
+
/** @deprecated Use `auth.user()`. */
|
|
415
|
+
export function currentUser() {
|
|
416
|
+
throw new UnknownExportError({ attemptedName: "currentUser", canonicalName: "auth.user()" });
|
|
417
|
+
}
|
|
418
|
+
/** @deprecated Use `auth.user()`. */
|
|
419
|
+
export function getCurrentUser() {
|
|
420
|
+
throw new UnknownExportError({ attemptedName: "getCurrentUser", canonicalName: "auth.user()" });
|
|
421
|
+
}
|
|
422
|
+
/** @deprecated Use `auth.user()`. */
|
|
423
|
+
export function getServerSession() {
|
|
424
|
+
throw new UnknownExportError({
|
|
425
|
+
attemptedName: "getServerSession",
|
|
426
|
+
canonicalName: "auth.user()",
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
// Internal helpers
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
function actorContextToPublicActor(ctxActor, projectId) {
|
|
433
|
+
if (!ctxActor)
|
|
434
|
+
return null;
|
|
435
|
+
return {
|
|
436
|
+
id: ctxActor.id,
|
|
437
|
+
projectId,
|
|
438
|
+
sessionId: ctxActor.sessionId,
|
|
439
|
+
email: ctxActor.email,
|
|
440
|
+
emailVerified: ctxActor.emailVerified,
|
|
441
|
+
authTime: ctxActor.authTime,
|
|
442
|
+
amr: [...ctxActor.amr],
|
|
443
|
+
amrTimes: { ...ctxActor.amrTimes },
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function currentReturnTo() {
|
|
447
|
+
const ctx = getCurrentContext();
|
|
448
|
+
if (!ctx)
|
|
449
|
+
return undefined;
|
|
450
|
+
return ctx.request.url;
|
|
451
|
+
}
|
|
452
|
+
export { AuthRequiredError, InsufficientRoleError, InsufficientMembershipError, FreshnessRequiredError, FetchAbsoluteUrlError, PrerenderedError, UnknownExportError, SessionBridgeUnverifiedError, IdentityLinkConflictError, UnknownIdentityError, Run402AuthError, } from "./errors.js";
|
|
453
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,GAEjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,GAAG,MAAM,eAAe,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EAErB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,8EAA8E;AAC9E,mCAAmC;AACnC,8EAA8E;AAE9E,KAAK,UAAU,IAAI;IACjB,oEAAoE;IACpE,8DAA8D;IAC9D,gBAAgB,EAAE,CAAC;IACnB,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,mEAAmE;QACnE,gEAAgE;QAChE,mEAAmE;QACnE,gEAAgE;QAChE,+DAA+D;QAC/D,qEAAqE;QACrE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,+DAA+D;IAC/D,mDAAmD;IACnD,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,yBAAyB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7D,CAAC;IACD,oEAAoE;IACpE,qEAAqE;IACrE,mEAAmE;IACnE,iEAAiE;IACjE,kEAAkE;IAClE,+DAA+D;IAC/D,2DAA2D;IAC3D,OAAO,4BAA4B,CAAC,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;iBAUiB;AACjB,SAAS,4BAA4B,CACnC,GAAsD;IAEtD,IAAI,CAAC,MAAM,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;IACpC,kEAAkE;IAClE,qEAAqE;IACrE,8BAA8B;IAC9B,IAAI,UAA8B,CAAC;IACnC,8DAA8D;IAC9D,MAAM,CAAC,GAAG,OAAc,CAAC;IACzB,IAAI,OAAO,CAAC,EAAE,GAAG,KAAK,UAAU,EAAE,CAAC;QACjC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,SAAS,CAAC;IAC7E,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC;QACzD,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACjD,CAAC;IACD,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CASvB,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7B,IAAI,OAAO,CAAC,UAAU,KAAK,GAAG,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QACtD,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,GAAG;YACf,SAAS,EAAE,OAAO,CAAC,UAAU;YAC7B,SAAS,EAAE,OAAO,CAAC,UAAU,IAAI,UAAU,OAAO,CAAC,GAAG,EAAE;YACxD,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE;YAC1B,aAAa,EAAE,KAAK;YACpB,QAAQ,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YAC5D,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;YACvD,QAAQ,EAAE,EAAE;SACb,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW;IACxB,MAAM,KAAK,GAAG,MAAM,IAAI,EAAE,CAAC;IAC3B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,iBAAiB,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,IAAO;IAEP,MAAM,KAAK,GAAG,MAAM,WAAW,EAAE,CAAC;IAClC,uEAAuE;IACvE,gEAAgE;IAChE,mEAAmE;IACnE,kCAAkC;IAClC,MAAM,GAAG,GAAG,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;IACzE,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IACD,MAAM,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,UAAU,CACjB,OAAsD,EACtD,IAAY;IAEZ,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACtF,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,UAAa;IAEb,MAAM,KAAK,GAAG,MAAM,WAAW,EAAE,CAAC;IAClC,wEAAwE;IACxE,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,GAAG,GAAG,oBAAoB,CAAC,wBAAwB,CAAC,CAAC;IAC3D,MAAM,gBAAgB,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,0BAA0B,CAAC,CAAC;IACrF,IAAI,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IACrC,CAAC;IACD,MAAM,IAAI,2BAA2B,CAAC,UAAU,CAAC,CAAC;AACpD,CAAC;AAaD,KAAK,UAAU,YAAY,CAAC,IAAyB;IACnD,gBAAgB,EAAE,CAAC;IACnB,MAAM,KAAK,GAAG,MAAM,WAAW,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC7C,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YAClC,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAClC,OAAO,OAAO,EAAE,KAAK,QAAQ,IAAI,MAAM,GAAG,EAAE,IAAI,SAAS,CAAC;QAC5D,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,IAAI,sBAAsB,CAAC;gBAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,QAAQ,EAAE,eAAe,EAAE;aAC5B,CAAC,CAAC;QACL,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,MAAM,GAAG,KAAK,CAAC,QAAQ,IAAI,SAAS;QAAE,OAAO;IACjD,MAAM,IAAI,sBAAsB,CAAC;QAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,GAAG,EAAE,EAAE;QACP,QAAQ,EAAE,eAAe,EAAE;KAC5B,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,EAAE,GAAG,oBAAoB,CAAC;IAChC,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvB,QAAQ,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,EAAE,CAAC;YAC5B,KAAK,GAAG;gBACN,KAAK,IAAI,CAAC,CAAC;gBACX,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;gBAChB,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;gBAClB,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC;gBACnB,MAAM;QACV,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,0DAA0D;AAC1D,8EAA8E;AAE9E,KAAK,UAAU,SAAS,CACtB,KAAwB,EACxB,IAAkB;IAElB,MAAM,GAAG,GAAG,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,WAAW,GAAG,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC;IACxE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,qBAAqB,CAAC;YAC9B,SAAS,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;YACpG,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;IACL,CAAC;IAED,kEAAkE;IAClE,mEAAmE;IACnE,mEAAmE;IACnE,kEAAkE;IAClE,6DAA6D;IAC7D,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,kEAAkE;IAClE,sEAAsE;IACtE,mEAAmE;IACnE,kEAAkE;IAClE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEzB,MAAM,WAAW,GAAgB;QAC/B,GAAG,IAAI;QACP,OAAO;QACP,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,QAAQ;KACrC,CAAC;IACF,OAAO,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED,8EAA8E;AAC9E,wEAAwE;AACxE,8EAA8E;AAE9E,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACvB,kEAAkE;QAClE,kEAAkE;QAClE,8DAA8D;QAC9D,yBAAyB;QACzB,MAAM,IAAI,iBAAiB,EAAE,CAAC;IAChC,CAAC;IACD,oEAAoE;IACpE,mEAAmE;IACnE,mEAAmE;IACnE,gEAAgE;IAChE,kEAAkE;IAClE,mEAAmE;IACnE,qDAAqD;IACrD,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,OAAO,CAAC;IAClE,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,4CAA4C,UAAU,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC;AACjF,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,8EAA8E;AAC9E,6DAA6D;AAC7D,EAAE;AACF,0EAA0E;AAC1E,0EAA0E;AAC1E,yEAAyE;AACzE,wEAAwE;AACxE,4CAA4C;AAC5C,8EAA8E;AAE9E,KAAK,UAAU,0BAA0B,CACvC,IAAuC;IAEvC,MAAM,GAAG,GAAG,oBAAoB,CAAC,0CAA0C,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,WAAW,GAAG,CAAC,IAAI,EAAE,CAAC;IACrC,+DAA+D;IAC/D,qEAAqE;IACrE,kEAAkE;IAClE,gEAAgE;IAChE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,iCAAiC,EAAE;QAClE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,QAAQ,EAAE,QAAQ;KACnB,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,WAAW;IACxB,MAAM,GAAG,GAAG,oBAAoB,CAAC,2BAA2B,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,WAAW,GAAG,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,uBAAuB,EAAE;QACxD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,QAAQ,EAAE,QAAQ;KACnB,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,KAAK,UAAU,YAAY,CAAC,IAAyB;IACnD,MAAM,GAAG,GAAG,oBAAoB,CAAC,sBAAsB,CAAC,CAAC;IACzD,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,WAAW,GAAG,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,0BAA0B,EAAE;QAC3D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,QAAQ,EAAE,QAAQ;KACnB,CAAC,CAAC;IACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvB,8CAA8C;QAC9C,8DAA8D;QAC9D,MAAM,IAAI,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,yBAAyB,CAAC;YAChE,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,MAAM,IAAI,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,4BAA4B,CAAC;YACnE,MAAM,EAAG,IAA0B,CAAC,IAAI,IAAI,gBAAgB,GAAG,CAAC,MAAM,EAAE;SACzE,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,6CAA6C;AAC7C,8EAA8E;AAE9E,MAAM,kBAAkB,GAA2B;IACjD,OAAO,EAAE,gDAAgD;IACzD,UAAU,EAAE,aAAa;IACzB,WAAW,EAAE,aAAa;IAC1B,cAAc,EAAE,aAAa;IAC7B,WAAW,EAAE,oBAAoB;IACjC,UAAU,EAAE,6CAA6C;IACzD,MAAM,EAAE,sFAAsF;IAC9F,OAAO,EAAE,6BAA6B;IACtC,OAAO,EAAE,6BAA6B;IACtC,MAAM,EAAE,6BAA6B;IACrC,KAAK,EAAE,iDAAiD;IACxD,gBAAgB,EAAE,yCAAyC;IAC3D,OAAO,EAAE,aAAa;IACtB,QAAQ,EAAE,iEAAiE;IAC3E,OAAO,EAAE,4CAA4C;CACtD,CAAC;AA2BF,MAAM,QAAQ,GAAkB;IAC9B,IAAI;IACJ,WAAW;IACX,WAAW;IACX,iBAAiB;IACjB,YAAY;IACZ,KAAK,EAAE,SAAS;IAChB,SAAS;IACT,SAAS;IACT,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;KACnB;IACD,QAAQ,EAAE;QACR,0BAA0B;QAC1B,WAAW;KACZ;CACF,CAAC;AAEF;;;gEAGgE;AAChE,MAAM,CAAC,MAAM,IAAI,GAAkB,IAAI,KAAK,CAAC,QAAQ,EAAE;IACrD,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ;QACxB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,CAAC;YAClD,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,IAAI,kBAAkB,CAAC;oBAC3B,aAAa,EAAE,QAAQ,IAAI,EAAE;oBAC7B,aAAa,EAAE,WAAW;iBAC3B,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,kBAAkB,CAAC;gBAC3B,aAAa,EAAE,QAAQ,IAAI,EAAE;gBAC7B,aAAa,EAAE,0EAA0E;aAC1F,CAAC,CAAC;QACL,CAAC;QACD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;CACF,CAAC,CAAC;AAEH;;;;;;;;GAQG;AAEH,6DAA6D;AAC7D,MAAM,UAAU,UAAU;IACxB,MAAM,IAAI,kBAAkB,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,WAAW;IACzB,MAAM,IAAI,kBAAkB,CAAC,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,cAAc;IAC5B,MAAM,IAAI,kBAAkB,CAAC,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC;AAClG,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,gBAAgB;IAC9B,MAAM,IAAI,kBAAkB,CAAC;QAC3B,aAAa,EAAE,kBAAkB;QACjC,aAAa,EAAE,aAAa;KAC7B,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,SAAS,yBAAyB,CAChC,QAA6B,EAC7B,SAAiB;IAEjB,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO;QACL,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,SAAS;QACT,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,GAAG,EAAE,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC;QACtB,QAAQ,EAAE,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE;KACnC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;AACzB,CAAC;AAID,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,EAC3B,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,4BAA4B,EAC5B,yBAAyB,EACzB,oBAAoB,EACpB,eAAe,GAChB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the `auth.*` namespace.
|
|
3
|
+
*
|
|
4
|
+
* The canonical actor shape used everywhere `auth.user()` /
|
|
5
|
+
* `auth.requireUser()` / `auth.requireRole()` etc. resolve to a user.
|
|
6
|
+
* Note that `id` (not `userId`) is the canonical public field — matches
|
|
7
|
+
* Supabase / Clerk / Auth.js / NextAuth so coding-agent generated code
|
|
8
|
+
* gets it right on the first try.
|
|
9
|
+
*
|
|
10
|
+
* @see openspec/changes/auth-aware-ssr/specs/auth-sdk-namespace/spec.md
|
|
11
|
+
*/
|
|
12
|
+
export interface Actor {
|
|
13
|
+
/** Canonical public user-id. Matches `internal.users.id` UUID. */
|
|
14
|
+
id: string;
|
|
15
|
+
projectId: string;
|
|
16
|
+
sessionId: string;
|
|
17
|
+
email: string;
|
|
18
|
+
emailVerified: boolean;
|
|
19
|
+
/** Last any-method auth proof, seconds-since-epoch. */
|
|
20
|
+
authTime: number;
|
|
21
|
+
amr: string[];
|
|
22
|
+
/** Per-AMR last-verified UNIX seconds. */
|
|
23
|
+
amrTimes: Record<string, number>;
|
|
24
|
+
}
|
|
25
|
+
/** Provider-shaped identity proof. The `wallet` shape carries an SIWX
|
|
26
|
+
* signature + message; `oidc` carries a JWT bound to a project-configured
|
|
27
|
+
* issuer; `custom` requires admin-registered project-side verifier and
|
|
28
|
+
* carries provider-specific bytes. */
|
|
29
|
+
export type IdentityProof = {
|
|
30
|
+
kind: "siwx";
|
|
31
|
+
signature: string;
|
|
32
|
+
message: string;
|
|
33
|
+
nonce?: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "oidc_jwt";
|
|
36
|
+
token: string;
|
|
37
|
+
nonce?: string;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "custom";
|
|
40
|
+
payload: unknown;
|
|
41
|
+
nonce?: string;
|
|
42
|
+
};
|
|
43
|
+
export interface CreateResponseFromIdentityOptions {
|
|
44
|
+
provider: "wallet" | "oidc" | "custom";
|
|
45
|
+
subject: string;
|
|
46
|
+
proof: IdentityProof;
|
|
47
|
+
amr: string[];
|
|
48
|
+
/** When `false` (default), unknown identities cause
|
|
49
|
+
* `R402_AUTH_UNKNOWN_IDENTITY`. When `true`, the platform creates the
|
|
50
|
+
* user + identity link in the same transaction as the session. */
|
|
51
|
+
createUser?: boolean;
|
|
52
|
+
}
|
|
53
|
+
export interface IdentityLinkOptions {
|
|
54
|
+
provider: string;
|
|
55
|
+
subject: string;
|
|
56
|
+
proof: IdentityProof;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,KAAK;IACpB,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;IACvB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;uCAGuC;AACvC,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,aAAa,CAAC;IACrB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd;;uEAEmE;IACnE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,aAAa,CAAC;CACtB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the `auth.*` namespace.
|
|
3
|
+
*
|
|
4
|
+
* The canonical actor shape used everywhere `auth.user()` /
|
|
5
|
+
* `auth.requireUser()` / `auth.requireRole()` etc. resolve to a user.
|
|
6
|
+
* Note that `id` (not `userId`) is the canonical public field — matches
|
|
7
|
+
* Supabase / Clerk / Auth.js / NextAuth so coding-agent generated code
|
|
8
|
+
* gets it right on the first try.
|
|
9
|
+
*
|
|
10
|
+
* @see openspec/changes/auth-aware-ssr/specs/auth-sdk-namespace/spec.md
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `auth.fetch` URL validation.
|
|
3
|
+
*
|
|
4
|
+
* Synchronous before-network checks: the URL is rejected (sync throw)
|
|
5
|
+
* before any network I/O if it's not safely same-origin. The set of
|
|
6
|
+
* rejected shapes is enumerated by the spec — we mirror it verbatim:
|
|
7
|
+
*
|
|
8
|
+
* - Cross-origin absolute URLs
|
|
9
|
+
* - URLs with embedded credentials (`http://user:pass@host/...`)
|
|
10
|
+
* - Non-HTTP(S) schemes (`javascript:`, `data:`, `file:`, etc.)
|
|
11
|
+
* - Protocol-relative URLs (`//evil.example/...`)
|
|
12
|
+
* - Subdomain-spoof patterns (`https://app.run402.app.evil.example/...`)
|
|
13
|
+
* - Port-mismatch against the current request origin
|
|
14
|
+
*
|
|
15
|
+
* Same-origin normalisation: scheme, host, and default-port comparisons
|
|
16
|
+
* use `URL.origin`, which strips `:80` for http and `:443` for https.
|
|
17
|
+
*
|
|
18
|
+
* @see openspec/changes/auth-aware-ssr/specs/auth-sdk-namespace/spec.md
|
|
19
|
+
*/
|
|
20
|
+
export interface UrlValidationContext {
|
|
21
|
+
requestOrigin: string;
|
|
22
|
+
}
|
|
23
|
+
export type UrlValidationResult = {
|
|
24
|
+
ok: true;
|
|
25
|
+
normalized: URL;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
reason: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function validateAuthFetchInput(input: RequestInfo | URL, ctx: UrlValidationContext): UrlValidationResult;
|
|
31
|
+
//# sourceMappingURL=url-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-validation.d.ts","sourceRoot":"","sources":["../../src/auth/url-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,GAAG,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAIlC,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,GAAG,EAAE,oBAAoB,GACxB,mBAAmB,CAiErB"}
|