better-auth 1.5.0 → 1.5.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/api/routes/password.mjs +1 -1
  2. package/dist/api/routes/password.mjs.map +1 -1
  3. package/dist/api/routes/update-user.mjs +1 -1
  4. package/dist/api/routes/update-user.mjs.map +1 -1
  5. package/dist/auth/trusted-origins.mjs +2 -25
  6. package/dist/auth/trusted-origins.mjs.map +1 -1
  7. package/dist/db/index.d.mts +1 -10
  8. package/dist/db/internal-adapter.mjs +22 -10
  9. package/dist/db/internal-adapter.mjs.map +1 -1
  10. package/dist/index.d.mts +2 -21
  11. package/dist/index.mjs +2 -2
  12. package/dist/plugins/email-otp/routes.mjs +17 -14
  13. package/dist/plugins/email-otp/routes.mjs.map +1 -1
  14. package/dist/plugins/generic-oauth/providers/auth0.mjs +7 -24
  15. package/dist/plugins/generic-oauth/providers/auth0.mjs.map +1 -1
  16. package/dist/plugins/generic-oauth/providers/keycloak.mjs +7 -24
  17. package/dist/plugins/generic-oauth/providers/keycloak.mjs.map +1 -1
  18. package/dist/plugins/generic-oauth/providers/okta.mjs +7 -24
  19. package/dist/plugins/generic-oauth/providers/okta.mjs.map +1 -1
  20. package/dist/plugins/jwt/types.d.mts +3 -4
  21. package/dist/plugins/magic-link/index.mjs +3 -3
  22. package/dist/plugins/magic-link/index.mjs.map +1 -1
  23. package/dist/plugins/mcp/index.mjs +2 -2
  24. package/dist/plugins/mcp/index.mjs.map +1 -1
  25. package/dist/plugins/oidc-provider/index.mjs +4 -4
  26. package/dist/plugins/oidc-provider/index.mjs.map +1 -1
  27. package/dist/plugins/one-time-token/index.mjs +1 -1
  28. package/dist/plugins/one-time-token/index.mjs.map +1 -1
  29. package/dist/plugins/organization/adapter.d.mts +1 -1
  30. package/dist/plugins/organization/client.d.mts +1 -1
  31. package/dist/plugins/organization/routes/crud-access-control.d.mts +1 -1
  32. package/dist/plugins/organization/routes/crud-invites.d.mts +1 -1
  33. package/dist/plugins/organization/routes/crud-members.d.mts +1 -1
  34. package/dist/plugins/organization/routes/crud-org.d.mts +1 -1
  35. package/dist/plugins/organization/routes/crud-team.d.mts +1 -1
  36. package/dist/plugins/phone-number/routes.mjs +8 -8
  37. package/dist/plugins/phone-number/routes.mjs.map +1 -1
  38. package/dist/plugins/siwe/index.mjs +1 -1
  39. package/dist/plugins/siwe/index.mjs.map +1 -1
  40. package/dist/plugins/two-factor/index.mjs +1 -1
  41. package/dist/plugins/two-factor/index.mjs.map +1 -1
  42. package/dist/plugins/two-factor/otp/index.mjs +3 -3
  43. package/dist/plugins/two-factor/otp/index.mjs.map +1 -1
  44. package/dist/plugins/two-factor/verify-two-factor.mjs +1 -1
  45. package/dist/plugins/two-factor/verify-two-factor.mjs.map +1 -1
  46. package/dist/state.mjs +1 -1
  47. package/dist/state.mjs.map +1 -1
  48. package/dist/types/models.d.mts +3 -4
  49. package/dist/utils/index.d.mts +1 -1
  50. package/dist/utils/index.mjs +1 -1
  51. package/dist/utils/url.d.mts +18 -1
  52. package/dist/utils/url.mjs +25 -2
  53. package/dist/utils/url.mjs.map +1 -1
  54. package/package.json +9 -9
@@ -157,7 +157,7 @@ const resetPassword = createAuthEndpoint("/reset-password", {
157
157
  accountId: userId
158
158
  });
159
159
  else await ctx.context.internalAdapter.updatePassword(userId, hashedPassword);
160
- await ctx.context.internalAdapter.deleteVerificationValue(verification.id);
160
+ await ctx.context.internalAdapter.deleteVerificationByIdentifier(id);
161
161
  if (ctx.context.options.emailAndPassword?.onPasswordReset) {
162
162
  const user = await ctx.context.internalAdapter.findUserById(userId);
163
163
  if (user) await ctx.context.options.emailAndPassword.onPasswordReset({ user }, ctx.request);
@@ -1 +1 @@
1
- {"version":3,"file":"password.mjs","names":[],"sources":["../../../src/api/routes/password.ts"],"sourcesContent":["import type { AuthContext } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { generateId } from \"@better-auth/core/utils/id\";\nimport * as z from \"zod\";\nimport { getDate } from \"../../utils/date\";\nimport { validatePassword } from \"../../utils/password\";\nimport { originCheck } from \"../middlewares\";\nimport { sensitiveSessionMiddleware } from \"./session\";\n\nfunction redirectError(\n\tctx: AuthContext,\n\tcallbackURL: string | undefined,\n\tquery?: Record<string, string> | undefined,\n): string {\n\tconst url = callbackURL\n\t\t? new URL(callbackURL, ctx.baseURL)\n\t\t: new URL(`${ctx.baseURL}/error`);\n\tif (query)\n\t\tObject.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));\n\treturn url.href;\n}\n\nfunction redirectCallback(\n\tctx: AuthContext,\n\tcallbackURL: string,\n\tquery?: Record<string, string> | undefined,\n): string {\n\tconst url = new URL(callbackURL, ctx.baseURL);\n\tif (query)\n\t\tObject.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));\n\treturn url.href;\n}\n\nexport const requestPasswordReset = createAuthEndpoint(\n\t\"/request-password-reset\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The email address of the user to send a password reset email to.\n\t\t\t */\n\t\t\temail: z.email().meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"The email address of the user to send a password reset email to\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The URL to redirect the user to reset their password.\n\t\t\t * If the token isn't valid or expired, it'll be redirected with a query parameter `?\n\t\t\t * error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?\n\t\t\t * token=VALID_TOKEN\n\t\t\t */\n\t\t\tredirectTo: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"requestPasswordReset\",\n\t\t\t\tdescription: \"Send a password reset email to the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.emailAndPassword?.sendResetPassword) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!\",\n\t\t\t);\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Reset password isn't enabled\",\n\t\t\t\tcode: \"RESET_PASSWORD_DISABLED\",\n\t\t\t});\n\t\t}\n\t\tconst { email, redirectTo } = ctx.body;\n\n\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email, {\n\t\t\tincludeAccounts: true,\n\t\t});\n\t\tif (!user) {\n\t\t\t/**\n\t\t\t * We simulate the verification token generation and the database lookup\n\t\t\t * to mitigate timing attacks.\n\t\t\t */\n\t\t\tgenerateId(24);\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\"dummy-verification-token\",\n\t\t\t);\n\t\t\tctx.context.logger.error(\"Reset Password: User not found\", { email });\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t\tmessage:\n\t\t\t\t\t\"If this email exists in our system, check your email for the reset link\",\n\t\t\t});\n\t\t}\n\t\tconst defaultExpiresIn = 60 * 60 * 1;\n\t\tconst expiresAt = getDate(\n\t\t\tctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn ||\n\t\t\t\tdefaultExpiresIn,\n\t\t\t\"sec\",\n\t\t);\n\t\tconst verificationToken = generateId(24);\n\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\tvalue: user.user.id,\n\t\t\tidentifier: `reset-password:${verificationToken}`,\n\t\t\texpiresAt,\n\t\t});\n\t\tconst callbackURL = redirectTo ? encodeURIComponent(redirectTo) : \"\";\n\t\tconst url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${callbackURL}`;\n\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\tctx.context.options.emailAndPassword.sendResetPassword(\n\t\t\t\t{\n\t\t\t\t\tuser: user.user,\n\t\t\t\t\turl,\n\t\t\t\t\ttoken: verificationToken,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t\tmessage:\n\t\t\t\t\"If this email exists in our system, check your email for the reset link\",\n\t\t});\n\t},\n);\n\nexport const requestPasswordResetCallback = createAuthEndpoint(\n\t\"/reset-password/:token\",\n\t{\n\t\tmethod: \"GET\",\n\t\toperationId: \"forgetPasswordCallback\",\n\t\tquery: z.object({\n\t\t\tcallbackURL: z.string().meta({\n\t\t\t\tdescription: \"The URL to redirect the user to reset their password\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"resetPasswordCallback\",\n\t\t\t\tdescription: \"Redirects the user to the callback URL with the token\",\n\t\t\t\tparameters: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"token\",\n\t\t\t\t\t\tin: \"path\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdescription: \"The token to reset the password\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"callbackURL\",\n\t\t\t\t\t\tin: \"query\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdescription: \"The URL to redirect the user to reset their password\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst { token } = ctx.params;\n\t\tconst { callbackURL } = ctx.query;\n\t\tif (!token || !callbackURL) {\n\t\t\tthrow ctx.redirect(\n\t\t\t\tredirectError(ctx.context, callbackURL, { error: \"INVALID_TOKEN\" }),\n\t\t\t);\n\t\t}\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t`reset-password:${token}`,\n\t\t\t);\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow ctx.redirect(\n\t\t\t\tredirectError(ctx.context, callbackURL, { error: \"INVALID_TOKEN\" }),\n\t\t\t);\n\t\t}\n\n\t\tthrow ctx.redirect(redirectCallback(ctx.context, callbackURL, { token }));\n\t},\n);\n\nexport const resetPassword = createAuthEndpoint(\n\t\"/reset-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\toperationId: \"resetPassword\",\n\t\tquery: z\n\t\t\t.object({\n\t\t\t\ttoken: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbody: z.object({\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set\",\n\t\t\t}),\n\t\t\ttoken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The token to reset the password\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"resetPassword\",\n\t\t\t\tdescription: \"Reset the password for a user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst token = ctx.body.token || ctx.query?.token;\n\t\tif (!token) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\n\t\tconst { newPassword } = ctx.body;\n\n\t\tconst minLength = ctx.context.password?.config.minPasswordLength;\n\t\tconst maxLength = ctx.context.password?.config.maxPasswordLength;\n\t\tif (newPassword.length < minLength) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_SHORT);\n\t\t}\n\t\tif (newPassword.length > maxLength) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_LONG);\n\t\t}\n\n\t\tconst id = `reset-password:${token}`;\n\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(id);\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\t\tconst userId = verification.value;\n\t\tconst hashedPassword = await ctx.context.password.hash(newPassword);\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(userId);\n\t\tconst account = accounts.find((ac) => ac.providerId === \"credential\");\n\t\tif (!account) {\n\t\t\tawait ctx.context.internalAdapter.createAccount({\n\t\t\t\tuserId,\n\t\t\t\tproviderId: \"credential\",\n\t\t\t\tpassword: hashedPassword,\n\t\t\t\taccountId: userId,\n\t\t\t});\n\t\t} else {\n\t\t\tawait ctx.context.internalAdapter.updatePassword(userId, hashedPassword);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteVerificationValue(verification.id);\n\n\t\tif (ctx.context.options.emailAndPassword?.onPasswordReset) {\n\t\t\tconst user = await ctx.context.internalAdapter.findUserById(userId);\n\t\t\tif (user) {\n\t\t\t\tawait ctx.context.options.emailAndPassword.onPasswordReset(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(userId);\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n\nexport const verifyPassword = createAuthEndpoint(\n\t\"/verify-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The password to verify\n\t\t\t */\n\t\t\tpassword: z.string().meta({\n\t\t\t\tdescription: \"The password to verify\",\n\t\t\t}),\n\t\t}),\n\t\tmetadata: {\n\t\t\tscope: \"server\",\n\t\t\topenapi: {\n\t\t\t\toperationId: \"verifyPassword\",\n\t\t\t\tdescription: \"Verify the current user's password\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tuse: [sensitiveSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { password } = ctx.body;\n\t\tconst session = ctx.context.session;\n\n\t\tconst isValid = await validatePassword(ctx, {\n\t\t\tpassword,\n\t\t\tuserId: session.user.id,\n\t\t});\n\n\t\tif (!isValid) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"password.mjs","names":[],"sources":["../../../src/api/routes/password.ts"],"sourcesContent":["import type { AuthContext } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { generateId } from \"@better-auth/core/utils/id\";\nimport * as z from \"zod\";\nimport { getDate } from \"../../utils/date\";\nimport { validatePassword } from \"../../utils/password\";\nimport { originCheck } from \"../middlewares\";\nimport { sensitiveSessionMiddleware } from \"./session\";\n\nfunction redirectError(\n\tctx: AuthContext,\n\tcallbackURL: string | undefined,\n\tquery?: Record<string, string> | undefined,\n): string {\n\tconst url = callbackURL\n\t\t? new URL(callbackURL, ctx.baseURL)\n\t\t: new URL(`${ctx.baseURL}/error`);\n\tif (query)\n\t\tObject.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));\n\treturn url.href;\n}\n\nfunction redirectCallback(\n\tctx: AuthContext,\n\tcallbackURL: string,\n\tquery?: Record<string, string> | undefined,\n): string {\n\tconst url = new URL(callbackURL, ctx.baseURL);\n\tif (query)\n\t\tObject.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));\n\treturn url.href;\n}\n\nexport const requestPasswordReset = createAuthEndpoint(\n\t\"/request-password-reset\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The email address of the user to send a password reset email to.\n\t\t\t */\n\t\t\temail: z.email().meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"The email address of the user to send a password reset email to\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The URL to redirect the user to reset their password.\n\t\t\t * If the token isn't valid or expired, it'll be redirected with a query parameter `?\n\t\t\t * error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?\n\t\t\t * token=VALID_TOKEN\n\t\t\t */\n\t\t\tredirectTo: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"requestPasswordReset\",\n\t\t\t\tdescription: \"Send a password reset email to the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.emailAndPassword?.sendResetPassword) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!\",\n\t\t\t);\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Reset password isn't enabled\",\n\t\t\t\tcode: \"RESET_PASSWORD_DISABLED\",\n\t\t\t});\n\t\t}\n\t\tconst { email, redirectTo } = ctx.body;\n\n\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email, {\n\t\t\tincludeAccounts: true,\n\t\t});\n\t\tif (!user) {\n\t\t\t/**\n\t\t\t * We simulate the verification token generation and the database lookup\n\t\t\t * to mitigate timing attacks.\n\t\t\t */\n\t\t\tgenerateId(24);\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\"dummy-verification-token\",\n\t\t\t);\n\t\t\tctx.context.logger.error(\"Reset Password: User not found\", { email });\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t\tmessage:\n\t\t\t\t\t\"If this email exists in our system, check your email for the reset link\",\n\t\t\t});\n\t\t}\n\t\tconst defaultExpiresIn = 60 * 60 * 1;\n\t\tconst expiresAt = getDate(\n\t\t\tctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn ||\n\t\t\t\tdefaultExpiresIn,\n\t\t\t\"sec\",\n\t\t);\n\t\tconst verificationToken = generateId(24);\n\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\tvalue: user.user.id,\n\t\t\tidentifier: `reset-password:${verificationToken}`,\n\t\t\texpiresAt,\n\t\t});\n\t\tconst callbackURL = redirectTo ? encodeURIComponent(redirectTo) : \"\";\n\t\tconst url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${callbackURL}`;\n\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\tctx.context.options.emailAndPassword.sendResetPassword(\n\t\t\t\t{\n\t\t\t\t\tuser: user.user,\n\t\t\t\t\turl,\n\t\t\t\t\ttoken: verificationToken,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t\tmessage:\n\t\t\t\t\"If this email exists in our system, check your email for the reset link\",\n\t\t});\n\t},\n);\n\nexport const requestPasswordResetCallback = createAuthEndpoint(\n\t\"/reset-password/:token\",\n\t{\n\t\tmethod: \"GET\",\n\t\toperationId: \"forgetPasswordCallback\",\n\t\tquery: z.object({\n\t\t\tcallbackURL: z.string().meta({\n\t\t\t\tdescription: \"The URL to redirect the user to reset their password\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"resetPasswordCallback\",\n\t\t\t\tdescription: \"Redirects the user to the callback URL with the token\",\n\t\t\t\tparameters: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"token\",\n\t\t\t\t\t\tin: \"path\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdescription: \"The token to reset the password\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"callbackURL\",\n\t\t\t\t\t\tin: \"query\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdescription: \"The URL to redirect the user to reset their password\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst { token } = ctx.params;\n\t\tconst { callbackURL } = ctx.query;\n\t\tif (!token || !callbackURL) {\n\t\t\tthrow ctx.redirect(\n\t\t\t\tredirectError(ctx.context, callbackURL, { error: \"INVALID_TOKEN\" }),\n\t\t\t);\n\t\t}\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t`reset-password:${token}`,\n\t\t\t);\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow ctx.redirect(\n\t\t\t\tredirectError(ctx.context, callbackURL, { error: \"INVALID_TOKEN\" }),\n\t\t\t);\n\t\t}\n\n\t\tthrow ctx.redirect(redirectCallback(ctx.context, callbackURL, { token }));\n\t},\n);\n\nexport const resetPassword = createAuthEndpoint(\n\t\"/reset-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\toperationId: \"resetPassword\",\n\t\tquery: z\n\t\t\t.object({\n\t\t\t\ttoken: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbody: z.object({\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set\",\n\t\t\t}),\n\t\t\ttoken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The token to reset the password\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"resetPassword\",\n\t\t\t\tdescription: \"Reset the password for a user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst token = ctx.body.token || ctx.query?.token;\n\t\tif (!token) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\n\t\tconst { newPassword } = ctx.body;\n\n\t\tconst minLength = ctx.context.password?.config.minPasswordLength;\n\t\tconst maxLength = ctx.context.password?.config.maxPasswordLength;\n\t\tif (newPassword.length < minLength) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_SHORT);\n\t\t}\n\t\tif (newPassword.length > maxLength) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_LONG);\n\t\t}\n\n\t\tconst id = `reset-password:${token}`;\n\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(id);\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\t\tconst userId = verification.value;\n\t\tconst hashedPassword = await ctx.context.password.hash(newPassword);\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(userId);\n\t\tconst account = accounts.find((ac) => ac.providerId === \"credential\");\n\t\tif (!account) {\n\t\t\tawait ctx.context.internalAdapter.createAccount({\n\t\t\t\tuserId,\n\t\t\t\tproviderId: \"credential\",\n\t\t\t\tpassword: hashedPassword,\n\t\t\t\taccountId: userId,\n\t\t\t});\n\t\t} else {\n\t\t\tawait ctx.context.internalAdapter.updatePassword(userId, hashedPassword);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteVerificationByIdentifier(id);\n\n\t\tif (ctx.context.options.emailAndPassword?.onPasswordReset) {\n\t\t\tconst user = await ctx.context.internalAdapter.findUserById(userId);\n\t\t\tif (user) {\n\t\t\t\tawait ctx.context.options.emailAndPassword.onPasswordReset(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(userId);\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n\nexport const verifyPassword = createAuthEndpoint(\n\t\"/verify-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The password to verify\n\t\t\t */\n\t\t\tpassword: z.string().meta({\n\t\t\t\tdescription: \"The password to verify\",\n\t\t\t}),\n\t\t}),\n\t\tmetadata: {\n\t\t\tscope: \"server\",\n\t\t\topenapi: {\n\t\t\t\toperationId: \"verifyPassword\",\n\t\t\t\tdescription: \"Verify the current user's password\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tuse: [sensitiveSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { password } = ctx.body;\n\t\tconst session = ctx.context.session;\n\n\t\tconst isValid = await validatePassword(ctx, {\n\t\t\tpassword,\n\t\t\tuserId: session.user.id,\n\t\t});\n\n\t\tif (!isValid) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
@@ -367,7 +367,7 @@ const deleteUserCallback = createAuthEndpoint("/delete-user/callback", {
367
367
  await ctx.context.internalAdapter.deleteUser(session.user.id);
368
368
  await ctx.context.internalAdapter.deleteSessions(session.user.id);
369
369
  await ctx.context.internalAdapter.deleteAccounts(session.user.id);
370
- await ctx.context.internalAdapter.deleteVerificationValue(token.id);
370
+ await ctx.context.internalAdapter.deleteVerificationByIdentifier(`delete-account-${ctx.query.token}`);
371
371
  deleteSessionCookie(ctx);
372
372
  const afterDelete = ctx.context.options.user.deleteUser?.afterDelete;
373
373
  if (afterDelete) await afterDelete(session.user, ctx.request);
@@ -1 +1 @@
1
- {"version":3,"file":"update-user.mjs","names":[],"sources":["../../../src/api/routes/update-user.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport * as z from \"zod\";\nimport { deleteSessionCookie, setSessionCookie } from \"../../cookies\";\nimport { generateRandomString } from \"../../crypto\";\nimport { parseUserInput, parseUserOutput } from \"../../db/schema\";\nimport type { AdditionalUserFieldsInput } from \"../../types\";\nimport { originCheck } from \"../middlewares\";\nimport { createEmailVerificationToken } from \"./email-verification\";\nimport {\n\tgetSessionFromCtx,\n\tsensitiveSessionMiddleware,\n\tsessionMiddleware,\n} from \"./session\";\n\nconst updateUserBodySchema = z.record(\n\tz.string().meta({\n\t\tdescription: \"Field name must be a string\",\n\t}),\n\tz.any(),\n);\n\nexport const updateUser = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/update-user\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"updateUser\",\n\t\t\tbody: updateUserBodySchema,\n\t\t\tuse: [sessionMiddleware],\n\t\t\tmetadata: {\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as Partial<AdditionalUserFieldsInput<O>> & {\n\t\t\t\t\t\tname?: string | undefined;\n\t\t\t\t\t\timage?: string | undefined | null;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"updateUser\",\n\t\t\t\t\tdescription: \"Update the current user\",\n\t\t\t\t\trequestBody: {\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tname: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The image of the user\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body as {\n\t\t\t\tname?: string | undefined;\n\t\t\t\timage?: string | undefined;\n\t\t\t\t[key: string]: any;\n\t\t\t};\n\n\t\t\tif (typeof body !== \"object\" || Array.isArray(body)) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tBASE_ERROR_CODES.BODY_MUST_BE_AN_OBJECT,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (body.email) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tBASE_ERROR_CODES.EMAIL_CAN_NOT_BE_UPDATED,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst { name, image, ...rest } = body;\n\t\t\tconst session = ctx.context.session;\n\t\t\tconst additionalFields = parseUserInput(\n\t\t\t\tctx.context.options,\n\t\t\t\trest,\n\t\t\t\t\"update\",\n\t\t\t);\n\t\t\tif (\n\t\t\t\timage === undefined &&\n\t\t\t\tname === undefined &&\n\t\t\t\tObject.keys(additionalFields).length === 0\n\t\t\t) {\n\t\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"No fields to update\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst user = await ctx.context.internalAdapter.updateUser(\n\t\t\t\tsession.user.id,\n\t\t\t\t{\n\t\t\t\t\tname,\n\t\t\t\t\timage,\n\t\t\t\t\t...additionalFields,\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst updatedUser = user ?? {\n\t\t\t\t...session.user,\n\t\t\t\t...(name !== undefined && { name }),\n\t\t\t\t...(image !== undefined && { image }),\n\t\t\t\t...additionalFields,\n\t\t\t};\n\t\t\t/**\n\t\t\t * Update the session cookie with the new user data\n\t\t\t */\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: session.session,\n\t\t\t\tuser: updatedUser,\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t},\n\t);\n\nexport const changePassword = createAuthEndpoint(\n\t\"/change-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\toperationId: \"changePassword\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The new password to set\n\t\t\t */\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The current password of the user\n\t\t\t */\n\t\t\tcurrentPassword: z.string().meta({\n\t\t\t\tdescription: \"The current password is required\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * revoke all sessions that are not the\n\t\t\t * current one logged in by the user\n\t\t\t */\n\t\t\trevokeOtherSessions: z\n\t\t\t\t.boolean()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Must be a boolean value\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"changePassword\",\n\t\t\t\tdescription: \"Change the password of the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Password successfully changed\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true, // Only present if revokeOtherSessions is true\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"New session token if other sessions were revoked\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\tid: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The unique identifier of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\temail: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The email address of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tname: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"uri\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The profile image URL of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\temailVerified: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Whether the email has been verified\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was created\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tupdatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was last updated\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\trequired: [\n\t\t\t\t\t\t\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"emailVerified\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"user\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst { newPassword, currentPassword, revokeOtherSessions } = ctx.body;\n\t\tconst session = ctx.context.session;\n\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\tif (newPassword.length < minPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_SHORT);\n\t\t}\n\n\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\n\t\tif (newPassword.length > maxPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_LONG);\n\t\t}\n\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst account = accounts.find(\n\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t);\n\t\tif (!account || !account.password) {\n\t\t\tthrow APIError.from(\n\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\tBASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND,\n\t\t\t);\n\t\t}\n\t\tconst passwordHash = await ctx.context.password.hash(newPassword);\n\t\tconst verify = await ctx.context.password.verify({\n\t\t\thash: account.password,\n\t\t\tpassword: currentPassword,\n\t\t});\n\t\tif (!verify) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t}\n\t\tawait ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\tpassword: passwordHash,\n\t\t});\n\t\tlet token = null;\n\t\tif (revokeOtherSessions) {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\t\tconst newSession = await ctx.context.internalAdapter.createSession(\n\t\t\t\tsession.user.id,\n\t\t\t);\n\t\t\tif (!newSession) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"INTERNAL_SERVER_ERROR\",\n\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_SESSION,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// set the new session cookie\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: newSession,\n\t\t\t\tuser: session.user,\n\t\t\t});\n\t\t\ttoken = newSession.token;\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\ttoken,\n\t\t\tuser: parseUserOutput(ctx.context.options, session.user),\n\t\t});\n\t},\n);\n\nexport const setPassword = createAuthEndpoint(\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The new password to set\n\t\t\t */\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set is required\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { newPassword } = ctx.body;\n\t\tconst session = ctx.context.session;\n\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\tif (newPassword.length < minPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_SHORT);\n\t\t}\n\n\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\n\t\tif (newPassword.length > maxPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_LONG);\n\t\t}\n\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst account = accounts.find(\n\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t);\n\t\tconst passwordHash = await ctx.context.password.hash(newPassword);\n\t\tif (!account) {\n\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\tuserId: session.user.id,\n\t\t\t\tproviderId: \"credential\",\n\t\t\t\taccountId: session.user.id,\n\t\t\t\tpassword: passwordHash,\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_ALREADY_SET);\n\t},\n);\n\nexport const deleteUser = createAuthEndpoint(\n\t\"/delete-user\",\n\t{\n\t\tmethod: \"POST\",\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The callback URL to redirect to after the user is deleted\n\t\t\t * this is only used on delete user callback\n\t\t\t */\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The callback URL to redirect to after the user is deleted\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * The password of the user. If the password isn't provided, session freshness\n\t\t\t * will be checked.\n\t\t\t */\n\t\t\tpassword: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The password of the user is required to delete the user\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * The token to delete the user. If the token is provided, the user will be deleted\n\t\t\t */\n\t\t\ttoken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The token to delete the user is required\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"deleteUser\",\n\t\t\t\tdescription: \"Delete the user\",\n\t\t\t\trequestBody: {\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\tcallbackURL: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\"The callback URL to redirect to after the user is deleted\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tpassword: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\"The user's password. Required if session is not fresh\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"The deletion verification token\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"User deletion processed successfully\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tsuccess: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the operation was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"User deleted\", \"Verification email sent\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Status message of the deletion process\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"success\", \"message\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.deleteUser?.enabled) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Delete user is disabled. Enable it in the options\",\n\t\t\t);\n\t\t\tthrow APIError.fromStatus(\"NOT_FOUND\");\n\t\t}\n\t\tconst session = ctx.context.session;\n\n\t\tif (ctx.body.password) {\n\t\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\t\tsession.user.id,\n\t\t\t);\n\t\t\tconst account = accounts.find(\n\t\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t\t);\n\t\t\tif (!account || !account.password) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tBASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst verify = await ctx.context.password.verify({\n\t\t\t\thash: account.password,\n\t\t\t\tpassword: ctx.body.password,\n\t\t\t});\n\t\t\tif (!verify) {\n\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t\t}\n\t\t}\n\n\t\tif (ctx.body.token) {\n\t\t\t//@ts-expect-error\n\t\t\tawait deleteUserCallback({\n\t\t\t\t...ctx,\n\t\t\t\tquery: {\n\t\t\t\t\ttoken: ctx.body.token,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: \"User deleted\",\n\t\t\t});\n\t\t}\n\n\t\tif (ctx.context.options.user.deleteUser?.sendDeleteAccountVerification) {\n\t\t\tconst token = generateRandomString(32, \"0-9\", \"a-z\");\n\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\tvalue: session.user.id,\n\t\t\t\tidentifier: `delete-account-${token}`,\n\t\t\t\texpiresAt: new Date(\n\t\t\t\t\tDate.now() +\n\t\t\t\t\t\t(ctx.context.options.user.deleteUser?.deleteTokenExpiresIn ||\n\t\t\t\t\t\t\t60 * 60 * 24) *\n\t\t\t\t\t\t\t1000,\n\t\t\t\t),\n\t\t\t});\n\t\t\tconst url = `${\n\t\t\t\tctx.context.baseURL\n\t\t\t}/delete-user/callback?token=${token}&callbackURL=${encodeURIComponent(\n\t\t\t\tctx.body.callbackURL || \"/\",\n\t\t\t)}`;\n\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\tctx.context.options.user.deleteUser.sendDeleteAccountVerification(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\turl,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn ctx.json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: \"Verification email sent\",\n\t\t\t});\n\t\t}\n\n\t\tif (!ctx.body.password && ctx.context.sessionConfig.freshAge !== 0) {\n\t\t\tconst currentAge = new Date(session.session.createdAt).getTime();\n\t\t\tconst freshAge = ctx.context.sessionConfig.freshAge * 1000;\n\t\t\tconst now = Date.now();\n\t\t\tif (now - currentAge > freshAge) {\n\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.SESSION_EXPIRED);\n\t\t\t}\n\t\t}\n\n\t\tconst beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;\n\t\tif (beforeDelete) {\n\t\t\tawait beforeDelete(session.user, ctx.request);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteUser(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\tdeleteSessionCookie(ctx);\n\t\tconst afterDelete = ctx.context.options.user.deleteUser?.afterDelete;\n\t\tif (afterDelete) {\n\t\t\tawait afterDelete(session.user, ctx.request);\n\t\t}\n\t\treturn ctx.json({\n\t\t\tsuccess: true,\n\t\t\tmessage: \"User deleted\",\n\t\t});\n\t},\n);\n\nexport const deleteUserCallback = createAuthEndpoint(\n\t\"/delete-user/callback\",\n\t{\n\t\tmethod: \"GET\",\n\t\tquery: z.object({\n\t\t\ttoken: z.string().meta({\n\t\t\t\tdescription: \"The token to verify the deletion request\",\n\t\t\t}),\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The URL to redirect to after deletion\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Callback to complete user deletion with verification token\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"User successfully deleted\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tsuccess: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the deletion was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"User deleted\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Confirmation message\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"success\", \"message\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.deleteUser?.enabled) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Delete user is disabled. Enable it in the options\",\n\t\t\t);\n\t\t\tthrow APIError.from(\"NOT_FOUND\", {\n\t\t\t\tmessage: \"Not found\",\n\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t});\n\t\t}\n\t\tconst session = await getSessionFromCtx(ctx);\n\t\tif (!session) {\n\t\t\tthrow APIError.from(\n\t\t\t\t\"NOT_FOUND\",\n\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_USER_INFO,\n\t\t\t);\n\t\t}\n\t\tconst token = await ctx.context.internalAdapter.findVerificationValue(\n\t\t\t`delete-account-${ctx.query.token}`,\n\t\t);\n\t\tif (!token || token.expiresAt < new Date()) {\n\t\t\tthrow APIError.from(\"NOT_FOUND\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\t\tif (token.value !== session.user.id) {\n\t\t\tthrow APIError.from(\"NOT_FOUND\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\t\tconst beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;\n\t\tif (beforeDelete) {\n\t\t\tawait beforeDelete(session.user, ctx.request);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteUser(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteAccounts(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteVerificationValue(token.id);\n\n\t\tdeleteSessionCookie(ctx);\n\n\t\tconst afterDelete = ctx.context.options.user.deleteUser?.afterDelete;\n\t\tif (afterDelete) {\n\t\t\tawait afterDelete(session.user, ctx.request);\n\t\t}\n\t\tif (ctx.query.callbackURL) {\n\t\t\tthrow ctx.redirect(ctx.query.callbackURL || \"/\");\n\t\t}\n\t\treturn ctx.json({\n\t\t\tsuccess: true,\n\t\t\tmessage: \"User deleted\",\n\t\t});\n\t},\n);\n\nexport const changeEmail = createAuthEndpoint(\n\t\"/change-email\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tnewEmail: z.email().meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"The new email address to set must be a valid email address\",\n\t\t\t}),\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The URL to redirect to after email verification\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"changeEmail\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Email change request processed successfully\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the request was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"Email updated\", \"Verification email sent\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Status message of the email change process\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.changeEmail?.enabled) {\n\t\t\tctx.context.logger.error(\"Change email is disabled.\");\n\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Change email is disabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst newEmail = ctx.body.newEmail.toLowerCase();\n\n\t\tif (newEmail === ctx.context.session.user.email) {\n\t\t\tctx.context.logger.error(\"Email is the same\");\n\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Email is the same\",\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * Early config check: ensure at least one email-change flow is\n\t\t * available for the current session state. Without this, an\n\t\t * existing-email lookup would return 200 while a non-existing\n\t\t * email would later throw 400, leaking email existence.\n\t\t */\n\t\tconst canUpdateWithoutVerification =\n\t\t\tctx.context.session.user.emailVerified !== true &&\n\t\t\tctx.context.options.user.changeEmail.updateEmailWithoutVerification;\n\t\tconst canSendConfirmation =\n\t\t\tctx.context.session.user.emailVerified &&\n\t\t\tctx.context.options.user.changeEmail.sendChangeEmailConfirmation;\n\t\tconst canSendVerification =\n\t\t\tctx.context.options.emailVerification?.sendVerificationEmail;\n\n\t\tif (\n\t\t\t!canUpdateWithoutVerification &&\n\t\t\t!canSendConfirmation &&\n\t\t\t!canSendVerification\n\t\t) {\n\t\t\tctx.context.logger.error(\"Verification email isn't enabled.\");\n\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Verification email isn't enabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst existingUser =\n\t\t\tawait ctx.context.internalAdapter.findUserByEmail(newEmail);\n\t\tif (existingUser) {\n\t\t\t// Simulate token generation to prevent timing attacks\n\t\t\tawait createEmailVerificationToken(\n\t\t\t\tctx.context.secret,\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\tnewEmail,\n\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t);\n\n\t\t\tctx.context.logger.info(\"Change email attempt for existing email\");\n\n\t\t\treturn ctx.json({ status: true });\n\t\t}\n\n\t\t/**\n\t\t * If the email is not verified, we can update the email if the option is enabled\n\t\t */\n\t\tif (canUpdateWithoutVerification) {\n\t\t\tawait ctx.context.internalAdapter.updateUserByEmail(\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\t{\n\t\t\t\t\temail: newEmail,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: ctx.context.session.session,\n\t\t\t\tuser: {\n\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\temail: newEmail,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (canSendVerification) {\n\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t\tnewEmail,\n\t\t\t\t\tundefined,\n\t\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t);\n\t\t\t\tconst url = `${\n\t\t\t\t\tctx.context.baseURL\n\t\t\t\t}/verify-email?token=${token}&callbackURL=${\n\t\t\t\t\tctx.body.callbackURL || \"/\"\n\t\t\t\t}`;\n\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\tcanSendVerification(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\t\t\t\temail: newEmail,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx.request,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * If the email is verified, we need to send a verification email\n\t\t */\n\t\tif (canSendConfirmation) {\n\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\tctx.context.secret,\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\tnewEmail,\n\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t{\n\t\t\t\t\trequestType: \"change-email-confirmation\",\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst url = `${\n\t\t\t\tctx.context.baseURL\n\t\t\t}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || \"/\"}`;\n\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\tcanSendConfirmation(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser: ctx.context.session.user,\n\t\t\t\t\t\tnewEmail: newEmail,\n\t\t\t\t\t\turl,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\n\t\tif (!canSendVerification) {\n\t\t\tctx.context.logger.error(\"Verification email isn't enabled.\");\n\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Verification email isn't enabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst token = await createEmailVerificationToken(\n\t\t\tctx.context.secret,\n\t\t\tctx.context.session.user.email,\n\t\t\tnewEmail,\n\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t{\n\t\t\t\trequestType: \"change-email-verification\",\n\t\t\t},\n\t\t);\n\t\tconst url = `${\n\t\t\tctx.context.baseURL\n\t\t}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || \"/\"}`;\n\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\tcanSendVerification(\n\t\t\t\t{\n\t\t\t\t\tuser: {\n\t\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\t\temail: newEmail,\n\t\t\t\t\t},\n\t\t\t\t\turl,\n\t\t\t\t\ttoken,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"update-user.mjs","names":[],"sources":["../../../src/api/routes/update-user.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport * as z from \"zod\";\nimport { deleteSessionCookie, setSessionCookie } from \"../../cookies\";\nimport { generateRandomString } from \"../../crypto\";\nimport { parseUserInput, parseUserOutput } from \"../../db/schema\";\nimport type { AdditionalUserFieldsInput } from \"../../types\";\nimport { originCheck } from \"../middlewares\";\nimport { createEmailVerificationToken } from \"./email-verification\";\nimport {\n\tgetSessionFromCtx,\n\tsensitiveSessionMiddleware,\n\tsessionMiddleware,\n} from \"./session\";\n\nconst updateUserBodySchema = z.record(\n\tz.string().meta({\n\t\tdescription: \"Field name must be a string\",\n\t}),\n\tz.any(),\n);\n\nexport const updateUser = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/update-user\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"updateUser\",\n\t\t\tbody: updateUserBodySchema,\n\t\t\tuse: [sessionMiddleware],\n\t\t\tmetadata: {\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as Partial<AdditionalUserFieldsInput<O>> & {\n\t\t\t\t\t\tname?: string | undefined;\n\t\t\t\t\t\timage?: string | undefined | null;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"updateUser\",\n\t\t\t\t\tdescription: \"Update the current user\",\n\t\t\t\t\trequestBody: {\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tname: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The image of the user\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body as {\n\t\t\t\tname?: string | undefined;\n\t\t\t\timage?: string | undefined;\n\t\t\t\t[key: string]: any;\n\t\t\t};\n\n\t\t\tif (typeof body !== \"object\" || Array.isArray(body)) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tBASE_ERROR_CODES.BODY_MUST_BE_AN_OBJECT,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (body.email) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tBASE_ERROR_CODES.EMAIL_CAN_NOT_BE_UPDATED,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst { name, image, ...rest } = body;\n\t\t\tconst session = ctx.context.session;\n\t\t\tconst additionalFields = parseUserInput(\n\t\t\t\tctx.context.options,\n\t\t\t\trest,\n\t\t\t\t\"update\",\n\t\t\t);\n\t\t\tif (\n\t\t\t\timage === undefined &&\n\t\t\t\tname === undefined &&\n\t\t\t\tObject.keys(additionalFields).length === 0\n\t\t\t) {\n\t\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"No fields to update\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst user = await ctx.context.internalAdapter.updateUser(\n\t\t\t\tsession.user.id,\n\t\t\t\t{\n\t\t\t\t\tname,\n\t\t\t\t\timage,\n\t\t\t\t\t...additionalFields,\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst updatedUser = user ?? {\n\t\t\t\t...session.user,\n\t\t\t\t...(name !== undefined && { name }),\n\t\t\t\t...(image !== undefined && { image }),\n\t\t\t\t...additionalFields,\n\t\t\t};\n\t\t\t/**\n\t\t\t * Update the session cookie with the new user data\n\t\t\t */\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: session.session,\n\t\t\t\tuser: updatedUser,\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t},\n\t);\n\nexport const changePassword = createAuthEndpoint(\n\t\"/change-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\toperationId: \"changePassword\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The new password to set\n\t\t\t */\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The current password of the user\n\t\t\t */\n\t\t\tcurrentPassword: z.string().meta({\n\t\t\t\tdescription: \"The current password is required\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * revoke all sessions that are not the\n\t\t\t * current one logged in by the user\n\t\t\t */\n\t\t\trevokeOtherSessions: z\n\t\t\t\t.boolean()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Must be a boolean value\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"changePassword\",\n\t\t\t\tdescription: \"Change the password of the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Password successfully changed\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true, // Only present if revokeOtherSessions is true\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"New session token if other sessions were revoked\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\tid: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The unique identifier of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\temail: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The email address of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tname: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"uri\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The profile image URL of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\temailVerified: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Whether the email has been verified\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was created\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tupdatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was last updated\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\trequired: [\n\t\t\t\t\t\t\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"emailVerified\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"user\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst { newPassword, currentPassword, revokeOtherSessions } = ctx.body;\n\t\tconst session = ctx.context.session;\n\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\tif (newPassword.length < minPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_SHORT);\n\t\t}\n\n\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\n\t\tif (newPassword.length > maxPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_LONG);\n\t\t}\n\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst account = accounts.find(\n\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t);\n\t\tif (!account || !account.password) {\n\t\t\tthrow APIError.from(\n\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\tBASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND,\n\t\t\t);\n\t\t}\n\t\tconst passwordHash = await ctx.context.password.hash(newPassword);\n\t\tconst verify = await ctx.context.password.verify({\n\t\t\thash: account.password,\n\t\t\tpassword: currentPassword,\n\t\t});\n\t\tif (!verify) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t}\n\t\tawait ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\tpassword: passwordHash,\n\t\t});\n\t\tlet token = null;\n\t\tif (revokeOtherSessions) {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\t\tconst newSession = await ctx.context.internalAdapter.createSession(\n\t\t\t\tsession.user.id,\n\t\t\t);\n\t\t\tif (!newSession) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"INTERNAL_SERVER_ERROR\",\n\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_SESSION,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// set the new session cookie\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: newSession,\n\t\t\t\tuser: session.user,\n\t\t\t});\n\t\t\ttoken = newSession.token;\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\ttoken,\n\t\t\tuser: parseUserOutput(ctx.context.options, session.user),\n\t\t});\n\t},\n);\n\nexport const setPassword = createAuthEndpoint(\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The new password to set\n\t\t\t */\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set is required\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { newPassword } = ctx.body;\n\t\tconst session = ctx.context.session;\n\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\tif (newPassword.length < minPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_SHORT);\n\t\t}\n\n\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\n\t\tif (newPassword.length > maxPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_LONG);\n\t\t}\n\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst account = accounts.find(\n\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t);\n\t\tconst passwordHash = await ctx.context.password.hash(newPassword);\n\t\tif (!account) {\n\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\tuserId: session.user.id,\n\t\t\t\tproviderId: \"credential\",\n\t\t\t\taccountId: session.user.id,\n\t\t\t\tpassword: passwordHash,\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_ALREADY_SET);\n\t},\n);\n\nexport const deleteUser = createAuthEndpoint(\n\t\"/delete-user\",\n\t{\n\t\tmethod: \"POST\",\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The callback URL to redirect to after the user is deleted\n\t\t\t * this is only used on delete user callback\n\t\t\t */\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The callback URL to redirect to after the user is deleted\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * The password of the user. If the password isn't provided, session freshness\n\t\t\t * will be checked.\n\t\t\t */\n\t\t\tpassword: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The password of the user is required to delete the user\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * The token to delete the user. If the token is provided, the user will be deleted\n\t\t\t */\n\t\t\ttoken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The token to delete the user is required\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"deleteUser\",\n\t\t\t\tdescription: \"Delete the user\",\n\t\t\t\trequestBody: {\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\tcallbackURL: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\"The callback URL to redirect to after the user is deleted\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tpassword: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\"The user's password. Required if session is not fresh\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"The deletion verification token\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"User deletion processed successfully\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tsuccess: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the operation was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"User deleted\", \"Verification email sent\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Status message of the deletion process\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"success\", \"message\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.deleteUser?.enabled) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Delete user is disabled. Enable it in the options\",\n\t\t\t);\n\t\t\tthrow APIError.fromStatus(\"NOT_FOUND\");\n\t\t}\n\t\tconst session = ctx.context.session;\n\n\t\tif (ctx.body.password) {\n\t\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\t\tsession.user.id,\n\t\t\t);\n\t\t\tconst account = accounts.find(\n\t\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t\t);\n\t\t\tif (!account || !account.password) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tBASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst verify = await ctx.context.password.verify({\n\t\t\t\thash: account.password,\n\t\t\t\tpassword: ctx.body.password,\n\t\t\t});\n\t\t\tif (!verify) {\n\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t\t}\n\t\t}\n\n\t\tif (ctx.body.token) {\n\t\t\t//@ts-expect-error\n\t\t\tawait deleteUserCallback({\n\t\t\t\t...ctx,\n\t\t\t\tquery: {\n\t\t\t\t\ttoken: ctx.body.token,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: \"User deleted\",\n\t\t\t});\n\t\t}\n\n\t\tif (ctx.context.options.user.deleteUser?.sendDeleteAccountVerification) {\n\t\t\tconst token = generateRandomString(32, \"0-9\", \"a-z\");\n\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\tvalue: session.user.id,\n\t\t\t\tidentifier: `delete-account-${token}`,\n\t\t\t\texpiresAt: new Date(\n\t\t\t\t\tDate.now() +\n\t\t\t\t\t\t(ctx.context.options.user.deleteUser?.deleteTokenExpiresIn ||\n\t\t\t\t\t\t\t60 * 60 * 24) *\n\t\t\t\t\t\t\t1000,\n\t\t\t\t),\n\t\t\t});\n\t\t\tconst url = `${\n\t\t\t\tctx.context.baseURL\n\t\t\t}/delete-user/callback?token=${token}&callbackURL=${encodeURIComponent(\n\t\t\t\tctx.body.callbackURL || \"/\",\n\t\t\t)}`;\n\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\tctx.context.options.user.deleteUser.sendDeleteAccountVerification(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\turl,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn ctx.json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: \"Verification email sent\",\n\t\t\t});\n\t\t}\n\n\t\tif (!ctx.body.password && ctx.context.sessionConfig.freshAge !== 0) {\n\t\t\tconst currentAge = new Date(session.session.createdAt).getTime();\n\t\t\tconst freshAge = ctx.context.sessionConfig.freshAge * 1000;\n\t\t\tconst now = Date.now();\n\t\t\tif (now - currentAge > freshAge) {\n\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.SESSION_EXPIRED);\n\t\t\t}\n\t\t}\n\n\t\tconst beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;\n\t\tif (beforeDelete) {\n\t\t\tawait beforeDelete(session.user, ctx.request);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteUser(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\tdeleteSessionCookie(ctx);\n\t\tconst afterDelete = ctx.context.options.user.deleteUser?.afterDelete;\n\t\tif (afterDelete) {\n\t\t\tawait afterDelete(session.user, ctx.request);\n\t\t}\n\t\treturn ctx.json({\n\t\t\tsuccess: true,\n\t\t\tmessage: \"User deleted\",\n\t\t});\n\t},\n);\n\nexport const deleteUserCallback = createAuthEndpoint(\n\t\"/delete-user/callback\",\n\t{\n\t\tmethod: \"GET\",\n\t\tquery: z.object({\n\t\t\ttoken: z.string().meta({\n\t\t\t\tdescription: \"The token to verify the deletion request\",\n\t\t\t}),\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The URL to redirect to after deletion\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Callback to complete user deletion with verification token\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"User successfully deleted\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tsuccess: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the deletion was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"User deleted\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Confirmation message\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"success\", \"message\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.deleteUser?.enabled) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Delete user is disabled. Enable it in the options\",\n\t\t\t);\n\t\t\tthrow APIError.from(\"NOT_FOUND\", {\n\t\t\t\tmessage: \"Not found\",\n\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t});\n\t\t}\n\t\tconst session = await getSessionFromCtx(ctx);\n\t\tif (!session) {\n\t\t\tthrow APIError.from(\n\t\t\t\t\"NOT_FOUND\",\n\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_USER_INFO,\n\t\t\t);\n\t\t}\n\t\tconst token = await ctx.context.internalAdapter.findVerificationValue(\n\t\t\t`delete-account-${ctx.query.token}`,\n\t\t);\n\t\tif (!token || token.expiresAt < new Date()) {\n\t\t\tthrow APIError.from(\"NOT_FOUND\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\t\tif (token.value !== session.user.id) {\n\t\t\tthrow APIError.from(\"NOT_FOUND\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\t\tconst beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;\n\t\tif (beforeDelete) {\n\t\t\tawait beforeDelete(session.user, ctx.request);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteUser(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteAccounts(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteVerificationByIdentifier(\n\t\t\t`delete-account-${ctx.query.token}`,\n\t\t);\n\n\t\tdeleteSessionCookie(ctx);\n\n\t\tconst afterDelete = ctx.context.options.user.deleteUser?.afterDelete;\n\t\tif (afterDelete) {\n\t\t\tawait afterDelete(session.user, ctx.request);\n\t\t}\n\t\tif (ctx.query.callbackURL) {\n\t\t\tthrow ctx.redirect(ctx.query.callbackURL || \"/\");\n\t\t}\n\t\treturn ctx.json({\n\t\t\tsuccess: true,\n\t\t\tmessage: \"User deleted\",\n\t\t});\n\t},\n);\n\nexport const changeEmail = createAuthEndpoint(\n\t\"/change-email\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tnewEmail: z.email().meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"The new email address to set must be a valid email address\",\n\t\t\t}),\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The URL to redirect to after email verification\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"changeEmail\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Email change request processed successfully\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the request was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"Email updated\", \"Verification email sent\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Status message of the email change process\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.changeEmail?.enabled) {\n\t\t\tctx.context.logger.error(\"Change email is disabled.\");\n\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Change email is disabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst newEmail = ctx.body.newEmail.toLowerCase();\n\n\t\tif (newEmail === ctx.context.session.user.email) {\n\t\t\tctx.context.logger.error(\"Email is the same\");\n\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Email is the same\",\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * Early config check: ensure at least one email-change flow is\n\t\t * available for the current session state. Without this, an\n\t\t * existing-email lookup would return 200 while a non-existing\n\t\t * email would later throw 400, leaking email existence.\n\t\t */\n\t\tconst canUpdateWithoutVerification =\n\t\t\tctx.context.session.user.emailVerified !== true &&\n\t\t\tctx.context.options.user.changeEmail.updateEmailWithoutVerification;\n\t\tconst canSendConfirmation =\n\t\t\tctx.context.session.user.emailVerified &&\n\t\t\tctx.context.options.user.changeEmail.sendChangeEmailConfirmation;\n\t\tconst canSendVerification =\n\t\t\tctx.context.options.emailVerification?.sendVerificationEmail;\n\n\t\tif (\n\t\t\t!canUpdateWithoutVerification &&\n\t\t\t!canSendConfirmation &&\n\t\t\t!canSendVerification\n\t\t) {\n\t\t\tctx.context.logger.error(\"Verification email isn't enabled.\");\n\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Verification email isn't enabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst existingUser =\n\t\t\tawait ctx.context.internalAdapter.findUserByEmail(newEmail);\n\t\tif (existingUser) {\n\t\t\t// Simulate token generation to prevent timing attacks\n\t\t\tawait createEmailVerificationToken(\n\t\t\t\tctx.context.secret,\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\tnewEmail,\n\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t);\n\n\t\t\tctx.context.logger.info(\"Change email attempt for existing email\");\n\n\t\t\treturn ctx.json({ status: true });\n\t\t}\n\n\t\t/**\n\t\t * If the email is not verified, we can update the email if the option is enabled\n\t\t */\n\t\tif (canUpdateWithoutVerification) {\n\t\t\tawait ctx.context.internalAdapter.updateUserByEmail(\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\t{\n\t\t\t\t\temail: newEmail,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: ctx.context.session.session,\n\t\t\t\tuser: {\n\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\temail: newEmail,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (canSendVerification) {\n\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t\tnewEmail,\n\t\t\t\t\tundefined,\n\t\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t);\n\t\t\t\tconst url = `${\n\t\t\t\t\tctx.context.baseURL\n\t\t\t\t}/verify-email?token=${token}&callbackURL=${\n\t\t\t\t\tctx.body.callbackURL || \"/\"\n\t\t\t\t}`;\n\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\tcanSendVerification(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\t\t\t\temail: newEmail,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx.request,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * If the email is verified, we need to send a verification email\n\t\t */\n\t\tif (canSendConfirmation) {\n\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\tctx.context.secret,\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\tnewEmail,\n\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t{\n\t\t\t\t\trequestType: \"change-email-confirmation\",\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst url = `${\n\t\t\t\tctx.context.baseURL\n\t\t\t}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || \"/\"}`;\n\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\tcanSendConfirmation(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser: ctx.context.session.user,\n\t\t\t\t\t\tnewEmail: newEmail,\n\t\t\t\t\t\turl,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\n\t\tif (!canSendVerification) {\n\t\t\tctx.context.logger.error(\"Verification email isn't enabled.\");\n\t\t\tthrow APIError.fromStatus(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Verification email isn't enabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst token = await createEmailVerificationToken(\n\t\t\tctx.context.secret,\n\t\t\tctx.context.session.user.email,\n\t\t\tnewEmail,\n\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t{\n\t\t\t\trequestType: \"change-email-verification\",\n\t\t\t},\n\t\t);\n\t\tconst url = `${\n\t\t\tctx.context.baseURL\n\t\t}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || \"/\"}`;\n\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\tcanSendVerification(\n\t\t\t\t{\n\t\t\t\t\tuser: {\n\t\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\t\temail: newEmail,\n\t\t\t\t\t},\n\t\t\t\t\turl,\n\t\t\t\t\ttoken,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
@@ -1,31 +1,8 @@
1
- import { getHost, getOrigin, getProtocol } from "../utils/url.mjs";
2
1
  import { wildcardMatch } from "../utils/wildcard.mjs";
2
+ import { getHost, getOrigin, getProtocol } from "../utils/url.mjs";
3
3
 
4
4
  //#region src/auth/trusted-origins.ts
5
5
  /**
6
- * Matches a hostname against a host pattern.
7
- * Supports wildcard patterns like `*.vercel.app` or `preview-*.myapp.com`.
8
- *
9
- * @param host The hostname to test (e.g., "myapp.com", "preview-123.vercel.app")
10
- * @param pattern The host pattern (e.g., "myapp.com", "*.vercel.app")
11
- * @returns {boolean} true if the host matches the pattern, false otherwise.
12
- *
13
- * @example
14
- * ```ts
15
- * matchesHostPattern("myapp.com", "myapp.com") // true
16
- * matchesHostPattern("preview-123.vercel.app", "*.vercel.app") // true
17
- * matchesHostPattern("preview-123.myapp.com", "preview-*.myapp.com") // true
18
- * matchesHostPattern("evil.com", "myapp.com") // false
19
- * ```
20
- */
21
- const matchesHostPattern = (host, pattern) => {
22
- if (!host || !pattern) return false;
23
- const normalizedHost = host.replace(/^https?:\/\//, "").split("/")[0].toLowerCase();
24
- const normalizedPattern = pattern.replace(/^https?:\/\//, "").split("/")[0].toLowerCase();
25
- if (normalizedPattern.includes("*") || normalizedPattern.includes("?")) return wildcardMatch(normalizedPattern)(normalizedHost);
26
- return normalizedHost.toLowerCase() === normalizedPattern.toLowerCase();
27
- };
28
- /**
29
6
  * Matches the given url against an origin or origin pattern
30
7
  * See "options.trustedOrigins" for details of supported patterns
31
8
  *
@@ -50,5 +27,5 @@ const matchesOriginPattern = (url, pattern, settings) => {
50
27
  };
51
28
 
52
29
  //#endregion
53
- export { matchesHostPattern, matchesOriginPattern };
30
+ export { matchesOriginPattern };
54
31
  //# sourceMappingURL=trusted-origins.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"trusted-origins.mjs","names":[],"sources":["../../src/auth/trusted-origins.ts"],"sourcesContent":["import { getHost, getOrigin, getProtocol } from \"../utils/url\";\nimport { wildcardMatch } from \"../utils/wildcard\";\n\n/**\n * Matches a hostname against a host pattern.\n * Supports wildcard patterns like `*.vercel.app` or `preview-*.myapp.com`.\n *\n * @param host The hostname to test (e.g., \"myapp.com\", \"preview-123.vercel.app\")\n * @param pattern The host pattern (e.g., \"myapp.com\", \"*.vercel.app\")\n * @returns {boolean} true if the host matches the pattern, false otherwise.\n *\n * @example\n * ```ts\n * matchesHostPattern(\"myapp.com\", \"myapp.com\") // true\n * matchesHostPattern(\"preview-123.vercel.app\", \"*.vercel.app\") // true\n * matchesHostPattern(\"preview-123.myapp.com\", \"preview-*.myapp.com\") // true\n * matchesHostPattern(\"evil.com\", \"myapp.com\") // false\n * ```\n */\nexport const matchesHostPattern = (host: string, pattern: string): boolean => {\n\tif (!host || !pattern) {\n\t\treturn false;\n\t}\n\n\t// Normalize: remove protocol if accidentally included, lowercase for case-insensitive matching\n\tconst normalizedHost = host\n\t\t.replace(/^https?:\\/\\//, \"\")\n\t\t.split(\"/\")[0]!\n\t\t.toLowerCase();\n\tconst normalizedPattern = pattern\n\t\t.replace(/^https?:\\/\\//, \"\")\n\t\t.split(\"/\")[0]!\n\t\t.toLowerCase();\n\n\t// Check if pattern contains wildcard characters\n\tconst hasWildcard =\n\t\tnormalizedPattern.includes(\"*\") || normalizedPattern.includes(\"?\");\n\n\tif (hasWildcard) {\n\t\treturn wildcardMatch(normalizedPattern)(normalizedHost);\n\t}\n\n\t// Exact match (case-insensitive for hostnames)\n\treturn normalizedHost.toLowerCase() === normalizedPattern.toLowerCase();\n};\n\n/**\n * Matches the given url against an origin or origin pattern\n * See \"options.trustedOrigins\" for details of supported patterns\n *\n * @param url The url to test\n * @param pattern The origin pattern\n * @param [settings] Specify supported pattern matching settings\n * @returns {boolean} true if the URL matches the origin pattern, false otherwise.\n */\nexport const matchesOriginPattern = (\n\turl: string,\n\tpattern: string,\n\tsettings?: { allowRelativePaths: boolean },\n): boolean => {\n\tif (url.startsWith(\"/\")) {\n\t\tif (settings?.allowRelativePaths) {\n\t\t\treturn (\n\t\t\t\turl.startsWith(\"/\") &&\n\t\t\t\t/^\\/(?!\\/|\\\\|%2f|%5c)[\\w\\-.\\+/@]*(?:\\?[\\w\\-.\\+/=&%@]*)?$/.test(url)\n\t\t\t);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t// Check if pattern contains wildcard characters (*, **, or ?)\n\tconst hasWildcard = pattern.includes(\"*\") || pattern.includes(\"?\");\n\tif (hasWildcard) {\n\t\t// For protocol-specific wildcards, match the full origin\n\t\tif (pattern.includes(\"://\")) {\n\t\t\treturn wildcardMatch(pattern)(getOrigin(url) || url);\n\t\t}\n\t\tconst host = getHost(url);\n\t\tif (!host) {\n\t\t\treturn false;\n\t\t}\n\t\t// For host-only wildcards, match just the host\n\t\treturn wildcardMatch(pattern)(host);\n\t}\n\tconst protocol = getProtocol(url);\n\treturn protocol === \"http:\" || protocol === \"https:\" || !protocol\n\t\t? pattern === getOrigin(url)\n\t\t: url.startsWith(pattern);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAmBA,MAAa,sBAAsB,MAAc,YAA6B;AAC7E,KAAI,CAAC,QAAQ,CAAC,QACb,QAAO;CAIR,MAAM,iBAAiB,KACrB,QAAQ,gBAAgB,GAAG,CAC3B,MAAM,IAAI,CAAC,GACX,aAAa;CACf,MAAM,oBAAoB,QACxB,QAAQ,gBAAgB,GAAG,CAC3B,MAAM,IAAI,CAAC,GACX,aAAa;AAMf,KAFC,kBAAkB,SAAS,IAAI,IAAI,kBAAkB,SAAS,IAAI,CAGlE,QAAO,cAAc,kBAAkB,CAAC,eAAe;AAIxD,QAAO,eAAe,aAAa,KAAK,kBAAkB,aAAa;;;;;;;;;;;AAYxE,MAAa,wBACZ,KACA,SACA,aACa;AACb,KAAI,IAAI,WAAW,IAAI,EAAE;AACxB,MAAI,UAAU,mBACb,QACC,IAAI,WAAW,IAAI,IACnB,0DAA0D,KAAK,IAAI;AAIrE,SAAO;;AAKR,KADoB,QAAQ,SAAS,IAAI,IAAI,QAAQ,SAAS,IAAI,EACjD;AAEhB,MAAI,QAAQ,SAAS,MAAM,CAC1B,QAAO,cAAc,QAAQ,CAAC,UAAU,IAAI,IAAI,IAAI;EAErD,MAAM,OAAO,QAAQ,IAAI;AACzB,MAAI,CAAC,KACJ,QAAO;AAGR,SAAO,cAAc,QAAQ,CAAC,KAAK;;CAEpC,MAAM,WAAW,YAAY,IAAI;AACjC,QAAO,aAAa,WAAW,aAAa,YAAY,CAAC,WACtD,YAAY,UAAU,IAAI,GAC1B,IAAI,WAAW,QAAQ"}
1
+ {"version":3,"file":"trusted-origins.mjs","names":[],"sources":["../../src/auth/trusted-origins.ts"],"sourcesContent":["import { getHost, getOrigin, getProtocol } from \"../utils/url\";\nimport { wildcardMatch } from \"../utils/wildcard\";\n\n/**\n * Matches the given url against an origin or origin pattern\n * See \"options.trustedOrigins\" for details of supported patterns\n *\n * @param url The url to test\n * @param pattern The origin pattern\n * @param [settings] Specify supported pattern matching settings\n * @returns {boolean} true if the URL matches the origin pattern, false otherwise.\n */\nexport const matchesOriginPattern = (\n\turl: string,\n\tpattern: string,\n\tsettings?: { allowRelativePaths: boolean },\n): boolean => {\n\tif (url.startsWith(\"/\")) {\n\t\tif (settings?.allowRelativePaths) {\n\t\t\treturn (\n\t\t\t\turl.startsWith(\"/\") &&\n\t\t\t\t/^\\/(?!\\/|\\\\|%2f|%5c)[\\w\\-.\\+/@]*(?:\\?[\\w\\-.\\+/=&%@]*)?$/.test(url)\n\t\t\t);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t// Check if pattern contains wildcard characters (*, **, or ?)\n\tconst hasWildcard = pattern.includes(\"*\") || pattern.includes(\"?\");\n\tif (hasWildcard) {\n\t\t// For protocol-specific wildcards, match the full origin\n\t\tif (pattern.includes(\"://\")) {\n\t\t\treturn wildcardMatch(pattern)(getOrigin(url) || url);\n\t\t}\n\t\tconst host = getHost(url);\n\t\tif (!host) {\n\t\t\treturn false;\n\t\t}\n\t\t// For host-only wildcards, match just the host\n\t\treturn wildcardMatch(pattern)(host);\n\t}\n\tconst protocol = getProtocol(url);\n\treturn protocol === \"http:\" || protocol === \"https:\" || !protocol\n\t\t? pattern === getOrigin(url)\n\t\t: url.startsWith(pattern);\n};\n"],"mappings":";;;;;;;;;;;;;AAYA,MAAa,wBACZ,KACA,SACA,aACa;AACb,KAAI,IAAI,WAAW,IAAI,EAAE;AACxB,MAAI,UAAU,mBACb,QACC,IAAI,WAAW,IAAI,IACnB,0DAA0D,KAAK,IAAI;AAIrE,SAAO;;AAKR,KADoB,QAAQ,SAAS,IAAI,IAAI,QAAQ,SAAS,IAAI,EACjD;AAEhB,MAAI,QAAQ,SAAS,MAAM,CAC1B,QAAO,cAAc,QAAQ,CAAC,UAAU,IAAI,IAAI,IAAI;EAErD,MAAM,OAAO,QAAQ,IAAI;AACzB,MAAI,CAAC,KACJ,QAAO;AAGR,SAAO,cAAc,QAAQ,CAAC,KAAK;;CAEpC,MAAM,WAAW,YAAY,IAAI;AACjC,QAAO,aAAa,WAAW,aAAa,YAAY,CAAC,WACtD,YAAY,UAAU,IAAI,GAC1B,IAAI,WAAW,QAAQ"}
@@ -1,4 +1,3 @@
1
- import { __exportAll, __reExport } from "../_virtual/_rolldown/runtime.mjs";
2
1
  import { FieldAttributeToObject, InferAdditionalFieldsFromPluginOptions, InferFieldsInputClient, InferFieldsOutput, RemoveFieldsWithReturnedFalse } from "./field.mjs";
3
2
  import { convertFromDB, convertToDB } from "./field-converter.mjs";
4
3
  import { getSchema } from "./get-schema.mjs";
@@ -7,12 +6,4 @@ import { getSessionDefaultFields, mergeSchema, parseAccountInput, parseAccountOu
7
6
  import { FieldAttributeToSchema, toZodSchema } from "./to-zod.mjs";
8
7
  import { getWithHooks } from "./with-hooks.mjs";
9
8
  export * from "@better-auth/core/db";
10
-
11
- //#region src/db/index.d.ts
12
- declare namespace index_d_exports {
13
- export { FieldAttributeToObject, FieldAttributeToSchema, InferAdditionalFieldsFromPluginOptions, InferFieldsInputClient, InferFieldsOutput, RemoveFieldsWithReturnedFalse, convertFromDB, convertToDB, createInternalAdapter, getSchema, getSessionDefaultFields, getWithHooks, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput, toZodSchema };
14
- }
15
- import * as import__better_auth_core_db from "@better-auth/core/db";
16
- //#endregion
17
- export { FieldAttributeToObject, FieldAttributeToSchema, InferAdditionalFieldsFromPluginOptions, InferFieldsInputClient, InferFieldsOutput, RemoveFieldsWithReturnedFalse, convertFromDB, convertToDB, createInternalAdapter, getSchema, getSessionDefaultFields, getWithHooks, index_d_exports, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput, toZodSchema };
18
- //# sourceMappingURL=index.d.mts.map
9
+ export { FieldAttributeToObject, FieldAttributeToSchema, InferAdditionalFieldsFromPluginOptions, InferFieldsInputClient, InferFieldsOutput, RemoveFieldsWithReturnedFalse, convertFromDB, convertToDB, createInternalAdapter, getSchema, getSessionDefaultFields, getWithHooks, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput, toZodSchema };
@@ -598,12 +598,6 @@ const createInternalAdapter = (adapter, ctx) => {
598
598
  }], "verification", void 0);
599
599
  return verification[0] || null;
600
600
  },
601
- deleteVerificationValue: async (id) => {
602
- if (!secondaryStorage || options.verification?.storeInDatabase) await deleteWithHooks([{
603
- field: "id",
604
- value: id
605
- }], "verification", void 0);
606
- },
607
601
  deleteVerificationByIdentifier: async (identifier) => {
608
602
  const storedIdentifier = await processIdentifier(identifier, getStorageOption(identifier, options.verification?.storeIdentifier));
609
603
  if (secondaryStorage) await secondaryStorage.delete(`verification:${storedIdentifier}`);
@@ -612,11 +606,29 @@ const createInternalAdapter = (adapter, ctx) => {
612
606
  value: storedIdentifier
613
607
  }], "verification", void 0);
614
608
  },
615
- updateVerificationValue: async (id, data) => {
616
- return await updateWithHooks(data, [{
617
- field: "id",
618
- value: id
609
+ updateVerificationByIdentifier: async (identifier, data) => {
610
+ const storedIdentifier = await processIdentifier(identifier, getStorageOption(identifier, options.verification?.storeIdentifier));
611
+ if (secondaryStorage) {
612
+ const cached = await secondaryStorage.get(`verification:${storedIdentifier}`);
613
+ if (cached) {
614
+ const parsed = safeJSONParse(cached);
615
+ if (parsed) {
616
+ const updated = {
617
+ ...parsed,
618
+ ...data
619
+ };
620
+ const expiresAt = updated.expiresAt ?? parsed.expiresAt;
621
+ const ttl = getTTLSeconds(expiresAt instanceof Date ? expiresAt : new Date(expiresAt));
622
+ if (ttl > 0) await secondaryStorage.set(`verification:${storedIdentifier}`, JSON.stringify(updated), ttl);
623
+ if (!options.verification?.storeInDatabase) return updated;
624
+ }
625
+ }
626
+ }
627
+ if (!secondaryStorage || options.verification?.storeInDatabase) return await updateWithHooks(data, [{
628
+ field: "identifier",
629
+ value: storedIdentifier
619
630
  }], "verification", void 0);
631
+ return data;
620
632
  }
621
633
  };
622
634
  };