@better-auth/core 1.5.0-beta.6 → 1.5.0-beta.7

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.
Files changed (43) hide show
  1. package/.turbo/turbo-build.log +26 -22
  2. package/dist/api/index.d.mts +10 -20
  3. package/dist/context/endpoint-context.mjs +6 -6
  4. package/dist/context/global.d.mts +7 -0
  5. package/dist/context/global.mjs +37 -0
  6. package/dist/context/index.d.mts +2 -1
  7. package/dist/context/index.mjs +2 -1
  8. package/dist/context/request-state.mjs +6 -6
  9. package/dist/context/transaction.d.mts +1 -1
  10. package/dist/context/transaction.mjs +6 -6
  11. package/dist/db/adapter/factory.mjs +13 -13
  12. package/dist/db/adapter/get-default-model-name.mjs +1 -1
  13. package/dist/db/adapter/get-id-field.d.mts +1 -1
  14. package/dist/db/adapter/get-id-field.mjs +2 -2
  15. package/dist/error/index.d.mts +3 -1
  16. package/dist/error/index.mjs +2 -3
  17. package/dist/index.d.mts +4 -4
  18. package/dist/social-providers/apple.mjs +3 -1
  19. package/dist/social-providers/gitlab.mjs +1 -1
  20. package/dist/types/context.d.mts +17 -16
  21. package/dist/types/cookie.d.mts +9 -17
  22. package/dist/types/index.d.mts +3 -3
  23. package/dist/types/init-options.d.mts +17 -29
  24. package/dist/utils/url.d.mts +20 -0
  25. package/dist/utils/url.mjs +32 -0
  26. package/package.json +1 -1
  27. package/src/context/endpoint-context.ts +7 -15
  28. package/src/context/global.ts +57 -0
  29. package/src/context/index.ts +1 -0
  30. package/src/context/request-state.ts +7 -12
  31. package/src/context/transaction.ts +7 -16
  32. package/src/db/adapter/factory.ts +13 -13
  33. package/src/db/adapter/get-default-model-name.ts +1 -1
  34. package/src/db/adapter/get-id-field.ts +2 -2
  35. package/src/error/index.ts +2 -3
  36. package/src/social-providers/apple.ts +12 -3
  37. package/src/social-providers/gitlab.ts +1 -1
  38. package/src/types/context.ts +137 -131
  39. package/src/types/cookie.ts +6 -4
  40. package/src/types/index.ts +4 -1
  41. package/src/types/init-options.ts +26 -32
  42. package/src/utils/url.ts +43 -0
  43. package/tsdown.config.ts +8 -0
@@ -9,7 +9,7 @@ import { DBAdapter, Where } from "../db/adapter/index.mjs";
9
9
  import { createLogger } from "../env/logger.mjs";
10
10
  import { OAuthProvider } from "../oauth2/oauth-provider.mjs";
11
11
  import "../oauth2/index.mjs";
12
- import { BetterAuthCookies } from "./cookie.mjs";
12
+ import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
13
13
  import { BetterAuthPlugin } from "./plugin.mjs";
14
14
  import { BetterAuthOptions, BetterAuthRateLimitOptions } from "./init-options.mjs";
15
15
  import { CookieOptions, EndpointContext } from "better-call";
@@ -89,10 +89,7 @@ interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions
89
89
  deleteVerificationByIdentifier(identifier: string): Promise<void>;
90
90
  updateVerificationValue(id: string, data: Partial<Verification>): Promise<Verification>;
91
91
  }
92
- type CreateCookieGetterFn = (cookieName: string, overrideAttributes?: Partial<CookieOptions> | undefined) => {
93
- name: string;
94
- attributes: CookieOptions;
95
- };
92
+ type CreateCookieGetterFn = (cookieName: string, overrideAttributes?: Partial<CookieOptions> | undefined) => BetterAuthCookie;
96
93
  type CheckPasswordFn<Options extends BetterAuthOptions = BetterAuthOptions> = (userId: string, ctx: GenericEndpointContext<Options>) => Promise<boolean>;
97
94
  type PluginContext = {
98
95
  getPlugin: <ID extends BetterAuthPluginRegistryIdentifier | LiteralString>(pluginId: ID) => (ID extends BetterAuthPluginRegistryIdentifier ? ReturnType<BetterAuthPluginRegistry<unknown, unknown>[ID]["creator"]> : BetterAuthPlugin) | null;
@@ -111,10 +108,13 @@ type PluginContext = {
111
108
  */
112
109
  hasPlugin: <ID extends BetterAuthPluginRegistryIdentifier | LiteralString>(pluginId: ID) => boolean;
113
110
  };
114
- type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = PluginContext & {
115
- options: Options;
111
+ type InfoContext = {
116
112
  appName: string;
117
113
  baseURL: string;
114
+ version: string;
115
+ };
116
+ type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = PluginContext & InfoContext & {
117
+ options: Options;
118
118
  trustedOrigins: string[];
119
119
  /**
120
120
  * Verifies whether url is a trusted origin according to the "trustedOrigins" configuration
@@ -166,7 +166,7 @@ type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = Plugin
166
166
  window: number;
167
167
  max: number;
168
168
  storage: "memory" | "database" | "secondary-storage";
169
- } & BetterAuthRateLimitOptions;
169
+ } & Omit<BetterAuthRateLimitOptions, "enabled" | "window" | "max" | "storage">;
170
170
  adapter: DBAdapter<Options>;
171
171
  internalAdapter: InternalAdapter<Options>;
172
172
  createAuthCookie: CreateCookieGetterFn;
@@ -205,17 +205,18 @@ type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = Plugin
205
205
  payload: Record<string, any>;
206
206
  }) => Promise<void>;
207
207
  /**
208
- * This skips the origin check for all requests.
208
+ * Skip origin check for requests.
209
209
  *
210
- * set to true by default for `test` environments and `false`
211
- * for other environments.
210
+ * - `true`: Skip for ALL requests (DANGEROUS - disables CSRF protection)
211
+ * - `string[]`: Skip only for specific paths (e.g., SAML callbacks)
212
+ * - `false`: Enable origin check (default)
212
213
  *
213
- * It's inferred from the `options.advanced?.disableCSRFCheck`
214
- * option or `options.advanced?.disableOriginCheck` option.
214
+ * Paths support prefix matching (e.g., "/sso/saml2/callback" matches
215
+ * "/sso/saml2/callback/provider-name").
215
216
  *
216
- * @default false
217
+ * @default false (true in test environments)
217
218
  */
218
- skipOriginCheck: boolean;
219
+ skipOriginCheck: boolean | string[];
219
220
  /**
220
221
  * This skips the CSRF check for all requests.
221
222
  *
@@ -243,4 +244,4 @@ type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = Plugin
243
244
  runInBackgroundOrAwait: (promise: Promise<unknown> | Promise<void> | void | unknown) => Promise<unknown>;
244
245
  };
245
246
  //#endregion
246
- export { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InternalAdapter, PluginContext };
247
+ export { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext };
@@ -1,23 +1,15 @@
1
1
  import { CookieOptions } from "better-call";
2
2
 
3
3
  //#region src/types/cookie.d.ts
4
+ type BetterAuthCookie = {
5
+ name: string;
6
+ attributes: CookieOptions;
7
+ };
4
8
  type BetterAuthCookies = {
5
- sessionToken: {
6
- name: string;
7
- options: CookieOptions;
8
- };
9
- sessionData: {
10
- name: string;
11
- options: CookieOptions;
12
- };
13
- accountData: {
14
- name: string;
15
- options: CookieOptions;
16
- };
17
- dontRememberToken: {
18
- name: string;
19
- options: CookieOptions;
20
- };
9
+ sessionToken: BetterAuthCookie;
10
+ sessionData: BetterAuthCookie;
11
+ accountData: BetterAuthCookie;
12
+ dontRememberToken: BetterAuthCookie;
21
13
  };
22
14
  //#endregion
23
- export { BetterAuthCookies };
15
+ export { BetterAuthCookie, BetterAuthCookies };
@@ -1,8 +1,8 @@
1
1
  import { Awaitable, LiteralString, LiteralUnion, Prettify, Primitive } from "./helper.mjs";
2
- import { BetterAuthCookies } from "./cookie.mjs";
2
+ import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
3
3
  import { BetterAuthPlugin, HookEndpointContext } from "./plugin.mjs";
4
- import { BetterAuthAdvancedOptions, BetterAuthOptions, BetterAuthRateLimitOptions, GenerateIdFn } from "./init-options.mjs";
5
- import { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InternalAdapter, PluginContext } from "./context.mjs";
4
+ import { BetterAuthAdvancedOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, GenerateIdFn } from "./init-options.mjs";
5
+ import { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext } from "./context.mjs";
6
6
  import { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientFetchOption, ClientStore } from "./plugin-client.mjs";
7
7
  import { StandardSchemaV1 as StandardSchemaV1$1 } from "@standard-schema/spec";
8
8
  export { type StandardSchemaV1$1 as StandardSchemaV1 };
@@ -27,46 +27,37 @@ type GenerateIdFn = (options: {
27
27
  model: ModelNames;
28
28
  size?: number | undefined;
29
29
  }) => string | false;
30
- type BetterAuthRateLimitOptions = {
31
- /**
32
- * By default, rate limiting is only
33
- * enabled on production.
34
- */
35
- enabled?: boolean | undefined;
30
+ interface BetterAuthRateLimitStorage {
31
+ get: (key: string) => Promise<RateLimit | null | undefined>;
32
+ set: (key: string, value: RateLimit, update?: boolean | undefined) => Promise<void>;
33
+ }
34
+ type BetterAuthRateLimitRule = {
36
35
  /**
37
36
  * Default window to use for rate limiting. The value
38
37
  * should be in seconds.
39
38
  *
40
39
  * @default 10 seconds
41
40
  */
42
- window?: number | undefined;
41
+ window: number;
43
42
  /**
44
43
  * The default maximum number of requests allowed within the window.
45
44
  *
46
45
  * @default 100 requests
47
46
  */
48
- max?: number | undefined;
47
+ max: number;
48
+ };
49
+ type BetterAuthRateLimitOptions = Optional<BetterAuthRateLimitRule> & {
50
+ /**
51
+ * By default, rate limiting is only
52
+ * enabled on production.
53
+ */
54
+ enabled?: boolean | undefined;
49
55
  /**
50
56
  * Custom rate limit rules to apply to
51
57
  * specific paths.
52
58
  */
53
59
  customRules?: {
54
- [key: string]: {
55
- /**
56
- * The window to use for the custom rule.
57
- */
58
- window: number;
59
- /**
60
- * The maximum number of requests allowed within the window.
61
- */
62
- max: number;
63
- } | false | ((request: Request) => {
64
- window: number;
65
- max: number;
66
- } | false | Promise<{
67
- window: number;
68
- max: number;
69
- } | false>);
60
+ [key: string]: BetterAuthRateLimitRule | false | ((request: Request, currentRule: BetterAuthRateLimitRule) => Awaitable<false | BetterAuthRateLimitRule>);
70
61
  } | undefined;
71
62
  /**
72
63
  * Storage configuration
@@ -95,10 +86,7 @@ type BetterAuthRateLimitOptions = {
95
86
  * NOTE: If custom storage is used storage
96
87
  * is ignored
97
88
  */
98
- customStorage?: {
99
- get: (key: string) => Promise<RateLimit | undefined>;
100
- set: (key: string, value: RateLimit) => Promise<void>;
101
- };
89
+ customStorage?: BetterAuthRateLimitStorage;
102
90
  };
103
91
  type BetterAuthAdvancedOptions = {
104
92
  /**
@@ -1263,4 +1251,4 @@ type BetterAuthOptions = {
1263
1251
  };
1264
1252
  };
1265
1253
  //#endregion
1266
- export { BetterAuthAdvancedOptions, BetterAuthOptions, BetterAuthRateLimitOptions, GenerateIdFn };
1254
+ export { BetterAuthAdvancedOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, GenerateIdFn };
@@ -0,0 +1,20 @@
1
+ //#region src/utils/url.d.ts
2
+ /**
3
+ * Normalizes a request pathname by removing the basePath prefix and trailing slashes.
4
+ * This is useful for matching paths against configured path lists.
5
+ *
6
+ * @param requestUrl - The full request URL
7
+ * @param basePath - The base path of the auth API (e.g., "/api/auth")
8
+ * @returns The normalized path without basePath prefix or trailing slashes,
9
+ * or "/" if URL parsing fails
10
+ *
11
+ * @example
12
+ * normalizePathname("http://localhost:3000/api/auth/sso/saml2/callback/provider1", "/api/auth")
13
+ * // Returns: "/sso/saml2/callback/provider1"
14
+ *
15
+ * normalizePathname("http://localhost:3000/sso/saml2/callback/provider1/", "/")
16
+ * // Returns: "/sso/saml2/callback/provider1"
17
+ */
18
+ declare function normalizePathname(requestUrl: string, basePath: string): string;
19
+ //#endregion
20
+ export { normalizePathname };
@@ -0,0 +1,32 @@
1
+ //#region src/utils/url.ts
2
+ /**
3
+ * Normalizes a request pathname by removing the basePath prefix and trailing slashes.
4
+ * This is useful for matching paths against configured path lists.
5
+ *
6
+ * @param requestUrl - The full request URL
7
+ * @param basePath - The base path of the auth API (e.g., "/api/auth")
8
+ * @returns The normalized path without basePath prefix or trailing slashes,
9
+ * or "/" if URL parsing fails
10
+ *
11
+ * @example
12
+ * normalizePathname("http://localhost:3000/api/auth/sso/saml2/callback/provider1", "/api/auth")
13
+ * // Returns: "/sso/saml2/callback/provider1"
14
+ *
15
+ * normalizePathname("http://localhost:3000/sso/saml2/callback/provider1/", "/")
16
+ * // Returns: "/sso/saml2/callback/provider1"
17
+ */
18
+ function normalizePathname(requestUrl, basePath) {
19
+ let pathname;
20
+ try {
21
+ pathname = new URL(requestUrl).pathname.replace(/\/+$/, "") || "/";
22
+ } catch {
23
+ return "/";
24
+ }
25
+ if (basePath === "/" || basePath === "") return pathname;
26
+ if (pathname === basePath) return "/";
27
+ if (pathname.startsWith(basePath + "/")) return pathname.slice(basePath.length).replace(/\/+$/, "") || "/";
28
+ return pathname;
29
+ }
30
+
31
+ //#endregion
32
+ export { normalizePathname };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/core",
3
- "version": "1.5.0-beta.6",
3
+ "version": "1.5.0-beta.7",
4
4
  "description": "The most comprehensive authentication framework for TypeScript.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -2,6 +2,7 @@ import type { AsyncLocalStorage } from "@better-auth/core/async_hooks";
2
2
  import { getAsyncLocalStorage } from "@better-auth/core/async_hooks";
3
3
  import type { EndpointContext, InputContext } from "better-call";
4
4
  import type { AuthContext } from "../types";
5
+ import { __getBetterAuthGlobal } from "./global";
5
6
 
6
7
  export type AuthEndpointContext = Partial<
7
8
  InputContext<string, any> & EndpointContext<string, any>
@@ -9,24 +10,15 @@ export type AuthEndpointContext = Partial<
9
10
  context: AuthContext;
10
11
  };
11
12
 
12
- const symbol = Symbol.for("better-auth:endpoint-context-async-storage");
13
-
14
- let currentContextAsyncStorage: AsyncLocalStorage<AuthEndpointContext> | null =
15
- null;
16
-
17
13
  const ensureAsyncStorage = async () => {
18
- if (
19
- !currentContextAsyncStorage ||
20
- (globalThis as any)[symbol] === undefined
21
- ) {
14
+ const betterAuthGlobal = __getBetterAuthGlobal();
15
+ if (!betterAuthGlobal.context.endpointContextAsyncStorage) {
22
16
  const AsyncLocalStorage = await getAsyncLocalStorage();
23
- currentContextAsyncStorage = new AsyncLocalStorage();
24
- (globalThis as any)[symbol] = currentContextAsyncStorage;
17
+ betterAuthGlobal.context.endpointContextAsyncStorage =
18
+ new AsyncLocalStorage<AuthEndpointContext>();
25
19
  }
26
- return (
27
- currentContextAsyncStorage ||
28
- ((globalThis as any)[symbol] as AsyncLocalStorage<AuthEndpointContext>)
29
- );
20
+ return betterAuthGlobal.context
21
+ .endpointContextAsyncStorage as AsyncLocalStorage<AuthEndpointContext>;
30
22
  };
31
23
 
32
24
  /**
@@ -0,0 +1,57 @@
1
+ import type { AsyncLocalStorage } from "@better-auth/core/async_hooks";
2
+
3
+ interface BetterAuthGlobal {
4
+ /**
5
+ * The version of BetterAuth.
6
+ */
7
+ version: string;
8
+ /**
9
+ * Used to track the number of BetterAuth instances in the same process.
10
+ *
11
+ * Debugging purposes only.
12
+ */
13
+ epoch: number;
14
+ /**
15
+ * Stores the AsyncLocalStorage instances for each context.
16
+ */
17
+ context: Record<string, AsyncLocalStorage<unknown>>;
18
+ }
19
+
20
+ const symbol = Symbol.for("better-auth:global");
21
+ let bind: BetterAuthGlobal | null = null;
22
+
23
+ const __context: Record<string, AsyncLocalStorage<unknown>> = {};
24
+ const __betterAuthVersion: string = import.meta.env
25
+ .BETTER_AUTH_VERSION as string;
26
+
27
+ /**
28
+ * We store context instance in the globalThis.
29
+ *
30
+ * The reason we do this is that some bundlers, web framework, or package managers might
31
+ * create multiple copies of BetterAuth in the same process intentionally or unintentionally.
32
+ *
33
+ * For example, yarn v1, Next.js, SSR, Vite...
34
+ *
35
+ * @internal
36
+ */
37
+ export function __getBetterAuthGlobal(): BetterAuthGlobal {
38
+ if (!(globalThis as any)[symbol]) {
39
+ (globalThis as any)[symbol] = {
40
+ version: __betterAuthVersion,
41
+ epoch: 1,
42
+ context: __context,
43
+ };
44
+ bind = (globalThis as any)[symbol] as BetterAuthGlobal;
45
+ }
46
+ bind = (globalThis as any)[symbol] as BetterAuthGlobal;
47
+ if (bind.version !== __betterAuthVersion) {
48
+ bind.version = __betterAuthVersion;
49
+ // Different versions of BetterAuth are loaded in the same process.
50
+ bind.epoch++;
51
+ }
52
+ return (globalThis as any)[symbol] as BetterAuthGlobal;
53
+ }
54
+
55
+ export function getBetterAuthVersion(): string {
56
+ return __getBetterAuthGlobal().version;
57
+ }
@@ -4,6 +4,7 @@ export {
4
4
  getCurrentAuthContextAsyncLocalStorage,
5
5
  runWithEndpointContext,
6
6
  } from "./endpoint-context";
7
+ export { getBetterAuthVersion } from "./global";
7
8
  export {
8
9
  defineRequestState,
9
10
  getCurrentRequestState,
@@ -1,23 +1,18 @@
1
1
  import type { AsyncLocalStorage } from "@better-auth/core/async_hooks";
2
2
  import { getAsyncLocalStorage } from "@better-auth/core/async_hooks";
3
+ import { __getBetterAuthGlobal } from "./global";
3
4
 
4
5
  export type RequestStateWeakMap = WeakMap<object, any>;
5
6
 
6
- const symbol = Symbol.for("better-auth:request-state-async-storage");
7
-
8
- let requestStateAsyncStorage: AsyncLocalStorage<RequestStateWeakMap> | null =
9
- null;
10
-
11
7
  const ensureAsyncStorage = async () => {
12
- if (!requestStateAsyncStorage || (globalThis as any)[symbol] === undefined) {
8
+ const betterAuthGlobal = __getBetterAuthGlobal();
9
+ if (!betterAuthGlobal.context.requestStateAsyncStorage) {
13
10
  const AsyncLocalStorage = await getAsyncLocalStorage();
14
- requestStateAsyncStorage = new AsyncLocalStorage();
15
- (globalThis as any)[symbol] = requestStateAsyncStorage;
11
+ betterAuthGlobal.context.requestStateAsyncStorage =
12
+ new AsyncLocalStorage<RequestStateWeakMap>();
16
13
  }
17
- return (
18
- requestStateAsyncStorage ||
19
- ((globalThis as any)[symbol] as AsyncLocalStorage<RequestStateWeakMap>)
20
- );
14
+ return betterAuthGlobal.context
15
+ .requestStateAsyncStorage as AsyncLocalStorage<RequestStateWeakMap>;
21
16
  };
22
17
 
23
18
  export async function getRequestStateAsyncLocalStorage() {
@@ -1,25 +1,16 @@
1
- import type { AsyncLocalStorage } from "@better-auth/core/async_hooks";
1
+ import type { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { getAsyncLocalStorage } from "@better-auth/core/async_hooks";
3
3
  import type { DBAdapter, DBTransactionAdapter } from "../db/adapter";
4
-
5
- const symbol = Symbol.for("better-auth:transaction-adapter-async-storage");
6
-
7
- let currentAdapterAsyncStorage: AsyncLocalStorage<DBTransactionAdapter> | null =
8
- null;
4
+ import { __getBetterAuthGlobal } from "./global";
9
5
 
10
6
  const ensureAsyncStorage = async () => {
11
- if (
12
- !currentAdapterAsyncStorage ||
13
- (globalThis as any)[symbol] === undefined
14
- ) {
7
+ const betterAuthGlobal = __getBetterAuthGlobal();
8
+ if (!betterAuthGlobal.context.adapterAsyncStorage) {
15
9
  const AsyncLocalStorage = await getAsyncLocalStorage();
16
- currentAdapterAsyncStorage = new AsyncLocalStorage();
17
- (globalThis as any)[symbol] = currentAdapterAsyncStorage;
10
+ betterAuthGlobal.context.adapterAsyncStorage = new AsyncLocalStorage();
18
11
  }
19
- return (
20
- currentAdapterAsyncStorage ||
21
- ((globalThis as any)[symbol] as AsyncLocalStorage<DBTransactionAdapter>)
22
- );
12
+ return betterAuthGlobal.context
13
+ .adapterAsyncStorage as AsyncLocalStorage<DBTransactionAdapter>;
23
14
  };
24
15
 
25
16
  /**
@@ -200,7 +200,7 @@ export const createAdapterFactory =
200
200
  let value = data[field];
201
201
  const fieldAttributes = fields[field];
202
202
 
203
- let newFieldName: string =
203
+ const newFieldName: string =
204
204
  newMappedKeys[field] || fields[field]!.fieldName || field;
205
205
  if (
206
206
  value === undefined &&
@@ -335,7 +335,7 @@ export const createAdapterFactory =
335
335
  newValue = await field.transform.output(newValue);
336
336
  }
337
337
 
338
- let newFieldName: string = newMappedKeys[key] || key;
338
+ const newFieldName: string = newMappedKeys[key] || key;
339
339
 
340
340
  if (originalKey === "id" || field.references?.field === "id") {
341
341
  // Even if `useNumberId` is true, we must always return a string `id` output.
@@ -392,7 +392,7 @@ export const createAdapterFactory =
392
392
  unsafe_model = getDefaultModelName(unsafe_model);
393
393
  // for now we just transform the base model
394
394
  // later we append the joined models to this object.
395
- let transformedData: Record<string, any> = await transformSingleOutput(
395
+ const transformedData: Record<string, any> = await transformSingleOutput(
396
396
  data,
397
397
  unsafe_model,
398
398
  select,
@@ -443,7 +443,7 @@ export const createAdapterFactory =
443
443
  joinedData = [joinedData];
444
444
  }
445
445
 
446
- let transformed = [];
446
+ const transformed = [];
447
447
 
448
448
  if (Array.isArray(joinedData)) {
449
449
  for (const item of joinedData) {
@@ -822,7 +822,7 @@ export const createAdapterFactory =
822
822
  forceAllowId?: boolean;
823
823
  }): Promise<R> => {
824
824
  transactionId++;
825
- let thisTransactionId = transactionId;
825
+ const thisTransactionId = transactionId;
826
826
  const model = getModelName(unsafeModel);
827
827
  unsafeModel = getDefaultModelName(unsafeModel);
828
828
  if (
@@ -903,7 +903,7 @@ export const createAdapterFactory =
903
903
  update: Record<string, any>;
904
904
  }): Promise<T | null> => {
905
905
  transactionId++;
906
- let thisTransactionId = transactionId;
906
+ const thisTransactionId = transactionId;
907
907
  unsafeModel = getDefaultModelName(unsafeModel);
908
908
  const model = getModelName(unsafeModel);
909
909
  const where = transformWhereClause({
@@ -965,7 +965,7 @@ export const createAdapterFactory =
965
965
  update: Record<string, any>;
966
966
  }) => {
967
967
  transactionId++;
968
- let thisTransactionId = transactionId;
968
+ const thisTransactionId = transactionId;
969
969
  const model = getModelName(unsafeModel);
970
970
  const where = transformWhereClause({
971
971
  model: unsafeModel,
@@ -1021,7 +1021,7 @@ export const createAdapterFactory =
1021
1021
  join?: JoinOption;
1022
1022
  }) => {
1023
1023
  transactionId++;
1024
- let thisTransactionId = transactionId;
1024
+ const thisTransactionId = transactionId;
1025
1025
  const model = getModelName(unsafeModel);
1026
1026
  const where = transformWhereClause({
1027
1027
  model: unsafeModel,
@@ -1095,7 +1095,7 @@ export const createAdapterFactory =
1095
1095
  join?: JoinOption;
1096
1096
  }) => {
1097
1097
  transactionId++;
1098
- let thisTransactionId = transactionId;
1098
+ const thisTransactionId = transactionId;
1099
1099
  const limit =
1100
1100
  unsafeLimit ??
1101
1101
  options.advanced?.database?.defaultFindManyLimit ??
@@ -1173,7 +1173,7 @@ export const createAdapterFactory =
1173
1173
  where: Where[];
1174
1174
  }) => {
1175
1175
  transactionId++;
1176
- let thisTransactionId = transactionId;
1176
+ const thisTransactionId = transactionId;
1177
1177
  const model = getModelName(unsafeModel);
1178
1178
  const where = transformWhereClause({
1179
1179
  model: unsafeModel,
@@ -1206,7 +1206,7 @@ export const createAdapterFactory =
1206
1206
  where: Where[];
1207
1207
  }) => {
1208
1208
  transactionId++;
1209
- let thisTransactionId = transactionId;
1209
+ const thisTransactionId = transactionId;
1210
1210
  const model = getModelName(unsafeModel);
1211
1211
  const where = transformWhereClause({
1212
1212
  model: unsafeModel,
@@ -1240,7 +1240,7 @@ export const createAdapterFactory =
1240
1240
  where?: Where[];
1241
1241
  }) => {
1242
1242
  transactionId++;
1243
- let thisTransactionId = transactionId;
1243
+ const thisTransactionId = transactionId;
1244
1244
  const model = getModelName(unsafeModel);
1245
1245
  const where = transformWhereClause({
1246
1246
  model: unsafeModel,
@@ -1350,7 +1350,7 @@ export const createAdapterFactory =
1350
1350
  }
1351
1351
 
1352
1352
  //`${colors.fg.blue}|${colors.reset} `,
1353
- let log: any[] = logs
1353
+ const log: any[] = logs
1354
1354
  .reverse()
1355
1355
  .map((log) => {
1356
1356
  log.args[0] = `\n${log.args[0]}`;
@@ -23,7 +23,7 @@ export const initGetDefaultModelName = ({
23
23
  // It's possible this `model` could had applied `usePlural`.
24
24
  // Thus we'll try the search but without the trailing `s`.
25
25
  if (usePlural && model.charAt(model.length - 1) === "s") {
26
- let pluralessModel = model.slice(0, -1);
26
+ const pluralessModel = model.slice(0, -1);
27
27
  let m = schema[pluralessModel] ? pluralessModel : undefined;
28
28
  if (!m) {
29
29
  m = Object.entries(schema).find(
@@ -36,7 +36,7 @@ export const initGetIdField = ({
36
36
  options.advanced?.database?.generateId === "serial";
37
37
  const useUUIDs = options.advanced?.database?.generateId === "uuid";
38
38
 
39
- let shouldGenerateId: boolean = (() => {
39
+ const shouldGenerateId: boolean = (() => {
40
40
  if (disableIdGeneration) {
41
41
  return false;
42
42
  } else if (useNumberId && !forceAllowId) {
@@ -58,7 +58,7 @@ export const initGetIdField = ({
58
58
  ? {
59
59
  defaultValue() {
60
60
  if (disableIdGeneration) return undefined;
61
- let generateId = options.advanced?.database?.generateId;
61
+ const generateId = options.advanced?.database?.generateId;
62
62
  if (generateId === false || useNumberId) return undefined;
63
63
  if (typeof generateId === "function") {
64
64
  return generateId({
@@ -1,11 +1,10 @@
1
1
  import { APIError as BaseAPIError } from "better-call/error";
2
2
 
3
3
  export class BetterAuthError extends Error {
4
- constructor(message: string, cause?: string | undefined) {
5
- super(message);
4
+ constructor(message: string, options?: { cause?: unknown | undefined }) {
5
+ super(message, options);
6
6
  this.name = "BetterAuthError";
7
7
  this.message = message;
8
- this.cause = cause;
9
8
  this.stack = "";
10
9
  }
11
10
  }
@@ -161,9 +161,18 @@ export const apple = (options: AppleOptions) => {
161
161
  if (!profile) {
162
162
  return null;
163
163
  }
164
- const name = token.user
165
- ? `${token.user.name?.firstName} ${token.user.name?.lastName}`
166
- : profile.name || profile.email;
164
+
165
+ // TODO: " " masking will be removed when the name field is made optional
166
+ let name: string;
167
+ if (token.user?.name) {
168
+ const firstName = token.user.name.firstName || "";
169
+ const lastName = token.user.name.lastName || "";
170
+ const fullName = `${firstName} ${lastName}`.trim();
171
+ name = fullName || " ";
172
+ } else {
173
+ name = profile.name || " ";
174
+ }
175
+
167
176
  const emailVerified =
168
177
  typeof profile.email_verified === "boolean"
169
178
  ? profile.email_verified
@@ -65,7 +65,7 @@ const cleanDoubleSlashes = (input: string = "") => {
65
65
  };
66
66
 
67
67
  const issuerToEndpoints = (issuer?: string | undefined) => {
68
- let baseUrl = issuer || "https://gitlab.com";
68
+ const baseUrl = issuer || "https://gitlab.com";
69
69
  return {
70
70
  authorizationEndpoint: cleanDoubleSlashes(`${baseUrl}/oauth/authorize`),
71
71
  tokenEndpoint: cleanDoubleSlashes(`${baseUrl}/oauth/token`),