better-auth 1.4.10 → 1.5.0-beta.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 (227) hide show
  1. package/dist/api/index.d.mts +400 -399
  2. package/dist/api/index.mjs +6 -4
  3. package/dist/api/index.mjs.map +1 -1
  4. package/dist/api/middlewares/origin-check.d.mts +4 -4
  5. package/dist/api/middlewares/origin-check.mjs +14 -5
  6. package/dist/api/middlewares/origin-check.mjs.map +1 -1
  7. package/dist/api/routes/account.d.mts +11 -11
  8. package/dist/api/routes/account.mjs +59 -30
  9. package/dist/api/routes/account.mjs.map +1 -1
  10. package/dist/api/routes/callback.d.mts +2 -2
  11. package/dist/api/routes/email-verification.d.mts +4 -4
  12. package/dist/api/routes/email-verification.mjs +14 -14
  13. package/dist/api/routes/email-verification.mjs.map +1 -1
  14. package/dist/api/routes/error.d.mts +2 -2
  15. package/dist/api/routes/ok.d.mts +2 -2
  16. package/dist/api/routes/reset-password.d.mts +5 -5
  17. package/dist/api/routes/reset-password.mjs +9 -7
  18. package/dist/api/routes/reset-password.mjs.map +1 -1
  19. package/dist/api/routes/session.d.mts +14 -14
  20. package/dist/api/routes/session.mjs +31 -11
  21. package/dist/api/routes/session.mjs.map +1 -1
  22. package/dist/api/routes/sign-in.d.mts +4 -4
  23. package/dist/api/routes/sign-in.mjs +22 -17
  24. package/dist/api/routes/sign-in.mjs.map +1 -1
  25. package/dist/api/routes/sign-out.d.mts +2 -2
  26. package/dist/api/routes/sign-up.d.mts +3 -3
  27. package/dist/api/routes/sign-up.mjs +16 -13
  28. package/dist/api/routes/sign-up.mjs.map +1 -1
  29. package/dist/api/routes/update-user.d.mts +13 -13
  30. package/dist/api/routes/update-user.mjs +29 -24
  31. package/dist/api/routes/update-user.mjs.map +1 -1
  32. package/dist/api/to-auth-endpoints.mjs +8 -6
  33. package/dist/api/to-auth-endpoints.mjs.map +1 -1
  34. package/dist/client/lynx/index.d.mts +13 -13
  35. package/dist/client/plugins/index.d.mts +11 -1
  36. package/dist/client/plugins/index.mjs +11 -1
  37. package/dist/client/svelte/index.d.mts +15 -15
  38. package/dist/client/types.d.mts +4 -1
  39. package/dist/client/vue/index.d.mts +15 -15
  40. package/dist/context/create-context.mjs +2 -2
  41. package/dist/context/create-context.mjs.map +1 -1
  42. package/dist/context/helpers.mjs +2 -2
  43. package/dist/context/helpers.mjs.map +1 -1
  44. package/dist/db/field.d.mts +6 -6
  45. package/dist/db/schema.mjs +14 -5
  46. package/dist/db/schema.mjs.map +1 -1
  47. package/dist/index.d.mts +1 -1
  48. package/dist/integrations/next-js.d.mts +4 -4
  49. package/dist/integrations/svelte-kit.d.mts +2 -2
  50. package/dist/integrations/tanstack-start.d.mts +4 -4
  51. package/dist/oauth2/link-account.mjs +3 -2
  52. package/dist/oauth2/link-account.mjs.map +1 -1
  53. package/dist/oauth2/state.mjs +3 -3
  54. package/dist/oauth2/state.mjs.map +1 -1
  55. package/dist/plugins/admin/admin.d.mts +84 -21
  56. package/dist/plugins/admin/admin.mjs +3 -4
  57. package/dist/plugins/admin/admin.mjs.map +1 -1
  58. package/dist/plugins/admin/client.d.mts +87 -0
  59. package/dist/plugins/admin/client.mjs +3 -1
  60. package/dist/plugins/admin/client.mjs.map +1 -1
  61. package/dist/plugins/admin/error-codes.d.mts +90 -0
  62. package/dist/plugins/admin/error-codes.mjs.map +1 -1
  63. package/dist/plugins/admin/routes.mjs +40 -46
  64. package/dist/plugins/admin/routes.mjs.map +1 -1
  65. package/dist/plugins/anonymous/client.d.mts +19 -0
  66. package/dist/plugins/anonymous/client.mjs +4 -1
  67. package/dist/plugins/anonymous/client.mjs.map +1 -1
  68. package/dist/plugins/anonymous/error-codes.d.mts +22 -0
  69. package/dist/plugins/anonymous/index.d.mts +21 -9
  70. package/dist/plugins/anonymous/index.mjs +5 -5
  71. package/dist/plugins/anonymous/index.mjs.map +1 -1
  72. package/dist/plugins/api-key/client.d.mts +103 -0
  73. package/dist/plugins/api-key/client.mjs +4 -1
  74. package/dist/plugins/api-key/client.mjs.map +1 -1
  75. package/dist/plugins/api-key/error-codes.d.mts +106 -0
  76. package/dist/plugins/api-key/error-codes.mjs +34 -0
  77. package/dist/plugins/api-key/error-codes.mjs.map +1 -0
  78. package/dist/plugins/api-key/index.d.mts +138 -69
  79. package/dist/plugins/api-key/index.mjs +7 -34
  80. package/dist/plugins/api-key/index.mjs.map +1 -1
  81. package/dist/plugins/api-key/rate-limit.mjs +3 -2
  82. package/dist/plugins/api-key/rate-limit.mjs.map +1 -1
  83. package/dist/plugins/api-key/routes/create-api-key.mjs +19 -17
  84. package/dist/plugins/api-key/routes/create-api-key.mjs.map +1 -1
  85. package/dist/plugins/api-key/routes/delete-api-key.mjs +7 -5
  86. package/dist/plugins/api-key/routes/delete-api-key.mjs.map +1 -1
  87. package/dist/plugins/api-key/routes/get-api-key.mjs +5 -3
  88. package/dist/plugins/api-key/routes/get-api-key.mjs.map +1 -1
  89. package/dist/plugins/api-key/routes/update-api-key.mjs +18 -16
  90. package/dist/plugins/api-key/routes/update-api-key.mjs.map +1 -1
  91. package/dist/plugins/api-key/routes/verify-api-key.mjs +16 -35
  92. package/dist/plugins/api-key/routes/verify-api-key.mjs.map +1 -1
  93. package/dist/plugins/bearer/index.d.mts +6 -6
  94. package/dist/plugins/captcha/index.d.mts +2 -2
  95. package/dist/plugins/captcha/index.mjs +3 -3
  96. package/dist/plugins/captcha/index.mjs.map +1 -1
  97. package/dist/plugins/captcha/verify-handlers/captchafox.mjs +2 -2
  98. package/dist/plugins/captcha/verify-handlers/captchafox.mjs.map +1 -1
  99. package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +2 -2
  100. package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs.map +1 -1
  101. package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +2 -2
  102. package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs.map +1 -1
  103. package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +2 -2
  104. package/dist/plugins/captcha/verify-handlers/h-captcha.mjs.map +1 -1
  105. package/dist/plugins/custom-session/index.d.mts +5 -5
  106. package/dist/plugins/device-authorization/index.d.mts +54 -18
  107. package/dist/plugins/device-authorization/routes.mjs +18 -18
  108. package/dist/plugins/device-authorization/routes.mjs.map +1 -1
  109. package/dist/plugins/email-otp/client.d.mts +15 -0
  110. package/dist/plugins/email-otp/client.mjs +4 -1
  111. package/dist/plugins/email-otp/client.mjs.map +1 -1
  112. package/dist/plugins/email-otp/error-codes.d.mts +18 -0
  113. package/dist/plugins/email-otp/error-codes.mjs +12 -0
  114. package/dist/plugins/email-otp/error-codes.mjs.map +1 -0
  115. package/dist/plugins/email-otp/index.d.mts +64 -55
  116. package/dist/plugins/email-otp/index.mjs +4 -3
  117. package/dist/plugins/email-otp/index.mjs.map +1 -1
  118. package/dist/plugins/email-otp/routes.mjs +30 -35
  119. package/dist/plugins/email-otp/routes.mjs.map +1 -1
  120. package/dist/plugins/generic-oauth/client.d.mts +27 -0
  121. package/dist/plugins/generic-oauth/client.mjs +4 -1
  122. package/dist/plugins/generic-oauth/client.mjs.map +1 -1
  123. package/dist/plugins/generic-oauth/error-codes.d.mts +30 -0
  124. package/dist/plugins/generic-oauth/index.d.mts +55 -37
  125. package/dist/plugins/generic-oauth/index.mjs +4 -4
  126. package/dist/plugins/generic-oauth/index.mjs.map +1 -1
  127. package/dist/plugins/generic-oauth/routes.mjs +11 -12
  128. package/dist/plugins/generic-oauth/routes.mjs.map +1 -1
  129. package/dist/plugins/haveibeenpwned/index.d.mts +7 -4
  130. package/dist/plugins/haveibeenpwned/index.mjs +5 -4
  131. package/dist/plugins/haveibeenpwned/index.mjs.map +1 -1
  132. package/dist/plugins/index.d.mts +4 -2
  133. package/dist/plugins/index.mjs +6 -4
  134. package/dist/plugins/jwt/client.d.mts +2 -2
  135. package/dist/plugins/jwt/index.d.mts +9 -9
  136. package/dist/plugins/jwt/index.mjs +2 -2
  137. package/dist/plugins/jwt/index.mjs.map +1 -1
  138. package/dist/plugins/last-login-method/index.d.mts +2 -2
  139. package/dist/plugins/magic-link/index.d.mts +4 -4
  140. package/dist/plugins/mcp/authorize.mjs +1 -1
  141. package/dist/plugins/mcp/authorize.mjs.map +1 -1
  142. package/dist/plugins/mcp/index.d.mts +10 -10
  143. package/dist/plugins/multi-session/client.d.mts +7 -0
  144. package/dist/plugins/multi-session/client.mjs +4 -1
  145. package/dist/plugins/multi-session/client.mjs.map +1 -1
  146. package/dist/plugins/multi-session/error-codes.d.mts +10 -0
  147. package/dist/plugins/multi-session/error-codes.mjs +8 -0
  148. package/dist/plugins/multi-session/error-codes.mjs.map +1 -0
  149. package/dist/plugins/multi-session/index.d.mts +20 -16
  150. package/dist/plugins/multi-session/index.mjs +6 -7
  151. package/dist/plugins/multi-session/index.mjs.map +1 -1
  152. package/dist/plugins/oauth-proxy/index.d.mts +8 -8
  153. package/dist/plugins/oidc-provider/authorize.mjs +1 -1
  154. package/dist/plugins/oidc-provider/authorize.mjs.map +1 -1
  155. package/dist/plugins/oidc-provider/error.mjs +1 -1
  156. package/dist/plugins/oidc-provider/error.mjs.map +1 -1
  157. package/dist/plugins/oidc-provider/index.d.mts +15 -15
  158. package/dist/plugins/one-tap/client.d.mts +5 -5
  159. package/dist/plugins/one-tap/index.d.mts +2 -2
  160. package/dist/plugins/one-time-token/index.d.mts +5 -5
  161. package/dist/plugins/open-api/index.d.mts +3 -3
  162. package/dist/plugins/organization/client.d.mts +236 -9
  163. package/dist/plugins/organization/client.mjs +3 -1
  164. package/dist/plugins/organization/client.mjs.map +1 -1
  165. package/dist/plugins/organization/error-codes.d.mts +224 -56
  166. package/dist/plugins/organization/organization.d.mts +7 -7
  167. package/dist/plugins/organization/organization.mjs +4 -4
  168. package/dist/plugins/organization/organization.mjs.map +1 -1
  169. package/dist/plugins/organization/routes/crud-access-control.d.mts +22 -22
  170. package/dist/plugins/organization/routes/crud-access-control.mjs +40 -39
  171. package/dist/plugins/organization/routes/crud-access-control.mjs.map +1 -1
  172. package/dist/plugins/organization/routes/crud-invites.d.mts +58 -58
  173. package/dist/plugins/organization/routes/crud-invites.mjs +42 -40
  174. package/dist/plugins/organization/routes/crud-invites.mjs.map +1 -1
  175. package/dist/plugins/organization/routes/crud-members.d.mts +67 -67
  176. package/dist/plugins/organization/routes/crud-members.mjs +41 -54
  177. package/dist/plugins/organization/routes/crud-members.mjs.map +1 -1
  178. package/dist/plugins/organization/routes/crud-org.d.mts +22 -22
  179. package/dist/plugins/organization/routes/crud-org.mjs +28 -25
  180. package/dist/plugins/organization/routes/crud-org.mjs.map +1 -1
  181. package/dist/plugins/organization/routes/crud-team.d.mts +34 -34
  182. package/dist/plugins/organization/routes/crud-team.mjs +41 -47
  183. package/dist/plugins/organization/routes/crud-team.mjs.map +1 -1
  184. package/dist/plugins/phone-number/client.d.mts +51 -0
  185. package/dist/plugins/phone-number/client.mjs +4 -1
  186. package/dist/plugins/phone-number/client.mjs.map +1 -1
  187. package/dist/plugins/phone-number/error-codes.d.mts +54 -0
  188. package/dist/plugins/phone-number/index.d.mts +81 -45
  189. package/dist/plugins/phone-number/index.mjs +2 -2
  190. package/dist/plugins/phone-number/index.mjs.map +1 -1
  191. package/dist/plugins/phone-number/routes.mjs +27 -28
  192. package/dist/plugins/phone-number/routes.mjs.map +1 -1
  193. package/dist/plugins/siwe/index.d.mts +3 -3
  194. package/dist/plugins/siwe/index.mjs +7 -6
  195. package/dist/plugins/siwe/index.mjs.map +1 -1
  196. package/dist/plugins/two-factor/backup-codes/index.mjs +7 -7
  197. package/dist/plugins/two-factor/backup-codes/index.mjs.map +1 -1
  198. package/dist/plugins/two-factor/client.d.mts +39 -0
  199. package/dist/plugins/two-factor/client.mjs +4 -1
  200. package/dist/plugins/two-factor/client.mjs.map +1 -1
  201. package/dist/plugins/two-factor/error-code.d.mts +36 -9
  202. package/dist/plugins/two-factor/index.d.mts +54 -27
  203. package/dist/plugins/two-factor/index.mjs +4 -5
  204. package/dist/plugins/two-factor/index.mjs.map +1 -1
  205. package/dist/plugins/two-factor/otp/index.mjs +8 -6
  206. package/dist/plugins/two-factor/otp/index.mjs.map +1 -1
  207. package/dist/plugins/two-factor/totp/index.mjs +16 -8
  208. package/dist/plugins/two-factor/totp/index.mjs.map +1 -1
  209. package/dist/plugins/two-factor/verify-two-factor.mjs +9 -6
  210. package/dist/plugins/two-factor/verify-two-factor.mjs.map +1 -1
  211. package/dist/plugins/username/client.d.mts +35 -0
  212. package/dist/plugins/username/client.mjs +4 -1
  213. package/dist/plugins/username/client.mjs.map +1 -1
  214. package/dist/plugins/username/error-codes.d.mts +32 -8
  215. package/dist/plugins/username/index.d.mts +44 -20
  216. package/dist/plugins/username/index.mjs +21 -31
  217. package/dist/plugins/username/index.mjs.map +1 -1
  218. package/dist/plugins/username/schema.d.mts +3 -3
  219. package/dist/test-utils/test-instance.d.mts +481 -344
  220. package/dist/utils/is-api-error.d.mts +7 -0
  221. package/dist/utils/is-api-error.mjs +11 -0
  222. package/dist/utils/is-api-error.mjs.map +1 -0
  223. package/dist/utils/password.mjs +3 -3
  224. package/dist/utils/password.mjs.map +1 -1
  225. package/dist/utils/plugin-helper.mjs +2 -2
  226. package/dist/utils/plugin-helper.mjs.map +1 -1
  227. package/package.json +3 -3
@@ -1,4 +1,5 @@
1
1
  import { getIp } from "../utils/get-request-ip.mjs";
2
+ import { isAPIError } from "../utils/is-api-error.mjs";
2
3
  import { getOAuthState } from "./middlewares/oauth.mjs";
3
4
  import { formCsrfMiddleware, originCheck, originCheckMiddleware } from "./middlewares/origin-check.mjs";
4
5
  import "./middlewares/index.mjs";
@@ -17,7 +18,8 @@ import { changeEmail, changePassword, deleteUser, deleteUserCallback, setPasswor
17
18
  import "./routes/index.mjs";
18
19
  import { toAuthEndpoints } from "./to-auth-endpoints.mjs";
19
20
  import { logger } from "@better-auth/core/env";
20
- import { APIError, APIError as APIError$1, createRouter } from "better-call";
21
+ import { APIError } from "@better-auth/core/error";
22
+ import { createRouter } from "better-call";
21
23
  import { createAuthEndpoint, createAuthMiddleware, optionsMiddleware } from "@better-auth/core/api";
22
24
 
23
25
  //#region src/api/index.ts
@@ -171,7 +173,7 @@ const router = (ctx, options) => {
171
173
  return res;
172
174
  },
173
175
  onError(e) {
174
- if (e instanceof APIError$1 && e.status === "FOUND") return;
176
+ if (isAPIError(e) && e.status === "FOUND") return;
175
177
  if (options.onAPIError?.throw) throw e;
176
178
  if (options.onAPIError?.onError) {
177
179
  options.onAPIError.onError(e, ctx);
@@ -186,7 +188,7 @@ const router = (ctx, options) => {
186
188
  return;
187
189
  }
188
190
  }
189
- if (e instanceof APIError$1) {
191
+ if (isAPIError(e)) {
190
192
  if (e.status === "INTERNAL_SERVER_ERROR") ctx.logger.error(e.status, e);
191
193
  log?.error(e.message);
192
194
  } else ctx.logger?.error(e && typeof e === "object" && "name" in e ? e.name : "", e);
@@ -196,5 +198,5 @@ const router = (ctx, options) => {
196
198
  };
197
199
 
198
200
  //#endregion
199
- export { APIError, accountInfo, callbackOAuth, changeEmail, changePassword, checkEndpointConflicts, createAuthEndpoint, createAuthMiddleware, createEmailVerificationToken, deleteUser, deleteUserCallback, error, formCsrfMiddleware, freshSessionMiddleware, getAccessToken, getEndpoints, getIp, getOAuthState, getSession, getSessionFromCtx, linkSocialAccount, listSessions, listUserAccounts, ok, optionsMiddleware, originCheck, originCheckMiddleware, refreshToken, requestOnlySessionMiddleware, requestPasswordReset, requestPasswordResetCallback, resetPassword, revokeOtherSessions, revokeSession, revokeSessions, router, sendVerificationEmail, sendVerificationEmailFn, sensitiveSessionMiddleware, sessionMiddleware, setPassword, signInEmail, signInSocial, signOut, signUpEmail, unlinkAccount, updateUser, verifyEmail };
201
+ export { APIError, accountInfo, callbackOAuth, changeEmail, changePassword, checkEndpointConflicts, createAuthEndpoint, createAuthMiddleware, createEmailVerificationToken, deleteUser, deleteUserCallback, error, formCsrfMiddleware, freshSessionMiddleware, getAccessToken, getEndpoints, getIp, getOAuthState, getSession, getSessionFromCtx, isAPIError, linkSocialAccount, listSessions, listUserAccounts, ok, optionsMiddleware, originCheck, originCheckMiddleware, refreshToken, requestOnlySessionMiddleware, requestPasswordReset, requestPasswordResetCallback, resetPassword, revokeOtherSessions, revokeSession, revokeSessions, router, sendVerificationEmail, sendVerificationEmailFn, sensitiveSessionMiddleware, sessionMiddleware, setPassword, signInEmail, signInSocial, signOut, signUpEmail, unlinkAccount, updateUser, verifyEmail };
200
202
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["methods: string[]","conflicts: {\n\t\tpath: string;\n\t\tplugins: string[];\n\t\tconflictingMethods: string[];\n\t}[]","conflictingMethods: string[]","APIError"],"sources":["../../src/api/index.ts"],"sourcesContent":["import type {\n\tAuthContext,\n\tAwaitable,\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n} from \"@better-auth/core\";\nimport type { InternalLogger } from \"@better-auth/core/env\";\nimport { logger } from \"@better-auth/core/env\";\nimport type { Endpoint, Middleware } from \"better-call\";\nimport { APIError, createRouter } from \"better-call\";\nimport type { UnionToIntersection } from \"../types/helper\";\nimport { originCheckMiddleware } from \"./middlewares\";\nimport { onRequestRateLimit } from \"./rate-limiter\";\nimport {\n\taccountInfo,\n\tcallbackOAuth,\n\tchangeEmail,\n\tchangePassword,\n\tdeleteUser,\n\tdeleteUserCallback,\n\terror,\n\tgetAccessToken,\n\tgetSession,\n\tlinkSocialAccount,\n\tlistSessions,\n\tlistUserAccounts,\n\tok,\n\trefreshToken,\n\trequestPasswordReset,\n\trequestPasswordResetCallback,\n\tresetPassword,\n\trevokeOtherSessions,\n\trevokeSession,\n\trevokeSessions,\n\tsendVerificationEmail,\n\tsetPassword,\n\tsignInEmail,\n\tsignInSocial,\n\tsignOut,\n\tsignUpEmail,\n\tunlinkAccount,\n\tupdateUser,\n\tverifyEmail,\n} from \"./routes\";\nimport { toAuthEndpoints } from \"./to-auth-endpoints\";\n\nexport function checkEndpointConflicts(\n\toptions: BetterAuthOptions,\n\tlogger: InternalLogger,\n) {\n\tconst endpointRegistry = new Map<\n\t\tstring,\n\t\t{ pluginId: string; endpointKey: string; methods: string[] }[]\n\t>();\n\n\toptions.plugins?.forEach((plugin) => {\n\t\tif (plugin.endpoints) {\n\t\t\tfor (const [key, endpoint] of Object.entries(plugin.endpoints)) {\n\t\t\t\tif (\n\t\t\t\t\tendpoint &&\n\t\t\t\t\t\"path\" in endpoint &&\n\t\t\t\t\ttypeof endpoint.path === \"string\"\n\t\t\t\t) {\n\t\t\t\t\tconst path = endpoint.path;\n\t\t\t\t\tlet methods: string[] = [];\n\t\t\t\t\tif (endpoint.options && \"method\" in endpoint.options) {\n\t\t\t\t\t\tif (Array.isArray(endpoint.options.method)) {\n\t\t\t\t\t\t\tmethods = endpoint.options.method;\n\t\t\t\t\t\t} else if (typeof endpoint.options.method === \"string\") {\n\t\t\t\t\t\t\tmethods = [endpoint.options.method];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (methods.length === 0) {\n\t\t\t\t\t\tmethods = [\"*\"];\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!endpointRegistry.has(path)) {\n\t\t\t\t\t\tendpointRegistry.set(path, []);\n\t\t\t\t\t}\n\t\t\t\t\tendpointRegistry.get(path)!.push({\n\t\t\t\t\t\tpluginId: plugin.id,\n\t\t\t\t\t\tendpointKey: key,\n\t\t\t\t\t\tmethods,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tconst conflicts: {\n\t\tpath: string;\n\t\tplugins: string[];\n\t\tconflictingMethods: string[];\n\t}[] = [];\n\tfor (const [path, entries] of endpointRegistry.entries()) {\n\t\tif (entries.length > 1) {\n\t\t\tconst methodMap = new Map<string, string[]>();\n\t\t\tlet hasConflict = false;\n\n\t\t\tfor (const entry of entries) {\n\t\t\t\tfor (const method of entry.methods) {\n\t\t\t\t\tif (!methodMap.has(method)) {\n\t\t\t\t\t\tmethodMap.set(method, []);\n\t\t\t\t\t}\n\t\t\t\t\tmethodMap.get(method)!.push(entry.pluginId);\n\n\t\t\t\t\tif (methodMap.get(method)!.length > 1) {\n\t\t\t\t\t\thasConflict = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (method === \"*\" && entries.length > 1) {\n\t\t\t\t\t\thasConflict = true;\n\t\t\t\t\t} else if (method !== \"*\" && methodMap.has(\"*\")) {\n\t\t\t\t\t\thasConflict = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (hasConflict) {\n\t\t\t\tconst uniquePlugins = [...new Set(entries.map((e) => e.pluginId))];\n\t\t\t\tconst conflictingMethods: string[] = [];\n\n\t\t\t\tfor (const [method, plugins] of methodMap.entries()) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tplugins.length > 1 ||\n\t\t\t\t\t\t(method === \"*\" && entries.length > 1) ||\n\t\t\t\t\t\t(method !== \"*\" && methodMap.has(\"*\"))\n\t\t\t\t\t) {\n\t\t\t\t\t\tconflictingMethods.push(method);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconflicts.push({\n\t\t\t\t\tpath,\n\t\t\t\t\tplugins: uniquePlugins,\n\t\t\t\t\tconflictingMethods,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tif (conflicts.length > 0) {\n\t\tconst conflictMessages = conflicts\n\t\t\t.map(\n\t\t\t\t(conflict) =>\n\t\t\t\t\t` - \"${conflict.path}\" [${conflict.conflictingMethods.join(\", \")}] used by plugins: ${conflict.plugins.join(\", \")}`,\n\t\t\t)\n\t\t\t.join(\"\\n\");\n\t\tlogger.error(\n\t\t\t`Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths with conflicting HTTP methods:\n${conflictMessages}\n\nTo resolve this, you can:\n\t1. Use only one of the conflicting plugins\n\t2. Configure the plugins to use different paths (if supported)\n\t3. Ensure plugins use different HTTP methods for the same path\n`,\n\t\t);\n\t}\n}\n\nexport function getEndpoints<Option extends BetterAuthOptions>(\n\tctx: Awaitable<AuthContext>,\n\toptions: Option,\n) {\n\tconst pluginEndpoints =\n\t\toptions.plugins?.reduce<Record<string, Endpoint>>((acc, plugin) => {\n\t\t\treturn {\n\t\t\t\t...acc,\n\t\t\t\t...plugin.endpoints,\n\t\t\t};\n\t\t}, {}) ?? {};\n\n\ttype PluginEndpoint = UnionToIntersection<\n\t\tOption[\"plugins\"] extends Array<infer T>\n\t\t\t? T extends BetterAuthPlugin\n\t\t\t\t? T extends {\n\t\t\t\t\t\tendpoints: infer E;\n\t\t\t\t\t}\n\t\t\t\t\t? E\n\t\t\t\t\t: {}\n\t\t\t\t: {}\n\t\t\t: {}\n\t>;\n\n\tconst middlewares =\n\t\toptions.plugins\n\t\t\t?.map((plugin) =>\n\t\t\t\tplugin.middlewares?.map((m) => {\n\t\t\t\t\tconst middleware = (async (context: any) => {\n\t\t\t\t\t\tconst authContext = await ctx;\n\t\t\t\t\t\treturn m.middleware({\n\t\t\t\t\t\t\t...context,\n\t\t\t\t\t\t\tcontext: {\n\t\t\t\t\t\t\t\t...authContext,\n\t\t\t\t\t\t\t\t...context.context,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}) as Middleware;\n\t\t\t\t\tmiddleware.options = m.middleware.options;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpath: m.path,\n\t\t\t\t\t\tmiddleware,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.filter((plugin) => plugin !== undefined)\n\t\t\t.flat() || [];\n\n\tconst baseEndpoints = {\n\t\tsignInSocial: signInSocial<Option>(),\n\t\tcallbackOAuth,\n\t\tgetSession: getSession<Option>(),\n\t\tsignOut,\n\t\tsignUpEmail: signUpEmail<Option>(),\n\t\tsignInEmail: signInEmail<Option>(),\n\t\tresetPassword,\n\t\tverifyEmail,\n\t\tsendVerificationEmail,\n\t\tchangeEmail,\n\t\tchangePassword,\n\t\tsetPassword,\n\t\tupdateUser: updateUser<Option>(),\n\t\tdeleteUser,\n\t\trequestPasswordReset,\n\t\trequestPasswordResetCallback,\n\t\tlistSessions: listSessions<Option>(),\n\t\trevokeSession,\n\t\trevokeSessions,\n\t\trevokeOtherSessions,\n\t\tlinkSocialAccount,\n\t\tlistUserAccounts,\n\t\tdeleteUserCallback,\n\t\tunlinkAccount,\n\t\trefreshToken,\n\t\tgetAccessToken,\n\t\taccountInfo,\n\t};\n\tconst endpoints = {\n\t\t...baseEndpoints,\n\t\t...pluginEndpoints,\n\t\tok,\n\t\terror,\n\t} as const;\n\tconst api = toAuthEndpoints(endpoints, ctx);\n\treturn {\n\t\tapi: api as typeof endpoints & PluginEndpoint,\n\t\tmiddlewares,\n\t};\n}\nexport const router = <Option extends BetterAuthOptions>(\n\tctx: AuthContext,\n\toptions: Option,\n) => {\n\tconst { api, middlewares } = getEndpoints(ctx, options);\n\tconst basePath = new URL(ctx.baseURL).pathname;\n\n\treturn createRouter(api, {\n\t\trouterContext: ctx,\n\t\topenapi: {\n\t\t\tdisabled: true,\n\t\t},\n\t\tbasePath,\n\t\trouterMiddleware: [\n\t\t\t{\n\t\t\t\tpath: \"/**\",\n\t\t\t\tmiddleware: originCheckMiddleware,\n\t\t\t},\n\t\t\t...middlewares,\n\t\t],\n\t\tallowedMediaTypes: [\"application/json\"],\n\t\tasync onRequest(req) {\n\t\t\t//handle disabled paths\n\t\t\tconst disabledPaths = ctx.options.disabledPaths || [];\n\t\t\tconst pathname = new URL(req.url).pathname.replace(/\\/+$/, \"\") || \"/\";\n\n\t\t\tconst normalizedPath =\n\t\t\t\tbasePath === \"/\"\n\t\t\t\t\t? pathname\n\t\t\t\t\t: pathname.startsWith(basePath)\n\t\t\t\t\t\t? pathname.slice(basePath.length).replace(/\\/+$/, \"\") || \"/\"\n\t\t\t\t\t\t: pathname;\n\t\t\tif (disabledPaths.includes(normalizedPath)) {\n\t\t\t\treturn new Response(\"Not Found\", { status: 404 });\n\t\t\t}\n\n\t\t\tlet currentRequest = req;\n\t\t\tfor (const plugin of ctx.options.plugins || []) {\n\t\t\t\tif (plugin.onRequest) {\n\t\t\t\t\tconst response = await plugin.onRequest(currentRequest, ctx);\n\t\t\t\t\tif (response && \"response\" in response) {\n\t\t\t\t\t\treturn response.response;\n\t\t\t\t\t}\n\t\t\t\t\tif (response && \"request\" in response) {\n\t\t\t\t\t\tcurrentRequest = response.request;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst rateLimitResponse = await onRequestRateLimit(currentRequest, ctx);\n\t\t\tif (rateLimitResponse) {\n\t\t\t\treturn rateLimitResponse;\n\t\t\t}\n\n\t\t\treturn currentRequest;\n\t\t},\n\t\tasync onResponse(res) {\n\t\t\tfor (const plugin of ctx.options.plugins || []) {\n\t\t\t\tif (plugin.onResponse) {\n\t\t\t\t\tconst response = await plugin.onResponse(res, ctx);\n\t\t\t\t\tif (response) {\n\t\t\t\t\t\treturn response.response;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn res;\n\t\t},\n\t\tonError(e) {\n\t\t\tif (e instanceof APIError && e.status === \"FOUND\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (options.onAPIError?.throw) {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\tif (options.onAPIError?.onError) {\n\t\t\t\toptions.onAPIError.onError(e, ctx);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst optLogLevel = options.logger?.level;\n\t\t\tconst log =\n\t\t\t\toptLogLevel === \"error\" ||\n\t\t\t\toptLogLevel === \"warn\" ||\n\t\t\t\toptLogLevel === \"debug\"\n\t\t\t\t\t? logger\n\t\t\t\t\t: undefined;\n\t\t\tif (options.logger?.disabled !== true) {\n\t\t\t\tif (\n\t\t\t\t\te &&\n\t\t\t\t\ttypeof e === \"object\" &&\n\t\t\t\t\t\"message\" in e &&\n\t\t\t\t\ttypeof e.message === \"string\"\n\t\t\t\t) {\n\t\t\t\t\tif (\n\t\t\t\t\t\te.message.includes(\"no column\") ||\n\t\t\t\t\t\te.message.includes(\"column\") ||\n\t\t\t\t\t\te.message.includes(\"relation\") ||\n\t\t\t\t\t\te.message.includes(\"table\") ||\n\t\t\t\t\t\te.message.includes(\"does not exist\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tctx.logger?.error(e.message);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (e instanceof APIError) {\n\t\t\t\t\tif (e.status === \"INTERNAL_SERVER_ERROR\") {\n\t\t\t\t\t\tctx.logger.error(e.status, e);\n\t\t\t\t\t}\n\t\t\t\t\tlog?.error(e.message);\n\t\t\t\t} else {\n\t\t\t\t\tctx.logger?.error(\n\t\t\t\t\t\te && typeof e === \"object\" && \"name\" in e ? (e.name as string) : \"\",\n\t\t\t\t\t\te,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n};\n\nexport {\n\ttype AuthEndpoint,\n\ttype AuthMiddleware,\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n\toptionsMiddleware,\n} from \"@better-auth/core/api\";\nexport { APIError } from \"better-call\";\nexport { getIp } from \"../utils/get-request-ip\";\nexport * from \"./middlewares\";\nexport * from \"./routes\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["methods: string[]","conflicts: {\n\t\tpath: string;\n\t\tplugins: string[];\n\t\tconflictingMethods: string[];\n\t}[]","conflictingMethods: string[]"],"sources":["../../src/api/index.ts"],"sourcesContent":["import type {\n\tAuthContext,\n\tAwaitable,\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n} from \"@better-auth/core\";\nimport type { InternalLogger } from \"@better-auth/core/env\";\nimport { logger } from \"@better-auth/core/env\";\nimport type { Endpoint, Middleware } from \"better-call\";\nimport { createRouter } from \"better-call\";\nimport type { UnionToIntersection } from \"../types/helper\";\nimport { isAPIError } from \"../utils/is-api-error\";\nimport { originCheckMiddleware } from \"./middlewares\";\nimport { onRequestRateLimit } from \"./rate-limiter\";\nimport {\n\taccountInfo,\n\tcallbackOAuth,\n\tchangeEmail,\n\tchangePassword,\n\tdeleteUser,\n\tdeleteUserCallback,\n\terror,\n\tgetAccessToken,\n\tgetSession,\n\tlinkSocialAccount,\n\tlistSessions,\n\tlistUserAccounts,\n\tok,\n\trefreshToken,\n\trequestPasswordReset,\n\trequestPasswordResetCallback,\n\tresetPassword,\n\trevokeOtherSessions,\n\trevokeSession,\n\trevokeSessions,\n\tsendVerificationEmail,\n\tsetPassword,\n\tsignInEmail,\n\tsignInSocial,\n\tsignOut,\n\tsignUpEmail,\n\tunlinkAccount,\n\tupdateUser,\n\tverifyEmail,\n} from \"./routes\";\nimport { toAuthEndpoints } from \"./to-auth-endpoints\";\n\nexport function checkEndpointConflicts(\n\toptions: BetterAuthOptions,\n\tlogger: InternalLogger,\n) {\n\tconst endpointRegistry = new Map<\n\t\tstring,\n\t\t{ pluginId: string; endpointKey: string; methods: string[] }[]\n\t>();\n\n\toptions.plugins?.forEach((plugin) => {\n\t\tif (plugin.endpoints) {\n\t\t\tfor (const [key, endpoint] of Object.entries(plugin.endpoints)) {\n\t\t\t\tif (\n\t\t\t\t\tendpoint &&\n\t\t\t\t\t\"path\" in endpoint &&\n\t\t\t\t\ttypeof endpoint.path === \"string\"\n\t\t\t\t) {\n\t\t\t\t\tconst path = endpoint.path;\n\t\t\t\t\tlet methods: string[] = [];\n\t\t\t\t\tif (endpoint.options && \"method\" in endpoint.options) {\n\t\t\t\t\t\tif (Array.isArray(endpoint.options.method)) {\n\t\t\t\t\t\t\tmethods = endpoint.options.method;\n\t\t\t\t\t\t} else if (typeof endpoint.options.method === \"string\") {\n\t\t\t\t\t\t\tmethods = [endpoint.options.method];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (methods.length === 0) {\n\t\t\t\t\t\tmethods = [\"*\"];\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!endpointRegistry.has(path)) {\n\t\t\t\t\t\tendpointRegistry.set(path, []);\n\t\t\t\t\t}\n\t\t\t\t\tendpointRegistry.get(path)!.push({\n\t\t\t\t\t\tpluginId: plugin.id,\n\t\t\t\t\t\tendpointKey: key,\n\t\t\t\t\t\tmethods,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tconst conflicts: {\n\t\tpath: string;\n\t\tplugins: string[];\n\t\tconflictingMethods: string[];\n\t}[] = [];\n\tfor (const [path, entries] of endpointRegistry.entries()) {\n\t\tif (entries.length > 1) {\n\t\t\tconst methodMap = new Map<string, string[]>();\n\t\t\tlet hasConflict = false;\n\n\t\t\tfor (const entry of entries) {\n\t\t\t\tfor (const method of entry.methods) {\n\t\t\t\t\tif (!methodMap.has(method)) {\n\t\t\t\t\t\tmethodMap.set(method, []);\n\t\t\t\t\t}\n\t\t\t\t\tmethodMap.get(method)!.push(entry.pluginId);\n\n\t\t\t\t\tif (methodMap.get(method)!.length > 1) {\n\t\t\t\t\t\thasConflict = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (method === \"*\" && entries.length > 1) {\n\t\t\t\t\t\thasConflict = true;\n\t\t\t\t\t} else if (method !== \"*\" && methodMap.has(\"*\")) {\n\t\t\t\t\t\thasConflict = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (hasConflict) {\n\t\t\t\tconst uniquePlugins = [...new Set(entries.map((e) => e.pluginId))];\n\t\t\t\tconst conflictingMethods: string[] = [];\n\n\t\t\t\tfor (const [method, plugins] of methodMap.entries()) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tplugins.length > 1 ||\n\t\t\t\t\t\t(method === \"*\" && entries.length > 1) ||\n\t\t\t\t\t\t(method !== \"*\" && methodMap.has(\"*\"))\n\t\t\t\t\t) {\n\t\t\t\t\t\tconflictingMethods.push(method);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconflicts.push({\n\t\t\t\t\tpath,\n\t\t\t\t\tplugins: uniquePlugins,\n\t\t\t\t\tconflictingMethods,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tif (conflicts.length > 0) {\n\t\tconst conflictMessages = conflicts\n\t\t\t.map(\n\t\t\t\t(conflict) =>\n\t\t\t\t\t` - \"${conflict.path}\" [${conflict.conflictingMethods.join(\", \")}] used by plugins: ${conflict.plugins.join(\", \")}`,\n\t\t\t)\n\t\t\t.join(\"\\n\");\n\t\tlogger.error(\n\t\t\t`Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths with conflicting HTTP methods:\n${conflictMessages}\n\nTo resolve this, you can:\n\t1. Use only one of the conflicting plugins\n\t2. Configure the plugins to use different paths (if supported)\n\t3. Ensure plugins use different HTTP methods for the same path\n`,\n\t\t);\n\t}\n}\n\nexport function getEndpoints<Option extends BetterAuthOptions>(\n\tctx: Awaitable<AuthContext>,\n\toptions: Option,\n) {\n\tconst pluginEndpoints =\n\t\toptions.plugins?.reduce<Record<string, Endpoint>>((acc, plugin) => {\n\t\t\treturn {\n\t\t\t\t...acc,\n\t\t\t\t...plugin.endpoints,\n\t\t\t};\n\t\t}, {}) ?? {};\n\n\ttype PluginEndpoint = UnionToIntersection<\n\t\tOption[\"plugins\"] extends Array<infer T>\n\t\t\t? T extends BetterAuthPlugin\n\t\t\t\t? T extends {\n\t\t\t\t\t\tendpoints: infer E;\n\t\t\t\t\t}\n\t\t\t\t\t? E\n\t\t\t\t\t: {}\n\t\t\t\t: {}\n\t\t\t: {}\n\t>;\n\n\tconst middlewares =\n\t\toptions.plugins\n\t\t\t?.map((plugin) =>\n\t\t\t\tplugin.middlewares?.map((m) => {\n\t\t\t\t\tconst middleware = (async (context: any) => {\n\t\t\t\t\t\tconst authContext = await ctx;\n\t\t\t\t\t\treturn m.middleware({\n\t\t\t\t\t\t\t...context,\n\t\t\t\t\t\t\tcontext: {\n\t\t\t\t\t\t\t\t...authContext,\n\t\t\t\t\t\t\t\t...context.context,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}) as Middleware;\n\t\t\t\t\tmiddleware.options = m.middleware.options;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpath: m.path,\n\t\t\t\t\t\tmiddleware,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.filter((plugin) => plugin !== undefined)\n\t\t\t.flat() || [];\n\n\tconst baseEndpoints = {\n\t\tsignInSocial: signInSocial<Option>(),\n\t\tcallbackOAuth,\n\t\tgetSession: getSession<Option>(),\n\t\tsignOut,\n\t\tsignUpEmail: signUpEmail<Option>(),\n\t\tsignInEmail: signInEmail<Option>(),\n\t\tresetPassword,\n\t\tverifyEmail,\n\t\tsendVerificationEmail,\n\t\tchangeEmail,\n\t\tchangePassword,\n\t\tsetPassword,\n\t\tupdateUser: updateUser<Option>(),\n\t\tdeleteUser,\n\t\trequestPasswordReset,\n\t\trequestPasswordResetCallback,\n\t\tlistSessions: listSessions<Option>(),\n\t\trevokeSession,\n\t\trevokeSessions,\n\t\trevokeOtherSessions,\n\t\tlinkSocialAccount,\n\t\tlistUserAccounts,\n\t\tdeleteUserCallback,\n\t\tunlinkAccount,\n\t\trefreshToken,\n\t\tgetAccessToken,\n\t\taccountInfo,\n\t};\n\tconst endpoints = {\n\t\t...baseEndpoints,\n\t\t...pluginEndpoints,\n\t\tok,\n\t\terror,\n\t} as const;\n\tconst api = toAuthEndpoints(endpoints, ctx);\n\treturn {\n\t\tapi: api as typeof endpoints & PluginEndpoint,\n\t\tmiddlewares,\n\t};\n}\nexport const router = <Option extends BetterAuthOptions>(\n\tctx: AuthContext,\n\toptions: Option,\n) => {\n\tconst { api, middlewares } = getEndpoints(ctx, options);\n\tconst basePath = new URL(ctx.baseURL).pathname;\n\n\treturn createRouter(api, {\n\t\trouterContext: ctx,\n\t\topenapi: {\n\t\t\tdisabled: true,\n\t\t},\n\t\tbasePath,\n\t\trouterMiddleware: [\n\t\t\t{\n\t\t\t\tpath: \"/**\",\n\t\t\t\tmiddleware: originCheckMiddleware,\n\t\t\t},\n\t\t\t...middlewares,\n\t\t],\n\t\tallowedMediaTypes: [\"application/json\"],\n\t\tasync onRequest(req) {\n\t\t\t//handle disabled paths\n\t\t\tconst disabledPaths = ctx.options.disabledPaths || [];\n\t\t\tconst pathname = new URL(req.url).pathname.replace(/\\/+$/, \"\") || \"/\";\n\n\t\t\tconst normalizedPath =\n\t\t\t\tbasePath === \"/\"\n\t\t\t\t\t? pathname\n\t\t\t\t\t: pathname.startsWith(basePath)\n\t\t\t\t\t\t? pathname.slice(basePath.length).replace(/\\/+$/, \"\") || \"/\"\n\t\t\t\t\t\t: pathname;\n\t\t\tif (disabledPaths.includes(normalizedPath)) {\n\t\t\t\treturn new Response(\"Not Found\", { status: 404 });\n\t\t\t}\n\n\t\t\tlet currentRequest = req;\n\t\t\tfor (const plugin of ctx.options.plugins || []) {\n\t\t\t\tif (plugin.onRequest) {\n\t\t\t\t\tconst response = await plugin.onRequest(currentRequest, ctx);\n\t\t\t\t\tif (response && \"response\" in response) {\n\t\t\t\t\t\treturn response.response;\n\t\t\t\t\t}\n\t\t\t\t\tif (response && \"request\" in response) {\n\t\t\t\t\t\tcurrentRequest = response.request;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst rateLimitResponse = await onRequestRateLimit(currentRequest, ctx);\n\t\t\tif (rateLimitResponse) {\n\t\t\t\treturn rateLimitResponse;\n\t\t\t}\n\n\t\t\treturn currentRequest;\n\t\t},\n\t\tasync onResponse(res) {\n\t\t\tfor (const plugin of ctx.options.plugins || []) {\n\t\t\t\tif (plugin.onResponse) {\n\t\t\t\t\tconst response = await plugin.onResponse(res, ctx);\n\t\t\t\t\tif (response) {\n\t\t\t\t\t\treturn response.response;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn res;\n\t\t},\n\t\tonError(e) {\n\t\t\tif (isAPIError(e) && e.status === \"FOUND\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (options.onAPIError?.throw) {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\tif (options.onAPIError?.onError) {\n\t\t\t\toptions.onAPIError.onError(e, ctx);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst optLogLevel = options.logger?.level;\n\t\t\tconst log =\n\t\t\t\toptLogLevel === \"error\" ||\n\t\t\t\toptLogLevel === \"warn\" ||\n\t\t\t\toptLogLevel === \"debug\"\n\t\t\t\t\t? logger\n\t\t\t\t\t: undefined;\n\t\t\tif (options.logger?.disabled !== true) {\n\t\t\t\tif (\n\t\t\t\t\te &&\n\t\t\t\t\ttypeof e === \"object\" &&\n\t\t\t\t\t\"message\" in e &&\n\t\t\t\t\ttypeof e.message === \"string\"\n\t\t\t\t) {\n\t\t\t\t\tif (\n\t\t\t\t\t\te.message.includes(\"no column\") ||\n\t\t\t\t\t\te.message.includes(\"column\") ||\n\t\t\t\t\t\te.message.includes(\"relation\") ||\n\t\t\t\t\t\te.message.includes(\"table\") ||\n\t\t\t\t\t\te.message.includes(\"does not exist\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tctx.logger?.error(e.message);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\tif (e.status === \"INTERNAL_SERVER_ERROR\") {\n\t\t\t\t\t\tctx.logger.error(e.status, e);\n\t\t\t\t\t}\n\t\t\t\t\tlog?.error(e.message);\n\t\t\t\t} else {\n\t\t\t\t\tctx.logger?.error(\n\t\t\t\t\t\te && typeof e === \"object\" && \"name\" in e ? (e.name as string) : \"\",\n\t\t\t\t\t\te,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n};\n\nexport {\n\ttype AuthEndpoint,\n\ttype AuthMiddleware,\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n\toptionsMiddleware,\n} from \"@better-auth/core/api\";\nexport { APIError } from \"@better-auth/core/error\";\nexport { getIp } from \"../utils/get-request-ip\";\nexport { isAPIError } from \"../utils/is-api-error\";\nexport * from \"./middlewares\";\nexport * from \"./routes\";\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { GenericEndpointContext } from "@better-auth/core";
2
- import * as better_call974 from "better-call";
2
+ import * as better_call800 from "better-call";
3
3
 
4
4
  //#region src/api/middlewares/origin-check.d.ts
5
5
 
@@ -7,13 +7,13 @@ import * as better_call974 from "better-call";
7
7
  * A middleware to validate callbackURL and origin against trustedOrigins.
8
8
  * Also handles CSRF protection using Fetch Metadata for first-login scenarios.
9
9
  */
10
- declare const originCheckMiddleware: (inputContext: better_call974.MiddlewareInputContext<better_call974.MiddlewareOptions>) => Promise<void>;
11
- declare const originCheck: (getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: better_call974.MiddlewareInputContext<better_call974.MiddlewareOptions>) => Promise<void>;
10
+ declare const originCheckMiddleware: (inputContext: better_call800.MiddlewareInputContext<better_call800.MiddlewareOptions>) => Promise<void>;
11
+ declare const originCheck: (getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: better_call800.MiddlewareInputContext<better_call800.MiddlewareOptions>) => Promise<void>;
12
12
  /**
13
13
  * Middleware for CSRF protection using Fetch Metadata headers.
14
14
  * This prevents cross-site navigation login attacks while supporting progressive enhancement.
15
15
  */
16
- declare const formCsrfMiddleware: (inputContext: better_call974.MiddlewareInputContext<better_call974.MiddlewareOptions>) => Promise<void>;
16
+ declare const formCsrfMiddleware: (inputContext: better_call800.MiddlewareInputContext<better_call800.MiddlewareOptions>) => Promise<void>;
17
17
  //#endregion
18
18
  export { formCsrfMiddleware, originCheck, originCheckMiddleware };
19
19
  //# sourceMappingURL=origin-check.d.mts.map
@@ -1,6 +1,5 @@
1
1
  import { matchesOriginPattern } from "../../auth/trusted-origins.mjs";
2
- import { BASE_ERROR_CODES } from "@better-auth/core/error";
3
- import { APIError } from "better-call";
2
+ import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
4
3
  import { createAuthMiddleware } from "@better-auth/core/api";
5
4
 
6
5
  //#region src/api/middlewares/origin-check.ts
@@ -21,7 +20,12 @@ const originCheckMiddleware = createAuthMiddleware(async (ctx) => {
21
20
  if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) {
22
21
  ctx.context.logger.error(`Invalid ${label}: ${url}`);
23
22
  ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\n`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`);
24
- throw new APIError("FORBIDDEN", { message: `Invalid ${label}` });
23
+ if (label === "origin") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_ORIGIN);
24
+ if (label === "callbackURL") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_CALLBACK_URL);
25
+ if (label === "redirectURL") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_REDIRECT_URL);
26
+ if (label === "errorCallbackURL") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_ERROR_CALLBACK_URL);
27
+ if (label === "newUserCallbackURL") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_NEW_USER_CALLBACK_URL);
28
+ throw APIError.fromStatus("FORBIDDEN", { message: `Invalid ${label}` });
25
29
  }
26
30
  };
27
31
  callbackURL && validateURL(callbackURL, "callbackURL");
@@ -37,7 +41,12 @@ const originCheck = (getValue) => createAuthMiddleware(async (ctx) => {
37
41
  if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) {
38
42
  ctx.context.logger.error(`Invalid ${label}: ${url}`);
39
43
  ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\n`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`);
40
- throw new APIError("FORBIDDEN", { message: `Invalid ${label}` });
44
+ if (label === "origin") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_ORIGIN);
45
+ if (label === "callbackURL") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_CALLBACK_URL);
46
+ if (label === "redirectURL") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_REDIRECT_URL);
47
+ if (label === "errorCallbackURL") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_ERROR_CALLBACK_URL);
48
+ if (label === "newUserCallbackURL") throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.INVALID_NEW_USER_CALLBACK_URL);
49
+ throw APIError.fromStatus("FORBIDDEN", { message: `Invalid ${label}` });
41
50
  }
42
51
  };
43
52
  const callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL];
@@ -89,7 +98,7 @@ async function validateFormCsrf(ctx) {
89
98
  secFetchMode: mode,
90
99
  secFetchDest: dest
91
100
  });
92
- throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.CROSS_SITE_NAVIGATION_LOGIN_BLOCKED });
101
+ throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.CROSS_SITE_NAVIGATION_LOGIN_BLOCKED);
93
102
  }
94
103
  return await validateOrigin(ctx, true);
95
104
  }
@@ -1 +1 @@
1
- {"version":3,"file":"origin-check.mjs","names":["trustedOrigins: string[]"],"sources":["../../../src/api/middlewares/origin-check.ts"],"sourcesContent":["import type { GenericEndpointContext } from \"@better-auth/core\";\nimport { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { APIError } from \"better-call\";\nimport { matchesOriginPattern } from \"../../auth/trusted-origins\";\n\n/**\n * A middleware to validate callbackURL and origin against trustedOrigins.\n * Also handles CSRF protection using Fetch Metadata for first-login scenarios.\n */\nexport const originCheckMiddleware = createAuthMiddleware(async (ctx) => {\n\t// Skip origin check for GET, OPTIONS, HEAD requests - we don't mutate state here.\n\tif (\n\t\tctx.request?.method === \"GET\" ||\n\t\tctx.request?.method === \"OPTIONS\" ||\n\t\tctx.request?.method === \"HEAD\" ||\n\t\t!ctx.request\n\t) {\n\t\treturn;\n\t}\n\tawait validateOrigin(ctx);\n\n\tconst { body, query } = ctx;\n\tconst callbackURL = body?.callbackURL || query?.callbackURL;\n\tconst redirectURL = body?.redirectTo;\n\tconst errorCallbackURL = body?.errorCallbackURL;\n\tconst newUserCallbackURL = body?.newUserCallbackURL;\n\n\tconst validateURL = (url: string | undefined, label: string) => {\n\t\tif (!url) {\n\t\t\treturn;\n\t\t}\n\t\tconst isTrustedOrigin = ctx.context.isTrustedOrigin(url, {\n\t\t\tallowRelativePaths: label !== \"origin\",\n\t\t});\n\n\t\tif (!isTrustedOrigin) {\n\t\t\tctx.context.logger.error(`Invalid ${label}: ${url}`);\n\t\t\tctx.context.logger.info(\n\t\t\t\t`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\\n`,\n\t\t\t\t`Current list of trustedOrigins: ${ctx.context.trustedOrigins}`,\n\t\t\t);\n\t\t\tthrow new APIError(\"FORBIDDEN\", { message: `Invalid ${label}` });\n\t\t}\n\t};\n\n\tcallbackURL && validateURL(callbackURL, \"callbackURL\");\n\tredirectURL && validateURL(redirectURL, \"redirectURL\");\n\terrorCallbackURL && validateURL(errorCallbackURL, \"errorCallbackURL\");\n\tnewUserCallbackURL && validateURL(newUserCallbackURL, \"newUserCallbackURL\");\n});\n\nexport const originCheck = (\n\tgetValue: (ctx: GenericEndpointContext) => string | string[],\n) =>\n\tcreateAuthMiddleware(async (ctx) => {\n\t\tif (!ctx.request) {\n\t\t\treturn;\n\t\t}\n\t\tconst callbackURL = getValue(ctx);\n\t\tconst validateURL = (url: string | undefined, label: string) => {\n\t\t\tif (!url) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst isTrustedOrigin = ctx.context.isTrustedOrigin(url, {\n\t\t\t\tallowRelativePaths: label !== \"origin\",\n\t\t\t});\n\n\t\t\tif (!isTrustedOrigin) {\n\t\t\t\tctx.context.logger.error(`Invalid ${label}: ${url}`);\n\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\\n`,\n\t\t\t\t\t`Current list of trustedOrigins: ${ctx.context.trustedOrigins}`,\n\t\t\t\t);\n\t\t\t\tthrow new APIError(\"FORBIDDEN\", { message: `Invalid ${label}` });\n\t\t\t}\n\t\t};\n\t\tconst callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL];\n\t\tfor (const url of callbacks) {\n\t\t\tvalidateURL(url, \"callbackURL\");\n\t\t}\n\t});\n\n/**\n * Validates origin header against trusted origins.\n * @param ctx - The endpoint context\n * @param forceValidate - If true, always validate origin regardless of cookies/skip flags\n */\nasync function validateOrigin(\n\tctx: GenericEndpointContext,\n\tforceValidate = false,\n): Promise<void> {\n\tconst headers = ctx.request?.headers;\n\tif (!headers || !ctx.request) {\n\t\treturn;\n\t}\n\tconst originHeader = headers.get(\"origin\") || headers.get(\"referer\") || \"\";\n\tconst useCookies = headers.has(\"cookie\");\n\n\tconst shouldValidate =\n\t\tforceValidate ||\n\t\t(useCookies && !ctx.context.skipCSRFCheck && !ctx.context.skipOriginCheck);\n\n\tif (!shouldValidate) {\n\t\treturn;\n\t}\n\n\tif (!originHeader || originHeader === \"null\") {\n\t\tthrow new APIError(\"FORBIDDEN\", { message: \"Missing or null Origin\" });\n\t}\n\n\tconst trustedOrigins: string[] = Array.isArray(\n\t\tctx.context.options.trustedOrigins,\n\t)\n\t\t? ctx.context.trustedOrigins\n\t\t: [\n\t\t\t\t...ctx.context.trustedOrigins,\n\t\t\t\t...((await ctx.context.options.trustedOrigins?.(ctx.request)) || []),\n\t\t\t];\n\n\tconst isTrustedOrigin = trustedOrigins.some((origin) =>\n\t\tmatchesOriginPattern(originHeader, origin),\n\t);\n\tif (!isTrustedOrigin) {\n\t\tctx.context.logger.error(`Invalid origin: ${originHeader}`);\n\t\tctx.context.logger.info(\n\t\t\t`If it's a valid URL, please add ${originHeader} to trustedOrigins in your auth config\\n`,\n\t\t\t`Current list of trustedOrigins: ${trustedOrigins}`,\n\t\t);\n\t\tthrow new APIError(\"FORBIDDEN\", { message: \"Invalid origin\" });\n\t}\n}\n\n/**\n * Middleware for CSRF protection using Fetch Metadata headers.\n * This prevents cross-site navigation login attacks while supporting progressive enhancement.\n */\nexport const formCsrfMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst request = ctx.request;\n\tif (!request) {\n\t\treturn;\n\t}\n\n\tawait validateFormCsrf(ctx);\n});\n\n/**\n * Validates CSRF protection for first-login scenarios using Fetch Metadata headers.\n * This prevents cross-site form submission attacks while supporting progressive enhancement.\n */\nasync function validateFormCsrf(ctx: GenericEndpointContext): Promise<void> {\n\tconst req = ctx.request;\n\tif (!req) {\n\t\treturn;\n\t}\n\n\tconst headers = req.headers;\n\tconst hasAnyCookies = headers.has(\"cookie\");\n\n\tif (hasAnyCookies) {\n\t\treturn await validateOrigin(ctx);\n\t}\n\n\tconst site = headers.get(\"Sec-Fetch-Site\");\n\tconst mode = headers.get(\"Sec-Fetch-Mode\");\n\tconst dest = headers.get(\"Sec-Fetch-Dest\");\n\n\tconst hasMetadata = Boolean(\n\t\t(site && site.trim()) || (mode && mode.trim()) || (dest && dest.trim()),\n\t);\n\n\tif (hasMetadata) {\n\t\t// Block cross-site navigation requests (classic CSRF attack pattern)\n\t\tif (site === \"cross-site\" && mode === \"navigate\") {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Blocked cross-site navigation login attempt (CSRF protection)\",\n\t\t\t\t{\n\t\t\t\t\tsecFetchSite: site,\n\t\t\t\t\tsecFetchMode: mode,\n\t\t\t\t\tsecFetchDest: dest,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.CROSS_SITE_NAVIGATION_LOGIN_BLOCKED,\n\t\t\t});\n\t\t}\n\n\t\treturn await validateOrigin(ctx, true);\n\t}\n\n\t// No cookies, no Fetch Metadata → fallback to old behavior (no validation)\n\treturn;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"origin-check.mjs","names":["trustedOrigins: string[]"],"sources":["../../../src/api/middlewares/origin-check.ts"],"sourcesContent":["import type { GenericEndpointContext } from \"@better-auth/core\";\nimport { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { matchesOriginPattern } from \"../../auth/trusted-origins\";\n\n/**\n * A middleware to validate callbackURL and origin against trustedOrigins.\n * Also handles CSRF protection using Fetch Metadata for first-login scenarios.\n */\nexport const originCheckMiddleware = createAuthMiddleware(async (ctx) => {\n\t// Skip origin check for GET, OPTIONS, HEAD requests - we don't mutate state here.\n\tif (\n\t\tctx.request?.method === \"GET\" ||\n\t\tctx.request?.method === \"OPTIONS\" ||\n\t\tctx.request?.method === \"HEAD\" ||\n\t\t!ctx.request\n\t) {\n\t\treturn;\n\t}\n\tawait validateOrigin(ctx);\n\n\tconst { body, query } = ctx;\n\tconst callbackURL = body?.callbackURL || query?.callbackURL;\n\tconst redirectURL = body?.redirectTo;\n\tconst errorCallbackURL = body?.errorCallbackURL;\n\tconst newUserCallbackURL = body?.newUserCallbackURL;\n\n\tconst validateURL = (\n\t\turl: string | undefined,\n\t\tlabel:\n\t\t\t| \"origin\"\n\t\t\t| \"callbackURL\"\n\t\t\t| \"redirectURL\"\n\t\t\t| \"errorCallbackURL\"\n\t\t\t| \"newUserCallbackURL\",\n\t) => {\n\t\tif (!url) {\n\t\t\treturn;\n\t\t}\n\t\tconst isTrustedOrigin = ctx.context.isTrustedOrigin(url, {\n\t\t\tallowRelativePaths: label !== \"origin\",\n\t\t});\n\n\t\tif (!isTrustedOrigin) {\n\t\t\tctx.context.logger.error(`Invalid ${label}: ${url}`);\n\t\t\tctx.context.logger.info(\n\t\t\t\t`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\\n`,\n\t\t\t\t`Current list of trustedOrigins: ${ctx.context.trustedOrigins}`,\n\t\t\t);\n\t\t\tif (label === \"origin\") {\n\t\t\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.INVALID_ORIGIN);\n\t\t\t}\n\t\t\tif (label === \"callbackURL\") {\n\t\t\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.INVALID_CALLBACK_URL);\n\t\t\t}\n\t\t\tif (label === \"redirectURL\") {\n\t\t\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.INVALID_REDIRECT_URL);\n\t\t\t}\n\t\t\tif (label === \"errorCallbackURL\") {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"FORBIDDEN\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_ERROR_CALLBACK_URL,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (label === \"newUserCallbackURL\") {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"FORBIDDEN\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_NEW_USER_CALLBACK_URL,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow APIError.fromStatus(\"FORBIDDEN\", {\n\t\t\t\tmessage: `Invalid ${label}`,\n\t\t\t});\n\t\t}\n\t};\n\n\tcallbackURL && validateURL(callbackURL, \"callbackURL\");\n\tredirectURL && validateURL(redirectURL, \"redirectURL\");\n\terrorCallbackURL && validateURL(errorCallbackURL, \"errorCallbackURL\");\n\tnewUserCallbackURL && validateURL(newUserCallbackURL, \"newUserCallbackURL\");\n});\n\nexport const originCheck = (\n\tgetValue: (ctx: GenericEndpointContext) => string | string[],\n) =>\n\tcreateAuthMiddleware(async (ctx) => {\n\t\tif (!ctx.request) {\n\t\t\treturn;\n\t\t}\n\t\tconst callbackURL = getValue(ctx);\n\t\tconst validateURL = (url: string | undefined, label: string) => {\n\t\t\tif (!url) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst isTrustedOrigin = ctx.context.isTrustedOrigin(url, {\n\t\t\t\tallowRelativePaths: label !== \"origin\",\n\t\t\t});\n\n\t\t\tif (!isTrustedOrigin) {\n\t\t\t\tctx.context.logger.error(`Invalid ${label}: ${url}`);\n\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\\n`,\n\t\t\t\t\t`Current list of trustedOrigins: ${ctx.context.trustedOrigins}`,\n\t\t\t\t);\n\t\t\t\tif (label === \"origin\") {\n\t\t\t\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.INVALID_ORIGIN);\n\t\t\t\t}\n\t\t\t\tif (label === \"callbackURL\") {\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"FORBIDDEN\",\n\t\t\t\t\t\tBASE_ERROR_CODES.INVALID_CALLBACK_URL,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (label === \"redirectURL\") {\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"FORBIDDEN\",\n\t\t\t\t\t\tBASE_ERROR_CODES.INVALID_REDIRECT_URL,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (label === \"errorCallbackURL\") {\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"FORBIDDEN\",\n\t\t\t\t\t\tBASE_ERROR_CODES.INVALID_ERROR_CALLBACK_URL,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (label === \"newUserCallbackURL\") {\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"FORBIDDEN\",\n\t\t\t\t\t\tBASE_ERROR_CODES.INVALID_NEW_USER_CALLBACK_URL,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow APIError.fromStatus(\"FORBIDDEN\", {\n\t\t\t\t\tmessage: `Invalid ${label}`,\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\tconst callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL];\n\t\tfor (const url of callbacks) {\n\t\t\tvalidateURL(url, \"callbackURL\");\n\t\t}\n\t});\n\n/**\n * Validates origin header against trusted origins.\n * @param ctx - The endpoint context\n * @param forceValidate - If true, always validate origin regardless of cookies/skip flags\n */\nasync function validateOrigin(\n\tctx: GenericEndpointContext,\n\tforceValidate = false,\n): Promise<void> {\n\tconst headers = ctx.request?.headers;\n\tif (!headers || !ctx.request) {\n\t\treturn;\n\t}\n\tconst originHeader = headers.get(\"origin\") || headers.get(\"referer\") || \"\";\n\tconst useCookies = headers.has(\"cookie\");\n\n\tconst shouldValidate =\n\t\tforceValidate ||\n\t\t(useCookies && !ctx.context.skipCSRFCheck && !ctx.context.skipOriginCheck);\n\n\tif (!shouldValidate) {\n\t\treturn;\n\t}\n\n\tif (!originHeader || originHeader === \"null\") {\n\t\tthrow new APIError(\"FORBIDDEN\", { message: \"Missing or null Origin\" });\n\t}\n\n\tconst trustedOrigins: string[] = Array.isArray(\n\t\tctx.context.options.trustedOrigins,\n\t)\n\t\t? ctx.context.trustedOrigins\n\t\t: [\n\t\t\t\t...ctx.context.trustedOrigins,\n\t\t\t\t...((await ctx.context.options.trustedOrigins?.(ctx.request)) || []),\n\t\t\t];\n\n\tconst isTrustedOrigin = trustedOrigins.some((origin) =>\n\t\tmatchesOriginPattern(originHeader, origin),\n\t);\n\tif (!isTrustedOrigin) {\n\t\tctx.context.logger.error(`Invalid origin: ${originHeader}`);\n\t\tctx.context.logger.info(\n\t\t\t`If it's a valid URL, please add ${originHeader} to trustedOrigins in your auth config\\n`,\n\t\t\t`Current list of trustedOrigins: ${trustedOrigins}`,\n\t\t);\n\t\tthrow new APIError(\"FORBIDDEN\", { message: \"Invalid origin\" });\n\t}\n}\n\n/**\n * Middleware for CSRF protection using Fetch Metadata headers.\n * This prevents cross-site navigation login attacks while supporting progressive enhancement.\n */\nexport const formCsrfMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst request = ctx.request;\n\tif (!request) {\n\t\treturn;\n\t}\n\n\tawait validateFormCsrf(ctx);\n});\n\n/**\n * Validates CSRF protection for first-login scenarios using Fetch Metadata headers.\n * This prevents cross-site form submission attacks while supporting progressive enhancement.\n */\nasync function validateFormCsrf(ctx: GenericEndpointContext): Promise<void> {\n\tconst req = ctx.request;\n\tif (!req) {\n\t\treturn;\n\t}\n\n\tconst headers = req.headers;\n\tconst hasAnyCookies = headers.has(\"cookie\");\n\n\tif (hasAnyCookies) {\n\t\treturn await validateOrigin(ctx);\n\t}\n\n\tconst site = headers.get(\"Sec-Fetch-Site\");\n\tconst mode = headers.get(\"Sec-Fetch-Mode\");\n\tconst dest = headers.get(\"Sec-Fetch-Dest\");\n\n\tconst hasMetadata = Boolean(\n\t\t(site && site.trim()) || (mode && mode.trim()) || (dest && dest.trim()),\n\t);\n\n\tif (hasMetadata) {\n\t\t// Block cross-site navigation requests (classic CSRF attack pattern)\n\t\tif (site === \"cross-site\" && mode === \"navigate\") {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Blocked cross-site navigation login attempt (CSRF protection)\",\n\t\t\t\t{\n\t\t\t\t\tsecFetchSite: site,\n\t\t\t\t\tsecFetchMode: mode,\n\t\t\t\t\tsecFetchDest: dest,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthrow APIError.from(\n\t\t\t\t\"FORBIDDEN\",\n\t\t\t\tBASE_ERROR_CODES.CROSS_SITE_NAVIGATION_LOGIN_BLOCKED,\n\t\t\t);\n\t\t}\n\n\t\treturn await validateOrigin(ctx, true);\n\t}\n\n\t// No cookies, no Fetch Metadata → fallback to old behavior (no validation)\n\treturn;\n}\n"],"mappings":";;;;;;;;;AASA,MAAa,wBAAwB,qBAAqB,OAAO,QAAQ;AAExE,KACC,IAAI,SAAS,WAAW,SACxB,IAAI,SAAS,WAAW,aACxB,IAAI,SAAS,WAAW,UACxB,CAAC,IAAI,QAEL;AAED,OAAM,eAAe,IAAI;CAEzB,MAAM,EAAE,MAAM,UAAU;CACxB,MAAM,cAAc,MAAM,eAAe,OAAO;CAChD,MAAM,cAAc,MAAM;CAC1B,MAAM,mBAAmB,MAAM;CAC/B,MAAM,qBAAqB,MAAM;CAEjC,MAAM,eACL,KACA,UAMI;AACJ,MAAI,CAAC,IACJ;AAMD,MAAI,CAJoB,IAAI,QAAQ,gBAAgB,KAAK,EACxD,oBAAoB,UAAU,UAC9B,CAAC,EAEoB;AACrB,OAAI,QAAQ,OAAO,MAAM,WAAW,MAAM,IAAI,MAAM;AACpD,OAAI,QAAQ,OAAO,KAClB,mCAAmC,IAAI,2CACvC,mCAAmC,IAAI,QAAQ,iBAC/C;AACD,OAAI,UAAU,SACb,OAAM,SAAS,KAAK,aAAa,iBAAiB,eAAe;AAElE,OAAI,UAAU,cACb,OAAM,SAAS,KAAK,aAAa,iBAAiB,qBAAqB;AAExE,OAAI,UAAU,cACb,OAAM,SAAS,KAAK,aAAa,iBAAiB,qBAAqB;AAExE,OAAI,UAAU,mBACb,OAAM,SAAS,KACd,aACA,iBAAiB,2BACjB;AAEF,OAAI,UAAU,qBACb,OAAM,SAAS,KACd,aACA,iBAAiB,8BACjB;AAEF,SAAM,SAAS,WAAW,aAAa,EACtC,SAAS,WAAW,SACpB,CAAC;;;AAIJ,gBAAe,YAAY,aAAa,cAAc;AACtD,gBAAe,YAAY,aAAa,cAAc;AACtD,qBAAoB,YAAY,kBAAkB,mBAAmB;AACrE,uBAAsB,YAAY,oBAAoB,qBAAqB;EAC1E;AAEF,MAAa,eACZ,aAEA,qBAAqB,OAAO,QAAQ;AACnC,KAAI,CAAC,IAAI,QACR;CAED,MAAM,cAAc,SAAS,IAAI;CACjC,MAAM,eAAe,KAAyB,UAAkB;AAC/D,MAAI,CAAC,IACJ;AAMD,MAAI,CAJoB,IAAI,QAAQ,gBAAgB,KAAK,EACxD,oBAAoB,UAAU,UAC9B,CAAC,EAEoB;AACrB,OAAI,QAAQ,OAAO,MAAM,WAAW,MAAM,IAAI,MAAM;AACpD,OAAI,QAAQ,OAAO,KAClB,mCAAmC,IAAI,2CACvC,mCAAmC,IAAI,QAAQ,iBAC/C;AACD,OAAI,UAAU,SACb,OAAM,SAAS,KAAK,aAAa,iBAAiB,eAAe;AAElE,OAAI,UAAU,cACb,OAAM,SAAS,KACd,aACA,iBAAiB,qBACjB;AAEF,OAAI,UAAU,cACb,OAAM,SAAS,KACd,aACA,iBAAiB,qBACjB;AAEF,OAAI,UAAU,mBACb,OAAM,SAAS,KACd,aACA,iBAAiB,2BACjB;AAEF,OAAI,UAAU,qBACb,OAAM,SAAS,KACd,aACA,iBAAiB,8BACjB;AAEF,SAAM,SAAS,WAAW,aAAa,EACtC,SAAS,WAAW,SACpB,CAAC;;;CAGJ,MAAM,YAAY,MAAM,QAAQ,YAAY,GAAG,cAAc,CAAC,YAAY;AAC1E,MAAK,MAAM,OAAO,UACjB,aAAY,KAAK,cAAc;EAE/B;;;;;;AAOH,eAAe,eACd,KACA,gBAAgB,OACA;CAChB,MAAM,UAAU,IAAI,SAAS;AAC7B,KAAI,CAAC,WAAW,CAAC,IAAI,QACpB;CAED,MAAM,eAAe,QAAQ,IAAI,SAAS,IAAI,QAAQ,IAAI,UAAU,IAAI;CACxE,MAAM,aAAa,QAAQ,IAAI,SAAS;AAMxC,KAAI,EAHH,iBACC,cAAc,CAAC,IAAI,QAAQ,iBAAiB,CAAC,IAAI,QAAQ,iBAG1D;AAGD,KAAI,CAAC,gBAAgB,iBAAiB,OACrC,OAAM,IAAI,SAAS,aAAa,EAAE,SAAS,0BAA0B,CAAC;CAGvE,MAAMA,iBAA2B,MAAM,QACtC,IAAI,QAAQ,QAAQ,eACpB,GACE,IAAI,QAAQ,iBACZ,CACA,GAAG,IAAI,QAAQ,gBACf,GAAK,MAAM,IAAI,QAAQ,QAAQ,iBAAiB,IAAI,QAAQ,IAAK,EAAE,CACnE;AAKH,KAAI,CAHoB,eAAe,MAAM,WAC5C,qBAAqB,cAAc,OAAO,CAC1C,EACqB;AACrB,MAAI,QAAQ,OAAO,MAAM,mBAAmB,eAAe;AAC3D,MAAI,QAAQ,OAAO,KAClB,mCAAmC,aAAa,2CAChD,mCAAmC,iBACnC;AACD,QAAM,IAAI,SAAS,aAAa,EAAE,SAAS,kBAAkB,CAAC;;;;;;;AAQhE,MAAa,qBAAqB,qBAAqB,OAAO,QAAQ;AAErE,KAAI,CADY,IAAI,QAEnB;AAGD,OAAM,iBAAiB,IAAI;EAC1B;;;;;AAMF,eAAe,iBAAiB,KAA4C;CAC3E,MAAM,MAAM,IAAI;AAChB,KAAI,CAAC,IACJ;CAGD,MAAM,UAAU,IAAI;AAGpB,KAFsB,QAAQ,IAAI,SAAS,CAG1C,QAAO,MAAM,eAAe,IAAI;CAGjC,MAAM,OAAO,QAAQ,IAAI,iBAAiB;CAC1C,MAAM,OAAO,QAAQ,IAAI,iBAAiB;CAC1C,MAAM,OAAO,QAAQ,IAAI,iBAAiB;AAM1C,KAJoB,QAClB,QAAQ,KAAK,MAAM,IAAM,QAAQ,KAAK,MAAM,IAAM,QAAQ,KAAK,MAAM,CACtE,EAEgB;AAEhB,MAAI,SAAS,gBAAgB,SAAS,YAAY;AACjD,OAAI,QAAQ,OAAO,MAClB,iEACA;IACC,cAAc;IACd,cAAc;IACd,cAAc;IACd,CACD;AACD,SAAM,SAAS,KACd,aACA,iBAAiB,oCACjB;;AAGF,SAAO,MAAM,eAAe,KAAK,KAAK"}
@@ -1,11 +1,11 @@
1
1
  import * as _better_auth_core_oauth28 from "@better-auth/core/oauth2";
2
2
  import * as z from "zod";
3
- import * as better_call950 from "better-call";
3
+ import * as better_call727 from "better-call";
4
4
 
5
5
  //#region src/api/routes/account.d.ts
6
- declare const listUserAccounts: better_call950.StrictEndpoint<"/list-accounts", {
6
+ declare const listUserAccounts: better_call727.StrictEndpoint<"/list-accounts", {
7
7
  method: "GET";
8
- use: ((inputContext: better_call950.MiddlewareInputContext<better_call950.MiddlewareOptions>) => Promise<{
8
+ use: ((inputContext: better_call727.MiddlewareInputContext<better_call727.MiddlewareOptions>) => Promise<{
9
9
  session: {
10
10
  session: Record<string, any> & {
11
11
  id: string;
@@ -87,7 +87,7 @@ declare const listUserAccounts: better_call950.StrictEndpoint<"/list-accounts",
87
87
  userId: string;
88
88
  scopes: string[];
89
89
  }[]>;
90
- declare const linkSocialAccount: better_call950.StrictEndpoint<"/link-social", {
90
+ declare const linkSocialAccount: better_call727.StrictEndpoint<"/link-social", {
91
91
  method: "POST";
92
92
  requireHeaders: true;
93
93
  body: z.ZodObject<{
@@ -106,7 +106,7 @@ declare const linkSocialAccount: better_call950.StrictEndpoint<"/link-social", {
106
106
  disableRedirect: z.ZodOptional<z.ZodBoolean>;
107
107
  additionalData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
108
108
  }, z.core.$strip>;
109
- use: ((inputContext: better_call950.MiddlewareInputContext<better_call950.MiddlewareOptions>) => Promise<{
109
+ use: ((inputContext: better_call727.MiddlewareInputContext<better_call727.MiddlewareOptions>) => Promise<{
110
110
  session: {
111
111
  session: Record<string, any> & {
112
112
  id: string;
@@ -165,13 +165,13 @@ declare const linkSocialAccount: better_call950.StrictEndpoint<"/link-social", {
165
165
  url: string;
166
166
  redirect: boolean;
167
167
  }>;
168
- declare const unlinkAccount: better_call950.StrictEndpoint<"/unlink-account", {
168
+ declare const unlinkAccount: better_call727.StrictEndpoint<"/unlink-account", {
169
169
  method: "POST";
170
170
  body: z.ZodObject<{
171
171
  providerId: z.ZodString;
172
172
  accountId: z.ZodOptional<z.ZodString>;
173
173
  }, z.core.$strip>;
174
- use: ((inputContext: better_call950.MiddlewareInputContext<better_call950.MiddlewareOptions>) => Promise<{
174
+ use: ((inputContext: better_call727.MiddlewareInputContext<better_call727.MiddlewareOptions>) => Promise<{
175
175
  session: {
176
176
  session: Record<string, any> & {
177
177
  id: string;
@@ -219,7 +219,7 @@ declare const unlinkAccount: better_call950.StrictEndpoint<"/unlink-account", {
219
219
  }, {
220
220
  status: boolean;
221
221
  }>;
222
- declare const getAccessToken: better_call950.StrictEndpoint<"/get-access-token", {
222
+ declare const getAccessToken: better_call727.StrictEndpoint<"/get-access-token", {
223
223
  method: "POST";
224
224
  body: z.ZodObject<{
225
225
  providerId: z.ZodString;
@@ -274,7 +274,7 @@ declare const getAccessToken: better_call950.StrictEndpoint<"/get-access-token",
274
274
  scopes: string[];
275
275
  idToken: string | undefined;
276
276
  }>;
277
- declare const refreshToken: better_call950.StrictEndpoint<"/refresh-token", {
277
+ declare const refreshToken: better_call727.StrictEndpoint<"/refresh-token", {
278
278
  method: "POST";
279
279
  body: z.ZodObject<{
280
280
  providerId: z.ZodString;
@@ -333,9 +333,9 @@ declare const refreshToken: better_call950.StrictEndpoint<"/refresh-token", {
333
333
  providerId: string;
334
334
  accountId: string;
335
335
  }>;
336
- declare const accountInfo: better_call950.StrictEndpoint<"/account-info", {
336
+ declare const accountInfo: better_call727.StrictEndpoint<"/account-info", {
337
337
  method: "GET";
338
- use: ((inputContext: better_call950.MiddlewareInputContext<better_call950.MiddlewareOptions>) => Promise<{
338
+ use: ((inputContext: better_call727.MiddlewareInputContext<better_call727.MiddlewareOptions>) => Promise<{
339
339
  session: {
340
340
  session: Record<string, any> & {
341
341
  id: string;
@@ -2,9 +2,8 @@ import { getAccountCookie, setAccountCookie } from "../../cookies/session-store.
2
2
  import { generateState } from "../../oauth2/state.mjs";
3
3
  import { decryptOAuthToken, setTokenUtil } from "../../oauth2/utils.mjs";
4
4
  import { freshSessionMiddleware, getSessionFromCtx, sessionMiddleware } from "./session.mjs";
5
- import { BASE_ERROR_CODES } from "@better-auth/core/error";
5
+ import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
6
6
  import * as z from "zod";
7
- import { APIError } from "better-call";
8
7
  import { SocialProviderListEnum } from "@better-auth/core/social-providers";
9
8
  import { createAuthEndpoint } from "@better-auth/core/api";
10
9
 
@@ -112,17 +111,17 @@ const linkSocialAccount = createAuthEndpoint("/link-social", {
112
111
  const provider = c.context.socialProviders.find((p) => p.id === c.body.provider);
113
112
  if (!provider) {
114
113
  c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider });
115
- throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND });
114
+ throw APIError.from("NOT_FOUND", BASE_ERROR_CODES.PROVIDER_NOT_FOUND);
116
115
  }
117
116
  if (c.body.idToken) {
118
117
  if (!provider.verifyIdToken) {
119
118
  c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider });
120
- throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED });
119
+ throw APIError.from("NOT_FOUND", BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED);
121
120
  }
122
121
  const { token, nonce } = c.body.idToken;
123
122
  if (!await provider.verifyIdToken(token, nonce)) {
124
123
  c.context.logger.error("Invalid id token", { provider: c.body.provider });
125
- throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN });
124
+ throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.INVALID_TOKEN);
126
125
  }
127
126
  const linkingUserInfo = await provider.getUserInfo({
128
127
  idToken: token,
@@ -131,20 +130,26 @@ const linkSocialAccount = createAuthEndpoint("/link-social", {
131
130
  });
132
131
  if (!linkingUserInfo || !linkingUserInfo?.user) {
133
132
  c.context.logger.error("Failed to get user info", { provider: c.body.provider });
134
- throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO });
133
+ throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO);
135
134
  }
136
135
  const linkingUserId = String(linkingUserInfo.user.id);
137
136
  if (!linkingUserInfo.user.email) {
138
137
  c.context.logger.error("User email not found", { provider: c.body.provider });
139
- throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND });
138
+ throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND);
140
139
  }
141
140
  if ((await c.context.internalAdapter.findAccounts(session.user.id)).find((a) => a.providerId === provider.id && a.accountId === linkingUserId)) return c.json({
142
141
  url: "",
143
142
  status: true,
144
143
  redirect: false
145
144
  });
146
- if (!(c.context.options.account?.accountLinking?.trustedProviders)?.includes(provider.id) && !linkingUserInfo.user.emailVerified || c.context.options.account?.accountLinking?.enabled === false) throw new APIError("UNAUTHORIZED", { message: "Account not linked - linking not allowed" });
147
- if (linkingUserInfo.user.email !== session.user.email && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) throw new APIError("UNAUTHORIZED", { message: "Account not linked - different emails not allowed" });
145
+ if (!(c.context.options.account?.accountLinking?.trustedProviders)?.includes(provider.id) && !linkingUserInfo.user.emailVerified || c.context.options.account?.accountLinking?.enabled === false) throw APIError.from("UNAUTHORIZED", {
146
+ message: "Account not linked - linking not allowed",
147
+ code: "LINKING_NOT_ALLOWED"
148
+ });
149
+ if (linkingUserInfo.user.email !== session.user.email && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) throw APIError.from("UNAUTHORIZED", {
150
+ message: "Account not linked - different emails not allowed",
151
+ code: "LINKING_DIFFERENT_EMAILS_NOT_ALLOWED"
152
+ });
148
153
  try {
149
154
  await c.context.internalAdapter.createAccount({
150
155
  userId: session.user.id,
@@ -155,8 +160,11 @@ const linkSocialAccount = createAuthEndpoint("/link-social", {
155
160
  refreshToken: c.body.idToken.refreshToken,
156
161
  scope: c.body.idToken.scopes?.join(",")
157
162
  });
158
- } catch {
159
- throw new APIError("EXPECTATION_FAILED", { message: "Account not linked - unable to create account" });
163
+ } catch (_e) {
164
+ throw APIError.from("EXPECTATION_FAILED", {
165
+ message: "Account not linked - unable to create account",
166
+ code: "LINKING_FAILED"
167
+ });
160
168
  }
161
169
  if (c.context.options.account?.accountLinking?.updateUserInfoOnLink === true) try {
162
170
  await c.context.internalAdapter.updateUser(session.user.id, {
@@ -207,9 +215,9 @@ const unlinkAccount = createAuthEndpoint("/unlink-account", {
207
215
  }, async (ctx) => {
208
216
  const { providerId, accountId } = ctx.body;
209
217
  const accounts = await ctx.context.internalAdapter.findAccounts(ctx.context.session.user.id);
210
- if (accounts.length === 1 && !ctx.context.options.account?.accountLinking?.allowUnlinkingAll) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT });
218
+ if (accounts.length === 1 && !ctx.context.options.account?.accountLinking?.allowUnlinkingAll) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT);
211
219
  const accountExist = accounts.find((account) => accountId ? account.accountId === accountId && account.providerId === providerId : account.providerId === providerId);
212
- if (!accountExist) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.ACCOUNT_NOT_FOUND });
220
+ if (!accountExist) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);
213
221
  await ctx.context.internalAdapter.deleteAccount(accountExist.id);
214
222
  return ctx.json({ status: true });
215
223
  });
@@ -253,14 +261,17 @@ const getAccessToken = createAuthEndpoint("/get-access-token", {
253
261
  if (req && !session) throw ctx.error("UNAUTHORIZED");
254
262
  let resolvedUserId = session?.user?.id || userId;
255
263
  if (!resolvedUserId) throw ctx.error("UNAUTHORIZED");
256
- if (!ctx.context.socialProviders.find((p) => p.id === providerId)) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} is not supported.` });
264
+ if (!ctx.context.socialProviders.find((p) => p.id === providerId)) throw APIError.from("BAD_REQUEST", {
265
+ message: `Provider ${providerId} is not supported.`,
266
+ code: "PROVIDER_NOT_SUPPORTED"
267
+ });
257
268
  const accountData = await getAccountCookie(ctx);
258
269
  let account = void 0;
259
270
  if (accountData && providerId === accountData.providerId && (!accountId || accountData.id === accountId)) account = accountData;
260
271
  else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId);
261
- if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" });
272
+ if (!account) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);
262
273
  const provider = ctx.context.socialProviders.find((p) => p.id === providerId);
263
- if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` });
274
+ if (!provider) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.PROVIDER_NOT_FOUND);
264
275
  try {
265
276
  let newTokens = null;
266
277
  const accessTokenExpired = account.accessTokenExpiresAt && new Date(account.accessTokenExpiresAt).getTime() - Date.now() < 5e3;
@@ -287,10 +298,10 @@ const getAccessToken = createAuthEndpoint("/get-access-token", {
287
298
  idToken: newTokens?.idToken ?? account.idToken ?? void 0
288
299
  };
289
300
  return ctx.json(tokens);
290
- } catch (error) {
291
- throw new APIError("BAD_REQUEST", {
301
+ } catch (_error) {
302
+ throw APIError.from("BAD_REQUEST", {
292
303
  message: "Failed to get a valid access token",
293
- cause: error
304
+ code: "FAILED_TO_GET_ACCESS_TOKEN"
294
305
  });
295
306
  }
296
307
  });
@@ -333,19 +344,31 @@ const refreshToken = createAuthEndpoint("/refresh-token", {
333
344
  const session = await getSessionFromCtx(ctx);
334
345
  if (req && !session) throw ctx.error("UNAUTHORIZED");
335
346
  let resolvedUserId = session?.user?.id || userId;
336
- if (!resolvedUserId) throw new APIError("BAD_REQUEST", { message: `Either userId or session is required` });
347
+ if (!resolvedUserId) throw APIError.from("BAD_REQUEST", {
348
+ message: `Either userId or session is required`,
349
+ code: "USER_ID_OR_SESSION_REQUIRED"
350
+ });
337
351
  const provider = ctx.context.socialProviders.find((p) => p.id === providerId);
338
- if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` });
339
- if (!provider.refreshAccessToken) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} does not support token refreshing.` });
352
+ if (!provider) throw APIError.from("BAD_REQUEST", {
353
+ message: `Provider ${providerId} not found.`,
354
+ code: "PROVIDER_NOT_FOUND"
355
+ });
356
+ if (!provider.refreshAccessToken) throw APIError.from("BAD_REQUEST", {
357
+ message: `Provider ${providerId} does not support token refreshing.`,
358
+ code: "TOKEN_REFRESH_NOT_SUPPORTED"
359
+ });
340
360
  let account = void 0;
341
361
  const accountData = await getAccountCookie(ctx);
342
362
  if (accountData && (!providerId || providerId === accountData?.providerId)) account = accountData;
343
363
  else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId);
344
- if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" });
364
+ if (!account) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);
345
365
  let refreshToken$1 = void 0;
346
366
  if (accountData && providerId === accountData.providerId) refreshToken$1 = accountData.refreshToken ?? void 0;
347
367
  else refreshToken$1 = account.refreshToken ?? void 0;
348
- if (!refreshToken$1) throw new APIError("BAD_REQUEST", { message: "Refresh token not found" });
368
+ if (!refreshToken$1) throw APIError.from("BAD_REQUEST", {
369
+ message: "Refresh token not found",
370
+ code: "REFRESH_TOKEN_NOT_FOUND"
371
+ });
349
372
  try {
350
373
  const decryptedRefreshToken = await decryptOAuthToken(refreshToken$1, ctx.context);
351
374
  const tokens = await provider.refreshAccessToken(decryptedRefreshToken);
@@ -380,10 +403,10 @@ const refreshToken = createAuthEndpoint("/refresh-token", {
380
403
  providerId: account.providerId,
381
404
  accountId: account.accountId
382
405
  });
383
- } catch (error) {
384
- throw new APIError("BAD_REQUEST", {
406
+ } catch (_error) {
407
+ throw APIError.from("BAD_REQUEST", {
385
408
  message: "Failed to refresh access token",
386
- cause: error
409
+ code: "FAILED_TO_REFRESH_ACCESS_TOKEN"
387
410
  });
388
411
  }
389
412
  });
@@ -433,9 +456,12 @@ const accountInfo = createAuthEndpoint("/account-info", {
433
456
  const accountData = await ctx.context.internalAdapter.findAccount(providedAccountId);
434
457
  if (accountData) account = accountData;
435
458
  }
436
- if (!account || account.userId !== ctx.context.session.user.id) throw new APIError("BAD_REQUEST", { message: "Account not found" });
459
+ if (!account || account.userId !== ctx.context.session.user.id) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);
437
460
  const provider = ctx.context.socialProviders.find((p) => p.id === account.providerId);
438
- if (!provider) throw new APIError("INTERNAL_SERVER_ERROR", { message: `Provider account provider is ${account.providerId} but it is not configured` });
461
+ if (!provider) throw APIError.from("INTERNAL_SERVER_ERROR", {
462
+ message: `Provider account provider is ${account.providerId} but it is not configured`,
463
+ code: "PROVIDER_NOT_CONFIGURED"
464
+ });
439
465
  const tokens = await getAccessToken({
440
466
  ...ctx,
441
467
  method: "POST",
@@ -446,7 +472,10 @@ const accountInfo = createAuthEndpoint("/account-info", {
446
472
  returnHeaders: false,
447
473
  returnStatus: false
448
474
  });
449
- if (!tokens.accessToken) throw new APIError("BAD_REQUEST", { message: "Access token not found" });
475
+ if (!tokens.accessToken) throw APIError.from("BAD_REQUEST", {
476
+ message: "Access token not found",
477
+ code: "ACCESS_TOKEN_NOT_FOUND"
478
+ });
450
479
  const info = await provider.getUserInfo({
451
480
  ...tokens,
452
481
  accessToken: tokens.accessToken