@better-auth/core 1.7.0-beta.0 → 1.7.0-beta.10
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 +44 -1
- package/dist/api/index.mjs +69 -4
- package/dist/context/global.mjs +1 -1
- package/dist/context/transaction.d.mts +7 -4
- package/dist/context/transaction.mjs +6 -3
- package/dist/db/adapter/factory.mjs +91 -3
- package/dist/db/adapter/get-id-field.mjs +1 -1
- package/dist/db/adapter/index.d.mts +87 -3
- package/dist/db/adapter/types.d.mts +1 -1
- package/dist/db/get-tables.mjs +2 -1
- package/dist/db/type.d.mts +17 -0
- package/dist/env/env-impl.mjs +1 -1
- package/dist/error/codes.d.mts +1 -0
- package/dist/error/codes.mjs +1 -0
- package/dist/error/index.d.mts +7 -0
- package/dist/index.d.mts +2 -2
- package/dist/instrumentation/api.mjs +12 -0
- package/dist/instrumentation/noop.mjs +42 -0
- package/dist/instrumentation/pure.index.d.mts +7 -0
- package/dist/instrumentation/pure.index.mjs +7 -0
- package/dist/instrumentation/tracer.mjs +6 -3
- package/dist/oauth2/authorization-params.d.mts +12 -0
- package/dist/oauth2/authorization-params.mjs +12 -0
- package/dist/oauth2/basic-credentials.d.mts +30 -0
- package/dist/oauth2/basic-credentials.mjs +64 -0
- package/dist/oauth2/client-assertion.d.mts +38 -22
- package/dist/oauth2/client-assertion.mjs +63 -28
- package/dist/oauth2/client-credentials-token.d.mts +19 -40
- package/dist/oauth2/client-credentials-token.mjs +20 -31
- package/dist/oauth2/create-authorization-url.d.mts +11 -1
- package/dist/oauth2/create-authorization-url.mjs +27 -7
- package/dist/oauth2/dpop.d.mts +142 -0
- package/dist/oauth2/dpop.mjs +246 -0
- package/dist/oauth2/index.d.mts +14 -9
- package/dist/oauth2/index.mjs +12 -8
- package/dist/oauth2/oauth-provider.d.mts +150 -10
- package/dist/oauth2/refresh-access-token.d.mts +20 -40
- package/dist/oauth2/refresh-access-token.mjs +38 -36
- package/dist/oauth2/reject-redirects.mjs +65 -0
- package/dist/oauth2/token-endpoint-auth.d.mts +17 -0
- package/dist/oauth2/token-endpoint-auth.mjs +89 -0
- package/dist/oauth2/utils.d.mts +23 -1
- package/dist/oauth2/utils.mjs +48 -2
- package/dist/oauth2/validate-authorization-code.d.mts +17 -52
- package/dist/oauth2/validate-authorization-code.mjs +28 -34
- package/dist/oauth2/verify-id-token.d.mts +27 -0
- package/dist/oauth2/verify-id-token.mjs +62 -0
- package/dist/oauth2/verify.d.mts +88 -15
- package/dist/oauth2/verify.mjs +203 -25
- package/dist/social-providers/apple.d.mts +16 -4
- package/dist/social-providers/apple.mjs +17 -24
- package/dist/social-providers/atlassian.d.mts +5 -1
- package/dist/social-providers/atlassian.mjs +6 -3
- package/dist/social-providers/cognito.d.mts +27 -3
- package/dist/social-providers/cognito.mjs +15 -25
- package/dist/social-providers/discord.d.mts +7 -3
- package/dist/social-providers/discord.mjs +16 -3
- package/dist/social-providers/dropbox.d.mts +5 -1
- package/dist/social-providers/dropbox.mjs +5 -4
- package/dist/social-providers/facebook.d.mts +24 -5
- package/dist/social-providers/facebook.mjs +54 -20
- package/dist/social-providers/figma.d.mts +5 -1
- package/dist/social-providers/figma.mjs +4 -3
- package/dist/social-providers/github.d.mts +6 -2
- package/dist/social-providers/github.mjs +5 -4
- package/dist/social-providers/gitlab.d.mts +5 -1
- package/dist/social-providers/gitlab.mjs +3 -2
- package/dist/social-providers/google.d.mts +53 -5
- package/dist/social-providers/google.mjs +69 -25
- package/dist/social-providers/huggingface.d.mts +5 -1
- package/dist/social-providers/huggingface.mjs +3 -2
- package/dist/social-providers/index.d.mts +221 -45
- package/dist/social-providers/index.mjs +2 -2
- package/dist/social-providers/kakao.d.mts +5 -1
- package/dist/social-providers/kakao.mjs +3 -2
- package/dist/social-providers/kick.d.mts +5 -1
- package/dist/social-providers/kick.mjs +3 -2
- package/dist/social-providers/line.d.mts +8 -2
- package/dist/social-providers/line.mjs +5 -6
- package/dist/social-providers/linear.d.mts +5 -1
- package/dist/social-providers/linear.mjs +3 -2
- package/dist/social-providers/linkedin.d.mts +7 -3
- package/dist/social-providers/linkedin.mjs +4 -3
- package/dist/social-providers/microsoft-entra-id.d.mts +41 -7
- package/dist/social-providers/microsoft-entra-id.mjs +37 -28
- package/dist/social-providers/naver.d.mts +5 -1
- package/dist/social-providers/naver.mjs +3 -2
- package/dist/social-providers/notion.d.mts +5 -1
- package/dist/social-providers/notion.mjs +5 -2
- package/dist/social-providers/paybin.d.mts +5 -1
- package/dist/social-providers/paybin.mjs +4 -3
- package/dist/social-providers/paypal.d.mts +6 -2
- package/dist/social-providers/paypal.mjs +19 -14
- package/dist/social-providers/polar.d.mts +5 -1
- package/dist/social-providers/polar.mjs +3 -2
- package/dist/social-providers/railway.d.mts +5 -1
- package/dist/social-providers/railway.mjs +3 -2
- package/dist/social-providers/reddit.d.mts +5 -1
- package/dist/social-providers/reddit.mjs +7 -5
- package/dist/social-providers/roblox.d.mts +6 -2
- package/dist/social-providers/roblox.mjs +12 -2
- package/dist/social-providers/salesforce.d.mts +5 -1
- package/dist/social-providers/salesforce.mjs +4 -3
- package/dist/social-providers/slack.d.mts +6 -2
- package/dist/social-providers/slack.mjs +11 -8
- package/dist/social-providers/spotify.d.mts +5 -1
- package/dist/social-providers/spotify.mjs +3 -2
- package/dist/social-providers/tiktok.d.mts +5 -1
- package/dist/social-providers/tiktok.mjs +14 -2
- package/dist/social-providers/twitch.d.mts +5 -1
- package/dist/social-providers/twitch.mjs +3 -2
- package/dist/social-providers/twitter.d.mts +4 -1
- package/dist/social-providers/twitter.mjs +2 -1
- package/dist/social-providers/vercel.d.mts +5 -1
- package/dist/social-providers/vercel.mjs +3 -2
- package/dist/social-providers/vk.d.mts +5 -1
- package/dist/social-providers/vk.mjs +3 -2
- package/dist/social-providers/wechat.d.mts +5 -1
- package/dist/social-providers/wechat.mjs +8 -2
- package/dist/social-providers/zoom.d.mts +5 -1
- package/dist/social-providers/zoom.mjs +10 -17
- package/dist/types/context.d.mts +55 -6
- package/dist/types/index.d.mts +1 -1
- package/dist/types/init-options.d.mts +182 -12
- package/dist/types/plugin-client.d.mts +12 -2
- package/dist/utils/async.d.mts +22 -0
- package/dist/utils/async.mjs +32 -0
- package/dist/utils/host.d.mts +147 -0
- package/dist/utils/host.mjs +298 -0
- package/dist/utils/ip.d.mts +28 -5
- package/dist/utils/ip.mjs +118 -4
- package/dist/utils/is-api-error.d.mts +6 -0
- package/dist/utils/is-api-error.mjs +8 -0
- package/dist/utils/redirect-uri.d.mts +20 -0
- package/dist/utils/redirect-uri.mjs +48 -0
- package/dist/utils/string.d.mts +5 -1
- package/dist/utils/string.mjs +20 -1
- package/dist/utils/url.d.mts +18 -1
- package/dist/utils/url.mjs +34 -4
- package/package.json +26 -16
- package/src/api/index.ts +121 -5
- package/src/context/transaction.ts +45 -12
- package/src/db/adapter/factory.ts +193 -7
- package/src/db/adapter/get-id-field.ts +2 -2
- package/src/db/adapter/index.ts +85 -2
- package/src/db/adapter/types.ts +2 -0
- package/src/db/get-tables.ts +9 -1
- package/src/db/schema/account.ts +4 -1
- package/src/db/schema/user.ts +3 -0
- package/src/db/type.ts +17 -0
- package/src/env/env-impl.ts +1 -2
- package/src/error/codes.ts +1 -0
- package/src/error/index.ts +9 -0
- package/src/instrumentation/api.ts +17 -0
- package/src/instrumentation/noop.ts +74 -0
- package/src/instrumentation/pure.index.ts +31 -0
- package/src/instrumentation/tracer.ts +8 -3
- package/src/oauth2/authorization-params.ts +28 -0
- package/src/oauth2/basic-credentials.ts +87 -0
- package/src/oauth2/client-assertion.ts +131 -58
- package/src/oauth2/client-credentials-token.ts +50 -74
- package/src/oauth2/create-authorization-url.ts +33 -7
- package/src/oauth2/dpop.ts +568 -0
- package/src/oauth2/index.ts +81 -11
- package/src/oauth2/oauth-provider.ts +159 -11
- package/src/oauth2/refresh-access-token.ts +82 -83
- package/src/oauth2/reject-redirects.ts +75 -0
- package/src/oauth2/token-endpoint-auth.ts +221 -0
- package/src/oauth2/utils.ts +72 -5
- package/src/oauth2/validate-authorization-code.ts +69 -89
- package/src/oauth2/verify-id-token.ts +115 -0
- package/src/oauth2/verify.ts +409 -78
- package/src/social-providers/apple.ts +30 -40
- package/src/social-providers/atlassian.ts +8 -1
- package/src/social-providers/cognito.ts +36 -39
- package/src/social-providers/discord.ts +22 -18
- package/src/social-providers/dropbox.ts +7 -5
- package/src/social-providers/facebook.ts +108 -52
- package/src/social-providers/figma.ts +8 -1
- package/src/social-providers/github.ts +5 -3
- package/src/social-providers/gitlab.ts +2 -0
- package/src/social-providers/google.ts +141 -39
- package/src/social-providers/huggingface.ts +8 -1
- package/src/social-providers/kakao.ts +2 -1
- package/src/social-providers/kick.ts +8 -1
- package/src/social-providers/line.ts +25 -27
- package/src/social-providers/linear.ts +8 -1
- package/src/social-providers/linkedin.ts +5 -3
- package/src/social-providers/microsoft-entra-id.ts +100 -55
- package/src/social-providers/naver.ts +2 -1
- package/src/social-providers/notion.ts +8 -1
- package/src/social-providers/paybin.ts +2 -0
- package/src/social-providers/paypal.ts +28 -17
- package/src/social-providers/polar.ts +8 -1
- package/src/social-providers/railway.ts +8 -1
- package/src/social-providers/reddit.ts +9 -4
- package/src/social-providers/roblox.ts +16 -11
- package/src/social-providers/salesforce.ts +8 -1
- package/src/social-providers/slack.ts +15 -9
- package/src/social-providers/spotify.ts +8 -1
- package/src/social-providers/tiktok.ts +22 -9
- package/src/social-providers/twitch.ts +2 -1
- package/src/social-providers/twitter.ts +1 -0
- package/src/social-providers/vercel.ts +8 -1
- package/src/social-providers/vk.ts +8 -1
- package/src/social-providers/wechat.ts +17 -2
- package/src/social-providers/zoom.ts +15 -19
- package/src/types/context.ts +57 -5
- package/src/types/index.ts +7 -0
- package/src/types/init-options.ts +204 -14
- package/src/types/plugin-client.ts +16 -2
- package/src/utils/async.ts +53 -0
- package/src/utils/host.ts +425 -0
- package/src/utils/ip.ts +197 -13
- package/src/utils/is-api-error.ts +10 -0
- package/src/utils/redirect-uri.ts +54 -0
- package/src/utils/string.ts +37 -0
- package/src/utils/url.ts +38 -4
|
@@ -24,7 +24,8 @@ declare const vk: (options: VkOption) => {
|
|
|
24
24
|
state,
|
|
25
25
|
scopes,
|
|
26
26
|
codeVerifier,
|
|
27
|
-
redirectURI
|
|
27
|
+
redirectURI,
|
|
28
|
+
additionalParams
|
|
28
29
|
}: {
|
|
29
30
|
state: string;
|
|
30
31
|
codeVerifier: string;
|
|
@@ -32,6 +33,8 @@ declare const vk: (options: VkOption) => {
|
|
|
32
33
|
redirectURI: string;
|
|
33
34
|
display?: string | undefined;
|
|
34
35
|
loginHint?: string | undefined;
|
|
36
|
+
idTokenNonce?: string | undefined;
|
|
37
|
+
additionalParams?: Record<string, string> | undefined;
|
|
35
38
|
}): Promise<URL>;
|
|
36
39
|
validateAuthorizationCode: ({
|
|
37
40
|
code,
|
|
@@ -46,6 +49,7 @@ declare const vk: (options: VkOption) => {
|
|
|
46
49
|
}) => Promise<OAuth2Tokens>;
|
|
47
50
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
48
51
|
getUserInfo(data: OAuth2Tokens & {
|
|
52
|
+
expectedIdTokenNonce?: string | undefined;
|
|
49
53
|
user?: {
|
|
50
54
|
name?: {
|
|
51
55
|
firstName?: string;
|
|
@@ -8,7 +8,7 @@ const vk = (options) => {
|
|
|
8
8
|
return {
|
|
9
9
|
id: "vk",
|
|
10
10
|
name: "VK",
|
|
11
|
-
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
11
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
12
12
|
const _scopes = options.disableDefaultScope ? [] : ["email", "phone"];
|
|
13
13
|
if (options.scope) _scopes.push(...options.scope);
|
|
14
14
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -19,7 +19,8 @@ const vk = (options) => {
|
|
|
19
19
|
scopes: _scopes,
|
|
20
20
|
state,
|
|
21
21
|
redirectURI,
|
|
22
|
-
codeVerifier
|
|
22
|
+
codeVerifier,
|
|
23
|
+
additionalParams
|
|
23
24
|
});
|
|
24
25
|
},
|
|
25
26
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI, deviceId }) => {
|
|
@@ -56,7 +56,8 @@ declare const wechat: (options: WeChatOptions) => {
|
|
|
56
56
|
createAuthorizationURL({
|
|
57
57
|
state,
|
|
58
58
|
scopes,
|
|
59
|
-
redirectURI
|
|
59
|
+
redirectURI,
|
|
60
|
+
additionalParams
|
|
60
61
|
}: {
|
|
61
62
|
state: string;
|
|
62
63
|
codeVerifier: string;
|
|
@@ -64,6 +65,8 @@ declare const wechat: (options: WeChatOptions) => {
|
|
|
64
65
|
redirectURI: string;
|
|
65
66
|
display?: string | undefined;
|
|
66
67
|
loginHint?: string | undefined;
|
|
68
|
+
idTokenNonce?: string | undefined;
|
|
69
|
+
additionalParams?: Record<string, string> | undefined;
|
|
67
70
|
}): URL;
|
|
68
71
|
validateAuthorizationCode: ({
|
|
69
72
|
code
|
|
@@ -89,6 +92,7 @@ declare const wechat: (options: WeChatOptions) => {
|
|
|
89
92
|
scopes: string[];
|
|
90
93
|
}>);
|
|
91
94
|
getUserInfo(token: OAuth2Tokens & {
|
|
95
|
+
expectedIdTokenNonce?: string | undefined;
|
|
92
96
|
user?: {
|
|
93
97
|
name?: {
|
|
94
98
|
firstName?: string;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { RESERVED_AUTHORIZATION_PARAMS_SET } from "../oauth2/create-authorization-url.mjs";
|
|
1
2
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
3
|
//#region src/social-providers/wechat.ts
|
|
3
4
|
const wechat = (options) => {
|
|
4
5
|
return {
|
|
5
6
|
id: "wechat",
|
|
6
7
|
name: "WeChat",
|
|
7
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
8
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
8
9
|
const _scopes = options.disableDefaultScope ? [] : ["snsapi_login"];
|
|
9
10
|
options.scope && _scopes.push(...options.scope);
|
|
10
11
|
scopes && _scopes.push(...scopes);
|
|
@@ -15,6 +16,11 @@ const wechat = (options) => {
|
|
|
15
16
|
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
16
17
|
url.searchParams.set("state", state);
|
|
17
18
|
url.searchParams.set("lang", options.lang || "cn");
|
|
19
|
+
if (additionalParams) for (const [key, value] of Object.entries(additionalParams)) {
|
|
20
|
+
if (RESERVED_AUTHORIZATION_PARAMS_SET.has(key)) continue;
|
|
21
|
+
if (key === "appid") continue;
|
|
22
|
+
url.searchParams.set(key, value);
|
|
23
|
+
}
|
|
18
24
|
url.hash = "wechat_redirect";
|
|
19
25
|
return url;
|
|
20
26
|
},
|
|
@@ -66,7 +72,7 @@ const wechat = (options) => {
|
|
|
66
72
|
user: {
|
|
67
73
|
id: profile.unionid || profile.openid || openid,
|
|
68
74
|
name: profile.nickname,
|
|
69
|
-
email: profile.email ||
|
|
75
|
+
email: profile.email || `${profile.unionid || profile.openid || openid}@wechat.invalid`,
|
|
70
76
|
image: profile.headimgurl,
|
|
71
77
|
emailVerified: false,
|
|
72
78
|
...userMap
|
|
@@ -119,7 +119,8 @@ declare const zoom: (userOptions: ZoomOptions) => {
|
|
|
119
119
|
createAuthorizationURL: ({
|
|
120
120
|
state,
|
|
121
121
|
redirectURI,
|
|
122
|
-
codeVerifier
|
|
122
|
+
codeVerifier,
|
|
123
|
+
additionalParams
|
|
123
124
|
}: {
|
|
124
125
|
state: string;
|
|
125
126
|
codeVerifier: string;
|
|
@@ -127,6 +128,8 @@ declare const zoom: (userOptions: ZoomOptions) => {
|
|
|
127
128
|
redirectURI: string;
|
|
128
129
|
display?: string | undefined;
|
|
129
130
|
loginHint?: string | undefined;
|
|
131
|
+
idTokenNonce?: string | undefined;
|
|
132
|
+
additionalParams?: Record<string, string> | undefined;
|
|
130
133
|
}) => Promise<URL>;
|
|
131
134
|
validateAuthorizationCode: ({
|
|
132
135
|
code,
|
|
@@ -140,6 +143,7 @@ declare const zoom: (userOptions: ZoomOptions) => {
|
|
|
140
143
|
}) => Promise<OAuth2Tokens>;
|
|
141
144
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
142
145
|
getUserInfo(token: OAuth2Tokens & {
|
|
146
|
+
expectedIdTokenNonce?: string | undefined;
|
|
143
147
|
user?: {
|
|
144
148
|
name?: {
|
|
145
149
|
firstName?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
2
2
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
3
3
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
4
4
|
import { betterFetch } from "@better-fetch/fetch";
|
|
@@ -11,22 +11,15 @@ const zoom = (userOptions) => {
|
|
|
11
11
|
return {
|
|
12
12
|
id: "zoom",
|
|
13
13
|
name: "Zoom",
|
|
14
|
-
createAuthorizationURL: async ({ state, redirectURI, codeVerifier }) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
params.set("code_challenge_method", "S256");
|
|
24
|
-
params.set("code_challenge", codeChallenge);
|
|
25
|
-
}
|
|
26
|
-
const url = new URL("https://zoom.us/oauth/authorize");
|
|
27
|
-
url.search = params.toString();
|
|
28
|
-
return url;
|
|
29
|
-
},
|
|
14
|
+
createAuthorizationURL: async ({ state, redirectURI, codeVerifier, additionalParams }) => createAuthorizationURL({
|
|
15
|
+
id: "zoom",
|
|
16
|
+
options,
|
|
17
|
+
authorizationEndpoint: "https://zoom.us/oauth/authorize",
|
|
18
|
+
state,
|
|
19
|
+
redirectURI,
|
|
20
|
+
codeVerifier: options.pkce ? codeVerifier : void 0,
|
|
21
|
+
additionalParams
|
|
22
|
+
}),
|
|
30
23
|
validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
|
|
31
24
|
return validateAuthorizationCode({
|
|
32
25
|
code,
|
package/dist/types/context.d.mts
CHANGED
|
@@ -6,7 +6,7 @@ import { Verification } from "../db/schema/verification.mjs";
|
|
|
6
6
|
import { createLogger } from "../env/logger.mjs";
|
|
7
7
|
import { Awaitable, LiteralString } from "./helper.mjs";
|
|
8
8
|
import { BetterAuthPlugin } from "./plugin.mjs";
|
|
9
|
-
import { BetterAuthOptions, BetterAuthRateLimitOptions } from "./init-options.mjs";
|
|
9
|
+
import { BetterAuthOptions, BetterAuthRateLimitOptions, UserProvisioningSource } from "./init-options.mjs";
|
|
10
10
|
import { Account } from "../db/schema/account.mjs";
|
|
11
11
|
import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
|
|
12
12
|
import { SecretConfig } from "./secret.mjs";
|
|
@@ -58,7 +58,13 @@ interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions
|
|
|
58
58
|
user: User;
|
|
59
59
|
account: Account;
|
|
60
60
|
}>;
|
|
61
|
-
createUser<T extends Record<string, any>>(user: Omit<User, "id" | "createdAt" | "updatedAt" | "emailVerified"> & Partial<User> & Record<string, any
|
|
61
|
+
createUser<T extends Record<string, any>>(user: Omit<User, "id" | "createdAt" | "updatedAt" | "emailVerified"> & Partial<User> & Record<string, any>,
|
|
62
|
+
/**
|
|
63
|
+
* Provisioning source. The creation seam adds `action: "create-user"` and
|
|
64
|
+
* runs the `user.validateUserInfo` gate.
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
source: UserProvisioningSource): Promise<T & User>;
|
|
62
68
|
createAccount<T extends Record<string, any>>(account: Omit<Account, "id" | "createdAt" | "updatedAt"> & Partial<Account> & T): Promise<T & Account>;
|
|
63
69
|
listSessions(userId: string, options?: {
|
|
64
70
|
onlyActiveSessions?: boolean | undefined;
|
|
@@ -83,8 +89,20 @@ interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions
|
|
|
83
89
|
updateSession(sessionToken: string, session: Partial<Session> & Record<string, any>): Promise<Session | null>;
|
|
84
90
|
deleteSession(token: string): Promise<void>;
|
|
85
91
|
deleteAccounts(userId: string): Promise<void>;
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Delete an account by its primary key.
|
|
94
|
+
*
|
|
95
|
+
* @param id - The account row's primary key (the `id` column, not the `accountId` column).
|
|
96
|
+
*/
|
|
97
|
+
deleteAccount(id: string): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Delete every session belonging to a user.
|
|
100
|
+
*/
|
|
101
|
+
deleteUserSessions(userId: string): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Delete sessions by their session tokens.
|
|
104
|
+
*/
|
|
105
|
+
deleteSessions(sessionTokens: string[]): Promise<void>;
|
|
88
106
|
findOAuthUser(email: string, accountId: string, providerId: string): Promise<{
|
|
89
107
|
user: User;
|
|
90
108
|
linkedAccount: Account | null;
|
|
@@ -102,14 +120,45 @@ interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions
|
|
|
102
120
|
updateUserByEmail<T extends Record<string, any>>(email: string, data: Partial<User & Record<string, any>>): Promise<User & T>;
|
|
103
121
|
updatePassword(userId: string, password: string): Promise<void>;
|
|
104
122
|
findAccounts(userId: string): Promise<Account[]>;
|
|
105
|
-
findAccount(accountId: string): Promise<Account | null>;
|
|
106
123
|
findAccountByProviderId(accountId: string, providerId: string): Promise<Account | null>;
|
|
107
124
|
findAccountByUserId(userId: string): Promise<Account[]>;
|
|
108
125
|
updateAccount(id: string, data: Partial<Account>): Promise<Account>;
|
|
109
126
|
createVerificationValue(data: Omit<Verification, "createdAt" | "id" | "updatedAt"> & Partial<Verification>): Promise<Verification>;
|
|
110
127
|
findVerificationValue(identifier: string): Promise<Verification | null>;
|
|
111
128
|
deleteVerificationByIdentifier(identifier: string): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Atomically consume a single-use verification row by `identifier` and
|
|
131
|
+
* return it. Only the first concurrent caller receives the latest row;
|
|
132
|
+
* subsequent callers receive `null`. Consuming one row invalidates the
|
|
133
|
+
* whole identifier so stale rows cannot be replayed. Rows past their
|
|
134
|
+
* `expiresAt` are treated as already invalid: the row is deleted but
|
|
135
|
+
* `null` is returned, so callers do not need to gate on `expiresAt`
|
|
136
|
+
* themselves. Callers MUST gate any state change (issue session, mint
|
|
137
|
+
* token, change password) on a non-null result.
|
|
138
|
+
*
|
|
139
|
+
* Replaces the racy `findVerificationValue` + `deleteVerificationByIdentifier`
|
|
140
|
+
* pair at single-use credential consumption sites.
|
|
141
|
+
*/
|
|
142
|
+
consumeVerificationValue(identifier: string): Promise<Verification | null>;
|
|
143
|
+
/**
|
|
144
|
+
* First-writer-wins create keyed by a deterministic primary key derived from
|
|
145
|
+
* `identifier`. Returns `true` when this caller created the row and `false`
|
|
146
|
+
* when a row for the same identifier already existed.
|
|
147
|
+
*
|
|
148
|
+
* The dual of `consumeVerificationValue`: reserve races to create a marker
|
|
149
|
+
* exactly once, where consume races to delete one exactly once. Use it for
|
|
150
|
+
* replay tombstones (a SAML assertion id, a JWT `jti`) where the first caller
|
|
151
|
+
* wins. The database path is atomic via the primary key. Secondary-storage-only
|
|
152
|
+
* verification is not supported for reservation and runtime implementations
|
|
153
|
+
* should fail closed unless verification is backed by the database.
|
|
154
|
+
*/
|
|
155
|
+
reserveVerificationValue(data: {
|
|
156
|
+
identifier: string;
|
|
157
|
+
value: string;
|
|
158
|
+
expiresAt: Date;
|
|
159
|
+
}): Promise<boolean>;
|
|
112
160
|
updateVerificationByIdentifier(identifier: string, data: Partial<Verification>): Promise<Verification>;
|
|
161
|
+
refreshUserSessions(user: User): Promise<void>;
|
|
113
162
|
}
|
|
114
163
|
type CreateCookieGetterFn = (cookieName: string, overrideAttributes?: Partial<CookieOptions> | undefined) => BetterAuthCookie;
|
|
115
164
|
type CheckPasswordFn<Options extends BetterAuthOptions = BetterAuthOptions> = (userId: string, ctx: GenericEndpointContext<Options>) => Promise<boolean>;
|
|
@@ -165,7 +214,7 @@ type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = Plugin
|
|
|
165
214
|
* - "cookie": Store state in an encrypted cookie (stateless)
|
|
166
215
|
* - "database": Store state in the database
|
|
167
216
|
*
|
|
168
|
-
* @default "cookie"
|
|
217
|
+
* @default "database" when `database` or `secondaryStorage` is configured, "cookie" otherwise
|
|
169
218
|
*/
|
|
170
219
|
storeStateStrategy: "database" | "cookie";
|
|
171
220
|
};
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Awaitable, AwaitableFunction, LiteralString, LiteralUnion, Prettify, Primitive, UnionToIntersection } from "./helper.mjs";
|
|
2
2
|
import { BetterAuthPlugin, BetterAuthPluginErrorCodePart, HookEndpointContext } from "./plugin.mjs";
|
|
3
|
-
import { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption } from "./init-options.mjs";
|
|
3
|
+
import { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource } from "./init-options.mjs";
|
|
4
4
|
import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
|
|
5
5
|
import { SecretConfig } from "./secret.mjs";
|
|
6
6
|
import { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext } from "./context.mjs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DBFieldAttribute, ModelNames, SecondaryStorage } from "../db/type.mjs";
|
|
2
2
|
import { DBAdapterDebugLogOption, DBAdapterInstance } from "../db/adapter/index.mjs";
|
|
3
|
-
import { BaseRateLimit
|
|
3
|
+
import { BaseRateLimit } from "../db/schema/rate-limit.mjs";
|
|
4
4
|
import { BaseSession, Session } from "../db/schema/session.mjs";
|
|
5
5
|
import { BaseUser, User } from "../db/schema/user.mjs";
|
|
6
6
|
import { BaseVerification, Verification } from "../db/schema/verification.mjs";
|
|
@@ -27,6 +27,73 @@ type GenerateIdFn = (options: {
|
|
|
27
27
|
model: ModelNames;
|
|
28
28
|
size?: number | undefined;
|
|
29
29
|
}) => string | false;
|
|
30
|
+
/**
|
|
31
|
+
* What Better Auth is about to do with an incoming identity when
|
|
32
|
+
* {@link BetterAuthOptions.user}'s `validateUserInfo` runs.
|
|
33
|
+
*
|
|
34
|
+
* - `create-user`: a brand-new user record is about to be created.
|
|
35
|
+
* - `link-account`: a new provider account is about to be linked to an
|
|
36
|
+
* already-existing user.
|
|
37
|
+
* - `sign-in`: an existing OAuth or SSO user is signing in again. This is the
|
|
38
|
+
* one case where the provider can assert *changed* data, so the hook receives
|
|
39
|
+
* the fresh provider email and profile (not the stored row), letting a domain
|
|
40
|
+
* or org policy reject a user whose provider identity moved out of bounds.
|
|
41
|
+
*
|
|
42
|
+
* Non-provider returning sign-ins are not re-validated: they carry only the
|
|
43
|
+
* stored row, which has not changed since `create-user` gated it. Use the admin
|
|
44
|
+
* plugin's ban controls or a `databaseHooks.session.create.before` hook to
|
|
45
|
+
* block those.
|
|
46
|
+
*/
|
|
47
|
+
type ValidateUserInfoAction = "create-user" | "link-account" | "sign-in";
|
|
48
|
+
/**
|
|
49
|
+
* The authentication method that produced the incoming user info. The named
|
|
50
|
+
* methods cover Better Auth's built-ins; the open `string` keeps it extensible
|
|
51
|
+
* for plugins (for example `"scim"`).
|
|
52
|
+
*/
|
|
53
|
+
type ValidateUserInfoMethod = "oauth" | "sso-oidc" | "sso-saml" | "email-password" | "magic-link" | "email-otp" | "anonymous" | "siwe" | "phone-number" | "admin" | (string & {});
|
|
54
|
+
/** OAuth-specific provisioning context; present only when `method` is `"oauth"`. */
|
|
55
|
+
type ValidateUserInfoOAuthInfo = {
|
|
56
|
+
/** The social or generic OAuth provider id (e.g. `"google"`). */providerId: string; /** The raw provider profile (userinfo or id-token claims), unmapped. */
|
|
57
|
+
profile?: Record<string, unknown> | undefined;
|
|
58
|
+
};
|
|
59
|
+
/** SSO-specific provisioning context; present for OIDC and SAML SSO methods. */
|
|
60
|
+
type ValidateUserInfoSSOInfo = {
|
|
61
|
+
/** The configured SSO provider id. */providerId: string; /** The raw OIDC claims or SAML assertion attributes, unmapped. */
|
|
62
|
+
profile?: Record<string, unknown> | undefined;
|
|
63
|
+
};
|
|
64
|
+
/** Provisioning origin passed to `createUser`; the creation seam adds `action: "create-user"` to build {@link ValidateUserInfoSource}. */
|
|
65
|
+
type UserProvisioningSource = {
|
|
66
|
+
method: ValidateUserInfoMethod; /** Provider id and raw profile; present iff `method` is `"oauth"`. */
|
|
67
|
+
oauth?: ValidateUserInfoOAuthInfo | undefined; /** Provider id and raw profile; present iff `method` is `"sso-oidc"` or `"sso-saml"`. */
|
|
68
|
+
sso?: ValidateUserInfoSSOInfo | undefined;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* The context passed to `validateUserInfo`: the lifecycle
|
|
72
|
+
* {@link ValidateUserInfoAction}, the {@link ValidateUserInfoMethod}, and (for
|
|
73
|
+
* OAuth/SSO provider methods) protocol-specific provider metadata.
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* // Scope to one OAuth provider:
|
|
77
|
+
* if (source.oauth?.providerId !== "google") return;
|
|
78
|
+
* // Branch on the method:
|
|
79
|
+
* if (source.method === "anonymous") return { error: "no_anonymous" };
|
|
80
|
+
* // Inspect SSO claims:
|
|
81
|
+
* if (source.method === "sso-saml" && source.sso?.profile?.department !== "eng") {
|
|
82
|
+
* return { error: "invalid_department" };
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
type ValidateUserInfoSource = UserProvisioningSource & {
|
|
87
|
+
action: ValidateUserInfoAction;
|
|
88
|
+
};
|
|
89
|
+
type ValidateUserInfoResult = {
|
|
90
|
+
/** A short, machine-readable rejection code, surfaced to the client. */error: string;
|
|
91
|
+
/**
|
|
92
|
+
* A human-readable reason, surfaced to the client. Do not put sensitive
|
|
93
|
+
* details here.
|
|
94
|
+
*/
|
|
95
|
+
errorDescription?: string | undefined;
|
|
96
|
+
};
|
|
30
97
|
/**
|
|
31
98
|
* Configuration for dynamic base URL resolution.
|
|
32
99
|
* Allows Better Auth to work with multiple domains (e.g., Vercel preview deployments).
|
|
@@ -71,8 +138,30 @@ type DynamicBaseURLConfig = {
|
|
|
71
138
|
*/
|
|
72
139
|
type BaseURLConfig = string | DynamicBaseURLConfig;
|
|
73
140
|
interface BetterAuthRateLimitStorage {
|
|
74
|
-
|
|
75
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Atomically records one request against `key` within the rolling `window`
|
|
143
|
+
* (in seconds) and reports whether it is allowed.
|
|
144
|
+
*
|
|
145
|
+
* When `allowed` is true the count was incremented within the active window,
|
|
146
|
+
* or the window had elapsed and was reset to start at 1. When `allowed` is
|
|
147
|
+
* false the limit was already reached and `retryAfter` is the number of
|
|
148
|
+
* seconds until the window frees up.
|
|
149
|
+
*
|
|
150
|
+
* Performing the check and the increment in a single step closes the
|
|
151
|
+
* concurrent-bypass gap of the separate `get`/`set` path: N simultaneous
|
|
152
|
+
* requests can no longer all pass a stale read before any increment lands.
|
|
153
|
+
*
|
|
154
|
+
* Custom storages must implement this operation directly. Better Auth no
|
|
155
|
+
* longer accepts separate `get`/`set` rate-limit storage because that shape
|
|
156
|
+
* cannot enforce a distributed limit under concurrent requests.
|
|
157
|
+
*/
|
|
158
|
+
consume: (key: string, rule: {
|
|
159
|
+
window: number;
|
|
160
|
+
max: number;
|
|
161
|
+
}) => Promise<{
|
|
162
|
+
allowed: boolean;
|
|
163
|
+
retryAfter: number | null;
|
|
164
|
+
}>;
|
|
76
165
|
}
|
|
77
166
|
type BetterAuthRateLimitRule = {
|
|
78
167
|
/**
|
|
@@ -147,7 +236,7 @@ type BetterAuthAdvancedOptions = {
|
|
|
147
236
|
* @example ["x-client-ip", "x-forwarded-for", "cf-connecting-ip"]
|
|
148
237
|
*
|
|
149
238
|
* @default
|
|
150
|
-
* @link https://github.com/better-auth/better-auth/blob/main/packages/
|
|
239
|
+
* @link https://github.com/better-auth/better-auth/blob/main/packages/core/src/utils/ip.ts
|
|
151
240
|
*/
|
|
152
241
|
ipAddressHeaders?: string[];
|
|
153
242
|
/**
|
|
@@ -157,12 +246,28 @@ type BetterAuthAdvancedOptions = {
|
|
|
157
246
|
*/
|
|
158
247
|
disableIpTracking?: boolean;
|
|
159
248
|
/**
|
|
160
|
-
* IPv6
|
|
161
|
-
*
|
|
249
|
+
* IPv6 prefix length used to collapse addresses before rate-limit keying.
|
|
250
|
+
* Any integer from 0 to 128 is accepted; common values are 32, 48, 56, 64, 128.
|
|
251
|
+
* Out-of-range values fall back to safe behavior (negative -> mask all, > 128 -> no mask).
|
|
162
252
|
*
|
|
163
253
|
* @default 64
|
|
164
254
|
*/
|
|
165
|
-
ipv6Subnet?:
|
|
255
|
+
ipv6Subnet?: number;
|
|
256
|
+
/**
|
|
257
|
+
* Trusted reverse-proxy IPs or CIDR ranges. When set, a forwarded IP
|
|
258
|
+
* chain is walked right to left, trusted hops are skipped, and the
|
|
259
|
+
* first untrusted address is the client IP. Unset trusts only
|
|
260
|
+
* single-value IP headers. Use the actual address or subnet of your
|
|
261
|
+
* proxies, not a broad private range that also covers clients.
|
|
262
|
+
*
|
|
263
|
+
* This only interprets the forwarded header chain and cannot verify
|
|
264
|
+
* the direct sender. It is safe only when your origin is reachable
|
|
265
|
+
* through these proxies and clients cannot set forwarded headers
|
|
266
|
+
* directly.
|
|
267
|
+
*
|
|
268
|
+
* @example ["192.0.2.10", "10.0.0.0/24"]
|
|
269
|
+
*/
|
|
270
|
+
trustedProxies?: string[];
|
|
166
271
|
} | undefined;
|
|
167
272
|
/**
|
|
168
273
|
* Force cookies to always use the `Secure` attribute. By default,
|
|
@@ -683,6 +788,30 @@ type BetterAuthOptions = {
|
|
|
683
788
|
* User configuration
|
|
684
789
|
*/
|
|
685
790
|
user?: (BetterAuthDBOptions<"user", keyof BaseUser> & {
|
|
791
|
+
/**
|
|
792
|
+
* Gate which identities Better Auth admits. Called just before
|
|
793
|
+
* `create-user`, `link-account`, and (for OAuth) `sign-in`, across
|
|
794
|
+
* every authentication method, including stateless setups with no
|
|
795
|
+
* persistent database. On `sign-in` the hook receives the *fresh*
|
|
796
|
+
* provider email and profile, so a domain policy can reject a user
|
|
797
|
+
* whose provider identity moved out of bounds.
|
|
798
|
+
*
|
|
799
|
+
* Non-provider returning sign-ins are not re-validated; use the admin
|
|
800
|
+
* plugin's ban controls or a `databaseHooks.session.create.before`
|
|
801
|
+
* hook for those.
|
|
802
|
+
*
|
|
803
|
+
* Return nothing to allow; return `{ error }` to reject. Browser flows
|
|
804
|
+
* redirect to the configured error URL; programmatic flows surface a
|
|
805
|
+
* `403`.
|
|
806
|
+
*
|
|
807
|
+
* TODO: rename to `validateUser` (and the `ValidateUserInfo*` types).
|
|
808
|
+
* "UserInfo" is the OIDC term and misleads for the email/password,
|
|
809
|
+
* SIWE, phone, and admin methods.
|
|
810
|
+
*/
|
|
811
|
+
validateUserInfo?: (data: {
|
|
812
|
+
user: Partial<User> & Record<string, unknown>;
|
|
813
|
+
source: ValidateUserInfoSource;
|
|
814
|
+
}, context: GenericEndpointContext) => Awaitable<void | ValidateUserInfoResult>;
|
|
686
815
|
/**
|
|
687
816
|
* Changing email configuration
|
|
688
817
|
*/
|
|
@@ -824,6 +953,20 @@ type BetterAuthOptions = {
|
|
|
824
953
|
* @default "compact"
|
|
825
954
|
*/
|
|
826
955
|
strategy?: "compact" | "jwt" | "jwe";
|
|
956
|
+
/**
|
|
957
|
+
* JWT-specific configuration for `strategy: "jwt"`.
|
|
958
|
+
*/
|
|
959
|
+
jwt?: {
|
|
960
|
+
/**
|
|
961
|
+
* Which signing key is used for cookie-cache JWTs.
|
|
962
|
+
*
|
|
963
|
+
* - `"secret"`: uses the Better Auth secret with HS256.
|
|
964
|
+
* - `"jwt-plugin"`: uses the installed `jwt()` plugin's asymmetric signing keys.
|
|
965
|
+
*
|
|
966
|
+
* @default "secret"
|
|
967
|
+
*/
|
|
968
|
+
signingKey?: "secret" | "jwt-plugin";
|
|
969
|
+
};
|
|
827
970
|
/**
|
|
828
971
|
* Controls stateless cookie cache refresh behavior.
|
|
829
972
|
*
|
|
@@ -906,6 +1049,25 @@ type BetterAuthOptions = {
|
|
|
906
1049
|
* @default false
|
|
907
1050
|
*/
|
|
908
1051
|
disableImplicitLinking?: boolean;
|
|
1052
|
+
/**
|
|
1053
|
+
* Require the existing local user row to have
|
|
1054
|
+
* `emailVerified: true` before implicit account linking
|
|
1055
|
+
* uses the IdP's `email_verified` claim as ownership
|
|
1056
|
+
* proof. Defaults to `true` so an attacker who
|
|
1057
|
+
* pre-registers an unverified account at a victim's
|
|
1058
|
+
* email cannot have the victim's OAuth identity linked
|
|
1059
|
+
* into the attacker-owned row on first sign-in. Set to
|
|
1060
|
+
* `false` for backward compatibility on apps whose
|
|
1061
|
+
* users sign up via OAuth without verifying their email
|
|
1062
|
+
* locally; understand the takeover risk before doing
|
|
1063
|
+
* so.
|
|
1064
|
+
*
|
|
1065
|
+
* @default true
|
|
1066
|
+
*
|
|
1067
|
+
* @deprecated The option will be removed on the next
|
|
1068
|
+
* minor; the gate will become unconditional.
|
|
1069
|
+
*/
|
|
1070
|
+
requireLocalEmailVerified?: boolean;
|
|
909
1071
|
/**
|
|
910
1072
|
* List of trusted providers. Can be a static array or a function
|
|
911
1073
|
* that returns providers dynamically. The function is called
|
|
@@ -943,7 +1105,11 @@ type BetterAuthOptions = {
|
|
|
943
1105
|
*/
|
|
944
1106
|
allowUnlinkingAll?: boolean;
|
|
945
1107
|
/**
|
|
946
|
-
*
|
|
1108
|
+
* When enabled, linking an account copies the provider's profile onto
|
|
1109
|
+
* the local user, matching the fields persisted on sign-up (`name`,
|
|
1110
|
+
* `image`, and any `mapProfileToUser` fields). The local `email` and
|
|
1111
|
+
* `emailVerified` are never changed, so a link cannot rebind the
|
|
1112
|
+
* account's identity.
|
|
947
1113
|
*
|
|
948
1114
|
* @default false
|
|
949
1115
|
*/
|
|
@@ -976,13 +1142,17 @@ type BetterAuthOptions = {
|
|
|
976
1142
|
* - "cookie": Store state in an encrypted cookie (stateless)
|
|
977
1143
|
* - "database": Store state in the database
|
|
978
1144
|
*
|
|
979
|
-
* @default "cookie"
|
|
1145
|
+
* @default "database" when `database` or `secondaryStorage` is configured, "cookie" otherwise
|
|
980
1146
|
*/
|
|
981
1147
|
storeStateStrategy?: "database" | "cookie";
|
|
982
1148
|
/**
|
|
983
|
-
* Store account data after
|
|
1149
|
+
* Store provider account data after an OAuth flow in an encrypted
|
|
1150
|
+
* cookie. This includes OAuth token material such as access tokens,
|
|
1151
|
+
* refresh tokens, ID tokens, scopes, and token expiry.
|
|
984
1152
|
*
|
|
985
|
-
* This is useful for database-less
|
|
1153
|
+
* This is useful for database-less flows, but large provider tokens can
|
|
1154
|
+
* still hit browser or proxy cookie/header limits even though Better Auth
|
|
1155
|
+
* chunks oversized account cookies.
|
|
986
1156
|
*
|
|
987
1157
|
* @default false
|
|
988
1158
|
*
|
|
@@ -1355,4 +1525,4 @@ type BetterAuthOptions = {
|
|
|
1355
1525
|
};
|
|
1356
1526
|
};
|
|
1357
1527
|
//#endregion
|
|
1358
|
-
export { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption };
|
|
1528
|
+
export { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource };
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import { LiteralString } from "./helper.mjs";
|
|
2
|
-
import { BetterAuthPlugin } from "./plugin.mjs";
|
|
3
2
|
import { BetterAuthOptions } from "./init-options.mjs";
|
|
4
3
|
import { BetterFetch, BetterFetchOption, BetterFetchPlugin } from "@better-fetch/fetch";
|
|
5
4
|
import { Atom, WritableAtom } from "nanostores";
|
|
6
5
|
|
|
7
6
|
//#region src/types/plugin-client.d.ts
|
|
7
|
+
type InferableServerPlugin = {
|
|
8
|
+
id?: LiteralString | undefined;
|
|
9
|
+
endpoints?: Record<string, unknown> | undefined;
|
|
10
|
+
schema?: Record<string, {
|
|
11
|
+
fields: Record<string, unknown>;
|
|
12
|
+
}> | undefined;
|
|
13
|
+
$ERROR_CODES?: Record<string, {
|
|
14
|
+
readonly code: string;
|
|
15
|
+
message: string;
|
|
16
|
+
}> | undefined;
|
|
17
|
+
};
|
|
8
18
|
interface ClientStore {
|
|
9
19
|
notify: (signal: string) => void;
|
|
10
20
|
listen: (signal: string, listener: () => void) => void;
|
|
@@ -71,7 +81,7 @@ interface BetterAuthClientPlugin {
|
|
|
71
81
|
* only used for type inference. don't pass the
|
|
72
82
|
* actual plugin
|
|
73
83
|
*/
|
|
74
|
-
$InferServerPlugin?:
|
|
84
|
+
$InferServerPlugin?: InferableServerPlugin | undefined;
|
|
75
85
|
/**
|
|
76
86
|
* Custom actions
|
|
77
87
|
*/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Awaitable } from "../types/helper.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/async.d.ts
|
|
4
|
+
interface MapConcurrentOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Max in-flight mappers. Non-integer values are floored, then clamped
|
|
7
|
+
* to the range `[1, items.length]`. `NaN` falls back to 1.
|
|
8
|
+
*/
|
|
9
|
+
concurrency: number;
|
|
10
|
+
/**
|
|
11
|
+
* Rejects with `signal.reason` when aborted. In-flight mappers keep
|
|
12
|
+
* running but their results are not returned.
|
|
13
|
+
*/
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Run an async mapper over items with bounded concurrency.
|
|
18
|
+
* Preserves input order in the result. Fails fast on the first rejection.
|
|
19
|
+
*/
|
|
20
|
+
declare function mapConcurrent<T, R>(items: readonly T[], fn: (item: T, index: number) => Awaitable<R>, options: MapConcurrentOptions): Promise<R[]>;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { MapConcurrentOptions, mapConcurrent };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/utils/async.ts
|
|
2
|
+
/**
|
|
3
|
+
* Run an async mapper over items with bounded concurrency.
|
|
4
|
+
* Preserves input order in the result. Fails fast on the first rejection.
|
|
5
|
+
*/
|
|
6
|
+
async function mapConcurrent(items, fn, options) {
|
|
7
|
+
const n = items.length;
|
|
8
|
+
if (n === 0) return [];
|
|
9
|
+
const { signal } = options;
|
|
10
|
+
if (signal?.aborted) throw signal.reason;
|
|
11
|
+
const raw = Math.floor(options.concurrency);
|
|
12
|
+
const width = Math.min(n, raw >= 1 ? raw : 1);
|
|
13
|
+
const results = new Array(n);
|
|
14
|
+
let idx = 0;
|
|
15
|
+
let failed = false;
|
|
16
|
+
const worker = async () => {
|
|
17
|
+
while (!failed && idx < n) {
|
|
18
|
+
if (signal?.aborted) throw signal.reason;
|
|
19
|
+
const i = idx++;
|
|
20
|
+
try {
|
|
21
|
+
results[i] = await fn(items[i], i);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
failed = true;
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
await Promise.all(Array.from({ length: width }, worker));
|
|
29
|
+
return results;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { mapConcurrent };
|