@masheev/better-auth 0.0.0-stage → 1.7.5

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 (465) hide show
  1. package/LICENSE.md +20 -0
  2. package/README.md +31 -2
  3. package/TYPE-PATCH-NOTICE.md +9 -0
  4. package/TYPE-PATCH-PROVENANCE.json +267 -0
  5. package/dist/_virtual/_rolldown/runtime.mjs +27 -0
  6. package/dist/adapters/drizzle-adapter/index.d.mts +1 -0
  7. package/dist/adapters/drizzle-adapter/index.mjs +2 -0
  8. package/dist/adapters/index.d.mts +26 -0
  9. package/dist/adapters/index.mjs +9 -0
  10. package/dist/adapters/kysely-adapter/index.d.mts +1 -0
  11. package/dist/adapters/kysely-adapter/index.mjs +2 -0
  12. package/dist/adapters/memory-adapter/index.d.mts +1 -0
  13. package/dist/adapters/memory-adapter/index.mjs +2 -0
  14. package/dist/adapters/mongodb-adapter/index.d.mts +1 -0
  15. package/dist/adapters/mongodb-adapter/index.mjs +2 -0
  16. package/dist/adapters/prisma-adapter/index.d.mts +1 -0
  17. package/dist/adapters/prisma-adapter/index.mjs +2 -0
  18. package/dist/api/dispatch.d.mts +34 -0
  19. package/dist/api/dispatch.mjs +275 -0
  20. package/dist/api/index.d.mts +4053 -0
  21. package/dist/api/index.mjs +220 -0
  22. package/dist/api/middlewares/authorization.d.mts +69 -0
  23. package/dist/api/middlewares/authorization.mjs +78 -0
  24. package/dist/api/middlewares/index.d.mts +2 -0
  25. package/dist/api/middlewares/origin-check.d.mts +17 -0
  26. package/dist/api/middlewares/origin-check.mjs +155 -0
  27. package/dist/api/rate-limiter/index.mjs +318 -0
  28. package/dist/api/routes/account.d.mts +413 -0
  29. package/dist/api/routes/account.mjs +619 -0
  30. package/dist/api/routes/callback.d.mts +32 -0
  31. package/dist/api/routes/callback.mjs +261 -0
  32. package/dist/api/routes/email-verification.d.mts +160 -0
  33. package/dist/api/routes/email-verification.mjs +324 -0
  34. package/dist/api/routes/error.d.mts +27 -0
  35. package/dist/api/routes/error.mjs +387 -0
  36. package/dist/api/routes/index.d.mts +12 -0
  37. package/dist/api/routes/ok.d.mts +35 -0
  38. package/dist/api/routes/ok.mjs +27 -0
  39. package/dist/api/routes/password.d.mts +182 -0
  40. package/dist/api/routes/password.mjs +206 -0
  41. package/dist/api/routes/session.d.mts +450 -0
  42. package/dist/api/routes/session.mjs +481 -0
  43. package/dist/api/routes/sign-in.d.mts +186 -0
  44. package/dist/api/routes/sign-in.mjs +368 -0
  45. package/dist/api/routes/sign-out.d.mts +51 -0
  46. package/dist/api/routes/sign-out.mjs +96 -0
  47. package/dist/api/routes/sign-up.d.mts +159 -0
  48. package/dist/api/routes/sign-up.mjs +275 -0
  49. package/dist/api/routes/update-session.d.mts +74 -0
  50. package/dist/api/routes/update-session.mjs +57 -0
  51. package/dist/api/routes/update-user.d.mts +428 -0
  52. package/dist/api/routes/update-user.mjs +522 -0
  53. package/dist/api/state/oauth.d.mts +53 -0
  54. package/dist/api/state/oauth.mjs +38 -0
  55. package/dist/api/state/should-session-refresh.d.mts +12 -0
  56. package/dist/api/state/should-session-refresh.mjs +13 -0
  57. package/dist/api/to-auth-endpoints.mjs +60 -0
  58. package/dist/auth/base.mjs +66 -0
  59. package/dist/auth/full.d.mts +28 -0
  60. package/dist/auth/full.mjs +29 -0
  61. package/dist/auth/minimal.d.mts +10 -0
  62. package/dist/auth/minimal.mjs +11 -0
  63. package/dist/auth/trusted-origins.mjs +106 -0
  64. package/dist/client/broadcast-channel.d.mts +19 -0
  65. package/dist/client/broadcast-channel.mjs +44 -0
  66. package/dist/client/config.d.mts +90 -0
  67. package/dist/client/config.mjs +113 -0
  68. package/dist/client/equality.d.mts +19 -0
  69. package/dist/client/equality.mjs +42 -0
  70. package/dist/client/fetch-plugins.mjs +17 -0
  71. package/dist/client/focus-manager.d.mts +10 -0
  72. package/dist/client/focus-manager.mjs +30 -0
  73. package/dist/client/index.d.mts +35 -0
  74. package/dist/client/index.mjs +22 -0
  75. package/dist/client/lynx/index.d.mts +43 -0
  76. package/dist/client/lynx/index.mjs +22 -0
  77. package/dist/client/lynx/lynx-store.d.mts +46 -0
  78. package/dist/client/lynx/lynx-store.mjs +44 -0
  79. package/dist/client/online-manager.d.mts +11 -0
  80. package/dist/client/online-manager.mjs +33 -0
  81. package/dist/client/parser.d.mts +10 -0
  82. package/dist/client/parser.mjs +70 -0
  83. package/dist/client/path-to-object.d.mts +113 -0
  84. package/dist/client/plugins/index.d.mts +44 -0
  85. package/dist/client/plugins/index.mjs +30 -0
  86. package/dist/client/plugins/infer-plugin.d.mts +16 -0
  87. package/dist/client/plugins/infer-plugin.mjs +11 -0
  88. package/dist/client/proxy.mjs +78 -0
  89. package/dist/client/query.d.mts +23 -0
  90. package/dist/client/query.mjs +124 -0
  91. package/dist/client/react/index.d.mts +44 -0
  92. package/dist/client/react/index.mjs +22 -0
  93. package/dist/client/react/react-store.d.mts +46 -0
  94. package/dist/client/react/react-store.mjs +44 -0
  95. package/dist/client/session-atom.d.mts +11 -0
  96. package/dist/client/session-atom.mjs +178 -0
  97. package/dist/client/session-refresh.d.mts +20 -0
  98. package/dist/client/session-refresh.mjs +131 -0
  99. package/dist/client/solid/index.d.mts +44 -0
  100. package/dist/client/solid/index.mjs +22 -0
  101. package/dist/client/solid/solid-store.mjs +21 -0
  102. package/dist/client/svelte/index.d.mts +44 -0
  103. package/dist/client/svelte/index.mjs +18 -0
  104. package/dist/client/types.d.mts +51 -0
  105. package/dist/client/vanilla.d.mts +42 -0
  106. package/dist/client/vanilla.mjs +18 -0
  107. package/dist/client/vue/index.d.mts +67 -0
  108. package/dist/client/vue/index.mjs +54 -0
  109. package/dist/client/vue/vue-store.mjs +23 -0
  110. package/dist/context/create-context.mjs +235 -0
  111. package/dist/context/helpers.mjs +158 -0
  112. package/dist/context/init-minimal.mjs +17 -0
  113. package/dist/context/init.mjs +19 -0
  114. package/dist/context/secret-utils.mjs +53 -0
  115. package/dist/context/store-capabilities.mjs +12 -0
  116. package/dist/cookies/cache.mjs +33 -0
  117. package/dist/cookies/cookie-utils.d.mts +72 -0
  118. package/dist/cookies/cookie-utils.mjs +203 -0
  119. package/dist/cookies/index.d.mts +124 -0
  120. package/dist/cookies/index.mjs +350 -0
  121. package/dist/cookies/jwt.mjs +44 -0
  122. package/dist/cookies/session-store.d.mts +32 -0
  123. package/dist/cookies/session-store.mjs +183 -0
  124. package/dist/crypto/buffer.d.mts +7 -0
  125. package/dist/crypto/buffer.mjs +16 -0
  126. package/dist/crypto/index.d.mts +32 -0
  127. package/dist/crypto/index.mjs +69 -0
  128. package/dist/crypto/jwt.d.mts +9 -0
  129. package/dist/crypto/jwt.mjs +141 -0
  130. package/dist/crypto/password.d.mts +13 -0
  131. package/dist/crypto/password.mjs +14 -0
  132. package/dist/crypto/random.d.mts +4 -0
  133. package/dist/crypto/random.mjs +5 -0
  134. package/dist/db/adapter-base.d.mts +7 -0
  135. package/dist/db/adapter-base.mjs +25 -0
  136. package/dist/db/adapter-kysely.d.mts +7 -0
  137. package/dist/db/adapter-kysely.mjs +17 -0
  138. package/dist/db/field-converter.d.mts +7 -0
  139. package/dist/db/field-converter.mjs +19 -0
  140. package/dist/db/field.d.mts +41 -0
  141. package/dist/db/get-migration.d.mts +56 -0
  142. package/dist/db/get-migration.mjs +685 -0
  143. package/dist/db/get-schema.d.mts +13 -0
  144. package/dist/db/get-schema.mjs +39 -0
  145. package/dist/db/index.d.mts +10 -0
  146. package/dist/db/index.mjs +35 -0
  147. package/dist/db/internal-adapter.d.mts +14 -0
  148. package/dist/db/internal-adapter.mjs +951 -0
  149. package/dist/db/revoke-unproven-account-access.d.mts +21 -0
  150. package/dist/db/revoke-unproven-account-access.mjs +58 -0
  151. package/dist/db/schema.d.mts +62 -0
  152. package/dist/db/schema.mjs +161 -0
  153. package/dist/db/to-zod.d.mts +35 -0
  154. package/dist/db/to-zod.mjs +23 -0
  155. package/dist/db/verification-token-storage.mjs +25 -0
  156. package/dist/db/with-hooks.d.mts +37 -0
  157. package/dist/db/with-hooks.mjs +255 -0
  158. package/dist/index.d.mts +30 -0
  159. package/dist/index.mjs +17 -0
  160. package/dist/integrations/cookie-plugin-guard.mjs +18 -0
  161. package/dist/integrations/next-js.d.mts +29 -0
  162. package/dist/integrations/next-js.mjs +105 -0
  163. package/dist/integrations/node.d.mts +11 -0
  164. package/dist/integrations/node.mjs +13 -0
  165. package/dist/integrations/solid-start.d.mts +22 -0
  166. package/dist/integrations/solid-start.mjs +15 -0
  167. package/dist/integrations/svelte-kit.d.mts +38 -0
  168. package/dist/integrations/svelte-kit.mjs +57 -0
  169. package/dist/integrations/tanstack-start-solid.d.mts +33 -0
  170. package/dist/integrations/tanstack-start-solid.mjs +57 -0
  171. package/dist/integrations/tanstack-start.d.mts +33 -0
  172. package/dist/integrations/tanstack-start.mjs +57 -0
  173. package/dist/oauth2/account-key.mjs +43 -0
  174. package/dist/oauth2/errors.mjs +49 -0
  175. package/dist/oauth2/index.d.mts +5 -0
  176. package/dist/oauth2/index.mjs +5 -0
  177. package/dist/oauth2/link-account.d.mts +96 -0
  178. package/dist/oauth2/link-account.mjs +329 -0
  179. package/dist/oauth2/state.d.mts +54 -0
  180. package/dist/oauth2/state.mjs +67 -0
  181. package/dist/oauth2/utils.d.mts +11 -0
  182. package/dist/oauth2/utils.mjs +33 -0
  183. package/dist/package.mjs +4 -0
  184. package/dist/plugins/access/access.d.mts +17 -0
  185. package/dist/plugins/access/access.mjs +78 -0
  186. package/dist/plugins/access/index.d.mts +3 -0
  187. package/dist/plugins/access/index.mjs +2 -0
  188. package/dist/plugins/access/types.d.mts +24 -0
  189. package/dist/plugins/additional-fields/client.d.mts +100 -0
  190. package/dist/plugins/additional-fields/client.mjs +11 -0
  191. package/dist/plugins/admin/access/index.d.mts +2 -0
  192. package/dist/plugins/admin/access/index.mjs +2 -0
  193. package/dist/plugins/admin/access/statement.d.mts +51 -0
  194. package/dist/plugins/admin/access/statement.mjs +52 -0
  195. package/dist/plugins/admin/admin.d.mts +911 -0
  196. package/dist/plugins/admin/admin.mjs +89 -0
  197. package/dist/plugins/admin/client.d.mts +81 -0
  198. package/dist/plugins/admin/client.mjs +39 -0
  199. package/dist/plugins/admin/error-codes.d.mts +30 -0
  200. package/dist/plugins/admin/error-codes.mjs +29 -0
  201. package/dist/plugins/admin/has-permission.mjs +12 -0
  202. package/dist/plugins/admin/index.d.mts +3 -0
  203. package/dist/plugins/admin/index.mjs +2 -0
  204. package/dist/plugins/admin/routes.mjs +919 -0
  205. package/dist/plugins/admin/schema.d.mts +40 -0
  206. package/dist/plugins/admin/schema.mjs +33 -0
  207. package/dist/plugins/admin/types.d.mts +88 -0
  208. package/dist/plugins/anonymous/client.d.mts +32 -0
  209. package/dist/plugins/anonymous/client.mjs +21 -0
  210. package/dist/plugins/anonymous/error-codes.d.mts +15 -0
  211. package/dist/plugins/anonymous/error-codes.mjs +14 -0
  212. package/dist/plugins/anonymous/index.d.mts +175 -0
  213. package/dist/plugins/anonymous/index.mjs +219 -0
  214. package/dist/plugins/anonymous/schema.d.mts +15 -0
  215. package/dist/plugins/anonymous/schema.mjs +9 -0
  216. package/dist/plugins/anonymous/types.d.mts +65 -0
  217. package/dist/plugins/bearer/index.d.mts +45 -0
  218. package/dist/plugins/bearer/index.mjs +74 -0
  219. package/dist/plugins/captcha/constants.d.mts +9 -0
  220. package/dist/plugins/captcha/constants.mjs +27 -0
  221. package/dist/plugins/captcha/error-codes.mjs +13 -0
  222. package/dist/plugins/captcha/index.d.mts +27 -0
  223. package/dist/plugins/captcha/index.mjs +79 -0
  224. package/dist/plugins/captcha/types.d.mts +52 -0
  225. package/dist/plugins/captcha/utils.mjs +9 -0
  226. package/dist/plugins/captcha/verify-handlers/captchafox.mjs +27 -0
  227. package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +47 -0
  228. package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +32 -0
  229. package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +27 -0
  230. package/dist/plugins/custom-session/client.d.mts +17 -0
  231. package/dist/plugins/custom-session/client.mjs +7 -0
  232. package/dist/plugins/custom-session/index.d.mts +73 -0
  233. package/dist/plugins/custom-session/index.mjs +65 -0
  234. package/dist/plugins/device-authorization/client.d.mts +17 -0
  235. package/dist/plugins/device-authorization/client.mjs +18 -0
  236. package/dist/plugins/device-authorization/error-codes.mjs +19 -0
  237. package/dist/plugins/device-authorization/index.d.mts +558 -0
  238. package/dist/plugins/device-authorization/index.mjs +87 -0
  239. package/dist/plugins/device-authorization/routes.d.mts +32 -0
  240. package/dist/plugins/device-authorization/routes.mjs +725 -0
  241. package/dist/plugins/device-authorization/schema.d.mts +18 -0
  242. package/dist/plugins/device-authorization/schema.mjs +63 -0
  243. package/dist/plugins/email-otp/client.d.mts +21 -0
  244. package/dist/plugins/email-otp/client.mjs +17 -0
  245. package/dist/plugins/email-otp/error-codes.d.mts +10 -0
  246. package/dist/plugins/email-otp/error-codes.mjs +9 -0
  247. package/dist/plugins/email-otp/index.d.mts +551 -0
  248. package/dist/plugins/email-otp/index.mjs +145 -0
  249. package/dist/plugins/email-otp/otp-token.mjs +55 -0
  250. package/dist/plugins/email-otp/routes.mjs +784 -0
  251. package/dist/plugins/email-otp/types.d.mts +109 -0
  252. package/dist/plugins/email-otp/utils.mjs +17 -0
  253. package/dist/plugins/generic-oauth/error-codes.mjs +8 -0
  254. package/dist/plugins/generic-oauth/index.d.mts +52 -0
  255. package/dist/plugins/generic-oauth/index.mjs +279 -0
  256. package/dist/plugins/generic-oauth/providers/auth0.d.mts +36 -0
  257. package/dist/plugins/generic-oauth/providers/auth0.mjs +49 -0
  258. package/dist/plugins/generic-oauth/providers/gumroad.d.mts +31 -0
  259. package/dist/plugins/generic-oauth/providers/gumroad.mjs +62 -0
  260. package/dist/plugins/generic-oauth/providers/hubspot.d.mts +36 -0
  261. package/dist/plugins/generic-oauth/providers/hubspot.mjs +62 -0
  262. package/dist/plugins/generic-oauth/providers/index.d.mts +10 -0
  263. package/dist/plugins/generic-oauth/providers/keycloak.d.mts +36 -0
  264. package/dist/plugins/generic-oauth/providers/keycloak.mjs +47 -0
  265. package/dist/plugins/generic-oauth/providers/line.d.mts +54 -0
  266. package/dist/plugins/generic-oauth/providers/line.mjs +93 -0
  267. package/dist/plugins/generic-oauth/providers/microsoft-entra-id.d.mts +39 -0
  268. package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs +104 -0
  269. package/dist/plugins/generic-oauth/providers/okta.d.mts +36 -0
  270. package/dist/plugins/generic-oauth/providers/okta.mjs +47 -0
  271. package/dist/plugins/generic-oauth/providers/patreon.d.mts +29 -0
  272. package/dist/plugins/generic-oauth/providers/patreon.mjs +61 -0
  273. package/dist/plugins/generic-oauth/providers/slack.d.mts +29 -0
  274. package/dist/plugins/generic-oauth/providers/slack.mjs +63 -0
  275. package/dist/plugins/generic-oauth/providers/yandex.d.mts +29 -0
  276. package/dist/plugins/generic-oauth/providers/yandex.mjs +67 -0
  277. package/dist/plugins/generic-oauth/types.d.mts +268 -0
  278. package/dist/plugins/haveibeenpwned/index.d.mts +63 -0
  279. package/dist/plugins/haveibeenpwned/index.mjs +81 -0
  280. package/dist/plugins/index.d.mts +69 -0
  281. package/dist/plugins/index.mjs +49 -0
  282. package/dist/plugins/jwt/adapter.mjs +68 -0
  283. package/dist/plugins/jwt/client.d.mts +41 -0
  284. package/dist/plugins/jwt/client.mjs +19 -0
  285. package/dist/plugins/jwt/cookie-cache.mjs +77 -0
  286. package/dist/plugins/jwt/index.d.mts +246 -0
  287. package/dist/plugins/jwt/index.mjs +214 -0
  288. package/dist/plugins/jwt/schema.d.mts +33 -0
  289. package/dist/plugins/jwt/schema.mjs +29 -0
  290. package/dist/plugins/jwt/sign.d.mts +128 -0
  291. package/dist/plugins/jwt/sign.mjs +130 -0
  292. package/dist/plugins/jwt/types.d.mts +256 -0
  293. package/dist/plugins/jwt/utils.d.mts +41 -0
  294. package/dist/plugins/jwt/utils.mjs +64 -0
  295. package/dist/plugins/jwt/verify.d.mts +11 -0
  296. package/dist/plugins/jwt/verify.mjs +45 -0
  297. package/dist/plugins/last-login-method/client.d.mts +48 -0
  298. package/dist/plugins/last-login-method/client.mjs +48 -0
  299. package/dist/plugins/last-login-method/index.d.mts +127 -0
  300. package/dist/plugins/last-login-method/index.mjs +98 -0
  301. package/dist/plugins/magic-link/client.d.mts +10 -0
  302. package/dist/plugins/magic-link/client.mjs +11 -0
  303. package/dist/plugins/magic-link/index.d.mts +213 -0
  304. package/dist/plugins/magic-link/index.mjs +208 -0
  305. package/dist/plugins/magic-link/utils.mjs +9 -0
  306. package/dist/plugins/multi-session/client.d.mts +19 -0
  307. package/dist/plugins/multi-session/client.mjs +19 -0
  308. package/dist/plugins/multi-session/error-codes.d.mts +8 -0
  309. package/dist/plugins/multi-session/error-codes.mjs +5 -0
  310. package/dist/plugins/multi-session/index.d.mts +212 -0
  311. package/dist/plugins/multi-session/index.mjs +217 -0
  312. package/dist/plugins/oauth-popup/client.d.mts +82 -0
  313. package/dist/plugins/oauth-popup/client.mjs +203 -0
  314. package/dist/plugins/oauth-popup/constants.d.mts +11 -0
  315. package/dist/plugins/oauth-popup/constants.mjs +11 -0
  316. package/dist/plugins/oauth-popup/error-codes.d.mts +11 -0
  317. package/dist/plugins/oauth-popup/error-codes.mjs +10 -0
  318. package/dist/plugins/oauth-popup/index.d.mts +67 -0
  319. package/dist/plugins/oauth-popup/index.mjs +232 -0
  320. package/dist/plugins/oauth-popup/types.d.mts +30 -0
  321. package/dist/plugins/oauth-proxy/index.d.mts +130 -0
  322. package/dist/plugins/oauth-proxy/index.mjs +407 -0
  323. package/dist/plugins/oauth-proxy/utils.mjs +55 -0
  324. package/dist/plugins/one-tap/client.d.mts +174 -0
  325. package/dist/plugins/one-tap/client.mjs +208 -0
  326. package/dist/plugins/one-tap/index.d.mts +82 -0
  327. package/dist/plugins/one-tap/index.mjs +100 -0
  328. package/dist/plugins/one-time-token/client.d.mts +10 -0
  329. package/dist/plugins/one-time-token/client.mjs +11 -0
  330. package/dist/plugins/one-time-token/index.d.mts +132 -0
  331. package/dist/plugins/one-time-token/index.mjs +107 -0
  332. package/dist/plugins/one-time-token/utils.mjs +9 -0
  333. package/dist/plugins/open-api/generator.d.mts +126 -0
  334. package/dist/plugins/open-api/generator.mjs +557 -0
  335. package/dist/plugins/open-api/index.d.mts +97 -0
  336. package/dist/plugins/open-api/index.mjs +65 -0
  337. package/dist/plugins/open-api/logo.mjs +13 -0
  338. package/dist/plugins/organization/access/index.d.mts +2 -0
  339. package/dist/plugins/organization/access/index.mjs +2 -0
  340. package/dist/plugins/organization/access/statement.d.mts +113 -0
  341. package/dist/plugins/organization/access/statement.mjs +77 -0
  342. package/dist/plugins/organization/adapter.d.mts +815 -0
  343. package/dist/plugins/organization/adapter.mjs +813 -0
  344. package/dist/plugins/organization/call.mjs +15 -0
  345. package/dist/plugins/organization/client.d.mts +375 -0
  346. package/dist/plugins/organization/client.mjs +104 -0
  347. package/dist/plugins/organization/error-codes.d.mts +66 -0
  348. package/dist/plugins/organization/error-codes.mjs +65 -0
  349. package/dist/plugins/organization/has-permission.d.mts +17 -0
  350. package/dist/plugins/organization/has-permission.mjs +34 -0
  351. package/dist/plugins/organization/index.d.mts +6 -0
  352. package/dist/plugins/organization/index.mjs +4 -0
  353. package/dist/plugins/organization/organization.d.mts +420 -0
  354. package/dist/plugins/organization/organization.mjs +886 -0
  355. package/dist/plugins/organization/permission.d.mts +15 -0
  356. package/dist/plugins/organization/permission.mjs +14 -0
  357. package/dist/plugins/organization/routes/crud-access-control.d.mts +511 -0
  358. package/dist/plugins/organization/routes/crud-access-control.mjs +674 -0
  359. package/dist/plugins/organization/routes/crud-invites.d.mts +1154 -0
  360. package/dist/plugins/organization/routes/crud-invites.mjs +602 -0
  361. package/dist/plugins/organization/routes/crud-members.d.mts +1057 -0
  362. package/dist/plugins/organization/routes/crud-members.mjs +518 -0
  363. package/dist/plugins/organization/routes/crud-org.d.mts +918 -0
  364. package/dist/plugins/organization/routes/crud-org.mjs +455 -0
  365. package/dist/plugins/organization/routes/crud-team.d.mts +1238 -0
  366. package/dist/plugins/organization/routes/crud-team.mjs +766 -0
  367. package/dist/plugins/organization/schema.d.mts +390 -0
  368. package/dist/plugins/organization/schema.mjs +65 -0
  369. package/dist/plugins/organization/types.d.mts +691 -0
  370. package/dist/plugins/phone-number/client.d.mts +31 -0
  371. package/dist/plugins/phone-number/client.mjs +19 -0
  372. package/dist/plugins/phone-number/error-codes.d.mts +19 -0
  373. package/dist/plugins/phone-number/error-codes.mjs +18 -0
  374. package/dist/plugins/phone-number/index.d.mts +360 -0
  375. package/dist/plugins/phone-number/index.mjs +57 -0
  376. package/dist/plugins/phone-number/routes.mjs +529 -0
  377. package/dist/plugins/phone-number/schema.d.mts +22 -0
  378. package/dist/plugins/phone-number/schema.mjs +18 -0
  379. package/dist/plugins/phone-number/types.d.mts +116 -0
  380. package/dist/plugins/siwe/client.d.mts +14 -0
  381. package/dist/plugins/siwe/client.mjs +15 -0
  382. package/dist/plugins/siwe/index.d.mts +62 -0
  383. package/dist/plugins/siwe/index.mjs +272 -0
  384. package/dist/plugins/siwe/parse-message.mjs +60 -0
  385. package/dist/plugins/siwe/schema.d.mts +35 -0
  386. package/dist/plugins/siwe/schema.mjs +30 -0
  387. package/dist/plugins/siwe/types.d.mts +43 -0
  388. package/dist/plugins/test-utils/auth-helpers.mjs +33 -0
  389. package/dist/plugins/test-utils/cookie-builder.mjs +55 -0
  390. package/dist/plugins/test-utils/db-helpers.mjs +65 -0
  391. package/dist/plugins/test-utils/factories.mjs +38 -0
  392. package/dist/plugins/test-utils/index.d.mts +73 -0
  393. package/dist/plugins/test-utils/index.mjs +97 -0
  394. package/dist/plugins/test-utils/otp-sink.mjs +21 -0
  395. package/dist/plugins/test-utils/types.d.mts +51 -0
  396. package/dist/plugins/two-factor/backup-codes/index.d.mts +291 -0
  397. package/dist/plugins/two-factor/backup-codes/index.mjs +341 -0
  398. package/dist/plugins/two-factor/client.d.mts +76 -0
  399. package/dist/plugins/two-factor/client.mjs +41 -0
  400. package/dist/plugins/two-factor/constant.mjs +6 -0
  401. package/dist/plugins/two-factor/error-code.d.mts +20 -0
  402. package/dist/plugins/two-factor/error-code.mjs +19 -0
  403. package/dist/plugins/two-factor/index.d.mts +720 -0
  404. package/dist/plugins/two-factor/index.mjs +349 -0
  405. package/dist/plugins/two-factor/otp/index.d.mts +216 -0
  406. package/dist/plugins/two-factor/otp/index.mjs +252 -0
  407. package/dist/plugins/two-factor/schema.d.mts +59 -0
  408. package/dist/plugins/two-factor/schema.mjs +53 -0
  409. package/dist/plugins/two-factor/totp/index.d.mts +219 -0
  410. package/dist/plugins/two-factor/totp/index.mjs +230 -0
  411. package/dist/plugins/two-factor/types.d.mts +111 -0
  412. package/dist/plugins/two-factor/utils.mjs +9 -0
  413. package/dist/plugins/two-factor/verify-two-factor.mjs +205 -0
  414. package/dist/plugins/username/client.d.mts +38 -0
  415. package/dist/plugins/username/client.mjs +17 -0
  416. package/dist/plugins/username/error-codes.d.mts +16 -0
  417. package/dist/plugins/username/error-codes.mjs +15 -0
  418. package/dist/plugins/username/index.d.mts +326 -0
  419. package/dist/plugins/username/index.mjs +312 -0
  420. package/dist/plugins/username/schema.d.mts +50 -0
  421. package/dist/plugins/username/schema.mjs +25 -0
  422. package/dist/social-providers/index.d.mts +1 -0
  423. package/dist/social-providers/index.mjs +2 -0
  424. package/dist/state.d.mts +48 -0
  425. package/dist/state.mjs +149 -0
  426. package/dist/test-utils/headers.d.mts +8 -0
  427. package/dist/test-utils/headers.mjs +17 -0
  428. package/dist/test-utils/http-test-instance.d.mts +413 -0
  429. package/dist/test-utils/http-test-instance.mjs +107 -0
  430. package/dist/test-utils/index.d.mts +4 -0
  431. package/dist/test-utils/index.mjs +4 -0
  432. package/dist/test-utils/test-instance.d.mts +56 -0
  433. package/dist/test-utils/test-instance.mjs +242 -0
  434. package/dist/types/adapter.d.mts +2 -0
  435. package/dist/types/api.d.mts +28 -0
  436. package/dist/types/auth.d.mts +32 -0
  437. package/dist/types/helper.d.mts +26 -0
  438. package/dist/types/index.d.mts +10 -0
  439. package/dist/types/index.mjs +1 -0
  440. package/dist/types/models.d.mts +10 -0
  441. package/dist/types/plugins.d.mts +19 -0
  442. package/dist/utils/boolean.mjs +6 -0
  443. package/dist/utils/constants.mjs +4 -0
  444. package/dist/utils/date.mjs +6 -0
  445. package/dist/utils/hashing.mjs +18 -0
  446. package/dist/utils/hide-metadata.d.mts +6 -0
  447. package/dist/utils/hide-metadata.mjs +4 -0
  448. package/dist/utils/index.d.mts +4 -0
  449. package/dist/utils/is-api-error.d.mts +2 -0
  450. package/dist/utils/is-api-error.mjs +2 -0
  451. package/dist/utils/is-atom.mjs +6 -0
  452. package/dist/utils/is-promise.mjs +6 -0
  453. package/dist/utils/middleware-response.mjs +7 -0
  454. package/dist/utils/password.mjs +32 -0
  455. package/dist/utils/plugin-helper.mjs +14 -0
  456. package/dist/utils/request.mjs +23 -0
  457. package/dist/utils/shim.mjs +22 -0
  458. package/dist/utils/time.d.mts +48 -0
  459. package/dist/utils/time.mjs +98 -0
  460. package/dist/utils/url.d.mts +78 -0
  461. package/dist/utils/url.mjs +238 -0
  462. package/dist/utils/validate-user-info.mjs +44 -0
  463. package/dist/utils/wildcard.mjs +106 -0
  464. package/dist/version.mjs +5 -0
  465. package/package.json +595 -3
@@ -0,0 +1,951 @@
1
+ import { getSessionDefaultFields, parseSessionOutput, parseUserOutput } from "./schema.mjs";
2
+ import { getDate } from "../utils/date.mjs";
3
+ import { assertValidUserInfo, assertValidUserInfoSource } from "../utils/validate-user-info.mjs";
4
+ import { getStorageOption, processIdentifier } from "./verification-token-storage.mjs";
5
+ import { getWithHooks } from "./with-hooks.mjs";
6
+ import { getCurrentAdapter, getCurrentAuthEndpointContext, queueAfterTransactionHook, runWithTransaction, tryGetCurrentAuthEndpointContext } from "@better-auth/core/context";
7
+ import { APIError, BetterAuthError } from "@better-auth/core/error";
8
+ import { generateId } from "@better-auth/core/utils/id";
9
+ import { safeJSONParse } from "@better-auth/core/utils/json";
10
+ import { getIP } from "@better-auth/core/utils/ip";
11
+ import { base64Url } from "@better-auth/utils/base64";
12
+ import { createHash } from "@better-auth/utils/hash";
13
+ //#region src/db/internal-adapter.ts
14
+ function getTTLSeconds(expiresAt, now = Date.now()) {
15
+ const expiresMs = typeof expiresAt === "number" ? expiresAt : expiresAt.getTime();
16
+ return Math.max(Math.floor((expiresMs - now) / 1e3), 0);
17
+ }
18
+ const createInternalAdapter = (adapter, ctx) => {
19
+ const logger = ctx.logger;
20
+ const options = ctx.options;
21
+ const secondaryStorage = options.secondaryStorage;
22
+ const verificationConsumeLocks = /* @__PURE__ */ new Map();
23
+ const sessionExpiration = options.session?.expiresIn || 3600 * 24 * 7;
24
+ const { createWithHooks, updateWithHooks, updateManyWithHooks, deleteWithHooks, deleteManyWithHooks, consumeOneWithHooks } = getWithHooks(adapter, ctx);
25
+ /**
26
+ * Ends the live session rows matched by `where` without physically deleting
27
+ * them.
28
+ *
29
+ * Used for `secondaryStorage` + `preserveSessionInDatabase`, where the row is
30
+ * kept for audit. The session-delete hooks still run (so OAuth token
31
+ * revocation and back-channel logout fire on session end), and the preserved
32
+ * row's `expiresAt` is set to now so every liveness check that keys off the
33
+ * session row (introspection, `/userinfo`) treats it as ended.
34
+ *
35
+ * Matching is restricted to still-live rows. The preserved row outlives the
36
+ * session, so without this a later delete call (a repeated `deleteSession`,
37
+ * or `deleteUserSessions` sweeping a user's accumulated preserved rows) would
38
+ * re-match it and re-fire the hooks, re-dispatching back-channel logout.
39
+ */
40
+ const endPreservedSessions = (where) => {
41
+ const liveSessions = [...where, {
42
+ field: "expiresAt",
43
+ value: /* @__PURE__ */ new Date(),
44
+ operator: "gt"
45
+ }];
46
+ return deleteManyWithHooks(liveSessions, "session", {
47
+ fn: async () => {
48
+ await (await getCurrentAdapter(adapter)).updateMany({
49
+ model: "session",
50
+ where: liveSessions,
51
+ update: { expiresAt: /* @__PURE__ */ new Date() }
52
+ });
53
+ },
54
+ executeMainFn: false
55
+ });
56
+ };
57
+ async function refreshUserSessions(user) {
58
+ if (!secondaryStorage) return;
59
+ const listRaw = await secondaryStorage.get(`active-sessions-${user.id}`);
60
+ if (!listRaw) return;
61
+ const now = Date.now();
62
+ const validSessions = (safeJSONParse(listRaw) || []).filter((s) => s.expiresAt > now);
63
+ await Promise.all(validSessions.map(async ({ token }) => {
64
+ const cached = await secondaryStorage.get(token);
65
+ if (!cached) return;
66
+ const parsed = safeJSONParse(cached);
67
+ if (!parsed) return;
68
+ const sessionTTL = getTTLSeconds(parsed.session.expiresAt, now);
69
+ await secondaryStorage.set(token, JSON.stringify({
70
+ session: parsed.session,
71
+ user
72
+ }), Math.floor(sessionTTL));
73
+ }));
74
+ }
75
+ async function getActiveSessionReferences(userId) {
76
+ if (!secondaryStorage) return [];
77
+ const activeSessions = await secondaryStorage.get(`active-sessions-${userId}`);
78
+ return activeSessions ? safeJSONParse(activeSessions) || [] : [];
79
+ }
80
+ async function deleteCachedUserSessions(userId, sessionReferences) {
81
+ if (!secondaryStorage) return;
82
+ const deletedTokens = new Set(sessionReferences.map((session) => session.token));
83
+ for (const { token } of sessionReferences) await secondaryStorage.delete(token);
84
+ const activeSessionsKey = `active-sessions-${userId}`;
85
+ const currentSessionReferences = await getActiveSessionReferences(userId);
86
+ const now = Date.now();
87
+ const remainingSessionReferences = currentSessionReferences.filter((session) => session.expiresAt > now && !deletedTokens.has(session.token));
88
+ remainingSessionReferences.sort((a, b) => a.expiresAt - b.expiresAt);
89
+ const furthestExpiration = remainingSessionReferences.at(-1)?.expiresAt;
90
+ if (furthestExpiration) {
91
+ await secondaryStorage.set(activeSessionsKey, JSON.stringify(remainingSessionReferences), getTTLSeconds(furthestExpiration, now));
92
+ return;
93
+ }
94
+ await secondaryStorage.delete(activeSessionsKey);
95
+ }
96
+ async function queueCachedUserSessionDeletion(userId, sessionReferences) {
97
+ if (!secondaryStorage) return;
98
+ const references = sessionReferences ?? await getActiveSessionReferences(userId);
99
+ await queueAfterTransactionHook(() => deleteCachedUserSessions(userId, references), { onError(error) {
100
+ logger.error("Failed to delete committed user sessions from secondary storage", error);
101
+ } });
102
+ }
103
+ async function withVerificationConsumeLock(key, fn) {
104
+ const previous = verificationConsumeLocks.get(key) ?? Promise.resolve();
105
+ let release;
106
+ const current = new Promise((resolve) => {
107
+ release = resolve;
108
+ });
109
+ const next = previous.catch(() => {}).then(() => current);
110
+ verificationConsumeLocks.set(key, next);
111
+ await previous.catch(() => {});
112
+ try {
113
+ return await fn();
114
+ } finally {
115
+ release();
116
+ if (verificationConsumeLocks.get(key) === next) verificationConsumeLocks.delete(key);
117
+ }
118
+ }
119
+ return {
120
+ createOAuthUser: async (user, account) => {
121
+ return runWithTransaction(adapter, async () => {
122
+ const createdUser = await createWithHooks({
123
+ createdAt: /* @__PURE__ */ new Date(),
124
+ updatedAt: /* @__PURE__ */ new Date(),
125
+ ...user,
126
+ email: user.email?.toLowerCase()
127
+ }, "user", void 0);
128
+ if (!createdUser) throw new APIError("BAD_REQUEST", { message: "Failed to create user" });
129
+ return {
130
+ user: createdUser,
131
+ account: await createWithHooks({
132
+ ...account,
133
+ userId: createdUser.id,
134
+ createdAt: /* @__PURE__ */ new Date(),
135
+ updatedAt: /* @__PURE__ */ new Date()
136
+ }, "account", void 0)
137
+ };
138
+ });
139
+ },
140
+ createUser: async (user, source) => {
141
+ const data = {
142
+ createdAt: /* @__PURE__ */ new Date(),
143
+ updatedAt: /* @__PURE__ */ new Date(),
144
+ ...user,
145
+ email: user.email?.toLowerCase()
146
+ };
147
+ if (options.user?.validateUserInfo) {
148
+ const validationSource = {
149
+ ...source,
150
+ action: "create-user"
151
+ };
152
+ assertValidUserInfoSource(validationSource);
153
+ let endpointContext;
154
+ try {
155
+ endpointContext = getCurrentAuthEndpointContext();
156
+ } catch (error) {
157
+ logger.error("Unable to run validateUserInfo: missing endpoint context", error);
158
+ throw new APIError("FORBIDDEN", {
159
+ code: "validation_context_missing",
160
+ message: "User validation requires an endpoint context"
161
+ });
162
+ }
163
+ await assertValidUserInfo(endpointContext, {
164
+ user: data,
165
+ source: validationSource
166
+ });
167
+ }
168
+ return await createWithHooks(data, "user", void 0);
169
+ },
170
+ createAccount: async (account) => {
171
+ return await createWithHooks({
172
+ createdAt: /* @__PURE__ */ new Date(),
173
+ updatedAt: /* @__PURE__ */ new Date(),
174
+ ...account
175
+ }, "account", void 0);
176
+ },
177
+ listSessions: async (userId, options) => {
178
+ if (secondaryStorage) {
179
+ const currentList = await secondaryStorage.get(`active-sessions-${userId}`);
180
+ if (!currentList) return [];
181
+ const list = safeJSONParse(currentList) || [];
182
+ const now = Date.now();
183
+ const seenTokens = /* @__PURE__ */ new Set();
184
+ const sessions = [];
185
+ for (const { token, expiresAt } of list) {
186
+ if (expiresAt <= now || seenTokens.has(token)) continue;
187
+ seenTokens.add(token);
188
+ const data = await secondaryStorage.get(token);
189
+ if (!data) continue;
190
+ try {
191
+ const parsed = typeof data === "string" ? JSON.parse(data) : data;
192
+ if (!parsed?.session) continue;
193
+ sessions.push(parseSessionOutput(ctx.options, {
194
+ ...parsed.session,
195
+ expiresAt: new Date(parsed.session.expiresAt)
196
+ }));
197
+ } catch {
198
+ continue;
199
+ }
200
+ }
201
+ return sessions;
202
+ }
203
+ return await (await getCurrentAdapter(adapter)).findMany({
204
+ model: "session",
205
+ where: [{
206
+ field: "userId",
207
+ value: userId
208
+ }, ...options?.onlyActiveSessions ? [{
209
+ field: "expiresAt",
210
+ value: /* @__PURE__ */ new Date(),
211
+ operator: "gt"
212
+ }] : []]
213
+ });
214
+ },
215
+ listUsers: async (limit, offset, sortBy, where) => {
216
+ return await (await getCurrentAdapter(adapter)).findMany({
217
+ model: "user",
218
+ limit,
219
+ offset,
220
+ sortBy,
221
+ where
222
+ });
223
+ },
224
+ countTotalUsers: async (where) => {
225
+ const total = await (await getCurrentAdapter(adapter)).count({
226
+ model: "user",
227
+ where
228
+ });
229
+ if (typeof total === "string") return parseInt(total);
230
+ return total;
231
+ },
232
+ deleteUser: async (userId) => {
233
+ const sessionReferences = await getActiveSessionReferences(userId);
234
+ if (!secondaryStorage || options.session?.storeSessionInDatabase) await deleteManyWithHooks([{
235
+ field: "userId",
236
+ value: userId
237
+ }], "session", void 0);
238
+ await deleteManyWithHooks([{
239
+ field: "userId",
240
+ value: userId
241
+ }], "account", void 0);
242
+ if (await deleteWithHooks([{
243
+ field: "id",
244
+ value: userId
245
+ }], "user", void 0) !== null) await queueCachedUserSessionDeletion(userId, sessionReferences);
246
+ },
247
+ createSession: async (userId, dontRememberMe, override, overrideAll, storageOptions) => {
248
+ const headers = await (async () => {
249
+ const ctx = tryGetCurrentAuthEndpointContext();
250
+ return ctx?.headers || ctx?.request?.headers;
251
+ })();
252
+ const storeInDb = options.session?.storeSessionInDatabase;
253
+ const databaseSessionFallbackEnabled = storeInDb === true && options.session?.preserveSessionInDatabase !== true;
254
+ const { id: _, ...rest } = override || {};
255
+ let sessionId;
256
+ if (secondaryStorage && !storeInDb) {
257
+ const generatedId = ctx.generateId({ model: "session" });
258
+ sessionId = generatedId !== false ? generatedId : generateId();
259
+ }
260
+ const defaultAdditionalFields = getSessionDefaultFields(options);
261
+ const data = {
262
+ ...sessionId ? { id: sessionId } : {},
263
+ ipAddress: headers ? getIP(headers, options) || "" : "",
264
+ userAgent: headers?.get("user-agent") || "",
265
+ ...rest,
266
+ /**
267
+ * If the user doesn't want to be remembered
268
+ * set the session to expire in 1 day.
269
+ * The cookie will be set to expire at the end of the session
270
+ */
271
+ expiresAt: dontRememberMe ? getDate(3600 * 24, "sec") : getDate(sessionExpiration, "sec"),
272
+ userId,
273
+ token: generateId(32),
274
+ createdAt: /* @__PURE__ */ new Date(),
275
+ updatedAt: /* @__PURE__ */ new Date(),
276
+ ...defaultAdditionalFields,
277
+ ...overrideAll ? rest : {}
278
+ };
279
+ const mirrorSessionToSecondaryStorage = async (sessionData) => {
280
+ if (!secondaryStorage) return sessionData;
281
+ const currentList = await secondaryStorage.get(`active-sessions-${userId}`);
282
+ let list = [];
283
+ const now = Date.now();
284
+ if (currentList) {
285
+ list = safeJSONParse(currentList) || [];
286
+ list = list.filter((session) => session.expiresAt > now && session.token !== data.token);
287
+ }
288
+ const sorted = [...list, {
289
+ token: data.token,
290
+ expiresAt: data.expiresAt.getTime()
291
+ }].sort((a, b) => a.expiresAt - b.expiresAt);
292
+ const furthestSessionTTL = getTTLSeconds(sorted.at(-1)?.expiresAt ?? data.expiresAt.getTime(), now);
293
+ if (furthestSessionTTL > 0) await secondaryStorage.set(`active-sessions-${userId}`, JSON.stringify(sorted), furthestSessionTTL);
294
+ const user = await (await getCurrentAdapter(adapter)).findOne({
295
+ model: "user",
296
+ where: [{
297
+ field: "id",
298
+ value: userId
299
+ }]
300
+ });
301
+ const sessionTTL = getTTLSeconds(data.expiresAt, now);
302
+ if (sessionTTL > 0) await secondaryStorage.set(data.token, JSON.stringify({
303
+ session: sessionData,
304
+ user
305
+ }), sessionTTL);
306
+ return sessionData;
307
+ };
308
+ const res = await createWithHooks(data, "session", secondaryStorage ? {
309
+ fn: async (sessionData) => {
310
+ return storageOptions?.deferSecondaryStorageWrites ? sessionData : mirrorSessionToSecondaryStorage(sessionData);
311
+ },
312
+ executeMainFn: storeInDb
313
+ } : void 0);
314
+ if (secondaryStorage && storageOptions?.deferSecondaryStorageWrites && res) await queueAfterTransactionHook(async () => {
315
+ await mirrorSessionToSecondaryStorage(res);
316
+ }, databaseSessionFallbackEnabled ? { onError(error) {
317
+ logger.error("Failed to mirror committed session to secondary storage", error);
318
+ } } : void 0);
319
+ return res;
320
+ },
321
+ findSession: async (token) => {
322
+ if (secondaryStorage) {
323
+ const sessionStringified = await secondaryStorage.get(token);
324
+ if (!sessionStringified && (!options.session?.storeSessionInDatabase || ctx.options.session?.preserveSessionInDatabase)) return null;
325
+ if (sessionStringified) {
326
+ const s = safeJSONParse(sessionStringified);
327
+ if (!s) return null;
328
+ return {
329
+ session: parseSessionOutput(ctx.options, {
330
+ ...s.session,
331
+ expiresAt: new Date(s.session.expiresAt),
332
+ createdAt: new Date(s.session.createdAt),
333
+ updatedAt: new Date(s.session.updatedAt)
334
+ }),
335
+ user: parseUserOutput(ctx.options, {
336
+ ...s.user,
337
+ createdAt: new Date(s.user.createdAt),
338
+ updatedAt: new Date(s.user.updatedAt)
339
+ })
340
+ };
341
+ }
342
+ }
343
+ const result = await (await getCurrentAdapter(adapter)).findOne({
344
+ model: "session",
345
+ where: [{
346
+ value: token,
347
+ field: "token"
348
+ }],
349
+ join: { user: true }
350
+ });
351
+ if (!result) return null;
352
+ const { user, ...session } = result;
353
+ if (!user) return null;
354
+ return {
355
+ session: parseSessionOutput(ctx.options, session),
356
+ user: parseUserOutput(ctx.options, user)
357
+ };
358
+ },
359
+ findSessions: async (sessionTokens, options) => {
360
+ if (secondaryStorage) {
361
+ const sessions = [];
362
+ for (const sessionToken of sessionTokens) {
363
+ const sessionStringified = await secondaryStorage.get(sessionToken);
364
+ if (sessionStringified) try {
365
+ const s = typeof sessionStringified === "string" ? JSON.parse(sessionStringified) : sessionStringified;
366
+ if (!s) continue;
367
+ const expiresAt = new Date(s.session.expiresAt);
368
+ if (options?.onlyActiveSessions && expiresAt <= /* @__PURE__ */ new Date()) continue;
369
+ const session = {
370
+ session: {
371
+ ...s.session,
372
+ expiresAt: new Date(s.session.expiresAt)
373
+ },
374
+ user: {
375
+ ...s.user,
376
+ createdAt: new Date(s.user.createdAt),
377
+ updatedAt: new Date(s.user.updatedAt)
378
+ }
379
+ };
380
+ sessions.push(session);
381
+ } catch {
382
+ continue;
383
+ }
384
+ }
385
+ return sessions;
386
+ }
387
+ const sessions = await (await getCurrentAdapter(adapter)).findMany({
388
+ model: "session",
389
+ where: [{
390
+ field: "token",
391
+ value: sessionTokens,
392
+ operator: "in"
393
+ }, ...options?.onlyActiveSessions ? [{
394
+ field: "expiresAt",
395
+ value: /* @__PURE__ */ new Date(),
396
+ operator: "gt"
397
+ }] : []],
398
+ join: { user: true }
399
+ });
400
+ if (!sessions.length) return [];
401
+ if (sessions.some((session) => !session.user)) return [];
402
+ return sessions.map((_session) => {
403
+ const { user, ...session } = _session;
404
+ return {
405
+ session,
406
+ user
407
+ };
408
+ });
409
+ },
410
+ updateSession: async (sessionToken, session) => {
411
+ return await updateWithHooks(session, [{
412
+ field: "token",
413
+ value: sessionToken
414
+ }], "session", secondaryStorage ? {
415
+ async fn(data) {
416
+ const currentSession = await secondaryStorage.get(sessionToken);
417
+ if (!currentSession) return null;
418
+ const parsedSession = safeJSONParse(currentSession);
419
+ if (!parsedSession) return null;
420
+ const mergedSession = {
421
+ ...parsedSession.session,
422
+ ...data,
423
+ expiresAt: new Date(data.expiresAt ?? parsedSession.session.expiresAt),
424
+ createdAt: new Date(parsedSession.session.createdAt),
425
+ updatedAt: new Date(data.updatedAt ?? parsedSession.session.updatedAt)
426
+ };
427
+ const updatedSession = parseSessionOutput(ctx.options, mergedSession);
428
+ const now = Date.now();
429
+ const expiresMs = new Date(updatedSession.expiresAt).getTime();
430
+ const sessionTTL = getTTLSeconds(expiresMs, now);
431
+ if (sessionTTL > 0) {
432
+ await secondaryStorage.set(sessionToken, JSON.stringify({
433
+ session: updatedSession,
434
+ user: parsedSession.user
435
+ }), sessionTTL);
436
+ const listKey = `active-sessions-${updatedSession.userId}`;
437
+ const listRaw = await secondaryStorage.get(listKey);
438
+ const sorted = (listRaw ? safeJSONParse(listRaw) || [] : []).filter((s) => s.token !== sessionToken && s.expiresAt > now).concat([{
439
+ token: sessionToken,
440
+ expiresAt: expiresMs
441
+ }]).sort((a, b) => a.expiresAt - b.expiresAt);
442
+ const furthestSessionExp = sorted.at(-1)?.expiresAt;
443
+ if (furthestSessionExp && furthestSessionExp > now) await secondaryStorage.set(listKey, JSON.stringify(sorted), getTTLSeconds(furthestSessionExp, now));
444
+ else await secondaryStorage.delete(listKey);
445
+ }
446
+ return updatedSession;
447
+ },
448
+ executeMainFn: options.session?.storeSessionInDatabase
449
+ } : void 0);
450
+ },
451
+ deleteSession: async (token) => {
452
+ if (secondaryStorage) {
453
+ const data = await secondaryStorage.get(token);
454
+ if (data) {
455
+ const { session } = safeJSONParse(data) ?? {};
456
+ if (!session) {
457
+ logger.error("Session not found in secondary storage");
458
+ return;
459
+ }
460
+ const userId = session.userId;
461
+ const currentList = await secondaryStorage.get(`active-sessions-${userId}`);
462
+ if (currentList) {
463
+ const list = safeJSONParse(currentList) || [];
464
+ const now = Date.now();
465
+ const filtered = list.filter((session) => session.expiresAt > now && session.token !== token);
466
+ const furthestSessionExp = filtered.sort((a, b) => a.expiresAt - b.expiresAt).at(-1)?.expiresAt;
467
+ if (filtered.length > 0 && furthestSessionExp && furthestSessionExp > Date.now()) await secondaryStorage.set(`active-sessions-${userId}`, JSON.stringify(filtered), getTTLSeconds(furthestSessionExp, now));
468
+ else await secondaryStorage.delete(`active-sessions-${userId}`);
469
+ } else logger.error("Active sessions list not found in secondary storage");
470
+ }
471
+ await secondaryStorage.delete(token);
472
+ if (!options.session?.storeSessionInDatabase) return;
473
+ if (ctx.options.session?.preserveSessionInDatabase) {
474
+ await endPreservedSessions([{
475
+ field: "token",
476
+ value: token
477
+ }]);
478
+ return;
479
+ }
480
+ }
481
+ await deleteWithHooks([{
482
+ field: "token",
483
+ value: token
484
+ }], "session", void 0);
485
+ },
486
+ deleteAccounts: async (userId) => {
487
+ await deleteManyWithHooks([{
488
+ field: "userId",
489
+ value: userId
490
+ }], "account", void 0);
491
+ },
492
+ /**
493
+ * Delete an account by its primary key.
494
+ *
495
+ * @param id - The account row's primary key, not its accountId.
496
+ */
497
+ deleteAccount: async (id) => {
498
+ await deleteWithHooks([{
499
+ field: "id",
500
+ value: id
501
+ }], "account", void 0);
502
+ },
503
+ deleteUserSessions: async (userId) => {
504
+ const sessionReferences = await getActiveSessionReferences(userId);
505
+ if (secondaryStorage) {
506
+ if (!options.session?.storeSessionInDatabase) {
507
+ await queueCachedUserSessionDeletion(userId, sessionReferences);
508
+ return;
509
+ }
510
+ if (ctx.options.session?.preserveSessionInDatabase) {
511
+ if (await endPreservedSessions([{
512
+ field: "userId",
513
+ value: userId
514
+ }]) !== null) await queueCachedUserSessionDeletion(userId, sessionReferences);
515
+ return;
516
+ }
517
+ }
518
+ if (await deleteManyWithHooks([{
519
+ field: "userId",
520
+ value: userId
521
+ }], "session", void 0) !== null) await queueCachedUserSessionDeletion(userId, sessionReferences);
522
+ },
523
+ deleteSessions: async (sessionTokens) => {
524
+ if (secondaryStorage) {
525
+ await Promise.all(sessionTokens.map((token) => secondaryStorage.delete(token)));
526
+ if (!options.session?.storeSessionInDatabase) return;
527
+ if (ctx.options.session?.preserveSessionInDatabase) {
528
+ await endPreservedSessions([{
529
+ field: "token",
530
+ value: sessionTokens,
531
+ operator: "in"
532
+ }]);
533
+ return;
534
+ }
535
+ }
536
+ await deleteManyWithHooks([{
537
+ field: "token",
538
+ value: sessionTokens,
539
+ operator: "in"
540
+ }], "session", void 0);
541
+ },
542
+ findAccountOwnerByKey: async ({ providerId, accountId }) => {
543
+ const accountsWithUsers = await (await getCurrentAdapter(adapter)).findMany({
544
+ model: "account",
545
+ where: [{
546
+ field: "providerId",
547
+ value: providerId
548
+ }, {
549
+ field: "accountId",
550
+ value: accountId
551
+ }],
552
+ limit: 2,
553
+ join: { user: true }
554
+ });
555
+ if (accountsWithUsers.length > 1) throw new BetterAuthError(`Multiple accounts match the same accountId for provider ${JSON.stringify(providerId)}. Resolve duplicate account identities before continuing.`);
556
+ const accountWithUser = accountsWithUsers[0];
557
+ if (!accountWithUser) return null;
558
+ const { user, ...account } = accountWithUser;
559
+ return user ? {
560
+ kind: "owned",
561
+ user,
562
+ account
563
+ } : {
564
+ kind: "orphaned",
565
+ account
566
+ };
567
+ },
568
+ findUserByEmail: async (email, options) => {
569
+ const result = await (await getCurrentAdapter(adapter)).findOne({
570
+ model: "user",
571
+ where: [{
572
+ value: email.toLowerCase(),
573
+ field: "email"
574
+ }],
575
+ join: { ...options?.includeAccounts ? { account: true } : {} }
576
+ });
577
+ if (!result) return null;
578
+ const { account: accounts, ...user } = result;
579
+ return {
580
+ user,
581
+ accounts: accounts ?? []
582
+ };
583
+ },
584
+ findUserById: async (userId) => {
585
+ if (!userId) return null;
586
+ return await (await getCurrentAdapter(adapter)).findOne({
587
+ model: "user",
588
+ where: [{
589
+ field: "id",
590
+ value: userId
591
+ }]
592
+ });
593
+ },
594
+ linkAccount: async (account) => {
595
+ return await createWithHooks({
596
+ createdAt: /* @__PURE__ */ new Date(),
597
+ updatedAt: /* @__PURE__ */ new Date(),
598
+ ...account
599
+ }, "account", void 0);
600
+ },
601
+ updateUser: async (userId, data) => {
602
+ const user = await updateWithHooks({
603
+ ...data,
604
+ ...data.email ? { email: data.email.toLowerCase() } : {}
605
+ }, [{
606
+ field: "id",
607
+ value: userId
608
+ }], "user", void 0);
609
+ await queueAfterTransactionHook(() => refreshUserSessions(user), { onError(error) {
610
+ logger.error("Failed to refresh committed user sessions in secondary storage", error);
611
+ } });
612
+ return user;
613
+ },
614
+ updateUserByEmail: async (email, data) => {
615
+ const user = await updateWithHooks({
616
+ ...data,
617
+ ...data.email ? { email: data.email.toLowerCase() } : {}
618
+ }, [{
619
+ field: "email",
620
+ value: email.toLowerCase()
621
+ }], "user", void 0);
622
+ await queueAfterTransactionHook(() => refreshUserSessions(user), { onError(error) {
623
+ logger.error("Failed to refresh committed user sessions in secondary storage", error);
624
+ } });
625
+ return user;
626
+ },
627
+ updatePassword: async (userId, password) => {
628
+ await updateManyWithHooks({ password }, [
629
+ {
630
+ field: "userId",
631
+ value: userId
632
+ },
633
+ {
634
+ field: "providerId",
635
+ value: "credential"
636
+ },
637
+ {
638
+ field: "accountId",
639
+ value: userId
640
+ }
641
+ ], "account", void 0);
642
+ },
643
+ findAccounts: async (userId) => {
644
+ return await (await getCurrentAdapter(adapter)).findMany({
645
+ model: "account",
646
+ where: [{
647
+ field: "userId",
648
+ value: userId
649
+ }]
650
+ });
651
+ },
652
+ findCredentialAccount: async (userId) => {
653
+ return (await getCurrentAdapter(adapter)).findOne({
654
+ model: "account",
655
+ where: [
656
+ {
657
+ field: "userId",
658
+ value: userId
659
+ },
660
+ {
661
+ field: "providerId",
662
+ value: "credential"
663
+ },
664
+ {
665
+ field: "accountId",
666
+ value: userId
667
+ }
668
+ ]
669
+ });
670
+ },
671
+ findAccountByKey: async ({ providerId, accountId }) => {
672
+ const accounts = await (await getCurrentAdapter(adapter)).findMany({
673
+ model: "account",
674
+ limit: 2,
675
+ where: [{
676
+ field: "providerId",
677
+ value: providerId
678
+ }, {
679
+ field: "accountId",
680
+ value: accountId
681
+ }]
682
+ });
683
+ if (accounts.length > 1) throw new BetterAuthError(`Multiple accounts match the same accountId for provider ${JSON.stringify(providerId)}. Resolve duplicate account identities before continuing.`);
684
+ return accounts[0] ?? null;
685
+ },
686
+ findAccountByUserId: async (userId) => {
687
+ return await (await getCurrentAdapter(adapter)).findMany({
688
+ model: "account",
689
+ where: [{
690
+ field: "userId",
691
+ value: userId
692
+ }]
693
+ });
694
+ },
695
+ updateAccount: async (id, data) => {
696
+ return await updateWithHooks(data, [{
697
+ field: "id",
698
+ value: id
699
+ }], "account", void 0);
700
+ },
701
+ createVerificationValue: async (data) => {
702
+ const storageOption = getStorageOption(data.identifier, options.verification?.storeIdentifier);
703
+ const storedIdentifier = await processIdentifier(data.identifier, storageOption);
704
+ return await createWithHooks({
705
+ createdAt: /* @__PURE__ */ new Date(),
706
+ updatedAt: /* @__PURE__ */ new Date(),
707
+ ...data,
708
+ identifier: storedIdentifier
709
+ }, "verification", secondaryStorage ? {
710
+ async fn(verificationData) {
711
+ const ttl = getTTLSeconds(verificationData.expiresAt);
712
+ if (ttl > 0) await secondaryStorage.set(`verification:${storedIdentifier}`, JSON.stringify(verificationData), ttl);
713
+ return verificationData;
714
+ },
715
+ executeMainFn: options.verification?.storeInDatabase
716
+ } : void 0);
717
+ },
718
+ findVerificationValue: async (identifier) => {
719
+ const storageOption = getStorageOption(identifier, options.verification?.storeIdentifier);
720
+ const storedIdentifier = await processIdentifier(identifier, storageOption);
721
+ if (secondaryStorage) {
722
+ const cached = await secondaryStorage.get(`verification:${storedIdentifier}`);
723
+ if (cached) {
724
+ const parsed = safeJSONParse(cached);
725
+ if (parsed) return parsed;
726
+ }
727
+ if (storageOption && storageOption !== "plain") {
728
+ const plainCached = await secondaryStorage.get(`verification:${identifier}`);
729
+ if (plainCached) {
730
+ const parsed = safeJSONParse(plainCached);
731
+ if (parsed) return parsed;
732
+ }
733
+ }
734
+ if (!options.verification?.storeInDatabase) return null;
735
+ }
736
+ const currentAdapter = await getCurrentAdapter(adapter);
737
+ async function findByIdentifier(id) {
738
+ return currentAdapter.findMany({
739
+ model: "verification",
740
+ where: [{
741
+ field: "identifier",
742
+ value: id
743
+ }],
744
+ sortBy: {
745
+ field: "createdAt",
746
+ direction: "desc"
747
+ },
748
+ limit: 1
749
+ });
750
+ }
751
+ let verification = await findByIdentifier(storedIdentifier);
752
+ if (!verification.length && storageOption && storageOption !== "plain") verification = await findByIdentifier(identifier);
753
+ if (!options.verification?.disableCleanup) await deleteManyWithHooks([{
754
+ field: "expiresAt",
755
+ value: /* @__PURE__ */ new Date(),
756
+ operator: "lt"
757
+ }], "verification", void 0);
758
+ return verification[0] || null;
759
+ },
760
+ deleteVerificationByIdentifier: async (identifier) => {
761
+ const storedIdentifier = await processIdentifier(identifier, getStorageOption(identifier, options.verification?.storeIdentifier));
762
+ if (secondaryStorage) await secondaryStorage.delete(`verification:${storedIdentifier}`);
763
+ if (!secondaryStorage || options.verification?.storeInDatabase) await deleteWithHooks([{
764
+ field: "identifier",
765
+ value: storedIdentifier
766
+ }], "verification", void 0);
767
+ },
768
+ /**
769
+ * Atomically consume a single-use verification row by `identifier` and
770
+ * return it. The first concurrent caller receives the latest row for the
771
+ * identifier; every other caller racing against it receives `null`.
772
+ *
773
+ * Race-safe replacement for the `findVerificationValue` then
774
+ * `deleteVerificationByIdentifier` pair. Callers MUST gate any state
775
+ * change (issue session, mint token, change password) on a non-null
776
+ * return value, because consuming one row invalidates the whole
777
+ * identifier and stale rows cannot be replayed.
778
+ *
779
+ * Rows past their `expiresAt` are treated as already invalid: the row
780
+ * is still deleted (so it cannot be replayed later) but `null` is
781
+ * returned. Callers do not need their own `expiresAt` gate.
782
+ *
783
+ * The secondary-storage-only path (`storeInDatabase: false`) consumes
784
+ * through `getAndDelete`, which is required on `SecondaryStorage` so
785
+ * single-use values are not read and deleted as separate operations.
786
+ */
787
+ consumeVerificationValue: async (identifier) => {
788
+ const storageOption = getStorageOption(identifier, options.verification?.storeIdentifier);
789
+ const storedIdentifier = await processIdentifier(identifier, storageOption);
790
+ const identifiersToTry = storageOption && storageOption !== "plain" ? [storedIdentifier, identifier] : [storedIdentifier];
791
+ const hydrateCachedVerification = (raw) => {
792
+ if (!raw) return null;
793
+ const candidate = typeof raw === "string" ? safeJSONParse(raw) : typeof raw === "object" ? raw : null;
794
+ if (!candidate) return null;
795
+ const expiresAt = new Date(candidate.expiresAt);
796
+ if (!Number.isFinite(expiresAt.getTime())) return null;
797
+ return {
798
+ ...candidate,
799
+ expiresAt
800
+ };
801
+ };
802
+ let consumed = null;
803
+ if (secondaryStorage && !options.verification?.storeInDatabase) {
804
+ const consumeCacheKey = async (key) => {
805
+ return hydrateCachedVerification(await secondaryStorage.getAndDelete(key));
806
+ };
807
+ for (const stored of identifiersToTry) {
808
+ const cached = await consumeCacheKey(`verification:${stored}`);
809
+ if (!cached) continue;
810
+ await Promise.all(identifiersToTry.filter((candidate) => candidate !== stored).map((candidate) => secondaryStorage.delete(`verification:${candidate}`)));
811
+ consumed = cached;
812
+ break;
813
+ }
814
+ } else {
815
+ const consumeByIdentifier = async (id) => withVerificationConsumeLock(`verification:${id}`, () => runWithTransaction(adapter, async () => {
816
+ const txAdapter = await getCurrentAdapter(adapter);
817
+ const where = [{
818
+ field: "identifier",
819
+ value: id
820
+ }];
821
+ const latest = (await txAdapter.findMany({
822
+ model: "verification",
823
+ where,
824
+ sortBy: {
825
+ field: "createdAt",
826
+ direction: "desc"
827
+ },
828
+ limit: 1
829
+ }))[0] ?? null;
830
+ if (!latest) return null;
831
+ return consumeOneWithHooks("verification", [{
832
+ field: "id",
833
+ value: latest.id
834
+ }], async () => {
835
+ const row = await txAdapter.consumeOne({
836
+ model: "verification",
837
+ where: [{
838
+ field: "id",
839
+ value: latest.id
840
+ }]
841
+ });
842
+ if (!row) return null;
843
+ await txAdapter.deleteMany({
844
+ model: "verification",
845
+ where
846
+ });
847
+ return row;
848
+ }, latest);
849
+ }));
850
+ for (const stored of identifiersToTry) {
851
+ consumed = await consumeByIdentifier(stored);
852
+ if (consumed) break;
853
+ }
854
+ if (consumed && secondaryStorage) await Promise.all(identifiersToTry.map((stored) => secondaryStorage.delete(`verification:${stored}`)));
855
+ }
856
+ if (!consumed || consumed.expiresAt < /* @__PURE__ */ new Date()) return null;
857
+ return consumed;
858
+ },
859
+ /**
860
+ * First-writer-wins create keyed by a deterministic primary key derived
861
+ * from `identifier`. Returns `true` when this caller created the row and
862
+ * `false` when a row for the same identifier already existed.
863
+ *
864
+ * The dual of `consumeVerificationValue`: where consume races to delete a
865
+ * marker exactly once, reserve races to create a marker exactly once. Use
866
+ * it for replay tombstones (a SAML assertion id, a JWT `jti`) where the
867
+ * first caller wins and every later caller must observe that the marker is
868
+ * already taken.
869
+ *
870
+ * The `verification.identifier` column is non-unique, so uniqueness comes
871
+ * from a deterministic primary key (`SHA-256` of `reserve:<identifier>`).
872
+ * The database path is atomic: the primary key turns the INSERT into the
873
+ * first-writer-wins gate, and a duplicate is detected portably by
874
+ * re-reading the row rather than matching adapter-specific errors.
875
+ * Secondary-storage-only verification cannot enforce the deterministic
876
+ * primary-key gate, so this operation fails closed unless verification is
877
+ * backed by the database.
878
+ *
879
+ * The atomic guarantee requires the configured adapter to reject a
880
+ * duplicate primary key on insert, which every real database enforces. The
881
+ * in-memory adapter does not enforce primary-key uniqueness, so reservation
882
+ * is best-effort there (it is intended for development and tests).
883
+ */
884
+ reserveVerificationValue: async (data) => {
885
+ const reservationId = base64Url.encode(new Uint8Array(await createHash("SHA-256").digest(new TextEncoder().encode("reserve:" + data.identifier))), { padding: false });
886
+ const storageOption = getStorageOption(data.identifier, options.verification?.storeIdentifier);
887
+ const storedIdentifier = await processIdentifier(data.identifier, storageOption);
888
+ if (secondaryStorage && !options.verification?.storeInDatabase) throw new BetterAuthError("reserveVerificationValue requires database-backed verification storage. Set verification.storeInDatabase to true for flows that reserve verification values.");
889
+ try {
890
+ await adapter.create({
891
+ model: "verification",
892
+ data: {
893
+ id: reservationId,
894
+ identifier: storedIdentifier,
895
+ value: data.value,
896
+ expiresAt: data.expiresAt,
897
+ createdAt: /* @__PURE__ */ new Date(),
898
+ updatedAt: /* @__PURE__ */ new Date()
899
+ },
900
+ forceAllowId: true
901
+ });
902
+ } catch (error) {
903
+ if (await adapter.findOne({
904
+ model: "verification",
905
+ where: [{
906
+ field: "id",
907
+ value: reservationId
908
+ }]
909
+ })) return false;
910
+ throw error;
911
+ }
912
+ if (secondaryStorage) {
913
+ const ttl = getTTLSeconds(data.expiresAt);
914
+ if (ttl > 0) await secondaryStorage.set(`verification:${storedIdentifier}`, JSON.stringify({
915
+ id: reservationId,
916
+ identifier: storedIdentifier,
917
+ value: data.value,
918
+ expiresAt: data.expiresAt
919
+ }), ttl);
920
+ }
921
+ return true;
922
+ },
923
+ updateVerificationByIdentifier: async (identifier, data) => {
924
+ const storedIdentifier = await processIdentifier(identifier, getStorageOption(identifier, options.verification?.storeIdentifier));
925
+ if (secondaryStorage) {
926
+ const cached = await secondaryStorage.get(`verification:${storedIdentifier}`);
927
+ if (cached) {
928
+ const parsed = safeJSONParse(cached);
929
+ if (parsed) {
930
+ const updated = {
931
+ ...parsed,
932
+ ...data
933
+ };
934
+ const expiresAt = updated.expiresAt ?? parsed.expiresAt;
935
+ const ttl = getTTLSeconds(expiresAt instanceof Date ? expiresAt : new Date(expiresAt));
936
+ if (ttl > 0) await secondaryStorage.set(`verification:${storedIdentifier}`, JSON.stringify(updated), ttl);
937
+ if (!options.verification?.storeInDatabase) return updated;
938
+ }
939
+ }
940
+ }
941
+ if (!secondaryStorage || options.verification?.storeInDatabase) return await updateWithHooks(data, [{
942
+ field: "identifier",
943
+ value: storedIdentifier
944
+ }], "verification", void 0);
945
+ return data;
946
+ },
947
+ refreshUserSessions
948
+ };
949
+ };
950
+ //#endregion
951
+ export { createInternalAdapter };