@bitbaum/accountkit 0.17.0 → 0.18.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/README.md +40 -0
- package/dist/auth/compat-testing.d.ts +51 -0
- package/dist/auth/compat-testing.d.ts.map +1 -0
- package/dist/auth/compat-testing.js +97 -0
- package/dist/auth/compat-testing.js.map +1 -0
- package/dist/auth/import-rehearsal.d.ts +32 -0
- package/dist/auth/import-rehearsal.d.ts.map +1 -0
- package/dist/auth/import-rehearsal.js +59 -0
- package/dist/auth/import-rehearsal.js.map +1 -0
- package/dist/auth/nextauth-compat.d.ts +123 -0
- package/dist/auth/nextauth-compat.d.ts.map +1 -0
- package/dist/auth/nextauth-compat.js +265 -0
- package/dist/auth/nextauth-compat.js.map +1 -0
- package/dist/auth/switch.d.ts +8 -0
- package/dist/auth/switch.d.ts.map +1 -0
- package/dist/auth/switch.js +10 -0
- package/dist/auth/switch.js.map +1 -0
- package/dist/bin/rehearse-import.d.ts +3 -0
- package/dist/bin/rehearse-import.d.ts.map +1 -0
- package/dist/bin/rehearse-import.js +82 -0
- package/dist/bin/rehearse-import.js.map +1 -0
- package/package.json +20 -1
package/README.md
CHANGED
|
@@ -257,6 +257,46 @@ product's hashes; `verify` answers whether the password fits. It works alone or
|
|
|
257
257
|
beside `legacyBcrypt`, and new passwords are native scrypt either way.
|
|
258
258
|
|
|
259
259
|
|
|
260
|
+
### Moving a product off Auth.js
|
|
261
|
+
|
|
262
|
+
A product whose pages call `next-auth/react` can run on the shared runtime
|
|
263
|
+
before any page changes. `@bitbaum/accountkit/auth/nextauth-compat` answers
|
|
264
|
+
that client protocol (`session`, `csrf`, `providers`, `signout`, each
|
|
265
|
+
credentials callback, and `signin/<oidc>` for every configured OIDC client)
|
|
266
|
+
from AccountKit:
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
const compat = createNextAuthCompat({
|
|
270
|
+
runtime: sharedAuth, // createAuthRuntime(...)
|
|
271
|
+
siteUrl: () => process.env.AUTH_URL!,
|
|
272
|
+
signInPath: "/login",
|
|
273
|
+
landing: "/dashboard",
|
|
274
|
+
toSession: async (shared) => productSessionFromRows(shared.user.id),
|
|
275
|
+
credentials: {
|
|
276
|
+
credentials: { name: "Email", resolve: async (form) => ({ email: String(form.get("email")) }) },
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
// app/api/auth/[...nextauth]/route.ts, with the switch on:
|
|
280
|
+
export const { GET, POST } = compat.route;
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The product supplies only what is its own: the session shape (re-read from
|
|
284
|
+
its rows on every request), which address each credentials form signs in (or
|
|
285
|
+
a refusal code such as an account lock), the codes its login page reads, and
|
|
286
|
+
hooks after a sign-in or a refusal. `sharedRuntimeEnabled()` (`@bitbaum/accountkit/auth/switch`) reads the one
|
|
287
|
+
switch, `AUTH_RUNTIME=accountkit`. `sessionFor(headers)` serves a proxy,
|
|
288
|
+
`currentSession()` a server component, and `sessionIdFor(headers)` names the
|
|
289
|
+
session making a change so the product can keep it while ending the others.
|
|
290
|
+
AccountKit's own sign-up, reset and password endpoints answer 404 through it,
|
|
291
|
+
so the product's writers stay the only ones until it adopts AccountKit's
|
|
292
|
+
screens.
|
|
293
|
+
|
|
294
|
+
`accountkit-rehearse-import <import.sql>` runs a product's own import SQL
|
|
295
|
+
against `DATABASE_URL` in one transaction that always rolls back, and prints
|
|
296
|
+
only counts. It uses the product's `pg` or `postgres` driver.
|
|
297
|
+
`@bitbaum/accountkit/auth/compat-testing` gives journey tests a client that
|
|
298
|
+
speaks what `next-auth/react` sends and keeps the cookie jar.
|
|
299
|
+
|
|
260
300
|
### A product's own plugins
|
|
261
301
|
|
|
262
302
|
`plugins` (both `createAuthRuntime` and `createAuthInstance`) mounts a
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A browser stand-in for journey tests of a product on the compat layer: it
|
|
3
|
+
* speaks what `next-auth/react` sends, keeps the cookie jar between calls,
|
|
4
|
+
* and gives each request its own client address so AccountKit's limiter
|
|
5
|
+
* never trips inside one test file.
|
|
6
|
+
*
|
|
7
|
+
* const client = createCompatClient({ compat, site: "https://app.example.test" });
|
|
8
|
+
* const result = await client.signIn("credentials", { email, password });
|
|
9
|
+
* expect(client.refusal(result)).toBeNull();
|
|
10
|
+
* expect((await client.session())?.user.id).toBe(id);
|
|
11
|
+
*/
|
|
12
|
+
/** What the client needs from `createNextAuthCompat(...)`. */
|
|
13
|
+
export interface CompatRoute {
|
|
14
|
+
route: {
|
|
15
|
+
GET: (request: Request) => Promise<Response>;
|
|
16
|
+
POST: (request: Request) => Promise<Response>;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export declare function createCompatClient(options: {
|
|
20
|
+
compat: CompatRoute;
|
|
21
|
+
site: string;
|
|
22
|
+
}): {
|
|
23
|
+
call: (route: string, form?: Record<string, string>) => Promise<Response>;
|
|
24
|
+
/** The jar as a Cookie header, to hand to server-side helpers. */
|
|
25
|
+
cookie: string;
|
|
26
|
+
/** signIn(provider, { redirect: false }) as next-auth/react posts it. */
|
|
27
|
+
signIn(provider: string, fields: Record<string, string>, callbackUrl?: string): Promise<{
|
|
28
|
+
url: string;
|
|
29
|
+
}>;
|
|
30
|
+
/** signOut({ redirect: false, callbackUrl }) as next-auth/react posts it. */
|
|
31
|
+
signOut(callbackUrl?: string): Promise<{
|
|
32
|
+
url: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** getSession(): the product session, or null. */
|
|
35
|
+
session<S = {
|
|
36
|
+
user: Record<string, unknown>;
|
|
37
|
+
}>(): Promise<S | null>;
|
|
38
|
+
/** useSession().update(): the same fresh read, posted. */
|
|
39
|
+
update<S = {
|
|
40
|
+
user: Record<string, unknown>;
|
|
41
|
+
}>(): Promise<S | null>;
|
|
42
|
+
/** The `error` a sign-in answer carries for the login page, or null on success. */
|
|
43
|
+
refusal(result: {
|
|
44
|
+
url: string;
|
|
45
|
+
}): string | null;
|
|
46
|
+
/** The login page's `code` from a refused sign-in. */
|
|
47
|
+
code(result: {
|
|
48
|
+
url: string;
|
|
49
|
+
}): string | null;
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=compat-testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat-testing.d.ts","sourceRoot":"","sources":["../../src/auth/compat-testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE;QACL,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;KAC/C,CAAC;CACH;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;kBAqBU,MAAM,SACN,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC5B,OAAO,CAAC,QAAQ,CAAC;IAsBlB,kEAAkE;YAKhD,MAAM;IAOxB,yEAAyE;qBAE7D,MAAM,UACR,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;aAQW,MAAM;;IAEjD,6EAA6E;;aAMlC,MAAM;;IAEjD,kDAAkD;YACpC,CAAC;cAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;UAAO,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAGzE,0DAA0D;WAC7C,CAAC;cAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;UAAO,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAKxE,mFAAmF;oBACnE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,GAAG,IAAI;IAG/C,sDAAsD;iBACzC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,GAAG,IAAI;EAI/C"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A browser stand-in for journey tests of a product on the compat layer: it
|
|
3
|
+
* speaks what `next-auth/react` sends, keeps the cookie jar between calls,
|
|
4
|
+
* and gives each request its own client address so AccountKit's limiter
|
|
5
|
+
* never trips inside one test file.
|
|
6
|
+
*
|
|
7
|
+
* const client = createCompatClient({ compat, site: "https://app.example.test" });
|
|
8
|
+
* const result = await client.signIn("credentials", { email, password });
|
|
9
|
+
* expect(client.refusal(result)).toBeNull();
|
|
10
|
+
* expect((await client.session())?.user.id).toBe(id);
|
|
11
|
+
*/
|
|
12
|
+
export function createCompatClient(options) {
|
|
13
|
+
const jar = new Map();
|
|
14
|
+
let ip = 0;
|
|
15
|
+
const cookieHeader = () => [...jar].map(([name, value]) => `${name}=${value}`).join("; ");
|
|
16
|
+
function keep(response) {
|
|
17
|
+
for (const set of response.headers.getSetCookie()) {
|
|
18
|
+
const [pair] = set.split(";");
|
|
19
|
+
const at = pair.indexOf("=");
|
|
20
|
+
const name = pair.slice(0, at);
|
|
21
|
+
const value = pair.slice(at + 1);
|
|
22
|
+
if (/max-age=0/i.test(set) || value === "")
|
|
23
|
+
jar.delete(name);
|
|
24
|
+
else
|
|
25
|
+
jar.set(name, value);
|
|
26
|
+
}
|
|
27
|
+
return response;
|
|
28
|
+
}
|
|
29
|
+
/** One request to /api/auth{route}: a form POST when `form` is given, else a GET. */
|
|
30
|
+
async function call(route, form) {
|
|
31
|
+
ip += 1;
|
|
32
|
+
const headers = new Headers({
|
|
33
|
+
origin: options.site,
|
|
34
|
+
"x-forwarded-for": `198.51.100.${ip % 250}`,
|
|
35
|
+
cookie: cookieHeader(),
|
|
36
|
+
});
|
|
37
|
+
if (form)
|
|
38
|
+
headers.set("content-type", "application/x-www-form-urlencoded");
|
|
39
|
+
const request = new Request(`${options.site}/api/auth${route}`, {
|
|
40
|
+
method: form ? "POST" : "GET",
|
|
41
|
+
headers,
|
|
42
|
+
body: form ? new URLSearchParams(form) : undefined,
|
|
43
|
+
});
|
|
44
|
+
return keep(await (form
|
|
45
|
+
? options.compat.route.POST(request)
|
|
46
|
+
: options.compat.route.GET(request)));
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
call,
|
|
50
|
+
/** The jar as a Cookie header, to hand to server-side helpers. */
|
|
51
|
+
get cookie() {
|
|
52
|
+
return cookieHeader();
|
|
53
|
+
},
|
|
54
|
+
/** Replace the jar (switch between people), from a Cookie header. */
|
|
55
|
+
set cookie(value) {
|
|
56
|
+
jar.clear();
|
|
57
|
+
for (const part of value.split("; ").filter(Boolean)) {
|
|
58
|
+
const at = part.indexOf("=");
|
|
59
|
+
jar.set(part.slice(0, at), part.slice(at + 1));
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
/** signIn(provider, { redirect: false }) as next-auth/react posts it. */
|
|
63
|
+
async signIn(provider, fields, callbackUrl = `${options.site}/`) {
|
|
64
|
+
const response = await call(`/callback/${provider}`, {
|
|
65
|
+
...fields,
|
|
66
|
+
csrfToken: "test",
|
|
67
|
+
callbackUrl,
|
|
68
|
+
});
|
|
69
|
+
return (await response.json());
|
|
70
|
+
},
|
|
71
|
+
/** signOut({ redirect: false, callbackUrl }) as next-auth/react posts it. */
|
|
72
|
+
async signOut(callbackUrl = `${options.site}/`) {
|
|
73
|
+
const response = await call("/signout", {
|
|
74
|
+
csrfToken: "test",
|
|
75
|
+
callbackUrl,
|
|
76
|
+
});
|
|
77
|
+
return (await response.json());
|
|
78
|
+
},
|
|
79
|
+
/** getSession(): the product session, or null. */
|
|
80
|
+
async session() {
|
|
81
|
+
return (await (await call("/session")).json());
|
|
82
|
+
},
|
|
83
|
+
/** useSession().update(): the same fresh read, posted. */
|
|
84
|
+
async update() {
|
|
85
|
+
return (await (await call("/session", { data: "{}" })).json());
|
|
86
|
+
},
|
|
87
|
+
/** The `error` a sign-in answer carries for the login page, or null on success. */
|
|
88
|
+
refusal(result) {
|
|
89
|
+
return new URL(result.url).searchParams.get("error");
|
|
90
|
+
},
|
|
91
|
+
/** The login page's `code` from a refused sign-in. */
|
|
92
|
+
code(result) {
|
|
93
|
+
return new URL(result.url).searchParams.get("code");
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=compat-testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat-testing.js","sourceRoot":"","sources":["../../src/auth/compat-testing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rehearse a product's account import (its own SQL, which copies its people
|
|
3
|
+
* into AccountKit's tables) inside one transaction that always rolls back,
|
|
4
|
+
* and report only counts. Constraint errors can carry addresses or hashes, so
|
|
5
|
+
* a failure reports a fixed sentence and never the database's message.
|
|
6
|
+
*
|
|
7
|
+
* The product's SQL refuses drift, collisions and a live shared runtime itself;
|
|
8
|
+
* this only runs it and counts what it would have written.
|
|
9
|
+
*/
|
|
10
|
+
/** Runs one SQL text inside the rehearsal's transaction and returns its rows. */
|
|
11
|
+
export type RehearsalQuery = (text: string) => Promise<Record<string, unknown>[]>;
|
|
12
|
+
export interface RehearsalCounts {
|
|
13
|
+
rehearsal: "rolled_back";
|
|
14
|
+
accounts: number;
|
|
15
|
+
verified_addresses: number;
|
|
16
|
+
password_accounts: number;
|
|
17
|
+
/** Linked sign-in providers other than passwords, by provider id. */
|
|
18
|
+
linked: Record<string, number>;
|
|
19
|
+
}
|
|
20
|
+
/** The counts the import left in the shared tables, read before rolling back. */
|
|
21
|
+
export declare function countsSql(prefix?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Open a transaction with `begin`, run the import and the counts through the
|
|
24
|
+
* query it provides, then roll back. `begin` must roll back when its callback
|
|
25
|
+
* throws (postgres-js `sql.begin`, or the pg adapter in ../bin).
|
|
26
|
+
*/
|
|
27
|
+
export declare function rehearseImport(options: {
|
|
28
|
+
begin: (work: (query: RehearsalQuery) => Promise<void>) => Promise<void>;
|
|
29
|
+
sql: string;
|
|
30
|
+
prefix?: string;
|
|
31
|
+
}): Promise<RehearsalCounts>;
|
|
32
|
+
//# sourceMappingURL=import-rehearsal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-rehearsal.d.ts","sourceRoot":"","sources":["../../src/auth/import-rehearsal.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,CAC3B,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;AAExC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,aAAa,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAID,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,MAAM,SAAU,GAAG,MAAM,CAUlD;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgC3B"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rehearse a product's account import (its own SQL, which copies its people
|
|
3
|
+
* into AccountKit's tables) inside one transaction that always rolls back,
|
|
4
|
+
* and report only counts. Constraint errors can carry addresses or hashes, so
|
|
5
|
+
* a failure reports a fixed sentence and never the database's message.
|
|
6
|
+
*
|
|
7
|
+
* The product's SQL refuses drift, collisions and a live shared runtime itself;
|
|
8
|
+
* this only runs it and counts what it would have written.
|
|
9
|
+
*/
|
|
10
|
+
const ROLLBACK = Symbol("rollback");
|
|
11
|
+
/** The counts the import left in the shared tables, read before rolling back. */
|
|
12
|
+
export function countsSql(prefix = "auth_") {
|
|
13
|
+
if (!/^[a-z_]*$/.test(prefix))
|
|
14
|
+
throw new Error("table prefix must be lower-case letters and _");
|
|
15
|
+
return `SELECT
|
|
16
|
+
(SELECT count(*)::int FROM ${prefix}users) AS accounts,
|
|
17
|
+
(SELECT count(*)::int FROM ${prefix}users WHERE email_verified) AS verified_addresses,
|
|
18
|
+
(SELECT count(*)::int FROM ${prefix}accounts WHERE provider_id = 'credential') AS password_accounts,
|
|
19
|
+
(SELECT coalesce(json_object_agg(provider_id, n), '{}'::json) FROM
|
|
20
|
+
(SELECT provider_id, count(*)::int AS n FROM ${prefix}accounts
|
|
21
|
+
WHERE provider_id <> 'credential' GROUP BY provider_id) linked) AS linked`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Open a transaction with `begin`, run the import and the counts through the
|
|
25
|
+
* query it provides, then roll back. `begin` must roll back when its callback
|
|
26
|
+
* throws (postgres-js `sql.begin`, or the pg adapter in ../bin).
|
|
27
|
+
*/
|
|
28
|
+
export async function rehearseImport(options) {
|
|
29
|
+
let counts;
|
|
30
|
+
try {
|
|
31
|
+
await options.begin(async (query) => {
|
|
32
|
+
await query("SET LOCAL lock_timeout = '5s'");
|
|
33
|
+
await query("SET LOCAL statement_timeout = '30s'");
|
|
34
|
+
await query(options.sql);
|
|
35
|
+
const [row] = await query(countsSql(options.prefix));
|
|
36
|
+
counts = {
|
|
37
|
+
rehearsal: "rolled_back",
|
|
38
|
+
accounts: Number(row.accounts),
|
|
39
|
+
verified_addresses: Number(row.verified_addresses),
|
|
40
|
+
password_accounts: Number(row.password_accounts),
|
|
41
|
+
linked: (row.linked ?? {}),
|
|
42
|
+
};
|
|
43
|
+
throw ROLLBACK;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error !== ROLLBACK) {
|
|
48
|
+
// The message is fixed (the database's can carry addresses or hashes);
|
|
49
|
+
// the cause stays attached for a debugger, never printed by the CLI.
|
|
50
|
+
throw new Error("Account import rehearsal failed; transaction rolled back", {
|
|
51
|
+
cause: error,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (!counts)
|
|
56
|
+
throw new Error("Account import rehearsal failed; transaction rolled back");
|
|
57
|
+
return counts;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=import-rehearsal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-rehearsal.js","sourceRoot":"","sources":["../../src/auth/import-rehearsal.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;AAEpC,iFAAiF;AACjF,MAAM,UAAU,SAAS,CAAC,MAAM,GAAG,OAAO;IACxC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,OAAO;iCACwB,MAAM;iCACN,MAAM;iCACN,MAAM;;qDAEc,MAAM;iFACsB,CAAC;AAClF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAIpC;IACC,IAAI,MAAmC,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAClC,MAAM,KAAK,CAAC,+BAA+B,CAAC,CAAC;YAC7C,MAAM,KAAK,CAAC,qCAAqC,CAAC,CAAC;YACnD,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YACrD,MAAM,GAAG;gBACP,SAAS,EAAE,aAAa;gBACxB,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAC9B,kBAAkB,EAAE,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC;gBAClD,iBAAiB,EAAE,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC;gBAChD,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAA2B;aACrD,CAAC;YACF,MAAM,QAAQ,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvB,uEAAuE;YACvE,qEAAqE;YACrE,MAAM,IAAI,KAAK,CACb,0DAA0D,EAC1D;gBACE,KAAK,EAAE,KAAK;aACb,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM;QACT,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { AuthSession } from "./next.js";
|
|
2
|
+
/**
|
|
3
|
+
* A product's existing screens on the shared runtime, unchanged.
|
|
4
|
+
*
|
|
5
|
+
* Products that grew up on Auth.js call `next-auth/react` (signIn, signOut,
|
|
6
|
+
* useSession, update) from every page. While they move to AccountKit one
|
|
7
|
+
* reversible step at a time, this answers that client protocol from the
|
|
8
|
+
* AccountKit runtime, so no page has to learn a second protocol and no Auth.js
|
|
9
|
+
* credential writer runs beside the shared one.
|
|
10
|
+
*
|
|
11
|
+
* const compat = createNextAuthCompat({ runtime: sharedAuth, siteUrl, ... });
|
|
12
|
+
* // /api/auth/[...nextauth]/route.ts, with the switch on:
|
|
13
|
+
* export const { GET, POST } = compat.route;
|
|
14
|
+
*
|
|
15
|
+
* Only what the screens use is open. AccountKit's own sign-up, reset and
|
|
16
|
+
* password endpoints answer 404 until the product adopts AccountKit's screens:
|
|
17
|
+
* a second credential writer would put hashes in the shared table that the
|
|
18
|
+
* product's own table never sees, and rolling back would lose them.
|
|
19
|
+
*/
|
|
20
|
+
/** The shared runtime, as `createAuthRuntime` returns it. */
|
|
21
|
+
export interface CompatRuntime {
|
|
22
|
+
GET: (request: Request) => Promise<Response>;
|
|
23
|
+
POST: (request: Request) => Promise<Response>;
|
|
24
|
+
sessionFor: (headers: Headers) => Promise<AuthSession | null>;
|
|
25
|
+
getSession: () => Promise<AuthSession | null>;
|
|
26
|
+
}
|
|
27
|
+
/** Why a sign-in was refused; the product maps each to the code its login page reads. */
|
|
28
|
+
export type RefusalReason = "missing" | "credentials" | "rate_limited" | "unavailable" | "email_unverified";
|
|
29
|
+
/** A credentials provider: what the form is called and which address it signs in. */
|
|
30
|
+
export interface CompatCredentialsProvider {
|
|
31
|
+
/** The provider's display name in /providers. */
|
|
32
|
+
name: string;
|
|
33
|
+
/**
|
|
34
|
+
* The address this form signs in, or a refusal code the login page reads
|
|
35
|
+
* (an account lock, say), or null for "missing input". The password is read
|
|
36
|
+
* by the compat layer from the form's `password` field.
|
|
37
|
+
*/
|
|
38
|
+
resolve: (form: FormData) => Promise<{
|
|
39
|
+
email: string;
|
|
40
|
+
} | {
|
|
41
|
+
refuse: string;
|
|
42
|
+
} | null>;
|
|
43
|
+
}
|
|
44
|
+
export interface SignInEvent {
|
|
45
|
+
provider: string;
|
|
46
|
+
email: string;
|
|
47
|
+
user: {
|
|
48
|
+
id: string;
|
|
49
|
+
name?: string | null;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface RefusalEvent {
|
|
53
|
+
provider: string;
|
|
54
|
+
email: string;
|
|
55
|
+
status: number;
|
|
56
|
+
reason: RefusalReason;
|
|
57
|
+
}
|
|
58
|
+
export interface NextAuthCompatOptions<S> {
|
|
59
|
+
runtime: CompatRuntime;
|
|
60
|
+
/** The public origin, read at request time (redirects and AccountKit's origin check). */
|
|
61
|
+
siteUrl: () => string;
|
|
62
|
+
/** Where a refusal sends the person (the product's sign-in page). */
|
|
63
|
+
signInPath: string;
|
|
64
|
+
/** Where a sign-in lands when the page named no same-origin callbackUrl. */
|
|
65
|
+
landing: string;
|
|
66
|
+
/**
|
|
67
|
+
* The product's session shape from a shared session, re-read from the
|
|
68
|
+
* product's own rows on every request; null when the person no longer exists.
|
|
69
|
+
*/
|
|
70
|
+
toSession: (shared: AuthSession) => Promise<S | null>;
|
|
71
|
+
/** next-auth credentials provider id → how it signs in. */
|
|
72
|
+
credentials: Record<string, CompatCredentialsProvider>;
|
|
73
|
+
/** The code the login page reads for each refusal (default: the reason itself). */
|
|
74
|
+
codes?: Partial<Record<RefusalReason, string>>;
|
|
75
|
+
/** After a successful credentials sign-in: lockout reset, onboarding, logs. */
|
|
76
|
+
onSignedIn?: (event: SignInEvent) => Promise<void>;
|
|
77
|
+
/** After AccountKit refused a password: failed-attempt counters, logs. */
|
|
78
|
+
onRefused?: (event: RefusalEvent) => Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Whether an OIDC sign-in by a person who is already signed in links the
|
|
81
|
+
* identity to them ("Connect OrangeCat") instead of signing in. Default: yes.
|
|
82
|
+
*/
|
|
83
|
+
linkWhenSignedIn?: (request: Request, session: S) => boolean | Promise<boolean>;
|
|
84
|
+
/** Where a failed link returns (default: the page it started from). */
|
|
85
|
+
linkErrorPath?: string;
|
|
86
|
+
/** The env OIDC providers are read from (default: process.env). */
|
|
87
|
+
env?: () => Record<string, string | undefined>;
|
|
88
|
+
}
|
|
89
|
+
/** One AccountKit endpoint's answer, for the compat layer to translate. */
|
|
90
|
+
export interface SharedAnswer {
|
|
91
|
+
status: number;
|
|
92
|
+
body: Record<string, unknown>;
|
|
93
|
+
cookies: string[];
|
|
94
|
+
}
|
|
95
|
+
/** AccountKit endpoints the screens reach directly; everything else answers 404. */
|
|
96
|
+
export declare function compatPathIsOpen(path: string): boolean;
|
|
97
|
+
/** A same-origin path from a client-supplied URL, or `fallback`. */
|
|
98
|
+
export declare function sameOriginPath(raw: FormDataEntryValue | string | null | undefined, site: string, fallback: string): string;
|
|
99
|
+
export declare function createNextAuthCompat<S>(options: NextAuthCompatOptions<S>): {
|
|
100
|
+
handle: (request: Request) => Promise<Response | null>;
|
|
101
|
+
/** /api/auth/* with the switch on: the compat answer, else the runtime. */
|
|
102
|
+
route: {
|
|
103
|
+
GET: (request: Request) => Promise<Response>;
|
|
104
|
+
POST: (request: Request) => Promise<Response>;
|
|
105
|
+
};
|
|
106
|
+
callShared: (request: Request, route: string, body: Record<string, unknown>) => Promise<SharedAnswer>;
|
|
107
|
+
sessionFor: (requestHeaders: Headers) => Promise<S | null>;
|
|
108
|
+
sessionIdFor: (requestHeaders: Headers) => Promise<string | null>;
|
|
109
|
+
currentSession: () => Promise<S | null>;
|
|
110
|
+
oidcSignIn: (request: Request, providerId: string, next: string) => Promise<{
|
|
111
|
+
url: string | null;
|
|
112
|
+
cookies: string[];
|
|
113
|
+
}>;
|
|
114
|
+
providers: () => Record<string, {
|
|
115
|
+
id: string;
|
|
116
|
+
name: string;
|
|
117
|
+
type: string;
|
|
118
|
+
signinUrl: string;
|
|
119
|
+
callbackUrl: string;
|
|
120
|
+
}>;
|
|
121
|
+
};
|
|
122
|
+
export type NextAuthCompat<S> = ReturnType<typeof createNextAuthCompat<S>>;
|
|
123
|
+
//# sourceMappingURL=nextauth-compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextauth-compat.d.ts","sourceRoot":"","sources":["../../src/auth/nextauth-compat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { oidcClients } from "./methods.js";
|
|
3
|
+
const OPEN_PATHS = new Set([
|
|
4
|
+
"/get-session",
|
|
5
|
+
"/sign-in/email",
|
|
6
|
+
"/sign-out",
|
|
7
|
+
"/ok",
|
|
8
|
+
"/error",
|
|
9
|
+
]);
|
|
10
|
+
/** AccountKit endpoints the screens reach directly; everything else answers 404. */
|
|
11
|
+
export function compatPathIsOpen(path) {
|
|
12
|
+
return OPEN_PATHS.has(path) || path.startsWith("/oauth2/callback/");
|
|
13
|
+
}
|
|
14
|
+
/** A same-origin path from a client-supplied URL, or `fallback`. */
|
|
15
|
+
export function sameOriginPath(raw, site, fallback) {
|
|
16
|
+
const origin = new URL(site).origin;
|
|
17
|
+
const value = typeof raw === "string" ? raw : "";
|
|
18
|
+
try {
|
|
19
|
+
const url = new URL(value || fallback, origin);
|
|
20
|
+
return url.origin === origin ? url.pathname + url.search : fallback;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return fallback;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** A redirect whose headers can still take cookies (Response.redirect's cannot). */
|
|
27
|
+
function redirectTo(location) {
|
|
28
|
+
return new Response(null, { status: 302, headers: { location } });
|
|
29
|
+
}
|
|
30
|
+
function withCookies(response, setCookies) {
|
|
31
|
+
for (const cookie of setCookies)
|
|
32
|
+
response.headers.append("set-cookie", cookie);
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
35
|
+
// React.cache dedupes per request on the server; outside a React server
|
|
36
|
+
// render (tests, scripts) it is absent and every call reads afresh.
|
|
37
|
+
const cache = React.cache ?? ((fn) => fn);
|
|
38
|
+
export function createNextAuthCompat(options) {
|
|
39
|
+
const { runtime } = options;
|
|
40
|
+
const code = (reason) => options.codes?.[reason] ?? reason;
|
|
41
|
+
const env = () => options.env?.() ?? process.env;
|
|
42
|
+
/** Run one AccountKit endpoint for this request, keeping its cookies and proxy hop. */
|
|
43
|
+
async function callShared(request, route, body) {
|
|
44
|
+
const origin = new URL(options.siteUrl()).origin;
|
|
45
|
+
const forwarded = new Headers(request.headers);
|
|
46
|
+
forwarded.delete("content-length");
|
|
47
|
+
forwarded.set("origin", origin);
|
|
48
|
+
forwarded.set("content-type", "application/json");
|
|
49
|
+
const response = await runtime.POST(new Request(`${origin}/api/auth${route}`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: forwarded,
|
|
52
|
+
body: JSON.stringify(body),
|
|
53
|
+
}));
|
|
54
|
+
const text = await response.text();
|
|
55
|
+
let parsed = {};
|
|
56
|
+
try {
|
|
57
|
+
parsed = text ? JSON.parse(text) : {};
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Nothing to translate.
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
status: response.status,
|
|
64
|
+
body: parsed,
|
|
65
|
+
cookies: response.headers.getSetCookie(),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function toSessionOrNull(shared) {
|
|
69
|
+
return shared ? options.toSession(shared) : null;
|
|
70
|
+
}
|
|
71
|
+
/** The product session behind these request headers (proxy, route handlers). */
|
|
72
|
+
async function sessionFor(requestHeaders) {
|
|
73
|
+
return toSessionOrNull(await runtime.sessionFor(requestHeaders).catch(() => null));
|
|
74
|
+
}
|
|
75
|
+
/** The shared session id behind these headers, for "keep this session" writes. */
|
|
76
|
+
async function sessionIdFor(requestHeaders) {
|
|
77
|
+
const shared = await runtime.sessionFor(requestHeaders).catch(() => null);
|
|
78
|
+
return shared?.session.id ?? null;
|
|
79
|
+
}
|
|
80
|
+
/** The product session of this request (server components, actions). */
|
|
81
|
+
const currentSession = cache(async () => toSessionOrNull(await runtime.getSession()));
|
|
82
|
+
/** What next-auth/react reads on a refusal: `error` and the login page's `code`. */
|
|
83
|
+
const refusal = (loginCode) => Response.json({
|
|
84
|
+
url: `${options.siteUrl()}${options.signInPath}?error=CredentialsSignin&code=${encodeURIComponent(loginCode)}`,
|
|
85
|
+
});
|
|
86
|
+
/** The methods the pages may use: the product's credentials, plus each configured OIDC client. */
|
|
87
|
+
function providers() {
|
|
88
|
+
const site = options.siteUrl();
|
|
89
|
+
const entry = (id, name, type) => ({
|
|
90
|
+
id,
|
|
91
|
+
name,
|
|
92
|
+
type,
|
|
93
|
+
signinUrl: `${site}/api/auth/signin/${id}`,
|
|
94
|
+
callbackUrl: `${site}/api/auth/callback/${id}`,
|
|
95
|
+
});
|
|
96
|
+
const list = {};
|
|
97
|
+
for (const client of oidcClients(env())) {
|
|
98
|
+
list[client.providerId] = entry(client.providerId, client.providerId === "orangecat" ? "OrangeCat" : "bitbaum", "oidc");
|
|
99
|
+
}
|
|
100
|
+
for (const [id, provider] of Object.entries(options.credentials)) {
|
|
101
|
+
list[id] = entry(id, provider.name, "credentials");
|
|
102
|
+
}
|
|
103
|
+
return list;
|
|
104
|
+
}
|
|
105
|
+
function oidcProviderIds() {
|
|
106
|
+
return new Set(oidcClients(env()).map((client) => client.providerId));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Start an OIDC round-trip: a sign-in, or — for a person already signed in
|
|
110
|
+
* whom the product lets link — linking the identity to them.
|
|
111
|
+
*/
|
|
112
|
+
async function oidcSignIn(request, providerId, next) {
|
|
113
|
+
const site = options.siteUrl();
|
|
114
|
+
const signedIn = await sessionFor(request.headers);
|
|
115
|
+
const link = signedIn
|
|
116
|
+
? await (options.linkWhenSignedIn?.(request, signedIn) ?? true)
|
|
117
|
+
: false;
|
|
118
|
+
const answer = await callShared(request, link ? "/oauth2/link" : "/sign-in/oauth2", {
|
|
119
|
+
providerId,
|
|
120
|
+
callbackURL: `${site}${next}`,
|
|
121
|
+
errorCallbackURL: link
|
|
122
|
+
? `${site}${options.linkErrorPath ?? next}`
|
|
123
|
+
: `${site}${options.signInPath}?error=OAuthSignin`,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
url: typeof answer.body.url === "string" ? answer.body.url : null,
|
|
127
|
+
cookies: answer.cookies,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** A hook's failure is logged and never costs the person their sign-in. */
|
|
131
|
+
async function runHook(name, hook) {
|
|
132
|
+
try {
|
|
133
|
+
await hook?.();
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
console.error(`[auth] compat ${name} hook failed: ${error.name}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function credentialSignIn(request, provider, form) {
|
|
140
|
+
let resolved;
|
|
141
|
+
let answer;
|
|
142
|
+
const password = String(form?.get("password") ?? "");
|
|
143
|
+
try {
|
|
144
|
+
resolved = await options.credentials[provider].resolve(form ?? new FormData());
|
|
145
|
+
if (resolved && "refuse" in resolved)
|
|
146
|
+
return refusal(resolved.refuse);
|
|
147
|
+
if (!resolved || !resolved.email || !password)
|
|
148
|
+
return refusal(code("missing"));
|
|
149
|
+
answer = await callShared(request, "/sign-in/email", {
|
|
150
|
+
email: resolved.email.trim().toLowerCase(),
|
|
151
|
+
password,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
// The product's database or the runtime is down: say so, never a 500.
|
|
156
|
+
console.error(`[auth] compat sign-in unavailable: ${error.name}`);
|
|
157
|
+
return refusal(code("unavailable"));
|
|
158
|
+
}
|
|
159
|
+
const email = resolved.email.trim().toLowerCase();
|
|
160
|
+
if (answer.status === 200) {
|
|
161
|
+
const user = answer.body.user;
|
|
162
|
+
if (user?.id) {
|
|
163
|
+
const signedIn = {
|
|
164
|
+
provider,
|
|
165
|
+
email,
|
|
166
|
+
user: { id: user.id, name: user.name },
|
|
167
|
+
};
|
|
168
|
+
await runHook("onSignedIn", options.onSignedIn && (() => options.onSignedIn(signedIn)));
|
|
169
|
+
}
|
|
170
|
+
const next = sameOriginPath(form?.get("callbackUrl"), options.siteUrl(), options.landing);
|
|
171
|
+
return withCookies(Response.json({ url: `${options.siteUrl()}${next}` }), answer.cookies);
|
|
172
|
+
}
|
|
173
|
+
const reason = answer.body.code === "EMAIL_NOT_VERIFIED"
|
|
174
|
+
? "email_unverified"
|
|
175
|
+
: answer.status === 429
|
|
176
|
+
? "rate_limited"
|
|
177
|
+
: answer.status >= 500
|
|
178
|
+
? "unavailable"
|
|
179
|
+
: "credentials";
|
|
180
|
+
const refused = { provider, email, status: answer.status, reason };
|
|
181
|
+
await runHook("onRefused", options.onRefused && (() => options.onRefused(refused)));
|
|
182
|
+
return refusal(code(reason));
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Auth.js's client protocol, answered by the shared runtime. Null for an
|
|
186
|
+
* AccountKit path the screens use, which then goes to the runtime itself.
|
|
187
|
+
*/
|
|
188
|
+
async function handle(request) {
|
|
189
|
+
const url = new URL(request.url);
|
|
190
|
+
const path = url.pathname.replace(/^\/api\/auth/, "");
|
|
191
|
+
const site = options.siteUrl();
|
|
192
|
+
const { method } = request;
|
|
193
|
+
// GET reads the session; POST is useSession().update(), which carries
|
|
194
|
+
// nothing: the session is re-read from the product's rows every request.
|
|
195
|
+
if (path === "/session" && (method === "GET" || method === "POST")) {
|
|
196
|
+
return Response.json(await sessionFor(request.headers), {
|
|
197
|
+
headers: { "Cache-Control": "no-store" },
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (method === "GET" && path === "/csrf") {
|
|
201
|
+
// AccountKit checks the request origin itself; the client needs a value.
|
|
202
|
+
return Response.json({ csrfToken: "accountkit" });
|
|
203
|
+
}
|
|
204
|
+
if (method === "GET" && path === "/providers")
|
|
205
|
+
return Response.json(providers());
|
|
206
|
+
if (method === "POST" && path === "/signout") {
|
|
207
|
+
const form = await request.formData().catch(() => null);
|
|
208
|
+
const answer = await callShared(request, "/sign-out", {});
|
|
209
|
+
const next = sameOriginPath(form?.get("callbackUrl"), site, options.signInPath);
|
|
210
|
+
return withCookies(Response.json({ url: `${site}${next}` }), answer.cookies);
|
|
211
|
+
}
|
|
212
|
+
const credentials = /^\/callback\/([^/]+)$/.exec(path);
|
|
213
|
+
if (method === "POST" &&
|
|
214
|
+
credentials &&
|
|
215
|
+
credentials[1] in options.credentials) {
|
|
216
|
+
return credentialSignIn(request, credentials[1], await request.formData().catch(() => null));
|
|
217
|
+
}
|
|
218
|
+
const signin = /^\/signin\/([^/]+)$/.exec(path);
|
|
219
|
+
if (signin && oidcProviderIds().has(signin[1])) {
|
|
220
|
+
if (method === "POST") {
|
|
221
|
+
const form = await request.formData().catch(() => null);
|
|
222
|
+
const next = sameOriginPath(form?.get("callbackUrl"), site, options.landing);
|
|
223
|
+
const started = await oidcSignIn(request, signin[1], next);
|
|
224
|
+
if (!started.url)
|
|
225
|
+
return refusal(code("unavailable"));
|
|
226
|
+
return withCookies(Response.json({ url: started.url }), started.cookies);
|
|
227
|
+
}
|
|
228
|
+
if (method === "GET") {
|
|
229
|
+
// A server-side signIn arrives here by redirect. Only a navigation the
|
|
230
|
+
// product itself started may begin a round-trip that can link.
|
|
231
|
+
const fetchSite = request.headers.get("sec-fetch-site");
|
|
232
|
+
if (fetchSite && fetchSite !== "same-origin" && fetchSite !== "none") {
|
|
233
|
+
return redirectTo(`${site}${options.signInPath}`);
|
|
234
|
+
}
|
|
235
|
+
const next = sameOriginPath(url.searchParams.get("callbackUrl"), site, options.landing);
|
|
236
|
+
const started = await oidcSignIn(request, signin[1], next);
|
|
237
|
+
if (!started.url)
|
|
238
|
+
return redirectTo(`${site}${options.signInPath}?error=OAuthSignin`);
|
|
239
|
+
return withCookies(redirectTo(started.url), started.cookies);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (method === "GET" && (path === "/signin" || signin)) {
|
|
243
|
+
// next-auth/react sends a provider this runtime does not offer here.
|
|
244
|
+
return redirectTo(`${site}${options.signInPath}?error=OAuthSignin`);
|
|
245
|
+
}
|
|
246
|
+
if (compatPathIsOpen(path))
|
|
247
|
+
return null;
|
|
248
|
+
return Response.json({ error: "not_found" }, { status: 404 });
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
handle,
|
|
252
|
+
/** /api/auth/* with the switch on: the compat answer, else the runtime. */
|
|
253
|
+
route: {
|
|
254
|
+
GET: async (request) => (await handle(request)) ?? runtime.GET(request),
|
|
255
|
+
POST: async (request) => (await handle(request)) ?? runtime.POST(request),
|
|
256
|
+
},
|
|
257
|
+
callShared,
|
|
258
|
+
sessionFor,
|
|
259
|
+
sessionIdFor,
|
|
260
|
+
currentSession,
|
|
261
|
+
oidcSignIn,
|
|
262
|
+
providers,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=nextauth-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextauth-compat.js","sourceRoot":"","sources":["../../src/auth/nextauth-compat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a product runs on the shared runtime yet: `AUTH_RUNTIME=accountkit`.
|
|
3
|
+
* The one switch every product staging AccountKit beside Auth.js reads, so
|
|
4
|
+
* "on" means the same thing everywhere. Free of every dependency, so a proxy
|
|
5
|
+
* or a provider gate can ask without loading the runtime.
|
|
6
|
+
*/
|
|
7
|
+
export declare function sharedRuntimeEnabled(env?: Record<string, string | undefined>): boolean;
|
|
8
|
+
//# sourceMappingURL=switch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/auth/switch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,OAAO,CAET"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a product runs on the shared runtime yet: `AUTH_RUNTIME=accountkit`.
|
|
3
|
+
* The one switch every product staging AccountKit beside Auth.js reads, so
|
|
4
|
+
* "on" means the same thing everywhere. Free of every dependency, so a proxy
|
|
5
|
+
* or a provider gate can ask without loading the runtime.
|
|
6
|
+
*/
|
|
7
|
+
export function sharedRuntimeEnabled(env = process.env) {
|
|
8
|
+
return env.AUTH_RUNTIME === "accountkit";
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=switch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switch.js","sourceRoot":"","sources":["../../src/auth/switch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAA0C,OAAO,CAAC,GAAG;IAErD,OAAO,GAAG,CAAC,YAAY,KAAK,YAAY,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rehearse-import.d.ts","sourceRoot":"","sources":["../../src/bin/rehearse-import.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* accountkit-rehearse-import <import.sql> [--prefix auth_]
|
|
4
|
+
*
|
|
5
|
+
* Rehearses a product's account import against DATABASE_URL in one
|
|
6
|
+
* transaction that always rolls back, and prints only counts as JSON. There is
|
|
7
|
+
* no apply mode. It takes locks even though it rolls back, so never point it
|
|
8
|
+
* at the served database. It uses the product's own driver: `pg` or
|
|
9
|
+
* `postgres`, resolved from the working directory.
|
|
10
|
+
*/
|
|
11
|
+
import { readFile } from "node:fs/promises";
|
|
12
|
+
import { createRequire } from "node:module";
|
|
13
|
+
import { join, resolve } from "node:path";
|
|
14
|
+
import { rehearseImport, } from "../auth/import-rehearsal.js";
|
|
15
|
+
/** A transaction runner over whichever Postgres driver the product has. */
|
|
16
|
+
function driver(url) {
|
|
17
|
+
const load = createRequire(join(process.cwd(), "package.json"));
|
|
18
|
+
try {
|
|
19
|
+
const pg = load("pg");
|
|
20
|
+
const pool = new pg.Pool({
|
|
21
|
+
connectionString: url,
|
|
22
|
+
connectionTimeoutMillis: 5000,
|
|
23
|
+
max: 1,
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
begin: async (work) => {
|
|
27
|
+
const client = await pool.connect();
|
|
28
|
+
try {
|
|
29
|
+
await client.query("BEGIN");
|
|
30
|
+
await work(async (text) => (await client.query(text)).rows);
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
await client.query("ROLLBACK").catch(() => { });
|
|
34
|
+
client.release();
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
end: () => pool.end(),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Not installed here; try postgres-js.
|
|
42
|
+
}
|
|
43
|
+
const postgres = load("postgres");
|
|
44
|
+
const sql = postgres(url, { max: 1, connect_timeout: 5, onnotice: () => { } });
|
|
45
|
+
return {
|
|
46
|
+
begin: async (work) => {
|
|
47
|
+
await sql.begin(async (tx) => {
|
|
48
|
+
await work(async (text) => [...(await tx.unsafe(text))]);
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
end: () => sql.end(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const args = process.argv.slice(2);
|
|
55
|
+
const file = args.find((arg) => !arg.startsWith("--"));
|
|
56
|
+
const prefixAt = args.indexOf("--prefix");
|
|
57
|
+
const prefix = prefixAt >= 0 ? args[prefixAt + 1] : "auth_";
|
|
58
|
+
if (!file) {
|
|
59
|
+
console.error("usage: accountkit-rehearse-import <import.sql> [--prefix auth_]");
|
|
60
|
+
process.exit(2);
|
|
61
|
+
}
|
|
62
|
+
if (!process.env.DATABASE_URL) {
|
|
63
|
+
console.error("DATABASE_URL is required");
|
|
64
|
+
process.exit(2);
|
|
65
|
+
}
|
|
66
|
+
const db = driver(process.env.DATABASE_URL);
|
|
67
|
+
try {
|
|
68
|
+
const counts = await rehearseImport({
|
|
69
|
+
begin: db.begin,
|
|
70
|
+
sql: await readFile(resolve(file), "utf8"),
|
|
71
|
+
prefix,
|
|
72
|
+
});
|
|
73
|
+
console.log(JSON.stringify(counts));
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.error(error.message);
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await db.end();
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=rehearse-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rehearse-import.js","sourceRoot":"","sources":["../../src/bin/rehearse-import.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitbaum/accountkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "One account for every bitbaum product: the account menu, accounts themselves (better-auth: password, magic link, passkeys, 2FA, OIDC) and Sign in with OrangeCat. Styled from @bitbaum/design-tokens.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Cato",
|
|
@@ -75,6 +75,22 @@
|
|
|
75
75
|
"types": "./dist/auth/next.d.ts",
|
|
76
76
|
"default": "./dist/auth/next.js"
|
|
77
77
|
},
|
|
78
|
+
"./auth/nextauth-compat": {
|
|
79
|
+
"types": "./dist/auth/nextauth-compat.d.ts",
|
|
80
|
+
"default": "./dist/auth/nextauth-compat.js"
|
|
81
|
+
},
|
|
82
|
+
"./auth/switch": {
|
|
83
|
+
"types": "./dist/auth/switch.d.ts",
|
|
84
|
+
"default": "./dist/auth/switch.js"
|
|
85
|
+
},
|
|
86
|
+
"./auth/compat-testing": {
|
|
87
|
+
"types": "./dist/auth/compat-testing.d.ts",
|
|
88
|
+
"default": "./dist/auth/compat-testing.js"
|
|
89
|
+
},
|
|
90
|
+
"./auth/import-rehearsal": {
|
|
91
|
+
"types": "./dist/auth/import-rehearsal.d.ts",
|
|
92
|
+
"default": "./dist/auth/import-rehearsal.js"
|
|
93
|
+
},
|
|
78
94
|
"./auth/client": {
|
|
79
95
|
"types": "./dist/auth/client.d.ts",
|
|
80
96
|
"default": "./dist/auth/client.js"
|
|
@@ -169,5 +185,8 @@
|
|
|
169
185
|
"dependencies": {
|
|
170
186
|
"limitkit": "^0.2.1",
|
|
171
187
|
"zod": "^4.6.7"
|
|
188
|
+
},
|
|
189
|
+
"bin": {
|
|
190
|
+
"accountkit-rehearse-import": "./dist/bin/rehearse-import.js"
|
|
172
191
|
}
|
|
173
192
|
}
|