better-auth 1.7.0-beta.2 → 1.7.0-beta.4

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 (282) hide show
  1. package/README.md +14 -15
  2. package/dist/_virtual/_rolldown/runtime.mjs +10 -1
  3. package/dist/api/index.d.mts +18 -48
  4. package/dist/api/routes/account.d.mts +4 -23
  5. package/dist/api/routes/account.mjs +102 -75
  6. package/dist/api/routes/callback.mjs +42 -20
  7. package/dist/api/routes/email-verification.d.mts +1 -0
  8. package/dist/api/routes/email-verification.mjs +6 -5
  9. package/dist/api/routes/error.mjs +1 -1
  10. package/dist/api/routes/password.mjs +1 -1
  11. package/dist/api/routes/session.mjs +15 -10
  12. package/dist/api/routes/sign-in.d.mts +3 -1
  13. package/dist/api/routes/sign-in.mjs +13 -15
  14. package/dist/api/routes/sign-up.d.mts +1 -0
  15. package/dist/api/routes/sign-up.mjs +10 -8
  16. package/dist/api/routes/update-user.mjs +8 -8
  17. package/dist/api/to-auth-endpoints.mjs +7 -1
  18. package/dist/auth/base.mjs +30 -27
  19. package/dist/client/config.mjs +8 -1
  20. package/dist/client/fetch-plugins.mjs +2 -1
  21. package/dist/client/index.d.mts +2 -2
  22. package/dist/client/lynx/index.d.mts +13 -0
  23. package/dist/client/lynx/index.mjs +2 -1
  24. package/dist/client/parser.mjs +0 -1
  25. package/dist/client/plugins/index.d.mts +4 -17
  26. package/dist/client/plugins/index.mjs +1 -4
  27. package/dist/client/proxy.mjs +2 -1
  28. package/dist/client/react/index.d.mts +13 -0
  29. package/dist/client/react/index.mjs +2 -1
  30. package/dist/client/session-atom.mjs +12 -1
  31. package/dist/client/solid/index.d.mts +13 -0
  32. package/dist/client/solid/index.mjs +3 -2
  33. package/dist/client/svelte/index.d.mts +13 -0
  34. package/dist/client/svelte/index.mjs +2 -1
  35. package/dist/client/vanilla.d.mts +13 -0
  36. package/dist/client/vanilla.mjs +2 -1
  37. package/dist/client/vue/index.d.mts +13 -0
  38. package/dist/client/vue/index.mjs +2 -1
  39. package/dist/context/create-context.mjs +10 -14
  40. package/dist/context/helpers.mjs +3 -2
  41. package/dist/cookies/cookie-utils.d.mts +33 -1
  42. package/dist/cookies/cookie-utils.mjs +95 -14
  43. package/dist/cookies/index.d.mts +2 -3
  44. package/dist/cookies/index.mjs +39 -11
  45. package/dist/cookies/session-store.mjs +4 -23
  46. package/dist/db/get-migration.mjs +4 -4
  47. package/dist/db/index.d.mts +2 -2
  48. package/dist/db/index.mjs +3 -2
  49. package/dist/db/internal-adapter.mjs +129 -27
  50. package/dist/db/schema.d.mts +14 -1
  51. package/dist/db/schema.mjs +26 -1
  52. package/dist/db/with-hooks.d.mts +1 -0
  53. package/dist/db/with-hooks.mjs +58 -1
  54. package/dist/index.d.mts +2 -2
  55. package/dist/index.mjs +2 -2
  56. package/dist/integrations/cookie-plugin-guard.mjs +18 -0
  57. package/dist/integrations/next-js.mjs +6 -0
  58. package/dist/integrations/svelte-kit.mjs +6 -0
  59. package/dist/integrations/tanstack-start-solid.mjs +6 -0
  60. package/dist/integrations/tanstack-start.mjs +6 -0
  61. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/index.mjs +32 -0
  62. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/lib/linux.mjs +55 -0
  63. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/lib/macos.mjs +26 -0
  64. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/lib/termux.mjs +39 -0
  65. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/lib/windows.mjs +19 -0
  66. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/chunks/prompt.mjs +845 -0
  67. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/core.mjs +386 -0
  68. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/index.mjs +320 -0
  69. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/shared/consola.DRwqZj3T.mjs +62 -0
  70. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/shared/consola.DXBYu-KD.mjs +190 -0
  71. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/utils.mjs +2 -0
  72. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.mjs +29 -0
  73. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.mjs +42 -0
  74. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.mjs +67 -0
  75. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.mjs +23 -0
  76. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.mjs +22 -0
  77. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.mjs +36 -0
  78. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/adapters/node.d.mts +292 -0
  79. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/adapters/node.mjs +127 -0
  80. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/index.d.mts +145 -0
  81. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.BQXMA5bH.d.mts +298 -0
  82. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.By9qWDAI.mjs +9 -0
  83. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.CipVM6lf.mjs +3549 -0
  84. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.D9ehKjSh.mjs +66 -0
  85. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.DfCzGthR.mjs +227 -0
  86. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/index.mjs +224 -0
  87. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/command.mjs +52 -0
  88. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/error.mjs +54 -0
  89. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/kill.mjs +62 -0
  90. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/pipe.mjs +26 -0
  91. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/promise.mjs +32 -0
  92. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/stdio.mjs +19 -0
  93. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/stream.mjs +98 -0
  94. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/verbose.mjs +15 -0
  95. package/dist/node_modules/.pnpm/get-port-please@3.2.0/node_modules/get-port-please/dist/index.d.mts +15 -0
  96. package/dist/node_modules/.pnpm/get-port-please@3.2.0/node_modules/get-port-please/dist/index.mjs +220 -0
  97. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/array-buffer.mjs +54 -0
  98. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/array.mjs +2 -0
  99. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/buffer.mjs +14 -0
  100. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/contents.mjs +76 -0
  101. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/index.mjs +6 -0
  102. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/string.mjs +35 -0
  103. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/utils.mjs +10 -0
  104. package/dist/node_modules/.pnpm/http-shutdown@1.2.2/node_modules/http-shutdown/index.mjs +76 -0
  105. package/dist/node_modules/.pnpm/human-signals@5.0.0/node_modules/human-signals/build/src/core.mjs +274 -0
  106. package/dist/node_modules/.pnpm/human-signals@5.0.0/node_modules/human-signals/build/src/main.mjs +44 -0
  107. package/dist/node_modules/.pnpm/human-signals@5.0.0/node_modules/human-signals/build/src/realtime.mjs +15 -0
  108. package/dist/node_modules/.pnpm/human-signals@5.0.0/node_modules/human-signals/build/src/signals.mjs +23 -0
  109. package/dist/node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.mjs +24 -0
  110. package/dist/node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.mjs +18 -0
  111. package/dist/node_modules/.pnpm/is-stream@3.0.0/node_modules/is-stream/index.mjs +9 -0
  112. package/dist/node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.mjs +20 -0
  113. package/dist/node_modules/.pnpm/is64bit@2.0.0/node_modules/is64bit/index.mjs +13 -0
  114. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.mjs +47 -0
  115. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.mjs +33 -0
  116. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.mjs +33 -0
  117. package/dist/node_modules/.pnpm/listhen@1.9.0/node_modules/listhen/dist/chunks/xdg-open.mjs +1070 -0
  118. package/dist/node_modules/.pnpm/listhen@1.9.0/node_modules/listhen/dist/index.mjs +619 -0
  119. package/dist/node_modules/.pnpm/listhen@1.9.0/node_modules/listhen/dist/shared/listhen.1c46e31d.d.mts +83 -0
  120. package/dist/node_modules/.pnpm/merge-stream@2.0.0/node_modules/merge-stream/index.mjs +38 -0
  121. package/dist/node_modules/.pnpm/mimic-fn@4.0.0/node_modules/mimic-fn/index.mjs +38 -0
  122. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/aes.mjs +597 -0
  123. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/aesCipherSuites.mjs +195 -0
  124. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/asn1-validator.mjs +76 -0
  125. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/asn1.mjs +967 -0
  126. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/baseN.mjs +137 -0
  127. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/cipher.mjs +186 -0
  128. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/cipherModes.mjs +597 -0
  129. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/des.mjs +1187 -0
  130. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/ed25519.mjs +1029 -0
  131. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/forge.mjs +15 -0
  132. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/hmac.mjs +107 -0
  133. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/index.mjs +66 -0
  134. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/jsbn.mjs +1334 -0
  135. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/kem.mjs +146 -0
  136. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/log.mjs +241 -0
  137. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/md.all.mjs +24 -0
  138. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/md.mjs +18 -0
  139. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/md5.mjs +324 -0
  140. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/mgf.mjs +20 -0
  141. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/mgf1.mjs +44 -0
  142. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/oids.mjs +154 -0
  143. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pbe.mjs +815 -0
  144. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pbkdf2.mjs +125 -0
  145. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pem.mjs +175 -0
  146. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pkcs1.mjs +200 -0
  147. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pkcs12.mjs +724 -0
  148. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pkcs7.mjs +642 -0
  149. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pkcs7asn1.mjs +405 -0
  150. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pki.mjs +101 -0
  151. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/prime.mjs +193 -0
  152. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/prng.mjs +290 -0
  153. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pss.mjs +141 -0
  154. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/random.mjs +141 -0
  155. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/rc2.mjs +538 -0
  156. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/rsa.mjs +1309 -0
  157. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/sha1.mjs +230 -0
  158. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/sha256.mjs +267 -0
  159. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/sha512.mjs +413 -0
  160. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/ssh.mjs +194 -0
  161. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/tls.mjs +3655 -0
  162. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/util.mjs +2117 -0
  163. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/x509.mjs +2168 -0
  164. package/dist/node_modules/.pnpm/npm-run-path@5.3.0/node_modules/npm-run-path/index.mjs +34 -0
  165. package/dist/node_modules/.pnpm/onetime@6.0.0/node_modules/onetime/index.mjs +26 -0
  166. package/dist/node_modules/.pnpm/path-key@3.1.1/node_modules/path-key/index.mjs +14 -0
  167. package/dist/node_modules/.pnpm/path-key@4.0.0/node_modules/path-key/index.mjs +8 -0
  168. package/dist/node_modules/.pnpm/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.mjs +176 -0
  169. package/dist/node_modules/.pnpm/shebang-command@2.0.0/node_modules/shebang-command/index.mjs +17 -0
  170. package/dist/node_modules/.pnpm/shebang-regex@3.0.0/node_modules/shebang-regex/index.mjs +8 -0
  171. package/dist/node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.mjs +169 -0
  172. package/dist/node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/signals.mjs +33 -0
  173. package/dist/node_modules/.pnpm/std-env@3.10.0/node_modules/std-env/dist/index.mjs +171 -0
  174. package/dist/node_modules/.pnpm/strip-final-newline@3.0.0/node_modules/strip-final-newline/index.mjs +10 -0
  175. package/dist/node_modules/.pnpm/system-architecture@0.1.0/node_modules/system-architecture/index.mjs +16 -0
  176. package/dist/node_modules/.pnpm/uncrypto@0.1.3/node_modules/uncrypto/dist/crypto.node.mjs +7 -0
  177. package/dist/node_modules/.pnpm/untun@0.1.3/node_modules/untun/dist/chunks/index.mjs +154 -0
  178. package/dist/node_modules/.pnpm/untun@0.1.3/node_modules/untun/dist/index.mjs +34 -0
  179. package/dist/node_modules/.pnpm/uqr@0.1.2/node_modules/uqr/dist/index.mjs +896 -0
  180. package/dist/node_modules/.pnpm/which@2.0.2/node_modules/which/which.mjs +76 -0
  181. package/dist/oauth2/errors.mjs +27 -0
  182. package/dist/oauth2/index.d.mts +2 -2
  183. package/dist/oauth2/index.mjs +3 -3
  184. package/dist/oauth2/link-account.d.mts +27 -1
  185. package/dist/oauth2/link-account.mjs +30 -5
  186. package/dist/oauth2/state.mjs +8 -2
  187. package/dist/{package.mjs → packages/better-auth/package.mjs} +1 -1
  188. package/dist/plugins/access/access.d.mts +3 -15
  189. package/dist/plugins/access/access.mjs +11 -6
  190. package/dist/plugins/access/index.d.mts +2 -2
  191. package/dist/plugins/access/types.d.mts +11 -4
  192. package/dist/plugins/admin/access/statement.d.mts +29 -93
  193. package/dist/plugins/admin/admin.mjs +0 -4
  194. package/dist/plugins/admin/client.d.mts +6 -1
  195. package/dist/plugins/admin/client.mjs +5 -0
  196. package/dist/plugins/admin/routes.mjs +3 -2
  197. package/dist/plugins/anonymous/client.d.mts +1 -0
  198. package/dist/plugins/anonymous/error-codes.d.mts +1 -0
  199. package/dist/plugins/anonymous/error-codes.mjs +1 -0
  200. package/dist/plugins/anonymous/index.d.mts +1 -0
  201. package/dist/plugins/anonymous/index.mjs +16 -2
  202. package/dist/plugins/bearer/index.mjs +5 -12
  203. package/dist/plugins/captcha/index.mjs +14 -1
  204. package/dist/plugins/device-authorization/error-codes.mjs +1 -0
  205. package/dist/plugins/device-authorization/index.d.mts +1 -0
  206. package/dist/plugins/device-authorization/routes.mjs +34 -3
  207. package/dist/plugins/email-otp/routes.mjs +4 -4
  208. package/dist/plugins/generic-oauth/error-codes.mjs +0 -1
  209. package/dist/plugins/generic-oauth/index.d.mts +2 -4
  210. package/dist/plugins/generic-oauth/index.mjs +23 -17
  211. package/dist/plugins/generic-oauth/providers/auth0.mjs +1 -0
  212. package/dist/plugins/generic-oauth/providers/gumroad.mjs +1 -0
  213. package/dist/plugins/generic-oauth/providers/hubspot.mjs +1 -0
  214. package/dist/plugins/generic-oauth/providers/keycloak.mjs +1 -0
  215. package/dist/plugins/generic-oauth/providers/line.mjs +1 -0
  216. package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs +1 -0
  217. package/dist/plugins/generic-oauth/providers/okta.mjs +1 -0
  218. package/dist/plugins/generic-oauth/providers/patreon.mjs +1 -0
  219. package/dist/plugins/generic-oauth/providers/slack.mjs +1 -0
  220. package/dist/plugins/generic-oauth/types.d.mts +30 -8
  221. package/dist/plugins/index.d.mts +2 -2
  222. package/dist/plugins/jwt/utils.d.mts +1 -1
  223. package/dist/plugins/last-login-method/client.mjs +2 -2
  224. package/dist/plugins/magic-link/index.d.mts +8 -1
  225. package/dist/plugins/magic-link/index.mjs +4 -17
  226. package/dist/plugins/mcp/authorize.mjs +8 -2
  227. package/dist/plugins/mcp/index.mjs +75 -35
  228. package/dist/plugins/multi-session/index.mjs +2 -2
  229. package/dist/plugins/oauth-proxy/index.mjs +45 -32
  230. package/dist/plugins/oauth-proxy/utils.mjs +3 -10
  231. package/dist/plugins/oidc-provider/authorize.mjs +8 -2
  232. package/dist/plugins/oidc-provider/index.mjs +65 -38
  233. package/dist/plugins/one-tap/client.mjs +9 -2
  234. package/dist/plugins/one-tap/index.mjs +19 -36
  235. package/dist/plugins/open-api/generator.mjs +25 -5
  236. package/dist/plugins/organization/access/statement.d.mts +68 -201
  237. package/dist/plugins/organization/adapter.d.mts +1 -1
  238. package/dist/plugins/organization/adapter.mjs +65 -58
  239. package/dist/plugins/organization/client.d.mts +3 -1
  240. package/dist/plugins/organization/client.mjs +1 -1
  241. package/dist/plugins/organization/error-codes.d.mts +2 -0
  242. package/dist/plugins/organization/error-codes.mjs +3 -1
  243. package/dist/plugins/organization/routes/crud-access-control.d.mts +2 -2
  244. package/dist/plugins/organization/routes/crud-invites.d.mts +8 -1
  245. package/dist/plugins/organization/routes/crud-invites.mjs +8 -3
  246. package/dist/plugins/organization/routes/crud-org.d.mts +4 -4
  247. package/dist/plugins/organization/routes/crud-org.mjs +2 -2
  248. package/dist/plugins/organization/routes/crud-team.mjs +7 -2
  249. package/dist/plugins/organization/schema.d.mts +1 -1
  250. package/dist/plugins/organization/types.d.mts +15 -5
  251. package/dist/plugins/phone-number/routes.mjs +1 -1
  252. package/dist/plugins/siwe/client.d.mts +4 -0
  253. package/dist/plugins/siwe/client.mjs +5 -1
  254. package/dist/plugins/siwe/index.d.mts +13 -2
  255. package/dist/plugins/siwe/index.mjs +179 -165
  256. package/dist/plugins/two-factor/backup-codes/index.d.mts +4 -3
  257. package/dist/plugins/two-factor/client.mjs +2 -1
  258. package/dist/plugins/two-factor/index.mjs +3 -2
  259. package/dist/plugins/username/client.d.mts +1 -0
  260. package/dist/plugins/username/error-codes.d.mts +1 -0
  261. package/dist/plugins/username/error-codes.mjs +2 -1
  262. package/dist/plugins/username/index.d.mts +43 -2
  263. package/dist/plugins/username/index.mjs +73 -6
  264. package/dist/state.d.mts +2 -2
  265. package/dist/state.mjs +18 -4
  266. package/dist/test-utils/headers.mjs +2 -7
  267. package/dist/test-utils/http-test-instance.d.mts +397 -0
  268. package/dist/test-utils/http-test-instance.mjs +54 -0
  269. package/dist/test-utils/index.d.mts +2 -1
  270. package/dist/test-utils/index.mjs +2 -1
  271. package/dist/test-utils/test-instance.d.mts +4110 -224
  272. package/dist/test-utils/test-instance.mjs +11 -2
  273. package/dist/types/auth.d.mts +4 -0
  274. package/dist/utils/index.d.mts +1 -1
  275. package/dist/utils/url.d.mts +2 -1
  276. package/dist/utils/url.mjs +9 -3
  277. package/dist/version.mjs +1 -1
  278. package/package.json +14 -14
  279. package/dist/oauth2/error-codes.d.mts +0 -20
  280. package/dist/plugins/generic-oauth/client.d.mts +0 -32
  281. package/dist/plugins/generic-oauth/client.mjs +0 -19
  282. package/dist/plugins/generic-oauth/error-codes.d.mts +0 -10
@@ -1,9 +1,11 @@
1
+ import { isAPIError } from "../../utils/is-api-error.mjs";
1
2
  import { setSessionCookie } from "../../cookies/index.mjs";
2
3
  import { getAwaitableValue } from "../../context/helpers.mjs";
3
- import { parseState } from "../../oauth2/state.mjs";
4
+ import { missingEmailLogMessage } from "../../oauth2/errors.mjs";
4
5
  import { setTokenUtil } from "../../oauth2/utils.mjs";
6
+ import { applyUpdateUserInfoOnLink, handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
7
+ import { generateState, parseState } from "../../oauth2/state.mjs";
5
8
  import { OAUTH_CALLBACK_ERROR_CODES } from "../../oauth2/error-codes.mjs";
6
- import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
7
9
  import { HIDE_METADATA } from "../../utils/hide-metadata.mjs";
8
10
  import { safeJSONParse } from "@better-auth/core/utils/json";
9
11
  import { createAuthEndpoint } from "@better-auth/core/api";
@@ -51,9 +53,21 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
51
53
  throw c.redirect(`${defaultErrorURL}?error=invalid_callback_request`);
52
54
  }
53
55
  const { code, error, state, error_description, device_id, user: userData, iss } = queryOrBody;
56
+ if (state === void 0 && code) {
57
+ const provider = await getAwaitableValue(c.context.socialProviders, { value: c.params.id });
58
+ if (provider?.allowIdpInitiated) {
59
+ const { state: freshState, codeVerifier } = await generateState(c, void 0, void 0);
60
+ const authUrl = await provider.createAuthorizationURL({
61
+ state: freshState,
62
+ codeVerifier,
63
+ redirectURI: `${c.context.baseURL}/callback/${provider.id}`
64
+ });
65
+ throw c.redirect(authUrl.toString());
66
+ }
67
+ }
54
68
  if (!state) {
55
69
  c.context.logger.error("State not found", error);
56
- const url = `${defaultErrorURL}${defaultErrorURL.includes("?") ? "&" : "?"}state=state_not_found`;
70
+ const url = `${defaultErrorURL}${defaultErrorURL.includes("?") ? "&" : "?"}error=state_not_found`;
57
71
  throw c.redirect(url);
58
72
  }
59
73
  const { codeVerifier, callbackURL, link, errorURL, newUserURL, requestSignUp } = await parseState(c);
@@ -99,10 +113,11 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
99
113
  ...tokens,
100
114
  user: parsedUserData ?? void 0
101
115
  }).then((res) => res?.user);
102
- if (!userInfo) {
116
+ if (!userInfo || userInfo.id === void 0 || userInfo.id === null) {
103
117
  c.context.logger.error("Unable to get user info");
104
118
  return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.UNABLE_TO_GET_USER_INFO);
105
119
  }
120
+ const providerAccountId = String(userInfo.id);
106
121
  if (!callbackURL) {
107
122
  c.context.logger.error("No callback URL found");
108
123
  throw redirectOnError(OAUTH_CALLBACK_ERROR_CODES.NO_CALLBACK_URL);
@@ -113,7 +128,7 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
113
128
  return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.UNABLE_TO_LINK_ACCOUNT);
114
129
  }
115
130
  if (userInfo.email?.toLowerCase() !== link.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.EMAIL_DOES_NOT_MATCH);
116
- const existingAccount = await c.context.internalAdapter.findAccountByProviderId(String(userInfo.id), provider.id);
131
+ const existingAccount = await c.context.internalAdapter.findAccountByProviderId(providerAccountId, provider.id);
117
132
  if (existingAccount) {
118
133
  if (existingAccount.userId.toString() !== link.userId.toString()) return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.ACCOUNT_ALREADY_LINKED_TO_DIFFERENT_USER);
119
134
  const updateData = Object.fromEntries(Object.entries({
@@ -128,12 +143,13 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
128
143
  } else if (!await c.context.internalAdapter.createAccount({
129
144
  userId: link.userId,
130
145
  providerId: provider.id,
131
- accountId: String(userInfo.id),
146
+ accountId: providerAccountId,
132
147
  ...tokens,
133
148
  accessToken: await setTokenUtil(tokens.accessToken, c.context),
134
149
  refreshToken: await setTokenUtil(tokens.refreshToken, c.context),
135
150
  scope: tokens.scopes?.join(",")
136
151
  })) return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.UNABLE_TO_LINK_ACCOUNT);
152
+ await applyUpdateUserInfoOnLink(c, link.userId, userInfo);
137
153
  let toRedirectTo;
138
154
  try {
139
155
  toRedirectTo = callbackURL.toString();
@@ -143,27 +159,33 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
143
159
  throw c.redirect(toRedirectTo);
144
160
  }
145
161
  if (!userInfo.email) {
146
- c.context.logger.error("Provider did not return email. This could be due to misconfiguration in the provider settings.");
162
+ c.context.logger.error(missingEmailLogMessage(provider.id));
147
163
  return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.EMAIL_NOT_FOUND);
148
164
  }
149
165
  const accountData = {
150
166
  providerId: provider.id,
151
- accountId: String(userInfo.id),
167
+ accountId: providerAccountId,
152
168
  ...tokens,
153
169
  scope: tokens.scopes?.join(",")
154
170
  };
155
- const result = await handleOAuthUserInfo(c, {
156
- userInfo: {
157
- ...userInfo,
158
- id: String(userInfo.id),
159
- email: userInfo.email,
160
- name: userInfo.name || ""
161
- },
162
- account: accountData,
163
- callbackURL,
164
- disableSignUp: provider.disableImplicitSignUp && !requestSignUp || provider.options?.disableSignUp,
165
- overrideUserInfo: provider.options?.overrideUserInfoOnSignIn
166
- });
171
+ let result;
172
+ try {
173
+ result = await handleOAuthUserInfo(c, {
174
+ userInfo: {
175
+ ...userInfo,
176
+ id: providerAccountId,
177
+ email: userInfo.email,
178
+ name: userInfo.name || ""
179
+ },
180
+ account: accountData,
181
+ callbackURL,
182
+ disableSignUp: provider.disableImplicitSignUp && !requestSignUp || provider.options?.disableSignUp,
183
+ overrideUserInfo: provider.options?.overrideUserInfoOnSignIn
184
+ });
185
+ } catch (e) {
186
+ if (isAPIError(e) && e.body?.code) redirectOnError(e.body.code, e.body.message);
187
+ throw e;
188
+ }
167
189
  if (result.error) {
168
190
  c.context.logger.error(result.error.split(" ").join("_"));
169
191
  return redirectOnError(result.error.split(" ").join("_"));
@@ -27,6 +27,7 @@ declare function sendVerificationEmailFn(ctx: GenericEndpointContext, user: User
27
27
  declare const sendVerificationEmail: better_call0.StrictEndpoint<"/send-verification-email", {
28
28
  method: "POST";
29
29
  operationId: string;
30
+ cloneRequest: true;
30
31
  body: z.ZodObject<{
31
32
  email: z.ZodEmail;
32
33
  callbackURL: z.ZodOptional<z.ZodString>;
@@ -12,7 +12,7 @@ import { JWTExpired } from "jose/errors";
12
12
  async function createEmailVerificationToken(secret, email, updateTo, expiresIn = 3600, extraPayload) {
13
13
  return await signJWT({
14
14
  email: email.toLowerCase(),
15
- updateTo,
15
+ updateTo: updateTo?.toLowerCase(),
16
16
  ...extraPayload
17
17
  }, secret, expiresIn);
18
18
  }
@@ -31,11 +31,12 @@ async function sendVerificationEmailFn(ctx, user) {
31
31
  user,
32
32
  url,
33
33
  token
34
- }, ctx.request));
34
+ }, ctx.request?.clone()));
35
35
  }
36
36
  const sendVerificationEmail = createAuthEndpoint("/send-verification-email", {
37
37
  method: "POST",
38
38
  operationId: "sendVerificationEmail",
39
+ cloneRequest: true,
39
40
  body: z.object({
40
41
  email: z.email().meta({ description: "The email to send the verification email to" }),
41
42
  callbackURL: z.string().meta({ description: "The URL to use for email verification callback" }).optional()
@@ -101,7 +102,7 @@ const sendVerificationEmail = createAuthEndpoint("/send-verification-email", {
101
102
  await sendVerificationEmailFn(ctx, user.user);
102
103
  return ctx.json({ status: true });
103
104
  }
104
- if (session?.user.email !== email) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.EMAIL_MISMATCH);
105
+ if (session?.user.email.toLowerCase() !== email.toLowerCase()) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.EMAIL_MISMATCH);
105
106
  if (session?.user.emailVerified) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.EMAIL_ALREADY_VERIFIED);
106
107
  await sendVerificationEmailFn(ctx, session.user);
107
108
  return ctx.json({ status: true });
@@ -185,7 +186,7 @@ const verifyEmail = createAuthEndpoint("/verify-email", {
185
186
  },
186
187
  url,
187
188
  token: newToken
188
- }, ctx.request));
189
+ }, ctx.request?.clone()));
189
190
  if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL);
190
191
  return ctx.json({ status: true });
191
192
  }
@@ -238,7 +239,7 @@ const verifyEmail = createAuthEndpoint("/verify-email", {
238
239
  user: updatedUser,
239
240
  url: `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`,
240
241
  token: newToken
241
- }, ctx.request));
242
+ }, ctx.request?.clone()));
242
243
  await setSessionCookie(ctx, {
243
244
  session: activeSession.session,
244
245
  user: {
@@ -282,7 +282,7 @@ ${custom?.disableBackgroundGrid ? "" : `
282
282
  text-wrap: pretty;
283
283
  "
284
284
  >
285
- ${!description ? `We encountered an unexpected error. Please try again or return to the home page. If you're a developer, you can find more information about the error <a href='https://better-auth.com/docs/reference/errors/${encodeURIComponent(code)}' target='_blank' rel="noopener noreferrer" style='color: var(--foreground); text-decoration: underline;'>here</a>.` : description}
285
+ ${!description ? `We encountered an unexpected error. Please try again or return to the home page. If you're a developer, you can find <a href='https://better-auth.com/docs/reference/errors/${encodeURIComponent(code)}' target='_blank' rel="noopener noreferrer" style='color: var(--foreground); text-decoration: underline;'>more information about the error</a>.` : description}
286
286
  </p>
287
287
  </div>
288
288
 
@@ -161,7 +161,7 @@ const resetPassword = createAuthEndpoint("/reset-password", {
161
161
  const user = await ctx.context.internalAdapter.findUserById(userId);
162
162
  if (user) await ctx.context.options.emailAndPassword.onPasswordReset({ user }, ctx.request);
163
163
  }
164
- if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteSessions(userId);
164
+ if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteUserSessions(userId);
165
165
  return ctx.json({ status: true });
166
166
  });
167
167
  const verifyPassword = createAuthEndpoint("/verify-password", {
@@ -129,12 +129,8 @@ const getSession = () => createAuthEndpoint("/get-session", {
129
129
  const updateAge = cookieRefreshCache.updateAge * 1e3;
130
130
  const shouldSkipSessionRefresh = await getShouldSkipSessionRefresh();
131
131
  if (timeUntilExpiry < updateAge && !shouldSkipSessionRefresh) {
132
- const newExpiresAt = getDate(ctx.context.options.session?.cookieCache?.maxAge || 300, "sec");
133
132
  const refreshedSession = {
134
- session: {
135
- ...session.session,
136
- expiresAt: newExpiresAt
137
- },
133
+ session: { ...session.session },
138
134
  user: session.user,
139
135
  updatedAt: Date.now()
140
136
  };
@@ -276,17 +272,26 @@ const getSessionFromCtx = async (ctx, config) => {
276
272
  method: "GET",
277
273
  asResponse: false,
278
274
  headers: ctx.headers,
279
- returnHeaders: false,
275
+ returnHeaders: true,
280
276
  returnStatus: false,
281
277
  query: {
282
278
  ...config,
283
279
  ...ctx.query
284
280
  }
285
- }).catch((e) => {
281
+ }).catch(() => {
286
282
  return null;
287
283
  });
288
- ctx.context.session = session;
289
- return session;
284
+ if (!session) {
285
+ ctx.context.session = null;
286
+ return null;
287
+ }
288
+ if (session.headers) session.headers.forEach((value, key) => {
289
+ if (!ctx.context.responseHeaders) ctx.context.responseHeaders = new Headers({ [key]: value });
290
+ else if (key.toLowerCase() === "set-cookie") ctx.context.responseHeaders.append(key, value);
291
+ else ctx.context.responseHeaders.set(key, value);
292
+ });
293
+ ctx.context.session = session.response;
294
+ return session.response;
290
295
  };
291
296
  /**
292
297
  * The middleware forces the endpoint to require a valid session.
@@ -440,7 +445,7 @@ const revokeSessions = createAuthEndpoint("/revoke-sessions", {
440
445
  } }
441
446
  }, async (ctx) => {
442
447
  try {
443
- await ctx.context.internalAdapter.deleteSessions(ctx.context.session.user.id);
448
+ await ctx.context.internalAdapter.deleteUserSessions(ctx.context.session.user.id);
444
449
  } catch (error) {
445
450
  ctx.context.logger.error(error && typeof error === "object" && "name" in error ? error.name : "", error);
446
451
  throw APIError.from("INTERNAL_SERVER_ERROR", {
@@ -27,6 +27,7 @@ declare const socialSignInBodySchema: z.ZodObject<{
27
27
  scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
28
28
  requestSignUp: z.ZodOptional<z.ZodBoolean>;
29
29
  loginHint: z.ZodOptional<z.ZodString>;
30
+ additionalParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
30
31
  additionalData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
31
32
  }, z.core.$strip>;
32
33
  declare const signInSocial: <O extends BetterAuthOptions>() => better_call0.StrictEndpoint<"/sign-in/social", {
@@ -55,6 +56,7 @@ declare const signInSocial: <O extends BetterAuthOptions>() => better_call0.Stri
55
56
  scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
56
57
  requestSignUp: z.ZodOptional<z.ZodBoolean>;
57
58
  loginHint: z.ZodOptional<z.ZodString>;
59
+ additionalParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
58
60
  additionalData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
59
61
  }, z.core.$strip>;
60
62
  metadata: {
@@ -91,7 +93,6 @@ declare const signInSocial: <O extends BetterAuthOptions>() => better_call0.Stri
91
93
  };
92
94
  redirect: {
93
95
  type: string;
94
- enum: boolean[];
95
96
  };
96
97
  };
97
98
  required: string[];
@@ -115,6 +116,7 @@ declare const signInEmail: <O extends BetterAuthOptions>() => better_call0.Stric
115
116
  method: "POST";
116
117
  operationId: string;
117
118
  use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>)[];
119
+ cloneRequest: true;
118
120
  body: z.ZodObject<{
119
121
  email: z.ZodString;
120
122
  password: z.ZodString;
@@ -2,10 +2,12 @@ import { formCsrfMiddleware } from "../middlewares/origin-check.mjs";
2
2
  import { parseUserOutput } from "../../db/schema.mjs";
3
3
  import { setSessionCookie } from "../../cookies/index.mjs";
4
4
  import { getAwaitableValue } from "../../context/helpers.mjs";
5
- import { generateState } from "../../oauth2/state.mjs";
5
+ import { missingEmailLogMessage } from "../../oauth2/errors.mjs";
6
6
  import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
7
+ import { generateState } from "../../oauth2/state.mjs";
7
8
  import { createEmailVerificationToken } from "./email-verification.mjs";
8
9
  import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
10
+ import { additionalAuthorizationParamsSchema } from "@better-auth/core/oauth2";
9
11
  import { SocialProviderListEnum } from "@better-auth/core/social-providers";
10
12
  import { createAuthEndpoint } from "@better-auth/core/api";
11
13
  import * as z from "zod";
@@ -33,6 +35,7 @@ const socialSignInBodySchema = z.object({
33
35
  scopes: z.array(z.string()).meta({ description: "Array of scopes to request from the provider. This will override the default scopes passed." }).optional(),
34
36
  requestSignUp: z.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" }).optional(),
35
37
  loginHint: z.string().meta({ description: "The login hint to use for the authorization code request" }).optional(),
38
+ additionalParams: additionalAuthorizationParamsSchema,
36
39
  additionalData: z.record(z.string(), z.any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" })
37
40
  });
38
41
  const signInSocial = () => createAuthEndpoint("/sign-in/social", {
@@ -48,10 +51,10 @@ const signInSocial = () => createAuthEndpoint("/sign-in/social", {
48
51
  description: "Sign in with a social provider",
49
52
  operationId: "socialSignIn",
50
53
  responses: { "200": {
51
- description: "Success - Returns either session details or redirect URL",
54
+ description: "Success - Returns session details (idToken branch) or an authorize URL (redirect branch)",
52
55
  content: { "application/json": { schema: {
53
56
  type: "object",
54
- description: "Session response when idToken is provided",
57
+ description: "Returns session details when idToken is provided, or an authorize URL otherwise",
55
58
  properties: {
56
59
  token: { type: "string" },
57
60
  user: {
@@ -59,16 +62,9 @@ const signInSocial = () => createAuthEndpoint("/sign-in/social", {
59
62
  $ref: "#/components/schemas/User"
60
63
  },
61
64
  url: { type: "string" },
62
- redirect: {
63
- type: "boolean",
64
- enum: [false]
65
- }
65
+ redirect: { type: "boolean" }
66
66
  },
67
- required: [
68
- "redirect",
69
- "token",
70
- "user"
71
- ]
67
+ required: ["redirect"]
72
68
  } } }
73
69
  } }
74
70
  }
@@ -100,7 +96,7 @@ const signInSocial = () => createAuthEndpoint("/sign-in/social", {
100
96
  throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO);
101
97
  }
102
98
  if (!userInfo.user.email) {
103
- c.context.logger.error("User email not found", { provider: c.body.provider });
99
+ c.context.logger.error(missingEmailLogMessage(c.body.provider, { source: "id_token" }), { provider: c.body.provider });
104
100
  throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND);
105
101
  }
106
102
  const data = await handleOAuthUserInfo(c, {
@@ -138,7 +134,8 @@ const signInSocial = () => createAuthEndpoint("/sign-in/social", {
138
134
  codeVerifier,
139
135
  redirectURI: `${c.context.baseURL}/callback/${provider.id}`,
140
136
  scopes: c.body.scopes,
141
- loginHint: c.body.loginHint
137
+ loginHint: c.body.loginHint,
138
+ additionalParams: c.body.additionalParams
142
139
  });
143
140
  if (!c.body.disableRedirect) c.setHeader("Location", url.toString());
144
141
  return c.json({
@@ -150,6 +147,7 @@ const signInEmail = () => createAuthEndpoint("/sign-in/email", {
150
147
  method: "POST",
151
148
  operationId: "signInEmail",
152
149
  use: [formCsrfMiddleware],
150
+ cloneRequest: true,
153
151
  body: z.object({
154
152
  email: z.string().meta({ description: "Email of the user" }),
155
153
  password: z.string().meta({ description: "Password of the user" }),
@@ -242,7 +240,7 @@ const signInEmail = () => createAuthEndpoint("/sign-in/email", {
242
240
  user: user.user,
243
241
  url,
244
242
  token
245
- }, ctx.request));
243
+ }, ctx.request?.clone()));
246
244
  }
247
245
  throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.EMAIL_NOT_VERIFIED);
248
246
  }
@@ -16,6 +16,7 @@ declare const signUpEmail: <O extends BetterAuthOptions>() => better_call0.Stric
16
16
  callbackURL: z.ZodOptional<z.ZodString>;
17
17
  rememberMe: z.ZodOptional<z.ZodBoolean>;
18
18
  }, z.core.$strip>, z.ZodRecord<z.ZodString, z.ZodAny>>;
19
+ cloneRequest: true;
19
20
  metadata: {
20
21
  allowedMediaTypes: string[];
21
22
  $Infer: {
@@ -1,6 +1,6 @@
1
1
  import { isAPIError } from "../../utils/is-api-error.mjs";
2
2
  import { formCsrfMiddleware } from "../middlewares/origin-check.mjs";
3
- import { parseUserInput, parseUserOutput } from "../../db/schema.mjs";
3
+ import { buildSyntheticUserOutput, parseUserInput, parseUserOutput } from "../../db/schema.mjs";
4
4
  import { setSessionCookie } from "../../cookies/index.mjs";
5
5
  import { createEmailVerificationToken } from "./email-verification.mjs";
6
6
  import { runWithTransaction } from "@better-auth/core/context";
@@ -23,6 +23,7 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
23
23
  operationId: "signUpWithEmailAndPassword",
24
24
  use: [formCsrfMiddleware],
25
25
  body: signUpEmailBodySchema,
26
+ cloneRequest: true,
26
27
  metadata: {
27
28
  allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"],
28
29
  $Infer: {
@@ -157,7 +158,7 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
157
158
  ctx.context.logger.error("Password is too long");
158
159
  throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.PASSWORD_TOO_LONG);
159
160
  }
160
- const shouldReturnGenericDuplicateResponse = ctx.context.options.emailAndPassword.requireEmailVerification;
161
+ const shouldReturnGenericDuplicateResponse = ctx.context.options.emailAndPassword.requireEmailVerification || ctx.context.options.emailAndPassword.autoSignIn === false;
161
162
  const shouldSkipAutoSignIn = ctx.context.options.emailAndPassword.autoSignIn === false || shouldReturnGenericDuplicateResponse;
162
163
  const additionalUserFields = parseUserInput(ctx.context.options, rest, "create");
163
164
  const normalizedEmail = email.toLowerCase();
@@ -170,14 +171,14 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
170
171
  * between existing and non-existing emails.
171
172
  */
172
173
  await ctx.context.password.hash(password);
173
- if (ctx.context.options.emailAndPassword?.onExistingUserSignUp) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailAndPassword.onExistingUserSignUp({ user: dbUser.user }, ctx.request));
174
+ if (ctx.context.options.emailAndPassword?.onExistingUserSignUp) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailAndPassword.onExistingUserSignUp({ user: dbUser.user }, ctx.request?.clone()));
174
175
  const now = /* @__PURE__ */ new Date();
175
176
  const generatedId = ctx.context.generateId({ model: "user" }) || generateId();
176
177
  const coreFields = {
177
178
  name,
178
179
  email: normalizedEmail,
179
180
  emailVerified: false,
180
- image: image || null,
181
+ image: image ?? null,
181
182
  createdAt: now,
182
183
  updatedAt: now
183
184
  };
@@ -187,16 +188,17 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
187
188
  const additionalFieldKeys = Object.keys(ctx.context.options.user?.additionalFields ?? {});
188
189
  const additionalFields = {};
189
190
  for (const key of additionalFieldKeys) if (key in additionalUserFields) additionalFields[key] = additionalUserFields[key];
190
- syntheticUser = customSyntheticUser({
191
+ const customResult = customSyntheticUser({
191
192
  coreFields,
192
193
  additionalFields,
193
194
  id: generatedId
194
195
  });
195
- } else syntheticUser = {
196
+ syntheticUser = buildSyntheticUserOutput(ctx.context.options, customResult);
197
+ } else syntheticUser = buildSyntheticUserOutput(ctx.context.options, {
196
198
  ...coreFields,
197
199
  ...additionalUserFields,
198
200
  id: generatedId
199
- };
201
+ });
200
202
  return ctx.json({
201
203
  token: null,
202
204
  user: parseUserOutput(ctx.context.options, syntheticUser)
@@ -244,7 +246,7 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
244
246
  user: createdUser,
245
247
  url,
246
248
  token
247
- }, ctx.request));
249
+ }, ctx.request?.clone()));
248
250
  }
249
251
  if (shouldSkipAutoSignIn) return ctx.json({
250
252
  token: null,
@@ -168,7 +168,7 @@ const changePassword = createAuthEndpoint("/change-password", {
168
168
  await ctx.context.internalAdapter.updateAccount(account.id, { password: passwordHash });
169
169
  let token = null;
170
170
  if (revokeOtherSessions) {
171
- await ctx.context.internalAdapter.deleteSessions(session.user.id);
171
+ await ctx.context.internalAdapter.deleteUserSessions(session.user.id);
172
172
  const newSession = await ctx.context.internalAdapter.createSession(session.user.id);
173
173
  if (!newSession) throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.FAILED_TO_GET_SESSION);
174
174
  await setSessionCookie(ctx, {
@@ -309,7 +309,7 @@ const deleteUser = createAuthEndpoint("/delete-user", {
309
309
  const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;
310
310
  if (beforeDelete) await beforeDelete(session.user, ctx.request);
311
311
  await ctx.context.internalAdapter.deleteUser(session.user.id);
312
- await ctx.context.internalAdapter.deleteSessions(session.user.id);
312
+ await ctx.context.internalAdapter.deleteUserSessions(session.user.id);
313
313
  deleteSessionCookie(ctx);
314
314
  const afterDelete = ctx.context.options.user.deleteUser?.afterDelete;
315
315
  if (afterDelete) await afterDelete(session.user, ctx.request);
@@ -362,7 +362,7 @@ const deleteUserCallback = createAuthEndpoint("/delete-user/callback", {
362
362
  const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;
363
363
  if (beforeDelete) await beforeDelete(session.user, ctx.request);
364
364
  await ctx.context.internalAdapter.deleteUser(session.user.id);
365
- await ctx.context.internalAdapter.deleteSessions(session.user.id);
365
+ await ctx.context.internalAdapter.deleteUserSessions(session.user.id);
366
366
  await ctx.context.internalAdapter.deleteAccounts(session.user.id);
367
367
  await ctx.context.internalAdapter.deleteVerificationByIdentifier(`delete-account-${ctx.query.token}`);
368
368
  deleteSessionCookie(ctx);
@@ -410,7 +410,7 @@ const changeEmail = createAuthEndpoint("/change-email", {
410
410
  }, async (ctx) => {
411
411
  if (!ctx.context.options.user?.changeEmail?.enabled) {
412
412
  ctx.context.logger.error("Change email is disabled.");
413
- throw APIError.fromStatus("BAD_REQUEST", { message: "Change email is disabled" });
413
+ throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.CHANGE_EMAIL_DISABLED);
414
414
  }
415
415
  const newEmail = ctx.body.newEmail.toLowerCase();
416
416
  if (newEmail === ctx.context.session.user.email) {
@@ -424,8 +424,8 @@ const changeEmail = createAuthEndpoint("/change-email", {
424
424
  * email would later throw 400, leaking email existence.
425
425
  */
426
426
  const canUpdateWithoutVerification = ctx.context.session.user.emailVerified !== true && ctx.context.options.user.changeEmail.updateEmailWithoutVerification;
427
- const canSendConfirmation = ctx.context.session.user.emailVerified && ctx.context.options.user.changeEmail.sendChangeEmailConfirmation;
428
427
  const canSendVerification = ctx.context.options.emailVerification?.sendVerificationEmail;
428
+ const canSendConfirmation = canSendVerification && ctx.context.session.user.emailVerified && ctx.context.options.user.changeEmail.sendChangeEmailConfirmation;
429
429
  if (!canUpdateWithoutVerification && !canSendConfirmation && !canSendVerification) {
430
430
  ctx.context.logger.error("Verification email isn't enabled.");
431
431
  throw APIError.fromStatus("BAD_REQUEST", { message: "Verification email isn't enabled" });
@@ -449,7 +449,7 @@ const changeEmail = createAuthEndpoint("/change-email", {
449
449
  });
450
450
  if (canSendVerification) {
451
451
  const token = await createEmailVerificationToken(ctx.context.secret, newEmail, void 0, ctx.context.options.emailVerification?.expiresIn);
452
- const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
452
+ const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${encodeURIComponent(ctx.body.callbackURL || "/")}`;
453
453
  await ctx.context.runInBackgroundOrAwait(canSendVerification({
454
454
  user: {
455
455
  ...ctx.context.session.user,
@@ -466,7 +466,7 @@ const changeEmail = createAuthEndpoint("/change-email", {
466
466
  */
467
467
  if (canSendConfirmation) {
468
468
  const token = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-confirmation" });
469
- const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
469
+ const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${encodeURIComponent(ctx.body.callbackURL || "/")}`;
470
470
  await ctx.context.runInBackgroundOrAwait(canSendConfirmation({
471
471
  user: ctx.context.session.user,
472
472
  newEmail,
@@ -480,7 +480,7 @@ const changeEmail = createAuthEndpoint("/change-email", {
480
480
  throw APIError.fromStatus("BAD_REQUEST", { message: "Verification email isn't enabled" });
481
481
  }
482
482
  const token = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-verification" });
483
- const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
483
+ const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${encodeURIComponent(ctx.body.callbackURL || "/")}`;
484
484
  await ctx.context.runInBackgroundOrAwait(canSendVerification({
485
485
  user: {
486
486
  ...ctx.context.session.user,
@@ -117,7 +117,13 @@ function toAuthEndpoints(endpoints, ctx) {
117
117
  * headers override while cookies accumulate.
118
118
  */
119
119
  const ctxHeaders = e[kAPIErrorHeaderSymbol];
120
- const errHeaders = e.headers ? new Headers(e.headers) : null;
120
+ /**
121
+ * `c.redirect()` (and similar APIError throws) reuse
122
+ * `ctx.responseHeaders` as `e.headers`, so when both sources
123
+ * reference the same Headers, iterating both duplicates every
124
+ * `set-cookie`. Skip the `errHeaders` copy in that case.
125
+ */
126
+ const errHeaders = e.headers && e.headers !== ctxHeaders ? new Headers(e.headers) : null;
121
127
  let headers = null;
122
128
  if (ctxHeaders || errHeaders) {
123
129
  headers = new Headers();
@@ -7,38 +7,41 @@ import { BASE_ERROR_CODES, BetterAuthError } from "@better-auth/core/error";
7
7
  const createBetterAuth = (options, initFn) => {
8
8
  const authContext = initFn(options);
9
9
  const { api } = getEndpoints(authContext, options);
10
- return {
11
- handler: async (request) => {
12
- const ctx = await authContext;
13
- const basePath = ctx.options.basePath || "/api/auth";
14
- let handlerCtx;
15
- if (isDynamicBaseURLConfig(options.baseURL)) handlerCtx = await resolveRequestContext(ctx, request, resolveDynamicTrustedProxyHeaders(ctx.options));
16
- else {
17
- handlerCtx = ctx;
18
- if (!ctx.options.baseURL) {
19
- const baseURL = getBaseURL(void 0, basePath, request, void 0, ctx.options.advanced?.trustedProxyHeaders);
20
- if (baseURL) {
21
- ctx.baseURL = baseURL;
22
- ctx.options.baseURL = getOrigin(ctx.baseURL) || void 0;
23
- } else throw new BetterAuthError("Could not get base URL from request. Please provide a valid base URL.");
24
- }
25
- handlerCtx.trustedOrigins = await getTrustedOrigins(ctx.options, request);
26
- handlerCtx.trustedProviders = await getTrustedProviders(ctx.options, request);
10
+ const errorCodes = options.plugins?.reduce((acc, plugin) => {
11
+ if (plugin.$ERROR_CODES) return {
12
+ ...acc,
13
+ ...plugin.$ERROR_CODES
14
+ };
15
+ return acc;
16
+ }, {});
17
+ const handler = async (request) => {
18
+ const ctx = await authContext;
19
+ const basePath = ctx.options.basePath || "/api/auth";
20
+ let handlerCtx;
21
+ if (isDynamicBaseURLConfig(options.baseURL)) handlerCtx = await resolveRequestContext(ctx, request, resolveDynamicTrustedProxyHeaders(ctx.options));
22
+ else {
23
+ handlerCtx = ctx;
24
+ if (!ctx.options.baseURL) {
25
+ const baseURL = getBaseURL(void 0, basePath, request, void 0, ctx.options.advanced?.trustedProxyHeaders);
26
+ if (baseURL) {
27
+ ctx.baseURL = baseURL;
28
+ ctx.options.baseURL = getOrigin(ctx.baseURL) || void 0;
29
+ } else throw new BetterAuthError("Could not get base URL from request. Please provide a valid base URL.");
27
30
  }
28
- const { handler } = router(handlerCtx, options);
29
- return runWithAdapter(handlerCtx.adapter, () => handler(request));
30
- },
31
+ handlerCtx.trustedOrigins = await getTrustedOrigins(ctx.options, request);
32
+ handlerCtx.trustedProviders = await getTrustedProviders(ctx.options, request);
33
+ }
34
+ const { handler } = router(handlerCtx, options);
35
+ return runWithAdapter(handlerCtx.adapter, () => handler(request));
36
+ };
37
+ return {
38
+ handler,
39
+ fetch: handler,
31
40
  api,
32
41
  options,
33
42
  $context: authContext,
34
43
  $ERROR_CODES: {
35
- ...options.plugins?.reduce((acc, plugin) => {
36
- if (plugin.$ERROR_CODES) return {
37
- ...acc,
38
- ...plugin.$ERROR_CODES
39
- };
40
- return acc;
41
- }, {}),
44
+ ...errorCodes,
42
45
  ...BASE_ERROR_CODES
43
46
  }
44
47
  };
@@ -1,7 +1,7 @@
1
1
  import { getBaseURL } from "../utils/url.mjs";
2
2
  import { parseJSON } from "./parser.mjs";
3
3
  import { redirectPlugin } from "./fetch-plugins.mjs";
4
- import { getSessionAtom } from "./session-atom.mjs";
4
+ import { getSessionAtom, hydrateSessionAtom } from "./session-atom.mjs";
5
5
  import { defu } from "defu";
6
6
  import { createFetch } from "@better-fetch/fetch";
7
7
  //#region src/client/config.ts
@@ -52,6 +52,12 @@ const getClientConfig = (options, loadEnv) => {
52
52
  ]
53
53
  });
54
54
  const { $sessionSignal, session, broadcastSessionUpdate } = getSessionAtom($fetch, options);
55
+ let hasHydrated = false;
56
+ const hydrateSession = (sessionData) => {
57
+ if (hasHydrated || sessionData === null) return;
58
+ hasHydrated = true;
59
+ hydrateSessionAtom(session, sessionData);
60
+ };
55
61
  const plugins = options?.plugins || [];
56
62
  let pluginsActions = {};
57
63
  const pluginsAtoms = {
@@ -97,6 +103,7 @@ const getClientConfig = (options, loadEnv) => {
97
103
  pluginsAtoms,
98
104
  pluginPathMethods,
99
105
  atomListeners,
106
+ hydrateSession,
100
107
  $fetch,
101
108
  $store
102
109
  };