better-auth 1.6.16 → 1.6.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.d.mts +2 -2
- package/dist/api/index.mjs +3 -4
- package/dist/api/middlewares/origin-check.mjs +5 -1
- package/dist/api/rate-limiter/index.mjs +259 -73
- package/dist/api/routes/account.mjs +22 -7
- package/dist/api/routes/callback.mjs +2 -2
- package/dist/api/routes/index.d.mts +1 -1
- package/dist/api/routes/password.mjs +3 -4
- package/dist/api/routes/session.d.mts +12 -1
- package/dist/api/routes/session.mjs +13 -1
- package/dist/api/routes/sign-in.mjs +5 -5
- package/dist/api/routes/sign-up.mjs +2 -2
- package/dist/api/routes/update-session.mjs +2 -3
- package/dist/api/routes/update-user.mjs +10 -12
- package/dist/auth/base.mjs +11 -7
- package/dist/client/equality.d.mts +19 -0
- package/dist/client/equality.mjs +42 -0
- package/dist/client/index.d.mts +5 -4
- package/dist/client/index.mjs +2 -1
- package/dist/client/lynx/index.d.mts +4 -2
- package/dist/client/path-to-object.d.mts +5 -2
- package/dist/client/plugins/index.d.mts +4 -1
- package/dist/client/plugins/index.mjs +4 -1
- package/dist/client/query.d.mts +4 -3
- package/dist/client/query.mjs +27 -17
- package/dist/client/react/index.d.mts +4 -2
- package/dist/client/session-atom.mjs +129 -4
- package/dist/client/session-refresh.d.mts +3 -18
- package/dist/client/session-refresh.mjs +38 -49
- package/dist/client/solid/index.d.mts +4 -2
- package/dist/client/svelte/index.d.mts +4 -2
- package/dist/client/types.d.mts +27 -16
- package/dist/client/vanilla.d.mts +4 -2
- package/dist/client/vue/index.d.mts +4 -2
- package/dist/context/create-context.mjs +2 -1
- package/dist/context/store-capabilities.mjs +12 -0
- package/dist/cookies/index.mjs +25 -2
- package/dist/db/internal-adapter.mjs +51 -0
- package/dist/package.mjs +1 -1
- package/dist/plugins/access/access.mjs +49 -19
- package/dist/plugins/admin/routes.mjs +10 -3
- package/dist/plugins/captcha/constants.mjs +8 -1
- package/dist/plugins/captcha/index.mjs +8 -2
- package/dist/plugins/captcha/types.d.mts +21 -0
- package/dist/plugins/captcha/verify-handlers/captchafox.mjs +2 -0
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +7 -2
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +7 -2
- package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +2 -0
- package/dist/plugins/device-authorization/routes.mjs +16 -9
- package/dist/plugins/email-otp/routes.mjs +22 -52
- package/dist/plugins/generic-oauth/index.mjs +7 -2
- package/dist/plugins/generic-oauth/routes.mjs +16 -12
- package/dist/plugins/haveibeenpwned/index.d.mts +1 -1
- package/dist/plugins/haveibeenpwned/index.mjs +5 -1
- package/dist/plugins/index.d.mts +6 -2
- package/dist/plugins/index.mjs +4 -1
- package/dist/plugins/jwt/index.mjs +2 -2
- package/dist/plugins/mcp/client/index.mjs +1 -0
- package/dist/plugins/mcp/index.mjs +8 -0
- package/dist/plugins/multi-session/index.mjs +7 -5
- package/dist/plugins/oauth-popup/client.d.mts +82 -0
- package/dist/plugins/oauth-popup/client.mjs +203 -0
- package/dist/plugins/oauth-popup/constants.d.mts +11 -0
- package/dist/plugins/oauth-popup/constants.mjs +11 -0
- package/dist/plugins/oauth-popup/error-codes.d.mts +11 -0
- package/dist/plugins/oauth-popup/error-codes.mjs +10 -0
- package/dist/plugins/oauth-popup/index.d.mts +67 -0
- package/dist/plugins/oauth-popup/index.mjs +227 -0
- package/dist/plugins/oauth-popup/types.d.mts +30 -0
- package/dist/plugins/oauth-proxy/index.mjs +2 -2
- package/dist/plugins/oauth-proxy/utils.mjs +16 -2
- package/dist/plugins/oidc-provider/index.mjs +10 -0
- package/dist/plugins/one-tap/client.mjs +12 -6
- package/dist/plugins/one-tap/index.d.mts +1 -0
- package/dist/plugins/one-tap/index.mjs +9 -5
- package/dist/plugins/one-time-token/index.mjs +1 -3
- package/dist/plugins/open-api/generator.d.mts +66 -57
- package/dist/plugins/open-api/generator.mjs +185 -67
- package/dist/plugins/open-api/index.d.mts +2 -2
- package/dist/plugins/organization/adapter.d.mts +29 -1
- package/dist/plugins/organization/adapter.mjs +66 -6
- package/dist/plugins/organization/routes/crud-invites.mjs +49 -34
- package/dist/plugins/organization/routes/crud-members.mjs +42 -6
- package/dist/plugins/organization/routes/crud-team.mjs +36 -3
- package/dist/plugins/phone-number/routes.mjs +41 -36
- package/dist/plugins/siwe/index.mjs +2 -3
- package/dist/plugins/two-factor/backup-codes/index.mjs +1 -1
- package/dist/plugins/two-factor/otp/index.mjs +11 -13
- package/dist/plugins/two-factor/totp/index.mjs +1 -1
- package/dist/plugins/two-factor/verify-two-factor.mjs +6 -2
- package/dist/plugins/username/index.mjs +6 -6
- package/dist/test-utils/test-instance.d.mts +26 -23
- package/package.json +9 -9
|
@@ -1,21 +1,146 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isJsonEqual, withEquality } from "./equality.mjs";
|
|
2
2
|
import { createSessionRefreshManager } from "./session-refresh.mjs";
|
|
3
3
|
import { atom, onMount } from "nanostores";
|
|
4
4
|
//#region src/client/session-atom.ts
|
|
5
|
+
const isServer = () => typeof window === "undefined";
|
|
6
|
+
/**
|
|
7
|
+
* Normalize $fetch response: `throw: true` returns data directly,
|
|
8
|
+
* otherwise `{ data, error }`.
|
|
9
|
+
*/
|
|
10
|
+
function normalizeSessionResponse(res) {
|
|
11
|
+
if (typeof res === "object" && res !== null && "data" in res && "error" in res) return res;
|
|
12
|
+
return {
|
|
13
|
+
data: res,
|
|
14
|
+
error: null
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function normalizeSessionData(data) {
|
|
18
|
+
if (!data) return null;
|
|
19
|
+
if (data.session === null && data.user === null) return null;
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
22
|
+
function isSessionAtomEqual(a, b) {
|
|
23
|
+
return isJsonEqual(a.data, b.data) && a.error === b.error && a.isPending === b.isPending && a.isRefetching === b.isRefetching && a.refetch === b.refetch;
|
|
24
|
+
}
|
|
5
25
|
function getSessionAtom($fetch, options) {
|
|
6
26
|
const $signal = atom(false);
|
|
7
|
-
|
|
27
|
+
let abortController;
|
|
28
|
+
const refetch = (queryParams) => fetchSession(queryParams);
|
|
29
|
+
const session = atom({
|
|
30
|
+
data: null,
|
|
31
|
+
error: null,
|
|
32
|
+
isPending: true,
|
|
33
|
+
isRefetching: false,
|
|
34
|
+
refetch
|
|
35
|
+
});
|
|
36
|
+
withEquality(session, isSessionAtomEqual);
|
|
37
|
+
const settleAbortedFetch = (controller) => {
|
|
38
|
+
if (abortController !== controller) return;
|
|
39
|
+
const current = session.get();
|
|
40
|
+
abortController = void 0;
|
|
41
|
+
if (!current.isPending && !current.isRefetching) return;
|
|
42
|
+
session.set({
|
|
43
|
+
...current,
|
|
44
|
+
isPending: false,
|
|
45
|
+
isRefetching: false,
|
|
46
|
+
refetch
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
const fetchSession = async (queryParams) => {
|
|
50
|
+
abortController?.abort();
|
|
51
|
+
const controller = new AbortController();
|
|
52
|
+
abortController = controller;
|
|
53
|
+
const current = session.get();
|
|
54
|
+
session.set({
|
|
55
|
+
...current,
|
|
56
|
+
isPending: current.data === null,
|
|
57
|
+
isRefetching: true,
|
|
58
|
+
error: null,
|
|
59
|
+
refetch
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
const res = await $fetch("/get-session", {
|
|
63
|
+
method: "GET",
|
|
64
|
+
query: queryParams?.query,
|
|
65
|
+
signal: controller.signal
|
|
66
|
+
});
|
|
67
|
+
if (controller.signal.aborted) {
|
|
68
|
+
settleAbortedFetch(controller);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
let { data, error } = normalizeSessionResponse(res);
|
|
72
|
+
if (data?.needsRefresh) try {
|
|
73
|
+
const refreshRes = await $fetch("/get-session", {
|
|
74
|
+
method: "POST",
|
|
75
|
+
signal: controller.signal
|
|
76
|
+
});
|
|
77
|
+
if (controller.signal.aborted) {
|
|
78
|
+
settleAbortedFetch(controller);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
({data, error} = normalizeSessionResponse(refreshRes));
|
|
82
|
+
} catch {
|
|
83
|
+
if (controller.signal.aborted) {
|
|
84
|
+
settleAbortedFetch(controller);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (error) {
|
|
89
|
+
const latest = session.get();
|
|
90
|
+
const isUnauthorized = error?.status === 401;
|
|
91
|
+
session.set({
|
|
92
|
+
data: isUnauthorized ? null : latest.data,
|
|
93
|
+
error,
|
|
94
|
+
isPending: false,
|
|
95
|
+
isRefetching: false,
|
|
96
|
+
refetch
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const sessionData = normalizeSessionData(data);
|
|
101
|
+
const current = session.get();
|
|
102
|
+
const stableData = current.data != null && sessionData != null && isJsonEqual(current.data, sessionData) ? current.data : sessionData;
|
|
103
|
+
session.set({
|
|
104
|
+
data: stableData,
|
|
105
|
+
error: null,
|
|
106
|
+
isPending: false,
|
|
107
|
+
isRefetching: false,
|
|
108
|
+
refetch
|
|
109
|
+
});
|
|
110
|
+
} catch (fetchError) {
|
|
111
|
+
if (controller.signal.aborted) {
|
|
112
|
+
settleAbortedFetch(controller);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const latest = session.get();
|
|
116
|
+
session.set({
|
|
117
|
+
data: latest.data,
|
|
118
|
+
error: fetchError,
|
|
119
|
+
isPending: false,
|
|
120
|
+
isRefetching: false,
|
|
121
|
+
refetch
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
};
|
|
8
125
|
let broadcastSessionUpdate = () => {};
|
|
9
126
|
onMount(session, () => {
|
|
127
|
+
let timeoutId;
|
|
128
|
+
if (!isServer()) timeoutId = setTimeout(() => {
|
|
129
|
+
fetchSession();
|
|
130
|
+
}, 0);
|
|
10
131
|
const refreshManager = createSessionRefreshManager({
|
|
11
|
-
|
|
132
|
+
fetchSession,
|
|
133
|
+
shouldPollSession: () => session.get().data != null,
|
|
12
134
|
sessionSignal: $signal,
|
|
13
|
-
$fetch,
|
|
14
135
|
options
|
|
15
136
|
});
|
|
16
137
|
refreshManager.init();
|
|
17
138
|
broadcastSessionUpdate = refreshManager.broadcastSessionUpdate;
|
|
18
139
|
return () => {
|
|
140
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
141
|
+
const controller = abortController;
|
|
142
|
+
controller?.abort();
|
|
143
|
+
if (controller) settleAbortedFetch(controller);
|
|
19
144
|
refreshManager.cleanup();
|
|
20
145
|
};
|
|
21
146
|
});
|
|
@@ -1,28 +1,13 @@
|
|
|
1
|
-
import { Session, User } from "../types/models.mjs";
|
|
2
|
-
import { AuthQueryAtom } from "./query.mjs";
|
|
3
1
|
import { BetterAuthClientOptions } from "@better-auth/core";
|
|
4
2
|
import { WritableAtom } from "nanostores";
|
|
5
|
-
import { BetterFetch } from "@better-fetch/fetch";
|
|
6
3
|
|
|
7
4
|
//#region src/client/session-refresh.d.ts
|
|
8
5
|
interface SessionRefreshOptions {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
session: Session;
|
|
12
|
-
} & Record<string, any>>;
|
|
6
|
+
fetchSession: () => Promise<void>;
|
|
7
|
+
shouldPollSession?: () => boolean;
|
|
13
8
|
sessionSignal: WritableAtom<boolean>;
|
|
14
|
-
$fetch: BetterFetch;
|
|
15
9
|
options?: BetterAuthClientOptions | undefined;
|
|
16
10
|
}
|
|
17
|
-
type SessionResponse = ({
|
|
18
|
-
session: null;
|
|
19
|
-
user: null;
|
|
20
|
-
needsRefresh?: boolean;
|
|
21
|
-
} | {
|
|
22
|
-
session: Session;
|
|
23
|
-
user: User;
|
|
24
|
-
needsRefresh?: boolean;
|
|
25
|
-
}) & Record<string, any>;
|
|
26
11
|
declare function createSessionRefreshManager(opts: SessionRefreshOptions): {
|
|
27
12
|
init: () => void;
|
|
28
13
|
cleanup: () => void;
|
|
@@ -32,4 +17,4 @@ declare function createSessionRefreshManager(opts: SessionRefreshOptions): {
|
|
|
32
17
|
broadcastSessionUpdate: (trigger: "signout" | "getSession" | "updateUser") => void;
|
|
33
18
|
};
|
|
34
19
|
//#endregion
|
|
35
|
-
export { SessionRefreshOptions,
|
|
20
|
+
export { SessionRefreshOptions, createSessionRefreshManager };
|
|
@@ -4,28 +4,17 @@ import { getGlobalOnlineManager } from "./online-manager.mjs";
|
|
|
4
4
|
//#region src/client/session-refresh.ts
|
|
5
5
|
const now = () => Math.floor(Date.now() / 1e3);
|
|
6
6
|
/**
|
|
7
|
-
* Normalize $fetch response: `throw: true` returns data directly, otherwise `{ data, error }`.
|
|
8
|
-
*/
|
|
9
|
-
function normalizeSessionResponse(res) {
|
|
10
|
-
if (typeof res === "object" && res !== null && "data" in res && "error" in res) return res;
|
|
11
|
-
return {
|
|
12
|
-
data: res,
|
|
13
|
-
error: null
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
7
|
* Rate limit: don't refetch on focus if a session request was made within this many seconds
|
|
18
8
|
*/
|
|
19
9
|
const FOCUS_REFETCH_RATE_LIMIT_SECONDS = 5;
|
|
20
10
|
function createSessionRefreshManager(opts) {
|
|
21
|
-
const {
|
|
11
|
+
const { fetchSession, shouldPollSession = () => true, sessionSignal, options = {} } = opts;
|
|
22
12
|
const refetchInterval = options.sessionOptions?.refetchInterval ?? 0;
|
|
23
13
|
const refetchOnWindowFocus = options.sessionOptions?.refetchOnWindowFocus ?? true;
|
|
24
14
|
const refetchWhenOffline = options.sessionOptions?.refetchWhenOffline ?? false;
|
|
25
15
|
const state = {
|
|
26
|
-
|
|
27
|
-
lastSessionRequest: 0
|
|
28
|
-
cachedSession: void 0
|
|
16
|
+
isInitialized: false,
|
|
17
|
+
lastSessionRequest: 0
|
|
29
18
|
};
|
|
30
19
|
const shouldRefetch = () => {
|
|
31
20
|
return refetchWhenOffline || getGlobalOnlineManager().isOnline;
|
|
@@ -33,45 +22,21 @@ function createSessionRefreshManager(opts) {
|
|
|
33
22
|
const triggerRefetch = (event) => {
|
|
34
23
|
if (!shouldRefetch()) return;
|
|
35
24
|
if (event?.event === "storage") {
|
|
36
|
-
|
|
37
|
-
sessionSignal.set(!sessionSignal.get());
|
|
25
|
+
fetchSession();
|
|
38
26
|
return;
|
|
39
27
|
}
|
|
40
|
-
const currentSession = sessionAtom.get();
|
|
41
|
-
const fetchSessionWithRefresh = () => {
|
|
42
|
-
state.lastSessionRequest = now();
|
|
43
|
-
$fetch("/get-session").then(async (res) => {
|
|
44
|
-
let { data, error } = normalizeSessionResponse(res);
|
|
45
|
-
if (data?.needsRefresh) try {
|
|
46
|
-
const refreshRes = await $fetch("/get-session", { method: "POST" });
|
|
47
|
-
({data, error} = normalizeSessionResponse(refreshRes));
|
|
48
|
-
} catch {}
|
|
49
|
-
const sessionData = data?.session && data?.user ? data : null;
|
|
50
|
-
sessionAtom.set({
|
|
51
|
-
...currentSession,
|
|
52
|
-
data: sessionData,
|
|
53
|
-
error
|
|
54
|
-
});
|
|
55
|
-
state.lastSync = now();
|
|
56
|
-
sessionSignal.set(!sessionSignal.get());
|
|
57
|
-
}).catch(() => {});
|
|
58
|
-
};
|
|
59
28
|
if (event?.event === "poll") {
|
|
60
|
-
|
|
29
|
+
state.lastSessionRequest = now();
|
|
30
|
+
fetchSession();
|
|
61
31
|
return;
|
|
62
32
|
}
|
|
63
33
|
if (event?.event === "visibilitychange") {
|
|
64
34
|
if (now() - state.lastSessionRequest < FOCUS_REFETCH_RATE_LIMIT_SECONDS) return;
|
|
65
35
|
state.lastSessionRequest = now();
|
|
66
|
-
|
|
67
|
-
if (event?.event === "visibilitychange") {
|
|
68
|
-
fetchSessionWithRefresh();
|
|
36
|
+
fetchSession();
|
|
69
37
|
return;
|
|
70
38
|
}
|
|
71
|
-
|
|
72
|
-
state.lastSync = now();
|
|
73
|
-
sessionSignal.set(!sessionSignal.get());
|
|
74
|
-
}
|
|
39
|
+
fetchSession();
|
|
75
40
|
};
|
|
76
41
|
const broadcastSessionUpdate = (trigger) => {
|
|
77
42
|
getGlobalBroadcastChannel().post({
|
|
@@ -82,7 +47,7 @@ function createSessionRefreshManager(opts) {
|
|
|
82
47
|
};
|
|
83
48
|
const setupPolling = () => {
|
|
84
49
|
if (refetchInterval && refetchInterval > 0) state.pollInterval = setInterval(() => {
|
|
85
|
-
if (
|
|
50
|
+
if (shouldPollSession()) triggerRefetch({ event: "poll" });
|
|
86
51
|
}, refetchInterval * 1e3);
|
|
87
52
|
};
|
|
88
53
|
const setupBroadcast = () => {
|
|
@@ -101,16 +66,25 @@ function createSessionRefreshManager(opts) {
|
|
|
101
66
|
if (online) triggerRefetch({ event: "visibilitychange" });
|
|
102
67
|
});
|
|
103
68
|
};
|
|
69
|
+
const setupSignalSubscription = () => {
|
|
70
|
+
state.unsubscribeSignal = sessionSignal.listen(() => {
|
|
71
|
+
fetchSession();
|
|
72
|
+
});
|
|
73
|
+
};
|
|
104
74
|
const init = () => {
|
|
75
|
+
if (state.isInitialized) return;
|
|
76
|
+
state.isInitialized = true;
|
|
105
77
|
setupPolling();
|
|
106
78
|
setupBroadcast();
|
|
107
79
|
setupFocusRefetch();
|
|
108
80
|
setupOnlineRefetch();
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
81
|
+
setupSignalSubscription();
|
|
82
|
+
state.cleanupBroadcastSetup = getGlobalBroadcastChannel().setup();
|
|
83
|
+
state.cleanupFocusSetup = getGlobalFocusManager().setup();
|
|
84
|
+
state.cleanupOnlineSetup = getGlobalOnlineManager().setup();
|
|
112
85
|
};
|
|
113
86
|
const cleanup = () => {
|
|
87
|
+
if (!state.isInitialized) return;
|
|
114
88
|
if (state.pollInterval) {
|
|
115
89
|
clearInterval(state.pollInterval);
|
|
116
90
|
state.pollInterval = void 0;
|
|
@@ -127,9 +101,24 @@ function createSessionRefreshManager(opts) {
|
|
|
127
101
|
state.unsubscribeOnline();
|
|
128
102
|
state.unsubscribeOnline = void 0;
|
|
129
103
|
}
|
|
130
|
-
state.
|
|
104
|
+
if (state.unsubscribeSignal) {
|
|
105
|
+
state.unsubscribeSignal();
|
|
106
|
+
state.unsubscribeSignal = void 0;
|
|
107
|
+
}
|
|
108
|
+
if (state.cleanupBroadcastSetup) {
|
|
109
|
+
state.cleanupBroadcastSetup();
|
|
110
|
+
state.cleanupBroadcastSetup = void 0;
|
|
111
|
+
}
|
|
112
|
+
if (state.cleanupFocusSetup) {
|
|
113
|
+
state.cleanupFocusSetup();
|
|
114
|
+
state.cleanupFocusSetup = void 0;
|
|
115
|
+
}
|
|
116
|
+
if (state.cleanupOnlineSetup) {
|
|
117
|
+
state.cleanupOnlineSetup();
|
|
118
|
+
state.cleanupOnlineSetup = void 0;
|
|
119
|
+
}
|
|
120
|
+
state.isInitialized = false;
|
|
131
121
|
state.lastSessionRequest = 0;
|
|
132
|
-
state.cachedSession = void 0;
|
|
133
122
|
};
|
|
134
123
|
return {
|
|
135
124
|
init,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ExtractPluginField, HasRequiredKeys, InferPluginFieldFromTuple, IsAny, OverrideMerge, Prettify, PrettifyDeep, RequiredKeysOf, StripEmptyObjects, UnionToIntersection } from "../../types/helper.mjs";
|
|
2
2
|
import { InferActions, InferClientAPI, InferErrorCodes, IsSignal, SessionQueryParams } from "../types.mjs";
|
|
3
|
-
import { BetterAuthClientOptions
|
|
3
|
+
import { BetterAuthClientOptions } from "@better-auth/core";
|
|
4
4
|
import { BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
5
5
|
import * as _better_fetch_fetch0 from "@better-fetch/fetch";
|
|
6
6
|
import { BetterFetchError } from "@better-fetch/fetch";
|
|
@@ -11,7 +11,9 @@ export * from "@better-fetch/fetch";
|
|
|
11
11
|
//#region src/client/solid/index.d.ts
|
|
12
12
|
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
|
|
13
13
|
plugins: Array<infer Plugin>;
|
|
14
|
-
} ? UnionToIntersection<Plugin extends
|
|
14
|
+
} ? UnionToIntersection<Plugin extends {
|
|
15
|
+
getAtoms?: infer GetAtoms;
|
|
16
|
+
} ? GetAtoms extends ((fetch: any) => infer Atoms) ? Atoms extends Record<string, any> ? { [key in keyof Atoms as IsSignal<key> extends true ? never : key extends string ? `use${Capitalize<key>}` : never]: () => Accessor<ReturnType<Atoms[key]["get"]>> } : {} : {} : {}> : {};
|
|
15
17
|
declare function createAuthClient<Option extends BetterAuthClientOptions>(options?: Option | undefined): UnionToIntersection<InferResolvedHooks<Option>> & InferClientAPI<Option> & InferActions<Option> & {
|
|
16
18
|
useSession: () => Accessor<{
|
|
17
19
|
data: InferClientAPI<Option> extends {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ExtractPluginField, HasRequiredKeys, InferPluginFieldFromTuple, IsAny, OverrideMerge, Prettify, PrettifyDeep, RequiredKeysOf, StripEmptyObjects, UnionToIntersection } from "../../types/helper.mjs";
|
|
2
2
|
import { InferActions, InferClientAPI, InferErrorCodes, IsSignal, SessionQueryParams } from "../types.mjs";
|
|
3
|
-
import { BetterAuthClientOptions
|
|
3
|
+
import { BetterAuthClientOptions } from "@better-auth/core";
|
|
4
4
|
import { BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
5
5
|
import * as nanostores from "nanostores";
|
|
6
6
|
import { Atom } from "nanostores";
|
|
@@ -12,7 +12,9 @@ export * from "@better-fetch/fetch";
|
|
|
12
12
|
//#region src/client/svelte/index.d.ts
|
|
13
13
|
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
|
|
14
14
|
plugins: Array<infer Plugin>;
|
|
15
|
-
} ? UnionToIntersection<Plugin extends
|
|
15
|
+
} ? UnionToIntersection<Plugin extends {
|
|
16
|
+
getAtoms?: infer GetAtoms;
|
|
17
|
+
} ? GetAtoms extends ((fetch: any) => infer Atoms) ? Atoms extends Record<string, any> ? { [key in keyof Atoms as IsSignal<key> extends true ? never : key extends string ? `use${Capitalize<key>}` : never]: () => Atoms[key] } : {} : {} : {}> : {};
|
|
16
18
|
declare function createAuthClient<Option extends BetterAuthClientOptions>(options?: Option | undefined): UnionToIntersection<InferResolvedHooks<Option>> & InferClientAPI<Option> & InferActions<Option> & {
|
|
17
19
|
useSession: () => Atom<{
|
|
18
20
|
data: InferClientAPI<Option> extends {
|
package/dist/client/types.d.mts
CHANGED
|
@@ -3,25 +3,32 @@ import { StripEmptyObjects, UnionToIntersection } from "../types/helper.mjs";
|
|
|
3
3
|
import { InferRoutes } from "./path-to-object.mjs";
|
|
4
4
|
import { Session as Session$1, User as User$1 } from "../types/models.mjs";
|
|
5
5
|
import { Auth } from "../types/auth.mjs";
|
|
6
|
-
import { BetterAuthClientOptions as BetterAuthClientOptions$1, BetterAuthClientPlugin
|
|
7
|
-
import {
|
|
8
|
-
import { RawError } from "@better-auth/core/utils/error-codes";
|
|
6
|
+
import { BetterAuthClientOptions as BetterAuthClientOptions$1, BetterAuthClientPlugin, ClientAtomListener, ClientStore as ClientStore$1 } from "@better-auth/core";
|
|
7
|
+
import { DBFieldAttribute, InferDBFieldsOutput } from "@better-auth/core/db";
|
|
9
8
|
|
|
10
9
|
//#region src/client/types.d.ts
|
|
10
|
+
type ClientPluginError<K extends string = string> = {
|
|
11
|
+
readonly code: K;
|
|
12
|
+
message: string;
|
|
13
|
+
};
|
|
11
14
|
type InferPluginEndpoints<Plugins> = Plugins extends Array<infer Pl> ? UnionToIntersection<Pl extends {
|
|
12
|
-
$InferServerPlugin
|
|
15
|
+
$InferServerPlugin?: infer Plug;
|
|
13
16
|
} ? Plug extends {
|
|
14
|
-
endpoints
|
|
15
|
-
} ? Endpoints : {} : {}> : {};
|
|
17
|
+
endpoints?: infer Endpoints;
|
|
18
|
+
} ? Endpoints extends Record<string, unknown> ? Endpoints : {} : {} : {}> : {};
|
|
16
19
|
type InferClientAPI<O extends BetterAuthClientOptions$1> = InferRoutes<O["plugins"] extends Array<any> ? Omit<Auth["api"], keyof InferPluginEndpoints<O["plugins"]>> & InferPluginEndpoints<O["plugins"]> : Auth["api"], O>;
|
|
17
|
-
type InferActions<O extends BetterAuthClientOptions$1> = (O["plugins"] extends Array<infer Plugin> ? UnionToIntersection<Plugin extends
|
|
20
|
+
type InferActions<O extends BetterAuthClientOptions$1> = (O["plugins"] extends Array<infer Plugin> ? UnionToIntersection<Plugin extends {
|
|
21
|
+
getActions?: infer GetActions;
|
|
22
|
+
} ? GetActions extends ((...args: any) => infer Actions) ? Actions : {} : {}> : {}) & InferRoutes<O["$InferAuth"] extends {
|
|
18
23
|
plugins: infer Plugins;
|
|
19
24
|
} ? Plugins extends Array<infer Plugin> ? Plugin extends {
|
|
20
|
-
endpoints
|
|
21
|
-
} ? Endpoints : {} : {} : {}, O>;
|
|
22
|
-
type InferErrorCodes<O extends BetterAuthClientOptions$1> = O["plugins"] extends Array<infer Plugin> ? UnionToIntersection<Plugin extends
|
|
23
|
-
$
|
|
24
|
-
} ?
|
|
25
|
+
endpoints?: infer Endpoints;
|
|
26
|
+
} ? Endpoints extends Record<string, unknown> ? Endpoints : {} : {} : {} : {}, O>;
|
|
27
|
+
type InferErrorCodes<O extends BetterAuthClientOptions$1> = O["plugins"] extends Array<infer Plugin> ? UnionToIntersection<Plugin extends {
|
|
28
|
+
$InferServerPlugin?: infer ServerPlugin;
|
|
29
|
+
} ? ServerPlugin extends {
|
|
30
|
+
$ERROR_CODES?: infer E;
|
|
31
|
+
} ? { [K in keyof E & string]: E[K] extends ClientPluginError ? ClientPluginError<K> : never } : {} : {}> : {};
|
|
25
32
|
/**
|
|
26
33
|
* signals are just used to recall a computed value.
|
|
27
34
|
* as a convention they start with "$"
|
|
@@ -29,12 +36,16 @@ type InferErrorCodes<O extends BetterAuthClientOptions$1> = O["plugins"] extends
|
|
|
29
36
|
type IsSignal<T> = T extends `$${infer _}` ? true : false;
|
|
30
37
|
type InferSessionFromClient<O extends BetterAuthClientOptions$1> = StripEmptyObjects<Session$1 & UnionToIntersection<InferAdditionalFromClient<O, "session", "output">>>;
|
|
31
38
|
type InferUserFromClient<O extends BetterAuthClientOptions$1> = StripEmptyObjects<User$1 & UnionToIntersection<InferAdditionalFromClient<O, "user", "output">>>;
|
|
32
|
-
type InferAdditionalFromClient<Options extends BetterAuthClientOptions$1, Key extends string, Format extends "input" | "output" = "output"> = Options["plugins"] extends Array<infer Plugin> ? Plugin extends
|
|
33
|
-
|
|
34
|
-
} ?
|
|
39
|
+
type InferAdditionalFromClient<Options extends BetterAuthClientOptions$1, Key extends string, Format extends "input" | "output" = "output"> = Options["plugins"] extends Array<infer Plugin> ? Plugin extends {
|
|
40
|
+
$InferServerPlugin?: infer ServerPlugin;
|
|
41
|
+
} ? ServerPlugin extends {
|
|
42
|
+
schema?: infer Schema;
|
|
43
|
+
} ? Schema extends Record<Key, {
|
|
44
|
+
fields: infer Fields;
|
|
45
|
+
}> ? Fields extends Record<string, DBFieldAttribute> ? Format extends "input" ? InferFieldsInputClient<Fields> : InferDBFieldsOutput<Fields> : {} : {} : {} : {} : {};
|
|
35
46
|
type SessionQueryParams = {
|
|
36
47
|
disableCookieCache?: boolean | undefined;
|
|
37
48
|
disableRefresh?: boolean | undefined;
|
|
38
49
|
};
|
|
39
50
|
//#endregion
|
|
40
|
-
export { type BetterAuthClientOptions$1 as BetterAuthClientOptions, type BetterAuthClientPlugin
|
|
51
|
+
export { type BetterAuthClientOptions$1 as BetterAuthClientOptions, type BetterAuthClientPlugin, type ClientAtomListener, type ClientStore$1 as ClientStore, InferActions, InferAdditionalFromClient, InferClientAPI, InferErrorCodes, InferSessionFromClient, InferUserFromClient, IsSignal, SessionQueryParams };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PrettifyDeep, UnionToIntersection } from "../types/helper.mjs";
|
|
2
2
|
import { InferActions, InferClientAPI, InferErrorCodes, IsSignal, SessionQueryParams } from "./types.mjs";
|
|
3
|
-
import { BetterAuthClientOptions
|
|
3
|
+
import { BetterAuthClientOptions } from "@better-auth/core";
|
|
4
4
|
import { BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
5
5
|
import * as nanostores from "nanostores";
|
|
6
6
|
import { Atom } from "nanostores";
|
|
@@ -10,7 +10,9 @@ import { BetterFetchError } from "@better-fetch/fetch";
|
|
|
10
10
|
//#region src/client/vanilla.d.ts
|
|
11
11
|
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
|
|
12
12
|
plugins: Array<infer Plugin>;
|
|
13
|
-
} ? UnionToIntersection<Plugin extends
|
|
13
|
+
} ? UnionToIntersection<Plugin extends {
|
|
14
|
+
getAtoms?: infer GetAtoms;
|
|
15
|
+
} ? GetAtoms extends ((fetch: any) => infer Atoms) ? Atoms extends Record<string, any> ? { [key in keyof Atoms as IsSignal<key> extends true ? never : key extends string ? `use${Capitalize<key>}` : never]: Atoms[key] } : {} : {} : {}> : {};
|
|
14
16
|
declare function createAuthClient<Option extends BetterAuthClientOptions>(options?: Option | undefined): UnionToIntersection<InferResolvedHooks<Option>> & InferClientAPI<Option> & InferActions<Option> & {
|
|
15
17
|
useSession: Atom<{
|
|
16
18
|
data: InferClientAPI<Option> extends {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ExtractPluginField, HasRequiredKeys, InferPluginFieldFromTuple, IsAny, OverrideMerge, Prettify, PrettifyDeep, RequiredKeysOf, StripEmptyObjects, UnionToIntersection } from "../../types/helper.mjs";
|
|
2
2
|
import { InferActions, InferClientAPI, InferErrorCodes, IsSignal, SessionQueryParams } from "../types.mjs";
|
|
3
|
-
import { BetterAuthClientOptions
|
|
3
|
+
import { BetterAuthClientOptions } from "@better-auth/core";
|
|
4
4
|
import { BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
5
5
|
import * as nanostores from "nanostores";
|
|
6
6
|
import * as _better_fetch_fetch0 from "@better-fetch/fetch";
|
|
@@ -12,7 +12,9 @@ export * from "@better-fetch/fetch";
|
|
|
12
12
|
//#region src/client/vue/index.d.ts
|
|
13
13
|
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
|
|
14
14
|
plugins: Array<infer Plugin>;
|
|
15
|
-
} ? UnionToIntersection<Plugin extends
|
|
15
|
+
} ? UnionToIntersection<Plugin extends {
|
|
16
|
+
getAtoms?: infer GetAtoms;
|
|
17
|
+
} ? GetAtoms extends ((fetch: any) => infer Atoms) ? Atoms extends Record<string, any> ? { [key in keyof Atoms as IsSignal<key> extends true ? never : key extends string ? `use${Capitalize<key>}` : never]: () => DeepReadonly<Ref<ReturnType<Atoms[key]["get"]>>> } : {} : {} : {}> : {};
|
|
16
18
|
declare function createAuthClient<Option extends BetterAuthClientOptions>(options?: Option | undefined): UnionToIntersection<InferResolvedHooks<Option>> & InferClientAPI<Option> & InferActions<Option> & {
|
|
17
19
|
useSession: {
|
|
18
20
|
(): DeepReadonly<Ref<{
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getBaseURL, isDynamicBaseURLConfig } from "../utils/url.mjs";
|
|
2
2
|
import { matchesOriginPattern } from "../auth/trusted-origins.mjs";
|
|
3
|
+
import { hasServerSessionStore } from "./store-capabilities.mjs";
|
|
3
4
|
import { isPromise } from "../utils/is-promise.mjs";
|
|
4
5
|
import { hashPassword, verifyPassword } from "../crypto/password.mjs";
|
|
5
6
|
import { createCookieGetter, getCookies } from "../cookies/index.mjs";
|
|
@@ -42,7 +43,7 @@ function validateSecret(secret, logger) {
|
|
|
42
43
|
if (estimateEntropy(secret) < 120) logger.warn("[better-auth] Warning: your BETTER_AUTH_SECRET appears low-entropy. Use a randomly generated secret for production.");
|
|
43
44
|
}
|
|
44
45
|
async function createAuthContext(adapter, options, getDatabaseType) {
|
|
45
|
-
const isStateful =
|
|
46
|
+
const isStateful = hasServerSessionStore(options);
|
|
46
47
|
if (!isStateful) options = defu$1(options, { session: { cookieCache: {
|
|
47
48
|
enabled: true,
|
|
48
49
|
strategy: "jwe",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/context/store-capabilities.ts
|
|
2
|
+
function hasServerSessionStore(options) {
|
|
3
|
+
return !!options.database || !!options.secondaryStorage;
|
|
4
|
+
}
|
|
5
|
+
function hasServerAccountStore(options) {
|
|
6
|
+
return !!options.database;
|
|
7
|
+
}
|
|
8
|
+
function shouldBindAccountCookieToSessionUser(options) {
|
|
9
|
+
return hasServerAccountStore(options);
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { hasServerSessionStore, shouldBindAccountCookieToSessionUser };
|
package/dist/cookies/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isDynamicBaseURLConfig } from "../utils/url.mjs";
|
|
2
|
+
import { shouldBindAccountCookieToSessionUser } from "../context/store-capabilities.mjs";
|
|
2
3
|
import { signJWT, symmetricDecodeJWT, symmetricEncodeJWT, verifyJWT } from "../crypto/jwt.mjs";
|
|
3
4
|
import { parseUserOutput } from "../db/schema.mjs";
|
|
4
5
|
import { getDate } from "../utils/date.mjs";
|
|
@@ -114,9 +115,9 @@ async function setCookieCache(ctx, session, dontRememberMe) {
|
|
|
114
115
|
}
|
|
115
116
|
ctx.setCookie(ctx.context.authCookies.sessionData.name, data, options);
|
|
116
117
|
}
|
|
117
|
-
if (ctx.context.options.account?.storeAccountCookie) {
|
|
118
|
+
if (ctx.context.options.account?.storeAccountCookie && !hasPendingSetCookie(ctx, ctx.context.authCookies.accountData.name)) {
|
|
118
119
|
const accountData = await getAccountCookie(ctx);
|
|
119
|
-
if (accountData) if (accountData.userId === session.user.id) await setAccountCookie(ctx, accountData);
|
|
120
|
+
if (accountData) if (!shouldBindAccountCookieToSessionUser(ctx.context.options) || accountData.userId === session.user.id) await setAccountCookie(ctx, accountData);
|
|
120
121
|
else {
|
|
121
122
|
expireCookie(ctx, ctx.context.authCookies.accountData);
|
|
122
123
|
const accountStore = createAccountStore(ctx.context.authCookies.accountData.name, ctx.context.authCookies.accountData.attributes, ctx);
|
|
@@ -175,6 +176,20 @@ function removeSetCookieEntries(ctx, cookieName) {
|
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
178
|
/**
|
|
179
|
+
* Whether the response already has a pending `Set-Cookie` for `cookieName`
|
|
180
|
+
* or a chunked variant.
|
|
181
|
+
*/
|
|
182
|
+
function hasPendingSetCookie(ctx, cookieName) {
|
|
183
|
+
const scoped = ctx;
|
|
184
|
+
const targets = /* @__PURE__ */ new Set();
|
|
185
|
+
if (scoped.responseHeaders) targets.add(scoped.responseHeaders);
|
|
186
|
+
if (scoped.context?.responseHeaders) targets.add(scoped.context.responseHeaders);
|
|
187
|
+
const exact = `${cookieName}=`;
|
|
188
|
+
const chunk = `${cookieName}.`;
|
|
189
|
+
for (const headers of targets) if ((typeof headers.getSetCookie === "function" ? headers.getSetCookie() : splitSetCookieHeader(headers.get("set-cookie") || "")).some((entry) => entry.startsWith(exact) || entry.startsWith(chunk))) return true;
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
178
193
|
* Expires a cookie by setting `maxAge: 0` while preserving its attributes
|
|
179
194
|
*/
|
|
180
195
|
function expireCookie(ctx, cookie) {
|
|
@@ -236,6 +251,10 @@ const getCookieCache = async (request, config) => {
|
|
|
236
251
|
const secret = config?.secret || env.BETTER_AUTH_SECRET;
|
|
237
252
|
if (!secret) throw new BetterAuthError("getCookieCache requires a secret to be provided. Either pass it as an option or set the BETTER_AUTH_SECRET environment variable");
|
|
238
253
|
const strategy = config?.strategy || "compact";
|
|
254
|
+
const isEmbeddedSessionExpired = (payload) => {
|
|
255
|
+
const expiresAt = payload.session?.expiresAt;
|
|
256
|
+
return !!expiresAt && new Date(expiresAt).getTime() < Date.now();
|
|
257
|
+
};
|
|
239
258
|
if (strategy === "jwe") {
|
|
240
259
|
const payload = await symmetricDecodeJWT(sessionData, secret, "better-auth-session");
|
|
241
260
|
if (payload && payload.session && payload.user) {
|
|
@@ -249,6 +268,7 @@ const getCookieCache = async (request, config) => {
|
|
|
249
268
|
}
|
|
250
269
|
if (cookieVersion !== expectedVersion) return null;
|
|
251
270
|
}
|
|
271
|
+
if (isEmbeddedSessionExpired(payload)) return null;
|
|
252
272
|
return payload;
|
|
253
273
|
}
|
|
254
274
|
return null;
|
|
@@ -265,6 +285,7 @@ const getCookieCache = async (request, config) => {
|
|
|
265
285
|
}
|
|
266
286
|
if (cookieVersion !== expectedVersion) return null;
|
|
267
287
|
}
|
|
288
|
+
if (isEmbeddedSessionExpired(payload)) return null;
|
|
268
289
|
return payload;
|
|
269
290
|
}
|
|
270
291
|
return null;
|
|
@@ -285,6 +306,8 @@ const getCookieCache = async (request, config) => {
|
|
|
285
306
|
}
|
|
286
307
|
if (cookieVersion !== expectedVersion) return null;
|
|
287
308
|
}
|
|
309
|
+
if (typeof sessionDataPayload.expiresAt === "number" && sessionDataPayload.expiresAt < Date.now()) return null;
|
|
310
|
+
if (isEmbeddedSessionExpired(sessionDataPayload.session)) return null;
|
|
288
311
|
return sessionDataPayload.session;
|
|
289
312
|
}
|
|
290
313
|
}
|
|
@@ -6,6 +6,8 @@ import { getWithHooks } from "./with-hooks.mjs";
|
|
|
6
6
|
import { getCurrentAdapter, getCurrentAuthContext, runWithTransaction } from "@better-auth/core/context";
|
|
7
7
|
import { generateId } from "@better-auth/core/utils/id";
|
|
8
8
|
import { safeJSONParse } from "@better-auth/core/utils/json";
|
|
9
|
+
import { base64Url } from "@better-auth/utils/base64";
|
|
10
|
+
import { createHash } from "@better-auth/utils/hash";
|
|
9
11
|
//#region src/db/internal-adapter.ts
|
|
10
12
|
function getTTLSeconds(expiresAt, now = Date.now()) {
|
|
11
13
|
const expiresMs = typeof expiresAt === "number" ? expiresAt : expiresAt.getTime();
|
|
@@ -717,6 +719,55 @@ const createInternalAdapter = (adapter, ctx) => {
|
|
|
717
719
|
if (!consumed || consumed.expiresAt < /* @__PURE__ */ new Date()) return null;
|
|
718
720
|
return consumed;
|
|
719
721
|
},
|
|
722
|
+
reserveVerificationValue: async (data) => {
|
|
723
|
+
const reservationId = base64Url.encode(new Uint8Array(await createHash("SHA-256").digest(new TextEncoder().encode("reserve:" + data.identifier))), { padding: false });
|
|
724
|
+
const storageOption = getStorageOption(data.identifier, options.verification?.storeIdentifier);
|
|
725
|
+
const storedIdentifier = await processIdentifier(data.identifier, storageOption);
|
|
726
|
+
if (secondaryStorage && !options.verification?.storeInDatabase) {
|
|
727
|
+
const cacheKey = `verification:${storedIdentifier}`;
|
|
728
|
+
if (await secondaryStorage.get(cacheKey)) return false;
|
|
729
|
+
await secondaryStorage.set(cacheKey, JSON.stringify({
|
|
730
|
+
id: reservationId,
|
|
731
|
+
identifier: storedIdentifier,
|
|
732
|
+
value: data.value,
|
|
733
|
+
expiresAt: data.expiresAt
|
|
734
|
+
}), getTTLSeconds(data.expiresAt));
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
737
|
+
try {
|
|
738
|
+
await adapter.create({
|
|
739
|
+
model: "verification",
|
|
740
|
+
data: {
|
|
741
|
+
id: reservationId,
|
|
742
|
+
identifier: storedIdentifier,
|
|
743
|
+
value: data.value,
|
|
744
|
+
expiresAt: data.expiresAt,
|
|
745
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
746
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
747
|
+
},
|
|
748
|
+
forceAllowId: true
|
|
749
|
+
});
|
|
750
|
+
} catch (error) {
|
|
751
|
+
if (await adapter.findOne({
|
|
752
|
+
model: "verification",
|
|
753
|
+
where: [{
|
|
754
|
+
field: "id",
|
|
755
|
+
value: reservationId
|
|
756
|
+
}]
|
|
757
|
+
})) return false;
|
|
758
|
+
throw error;
|
|
759
|
+
}
|
|
760
|
+
if (secondaryStorage) {
|
|
761
|
+
const ttl = getTTLSeconds(data.expiresAt);
|
|
762
|
+
if (ttl > 0) await secondaryStorage.set(`verification:${storedIdentifier}`, JSON.stringify({
|
|
763
|
+
id: reservationId,
|
|
764
|
+
identifier: storedIdentifier,
|
|
765
|
+
value: data.value,
|
|
766
|
+
expiresAt: data.expiresAt
|
|
767
|
+
}), ttl);
|
|
768
|
+
}
|
|
769
|
+
return true;
|
|
770
|
+
},
|
|
720
771
|
updateVerificationByIdentifier: async (identifier, data) => {
|
|
721
772
|
const storedIdentifier = await processIdentifier(identifier, getStorageOption(identifier, options.verification?.storeIdentifier));
|
|
722
773
|
if (secondaryStorage) {
|
package/dist/package.mjs
CHANGED