better-auth 0.5.3-beta.8 → 0.5.3-beta.9
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.
- package/dist/access.js +1 -0
- package/dist/access.js.map +1 -0
- package/dist/adapters/drizzle.js +2 -1
- package/dist/adapters/drizzle.js.map +1 -0
- package/dist/adapters/kysely.js +1 -0
- package/dist/adapters/kysely.js.map +1 -0
- package/dist/adapters/mongodb.js +1 -0
- package/dist/adapters/mongodb.js.map +1 -0
- package/dist/adapters/prisma.js +1 -0
- package/dist/adapters/prisma.js.map +1 -0
- package/dist/api.js +2 -1
- package/dist/api.js.map +1 -0
- package/dist/client/plugins.js +1 -0
- package/dist/client/plugins.js.map +1 -0
- package/dist/client.js +2 -1
- package/dist/client.js.map +1 -0
- package/dist/cookies.js +2 -1
- package/dist/cookies.js.map +1 -0
- package/dist/crypto.js +1 -0
- package/dist/crypto.js.map +1 -0
- package/dist/db.js +2 -1
- package/dist/db.js.map +1 -0
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -0
- package/dist/next-js.js +1 -0
- package/dist/next-js.js.map +1 -0
- package/dist/node.js +1 -0
- package/dist/node.js.map +1 -0
- package/dist/oauth2.js +1 -0
- package/dist/oauth2.js.map +1 -0
- package/dist/plugins.js +2 -1
- package/dist/plugins.js.map +1 -0
- package/dist/react.js +2 -1
- package/dist/react.js.map +1 -0
- package/dist/social.js +2 -1
- package/dist/social.js.map +1 -0
- package/dist/solid-start.js +1 -0
- package/dist/solid-start.js.map +1 -0
- package/dist/solid.js +2 -1
- package/dist/solid.js.map +1 -0
- package/dist/svelte-kit.js +2 -1
- package/dist/svelte-kit.js.map +1 -0
- package/dist/svelte.js +2 -1
- package/dist/svelte.js.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/vue.js +2 -1
- package/dist/vue.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/organization/organization.ts","../src/api/call.ts","../src/api/routes/sign-in.ts","../src/oauth2/state.ts","../src/crypto/hash.ts","../src/crypto/buffer.ts","../src/cookies/index.ts","../src/error/index.ts","../src/api/middlewares/redirect.ts","../src/utils/logger.ts","../src/social-providers/apple.ts","../src/oauth2/utils.ts","../src/oauth2/create-authorization-url.ts","../src/oauth2/validate-authorization-code.ts","../src/oauth2/get-account.ts","../src/social-providers/discord.ts","../src/social-providers/facebook.ts","../src/social-providers/github.ts","../src/social-providers/google.ts","../src/social-providers/microsoft-entra-id.ts","../src/social-providers/spotify.ts","../src/social-providers/twitch.ts","../src/utils/hide-metadata.ts","../src/utils/id.ts","../src/social-providers/twitter.ts","../src/social-providers/index.ts","../src/api/routes/email-verification.ts","../src/api/routes/session.ts","../src/utils/date.ts","../src/api/routes/callback.ts","../src/db/schema.ts","../src/api/routes/sign-out.ts","../src/api/routes/forget-password.ts","../src/api/routes/update-user.ts","../src/crypto/random.ts","../src/crypto/index.ts","../src/crypto/password.ts","../src/api/routes/csrf.ts","../src/api/routes/error.ts","../src/api/routes/ok.ts","../src/api/routes/sign-up.ts","../src/utils/shim.ts","../src/plugins/organization/access/index.ts","../src/plugins/organization/access/src/access.ts","../src/plugins/organization/access/statement.ts","../src/plugins/organization/access/utils.ts","../src/plugins/organization/adapter.ts","../src/plugins/organization/call.ts","../src/api/index.ts","../src/api/middlewares/csrf.ts","../src/utils/get-request-ip.ts","../src/plugins/organization/routes/crud-invites.ts","../src/plugins/organization/schema.ts","../src/plugins/organization/routes/crud-members.ts","../src/plugins/organization/routes/crud-org.ts","../src/plugins/two-factor/index.ts","../src/plugins/two-factor/backup-codes/index.ts","../src/plugins/two-factor/verify-middleware.ts","../src/plugins/two-factor/constant.ts","../src/plugins/two-factor/otp/index.ts","../src/plugins/two-factor/totp/index.ts","../src/utils/password.ts","../src/plugins/two-factor/client.ts","../src/plugins/passkey/index.ts","../src/plugins/passkey/client.ts","../src/client/config.ts","../src/utils/url.ts","../src/client/fetch-plugins.ts","../src/client/session-atom.ts","../src/client/query.ts","../src/plugins/username/index.ts","../src/plugins/bearer/index.ts","../src/plugins/magic-link/index.ts","../src/plugins/phone-number/index.ts","../src/plugins/anonymous/index.ts","../src/plugins/admin/index.ts","../src/plugins/generic-oauth/index.ts","../src/plugins/jwt/schema.ts","../src/plugins/jwt/adapter.ts","../src/plugins/jwt/index.ts","../src/plugins/jwt/utils.ts","../src/plugins/multi-session/index.ts"],"sourcesContent":["import { APIError } from \"better-call\";\nimport {\n\ttype ZodArray,\n\ttype ZodLiteral,\n\ttype ZodObject,\n\ttype ZodOptional,\n\tz,\n} from \"zod\";\nimport type { User } from \"../../db/schema\";\nimport { createAuthEndpoint } from \"../../api/call\";\nimport { getSessionFromCtx } from \"../../api/routes\";\nimport type { AuthContext } from \"../../init\";\nimport type { BetterAuthPlugin } from \"../../types/plugins\";\nimport { shimContext } from \"../../utils/shim\";\nimport {\n\ttype AccessControl,\n\ttype Role,\n\tdefaultRoles,\n\ttype defaultStatements,\n} from \"./access\";\nimport { getOrgAdapter } from \"./adapter\";\nimport { orgSessionMiddleware } from \"./call\";\nimport {\n\tacceptInvitation,\n\tcancelInvitation,\n\tcreateInvitation,\n\tgetInvitation,\n\trejectInvitation,\n} from \"./routes/crud-invites\";\nimport { removeMember, updateMemberRole } from \"./routes/crud-members\";\nimport {\n\tcreateOrganization,\n\tdeleteOrganization,\n\tgetFullOrganization,\n\tlistOrganization,\n\tsetActiveOrganization,\n\tupdateOrganization,\n} from \"./routes/crud-org\";\nimport type { Invitation, Member, Organization } from \"./schema\";\nimport type { Prettify } from \"../../types/helper\";\n\nexport interface OrganizationOptions {\n\t/**\n\t * Configure whether new users are able to create new organizations.\n\t * You can also pass a function that returns a boolean.\n\t *\n\t * \t@example\n\t * ```ts\n\t * allowUserToCreateOrganization: async (user) => {\n\t * \t\tconst plan = await getUserPlan(user);\n\t * return plan.name === \"pro\";\n\t * }\n\t * ```\n\t * @default true\n\t */\n\tallowUserToCreateOrganization?:\n\t\t| boolean\n\t\t| ((user: User) => Promise<boolean> | boolean);\n\t/**\n\t * The maximum number of organizations a user can create.\n\t *\n\t * You can also pass a function that returns a boolean\n\t */\n\torganizationLimit?: number | ((user: User) => Promise<boolean> | boolean);\n\t/**\n\t * The role that is assigned to the creator of the organization.\n\t *\n\t * @default \"admin\"\n\t */\n\tcreatorRole?: \"admin\" | \"owner\";\n\t/**\n\t * The number of memberships a user can have in an organization.\n\t *\n\t * @default \"unlimited\"\n\t */\n\tmembershipLimit?: number;\n\t/**\n\t * Configure the roles and permissions for the organization plugin.\n\t *\n\t */\n\tac?: AccessControl;\n\t/**\n\t * Custom permissions for roles.\n\t */\n\troles?: {\n\t\t[key in \"admin\" | \"member\" | \"owner\"]?: Role<any>;\n\t};\n\t/**\n\t * The expiration time for the invitation link.\n\t *\n\t * @default 48 hours\n\t */\n\tinvitationExpiresIn?: number;\n\t/**\n\t * Send an email with the\n\t * invitation link to the user.\n\t *\n\t * Note: Better Auth doesn't\n\t * generate invitation URLs.\n\t * You'll need to construct the\n\t * URL using the invitation ID\n\t * and pass it to the\n\t * acceptInvitation endpoint for\n\t * the user to accept the\n\t * invitation.\n\t *\n\t * @example\n\t * ```ts\n\t * sendInvitationEmail: async (data) => {\n\t * \tconst url = `https://yourapp.com/organization/\n\t * accept-invitation?id=${data.id}`;\n\t * \tawait sendEmail(data.email, \"Invitation to join\n\t * organization\", `Click the link to join the\n\t * organization: ${url}`);\n\t * }\n\t * ```\n\t */\n\tsendInvitationEmail?: (\n\t\tdata: {\n\t\t\t/**\n\t\t\t * the invitation id\n\t\t\t */\n\t\t\tid: string;\n\t\t\t/**\n\t\t\t * the role of the user\n\t\t\t */\n\t\t\trole: \"admin\" | \"owner\" | \"member\";\n\t\t\t/**\n\t\t\t * the email of the user\n\t\t\t */\n\t\t\temail: string;\n\t\t\t/**\n\t\t\t * the organization the user is invited to\n\t\t\t */\n\t\t\torganization: Organization;\n\t\t\t/**\n\t\t\t * the member who is inviting the user\n\t\t\t */\n\t\t\tinviter: Member & {\n\t\t\t\tuser: User;\n\t\t\t};\n\t\t},\n\t\t/**\n\t\t * The request object\n\t\t */\n\t\trequest?: Request,\n\t) => Promise<void>;\n}\n/**\n * Organization plugin for Better Auth. Organization allows you to create teams, members,\n * and manage access control for your users.\n *\n * @example\n * ```ts\n * const auth = createAuth({\n * \tplugins: [\n * \t\torganization({\n * \t\t\tallowUserToCreateOrganization: true,\n * \t\t}),\n * \t],\n * });\n * ```\n */\nexport const organization = <O extends OrganizationOptions>(options?: O) => {\n\tconst endpoints = {\n\t\tcreateOrganization,\n\t\tupdateOrganization,\n\t\tdeleteOrganization,\n\t\tsetActiveOrganization,\n\t\tgetFullOrganization,\n\t\tlistOrganization,\n\t\tcreateInvitation,\n\t\tcancelInvitation,\n\t\tacceptInvitation,\n\t\tgetInvitation,\n\t\trejectInvitation,\n\t\tremoveMember,\n\t\tupdateMemberRole,\n\t};\n\n\tconst roles = {\n\t\t...defaultRoles,\n\t\t...options?.roles,\n\t};\n\n\tconst api = shimContext(endpoints, {\n\t\torgOptions: options || {},\n\t\troles,\n\t\tgetSession: async (context: AuthContext) => {\n\t\t\t//@ts-expect-error\n\t\t\treturn await getSessionFromCtx(context);\n\t\t},\n\t});\n\n\ttype DefaultStatements = typeof defaultStatements;\n\ttype Statements = O[\"ac\"] extends AccessControl<infer S>\n\t\t? S extends Record<string, any>\n\t\t\t? S & DefaultStatements\n\t\t\t: DefaultStatements\n\t\t: DefaultStatements;\n\treturn {\n\t\tid: \"organization\",\n\t\tendpoints: {\n\t\t\t...api,\n\t\t\thasPermission: createAuthEndpoint(\n\t\t\t\t\"/organization/has-permission\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tpermission: z.record(z.string(), z.array(z.string())),\n\t\t\t\t\t}) as unknown as ZodObject<{\n\t\t\t\t\t\tpermission: ZodObject<{\n\t\t\t\t\t\t\t[key in keyof Statements]: ZodOptional<\n\t\t\t\t\t\t\t\t//@ts-expect-error TODO: fix this\n\t\t\t\t\t\t\t\tZodArray<ZodLiteral<Statements[key][number]>>\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\tuse: [orgSessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tif (!ctx.context.session.session.activeOrganizationId) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"No active organization\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst adapter = getOrgAdapter(ctx.context);\n\t\t\t\t\tconst member = await adapter.findMemberByOrgId({\n\t\t\t\t\t\tuserId: ctx.context.session.user.id,\n\t\t\t\t\t\torganizationId:\n\t\t\t\t\t\t\tctx.context.session.session.activeOrganizationId || \"\",\n\t\t\t\t\t});\n\t\t\t\t\tif (!member) {\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"You are not a member of this organization\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst role = roles[member.role];\n\t\t\t\t\tconst result = role.authorize(ctx.body.permission as any);\n\t\t\t\t\tif (result.error) {\n\t\t\t\t\t\treturn ctx.json(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\terror: result.error,\n\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstatus: 403,\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\treturn ctx.json({\n\t\t\t\t\t\terror: null,\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\tschema: {\n\t\t\tsession: {\n\t\t\t\tfields: {\n\t\t\t\t\tactiveOrganizationId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\torganization: {\n\t\t\t\tfields: {\n\t\t\t\t\tname: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\tslug: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t},\n\t\t\t\t\tlogo: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\ttype: \"date\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tmember: {\n\t\t\t\tfields: {\n\t\t\t\t\torganizationId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tuserId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\temail: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\trole: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdefaultValue: \"member\",\n\t\t\t\t\t},\n\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\ttype: \"date\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tinvitation: {\n\t\t\t\tfields: {\n\t\t\t\t\torganizationId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\temail: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\trole: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t\tstatus: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdefaultValue: \"pending\",\n\t\t\t\t\t},\n\t\t\t\t\texpiresAt: {\n\t\t\t\t\t\ttype: \"date\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\tinviterId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t$Infer: {\n\t\t\tOrganization: {} as Organization,\n\t\t\tInvitation: {} as Invitation,\n\t\t\tMember: {} as Member,\n\t\t\tActiveOrganization: {} as Prettify<\n\t\t\t\tOrganization & {\n\t\t\t\t\tmembers: Prettify<\n\t\t\t\t\t\tMember & {\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\tid: string;\n\t\t\t\t\t\t\t\tname: string;\n\t\t\t\t\t\t\t\temail: string;\n\t\t\t\t\t\t\t\timage: string;\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\tinvitations: Invitation[];\n\t\t\t\t}\n\t\t\t>,\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n","import {\n\tAPIError,\n\ttype Endpoint,\n\ttype EndpointResponse,\n\tcreateEndpointCreator,\n\tcreateMiddleware,\n\tcreateMiddlewareCreator,\n} from \"better-call\";\nimport type { AuthContext } from \"../init\";\nimport type { BetterAuthOptions } from \"../types/options\";\n\nexport const optionsMiddleware = createMiddleware(async () => {\n\t/**\n\t * This will be passed on the instance of\n\t * the context. Used to infer the type\n\t * here.\n\t */\n\treturn {} as AuthContext;\n});\n\nexport const createAuthMiddleware = createMiddlewareCreator({\n\tuse: [\n\t\toptionsMiddleware,\n\t\t/**\n\t\t * Only use for post hooks\n\t\t */\n\t\tcreateMiddleware(async () => {\n\t\t\treturn {} as {\n\t\t\t\treturned?: Response;\n\t\t\t};\n\t\t}),\n\t],\n});\n\nexport const createAuthEndpoint = createEndpointCreator({\n\tuse: [optionsMiddleware],\n});\n\nexport type AuthEndpoint = Endpoint<\n\t(ctx: {\n\t\toptions: BetterAuthOptions;\n\t\tbody: any;\n\t\tquery: any;\n\t\tparams: any;\n\t\theaders: Headers;\n\t}) => Promise<EndpointResponse>\n>;\n\nexport type AuthMiddleware = ReturnType<typeof createAuthMiddleware>;\n","import { APIError } from \"better-call\";\nimport { generateCodeVerifier } from \"oslo/oauth2\";\nimport { z } from \"zod\";\nimport { generateState } from \"../../oauth2/state\";\nimport { createAuthEndpoint } from \"../call\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { redirectURLMiddleware } from \"../middlewares/redirect\";\nimport { socialProviderList } from \"../../social-providers\";\nimport { createEmailVerificationToken } from \"./email-verification\";\nimport { logger } from \"../../utils\";\n\nexport const signInOAuth = createAuthEndpoint(\n\t\"/sign-in/social\",\n\t{\n\t\tmethod: \"POST\",\n\t\trequireHeaders: true,\n\t\tquery: z\n\t\t\t.object({\n\t\t\t\t/**\n\t\t\t\t * Redirect to the current URL after the\n\t\t\t\t * user has signed in.\n\t\t\t\t */\n\t\t\t\tcurrentURL: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * Callback URL to redirect to after the user has signed in.\n\t\t\t */\n\t\t\tcallbackURL: z.string().optional(),\n\t\t\t/**\n\t\t\t * OAuth2 provider to use`\n\t\t\t */\n\t\t\tprovider: z.enum(socialProviderList),\n\t\t}),\n\t\tuse: [redirectURLMiddleware],\n\t},\n\tasync (c) => {\n\t\tconst provider = c.context.socialProviders.find(\n\t\t\t(p) => p.id === c.body.provider,\n\t\t);\n\t\tif (!provider) {\n\t\t\tc.context.logger.error(\n\t\t\t\t\"Provider not found. Make sure to add the provider in your auth config\",\n\t\t\t\t{\n\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthrow new APIError(\"NOT_FOUND\", {\n\t\t\t\tmessage: \"Provider not found\",\n\t\t\t});\n\t\t}\n\t\tconst cookie = c.context.authCookies;\n\t\tconst currentURL = c.query?.currentURL\n\t\t\t? new URL(c.query?.currentURL)\n\t\t\t: null;\n\n\t\tconst callbackURL = c.body.callbackURL?.startsWith(\"http\")\n\t\t\t? c.body.callbackURL\n\t\t\t: `${currentURL?.origin}${c.body.callbackURL || \"\"}`;\n\n\t\tconst state = await generateState(\n\t\t\tcallbackURL || currentURL?.origin || c.context.options.baseURL,\n\t\t);\n\t\tawait c.setSignedCookie(\n\t\t\tcookie.state.name,\n\t\t\tstate.hash,\n\t\t\tc.context.secret,\n\t\t\tcookie.state.options,\n\t\t);\n\t\tconst codeVerifier = generateCodeVerifier();\n\t\tawait c.setSignedCookie(\n\t\t\tcookie.pkCodeVerifier.name,\n\t\t\tcodeVerifier,\n\t\t\tc.context.secret,\n\t\t\tcookie.pkCodeVerifier.options,\n\t\t);\n\t\tconst url = await provider.createAuthorizationURL({\n\t\t\tstate: state.raw,\n\t\t\tcodeVerifier,\n\t\t\tredirectURI: `${c.context.baseURL}/callback/${provider.id}`,\n\t\t});\n\t\treturn c.json({\n\t\t\turl: url.toString(),\n\t\t\tstate: state,\n\t\t\tcodeVerifier,\n\t\t\tredirect: true,\n\t\t});\n\t},\n);\n\nexport const signInEmail = createAuthEndpoint(\n\t\"/sign-in/email\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\temail: z.string(),\n\t\t\tpassword: z.string(),\n\t\t\tcallbackURL: z.string().optional(),\n\t\t\t/**\n\t\t\t * If this is true the session will only be valid for the current browser session\n\t\t\t * @default false\n\t\t\t */\n\t\t\tdontRememberMe: z.boolean().default(false).optional(),\n\t\t}),\n\t\tuse: [redirectURLMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options?.emailAndPassword?.enabled) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Email and password is not enabled. Make sure to enable it in the options on you `auth.ts` file. Check `https://better-auth.com/docs/authentication/email-password` for more!\",\n\t\t\t);\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Email and password is not enabled\",\n\t\t\t});\n\t\t}\n\t\tconst { email, password } = ctx.body;\n\t\tconst isValidEmail = z.string().email().safeParse(email);\n\t\tif (!isValidEmail.success) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invalid email\",\n\t\t\t});\n\t\t}\n\t\tconst checkEmail = z.string().email().safeParse(email);\n\t\tif (!checkEmail.success) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invalid email\",\n\t\t\t});\n\t\t}\n\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email, {\n\t\t\tincludeAccounts: true,\n\t\t});\n\n\t\tif (!user) {\n\t\t\tawait ctx.context.password.hash(password);\n\t\t\tctx.context.logger.error(\"User not found\", { email });\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Invalid email or password\",\n\t\t\t});\n\t\t}\n\n\t\tconst credentialAccount = user.accounts.find(\n\t\t\t(a) => a.providerId === \"credential\",\n\t\t);\n\t\tif (!credentialAccount) {\n\t\t\tctx.context.logger.error(\"Credential account not found\", { email });\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Invalid email or password\",\n\t\t\t});\n\t\t}\n\t\tconst currentPassword = credentialAccount?.password;\n\t\tif (!currentPassword) {\n\t\t\tctx.context.logger.error(\"Password not found\", { email });\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Unexpected error\",\n\t\t\t});\n\t\t}\n\t\tconst validPassword = await ctx.context.password.verify(\n\t\t\tcurrentPassword,\n\t\t\tpassword,\n\t\t);\n\t\tif (!validPassword) {\n\t\t\tctx.context.logger.error(\"Invalid password\");\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Invalid email or password\",\n\t\t\t});\n\t\t}\n\n\t\tif (\n\t\t\tctx.context.options?.emailAndPassword?.requireEmailVerification &&\n\t\t\t!user.user.emailVerified\n\t\t) {\n\t\t\tif (!ctx.context.options?.emailVerification?.sendVerificationEmail) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"Email verification is required but no email verification handler is provided\",\n\t\t\t\t);\n\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\tmessage: \"Email is not verified.\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\tctx.context.secret,\n\t\t\t\tuser.user.email,\n\t\t\t);\n\t\t\tconst url = `${ctx.context.options.baseURL}/verify-email?token=${token}`;\n\t\t\tawait ctx.context.options.emailVerification.sendVerificationEmail(\n\t\t\t\tuser.user,\n\t\t\t\turl,\n\t\t\t\ttoken,\n\t\t\t);\n\t\t\tctx.context.logger.error(\"Email not verified\", { email });\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage:\n\t\t\t\t\t\"Email is not verified. Check your email for a verification link\",\n\t\t\t});\n\t\t}\n\n\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\tuser.user.id,\n\t\t\tctx.headers,\n\t\t\tctx.body.dontRememberMe,\n\t\t);\n\n\t\tif (!session) {\n\t\t\tctx.context.logger.error(\"Failed to create session\");\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Failed to create session\",\n\t\t\t});\n\t\t}\n\n\t\tawait setSessionCookie(ctx, session.id, ctx.body.dontRememberMe);\n\t\treturn ctx.json({\n\t\t\tuser: user.user,\n\t\t\tsession,\n\t\t\tredirect: !!ctx.body.callbackURL,\n\t\t\turl: ctx.body.callbackURL,\n\t\t});\n\t},\n);\n","import { generateState as generateStateOAuth } from \"oslo/oauth2\";\nimport { z } from \"zod\";\nimport { hashToBase64 } from \"../crypto/hash\";\nimport { APIError } from \"better-call\";\n\nexport async function generateState(callbackURL?: string) {\n\tconst code = generateStateOAuth();\n\tconst raw = JSON.stringify({\n\t\tcode,\n\t\tcallbackURL,\n\t});\n\tconst hash = await hashToBase64(raw);\n\treturn { raw, hash };\n}\n\nexport function parseState(state: string) {\n\tconst data = z\n\t\t.object({\n\t\t\tcode: z.string(),\n\t\t\tcallbackURL: z.string().optional(),\n\t\t\tcurrentURL: z.string().optional(),\n\t\t})\n\t\t.safeParse(JSON.parse(state));\n\treturn data;\n}\n","import { sha256 } from \"oslo/crypto\";\nimport { constantTimeEqual } from \"./buffer\";\n\nexport async function hashToBase64(\n\tdata: string | ArrayBuffer,\n): Promise<string> {\n\tconst buffer = await sha256(\n\t\ttypeof data === \"string\" ? new TextEncoder().encode(data) : data,\n\t);\n\treturn Buffer.from(buffer).toString(\"base64\");\n}\n\nexport async function compareHash(\n\tdata: string | ArrayBuffer,\n\thash: string,\n): Promise<boolean> {\n\tconst buffer = await sha256(\n\t\ttypeof data === \"string\" ? new TextEncoder().encode(data) : data,\n\t);\n\tconst hashBuffer = Buffer.from(hash, \"base64\");\n\treturn constantTimeEqual(buffer, hashBuffer);\n}\n","/**\n * Compare two buffers in constant time.\n */\nexport function constantTimeEqual(\n\ta: ArrayBuffer | Uint8Array,\n\tb: ArrayBuffer | Uint8Array,\n): boolean {\n\tconst aBuffer = new Uint8Array(a);\n\tconst bBuffer = new Uint8Array(b);\n\tif (aBuffer.length !== bBuffer.length) {\n\t\treturn false;\n\t}\n\tlet c = 0;\n\tfor (let i = 0; i < aBuffer.length; i++) {\n\t\tc |= aBuffer[i]! ^ bBuffer[i]!; // ^: XOR operator\n\t}\n\treturn c === 0;\n}\n","import type { CookieOptions } from \"better-call\";\nimport { TimeSpan } from \"oslo\";\nimport type { BetterAuthOptions } from \"../types/options\";\nimport type { GenericEndpointContext } from \"../types/context\";\nimport { BetterAuthError } from \"../error\";\nimport { env, isProduction } from \"std-env\";\n\nexport function getCookies(options: BetterAuthOptions) {\n\tconst secure =\n\t\toptions.advanced?.useSecureCookies !== undefined\n\t\t\t? options.advanced?.useSecureCookies\n\t\t\t: options.baseURL !== undefined\n\t\t\t\t? options.baseURL.startsWith(\"https://\")\n\t\t\t\t\t? true\n\t\t\t\t\t: false\n\t\t\t\t: isProduction;\n\n\tconst secureCookiePrefix = secure ? \"__Secure-\" : \"\";\n\tconst cookiePrefix = \"better-auth\";\n\tconst sessionMaxAge =\n\t\toptions.session?.expiresIn || new TimeSpan(7, \"d\").seconds();\n\tconst crossSubdomainEnabled =\n\t\t!!options.advanced?.crossSubDomainCookies?.enabled;\n\n\tconst domain = crossSubdomainEnabled\n\t\t? options.advanced?.crossSubDomainCookies?.domain ||\n\t\t\t(options.baseURL ? new URL(options.baseURL).hostname : undefined)\n\t\t: undefined;\n\n\tif (crossSubdomainEnabled && !domain) {\n\t\tthrow new BetterAuthError(\n\t\t\t\"baseURL is required when crossSubdomainCookies are enabled\",\n\t\t);\n\t}\n\n\tconst sameSite = crossSubdomainEnabled ? \"none\" : \"lax\";\n\treturn {\n\t\tsessionToken: {\n\t\t\tname: `${secureCookiePrefix}${cookiePrefix}.session_token`,\n\t\t\toptions: {\n\t\t\t\thttpOnly: true,\n\t\t\t\tsameSite,\n\t\t\t\tpath: \"/\",\n\t\t\t\tsecure: !!secureCookiePrefix,\n\t\t\t\tmaxAge: sessionMaxAge,\n\t\t\t\t...(crossSubdomainEnabled ? { domain } : {}),\n\t\t\t} satisfies CookieOptions,\n\t\t},\n\t\tcsrfToken: {\n\t\t\tname: `${secureCookiePrefix}${cookiePrefix}.csrf_token`,\n\t\t\toptions: {\n\t\t\t\thttpOnly: true,\n\t\t\t\tsameSite,\n\t\t\t\tpath: \"/\",\n\t\t\t\tsecure: !!secureCookiePrefix,\n\t\t\t\tmaxAge: 60 * 60 * 24 * 7,\n\t\t\t\t...(crossSubdomainEnabled ? { domain } : {}),\n\t\t\t} satisfies CookieOptions,\n\t\t},\n\t\tstate: {\n\t\t\tname: `${secureCookiePrefix}${cookiePrefix}.state`,\n\t\t\toptions: {\n\t\t\t\thttpOnly: true,\n\t\t\t\tsameSite,\n\t\t\t\tpath: \"/\",\n\t\t\t\tsecure: !!secureCookiePrefix,\n\t\t\t\tmaxAge: 60 * 15,\n\t\t\t\t...(crossSubdomainEnabled ? { domain } : {}),\n\t\t\t} satisfies CookieOptions,\n\t\t},\n\t\tpkCodeVerifier: {\n\t\t\tname: `${secureCookiePrefix}${cookiePrefix}.pk_code_verifier`,\n\t\t\toptions: {\n\t\t\t\thttpOnly: true,\n\t\t\t\tsameSite,\n\t\t\t\tpath: \"/\",\n\t\t\t\tsecure: !!secureCookiePrefix,\n\t\t\t\tmaxAge: 60 * 15,\n\t\t\t\t...(crossSubdomainEnabled ? { domain } : {}),\n\t\t\t} as CookieOptions,\n\t\t},\n\t\tdontRememberToken: {\n\t\t\tname: `${secureCookiePrefix}${cookiePrefix}.dont_remember`,\n\t\t\toptions: {\n\t\t\t\thttpOnly: true,\n\t\t\t\tsameSite,\n\t\t\t\tpath: \"/\",\n\t\t\t\tsecure: !!secureCookiePrefix,\n\t\t\t\t//no max age so it expires when the browser closes\n\t\t\t\t...(crossSubdomainEnabled ? { domain } : {}),\n\t\t\t} as CookieOptions,\n\t\t},\n\t\tnonce: {\n\t\t\tname: `${secureCookiePrefix}${cookiePrefix}.nonce`,\n\t\t\toptions: {\n\t\t\t\thttpOnly: true,\n\t\t\t\tsameSite,\n\t\t\t\tpath: \"/\",\n\t\t\t\tsecure: !!secureCookiePrefix,\n\t\t\t\tmaxAge: 60 * 15,\n\t\t\t\t...(crossSubdomainEnabled ? { domain } : {}),\n\t\t\t} as CookieOptions,\n\t\t},\n\t};\n}\n\nexport function createCookieGetter(options: BetterAuthOptions) {\n\tconst secure =\n\t\toptions.advanced?.useSecureCookies !== undefined\n\t\t\t? options.advanced?.useSecureCookies\n\t\t\t: options.baseURL?.startsWith(\"https://\") || isProduction;\n\tconst secureCookiePrefix = secure ? \"__Secure-\" : \"\";\n\tconst cookiePrefix = \"better-auth\";\n\n\tconst domain =\n\t\toptions.advanced?.crossSubDomainCookies?.domain ||\n\t\t(options.baseURL ? new URL(options.baseURL).hostname : undefined);\n\n\tfunction getCookie(cookieName: string, opts?: CookieOptions) {\n\t\tconst crossSubdomainEnabled = options.advanced?.crossSubDomainCookies\n\t\t\t?.enabled\n\t\t\t? options.advanced.crossSubDomainCookies.additionalCookies?.includes(\n\t\t\t\t\tcookieName,\n\t\t\t\t)\n\t\t\t: undefined;\n\t\treturn {\n\t\t\tname:\n\t\t\t\tenv.NODE_ENV === \"production\"\n\t\t\t\t\t? `${secureCookiePrefix}${cookiePrefix}.${cookieName}`\n\t\t\t\t\t: `${cookiePrefix}.${cookieName}`,\n\t\t\toptions: {\n\t\t\t\tsecure: !!secureCookiePrefix,\n\t\t\t\tsameSite: \"lax\",\n\t\t\t\tpath: \"/\",\n\t\t\t\tmaxAge: 60 * 15, // 15 minutes in seconds\n\t\t\t\t...opts,\n\t\t\t\t...(crossSubdomainEnabled ? { domain } : {}),\n\t\t\t} as CookieOptions,\n\t\t};\n\t}\n\treturn getCookie;\n}\nexport type BetterAuthCookies = ReturnType<typeof getCookies>;\n\nexport async function setSessionCookie(\n\tctx: GenericEndpointContext,\n\tsessionToken: string,\n\tdontRememberMe?: boolean,\n\toverrides?: Partial<CookieOptions>,\n) {\n\tconst options = ctx.context.authCookies.sessionToken.options;\n\t//@ts-expect-error\n\toptions.maxAge = dontRememberMe\n\t\t? undefined\n\t\t: ctx.context.sessionConfig.expiresIn;\n\n\tawait ctx.setSignedCookie(\n\t\tctx.context.authCookies.sessionToken.name,\n\t\tsessionToken,\n\t\tctx.context.secret,\n\t\t{\n\t\t\t...options,\n\t\t\t...overrides,\n\t\t},\n\t);\n\tif (dontRememberMe) {\n\t\tawait ctx.setSignedCookie(\n\t\t\tctx.context.authCookies.dontRememberToken.name,\n\t\t\t\"true\",\n\t\t\tctx.context.secret,\n\t\t\tctx.context.authCookies.dontRememberToken.options,\n\t\t);\n\t}\n}\n\nexport function deleteSessionCookie(ctx: GenericEndpointContext) {\n\tctx.setCookie(ctx.context.authCookies.sessionToken.name, \"\", {\n\t\tmaxAge: 0,\n\t});\n\tctx.setCookie(ctx.context.authCookies.dontRememberToken.name, \"\", {\n\t\tmaxAge: 0,\n\t});\n}\n\ntype CookieAttributes = {\n\tvalue: string;\n\t[key: string]: string | boolean;\n};\n\nexport function parseSetCookieHeader(\n\theader: string,\n): Map<string, CookieAttributes> {\n\tconst cookieMap = new Map<string, CookieAttributes>();\n\n\t// Split the header into individual cookies\n\tconst cookies = header.split(\", \");\n\n\tcookies.forEach((cookie) => {\n\t\tconst [nameValue, ...attributes] = cookie.split(\"; \");\n\t\tconst [name, value] = nameValue.split(\"=\");\n\n\t\tconst cookieObj: CookieAttributes = { value };\n\n\t\tattributes.forEach((attr) => {\n\t\t\tconst [attrName, attrValue] = attr.split(\"=\");\n\t\t\tcookieObj[attrName.toLowerCase()] = attrValue || true;\n\t\t});\n\n\t\tcookieMap.set(name, cookieObj);\n\t});\n\n\treturn cookieMap;\n}\nexport function parseCookies(cookieHeader: string) {\n\tconst cookies = cookieHeader.split(\"; \");\n\tconst cookieMap = new Map<string, string>();\n\n\tcookies.forEach((cookie) => {\n\t\tconst [name, value] = cookie.split(\"=\");\n\t\tcookieMap.set(name, value);\n\t});\n\treturn cookieMap;\n}\n\nexport type EligibleCookies = (string & {}) | (keyof BetterAuthCookies & {});\n","export class BetterAuthError extends Error {\n\tconstructor(message: string, cause?: string) {\n\t\tsuper(message);\n\t\tthis.name = \"BetterAuthError\";\n\t\tthis.message = message;\n\t\tthis.cause = cause;\n\t}\n}\nexport class MissingDependencyError extends BetterAuthError {\n\tconstructor(pkgName: string) {\n\t\tsuper(\n\t\t\t`The package \"${pkgName}\" is required. Make sure it is installed.`,\n\t\t\tpkgName,\n\t\t);\n\t}\n}\n","import { APIError } from \"better-call\";\nimport { createAuthMiddleware } from \"../call\";\nimport { logger } from \"../../utils/logger\";\n\n/**\n * Middleware to validate callbackURL and currentURL against trustedOrigins,\n * preventing open redirect attacks.\n */\nexport const redirectURLMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst { body, query, headers, context } = ctx;\n\n\tconst callbackURL =\n\t\tbody?.callbackURL ||\n\t\tquery?.callbackURL ||\n\t\tquery?.redirectTo ||\n\t\tbody?.redirectTo;\n\tconst currentURL =\n\t\tquery?.currentURL || headers?.get(\"referer\") || context.baseURL;\n\tconst trustedOrigins = context.trustedOrigins;\n\n\tconst validateURL = (url: string | undefined, label: string) => {\n\t\tif (url?.startsWith(\"http\")) {\n\t\t\tconst isTrustedOrigin = trustedOrigins.some((origin) =>\n\t\t\t\turl.startsWith(origin),\n\t\t\t);\n\t\t\tif (!isTrustedOrigin) {\n\t\t\t\tlogger.error(`Invalid ${label}`, { [label]: url, trustedOrigins });\n\t\t\t\tthrow new APIError(\"FORBIDDEN\", { message: `Invalid ${label}` });\n\t\t\t}\n\t\t}\n\t};\n\n\tvalidateURL(callbackURL, \"callbackURL\");\n\tvalidateURL(currentURL, \"currentURL\");\n});\n","import { createConsola } from \"consola\";\n\nconst consola = createConsola({\n\tformatOptions: {\n\t\tdate: false,\n\t\tcolors: true,\n\t\tcompact: true,\n\t},\n\tdefaults: {\n\t\ttag: \"Better Auth\",\n\t},\n});\n\nexport const createLogger = (options?: {\n\tdisabled?: boolean;\n}) => {\n\treturn {\n\t\tlog: (...args: any[]) => {\n\t\t\t!options?.disabled && consola.log(\"\", ...args);\n\t\t},\n\t\terror: (...args: any[]) => {\n\t\t\t!options?.disabled && consola.error(\"\", ...args);\n\t\t},\n\t\twarn: (...args: any[]) => {\n\t\t\t!options?.disabled && consola.warn(\"\", ...args);\n\t\t},\n\t\tinfo: (...args: any[]) => {\n\t\t\t!options?.disabled && consola.info(\"\", ...args);\n\t\t},\n\t\tdebug: (...args: any[]) => {\n\t\t\t!options?.disabled && consola.debug(\"\", ...args);\n\t\t},\n\t\tbox: (...args: any[]) => {\n\t\t\t!options?.disabled && consola.box(\"\", ...args);\n\t\t},\n\t\tsuccess: (...args: any[]) => {\n\t\t\t!options?.disabled && consola.success(\"\", ...args);\n\t\t},\n\t\tbreak: (...args: any[]) => {\n\t\t\t!options?.disabled && console.log(\"\\n\");\n\t\t},\n\t};\n};\n\nexport const logger = createLogger();\n","import type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { validateAuthorizationCode } from \"../oauth2\";\nexport interface AppleProfile {\n\t/**\n\t * The subject registered claim identifies the principal that’s the subject\n\t * of the identity token. Because this token is for your app, the value is\n\t * the unique identifier for the user.\n\t */\n\tsub: string;\n\t/**\n\t * A String value representing the user's email address.\n\t * The email address is either the user's real email address or the proxy\n\t * address, depending on their status private email relay service.\n\t */\n\temail: string;\n\t/**\n\t * A string or Boolean value that indicates whether the service verifies\n\t * the email. The value can either be a string (\"true\" or \"false\") or a\n\t * Boolean (true or false). The system may not verify email addresses for\n\t * Sign in with Apple at Work & School users, and this claim is \"false\" or\n\t * false for those users.\n\t */\n\temail_verified: true | \"true\";\n\t/**\n\t * A string or Boolean value that indicates whether the email that the user\n\t * shares is the proxy address. The value can either be a string (\"true\" or\n\t * \"false\") or a Boolean (true or false).\n\t */\n\tis_private_email: boolean;\n\t/**\n\t * An Integer value that indicates whether the user appears to be a real\n\t * person. Use the value of this claim to mitigate fraud. The possible\n\t * values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). For\n\t * more information, see ASUserDetectionStatus. This claim is present only\n\t * in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14\n\t * and later. The claim isn’t present or supported for web-based apps.\n\t */\n\treal_user_status: number;\n\t/**\n\t * The user’s full name in the format provided during the authorization\n\t * process.\n\t */\n\tname: string;\n}\n\nexport interface AppleOptions extends ProviderOptions {}\n\nexport const apple = (options: AppleOptions) => {\n\tconst tokenEndpoint = \"https://appleid.apple.com/auth/token\";\n\treturn {\n\t\tid: \"apple\",\n\t\tname: \"Apple\",\n\t\tcreateAuthorizationURL({ state, scopes, redirectURI }) {\n\t\t\tconst _scope = options.scope || scopes || [\"email\", \"name\", \"openid\"];\n\t\t\treturn new URL(\n\t\t\t\t`https://appleid.apple.com/auth/authorize?client_id=${\n\t\t\t\t\toptions.clientId\n\t\t\t\t}&response_type=code&redirect_uri=${\n\t\t\t\t\tredirectURI || options.redirectURI\n\t\t\t\t}&scope=${_scope.join(\" \")}&state=${state}`,\n\t\t\t);\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint,\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tif (!token.idToken) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst data = parseJWT(token.idToken)?.payload as AppleProfile | null;\n\t\t\tif (!data) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: data.sub,\n\t\t\t\t\tname: data.name,\n\t\t\t\t\temail: data.email,\n\t\t\t\t\temailVerified: data.email_verified === \"true\",\n\t\t\t\t},\n\t\t\t\tdata,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<AppleProfile>;\n};\n","import { sha256 } from \"oslo/crypto\";\nimport { base64url } from \"oslo/encoding\";\nimport type { OAuth2Tokens } from \"./types\";\n\nexport async function generateCodeChallenge(codeVerifier: string) {\n\tconst codeChallengeBytes = await sha256(\n\t\tnew TextEncoder().encode(codeVerifier),\n\t);\n\treturn base64url.encode(new Uint8Array(codeChallengeBytes), {\n\t\tincludePadding: false,\n\t});\n}\n\nexport function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens {\n\treturn {\n\t\ttokenType: data.token_type,\n\t\taccessToken: data.access_token,\n\t\trefreshToken: data.refresh_token,\n\t\taccessTokenExpiresAt: data.expires_at\n\t\t\t? new Date((Date.now() + data.expires_in) * 1000)\n\t\t\t: undefined,\n\t\tscopes: data?.scope\n\t\t\t? typeof data.scope === \"string\"\n\t\t\t\t? data.scope.split(\" \")\n\t\t\t\t: data.scope\n\t\t\t: [],\n\t\tidToken: data.id_token,\n\t};\n}\n","import type { ProviderOptions } from \"./types\";\nimport { generateCodeChallenge } from \"./utils\";\n\nexport async function createAuthorizationURL({\n\tid,\n\toptions,\n\tauthorizationEndpoint,\n\tstate,\n\tcodeVerifier,\n\tscopes,\n\tclaims,\n\tdisablePkce,\n\tredirectURI,\n}: {\n\tid: string;\n\toptions: ProviderOptions;\n\tredirectURI: string;\n\tauthorizationEndpoint: string;\n\tstate: string;\n\tcodeVerifier?: string;\n\tscopes: string[];\n\tdisablePkce?: boolean;\n\tclaims?: string[];\n}) {\n\tconst url = new URL(authorizationEndpoint);\n\turl.searchParams.set(\"response_type\", \"code\");\n\turl.searchParams.set(\"client_id\", options.clientId);\n\turl.searchParams.set(\"state\", state);\n\turl.searchParams.set(\"scope\", scopes.join(\" \"));\n\turl.searchParams.set(\"redirect_uri\", options.redirectURI || redirectURI);\n\n\tif (!disablePkce && codeVerifier) {\n\t\tconst codeChallenge = await generateCodeChallenge(codeVerifier);\n\t\turl.searchParams.set(\"code_challenge_method\", \"S256\");\n\t\turl.searchParams.set(\"code_challenge\", codeChallenge);\n\t}\n\tif (claims) {\n\t\tconst claimsObj = claims.reduce(\n\t\t\t(acc, claim) => {\n\t\t\t\tacc[claim] = null;\n\t\t\t\treturn acc;\n\t\t\t},\n\t\t\t{} as Record<string, null>,\n\t\t);\n\t\turl.searchParams.set(\n\t\t\t\"claims\",\n\t\t\tJSON.stringify({\n\t\t\t\tid_token: { email: null, email_verified: null, ...claimsObj },\n\t\t\t}),\n\t\t);\n\t}\n\treturn url;\n}\n","import { betterFetch } from \"@better-fetch/fetch\";\nimport type { ProviderOptions } from \"./types\";\nimport { getOAuth2Tokens } from \"./utils\";\n\nexport async function validateAuthorizationCode({\n\tcode,\n\tcodeVerifier,\n\tredirectURI,\n\toptions,\n\ttokenEndpoint,\n}: {\n\tcode: string;\n\tredirectURI: string;\n\toptions: ProviderOptions;\n\tcodeVerifier?: string;\n\ttokenEndpoint: string;\n}) {\n\tconst body = new URLSearchParams();\n\tbody.set(\"grant_type\", \"authorization_code\");\n\tbody.set(\"code\", code);\n\tcodeVerifier && body.set(\"code_verifier\", codeVerifier);\n\tbody.set(\"redirect_uri\", redirectURI);\n\tbody.set(\"client_id\", options.clientId);\n\tbody.set(\"client_secret\", options.clientSecret);\n\tconst { data, error } = await betterFetch<object>(tokenEndpoint, {\n\t\tmethod: \"POST\",\n\t\tbody: body,\n\t\theaders: {\n\t\t\t\"content-type\": \"application/x-www-form-urlencoded\",\n\t\t\taccept: \"application/json\",\n\t\t\t\"user-agent\": \"better-auth\",\n\t\t},\n\t});\n\tif (error) {\n\t\tthrow error;\n\t}\n\tconst tokens = getOAuth2Tokens(data);\n\treturn tokens;\n}\n","import type { OAuth2Tokens } from \".\";\n\nexport function getAccountTokens(tokens: OAuth2Tokens) {\n\tconst accessToken = tokens.accessToken;\n\tlet refreshToken = tokens.refreshToken;\n\tlet accessTokenExpiresAt = undefined;\n\ttry {\n\t\taccessTokenExpiresAt = tokens.accessTokenExpiresAt;\n\t} catch {}\n\treturn {\n\t\taccessToken,\n\t\trefreshToken,\n\t\texpiresAt: accessTokenExpiresAt,\n\t};\n}\n","import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { validateAuthorizationCode } from \"../oauth2\";\n\nexport interface DiscordProfile extends Record<string, any> {\n\t/** the user's id (i.e. the numerical snowflake) */\n\tid: string;\n\t/** the user's username, not unique across the platform */\n\tusername: string;\n\t/** the user's Discord-tag */\n\tdiscriminator: string;\n\t/** the user's display name, if it is set */\n\tglobal_name: string | null;\n\t/**\n\t * the user's avatar hash:\n\t * https://discord.com/developers/docs/reference#image-formatting\n\t */\n\tavatar: string | null;\n\t/** whether the user belongs to an OAuth2 application */\n\tbot?: boolean;\n\t/**\n\t * whether the user is an Official Discord System user (part of the urgent\n\t * message system)\n\t */\n\tsystem?: boolean;\n\t/** whether the user has two factor enabled on their account */\n\tmfa_enabled: boolean;\n\t/**\n\t * the user's banner hash:\n\t * https://discord.com/developers/docs/reference#image-formatting\n\t */\n\tbanner: string | null;\n\n\t/** the user's banner color encoded as an integer representation of hexadecimal color code */\n\taccent_color: number | null;\n\n\t/**\n\t * the user's chosen language option:\n\t * https://discord.com/developers/docs/reference#locales\n\t */\n\tlocale: string;\n\t/** whether the email on this account has been verified */\n\tverified: boolean;\n\t/** the user's email */\n\temail: string;\n\t/**\n\t * the flags on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-user-flags\n\t */\n\tflags: number;\n\t/**\n\t * the type of Nitro subscription on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-premium-types\n\t */\n\tpremium_type: number;\n\t/**\n\t * the public flags on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-user-flags\n\t */\n\tpublic_flags: number;\n\t/** undocumented field; corresponds to the user's custom nickname */\n\tdisplay_name: string | null;\n\t/**\n\t * undocumented field; corresponds to the Discord feature where you can e.g.\n\t * put your avatar inside of an ice cube\n\t */\n\tavatar_decoration: string | null;\n\t/**\n\t * undocumented field; corresponds to the premium feature where you can\n\t * select a custom banner color\n\t */\n\tbanner_color: string | null;\n\t/** undocumented field; the CDN URL of their profile picture */\n\timage_url: string;\n}\n\nexport interface DiscordOptions extends ProviderOptions {}\n\nexport const discord = (options: DiscordOptions) => {\n\treturn {\n\t\tid: \"discord\",\n\t\tname: \"Discord\",\n\t\tcreateAuthorizationURL({ state, scopes, redirectURI }) {\n\t\t\tconst _scopes = options.scope || scopes || [\"identify\", \"email\"];\n\t\t\treturn new URL(\n\t\t\t\t`https://discord.com/api/oauth2/authorize?scope=${_scopes.join(\n\t\t\t\t\t\"+\",\n\t\t\t\t)}&response_type=code&client_id=${\n\t\t\t\t\toptions.clientId\n\t\t\t\t}&redirect_uri=${encodeURIComponent(\n\t\t\t\t\toptions.redirectURI || redirectURI,\n\t\t\t\t)}&state=${state}`,\n\t\t\t);\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://discord.com/api/oauth2/token\",\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tconst { data: profile, error } = await betterFetch<DiscordProfile>(\n\t\t\t\t\"https://discord.com/api/users/@me\",\n\t\t\t\t{\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tauthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (profile.avatar === null) {\n\t\t\t\tconst defaultAvatarNumber =\n\t\t\t\t\tprofile.discriminator === \"0\"\n\t\t\t\t\t\t? Number(BigInt(profile.id) >> BigInt(22)) % 6\n\t\t\t\t\t\t: parseInt(profile.discriminator) % 5;\n\t\t\t\tprofile.image_url = `https://cdn.discordapp.com/embed/avatars/${defaultAvatarNumber}.png`;\n\t\t\t} else {\n\t\t\t\tconst format = profile.avatar.startsWith(\"a_\") ? \"gif\" : \"png\";\n\t\t\t\tprofile.image_url = `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.id,\n\t\t\t\t\tname: profile.display_name || profile.username || \"\",\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\temailVerified: profile.verified,\n\t\t\t\t\timage: profile.image_url,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<DiscordProfile>;\n};\n","import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { createAuthorizationURL, validateAuthorizationCode } from \"../oauth2\";\n\nexport interface FacebookProfile {\n\tid: string;\n\tname: string;\n\temail: string;\n\temail_verified: boolean;\n\tpicture: {\n\t\tdata: {\n\t\t\theight: number;\n\t\t\tis_silhouette: boolean;\n\t\t\turl: string;\n\t\t\twidth: number;\n\t\t};\n\t};\n}\nexport interface FacebookOptions extends ProviderOptions {}\nexport const facebook = (options: FacebookOptions) => {\n\treturn {\n\t\tid: \"facebook\",\n\t\tname: \"Facebook\",\n\t\tasync createAuthorizationURL({ state, scopes, redirectURI }) {\n\t\t\tconst _scopes = options.scope || scopes || [\"email\", \"public_profile\"];\n\t\t\treturn await createAuthorizationURL({\n\t\t\t\tid: \"facebook\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://www.facebook.com/v21.0/dialog/oauth\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tredirectURI,\n\t\t\t});\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://graph.facebook.com/oauth/access_token\",\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tconst { data: profile, error } = await betterFetch<FacebookProfile>(\n\t\t\t\t\"https://graph.facebook.com/me?fields=id,name,email,picture\",\n\t\t\t\t{\n\t\t\t\t\tauth: {\n\t\t\t\t\t\ttype: \"Bearer\",\n\t\t\t\t\t\ttoken: token.accessToken,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.id,\n\t\t\t\t\tname: profile.name,\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\timage: profile.picture.data.url,\n\t\t\t\t\temailVerified: profile.email_verified,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<FacebookProfile>;\n};\n","import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { createAuthorizationURL, validateAuthorizationCode } from \"../oauth2\";\n\nexport interface GithubProfile {\n\tlogin: string;\n\tid: string;\n\tnode_id: string;\n\tavatar_url: string;\n\tgravatar_id: string;\n\turl: string;\n\thtml_url: string;\n\tfollowers_url: string;\n\tfollowing_url: string;\n\tgists_url: string;\n\tstarred_url: string;\n\tsubscriptions_url: string;\n\torganizations_url: string;\n\trepos_url: string;\n\tevents_url: string;\n\treceived_events_url: string;\n\ttype: string;\n\tsite_admin: boolean;\n\tname: string;\n\tcompany: string;\n\tblog: string;\n\tlocation: string;\n\temail: string;\n\thireable: boolean;\n\tbio: string;\n\ttwitter_username: string;\n\tpublic_repos: string;\n\tpublic_gists: string;\n\tfollowers: string;\n\tfollowing: string;\n\tcreated_at: string;\n\tupdated_at: string;\n\tprivate_gists: string;\n\ttotal_private_repos: string;\n\towned_private_repos: string;\n\tdisk_usage: string;\n\tcollaborators: string;\n\ttwo_factor_authentication: boolean;\n\tplan: {\n\t\tname: string;\n\t\tspace: string;\n\t\tprivate_repos: string;\n\t\tcollaborators: string;\n\t};\n\tfirst_name: string;\n\tlast_name: string;\n}\n\nexport interface GithubOptions extends ProviderOptions {}\nexport const github = (options: GithubOptions) => {\n\tconst tokenEndpoint = \"https://github.com/login/oauth/access_token\";\n\treturn {\n\t\tid: \"github\",\n\t\tname: \"Github\",\n\t\tcreateAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {\n\t\t\tconst _scopes = options.scope || scopes || [\"user:email\"];\n\t\t\treturn createAuthorizationURL({\n\t\t\t\tid: \"github\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://github.com/login/oauth/authorize\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tredirectURI,\n\t\t\t\tcodeVerifier,\n\t\t\t});\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint,\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tconst { data: profile, error } = await betterFetch<GithubProfile>(\n\t\t\t\t\"https://api.github.com/user\",\n\t\t\t\t{\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"User-Agent\": \"better-auth\",\n\t\t\t\t\t\tauthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tlet emailVerified = false;\n\t\t\tif (!profile.email) {\n\t\t\t\tconst { data, error } = await betterFetch<\n\t\t\t\t\t{\n\t\t\t\t\t\temail: string;\n\t\t\t\t\t\tprimary: boolean;\n\t\t\t\t\t\tverified: boolean;\n\t\t\t\t\t\tvisibility: \"public\" | \"private\";\n\t\t\t\t\t}[]\n\t\t\t\t>(\"https://api.github.com/user/emails\", {\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tauthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t\t\"User-Agent\": \"better-auth\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (!error) {\n\t\t\t\t\tprofile.email = (data.find((e) => e.primary) ?? data[0])\n\t\t\t\t\t\t?.email as string;\n\t\t\t\t\temailVerified =\n\t\t\t\t\t\tdata.find((e) => e.email === profile.email)?.verified ?? false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.id.toString(),\n\t\t\t\t\tname: profile.name || profile.login,\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\timage: profile.avatar_url,\n\t\t\t\t\temailVerified,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<GithubProfile>;\n};\n","import { parseJWT } from \"oslo/jwt\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { BetterAuthError } from \"../error\";\nimport { logger } from \"../utils/logger\";\nimport { createAuthorizationURL, validateAuthorizationCode } from \"../oauth2\";\n\nexport interface GoogleProfile {\n\taud: string;\n\tazp: string;\n\temail: string;\n\temail_verified: boolean;\n\texp: number;\n\t/**\n\t * The family name of the user, or last name in most\n\t * Western languages.\n\t */\n\tfamily_name: string;\n\t/**\n\t * The given name of the user, or first name in most\n\t * Western languages.\n\t */\n\tgiven_name: string;\n\thd?: string;\n\tiat: number;\n\tiss: string;\n\tjti?: string;\n\tlocale?: string;\n\tname: string;\n\tnbf?: number;\n\tpicture: string;\n\tsub: string;\n}\n\nexport interface GoogleOptions extends ProviderOptions {}\n\nexport const google = (options: GoogleOptions) => {\n\treturn {\n\t\tid: \"google\",\n\t\tname: \"Google\",\n\t\tcreateAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {\n\t\t\tif (!options.clientId || !options.clientSecret) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"Client Id and Client Secret is required for Google. Make sure to provide them in the options.\",\n\t\t\t\t);\n\t\t\t\tthrow new BetterAuthError(\"CLIENT_ID_AND_SECRET_REQUIRED\");\n\t\t\t}\n\t\t\tif (!codeVerifier) {\n\t\t\t\tthrow new BetterAuthError(\"codeVerifier is required for Google\");\n\t\t\t}\n\t\t\tconst _scopes = options.scope || scopes || [\"email\", \"profile\"];\n\n\t\t\tconst url = createAuthorizationURL({\n\t\t\t\tid: \"google\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://accounts.google.com/o/oauth2/auth\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t});\n\t\t\treturn url;\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://oauth2.googleapis.com/token\",\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tif (!token.idToken) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst user = parseJWT(token.idToken)?.payload as GoogleProfile;\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: user.sub,\n\t\t\t\t\tname: user.name,\n\t\t\t\t\temail: user.email,\n\t\t\t\t\timage: user.picture,\n\t\t\t\t\temailVerified: user.email_verified,\n\t\t\t\t},\n\t\t\t\tdata: user,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<GoogleProfile>;\n};\n","import type { ProviderOptions } from \"../oauth2\";\nimport { validateAuthorizationCode, createAuthorizationURL } from \"../oauth2\";\nimport type { OAuthProvider } from \"../oauth2\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { logger } from \"../utils/logger\";\n\nexport interface MicrosoftEntraIDProfile extends Record<string, any> {\n\tsub: string;\n\tname: string;\n\temail: string;\n\tpicture: string;\n}\n\nexport interface MicrosoftOptions extends ProviderOptions {\n\t/**\n\t * The tenant ID of the Microsoft account\n\t * @default \"common\"\n\t */\n\ttenantId?: string;\n\t/**\n\t * The size of the profile photo\n\t * @default 48\n\t */\n\tprofilePhotoSize?: 48 | 64 | 96 | 120 | 240 | 360 | 432 | 504 | 648;\n\t/**\n\t * Disable profile photo\n\t */\n\tdisableProfilePhoto?: boolean;\n}\n\nexport const microsoft = (options: MicrosoftOptions) => {\n\tconst tenant = options.tenantId || \"common\";\n\tconst authorizationEndpoint = `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize`;\n\tconst tokenEndpoint = `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`;\n\treturn {\n\t\tid: \"microsoft\",\n\t\tname: \"Microsoft EntraID\",\n\t\tcreateAuthorizationURL(data) {\n\t\t\tconst scopes = options.scope ||\n\t\t\t\tdata.scopes || [\"openid\", \"profile\", \"email\", \"User.Read\"];\n\t\t\treturn createAuthorizationURL({\n\t\t\t\tid: \"microsoft\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint,\n\t\t\t\tstate: data.state,\n\t\t\t\tcodeVerifier: data.codeVerifier,\n\t\t\t\tscopes,\n\t\t\t\tredirectURI: data.redirectURI,\n\t\t\t});\n\t\t},\n\t\tvalidateAuthorizationCode({ code, codeVerifier, redirectURI }) {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint,\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tif (!token.idToken) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst user = parseJWT(token.idToken)?.payload as MicrosoftEntraIDProfile;\n\t\t\tconst profilePhotoSize = options.profilePhotoSize || 48;\n\t\t\tawait betterFetch<ArrayBuffer>(\n\t\t\t\t`https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`,\n\t\t\t\t{\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tAuthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t\tasync onResponse(context) {\n\t\t\t\t\t\tif (options.disableProfilePhoto || !context.response.ok) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst response = context.response.clone();\n\t\t\t\t\t\t\tconst pictureBuffer = await response.arrayBuffer();\n\t\t\t\t\t\t\tconst pictureBase64 =\n\t\t\t\t\t\t\t\tBuffer.from(pictureBuffer).toString(\"base64\");\n\t\t\t\t\t\t\tuser.picture = `data:image/jpeg;base64, ${pictureBase64}`;\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tlogger.error(e);\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\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: user.sub,\n\t\t\t\t\tname: user.name,\n\t\t\t\t\temail: user.email,\n\t\t\t\t\timage: user.picture,\n\t\t\t\t\temailVerified: true,\n\t\t\t\t},\n\t\t\t\tdata: user,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider;\n};\n","import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { createAuthorizationURL, validateAuthorizationCode } from \"../oauth2\";\n\nexport interface SpotifyProfile {\n\tid: string;\n\tdisplay_name: string;\n\temail: string;\n\timages: {\n\t\turl: string;\n\t}[];\n}\n\nexport interface SpotifyOptions extends ProviderOptions {}\n\nexport const spotify = (options: SpotifyOptions) => {\n\treturn {\n\t\tid: \"spotify\",\n\t\tname: \"Spotify\",\n\t\tcreateAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {\n\t\t\tconst _scopes = options.scope || scopes || [\"user-read-email\"];\n\t\t\treturn createAuthorizationURL({\n\t\t\t\tid: \"spotify\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://accounts.spotify.com/authorize\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t});\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://accounts.spotify.com/api/token\",\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tconst { data: profile, error } = await betterFetch<SpotifyProfile>(\n\t\t\t\t\"https://api.spotify.com/v1/me\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tAuthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.id,\n\t\t\t\t\tname: profile.display_name,\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\timage: profile.images[0]?.url,\n\t\t\t\t\temailVerified: false,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<SpotifyProfile>;\n};\n","import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { logger } from \"../utils\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { createAuthorizationURL, validateAuthorizationCode } from \"../oauth2\";\n\nexport interface TwitchProfile {\n\t/**\n\t * The sub of the user\n\t */\n\tsub: string;\n\t/**\n\t * The preferred username of the user\n\t */\n\tpreferred_username: string;\n\t/**\n\t * The email of the user\n\t */\n\temail: string;\n\t/**\n\t * The picture of the user\n\t */\n\tpicture: string;\n}\n\nexport interface TwitchOptions extends ProviderOptions {\n\tclaims?: string[];\n}\nexport const twitch = (options: TwitchOptions) => {\n\treturn {\n\t\tid: \"twitch\",\n\t\tname: \"Twitch\",\n\t\tcreateAuthorizationURL({ state, scopes, redirectURI }) {\n\t\t\tconst _scopes = options.scope || scopes || [\"user:read:email\", \"openid\"];\n\t\t\treturn createAuthorizationURL({\n\t\t\t\tid: \"twitch\",\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://id.twitch.tv/oauth2/authorize\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tclaims: options.claims || [\n\t\t\t\t\t\"email\",\n\t\t\t\t\t\"email_verified\",\n\t\t\t\t\t\"preferred_username\",\n\t\t\t\t\t\"picture\",\n\t\t\t\t],\n\t\t\t});\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://id.twitch.tv/oauth2/token\",\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tconst idToken = token.idToken;\n\t\t\tif (!idToken) {\n\t\t\t\tlogger.error(\"No idToken found in token\");\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst profile = parseJWT(idToken)?.payload as TwitchProfile;\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.sub,\n\t\t\t\t\tname: profile.preferred_username,\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\timage: profile.picture,\n\t\t\t\t\temailVerified: false,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<TwitchProfile>;\n};\n","export const HIDE_METADATA = {\n\tisAction: false as const,\n};\n","import { nanoid } from \"nanoid\";\n\nexport const generateId = (size?: number) => {\n\treturn nanoid(size);\n};\n","import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { createAuthorizationURL, validateAuthorizationCode } from \"../oauth2\";\n\nexport interface TwitterProfile {\n\tdata: {\n\t\t/**\n\t\t * Unique identifier of this user. This is returned as a string in order to avoid complications with languages and tools\n\t\t * that cannot handle large integers.\n\t\t */\n\t\tid: string;\n\t\t/** The friendly name of this user, as shown on their profile. */\n\t\tname: string;\n\t\t/** @note Email is currently unsupported by Twitter. */\n\t\temail?: string;\n\t\t/** The Twitter handle (screen name) of this user. */\n\t\tusername: string;\n\t\t/**\n\t\t * The location specified in the user's profile, if the user provided one.\n\t\t * As this is a freeform value, it may not indicate a valid location, but it may be fuzzily evaluated when performing searches with location queries.\n\t\t *\n\t\t * To return this field, add `user.fields=location` in the authorization request's query parameter.\n\t\t */\n\t\tlocation?: string;\n\t\t/**\n\t\t * This object and its children fields contain details about text that has a special meaning in the user's description.\n\t\t *\n\t\t *To return this field, add `user.fields=entities` in the authorization request's query parameter.\n\t\t */\n\t\tentities?: {\n\t\t\t/** Contains details about the user's profile website. */\n\t\t\turl: {\n\t\t\t\t/** Contains details about the user's profile website. */\n\t\t\t\turls: Array<{\n\t\t\t\t\t/** The start position (zero-based) of the recognized user's profile website. All start indices are inclusive. */\n\t\t\t\t\tstart: number;\n\t\t\t\t\t/** The end position (zero-based) of the recognized user's profile website. This end index is exclusive. */\n\t\t\t\t\tend: number;\n\t\t\t\t\t/** The URL in the format entered by the user. */\n\t\t\t\t\turl: string;\n\t\t\t\t\t/** The fully resolved URL. */\n\t\t\t\t\texpanded_url: string;\n\t\t\t\t\t/** The URL as displayed in the user's profile. */\n\t\t\t\t\tdisplay_url: string;\n\t\t\t\t}>;\n\t\t\t};\n\t\t\t/** Contains details about URLs, Hashtags, Cashtags, or mentions located within a user's description. */\n\t\t\tdescription: {\n\t\t\t\thashtags: Array<{\n\t\t\t\t\tstart: number;\n\t\t\t\t\tend: number;\n\t\t\t\t\ttag: string;\n\t\t\t\t}>;\n\t\t\t};\n\t\t};\n\t\t/**\n\t\t * Indicate if this user is a verified Twitter user.\n\t\t *\n\t\t * To return this field, add `user.fields=verified` in the authorization request's query parameter.\n\t\t */\n\t\tverified?: boolean;\n\t\t/**\n\t\t * The text of this user's profile description (also known as bio), if the user provided one.\n\t\t *\n\t\t * To return this field, add `user.fields=description` in the authorization request's query parameter.\n\t\t */\n\t\tdescription?: string;\n\t\t/**\n\t\t * The URL specified in the user's profile, if present.\n\t\t *\n\t\t * To return this field, add `user.fields=url` in the authorization request's query parameter.\n\t\t */\n\t\turl?: string;\n\t\t/** The URL to the profile image for this user, as shown on the user's profile. */\n\t\tprofile_image_url?: string;\n\t\tprotected?: boolean;\n\t\t/**\n\t\t * Unique identifier of this user's pinned Tweet.\n\t\t *\n\t\t * You can obtain the expanded object in `includes.tweets` by adding `expansions=pinned_tweet_id` in the authorization request's query parameter.\n\t\t */\n\t\tpinned_tweet_id?: string;\n\t\tcreated_at?: string;\n\t};\n\tincludes?: {\n\t\ttweets?: Array<{\n\t\t\tid: string;\n\t\t\ttext: string;\n\t\t}>;\n\t};\n\t[claims: string]: unknown;\n}\n\nexport interface TwitterOption extends ProviderOptions {}\n\nexport const twitter = (options: TwitterOption) => {\n\treturn {\n\t\tid: \"twitter\",\n\t\tname: \"Twitter\",\n\t\tcreateAuthorizationURL(data) {\n\t\t\tconst _scopes = options.scope || data.scopes || [\"account_info.read\"];\n\t\t\treturn createAuthorizationURL({\n\t\t\t\tid: \"twitter\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://twitter.com/i/oauth2/authorize\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate: data.state,\n\t\t\t\tcodeVerifier: data.codeVerifier,\n\t\t\t\tredirectURI: data.redirectURI,\n\t\t\t});\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://id.twitch.tv/oauth2/token\",\n\t\t\t});\n\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tconst { data: profile, error } = await betterFetch<TwitterProfile>(\n\t\t\t\t\"https://api.x.com/2/users/me?user.fields=profile_image_url\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tAuthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (!profile.data.email) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.data.id,\n\t\t\t\t\tname: profile.data.name,\n\t\t\t\t\temail: profile.data.email,\n\t\t\t\t\timage: profile.data.profile_image_url,\n\t\t\t\t\temailVerified: profile.data.verified || false,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<TwitterProfile>;\n};\n","import type { Prettify } from \"../types\";\nimport { apple } from \"./apple\";\nimport { discord } from \"./discord\";\nimport { facebook } from \"./facebook\";\nimport { github } from \"./github\";\nimport { google } from \"./google\";\nimport { microsoft } from \"./microsoft-entra-id\";\nimport { spotify } from \"./spotify\";\nimport { twitch } from \"./twitch\";\nimport { twitter } from \"./twitter\";\n\nexport const socialProviders = {\n\tapple,\n\tdiscord,\n\tfacebook,\n\tgithub,\n\tmicrosoft,\n\tgoogle,\n\tspotify,\n\ttwitch,\n\ttwitter,\n};\n\nexport const socialProviderList = Object.keys(socialProviders) as [\n\t\"github\",\n\t...(keyof typeof socialProviders)[],\n];\n\nexport type SocialProviders = typeof socialProviders extends {\n\t[key in infer K]: infer V;\n}\n\t? V extends (options: infer V) => any\n\t\t? Partial<Record<K, Prettify<V & { enabled?: boolean }>>>\n\t\t: never\n\t: never;\n\nexport * from \"./github\";\nexport * from \"./google\";\nexport * from \"./apple\";\nexport * from \"./microsoft-entra-id\";\nexport * from \"./discord\";\nexport * from \"./spotify\";\nexport * from \"./twitch\";\nexport * from \"./facebook\";\nexport * from \"./twitter\";\n\nexport type SocialProviderList = typeof socialProviderList;\n","import { TimeSpan } from \"oslo\";\nimport { createJWT, validateJWT, type JWT } from \"oslo/jwt\";\nimport { z } from \"zod\";\nimport { createAuthEndpoint } from \"../call\";\nimport { APIError } from \"better-call\";\nimport { redirectURLMiddleware } from \"../middlewares/redirect\";\nimport { getSessionFromCtx } from \"./session\";\n\nexport async function createEmailVerificationToken(\n\tsecret: string,\n\temail: string,\n\t/**\n\t * The email to update from\n\t */\n\tupdateTo?: string,\n) {\n\tconst token = await createJWT(\n\t\t\"HS256\",\n\t\tBuffer.from(secret),\n\t\t{\n\t\t\temail: email.toLowerCase(),\n\t\t\tupdateTo,\n\t\t},\n\t\t{\n\t\t\texpiresIn: new TimeSpan(1, \"h\"),\n\t\t\tissuer: \"better-auth\",\n\t\t\tsubject: \"verify-email\",\n\t\t\taudiences: [email],\n\t\t\tincludeIssuedTimestamp: true,\n\t\t},\n\t);\n\treturn token;\n}\n\nexport const sendVerificationEmail = createAuthEndpoint(\n\t\"/send-verification-email\",\n\t{\n\t\tmethod: \"POST\",\n\t\tquery: z\n\t\t\t.object({\n\t\t\t\tcurrentURL: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbody: z.object({\n\t\t\temail: z.string().email(),\n\t\t\tcallbackURL: z.string().optional(),\n\t\t}),\n\t\tuse: [redirectURLMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.emailVerification?.sendVerificationEmail) {\n\t\t\tctx.context.logger.error(\"Verification email isn't enabled.\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Verification email isn't enabled\",\n\t\t\t});\n\t\t}\n\t\tconst { email } = ctx.body;\n\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email);\n\t\tif (!user) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"User not found\",\n\t\t\t});\n\t\t}\n\t\tconst token = await createEmailVerificationToken(ctx.context.secret, email);\n\t\tconst url = `${\n\t\t\tctx.context.baseURL\n\t\t}/verify-email?token=${token}&callbackURL=${\n\t\t\tctx.body.callbackURL || ctx.query?.currentURL || \"/\"\n\t\t}`;\n\t\tawait ctx.context.options.emailVerification.sendVerificationEmail(\n\t\t\tuser.user,\n\t\t\turl,\n\t\t\ttoken,\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n\nexport const verifyEmail = createAuthEndpoint(\n\t\"/verify-email\",\n\t{\n\t\tmethod: \"GET\",\n\t\tquery: z.object({\n\t\t\ttoken: z.string(),\n\t\t\tcallbackURL: z.string().optional(),\n\t\t}),\n\t\tuse: [redirectURLMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { token } = ctx.query;\n\t\tlet jwt: JWT;\n\t\ttry {\n\t\t\tjwt = await validateJWT(\"HS256\", Buffer.from(ctx.context.secret), token);\n\t\t} catch (e) {\n\t\t\tctx.context.logger.error(\"Failed to verify email\", e);\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invalid token\",\n\t\t\t});\n\t\t}\n\t\tconst schema = z.object({\n\t\t\temail: z.string().email(),\n\t\t\tupdateTo: z.string().optional(),\n\t\t});\n\t\tconst parsed = schema.parse(jwt.payload);\n\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(\n\t\t\tparsed.email,\n\t\t);\n\t\tif (!user) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"User not found\",\n\t\t\t});\n\t\t}\n\t\tif (parsed.updateTo) {\n\t\t\tconst session = await getSessionFromCtx(ctx);\n\t\t\tif (!session) {\n\t\t\t\tif (ctx.query.callbackURL) {\n\t\t\t\t\tthrow ctx.redirect(`${ctx.query.callbackURL}?error=unauthorized`);\n\t\t\t\t}\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"Session not found\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (session.user.email !== parsed.email) {\n\t\t\t\tif (ctx.query.callbackURL) {\n\t\t\t\t\tthrow ctx.redirect(`${ctx.query.callbackURL}?error=unauthorized`);\n\t\t\t\t}\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"Invalid session\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst updatedUser = await ctx.context.internalAdapter.updateUserByEmail(\n\t\t\t\tparsed.email,\n\t\t\t\t{\n\t\t\t\t\temail: parsed.updateTo,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\t//send verification email to the new email\n\t\t\tawait ctx.context.options.emailVerification?.sendVerificationEmail?.(\n\t\t\t\tupdatedUser,\n\t\t\t\t`${ctx.context.baseURL}/verify-email?token=${token}`,\n\t\t\t\ttoken,\n\t\t\t);\n\n\t\t\tif (ctx.query.callbackURL) {\n\t\t\t\tthrow ctx.redirect(ctx.query.callbackURL);\n\t\t\t}\n\t\t\treturn ctx.json({\n\t\t\t\tuser: updatedUser,\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\t\tawait ctx.context.internalAdapter.updateUserByEmail(parsed.email, {\n\t\t\temailVerified: true,\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\tuser: null,\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n","import { APIError, type Context } from \"better-call\";\nimport { createAuthEndpoint, createAuthMiddleware } from \"../call\";\nimport { getDate } from \"../../utils/date\";\nimport { deleteSessionCookie, setSessionCookie } from \"../../cookies\";\nimport { z } from \"zod\";\nimport type {\n\tBetterAuthOptions,\n\tInferSession,\n\tInferUser,\n\tPrettify,\n} from \"../../types\";\n\nexport const getSession = <Option extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/session\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\trequireHeaders: true,\n\t\t},\n\t\tasync (ctx) => {\n\t\t\ttry {\n\t\t\t\tconst sessionCookieToken = await ctx.getSignedCookie(\n\t\t\t\t\tctx.context.authCookies.sessionToken.name,\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t);\n\t\t\t\tif (!sessionCookieToken) {\n\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\tstatus: 401,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst session =\n\t\t\t\t\tawait ctx.context.internalAdapter.findSession(sessionCookieToken);\n\n\t\t\t\tif (!session || session.session.expiresAt < new Date()) {\n\t\t\t\t\tdeleteSessionCookie(ctx);\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * if session expired clean up the session\n\t\t\t\t\t\t */\n\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteSession(session.session.id);\n\t\t\t\t\t}\n\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\tstatus: 401,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst dontRememberMe = await ctx.getSignedCookie(\n\t\t\t\t\tctx.context.authCookies.dontRememberToken.name,\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t);\n\t\t\t\t/**\n\t\t\t\t * We don't need to update the session if the user doesn't want to be remembered\n\t\t\t\t */\n\t\t\t\tif (dontRememberMe) {\n\t\t\t\t\treturn ctx.json(\n\t\t\t\t\t\tsession as unknown as {\n\t\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst expiresIn = ctx.context.sessionConfig.expiresIn;\n\t\t\t\tconst updateAge = ctx.context.sessionConfig.updateAge;\n\t\t\t\t/**\n\t\t\t\t * Calculate last updated date to throttle write updates to database\n\t\t\t\t * Formula: ({expiry date} - sessionMaxAge) + sessionUpdateAge\n\t\t\t\t *\n\t\t\t\t * e.g. ({expiry date} - 30 days) + 1 hour\n\t\t\t\t *\n\t\t\t\t * inspired by: https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/lib/actions/session.ts\n\t\t\t\t */\n\t\t\t\tconst sessionIsDueToBeUpdatedDate =\n\t\t\t\t\tsession.session.expiresAt.valueOf() -\n\t\t\t\t\texpiresIn * 1000 +\n\t\t\t\t\tupdateAge * 1000;\n\t\t\t\tconst shouldBeUpdated = sessionIsDueToBeUpdatedDate <= Date.now();\n\n\t\t\t\tif (shouldBeUpdated) {\n\t\t\t\t\tconst updatedSession =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.updateSession(\n\t\t\t\t\t\t\tsession.session.id,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\texpiresAt: getDate(ctx.context.sessionConfig.expiresIn, \"sec\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!updatedSession) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Handle case where session update fails (e.g., concurrent deletion)\n\t\t\t\t\t\t */\n\t\t\t\t\t\tdeleteSessionCookie(ctx);\n\t\t\t\t\t\treturn ctx.json(null, { status: 401 });\n\t\t\t\t\t}\n\t\t\t\t\tconst maxAge =\n\t\t\t\t\t\t(updatedSession.expiresAt.valueOf() - Date.now()) / 1000;\n\t\t\t\t\tawait setSessionCookie(ctx, updatedSession.id, false, {\n\t\t\t\t\t\tmaxAge,\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: updatedSession,\n\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t} as unknown as {\n\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn ctx.json(\n\t\t\t\t\tsession as unknown as {\n\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tctx.context.logger.error(error);\n\t\t\t\treturn ctx.json(null, { status: 500 });\n\t\t\t}\n\t\t},\n\t);\n\nexport const getSessionFromCtx = async (ctx: Context<any, any>) => {\n\t//@ts-ignore\n\tconst session = await getSession()({\n\t\t...ctx,\n\t\t_flag: \"json\",\n\t\theaders: ctx.headers!,\n\t});\n\n\treturn session;\n};\n\nexport const sessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx);\n\tif (!session?.session) {\n\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n\n/**\n * user active sessions list\n */\nexport const listSessions = <Option extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/user/list-sessions\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tuse: [sessionMiddleware],\n\t\t\trequireHeaders: true,\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst sessions = await ctx.context.internalAdapter.listSessions(\n\t\t\t\tctx.context.session.user.id,\n\t\t\t);\n\t\t\tconst activeSessions = sessions.filter((session) => {\n\t\t\t\treturn session.expiresAt > new Date();\n\t\t\t});\n\t\t\treturn ctx.json(\n\t\t\t\tactiveSessions as unknown as Prettify<InferSession<Option>>[],\n\t\t\t);\n\t\t},\n\t);\n\n/**\n * revoke a single session\n */\nexport const revokeSession = createAuthEndpoint(\n\t\"/user/revoke-session\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tid: z.string(),\n\t\t}),\n\t\tuse: [sessionMiddleware],\n\t\trequireHeaders: true,\n\t},\n\tasync (ctx) => {\n\t\tconst id = ctx.body.id;\n\t\tconst findSession = await ctx.context.internalAdapter.findSession(id);\n\t\tif (!findSession) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Session not found\",\n\t\t\t});\n\t\t}\n\t\tif (findSession.session.userId !== ctx.context.session.user.id) {\n\t\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t\t}\n\t\ttry {\n\t\t\tawait ctx.context.internalAdapter.deleteSession(id);\n\t\t} catch (error) {\n\t\t\tctx.context.logger.error(error);\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\");\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n/**\n * revoke all user sessions\n */\nexport const revokeSessions = createAuthEndpoint(\n\t\"/user/revoke-sessions\",\n\t{\n\t\tmethod: \"POST\",\n\t\tuse: [sessionMiddleware],\n\t\trequireHeaders: true,\n\t},\n\tasync (ctx) => {\n\t\ttry {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(\n\t\t\t\tctx.context.session.user.id,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tctx.context.logger.error(error);\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\");\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n","export const getDate = (span: number, unit: \"sec\" | \"ms\" = \"ms\") => {\n\treturn new Date(Date.now() + (unit === \"sec\" ? span * 1000 : span));\n};\n","import { z } from \"zod\";\nimport { userSchema } from \"../../db/schema\";\nimport { generateId } from \"../../utils/id\";\nimport { parseState } from \"../../oauth2/state\";\nimport { createAuthEndpoint } from \"../call\";\nimport { HIDE_METADATA } from \"../../utils/hide-metadata\";\nimport { getAccountTokens } from \"../../oauth2/get-account\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { logger } from \"../../utils/logger\";\nimport type { OAuth2Tokens } from \"../../oauth2\";\nimport { compareHash } from \"../../crypto/hash\";\nimport { createEmailVerificationToken } from \"./email-verification\";\n\nexport const callbackOAuth = createAuthEndpoint(\n\t\"/callback/:id\",\n\t{\n\t\tmethod: \"GET\",\n\t\tquery: z.object({\n\t\t\tstate: z.string(),\n\t\t\tcode: z.string().optional(),\n\t\t\terror: z.string().optional(),\n\t\t}),\n\t\tmetadata: HIDE_METADATA,\n\t},\n\tasync (c) => {\n\t\tif (c.query.error || !c.query.code) {\n\t\t\tconst parsedState = parseState(c.query.state);\n\t\t\tconst callbackURL =\n\t\t\t\tparsedState.data?.callbackURL || `${c.context.baseURL}/error`;\n\t\t\tc.context.logger.error(c.query.error, c.params.id);\n\t\t\tthrow c.redirect(\n\t\t\t\t`${callbackURL}?error=${c.query.error || \"oAuth_code_missing\"}`,\n\t\t\t);\n\t\t}\n\n\t\tconst provider = c.context.socialProviders.find(\n\t\t\t(p) => p.id === c.params.id,\n\t\t);\n\n\t\tif (!provider) {\n\t\t\tc.context.logger.error(\n\t\t\t\t\"Oauth provider with id\",\n\t\t\t\tc.params.id,\n\t\t\t\t\"not found\",\n\t\t\t);\n\t\t\tthrow c.redirect(\n\t\t\t\t`${c.context.baseURL}/error?error=oauth_provider_not_found`,\n\t\t\t);\n\t\t}\n\n\t\tconst parsedState = parseState(c.query.state);\n\t\tif (!parsedState.success) {\n\t\t\tc.context.logger.error(\"Unable to parse state\");\n\t\t\tthrow c.redirect(\n\t\t\t\t`${c.context.baseURL}/error?error=please_restart_the_process`,\n\t\t\t);\n\t\t}\n\n\t\tconst {\n\t\t\tdata: { callbackURL, currentURL },\n\t\t} = parsedState;\n\n\t\tconst storedState = await c.getSignedCookie(\n\t\t\tc.context.authCookies.state.name,\n\t\t\tc.context.secret,\n\t\t);\n\n\t\tif (!storedState) {\n\t\t\tlogger.error(\"No stored state found\");\n\t\t\tthrow c.redirect(\n\t\t\t\t`${c.context.baseURL}/error?error=please_restart_the_process`,\n\t\t\t);\n\t\t}\n\n\t\tconst isValidState = await compareHash(c.query.state, storedState);\n\t\tif (!isValidState) {\n\t\t\tlogger.error(\"OAuth state mismatch\");\n\t\t\tthrow c.redirect(\n\t\t\t\t`${c.context.baseURL}/error?error=please_restart_the_process`,\n\t\t\t);\n\t\t}\n\t\tconst codeVerifier = await c.getSignedCookie(\n\t\t\tc.context.authCookies.pkCodeVerifier.name,\n\t\t\tc.context.secret,\n\t\t);\n\t\tlet tokens: OAuth2Tokens;\n\t\ttry {\n\t\t\ttokens = await provider.validateAuthorizationCode({\n\t\t\t\tcode: c.query.code,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI: `${c.context.baseURL}/callback/${provider.id}`,\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tc.context.logger.error(e);\n\t\t\tthrow c.redirect(\n\t\t\t\t`${c.context.baseURL}/error?error=please_restart_the_process`,\n\t\t\t);\n\t\t}\n\t\tconst user = await provider.getUserInfo(tokens).then((res) => res?.user);\n\t\tconst id = generateId();\n\t\tconst data = userSchema.safeParse({\n\t\t\t...user,\n\t\t\tid,\n\t\t});\n\n\t\tif (!user || data.success === false) {\n\t\t\tlogger.error(\"Unable to get user info\", data.error);\n\t\t\tthrow c.redirect(\n\t\t\t\t`${c.context.baseURL}/error?error=please_restart_the_process`,\n\t\t\t);\n\t\t}\n\t\tif (!callbackURL) {\n\t\t\tthrow c.redirect(\n\t\t\t\t`${c.context.baseURL}/error?error=please_restart_the_process`,\n\t\t\t);\n\t\t}\n\n\t\tfunction redirectOnError(error: string) {\n\t\t\tthrow c.redirect(\n\t\t\t\t`${\n\t\t\t\t\tcurrentURL || callbackURL || `${c.context.baseURL}/error`\n\t\t\t\t}?error=${error}`,\n\t\t\t);\n\t\t}\n\n\t\tconst dbUser = await c.context.internalAdapter\n\t\t\t.findUserByEmail(user.email, {\n\t\t\t\tincludeAccounts: true,\n\t\t\t})\n\t\t\t.catch((e) => {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"Better auth was unable to query your database.\\nError: \",\n\t\t\t\t\te,\n\t\t\t\t);\n\t\t\t\tthrow c.redirect(\n\t\t\t\t\t`${c.context.baseURL}/error?error=internal_server_error`,\n\t\t\t\t);\n\t\t\t});\n\n\t\tlet userId = dbUser?.user.id;\n\t\tif (dbUser) {\n\t\t\tconst hasBeenLinked = dbUser.accounts.find(\n\t\t\t\t(a) => a.providerId === provider.id,\n\t\t\t);\n\t\t\tif (!hasBeenLinked) {\n\t\t\t\tconst trustedProviders =\n\t\t\t\t\tc.context.options.account?.accountLinking?.trustedProviders;\n\t\t\t\tconst isTrustedProvider = trustedProviders?.includes(\n\t\t\t\t\tprovider.id as \"apple\",\n\t\t\t\t);\n\t\t\t\tif (\n\t\t\t\t\t(!isTrustedProvider && !user.emailVerified) ||\n\t\t\t\t\t!c.context.options.account?.accountLinking?.enabled\n\t\t\t\t) {\n\t\t\t\t\tredirectOnError(\"account_not_linked\");\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait c.context.internalAdapter.linkAccount({\n\t\t\t\t\t\tproviderId: provider.id,\n\t\t\t\t\t\taccountId: user.id.toString(),\n\t\t\t\t\t\tid: `${provider.id}:${user.id}`,\n\t\t\t\t\t\tuserId: dbUser.user.id,\n\t\t\t\t\t\t...getAccountTokens(tokens),\n\t\t\t\t\t});\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error(\"Unable to link account\", e);\n\t\t\t\t\tredirectOnError(\"unable_to_link_account\");\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tconst emailVerified = user.emailVerified || false;\n\t\t\t\tconst created = await c.context.internalAdapter.createOAuthUser(\n\t\t\t\t\t{\n\t\t\t\t\t\t...data.data,\n\t\t\t\t\t\temailVerified,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t...getAccountTokens(tokens),\n\t\t\t\t\t\tproviderId: provider.id,\n\t\t\t\t\t\taccountId: user.id.toString(),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tuserId = created?.user.id;\n\t\t\t\tif (\n\t\t\t\t\t!emailVerified &&\n\t\t\t\t\tcreated &&\n\t\t\t\t\tc.context.options.emailVerification?.sendOnSignUp\n\t\t\t\t) {\n\t\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\t\tc.context.secret,\n\t\t\t\t\t\tuser.email,\n\t\t\t\t\t);\n\t\t\t\t\tconst url = `${c.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;\n\t\t\t\t\tawait c.context.options.emailVerification?.sendVerificationEmail?.(\n\t\t\t\t\t\tcreated.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}\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error(\"Unable to create user\", e);\n\t\t\t\tredirectOnError(\"unable_to_create_user\");\n\t\t\t}\n\t\t}\n\n\t\tif (!userId) {\n\t\t\tredirectOnError(\"unable_to_create_user\");\n\t\t}\n\n\t\tconst session = await c.context.internalAdapter.createSession(\n\t\t\tuserId!,\n\t\t\tc.request,\n\t\t);\n\t\tif (!session) {\n\t\t\tredirectOnError(\"unable_to_create_session\");\n\t\t}\n\t\tawait setSessionCookie(c, session.id);\n\t\tthrow c.redirect(callbackURL);\n\t},\n);\n","import { z } from \"zod\";\nimport type { FieldAttribute } from \".\";\nimport type { BetterAuthOptions } from \"../types\";\n\nexport const accountSchema = z.object({\n\tid: z.string(),\n\tproviderId: z.string(),\n\taccountId: z.string(),\n\tuserId: z.string(),\n\taccessToken: z.string().nullable().optional(),\n\trefreshToken: z.string().nullable().optional(),\n\tidToken: z.string().nullable().optional(),\n\t/**\n\t * Access token expires at\n\t */\n\texpiresAt: z.date().nullable().optional(),\n\t/**\n\t * Password is only stored in the credential provider\n\t */\n\tpassword: z.string().optional().nullable(),\n});\n\nexport const userSchema = z.object({\n\tid: z.string(),\n\temail: z.string().transform((val) => val.toLowerCase()),\n\temailVerified: z.boolean().default(false),\n\tname: z.string(),\n\timage: z.string().optional(),\n\tcreatedAt: z.date().default(new Date()),\n\tupdatedAt: z.date().default(new Date()),\n});\n\nexport const sessionSchema = z.object({\n\tid: z.string(),\n\tuserId: z.string(),\n\texpiresAt: z.date(),\n\tipAddress: z.string().optional(),\n\tuserAgent: z.string().optional(),\n});\n\nexport const verificationSchema = z.object({\n\tid: z.string(),\n\tvalue: z.string(),\n\texpiresAt: z.date(),\n\tidentifier: z.string(),\n});\n\nexport type User = z.infer<typeof userSchema>;\nexport type Account = z.infer<typeof accountSchema>;\nexport type Session = z.infer<typeof sessionSchema>;\nexport type Verification = z.infer<typeof verificationSchema>;\n\nexport function parseOutputData<T extends Record<string, any>>(\n\tdata: T,\n\tschema: {\n\t\tfields: Record<string, FieldAttribute>;\n\t},\n) {\n\tconst fields = schema.fields;\n\tconst parsedData: Record<string, any> = {};\n\tfor (const key in data) {\n\t\tconst field = fields[key];\n\t\tif (!field) {\n\t\t\tparsedData[key] = data[key];\n\t\t\tcontinue;\n\t\t}\n\t\tif (field.returned === false) {\n\t\t\tcontinue;\n\t\t}\n\t\tparsedData[key] = data[key];\n\t}\n\treturn parsedData as T;\n}\n\nexport function getAllFields(options: BetterAuthOptions, table: string) {\n\tlet schema: Record<string, FieldAttribute> = {\n\t\t...(table === \"user\" ? options.user?.additionalFields : {}),\n\t\t...(table === \"session\" ? options.session?.additionalFields : {}),\n\t};\n\tfor (const plugin of options.plugins || []) {\n\t\tif (plugin.schema && plugin.schema[table]) {\n\t\t\tschema = {\n\t\t\t\t...schema,\n\t\t\t\t...plugin.schema[table].fields,\n\t\t\t};\n\t\t}\n\t}\n\treturn schema;\n}\n\nexport function parseUserOutput(options: BetterAuthOptions, user: User) {\n\tconst schema = getAllFields(options, \"user\");\n\treturn parseOutputData(user, { fields: schema });\n}\n\nexport function parseAccountOutput(\n\toptions: BetterAuthOptions,\n\taccount: Account,\n) {\n\tconst schema = getAllFields(options, \"account\");\n\treturn parseOutputData(account, { fields: schema });\n}\n\nexport function parseSessionOutput(\n\toptions: BetterAuthOptions,\n\tsession: Session,\n) {\n\tconst schema = getAllFields(options, \"session\");\n\treturn parseOutputData(session, { fields: schema });\n}\n\nexport function parseInputData<T extends Record<string, any>>(\n\tdata: T,\n\tschema: {\n\t\tfields: Record<string, FieldAttribute>;\n\t},\n) {\n\tconst fields = schema.fields;\n\tconst parsedData: Record<string, any> = {};\n\tfor (const key in fields) {\n\t\tif (key in data) {\n\t\t\tif (fields[key].input === false) {\n\t\t\t\tif (fields[key].defaultValue) {\n\t\t\t\t\tparsedData[key] = fields[key].defaultValue;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tparsedData[key] = data[key];\n\t\t\tcontinue;\n\t\t}\n\t\tif (fields[key].defaultValue) {\n\t\t\tparsedData[key] = fields[key].defaultValue;\n\t\t\tcontinue;\n\t\t}\n\t}\n\treturn parsedData as Partial<T>;\n}\n\nexport function parseUserInput(\n\toptions: BetterAuthOptions,\n\tuser?: Record<string, any>,\n) {\n\tconst schema = getAllFields(options, \"user\");\n\treturn parseInputData(user || {}, { fields: schema });\n}\n\nexport function parseAdditionalUserInput(\n\toptions: BetterAuthOptions,\n\tuser?: Record<string, any>,\n) {\n\tconst schema = getAllFields(options, \"user\");\n\treturn parseInputData(user || {}, { fields: schema });\n}\n\nexport function parseAccountInput(\n\toptions: BetterAuthOptions,\n\taccount: Partial<Account>,\n) {\n\tconst schema = getAllFields(options, \"account\");\n\treturn parseInputData(account, { fields: schema });\n}\n\nexport function parseSessionInput(\n\toptions: BetterAuthOptions,\n\tsession: Partial<Session>,\n) {\n\tconst schema = getAllFields(options, \"session\");\n\treturn parseInputData(session, { fields: schema });\n}\n","import { z } from \"zod\";\nimport { createAuthEndpoint } from \"../call\";\nimport { deleteSessionCookie } from \"../../cookies\";\nimport { APIError } from \"better-call\";\nimport { redirectURLMiddleware } from \"../middlewares/redirect\";\n\nexport const signOut = createAuthEndpoint(\n\t\"/sign-out\",\n\t{\n\t\tmethod: \"POST\",\n\t},\n\tasync (ctx) => {\n\t\tconst sessionCookieToken = await ctx.getSignedCookie(\n\t\t\tctx.context.authCookies.sessionToken.name,\n\t\t\tctx.context.secret,\n\t\t);\n\t\tif (!sessionCookieToken) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Session not found\",\n\t\t\t});\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteSession(sessionCookieToken);\n\t\tdeleteSessionCookie(ctx);\n\t\treturn ctx.json({\n\t\t\tsuccess: true,\n\t\t});\n\t},\n);\n","import { z } from \"zod\";\nimport { createAuthEndpoint } from \"../call\";\nimport { APIError } from \"better-call\";\nimport { redirectURLMiddleware } from \"../middlewares/redirect\";\n\nexport const forgetPassword = createAuthEndpoint(\n\t\"/forget-password\",\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.string().email(),\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.string(),\n\t\t}),\n\t\tuse: [redirectURLMiddleware],\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.sendResetPasswordToken function in your auth config!\",\n\t\t\t);\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Reset password isn't enabled\",\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\tctx.context.logger.error(\"Reset Password: User not found\", { email });\n\t\t\t//only on the server status is false for the client it's always true\n\t\t\t//to avoid leaking information\n\t\t\treturn ctx.json(\n\t\t\t\t{\n\t\t\t\t\tstatus: false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tstatus: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tconst defaultExpiresIn = 60 * 60 * 1;\n\t\tconst expiresAt = new Date(\n\t\t\tDate.now() +\n\t\t\t\t1000 *\n\t\t\t\t\t(ctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn ||\n\t\t\t\t\t\tdefaultExpiresIn),\n\t\t);\n\t\tconst verificationToken = ctx.context.uuid();\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 url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${redirectTo}`;\n\t\tawait ctx.context.options.emailAndPassword.sendResetPassword(\n\t\t\tuser.user,\n\t\t\turl,\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n\nexport const forgetPasswordCallback = createAuthEndpoint(\n\t\"/reset-password/:token\",\n\t{\n\t\tmethod: \"GET\",\n\t\tquery: z.object({\n\t\t\tcallbackURL: z.string(),\n\t\t}),\n\t\tuse: [redirectURLMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { token } = ctx.params;\n\t\tconst callbackURL = ctx.query.callbackURL;\n\t\tconst redirectTo = callbackURL.startsWith(\"http\")\n\t\t\t? callbackURL\n\t\t\t: `${ctx.context.options.baseURL}${callbackURL}`;\n\t\tif (!token || !callbackURL) {\n\t\t\tthrow ctx.redirect(`${ctx.context.baseURL}/error?error=INVALID_TOKEN`);\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(`${redirectTo}?error=INVALID_TOKEN`);\n\t\t}\n\t\tthrow ctx.redirect(`${redirectTo}?token=${token}`);\n\t},\n);\n\nexport const resetPassword = createAuthEndpoint(\n\t\"/reset-password\",\n\t{\n\t\tquery: z.optional(\n\t\t\tz.object({\n\t\t\t\ttoken: z.string().optional(),\n\t\t\t\tcurrentURL: z.string().optional(),\n\t\t\t}),\n\t\t),\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tnewPassword: z.string(),\n\t\t}),\n\t},\n\tasync (ctx) => {\n\t\tconst token =\n\t\t\tctx.query?.token ||\n\t\t\t(ctx.query?.currentURL\n\t\t\t\t? new URL(ctx.query.currentURL).searchParams.get(\"token\")\n\t\t\t\t: \"\");\n\t\tif (!token) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Token not found\",\n\t\t\t});\n\t\t}\n\t\tconst { newPassword } = ctx.body;\n\t\tconst id = `reset-password:${token}`;\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(id);\n\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invalid token\",\n\t\t\t});\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteVerificationValue(verification.id);\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: ctx.context.uuid(),\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\tconst updatedUser = await ctx.context.internalAdapter.updatePassword(\n\t\t\tuserId,\n\t\t\thashedPassword,\n\t\t);\n\t\tif (!updatedUser) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Failed to update password\",\n\t\t\t});\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n","import { z, ZodObject, ZodOptional, ZodString } from \"zod\";\nimport { createAuthEndpoint } from \"../call\";\nimport { alphabet, generateRandomString } from \"../../crypto/random\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { sessionMiddleware } from \"./session\";\nimport { APIError } from \"better-call\";\nimport { redirectURLMiddleware } from \"../middlewares/redirect\";\nimport { createEmailVerificationToken } from \"./email-verification\";\nimport type { toZod } from \"../../types/to-zod\";\nimport type { AdditionalUserFieldsInput, BetterAuthOptions } from \"../../types\";\nimport { parseUserInput } from \"../../db/schema\";\n\nexport const updateUser = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/user/update\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: z.record(z.string(), z.any()) as unknown as ZodObject<{\n\t\t\t\tname: ZodOptional<ZodString>;\n\t\t\t\timage: ZodOptional<ZodString>;\n\t\t\t}> &\n\t\t\t\ttoZod<AdditionalUserFieldsInput<O>>,\n\t\t\tuse: [sessionMiddleware, redirectURLMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body as {\n\t\t\t\tname?: string;\n\t\t\t\timage?: string;\n\t\t\t\t[key: string]: any;\n\t\t\t};\n\n\t\t\tif (body.email) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"You can't update email\",\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\tif (!image && !name && Object.keys(rest).length === 0) {\n\t\t\t\treturn ctx.json({\n\t\t\t\t\tuser: session.user,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst additionalFields = parseUserInput(ctx.context.options, rest);\n\t\t\tconst user = await ctx.context.internalAdapter.updateUserByEmail(\n\t\t\t\tsession.user.email,\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\treturn ctx.json({\n\t\t\t\tuser,\n\t\t\t});\n\t\t},\n\t);\n\nexport const changePassword = createAuthEndpoint(\n\t\"/user/change-password\",\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(),\n\t\t\t/**\n\t\t\t * The current password of the user\n\t\t\t */\n\t\t\tcurrentPassword: z.string(),\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.boolean().optional(),\n\t\t}),\n\t\tuse: [sessionMiddleware],\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 new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Password is too short\",\n\t\t\t});\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 new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Password too long\",\n\t\t\t});\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 new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"User does not have a password\",\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\taccount.password,\n\t\t\tcurrentPassword,\n\t\t);\n\t\tif (!verify) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Incorrect password\",\n\t\t\t});\n\t\t}\n\t\tawait ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\tpassword: passwordHash,\n\t\t});\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\tctx.headers,\n\t\t\t);\n\t\t\tif (!newSession) {\n\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\tmessage: \"Unable to create 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, newSession.id);\n\t\t}\n\n\t\treturn ctx.json(session.user);\n\t},\n);\n\nexport const setPassword = createAuthEndpoint(\n\t\"/user/set-password\",\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(),\n\t\t}),\n\t\tuse: [sessionMiddleware],\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 new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Password is too short\",\n\t\t\t});\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 new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Password too long\",\n\t\t\t});\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(session.user);\n\t\t}\n\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\tmessage: \"user already has a password\",\n\t\t});\n\t},\n);\n\nexport const deleteUser = createAuthEndpoint(\n\t\"/user/delete\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tpassword: z.string(),\n\t\t}),\n\t\tuse: [sessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { password } = ctx.body;\n\t\tconst session = ctx.context.session;\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 new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"User does not have a password\",\n\t\t\t});\n\t\t}\n\t\tconst verify = await ctx.context.password.verify(\n\t\t\taccount.password,\n\t\t\tpassword,\n\t\t);\n\t\tif (!verify) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Incorrect password\",\n\t\t\t});\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\tconst sessionCookie = ctx.context.authCookies.sessionToken;\n\t\tctx.setCookie(sessionCookie.name, \"\", {\n\t\t\tmaxAge: 0,\n\t\t});\n\t\treturn ctx.json(null);\n\t},\n);\n\nexport const changeEmail = createAuthEndpoint(\n\t\"/user/change-email\",\n\t{\n\t\tmethod: \"POST\",\n\t\tquery: z\n\t\t\t.object({\n\t\t\t\tcurrentURL: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbody: z.object({\n\t\t\tnewEmail: z.string().email(),\n\t\t\tcallbackURL: z.string().optional(),\n\t\t}),\n\t\tuse: [sessionMiddleware, redirectURLMiddleware],\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 new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Change email is disabled\",\n\t\t\t});\n\t\t}\n\n\t\tif (ctx.body.newEmail === ctx.context.session.user.email) {\n\t\t\tctx.context.logger.error(\"Email is the same\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Email is the same\",\n\t\t\t});\n\t\t}\n\t\tconst existingUser = await ctx.context.internalAdapter.findUserByEmail(\n\t\t\tctx.body.newEmail,\n\t\t);\n\t\tif (existingUser) {\n\t\t\tctx.context.logger.error(\"Email already exists\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Couldn't update your email\",\n\t\t\t});\n\t\t}\n\t\t/**\n\t\t * If the email is not verified, we can update the email\n\t\t */\n\t\tif (ctx.context.session.user.emailVerified !== true) {\n\t\t\tconst updatedUser = await ctx.context.internalAdapter.updateUserByEmail(\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\t{\n\t\t\t\t\temail: ctx.body.newEmail,\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn ctx.json({\n\t\t\t\tuser: updatedUser,\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 (!ctx.context.options.user.changeEmail.sendChangeEmailVerification) {\n\t\t\tctx.context.logger.error(\"Verification email isn't enabled.\");\n\t\t\tthrow new APIError(\"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\tctx.body.newEmail,\n\t\t);\n\t\tconst url = `${\n\t\t\tctx.context.baseURL\n\t\t}/verify-email?token=${token}&callbackURL=${\n\t\t\tctx.body.callbackURL || ctx.query?.currentURL || \"/\"\n\t\t}`;\n\t\tawait ctx.context.options.user.changeEmail.sendChangeEmailVerification(\n\t\t\tctx.context.session.user,\n\t\t\tctx.body.newEmail,\n\t\t\turl,\n\t\t\ttoken,\n\t\t);\n\t\treturn ctx.json({\n\t\t\tuser: null,\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n","//https://github.com/pilcrowOnPaper/oslo/blob/main/src/crypto/random.ts\nimport crypto from \"uncrypto\";\n\nexport function byteToBinary(byte: number): string {\n\treturn byte.toString(2).padStart(8, \"0\");\n}\n\nexport function bytesToBinary(bytes: Uint8Array): string {\n\treturn [...bytes].map((val) => byteToBinary(val)).join(\"\");\n}\n\nexport function bytesToInteger(bytes: Uint8Array): number {\n\treturn parseInt(bytesToBinary(bytes), 2);\n}\n\nexport function random(): number {\n\tconst buffer = new ArrayBuffer(8);\n\tconst bytes = crypto.getRandomValues(new Uint8Array(buffer));\n\n\t// sets the exponent value (11 bits) to 01111111111 (1023)\n\t// since the bias is 1023 (2 * (11 - 1) - 1), 1023 - 1023 = 0\n\t// 2^0 * (1 + [52 bit number between 0-1]) = number between 1-2\n\tbytes[0] = 63;\n\tbytes[1] = bytes[1]! | 240;\n\n\treturn new DataView(buffer).getFloat64(0) - 1;\n}\n\nexport function generateRandomInteger(max: number): number {\n\tif (max < 0 || !Number.isInteger(max)) {\n\t\tthrow new Error(\n\t\t\t\"Argument 'max' must be an integer greater than or equal to 0\",\n\t\t);\n\t}\n\tconst bitLength = (max - 1).toString(2).length;\n\tconst shift = bitLength % 8;\n\tconst bytes = new Uint8Array(Math.ceil(bitLength / 8));\n\n\tcrypto.getRandomValues(bytes);\n\n\t// This zeroes bits that can be ignored to increase the chance `result` < `max`.\n\t// For example, if `max` can be represented with 10 bits, the leading 6 bits of the random 16 bits (2 bytes) can be ignored.\n\tif (shift !== 0) {\n\t\tbytes[0] &= (1 << shift) - 1;\n\t}\n\tlet result = bytesToInteger(bytes);\n\twhile (result >= max) {\n\t\tcrypto.getRandomValues(bytes);\n\t\tif (shift !== 0) {\n\t\t\tbytes[0] &= (1 << shift) - 1;\n\t\t}\n\t\tresult = bytesToInteger(bytes);\n\t}\n\treturn result;\n}\n\nexport function generateRandomString(length: number, alphabet: string): string {\n\tlet result = \"\";\n\tfor (let i = 0; i < length; i++) {\n\t\tresult += alphabet[generateRandomInteger(alphabet.length)];\n\t}\n\treturn result;\n}\n\ntype AlphabetPattern = \"a-z\" | \"A-Z\" | \"0-9\" | \"-\" | \"_\";\n\nexport function alphabet(...patterns: AlphabetPattern[]): string {\n\tconst patternSet = new Set<AlphabetPattern>(patterns);\n\tlet result = \"\";\n\tfor (const pattern of patternSet) {\n\t\tif (pattern === \"a-z\") {\n\t\t\tresult += \"abcdefghijklmnopqrstuvwxyz\";\n\t\t} else if (pattern === \"A-Z\") {\n\t\t\tresult += \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\t\t} else if (pattern === \"0-9\") {\n\t\t\tresult += \"0123456789\";\n\t\t} else {\n\t\t\tresult += pattern;\n\t\t}\n\t}\n\treturn result;\n}\n","import { xchacha20poly1305 } from \"@noble/ciphers/chacha\";\nimport { bytesToHex, hexToBytes, utf8ToBytes } from \"@noble/ciphers/utils\";\nimport { managedNonce } from \"@noble/ciphers/webcrypto\";\nimport { sha256 } from \"oslo/crypto\";\nimport crypto from \"uncrypto\";\n\nexport async function hs256(secretKey: string, message: string) {\n\tconst enc = new TextEncoder();\n\tconst algorithm = { name: \"HMAC\", hash: \"SHA-256\" };\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tenc.encode(secretKey),\n\t\talgorithm,\n\t\tfalse,\n\t\t[\"sign\", \"verify\"],\n\t);\n\tconst signature = await crypto.subtle.sign(\n\t\talgorithm.name,\n\t\tkey,\n\t\tenc.encode(message),\n\t);\n\treturn btoa(String.fromCharCode(...new Uint8Array(signature)));\n}\n\nexport type SymmetricEncryptOptions = {\n\tkey: string;\n\tdata: string;\n};\n\nexport const symmetricEncrypt = async ({\n\tkey,\n\tdata,\n}: SymmetricEncryptOptions) => {\n\tconst keyAsBytes = await sha256(new TextEncoder().encode(key));\n\tconst dataAsBytes = utf8ToBytes(data);\n\tconst chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes));\n\treturn bytesToHex(chacha.encrypt(dataAsBytes));\n};\n\nexport type SymmetricDecryptOptions = {\n\tkey: string;\n\tdata: string;\n};\n\nexport const symmetricDecrypt = async ({\n\tkey,\n\tdata,\n}: SymmetricDecryptOptions) => {\n\tconst keyAsBytes = await sha256(new TextEncoder().encode(key));\n\tconst dataAsBytes = hexToBytes(data);\n\tconst chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes));\n\treturn new TextDecoder().decode(chacha.decrypt(dataAsBytes));\n};\n\nexport * from \"./buffer\";\nexport * from \"./password\";\nexport * from \"./random\";\nexport * from \"./buffer\";\n","import { decodeHex, encodeHex } from \"oslo/encoding\";\nimport { constantTimeEqual } from \"./buffer\";\nimport { scryptAsync } from \"@noble/hashes/scrypt\";\nimport { getRandomValues } from \"uncrypto\";\n\nconst config = {\n\tN: 16384,\n\tr: 16,\n\tp: 1,\n\tdkLen: 64,\n};\n\nasync function generateKey(password: string, salt: string) {\n\treturn await scryptAsync(password.normalize(\"NFKC\"), salt, {\n\t\tN: config.N,\n\t\tp: config.p,\n\t\tr: config.r,\n\t\tdkLen: config.dkLen,\n\t\tmaxmem: 128 * config.N * config.r * 2,\n\t});\n}\n\nexport const hashPassword = async (password: string) => {\n\tconst salt = encodeHex(getRandomValues(new Uint8Array(16)));\n\tconst key = await generateKey(password, salt);\n\treturn `${salt}:${encodeHex(key)}`;\n};\n\nexport const verifyPassword = async (hash: string, password: string) => {\n\tconst [salt, key] = hash.split(\":\");\n\tconst targetKey = await generateKey(password, salt!);\n\treturn constantTimeEqual(targetKey, decodeHex(key!));\n};\n","import { alphabet, generateRandomString } from \"../../crypto/random\";\nimport { hs256 } from \"../../crypto\";\nimport { createAuthEndpoint } from \"../call\";\nimport { HIDE_METADATA } from \"../../utils/hide-metadata\";\n\nexport const getCSRFToken = createAuthEndpoint(\n\t\"/csrf\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: HIDE_METADATA,\n\t},\n\tasync (ctx) => {\n\t\tconst csrfCookie = await ctx.getSignedCookie(\n\t\t\tctx.context.authCookies.csrfToken.name,\n\t\t\tctx.context.secret,\n\t\t);\n\n\t\tif (csrfCookie) {\n\t\t\tconst [token, _] = csrfCookie.split(\"!\") || [null, null];\n\t\t\treturn ctx.json({\n\t\t\t\tcsrfToken: token,\n\t\t\t});\n\t\t}\n\n\t\tconst token = generateRandomString(32, alphabet(\"a-z\", \"0-9\", \"A-Z\"));\n\t\tconst hash = await hs256(ctx.context.secret, token);\n\t\tconst cookie = `${token}!${hash}`;\n\t\tawait ctx.setSignedCookie(\n\t\t\tctx.context.authCookies.csrfToken.name,\n\t\t\tcookie,\n\t\t\tctx.context.secret,\n\t\t\tctx.context.authCookies.csrfToken.options,\n\t\t);\n\t\treturn ctx.json({\n\t\t\tcsrfToken: token,\n\t\t});\n\t},\n);\n","import { HIDE_METADATA } from \"../../utils/hide-metadata\";\nimport { createAuthEndpoint } from \"../call\";\n\nconst html = (errorCode: string = \"Unknown\") => `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Authentication Error</title>\n <style>\n :root {\n --bg-color: #f8f9fa;\n --text-color: #212529;\n --accent-color: #000000;\n --error-color: #dc3545;\n --border-color: #e9ecef;\n }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n background-color: var(--bg-color);\n color: var(--text-color);\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n margin: 0;\n line-height: 1.5;\n }\n .error-container {\n background-color: #ffffff;\n border-radius: 12px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);\n padding: 2.5rem;\n text-align: center;\n max-width: 90%;\n width: 400px;\n }\n h1 {\n color: var(--error-color);\n font-size: 1.75rem;\n margin-bottom: 1rem;\n font-weight: 600;\n }\n p {\n margin-bottom: 1.5rem;\n color: #495057;\n }\n .btn {\n background-color: var(--accent-color);\n color: #ffffff;\n text-decoration: none;\n padding: 0.75rem 1.5rem;\n border-radius: 6px;\n transition: all 0.3s ease;\n display: inline-block;\n font-weight: 500;\n border: 2px solid var(--accent-color);\n }\n .btn:hover {\n background-color: #131721;\n }\n .error-code {\n font-size: 0.875rem;\n color: #6c757d;\n margin-top: 1.5rem;\n padding-top: 1.5rem;\n border-top: 1px solid var(--border-color);\n }\n .icon {\n font-size: 3rem;\n margin-bottom: 1rem;\n }\n </style>\n</head>\n<body>\n <div class=\"error-container\">\n <div class=\"icon\">⚠️</div>\n <h1>Better Auth Error</h1>\n <p>We encountered an issue while processing your request. Please try again or contact the application owner if the problem persists.</p>\n <a href=\"/\" id=\"returnLink\" class=\"btn\">Return to Application</a>\n <div class=\"error-code\">Error Code: <span id=\"errorCode\">${errorCode}</span></div>\n </div>\n</body>\n</html>`;\n\nexport const error = createAuthEndpoint(\n\t\"/error\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: HIDE_METADATA,\n\t},\n\tasync (c) => {\n\t\tconst query =\n\t\t\tnew URL(c.request?.url || \"\").searchParams.get(\"error\") || \"Unknown\";\n\t\treturn new Response(html(query), {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"text/html\",\n\t\t\t},\n\t\t});\n\t},\n);\n","import { HIDE_METADATA } from \"../../utils/hide-metadata\";\nimport { createAuthEndpoint } from \"../call\";\n\nexport const ok = createAuthEndpoint(\n\t\"/ok\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: HIDE_METADATA,\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\tok: true,\n\t\t});\n\t},\n);\n","import { z, ZodObject, ZodOptional, ZodString } from \"zod\";\nimport { createAuthEndpoint } from \"../call\";\nimport { createEmailVerificationToken } from \"./email-verification\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { APIError } from \"better-call\";\nimport type {\n\tAdditionalUserFieldsInput,\n\tBetterAuthOptions,\n\tInferSession,\n\tInferUser,\n\tUser,\n} from \"../../types\";\nimport type { toZod } from \"../../types/to-zod\";\nimport { parseAdditionalUserInput } from \"../../db/schema\";\nimport { getDate } from \"../../utils/date\";\nimport { redirectURLMiddleware } from \"../middlewares/redirect\";\n\nexport const signUpEmail = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/sign-up/email\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tquery: z\n\t\t\t\t.object({\n\t\t\t\t\tcurrentURL: z.string().optional(),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tbody: z.record(z.string(), z.any()) as unknown as ZodObject<{\n\t\t\t\tname: ZodString;\n\t\t\t\temail: ZodString;\n\t\t\t\tpassword: ZodString;\n\t\t\t\tcallbackURL: ZodOptional<ZodString>;\n\t\t\t}> &\n\t\t\t\ttoZod<AdditionalUserFieldsInput<O>>,\n\t\t\tuse: [redirectURLMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!ctx.context.options.emailAndPassword?.enabled) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Email and password sign up is not enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst body = ctx.body as any as User & {\n\t\t\t\tpassword: string;\n\t\t\t\tcallbackURL?: string;\n\t\t\t} & {\n\t\t\t\t[key: string]: any;\n\t\t\t};\n\t\t\tconst { name, email, password, image, callbackURL, ...additionalFields } =\n\t\t\t\tbody;\n\t\t\tconst isValidEmail = z.string().email().safeParse(email);\n\n\t\t\tif (!isValidEmail.success) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Invalid email\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\t\tif (password.length < minPasswordLength) {\n\t\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Password is too short\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\t\t\tif (password.length > maxPasswordLength) {\n\t\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Password is too long\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst dbUser = await ctx.context.internalAdapter.findUserByEmail(email);\n\t\t\tif (dbUser?.user) {\n\t\t\t\tctx.context.logger.info(`Sign-up attempt for existing email: ${email}`);\n\t\t\t\tthrow new APIError(\"UNPROCESSABLE_ENTITY\", {\n\t\t\t\t\tmessage: \"Failed to create user\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst additionalData = parseAdditionalUserInput(\n\t\t\t\tctx.context.options,\n\t\t\t\tadditionalFields as any,\n\t\t\t);\n\t\t\tlet createdUser: User;\n\t\t\ttry {\n\t\t\t\tcreatedUser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\temail: email.toLowerCase(),\n\t\t\t\t\tname,\n\t\t\t\t\timage,\n\t\t\t\t\t...additionalData,\n\t\t\t\t\temailVerified: false,\n\t\t\t\t});\n\t\t\t\tif (!createdUser) {\n\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: \"Failed to create user\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tthrow new APIError(\"UNPROCESSABLE_ENTITY\", {\n\t\t\t\t\tmessage: \"Failed to create user\",\n\t\t\t\t\tdetails: e,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!createdUser) {\n\t\t\t\tthrow new APIError(\"UNPROCESSABLE_ENTITY\", {\n\t\t\t\t\tmessage: \"Failed to create user\",\n\t\t\t\t});\n\t\t\t}\n\t\t\t/**\n\t\t\t * Link the account to the user\n\t\t\t */\n\t\t\tconst hash = await ctx.context.password.hash(password);\n\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\tuserId: createdUser.id,\n\t\t\t\tproviderId: \"credential\",\n\t\t\t\taccountId: createdUser.id,\n\t\t\t\tpassword: hash,\n\t\t\t\texpiresAt: getDate(60 * 60 * 24 * 30, \"sec\"),\n\t\t\t});\n\t\t\tif (ctx.context.options.emailVerification?.sendOnSignUp) {\n\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t\tcreatedUser.email,\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\tbody.callbackURL || ctx.query?.currentURL || \"/\"\n\t\t\t\t}`;\n\t\t\t\tawait ctx.context.options.emailVerification?.sendVerificationEmail?.(\n\t\t\t\t\tcreatedUser,\n\t\t\t\t\turl,\n\t\t\t\t\ttoken,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!ctx.context.options.emailAndPassword.autoSignIn ||\n\t\t\t\tctx.context.options.emailAndPassword.requireEmailVerification\n\t\t\t) {\n\t\t\t\treturn ctx.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser: createdUser as InferUser<O>,\n\t\t\t\t\t\tsession: null,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tbody: body.callbackURL\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\turl: body.callbackURL,\n\t\t\t\t\t\t\t\t\tredirect: true,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\tuser: createdUser,\n\t\t\t\t\t\t\t\t\tsession: null,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\tcreatedUser.id,\n\t\t\t\tctx.request,\n\t\t\t);\n\t\t\tif (!session) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Failed to create session\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tawait setSessionCookie(ctx, session.id);\n\t\t\treturn ctx.json(\n\t\t\t\t{\n\t\t\t\t\tuser: createdUser as InferUser<O>,\n\t\t\t\t\tsession: session as InferSession<O>,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbody: body.callbackURL\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\turl: body.callbackURL,\n\t\t\t\t\t\t\t\tredirect: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tuser: createdUser,\n\t\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t);\n","import type { AuthContext } from \"../init\";\n\nexport const shimContext = <T extends Record<string, any>>(\n\toriginalObject: T,\n\tnewContext: Record<string, any>,\n) => {\n\tconst shimmedObj: Record<string, any> = {};\n\tfor (const [key, value] of Object.entries(originalObject)) {\n\t\tshimmedObj[key] = (ctx: Record<string, any>) => {\n\t\t\treturn value({\n\t\t\t\t...ctx,\n\t\t\t\tcontext: {\n\t\t\t\t\t...newContext,\n\t\t\t\t\t...ctx.context,\n\t\t\t\t},\n\t\t\t});\n\t\t};\n\t\tshimmedObj[key].path = value.path;\n\t\tshimmedObj[key].method = value.method;\n\t\tshimmedObj[key].options = value.options;\n\t\tshimmedObj[key].headers = value.headers;\n\t}\n\treturn shimmedObj as T;\n};\n\nexport const shimEndpoint = (ctx: AuthContext, value: any) => {\n\treturn async (context: any) => {\n\t\tfor (const plugin of ctx.options.plugins || []) {\n\t\t\tif (plugin.hooks?.before) {\n\t\t\t\tfor (const hook of plugin.hooks.before) {\n\t\t\t\t\tconst match = hook.matcher({\n\t\t\t\t\t\t...context,\n\t\t\t\t\t\t...value,\n\t\t\t\t\t});\n\t\t\t\t\tif (match) {\n\t\t\t\t\t\tconst hookRes = await hook.handler(context);\n\t\t\t\t\t\tif (hookRes && \"context\" in hookRes) {\n\t\t\t\t\t\t\tcontext = {\n\t\t\t\t\t\t\t\t...context,\n\t\t\t\t\t\t\t\t...hookRes.context,\n\t\t\t\t\t\t\t\t...value,\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\t//@ts-ignore\n\t\tconst endpointRes = value({\n\t\t\t...context,\n\t\t\tcontext: {\n\t\t\t\t...ctx,\n\t\t\t\t...context.context,\n\t\t\t},\n\t\t});\n\t\tlet response = endpointRes;\n\t\tfor (const plugin of ctx.options.plugins || []) {\n\t\t\tif (plugin.hooks?.after) {\n\t\t\t\tfor (const hook of plugin.hooks.after) {\n\t\t\t\t\tconst match = hook.matcher(context);\n\t\t\t\t\tif (match) {\n\t\t\t\t\t\tconst obj = Object.assign(context, {\n\t\t\t\t\t\t\treturned: endpointRes,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst hookRes = await hook.handler(obj);\n\t\t\t\t\t\tif (hookRes && \"response\" in hookRes) {\n\t\t\t\t\t\t\tresponse = hookRes.response as any;\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\treturn response;\n\t};\n};\n","export * from \"./src/access\";\nexport * from \"./src/types\";\nexport * from \"./statement\";\nexport * from \"./utils\";\n","import type { StatementsPrimitive as Statements, Subset } from \"./types\";\n\nexport class ParsingError extends Error {\n\tpublic readonly path: string;\n\tconstructor(message: string, path: string) {\n\t\tsuper(message);\n\t\tthis.path = path;\n\t}\n}\n\ntype Connector = \"OR\" | \"AND\";\n\nexport class AccessControl<TStatements extends Statements = Statements> {\n\tprivate readonly statements: TStatements;\n\tconstructor(private readonly s: TStatements) {\n\t\tthis.statements = s;\n\t}\n\tpublic newRole<K extends keyof TStatements>(\n\t\tstatements: Subset<K, TStatements>,\n\t) {\n\t\treturn new Role<Subset<K, TStatements>>(statements);\n\t}\n}\n\nexport type AuthortizeResponse =\n\t| { success: false; error: string }\n\t| { success: true; error?: never };\n\nexport class Role<TStatements extends Statements> {\n\tpublic readonly statements: TStatements;\n\n\tconstructor(statements: TStatements) {\n\t\tthis.statements = statements;\n\t}\n\n\tpublic authorize<K extends keyof TStatements>(\n\t\trequest: Subset<K, TStatements>,\n\t\tconnector?: Connector,\n\t): AuthortizeResponse {\n\t\tfor (const [requestedResource, requestedActions] of Object.entries(\n\t\t\trequest,\n\t\t)) {\n\t\t\tconst allowedActions = this.statements[requestedResource];\n\t\t\tif (!allowedActions) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `You are not allowed to access resource: ${requestedResource}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst success =\n\t\t\t\tconnector === \"OR\"\n\t\t\t\t\t? (requestedActions as string[]).some((requestedAction) =>\n\t\t\t\t\t\t\tallowedActions.includes(requestedAction),\n\t\t\t\t\t\t)\n\t\t\t\t\t: (requestedActions as string[]).every((requestedAction) =>\n\t\t\t\t\t\t\tallowedActions.includes(requestedAction),\n\t\t\t\t\t\t);\n\t\t\tif (success) {\n\t\t\t\treturn { success };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `unauthorized to access resource \"${requestedResource}\"`,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: \"Not authorized\",\n\t\t};\n\t}\n\n\tstatic fromString<TStatements extends Statements>(s: string) {\n\t\tconst statements = JSON.parse(s) as TStatements;\n\n\t\tif (typeof statements !== \"object\") {\n\t\t\tthrow new ParsingError(\"statements is not an object\", \".\");\n\t\t}\n\t\tfor (const [resource, actions] of Object.entries(statements)) {\n\t\t\tif (typeof resource !== \"string\") {\n\t\t\t\tthrow new ParsingError(\"invalid resource identifier\", resource);\n\t\t\t}\n\t\t\tif (!Array.isArray(actions)) {\n\t\t\t\tthrow new ParsingError(\"actions is not an array\", resource);\n\t\t\t}\n\t\t\tfor (let i = 0; i < actions.length; i++) {\n\t\t\t\tif (typeof actions[i] !== \"string\") {\n\t\t\t\t\tthrow new ParsingError(\"action is not a string\", `${resource}[${i}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new Role<TStatements>(statements);\n\t}\n\n\tpublic toString(): string {\n\t\treturn JSON.stringify(this.statements);\n\t}\n}\n","import { AccessControl } from \"./src/access\";\nimport type { StatementsPrimitive } from \"./src/types\";\n\nexport const createAccessControl = <S extends StatementsPrimitive>(\n\tstatements: S,\n) => {\n\treturn new AccessControl<S>(statements);\n};\n\nexport const defaultStatements = {\n\torganization: [\"update\", \"delete\"],\n\tmember: [\"create\", \"update\", \"delete\"],\n\tinvitation: [\"create\", \"cancel\"],\n} as const;\n\nexport const defaultAc = createAccessControl(defaultStatements);\n\nexport const adminAc = defaultAc.newRole({\n\torganization: [\"update\"],\n\tinvitation: [\"create\", \"cancel\"],\n\tmember: [\"create\", \"update\", \"delete\"],\n});\n\nexport const ownerAc = defaultAc.newRole({\n\torganization: [\"update\", \"delete\"],\n\tmember: [\"create\", \"update\", \"delete\"],\n\tinvitation: [\"create\", \"cancel\"],\n});\n\nexport const memberAc = defaultAc.newRole({\n\torganization: [],\n\tmember: [],\n\tinvitation: [],\n});\n\nexport const defaultRoles = {\n\tadmin: adminAc,\n\towner: ownerAc,\n\tmember: memberAc,\n};\n","import { Role } from \"./src/access\";\n\nexport const permissionFromString = (permission?: string) => {\n\treturn Role.fromString(permission ?? \"\");\n};\n","import type { Kysely } from \"kysely\";\nimport type { Session, User } from \"../../db/schema\";\nimport { getDate } from \"../../utils/date\";\nimport { generateId } from \"../../utils/id\";\nimport type { OrganizationOptions } from \"./organization\";\nimport type { Invitation, Member, Organization } from \"./schema\";\nimport { BetterAuthError } from \"../../error\";\nimport type { AuthContext } from \"../../types\";\n\nexport const getOrgAdapter = (\n\tcontext: AuthContext,\n\toptions?: OrganizationOptions,\n) => {\n\tconst adapter = context.adapter;\n\treturn {\n\t\tfindOrganizationBySlug: async (slug: string) => {\n\t\t\tconst organization = await adapter.findOne<Organization>({\n\t\t\t\tmodel: \"organization\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"slug\",\n\t\t\t\t\t\tvalue: slug,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn organization;\n\t\t},\n\t\tcreateOrganization: async (data: {\n\t\t\torganization: Organization;\n\t\t\tuser: User;\n\t\t}) => {\n\t\t\tconst organization = await adapter.create<Organization>({\n\t\t\t\tmodel: \"organization\",\n\t\t\t\tdata: {\n\t\t\t\t\t...data.organization,\n\t\t\t\t\tmetadata: data.organization.metadata\n\t\t\t\t\t\t? JSON.stringify(data.organization.metadata)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst member = await adapter.create<Member>({\n\t\t\t\tmodel: \"member\",\n\t\t\t\tdata: {\n\t\t\t\t\tid: generateId(),\n\t\t\t\t\torganizationId: organization.id,\n\t\t\t\t\tuserId: data.user.id,\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\temail: data.user.email,\n\t\t\t\t\trole: options?.creatorRole || \"owner\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn {\n\t\t\t\t...organization,\n\t\t\t\tmetadata: organization.metadata\n\t\t\t\t\t? JSON.parse(organization.metadata)\n\t\t\t\t\t: undefined,\n\t\t\t\tmembers: [\n\t\t\t\t\t{\n\t\t\t\t\t\t...member,\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tid: data.user.id,\n\t\t\t\t\t\t\tname: data.user.name,\n\t\t\t\t\t\t\temail: data.user.email,\n\t\t\t\t\t\t\timage: data.user.image,\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\tfindMemberByEmail: async (data: {\n\t\t\temail: string;\n\t\t\torganizationId: string;\n\t\t}) => {\n\t\t\tconst member = await adapter.findOne<Member>({\n\t\t\t\tmodel: \"member\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t\tvalue: data.email,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\tvalue: data.organizationId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!member) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst user = await adapter.findOne<User>({\n\t\t\t\tmodel: context.tables.user.tableName,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: member.userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!user) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...member,\n\t\t\t\tuser: {\n\t\t\t\t\tid: user.id,\n\t\t\t\t\tname: user.name,\n\t\t\t\t\temail: user.email,\n\t\t\t\t\timage: user.image,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tfindMemberByOrgId: async (data: {\n\t\t\tuserId: string;\n\t\t\torganizationId: string;\n\t\t}) => {\n\t\t\tconst [member, user] = await Promise.all([\n\t\t\t\tawait adapter.findOne<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\tvalue: data.userId,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\t\tvalue: data.organizationId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t}),\n\t\t\t\tawait adapter.findOne<User>({\n\t\t\t\t\tmodel: context.tables.user.tableName,\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\tvalue: data.userId,\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\tif (!user || !member) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...member,\n\t\t\t\tuser: {\n\t\t\t\t\tid: user.id,\n\t\t\t\t\tname: user.name,\n\t\t\t\t\temail: user.email,\n\t\t\t\t\timage: user.image,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tfindMemberById: async (memberId: string) => {\n\t\t\tconst member = await adapter.findOne<Member>({\n\t\t\t\tmodel: \"member\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: memberId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!member) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst user = await adapter.findOne<User>({\n\t\t\t\tmodel: context.tables.user.tableName,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: member.userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!user) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...member,\n\t\t\t\tuser: {\n\t\t\t\t\tid: user.id,\n\t\t\t\t\tname: user.name,\n\t\t\t\t\temail: user.email,\n\t\t\t\t\timage: user.image,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tcreateMember: async (data: Member) => {\n\t\t\tconst member = await adapter.create<Member>({\n\t\t\t\tmodel: \"member\",\n\t\t\t\tdata: data,\n\t\t\t});\n\t\t\treturn member;\n\t\t},\n\t\tupdateMember: async (memberId: string, role: string) => {\n\t\t\tconst member = await adapter.update<Member>({\n\t\t\t\tmodel: \"member\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: memberId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tupdate: {\n\t\t\t\t\trole,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn member;\n\t\t},\n\t\tdeleteMember: async (memberId: string) => {\n\t\t\tconst member = await adapter.delete<Member>({\n\t\t\t\tmodel: \"member\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: memberId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn member;\n\t\t},\n\t\tupdateOrganization: async (orgId: string, data: Partial<Organization>) => {\n\t\t\tconst organization = await adapter.update<Organization>({\n\t\t\t\tmodel: \"organization\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: orgId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tupdate: data,\n\t\t\t});\n\t\t\treturn organization;\n\t\t},\n\t\tdeleteOrganization: async (orgId: string) => {\n\t\t\tawait adapter.delete({\n\t\t\t\tmodel: \"member\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\tvalue: orgId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tawait adapter.delete({\n\t\t\t\tmodel: \"invitation\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\tvalue: orgId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tawait adapter.delete<Organization>({\n\t\t\t\tmodel: \"organization\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: orgId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn orgId;\n\t\t},\n\t\tsetActiveOrganization: async (sessionId: string, orgId: string | null) => {\n\t\t\tconst session = await adapter.update<Session>({\n\t\t\t\tmodel: context.tables.session.tableName,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: sessionId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tupdate: {\n\t\t\t\t\tactiveOrganizationId: orgId,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn session;\n\t\t},\n\t\tfindOrganizationById: async (orgId: string) => {\n\t\t\tconst organization = await adapter.findOne<Organization>({\n\t\t\t\tmodel: \"organization\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: orgId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn organization;\n\t\t},\n\t\t/**\n\t\t * @requires db\n\t\t */\n\t\tfindFullOrganization: async (orgId: string, db?: Kysely<any>) => {\n\t\t\tconst [org, invitations, members] = await Promise.all([\n\t\t\t\tadapter.findOne<Organization>({\n\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\twhere: [{ field: \"id\", value: orgId }],\n\t\t\t\t}),\n\t\t\t\tadapter.findMany<Invitation>({\n\t\t\t\t\tmodel: \"invitation\",\n\t\t\t\t\twhere: [{ field: \"organizationId\", value: orgId }],\n\t\t\t\t}),\n\t\t\t\tadapter.findMany<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [{ field: \"organizationId\", value: orgId }],\n\t\t\t\t}),\n\t\t\t]);\n\n\t\t\tif (!org) return null;\n\n\t\t\tconst userIds = members.map((member) => member.userId);\n\t\t\tconst users = await adapter.findMany<User>({\n\t\t\t\tmodel: context.tables.user.tableName,\n\t\t\t\twhere: [{ field: \"id\", value: userIds, operator: \"in\" }],\n\t\t\t});\n\n\t\t\tconst userMap = new Map(users.map((user) => [user.id, user]));\n\n\t\t\tconst membersWithUsers = members.map((member) => {\n\t\t\t\tconst user = userMap.get(member.userId);\n\t\t\t\tif (!user) {\n\t\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\t\"Unexpected error: User not found for member\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\t...member,\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tid: user.id,\n\t\t\t\t\t\tname: user.name,\n\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\timage: user.image,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\t...org,\n\t\t\t\tinvitations,\n\t\t\t\tmembers: membersWithUsers,\n\t\t\t};\n\t\t},\n\t\tlistOrganizations: async (userId: string) => {\n\t\t\tconst members = await adapter.findMany<Member>({\n\t\t\t\tmodel: \"member\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (!members || members.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst organizationIds = members.map((member) => member.organizationId);\n\n\t\t\tconst organizations = await adapter.findMany<Organization>({\n\t\t\t\tmodel: \"organization\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: organizationIds,\n\t\t\t\t\t\toperator: \"in\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\treturn organizations;\n\t\t},\n\t\tcreateInvitation: async ({\n\t\t\tinvitation,\n\t\t\tuser,\n\t\t}: {\n\t\t\tinvitation: {\n\t\t\t\temail: string;\n\t\t\t\trole: \"admin\" | \"member\" | \"owner\";\n\t\t\t\torganizationId: string;\n\t\t\t};\n\t\t\tuser: User;\n\t\t}) => {\n\t\t\tconst defaultExpiration = 1000 * 60 * 60 * 48;\n\t\t\tconst expiresAt = getDate(\n\t\t\t\toptions?.invitationExpiresIn || defaultExpiration,\n\t\t\t);\n\t\t\tconst invite = await adapter.create<Invitation>({\n\t\t\t\tmodel: \"invitation\",\n\t\t\t\tdata: {\n\t\t\t\t\tid: generateId(),\n\t\t\t\t\temail: invitation.email,\n\t\t\t\t\trole: invitation.role,\n\t\t\t\t\torganizationId: invitation.organizationId,\n\t\t\t\t\tstatus: \"pending\",\n\t\t\t\t\texpiresAt,\n\t\t\t\t\tinviterId: user.id,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn invite;\n\t\t},\n\t\tfindInvitationById: async (id: string) => {\n\t\t\tconst invitation = await adapter.findOne<Invitation>({\n\t\t\t\tmodel: \"invitation\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn invitation;\n\t\t},\n\t\tfindPendingInvitation: async (data: {\n\t\t\temail: string;\n\t\t\torganizationId: string;\n\t\t}) => {\n\t\t\tconst invitation = await adapter.findMany<Invitation>({\n\t\t\t\tmodel: \"invitation\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t\tvalue: data.email,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\tvalue: data.organizationId,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"status\",\n\t\t\t\t\t\tvalue: \"pending\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn invitation.filter(\n\t\t\t\t(invite) => new Date(invite.expiresAt) > new Date(),\n\t\t\t);\n\t\t},\n\t\tupdateInvitation: async (data: {\n\t\t\tinvitationId: string;\n\t\t\tstatus: \"accepted\" | \"canceled\" | \"rejected\";\n\t\t}) => {\n\t\t\tconst invitation = await adapter.update<Invitation>({\n\t\t\t\tmodel: \"invitation\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: data.invitationId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tupdate: {\n\t\t\t\t\tstatus: data.status,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn invitation;\n\t\t},\n\t};\n};\n","import { APIError, type Context, createEndpointCreator } from \"better-call\";\nimport type { Session, User } from \"../../db/schema\";\nimport { createAuthMiddleware, optionsMiddleware } from \"../../api/call\";\nimport { sessionMiddleware } from \"../../api\";\nimport type { Role, defaultRoles } from \"./access\";\nimport type { OrganizationOptions } from \"./organization\";\n\nexport const orgMiddleware = createAuthMiddleware(async (ctx) => {\n\treturn {} as {\n\t\torgOptions: OrganizationOptions;\n\t\troles: typeof defaultRoles & {\n\t\t\t[key: string]: Role<{}>;\n\t\t};\n\t\tgetSession: (context: Context<any, any>) => Promise<{\n\t\t\tsession: Session & {\n\t\t\t\tactiveOrganizationId?: string;\n\t\t\t};\n\t\t\tuser: User;\n\t\t}>;\n\t};\n});\n\nexport const orgSessionMiddleware = createAuthMiddleware(\n\t{\n\t\tuse: [sessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\t//@ts-expect-error: fix this later on better-call repo. Session middleware will return session in the context.\n\t\tconst session = ctx.context.session as {\n\t\t\tsession: Session & {\n\t\t\t\tactiveOrganizationId?: string;\n\t\t\t};\n\t\t\tuser: User;\n\t\t};\n\t\treturn {\n\t\t\tsession,\n\t\t};\n\t},\n);\n","import { APIError, type Endpoint, createRouter, statusCode } from \"better-call\";\nimport type { AuthContext } from \"../init\";\nimport type { BetterAuthOptions } from \"../types\";\nimport type { UnionToIntersection } from \"../types/helper\";\nimport { csrfMiddleware } from \"./middlewares/csrf\";\nimport {\n\tcallbackOAuth,\n\tforgetPassword,\n\tforgetPasswordCallback,\n\tgetSession,\n\tlistSessions,\n\tresetPassword,\n\trevokeSession,\n\trevokeSessions,\n\tsendVerificationEmail,\n\tchangeEmail,\n\tsignInEmail,\n\tsignInOAuth,\n\tsignOut,\n\tverifyEmail,\n} from \"./routes\";\nimport { getCSRFToken } from \"./routes/csrf\";\nimport { ok } from \"./routes/ok\";\nimport { signUpEmail } from \"./routes/sign-up\";\nimport { error } from \"./routes/error\";\nimport { logger } from \"../utils/logger\";\nimport {\n\tchangePassword,\n\tdeleteUser,\n\tsetPassword,\n\tupdateUser,\n} from \"./routes/update-user\";\nimport type { BetterAuthPlugin } from \"../plugins\";\nimport { onRequestRateLimit } from \"./rate-limiter\";\n\nexport function getEndpoints<\n\tC extends AuthContext,\n\tOption extends BetterAuthOptions,\n>(ctx: Promise<C> | C, options: Option) {\n\tconst pluginEndpoints = options.plugins?.reduce(\n\t\t(acc, plugin) => {\n\t\t\treturn {\n\t\t\t\t...acc,\n\t\t\t\t...plugin.endpoints,\n\t\t\t};\n\t\t},\n\t\t{} as Record<string, any>,\n\t);\n\n\ttype PluginEndpoint = UnionToIntersection<\n\t\tOption[\"plugins\"] extends Array<infer T>\n\t\t\t? T extends BetterAuthPlugin\n\t\t\t\t? T extends {\n\t\t\t\t\t\tendpoints: infer E;\n\t\t\t\t\t}\n\t\t\t\t\t? E\n\t\t\t\t\t: {}\n\t\t\t\t: {}\n\t\t\t: {}\n\t>;\n\n\tconst middlewares =\n\t\toptions.plugins\n\t\t\t?.map((plugin) =>\n\t\t\t\tplugin.middlewares?.map((m) => {\n\t\t\t\t\tconst middleware = (async (context: any) => {\n\t\t\t\t\t\treturn m.middleware({\n\t\t\t\t\t\t\t...context,\n\t\t\t\t\t\t\tcontext: {\n\t\t\t\t\t\t\t\t...ctx,\n\t\t\t\t\t\t\t\t...context.context,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}) as Endpoint;\n\t\t\t\t\tmiddleware.path = m.path;\n\t\t\t\t\tmiddleware.options = m.middleware.options;\n\t\t\t\t\tmiddleware.headers = m.middleware.headers;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpath: m.path,\n\t\t\t\t\t\tmiddleware,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.filter((plugin) => plugin !== undefined)\n\t\t\t.flat() || [];\n\n\tconst baseEndpoints = {\n\t\tsignInOAuth,\n\t\tcallbackOAuth,\n\t\tgetCSRFToken,\n\t\tgetSession: getSession<Option>(),\n\t\tsignOut,\n\t\tsignUpEmail: signUpEmail<Option>(),\n\t\tsignInEmail,\n\t\tforgetPassword,\n\t\tresetPassword,\n\t\tverifyEmail,\n\t\tsendVerificationEmail,\n\t\tchangeEmail,\n\t\tchangePassword,\n\t\tsetPassword,\n\t\tupdateUser: updateUser<Option>(),\n\t\tdeleteUser,\n\t\tforgetPasswordCallback,\n\t\tlistSessions: listSessions<Option>(),\n\t\trevokeSession,\n\t\trevokeSessions,\n\t};\n\tconst endpoints = {\n\t\t...baseEndpoints,\n\t\t...pluginEndpoints,\n\t\tok,\n\t\terror,\n\t};\n\tlet api: Record<string, any> = {};\n\tfor (const [key, value] of Object.entries(endpoints)) {\n\t\tapi[key] = async (context = {} as any) => {\n\t\t\tlet c = await ctx;\n\t\t\tfor (const plugin of options.plugins || []) {\n\t\t\t\tif (plugin.hooks?.before) {\n\t\t\t\t\tfor (const hook of plugin.hooks.before) {\n\t\t\t\t\t\tconst match = hook.matcher({\n\t\t\t\t\t\t\t...value,\n\t\t\t\t\t\t\t...context,\n\t\t\t\t\t\t\tcontext: c,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\tconst hookRes = await hook.handler({\n\t\t\t\t\t\t\t\t...context,\n\t\t\t\t\t\t\t\tcontext: {\n\t\t\t\t\t\t\t\t\t...c,\n\t\t\t\t\t\t\t\t\t...context?.context,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (hookRes && \"context\" in hookRes) {\n\t\t\t\t\t\t\t\tc = {\n\t\t\t\t\t\t\t\t\t...c,\n\t\t\t\t\t\t\t\t\t...hookRes.context,\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\tlet endpointRes: any;\n\t\t\ttry {\n\t\t\t\t//@ts-ignore\n\t\t\t\tendpointRes = await value({\n\t\t\t\t\t...context,\n\t\t\t\t\tcontext: {\n\t\t\t\t\t\t...c,\n\t\t\t\t\t\t...context.context,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tif (e instanceof APIError) {\n\t\t\t\t\tconst afterPlugins = options.plugins\n\t\t\t\t\t\t?.map((plugin) => {\n\t\t\t\t\t\t\tif (plugin.hooks?.after) {\n\t\t\t\t\t\t\t\treturn plugin.hooks.after;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.filter((plugin) => plugin !== undefined)\n\t\t\t\t\t\t.flat();\n\n\t\t\t\t\tif (!afterPlugins?.length) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet response = new Response(JSON.stringify(e.body), {\n\t\t\t\t\t\tstatus: statusCode[e.status],\n\t\t\t\t\t\theaders: e.headers,\n\t\t\t\t\t});\n\n\t\t\t\t\tfor (const hook of afterPlugins || []) {\n\t\t\t\t\t\tconst match = hook.matcher(context);\n\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\tconst obj = Object.assign(context, {\n\t\t\t\t\t\t\t\tcontext: {\n\t\t\t\t\t\t\t\t\t...ctx,\n\t\t\t\t\t\t\t\t\treturned: response,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst hookRes = await hook.handler(obj);\n\t\t\t\t\t\t\tif (hookRes && \"response\" in hookRes) {\n\t\t\t\t\t\t\t\tresponse = hookRes.response as any;\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\treturn response;\n\t\t\t\t}\n\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\tlet response = endpointRes;\n\t\t\tfor (const plugin of options.plugins || []) {\n\t\t\t\tif (plugin.hooks?.after) {\n\t\t\t\t\tfor (const hook of plugin.hooks.after) {\n\t\t\t\t\t\tconst match = hook.matcher(context);\n\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\tconst obj = Object.assign(context, {\n\t\t\t\t\t\t\t\tcontext: {\n\t\t\t\t\t\t\t\t\t...ctx,\n\t\t\t\t\t\t\t\t\treturned: response,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst hookRes = await hook.handler(obj);\n\t\t\t\t\t\t\tif (hookRes && \"response\" in hookRes) {\n\t\t\t\t\t\t\t\tresponse = hookRes.response as any;\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\treturn response;\n\t\t};\n\t\tapi[key].path = value.path;\n\t\tapi[key].method = value.method;\n\t\tapi[key].options = value.options;\n\t\tapi[key].headers = value.headers;\n\t}\n\treturn {\n\t\tapi: api as typeof endpoints & PluginEndpoint,\n\t\tmiddlewares,\n\t};\n}\n\nexport const router = <C extends AuthContext, Option extends BetterAuthOptions>(\n\tctx: C,\n\toptions: Option,\n) => {\n\tconst { api, middlewares } = getEndpoints(ctx, options);\n\tconst basePath = new URL(ctx.baseURL).pathname;\n\n\treturn createRouter(api, {\n\t\textraContext: ctx,\n\t\tbasePath,\n\t\trouterMiddleware: [\n\t\t\t{\n\t\t\t\tpath: \"/**\",\n\t\t\t\tmiddleware: csrfMiddleware,\n\t\t\t},\n\t\t\t...middlewares,\n\t\t],\n\t\tasync onRequest(req) {\n\t\t\tfor (const plugin of ctx.options.plugins || []) {\n\t\t\t\tif (plugin.onRequest) {\n\t\t\t\t\tconst response = await plugin.onRequest(req, ctx);\n\t\t\t\t\tif (response) {\n\t\t\t\t\t\treturn response;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn onRequestRateLimit(req, ctx);\n\t\t},\n\t\tasync onResponse(res) {\n\t\t\tfor (const plugin of ctx.options.plugins || []) {\n\t\t\t\tif (plugin.onResponse) {\n\t\t\t\t\tconst response = await plugin.onResponse(res, ctx);\n\t\t\t\t\tif (response) {\n\t\t\t\t\t\treturn response.response;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn res;\n\t\t},\n\t\tonError(e) {\n\t\t\tif (options.onAPIError?.throw) {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\tif (options.onAPIError?.onError) {\n\t\t\t\toptions.onAPIError.onError(e, ctx);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst log = options.logger?.verboseLogging ? logger : undefined;\n\t\t\tif (options.logger?.disabled !== true) {\n\t\t\t\tif (e instanceof APIError) {\n\t\t\t\t\tif (e.status === \"INTERNAL_SERVER_ERROR\") {\n\t\t\t\t\t\tlogger.error(e);\n\t\t\t\t\t}\n\t\t\t\t\tlog?.error(e.message);\n\t\t\t\t} else {\n\t\t\t\t\tlogger?.error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n};\n\nexport * from \"./routes\";\nexport * from \"./middlewares\";\nexport * from \"./call\";\nexport { APIError } from \"better-call\";\n","import { APIError } from \"better-call\";\nimport { z } from \"zod\";\nimport { hs256 } from \"../../crypto\";\nimport { createAuthMiddleware } from \"../call\";\n\nexport const csrfMiddleware = createAuthMiddleware(\n\t{\n\t\tbody: z\n\t\t\t.object({\n\t\t\t\tcsrfToken: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t},\n\tasync (ctx) => {\n\t\tif (\n\t\t\tctx.request?.method !== \"POST\" ||\n\t\t\tctx.context.options.advanced?.disableCSRFCheck\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tconst originHeader = ctx.headers?.get(\"origin\") || \"\";\n\t\t/**\n\t\t * If origin is the same as baseURL or if the\n\t\t * origin is in the trustedOrigins then we\n\t\t * don't need to check the CSRF token.\n\t\t */\n\t\tif (originHeader) {\n\t\t\tconst origin = new URL(originHeader).origin;\n\t\t\tif (ctx.context.trustedOrigins.includes(origin)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst csrfToken = ctx.body?.csrfToken;\n\t\tif (!csrfToken) {\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"CSRF Token is required\",\n\t\t\t});\n\t\t}\n\t\tconst csrfCookie = await ctx.getSignedCookie(\n\t\t\tctx.context.authCookies.csrfToken.name,\n\t\t\tctx.context.secret,\n\t\t);\n\t\tconst [token, hash] = csrfCookie?.split(\"!\") || [null, null];\n\t\tif (!csrfToken || !token || !hash || token !== csrfToken) {\n\t\t\tctx.setCookie(ctx.context.authCookies.csrfToken.name, \"\", {\n\t\t\t\tmaxAge: 0,\n\t\t\t});\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Invalid CSRF Token\",\n\t\t\t});\n\t\t}\n\t\tconst expectedHash = await hs256(ctx.context.secret, token);\n\t\tif (hash !== expectedHash) {\n\t\t\tctx.setCookie(ctx.context.authCookies.csrfToken.name, \"\", {\n\t\t\t\tmaxAge: 0,\n\t\t\t});\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Invalid CSRF Token\",\n\t\t\t});\n\t\t}\n\t},\n);\n","import { isTest } from \"std-env\";\n\nexport function getIp(req: Request | Headers): string | null {\n\tconst testIP = \"127.0.0.1\";\n\tif (isTest) {\n\t\treturn testIP;\n\t}\n\tconst keys = [\n\t\t\"x-client-ip\",\n\t\t\"x-forwarded-for\",\n\t\t\"cf-connecting-ip\",\n\t\t\"fastly-client-ip\",\n\t\t\"x-real-ip\",\n\t\t\"x-cluster-client-ip\",\n\t\t\"x-forwarded\",\n\t\t\"forwarded-for\",\n\t\t\"forwarded\",\n\t];\n\tconst headers = req instanceof Request ? req.headers : req;\n\tfor (const key of keys) {\n\t\tconst value = headers.get(key);\n\t\tif (typeof value === \"string\") {\n\t\t\tconst ip = value.split(\",\")[0].trim();\n\t\t\tif (ip) return ip;\n\t\t}\n\t}\n\treturn null;\n}\n","import { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../../api/call\";\nimport { getSessionFromCtx } from \"../../../api/routes\";\nimport { generateId } from \"../../../utils/id\";\nimport { getOrgAdapter } from \"../adapter\";\nimport { orgMiddleware, orgSessionMiddleware } from \"../call\";\nimport { role } from \"../schema\";\nimport { logger } from \"../../../utils/logger\";\nimport { APIError } from \"better-call\";\n\nexport const createInvitation = createAuthEndpoint(\n\t\"/organization/invite-member\",\n\t{\n\t\tmethod: \"POST\",\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t\tbody: z.object({\n\t\t\temail: z.string(),\n\t\t\trole: role,\n\t\t\torganizationId: z.string().optional(),\n\t\t\tresend: z.boolean().optional(),\n\t\t}),\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.orgOptions.sendInvitationEmail) {\n\t\t\tlogger.warn(\n\t\t\t\t\"Invitation email is not enabled. Pass `sendInvitationEmail` to the plugin options to enable it.\",\n\t\t\t);\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invitation email is not enabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst session = ctx.context.session;\n\t\tconst orgId =\n\t\t\tctx.body.organizationId || session.session.activeOrganizationId;\n\t\tif (!orgId) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Organization not found\",\n\t\t\t});\n\t\t}\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst member = await adapter.findMemberByOrgId({\n\t\t\tuserId: session.user.id,\n\t\t\torganizationId: orgId,\n\t\t});\n\t\tif (!member) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Member not found!\",\n\t\t\t});\n\t\t}\n\t\tconst role = ctx.context.roles[member.role];\n\t\tif (!role) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Role not found!\",\n\t\t\t});\n\t\t}\n\t\tconst canInvite = role.authorize({\n\t\t\tinvitation: [\"create\"],\n\t\t});\n\t\tif (canInvite.error) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You are not allowed to invite members\",\n\t\t\t});\n\t\t}\n\t\tconst alreadyMember = await adapter.findMemberByEmail({\n\t\t\temail: ctx.body.email,\n\t\t\torganizationId: orgId,\n\t\t});\n\t\tif (alreadyMember) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"User is already a member of this organization\",\n\t\t\t});\n\t\t}\n\t\tconst alreadyInvited = await adapter.findPendingInvitation({\n\t\t\temail: ctx.body.email,\n\t\t\torganizationId: orgId,\n\t\t});\n\t\tif (alreadyInvited.length && !ctx.body.resend) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"User is already invited to this organization\",\n\t\t\t});\n\t\t}\n\t\tconst invitation = await adapter.createInvitation({\n\t\t\tinvitation: {\n\t\t\t\trole: ctx.body.role,\n\t\t\t\temail: ctx.body.email,\n\t\t\t\torganizationId: orgId,\n\t\t\t},\n\t\t\tuser: session.user,\n\t\t});\n\n\t\tconst organization = await adapter.findOrganizationById(orgId);\n\n\t\tif (!organization) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Organization not found\",\n\t\t\t});\n\t\t}\n\n\t\tawait ctx.context.orgOptions.sendInvitationEmail?.(\n\t\t\t{\n\t\t\t\tid: invitation.id,\n\t\t\t\trole: invitation.role,\n\t\t\t\temail: invitation.email,\n\t\t\t\torganization: organization,\n\t\t\t\tinviter: {\n\t\t\t\t\t...member,\n\t\t\t\t\tuser: session.user,\n\t\t\t\t},\n\t\t\t},\n\t\t\tctx.request,\n\t\t);\n\t\treturn ctx.json(invitation);\n\t},\n);\n\nexport const acceptInvitation = createAuthEndpoint(\n\t\"/organization/accept-invitation\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tinvitationId: z.string(),\n\t\t}),\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst invitation = await adapter.findInvitationById(ctx.body.invitationId);\n\t\tif (\n\t\t\t!invitation ||\n\t\t\tinvitation.expiresAt < new Date() ||\n\t\t\tinvitation.status !== \"pending\"\n\t\t) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invitation not found!\",\n\t\t\t});\n\t\t}\n\t\tif (invitation.email !== session.user.email) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You are not the recipient of the invitation\",\n\t\t\t});\n\t\t}\n\t\tconst acceptedI = await adapter.updateInvitation({\n\t\t\tinvitationId: ctx.body.invitationId,\n\t\t\tstatus: \"accepted\",\n\t\t});\n\t\tconst member = await adapter.createMember({\n\t\t\tid: generateId(),\n\t\t\torganizationId: invitation.organizationId,\n\t\t\tuserId: session.user.id,\n\t\t\temail: invitation.email,\n\t\t\trole: invitation.role,\n\t\t\tcreatedAt: new Date(),\n\t\t});\n\t\tawait adapter.setActiveOrganization(\n\t\t\tsession.session.id,\n\t\t\tinvitation.organizationId,\n\t\t);\n\t\tif (!acceptedI) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"Invitation not found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\treturn ctx.json({\n\t\t\tinvitation: acceptedI,\n\t\t\tmember,\n\t\t});\n\t},\n);\nexport const rejectInvitation = createAuthEndpoint(\n\t\"/organization/reject-invitation\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tinvitationId: z.string(),\n\t\t}),\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst invitation = await adapter.findInvitationById(ctx.body.invitationId);\n\t\tif (\n\t\t\t!invitation ||\n\t\t\tinvitation.expiresAt < new Date() ||\n\t\t\tinvitation.status !== \"pending\"\n\t\t) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invitation not found!\",\n\t\t\t});\n\t\t}\n\t\tif (invitation.email !== session.user.email) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You are not the recipient of the invitation\",\n\t\t\t});\n\t\t}\n\t\tconst rejectedI = await adapter.updateInvitation({\n\t\t\tinvitationId: ctx.body.invitationId,\n\t\t\tstatus: \"rejected\",\n\t\t});\n\t\treturn ctx.json({\n\t\t\tinvitation: rejectedI,\n\t\t\tmember: null,\n\t\t});\n\t},\n);\n\nexport const cancelInvitation = createAuthEndpoint(\n\t\"/organization/cancel-invitation\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tinvitationId: z.string(),\n\t\t}),\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst invitation = await adapter.findInvitationById(ctx.body.invitationId);\n\t\tif (!invitation) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invitation not found!\",\n\t\t\t});\n\t\t}\n\t\tconst member = await adapter.findMemberByOrgId({\n\t\t\tuserId: session.user.id,\n\t\t\torganizationId: invitation.organizationId,\n\t\t});\n\t\tif (!member) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Member not found!\",\n\t\t\t});\n\t\t}\n\t\tconst canCancel = ctx.context.roles[member.role].authorize({\n\t\t\tinvitation: [\"cancel\"],\n\t\t});\n\t\tif (canCancel.error) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You are not allowed to cancel this invitation\",\n\t\t\t});\n\t\t}\n\t\tconst canceledI = await adapter.updateInvitation({\n\t\t\tinvitationId: ctx.body.invitationId,\n\t\t\tstatus: \"canceled\",\n\t\t});\n\t\treturn ctx.json(canceledI);\n\t},\n);\n\nexport const getInvitation = createAuthEndpoint(\n\t\"/organization/get-invitation\",\n\t{\n\t\tmethod: \"GET\",\n\t\tuse: [orgMiddleware],\n\t\trequireHeaders: true,\n\t\tquery: z.object({\n\t\t\tid: z.string(),\n\t\t}),\n\t},\n\tasync (ctx) => {\n\t\tconst session = await getSessionFromCtx(ctx);\n\t\tif (!session) {\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Not authenticated\",\n\t\t\t});\n\t\t}\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst invitation = await adapter.findInvitationById(ctx.query.id);\n\t\tif (\n\t\t\t!invitation ||\n\t\t\tinvitation.status !== \"pending\" ||\n\t\t\tinvitation.expiresAt < new Date()\n\t\t) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Invitation not found!\",\n\t\t\t});\n\t\t}\n\t\tif (invitation.email !== session.user.email) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You are not the recipient of the invitation\",\n\t\t\t});\n\t\t}\n\t\tconst organization = await adapter.findOrganizationById(\n\t\t\tinvitation.organizationId,\n\t\t);\n\t\tif (!organization) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Organization not found\",\n\t\t\t});\n\t\t}\n\t\tconst member = await adapter.findMemberByOrgId({\n\t\t\tuserId: invitation.inviterId,\n\t\t\torganizationId: invitation.organizationId,\n\t\t});\n\t\tif (!member) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Inviter is no longer a member of the organization\",\n\t\t\t});\n\t\t}\n\t\treturn ctx.json({\n\t\t\t...invitation,\n\t\t\torganizationName: organization.name,\n\t\t\torganizationSlug: organization.slug,\n\t\t\tinviterEmail: member.email,\n\t\t});\n\t},\n);\n","import { z } from \"zod\";\n\nexport const role = z.enum([\"admin\", \"member\", \"owner\"]);\nexport const invitationStatus = z\n\t.enum([\"pending\", \"accepted\", \"rejected\", \"canceled\"])\n\t.default(\"pending\");\nexport const organizationSchema = z.object({\n\tid: z.string(),\n\tname: z.string(),\n\tslug: z.string(),\n\tlogo: z.string().optional(),\n\tmetadata: z\n\t\t.record(z.string())\n\t\t.or(z.string().transform((v) => JSON.parse(v)))\n\t\t.optional(),\n\tcreatedAt: z.date(),\n});\n\nexport const memberSchema = z.object({\n\tid: z.string(),\n\temail: z.string(),\n\torganizationId: z.string(),\n\tuserId: z.string(),\n\trole,\n\tcreatedAt: z.date(),\n});\n\nexport const invitationSchema = z.object({\n\tid: z.string(),\n\torganizationId: z.string(),\n\temail: z.string(),\n\trole,\n\tstatus: invitationStatus,\n\t/**\n\t * The id of the user who invited the user.\n\t */\n\tinviterId: z.string(),\n\texpiresAt: z.date(),\n});\n\nexport type Organization = z.infer<typeof organizationSchema>;\nexport type Member = z.infer<typeof memberSchema>;\nexport type Invitation = z.infer<typeof invitationSchema>;\n","import { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../../api/call\";\nimport { getOrgAdapter } from \"../adapter\";\nimport { orgMiddleware, orgSessionMiddleware } from \"../call\";\nimport type { Member } from \"../schema\";\nimport { APIError } from \"better-call\";\n\nexport const removeMember = createAuthEndpoint(\n\t\"/organization/remove-member\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tmemberIdOrEmail: z.string(),\n\t\t\t/**\n\t\t\t * If not provided, the active organization will be used\n\t\t\t */\n\t\t\torganizationId: z.string().optional(),\n\t\t}),\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tconst orgId =\n\t\t\tctx.body.organizationId || session.session.activeOrganizationId;\n\t\tif (!orgId) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"No active organization found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst member = await adapter.findMemberByOrgId({\n\t\t\tuserId: session.user.id,\n\t\t\torganizationId: orgId,\n\t\t});\n\t\tif (!member) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Member not found!\",\n\t\t\t});\n\t\t}\n\t\tconst role = ctx.context.roles[member.role];\n\t\tif (!role) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Role not found!\",\n\t\t\t});\n\t\t}\n\t\tconst isLeaving =\n\t\t\tsession.user.email === ctx.body.memberIdOrEmail ||\n\t\t\tmember.id === ctx.body.memberIdOrEmail;\n\t\tconst isOwnerLeaving =\n\t\t\tisLeaving &&\n\t\t\tmember.role === (ctx.context.orgOptions?.creatorRole || \"owner\");\n\t\tif (isOwnerLeaving) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"You cannot leave the organization as the owner\",\n\t\t\t});\n\t\t}\n\n\t\tconst canDeleteMember =\n\t\t\tisLeaving ||\n\t\t\trole.authorize({\n\t\t\t\tmember: [\"delete\"],\n\t\t\t}).success;\n\t\tif (!canDeleteMember) {\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"You are not allowed to delete this member\",\n\t\t\t});\n\t\t}\n\t\tlet existing: Member | null = null;\n\t\tif (ctx.body.memberIdOrEmail.includes(\"@\")) {\n\t\t\texisting = await adapter.findMemberByEmail({\n\t\t\t\temail: ctx.body.memberIdOrEmail,\n\t\t\t\torganizationId: orgId,\n\t\t\t});\n\t\t} else {\n\t\t\texisting = await adapter.findMemberById(ctx.body.memberIdOrEmail);\n\t\t}\n\t\tif (existing?.organizationId !== orgId) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Member not found!\",\n\t\t\t});\n\t\t}\n\t\tawait adapter.deleteMember(existing.id);\n\t\tif (\n\t\t\tsession.user.id === existing.userId &&\n\t\t\tsession.session.activeOrganizationId === existing.organizationId\n\t\t) {\n\t\t\tawait adapter.setActiveOrganization(session.session.id, null);\n\t\t}\n\t\treturn ctx.json({\n\t\t\tmember: existing,\n\t\t});\n\t},\n);\n\nexport const updateMemberRole = createAuthEndpoint(\n\t\"/organization/update-member-role\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\trole: z.enum([\"admin\", \"member\", \"owner\"]),\n\t\t\tmemberId: z.string(),\n\t\t\t/**\n\t\t\t * If not provided, the active organization will be used\n\t\t\t */\n\t\t\torganizationId: z.string().optional(),\n\t\t}),\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tconst orgId =\n\t\t\tctx.body.organizationId || session.session.activeOrganizationId;\n\t\tif (!orgId) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"No active organization found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst member = await adapter.findMemberByOrgId({\n\t\t\tuserId: session.user.id,\n\t\t\torganizationId: orgId,\n\t\t});\n\t\tif (!member) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"Member not found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst role = ctx.context.roles[member.role];\n\t\tif (!role) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"Role not found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\t/**\n\t\t * If the member is not an owner, they cannot update the role of another member\n\t\t * as an owner.\n\t\t */\n\t\tconst canUpdateMember =\n\t\t\trole.authorize({\n\t\t\t\tmember: [\"update\"],\n\t\t\t}).error ||\n\t\t\t(ctx.body.role === \"owner\" && member.role !== \"owner\");\n\t\tif (canUpdateMember) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"You are not allowed to update this member\",\n\t\t\t\t},\n\t\t\t\tstatus: 403,\n\t\t\t});\n\t\t}\n\n\t\tconst updatedMember = await adapter.updateMember(\n\t\t\tctx.body.memberId,\n\t\t\tctx.body.role,\n\t\t);\n\t\tif (!updatedMember) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"Member not found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\treturn ctx.json(updatedMember);\n\t},\n);\n","import { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../../api/call\";\nimport { generateId } from \"../../../utils/id\";\nimport { getOrgAdapter } from \"../adapter\";\nimport { orgMiddleware, orgSessionMiddleware } from \"../call\";\nimport { APIError } from \"better-call\";\n\nexport const createOrganization = createAuthEndpoint(\n\t\"/organization/create\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tname: z.string(),\n\t\t\tslug: z.string(),\n\t\t\tuserId: z.string().optional(),\n\t\t\tlogo: z.string().optional(),\n\t\t\tmetadata: z.record(z.string()).optional(),\n\t\t}),\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst user = ctx.context.session.user;\n\t\tif (!user) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 401,\n\t\t\t});\n\t\t}\n\t\tconst options = ctx.context.orgOptions;\n\t\tconst canCreateOrg =\n\t\t\ttypeof options?.allowUserToCreateOrganization === \"function\"\n\t\t\t\t? await options.allowUserToCreateOrganization(user)\n\t\t\t\t: options?.allowUserToCreateOrganization === undefined\n\t\t\t\t\t? true\n\t\t\t\t\t: options.allowUserToCreateOrganization;\n\n\t\tif (!canCreateOrg) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You are not allowed to create an organization\",\n\t\t\t});\n\t\t}\n\t\tconst adapter = getOrgAdapter(ctx.context, options);\n\n\t\tconst userOrganizations = await adapter.listOrganizations(user.id);\n\t\tconst hasReachedOrgLimit =\n\t\t\ttypeof options.organizationLimit === \"number\"\n\t\t\t\t? userOrganizations.length >= options.organizationLimit\n\t\t\t\t: typeof options.organizationLimit === \"function\"\n\t\t\t\t\t? await options.organizationLimit(user)\n\t\t\t\t\t: false;\n\n\t\tif (hasReachedOrgLimit) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You have reached the organization limit\",\n\t\t\t});\n\t\t}\n\n\t\tconst existingOrganization = await adapter.findOrganizationBySlug(\n\t\t\tctx.body.slug,\n\t\t);\n\t\tif (existingOrganization) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Organization with this slug already exists\",\n\t\t\t});\n\t\t}\n\t\tconst organization = await adapter.createOrganization({\n\t\t\torganization: {\n\t\t\t\tid: generateId(),\n\t\t\t\tslug: ctx.body.slug,\n\t\t\t\tname: ctx.body.name,\n\t\t\t\tlogo: ctx.body.logo,\n\t\t\t\tcreatedAt: new Date(),\n\t\t\t\tmetadata: ctx.body.metadata,\n\t\t\t},\n\t\t\tuser,\n\t\t});\n\t\treturn ctx.json(organization);\n\t},\n);\n\nexport const updateOrganization = createAuthEndpoint(\n\t\"/organization/update\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tdata: z\n\t\t\t\t.object({\n\t\t\t\t\tname: z.string().optional(),\n\t\t\t\t\tslug: z.string().optional(),\n\t\t\t\t})\n\t\t\t\t.partial(),\n\t\t\torgId: z.string().optional(),\n\t\t}),\n\t\trequireHeaders: true,\n\t\tuse: [orgMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = await ctx.context.getSession(ctx);\n\t\tif (!session) {\n\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"User not found\",\n\t\t\t});\n\t\t}\n\t\tconst orgId = ctx.body.orgId || session.session.activeOrganizationId;\n\t\tif (!orgId) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"Organization id not found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst member = await adapter.findMemberByOrgId({\n\t\t\tuserId: session.user.id,\n\t\t\torganizationId: orgId,\n\t\t});\n\t\tif (!member) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"User is not a member of this organization!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst role = ctx.context.roles[member.role];\n\t\tif (!role) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"Role not found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst canUpdateOrg = role.authorize({\n\t\t\torganization: [\"update\"],\n\t\t});\n\t\tif (canUpdateOrg.error) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"You are not allowed to update this organization\",\n\t\t\t\t},\n\t\t\t\tstatus: 403,\n\t\t\t});\n\t\t}\n\t\tconst updatedOrg = await adapter.updateOrganization(orgId, ctx.body.data);\n\t\treturn ctx.json(updatedOrg);\n\t},\n);\n\nexport const deleteOrganization = createAuthEndpoint(\n\t\"/organization/delete\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\torgId: z.string(),\n\t\t}),\n\t\trequireHeaders: true,\n\t\tuse: [orgMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = await ctx.context.getSession(ctx);\n\t\tif (!session) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 401,\n\t\t\t});\n\t\t}\n\t\tconst orgId = ctx.body.orgId;\n\t\tif (!orgId) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"Organization id not found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst member = await adapter.findMemberByOrgId({\n\t\t\tuserId: session.user.id,\n\t\t\torganizationId: orgId,\n\t\t});\n\t\tif (!member) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"User is not a member of this organization!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst role = ctx.context.roles[member.role];\n\t\tif (!role) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t\tbody: {\n\t\t\t\t\tmessage: \"Role not found!\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tconst canDeleteOrg = role.authorize({\n\t\t\torganization: [\"delete\"],\n\t\t});\n\t\tif (canDeleteOrg.error) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You are not allowed to delete this organization\",\n\t\t\t});\n\t\t}\n\t\tif (orgId === session.session.activeOrganizationId) {\n\t\t\t/**\n\t\t\t * If the organization is deleted, we set the active organization to null\n\t\t\t */\n\t\t\tawait adapter.setActiveOrganization(session.session.id, null);\n\t\t}\n\t\tawait adapter.deleteOrganization(orgId);\n\t\treturn ctx.json(orgId);\n\t},\n);\n\nexport const getFullOrganization = createAuthEndpoint(\n\t\"/organization/get-full\",\n\t{\n\t\tmethod: \"GET\",\n\t\tquery: z.object({\n\t\t\torgId: z.string().optional(),\n\t\t}),\n\t\trequireHeaders: true,\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tconst orgId = ctx.query.orgId || session.session.activeOrganizationId;\n\t\tif (!orgId) {\n\t\t\treturn ctx.json(null, {\n\t\t\t\tstatus: 400,\n\t\t\t});\n\t\t}\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst organization = await adapter.findFullOrganization(\n\t\t\torgId,\n\t\t\tctx.context.db || undefined,\n\t\t);\n\t\tif (!organization) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Organization not found\",\n\t\t\t});\n\t\t}\n\t\treturn ctx.json(organization);\n\t},\n);\n\nexport const setActiveOrganization = createAuthEndpoint(\n\t\"/organization/activate\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\torgId: z.string().nullable().optional(),\n\t\t}),\n\t\tuse: [orgSessionMiddleware, orgMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst session = ctx.context.session;\n\t\tlet orgId = ctx.body.orgId;\n\t\tif (orgId === null) {\n\t\t\tconst sessionOrgId = session.session.activeOrganizationId;\n\t\t\tif (!sessionOrgId) {\n\t\t\t\treturn ctx.json(null);\n\t\t\t}\n\t\t\tawait adapter.setActiveOrganization(session.session.id, null);\n\t\t\treturn ctx.json(null);\n\t\t}\n\t\tif (!orgId) {\n\t\t\tconst sessionOrgId = session.session.activeOrganizationId;\n\t\t\tif (!sessionOrgId) {\n\t\t\t\treturn ctx.json(null);\n\t\t\t}\n\t\t\torgId = sessionOrgId;\n\t\t}\n\t\tconst isMember = await adapter.findMemberByOrgId({\n\t\t\tuserId: session.user.id,\n\t\t\torganizationId: orgId,\n\t\t});\n\t\tif (!isMember) {\n\t\t\tawait adapter.setActiveOrganization(session.session.id, null);\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"You are not a member of this organization\",\n\t\t\t});\n\t\t}\n\t\tawait adapter.setActiveOrganization(session.session.id, orgId);\n\t\tconst organization = await adapter.findFullOrganization(\n\t\t\torgId,\n\t\t\tctx.context.db || undefined,\n\t\t);\n\t\treturn ctx.json(organization);\n\t},\n);\n\nexport const listOrganization = createAuthEndpoint(\n\t\"/organization/list\",\n\t{\n\t\tmethod: \"GET\",\n\t\tuse: [orgMiddleware, orgSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);\n\t\tconst organizations = await adapter.listOrganizations(\n\t\t\tctx.context.session.user.id,\n\t\t);\n\t\treturn ctx.json(organizations);\n\t},\n);\n","import { alphabet, generateRandomString } from \"../../crypto/random\";\nimport { z } from \"zod\";\nimport { createAuthEndpoint, createAuthMiddleware } from \"../../api/call\";\nimport { sessionMiddleware } from \"../../api\";\nimport { hs256, symmetricEncrypt } from \"../../crypto\";\nimport type { BetterAuthPlugin } from \"../../types/plugins\";\nimport { backupCode2fa, generateBackupCodes } from \"./backup-codes\";\nimport { otp2fa } from \"./otp\";\nimport { totp2fa } from \"./totp\";\nimport type { TwoFactorOptions, UserWithTwoFactor } from \"./types\";\nimport type { Session } from \"../../db/schema\";\nimport { TWO_FACTOR_COOKIE_NAME, TRUST_DEVICE_COOKIE_NAME } from \"./constant\";\nimport { validatePassword } from \"../../utils/password\";\nimport { APIError } from \"better-call\";\nimport { createTOTPKeyURI } from \"oslo/otp\";\nimport { TimeSpan } from \"oslo\";\n\nexport const twoFactor = (options?: TwoFactorOptions) => {\n\tconst opts = {\n\t\ttwoFactorTable: options?.twoFactorTable || (\"twoFactor\" as const),\n\t};\n\tconst totp = totp2fa(\n\t\t{\n\t\t\tissuer: options?.issuer || \"better-auth\",\n\t\t\t...options?.totpOptions,\n\t\t},\n\t\topts.twoFactorTable,\n\t);\n\tconst backupCode = backupCode2fa(\n\t\t{\n\t\t\t...options?.backupCodeOptions,\n\t\t},\n\t\topts.twoFactorTable,\n\t);\n\tconst otp = otp2fa(\n\t\t{\n\t\t\t...options?.otpOptions,\n\t\t},\n\t\topts.twoFactorTable,\n\t);\n\treturn {\n\t\tid: \"two-factor\",\n\t\tendpoints: {\n\t\t\t...totp.endpoints,\n\t\t\t...otp.endpoints,\n\t\t\t...backupCode.endpoints,\n\t\t\tenableTwoFactor: createAuthEndpoint(\n\t\t\t\t\"/two-factor/enable\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tpassword: z.string().min(8),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\t\t\tconst { password } = ctx.body;\n\t\t\t\t\tconst isPasswordValid = await validatePassword(ctx, {\n\t\t\t\t\t\tpassword,\n\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t});\n\t\t\t\t\tif (!isPasswordValid) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Invalid password\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst secret = generateRandomString(16, alphabet(\"a-z\", \"0-9\", \"-\"));\n\t\t\t\t\tconst encryptedSecret = await symmetricEncrypt({\n\t\t\t\t\t\tkey: ctx.context.secret,\n\t\t\t\t\t\tdata: secret,\n\t\t\t\t\t});\n\t\t\t\t\tconst backupCodes = await generateBackupCodes(\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\toptions?.backupCodeOptions,\n\t\t\t\t\t);\n\t\t\t\t\tif (options?.skipVerificationOnEnable) {\n\t\t\t\t\t\tawait ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\ttwoFactorEnabled: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\t//delete existing two factor\n\t\t\t\t\tawait ctx.context.adapter.deleteMany({\n\t\t\t\t\t\tmodel: opts.twoFactorTable,\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\n\t\t\t\t\tawait ctx.context.adapter.create({\n\t\t\t\t\t\tmodel: opts.twoFactorTable,\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tid: ctx.context.uuid(),\n\t\t\t\t\t\t\tsecret: encryptedSecret,\n\t\t\t\t\t\t\tbackupCodes: backupCodes.encryptedBackupCodes,\n\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tconst totpURI = createTOTPKeyURI(\n\t\t\t\t\t\toptions?.issuer || \"BetterAuth\",\n\t\t\t\t\t\tuser.email,\n\t\t\t\t\t\tBuffer.from(secret),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdigits: options?.totpOptions?.digits || 6,\n\t\t\t\t\t\t\tperiod: new TimeSpan(options?.totpOptions?.period || 30, \"s\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json({ totpURI, backupCodes: backupCodes.backupCodes });\n\t\t\t\t},\n\t\t\t),\n\t\t\tdisableTwoFactor: createAuthEndpoint(\n\t\t\t\t\"/two-factor/disable\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tpassword: z.string().min(8),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\t\t\tconst { password } = ctx.body;\n\t\t\t\t\tconst isPasswordValid = await validatePassword(ctx, {\n\t\t\t\t\t\tpassword,\n\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t});\n\t\t\t\t\tif (!isPasswordValid) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Invalid password\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tawait ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\ttwoFactorEnabled: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait ctx.context.adapter.delete({\n\t\t\t\t\t\tmodel: opts.twoFactorTable,\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t\tvalue: user.id,\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\treturn ctx.json({ status: true });\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\toptions: options,\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher(context) {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\tcontext.path === \"/sign-in/email\" ||\n\t\t\t\t\t\t\tcontext.path === \"/sign-in/username\"\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst returned = ctx.context.returned;\n\t\t\t\t\t\tif (returned?.status !== 200) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst response = (await returned.clone().json()) as {\n\t\t\t\t\t\t\tuser: UserWithTwoFactor;\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (!response.user.twoFactorEnabled) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check for trust device cookie\n\t\t\t\t\t\tconst trustDeviceCookieName = ctx.context.createAuthCookie(\n\t\t\t\t\t\t\tTRUST_DEVICE_COOKIE_NAME,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmaxAge: 30 * 24 * 60 * 60, // 30 days\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst trustDeviceCookie = await ctx.getSignedCookie(\n\t\t\t\t\t\t\ttrustDeviceCookieName.name,\n\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (trustDeviceCookie) {\n\t\t\t\t\t\t\tconst [token, sessionId] = trustDeviceCookie.split(\"!\");\n\t\t\t\t\t\t\tconst expectedToken = await hs256(\n\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\t`${response.user.id}!${sessionId}`,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (token === expectedToken) {\n\t\t\t\t\t\t\t\t// Trust device cookie is valid, refresh it and skip 2FA\n\t\t\t\t\t\t\t\tconst newToken = await hs256(\n\t\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\t\t`${response.user.id}!${response.session.id}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\t\t\t\ttrustDeviceCookieName.name,\n\t\t\t\t\t\t\t\t\t`${newToken}!${response.session.id}`,\n\t\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\t\ttrustDeviceCookieName.options,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * remove the session cookie. It's set by the sign in credential\n\t\t\t\t\t\t */\n\t\t\t\t\t\tctx.setCookie(ctx.context.authCookies.sessionToken.name, \"\", {\n\t\t\t\t\t\t\tpath: \"/\",\n\t\t\t\t\t\t\tsameSite: \"lax\",\n\t\t\t\t\t\t\thttpOnly: true,\n\t\t\t\t\t\t\tsecure: false,\n\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst hash = await hs256(ctx.context.secret, response.session.id);\n\t\t\t\t\t\tconst cookieName = ctx.context.createAuthCookie(\n\t\t\t\t\t\t\tTWO_FACTOR_COOKIE_NAME,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmaxAge: 60 * 60 * 24, // 24 hours,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * We set the user id and the session\n\t\t\t\t\t\t * id as a hash. Later will fetch for\n\t\t\t\t\t\t * sessions with the user id compare\n\t\t\t\t\t\t * the hash and set that as session.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\t\tcookieName.name,\n\t\t\t\t\t\t\t`${response.session.userId}!${hash}`,\n\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\tcookieName.options,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst res = new Response(\n\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\ttwoFactorRedirect: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\theaders: ctx.responseHeader,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tresponse: res,\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\tschema: {\n\t\t\tuser: {\n\t\t\t\tfields: {\n\t\t\t\t\ttwoFactorEnabled: {\n\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\tdefaultValue: false,\n\t\t\t\t\t\tinput: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttwoFactor: {\n\t\t\t\ttableName: opts.twoFactorTable,\n\t\t\t\tfields: {\n\t\t\t\t\tsecret: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\treturned: false,\n\t\t\t\t\t},\n\t\t\t\t\tbackupCodes: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\treturned: false,\n\t\t\t\t\t},\n\t\t\t\t\tuserId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\treturned: false,\n\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\tfield: \"id\",\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\trateLimit: [\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path.startsWith(\"/two-factor/\");\n\t\t\t\t},\n\t\t\t\twindow: 10,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t],\n\t} satisfies BetterAuthPlugin;\n};\n\nexport * from \"./client\";\n","import { alphabet, generateRandomString } from \"../../../crypto/random\";\nimport { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../../api/call\";\nimport { sessionMiddleware } from \"../../../api\";\nimport { symmetricDecrypt, symmetricEncrypt } from \"../../../crypto\";\nimport { verifyTwoFactorMiddleware } from \"../verify-middleware\";\nimport type {\n\tTwoFactorProvider,\n\tTwoFactorTable,\n\tUserWithTwoFactor,\n} from \"../types\";\nimport { APIError } from \"better-call\";\nimport { setSessionCookie } from \"../../../cookies\";\n\nexport interface BackupCodeOptions {\n\t/**\n\t * The amount of backup codes to generate\n\t *\n\t * @default 10\n\t */\n\tamount?: number;\n\t/**\n\t * The length of the backup codes\n\t *\n\t * @default 10\n\t */\n\tlength?: number;\n\tcustomBackupCodesGenerate?: () => string[];\n}\n\nfunction generateBackupCodesFn(options?: BackupCodeOptions) {\n\treturn Array.from({ length: options?.amount ?? 10 })\n\t\t.fill(null)\n\t\t.map(() =>\n\t\t\tgenerateRandomString(options?.length ?? 10, alphabet(\"a-z\", \"0-9\")),\n\t\t)\n\t\t.map((code) => `${code.slice(0, 5)}-${code.slice(5)}`);\n}\n\nexport async function generateBackupCodes(\n\tsecret: string,\n\toptions?: BackupCodeOptions,\n) {\n\tconst key = secret;\n\tconst backupCodes = options?.customBackupCodesGenerate\n\t\t? options.customBackupCodesGenerate()\n\t\t: generateBackupCodesFn();\n\tconst encCodes = await symmetricEncrypt({\n\t\tdata: JSON.stringify(backupCodes),\n\t\tkey: key,\n\t});\n\treturn {\n\t\tbackupCodes,\n\t\tencryptedBackupCodes: encCodes,\n\t};\n}\n\nexport async function verifyBackupCode(\n\tdata: {\n\t\tbackupCodes: string;\n\t\tcode: string;\n\t},\n\tkey: string,\n) {\n\tconst codes = await getBackupCodes(data.backupCodes, key);\n\tif (!codes) {\n\t\treturn false;\n\t}\n\treturn codes.includes(data.code);\n}\n\nexport async function getBackupCodes(backupCodes: string, key: string) {\n\tconst secret = Buffer.from(\n\t\tawait symmetricDecrypt({ key, data: backupCodes }),\n\t).toString(\"utf-8\");\n\tconst data = JSON.parse(secret);\n\tconst result = z.array(z.string()).safeParse(data);\n\tif (result.success) {\n\t\treturn result.data;\n\t}\n\treturn null;\n}\n\nexport const backupCode2fa = (\n\toptions: BackupCodeOptions,\n\ttwoFactorTable: string,\n) => {\n\treturn {\n\t\tid: \"backup_code\",\n\t\tendpoints: {\n\t\t\tverifyBackupCode: createAuthEndpoint(\n\t\t\t\t\"/two-factor/verify-backup-code\",\n\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tcode: z.string(),\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Disable setting the session cookie\n\t\t\t\t\t\t */\n\t\t\t\t\t\tdisableSession: z.boolean().optional(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [verifyTwoFactorMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\t\t\tconst twoFactor = await ctx.context.adapter.findOne<TwoFactorTable>({\n\t\t\t\t\t\tmodel: twoFactorTable,\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t\tvalue: user.id,\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\tif (!twoFactor) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Backup codes aren't enabled\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst validate = verifyBackupCode(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbackupCodes: twoFactor.backupCodes,\n\t\t\t\t\t\t\tcode: ctx.body.code,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t);\n\t\t\t\t\tif (!validate) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Invalid backup code\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (!ctx.body.disableSession) {\n\t\t\t\t\t\tawait setSessionCookie(ctx, ctx.context.session.id);\n\t\t\t\t\t}\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tuser: user,\n\t\t\t\t\t\tsession: ctx.context.session,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tgenerateBackupCodes: createAuthEndpoint(\n\t\t\t\t\"/two-factor/generate-backup-codes\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\t\t\tif (!user.twoFactorEnabled) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Two factor isn't enabled\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst backupCodes = await generateBackupCodes(\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t);\n\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\tmodel: twoFactorTable,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tbackupCodes: backupCodes.encryptedBackupCodes,\n\t\t\t\t\t\t},\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t\tvalue: ctx.context.session.user.id,\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\treturn ctx.json({\n\t\t\t\t\t\tstatus: true,\n\t\t\t\t\t\tbackupCodes: backupCodes.backupCodes,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tviewBackupCodes: createAuthEndpoint(\n\t\t\t\t\"/view/backup-codes\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\t\t\tconst twoFactor = await ctx.context.adapter.findOne<TwoFactorTable>({\n\t\t\t\t\t\tmodel: twoFactorTable,\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t\tvalue: user.id,\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\tif (!twoFactor) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Backup codes aren't enabled\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst backupCodes = getBackupCodes(\n\t\t\t\t\t\ttwoFactor.backupCodes,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t);\n\t\t\t\t\tif (!backupCodes) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Backup codes aren't enabled\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tstatus: true,\n\t\t\t\t\t\tbackupCodes: backupCodes,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t} satisfies TwoFactorProvider;\n};\n","import { APIError } from \"better-call\";\nimport type { Session } from \"../../db/schema\";\nimport { createAuthMiddleware } from \"../../api/call\";\nimport { hs256 } from \"../../crypto\";\nimport { TRUST_DEVICE_COOKIE_NAME, TWO_FACTOR_COOKIE_NAME } from \"./constant\";\nimport type { UserWithTwoFactor } from \"./types\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { z } from \"zod\";\nimport { getSessionFromCtx } from \"../../api\";\n\nexport const verifyTwoFactorMiddleware = createAuthMiddleware(\n\t{\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * if true, the device will be trusted\n\t\t\t * for 30 days. It'll be refreshed on\n\t\t\t * every sign in request within this time.\n\t\t\t */\n\t\t\ttrustDevice: z.boolean().optional(),\n\t\t}),\n\t},\n\tasync (ctx) => {\n\t\tconst session = await getSessionFromCtx(ctx);\n\t\tif (!session) {\n\t\t\tconst cookieName = ctx.context.createAuthCookie(TWO_FACTOR_COOKIE_NAME);\n\t\t\tconst cookie = await ctx.getSignedCookie(\n\t\t\t\tcookieName.name,\n\t\t\t\tctx.context.secret,\n\t\t\t);\n\t\t\tif (!cookie) {\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"invalid two factor cookie\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst [userId, hash] = cookie.split(\"!\");\n\t\t\tif (!userId || !hash) {\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"invalid two factor cookie\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst sessions = await ctx.context.adapter.findMany<Session>({\n\t\t\t\tmodel: ctx.context.tables.session.tableName,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!sessions.length) {\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"invalid session\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst activeSessions = sessions.filter(\n\t\t\t\t(session) => session.expiresAt > new Date(),\n\t\t\t);\n\t\t\tif (!activeSessions) {\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"invalid session\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const session of activeSessions) {\n\t\t\t\tconst hashToMatch = await hs256(ctx.context.secret, session.id);\n\t\t\t\tconst user = await ctx.context.adapter.findOne<UserWithTwoFactor>({\n\t\t\t\t\tmodel: ctx.context.tables.user.tableName,\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\tvalue: session.userId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tif (!user) {\n\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\tmessage: \"invalid session\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (hashToMatch === hash) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tvalid: async () => {\n\t\t\t\t\t\t\tawait setSessionCookie(ctx, session.id, false);\n\t\t\t\t\t\t\tif (ctx.body.trustDevice) {\n\t\t\t\t\t\t\t\tconst trustDeviceCookie = ctx.context.createAuthCookie(\n\t\t\t\t\t\t\t\t\tTRUST_DEVICE_COOKIE_NAME,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tmaxAge: 30 * 24 * 60 * 60, // 30 days, it'll be refreshed on sign in requests\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\t/**\n\t\t\t\t\t\t\t\t * create a token that will be used to\n\t\t\t\t\t\t\t\t * verify the device\n\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\tconst token = await hs256(\n\t\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\t\t`${user.id}!${session.id}`,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\t\t\t\ttrustDeviceCookie.name,\n\t\t\t\t\t\t\t\t\t`${token}!${session.id}`,\n\t\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\t\ttrustDeviceCookie.options,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinvalid: async () => {\n\t\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\t\tmessage: \"invalid two factor authentication\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\tid: session.id,\n\t\t\t\t\t\t\tuserId: session.userId,\n\t\t\t\t\t\t\texpiresAt: session.expiresAt,\n\t\t\t\t\t\t\tuser,\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\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"invalid two factor cookie\",\n\t\t\t});\n\t\t}\n\t\treturn {\n\t\t\tvalid: async () => {\n\t\t\t\treturn ctx.json({\n\t\t\t\t\tsession,\n\t\t\t\t\tuser: session.user,\n\t\t\t\t});\n\t\t\t},\n\t\t\tinvalid: async () => {\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"invalid two factor authentication\",\n\t\t\t\t});\n\t\t\t},\n\t\t\tsession,\n\t\t};\n\t},\n);\n","export const TWO_FACTOR_COOKIE_NAME = \"two-factor\";\nexport const OTP_RANDOM_NUMBER_COOKIE_NAME = \"otp.counter\";\nexport const TRUST_DEVICE_COOKIE_NAME = \"trust-device\";\n","import { APIError } from \"better-call\";\nimport { TOTPController } from \"oslo/otp\";\nimport { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../../api/call\";\nimport { verifyTwoFactorMiddleware } from \"../verify-middleware\";\nimport type {\n\tTwoFactorProvider,\n\tTwoFactorTable,\n\tUserWithTwoFactor,\n} from \"../types\";\nimport { TimeSpan } from \"oslo\";\n\nexport interface OTPOptions {\n\t/**\n\t * How long the opt will be valid for in\n\t * minutes\n\t *\n\t * @default \"3 mins\"\n\t */\n\tperiod?: number;\n\t/**\n\t * Send the otp to the user\n\t *\n\t * @param user - The user to send the otp to\n\t * @param otp - The otp to send\n\t * @returns void | Promise<void>\n\t */\n\tsendOTP?: (user: UserWithTwoFactor, otp: string) => Promise<void> | void;\n}\n\n/**\n * The otp adapter is created from the totp adapter.\n */\nexport const otp2fa = (options: OTPOptions, twoFactorTable: string) => {\n\tconst opts = {\n\t\t...options,\n\t\tperiod: new TimeSpan(options?.period || 3, \"m\"),\n\t};\n\tconst totp = new TOTPController({\n\t\tdigits: 6,\n\t\tperiod: opts.period,\n\t});\n\t/**\n\t * Generate OTP and send it to the user.\n\t */\n\tconst send2FaOTP = createAuthEndpoint(\n\t\t\"/two-factor/send-otp\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tuse: [verifyTwoFactorMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!options || !options.sendOTP) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\"send otp isn't configured. Please configure the send otp function on otp options.\",\n\t\t\t\t);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"otp isn't configured\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\tconst twoFactor = await ctx.context.adapter.findOne<TwoFactorTable>({\n\t\t\t\tmodel: twoFactorTable,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!twoFactor) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"OTP isn't enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst code = await totp.generate(Buffer.from(twoFactor.secret));\n\t\t\tawait options.sendOTP(user, code);\n\t\t\treturn ctx.json({ status: true });\n\t\t},\n\t);\n\n\tconst verifyOTP = createAuthEndpoint(\n\t\t\"/two-factor/verify-otp\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: z.object({\n\t\t\t\tcode: z.string(),\n\t\t\t}),\n\t\t\tuse: [verifyTwoFactorMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst user = ctx.context.session.user;\n\t\t\tif (!user.twoFactorEnabled) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"two factor isn't enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst twoFactor = await ctx.context.adapter.findOne<TwoFactorTable>({\n\t\t\t\tmodel: twoFactorTable,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!twoFactor) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"OTP isn't enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst toCheckOtp = await totp.generate(Buffer.from(twoFactor.secret));\n\t\t\tif (toCheckOtp === ctx.body.code) {\n\t\t\t\treturn ctx.context.valid();\n\t\t\t} else {\n\t\t\t\treturn ctx.context.invalid();\n\t\t\t}\n\t\t},\n\t);\n\treturn {\n\t\tid: \"otp\",\n\t\tendpoints: {\n\t\t\tsend2FaOTP,\n\t\t\tverifyOTP,\n\t\t},\n\t} satisfies TwoFactorProvider;\n};\n","import { APIError } from \"better-call\";\nimport { TimeSpan } from \"oslo\";\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../../api/call\";\nimport { sessionMiddleware } from \"../../../api\";\nimport { symmetricDecrypt } from \"../../../crypto\";\nimport type { BackupCodeOptions } from \"../backup-codes\";\nimport { verifyTwoFactorMiddleware } from \"../verify-middleware\";\nimport type {\n\tTwoFactorProvider,\n\tTwoFactorTable,\n\tUserWithTwoFactor,\n} from \"../types\";\n\nexport type TOTPOptions = {\n\t/**\n\t * Issuer\n\t */\n\tissuer: string;\n\t/**\n\t * How many digits the otp to be\n\t *\n\t * @default 6\n\t */\n\tdigits?: 6 | 8;\n\t/**\n\t * Period for otp in seconds.\n\t * @default 30\n\t */\n\tperiod?: number;\n\t/**\n\t * Backup codes configuration\n\t */\n\tbackupCodes?: BackupCodeOptions;\n};\n\nexport const totp2fa = (options: TOTPOptions, twoFactorTable: string) => {\n\tconst opts = {\n\t\t...options,\n\t\tdigits: 6,\n\t\tperiod: new TimeSpan(options?.period || 30, \"s\"),\n\t};\n\n\tconst generateTOTP = createAuthEndpoint(\n\t\t\"/totp/generate\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tuse: [sessionMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!options) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\"totp isn't configured. please pass totp option on two factor plugin to enable totp\",\n\t\t\t\t);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"totp isn't configured\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\tconst twoFactor = await ctx.context.adapter.findOne<TwoFactorTable>({\n\t\t\t\tmodel: twoFactorTable,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!twoFactor) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"totp isn't enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst totp = new TOTPController(opts);\n\t\t\tconst code = await totp.generate(Buffer.from(twoFactor.secret));\n\t\t\treturn { code };\n\t\t},\n\t);\n\n\tconst getTOTPURI = createAuthEndpoint(\n\t\t\"/two-factor/get-totp-uri\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tuse: [sessionMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!options) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\"totp isn't configured. please pass totp option on two factor plugin to enable totp\",\n\t\t\t\t);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"totp isn't configured\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\tconst twoFactor = await ctx.context.adapter.findOne<TwoFactorTable>({\n\t\t\t\tmodel: twoFactorTable,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!twoFactor || !user.twoFactorEnabled) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"totp isn't enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttotpURI: createTOTPKeyURI(\n\t\t\t\t\toptions?.issuer || \"BetterAuth\",\n\t\t\t\t\tuser.email,\n\t\t\t\t\tBuffer.from(twoFactor.secret),\n\t\t\t\t\topts,\n\t\t\t\t),\n\t\t\t};\n\t\t},\n\t);\n\n\tconst verifyTOTP = createAuthEndpoint(\n\t\t\"/two-factor/verify-totp\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: z.object({\n\t\t\t\tcode: z.string(),\n\t\t\t}),\n\t\t\tuse: [verifyTwoFactorMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!options) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\"totp isn't configured. please pass totp option on two factor plugin to enable totp\",\n\t\t\t\t);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"totp isn't configured\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst user = ctx.context.session.user as UserWithTwoFactor;\n\t\t\tconst twoFactor = await ctx.context.adapter.findOne<TwoFactorTable>({\n\t\t\t\tmodel: twoFactorTable,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (!twoFactor) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"totp isn't enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst totp = new TOTPController(opts);\n\t\t\tconst decrypted = await symmetricDecrypt({\n\t\t\t\tkey: ctx.context.secret,\n\t\t\t\tdata: twoFactor.secret,\n\t\t\t});\n\t\t\tconst secret = Buffer.from(decrypted);\n\t\t\tconst status = await totp.verify(ctx.body.code, secret);\n\t\t\tif (!status) {\n\t\t\t\treturn ctx.context.invalid();\n\t\t\t}\n\n\t\t\tif (!user.twoFactorEnabled) {\n\t\t\t\tawait ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\ttwoFactorEnabled: true,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn ctx.context.valid();\n\t\t},\n\t);\n\treturn {\n\t\tid: \"totp\",\n\t\tendpoints: {\n\t\t\tgenerateTOTP: generateTOTP,\n\t\t\tviewTOTPURI: getTOTPURI,\n\t\t\tverifyTOTP,\n\t\t},\n\t} satisfies TwoFactorProvider;\n};\n","import type { GenericEndpointContext } from \"../types/context\";\n\nexport async function validatePassword(\n\tctx: GenericEndpointContext,\n\tdata: {\n\t\tpassword: string;\n\t\tuserId: string;\n\t},\n) {\n\tconst accounts = await ctx.context.internalAdapter.findAccounts(data.userId);\n\tconst credentialAccount = accounts?.find(\n\t\t(account) => account.providerId === \"credential\",\n\t);\n\tconst currentPassword = credentialAccount?.password;\n\tif (!credentialAccount || !currentPassword) {\n\t\treturn false;\n\t}\n\tconst compare = await ctx.context.password.verify(\n\t\tcurrentPassword,\n\t\tdata.password,\n\t);\n\treturn compare;\n}\n","import type { BetterAuthClientPlugin } from \"../../client/types\";\nimport type { twoFactor as twoFa } from \"../../plugins/two-factor\";\n\nexport const twoFactorClient = (\n\toptions: {\n\t\ttwoFactorPage: string;\n\t\t/**\n\t\t * Redirect to the two factor page. If twoFactorPage\n\t\t * is not set this will redirect to the root path.\n\t\t * @default true\n\t\t */\n\t\tredirect?: boolean;\n\t} = {\n\t\tredirect: true,\n\t\ttwoFactorPage: \"/\",\n\t},\n) => {\n\treturn {\n\t\tid: \"two-factor\",\n\t\t$InferServerPlugin: {} as ReturnType<typeof twoFa>,\n\t\tatomListeners: [\n\t\t\t{\n\t\t\t\tmatcher: (path) => path.startsWith(\"/two-factor/\"),\n\t\t\t\tsignal: \"_sessionSignal\",\n\t\t\t},\n\t\t],\n\t\tpathMethods: {\n\t\t\t\"/two-factor/disable\": \"POST\",\n\t\t\t\"/two-factor/enable\": \"POST\",\n\t\t\t\"/two-factor/send-otp\": \"POST\",\n\t\t\t\"/two-factor/generate-backup-codes\": \"POST\",\n\t\t},\n\t\tfetchPlugins: [\n\t\t\t{\n\t\t\t\tid: \"two-factor\",\n\t\t\t\tname: \"two-factor\",\n\t\t\t\thooks: {\n\t\t\t\t\tasync onSuccess(context) {\n\t\t\t\t\t\tif (context.data?.twoFactorRedirect) {\n\t\t\t\t\t\t\tif (options.redirect || options.twoFactorPage) {\n\t\t\t\t\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\t\t\t\t\twindow.location.href = options.twoFactorPage;\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} satisfies BetterAuthClientPlugin;\n};\n","import {\n\tgenerateAuthenticationOptions,\n\tgenerateRegistrationOptions,\n\tverifyAuthenticationResponse,\n\tverifyRegistrationResponse,\n} from \"@simplewebauthn/server\";\nimport type {\n\tAuthenticationResponseJSON,\n\tAuthenticatorTransportFuture,\n\tCredentialDeviceType,\n\tPublicKeyCredentialCreationOptionsJSON,\n} from \"@simplewebauthn/types\";\nimport { APIError } from \"better-call\";\nimport { alphabet, generateRandomString } from \"../../crypto/random\";\nimport { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../api/call\";\nimport { sessionMiddleware } from \"../../api\";\nimport { getSessionFromCtx } from \"../../api/routes\";\nimport type { BetterAuthPlugin } from \"../../types/plugins\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { BetterAuthError } from \"../../error\";\nimport { generateId } from \"../../utils/id\";\nimport { env } from \"std-env\";\n\ninterface WebAuthnChallengeValue {\n\texpectedChallenge: string;\n\tuserData: {\n\t\tid: string;\n\t};\n}\n\nexport interface PasskeyOptions {\n\t/**\n\t * A unique identifier for your website. 'localhost' is okay for\n\t * local dev\n\t *\n\t * @default \"localhost\"\n\t */\n\trpID?: string;\n\t/**\n\t * Human-readable title for your website\n\t *\n\t * @default \"Better Auth\"\n\t */\n\trpName?: string;\n\t/**\n\t * The URL at which registrations and authentications should occur.\n\t * 'http://localhost' and 'http://localhost:PORT' are also valid.\n\t * Do NOT include any trailing /\n\t *\n\t * if this isn't provided. The client itself will\n\t * pass this value.\n\t */\n\torigin?: string | null;\n\t/**\n\t * Advanced options\n\t */\n\tadvanced?: {\n\t\twebAuthnChallengeCookie?: string;\n\t};\n}\n\nexport type Passkey = {\n\tid: string;\n\tname?: string;\n\tpublicKey: string;\n\tuserId: string;\n\twebauthnUserID: string;\n\tcounter: number;\n\tdeviceType: CredentialDeviceType;\n\tbackedUp: boolean;\n\ttransports?: string;\n\tcreatedAt: Date;\n};\n\nexport const passkey = (options?: PasskeyOptions) => {\n\tconst baseURL = env.BETTER_AUTH_URL;\n\tconst rpID =\n\t\toptions?.rpID ||\n\t\tbaseURL?.replace(\"http://\", \"\").replace(\"https://\", \"\").split(\":\")[0] ||\n\t\t\"localhost\";\n\tif (!rpID) {\n\t\tthrow new BetterAuthError(\n\t\t\t\"passkey rpID not found. Please provide a rpID in the options or set the BETTER_AUTH_URL environment variable.\",\n\t\t);\n\t}\n\tconst opts = {\n\t\torigin: null,\n\t\t...options,\n\t\trpID,\n\t\tadvanced: {\n\t\t\twebAuthnChallengeCookie: \"better-auth-passkey\",\n\t\t\t...options?.advanced,\n\t\t},\n\t};\n\tconst expirationTime = new Date(Date.now() + 1000 * 60 * 5);\n\tconst currentTime = new Date();\n\tconst maxAgeInSeconds = Math.floor(\n\t\t(expirationTime.getTime() - currentTime.getTime()) / 1000,\n\t);\n\treturn {\n\t\tid: \"passkey\",\n\t\tendpoints: {\n\t\t\tgeneratePasskeyRegistrationOptions: createAuthEndpoint(\n\t\t\t\t\"/passkey/generate-register-options\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tclient: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst session = ctx.context.session;\n\t\t\t\t\tconst userPasskeys = await ctx.context.adapter.findMany<Passkey>({\n\t\t\t\t\t\tmodel: \"passkey\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t\tvalue: session.user.id,\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\tconst userID = new Uint8Array(\n\t\t\t\t\t\tBuffer.from(generateRandomString(32, alphabet(\"a-z\", \"0-9\"))),\n\t\t\t\t\t);\n\t\t\t\t\tlet options: PublicKeyCredentialCreationOptionsJSON;\n\t\t\t\t\toptions = await generateRegistrationOptions({\n\t\t\t\t\t\trpName: opts.rpName || ctx.context.appName,\n\t\t\t\t\t\trpID: opts.rpID,\n\t\t\t\t\t\tuserID,\n\t\t\t\t\t\tuserName: session.user.email || session.user.id,\n\t\t\t\t\t\tattestationType: \"none\",\n\t\t\t\t\t\texcludeCredentials: userPasskeys.map((passkey) => ({\n\t\t\t\t\t\t\tid: passkey.id,\n\t\t\t\t\t\t\ttransports: passkey.transports?.split(\n\t\t\t\t\t\t\t\t\",\",\n\t\t\t\t\t\t\t) as AuthenticatorTransportFuture[],\n\t\t\t\t\t\t})),\n\t\t\t\t\t\tauthenticatorSelection: {\n\t\t\t\t\t\t\tresidentKey: \"preferred\",\n\t\t\t\t\t\t\tuserVerification: \"preferred\",\n\t\t\t\t\t\t\tauthenticatorAttachment: \"platform\",\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tconst id = generateId();\n\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\topts.advanced.webAuthnChallengeCookie,\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsecure: true,\n\t\t\t\t\t\t\thttpOnly: true,\n\t\t\t\t\t\t\tsameSite: \"lax\",\n\t\t\t\t\t\t\tmaxAge: maxAgeInSeconds,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\tidentifier: id,\n\t\t\t\t\t\tvalue: JSON.stringify({\n\t\t\t\t\t\t\texpectedChallenge: options.challenge,\n\t\t\t\t\t\t\tuserData: {\n\t\t\t\t\t\t\t\tid: session.user.id,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\texpiresAt: expirationTime,\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json(options, {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tgeneratePasskeyAuthenticationOptions: createAuthEndpoint(\n\t\t\t\t\"/passkey/generate-authenticate-options\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z\n\t\t\t\t\t\t.object({\n\t\t\t\t\t\t\temail: z.string().optional(),\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.optional(),\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst session = await getSessionFromCtx(ctx);\n\t\t\t\t\tlet userPasskeys: Passkey[] = [];\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\tuserPasskeys = await ctx.context.adapter.findMany<Passkey>({\n\t\t\t\t\t\t\tmodel: \"passkey\",\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t\t\tvalue: session.user.id,\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\tconst options = await generateAuthenticationOptions({\n\t\t\t\t\t\trpID: opts.rpID,\n\t\t\t\t\t\tuserVerification: \"preferred\",\n\t\t\t\t\t\t...(userPasskeys.length\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tallowCredentials: userPasskeys.map((passkey) => ({\n\t\t\t\t\t\t\t\t\t\tid: passkey.id,\n\t\t\t\t\t\t\t\t\t\ttransports: passkey.transports?.split(\n\t\t\t\t\t\t\t\t\t\t\t\",\",\n\t\t\t\t\t\t\t\t\t\t) as AuthenticatorTransportFuture[],\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});\n\t\t\t\t\tconst data = {\n\t\t\t\t\t\texpectedChallenge: options.challenge,\n\t\t\t\t\t\tuserData: {\n\t\t\t\t\t\t\tid: session?.user.id || \"\",\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tconst id = generateId();\n\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\topts.advanced.webAuthnChallengeCookie,\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsecure: true,\n\t\t\t\t\t\t\thttpOnly: true,\n\t\t\t\t\t\t\tsameSite: \"lax\",\n\t\t\t\t\t\t\tmaxAge: maxAgeInSeconds,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\tidentifier: id,\n\t\t\t\t\t\tvalue: JSON.stringify(data),\n\t\t\t\t\t\texpiresAt: expirationTime,\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json(options, {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tverifyPasskeyRegistration: createAuthEndpoint(\n\t\t\t\t\"/passkey/verify-registration\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tresponse: z.any(),\n\t\t\t\t\t\tname: z.string().optional(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst origin = options?.origin || ctx.headers?.get(\"origin\") || \"\";\n\t\t\t\t\tif (!origin) {\n\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst resp = ctx.body.response;\n\t\t\t\t\tconst challengeId = await ctx.getSignedCookie(\n\t\t\t\t\t\topts.advanced.webAuthnChallengeCookie,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t);\n\t\t\t\t\tif (!challengeId) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Challenge not found\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst data =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\t\t\tchallengeId,\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!data) {\n\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst { expectedChallenge, userData } = JSON.parse(\n\t\t\t\t\t\tdata.value,\n\t\t\t\t\t) as WebAuthnChallengeValue;\n\n\t\t\t\t\tif (userData.id !== ctx.context.session.user.id) {\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"You are not authorized to register this passkey\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst verification = await verifyRegistrationResponse({\n\t\t\t\t\t\t\tresponse: resp,\n\t\t\t\t\t\t\texpectedChallenge,\n\t\t\t\t\t\t\texpectedOrigin: origin,\n\t\t\t\t\t\t\texpectedRPID: options?.rpID,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst { verified, registrationInfo } = verification;\n\t\t\t\t\t\tif (!verified || !registrationInfo) {\n\t\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst {\n\t\t\t\t\t\t\tcredentialID,\n\t\t\t\t\t\t\tcredentialPublicKey,\n\t\t\t\t\t\t\tcounter,\n\t\t\t\t\t\t\tcredentialDeviceType,\n\t\t\t\t\t\t\tcredentialBackedUp,\n\t\t\t\t\t\t} = registrationInfo;\n\t\t\t\t\t\tconst pubKey = Buffer.from(credentialPublicKey).toString(\"base64\");\n\t\t\t\t\t\tconst userID = generateId();\n\t\t\t\t\t\tconst newPasskey: Passkey = {\n\t\t\t\t\t\t\tname: ctx.body.name,\n\t\t\t\t\t\t\tuserId: userData.id,\n\t\t\t\t\t\t\twebauthnUserID: userID,\n\t\t\t\t\t\t\tid: credentialID,\n\t\t\t\t\t\t\tpublicKey: pubKey,\n\t\t\t\t\t\t\tcounter,\n\t\t\t\t\t\t\tdeviceType: credentialDeviceType,\n\t\t\t\t\t\t\ttransports: resp.response.transports.join(\",\"),\n\t\t\t\t\t\t\tbackedUp: credentialBackedUp,\n\t\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst newPasskeyRes = await ctx.context.adapter.create<Passkey>({\n\t\t\t\t\t\t\tmodel: \"passkey\",\n\t\t\t\t\t\t\tdata: newPasskey,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn ctx.json(newPasskeyRes, {\n\t\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.log(e);\n\t\t\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\t\t\tmessage: \"Failed to verify registration\",\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\tverifyPasskeyAuthentication: createAuthEndpoint(\n\t\t\t\t\"/passkey/verify-authentication\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tresponse: z.any(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst origin = options?.origin || ctx.headers?.get(\"origin\") || \"\";\n\t\t\t\t\tif (!origin) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"origin missing\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst resp = ctx.body.response;\n\t\t\t\t\tconst challengeId = await ctx.getSignedCookie(\n\t\t\t\t\t\topts.advanced.webAuthnChallengeCookie,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t);\n\t\t\t\t\tif (!challengeId) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Challenge not found\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst data =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\t\t\tchallengeId,\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!data) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Challenge not found\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst { expectedChallenge } = JSON.parse(\n\t\t\t\t\t\tdata.value,\n\t\t\t\t\t) as WebAuthnChallengeValue;\n\t\t\t\t\tconst passkey = await ctx.context.adapter.findOne<Passkey>({\n\t\t\t\t\t\tmodel: \"passkey\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: resp.id,\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\tif (!passkey) {\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"Passkey not found\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst verification = await verifyAuthenticationResponse({\n\t\t\t\t\t\t\tresponse: resp as AuthenticationResponseJSON,\n\t\t\t\t\t\t\texpectedChallenge,\n\t\t\t\t\t\t\texpectedOrigin: origin,\n\t\t\t\t\t\t\texpectedRPID: opts.rpID,\n\t\t\t\t\t\t\tauthenticator: {\n\t\t\t\t\t\t\t\tcredentialID: passkey.id,\n\t\t\t\t\t\t\t\tcredentialPublicKey: new Uint8Array(\n\t\t\t\t\t\t\t\t\tBuffer.from(passkey.publicKey, \"base64\"),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tcounter: passkey.counter,\n\t\t\t\t\t\t\t\ttransports: passkey.transports?.split(\n\t\t\t\t\t\t\t\t\t\",\",\n\t\t\t\t\t\t\t\t) as AuthenticatorTransportFuture[],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst { verified } = verification;\n\t\t\t\t\t\tif (!verified)\n\t\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\t\tmessage: \"Authentication failed\",\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\tawait ctx.context.adapter.update<Passkey>({\n\t\t\t\t\t\t\tmodel: \"passkey\",\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\tvalue: passkey.id,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tcounter: verification.authenticationInfo.newCounter,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst s = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\t\tpasskey.userId,\n\t\t\t\t\t\t\tctx.request,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (!s) {\n\t\t\t\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\t\t\t\tmessage: \"Unable to create session\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait setSessionCookie(ctx, s.id);\n\t\t\t\t\t\treturn ctx.json(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsession: s,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tctx.context.logger.error(e);\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Failed to verify authentication\",\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\tlistPasskeys: createAuthEndpoint(\n\t\t\t\t\"/passkey/list-user-passkeys\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst passkeys = await ctx.context.adapter.findMany<Passkey>({\n\t\t\t\t\t\tmodel: \"passkey\",\n\t\t\t\t\t\twhere: [{ field: \"userId\", value: ctx.context.session.user.id }],\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json(passkeys, {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tdeletePasskey: createAuthEndpoint(\n\t\t\t\t\"/passkey/delete-passkey\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tid: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tawait ctx.context.adapter.delete<Passkey>({\n\t\t\t\t\t\tmodel: \"passkey\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: ctx.body.id,\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\treturn ctx.json(null, {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\tschema: {\n\t\t\tpasskey: {\n\t\t\t\tfields: {\n\t\t\t\t\tname: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t\tpublicKey: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\tuserId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\twebauthnUserID: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\tcounter: {\n\t\t\t\t\t\ttype: \"number\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\tdeviceType: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\tbackedUp: {\n\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t},\n\t\t\t\t\ttransports: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\ttype: \"date\",\n\t\t\t\t\t\tdefaultValue: new Date(),\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n\nexport * from \"./client\";\n","import type { BetterFetch, BetterFetchOption } from \"@better-fetch/fetch\";\nimport {\n\tWebAuthnError,\n\tstartAuthentication,\n\tstartRegistration,\n} from \"@simplewebauthn/browser\";\nimport type {\n\tPublicKeyCredentialCreationOptionsJSON,\n\tPublicKeyCredentialRequestOptionsJSON,\n} from \"@simplewebauthn/types\";\nimport type { Session } from \"inspector\";\nimport type { User } from \"../../db/schema\";\nimport type { passkey as passkeyPl, Passkey } from \"../../plugins\";\nimport type { BetterAuthClientPlugin } from \"../../client/types\";\nimport { useAuthQuery } from \"../../client\";\nimport { atom } from \"nanostores\";\n\nexport const getPasskeyActions = (\n\t$fetch: BetterFetch,\n\t{\n\t\t_listPasskeys,\n\t}: {\n\t\t_listPasskeys: ReturnType<typeof atom<any>>;\n\t},\n) => {\n\tconst signInPasskey = async (\n\t\topts?: {\n\t\t\tautoFill?: boolean;\n\t\t\temail?: string;\n\t\t\tfetchOptions?: BetterFetchOption;\n\t\t},\n\t\toptions?: BetterFetchOption,\n\t) => {\n\t\tconst response = await $fetch<PublicKeyCredentialRequestOptionsJSON>(\n\t\t\t\"/passkey/generate-authenticate-options\",\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: {\n\t\t\t\t\temail: opts?.email,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\tif (!response.data) {\n\t\t\treturn response;\n\t\t}\n\t\ttry {\n\t\t\tconst res = await startAuthentication(\n\t\t\t\tresponse.data,\n\t\t\t\topts?.autoFill || false,\n\t\t\t);\n\t\t\tconst verified = await $fetch<{\n\t\t\t\tsession: Session;\n\t\t\t\tuser: User;\n\t\t\t}>(\"/passkey/verify-authentication\", {\n\t\t\t\tbody: {\n\t\t\t\t\tresponse: res,\n\t\t\t\t},\n\t\t\t\t...opts?.fetchOptions,\n\t\t\t\t...options,\n\t\t\t\tmethod: \"POST\",\n\t\t\t});\n\t\t\tif (!verified.data) {\n\t\t\t\treturn verified;\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.log(e);\n\t\t}\n\t};\n\n\tconst registerPasskey = async (\n\t\topts?: {\n\t\t\tfetchOptions?: BetterFetchOption;\n\t\t\t/**\n\t\t\t * The name of the passkey. This is used to\n\t\t\t * identify the passkey in the UI.\n\t\t\t */\n\t\t\tname?: string;\n\t\t},\n\t\tfetchOpts?: BetterFetchOption,\n\t) => {\n\t\tconst options = await $fetch<PublicKeyCredentialCreationOptionsJSON>(\n\t\t\t\"/passkey/generate-register-options\",\n\t\t\t{\n\t\t\t\tmethod: \"GET\",\n\t\t\t},\n\t\t);\n\t\tif (!options.data) {\n\t\t\treturn options;\n\t\t}\n\t\ttry {\n\t\t\tconst res = await startRegistration(options.data);\n\t\t\tconst verified = await $fetch<{\n\t\t\t\tpasskey: Passkey;\n\t\t\t}>(\"/passkey/verify-registration\", {\n\t\t\t\t...opts?.fetchOptions,\n\t\t\t\t...fetchOpts,\n\t\t\t\tbody: {\n\t\t\t\t\tresponse: res,\n\t\t\t\t\tname: opts?.name,\n\t\t\t\t},\n\t\t\t\tmethod: \"POST\",\n\t\t\t});\n\t\t\tif (!verified.data) {\n\t\t\t\treturn verified;\n\t\t\t}\n\t\t\t_listPasskeys.set(Math.random());\n\t\t} catch (e) {\n\t\t\tif (e instanceof WebAuthnError) {\n\t\t\t\tif (e.code === \"ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdata: null,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: \"previously registered\",\n\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t\tstatusText: \"BAD_REQUEST\",\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (e.code === \"ERROR_CEREMONY_ABORTED\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdata: null,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: \"registration cancelled\",\n\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t\tstatusText: \"BAD_REQUEST\",\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tdata: null,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\tstatusText: \"BAD_REQUEST\",\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tdata: null,\n\t\t\t\terror: {\n\t\t\t\t\tmessage: e instanceof Error ? e.message : \"unknown error\",\n\t\t\t\t\tstatus: 500,\n\t\t\t\t\tstatusText: \"INTERNAL_SERVER_ERROR\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t};\n\n\treturn {\n\t\tsignIn: {\n\t\t\t/**\n\t\t\t * Sign in with a registered passkey\n\t\t\t */\n\t\t\tpasskey: signInPasskey,\n\t\t},\n\t\tpasskey: {\n\t\t\t/**\n\t\t\t * Add a passkey to the user account\n\t\t\t */\n\t\t\taddPasskey: registerPasskey,\n\t\t},\n\t\t/**\n\t\t * Inferred Internal Types\n\t\t */\n\t\t$Infer: {} as {\n\t\t\tPasskey: Passkey;\n\t\t},\n\t};\n};\n\nexport const passkeyClient = () => {\n\tconst _listPasskeys = atom<any>();\n\treturn {\n\t\tid: \"passkey\",\n\t\t$InferServerPlugin: {} as ReturnType<typeof passkeyPl>,\n\t\tgetActions: ($fetch) =>\n\t\t\tgetPasskeyActions($fetch, {\n\t\t\t\t_listPasskeys,\n\t\t\t}),\n\t\tgetAtoms($fetch) {\n\t\t\tconst listPasskeys = useAuthQuery<Passkey[]>(\n\t\t\t\t_listPasskeys,\n\t\t\t\t\"/passkey/list-user-passkeys\",\n\t\t\t\t$fetch,\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tcredentials: \"include\",\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tlistPasskeys,\n\t\t\t\t_listPasskeys,\n\t\t\t};\n\t\t},\n\t\tpathMethods: {\n\t\t\t\"/passkey/register\": \"POST\",\n\t\t\t\"/passkey/authenticate\": \"POST\",\n\t\t},\n\t\tatomListeners: [\n\t\t\t{\n\t\t\t\tmatcher(path) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tpath === \"/passkey/verify-registration\" ||\n\t\t\t\t\t\tpath === \"/passkey/delete-passkey\"\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tsignal: \"_listPasskeys\",\n\t\t\t},\n\t\t],\n\t} satisfies BetterAuthClientPlugin;\n};\n","import { createFetch } from \"@better-fetch/fetch\";\nimport { getBaseURL } from \"../utils/url\";\nimport { type Atom } from \"nanostores\";\nimport type { AtomListener, ClientOptions } from \"./types\";\nimport { addCurrentURL, csrfPlugin, redirectPlugin } from \"./fetch-plugins\";\n\nexport const getClientConfig = <O extends ClientOptions>(options?: O) => {\n\tconst $fetch = createFetch({\n\t\tbaseURL: getBaseURL(options?.fetchOptions?.baseURL || options?.baseURL),\n\t\tcredentials: \"include\",\n\t\tmethod: \"GET\",\n\t\t...options?.fetchOptions,\n\t\tplugins: options?.disableDefaultFetchPlugins\n\t\t\t? options.fetchOptions?.plugins\n\t\t\t: [\n\t\t\t\t\t...(!options?.disableCSRFTokenCheck ? [csrfPlugin] : []),\n\t\t\t\t\tredirectPlugin,\n\t\t\t\t\taddCurrentURL,\n\t\t\t\t\t...(options?.fetchOptions?.plugins?.filter(\n\t\t\t\t\t\t(pl) => pl !== undefined,\n\t\t\t\t\t) || []),\n\t\t\t\t\t...(options?.plugins\n\t\t\t\t\t\t?.flatMap((plugin) => plugin.fetchPlugins)\n\t\t\t\t\t\t.filter((pl) => pl !== undefined) || []),\n\t\t\t\t],\n\t});\n\n\tconst plugins = options?.plugins || [];\n\tlet pluginsActions = {} as Record<string, any>;\n\tlet pluginsAtoms = {} as Record<string, Atom<any>>;\n\tlet pluginPathMethods: Record<string, \"POST\" | \"GET\"> = {\n\t\t\"/sign-out\": \"POST\",\n\t\t\"/user/revoke-sessions\": \"POST\",\n\t};\n\tconst atomListeners: AtomListener[] = [\n\t\t{\n\t\t\tsignal: \"_sessionSignal\",\n\t\t\tmatcher(path) {\n\t\t\t\treturn (\n\t\t\t\t\tpath === \"/sign-out\" ||\n\t\t\t\t\tpath === \"/user/update\" ||\n\t\t\t\t\tpath.startsWith(\"/sign-in\") ||\n\t\t\t\t\tpath.startsWith(\"/sign-up\")\n\t\t\t\t);\n\t\t\t},\n\t\t},\n\t];\n\tfor (const plugin of plugins) {\n\t\tif (plugin.getActions) {\n\t\t\tObject.assign(pluginsActions, plugin.getActions?.($fetch));\n\t\t}\n\t\tif (plugin.getAtoms) {\n\t\t\tObject.assign(pluginsAtoms, plugin.getAtoms?.($fetch));\n\t\t}\n\t\tif (plugin.pathMethods) {\n\t\t\tObject.assign(pluginPathMethods, plugin.pathMethods);\n\t\t}\n\t\tif (plugin.atomListeners) {\n\t\t\tatomListeners.push(...plugin.atomListeners);\n\t\t}\n\t}\n\treturn {\n\t\tpluginsActions,\n\t\tpluginsAtoms,\n\t\tpluginPathMethods,\n\t\tatomListeners,\n\t\t$fetch,\n\t};\n};\n","import { env } from \"std-env\";\nimport { BetterAuthError } from \"../error\";\n\nfunction checkHasPath(url: string): boolean {\n\ttry {\n\t\tconst parsedUrl = new URL(url);\n\t\treturn parsedUrl.pathname !== \"/\";\n\t} catch (error) {\n\t\tthrow new BetterAuthError(\n\t\t\t`Invalid base URL: ${url}. Please provide a valid base URL.`,\n\t\t);\n\t}\n}\n\nfunction withPath(url: string, path = \"/api/auth\") {\n\tconst hasPath = checkHasPath(url);\n\tif (hasPath) {\n\t\treturn url;\n\t}\n\tpath = path.startsWith(\"/\") ? path : `/${path}`;\n\treturn `${url}${path}`;\n}\n\nexport function getBaseURL(url?: string, path?: string) {\n\tif (url) {\n\t\treturn withPath(url, path);\n\t}\n\tconst fromEnv =\n\t\tenv.BETTER_AUTH_URL ||\n\t\tenv.NEXT_PUBLIC_BETTER_AUTH_URL ||\n\t\tenv.PUBLIC_BETTER_AUTH_URL ||\n\t\tenv.NUXT_PUBLIC_BETTER_AUTH_URL ||\n\t\tenv.NUXT_PUBLIC_AUTH_URL ||\n\t\t(env.BASE_URL !== \"/\" ? env.BASE_URL : undefined);\n\n\tif (fromEnv) {\n\t\treturn withPath(fromEnv, path);\n\t}\n\n\tif (typeof window !== \"undefined\") {\n\t\treturn withPath(window.location.origin, path);\n\t}\n\treturn undefined;\n}\n\nexport function getOrigin(url: string) {\n\tconst parsedUrl = new URL(url);\n\treturn parsedUrl.origin.replace(\"http://\", \"\").replace(\"https://\", \"\");\n}\n","import { type BetterFetchPlugin, betterFetch } from \"@better-fetch/fetch\";\nimport { BetterAuthError } from \"../error\";\n\nexport const redirectPlugin = {\n\tid: \"redirect\",\n\tname: \"Redirect\",\n\thooks: {\n\t\tonSuccess(context) {\n\t\t\tif (context.data?.url && context.data?.redirect) {\n\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\twindow.location.href = context.data.url;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n} satisfies BetterFetchPlugin;\n\nexport const addCurrentURL = {\n\tid: \"add-current-url\",\n\tname: \"Add current URL\",\n\thooks: {\n\t\tonRequest(context) {\n\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\tconst url = new URL(context.url);\n\t\t\t\turl.searchParams.set(\"currentURL\", window.location.href);\n\t\t\t\tcontext.url = url;\n\t\t\t}\n\t\t\treturn context;\n\t\t},\n\t},\n} satisfies BetterFetchPlugin;\n\nexport const csrfPlugin = {\n\tid: \"csrf\",\n\tname: \"CSRF Check\",\n\tasync init(url, options) {\n\t\tif (options?.method !== \"GET\") {\n\t\t\toptions = options || {};\n\t\t\tconst { data, error } = await betterFetch<{\n\t\t\t\tcsrfToken: string;\n\t\t\t}>(\"/csrf\", {\n\t\t\t\tbody: undefined,\n\t\t\t\tbaseURL: options.baseURL,\n\t\t\t\tplugins: [],\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tcredentials: \"include\",\n\t\t\t\tcustomFetchImpl: options.customFetchImpl,\n\t\t\t});\n\t\t\tif (error) {\n\t\t\t\tif (error.status === 404) {\n\t\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\t\"CSRF route not found. Make sure the server is running and the base URL is correct and includes the path (e.g. http://localhost:3000/api/auth).\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (error.status === 429) {\n\t\t\t\t\treturn new Response(\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\tmessage: \"Too many requests. Please try again later.\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 429,\n\t\t\t\t\t\t\tstatusText: \"Too Many Requests\",\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\"Failed to fetch CSRF token: \" + error.message,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst csrfToken = data?.csrfToken;\n\t\t\toptions.body = {\n\t\t\t\t...options?.body,\n\t\t\t\tcsrfToken: csrfToken,\n\t\t\t};\n\t\t}\n\t\toptions.credentials = \"include\";\n\t\treturn { url, options };\n\t},\n} satisfies BetterFetchPlugin;\n","import type { BetterFetch } from \"@better-fetch/fetch\";\nimport { atom } from \"nanostores\";\nimport type { Prettify } from \"../types/helper\";\nimport type {\n\tClientOptions,\n\tInferSessionFromClient,\n\tInferUserFromClient,\n} from \"./types\";\nimport { useAuthQuery } from \"./query\";\n\nexport function getSessionAtom<Option extends ClientOptions>(\n\t$fetch: BetterFetch,\n) {\n\ttype UserWithAdditionalFields = InferUserFromClient<Option>;\n\ttype SessionWithAdditionalFields = InferSessionFromClient<Option>;\n\tconst $signal = atom<boolean>(false);\n\tconst session = useAuthQuery<{\n\t\tuser: Prettify<UserWithAdditionalFields>;\n\t\tsession: Prettify<SessionWithAdditionalFields>;\n\t}>($signal, \"/session\", $fetch, {\n\t\tmethod: \"GET\",\n\t});\n\treturn {\n\t\t$session: session,\n\t\t_sessionSignal: $signal,\n\t\t$Infer: {} as {\n\t\t\tSession: {\n\t\t\t\tsession: SessionWithAdditionalFields;\n\t\t\t\tuser: UserWithAdditionalFields;\n\t\t\t};\n\t\t},\n\t};\n}\n","import {\n\tBetterFetchError,\n\ttype BetterFetch,\n\ttype BetterFetchOption,\n} from \"@better-fetch/fetch\";\nimport { atom, onMount, type PreinitializedWritableAtom } from \"nanostores\";\n\nexport const useAuthQuery = <T>(\n\tinitializedAtom:\n\t\t| PreinitializedWritableAtom<any>\n\t\t| PreinitializedWritableAtom<any>[],\n\tpath: string,\n\t$fetch: BetterFetch,\n\toptions?:\n\t\t| ((value: {\n\t\t\t\tdata: null | T;\n\t\t\t\terror: null | BetterFetchError;\n\t\t\t\tisPending: boolean;\n\t\t }) => BetterFetchOption)\n\t\t| BetterFetchOption,\n) => {\n\tconst value = atom<{\n\t\tdata: null | T;\n\t\terror: null | BetterFetchError;\n\t\tisPending: boolean;\n\t\tisRefetching: boolean;\n\t}>({\n\t\tdata: null,\n\t\terror: null,\n\t\tisPending: false,\n\t\tisRefetching: false,\n\t});\n\n\tconst fn = () => {\n\t\tconst opts =\n\t\t\ttypeof options === \"function\"\n\t\t\t\t? options({\n\t\t\t\t\t\tdata: value.get().data,\n\t\t\t\t\t\terror: value.get().error,\n\t\t\t\t\t\tisPending: value.get().isPending,\n\t\t\t\t\t})\n\t\t\t\t: options;\n\t\treturn $fetch<T>(path, {\n\t\t\t...opts,\n\t\t\tonSuccess: async (context) => {\n\t\t\t\tvalue.set({\n\t\t\t\t\tdata: context.data,\n\t\t\t\t\terror: null,\n\t\t\t\t\tisPending: false,\n\t\t\t\t\tisRefetching: false,\n\t\t\t\t});\n\t\t\t\tawait opts?.onSuccess?.(context);\n\t\t\t},\n\t\t\tasync onError(context) {\n\t\t\t\tvalue.set({\n\t\t\t\t\terror: context.error,\n\t\t\t\t\tdata: null,\n\t\t\t\t\tisPending: false,\n\t\t\t\t\tisRefetching: false,\n\t\t\t\t});\n\t\t\t\tawait opts?.onError?.(context);\n\t\t\t},\n\t\t\tasync onRequest(context) {\n\t\t\t\tconst currentValue = value.get();\n\t\t\t\tvalue.set({\n\t\t\t\t\tisPending: currentValue.data === null,\n\t\t\t\t\tdata: currentValue.data,\n\t\t\t\t\terror: null,\n\t\t\t\t\tisRefetching: true,\n\t\t\t\t});\n\t\t\t\tawait opts?.onRequest?.(context);\n\t\t\t},\n\t\t});\n\t};\n\n\tinitializedAtom = Array.isArray(initializedAtom)\n\t\t? initializedAtom\n\t\t: [initializedAtom];\n\tlet isMounted = false;\n\tfor (const initAtom of initializedAtom) {\n\t\tinitAtom.subscribe(() => {\n\t\t\tif (isMounted) {\n\t\t\t\tfn();\n\t\t\t} else {\n\t\t\t\tonMount(value, () => {\n\t\t\t\t\tfn();\n\t\t\t\t\tisMounted = true;\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tvalue.off();\n\t\t\t\t\t\tinitAtom.off();\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\treturn value;\n};\n","import { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../api/call\";\nimport type { BetterAuthPlugin } from \"../../types/plugins\";\nimport { APIError } from \"better-call\";\nimport type { Account, User } from \"../../db/schema\";\n\nexport const username = () => {\n\treturn {\n\t\tid: \"username\",\n\t\tendpoints: {\n\t\t\tsignInUsername: createAuthEndpoint(\n\t\t\t\t\"/sign-in/username\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tusername: z.string(),\n\t\t\t\t\t\tpassword: z.string(),\n\t\t\t\t\t\tdontRememberMe: z.boolean().optional(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst user = await ctx.context.adapter.findOne<User>({\n\t\t\t\t\t\tmodel: ctx.context.tables.user.tableName,\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"username\",\n\t\t\t\t\t\t\t\tvalue: ctx.body.username,\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\tif (!user) {\n\t\t\t\t\t\tawait ctx.context.password.hash(ctx.body.password);\n\t\t\t\t\t\tctx.context.logger.error(\"User not found\", { username });\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"Invalid username or password\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst account = await ctx.context.adapter.findOne<Account>({\n\t\t\t\t\t\tmodel: ctx.context.tables.account.tableName,\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield:\n\t\t\t\t\t\t\t\t\tctx.context.tables.account.fields.userId.fieldName ||\n\t\t\t\t\t\t\t\t\t\"userId\",\n\t\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield:\n\t\t\t\t\t\t\t\t\tctx.context.tables.account.fields.providerId.fieldName ||\n\t\t\t\t\t\t\t\t\t\"providerId\",\n\t\t\t\t\t\t\t\tvalue: \"credential\",\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\tif (!account) {\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"Invalid username or password\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst currentPassword = account?.password;\n\t\t\t\t\tif (!currentPassword) {\n\t\t\t\t\t\tctx.context.logger.error(\"Password not found\", { username });\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"Unexpected error\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst validPassword = await ctx.context.password.verify(\n\t\t\t\t\t\tcurrentPassword,\n\t\t\t\t\t\tctx.body.password,\n\t\t\t\t\t);\n\t\t\t\t\tif (!validPassword) {\n\t\t\t\t\t\tctx.context.logger.error(\"Invalid password\");\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"Invalid username or password\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\tuser.id,\n\t\t\t\t\t\tctx.request,\n\t\t\t\t\t);\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tmessage: \"Failed to create session\",\n\t\t\t\t\t\t\t\tstatus: 500,\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\tawait ctx.setSignedCookie(\n\t\t\t\t\t\tctx.context.authCookies.sessionToken.name,\n\t\t\t\t\t\tsession.id,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\tctx.body.dontRememberMe\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t...ctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t\t\t\t\tmaxAge: undefined,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: ctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tuser: user,\n\t\t\t\t\t\tsession,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\tschema: {\n\t\t\tuser: {\n\t\t\t\tfields: {\n\t\t\t\t\tusername: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t\treturned: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n","import { serializeSigned } from \"better-call\";\nimport type { BetterAuthPlugin } from \"../../types/plugins\";\n\n/**\n * Converts bearer token to session cookie\n */\nexport const bearer = () => {\n\treturn {\n\t\tid: \"bearer\",\n\t\thooks: {\n\t\t\tbefore: [\n\t\t\t\t{\n\t\t\t\t\tmatcher(context) {\n\t\t\t\t\t\treturn Boolean(\n\t\t\t\t\t\t\tcontext.request?.headers.get(\"authorization\") ||\n\t\t\t\t\t\t\t\tcontext.headers?.get(\"authorization\"),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\thandler: async (c) => {\n\t\t\t\t\t\tconst token =\n\t\t\t\t\t\t\tc.request?.headers.get(\"authorization\")?.replace(\"Bearer \", \"\") ||\n\t\t\t\t\t\t\tc.headers?.get(\"authorization\")?.replace(\"Bearer \", \"\");\n\t\t\t\t\t\tif (!token) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet signedToken = \"\";\n\n\t\t\t\t\t\tif (token.includes(\".\")) {\n\t\t\t\t\t\t\tsignedToken = token;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsignedToken = await serializeSigned(\"\", token, c.context.secret);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (c.request) {\n\t\t\t\t\t\t\tc.request.headers.set(\n\t\t\t\t\t\t\t\t\"cookie\",\n\t\t\t\t\t\t\t\t`${\n\t\t\t\t\t\t\t\t\tc.context.authCookies.sessionToken.name\n\t\t\t\t\t\t\t\t}=${signedToken.replace(\"=\", \"\")}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (c.headers) {\n\t\t\t\t\t\t\tc.headers.set(\n\t\t\t\t\t\t\t\t\"cookie\",\n\t\t\t\t\t\t\t\t`${\n\t\t\t\t\t\t\t\t\tc.context.authCookies.sessionToken.name\n\t\t\t\t\t\t\t\t}=${signedToken.replace(\"=\", \"\")}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontext: c,\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} satisfies BetterAuthPlugin;\n};\n","import { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../api/call\";\nimport type { BetterAuthPlugin } from \"../../types/plugins\";\nimport { APIError } from \"better-call\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { redirectURLMiddleware } from \"../../api/middlewares/redirect\";\nimport { alphabet, generateRandomString } from \"../../crypto\";\n\ninterface MagicLinkOptions {\n\t/**\n\t * Time in seconds until the magic link expires.\n\t * @default (60 * 5) // 5 minutes\n\t */\n\texpiresIn?: number;\n\t/**\n\t * Send magic link implementation.\n\t */\n\tsendMagicLink: (data: {\n\t\temail: string;\n\t\turl: string;\n\t\ttoken: string;\n\t}) => Promise<void> | void;\n\t/**\n\t * Disable sign up if user is not found.\n\t *\n\t * @default false\n\t */\n\tdisableSignUp?: boolean;\n\t/**\n\t * Rate limit configuration.\n\t *\n\t * @default {\n\t * window: 60,\n\t * max: 5,\n\t * }\n\t */\n\trateLimit?: {\n\t\twindow: number;\n\t\tmax: number;\n\t};\n}\n\nexport const magicLink = (options: MagicLinkOptions) => {\n\treturn {\n\t\tid: \"magic-link\",\n\t\tendpoints: {\n\t\t\tsignInMagicLink: createAuthEndpoint(\n\t\t\t\t\"/sign-in/magic-link\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\temail: z.string().email(),\n\t\t\t\t\t\tcallbackURL: z.string().optional(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [redirectURLMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst { email } = ctx.body;\n\t\t\t\t\tconst verificationToken = generateRandomString(\n\t\t\t\t\t\t32,\n\t\t\t\t\t\talphabet(\"a-z\", \"A-Z\"),\n\t\t\t\t\t);\n\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\tidentifier: verificationToken,\n\t\t\t\t\t\tvalue: email,\n\t\t\t\t\t\texpiresAt: new Date(\n\t\t\t\t\t\t\tDate.now() + (options.expiresIn || 60 * 5) * 1000,\n\t\t\t\t\t\t),\n\t\t\t\t\t});\n\t\t\t\t\tconst url = `${\n\t\t\t\t\t\tctx.context.baseURL\n\t\t\t\t\t}/magic-link/verify?token=${verificationToken}&callbackURL=${\n\t\t\t\t\t\tctx.body.callbackURL || \"/\"\n\t\t\t\t\t}`;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait options.sendMagicLink({\n\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttoken: verificationToken,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tctx.context.logger.error(\"Failed to send magic link\", e);\n\t\t\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\t\t\tmessage: \"Failed to send magic link\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tstatus: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tmagicLinkVerify: createAuthEndpoint(\n\t\t\t\t\"/magic-link/verify\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tquery: z.object({\n\t\t\t\t\t\ttoken: z.string(),\n\t\t\t\t\t\tcallbackURL: z.string().optional(),\n\t\t\t\t\t}),\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst { token, callbackURL } = ctx.query;\n\t\t\t\t\tconst toRedirectTo = callbackURL?.startsWith(\"http\")\n\t\t\t\t\t\t? callbackURL\n\t\t\t\t\t\t: callbackURL\n\t\t\t\t\t\t\t? `${ctx.context.options.baseURL}${callbackURL}`\n\t\t\t\t\t\t\t: ctx.context.options.baseURL;\n\t\t\t\t\tconst tokenValue =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findVerificationValue(token);\n\t\t\t\t\tif (!tokenValue) {\n\t\t\t\t\t\tthrow ctx.redirect(`${toRedirectTo}?error=INVALID_TOKEN`);\n\t\t\t\t\t}\n\t\t\t\t\tif (tokenValue.expiresAt < new Date()) {\n\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(\n\t\t\t\t\t\t\ttokenValue.id,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthrow ctx.redirect(`${toRedirectTo}?error=EXPIRED_TOKEN`);\n\t\t\t\t\t}\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(\n\t\t\t\t\t\ttokenValue.id,\n\t\t\t\t\t);\n\t\t\t\t\tconst email = tokenValue.value;\n\t\t\t\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email);\n\t\t\t\t\tlet userId: string = user?.user.id || \"\";\n\n\t\t\t\t\tif (!user) {\n\t\t\t\t\t\tif (!options.disableSignUp) {\n\t\t\t\t\t\t\tconst newUser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\t\t\t\temail: email,\n\t\t\t\t\t\t\t\temailVerified: true,\n\t\t\t\t\t\t\t\tname: email,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tuserId = newUser.id;\n\t\t\t\t\t\t\tif (!userId) {\n\t\t\t\t\t\t\t\tthrow ctx.redirect(`${toRedirectTo}?error=USER_NOT_CREATED`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow ctx.redirect(`${toRedirectTo}?error=USER_NOT_FOUND`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\tuserId,\n\t\t\t\t\t\tctx.headers,\n\t\t\t\t\t);\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\tthrow ctx.redirect(`${toRedirectTo}?error=SESSION_NOT_CREATED`);\n\t\t\t\t\t}\n\t\t\t\t\tawait setSessionCookie(ctx, session.id);\n\t\t\t\t\tif (!callbackURL) {\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\tstatus: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthrow ctx.redirect(callbackURL);\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\trateLimit: [\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tpath.startsWith(\"/sign-in/magic-link\") ||\n\t\t\t\t\t\tpath.startsWith(\"/magic-link/verify\")\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\twindow: options.rateLimit?.window || 60,\n\t\t\t\tmax: options.rateLimit?.max || 5,\n\t\t\t},\n\t\t],\n\t} satisfies BetterAuthPlugin;\n};\n","import { z } from \"zod\";\nimport { createAuthEndpoint } from \"../../api/call\";\nimport type { BetterAuthPlugin } from \"../../types/plugins\";\nimport { APIError } from \"better-call\";\nimport type { User } from \"../../db/schema\";\nimport { alphabet, generateRandomString } from \"../../crypto/random\";\nimport { getSessionFromCtx } from \"../../api\";\nimport { getDate } from \"../../utils/date\";\nimport { logger } from \"../../utils/logger\";\nimport { setSessionCookie } from \"../../cookies\";\n\nexport interface UserWithPhoneNumber extends User {\n\tphoneNumber: string;\n\tphoneNumberVerified: boolean;\n}\n\nfunction generateOTP(size: number) {\n\treturn generateRandomString(size, alphabet(\"0-9\"));\n}\n\nexport const phoneNumber = (options?: {\n\t/**\n\t * Length of the OTP code\n\t * @default 6\n\t */\n\totpLength?: number;\n\t/**\n\t * Send OTP code to the user\n\t *\n\t * @param phoneNumber\n\t * @param code\n\t * @returns\n\t */\n\tsendOTP: (phoneNumber: string, code: string) => Promise<void> | void;\n\t/**\n\t * custom function to verify the OTP code\n\t */\n\tverifyOTP?: (phoneNumber: string, code: string) => Promise<boolean> | boolean;\n\t/**\n\t * Expiry time of the OTP code in seconds\n\t * @default 300\n\t */\n\texpiresIn?: number;\n\t/**\n\t * Function to validate phone number\n\t *\n\t * by default any string is accepted\n\t */\n\tphoneNumberValidator?: (phoneNumber: string) => boolean;\n\t/**\n\t * Sign up user after phone number verification\n\t *\n\t * the user will be signed up with the temporary email\n\t * and the phone number will be updated after verification\n\t */\n\tsignUpOnVerification?: {\n\t\t/**\n\t\t * When a user signs up, a temporary email will be need to be created\n\t\t * to sign up the user. This function should return a temporary email\n\t\t * for the user given the phone number\n\t\t *\n\t\t * @param phoneNumber\n\t\t * @returns string (temporary email)\n\t\t */\n\t\tgetTempEmail: (phoneNumber: string) => string;\n\t\t/**\n\t\t * When a user signs up, a temporary name will be need to be created\n\t\t * to sign up the user. This function should return a temporary name\n\t\t * for the user given the phone number\n\t\t *\n\t\t * @param phoneNumber\n\t\t * @returns string (temporary name)\n\t\t *\n\t\t * @default phoneNumber - the phone number will be used as the name\n\t\t */\n\t\tgetTempName?: (phoneNumber: string) => string;\n\t};\n}) => {\n\tconst opts = {\n\t\tphoneNumber: \"phoneNumber\",\n\t\tphoneNumberVerified: \"phoneNumberVerified\",\n\t\tcode: \"code\",\n\t\tcreatedAt: \"createdAt\",\n\t\texpiresIn: options?.expiresIn || 300,\n\t\totpLength: options?.otpLength || 6,\n\t};\n\treturn {\n\t\tid: \"phone-number\",\n\t\tendpoints: {\n\t\t\tsendPhoneNumberOTP: createAuthEndpoint(\n\t\t\t\t\"/phone-number/send-otp\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tphoneNumber: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tif (!options?.sendOTP) {\n\t\t\t\t\t\tlogger.warn(\"sendOTP not implemented\");\n\t\t\t\t\t\tthrow new APIError(\"NOT_IMPLEMENTED\", {\n\t\t\t\t\t\t\tmessage: \"sendOTP not implemented\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst code = generateOTP(opts.otpLength);\n\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\tvalue: code,\n\t\t\t\t\t\tidentifier: ctx.body.phoneNumber,\n\t\t\t\t\t\texpiresAt: getDate(opts.expiresIn, \"sec\"),\n\t\t\t\t\t});\n\t\t\t\t\tawait options.sendOTP(ctx.body.phoneNumber, code);\n\t\t\t\t\treturn ctx.json(\n\t\t\t\t\t\t{ code },\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tmessage: \"Code sent\",\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\tverifyPhoneNumber: createAuthEndpoint(\n\t\t\t\t\"/phone-number/verify\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Phone number\n\t\t\t\t\t\t */\n\t\t\t\t\t\tphoneNumber: z.string(),\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * OTP code\n\t\t\t\t\t\t */\n\t\t\t\t\t\tcode: z.string(),\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Disable session creation after verification\n\t\t\t\t\t\t * @default false\n\t\t\t\t\t\t */\n\t\t\t\t\t\tdisableSession: z.boolean().optional(),\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * This checks if there is a session already\n\t\t\t\t\t\t * and updates the phone number with the provided\n\t\t\t\t\t\t * phone number\n\t\t\t\t\t\t */\n\t\t\t\t\t\tupdatePhoneNumber: z.boolean().optional(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst otp = await ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\t\tctx.body.phoneNumber,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (!otp || otp.expiresAt < new Date()) {\n\t\t\t\t\t\tif (otp && otp.expiresAt < new Date()) {\n\t\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(otp.id);\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: \"OTP expired\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"OTP not found\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (otp.value !== ctx.body.code) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Invalid OTP\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(otp.id);\n\n\t\t\t\t\tif (ctx.body.updatePhoneNumber) {\n\t\t\t\t\t\tconst session = await getSessionFromCtx(ctx);\n\t\t\t\t\t\tif (!session) {\n\t\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\t\tmessage: \"Session not found\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst user = await ctx.context.internalAdapter.updateUser(\n\t\t\t\t\t\t\tsession.user.id,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t[opts.phoneNumber]: ctx.body.phoneNumber,\n\t\t\t\t\t\t\t\t[opts.phoneNumberVerified]: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\tuser: user as UserWithPhoneNumber,\n\t\t\t\t\t\t\tsession: session.session,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tlet user = await ctx.context.adapter.findOne<User>({\n\t\t\t\t\t\tmodel: ctx.context.tables.user.tableName,\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: ctx.body.phoneNumber,\n\t\t\t\t\t\t\t\tfield: opts.phoneNumber,\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\tif (!user) {\n\t\t\t\t\t\tif (options?.signUpOnVerification) {\n\t\t\t\t\t\t\tuser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\t\t\t\temail: `temp-${ctx.body.phoneNumber}`,\n\t\t\t\t\t\t\t\tname: ctx.body.phoneNumber,\n\t\t\t\t\t\t\t\t[opts.phoneNumber]: ctx.body.phoneNumber,\n\t\t\t\t\t\t\t\t[opts.phoneNumberVerified]: true,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (!user) {\n\t\t\t\t\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\t\t\t\t\tmessage: \"Failed to create 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} else {\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: \"Phone number not found\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tuser = await ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\t[opts.phoneNumberVerified]: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!user) {\n\t\t\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\t\t\tmessage: \"Failed to update user\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!ctx.body.disableSession) {\n\t\t\t\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\t\tuser.id,\n\t\t\t\t\t\t\tctx.request,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (!session) {\n\t\t\t\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\t\t\t\tmessage: \"Failed to create session\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait setSessionCookie(ctx, session.id);\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tuser,\n\t\t\t\t\t\tsession: null,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\tschema: {\n\t\t\tuser: {\n\t\t\t\tfields: {\n\t\t\t\t\tphoneNumber: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t\treturned: true,\n\t\t\t\t\t},\n\t\t\t\t\tphoneNumberVerified: {\n\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\treturned: true,\n\t\t\t\t\t\tinput: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n","import { createAuthEndpoint, sessionMiddleware } from \"../../api\";\nimport type { BetterAuthPlugin } from \"../../types\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { z } from \"zod\";\nimport { generateId } from \"../../utils/id\";\nimport { getOrigin } from \"../../utils/url\";\n\nexport interface AnonymousOptions {\n\t/**\n\t * Configure the domain name of the temporary email\n\t * address for anonymous users in the database.\n\t * @default \"baseURL\"\n\t */\n\temailDomainName?: string;\n}\n\nexport const anonymous = (options?: AnonymousOptions) => {\n\treturn {\n\t\tid: \"anonymous\",\n\t\tendpoints: {\n\t\t\tsignInAnonymous: createAuthEndpoint(\n\t\t\t\t\"/sign-in/anonymous\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst { emailDomainName = getOrigin(ctx.context.baseURL) } =\n\t\t\t\t\t\toptions || {};\n\t\t\t\t\tconst id = generateId();\n\t\t\t\t\tconst email = `temp-${id}@${emailDomainName}`;\n\t\t\t\t\tconst newUser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\t\tid,\n\t\t\t\t\t\temail,\n\t\t\t\t\t\temailVerified: false,\n\t\t\t\t\t\tisAnonymous: true,\n\t\t\t\t\t\tname: \"Anonymous\",\n\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t});\n\t\t\t\t\tif (!newUser) {\n\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tmessage: \"Failed to create user\",\n\t\t\t\t\t\t\t\tstatus: 500,\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\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\tnewUser.id,\n\t\t\t\t\t\tctx.request,\n\t\t\t\t\t);\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tmessage: \"Could not create session\",\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\tawait setSessionCookie(ctx, session.id);\n\t\t\t\t\treturn ctx.json({ user: newUser, session });\n\t\t\t\t},\n\t\t\t),\n\t\t\tlinkAccount: createAuthEndpoint(\n\t\t\t\t\"/anonymous/link-account\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\temail: z.string().email().optional(),\n\t\t\t\t\t\tpassword: z.string().min(6),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst userId = ctx.context.session.user.id;\n\t\t\t\t\tconst { email, password } = ctx.body;\n\t\t\t\t\tlet updatedUser = null;\n\t\t\t\t\t// handling both the email - password and updating the user\n\t\t\t\t\tif (email && password) {\n\t\t\t\t\t\tupdatedUser = await ctx.context.internalAdapter.updateUser(userId, {\n\t\t\t\t\t\t\temail: email,\n\t\t\t\t\t\t\tisAnonymous: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (!updatedUser) {\n\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tmessage: \"Failed to update user\",\n\t\t\t\t\t\t\t\tstatus: 500,\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\tconst hash = await ctx.context.password.hash(password);\n\t\t\t\t\tconst updateUserAccount =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\t\t\t\tuserId: updatedUser.id,\n\t\t\t\t\t\t\tproviderId: \"credential\",\n\t\t\t\t\t\t\tpassword: hash,\n\t\t\t\t\t\t\taccountId: updatedUser.id,\n\t\t\t\t\t\t});\n\t\t\t\t\tif (!updateUserAccount) {\n\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tmessage: \"Failed to update account\",\n\t\t\t\t\t\t\t\tstatus: 500,\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\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\tupdatedUser.id,\n\t\t\t\t\t\tctx.request,\n\t\t\t\t\t);\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\treturn ctx.json(null, {\n\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tmessage: \"Could not create session\",\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\tawait setSessionCookie(ctx, session.id);\n\t\t\t\t\treturn ctx.json({ session, user: updatedUser });\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\tschema: {\n\t\t\tuser: {\n\t\t\t\tfields: {\n\t\t\t\t\tisAnonymous: {\n\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\tdefaultValue: true,\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n","import { z } from \"zod\";\nimport {\n\tAPIError,\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n\tgetSessionFromCtx,\n} from \"../../api\";\nimport type { BetterAuthPlugin, Session, User } from \"../../types\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { getDate } from \"../../utils/date\";\n\nexport interface UserWithRole extends User {\n\trole?: string;\n\tbanned?: boolean;\n\tbanReason?: string;\n\tbanExpires?: number;\n}\n\ninterface SessionWithImpersonatedBy extends Session {\n\timpersonatedBy?: string;\n}\n\nexport const adminMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx);\n\tif (!session?.session) {\n\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t}\n\tconst user = session.user as UserWithRole;\n\tif (user.role !== \"admin\") {\n\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\tmessage: \"Only admins can access this endpoint\",\n\t\t});\n\t}\n\treturn {\n\t\tsession: {\n\t\t\tuser: user,\n\t\t\tsession: session.session,\n\t\t},\n\t};\n});\n\ninterface AdminOptions {\n\t/**\n\t * The default role for a user created by the admin\n\t *\n\t * @default \"user\"\n\t */\n\tdefaultRole?: string | false;\n\t/**\n\t * A default ban reason\n\t *\n\t * By default, no reason is provided\n\t */\n\tdefaultBanReason?: string;\n\t/**\n\t * Number of seconds until the ban expires\n\t *\n\t * By default, the ban never expires\n\t */\n\tdefaultBanExpiresIn?: number;\n\t/**\n\t * Duration of the impersonation session in seconds\n\t *\n\t * By default, the impersonation session lasts 1 hour\n\t */\n\timpersonationSessionDuration?: number;\n}\n\nexport const admin = (options?: AdminOptions) => {\n\treturn {\n\t\tid: \"admin\",\n\t\tinit(ctx) {\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\tdatabaseHooks: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync before(user) {\n\t\t\t\t\t\t\t\t\tif (options?.defaultRole === false) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\trole: options?.defaultRole ?? \"user\",\n\t\t\t\t\t\t\t\t\t\t\t...user,\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\tsession: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync before(session) {\n\t\t\t\t\t\t\t\t\tconst user = (await ctx.internalAdapter.findUserById(\n\t\t\t\t\t\t\t\t\t\tsession.userId,\n\t\t\t\t\t\t\t\t\t)) as UserWithRole;\n\n\t\t\t\t\t\t\t\t\tif (user.banned) {\n\t\t\t\t\t\t\t\t\t\tif (user.banExpires && user.banExpires < Date.now()) {\n\t\t\t\t\t\t\t\t\t\t\tawait ctx.internalAdapter.updateUser(session.userId, {\n\t\t\t\t\t\t\t\t\t\t\t\tbanned: false,\n\t\t\t\t\t\t\t\t\t\t\t\tbanReason: null,\n\t\t\t\t\t\t\t\t\t\t\t\tbanExpires: null,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\treturn false;\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\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher(context) {\n\t\t\t\t\t\treturn context.path === \"/user/list-sessions\";\n\t\t\t\t\t},\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst returned = ctx.context.returned;\n\t\t\t\t\t\tif (returned) {\n\t\t\t\t\t\t\tconst json =\n\t\t\t\t\t\t\t\t(await returned.json()) as SessionWithImpersonatedBy[];\n\t\t\t\t\t\t\tconst newJson = json.filter((session) => {\n\t\t\t\t\t\t\t\treturn !session.impersonatedBy;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst response = new Response(JSON.stringify(newJson), {\n\t\t\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\t\t\tstatusText: \"OK\",\n\t\t\t\t\t\t\t\theaders: returned.headers,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\tresponse: response,\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\tendpoints: {\n\t\t\tsetRole: createAuthEndpoint(\n\t\t\t\t\"/admin/set-role\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tuserId: z.string(),\n\t\t\t\t\t\trole: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst updatedUser = await ctx.context.internalAdapter.updateUser(\n\t\t\t\t\t\tctx.body.userId,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trole: ctx.body.role,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tuser: updatedUser as UserWithRole,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tcreateUser: createAuthEndpoint(\n\t\t\t\t\"/admin/create-user\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\temail: z.string(),\n\t\t\t\t\t\tpassword: z.string(),\n\t\t\t\t\t\tname: z.string(),\n\t\t\t\t\t\trole: z.string(),\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * extra fields for user\n\t\t\t\t\t\t */\n\t\t\t\t\t\tdata: z.optional(z.record(z.any())),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst existUser = await ctx.context.internalAdapter.findUserByEmail(\n\t\t\t\t\t\tctx.body.email,\n\t\t\t\t\t);\n\t\t\t\t\tif (existUser) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"User already exists\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst user =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.createUser<UserWithRole>({\n\t\t\t\t\t\t\temail: ctx.body.email,\n\t\t\t\t\t\t\tname: ctx.body.name,\n\t\t\t\t\t\t\trole: ctx.body.role,\n\t\t\t\t\t\t\t...ctx.body.data,\n\t\t\t\t\t\t});\n\n\t\t\t\t\tif (!user) {\n\t\t\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\t\t\tmessage: \"Failed to create user\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst hashedPassword = await ctx.context.password.hash(\n\t\t\t\t\t\tctx.body.password,\n\t\t\t\t\t);\n\t\t\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\t\t\taccountId: user.id,\n\t\t\t\t\t\tproviderId: \"credential\",\n\t\t\t\t\t\tpassword: hashedPassword,\n\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tuser: user as UserWithRole,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tlistUsers: createAuthEndpoint(\n\t\t\t\t\"/admin/list-users\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t\tquery: z.object({\n\t\t\t\t\t\tsearch: z\n\t\t\t\t\t\t\t.object({\n\t\t\t\t\t\t\t\tfield: z.enum([\"email\", \"name\"]),\n\t\t\t\t\t\t\t\toperator: z\n\t\t\t\t\t\t\t\t\t.enum([\"contains\", \"starts_with\", \"ends_with\"])\n\t\t\t\t\t\t\t\t\t.default(\"contains\"),\n\t\t\t\t\t\t\t\tvalue: z.string(),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.optional(),\n\t\t\t\t\t\tlimit: z.string().or(z.number()).optional(),\n\t\t\t\t\t\toffset: z.string().or(z.number()).optional(),\n\t\t\t\t\t\tsortBy: z.string().optional(),\n\t\t\t\t\t\tsortDirection: z.enum([\"asc\", \"desc\"]).optional(),\n\t\t\t\t\t\tfilter: z\n\t\t\t\t\t\t\t.array(\n\t\t\t\t\t\t\t\tz.object({\n\t\t\t\t\t\t\t\t\tfield: z.string(),\n\t\t\t\t\t\t\t\t\tvalue: z.string().or(z.number()).or(z.boolean()),\n\t\t\t\t\t\t\t\t\toperator: z.enum([\"eq\", \"ne\", \"lt\", \"lte\", \"gt\", \"gte\"]),\n\t\t\t\t\t\t\t\t\tconnector: z.enum([\"AND\", \"OR\"]).optional(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.optional(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst where = [];\n\n\t\t\t\t\tif (ctx.query?.search) {\n\t\t\t\t\t\twhere.push({\n\t\t\t\t\t\t\tfield: ctx.query.search.field,\n\t\t\t\t\t\t\toperator: ctx.query.search.operator,\n\t\t\t\t\t\t\tvalue: ctx.query.search.value,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tif (ctx.query?.filter) {\n\t\t\t\t\t\twhere.push(...(ctx.query.filter || []));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst users = await ctx.context.internalAdapter.listUsers(\n\t\t\t\t\t\tNumber(ctx.query?.limit) || undefined,\n\t\t\t\t\t\tNumber(ctx.query?.offset) || undefined,\n\t\t\t\t\t\tctx.query?.sortBy\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tfield: ctx.query.sortBy,\n\t\t\t\t\t\t\t\t\tdirection: ctx.query.sortDirection || \"asc\",\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined,\n\n\t\t\t\t\t\twhere.length ? where : undefined,\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tusers: users as UserWithRole[],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tlistUserSessions: createAuthEndpoint(\n\t\t\t\t\"/admin/list-user-sessions\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tuserId: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst sessions = await ctx.context.internalAdapter.listSessions(\n\t\t\t\t\t\tctx.body.userId,\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsessions: sessions,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t),\n\t\t\tunbanUser: createAuthEndpoint(\n\t\t\t\t\"/admin/unban-user\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tuserId: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst user = await ctx.context.internalAdapter.updateUser(\n\t\t\t\t\t\tctx.body.userId,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbanned: false,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tuser: user,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tbanUser: createAuthEndpoint(\n\t\t\t\t\"/admin/ban-user\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tuserId: z.string(),\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Reason for the ban\n\t\t\t\t\t\t */\n\t\t\t\t\t\tbanReason: z.string().optional(),\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Number of seconds until the ban expires\n\t\t\t\t\t\t */\n\t\t\t\t\t\tbanExpiresIn: z.number().optional(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tif (ctx.body.userId === ctx.context.session.user.id) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"You cannot ban yourself\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst user = await ctx.context.internalAdapter.updateUser(\n\t\t\t\t\t\tctx.body.userId,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbanned: true,\n\t\t\t\t\t\t\tbanReason:\n\t\t\t\t\t\t\t\tctx.body.banReason || options?.defaultBanReason || \"No reason\",\n\t\t\t\t\t\t\tbanExpires: ctx.body.banExpiresIn\n\t\t\t\t\t\t\t\t? Date.now() + ctx.body.banExpiresIn * 1000\n\t\t\t\t\t\t\t\t: options?.defaultBanExpiresIn\n\t\t\t\t\t\t\t\t\t? Date.now() + options.defaultBanExpiresIn * 1000\n\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\t//revoke all sessions\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteSessions(ctx.body.userId);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tuser: user,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\timpersonateUser: createAuthEndpoint(\n\t\t\t\t\"/admin/impersonate-user\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tuserId: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst targetUser = await ctx.context.internalAdapter.findUserById(\n\t\t\t\t\t\tctx.body.userId,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (!targetUser) {\n\t\t\t\t\t\tthrow new APIError(\"NOT_FOUND\", {\n\t\t\t\t\t\t\tmessage: \"User not found\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\ttargetUser.id,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\timpersonatedBy: ctx.context.session.user.id,\n\t\t\t\t\t\t\texpiresAt: options?.impersonationSessionDuration\n\t\t\t\t\t\t\t\t? getDate(options.impersonationSessionDuration, \"sec\")\n\t\t\t\t\t\t\t\t: getDate(60 * 60, \"sec\"), // 1 hour\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\t\t\tmessage: \"Failed to create session\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tawait setSessionCookie(ctx, session.id, true);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: session,\n\t\t\t\t\t\tuser: targetUser,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\trevokeUserSession: createAuthEndpoint(\n\t\t\t\t\"/admin/revoke-user-session\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tsessionId: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteSession(ctx.body.sessionId);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\trevokeUserSessions: createAuthEndpoint(\n\t\t\t\t\"/admin/revoke-user-sessions\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tuserId: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteSessions(ctx.body.userId);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\tremoveUser: createAuthEndpoint(\n\t\t\t\t\"/admin/remove-user\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tuserId: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [adminMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteUser(ctx.body.userId);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\tschema: {\n\t\t\tuser: {\n\t\t\t\tfields: {\n\t\t\t\t\trole: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\tinput: false,\n\t\t\t\t\t},\n\t\t\t\t\tbanned: {\n\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\tdefaultValue: false,\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\tinput: false,\n\t\t\t\t\t},\n\t\t\t\t\tbanReason: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\tinput: false,\n\t\t\t\t\t},\n\t\t\t\t\tbanExpires: {\n\t\t\t\t\t\ttype: \"number\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\tinput: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tsession: {\n\t\t\t\tfields: {\n\t\t\t\t\timpersonatedBy: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n","import { z } from \"zod\";\nimport { APIError } from \"better-call\";\nimport type { BetterAuthPlugin, User } from \"../../types\";\nimport { createAuthEndpoint } from \"../../api\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport { generateState, parseState } from \"../../oauth2/state\";\nimport { generateCodeVerifier } from \"oslo/oauth2\";\nimport { logger } from \"../../utils/logger\";\n\nimport { parseJWT } from \"oslo/jwt\";\nimport { userSchema } from \"../../db/schema\";\nimport { generateId } from \"../../utils/id\";\nimport { getAccountTokens } from \"../../oauth2/get-account\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { redirectURLMiddleware } from \"../../api/middlewares/redirect\";\nimport {\n\tcreateAuthorizationURL,\n\tvalidateAuthorizationCode,\n\ttype OAuth2Tokens,\n} from \"../../oauth2\";\nimport { compareHash } from \"../../crypto/hash\";\n\n/**\n * Configuration interface for generic OAuth providers.\n */\ninterface GenericOAuthConfig {\n\t/** Unique identifier for the OAuth provider */\n\tproviderId: string;\n\t/**\n\t * URL to fetch OAuth 2.0 configuration.\n\t * If provided, the authorization and token endpoints will be fetched from this URL.\n\t */\n\tdiscoveryUrl?: string;\n\t/**\n\t * Type of OAuth flow.\n\t * @default \"oauth2\"\n\t */\n\ttype?: \"oauth2\" | \"oidc\";\n\t/**\n\t * URL for the authorization endpoint.\n\t * Optional if using discoveryUrl.\n\t */\n\tauthorizationUrl?: string;\n\t/**\n\t * URL for the token endpoint.\n\t * Optional if using discoveryUrl.\n\t */\n\ttokenUrl?: string;\n\t/**\n\t * URL for the user info endpoint.\n\t * Optional if using discoveryUrl.\n\t */\n\tuserInfoUrl?: string;\n\t/** OAuth client ID */\n\tclientId: string;\n\t/** OAuth client secret */\n\tclientSecret: string;\n\t/**\n\t * Array of OAuth scopes to request.\n\t * @default []\n\t */\n\tscopes?: string[];\n\t/**\n\t * Custom redirect URI.\n\t * If not provided, a default URI will be constructed.\n\t */\n\tredirectURI?: string;\n\t/**\n\t * OAuth response type.\n\t * @default \"code\"\n\t */\n\tresponseType?: string;\n\t/**\n\t * Prompt parameter for the authorization request.\n\t * Controls the authentication experience for the user.\n\t */\n\tprompt?: string;\n\t/**\n\t * Whether to use PKCE (Proof Key for Code Exchange)\n\t * @default false\n\t */\n\tpkce?: boolean;\n\t/**\n\t * Access type for the authorization request.\n\t * Use \"offline\" to request a refresh token.\n\t */\n\taccessType?: string;\n\t/**\n\t * Custom function to fetch user info.\n\t * If provided, this function will be used instead of the default user info fetching logic.\n\t * @param tokens - The OAuth tokens received after successful authentication\n\t * @returns A promise that resolves to a User object or null\n\t */\n\tgetUserInfo?: (tokens: OAuth2Tokens) => Promise<User | null>;\n}\n\ninterface GenericOAuthOptions {\n\t/**\n\t * Array of OAuth provider configurations.\n\t */\n\tconfig: GenericOAuthConfig[];\n}\n\nasync function getUserInfo(\n\ttokens: OAuth2Tokens,\n\ttype: \"oauth2\" | \"oidc\",\n\tfinalUserInfoUrl: string | undefined,\n) {\n\tif (type === \"oidc\" && tokens.idToken) {\n\t\tconst decoded = parseJWT(tokens.idToken);\n\t\tif (decoded?.payload) {\n\t\t\treturn decoded.payload;\n\t\t}\n\t}\n\n\tif (!finalUserInfoUrl) {\n\t\treturn null;\n\t}\n\n\tconst userInfo = await betterFetch<User>(finalUserInfoUrl, {\n\t\tmethod: \"GET\",\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${tokens.accessToken}`,\n\t\t},\n\t});\n\treturn userInfo.data;\n}\n\n/**\n * A generic OAuth plugin that can be used to add OAuth support to any provider\n */\nexport const genericOAuth = (options: GenericOAuthOptions) => {\n\treturn {\n\t\tid: \"generic-oauth\",\n\t\tendpoints: {\n\t\t\tsignInWithOAuth2: createAuthEndpoint(\n\t\t\t\t\"/sign-in/oauth2\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tquery: z\n\t\t\t\t\t\t.object({\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * Redirect to the current URL after the\n\t\t\t\t\t\t\t * user has signed in.\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tcurrentURL: z.string().optional(),\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.optional(),\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tproviderId: z.string(),\n\t\t\t\t\t\tcallbackURL: z.string().optional(),\n\t\t\t\t\t}),\n\t\t\t\t\tuse: [redirectURLMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst { providerId } = ctx.body;\n\t\t\t\t\tconst config = options.config.find(\n\t\t\t\t\t\t(c) => c.providerId === providerId,\n\t\t\t\t\t);\n\t\t\t\t\tif (!config) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: `No config found for provider ${providerId}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst {\n\t\t\t\t\t\tdiscoveryUrl,\n\t\t\t\t\t\tauthorizationUrl,\n\t\t\t\t\t\ttokenUrl,\n\t\t\t\t\t\tclientId,\n\t\t\t\t\t\tclientSecret,\n\t\t\t\t\t\tscopes,\n\t\t\t\t\t\tredirectURI,\n\t\t\t\t\t\tresponseType,\n\t\t\t\t\t\tpkce,\n\t\t\t\t\t\tprompt,\n\t\t\t\t\t\taccessType,\n\t\t\t\t\t} = config;\n\t\t\t\t\tlet finalAuthUrl = authorizationUrl;\n\t\t\t\t\tlet finalTokenUrl = tokenUrl;\n\t\t\t\t\tif (discoveryUrl) {\n\t\t\t\t\t\tconst discovery = await betterFetch<{\n\t\t\t\t\t\t\tauthorization_endpoint: string;\n\t\t\t\t\t\t\ttoken_endpoint: string;\n\t\t\t\t\t\t}>(discoveryUrl, {\n\t\t\t\t\t\t\tonError(context) {\n\t\t\t\t\t\t\t\tlogger.error(context.error, {\n\t\t\t\t\t\t\t\t\tdiscoveryUrl,\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\tif (discovery.data) {\n\t\t\t\t\t\t\tfinalAuthUrl = discovery.data.authorization_endpoint;\n\t\t\t\t\t\t\tfinalTokenUrl = discovery.data.token_endpoint;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!finalAuthUrl || !finalTokenUrl) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Invalid OAuth configuration.\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst currentURL = ctx.query?.currentURL\n\t\t\t\t\t\t? new URL(ctx.query?.currentURL)\n\t\t\t\t\t\t: null;\n\t\t\t\t\tconst callbackURL = ctx.body.callbackURL?.startsWith(\"http\")\n\t\t\t\t\t\t? ctx.body.callbackURL\n\t\t\t\t\t\t: `${currentURL?.origin}${ctx.body.callbackURL || \"\"}`;\n\t\t\t\t\tconst state = await generateState(\n\t\t\t\t\t\tcallbackURL || currentURL?.origin || ctx.context.options.baseURL,\n\t\t\t\t\t);\n\t\t\t\t\tconst cookie = ctx.context.authCookies;\n\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\tcookie.state.name,\n\t\t\t\t\t\tstate.hash,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\tcookie.state.options,\n\t\t\t\t\t);\n\t\t\t\t\tconst codeVerifier = generateCodeVerifier();\n\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\tcookie.pkCodeVerifier.name,\n\t\t\t\t\t\tcodeVerifier,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\tcookie.pkCodeVerifier.options,\n\t\t\t\t\t);\n\t\t\t\t\tconst authUrl = await createAuthorizationURL({\n\t\t\t\t\t\tid: providerId,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId,\n\t\t\t\t\t\t\tclientSecret,\n\t\t\t\t\t\t\tredirectURI,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tauthorizationEndpoint: finalAuthUrl,\n\t\t\t\t\t\tstate: state.raw,\n\t\t\t\t\t\tcodeVerifier: codeVerifier,\n\t\t\t\t\t\tscopes: scopes || [],\n\t\t\t\t\t\tdisablePkce: !pkce,\n\t\t\t\t\t\tredirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerId}`,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (responseType && responseType !== \"code\") {\n\t\t\t\t\t\tauthUrl.searchParams.set(\"response_type\", responseType);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (prompt) {\n\t\t\t\t\t\tauthUrl.searchParams.set(\"prompt\", prompt);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (accessType) {\n\t\t\t\t\t\tauthUrl.searchParams.set(\"access_type\", accessType);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\turl: authUrl.toString(),\n\t\t\t\t\t\tstate: state,\n\t\t\t\t\t\tcodeVerifier,\n\t\t\t\t\t\tredirect: true,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t),\n\t\t\toAuth2Callback: createAuthEndpoint(\n\t\t\t\t\"/oauth2/callback/:providerId\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tquery: z.object({\n\t\t\t\t\t\tcode: z.string().optional(),\n\t\t\t\t\t\terror: z.string().optional(),\n\t\t\t\t\t\tstate: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tif (ctx.query.error || !ctx.query.code) {\n\t\t\t\t\t\tconst parsedState = parseState(ctx.query.state);\n\t\t\t\t\t\tconst callbackURL =\n\t\t\t\t\t\t\tparsedState.data?.currentURL || `${ctx.context.baseURL}/error`;\n\t\t\t\t\t\tctx.context.logger.error(ctx.query.error, ctx.params.providerId);\n\t\t\t\t\t\tthrow ctx.redirect(\n\t\t\t\t\t\t\t`${callbackURL}?error=${ctx.query.error || \"oAuth_code_missing\"}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst provider = options.config.find(\n\t\t\t\t\t\t(p) => p.providerId === ctx.params.providerId,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (!provider) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: `No config found for provider ${ctx.params.providerId}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst codeVerifier = await ctx.getSignedCookie(\n\t\t\t\t\t\tctx.context.authCookies.pkCodeVerifier.name,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t);\n\n\t\t\t\t\tlet tokens: OAuth2Tokens | undefined = undefined;\n\t\t\t\t\tconst parsedState = parseState(ctx.query.state);\n\t\t\t\t\tif (!parsedState.success) {\n\t\t\t\t\t\tthrow ctx.redirect(\n\t\t\t\t\t\t\t`${ctx.context.baseURL}/error?error=invalid_state`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst state = ctx.query.state;\n\t\t\t\t\tconst {\n\t\t\t\t\t\tdata: { callbackURL, currentURL },\n\t\t\t\t\t} = parsedState;\n\t\t\t\t\tconst code = ctx.query.code;\n\t\t\t\t\tconst errorURL =\n\t\t\t\t\t\tparsedState.data?.currentURL || `${ctx.context.baseURL}/error`;\n\t\t\t\t\tconst storedState = await ctx.getSignedCookie(\n\t\t\t\t\t\tctx.context.authCookies.state.name,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t);\n\t\t\t\t\tif (!storedState) {\n\t\t\t\t\t\tlogger.error(\"No stored state found\");\n\t\t\t\t\t\tthrow ctx.redirect(`${errorURL}?error=please_restart_the_process`);\n\t\t\t\t\t}\n\t\t\t\t\tconst isValidState = await compareHash(state, storedState);\n\t\t\t\t\tif (!isValidState) {\n\t\t\t\t\t\tlogger.error(\"OAuth code mismatch\");\n\t\t\t\t\t\tthrow ctx.redirect(`${errorURL}?error=please_restart_the_process`);\n\t\t\t\t\t}\n\t\t\t\t\tlet finalTokenUrl = provider.tokenUrl;\n\t\t\t\t\tlet finalUserInfoUrl = provider.userInfoUrl;\n\t\t\t\t\tif (provider.discoveryUrl) {\n\t\t\t\t\t\tconst discovery = await betterFetch<{\n\t\t\t\t\t\t\ttoken_endpoint: string;\n\t\t\t\t\t\t\tuserinfo_endpoint: string;\n\t\t\t\t\t\t}>(provider.discoveryUrl, {\n\t\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (discovery.data) {\n\t\t\t\t\t\t\tfinalTokenUrl = discovery.data.token_endpoint;\n\t\t\t\t\t\t\tfinalUserInfoUrl = discovery.data.userinfo_endpoint;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!finalTokenUrl) {\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: \"Invalid OAuth configuration.\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttokens = await validateAuthorizationCode({\n\t\t\t\t\t\t\tcode,\n\t\t\t\t\t\t\tcodeVerifier,\n\t\t\t\t\t\t\tredirectURI: `${ctx.context.baseURL}/oauth2/callback/${provider.providerId}`,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclientId: provider.clientId,\n\t\t\t\t\t\t\t\tclientSecret: provider.clientSecret,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttokenEndpoint: finalTokenUrl,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tctx.context.logger.error(e);\n\t\t\t\t\t\tthrow ctx.redirect(\n\t\t\t\t\t\t\t`${errorURL}?error=oauth_code_verification_failed`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!tokens) {\n\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: \"Invalid OAuth configuration.\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst userInfo = provider.getUserInfo\n\t\t\t\t\t\t? await provider.getUserInfo(tokens)\n\t\t\t\t\t\t: await getUserInfo(\n\t\t\t\t\t\t\t\ttokens,\n\t\t\t\t\t\t\t\tprovider.type || \"oauth2\",\n\t\t\t\t\t\t\t\tfinalUserInfoUrl,\n\t\t\t\t\t\t\t);\n\t\t\t\t\tconst id = generateId();\n\t\t\t\t\tconst user = userInfo\n\t\t\t\t\t\t? userSchema.safeParse({\n\t\t\t\t\t\t\t\t...userInfo,\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: null;\n\t\t\t\t\tif (!user?.success) {\n\t\t\t\t\t\tthrow ctx.redirect(`${errorURL}?error=oauth_user_info_invalid`);\n\t\t\t\t\t}\n\t\t\t\t\tconst dbUser = await ctx.context.internalAdapter\n\t\t\t\t\t\t.findUserByEmail(user.data.email)\n\t\t\t\t\t\t.catch((e) => {\n\t\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t\t\"Better auth was unable to query your database.\\nError: \",\n\t\t\t\t\t\t\t\te,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tthrow ctx.redirect(`${errorURL}?error=internal_server_error`);\n\t\t\t\t\t\t});\n\n\t\t\t\t\tconst userId = dbUser?.user.id || id;\n\n\t\t\t\t\tif (dbUser) {\n\t\t\t\t\t\t//check if user has already linked this provider\n\t\t\t\t\t\tconst hasBeenLinked = dbUser.accounts.find(\n\t\t\t\t\t\t\t(a) => a.providerId === provider.providerId,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst trustedProviders =\n\t\t\t\t\t\t\tctx.context.options.account?.accountLinking?.trustedProviders;\n\t\t\t\t\t\tconst isTrustedProvider = trustedProviders\n\t\t\t\t\t\t\t? trustedProviders.includes(provider.providerId as \"apple\")\n\t\t\t\t\t\t\t: true;\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!hasBeenLinked &&\n\t\t\t\t\t\t\t(!user?.data.emailVerified || !isTrustedProvider)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tlet url: URL;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\turl = new URL(errorURL);\n\t\t\t\t\t\t\t\turl.searchParams.set(\"error\", \"account_not_linked\");\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\tthrow ctx.redirect(`${errorURL}?error=account_not_linked`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow ctx.redirect(url.toString());\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!hasBeenLinked) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\t\t\t\t\t\tproviderId: provider.providerId,\n\t\t\t\t\t\t\t\t\taccountId: user.data.id,\n\t\t\t\t\t\t\t\t\tid: `${provider.providerId}:${user.data.id}`,\n\t\t\t\t\t\t\t\t\tuserId: dbUser.user.id,\n\t\t\t\t\t\t\t\t\t...getAccountTokens(tokens),\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\tconsole.log(e);\n\t\t\t\t\t\t\t\tthrow ctx.redirect(`${errorURL}?error=failed_linking_account`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait ctx.context.internalAdapter.createOAuthUser(user.data, {\n\t\t\t\t\t\t\t\t...getAccountTokens(tokens),\n\t\t\t\t\t\t\t\tid: `${provider.providerId}:${user.data.id}`,\n\t\t\t\t\t\t\t\tproviderId: provider.providerId,\n\t\t\t\t\t\t\t\taccountId: user.data.id,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tconst url = new URL(errorURL);\n\t\t\t\t\t\t\turl.searchParams.set(\"error\", \"unable_to_create_user\");\n\t\t\t\t\t\t\tctx.setHeader(\"Location\", url.toString());\n\t\t\t\t\t\t\tthrow ctx.redirect(url.toString());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\t\tuserId || id,\n\t\t\t\t\t\t\tctx.request,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (!session) {\n\t\t\t\t\t\t\tthrow ctx.redirect(`${errorURL}?error=unable_to_create_session`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait setSessionCookie(ctx, session.id);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthrow ctx.redirect(`${errorURL}?error=unable_to_create_session`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow ctx.redirect(callbackURL || currentURL || \"\");\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n","import type { PluginSchema } from \"../../types\";\nimport { z } from \"zod\";\n\nexport const schema: PluginSchema = {\n\tjwks: {\n\t\tfields: {\n\t\t\tpublicKey: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tprivateKey: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tcreatedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t},\n\t},\n};\n\nexport const jwk = z.object({\n\tid: z.string(),\n\tpublicKey: z.string(),\n\tprivateKey: z.string(),\n\tcreatedAt: z.date(),\n});\n\nexport type Jwk = z.infer<typeof jwk>;\n","import type { Adapter } from \"../../types\";\nimport type { Jwk } from \"./schema\";\n\nexport const getJwksAdapter = (adapter: Adapter) => {\n\treturn {\n\t\tgetAllKeys: async () => {\n\t\t\treturn await adapter.findMany<Jwk>({\n\t\t\t\tmodel: \"jwks\",\n\t\t\t});\n\t\t},\n\t\tgetLatestKey: async () => {\n\t\t\tconst key = await adapter.findMany<Jwk>({\n\t\t\t\tmodel: \"jwks\",\n\t\t\t\tsortBy: {\n\t\t\t\t\tfield: \"createdAt\",\n\t\t\t\t\tdirection: \"desc\",\n\t\t\t\t},\n\t\t\t\tlimit: 1,\n\t\t\t});\n\n\t\t\treturn key[0];\n\t\t},\n\t\tcreateJwk: async (webKey: Jwk) => {\n\t\t\tconst jwk = await adapter.create<Jwk>({\n\t\t\t\tmodel: \"jwks\",\n\t\t\t\tdata: {\n\t\t\t\t\t...webKey,\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn jwk;\n\t\t},\n\t};\n};\n","import type { BetterAuthPlugin, User } from \"../../types\";\nimport { type Jwk, schema } from \"./schema\";\nimport { getJwksAdapter } from \"./adapter\";\nimport { exportJWK, generateKeyPair, importJWK, SignJWT } from \"jose\";\nimport { decryptPrivateKey, encryptPrivateKey } from \"./utils\";\nimport { createAuthEndpoint, sessionMiddleware } from \"../../api\";\n\ntype JWKOptions =\n\t| {\n\t\t\talg: \"EdDSA\"; // EdDSA with either Ed25519 or Ed448 curve\n\t\t\tcrv?: \"Ed25519\" | \"Ed448\";\n\t }\n\t| {\n\t\t\talg: \"ES256\"; // ECDSA with P-256 curve\n\t\t\tcrv?: never; // Only one valid option, no need for crv\n\t }\n\t| {\n\t\t\talg: \"RS256\"; // RSA with SHA-256\n\t\t\tmodulusLength?: number; // Default to 2048 or higher\n\t }\n\t| {\n\t\t\talg: \"PS256\"; // RSA-PSS with SHA-256\n\t\t\tmodulusLength?: number; // Default to 2048 or higher\n\t }\n\t| {\n\t\t\talg: \"ECDH-ES\"; // Key agreement algorithm with P-256 as default curve\n\t\t\tcrv?: \"P-256\" | \"P-384\" | \"P-521\";\n\t }\n\t| {\n\t\t\talg: \"ES512\"; // ECDSA with P-521 curve\n\t\t\tcrv?: never; // Only P-521 for ES512\n\t };\n\nexport interface JwtOptions {\n\tjwks?: {\n\t\t/**\n\t\t * Key pair configuration\n\t\t * @description A subset of the options available for the generateKeyPair function\n\t\t *\n\t\t * @see https://github.com/panva/jose/blob/main/src/runtime/node/generate.ts\n\t\t *\n\t\t * @default { alg: 'EdDSA', crv: 'Ed25519' }\n\t\t */\n\t\tkeyPairConfig?: JWKOptions;\n\n\t\t/**\n\t\t * Disable private key encryption\n\t\t * @description Disable the encryption of the private key in the database\n\t\t *\n\t\t * @default false\n\t\t */\n\t\tdisablePrivateKeyEncryption?: boolean;\n\t};\n\n\tjwt?: {\n\t\tissuer?: string;\n\t\taudience?: string;\n\t\t/**\n\t\t * Set the \"exp\" (Expiration Time) Claim.\n\t\t *\n\t\t * - If a `number` is passed as an argument it is used as the claim directly.\n\t\t * - If a `Date` instance is passed as an argument it is converted to unix timestamp and used as the\n\t\t * claim.\n\t\t * - If a `string` is passed as an argument it is resolved to a time span, and then added to the\n\t\t * current unix timestamp and used as the claim.\n\t\t *\n\t\t * Format used for time span should be a number followed by a unit, such as \"5 minutes\" or \"1\n\t\t * day\".\n\t\t *\n\t\t * Valid units are: \"sec\", \"secs\", \"second\", \"seconds\", \"s\", \"minute\", \"minutes\", \"min\", \"mins\",\n\t\t * \"m\", \"hour\", \"hours\", \"hr\", \"hrs\", \"h\", \"day\", \"days\", \"d\", \"week\", \"weeks\", \"w\", \"year\",\n\t\t * \"years\", \"yr\", \"yrs\", and \"y\". It is not possible to specify months. 365.25 days is used as an\n\t\t * alias for a year.\n\t\t *\n\t\t * If the string is suffixed with \"ago\", or prefixed with a \"-\", the resulting time span gets\n\t\t * subtracted from the current unix timestamp. A \"from now\" suffix can also be used for\n\t\t * readability when adding to the current unix timestamp.\n\t\t *\n\t\t * @default 15m\n\t\t */\n\t\texpirationTime?: number | string | Date;\n\t\tdefinePayload?: (\n\t\t\tuser: User,\n\t\t) => Promise<Record<string, any>> | Record<string, any>;\n\t};\n}\n\nexport const jwt = (options?: JwtOptions) => {\n\treturn {\n\t\tid: \"jwt\",\n\t\tendpoints: {\n\t\t\tgetJwks: createAuthEndpoint(\n\t\t\t\t\"/jwks\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst adapter = getJwksAdapter(ctx.context.adapter);\n\n\t\t\t\t\tconst keySets = await adapter.getAllKeys();\n\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tkeys: keySets.map((keySet) => ({\n\t\t\t\t\t\t\t...JSON.parse(keySet.publicKey),\n\t\t\t\t\t\t\tkid: keySet.id,\n\t\t\t\t\t\t})),\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\n\t\t\tgetToken: createAuthEndpoint(\n\t\t\t\t\"/token\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst adapter = getJwksAdapter(ctx.context.adapter);\n\n\t\t\t\t\tlet key = await adapter.getLatestKey();\n\t\t\t\t\tconst privateKeyEncryptionEnabled =\n\t\t\t\t\t\t!options?.jwks?.disablePrivateKeyEncryption;\n\n\t\t\t\t\tif (key === undefined) {\n\t\t\t\t\t\tconst { publicKey, privateKey } = await generateKeyPair(\n\t\t\t\t\t\t\toptions?.jwks?.keyPairConfig?.alg ?? \"EdDSA\",\n\t\t\t\t\t\t\toptions?.jwks?.keyPairConfig ?? { crv: \"Ed25519\" },\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst publicWebKey = await exportJWK(publicKey);\n\t\t\t\t\t\tconst privateWebKey = await exportJWK(privateKey);\n\t\t\t\t\t\tconst stringifiedPrivateWebKey = JSON.stringify(privateWebKey);\n\n\t\t\t\t\t\tlet jwk: Partial<Jwk> = {\n\t\t\t\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\t\t\t\tpublicKey: JSON.stringify(publicWebKey),\n\t\t\t\t\t\t\tprivateKey: privateKeyEncryptionEnabled\n\t\t\t\t\t\t\t\t? JSON.stringify(\n\t\t\t\t\t\t\t\t\t\tencryptPrivateKey(\n\t\t\t\t\t\t\t\t\t\t\tstringifiedPrivateWebKey,\n\t\t\t\t\t\t\t\t\t\t\tctx.context.options.secret!,\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: stringifiedPrivateWebKey,\n\t\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tkey = await adapter.createJwk(jwk as Jwk);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet privateWebKey = privateKeyEncryptionEnabled\n\t\t\t\t\t\t? decryptPrivateKey(\n\t\t\t\t\t\t\t\tJSON.parse(key.privateKey),\n\t\t\t\t\t\t\t\tctx.context.options.secret!,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: key.privateKey;\n\n\t\t\t\t\tconst privateKey = await importJWK(JSON.parse(privateWebKey));\n\n\t\t\t\t\tconst payload = !options?.jwt?.definePayload\n\t\t\t\t\t\t? ctx.context.session.user\n\t\t\t\t\t\t: await options?.jwt.definePayload(ctx.context.session.user);\n\n\t\t\t\t\tconst jwt = await new SignJWT({\n\t\t\t\t\t\t...payload,\n\t\t\t\t\t\t// I am aware that this is not the best way to handle this, but this is the only way I know to get the impersonatedBy field\n\t\t\t\t\t\t...((ctx.context.session.session as any).impersonatedBy!\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\timpersonatedBy: (ctx.context.session.session as any)\n\t\t\t\t\t\t\t\t\t\t.impersonatedBy,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t})\n\t\t\t\t\t\t.setProtectedHeader({\n\t\t\t\t\t\t\talg: options?.jwks?.keyPairConfig?.alg ?? \"EdDSA\",\n\t\t\t\t\t\t\tkid: key.id,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.setIssuedAt()\n\t\t\t\t\t\t.setIssuer(options?.jwt?.issuer ?? ctx.context.options.baseURL!)\n\t\t\t\t\t\t.setAudience(options?.jwt?.audience ?? ctx.context.options.baseURL!)\n\t\t\t\t\t\t.setExpirationTime(options?.jwt?.expirationTime ?? \"15m\")\n\t\t\t\t\t\t.setSubject(ctx.context.session.user.id)\n\t\t\t\t\t\t.sign(privateKey);\n\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\ttoken: jwt,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\tschema,\n\t} satisfies BetterAuthPlugin;\n};\n","import {\n\tcreateCipheriv,\n\tcreateDecipheriv,\n\tcreateHash,\n\trandomBytes,\n} from \"crypto\";\n\n// Helper function to handle different key formats and lengths\nfunction deriveKey(secretKey: string) {\n\tlet keyBuffer: string | Buffer;\n\n\tif (Buffer.byteLength(secretKey, \"utf8\") === 32) {\n\t\tkeyBuffer = Buffer.from(secretKey, \"utf8\"); // Key is already 32 bytes\n\t} else {\n\t\tkeyBuffer = createHash(\"sha256\").update(secretKey).digest(); // Hash to ensure 32 bytes\n\t}\n\n\treturn keyBuffer;\n}\n\n// Encryption function using the provided secret as a key\nexport function encryptPrivateKey(privateKey: string, secretKey: string) {\n\tconst key = deriveKey(secretKey); // Derive a 32-byte key from the provided secret\n\n\tconst iv = randomBytes(12); // 12-byte IV for AES-GCM\n\tconst cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n\n\tlet ciphertext = cipher.update(privateKey, \"utf8\", \"base64\");\n\tciphertext += cipher.final(\"base64\");\n\n\tconst authTag = cipher.getAuthTag(); // Get the authentication tag\n\n\treturn {\n\t\tencryptedPrivateKey: ciphertext,\n\t\tiv: iv.toString(\"base64\"),\n\t\tauthTag: authTag.toString(\"base64\"),\n\t};\n}\n\n// Decryption function using the same secret\nexport function decryptPrivateKey(\n\tencryptedPrivate: {\n\t\tencryptedPrivateKey: string;\n\t\tiv: string;\n\t\tauthTag: string;\n\t},\n\tsecretKey: string,\n) {\n\tconst key = deriveKey(secretKey); // Derive a 32-byte key from the provided secret\n\n\tconst { encryptedPrivateKey, iv, authTag } = encryptedPrivate;\n\n\tconst ivBuffer = Buffer.from(iv, \"base64\");\n\tconst authTagBuffer = Buffer.from(authTag, \"base64\");\n\n\tconst decipher = createDecipheriv(\"aes-256-gcm\", key, ivBuffer);\n\tdecipher.setAuthTag(authTagBuffer);\n\n\tlet plaintext = decipher.update(encryptedPrivateKey, \"base64\", \"utf8\");\n\tplaintext += decipher.final(\"utf8\");\n\n\treturn plaintext;\n}\n","import { z } from \"zod\";\nimport {\n\tAPIError,\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n\tsessionMiddleware,\n} from \"../../api\";\nimport { parseCookies, parseSetCookieHeader } from \"../../cookies\";\nimport type { BetterAuthPlugin } from \"../../types\";\n\ninterface MultiSessionConfig {\n\t/**\n\t * The maximum number of sessions a user can have\n\t * at a time\n\t * @default 5\n\t */\n\tmaximumSessions?: number;\n}\n\nexport const multiSession = (options?: MultiSessionConfig) => {\n\tconst opts = {\n\t\tmaximumSessions: 5,\n\t\t...options,\n\t};\n\n\tconst isMultiSessionCookie = (key: string) => key.includes(\"_multi-\");\n\n\treturn {\n\t\tid: \"multi-session\",\n\t\tendpoints: {\n\t\t\tlistDeviceSessions: createAuthEndpoint(\n\t\t\t\t\"/multi-session/list-device-sessions\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst cookieHeader = ctx.headers?.get(\"cookie\");\n\t\t\t\t\tif (!cookieHeader) return ctx.json([]);\n\n\t\t\t\t\tconst cookies = Object.fromEntries(parseCookies(cookieHeader));\n\n\t\t\t\t\tconst sessionIds = (\n\t\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\t\tObject.entries(cookies)\n\t\t\t\t\t\t\t\t.filter(([key]) => isMultiSessionCookie(key))\n\t\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t\tasync ([key]) =>\n\t\t\t\t\t\t\t\t\t\tawait ctx.getSignedCookie(key, ctx.context.secret),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t).filter((v) => v !== undefined);\n\t\t\t\t\tif (!sessionIds.length) return ctx.json([]);\n\t\t\t\t\tconst sessions =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findSessions(sessionIds);\n\n\t\t\t\t\tconst validSessions = sessions\n\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t(session) => session && session.session.expiresAt > new Date(),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t(session, index, self) =>\n\t\t\t\t\t\t\t\tindex === self.findIndex((s) => s.user.id === session.user.id),\n\t\t\t\t\t\t);\n\n\t\t\t\t\tObject.entries(cookies)\n\t\t\t\t\t\t.filter(([key]) => isMultiSessionCookie(key))\n\t\t\t\t\t\t.forEach(([key, value]) => {\n\t\t\t\t\t\t\tif (!validSessions.some((s) => s.session.id === value)) {\n\t\t\t\t\t\t\t\tctx.setCookie(key, \"\", {\n\t\t\t\t\t\t\t\t\t...ctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t\t\t\t\tmaxAge: 0,\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\n\t\t\t\t\treturn ctx.json(validSessions);\n\t\t\t\t},\n\t\t\t),\n\t\t\tsetActiveSession: createAuthEndpoint(\n\t\t\t\t\"/multi-session/set-active\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tsessionId: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst sessionId = ctx.body.sessionId;\n\t\t\t\t\tconst multiSessionCookieName = `${ctx.context.authCookies.sessionToken.name}_multi-${sessionId}`;\n\t\t\t\t\tconst sessionCookie = await ctx.getSignedCookie(\n\t\t\t\t\t\tmultiSessionCookieName,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t);\n\t\t\t\t\tif (!sessionCookie) {\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"Invalid session id\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst session =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findSession(sessionId);\n\t\t\t\t\tif (!session || session.session.expiresAt < new Date()) {\n\t\t\t\t\t\tctx.setCookie(multiSessionCookieName, \"\", {\n\t\t\t\t\t\t\t...ctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"Invalid session id\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\tctx.context.authCookies.sessionToken.name,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\tctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json(session);\n\t\t\t\t},\n\t\t\t),\n\t\t\trevokeDeviceSession: createAuthEndpoint(\n\t\t\t\t\"/multi-session/revoke\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: z.object({\n\t\t\t\t\t\tsessionId: z.string(),\n\t\t\t\t\t}),\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tuse: [sessionMiddleware],\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst sessionId = ctx.body.sessionId;\n\t\t\t\t\tconst multiSessionCookieName = `${ctx.context.authCookies.sessionToken.name}_multi-${sessionId}`;\n\t\t\t\t\tconst sessionCookie = await ctx.getSignedCookie(\n\t\t\t\t\t\tmultiSessionCookieName,\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t);\n\t\t\t\t\tif (!sessionCookie) {\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\tmessage: \"Invalid session id\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst session =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findSession(sessionId);\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\tctx.setCookie(multiSessionCookieName, \"\", {\n\t\t\t\t\t\t\t...ctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteSession(sessionId);\n\t\t\t\t\tctx.setCookie(multiSessionCookieName, \"\", {\n\t\t\t\t\t\t...ctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher: () => true,\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!ctx.context.returned ||\n\t\t\t\t\t\t\t!(ctx.context.returned instanceof Response)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\tconst cookieString = ctx.context.returned.headers.get(\"set-cookie\");\n\t\t\t\t\t\tif (!cookieString) return;\n\n\t\t\t\t\t\tconst setCookies = parseSetCookieHeader(cookieString);\n\t\t\t\t\t\tconst sessionCookieConfig = ctx.context.authCookies.sessionToken;\n\t\t\t\t\t\tconst sessionToken = setCookies.get(\n\t\t\t\t\t\t\tsessionCookieConfig.name,\n\t\t\t\t\t\t)?.value;\n\t\t\t\t\t\tif (!sessionToken) return;\n\n\t\t\t\t\t\tconst cookies = parseCookies(ctx.headers?.get(\"cookie\") || \"\");\n\t\t\t\t\t\tconst rawSession = sessionToken.split(\".\")[0];\n\t\t\t\t\t\tconst cookieName = `${sessionCookieConfig.name}_multi-${rawSession}`;\n\n\t\t\t\t\t\tif (setCookies.get(cookieName) || cookies.get(cookieName)) return;\n\n\t\t\t\t\t\tconst currentMultiSessions =\n\t\t\t\t\t\t\tObject.keys(Object.fromEntries(cookies)).filter(\n\t\t\t\t\t\t\t\tisMultiSessionCookie,\n\t\t\t\t\t\t\t).length + (cookieString.includes(\"session_token\") ? 1 : 0);\n\n\t\t\t\t\t\tif (currentMultiSessions > opts.maximumSessions) {\n\t\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\t\tmessage: \"Maximum number of device sessions reached.\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\t\tcookieName,\n\t\t\t\t\t\t\trawSession,\n\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\tsessionCookieConfig.options,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst response = ctx.context.returned;\n\t\t\t\t\t\tresponse.headers.append(\n\t\t\t\t\t\t\t\"Set-Cookie\",\n\t\t\t\t\t\t\tctx.responseHeader.get(\"set-cookie\")!,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn { response };\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tmatcher: (context) => context.path === \"/sign-out\",\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst cookieHeader = ctx.headers?.get(\"cookie\");\n\t\t\t\t\t\tif (!cookieHeader) return;\n\n\t\t\t\t\t\tconst cookies = Object.fromEntries(parseCookies(cookieHeader));\n\n\t\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\t\tObject.entries(cookies).map(async ([key, value]) => {\n\t\t\t\t\t\t\t\tif (isMultiSessionCookie(key)) {\n\t\t\t\t\t\t\t\t\tctx.setCookie(key, \"\", { maxAge: 0 });\n\t\t\t\t\t\t\t\t\tconst id = key.split(\"_multi-\")[1];\n\t\t\t\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteSession(id);\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\n\t\t\t\t\t\tconst response = ctx.context.returned;\n\t\t\t\t\t\tresponse?.headers.append(\n\t\t\t\t\t\t\t\"Set-Cookie\",\n\t\t\t\t\t\t\tctx.responseHeader.get(\"set-cookie\")!,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn { response };\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":"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","names":["APIError","z","createEndpointCreator","createMiddleware","createMiddlewareCreator","optionsMiddleware","createAuthMiddleware","createAuthEndpoint","APIError","generateCodeVerifier","z","generateStateOAuth","z","sha256","constantTimeEqual","a","b","aBuffer","bBuffer","c","hashToBase64","data","buffer","sha256","compareHash","hash","hashBuffer","constantTimeEqual","generateState","callbackURL","code","generateStateOAuth","raw","hash","hashToBase64","parseState","state","z","TimeSpan","BetterAuthError","message","cause","env","isProduction","setSessionCookie","ctx","sessionToken","dontRememberMe","overrides","options","deleteSessionCookie","parseSetCookieHeader","header","cookieMap","cookie","nameValue","attributes","name","value","cookieObj","attr","attrName","attrValue","parseCookies","cookieHeader","cookies","APIError","createConsola","consola","createLogger","options","args","logger","redirectURLMiddleware","createAuthMiddleware","ctx","body","query","headers","context","callbackURL","currentURL","trustedOrigins","validateURL","url","label","origin","logger","APIError","parseJWT","sha256","base64url","generateCodeChallenge","codeVerifier","codeChallengeBytes","getOAuth2Tokens","data","createAuthorizationURL","id","options","authorizationEndpoint","state","codeVerifier","scopes","claims","disablePkce","redirectURI","url","codeChallenge","generateCodeChallenge","claimsObj","acc","claim","betterFetch","validateAuthorizationCode","code","codeVerifier","redirectURI","options","tokenEndpoint","body","data","error","betterFetch","getOAuth2Tokens","getAccountTokens","tokens","accessToken","refreshToken","accessTokenExpiresAt","apple","options","tokenEndpoint","state","scopes","redirectURI","_scope","code","codeVerifier","validateAuthorizationCode","token","data","parseJWT","betterFetch","discord","options","state","scopes","redirectURI","_scopes","code","validateAuthorizationCode","token","profile","error","betterFetch","defaultAvatarNumber","format","betterFetch","facebook","options","state","scopes","redirectURI","_scopes","createAuthorizationURL","code","validateAuthorizationCode","token","profile","error","betterFetch","betterFetch","github","options","tokenEndpoint","state","scopes","codeVerifier","redirectURI","_scopes","createAuthorizationURL","code","validateAuthorizationCode","token","profile","error","betterFetch","emailVerified","data","e","parseJWT","google","options","state","scopes","codeVerifier","redirectURI","logger","BetterAuthError","_scopes","createAuthorizationURL","code","validateAuthorizationCode","token","user","parseJWT","betterFetch","parseJWT","microsoft","options","tenant","authorizationEndpoint","tokenEndpoint","data","scopes","createAuthorizationURL","code","codeVerifier","redirectURI","validateAuthorizationCode","token","user","parseJWT","profilePhotoSize","betterFetch","context","pictureBuffer","pictureBase64","e","logger","betterFetch","spotify","options","state","scopes","codeVerifier","redirectURI","_scopes","createAuthorizationURL","code","validateAuthorizationCode","token","profile","error","betterFetch","HIDE_METADATA","nanoid","generateId","size","parseJWT","twitch","options","state","scopes","redirectURI","_scopes","createAuthorizationURL","code","validateAuthorizationCode","token","idToken","logger","profile","parseJWT","betterFetch","twitter","options","data","_scopes","createAuthorizationURL","code","codeVerifier","redirectURI","validateAuthorizationCode","token","profile","error","betterFetch","socialProviders","apple","discord","facebook","github","microsoft","google","spotify","twitch","twitter","socialProviderList","TimeSpan","createJWT","validateJWT","z","APIError","APIError","getDate","span","unit","z","getSession","createAuthEndpoint","ctx","sessionCookieToken","session","deleteSessionCookie","expiresIn","updateAge","updatedSession","getDate","maxAge","setSessionCookie","error","getSessionFromCtx","sessionMiddleware","createAuthMiddleware","APIError","revokeSession","createAuthEndpoint","z","sessionMiddleware","ctx","id","findSession","APIError","error","revokeSessions","createEmailVerificationToken","secret","email","updateTo","createJWT","TimeSpan","sendVerificationEmail","createAuthEndpoint","z","redirectURLMiddleware","ctx","APIError","user","token","url","verifyEmail","jwt","validateJWT","e","parsed","session","getSessionFromCtx","updatedUser","signInOAuth","createAuthEndpoint","z","socialProviderList","redirectURLMiddleware","c","provider","p","APIError","cookie","currentURL","callbackURL","state","generateState","codeVerifier","generateCodeVerifier","url","signInEmail","ctx","email","password","user","credentialAccount","a","currentPassword","logger","token","createEmailVerificationToken","session","setSessionCookie","z","z","accountSchema","userSchema","val","sessionSchema","verificationSchema","callbackOAuth","createAuthEndpoint","z","HIDE_METADATA","c","callbackURL","parseState","provider","p","parsedState","currentURL","storedState","logger","compareHash","codeVerifier","tokens","e","user","res","id","generateId","data","userSchema","redirectOnError","error","dbUser","userId","a","getAccountTokens","emailVerified","created","token","createEmailVerificationToken","url","session","setSessionCookie","APIError","signOut","createAuthEndpoint","ctx","sessionCookieToken","APIError","deleteSessionCookie","z","APIError","forgetPassword","createAuthEndpoint","z","redirectURLMiddleware","ctx","APIError","email","redirectTo","user","defaultExpiresIn","expiresAt","verificationToken","url","forgetPasswordCallback","token","callbackURL","verification","resetPassword","newPassword","id","userId","hashedPassword","ac","z","crypto","byteToBinary","byte","bytesToBinary","bytes","val","bytesToInteger","generateRandomInteger","max","bitLength","shift","bytes","crypto","result","bytesToInteger","generateRandomString","length","alphabet","i","patterns","patternSet","pattern","APIError","changePassword","createAuthEndpoint","z","sessionMiddleware","ctx","newPassword","currentPassword","revokeOtherSessions","session","minPasswordLength","APIError","maxPasswordLength","account","passwordHash","newSession","setSessionCookie","setPassword","deleteUser","password","sessionCookie","changeEmail","redirectURLMiddleware","updatedUser","token","createEmailVerificationToken","url","xchacha20poly1305","bytesToHex","hexToBytes","utf8ToBytes","managedNonce","sha256","crypto","decodeHex","encodeHex","scryptAsync","getRandomValues","hs256","secretKey","message","enc","algorithm","key","crypto","signature","symmetricEncrypt","data","keyAsBytes","sha256","dataAsBytes","utf8ToBytes","chacha","managedNonce","xchacha20poly1305","bytesToHex","symmetricDecrypt","hexToBytes","getCSRFToken","createAuthEndpoint","HIDE_METADATA","ctx","csrfCookie","token","_","generateRandomString","alphabet","hash","hs256","cookie","html","errorCode","error","createAuthEndpoint","HIDE_METADATA","c","query","ok","createAuthEndpoint","HIDE_METADATA","ctx","z","APIError","shimContext","originalObject","newContext","shimmedObj","key","value","ctx","access_exports","__export","AccessControl","ParsingError","Role","adminAc","createAccessControl","defaultAc","defaultRoles","defaultStatements","memberAc","ownerAc","permissionFromString","ParsingError","message","path","AccessControl","s","statements","Role","_Role","request","connector","requestedResource","requestedActions","allowedActions","success","requestedAction","resource","actions","createAccessControl","statements","AccessControl","defaultStatements","defaultAc","adminAc","ownerAc","memberAc","defaultRoles","permissionFromString","permission","Role","getOrgAdapter","context","options","adapter","slug","data","organization","member","generateId","user","memberId","role","orgId","sessionId","db","org","invitations","members","userIds","users","userMap","membersWithUsers","BetterAuthError","userId","organizationIds","invitation","expiresAt","getDate","id","invite","APIError","createRouter","statusCode","APIError","z","csrfMiddleware","createAuthMiddleware","z","ctx","originHeader","origin","csrfToken","APIError","csrfCookie","token","hash","expectedHash","hs256","isTest","APIError","orgMiddleware","createAuthMiddleware","ctx","orgSessionMiddleware","sessionMiddleware","z","z","role","invitationStatus","organizationSchema","v","memberSchema","invitationSchema","APIError","createInvitation","createAuthEndpoint","orgMiddleware","orgSessionMiddleware","z","role","ctx","logger","session","orgId","adapter","getOrgAdapter","member","invitation","organization","acceptInvitation","acceptedI","generateId","rejectInvitation","rejectedI","cancelInvitation","canceledI","getInvitation","getSessionFromCtx","z","APIError","removeMember","createAuthEndpoint","z","orgMiddleware","orgSessionMiddleware","ctx","session","orgId","adapter","getOrgAdapter","member","role","isLeaving","existing","updateMemberRole","updatedMember","z","APIError","createOrganization","createAuthEndpoint","z","orgMiddleware","orgSessionMiddleware","ctx","user","options","adapter","getOrgAdapter","userOrganizations","organization","generateId","updateOrganization","session","orgId","member","role","updatedOrg","deleteOrganization","getFullOrganization","setActiveOrganization","sessionOrgId","listOrganization","organizations","organization","options","endpoints","createOrganization","updateOrganization","deleteOrganization","setActiveOrganization","getFullOrganization","listOrganization","createInvitation","cancelInvitation","acceptInvitation","getInvitation","rejectInvitation","removeMember","updateMemberRole","roles","defaultRoles","shimContext","context","getSessionFromCtx","createAuthEndpoint","z","orgSessionMiddleware","ctx","APIError","member","getOrgAdapter","result","z","z","APIError","TWO_FACTOR_COOKIE_NAME","TRUST_DEVICE_COOKIE_NAME","z","verifyTwoFactorMiddleware","createAuthMiddleware","z","ctx","session","getSessionFromCtx","cookieName","TWO_FACTOR_COOKIE_NAME","cookie","APIError","userId","hash","sessions","activeSessions","hashToMatch","hs256","user","setSessionCookie","trustDeviceCookie","TRUST_DEVICE_COOKIE_NAME","token","APIError","generateBackupCodesFn","options","generateRandomString","alphabet","code","generateBackupCodes","secret","key","backupCodes","encCodes","symmetricEncrypt","verifyBackupCode","data","codes","getBackupCodes","symmetricDecrypt","result","z","backupCode2fa","twoFactorTable","createAuthEndpoint","verifyTwoFactorMiddleware","ctx","user","twoFactor","APIError","setSessionCookie","sessionMiddleware","APIError","TOTPController","z","TimeSpan","otp2fa","options","twoFactorTable","opts","totp","TOTPController","send2FaOTP","createAuthEndpoint","verifyTwoFactorMiddleware","ctx","APIError","user","twoFactor","code","verifyOTP","z","APIError","TimeSpan","TOTPController","createTOTPKeyURI","z","totp2fa","options","twoFactorTable","opts","TimeSpan","generateTOTP","createAuthEndpoint","sessionMiddleware","ctx","APIError","user","twoFactor","TOTPController","getTOTPURI","createTOTPKeyURI","verifyTOTP","z","verifyTwoFactorMiddleware","totp","decrypted","symmetricDecrypt","secret","validatePassword","ctx","data","credentialAccount","account","currentPassword","APIError","createTOTPKeyURI","TimeSpan","twoFactorClient","options","path","context","twoFactor","options","opts","totp","totp2fa","backupCode","backupCode2fa","otp","otp2fa","createAuthEndpoint","z","sessionMiddleware","ctx","user","password","validatePassword","APIError","secret","generateRandomString","alphabet","encryptedSecret","symmetricEncrypt","backupCodes","generateBackupCodes","totpURI","createTOTPKeyURI","TimeSpan","context","createAuthMiddleware","returned","response","trustDeviceCookieName","TRUST_DEVICE_COOKIE_NAME","trustDeviceCookie","token","sessionId","expectedToken","hs256","newToken","hash","cookieName","TWO_FACTOR_COOKIE_NAME","path","generateAuthenticationOptions","generateRegistrationOptions","verifyAuthenticationResponse","verifyRegistrationResponse","APIError","z","env","WebAuthnError","startAuthentication","startRegistration","createFetch","env","getOrigin","url","betterFetch","atom","atom","onMount","useAuthQuery","initializedAtom","path","$fetch","options","value","fn","opts","context","currentValue","isMounted","initAtom","atom","getPasskeyActions","$fetch","_listPasskeys","opts","options","response","res","startAuthentication","verified","e","fetchOpts","startRegistration","WebAuthnError","passkeyClient","useAuthQuery","path","passkey","options","baseURL","env","rpID","BetterAuthError","opts","expirationTime","currentTime","maxAgeInSeconds","createAuthEndpoint","sessionMiddleware","ctx","session","userPasskeys","userID","generateRandomString","alphabet","generateRegistrationOptions","id","generateId","z","getSessionFromCtx","generateAuthenticationOptions","data","origin","resp","challengeId","APIError","expectedChallenge","userData","verification","verifyRegistrationResponse","verified","registrationInfo","credentialID","credentialPublicKey","counter","credentialDeviceType","credentialBackedUp","pubKey","newPasskey","newPasskeyRes","e","verifyAuthenticationResponse","s","setSessionCookie","passkeys","z","APIError","username","createAuthEndpoint","z","ctx","user","account","currentPassword","session","serializeSigned","bearer","context","c","token","signedToken","z","APIError","magicLink","options","createAuthEndpoint","z","redirectURLMiddleware","ctx","email","verificationToken","generateRandomString","alphabet","url","e","APIError","token","callbackURL","toRedirectTo","tokenValue","user","userId","session","setSessionCookie","path","z","APIError","generateOTP","size","generateRandomString","alphabet","phoneNumber","options","opts","createAuthEndpoint","z","ctx","logger","APIError","code","getDate","otp","session","getSessionFromCtx","user","setSessionCookie","z","anonymous","options","createAuthEndpoint","ctx","emailDomainName","getOrigin","id","generateId","email","newUser","session","setSessionCookie","z","sessionMiddleware","userId","password","updatedUser","hash","z","adminMiddleware","createAuthMiddleware","ctx","session","getSessionFromCtx","APIError","user","admin","options","context","returned","newJson","response","createAuthEndpoint","z","updatedUser","hashedPassword","where","users","targetUser","getDate","setSessionCookie","z","APIError","betterFetch","generateCodeVerifier","parseJWT","getUserInfo","tokens","type","finalUserInfoUrl","decoded","parseJWT","betterFetch","genericOAuth","options","createAuthEndpoint","z","redirectURLMiddleware","ctx","providerId","config","c","APIError","discoveryUrl","authorizationUrl","tokenUrl","clientId","clientSecret","scopes","redirectURI","responseType","pkce","prompt","accessType","finalAuthUrl","finalTokenUrl","discovery","context","logger","currentURL","callbackURL","state","generateState","cookie","codeVerifier","generateCodeVerifier","authUrl","createAuthorizationURL","parseState","provider","p","parsedState","code","errorURL","storedState","compareHash","validateAuthorizationCode","e","userInfo","id","generateId","user","userSchema","dbUser","userId","hasBeenLinked","a","trustedProviders","isTrustedProvider","url","getAccountTokens","session","setSessionCookie","z","schema","jwk","getJwksAdapter","adapter","webKey","exportJWK","generateKeyPair","importJWK","SignJWT","createCipheriv","createDecipheriv","createHash","randomBytes","deriveKey","secretKey","keyBuffer","encryptPrivateKey","privateKey","key","iv","cipher","ciphertext","authTag","decryptPrivateKey","encryptedPrivate","encryptedPrivateKey","ivBuffer","authTagBuffer","decipher","plaintext","jwt","options","createAuthEndpoint","ctx","keySets","getJwksAdapter","keySet","sessionMiddleware","adapter","key","privateKeyEncryptionEnabled","publicKey","privateKey","generateKeyPair","publicWebKey","exportJWK","privateWebKey","stringifiedPrivateWebKey","jwk","encryptPrivateKey","decryptPrivateKey","importJWK","payload","SignJWT","schema","z","multiSession","options","opts","isMultiSessionCookie","key","createAuthEndpoint","ctx","cookieHeader","cookies","parseCookies","sessionIds","v","validSessions","session","index","self","s","value","z","sessionMiddleware","sessionId","multiSessionCookieName","APIError","createAuthMiddleware","cookieString","setCookies","parseSetCookieHeader","sessionCookieConfig","sessionToken","rawSession","cookieName","response","context","id"]}
|