@wtfalch/auth 0.30.0 → 0.31.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 +112 -0
- package/dist/auth.d.ts +29 -1
- package/dist/auth.js +138 -4
- package/dist/broker.d.ts +6 -0
- package/dist/broker.js +5 -0
- package/dist/browser.d.ts +11 -1
- package/dist/browser.js +17 -1
- package/dist/config.d.ts +34 -4
- package/dist/config.js +1 -0
- package/dist/desktop.d.ts +199 -0
- package/dist/desktop.js +528 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/mcp.d.ts +15 -4
- package/dist/mcp.js +24 -10
- package/dist/names.d.ts +5 -3
- package/dist/names.js +15 -5
- package/dist/namespace-browser.js +4 -3
- package/dist/namespace-session.js +2 -2
- package/dist/next.js +1 -1
- package/dist/oidc.d.ts +24 -1
- package/dist/oidc.js +57 -1
- package/dist/onboarding.d.ts +0 -2
- package/dist/onboarding.js +0 -2
- package/dist/person-token.d.ts +44 -10
- package/dist/person-token.js +108 -36
- package/dist/qr-door-scene.d.ts +5 -0
- package/dist/qr-door-scene.js +14 -0
- package/dist/qr-door.js +14 -3
- package/dist/redirect.js +4 -3
- package/dist/sessions.d.ts +0 -5
- package/dist/sessions.js +0 -60
- package/dist/util.d.ts +14 -0
- package/dist/util.js +16 -0
- package/dist/worker-session.d.ts +14 -0
- package/dist/worker-session.js +29 -16
- package/package.json +4 -4
- package/dist/testing.d.ts +0 -57
- package/dist/testing.js +0 -138
package/dist/sessions.d.ts
CHANGED
|
@@ -60,11 +60,6 @@ export interface SessionStore {
|
|
|
60
60
|
/** Live (not revoked, not expired) records for this subject under this binding context, newest first: the devices page. */
|
|
61
61
|
listSubject(context: string, subject: string): Promise<SessionRecord[]>;
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
64
|
-
* One process only. For tests and a single-instance development server: two
|
|
65
|
-
* replicas with separate memory stores do not share revocations.
|
|
66
|
-
*/
|
|
67
|
-
export declare function createMemorySessionStore(): SessionStore;
|
|
68
63
|
/** The table `createPostgresSessionStore` expects. Run it in the app's own migrations. */
|
|
69
64
|
export declare const POSTGRES_SESSION_TABLE = "create table if not exists wtfalch_auth_sessions (\n key text primary key,\n context text not null,\n subject text not null,\n generation integer not null,\n payload text not null,\n expires_at bigint not null,\n lease_until bigint,\n revoked_at bigint,\n created_at bigint,\n last_seen_at bigint,\n user_agent text,\n ip text\n);\ncreate index if not exists wtfalch_auth_sessions_subject on wtfalch_auth_sessions (context, subject);\ncreate index if not exists wtfalch_auth_sessions_expiry on wtfalch_auth_sessions (expires_at);";
|
|
70
65
|
/**
|
package/dist/sessions.js
CHANGED
|
@@ -1,63 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One process only. For tests and a single-instance development server: two
|
|
3
|
-
* replicas with separate memory stores do not share revocations.
|
|
4
|
-
*/
|
|
5
|
-
export function createMemorySessionStore() {
|
|
6
|
-
const records = new Map();
|
|
7
|
-
const sweep = (now) => {
|
|
8
|
-
for (const [key, record] of records)
|
|
9
|
-
if (record.expiresAt <= now)
|
|
10
|
-
records.delete(key);
|
|
11
|
-
};
|
|
12
|
-
return {
|
|
13
|
-
async create(record) {
|
|
14
|
-
sweep(Math.floor(Date.now() / 1000));
|
|
15
|
-
if (records.has(record.key))
|
|
16
|
-
throw new Error('session record already exists');
|
|
17
|
-
records.set(record.key, { ...record });
|
|
18
|
-
},
|
|
19
|
-
async get(key) {
|
|
20
|
-
const record = records.get(key);
|
|
21
|
-
return record ? { ...record } : null;
|
|
22
|
-
},
|
|
23
|
-
async advance(key, generation, next) {
|
|
24
|
-
const record = records.get(key);
|
|
25
|
-
if (!record || record.revokedAt !== null || record.generation !== generation)
|
|
26
|
-
return false;
|
|
27
|
-
records.set(key, {
|
|
28
|
-
...record,
|
|
29
|
-
...next,
|
|
30
|
-
generation: generation + 1,
|
|
31
|
-
lastSeenAt: Math.floor(Date.now() / 1000),
|
|
32
|
-
});
|
|
33
|
-
return true;
|
|
34
|
-
},
|
|
35
|
-
async revoke(key, at) {
|
|
36
|
-
const record = records.get(key);
|
|
37
|
-
if (record && record.revokedAt === null)
|
|
38
|
-
record.revokedAt = at;
|
|
39
|
-
},
|
|
40
|
-
async revokeSubject(context, subject, at) {
|
|
41
|
-
let count = 0;
|
|
42
|
-
for (const record of records.values())
|
|
43
|
-
if (record.context === context && record.subject === subject && record.revokedAt === null) {
|
|
44
|
-
record.revokedAt = at;
|
|
45
|
-
count++;
|
|
46
|
-
}
|
|
47
|
-
return count;
|
|
48
|
-
},
|
|
49
|
-
async listSubject(context, subject) {
|
|
50
|
-
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
51
|
-
return [...records.values()]
|
|
52
|
-
.filter((r) => r.context === context &&
|
|
53
|
-
r.subject === subject &&
|
|
54
|
-
r.revokedAt === null &&
|
|
55
|
-
r.expiresAt > nowSeconds)
|
|
56
|
-
.sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0))
|
|
57
|
-
.map((r) => ({ ...r }));
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
1
|
/** The table `createPostgresSessionStore` expects. Run it in the app's own migrations. */
|
|
62
2
|
export const POSTGRES_SESSION_TABLE = `create table if not exists wtfalch_auth_sessions (
|
|
63
3
|
key text primary key,
|
package/dist/util.d.ts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
/** Helpers shared by the server and browser entry points. No Node-only imports: the browser bundle uses this file too. */
|
|
2
|
+
/** ZITADEL's resource-owner (organisation) claim, on a JWT and on an introspection response alike. */
|
|
3
|
+
export declare const ORG_CLAIM = "urn:zitadel:iam:user:resourceowner:id";
|
|
2
4
|
/** How long an SDK request to the broker or issuer may take before it is abandoned. */
|
|
3
5
|
export declare const FETCH_TIMEOUT_MS = 15000;
|
|
6
|
+
/**
|
|
7
|
+
* The longest a cookie or namespace session may go without the SDK asking
|
|
8
|
+
* the issuer whether the grant behind it is still good. `freshness` (an
|
|
9
|
+
* app's own option, default 5 minutes) already forces that ask on an
|
|
10
|
+
* interval -- this is a hard ceiling under it, so a deactivated person is
|
|
11
|
+
* signed out everywhere within a minute even when an app raised `freshness`
|
|
12
|
+
* past that. The ask itself is the existing refresh grant: a disabled
|
|
13
|
+
* account's refresh token answers 4xx there already, in both session modes.
|
|
14
|
+
*/
|
|
15
|
+
export declare const REVOCATION_RECHECK_SECONDS = 60;
|
|
16
|
+
/** How long a session's id token may age before the SDK asks the issuer again: the app's `freshness`, never more than `REVOCATION_RECHECK_SECONDS`. */
|
|
17
|
+
export declare function recheckSeconds(freshness: number): number;
|
|
4
18
|
/** `signal` if the caller brought one, otherwise a 15 second timeout. */
|
|
5
19
|
export declare function timeoutSignal(signal?: AbortSignal): AbortSignal;
|
|
6
20
|
/** Bytes as unpadded base64url. */
|
package/dist/util.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
/** Helpers shared by the server and browser entry points. No Node-only imports: the browser bundle uses this file too. */
|
|
2
|
+
/** ZITADEL's resource-owner (organisation) claim, on a JWT and on an introspection response alike. */
|
|
3
|
+
export const ORG_CLAIM = 'urn:zitadel:iam:user:resourceowner:id';
|
|
2
4
|
/** How long an SDK request to the broker or issuer may take before it is abandoned. */
|
|
3
5
|
export const FETCH_TIMEOUT_MS = 15_000;
|
|
6
|
+
/**
|
|
7
|
+
* The longest a cookie or namespace session may go without the SDK asking
|
|
8
|
+
* the issuer whether the grant behind it is still good. `freshness` (an
|
|
9
|
+
* app's own option, default 5 minutes) already forces that ask on an
|
|
10
|
+
* interval -- this is a hard ceiling under it, so a deactivated person is
|
|
11
|
+
* signed out everywhere within a minute even when an app raised `freshness`
|
|
12
|
+
* past that. The ask itself is the existing refresh grant: a disabled
|
|
13
|
+
* account's refresh token answers 4xx there already, in both session modes.
|
|
14
|
+
*/
|
|
15
|
+
export const REVOCATION_RECHECK_SECONDS = 60;
|
|
16
|
+
/** How long a session's id token may age before the SDK asks the issuer again: the app's `freshness`, never more than `REVOCATION_RECHECK_SECONDS`. */
|
|
17
|
+
export function recheckSeconds(freshness) {
|
|
18
|
+
return Math.min(freshness, REVOCATION_RECHECK_SECONDS);
|
|
19
|
+
}
|
|
4
20
|
/** `signal` if the caller brought one, otherwise a 15 second timeout. */
|
|
5
21
|
export function timeoutSignal(signal) {
|
|
6
22
|
return signal ?? AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
package/dist/worker-session.d.ts
CHANGED
|
@@ -29,6 +29,10 @@ export interface WorkerSignedIn {
|
|
|
29
29
|
*/
|
|
30
30
|
setCookies: string[];
|
|
31
31
|
}
|
|
32
|
+
export interface WorkerSessionState {
|
|
33
|
+
user: WorkerSignedIn | null;
|
|
34
|
+
clearCookies: string[];
|
|
35
|
+
}
|
|
32
36
|
export interface WorkerSession {
|
|
33
37
|
/** Redirects to the issuer. `register` opens registration, `returnTo` is a path on this app. */
|
|
34
38
|
signIn(req: Request, o?: {
|
|
@@ -38,6 +42,16 @@ export interface WorkerSession {
|
|
|
38
42
|
/** Route `redirectPath` here. Always a redirect: to `returnTo` on success, to `/?auth_error=<reason>` otherwise. */
|
|
39
43
|
callback(req: Request): Promise<Response>;
|
|
40
44
|
currentUser(req: Request): Promise<WorkerSignedIn | null>;
|
|
45
|
+
/**
|
|
46
|
+
* `currentUser`, plus what to do about a session that is dead. `clearCookies`
|
|
47
|
+
* are `Set-Cookie` header values that remove a session cookie the SDK found
|
|
48
|
+
* unusable (a refresh that came back for another organisation, a token it
|
|
49
|
+
* rejected). Add them to the app's response when `user` is null, or the same
|
|
50
|
+
* dead cookie is tried again on every request. Empty when the person is
|
|
51
|
+
* signed in, has no cookie, or the failure may pass (the issuer refused a
|
|
52
|
+
* refresh, or could not be reached): those keep the cookie.
|
|
53
|
+
*/
|
|
54
|
+
readSession(req: Request): Promise<WorkerSessionState>;
|
|
41
55
|
/** POST from the app's own origin only. */
|
|
42
56
|
signOut(req: Request): Promise<Response>;
|
|
43
57
|
}
|
package/dist/worker-session.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createAuth } from './auth.js';
|
|
2
2
|
import { resolveOptions } from './config.js';
|
|
3
3
|
import { FETCH_TIMEOUT_MS } from './util.js';
|
|
4
|
+
/** Origins one isolate keeps an `Auth` for. */
|
|
5
|
+
const MAX_ORIGINS = 64;
|
|
4
6
|
const CALLBACK = /^(\/[A-Za-z0-9._~-]+)+\/callback$/;
|
|
5
7
|
/** The fetch the SDK is given: every outside call (discovery, token, JWKS, revoke) is abandoned after FETCH_TIMEOUT_MS unless the caller set its own signal. */
|
|
6
8
|
function withTimeout(fetchImpl) {
|
|
@@ -39,14 +41,21 @@ export function createWorkerSession(opts) {
|
|
|
39
41
|
// A bad secret or client is a startup error, not the first visitor's.
|
|
40
42
|
resolveOptions(config('https://placeholder.invalid'));
|
|
41
43
|
// One Auth per origin, so the discovery document, JWKS and refresh dedupe are shared across requests in an isolate.
|
|
44
|
+
// On a wildcard route the Host header is the caller's, so the map is capped and the least recently used origin dropped:
|
|
45
|
+
// an evicted origin only loses its caches.
|
|
42
46
|
const byOrigin = new Map();
|
|
43
47
|
const authFor = (req) => {
|
|
44
48
|
const origin = new URL(req.url).origin;
|
|
45
49
|
let auth = byOrigin.get(origin);
|
|
46
|
-
if (
|
|
50
|
+
if (auth) {
|
|
51
|
+
byOrigin.delete(origin);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
47
54
|
auth = createAuth(config(origin));
|
|
48
|
-
byOrigin.
|
|
55
|
+
if (byOrigin.size >= MAX_ORIGINS)
|
|
56
|
+
byOrigin.delete(byOrigin.keys().next().value);
|
|
49
57
|
}
|
|
58
|
+
byOrigin.set(origin, auth);
|
|
50
59
|
return auth;
|
|
51
60
|
};
|
|
52
61
|
// An outside failure is logged by its class only: messages can carry URLs and token fragments.
|
|
@@ -54,6 +63,22 @@ export function createWorkerSession(opts) {
|
|
|
54
63
|
console.error(`@wtfalch/auth: worker session ${what} failed`, error instanceof Error ? error.name : 'unknown');
|
|
55
64
|
return new Response('Sign-in is unavailable', { status: 503 });
|
|
56
65
|
};
|
|
66
|
+
const readSession = async (req) => {
|
|
67
|
+
try {
|
|
68
|
+
const { user, cookies } = await authFor(req).read(req);
|
|
69
|
+
const headers = cookies.map((c) => c.header);
|
|
70
|
+
if (!user)
|
|
71
|
+
return { user: null, clearCookies: headers };
|
|
72
|
+
return {
|
|
73
|
+
user: { userId: user.id, orgId: user.organizationId, setCookies: headers },
|
|
74
|
+
clearCookies: [],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
unavailable('session read', error);
|
|
79
|
+
return { user: null, clearCookies: [] };
|
|
80
|
+
}
|
|
81
|
+
};
|
|
57
82
|
return {
|
|
58
83
|
async signIn(req, o = {}) {
|
|
59
84
|
const url = new URL(`${basePath}/start`, req.url);
|
|
@@ -76,21 +101,9 @@ export function createWorkerSession(opts) {
|
|
|
76
101
|
return unavailable('callback', error);
|
|
77
102
|
}
|
|
78
103
|
},
|
|
104
|
+
readSession,
|
|
79
105
|
async currentUser(req) {
|
|
80
|
-
|
|
81
|
-
const { user, cookies } = await authFor(req).read(req);
|
|
82
|
-
if (!user)
|
|
83
|
-
return null;
|
|
84
|
-
return {
|
|
85
|
-
userId: user.id,
|
|
86
|
-
orgId: user.organizationId,
|
|
87
|
-
setCookies: cookies.map((c) => c.header),
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
unavailable('session read', error);
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
106
|
+
return (await readSession(req)).user;
|
|
94
107
|
},
|
|
95
108
|
async signOut(req) {
|
|
96
109
|
if (req.method !== 'POST')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtfalch/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "Sign in against a self-hosted ZITADEL issuer: a server session for a Next.js app, and a browser client with silent single sign-on across subdomains.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -62,9 +62,9 @@
|
|
|
62
62
|
"types": "./dist/qr-door.d.ts",
|
|
63
63
|
"default": "./dist/qr-door.js"
|
|
64
64
|
},
|
|
65
|
-
"./
|
|
66
|
-
"types": "./dist/
|
|
67
|
-
"default": "./dist/
|
|
65
|
+
"./desktop": {
|
|
66
|
+
"types": "./dist/desktop.d.ts",
|
|
67
|
+
"default": "./dist/desktop.js"
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"sideEffects": false,
|
package/dist/testing.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { Auth, User } from './auth.js';
|
|
2
|
-
import type { NextAuth } from './next.js';
|
|
3
|
-
export declare function setSessionUser(user: User | null): void;
|
|
4
|
-
/** A User shaped like the SDK's, for `setSessionUser`. */
|
|
5
|
-
export declare function testUser(id: string, overrides?: Partial<User>): User;
|
|
6
|
-
export declare function getUser(): Promise<User | null>;
|
|
7
|
-
export declare function requireUser(_next?: string): Promise<User>;
|
|
8
|
-
export declare const requireFreshUser: NextAuth['requireFreshUser'];
|
|
9
|
-
export declare const handlers: () => never;
|
|
10
|
-
export declare const proxy: () => never;
|
|
11
|
-
export declare const authRequest: () => never;
|
|
12
|
-
export declare const signIn: () => never;
|
|
13
|
-
export declare const signUp: () => never;
|
|
14
|
-
export declare const requestPasswordReset: () => never;
|
|
15
|
-
export declare const resetPassword: () => never;
|
|
16
|
-
export declare const sendLink: () => never;
|
|
17
|
-
export declare const resendVerification: () => never;
|
|
18
|
-
export declare const setNewPassword: () => never;
|
|
19
|
-
export declare const invite: () => never;
|
|
20
|
-
export declare const people: () => never;
|
|
21
|
-
export declare const setPersonActive: () => never;
|
|
22
|
-
export declare const adminResetPassword: () => never;
|
|
23
|
-
export declare const sessions: () => never;
|
|
24
|
-
export declare const endSession: () => never;
|
|
25
|
-
export declare const startPasskeyRegistration: () => never;
|
|
26
|
-
export declare const finishPasskeyRegistration: () => never;
|
|
27
|
-
export declare const startEmailChange: () => never;
|
|
28
|
-
export declare const completeEmailChange: () => never;
|
|
29
|
-
export declare const changePassword: () => never;
|
|
30
|
-
export declare const passkeys: () => never;
|
|
31
|
-
export declare const deletePasskey: () => never;
|
|
32
|
-
export declare const startPasskeySignIn: () => never;
|
|
33
|
-
export declare const finishPasskeySignIn: () => never;
|
|
34
|
-
export declare const startQrSignIn: () => never;
|
|
35
|
-
export declare const pollQrSignIn: () => never;
|
|
36
|
-
/**
|
|
37
|
-
* The core SDK instance, as far as a device sign-in module reaches into it.
|
|
38
|
-
*
|
|
39
|
-
* The real one talks to the issuer. This one records what was asked and
|
|
40
|
-
* answers with whatever a test set, so a device/link sign-in flow can be
|
|
41
|
-
* exercised against a real database without one. Only the members named
|
|
42
|
-
* here are stubbed; anything else read off `auth` is a mistake worth a loud
|
|
43
|
-
* one.
|
|
44
|
-
*/
|
|
45
|
-
export declare const sentLinks: {
|
|
46
|
-
email: string;
|
|
47
|
-
next?: string;
|
|
48
|
-
}[];
|
|
49
|
-
export declare function setFollowLinkResult(result: unknown): void;
|
|
50
|
-
export declare function setCookieUser(user: User | null): void;
|
|
51
|
-
export declare const auth: Auth;
|
|
52
|
-
/**
|
|
53
|
-
* Every member of `NextAuth`, so the compiler fails here when the real
|
|
54
|
-
* surface gains one this stub lacks. `export const { getUser } = nextAuthStub`
|
|
55
|
-
* is the same as importing the named exports above.
|
|
56
|
-
*/
|
|
57
|
-
export declare const nextAuthStub: NextAuth;
|
package/dist/testing.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A stub for whatever `@/lib/auth` resolves to in an app's integration test
|
|
3
|
-
* tier. The real module reads a sealed cookie through `next/headers`, which
|
|
4
|
-
* does not load outside a Next.js build; this one answers with whatever
|
|
5
|
-
* `setSessionUser` last set, so a test can be "signed in" as one person,
|
|
6
|
-
* call the app's own authorization logic for real, then sign in as another.
|
|
7
|
-
* Nothing here talks to the issuer.
|
|
8
|
-
*
|
|
9
|
-
* Alias the app's auth module to `@wtfalch/auth/testing` for that tier (for
|
|
10
|
-
* example in a vitest config's `resolve.alias`), or re-export from it.
|
|
11
|
-
*/
|
|
12
|
-
let current = null;
|
|
13
|
-
export function setSessionUser(user) {
|
|
14
|
-
current = user;
|
|
15
|
-
}
|
|
16
|
-
/** A User shaped like the SDK's, for `setSessionUser`. */
|
|
17
|
-
export function testUser(id, overrides = {}) {
|
|
18
|
-
return {
|
|
19
|
-
id,
|
|
20
|
-
email: `${id}@example.test`,
|
|
21
|
-
emailVerified: true,
|
|
22
|
-
name: `Person ${id}`,
|
|
23
|
-
givenName: null,
|
|
24
|
-
familyName: null,
|
|
25
|
-
preferredUsername: null,
|
|
26
|
-
organizationId: 'org-test',
|
|
27
|
-
// Never fresh, which is what a stubbed session should be: the issuer only
|
|
28
|
-
// owes `auth_time` when the request asked for it, and nothing here asks.
|
|
29
|
-
authTime: null,
|
|
30
|
-
claims: {},
|
|
31
|
-
...overrides,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
export async function getUser() {
|
|
35
|
-
return current;
|
|
36
|
-
}
|
|
37
|
-
export async function requireUser(_next) {
|
|
38
|
-
if (!current)
|
|
39
|
-
throw new Error('requireUser: no session set; call setSessionUser first');
|
|
40
|
-
return current;
|
|
41
|
-
}
|
|
42
|
-
export const requireFreshUser = async () => requireUser();
|
|
43
|
-
function unavailable(name) {
|
|
44
|
-
return () => {
|
|
45
|
-
throw new Error(`${name} is not available in the integration tier`);
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
export const handlers = unavailable('handlers');
|
|
49
|
-
export const proxy = unavailable('proxy');
|
|
50
|
-
export const authRequest = unavailable('authRequest');
|
|
51
|
-
export const signIn = unavailable('signIn');
|
|
52
|
-
export const signUp = unavailable('signUp');
|
|
53
|
-
export const requestPasswordReset = unavailable('requestPasswordReset');
|
|
54
|
-
export const resetPassword = unavailable('resetPassword');
|
|
55
|
-
export const sendLink = unavailable('sendLink');
|
|
56
|
-
export const resendVerification = unavailable('resendVerification');
|
|
57
|
-
export const setNewPassword = unavailable('setNewPassword');
|
|
58
|
-
export const invite = unavailable('invite');
|
|
59
|
-
export const people = unavailable('people');
|
|
60
|
-
export const setPersonActive = unavailable('setPersonActive');
|
|
61
|
-
export const adminResetPassword = unavailable('adminResetPassword');
|
|
62
|
-
export const sessions = unavailable('sessions');
|
|
63
|
-
export const endSession = unavailable('endSession');
|
|
64
|
-
export const startPasskeyRegistration = unavailable('startPasskeyRegistration');
|
|
65
|
-
export const finishPasskeyRegistration = unavailable('finishPasskeyRegistration');
|
|
66
|
-
export const startEmailChange = unavailable('startEmailChange');
|
|
67
|
-
export const completeEmailChange = unavailable('completeEmailChange');
|
|
68
|
-
export const changePassword = unavailable('changePassword');
|
|
69
|
-
export const passkeys = unavailable('passkeys');
|
|
70
|
-
export const deletePasskey = unavailable('deletePasskey');
|
|
71
|
-
export const startPasskeySignIn = unavailable('startPasskeySignIn');
|
|
72
|
-
export const finishPasskeySignIn = unavailable('finishPasskeySignIn');
|
|
73
|
-
export const startQrSignIn = unavailable('startQrSignIn');
|
|
74
|
-
export const pollQrSignIn = unavailable('pollQrSignIn');
|
|
75
|
-
/**
|
|
76
|
-
* The core SDK instance, as far as a device sign-in module reaches into it.
|
|
77
|
-
*
|
|
78
|
-
* The real one talks to the issuer. This one records what was asked and
|
|
79
|
-
* answers with whatever a test set, so a device/link sign-in flow can be
|
|
80
|
-
* exercised against a real database without one. Only the members named
|
|
81
|
-
* here are stubbed; anything else read off `auth` is a mistake worth a loud
|
|
82
|
-
* one.
|
|
83
|
-
*/
|
|
84
|
-
export const sentLinks = [];
|
|
85
|
-
let linkResult = { ok: false, error: 'invalid_code', message: 'no result set' };
|
|
86
|
-
let cookieUser = null;
|
|
87
|
-
export function setFollowLinkResult(result) {
|
|
88
|
-
linkResult = result;
|
|
89
|
-
}
|
|
90
|
-
export function setCookieUser(user) {
|
|
91
|
-
cookieUser = user;
|
|
92
|
-
}
|
|
93
|
-
export const auth = {
|
|
94
|
-
sessionCookieName: '__Host-wtfalch_auth',
|
|
95
|
-
sendLink: async (email, next) => {
|
|
96
|
-
sentLinks.push({ email, next });
|
|
97
|
-
},
|
|
98
|
-
followLink: async () => linkResult,
|
|
99
|
-
readCookie: async () => ({ user: cookieUser, cookies: [] }),
|
|
100
|
-
};
|
|
101
|
-
/**
|
|
102
|
-
* Every member of `NextAuth`, so the compiler fails here when the real
|
|
103
|
-
* surface gains one this stub lacks. `export const { getUser } = nextAuthStub`
|
|
104
|
-
* is the same as importing the named exports above.
|
|
105
|
-
*/
|
|
106
|
-
export const nextAuthStub = {
|
|
107
|
-
auth,
|
|
108
|
-
handlers: handlers,
|
|
109
|
-
proxy,
|
|
110
|
-
getUser,
|
|
111
|
-
requireUser,
|
|
112
|
-
requireFreshUser,
|
|
113
|
-
authRequest,
|
|
114
|
-
signIn,
|
|
115
|
-
setNewPassword,
|
|
116
|
-
signUp,
|
|
117
|
-
resendVerification,
|
|
118
|
-
requestPasswordReset,
|
|
119
|
-
sendLink,
|
|
120
|
-
invite,
|
|
121
|
-
people,
|
|
122
|
-
setPersonActive,
|
|
123
|
-
adminResetPassword,
|
|
124
|
-
sessions,
|
|
125
|
-
endSession,
|
|
126
|
-
resetPassword,
|
|
127
|
-
startPasskeyRegistration,
|
|
128
|
-
finishPasskeyRegistration,
|
|
129
|
-
startEmailChange,
|
|
130
|
-
completeEmailChange,
|
|
131
|
-
changePassword,
|
|
132
|
-
passkeys,
|
|
133
|
-
deletePasskey,
|
|
134
|
-
startPasskeySignIn,
|
|
135
|
-
finishPasskeySignIn,
|
|
136
|
-
startQrSignIn,
|
|
137
|
-
pollQrSignIn,
|
|
138
|
-
};
|