@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
package/dist/api/index.d.mts
CHANGED
|
@@ -8,6 +8,24 @@ import { EndpointContext, EndpointOptions, StrictEndpoint } from "better-call";
|
|
|
8
8
|
import * as _better_auth_core0 from "@better-auth/core";
|
|
9
9
|
|
|
10
10
|
//#region src/api/index.d.ts
|
|
11
|
+
/**
|
|
12
|
+
* Response headers that forbid any intermediary (proxy, CDN, browser) from
|
|
13
|
+
* caching a response body. Credential-bearing responses (access/refresh tokens,
|
|
14
|
+
* ID tokens, client secrets, device codes) must carry them.
|
|
15
|
+
*
|
|
16
|
+
* Set `metadata: { noStore: true }` on an endpoint and {@link createAuthEndpoint}
|
|
17
|
+
* applies these to the responses its handler produces: the success body and any
|
|
18
|
+
* error the handler throws. A request rejected by schema or media-type
|
|
19
|
+
* validation before the handler runs is not covered, and carries no credentials
|
|
20
|
+
* to protect. Spread them into a hand-built `Response` or `APIError`'s headers
|
|
21
|
+
* for the rare endpoint that constructs its own response.
|
|
22
|
+
*
|
|
23
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
|
|
24
|
+
*/
|
|
25
|
+
declare const NO_STORE_HEADERS: {
|
|
26
|
+
readonly "Cache-Control": "no-store";
|
|
27
|
+
readonly Pragma: "no-cache";
|
|
28
|
+
};
|
|
11
29
|
declare const optionsMiddleware: <InputCtx extends better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>>(inputContext: InputCtx) => Promise<AuthContext>;
|
|
12
30
|
declare const createAuthMiddleware: {
|
|
13
31
|
<Options extends better_call0.MiddlewareOptions, R>(options: Options, handler: (ctx: better_call0.MiddlewareContext<Options, {
|
|
@@ -272,7 +290,32 @@ declare const createAuthMiddleware: {
|
|
|
272
290
|
type EndpointHandler<Path extends string, Options extends EndpointOptions, R> = (context: EndpointContext<Path, Options, AuthContext>) => Promise<R>;
|
|
273
291
|
declare function createAuthEndpoint<Path extends string, Options extends EndpointOptions, R>(path: Path, options: Options, handler: EndpointHandler<Path, Options, R>): StrictEndpoint<Path, Options, R>;
|
|
274
292
|
declare function createAuthEndpoint<Path extends string, Options extends EndpointOptions, R>(options: Options, handler: EndpointHandler<Path, Options, R>): StrictEndpoint<Path, Options, R>;
|
|
293
|
+
declare namespace createAuthEndpoint {
|
|
294
|
+
/**
|
|
295
|
+
* Declare a **server-only** endpoint.
|
|
296
|
+
*
|
|
297
|
+
* The endpoint is callable through `auth.api.*` from trusted server code but is
|
|
298
|
+
* never registered on the HTTP router and never emitted into the OpenAPI
|
|
299
|
+
* schema. It takes no path because it has no URL to be reached at.
|
|
300
|
+
*
|
|
301
|
+
* Prefer this over the path-less `createAuthEndpoint({ ... }, handler)` form.
|
|
302
|
+
* Setting `metadata.SERVER_ONLY` makes the intent explicit at the call site and
|
|
303
|
+
* keeps the endpoint off the HTTP surface even if a path is later added by
|
|
304
|
+
* mistake: better-call's router skips an endpoint when its path is missing *or*
|
|
305
|
+
* when `SERVER_ONLY` is set, so the two together are defense in depth. Relying
|
|
306
|
+
* on path omission alone is invisible and one keystroke away from exposure.
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```ts
|
|
310
|
+
* viewBackupCodes: createAuthEndpoint.serverOnly(
|
|
311
|
+
* { method: "POST", body: schema },
|
|
312
|
+
* async (ctx) => { ... },
|
|
313
|
+
* )
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
function serverOnly<Path extends string, Options extends EndpointOptions, R>(options: Options, handler: EndpointHandler<Path, Options, R>): StrictEndpoint<Path, Options, R>;
|
|
317
|
+
}
|
|
275
318
|
type AuthEndpoint<Path extends string, Opts extends EndpointOptions, R> = ReturnType<typeof createAuthEndpoint<Path, Opts, R>>;
|
|
276
319
|
type AuthMiddleware = ReturnType<typeof createAuthMiddleware>;
|
|
277
320
|
//#endregion
|
|
278
|
-
export { AuthEndpoint, AuthMiddleware, createAuthEndpoint, createAuthMiddleware, optionsMiddleware };
|
|
321
|
+
export { AuthEndpoint, AuthMiddleware, NO_STORE_HEADERS, createAuthEndpoint, createAuthMiddleware, optionsMiddleware };
|
package/dist/api/index.mjs
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
import { runWithEndpointContext } from "../context/endpoint-context.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { isAPIError } from "../utils/is-api-error.mjs";
|
|
3
|
+
import { createEndpoint, createMiddleware, kAPIErrorHeaderSymbol } from "better-call";
|
|
3
4
|
//#region src/api/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Response headers that forbid any intermediary (proxy, CDN, browser) from
|
|
7
|
+
* caching a response body. Credential-bearing responses (access/refresh tokens,
|
|
8
|
+
* ID tokens, client secrets, device codes) must carry them.
|
|
9
|
+
*
|
|
10
|
+
* Set `metadata: { noStore: true }` on an endpoint and {@link createAuthEndpoint}
|
|
11
|
+
* applies these to the responses its handler produces: the success body and any
|
|
12
|
+
* error the handler throws. A request rejected by schema or media-type
|
|
13
|
+
* validation before the handler runs is not covered, and carries no credentials
|
|
14
|
+
* to protect. Spread them into a hand-built `Response` or `APIError`'s headers
|
|
15
|
+
* for the rare endpoint that constructs its own response.
|
|
16
|
+
*
|
|
17
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
|
|
18
|
+
*/
|
|
19
|
+
const NO_STORE_HEADERS = {
|
|
20
|
+
"Cache-Control": "no-store",
|
|
21
|
+
Pragma: "no-cache"
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Better-call's createEndpoint re-throws APIError without exposing the headers
|
|
25
|
+
* accumulated on ctx.responseHeaders (e.g. Set-Cookie from deleteSessionCookie
|
|
26
|
+
* before throw). Attach them to the error via kAPIErrorHeaderSymbol — matching
|
|
27
|
+
* better-call's createMiddleware contract so the outer pipeline can merge them
|
|
28
|
+
* into the response.
|
|
29
|
+
*/
|
|
30
|
+
function attachResponseHeadersToAPIError(responseHeaders, e) {
|
|
31
|
+
if (!isAPIError(e) || !responseHeaders) return;
|
|
32
|
+
Object.defineProperty(e, kAPIErrorHeaderSymbol, {
|
|
33
|
+
enumerable: false,
|
|
34
|
+
configurable: true,
|
|
35
|
+
value: responseHeaders,
|
|
36
|
+
writable: false
|
|
37
|
+
});
|
|
38
|
+
}
|
|
4
39
|
const optionsMiddleware = createMiddleware(async () => {
|
|
5
40
|
/**
|
|
6
41
|
* This will be passed on the instance of
|
|
@@ -17,14 +52,44 @@ function createAuthEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
|
|
|
17
52
|
const path = typeof pathOrOptions === "string" ? pathOrOptions : void 0;
|
|
18
53
|
const options = typeof handlerOrOptions === "object" ? handlerOrOptions : pathOrOptions;
|
|
19
54
|
const handler = typeof handlerOrOptions === "function" ? handlerOrOptions : handlerOrNever;
|
|
55
|
+
const noStore = options.metadata?.noStore === true;
|
|
56
|
+
const wrapped = async (ctx) => {
|
|
57
|
+
if (noStore) for (const [name, value] of Object.entries(NO_STORE_HEADERS)) ctx.setHeader(name, value);
|
|
58
|
+
const runtimeCtx = ctx;
|
|
59
|
+
try {
|
|
60
|
+
return await runWithEndpointContext(ctx, () => handler(ctx));
|
|
61
|
+
} catch (e) {
|
|
62
|
+
attachResponseHeadersToAPIError(runtimeCtx.responseHeaders, e);
|
|
63
|
+
throw e;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
20
66
|
if (path) return createEndpoint(path, {
|
|
21
67
|
...options,
|
|
22
68
|
use: [...options?.use || [], ...use]
|
|
23
|
-
},
|
|
69
|
+
}, wrapped);
|
|
24
70
|
return createEndpoint({
|
|
25
71
|
...options,
|
|
26
72
|
use: [...options?.use || [], ...use]
|
|
27
|
-
},
|
|
73
|
+
}, wrapped);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Set `metadata.SERVER_ONLY` while preserving any existing metadata
|
|
77
|
+
* (`$Infer`, `openapi`, ...).
|
|
78
|
+
*/
|
|
79
|
+
function withServerOnly(options) {
|
|
80
|
+
return {
|
|
81
|
+
...options,
|
|
82
|
+
metadata: {
|
|
83
|
+
...options.metadata,
|
|
84
|
+
SERVER_ONLY: true
|
|
85
|
+
}
|
|
86
|
+
};
|
|
28
87
|
}
|
|
88
|
+
(function(_createAuthEndpoint) {
|
|
89
|
+
function serverOnly(options, handler) {
|
|
90
|
+
return createAuthEndpoint(withServerOnly(options), handler);
|
|
91
|
+
}
|
|
92
|
+
_createAuthEndpoint.serverOnly = serverOnly;
|
|
93
|
+
})(createAuthEndpoint || (createAuthEndpoint = {}));
|
|
29
94
|
//#endregion
|
|
30
|
-
export { createAuthEndpoint, createAuthMiddleware, optionsMiddleware };
|
|
95
|
+
export { NO_STORE_HEADERS, createAuthEndpoint, createAuthMiddleware, optionsMiddleware };
|
package/dist/context/global.mjs
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { DBAdapter, DBTransactionAdapter } from "../db/adapter/index.mjs";
|
|
2
|
+
import { BetterAuthOptions } from "../types/init-options.mjs";
|
|
2
3
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
4
|
|
|
4
5
|
//#region src/context/transaction.d.ts
|
|
6
|
+
type StoredAdapter = DBTransactionAdapter<BetterAuthOptions>;
|
|
5
7
|
type HookContext = {
|
|
6
|
-
adapter:
|
|
8
|
+
adapter: StoredAdapter;
|
|
7
9
|
pendingHooks: Array<() => Promise<void>>;
|
|
10
|
+
isTransactionActive: boolean;
|
|
8
11
|
};
|
|
9
12
|
/**
|
|
10
13
|
* This is for internal use only. Most users should use `getCurrentAdapter` instead.
|
|
@@ -12,9 +15,9 @@ type HookContext = {
|
|
|
12
15
|
* It is exposed for advanced use cases where you need direct access to the AsyncLocalStorage instance.
|
|
13
16
|
*/
|
|
14
17
|
declare const getCurrentDBAdapterAsyncLocalStorage: () => Promise<AsyncLocalStorage<HookContext>>;
|
|
15
|
-
declare const getCurrentAdapter: (fallback: DBTransactionAdapter) => Promise<DBTransactionAdapter
|
|
16
|
-
declare const runWithAdapter: <R>(adapter: DBAdapter
|
|
17
|
-
declare const runWithTransaction: <R>(adapter: DBAdapter
|
|
18
|
+
declare const getCurrentAdapter: <Options extends BetterAuthOptions = BetterAuthOptions>(fallback: DBTransactionAdapter<Options>) => Promise<DBTransactionAdapter<Options>>;
|
|
19
|
+
declare const runWithAdapter: <R, Options extends BetterAuthOptions = BetterAuthOptions>(adapter: DBAdapter<Options>, fn: () => R) => Promise<R>;
|
|
20
|
+
declare const runWithTransaction: <R, Options extends BetterAuthOptions = BetterAuthOptions>(adapter: DBAdapter<Options>, fn: () => R) => Promise<R>;
|
|
18
21
|
/**
|
|
19
22
|
* Queue a hook to be executed after the current transaction commits.
|
|
20
23
|
* If not in a transaction, the hook will execute immediately.
|
|
@@ -35,7 +35,8 @@ const runWithAdapter = async (adapter, fn) => {
|
|
|
35
35
|
try {
|
|
36
36
|
result = await als.run({
|
|
37
37
|
adapter,
|
|
38
|
-
pendingHooks
|
|
38
|
+
pendingHooks,
|
|
39
|
+
isTransactionActive: false
|
|
39
40
|
}, fn);
|
|
40
41
|
} catch (err) {
|
|
41
42
|
error = err;
|
|
@@ -50,9 +51,10 @@ const runWithAdapter = async (adapter, fn) => {
|
|
|
50
51
|
});
|
|
51
52
|
};
|
|
52
53
|
const runWithTransaction = async (adapter, fn) => {
|
|
53
|
-
let called =
|
|
54
|
+
let called = false;
|
|
54
55
|
return ensureAsyncStorage().then(async (als) => {
|
|
55
56
|
called = true;
|
|
57
|
+
if (als.getStore()?.isTransactionActive) return fn();
|
|
56
58
|
const pendingHooks = [];
|
|
57
59
|
let result;
|
|
58
60
|
let error;
|
|
@@ -61,7 +63,8 @@ const runWithTransaction = async (adapter, fn) => {
|
|
|
61
63
|
result = await adapter.transaction(async (trx) => {
|
|
62
64
|
return als.run({
|
|
63
65
|
adapter: trx,
|
|
64
|
-
pendingHooks
|
|
66
|
+
pendingHooks,
|
|
67
|
+
isTransactionActive: true
|
|
65
68
|
}, fn);
|
|
66
69
|
});
|
|
67
70
|
} catch (e) {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
+
import { BetterAuthError } from "../../error/index.mjs";
|
|
1
2
|
import { getAuthTables } from "../get-tables.mjs";
|
|
2
3
|
import { getColorDepth } from "../../env/color-depth.mjs";
|
|
3
4
|
import { TTY_COLORS, createLogger } from "../../env/logger.mjs";
|
|
4
|
-
import { BetterAuthError } from "../../error/index.mjs";
|
|
5
|
-
import { ATTR_DB_COLLECTION_NAME, ATTR_DB_OPERATION_NAME } from "../../instrumentation/attributes.mjs";
|
|
6
|
-
import { withSpan } from "../../instrumentation/tracer.mjs";
|
|
7
5
|
import { safeJSONParse } from "../../utils/json.mjs";
|
|
8
6
|
import { initGetDefaultModelName } from "./get-default-model-name.mjs";
|
|
9
7
|
import { initGetDefaultFieldName } from "./get-default-field-name.mjs";
|
|
@@ -12,6 +10,7 @@ import { initGetFieldAttributes } from "./get-field-attributes.mjs";
|
|
|
12
10
|
import { initGetFieldName } from "./get-field-name.mjs";
|
|
13
11
|
import { initGetModelName } from "./get-model-name.mjs";
|
|
14
12
|
import { withApplyDefault } from "./utils.mjs";
|
|
13
|
+
import { ATTR_DB_COLLECTION_NAME, ATTR_DB_OPERATION_NAME, withSpan } from "@better-auth/core/instrumentation";
|
|
15
14
|
//#region src/db/adapter/factory.ts
|
|
16
15
|
let debugLogs = [];
|
|
17
16
|
let transactionId = -1;
|
|
@@ -58,6 +57,8 @@ const createAdapterFactory = ({ adapter: customAdapter, config: cfg }) => (optio
|
|
|
58
57
|
else if (method === "findMany" && !config.debugLogs.findMany) return;
|
|
59
58
|
else if (method === "delete" && !config.debugLogs.delete) return;
|
|
60
59
|
else if (method === "deleteMany" && !config.debugLogs.deleteMany) return;
|
|
60
|
+
else if (method === "consumeOne" && !config.debugLogs.consumeOne) return;
|
|
61
|
+
else if (method === "incrementOne" && !config.debugLogs.incrementOne) return;
|
|
61
62
|
else if (method === "count" && !config.debugLogs.count) return;
|
|
62
63
|
}
|
|
63
64
|
logger.info(`[${config.adapterName}]`, ...args);
|
|
@@ -457,6 +458,7 @@ const createAdapterFactory = ({ adapter: customAdapter, config: cfg }) => (optio
|
|
|
457
458
|
where: unsafeWhere,
|
|
458
459
|
action: "update"
|
|
459
460
|
});
|
|
461
|
+
if (where.length === 0) return null;
|
|
460
462
|
debugLog({ method: "update" }, `${formatTransactionId(thisTransactionId)} ${formatStep(1, 4)}`, `${formatMethod("update")} ${formatAction("Unsafe Input")}:`, {
|
|
461
463
|
model,
|
|
462
464
|
data: unsafeData
|
|
@@ -515,6 +517,7 @@ const createAdapterFactory = ({ adapter: customAdapter, config: cfg }) => (optio
|
|
|
515
517
|
where,
|
|
516
518
|
update: data
|
|
517
519
|
}));
|
|
520
|
+
if (typeof updatedCount !== "number" || !Number.isFinite(updatedCount)) throw new BetterAuthError(`Adapter "${config.adapterId}" updateMany must return a finite number affected row count.`);
|
|
518
521
|
debugLog({ method: "updateMany" }, `${formatTransactionId(thisTransactionId)} ${formatStep(3, 4)}`, `${formatMethod("updateMany")} ${formatAction("DB Result")}:`, {
|
|
519
522
|
model,
|
|
520
523
|
data: updatedCount
|
|
@@ -677,6 +680,91 @@ const createAdapterFactory = ({ adapter: customAdapter, config: cfg }) => (optio
|
|
|
677
680
|
});
|
|
678
681
|
return res;
|
|
679
682
|
},
|
|
683
|
+
consumeOne: async ({ model: unsafeModel, where: unsafeWhere }) => {
|
|
684
|
+
transactionId++;
|
|
685
|
+
const thisTransactionId = transactionId;
|
|
686
|
+
const model = getModelName(unsafeModel);
|
|
687
|
+
const where = transformWhereClause({
|
|
688
|
+
model: unsafeModel,
|
|
689
|
+
where: unsafeWhere,
|
|
690
|
+
action: "consumeOne"
|
|
691
|
+
});
|
|
692
|
+
unsafeModel = getDefaultModelName(unsafeModel);
|
|
693
|
+
debugLog({ method: "consumeOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(1, 3)}`, `${formatMethod("consumeOne")} ${formatAction("ConsumeOne")}:`, {
|
|
694
|
+
model,
|
|
695
|
+
where
|
|
696
|
+
});
|
|
697
|
+
if (typeof adapterInstance.consumeOne !== "function") throw new BetterAuthError(`Adapter "${config.adapterId}" must implement consumeOne for atomic single-use credential consumption.`);
|
|
698
|
+
const res = await withSpan(`db consumeOne ${model}`, {
|
|
699
|
+
[ATTR_DB_OPERATION_NAME]: "consumeOne",
|
|
700
|
+
[ATTR_DB_COLLECTION_NAME]: model
|
|
701
|
+
}, () => adapterInstance.consumeOne({
|
|
702
|
+
model,
|
|
703
|
+
where
|
|
704
|
+
}));
|
|
705
|
+
debugLog({ method: "consumeOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(2, 3)}`, `${formatMethod("consumeOne")} ${formatAction("DB Result")}:`, {
|
|
706
|
+
model,
|
|
707
|
+
data: res
|
|
708
|
+
});
|
|
709
|
+
let transformed = res;
|
|
710
|
+
if (!config.disableTransformOutput && res) transformed = await transformOutput(res, unsafeModel, void 0, void 0);
|
|
711
|
+
debugLog({ method: "consumeOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(3, 3)}`, `${formatMethod("consumeOne")} ${formatAction("Parsed Result")}:`, {
|
|
712
|
+
model,
|
|
713
|
+
data: transformed
|
|
714
|
+
});
|
|
715
|
+
return transformed;
|
|
716
|
+
},
|
|
717
|
+
incrementOne: async ({ model: unsafeModel, where: unsafeWhere, increment: unsafeIncrement, set: unsafeSet }) => {
|
|
718
|
+
const hasIncrement = Object.keys(unsafeIncrement).length > 0;
|
|
719
|
+
const hasSet = !!unsafeSet && Object.keys(unsafeSet).length > 0;
|
|
720
|
+
if (!hasIncrement && !hasSet) throw new BetterAuthError("incrementOne requires a non-empty `increment` or `set`; both were empty.");
|
|
721
|
+
transactionId++;
|
|
722
|
+
const thisTransactionId = transactionId;
|
|
723
|
+
const model = getModelName(unsafeModel);
|
|
724
|
+
const where = transformWhereClause({
|
|
725
|
+
model: unsafeModel,
|
|
726
|
+
where: unsafeWhere,
|
|
727
|
+
action: "incrementOne"
|
|
728
|
+
});
|
|
729
|
+
unsafeModel = getDefaultModelName(unsafeModel);
|
|
730
|
+
debugLog({ method: "incrementOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(1, 3)}`, `${formatMethod("incrementOne")} ${formatAction("IncrementOne")}:`, {
|
|
731
|
+
model,
|
|
732
|
+
where,
|
|
733
|
+
increment: unsafeIncrement,
|
|
734
|
+
set: unsafeSet
|
|
735
|
+
});
|
|
736
|
+
if (typeof adapterInstance.incrementOne !== "function") throw new BetterAuthError(`Adapter "${config.adapterId}" must implement incrementOne for atomic guarded counter updates.`);
|
|
737
|
+
const mappedKeys = config.mapKeysTransformInput ?? {};
|
|
738
|
+
const increment = {};
|
|
739
|
+
for (const [field, delta] of Object.entries(unsafeIncrement)) increment[mappedKeys[field] || getFieldName({
|
|
740
|
+
model: unsafeModel,
|
|
741
|
+
field
|
|
742
|
+
})] = delta;
|
|
743
|
+
let set;
|
|
744
|
+
if (unsafeSet && !config.disableTransformInput) set = await transformInput(unsafeSet, unsafeModel, "update");
|
|
745
|
+
else set = unsafeSet;
|
|
746
|
+
if (Object.keys(increment).length === 0 && (!set || Object.keys(set).length === 0)) throw new BetterAuthError("incrementOne resolved to an empty update: every increment/set field was unknown to the schema or transformed away.");
|
|
747
|
+
const res = await withSpan(`db incrementOne ${model}`, {
|
|
748
|
+
[ATTR_DB_OPERATION_NAME]: "incrementOne",
|
|
749
|
+
[ATTR_DB_COLLECTION_NAME]: model
|
|
750
|
+
}, () => adapterInstance.incrementOne({
|
|
751
|
+
model,
|
|
752
|
+
where,
|
|
753
|
+
increment,
|
|
754
|
+
set
|
|
755
|
+
}));
|
|
756
|
+
debugLog({ method: "incrementOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(2, 3)}`, `${formatMethod("incrementOne")} ${formatAction("DB Result")}:`, {
|
|
757
|
+
model,
|
|
758
|
+
data: res
|
|
759
|
+
});
|
|
760
|
+
let transformed = res;
|
|
761
|
+
if (!config.disableTransformOutput && res) transformed = await transformOutput(res, unsafeModel, void 0, void 0);
|
|
762
|
+
debugLog({ method: "incrementOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(3, 3)}`, `${formatMethod("incrementOne")} ${formatAction("Parsed Result")}:`, {
|
|
763
|
+
model,
|
|
764
|
+
data: transformed
|
|
765
|
+
});
|
|
766
|
+
return transformed;
|
|
767
|
+
},
|
|
680
768
|
count: async ({ model: unsafeModel, where: unsafeWhere }) => {
|
|
681
769
|
transactionId++;
|
|
682
770
|
const thisTransactionId = transactionId;
|
|
@@ -40,12 +40,12 @@ const initGetIdField = ({ usePlural, schema, disableIdGeneration, options, custo
|
|
|
40
40
|
if (useUUIDs) {
|
|
41
41
|
if (shouldGenerateId && !forceAllowId) return value;
|
|
42
42
|
if (disableIdGeneration) return void 0;
|
|
43
|
-
if (supportsUUIDs) return void 0;
|
|
44
43
|
if (forceAllowId && typeof value === "string") if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) return value;
|
|
45
44
|
else {
|
|
46
45
|
const stack = (/* @__PURE__ */ new Error()).stack?.split("\n").filter((_, i) => i !== 1).join("\n").replace("Error:", "");
|
|
47
46
|
logger.warn("[Adapter Factory] - Invalid UUID value for field `id` provided when `forceAllowId` is true. Generating a new UUID.", stack);
|
|
48
47
|
}
|
|
48
|
+
if (supportsUUIDs) return void 0;
|
|
49
49
|
if (typeof value !== "string" && !supportsUUIDs) return crypto.randomUUID();
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
@@ -22,6 +22,8 @@ type DBAdapterDebugLogOption = boolean | {
|
|
|
22
22
|
findMany?: boolean | undefined;
|
|
23
23
|
delete?: boolean | undefined;
|
|
24
24
|
deleteMany?: boolean | undefined;
|
|
25
|
+
consumeOne?: boolean | undefined;
|
|
26
|
+
incrementOne?: boolean | undefined;
|
|
25
27
|
count?: boolean | undefined;
|
|
26
28
|
} | {
|
|
27
29
|
/**
|
|
@@ -197,7 +199,7 @@ interface DBAdapterFactoryConfig<Options extends BetterAuthOptions = BetterAuthO
|
|
|
197
199
|
/**
|
|
198
200
|
* The action which was called from the adapter.
|
|
199
201
|
*/
|
|
200
|
-
action: "create" | "update" | "findOne" | "findMany" | "updateMany" | "delete" | "deleteMany" | "count";
|
|
202
|
+
action: "create" | "update" | "findOne" | "findMany" | "updateMany" | "delete" | "deleteMany" | "consumeOne" | "incrementOne" | "count";
|
|
201
203
|
/**
|
|
202
204
|
* The model name.
|
|
203
205
|
*/
|
|
@@ -394,8 +396,14 @@ type DBAdapter<Options extends BetterAuthOptions = BetterAuthOptions> = {
|
|
|
394
396
|
where?: Where[] | undefined;
|
|
395
397
|
}) => Promise<number>;
|
|
396
398
|
/**
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
+
* Update a single row matching the where clause.
|
|
400
|
+
*
|
|
401
|
+
* Returns the updated row, or `null` when no row matched. Empty `where`
|
|
402
|
+
* clauses return `null`; use `updateMany` for intentional bulk updates.
|
|
403
|
+
*
|
|
404
|
+
* This is not the race-safe primitive for guarded state transitions. Use
|
|
405
|
+
* `incrementOne` when the predicate is both selector and guard, and use
|
|
406
|
+
* `consumeOne` for single-use destructive reads.
|
|
399
407
|
*/
|
|
400
408
|
update: <T>(data: {
|
|
401
409
|
model: string;
|
|
@@ -415,6 +423,54 @@ type DBAdapter<Options extends BetterAuthOptions = BetterAuthOptions> = {
|
|
|
415
423
|
model: string;
|
|
416
424
|
where: Where[];
|
|
417
425
|
}) => Promise<number>;
|
|
426
|
+
/**
|
|
427
|
+
* Atomically consume a single row matching the where clause: delete it and
|
|
428
|
+
* return the deleted row, or return `null` if no row matched.
|
|
429
|
+
* Implementations MUST NOT delete any additional rows that also match a
|
|
430
|
+
* non-unique predicate.
|
|
431
|
+
*
|
|
432
|
+
* Under concurrent invocation against the same row, exactly one caller
|
|
433
|
+
* receives the row; subsequent racers receive `null`. This is the
|
|
434
|
+
* race-safe primitive for consuming single-use credentials
|
|
435
|
+
* (verification tokens, authorization codes, one-time tokens).
|
|
436
|
+
*
|
|
437
|
+
* Always defined on the factory-wrapped adapter. The underlying
|
|
438
|
+
* `CustomAdapter` must implement this natively; there is no portable
|
|
439
|
+
* fallback that can guarantee cross-process single-use semantics.
|
|
440
|
+
*/
|
|
441
|
+
consumeOne: <T>(data: {
|
|
442
|
+
model: string;
|
|
443
|
+
where: Where[];
|
|
444
|
+
}) => Promise<T | null>;
|
|
445
|
+
/**
|
|
446
|
+
* Atomically apply signed numeric deltas to a single row matching the where
|
|
447
|
+
* clause. For each entry in `increment`, the operation applies
|
|
448
|
+
* `field = field + delta` in one atomic step; a negative delta decrements.
|
|
449
|
+
*
|
|
450
|
+
* The `where` clause is both the selector AND the guard: comparison
|
|
451
|
+
* operators are honored, so passing `{ field: "remaining", operator: "gt",
|
|
452
|
+
* value: 0 }` only mutates the row while `remaining` is still above zero.
|
|
453
|
+
* When the guard matches no row, the operation makes no change and returns
|
|
454
|
+
* `null`.
|
|
455
|
+
*
|
|
456
|
+
* The optional `set` map assigns absolute values to fields in the same
|
|
457
|
+
* atomic operation, alongside the increments.
|
|
458
|
+
*
|
|
459
|
+
* Returns the updated row, or `null` when the guard matched no row. Under
|
|
460
|
+
* concurrent invocation against the same row, this is the race-safe
|
|
461
|
+
* primitive for guarded counter updates (e.g. decrementing a remaining-uses
|
|
462
|
+
* counter only while it is still positive).
|
|
463
|
+
*
|
|
464
|
+
* Always defined on the factory-wrapped adapter. The underlying
|
|
465
|
+
* `CustomAdapter` must implement this natively; there is no portable
|
|
466
|
+
* fallback that can guarantee guarded counter semantics across runtimes.
|
|
467
|
+
*/
|
|
468
|
+
incrementOne: <T>(data: {
|
|
469
|
+
model: string;
|
|
470
|
+
where: Where[];
|
|
471
|
+
increment: Record<string, number>;
|
|
472
|
+
set?: Record<string, unknown> | undefined;
|
|
473
|
+
}) => Promise<T | null>;
|
|
418
474
|
/**
|
|
419
475
|
* Execute multiple operations in a transaction.
|
|
420
476
|
* If the adapter doesn't support transactions, operations will be executed sequentially.
|
|
@@ -496,6 +552,34 @@ interface CustomAdapter {
|
|
|
496
552
|
model: string;
|
|
497
553
|
where: CleanedWhere[];
|
|
498
554
|
}) => Promise<number>;
|
|
555
|
+
/**
|
|
556
|
+
* Native atomic single-row consume.
|
|
557
|
+
* Implementing this method natively (e.g. `DELETE ... RETURNING *`,
|
|
558
|
+
* `findOneAndDelete`, `OUTPUT deleted.*`) gives one round trip and the
|
|
559
|
+
* strongest race-safety guarantee. Implementations must delete at most
|
|
560
|
+
* one matching row.
|
|
561
|
+
*/
|
|
562
|
+
consumeOne: <T>(data: {
|
|
563
|
+
model: string;
|
|
564
|
+
where: CleanedWhere[];
|
|
565
|
+
}) => Promise<T | null>;
|
|
566
|
+
/**
|
|
567
|
+
* Native atomic guarded counter mutation. Applies
|
|
568
|
+
* `field = field + delta` for each entry in `increment` (negative deltas
|
|
569
|
+
* decrement), with `where` acting as both selector and guard and `set`
|
|
570
|
+
* assigning absolute values in the same operation. Returns the updated row,
|
|
571
|
+
* or `null` when the guard matched no row.
|
|
572
|
+
*
|
|
573
|
+
* Implementing this natively (e.g. `UPDATE ... SET n = n + $delta WHERE ...
|
|
574
|
+
* RETURNING *`) gives one round trip and the strongest race-safety
|
|
575
|
+
* guarantee.
|
|
576
|
+
*/
|
|
577
|
+
incrementOne: <T>(data: {
|
|
578
|
+
model: string;
|
|
579
|
+
where: CleanedWhere[];
|
|
580
|
+
increment: Record<string, number>;
|
|
581
|
+
set?: Record<string, unknown> | undefined;
|
|
582
|
+
}) => Promise<T | null>;
|
|
499
583
|
count: ({
|
|
500
584
|
model,
|
|
501
585
|
where
|
|
@@ -94,7 +94,7 @@ type AdapterFactoryCustomizeAdapterCreator = (config: {
|
|
|
94
94
|
}: {
|
|
95
95
|
where: W;
|
|
96
96
|
model: string;
|
|
97
|
-
action: "create" | "update" | "findOne" | "findMany" | "updateMany" | "delete" | "deleteMany" | "count";
|
|
97
|
+
action: "create" | "update" | "findOne" | "findMany" | "updateMany" | "delete" | "deleteMany" | "consumeOne" | "incrementOne" | "count";
|
|
98
98
|
}) => W extends undefined ? undefined : CleanedWhere[];
|
|
99
99
|
}) => CustomAdapter;
|
|
100
100
|
type AdapterTestDebugLogs = {
|
package/dist/db/get-tables.mjs
CHANGED
|
@@ -8,7 +8,8 @@ const getAuthTables = (options) => {
|
|
|
8
8
|
...acc[key]?.fields,
|
|
9
9
|
...value.fields
|
|
10
10
|
},
|
|
11
|
-
modelName: value.modelName || key
|
|
11
|
+
modelName: value.modelName || key,
|
|
12
|
+
disableMigrations: value.disableMigration ?? acc[key]?.disableMigrations
|
|
12
13
|
};
|
|
13
14
|
return acc;
|
|
14
15
|
}, {});
|
package/dist/db/type.d.mts
CHANGED
|
@@ -141,6 +141,23 @@ interface SecondaryStorage {
|
|
|
141
141
|
* @returns - Value of the key
|
|
142
142
|
*/
|
|
143
143
|
get: (key: string) => Awaitable<unknown>;
|
|
144
|
+
/**
|
|
145
|
+
* Atomically get a value and delete it from storage.
|
|
146
|
+
*/
|
|
147
|
+
getAndDelete: (key: string) => Awaitable<unknown>;
|
|
148
|
+
/**
|
|
149
|
+
* Atomically increment the counter at `key` by one, returning the
|
|
150
|
+
* post-increment value.
|
|
151
|
+
*
|
|
152
|
+
* When the key is absent, it is created with a value of `1` and the given
|
|
153
|
+
* `ttl` (in SECONDS). The TTL is applied only on creation; later increments
|
|
154
|
+
* never extend it, so the counter expires a fixed window after it was first
|
|
155
|
+
* created.
|
|
156
|
+
*
|
|
157
|
+
* Required so secondary-storage-backed rate limiting can enforce the limit
|
|
158
|
+
* in one distributed-safe operation.
|
|
159
|
+
*/
|
|
160
|
+
increment: (key: string, ttl: number) => Awaitable<number>;
|
|
144
161
|
set: (
|
|
145
162
|
/**
|
|
146
163
|
* Key to store
|
package/dist/env/env-impl.mjs
CHANGED
|
@@ -27,7 +27,7 @@ const env = new Proxy(_envShim, {
|
|
|
27
27
|
function toBoolean(val) {
|
|
28
28
|
return val ? val !== "false" : false;
|
|
29
29
|
}
|
|
30
|
-
const nodeENV =
|
|
30
|
+
const nodeENV = env.NODE_ENV ?? "";
|
|
31
31
|
/** Detect if `NODE_ENV` environment variable is `production` */
|
|
32
32
|
const isProduction = nodeENV === "production";
|
|
33
33
|
/** Detect if `NODE_ENV` environment variable is `dev` or `development` */
|
package/dist/error/codes.d.mts
CHANGED
|
@@ -36,6 +36,7 @@ declare const BASE_ERROR_CODES: {
|
|
|
36
36
|
USER_ALREADY_EXISTS: RawError<"USER_ALREADY_EXISTS">;
|
|
37
37
|
USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: RawError<"USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL">;
|
|
38
38
|
EMAIL_CAN_NOT_BE_UPDATED: RawError<"EMAIL_CAN_NOT_BE_UPDATED">;
|
|
39
|
+
CHANGE_EMAIL_DISABLED: RawError<"CHANGE_EMAIL_DISABLED">;
|
|
39
40
|
CREDENTIAL_ACCOUNT_NOT_FOUND: RawError<"CREDENTIAL_ACCOUNT_NOT_FOUND">;
|
|
40
41
|
ACCOUNT_NOT_FOUND: RawError<"ACCOUNT_NOT_FOUND">;
|
|
41
42
|
SESSION_EXPIRED: RawError<"SESSION_EXPIRED">;
|
package/dist/error/codes.mjs
CHANGED
|
@@ -23,6 +23,7 @@ const BASE_ERROR_CODES = defineErrorCodes({
|
|
|
23
23
|
USER_ALREADY_EXISTS: "User already exists.",
|
|
24
24
|
USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: "User already exists. Use another email.",
|
|
25
25
|
EMAIL_CAN_NOT_BE_UPDATED: "Email can not be updated",
|
|
26
|
+
CHANGE_EMAIL_DISABLED: "Change email is disabled",
|
|
26
27
|
CREDENTIAL_ACCOUNT_NOT_FOUND: "Credential account not found",
|
|
27
28
|
SESSION_EXPIRED: "Session expired. Re-authenticate to perform this action.",
|
|
28
29
|
FAILED_TO_UNLINK_LAST_ACCOUNT: "You can't unlink your last account",
|
package/dist/error/index.d.mts
CHANGED
|
@@ -7,7 +7,14 @@ declare class BetterAuthError extends Error {
|
|
|
7
7
|
cause?: unknown | undefined;
|
|
8
8
|
});
|
|
9
9
|
}
|
|
10
|
+
type BaseAPIErrorInstance = InstanceType<typeof APIError$1>;
|
|
10
11
|
declare class APIError extends APIError$1 {
|
|
12
|
+
status: BaseAPIErrorInstance["status"];
|
|
13
|
+
body: BaseAPIErrorInstance["body"];
|
|
14
|
+
headers: BaseAPIErrorInstance["headers"];
|
|
15
|
+
statusCode: BaseAPIErrorInstance["statusCode"];
|
|
16
|
+
message: string;
|
|
17
|
+
errorStack: BaseAPIErrorInstance["errorStack"];
|
|
11
18
|
constructor(...args: ConstructorParameters<typeof APIError$1>);
|
|
12
19
|
static fromStatus(status: ConstructorParameters<typeof APIError$1>[0], body?: ConstructorParameters<typeof APIError$1>[1]): APIError;
|
|
13
20
|
static from(status: ConstructorParameters<typeof APIError$1>[0], error: {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Awaitable, AwaitableFunction, LiteralString, LiteralUnion, Prettify, Primitive, UnionToIntersection } from "./types/helper.mjs";
|
|
2
2
|
import { BetterAuthPlugin, BetterAuthPluginErrorCodePart, HookEndpointContext } from "./types/plugin.mjs";
|
|
3
|
-
import { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption } from "./types/init-options.mjs";
|
|
3
|
+
import { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource } from "./types/init-options.mjs";
|
|
4
4
|
import { BetterAuthCookie, BetterAuthCookies } from "./types/cookie.mjs";
|
|
5
5
|
import { SecretConfig } from "./types/secret.mjs";
|
|
6
6
|
import { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext } from "./types/context.mjs";
|
|
7
7
|
import { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientFetchOption, ClientStore } from "./types/plugin-client.mjs";
|
|
8
8
|
import { StandardSchemaV1 } from "./types/index.mjs";
|
|
9
|
-
export { AuthContext, Awaitable, AwaitableFunction, BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthClientOptions, BetterAuthClientPlugin, BetterAuthCookie, BetterAuthCookies, BetterAuthDBOptions, BetterAuthOptions, BetterAuthPlugin, BetterAuthPluginErrorCodePart, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, ClientAtomListener, ClientFetchOption, ClientStore, DynamicBaseURLConfig, GenerateIdFn, GenericEndpointContext, HookEndpointContext, InfoContext, InternalAdapter, LiteralString, LiteralUnion, PluginContext, Prettify, Primitive, SecretConfig, StandardSchemaV1, StoreIdentifierOption, UnionToIntersection };
|
|
9
|
+
export { AuthContext, Awaitable, AwaitableFunction, BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthClientOptions, BetterAuthClientPlugin, BetterAuthCookie, BetterAuthCookies, BetterAuthDBOptions, BetterAuthOptions, BetterAuthPlugin, BetterAuthPluginErrorCodePart, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, ClientAtomListener, ClientFetchOption, ClientStore, DynamicBaseURLConfig, GenerateIdFn, GenericEndpointContext, HookEndpointContext, InfoContext, InternalAdapter, LiteralString, LiteralUnion, PluginContext, Prettify, Primitive, SecretConfig, StandardSchemaV1, StoreIdentifierOption, UnionToIntersection, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { noopOpenTelemetryAPI } from "./noop.mjs";
|
|
2
|
+
//#region src/instrumentation/api.ts
|
|
3
|
+
let openTelemetryAPIPromise;
|
|
4
|
+
let openTelemetryAPI;
|
|
5
|
+
function getOpenTelemetryAPI() {
|
|
6
|
+
if (!openTelemetryAPIPromise) openTelemetryAPIPromise = import("@opentelemetry/api").then((mod) => {
|
|
7
|
+
openTelemetryAPI = mod;
|
|
8
|
+
}).catch(() => void 0);
|
|
9
|
+
return openTelemetryAPI ?? noopOpenTelemetryAPI;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { getOpenTelemetryAPI };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/instrumentation/noop.ts
|
|
2
|
+
function createNoopSpan() {
|
|
3
|
+
const span = {
|
|
4
|
+
end() {},
|
|
5
|
+
setAttribute(_key, _value) {},
|
|
6
|
+
setStatus(_status) {},
|
|
7
|
+
recordException(_exception) {},
|
|
8
|
+
updateName(_name) {
|
|
9
|
+
return span;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
return span;
|
|
13
|
+
}
|
|
14
|
+
function createNoopTracer(noopSpan) {
|
|
15
|
+
function startActiveSpan(_name, ...rest) {
|
|
16
|
+
const fn = rest[rest.length - 1];
|
|
17
|
+
return fn(noopSpan);
|
|
18
|
+
}
|
|
19
|
+
return { startActiveSpan };
|
|
20
|
+
}
|
|
21
|
+
function createNoopTraceAPI() {
|
|
22
|
+
const noopTracer = createNoopTracer(createNoopSpan());
|
|
23
|
+
return {
|
|
24
|
+
getTracer(_name, _version) {
|
|
25
|
+
return noopTracer;
|
|
26
|
+
},
|
|
27
|
+
getActiveSpan() {}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function createNoopOpenTelemetryAPI() {
|
|
31
|
+
return {
|
|
32
|
+
SpanStatusCode: {
|
|
33
|
+
UNSET: 0,
|
|
34
|
+
OK: 1,
|
|
35
|
+
ERROR: 2
|
|
36
|
+
},
|
|
37
|
+
trace: createNoopTraceAPI()
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const noopOpenTelemetryAPI = createNoopOpenTelemetryAPI();
|
|
41
|
+
//#endregion
|
|
42
|
+
export { noopOpenTelemetryAPI };
|