@better-auth/core 1.7.0-rc.1 → 1.7.0-rc.2

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 (208) hide show
  1. package/dist/api/index.d.mts +28 -28
  2. package/dist/async_hooks/index.d.mts +0 -1
  3. package/dist/async_hooks/pure.index.d.mts +0 -1
  4. package/dist/context/endpoint-context.d.mts +1 -1
  5. package/dist/context/global.d.mts +0 -1
  6. package/dist/context/global.mjs +1 -1
  7. package/dist/context/request-state.d.mts +0 -1
  8. package/dist/context/request-state.mjs +8 -5
  9. package/dist/context/transaction.d.mts +8 -3
  10. package/dist/context/transaction.mjs +27 -10
  11. package/dist/db/adapter/factory.d.mts +3 -5
  12. package/dist/db/adapter/factory.mjs +7 -5
  13. package/dist/db/adapter/get-default-field-name.d.mts +2 -9
  14. package/dist/db/adapter/get-default-model-name.d.mts +1 -5
  15. package/dist/db/adapter/get-default-model-name.mjs +6 -5
  16. package/dist/db/adapter/get-field-attributes.d.mts +4 -11
  17. package/dist/db/adapter/get-field-name.d.mts +2 -9
  18. package/dist/db/adapter/get-id-field.d.mts +4 -12
  19. package/dist/db/adapter/get-model-name.d.mts +1 -5
  20. package/dist/db/adapter/index.d.mts +7 -32
  21. package/dist/db/adapter/types.d.mts +5 -17
  22. package/dist/db/adapter/utils.d.mts +0 -1
  23. package/dist/db/database-index.d.mts +44 -0
  24. package/dist/db/database-index.mjs +168 -0
  25. package/dist/db/get-tables.d.mts +7 -1
  26. package/dist/db/get-tables.mjs +47 -6
  27. package/dist/db/index.d.mts +3 -3
  28. package/dist/db/index.mjs +2 -2
  29. package/dist/db/internal.d.mts +3 -0
  30. package/dist/db/internal.mjs +3 -0
  31. package/dist/db/plugin.d.mts +4 -3
  32. package/dist/db/schema/account.d.mts +16 -3
  33. package/dist/db/schema/account.mjs +35 -2
  34. package/dist/db/schema/rate-limit.d.mts +1 -1
  35. package/dist/db/schema/rate-limit.mjs +9 -0
  36. package/dist/db/schema/session.d.mts +1 -1
  37. package/dist/db/schema/shared.d.mts +0 -1
  38. package/dist/db/schema/user.d.mts +1 -1
  39. package/dist/db/schema/verification.d.mts +1 -1
  40. package/dist/db/type.d.mts +17 -9
  41. package/dist/env/logger.d.mts +25 -25
  42. package/dist/error/codes.d.mts +0 -1
  43. package/dist/error/index.d.mts +0 -1
  44. package/dist/index.d.mts +1 -1
  45. package/dist/instrumentation/attributes.d.mts +0 -1
  46. package/dist/instrumentation/pure.index.d.mts +0 -1
  47. package/dist/instrumentation/tracer.mjs +1 -1
  48. package/dist/oauth2/authorization-params.d.mts +0 -1
  49. package/dist/oauth2/client-assertion.d.mts +3 -13
  50. package/dist/oauth2/client-credentials-token.d.mts +3 -17
  51. package/dist/oauth2/client-credentials-token.mjs +1 -4
  52. package/dist/oauth2/create-authorization-url.d.mts +3 -21
  53. package/dist/oauth2/dpop.d.mts +2 -23
  54. package/dist/oauth2/dpop.mjs +1 -1
  55. package/dist/oauth2/index.d.mts +2 -2
  56. package/dist/oauth2/oauth-provider.d.mts +85 -36
  57. package/dist/oauth2/refresh-access-token.d.mts +3 -19
  58. package/dist/oauth2/refresh-access-token.mjs +3 -9
  59. package/dist/oauth2/reject-redirects.mjs +1 -1
  60. package/dist/oauth2/token-endpoint-auth.d.mts +0 -1
  61. package/dist/oauth2/utils.d.mts +0 -1
  62. package/dist/oauth2/utils.mjs +2 -3
  63. package/dist/oauth2/validate-authorization-code.d.mts +5 -29
  64. package/dist/oauth2/verify-id-token.d.mts +3 -2
  65. package/dist/oauth2/verify-id-token.mjs +3 -3
  66. package/dist/oauth2/verify.d.mts +5 -7
  67. package/dist/oauth2/verify.mjs +2 -2
  68. package/dist/social-providers/apple.d.mts +9 -24
  69. package/dist/social-providers/apple.mjs +2 -1
  70. package/dist/social-providers/atlassian.d.mts +18 -19
  71. package/dist/social-providers/atlassian.mjs +1 -1
  72. package/dist/social-providers/cognito.d.mts +33 -22
  73. package/dist/social-providers/cognito.mjs +2 -2
  74. package/dist/social-providers/discord.d.mts +7 -20
  75. package/dist/social-providers/discord.mjs +1 -1
  76. package/dist/social-providers/dropbox.d.mts +7 -22
  77. package/dist/social-providers/dropbox.mjs +1 -1
  78. package/dist/social-providers/facebook.d.mts +19 -27
  79. package/dist/social-providers/facebook.mjs +6 -17
  80. package/dist/social-providers/figma.d.mts +7 -22
  81. package/dist/social-providers/figma.mjs +1 -1
  82. package/dist/social-providers/github.d.mts +7 -23
  83. package/dist/social-providers/github.mjs +1 -1
  84. package/dist/social-providers/gitlab.d.mts +6 -43
  85. package/dist/social-providers/gitlab.mjs +1 -1
  86. package/dist/social-providers/google.d.mts +10 -32
  87. package/dist/social-providers/google.mjs +2 -1
  88. package/dist/social-providers/huggingface.d.mts +7 -22
  89. package/dist/social-providers/huggingface.mjs +1 -1
  90. package/dist/social-providers/index.d.mts +229 -787
  91. package/dist/social-providers/kakao.d.mts +8 -33
  92. package/dist/social-providers/kakao.mjs +1 -1
  93. package/dist/social-providers/kick.d.mts +7 -22
  94. package/dist/social-providers/kick.mjs +1 -1
  95. package/dist/social-providers/line.d.mts +8 -44
  96. package/dist/social-providers/line.mjs +4 -6
  97. package/dist/social-providers/linear.d.mts +7 -21
  98. package/dist/social-providers/linear.mjs +1 -1
  99. package/dist/social-providers/linkedin.d.mts +7 -21
  100. package/dist/social-providers/linkedin.mjs +1 -1
  101. package/dist/social-providers/microsoft-entra-id.d.mts +8 -18
  102. package/dist/social-providers/microsoft-entra-id.mjs +18 -2
  103. package/dist/social-providers/naver.d.mts +27 -42
  104. package/dist/social-providers/naver.mjs +1 -1
  105. package/dist/social-providers/notion.d.mts +7 -21
  106. package/dist/social-providers/notion.mjs +1 -1
  107. package/dist/social-providers/paybin.d.mts +8 -23
  108. package/dist/social-providers/paybin.mjs +2 -1
  109. package/dist/social-providers/paypal.d.mts +8 -33
  110. package/dist/social-providers/paypal.mjs +1 -1
  111. package/dist/social-providers/polar.d.mts +7 -22
  112. package/dist/social-providers/polar.mjs +1 -1
  113. package/dist/social-providers/railway.d.mts +7 -22
  114. package/dist/social-providers/railway.mjs +1 -1
  115. package/dist/social-providers/reddit.d.mts +7 -20
  116. package/dist/social-providers/reddit.mjs +1 -1
  117. package/dist/social-providers/roblox.d.mts +7 -20
  118. package/dist/social-providers/roblox.mjs +1 -1
  119. package/dist/social-providers/salesforce.d.mts +7 -22
  120. package/dist/social-providers/salesforce.mjs +1 -1
  121. package/dist/social-providers/slack.d.mts +7 -20
  122. package/dist/social-providers/slack.mjs +1 -1
  123. package/dist/social-providers/spotify.d.mts +7 -22
  124. package/dist/social-providers/spotify.mjs +1 -1
  125. package/dist/social-providers/tiktok.d.mts +10 -22
  126. package/dist/social-providers/tiktok.mjs +1 -1
  127. package/dist/social-providers/twitch.d.mts +7 -20
  128. package/dist/social-providers/twitch.mjs +1 -1
  129. package/dist/social-providers/twitter.d.mts +29 -26
  130. package/dist/social-providers/twitter.mjs +1 -1
  131. package/dist/social-providers/vercel.d.mts +7 -22
  132. package/dist/social-providers/vercel.mjs +1 -1
  133. package/dist/social-providers/vk.d.mts +8 -24
  134. package/dist/social-providers/vk.mjs +5 -6
  135. package/dist/social-providers/wechat.d.mts +7 -19
  136. package/dist/social-providers/wechat.mjs +1 -1
  137. package/dist/social-providers/zoom.d.mts +9 -25
  138. package/dist/social-providers/zoom.mjs +1 -1
  139. package/dist/types/context.d.mts +16 -9
  140. package/dist/types/cookie.d.mts +0 -1
  141. package/dist/types/helper.d.mts +1 -1
  142. package/dist/types/index.d.mts +1 -1
  143. package/dist/types/init-options.d.mts +37 -26
  144. package/dist/types/plugin-client.d.mts +1 -3
  145. package/dist/types/plugin.d.mts +2 -2
  146. package/dist/utils/async.d.mts +0 -1
  147. package/dist/utils/db.d.mts +1 -0
  148. package/dist/utils/deprecate.d.mts +0 -1
  149. package/dist/utils/error-codes.d.mts +2 -2
  150. package/dist/utils/host.d.mts +27 -1
  151. package/dist/utils/host.mjs +1 -1
  152. package/dist/utils/ip.d.mts +1 -0
  153. package/dist/utils/ip.mjs +1 -1
  154. package/dist/utils/is-api-error.d.mts +0 -1
  155. package/dist/utils/redirect-uri.d.mts +0 -1
  156. package/package.json +10 -2
  157. package/src/context/request-state.ts +26 -6
  158. package/src/context/transaction.ts +37 -18
  159. package/src/db/adapter/factory.ts +24 -18
  160. package/src/db/adapter/get-default-model-name.ts +23 -14
  161. package/src/db/database-index.ts +351 -0
  162. package/src/db/get-tables.ts +89 -9
  163. package/src/db/index.ts +4 -0
  164. package/src/db/internal.ts +12 -0
  165. package/src/db/plugin.ts +3 -1
  166. package/src/db/schema/account.ts +27 -1
  167. package/src/db/schema/user.ts +1 -1
  168. package/src/db/type.ts +12 -0
  169. package/src/oauth2/index.ts +3 -0
  170. package/src/oauth2/oauth-provider.ts +94 -36
  171. package/src/oauth2/verify-id-token.ts +4 -2
  172. package/src/social-providers/apple.ts +2 -1
  173. package/src/social-providers/atlassian.ts +1 -1
  174. package/src/social-providers/cognito.ts +2 -2
  175. package/src/social-providers/discord.ts +1 -1
  176. package/src/social-providers/dropbox.ts +1 -1
  177. package/src/social-providers/facebook.ts +21 -28
  178. package/src/social-providers/figma.ts +1 -1
  179. package/src/social-providers/github.ts +1 -1
  180. package/src/social-providers/gitlab.ts +1 -1
  181. package/src/social-providers/google.ts +2 -1
  182. package/src/social-providers/huggingface.ts +1 -1
  183. package/src/social-providers/kakao.ts +1 -1
  184. package/src/social-providers/kick.ts +1 -1
  185. package/src/social-providers/line.ts +7 -12
  186. package/src/social-providers/linear.ts +1 -1
  187. package/src/social-providers/linkedin.ts +1 -1
  188. package/src/social-providers/microsoft-entra-id.ts +3 -2
  189. package/src/social-providers/naver.ts +1 -1
  190. package/src/social-providers/notion.ts +1 -1
  191. package/src/social-providers/paybin.ts +2 -1
  192. package/src/social-providers/paypal.ts +1 -1
  193. package/src/social-providers/polar.ts +1 -1
  194. package/src/social-providers/railway.ts +1 -1
  195. package/src/social-providers/reddit.ts +1 -1
  196. package/src/social-providers/roblox.ts +1 -1
  197. package/src/social-providers/salesforce.ts +1 -1
  198. package/src/social-providers/slack.ts +1 -1
  199. package/src/social-providers/spotify.ts +1 -1
  200. package/src/social-providers/tiktok.ts +2 -2
  201. package/src/social-providers/twitch.ts +1 -1
  202. package/src/social-providers/twitter.ts +1 -1
  203. package/src/social-providers/vercel.ts +1 -1
  204. package/src/social-providers/vk.ts +2 -2
  205. package/src/social-providers/wechat.ts +1 -1
  206. package/src/social-providers/zoom.ts +1 -1
  207. package/src/types/context.ts +21 -14
  208. package/src/types/init-options.ts +15 -14
@@ -4,7 +4,7 @@ type Awaitable<T> = T | Promise<T>;
4
4
  type AwaitableFunction<T> = T | (() => Awaitable<T>);
5
5
  type LiteralString = "" | (string & Record<never, never>);
6
6
  type LiteralUnion<LiteralType, BaseType extends Primitive> = LiteralType | (BaseType & Record<never, never>);
7
- type Prettify<T> = { [K in keyof T]: T[K] } & {};
7
+ type Prettify<T> = { [K in keyof T]: T[K]; } & {};
8
8
  type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
9
9
  //#endregion
10
10
  export { Awaitable, AwaitableFunction, LiteralString, LiteralUnion, Prettify, Primitive, UnionToIntersection };
@@ -6,4 +6,4 @@ import { SecretConfig } from "./secret.mjs";
6
6
  import { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext } from "./context.mjs";
7
7
  import { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientFetchOption, ClientStore } from "./plugin-client.mjs";
8
8
  import { StandardSchemaV1 as StandardSchemaV1$1 } from "@standard-schema/spec";
9
- export { type StandardSchemaV1$1 as StandardSchemaV1 };
9
+ export type { 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$1 as StandardSchemaV1, StoreIdentifierOption, UnionToIntersection, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource };
@@ -9,6 +9,7 @@ import { SocialProviderList, SocialProviders } from "../social-providers/index.m
9
9
  import { Awaitable, LiteralString, LiteralUnion } from "./helper.mjs";
10
10
  import { BetterAuthPlugin } from "./plugin.mjs";
11
11
  import { Account, BaseAccount } from "../db/schema/account.mjs";
12
+ import "../db/index.mjs";
12
13
  import { AuthContext, GenericEndpointContext } from "./context.mjs";
13
14
  import { AuthMiddleware } from "../api/index.mjs";
14
15
  import { CookieOptions } from "better-call";
@@ -16,10 +17,9 @@ import { Database } from "bun:sqlite";
16
17
  import { DatabaseSync } from "node:sqlite";
17
18
  import { D1Database } from "@cloudflare/workers-types";
18
19
  import { Dialect, Kysely, MysqlPool, PostgresPool, SqliteDatabase } from "kysely";
19
-
20
20
  //#region src/types/init-options.d.ts
21
21
  type KyselyDatabaseType = "postgres" | "mysql" | "sqlite" | "mssql";
22
- type Optional<T> = { [P in keyof T]?: T[P] | undefined };
22
+ type Optional<T> = { [P in keyof T]?: T[P] | undefined; };
23
23
  type StoreIdentifierOption = "plain" | "hashed" | {
24
24
  hash: (identifier: string) => Promise<string>;
25
25
  };
@@ -53,18 +53,24 @@ type ValidateUserInfoAction = "create-user" | "link-account" | "sign-in";
53
53
  type ValidateUserInfoMethod = "oauth" | "sso-oidc" | "sso-saml" | "email-password" | "magic-link" | "email-otp" | "anonymous" | "siwe" | "phone-number" | "admin" | (string & {});
54
54
  /** OAuth-specific provisioning context; present only when `method` is `"oauth"`. */
55
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. */
56
+ /** The social or generic OAuth provider id (e.g. `"google"`). */
57
+ providerId: string;
58
+ /** The raw provider profile (userinfo or id-token claims), unmapped. */
57
59
  profile?: Record<string, unknown> | undefined;
58
60
  };
59
61
  /** SSO-specific provisioning context; present for OIDC and SAML SSO methods. */
60
62
  type ValidateUserInfoSSOInfo = {
61
- /** The configured SSO provider id. */providerId: string; /** The raw OIDC claims or SAML assertion attributes, unmapped. */
63
+ /** The configured SSO provider id. */
64
+ providerId: string;
65
+ /** The raw OIDC claims or SAML assertion attributes, unmapped. */
62
66
  profile?: Record<string, unknown> | undefined;
63
67
  };
64
68
  /** Provisioning origin passed to `createUser`; the creation seam adds `action: "create-user"` to build {@link ValidateUserInfoSource}. */
65
69
  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"`. */
70
+ method: ValidateUserInfoMethod;
71
+ /** Provider id and raw profile; present iff `method` is `"oauth"`. */
72
+ oauth?: ValidateUserInfoOAuthInfo | undefined;
73
+ /** Provider id and raw profile; present iff `method` is `"sso-oidc"` or `"sso-saml"`. */
68
74
  sso?: ValidateUserInfoSSOInfo | undefined;
69
75
  };
70
76
  /**
@@ -87,7 +93,8 @@ type ValidateUserInfoSource = UserProvisioningSource & {
87
93
  action: ValidateUserInfoAction;
88
94
  };
89
95
  type ValidateUserInfoResult = {
90
- /** A short, machine-readable rejection code, surfaced to the client. */error: string;
96
+ /** A short, machine-readable rejection code, surfaced to the client. */
97
+ error: string;
91
98
  /**
92
99
  * A human-readable reason, surfaced to the client. Do not put sensitive
93
100
  * details here.
@@ -190,7 +197,7 @@ type BetterAuthDBOptions<ModelName extends string, Keys extends string = string>
190
197
  /**
191
198
  * Additional fields for the model
192
199
  */
193
- additionalFields?: { [Key in Exclude<string, Keys | "id">]: DBFieldAttribute };
200
+ additionalFields?: { [Key in Exclude<string, Keys | "id">]: DBFieldAttribute; };
194
201
  };
195
202
  type BetterAuthRateLimitOptions = Optional<BetterAuthRateLimitRule> & Omit<BetterAuthDBOptions<"rateLimit", keyof BaseRateLimit>, "additionalFields"> & {
196
203
  /**
@@ -370,11 +377,26 @@ type BetterAuthAdvancedOptions = {
370
377
  * function.
371
378
  */
372
379
  generateId?: GenerateIdFn | false | "serial" | "uuid";
380
+ /**
381
+ * Enable database joins for adapters that support them.
382
+ *
383
+ * When disabled (default), related data is fetched via
384
+ * separate queries. When enabled, adapters that support
385
+ * native joins use them; otherwise Better Auth falls back
386
+ * to separate queries.
387
+ *
388
+ * Please read the adapter documentation for more
389
+ * information regarding joins before enabling this.
390
+ * Not all adapters support joins.
391
+ *
392
+ * @default false
393
+ */
394
+ joins?: boolean;
373
395
  } | undefined;
374
396
  /**
375
397
  * Trusted proxy headers
376
398
  *
377
- * - `x-forwarded-host`
399
+ * - `x-forwarded-host`
378
400
  * - `x-forwarded-proto`
379
401
  *
380
402
  * If set to `true` and no `baseURL` option is provided, we will use the headers to infer the
@@ -764,15 +786,18 @@ type BetterAuthOptions = {
764
786
  * ```
765
787
  */
766
788
  customSyntheticUser?: (params: {
767
- /** Core user fields: name, email, emailVerified, image, createdAt, updatedAt */coreFields: {
789
+ /** Core user fields: name, email, emailVerified, image, createdAt, updatedAt */
790
+ coreFields: {
768
791
  name: string;
769
792
  email: string;
770
793
  emailVerified: boolean;
771
794
  image: string | null;
772
795
  createdAt: Date;
773
796
  updatedAt: Date;
774
- }; /** Processed additional fields from options.user.additionalFields (with defaults applied) */
775
- additionalFields: Record<string, unknown>; /** Generated user ID */
797
+ };
798
+ /** Processed additional fields from options.user.additionalFields (with defaults applied) */
799
+ additionalFields: Record<string, unknown>;
800
+ /** Generated user ID */
776
801
  id: string;
777
802
  }) => Record<string, unknown>;
778
803
  } | undefined;
@@ -1509,20 +1534,6 @@ type BetterAuthOptions = {
1509
1534
  */
1510
1535
  debug?: boolean;
1511
1536
  } | undefined;
1512
- /**
1513
- * Experimental features
1514
- */
1515
- experimental?: {
1516
- /**
1517
- * Enable experimental joins for your database adapter.
1518
- *
1519
- * Please read the adapter documentation for more information regarding joins before enabling this.
1520
- * Not all adapters support joins.
1521
- *
1522
- * @default false
1523
- */
1524
- joins?: boolean;
1525
- };
1526
1537
  };
1527
1538
  //#endregion
1528
1539
  export { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource };
@@ -2,7 +2,6 @@ import { LiteralString } from "./helper.mjs";
2
2
  import { BetterAuthOptions } from "./init-options.mjs";
3
3
  import { BetterFetch, BetterFetchOption, BetterFetchPlugin } from "@better-fetch/fetch";
4
4
  import { Atom, WritableAtom } from "nanostores";
5
-
6
5
  //#region src/types/plugin-client.d.ts
7
6
  type InferableServerPlugin = {
8
7
  id?: LiteralString | undefined;
@@ -89,7 +88,6 @@ interface BetterAuthClientPlugin {
89
88
  /**
90
89
  * better-auth client options
91
90
  */
92
-
93
91
  options: BetterAuthClientOptions | undefined) => Record<string, any>;
94
92
  /**
95
93
  * State atoms that'll be resolved by each framework
@@ -120,4 +118,4 @@ interface BetterAuthClientPlugin {
120
118
  }>;
121
119
  }
122
120
  //#endregion
123
- export { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientFetchOption, ClientStore };
121
+ export { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientFetchOption, ClientStore, RevalidateOptions };
@@ -2,13 +2,13 @@ import { BetterAuthPluginDBSchema } from "../db/plugin.mjs";
2
2
  import { Awaitable, LiteralString } from "./helper.mjs";
3
3
  import { RawError } from "../utils/error-codes.mjs";
4
4
  import { BetterAuthOptions } from "./init-options.mjs";
5
+ import "../db/index.mjs";
5
6
  import { AuthContext } from "./context.mjs";
6
7
  import { AuthMiddleware } from "../api/index.mjs";
7
8
  import { Endpoint, EndpointContext, InputContext, Middleware } from "better-call";
8
9
  import { Migration } from "kysely";
9
-
10
10
  //#region src/types/plugin.d.ts
11
- type DeepPartial<T> = T extends Function ? T : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
11
+ type DeepPartial<T> = T extends Function ? T : T extends object ? { [K in keyof T]?: DeepPartial<T[K]>; } : T;
12
12
  type HookEndpointContext = Partial<EndpointContext<string, any> & Omit<InputContext<string, any>, "method">> & {
13
13
  path?: string;
14
14
  context: AuthContext & {
@@ -1,5 +1,4 @@
1
1
  import { Awaitable } from "../types/helper.mjs";
2
-
3
2
  //#region src/utils/async.d.ts
4
3
  interface MapConcurrentOptions {
5
4
  /**
@@ -1,4 +1,5 @@
1
1
  import { DBFieldAttribute } from "../db/type.mjs";
2
+ import "../db/index.mjs";
2
3
  //#region src/utils/db.d.ts
3
4
  /**
4
5
  * Filters output data by removing fields with the `returned: false` attribute.
@@ -1,5 +1,4 @@
1
1
  import { InternalLogger } from "../env/logger.mjs";
2
-
3
2
  //#region src/utils/deprecate.d.ts
4
3
  /**
5
4
  * Wraps a function to log a deprecation warning at once.
@@ -3,11 +3,11 @@ type UpperLetter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "
3
3
  type SpecialCharacter = "_";
4
4
  type IsValidUpperSnakeCase<S extends string> = S extends `${infer F}${infer R}` ? F extends UpperLetter | SpecialCharacter ? IsValidUpperSnakeCase<R> : false : true;
5
5
  type InvalidKeyError<K extends string> = `Invalid error code key: "${K}" - must only contain uppercase letters (A-Z) and underscores (_)`;
6
- type ValidateErrorCodes<T> = { [K in keyof T]: K extends string ? IsValidUpperSnakeCase<K> extends false ? InvalidKeyError<K> : T[K] : T[K] };
6
+ type ValidateErrorCodes<T> = { [K in keyof T]: K extends string ? IsValidUpperSnakeCase<K> extends false ? InvalidKeyError<K> : T[K] : T[K]; };
7
7
  type RawError<K extends string = string> = {
8
8
  readonly code: K;
9
9
  message: string;
10
10
  };
11
- declare function defineErrorCodes<const T extends Record<string, string>, R extends { [K in keyof T & string]: RawError<K> }>(codes: ValidateErrorCodes<T>): R;
11
+ declare function defineErrorCodes<const T extends Record<string, string>, R extends { [K in keyof T & string]: RawError<K>; }>(codes: ValidateErrorCodes<T>): R;
12
12
  //#endregion
13
13
  export { RawError, defineErrorCodes };
@@ -26,7 +26,33 @@
26
26
  * The semantic kind of a host, derived from RFC 6890 special-purpose registries
27
27
  * plus a few domain-name categories (localhost, cloud metadata FQDNs).
28
28
  */
29
- type HostKind = /** IPv4 `127.0.0.0/8` or IPv6 `::1`. */"loopback" /** DNS name `localhost` or RFC 6761 `.localhost` TLD. */ | "localhost" /** IPv4 `0.0.0.0` or IPv6 `::` — "this host on this network", not loopback. */ | "unspecified" /** RFC 1918 `10/8`, `172.16/12`, `192.168/16`, or IPv6 ULA `fc00::/7`. */ | "private" /** IPv4 `169.254/16` or IPv6 `fe80::/10`. Includes AWS IMDS `169.254.169.254`. */ | "linkLocal" /** RFC 6598 carrier-grade NAT `100.64.0.0/10`. */ | "sharedAddressSpace" /** RFC 5737 `192.0.2/24`, `198.51.100/24`, `203.0.113/24`, or RFC 3849 `2001:db8::/32`. */ | "documentation" /** RFC 2544 `198.18.0.0/15`. */ | "benchmarking" /** IPv4 `224.0.0.0/4` or IPv6 `ff00::/8`. */ | "multicast" /** IPv4 limited broadcast `255.255.255.255`. */ | "broadcast" /** Other RFC 6890 special-purpose ranges (0.0.0.0/8, 192.0.0.0/24, 192.88.99.0/24, 240.0.0.0/4, 2001::/32, etc.). */ | "reserved" /** Cloud metadata service FQDN (e.g. `metadata.google.internal`). */ | "cloudMetadata" /** Any host not matching a special-purpose range above. */ | "public";
29
+ type HostKind =
30
+ /** IPv4 `127.0.0.0/8` or IPv6 `::1`. */
31
+ "loopback" |
32
+ /** DNS name `localhost` or RFC 6761 `.localhost` TLD. */
33
+ "localhost" |
34
+ /** IPv4 `0.0.0.0` or IPv6 `::` — "this host on this network", not loopback. */
35
+ "unspecified" |
36
+ /** RFC 1918 `10/8`, `172.16/12`, `192.168/16`, or IPv6 ULA `fc00::/7`. */
37
+ "private" |
38
+ /** IPv4 `169.254/16` or IPv6 `fe80::/10`. Includes AWS IMDS `169.254.169.254`. */
39
+ "linkLocal" |
40
+ /** RFC 6598 carrier-grade NAT `100.64.0.0/10`. */
41
+ "sharedAddressSpace" |
42
+ /** RFC 5737 `192.0.2/24`, `198.51.100/24`, `203.0.113/24`, or RFC 3849 `2001:db8::/32`. */
43
+ "documentation" |
44
+ /** RFC 2544 `198.18.0.0/15`. */
45
+ "benchmarking" |
46
+ /** IPv4 `224.0.0.0/4` or IPv6 `ff00::/8`. */
47
+ "multicast" |
48
+ /** IPv4 limited broadcast `255.255.255.255`. */
49
+ "broadcast" |
50
+ /** Other RFC 6890 special-purpose ranges (0.0.0.0/8, 192.0.0.0/24, 192.88.99.0/24, 240.0.0.0/4, 2001::/32, etc.). */
51
+ "reserved" |
52
+ /** Cloud metadata service FQDN (e.g. `metadata.google.internal`). */
53
+ "cloudMetadata" |
54
+ /** Any host not matching a special-purpose range above. */
55
+ "public";
30
56
  /**
31
57
  * The syntactic form of the input host: an IPv4 literal, an IPv6 literal, or
32
58
  * a domain name. IPv4-mapped IPv6 (`::ffff:192.0.2.1`) is reported as `ipv4`
@@ -9,7 +9,7 @@ import { isValidIP, normalizeIP } from "./ip.mjs";
9
9
  * only exists for the FQDN form that a naive server-side fetch might resolve
10
10
  * via its own resolver.
11
11
  */
12
- const CLOUD_METADATA_HOSTS = new Set([
12
+ const CLOUD_METADATA_HOSTS = /* @__PURE__ */ new Set([
13
13
  "metadata.google.internal",
14
14
  "metadata.goog",
15
15
  "metadata",
@@ -1,4 +1,5 @@
1
1
  import { BetterAuthOptions } from "../types/init-options.mjs";
2
+ import "../types/index.mjs";
2
3
  //#region src/utils/ip.d.ts
3
4
  /**
4
5
  * Normalizes an IP address for consistent rate limiting.
package/dist/utils/ip.mjs CHANGED
@@ -111,7 +111,7 @@ function ipToBytes(ip) {
111
111
  const mapped = extractIPv4FromMapped(ip);
112
112
  if (mapped) return Uint8Array.from(mapped.split(".").map((octet) => Number(octet)));
113
113
  const groups = expandIPv6(ip);
114
- const bytes = new Uint8Array(16);
114
+ const bytes = /* @__PURE__ */ new Uint8Array(16);
115
115
  for (let i = 0; i < 8; i++) {
116
116
  const group = Number.parseInt(groups[i] ?? "0", 16);
117
117
  bytes[i * 2] = group >> 8 & 255;
@@ -1,5 +1,4 @@
1
1
  import { APIError } from "../error/index.mjs";
2
-
3
2
  //#region src/utils/is-api-error.d.ts
4
3
  declare function isAPIError(error: unknown): error is APIError;
5
4
  //#endregion
@@ -1,5 +1,4 @@
1
1
  import * as z from "zod";
2
-
3
2
  //#region src/utils/redirect-uri.d.ts
4
3
  /**
5
4
  * Zod schema for OAuth redirect URIs and other developer-supplied URLs that the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/core",
3
- "version": "1.7.0-rc.1",
3
+ "version": "1.7.0-rc.2",
4
4
  "description": "The most comprehensive authentication framework for TypeScript.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -80,6 +80,11 @@
80
80
  "types": "./dist/db/index.d.mts",
81
81
  "default": "./dist/db/index.mjs"
82
82
  },
83
+ "./db/internal": {
84
+ "dev-source": "./src/db/internal.ts",
85
+ "types": "./dist/db/internal.d.mts",
86
+ "default": "./dist/db/internal.mjs"
87
+ },
83
88
  "./db/adapter": {
84
89
  "dev-source": "./src/db/adapter/index.ts",
85
90
  "types": "./dist/db/adapter/index.d.mts",
@@ -135,6 +140,9 @@
135
140
  "db": [
136
141
  "dist/db/index.d.mts"
137
142
  ],
143
+ "db/internal": [
144
+ "dist/db/internal.d.mts"
145
+ ],
138
146
  "db/adapter": [
139
147
  "dist/db/adapter/index.d.mts"
140
148
  ],
@@ -162,7 +170,7 @@
162
170
  "jose": "^6.2.3",
163
171
  "kysely": "^0.28.17 || ^0.29.0",
164
172
  "nanostores": "^1.3.0",
165
- "tsdown": "0.21.1"
173
+ "tsdown": "0.22.7"
166
174
  },
167
175
  "peerDependencies": {
168
176
  "@better-auth/utils": "0.4.2",
@@ -4,15 +4,35 @@ import { __getBetterAuthGlobal } from "./global";
4
4
 
5
5
  export type RequestStateWeakMap = WeakMap<object, any>;
6
6
 
7
+ // Memoizes the in-flight AsyncLocalStorage initialization so concurrent
8
+ // first-callers share a single instance instead of each constructing one.
9
+ let asyncStorageInit: Promise<AsyncLocalStorage<RequestStateWeakMap>> | null =
10
+ null;
11
+
7
12
  const ensureAsyncStorage = async () => {
8
13
  const betterAuthGlobal = __getBetterAuthGlobal();
9
- if (!betterAuthGlobal.context.requestStateAsyncStorage) {
10
- const AsyncLocalStorage = await getAsyncLocalStorage();
11
- betterAuthGlobal.context.requestStateAsyncStorage =
12
- new AsyncLocalStorage<RequestStateWeakMap>();
14
+ const existing = betterAuthGlobal.context.requestStateAsyncStorage;
15
+ if (existing) {
16
+ return existing as AsyncLocalStorage<RequestStateWeakMap>;
17
+ }
18
+ // Without memoizing the init, several concurrent callers can each pass the
19
+ // check above, each `await getAsyncLocalStorage()`, and each assign a fresh
20
+ // instance — last write wins. `runWithRequestState().run()` then executes on
21
+ // one instance while a nested `getCurrentRequestState()` reads the
22
+ // overwritten one, throwing "No request state found". This shows up
23
+ // intermittently on serverless cold start (e.g. Cloudflare Workers), where
24
+ // the first requests hit before the lazy `node:async_hooks` import settles.
25
+ // The idempotent `??=` keeps the global singleton stable even if multiple
26
+ // BetterAuth copies (Dual Module Hazard) race here.
27
+ if (!asyncStorageInit) {
28
+ asyncStorageInit = getAsyncLocalStorage().then((AsyncLocalStorage) => {
29
+ betterAuthGlobal.context.requestStateAsyncStorage ??=
30
+ new AsyncLocalStorage<RequestStateWeakMap>();
31
+ return betterAuthGlobal.context
32
+ .requestStateAsyncStorage as AsyncLocalStorage<RequestStateWeakMap>;
33
+ });
13
34
  }
14
- return betterAuthGlobal.context
15
- .requestStateAsyncStorage as AsyncLocalStorage<RequestStateWeakMap>;
35
+ return asyncStorageInit;
16
36
  };
17
37
 
18
38
  export async function getRequestStateAsyncLocalStorage() {
@@ -100,6 +100,9 @@ export const runWithTransaction = async <
100
100
  >(
101
101
  adapter: DBAdapter<Options>,
102
102
  fn: () => R,
103
+ options?: {
104
+ onAfterCommitHookError?: (error: unknown) => void | Promise<void>;
105
+ },
103
106
  ): Promise<R> => {
104
107
  let called = false;
105
108
  return ensureAsyncStorage()
@@ -128,12 +131,21 @@ export const runWithTransaction = async <
128
131
  hasError = true;
129
132
  error = e;
130
133
  }
131
- for (const hook of pendingHooks) {
132
- await hook();
133
- }
134
134
  if (hasError) {
135
135
  throw error;
136
136
  }
137
+ for (const hook of pendingHooks) {
138
+ try {
139
+ await hook();
140
+ } catch (error) {
141
+ if (!options?.onAfterCommitHookError) throw error;
142
+ try {
143
+ await options.onAfterCommitHookError(error);
144
+ } catch {
145
+ // Reporting cannot roll back committed work or suppress later hooks.
146
+ }
147
+ }
148
+ }
137
149
  return result!;
138
150
  })
139
151
  .catch((err) => {
@@ -150,20 +162,27 @@ export const runWithTransaction = async <
150
162
  */
151
163
  export const queueAfterTransactionHook = async (
152
164
  hook: () => Promise<void>,
165
+ options?: {
166
+ /** Handles a queued hook failure after the surrounding work has committed. */
167
+ onError?: (error: unknown) => void | Promise<void>;
168
+ },
153
169
  ): Promise<void> => {
154
- return ensureAsyncStorage()
155
- .then((als) => {
156
- const store = als.getStore();
157
- if (store) {
158
- // We're in a transaction context, queue the hook
159
- store.pendingHooks.push(hook);
160
- } else {
161
- // Not in a transaction, execute immediately
162
- return hook();
163
- }
164
- })
165
- .catch(() => {
166
- // No async storage available, execute immediately
167
- return hook();
168
- });
170
+ const executeHook = async () => {
171
+ try {
172
+ await hook();
173
+ } catch (error) {
174
+ if (!options?.onError) throw error;
175
+ await options.onError(error);
176
+ }
177
+ };
178
+ let storage: Awaited<ReturnType<typeof ensureAsyncStorage>>;
179
+ try {
180
+ storage = await ensureAsyncStorage();
181
+ } catch {
182
+ return executeHook();
183
+ }
184
+
185
+ const store = storage.getStore();
186
+ if (!store?.isTransactionActive) return executeHook();
187
+ store.pendingHooks.push(executeHook);
169
188
  };
@@ -425,19 +425,19 @@ export const createAdapterFactory =
425
425
  joinConfig,
426
426
  } of requiredModels) {
427
427
  let joinedData = await (async () => {
428
- if (options.experimental?.joins) {
429
- const result = data[modelName];
430
- return result;
431
- } else {
432
- // doesn't support joins, so fallback to handleFallbackJoin
433
- const result = await handleFallbackJoin({
434
- baseModel: unsafe_model,
435
- baseData: transformedData,
436
- joinModel: modelName,
437
- specificJoinConfig: joinConfig,
438
- });
439
- return result;
428
+ if (options.advanced?.database?.joins) {
429
+ // Use native joined data when the adapter included the key;
430
+ // otherwise fall back to separate queries.
431
+ if (modelName in data) {
432
+ return data[modelName];
433
+ }
440
434
  }
435
+ return await handleFallbackJoin({
436
+ baseModel: unsafe_model,
437
+ baseData: transformedData,
438
+ joinModel: modelName,
439
+ specificJoinConfig: joinConfig,
440
+ });
441
441
  })();
442
442
 
443
443
  // If joinedData is undefined, initialize it based on relationship type
@@ -1118,9 +1118,12 @@ export const createAdapterFactory =
1118
1118
  join = result.join;
1119
1119
  select = result.select;
1120
1120
  }
1121
- // If adapter doesn't support joins and we have joins, don't pass them to the adapter
1122
- const experimentalJoins = options.experimental?.joins;
1123
- if (!experimentalJoins && join && Object.keys(join).length > 0) {
1121
+ // If joins are disabled and we have joins, don't pass them to the adapter
1122
+ if (
1123
+ !options.advanced?.database?.joins &&
1124
+ join &&
1125
+ Object.keys(join).length > 0
1126
+ ) {
1124
1127
  passJoinToAdapter = false;
1125
1128
  }
1126
1129
  } else {
@@ -1206,9 +1209,12 @@ export const createAdapterFactory =
1206
1209
  join = result.join;
1207
1210
  select = result.select;
1208
1211
  }
1209
- // If adapter doesn't support joins and we have joins, don't pass them to the adapter
1210
- const experimentalJoins = options.experimental?.joins;
1211
- if (!experimentalJoins && join && Object.keys(join).length > 0) {
1212
+ // If joins are disabled and we have joins, don't pass them to the adapter
1213
+ if (
1214
+ !options.advanced?.database?.joins &&
1215
+ join &&
1216
+ Object.keys(join).length > 0
1217
+ ) {
1212
1218
  passJoinToAdapter = false;
1213
1219
  }
1214
1220
  } else {
@@ -20,26 +20,35 @@ export const initGetDefaultModelName = ({
20
20
  * 3. Using this function helps us get the actual model name based on the user's defined custom modelName.
21
21
  */
22
22
  const getDefaultModelName = (model: string) => {
23
+ // Resolve a model string (either a schema key or a user-defined
24
+ // `modelName`) back to its canonical schema key.
25
+ //
26
+ // An exact schema-key match must win over a `modelName` match.
27
+ // Better-auth internals (and `references.model`, see get-tables.ts)
28
+ // always pass canonical schema keys, so when a user remaps a
29
+ // built-in table onto another table's schema key (e.g.
30
+ // `user.modelName = "account"`), preferring the modelName alias
31
+ // would silently reroute every internal "account" query to the
32
+ // user table. The modelName lookup is only a fallback for
33
+ // externally supplied physical table names.
34
+ // @see https://github.com/better-auth/better-auth/issues/8111
35
+ // @see https://github.com/better-auth/better-auth/issues/10136
36
+ const resolve = (candidate: string): string | undefined => {
37
+ if (schema[candidate]) return candidate;
38
+ return Object.entries(schema).find(
39
+ ([_, f]) => f.modelName === candidate,
40
+ )?.[0];
41
+ };
42
+
23
43
  // It's possible this `model` could had applied `usePlural`.
24
44
  // Thus we'll try the search but without the trailing `s`.
25
45
  if (usePlural && model.charAt(model.length - 1) === "s") {
26
46
  const pluralessModel = model.slice(0, -1);
27
- let m = schema[pluralessModel] ? pluralessModel : undefined;
28
- if (!m) {
29
- m = Object.entries(schema).find(
30
- ([_, f]) => f.modelName === pluralessModel,
31
- )?.[0];
32
- }
33
-
34
- if (m) {
35
- return m;
36
- }
47
+ const m = resolve(pluralessModel);
48
+ if (m) return m;
37
49
  }
38
50
 
39
- let m = schema[model] ? model : undefined;
40
- if (!m) {
41
- m = Object.entries(schema).find(([_, f]) => f.modelName === model)?.[0];
42
- }
51
+ const m = resolve(model);
43
52
 
44
53
  if (!m) {
45
54
  throw new BetterAuthError(`Model "${model}" not found in schema`);