@iaurelius/accounts-nextjs 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/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/client.d.ts +68 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +211 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +44 -0
- package/dist/config.js.map +1 -0
- package/dist/cookies.d.ts +18 -0
- package/dist/cookies.d.ts.map +1 -0
- package/dist/cookies.js +94 -0
- package/dist/cookies.js.map +1 -0
- package/dist/handlers.d.ts +8 -0
- package/dist/handlers.d.ts.map +1 -0
- package/dist/handlers.js +157 -0
- package/dist/handlers.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/index.server.d.ts +3 -0
- package/dist/index.server.d.ts.map +1 -0
- package/dist/index.server.js +5 -0
- package/dist/index.server.js.map +1 -0
- package/dist/provider.server.d.ts +10 -0
- package/dist/provider.server.d.ts.map +1 -0
- package/dist/provider.server.js +19 -0
- package/dist/provider.server.js.map +1 -0
- package/dist/proxy.d.ts +17 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +61 -0
- package/dist/proxy.js.map +1 -0
- package/dist/server.d.ts +47 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +72 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +48 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +89 -0
- package/dist/session.js.map +1 -0
- package/package.json +58 -0
package/dist/cookies.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// The session lives in the browser, encrypted (JWE dir + A256GCM) with a key derived from the app's
|
|
2
|
+
// secret: the tokens never reach JavaScript, and nobody can read or forge the cookie without the key.
|
|
3
|
+
import { EncryptJWT, jwtDecrypt } from "jose";
|
|
4
|
+
const enc = new TextEncoder();
|
|
5
|
+
const keys = new Map();
|
|
6
|
+
/** 256 bits for A256GCM from the secret (HKDF-SHA256), per purpose. */
|
|
7
|
+
function keyFor(secret, purpose) {
|
|
8
|
+
const id = `${purpose}\u0000${secret}`;
|
|
9
|
+
let k = keys.get(id);
|
|
10
|
+
if (!k) {
|
|
11
|
+
k = (async () => {
|
|
12
|
+
const ikm = await crypto.subtle.importKey("raw", enc.encode(secret), "HKDF", false, ["deriveBits"]);
|
|
13
|
+
const bits = await crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", salt: enc.encode("@iaurelius/accounts-nextjs"), info: enc.encode(`${purpose} v1`) }, ikm, 256);
|
|
14
|
+
return new Uint8Array(bits);
|
|
15
|
+
})();
|
|
16
|
+
keys.set(id, k);
|
|
17
|
+
}
|
|
18
|
+
return k;
|
|
19
|
+
}
|
|
20
|
+
export async function seal(payload, secret, purpose, maxAgeSeconds) {
|
|
21
|
+
return new EncryptJWT(payload)
|
|
22
|
+
.setProtectedHeader({ alg: "dir", enc: "A256GCM" })
|
|
23
|
+
.setIssuedAt()
|
|
24
|
+
.setExpirationTime(Math.floor(Date.now() / 1000) + maxAgeSeconds)
|
|
25
|
+
.encrypt(await keyFor(secret, purpose));
|
|
26
|
+
}
|
|
27
|
+
/** The payload, or null for anything not sealed by us for this purpose, or expired. */
|
|
28
|
+
export async function unseal(value, secret, purpose) {
|
|
29
|
+
if (!value)
|
|
30
|
+
return null;
|
|
31
|
+
try {
|
|
32
|
+
return (await jwtDecrypt(value, await keyFor(secret, purpose), { keyManagementAlgorithms: ["dir"], contentEncryptionAlgorithms: ["A256GCM"] })).payload;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function parseCookies(header) {
|
|
39
|
+
const out = new Map();
|
|
40
|
+
for (const part of (header ?? "").split(";")) {
|
|
41
|
+
const i = part.indexOf("=");
|
|
42
|
+
if (i < 1)
|
|
43
|
+
continue;
|
|
44
|
+
const name = part.slice(0, i).trim();
|
|
45
|
+
if (!out.has(name))
|
|
46
|
+
out.set(name, part.slice(i + 1).trim());
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
export function serialize(name, value, o) {
|
|
51
|
+
const parts = [`${name}=${value}`, `Path=${o.path ?? "/"}`, "SameSite=Lax"];
|
|
52
|
+
if (o.httpOnly !== false)
|
|
53
|
+
parts.push("HttpOnly");
|
|
54
|
+
if (o.secure)
|
|
55
|
+
parts.push("Secure");
|
|
56
|
+
if (o.maxAge !== undefined)
|
|
57
|
+
parts.push(`Max-Age=${Math.max(0, Math.floor(o.maxAge))}`);
|
|
58
|
+
return parts.join("; ");
|
|
59
|
+
}
|
|
60
|
+
/** Browsers keep up to ~4 KB per cookie: a bigger session is split into name.0, name.1… */
|
|
61
|
+
const CHUNK = 3800;
|
|
62
|
+
/** The Set-Cookie headers that store `value` under `name` (chunked if needed) and drop the chunks it no longer uses. */
|
|
63
|
+
export function writeChunked(name, value, existing, o) {
|
|
64
|
+
const out = [];
|
|
65
|
+
const chunks = value.length > CHUNK ? Array.from({ length: Math.ceil(value.length / CHUNK) }, (_, i) => value.slice(i * CHUNK, (i + 1) * CHUNK)) : null;
|
|
66
|
+
if (chunks) {
|
|
67
|
+
chunks.forEach((c, i) => out.push(serialize(`${name}.${i}`, c, o)));
|
|
68
|
+
if (existing.has(name))
|
|
69
|
+
out.push(serialize(name, "", { ...o, maxAge: 0 }));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
out.push(serialize(name, value, o));
|
|
73
|
+
}
|
|
74
|
+
for (const k of existing.keys()) {
|
|
75
|
+
const m = k.startsWith(`${name}.`) ? Number(k.slice(name.length + 1)) : NaN;
|
|
76
|
+
if (Number.isInteger(m) && (!chunks || m >= chunks.length))
|
|
77
|
+
out.push(serialize(k, "", { ...o, maxAge: 0 }));
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
export function readChunked(name, cookies) {
|
|
82
|
+
const whole = cookies.get(name);
|
|
83
|
+
if (whole)
|
|
84
|
+
return whole;
|
|
85
|
+
const parts = [];
|
|
86
|
+
for (let i = 0; cookies.has(`${name}.${i}`); i++)
|
|
87
|
+
parts.push(cookies.get(`${name}.${i}`));
|
|
88
|
+
return parts.length ? parts.join("") : undefined;
|
|
89
|
+
}
|
|
90
|
+
/** Set-Cookie headers that remove `name` and every chunk of it. */
|
|
91
|
+
export function clearChunked(name, existing, o) {
|
|
92
|
+
return [...existing.keys()].filter((k) => k === name || /^\d+$/.test(k.slice(name.length + 1)) && k.startsWith(`${name}.`)).map((k) => serialize(k, "", { ...o, maxAge: 0 }));
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=cookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AccountsConfig } from "./config.js";
|
|
2
|
+
export declare const originOf: (req: Request, cfg: AccountsConfig) => string;
|
|
3
|
+
export declare const isSecure: (origin: string) => boolean;
|
|
4
|
+
/** Only paths of this app: never another origin (no open redirect). */
|
|
5
|
+
export declare function safeReturnPath(v: string | null, origin: string): string;
|
|
6
|
+
/** The response for a request under basePath, or null if it is not one of ours. */
|
|
7
|
+
export declare function handleAccountsRoute(req: Request, cfg: AccountsConfig): Promise<Response | null>;
|
|
8
|
+
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAOlD,eAAO,MAAM,QAAQ,QAAS,OAAO,OAAO,cAAc,WAA0C,CAAC;AACrG,eAAO,MAAM,QAAQ,WAAY,MAAM,YAAkC,CAAC;AAE1E,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAWvE;AAoGD,mFAAmF;AACnF,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAqBrG"}
|
package/dist/handlers.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// The routes the SDK answers under basePath (/api/accounts), with Fetch API requests and responses:
|
|
2
|
+
// sign-in, sign-up, callback, sign-out, session and token. The proxy calls them; no route files.
|
|
3
|
+
import { verifyIdToken } from "@iaurelius/accounts";
|
|
4
|
+
import { OAuthError, authorizationUrl, endSessionUrl, exchangeCode, pkce, randomString, revokeToken } from "@iaurelius/accounts/oidc";
|
|
5
|
+
import { parseCookies, seal, serialize, unseal } from "./cookies.js";
|
|
6
|
+
import { clearSession, infoOf, profileOf, readSession, resolveSession, writeSession } from "./session.js";
|
|
7
|
+
const TX_COOKIE = "__accounts_tx_";
|
|
8
|
+
const TX_MAX_AGE = 600;
|
|
9
|
+
export const originOf = (req, cfg) => cfg.appUrl ?? new URL(req.url).origin;
|
|
10
|
+
export const isSecure = (origin) => origin.startsWith("https://");
|
|
11
|
+
/** Only paths of this app: never another origin (no open redirect). */
|
|
12
|
+
export function safeReturnPath(v, origin) {
|
|
13
|
+
if (!v)
|
|
14
|
+
return "/";
|
|
15
|
+
try {
|
|
16
|
+
const u = new URL(v, origin);
|
|
17
|
+
const path = u.pathname + u.search + u.hash;
|
|
18
|
+
// Checked on the resolved path: "/.//evil.test" resolves to "//evil.test", another site for a browser.
|
|
19
|
+
if (u.origin !== origin || /^\/[\\/]/.test(path))
|
|
20
|
+
return "/";
|
|
21
|
+
return path;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return "/";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const noStore = { "cache-control": "no-store" };
|
|
28
|
+
function redirect(location, setCookies = [], status = 303) {
|
|
29
|
+
const h = new Headers({ location, ...noStore });
|
|
30
|
+
for (const c of setCookies)
|
|
31
|
+
h.append("set-cookie", c);
|
|
32
|
+
return new Response(null, { status, headers: h });
|
|
33
|
+
}
|
|
34
|
+
function json(body, status = 200, setCookies = []) {
|
|
35
|
+
const h = new Headers({ "content-type": "application/json", ...noStore });
|
|
36
|
+
for (const c of setCookies)
|
|
37
|
+
h.append("set-cookie", c);
|
|
38
|
+
return new Response(JSON.stringify(body), { status, headers: h });
|
|
39
|
+
}
|
|
40
|
+
const escape = (s) => s.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
|
|
41
|
+
/** A plain page that says what went wrong and how to try again. */
|
|
42
|
+
function errorPage(code, message, retry, setCookies = []) {
|
|
43
|
+
const h = new Headers({ "content-type": "text/html; charset=utf-8", ...noStore });
|
|
44
|
+
for (const c of setCookies)
|
|
45
|
+
h.append("set-cookie", c);
|
|
46
|
+
const body = `<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Sign-in failed</title><body style="font:16px/1.5 system-ui,sans-serif;max-width:32rem;margin:15vh auto;padding:0 16px"><h1 style="font-size:1.4rem">Sign-in failed</h1><p>${escape(message)}</p><p style="color:#666;font:13px ui-monospace,monospace">${escape(code)}</p><p><a href="${escape(retry)}">Try again</a></p></body>`;
|
|
47
|
+
return new Response(body, { status: 400, headers: h });
|
|
48
|
+
}
|
|
49
|
+
async function signIn(req, cfg, prompt) {
|
|
50
|
+
const origin = originOf(req, cfg);
|
|
51
|
+
const url = new URL(req.url);
|
|
52
|
+
const returnTo = safeReturnPath(url.searchParams.get("redirect_url"), origin);
|
|
53
|
+
const { verifier, challenge } = await pkce();
|
|
54
|
+
const state = randomString(24);
|
|
55
|
+
const nonce = randomString(24);
|
|
56
|
+
const tx = await seal({ typ: "tx", state, nonce, verifier, returnTo }, cfg.cookieSecret, "tx", TX_MAX_AGE);
|
|
57
|
+
// One cookie per sign-in: two tabs signing in at once do not overwrite each other.
|
|
58
|
+
const cookie = serialize(`${TX_COOKIE}${state.slice(0, 16)}`, tx, { secure: isSecure(origin), maxAge: TX_MAX_AGE, path: cfg.basePath });
|
|
59
|
+
const location = authorizationUrl({ issuer: cfg.issuer, clientId: cfg.clientId, redirectUri: `${origin}${cfg.basePath}/callback`, state, nonce, codeChallenge: challenge, resource: cfg.audience, prompt });
|
|
60
|
+
return redirect(location, [cookie], 302);
|
|
61
|
+
}
|
|
62
|
+
async function callback(req, cfg) {
|
|
63
|
+
const origin = originOf(req, cfg);
|
|
64
|
+
const secure = isSecure(origin);
|
|
65
|
+
const q = new URL(req.url).searchParams;
|
|
66
|
+
const state = q.get("state") ?? "";
|
|
67
|
+
const cookies = parseCookies(req.headers.get("cookie"));
|
|
68
|
+
const txName = `${TX_COOKIE}${state.slice(0, 16)}`;
|
|
69
|
+
const tx = state ? await unseal(cookies.get(txName), cfg.cookieSecret, "tx") : null;
|
|
70
|
+
const retry = `${cfg.basePath}/sign-in`;
|
|
71
|
+
const dropTx = [serialize(txName, "", { secure, maxAge: 0, path: cfg.basePath })];
|
|
72
|
+
if (!tx || tx.typ !== "tx" || tx.state !== state)
|
|
73
|
+
return errorPage("invalid_state", "This sign-in expired or was started in another browser. Start again from the app.", retry, dropTx);
|
|
74
|
+
const back = `${retry}?redirect_url=${encodeURIComponent(tx.returnTo)}`;
|
|
75
|
+
const error = q.get("error");
|
|
76
|
+
if (error) {
|
|
77
|
+
// Closing the hosted page is not an error: back where the person was.
|
|
78
|
+
if (error === "access_denied")
|
|
79
|
+
return redirect(`${origin}${tx.returnTo}`, dropTx);
|
|
80
|
+
return errorPage(error, q.get("error_description") ?? "The sign-in was not completed.", back, dropTx);
|
|
81
|
+
}
|
|
82
|
+
// RFC 9207: the answer must come from our application (Accounts always sends iss).
|
|
83
|
+
if (q.get("iss") !== cfg.issuer)
|
|
84
|
+
return errorPage("invalid_issuer", "The answer did not come from this app's sign-in.", back, dropTx);
|
|
85
|
+
const code = q.get("code");
|
|
86
|
+
if (!code)
|
|
87
|
+
return errorPage("invalid_request", "The answer has no code.", back, dropTx);
|
|
88
|
+
let session;
|
|
89
|
+
try {
|
|
90
|
+
const t = await exchangeCode({ issuer: cfg.issuer, clientId: cfg.clientId, clientSecret: cfg.clientSecret, fetch: cfg.fetch }, { code, redirectUri: `${origin}${cfg.basePath}/callback`, codeVerifier: tx.verifier, resource: cfg.audience });
|
|
91
|
+
if (!t.idToken)
|
|
92
|
+
throw new OAuthError("invalid_response", "No ID token: the app needs the openid scope.");
|
|
93
|
+
await verifyIdToken(t.idToken, { issuer: cfg.issuer, clientId: cfg.clientId, nonce: tx.nonce, fetch: cfg.fetch });
|
|
94
|
+
session = { at: t.accessToken, rt: t.refreshToken, it: t.idToken, exp: t.expiresAt, u: await profileOf(cfg, t.accessToken) };
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
const oe = e instanceof OAuthError ? e : new OAuthError("server_error", "Could not complete the sign-in.");
|
|
98
|
+
return errorPage(oe.error, oe.message, back, dropTx);
|
|
99
|
+
}
|
|
100
|
+
// Absolute: Next's proxy refuses a relative Location.
|
|
101
|
+
return redirect(`${origin}${tx.returnTo}`, [...dropTx, ...(await writeSession(session, cookies, cfg, secure))]);
|
|
102
|
+
}
|
|
103
|
+
async function signOut(req, cfg) {
|
|
104
|
+
const origin = originOf(req, cfg);
|
|
105
|
+
// Only this app's own pages may sign someone out (a form POST from anywhere else is CSRF).
|
|
106
|
+
if (req.headers.get("origin") !== origin)
|
|
107
|
+
return json({ error: "forbidden", error_description: "Sign out from the app's own pages." }, 403);
|
|
108
|
+
const cookies = parseCookies(req.headers.get("cookie"));
|
|
109
|
+
const s = await readSession(cookies, cfg);
|
|
110
|
+
const cleared = clearSession(cookies, cfg, isSecure(origin));
|
|
111
|
+
const after = `${origin}${cfg.afterSignOutPath}`;
|
|
112
|
+
if (!s)
|
|
113
|
+
return redirect(after, cleared);
|
|
114
|
+
if (s.rt)
|
|
115
|
+
await revokeToken({ issuer: cfg.issuer, clientId: cfg.clientId, clientSecret: cfg.clientSecret, fetch: cfg.fetch }, { token: s.rt, hint: "refresh_token" });
|
|
116
|
+
// Also closes the session on the hosted pages, and comes back here.
|
|
117
|
+
return redirect(endSessionUrl({ issuer: cfg.issuer, clientId: cfg.clientId, idTokenHint: s.it, postLogoutRedirectUri: after }), cleared);
|
|
118
|
+
}
|
|
119
|
+
/** GET session: who is signed in, for the browser. GET token: the access token, for calling your API. */
|
|
120
|
+
async function sessionRoute(req, cfg, withToken) {
|
|
121
|
+
const origin = originOf(req, cfg);
|
|
122
|
+
// Readable by this app's pages only (a script elsewhere cannot read it anyway: no CORS; this is belt and braces).
|
|
123
|
+
const site = req.headers.get("sec-fetch-site");
|
|
124
|
+
if (withToken && site && site !== "same-origin")
|
|
125
|
+
return json({ error: "forbidden" }, 403);
|
|
126
|
+
const cookies = parseCookies(req.headers.get("cookie"));
|
|
127
|
+
const { session, setCookies } = await resolveSession(cookies, cfg, isSecure(origin));
|
|
128
|
+
const info = session ? infoOf(session) : null;
|
|
129
|
+
if (withToken)
|
|
130
|
+
return session ? json({ token: session.at, expiresAt: session.exp }, 200, setCookies) : json({ token: null }, 401, setCookies);
|
|
131
|
+
return json(info ? { isSignedIn: true, ...info } : { isSignedIn: false }, 200, setCookies);
|
|
132
|
+
}
|
|
133
|
+
/** The response for a request under basePath, or null if it is not one of ours. */
|
|
134
|
+
export async function handleAccountsRoute(req, cfg) {
|
|
135
|
+
const path = new URL(req.url).pathname;
|
|
136
|
+
if (!path.startsWith(`${cfg.basePath}/`))
|
|
137
|
+
return null;
|
|
138
|
+
const route = path.slice(cfg.basePath.length);
|
|
139
|
+
const get = req.method === "GET" || req.method === "HEAD";
|
|
140
|
+
switch (route) {
|
|
141
|
+
case "/sign-in":
|
|
142
|
+
return get ? signIn(req, cfg) : json({ error: "method_not_allowed" }, 405);
|
|
143
|
+
case "/sign-up":
|
|
144
|
+
return get ? signIn(req, cfg, "create") : json({ error: "method_not_allowed" }, 405);
|
|
145
|
+
case "/callback":
|
|
146
|
+
return get ? callback(req, cfg) : json({ error: "method_not_allowed" }, 405);
|
|
147
|
+
case "/sign-out":
|
|
148
|
+
return req.method === "POST" ? signOut(req, cfg) : json({ error: "method_not_allowed", error_description: "Sign out with a POST (<SignOutButton />)." }, 405);
|
|
149
|
+
case "/session":
|
|
150
|
+
return get ? sessionRoute(req, cfg, false) : json({ error: "method_not_allowed" }, 405);
|
|
151
|
+
case "/token":
|
|
152
|
+
return get ? sessionRoute(req, cfg, true) : json({ error: "method_not_allowed" }, 405);
|
|
153
|
+
default:
|
|
154
|
+
return json({ error: "not_found" }, 404);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,iGAAiG;AACjG,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEtI,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAgB,MAAM,cAAc,CAAC;AAExH,MAAM,SAAS,GAAG,gBAAgB,CAAC;AACnC,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAY,EAAE,GAAmB,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACrG,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAE1E,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAAC,CAAgB,EAAE,MAAc;IAC7D,IAAI,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;QAC5C,uGAAuG;QACvG,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,GAAG,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC;AAChD,SAAS,QAAQ,CAAC,QAAgB,EAAE,UAAU,GAAa,EAAE,EAAE,MAAM,GAAG,GAAG;IACzE,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IAChD,KAAK,MAAM,CAAC,IAAI,UAAU;QAAE,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC;AACD,SAAS,IAAI,CAAC,IAAa,EAAE,MAAM,GAAG,GAAG,EAAE,UAAU,GAAa,EAAE;IAClE,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IAC1E,KAAK,MAAM,CAAC,IAAI,UAAU;QAAE,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AACpE,CAAC;AACD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACpF,mEAAmE;AACnE,SAAS,SAAS,CAAC,IAAY,EAAE,OAAe,EAAE,KAAa,EAAE,UAAU,GAAa,EAAE;IACxF,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,cAAc,EAAE,0BAA0B,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IAClF,KAAK,MAAM,CAAC,IAAI,UAAU;QAAE,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,4RAA4R,MAAM,CAAC,OAAO,CAAC,8DAA8D,MAAM,CAAC,IAAI,CAAC,mBAAmB,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC;IAC/b,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,GAAY,EAAE,GAAmB,EAAE,MAAiB;IACxE,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;IAC9E,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAC3G,mFAAmF;IACnF,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IACxI,MAAM,QAAQ,GAAG,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,GAAG,GAAG,CAAC,QAAQ,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5M,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,GAAmB;IACvD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,GAAG,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACnD,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,MAAM,CAAoF,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvK,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,QAAQ,UAAU,CAAC;IACxC,MAAM,MAAM,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAClF,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,KAAK,KAAK,KAAK;QAC9C,OAAO,SAAS,CAAC,eAAe,EAAE,mFAAmF,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACxI,MAAM,IAAI,GAAG,GAAG,KAAK,iBAAiB,kBAAkB,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IACxE,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,KAAK,EAAE,CAAC;QACV,sEAAsE;QACtE,IAAI,KAAK,KAAK,eAAe;YAAE,OAAO,QAAQ,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,MAAM,CAAC,CAAC;QAClF,OAAO,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,gCAAgC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACxG,CAAC;IACD,mFAAmF;IACnF,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC,gBAAgB,EAAE,kDAAkD,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACtI,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC,iBAAiB,EAAE,yBAAyB,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACxF,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,GAAG,GAAG,CAAC,QAAQ,WAAW,EAAE,YAAY,EAAE,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9O,IAAI,CAAC,CAAC,CAAC,OAAO;YAAE,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,8CAA8C,CAAC,CAAC;QACzG,MAAM,aAAa,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAClH,OAAO,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,EAAE,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC;IAC/H,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,EAAE,GAAG,CAAC,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,cAAc,EAAE,iCAAiC,CAAC,CAAC;QAC3G,OAAO,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IACD,sDAAsD;IACtD,OAAO,QAAQ,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAClH,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,GAAY,EAAE,GAAmB;IACtD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAClC,2FAA2F;IAC3F,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,oCAAoC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC5I,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxD,MAAM,CAAC,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,GAAG,MAAM,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACjD,IAAI,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxC,IAAI,CAAC,CAAC,EAAE;QAAE,MAAM,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;IACtK,oEAAoE;IACpE,OAAO,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3I,CAAC;AAED,yGAAyG;AACzG,KAAK,UAAU,YAAY,CAAC,GAAY,EAAE,GAAmB,EAAE,SAAkB;IAC/E,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAClC,kHAAkH;IAClH,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC/C,IAAI,SAAS,IAAI,IAAI,IAAI,IAAI,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1F,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACrF,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,IAAI,SAAS;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IAC9I,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;AAC7F,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAY,EAAE,GAAmB;IACzE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IACvC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC;IAC1D,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,UAAU;YACb,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QAC7E,KAAK,UAAU;YACb,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QACvF,KAAK,WAAW;YACd,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QAC/E,KAAK,WAAW;YACd,OAAO,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,2CAA2C,EAAE,EAAE,GAAG,CAAC,CAAC;QAChK,KAAK,UAAU;YACb,OAAO,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QAC1F,KAAK,QAAQ;YACX,OAAO,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QACzF;YACE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { AccountsClientProvider as AccountsProvider, SignInButton, SignOutButton, SignUpButton, SignedIn, SignedOut, UserButton, useAuth, useUser, type AccountsProviderProps, type AuthState, type Locale, type SessionUser, } from "./client.js";
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,sBAAsB,IAAI,gBAAgB,EAC1C,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,UAAU,EACV,OAAO,EACP,OAAO,EACP,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// @iaurelius/accounts-nextjs in the browser (and client components): what the "react-server" build
|
|
2
|
+
// (index.server.ts) exports too, with the provider and <SignedIn>/<SignedOut> of the client.
|
|
3
|
+
export { AccountsClientProvider as AccountsProvider, SignInButton, SignOutButton, SignUpButton, SignedIn, SignedOut, UserButton, useAuth, useUser, } from "./client.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,6FAA6F;AAC7F,OAAO,EACL,sBAAsB,IAAI,gBAAgB,EAC1C,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,UAAU,EACV,OAAO,EACP,OAAO,GAKR,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { AccountsProvider, SignedIn, SignedOut } from "./provider.server.js";
|
|
2
|
+
export { SignInButton, SignOutButton, SignUpButton, UserButton, useAuth, useUser, type AccountsProviderProps, type AuthState, type Locale, type SessionUser } from "./client.js";
|
|
3
|
+
//# sourceMappingURL=index.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.server.d.ts","sourceRoot":"","sources":["../src/index.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,qBAAqB,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @iaurelius/accounts-nextjs in server components (the "react-server" condition): the provider reads
|
|
2
|
+
// the session on the server; the interactive parts are the client's.
|
|
3
|
+
export { AccountsProvider, SignedIn, SignedOut } from "./provider.server.js";
|
|
4
|
+
export { SignInButton, SignOutButton, SignUpButton, UserButton, useAuth, useUser } from "./client.js";
|
|
5
|
+
//# sourceMappingURL=index.server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.server.js","sourceRoot":"","sources":["../src/index.server.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,qEAAqE;AACrE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAA6E,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type AccountsProviderProps } from "./client.js";
|
|
3
|
+
export declare function AccountsProvider({ children, locale }: Pick<AccountsProviderProps, "children" | "locale">): Promise<import("react").JSX.Element>;
|
|
4
|
+
export declare function SignedIn({ children }: {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}): Promise<import("react").JSX.Element | null>;
|
|
7
|
+
export declare function SignedOut({ children }: {
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}): Promise<import("react").JSX.Element | null>;
|
|
10
|
+
//# sourceMappingURL=provider.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.server.d.ts","sourceRoot":"","sources":["../src/provider.server.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAA0B,KAAK,qBAAqB,EAAkB,MAAM,aAAa,CAAC;AAIjG,wBAAsB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,qBAAqB,EAAE,UAAU,GAAG,QAAQ,CAAC,wCAW9G;AAED,wBAAsB,QAAQ,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,+CAEpE;AAED,wBAAsB,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,+CAErE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { AccountsClientProvider } from "./client.js";
|
|
3
|
+
import { configOf } from "./config.js";
|
|
4
|
+
import { auth } from "./server.js";
|
|
5
|
+
export async function AccountsProvider({ children, locale }) {
|
|
6
|
+
const a = await auth();
|
|
7
|
+
const cfg = configOf();
|
|
8
|
+
const initialState = a.isAuthenticated
|
|
9
|
+
? { isLoaded: true, isSignedIn: true, user: a.user, sessionId: a.sessionId, orgId: a.orgId }
|
|
10
|
+
: { isLoaded: true, isSignedIn: false, user: null, sessionId: null, orgId: null };
|
|
11
|
+
return (_jsx(AccountsClientProvider, { initialState: initialState, issuer: cfg.issuer, basePath: cfg.basePath, locale: locale, children: children }));
|
|
12
|
+
}
|
|
13
|
+
export async function SignedIn({ children }) {
|
|
14
|
+
return (await auth()).isAuthenticated ? _jsx(_Fragment, { children: children }) : null;
|
|
15
|
+
}
|
|
16
|
+
export async function SignedOut({ children }) {
|
|
17
|
+
return (await auth()).isAuthenticated ? null : _jsx(_Fragment, { children: children });
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=provider.server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.server.js","sourceRoot":"","sources":["../src/provider.server.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,sBAAsB,EAA8C,MAAM,aAAa,CAAC;AACjG,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAsD;IAC7G,MAAM,CAAC,GAAG,MAAM,IAAI,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;IACvB,MAAM,YAAY,GAAc,CAAC,CAAC,eAAe;QAC/C,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE;QAC5F,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACpF,OAAO,CACL,KAAC,sBAAsB,IAAC,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,YAC3G,QAAQ,GACc,CAC1B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,EAAE,QAAQ,EAA4B;IACnE,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,4BAAG,QAAQ,GAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAE,QAAQ,EAA4B;IACpE,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,4BAAG,QAAQ,GAAI,CAAC;AACjE,CAAC"}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type NextRequest } from "next/server.js";
|
|
2
|
+
import { type AccountsOptions } from "./config.js";
|
|
3
|
+
/** Headers the proxy sets for the rest of the request; one sent by the browser is dropped. */
|
|
4
|
+
export declare const PATH_HEADER = "x-accounts-path";
|
|
5
|
+
export type RouteMatcher = (req: {
|
|
6
|
+
nextUrl: {
|
|
7
|
+
pathname: string;
|
|
8
|
+
};
|
|
9
|
+
} | Request) => boolean;
|
|
10
|
+
/** A matcher from paths or patterns: "/dashboard(.*)" matches /dashboard and everything under it. */
|
|
11
|
+
export declare function createRouteMatcher(patterns: (string | RegExp)[] | string | RegExp): RouteMatcher;
|
|
12
|
+
export type AccountsMiddlewareOptions = AccountsOptions & {
|
|
13
|
+
/** Routes that need a signed-in person: pages redirect to the sign-in, API routes answer 401. */
|
|
14
|
+
protect?: (string | RegExp)[] | RouteMatcher;
|
|
15
|
+
};
|
|
16
|
+
export declare function accountsMiddleware(options?: AccountsMiddlewareOptions): (req: NextRequest) => Promise<Response>;
|
|
17
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAK7D,8FAA8F;AAC9F,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE;IAAE,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,OAAO,KAAK,OAAO,CAAC;AAEzF,qGAAqG;AACrG,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAMhG;AAED,MAAM,MAAM,yBAAyB,GAAG,eAAe,GAAG;IACxD,iGAAiG;IACjG,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,YAAY,CAAC;CAC9C,CAAC;AAIF,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,SAEvC,WAAW,KAAG,OAAO,CAAC,QAAQ,CAAC,CAmCjE"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// accountsMiddleware(): the one line in proxy.ts (middleware.ts before Next 16). It answers the SDK's
|
|
2
|
+
// routes, keeps the session fresh (refresh before the access token expires), protects the routes it is
|
|
3
|
+
// told to, and hands the fresh session to the rest of the request (auth(), server components).
|
|
4
|
+
import { NextResponse } from "next/server.js";
|
|
5
|
+
import { configOf } from "./config.js";
|
|
6
|
+
import { parseCookies } from "./cookies.js";
|
|
7
|
+
import { handleAccountsRoute, isSecure, originOf } from "./handlers.js";
|
|
8
|
+
import { applySetCookies, cookieHeader, resolveSession } from "./session.js";
|
|
9
|
+
/** Headers the proxy sets for the rest of the request; one sent by the browser is dropped. */
|
|
10
|
+
export const PATH_HEADER = "x-accounts-path";
|
|
11
|
+
/** A matcher from paths or patterns: "/dashboard(.*)" matches /dashboard and everything under it. */
|
|
12
|
+
export function createRouteMatcher(patterns) {
|
|
13
|
+
const list = (Array.isArray(patterns) ? patterns : [patterns]).map((p) => (p instanceof RegExp ? p : new RegExp(`^${p}$`)));
|
|
14
|
+
return (req) => {
|
|
15
|
+
const path = "nextUrl" in req ? req.nextUrl.pathname : new URL(req.url).pathname;
|
|
16
|
+
return list.some((r) => r.test(path));
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const isApi = (req) => req.nextUrl.pathname.startsWith("/api/") || (req.headers.get("accept") ?? "").includes("application/json");
|
|
20
|
+
export function accountsMiddleware(options = {}) {
|
|
21
|
+
const isProtected = !options.protect ? null : typeof options.protect === "function" ? options.protect : createRouteMatcher(options.protect);
|
|
22
|
+
return async function proxy(req) {
|
|
23
|
+
const cfg = configOf(options);
|
|
24
|
+
const own = await handleAccountsRoute(req, cfg);
|
|
25
|
+
if (own)
|
|
26
|
+
return own;
|
|
27
|
+
const origin = originOf(req, cfg);
|
|
28
|
+
const cookies = parseCookies(req.headers.get("cookie"));
|
|
29
|
+
const { session, setCookies } = await resolveSession(cookies, cfg, isSecure(origin));
|
|
30
|
+
if (!session && isProtected?.(req)) {
|
|
31
|
+
if (isApi(req)) {
|
|
32
|
+
const res = NextResponse.json({ error: "unauthorized", error_description: "Sign in first." }, { status: 401, headers: { "cache-control": "no-store" } });
|
|
33
|
+
for (const c of setCookies)
|
|
34
|
+
res.headers.append("set-cookie", c);
|
|
35
|
+
return res;
|
|
36
|
+
}
|
|
37
|
+
const to = new URL(`${cfg.basePath}/sign-in`, origin);
|
|
38
|
+
to.searchParams.set("redirect_url", req.nextUrl.pathname + req.nextUrl.search);
|
|
39
|
+
const res = NextResponse.redirect(to, 307);
|
|
40
|
+
for (const c of setCookies)
|
|
41
|
+
res.headers.append("set-cookie", c);
|
|
42
|
+
return res;
|
|
43
|
+
}
|
|
44
|
+
// The rest of this request (auth(), server components) sees the session as it is now.
|
|
45
|
+
const headers = new Headers(req.headers);
|
|
46
|
+
headers.delete(PATH_HEADER);
|
|
47
|
+
headers.set(PATH_HEADER, req.nextUrl.pathname + req.nextUrl.search);
|
|
48
|
+
if (setCookies.length) {
|
|
49
|
+
const now = cookieHeader(applySetCookies(cookies, setCookies));
|
|
50
|
+
if (now)
|
|
51
|
+
headers.set("cookie", now);
|
|
52
|
+
else
|
|
53
|
+
headers.delete("cookie");
|
|
54
|
+
}
|
|
55
|
+
const res = NextResponse.next({ request: { headers } });
|
|
56
|
+
for (const c of setCookies)
|
|
57
|
+
res.headers.append("set-cookie", c);
|
|
58
|
+
return res;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,uGAAuG;AACvG,+FAA+F;AAC/F,OAAO,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE7E,8FAA8F;AAC9F,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAI7C,qGAAqG;AACrG,MAAM,UAAU,kBAAkB,CAAC,QAA+C;IAChF,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5H,OAAO,CAAC,GAAG,EAAE,EAAE;QACb,MAAM,IAAI,GAAG,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QACjF,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC;AAOD,MAAM,KAAK,GAAG,CAAC,GAAgB,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;AAE/I,MAAM,UAAU,kBAAkB,CAAC,OAAO,GAA8B,EAAE;IACxE,MAAM,WAAW,GAAwB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjK,OAAO,KAAK,UAAU,KAAK,CAAC,GAAgB;QAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChD,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;QAEpB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAErF,IAAI,CAAC,OAAO,IAAI,WAAW,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBACf,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;gBACzJ,KAAK,MAAM,CAAC,IAAI,UAAU;oBAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;gBAChE,OAAO,GAAG,CAAC;YACb,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,UAAU,EAAE,MAAM,CAAC,CAAC;YACtD,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC/E,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YAC3C,KAAK,MAAM,CAAC,IAAI,UAAU;gBAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;YAChE,OAAO,GAAG,CAAC;QACb,CAAC;QAED,sFAAsF;QACtF,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACpE,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,YAAY,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;YAC/D,IAAI,GAAG;gBAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;;gBAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;QACD,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QACxD,KAAK,MAAM,CAAC,IAAI,UAAU;YAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAChE,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type SessionUser } from "@iaurelius/accounts/oidc";
|
|
2
|
+
import { type AccountsOptions } from "./config.js";
|
|
3
|
+
export { accountsMiddleware, createRouteMatcher, type AccountsMiddlewareOptions, type RouteMatcher } from "./proxy.js";
|
|
4
|
+
export type { AccountsOptions } from "./config.js";
|
|
5
|
+
export type { SessionUser } from "@iaurelius/accounts/oidc";
|
|
6
|
+
type Base = {
|
|
7
|
+
/** Sends a signed-out person to the sign-in, and back here after it. */
|
|
8
|
+
redirectToSignIn: (opts?: {
|
|
9
|
+
returnTo?: string;
|
|
10
|
+
}) => never;
|
|
11
|
+
};
|
|
12
|
+
export type SignedInAuthObject = Base & {
|
|
13
|
+
isAuthenticated: true;
|
|
14
|
+
userId: string;
|
|
15
|
+
sessionId: string | null;
|
|
16
|
+
orgId: string | null;
|
|
17
|
+
/** The person, from the session's ID token (no request). For their latest data, currentUser(). */
|
|
18
|
+
user: SessionUser;
|
|
19
|
+
/** The access token, for calling your API (issued for ACCOUNTS_AUDIENCE). */
|
|
20
|
+
getToken: () => Promise<string>;
|
|
21
|
+
/** Does nothing: the person is signed in. */
|
|
22
|
+
protect: () => Promise<SignedInAuthObject>;
|
|
23
|
+
};
|
|
24
|
+
export type SignedOutAuthObject = Base & {
|
|
25
|
+
isAuthenticated: false;
|
|
26
|
+
userId: null;
|
|
27
|
+
sessionId: null;
|
|
28
|
+
orgId: null;
|
|
29
|
+
user: null;
|
|
30
|
+
getToken: () => Promise<null>;
|
|
31
|
+
/** Redirects to the sign-in (never returns). */
|
|
32
|
+
protect: () => Promise<never>;
|
|
33
|
+
};
|
|
34
|
+
export type AuthObject = SignedInAuthObject | SignedOutAuthObject;
|
|
35
|
+
/**
|
|
36
|
+
* Who is signed in on this request. Needs accountsMiddleware() in proxy.ts, which keeps the session fresh.
|
|
37
|
+
* `await auth.protect()` returns the signed-in person, or sends a signed-out one to the sign-in.
|
|
38
|
+
*/
|
|
39
|
+
export declare const auth: (() => Promise<AuthObject>) & {
|
|
40
|
+
protect: () => Promise<SignedInAuthObject>;
|
|
41
|
+
};
|
|
42
|
+
export type CurrentUser = SessionUser & {
|
|
43
|
+
claims: Record<string, unknown>;
|
|
44
|
+
};
|
|
45
|
+
/** The signed-in person as the application has them now (its userinfo), or null. One request per render. */
|
|
46
|
+
export declare const currentUser: (options?: Pick<AccountsOptions, "fetch">) => Promise<CurrentUser | null>;
|
|
47
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAI7D,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACvH,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,KAAK,IAAI,GAAG;IACV,wEAAwE;IACxE,gBAAgB,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,KAAK,CAAC;CAC3D,CAAC;AACF,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG;IACtC,eAAe,EAAE,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,kGAAkG;IAClG,IAAI,EAAE,WAAW,CAAC;IAClB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,6CAA6C;IAC7C,OAAO,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC5C,CAAC;AACF,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG;IACvC,eAAe,EAAE,KAAK,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,gDAAgD;IAChD,OAAO,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;CAC/B,CAAC;AACF,MAAM,MAAM,UAAU,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AAqClE;;;GAGG;AACH,eAAO,MAAM,IAAI,SAA2B,OAAO,CAAC,UAAU,CAAC;mBAC1C,OAAO,CAAC,kBAAkB,CAAC;CAC9C,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAE5E,4GAA4G;AAC5G,eAAO,MAAM,WAAW,aAAyB,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,KAAQ,OAAO,CAAC,WAAW,GAAG,IAAI,CAgB/G,CAAC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// On the server: auth() and currentUser() in server components, route handlers and server actions,
|
|
2
|
+
// and accountsMiddleware() for proxy.ts.
|
|
3
|
+
import { cookies, headers } from "next/headers.js";
|
|
4
|
+
import { redirect } from "next/navigation.js";
|
|
5
|
+
import { cache } from "react";
|
|
6
|
+
import { endpoints } from "@iaurelius/accounts/oidc";
|
|
7
|
+
import { configOf } from "./config.js";
|
|
8
|
+
import { PATH_HEADER } from "./proxy.js";
|
|
9
|
+
import { infoOf, readSession } from "./session.js";
|
|
10
|
+
export { accountsMiddleware, createRouteMatcher } from "./proxy.js";
|
|
11
|
+
const readAuth = cache(async () => {
|
|
12
|
+
// Cookies first: that makes the route dynamic, so a build without settings does not try to prerender it.
|
|
13
|
+
const jar = await cookies();
|
|
14
|
+
const cfg = configOf();
|
|
15
|
+
const map = new Map(jar.getAll().map((c) => [c.name, c.value]));
|
|
16
|
+
const s = await readSession(map, cfg);
|
|
17
|
+
const current = (await headers()).get(PATH_HEADER) ?? "/";
|
|
18
|
+
const redirectToSignIn = (opts) => redirect(`${cfg.basePath}/sign-in?redirect_url=${encodeURIComponent(opts?.returnTo ?? current)}`);
|
|
19
|
+
const info = s && s.exp > Math.floor(Date.now() / 1000) ? infoOf(s) : null;
|
|
20
|
+
if (!s || !info) {
|
|
21
|
+
const out = {
|
|
22
|
+
isAuthenticated: false,
|
|
23
|
+
userId: null,
|
|
24
|
+
sessionId: null,
|
|
25
|
+
orgId: null,
|
|
26
|
+
user: null,
|
|
27
|
+
getToken: async () => null,
|
|
28
|
+
redirectToSignIn,
|
|
29
|
+
protect: async () => redirectToSignIn(),
|
|
30
|
+
};
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
const out = {
|
|
34
|
+
isAuthenticated: true,
|
|
35
|
+
userId: info.user.id,
|
|
36
|
+
sessionId: info.sessionId,
|
|
37
|
+
orgId: info.orgId,
|
|
38
|
+
user: info.user,
|
|
39
|
+
getToken: async () => s.at,
|
|
40
|
+
redirectToSignIn,
|
|
41
|
+
protect: async () => out,
|
|
42
|
+
};
|
|
43
|
+
return out;
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* Who is signed in on this request. Needs accountsMiddleware() in proxy.ts, which keeps the session fresh.
|
|
47
|
+
* `await auth.protect()` returns the signed-in person, or sends a signed-out one to the sign-in.
|
|
48
|
+
*/
|
|
49
|
+
export const auth = Object.assign(async () => readAuth(), {
|
|
50
|
+
protect: async () => (await readAuth()).protect(),
|
|
51
|
+
});
|
|
52
|
+
/** The signed-in person as the application has them now (its userinfo), or null. One request per render. */
|
|
53
|
+
export const currentUser = cache(async (options = {}) => {
|
|
54
|
+
const a = await auth();
|
|
55
|
+
if (!a.isAuthenticated)
|
|
56
|
+
return null;
|
|
57
|
+
const cfg = configOf(options);
|
|
58
|
+
const f = cfg.fetch ?? ((i, init) => globalThis.fetch(i, init));
|
|
59
|
+
const res = await f(endpoints(cfg.issuer).userinfo, { headers: { authorization: `Bearer ${await a.getToken()}` }, cache: "no-store" });
|
|
60
|
+
if (!res.ok)
|
|
61
|
+
return null;
|
|
62
|
+
const c = (await res.json());
|
|
63
|
+
return {
|
|
64
|
+
id: String(c.sub ?? a.userId),
|
|
65
|
+
email: typeof c.email === "string" ? c.email : a.user.email,
|
|
66
|
+
emailVerified: c.email_verified === true,
|
|
67
|
+
name: typeof c.name === "string" && c.name ? c.name : null,
|
|
68
|
+
imageUrl: typeof c.picture === "string" && c.picture ? c.picture : null,
|
|
69
|
+
claims: c,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|