diff --git a/dist/server/index.js b/dist/server/index.js index e4cdf99..a8d2c65 100644 --- a/dist/server/index.js +++ b/dist/server/index.js @@ -626,7 +626,17 @@ function registerAuthApiRoutes(options) { return res.status(200).json({ ok: true }); }); options.app.get(mePath, options.requireSession, async (req, res) => { - res.json({ user: req.authUser }); + const authUser = req.authUser; + if (typeof authUser?.id === "string") { + try { + await options.prisma.user.update({ + where: { id: authUser.id }, + data: { lastConnectionAt: /* @__PURE__ */ new Date() } + }); + } catch { + } + } + res.json({ user: authUser }); }); } export { diff --git a/dist/server/index.js.map b/dist/server/index.js.map index 347ddf0..7cdb341 100644 --- a/dist/server/index.js.map +++ b/dist/server/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../server/module.ts","../../server/invites.ts","../../server/routes.ts"],"sourcesContent":["import { ExpressAuth } from \"@auth/express\";\nimport Credentials from \"@auth/express/providers/credentials\";\nimport Google from \"@auth/express/providers/google\";\nimport Slack from \"@auth/express/providers/slack\";\nimport { PrismaAdapter } from \"@auth/prisma-adapter\";\nimport type { Request, RequestHandler } from \"express\";\nimport { z } from \"zod\";\n\ntype CredentialUser = {\n id: string;\n name: string | null;\n email: string | null;\n image?: string | null;\n passwordHash: string | null;\n};\n\ntype CreateAuthModuleOptions = {\n prisma: any;\n clientUrl: string;\n sessionCookieName: string;\n sessionCookieSecure: boolean;\n authUrl?: string;\n authDebug?: boolean;\n authSecret?: string;\n trustHost?: boolean;\n extraSessionCookieNames?: string[];\n signInPath?: string;\n authenticatedRedirectPath?: string;\n googleClientId?: string;\n googleClientSecret?: string;\n slackClientId?: string;\n slackClientSecret?: string;\n findCredentialsUserByEmail: (email: string) => Promise;\n comparePassword: (password: string, passwordHash: string) => Promise;\n sessionUserSelect: Record;\n mapSessionUser: (user: any) => TAuthUser;\n onSessionValidated?: (user: TAuthUser) => Promise | void;\n};\n\nfunction parseBoolean(value: string | undefined, fallback: boolean): boolean {\n if (value === undefined) {\n return fallback;\n }\n const normalized = value.trim().toLowerCase();\n if ([\"1\", \"true\", \"yes\", \"on\"].includes(normalized)) {\n return true;\n }\n if ([\"0\", \"false\", \"no\", \"off\"].includes(normalized)) {\n return false;\n }\n return fallback;\n}\n\nexport function createAuthModule(options: CreateAuthModuleOptions) {\n const signInPath = options.signInPath ?? \"/login\";\n const authenticatedRedirectPath = options.authenticatedRedirectPath ?? \"/chat\";\n const googleAuthEnabled = Boolean(options.googleClientId && options.googleClientSecret);\n const slackAuthEnabled = Boolean(options.slackClientId && options.slackClientSecret);\n\n const providers: any[] = [\n Credentials({\n name: \"Email et mot de passe\",\n credentials: {\n email: { label: \"Email\", type: \"email\" },\n password: { label: \"Password\", type: \"password\" }\n },\n authorize: async (rawCredentials) => {\n const parsed = z\n .object({\n email: z.string().email(),\n password: z.string().min(8)\n })\n .safeParse(rawCredentials);\n\n if (!parsed.success) {\n return null;\n }\n\n const user = await options.findCredentialsUserByEmail(parsed.data.email);\n if (!user?.passwordHash) {\n return null;\n }\n\n const valid = await options.comparePassword(parsed.data.password, user.passwordHash);\n if (!valid) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n email: user.email,\n image: user.image ?? null\n };\n }\n })\n ];\n\n if (googleAuthEnabled) {\n providers.push(\n Google({\n clientId: options.googleClientId!,\n clientSecret: options.googleClientSecret!,\n authorization: {\n params: {\n prompt: \"select_account\"\n }\n },\n allowDangerousEmailAccountLinking: true\n })\n );\n }\n\n if (slackAuthEnabled) {\n providers.push(\n Slack({\n clientId: options.slackClientId!,\n clientSecret: options.slackClientSecret!,\n allowDangerousEmailAccountLinking: true\n })\n );\n }\n\n const authConfig = {\n adapter: PrismaAdapter(options.prisma),\n trustHost: options.trustHost ?? parseBoolean(process.env.AUTH_TRUST_HOST, true),\n debug: options.authDebug ?? parseBoolean(process.env.AUTH_DEBUG, false),\n logger: options.authDebug\n ? {\n error(error: Error) {\n console.error(\"[authjs:error]\", error.name, error.message, error.cause ?? \"\");\n },\n warn(code: string) {\n console.warn(\"[authjs:warn]\", code);\n },\n debug(message: string, metadata?: unknown) {\n console.log(\"[authjs:debug]\", message, metadata ?? \"\");\n }\n }\n : undefined,\n session: { strategy: \"database\" as const },\n secret: options.authSecret ?? process.env.AUTH_SECRET,\n cookies: {\n sessionToken: {\n name: options.sessionCookieName,\n options: {\n httpOnly: true,\n sameSite: \"lax\" as const,\n path: \"/\",\n secure: options.sessionCookieSecure\n }\n }\n },\n providers,\n pages: {\n signIn: signInPath\n },\n callbacks: {\n redirect: async ({ url, baseUrl }: { url: string; baseUrl: string }) => {\n const clientOrigin = new URL(options.clientUrl).origin;\n const successUrl = new URL(authenticatedRedirectPath, clientOrigin).toString();\n\n const shouldForceChat = (pathname: string, searchParams: URLSearchParams): boolean => {\n if (pathname !== \"/\" && pathname !== signInPath) {\n return false;\n }\n return !searchParams.has(\"error\");\n };\n\n if (url.startsWith(\"/\")) {\n const relative = new URL(url, clientOrigin);\n if (shouldForceChat(relative.pathname, relative.searchParams)) {\n return successUrl;\n }\n return `${clientOrigin}${relative.pathname}${relative.search}${relative.hash}`;\n }\n\n try {\n const target = new URL(url);\n const base = new URL(baseUrl);\n\n if (target.origin === clientOrigin) {\n if (shouldForceChat(target.pathname, target.searchParams)) {\n return successUrl;\n }\n return target.toString();\n }\n\n if (target.origin === base.origin) {\n if (shouldForceChat(target.pathname, target.searchParams)) {\n return successUrl;\n }\n return `${clientOrigin}${target.pathname}${target.search}${target.hash}`;\n }\n } catch {\n return successUrl;\n }\n\n return successUrl;\n }\n }\n };\n\n const authHandler = ExpressAuth(authConfig);\n\n const requireSession: RequestHandler = async (req, res, next) => {\n const token = extractSessionToken(req.headers.cookie);\n const authDebug = options.authDebug ?? parseBoolean(process.env.AUTH_DEBUG, false);\n\n if (!token) {\n const payload: { error: string; reason?: string } = { error: \"Unauthorized\" };\n if (authDebug) {\n payload.reason = \"missing_session_cookie\";\n }\n return res.status(401).json(payload);\n }\n\n const session = await options.prisma.session.findUnique({\n where: { sessionToken: token },\n include: {\n user: {\n select: options.sessionUserSelect\n }\n }\n });\n\n if (!session || session.expires <= new Date()) {\n const payload: { error: string; reason?: string } = { error: \"Unauthorized\" };\n if (authDebug) {\n payload.reason = !session ? \"session_not_found\" : \"session_expired\";\n }\n return res.status(401).json(payload);\n }\n\n const authUser = options.mapSessionUser(session.user);\n (req as Request & { authUser?: TAuthUser }).authUser = authUser;\n await options.onSessionValidated?.(authUser);\n next();\n };\n\n const extractSessionToken = (cookieHeader: string | undefined): string | null => {\n if (!cookieHeader) {\n return null;\n }\n\n const cookies = cookieHeader\n .split(\";\")\n .map((part) => part.trim())\n .map((part) => {\n const index = part.indexOf(\"=\");\n if (index < 0) {\n return null;\n }\n return [part.slice(0, index), decodeURIComponent(part.slice(index + 1))] as const;\n })\n .filter((entry): entry is readonly [string, string] => entry !== null);\n\n const possibleNames = [\n options.sessionCookieName,\n ...(options.extraSessionCookieNames ?? []),\n \"__Secure-authjs.session-token\",\n \"authjs.session-token\",\n \"__Secure-next-auth.session-token\",\n \"next-auth.session-token\"\n ];\n\n for (const name of possibleNames) {\n const exact = cookies.find(([cookieName]) => cookieName === name);\n if (exact) {\n return exact[1];\n }\n\n const chunks = cookies\n .filter(([cookieName]) => cookieName.startsWith(`${name}.`))\n .map(([cookieName, value]) => {\n const suffix = cookieName.slice(name.length + 1);\n return [Number.parseInt(suffix, 10), value] as const;\n })\n .filter(([index]) => Number.isInteger(index))\n .sort((left, right) => left[0] - right[0]);\n\n if (chunks.length > 0) {\n return chunks.map(([, value]) => value).join(\"\");\n }\n }\n\n return null;\n };\n\n return {\n authConfig,\n authHandler,\n requireSession,\n extractSessionToken,\n googleAuthEnabled,\n slackAuthEnabled\n };\n}\n","import { createHash, randomBytes } from \"node:crypto\";\n\ntype AccountInviteContext = {\n verificationToken: { identifier: string; expires: Date };\n user: {\n id: string;\n email: string | null;\n name: string | null;\n passwordHash: string | null;\n emailVerified: Date | null;\n accounts: Array<{ id: string }>;\n };\n};\n\ntype AccountInviteOptions = {\n prisma: any;\n tokenTtlMs?: number;\n identifierPrefix?: string;\n};\n\nconst DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX = \"account-invite:\";\nconst DEFAULT_ACCOUNT_INVITE_TOKEN_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\nfunction hashAccountInviteToken(token: string): string {\n return createHash(\"sha256\").update(token).digest(\"hex\");\n}\n\nfunction buildAccountInviteIdentifier(prefix: string, userId: string): string {\n return `${prefix}${userId}`;\n}\n\nexport async function createAccountInviteToken(\n options: AccountInviteOptions & { userId: string }\n): Promise<{ token: string; expiresAt: Date }> {\n const identifierPrefix = options.identifierPrefix ?? DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX;\n const identifier = buildAccountInviteIdentifier(identifierPrefix, options.userId);\n const token = randomBytes(32).toString(\"hex\");\n const expiresAt = new Date(Date.now() + (options.tokenTtlMs ?? DEFAULT_ACCOUNT_INVITE_TOKEN_TTL_MS));\n\n await options.prisma.verificationToken.deleteMany({\n where: {\n OR: [{ identifier }, { expires: { lt: new Date() } }]\n }\n });\n\n await options.prisma.verificationToken.create({\n data: {\n identifier,\n token: hashAccountInviteToken(token),\n expires: expiresAt\n }\n });\n\n return { token, expiresAt };\n}\n\nexport async function getAccountInviteContext(\n options: AccountInviteOptions & { token: string }\n): Promise {\n const identifierPrefix = options.identifierPrefix ?? DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX;\n const verificationToken = await options.prisma.verificationToken.findUnique({\n where: { token: hashAccountInviteToken(options.token) },\n select: { identifier: true, expires: true }\n });\n\n if (\n !verificationToken ||\n verificationToken.expires <= new Date() ||\n !verificationToken.identifier.startsWith(identifierPrefix)\n ) {\n return null;\n }\n\n const userId = verificationToken.identifier.slice(identifierPrefix.length);\n if (!userId) {\n return null;\n }\n\n const user = await options.prisma.user.findUnique({\n where: { id: userId },\n select: {\n id: true,\n email: true,\n name: true,\n passwordHash: true,\n emailVerified: true,\n accounts: {\n select: { id: true },\n take: 1\n }\n }\n });\n\n if (!user?.email) {\n return null;\n }\n\n return {\n verificationToken,\n user\n };\n}\n\nexport {\n DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX,\n DEFAULT_ACCOUNT_INVITE_TOKEN_TTL_MS,\n buildAccountInviteIdentifier,\n hashAccountInviteToken\n};\n","import { createHash, randomBytes } from \"node:crypto\";\nimport type { Express, RequestHandler } from \"express\";\nimport { z } from \"zod\";\nimport { DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX, getAccountInviteContext } from \"./invites.js\";\n\ntype RegisterAuthApiRoutesOptions = {\n app: Express;\n prisma: any;\n authHandler: RequestHandler;\n requireSession: RequestHandler;\n extractSessionToken: (cookieHeader: string | undefined) => string | null;\n providersAvailability: Record;\n sessionCookieName: string;\n sessionCookieSecure: boolean;\n extraCookieNamesToClear?: string[];\n messages?: Partial;\n authBasePath?: string;\n authApiBasePath?: string;\n mePath?: string;\n normalizeEmail?: (email: string) => string;\n passwordHasher?: (password: string) => Promise;\n passwordComparator?: (password: string, passwordHash: string) => Promise;\n passwordReset?: {\n enabled: boolean;\n tokenTtlMs?: number;\n identifierPrefix?: string;\n buildResetUrl: (token: string) => string;\n sendMessage: (input: {\n user: { id: string; email: string; name: string | null; passwordHash: string | null };\n resetUrl: string;\n isPasswordCreation: boolean;\n expiresAt: Date;\n }) => Promise;\n };\n accountInvite?: {\n enabled: boolean;\n identifierPrefix?: string;\n };\n onUserRegistered?: (user: { id: string; email: string | null; name: string | null }) => Promise | void;\n onPasswordResetConfirmed?: (user: { id: string; email: string | null; name: string | null }) => Promise | void;\n};\n\ntype AuthRouteMessages = {\n invalidPayload: string;\n emailAlreadyUsed: string;\n accountNotFound: string;\n externalAccountOnly: string;\n invalidPassword: string;\n passwordResetUnavailable: string;\n invalidResetLink: string;\n expiredResetLink: string;\n invalidInviteLink: string;\n inviteAlreadyAccepted: string;\n};\n\nconst defaultNormalizeEmail = (email: string) => email.trim();\nconst defaultPasswordResetIdentifierPrefix = \"password-reset:\";\nconst defaultMessages: AuthRouteMessages = {\n invalidPayload: \"Invalid payload\",\n emailAlreadyUsed: \"Email already used\",\n accountNotFound: \"Account not found\",\n externalAccountOnly: \"This account uses an external sign-in provider.\",\n invalidPassword: \"Invalid password\",\n passwordResetUnavailable: \"Email service is not configured.\",\n invalidResetLink: \"Invalid reset link\",\n expiredResetLink: \"Invalid or expired reset link\",\n invalidInviteLink: \"Invalid or expired invite link\",\n inviteAlreadyAccepted: \"This invite has already been accepted\"\n};\n\nfunction hashPasswordResetToken(token: string): string {\n return createHash(\"sha256\").update(token).digest(\"hex\");\n}\n\nfunction buildPasswordResetIdentifier(prefix: string, userId: string): string {\n return `${prefix}${userId}`;\n}\n\nexport function registerAuthApiRoutes(options: RegisterAuthApiRoutesOptions): void {\n const authBasePath = options.authBasePath ?? \"/auth\";\n const authApiBasePath = options.authApiBasePath ?? \"/api/auth\";\n const mePath = options.mePath ?? \"/api/me\";\n const normalizeEmail = options.normalizeEmail ?? defaultNormalizeEmail;\n const passwordHasher = options.passwordHasher ?? ((password: string) => Promise.resolve(password));\n const passwordComparator = options.passwordComparator ?? ((password: string, hash: string) => Promise.resolve(password === hash));\n const passwordResetIdentifierPrefix = options.passwordReset?.identifierPrefix ?? defaultPasswordResetIdentifierPrefix;\n const accountInviteIdentifierPrefix = options.accountInvite?.identifierPrefix ?? DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX;\n const messages = { ...defaultMessages, ...(options.messages ?? {}) };\n\n const buildSession = (userId: string) => ({\n sessionToken: randomBytes(32).toString(\"hex\"),\n userId,\n expires: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)\n });\n\n const applySessionCookie = (res: any, session: { sessionToken: string; expires: Date }) => {\n res.cookie(options.sessionCookieName, session.sessionToken, {\n httpOnly: true,\n sameSite: \"lax\",\n secure: options.sessionCookieSecure,\n path: \"/\",\n expires: session.expires\n });\n };\n\n const findUserByEmail = async (email: string) => {\n const normalized = normalizeEmail(email);\n const lowered = normalized.toLowerCase();\n\n return options.prisma.user.findFirst({\n where: {\n OR: lowered === normalized ? [{ email: normalized }] : [{ email: normalized }, { email: lowered }]\n },\n select: {\n id: true,\n email: true,\n name: true,\n image: true,\n passwordHash: true,\n emailVerified: true\n }\n });\n };\n\n const getPasswordResetContext = async (\n rawToken: string\n ): Promise<\n | {\n verificationToken: { identifier: string; expires: Date };\n user: { id: string; email: string | null; name: string | null; passwordHash: string | null; emailVerified: Date | null };\n }\n | null\n > => {\n const verificationToken = await options.prisma.verificationToken.findUnique({\n where: { token: hashPasswordResetToken(rawToken) },\n select: { identifier: true, expires: true }\n });\n\n if (\n !verificationToken ||\n verificationToken.expires <= new Date() ||\n !verificationToken.identifier.startsWith(passwordResetIdentifierPrefix)\n ) {\n return null;\n }\n\n const userId = verificationToken.identifier.slice(passwordResetIdentifierPrefix.length);\n if (!userId) {\n return null;\n }\n\n const user = await options.prisma.user.findUnique({\n where: { id: userId },\n select: {\n id: true,\n email: true,\n name: true,\n passwordHash: true,\n emailVerified: true\n }\n });\n\n if (!user?.email) {\n return null;\n }\n\n return { verificationToken, user };\n };\n\n options.app.use(authBasePath, options.authHandler);\n\n options.app.get(`${authApiBasePath}/providers`, (_req, res) => {\n res.json(options.providersAvailability);\n });\n\n options.app.post(`${authApiBasePath}/register`, async (req, res) => {\n const parsed = z\n .object({\n name: z.string().min(2).max(60),\n email: z.string().email(),\n password: z.string().min(8)\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n const email = normalizeEmail(parsed.data.email);\n const exists = await findUserByEmail(email);\n if (exists) {\n return res.status(409).json({ error: messages.emailAlreadyUsed });\n }\n\n const passwordHash = await passwordHasher(parsed.data.password);\n const created = await options.prisma.user.create({\n data: {\n name: parsed.data.name,\n email,\n passwordHash\n },\n select: { id: true, email: true, name: true }\n });\n\n await options.onUserRegistered?.(created);\n return res.status(201).json(created);\n });\n\n options.app.post(`${authApiBasePath}/login`, async (req, res) => {\n const parsed = z\n .object({\n email: z.string().email(),\n password: z.string().min(8)\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n const email = normalizeEmail(parsed.data.email);\n const user = await findUserByEmail(email);\n if (!user) {\n return res.status(404).json({ error: messages.accountNotFound });\n }\n\n if (!user.passwordHash) {\n return res.status(400).json({ error: messages.externalAccountOnly });\n }\n\n const valid = await passwordComparator(parsed.data.password, user.passwordHash);\n if (!valid) {\n return res.status(401).json({ error: messages.invalidPassword });\n }\n\n const session = buildSession(user.id);\n await options.prisma.session.create({\n data: session\n });\n applySessionCookie(res, session);\n\n return res.status(200).json({ ok: true });\n });\n\n options.app.post(`${authApiBasePath}/password-reset/request`, async (req, res) => {\n const parsed = z\n .object({\n email: z.string().email()\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n if (!options.passwordReset?.enabled) {\n return res.status(503).json({ error: messages.passwordResetUnavailable });\n }\n\n const email = normalizeEmail(parsed.data.email);\n const user = await findUserByEmail(email);\n if (!user?.email) {\n return res.status(200).json({ ok: true });\n }\n\n const rawToken = randomBytes(32).toString(\"hex\");\n const identifier = buildPasswordResetIdentifier(passwordResetIdentifierPrefix, user.id);\n const expiresAt = new Date(Date.now() + (options.passwordReset.tokenTtlMs ?? 2 * 60 * 60 * 1000));\n const resetUrl = options.passwordReset.buildResetUrl(rawToken);\n const isPasswordCreation = !user.passwordHash;\n\n await options.prisma.verificationToken.deleteMany({\n where: {\n OR: [{ identifier }, { expires: { lt: new Date() } }]\n }\n });\n\n await options.prisma.verificationToken.create({\n data: {\n identifier,\n token: hashPasswordResetToken(rawToken),\n expires: expiresAt\n }\n });\n\n await options.passwordReset.sendMessage({\n user: {\n id: user.id,\n email: user.email,\n name: user.name,\n passwordHash: user.passwordHash\n },\n resetUrl,\n isPasswordCreation,\n expiresAt\n });\n\n return res.status(200).json({ ok: true });\n });\n\n options.app.get(`${authApiBasePath}/password-reset/validate`, async (req, res) => {\n if (!options.passwordReset?.enabled) {\n return res.status(400).json({ error: messages.expiredResetLink });\n }\n\n const parsed = z.object({ token: z.string().min(1) }).safeParse({\n token: Array.isArray(req.query.token) ? req.query.token[0] : req.query.token\n });\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidResetLink });\n }\n\n const context = await getPasswordResetContext(parsed.data.token);\n if (!context) {\n return res.status(400).json({ error: messages.expiredResetLink });\n }\n\n return res.status(200).json({\n ok: true,\n email: context.user.email,\n mode: context.user.passwordHash ? \"reset\" : \"create\"\n });\n });\n\n options.app.post(`${authApiBasePath}/password-reset/confirm`, async (req, res) => {\n if (!options.passwordReset?.enabled) {\n return res.status(400).json({ error: messages.expiredResetLink });\n }\n\n const parsed = z\n .object({\n token: z.string().min(1),\n password: z.string().min(8)\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n const context = await getPasswordResetContext(parsed.data.token);\n if (!context) {\n return res.status(400).json({ error: messages.expiredResetLink });\n }\n\n const passwordHash = await passwordHasher(parsed.data.password);\n await options.prisma.$transaction([\n options.prisma.verificationToken.deleteMany({\n where: { identifier: context.verificationToken.identifier }\n }),\n options.prisma.session.deleteMany({\n where: { userId: context.user.id }\n }),\n options.prisma.user.update({\n where: { id: context.user.id },\n data: {\n passwordHash,\n emailVerified: context.user.emailVerified ?? new Date()\n }\n })\n ]);\n\n await options.onPasswordResetConfirmed?.(context.user);\n return res.status(200).json({ ok: true });\n });\n\n options.app.get(`${authApiBasePath}/invite/validate`, async (req, res) => {\n if (!options.accountInvite?.enabled) {\n return res.status(404).json({ error: messages.invalidInviteLink });\n }\n\n const parsed = z.object({ token: z.string().min(1) }).safeParse({\n token: Array.isArray(req.query.token) ? req.query.token[0] : req.query.token\n });\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidInviteLink });\n }\n\n const context = await getAccountInviteContext({\n prisma: options.prisma,\n token: parsed.data.token,\n identifierPrefix: accountInviteIdentifierPrefix\n });\n\n if (!context) {\n return res.status(400).json({ error: messages.invalidInviteLink });\n }\n\n if (context.user.passwordHash || context.user.accounts.length > 0) {\n return res.status(409).json({ error: messages.inviteAlreadyAccepted });\n }\n\n return res.status(200).json({\n ok: true,\n email: context.user.email,\n name: context.user.name\n });\n });\n\n options.app.post(`${authApiBasePath}/invite/accept`, async (req, res) => {\n if (!options.accountInvite?.enabled) {\n return res.status(404).json({ error: messages.invalidInviteLink });\n }\n\n const parsed = z\n .object({\n token: z.string().min(1),\n name: z.string().min(2).max(60),\n password: z.string().min(8)\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n const context = await getAccountInviteContext({\n prisma: options.prisma,\n token: parsed.data.token,\n identifierPrefix: accountInviteIdentifierPrefix\n });\n\n if (!context) {\n return res.status(400).json({ error: messages.invalidInviteLink });\n }\n\n if (context.user.passwordHash || context.user.accounts.length > 0) {\n return res.status(409).json({ error: messages.inviteAlreadyAccepted });\n }\n\n const passwordHash = await passwordHasher(parsed.data.password);\n const session = buildSession(context.user.id);\n\n await options.prisma.$transaction([\n options.prisma.verificationToken.deleteMany({\n where: { identifier: context.verificationToken.identifier }\n }),\n options.prisma.session.create({\n data: session\n }),\n options.prisma.user.update({\n where: { id: context.user.id },\n data: {\n name: parsed.data.name,\n passwordHash,\n emailVerified: context.user.emailVerified ?? new Date()\n }\n })\n ]);\n\n applySessionCookie(res, session);\n return res.status(200).json({ ok: true });\n });\n\n options.app.post(`${authApiBasePath}/logout`, async (req, res) => {\n const token = options.extractSessionToken(req.headers.cookie);\n\n if (token) {\n await options.prisma.session.deleteMany({ where: { sessionToken: token } });\n }\n\n const cookieNamesToClear = [\n options.sessionCookieName,\n ...(options.extraCookieNamesToClear ?? []),\n \"authjs.session-token\",\n \"__Secure-authjs.session-token\",\n \"next-auth.session-token\",\n \"__Secure-next-auth.session-token\"\n ];\n\n for (const cookieName of cookieNamesToClear) {\n res.clearCookie(cookieName, { path: \"/\" });\n }\n\n return res.status(200).json({ ok: true });\n });\n\n options.app.get(mePath, options.requireSession, async (req, res) => {\n res.json({ user: (req as { authUser?: unknown }).authUser });\n });\n}\n"],"mappings":";AAAA,SAAS,mBAAmB;AAC5B,OAAO,iBAAiB;AACxB,OAAO,YAAY;AACnB,OAAO,WAAW;AAClB,SAAS,qBAAqB;AAE9B,SAAS,SAAS;AAiClB,SAAS,aAAa,OAA2B,UAA4B;AAC3E,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,QAAM,aAAa,MAAM,KAAK,EAAE,YAAY;AAC5C,MAAI,CAAC,KAAK,QAAQ,OAAO,IAAI,EAAE,SAAS,UAAU,GAAG;AACnD,WAAO;AAAA,EACT;AACA,MAAI,CAAC,KAAK,SAAS,MAAM,KAAK,EAAE,SAAS,UAAU,GAAG;AACpD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,iBAA4B,SAA6C;AACvF,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,4BAA4B,QAAQ,6BAA6B;AACvE,QAAM,oBAAoB,QAAQ,QAAQ,kBAAkB,QAAQ,kBAAkB;AACtF,QAAM,mBAAmB,QAAQ,QAAQ,iBAAiB,QAAQ,iBAAiB;AAEnF,QAAM,YAAmB;AAAA,IACvB,YAAY;AAAA,MACV,MAAM;AAAA,MACN,aAAa;AAAA,QACX,OAAO,EAAE,OAAO,SAAS,MAAM,QAAQ;AAAA,QACvC,UAAU,EAAE,OAAO,YAAY,MAAM,WAAW;AAAA,MAClD;AAAA,MACA,WAAW,OAAO,mBAAmB;AACnC,cAAM,SAAS,EACZ,OAAO;AAAA,UACN,OAAO,EAAE,OAAO,EAAE,MAAM;AAAA,UACxB,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,QAC5B,CAAC,EACA,UAAU,cAAc;AAE3B,YAAI,CAAC,OAAO,SAAS;AACnB,iBAAO;AAAA,QACT;AAEA,cAAM,OAAO,MAAM,QAAQ,2BAA2B,OAAO,KAAK,KAAK;AACvE,YAAI,CAAC,MAAM,cAAc;AACvB,iBAAO;AAAA,QACT;AAEA,cAAM,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,KAAK,UAAU,KAAK,YAAY;AACnF,YAAI,CAAC,OAAO;AACV,iBAAO;AAAA,QACT;AAEA,eAAO;AAAA,UACL,IAAI,KAAK;AAAA,UACT,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA,UACZ,OAAO,KAAK,SAAS;AAAA,QACvB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,mBAAmB;AACrB,cAAU;AAAA,MACR,OAAO;AAAA,QACL,UAAU,QAAQ;AAAA,QAClB,cAAc,QAAQ;AAAA,QACtB,eAAe;AAAA,UACb,QAAQ;AAAA,YACN,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,mCAAmC;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,kBAAkB;AACpB,cAAU;AAAA,MACR,MAAM;AAAA,QACJ,UAAU,QAAQ;AAAA,QAClB,cAAc,QAAQ;AAAA,QACtB,mCAAmC;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,aAAa;AAAA,IACjB,SAAS,cAAc,QAAQ,MAAM;AAAA,IACrC,WAAW,QAAQ,aAAa,aAAa,QAAQ,IAAI,iBAAiB,IAAI;AAAA,IAC9E,OAAO,QAAQ,aAAa,aAAa,QAAQ,IAAI,YAAY,KAAK;AAAA,IACtE,QAAQ,QAAQ,YACZ;AAAA,MACE,MAAM,OAAc;AAClB,gBAAQ,MAAM,kBAAkB,MAAM,MAAM,MAAM,SAAS,MAAM,SAAS,EAAE;AAAA,MAC9E;AAAA,MACA,KAAK,MAAc;AACjB,gBAAQ,KAAK,iBAAiB,IAAI;AAAA,MACpC;AAAA,MACA,MAAM,SAAiB,UAAoB;AACzC,gBAAQ,IAAI,kBAAkB,SAAS,YAAY,EAAE;AAAA,MACvD;AAAA,IACF,IACA;AAAA,IACJ,SAAS,EAAE,UAAU,WAAoB;AAAA,IACzC,QAAQ,QAAQ,cAAc,QAAQ,IAAI;AAAA,IAC1C,SAAS;AAAA,MACP,cAAc;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,SAAS;AAAA,UACP,UAAU;AAAA,UACV,UAAU;AAAA,UACV,MAAM;AAAA,UACN,QAAQ,QAAQ;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,IACA,OAAO;AAAA,MACL,QAAQ;AAAA,IACV;AAAA,IACA,WAAW;AAAA,MACT,UAAU,OAAO,EAAE,KAAK,QAAQ,MAAwC;AACtE,cAAM,eAAe,IAAI,IAAI,QAAQ,SAAS,EAAE;AAChD,cAAM,aAAa,IAAI,IAAI,2BAA2B,YAAY,EAAE,SAAS;AAE7E,cAAM,kBAAkB,CAAC,UAAkB,iBAA2C;AACpF,cAAI,aAAa,OAAO,aAAa,YAAY;AAC/C,mBAAO;AAAA,UACT;AACA,iBAAO,CAAC,aAAa,IAAI,OAAO;AAAA,QAClC;AAEA,YAAI,IAAI,WAAW,GAAG,GAAG;AACvB,gBAAM,WAAW,IAAI,IAAI,KAAK,YAAY;AAC1C,cAAI,gBAAgB,SAAS,UAAU,SAAS,YAAY,GAAG;AAC7D,mBAAO;AAAA,UACT;AACA,iBAAO,GAAG,YAAY,GAAG,SAAS,QAAQ,GAAG,SAAS,MAAM,GAAG,SAAS,IAAI;AAAA,QAC9E;AAEA,YAAI;AACF,gBAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,gBAAM,OAAO,IAAI,IAAI,OAAO;AAE5B,cAAI,OAAO,WAAW,cAAc;AAClC,gBAAI,gBAAgB,OAAO,UAAU,OAAO,YAAY,GAAG;AACzD,qBAAO;AAAA,YACT;AACA,mBAAO,OAAO,SAAS;AAAA,UACzB;AAEA,cAAI,OAAO,WAAW,KAAK,QAAQ;AACjC,gBAAI,gBAAgB,OAAO,UAAU,OAAO,YAAY,GAAG;AACzD,qBAAO;AAAA,YACT;AACA,mBAAO,GAAG,YAAY,GAAG,OAAO,QAAQ,GAAG,OAAO,MAAM,GAAG,OAAO,IAAI;AAAA,UACxE;AAAA,QACF,QAAQ;AACN,iBAAO;AAAA,QACT;AAEA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,YAAY,UAAU;AAE1C,QAAM,iBAAiC,OAAO,KAAK,KAAK,SAAS;AAC/D,UAAM,QAAQ,oBAAoB,IAAI,QAAQ,MAAM;AACpD,UAAM,YAAY,QAAQ,aAAa,aAAa,QAAQ,IAAI,YAAY,KAAK;AAEjF,QAAI,CAAC,OAAO;AACV,YAAM,UAA8C,EAAE,OAAO,eAAe;AAC5E,UAAI,WAAW;AACb,gBAAQ,SAAS;AAAA,MACnB;AACA,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,OAAO;AAAA,IACrC;AAEA,UAAM,UAAU,MAAM,QAAQ,OAAO,QAAQ,WAAW;AAAA,MACtD,OAAO,EAAE,cAAc,MAAM;AAAA,MAC7B,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,QAAQ,QAAQ;AAAA,QAClB;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,CAAC,WAAW,QAAQ,WAAW,oBAAI,KAAK,GAAG;AAC7C,YAAM,UAA8C,EAAE,OAAO,eAAe;AAC5E,UAAI,WAAW;AACb,gBAAQ,SAAS,CAAC,UAAU,sBAAsB;AAAA,MACpD;AACA,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,OAAO;AAAA,IACrC;AAEA,UAAM,WAAW,QAAQ,eAAe,QAAQ,IAAI;AACpD,IAAC,IAA2C,WAAW;AACvD,UAAM,QAAQ,qBAAqB,QAAQ;AAC3C,SAAK;AAAA,EACP;AAEA,QAAM,sBAAsB,CAAC,iBAAoD;AAC/E,QAAI,CAAC,cAAc;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,aACb,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,IAAI,CAAC,SAAS;AACb,YAAM,QAAQ,KAAK,QAAQ,GAAG;AAC9B,UAAI,QAAQ,GAAG;AACb,eAAO;AAAA,MACT;AACA,aAAO,CAAC,KAAK,MAAM,GAAG,KAAK,GAAG,mBAAmB,KAAK,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,IACzE,CAAC,EACA,OAAO,CAAC,UAA8C,UAAU,IAAI;AAEvE,UAAM,gBAAgB;AAAA,MACpB,QAAQ;AAAA,MACR,GAAI,QAAQ,2BAA2B,CAAC;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,eAAW,QAAQ,eAAe;AAChC,YAAM,QAAQ,QAAQ,KAAK,CAAC,CAAC,UAAU,MAAM,eAAe,IAAI;AAChE,UAAI,OAAO;AACT,eAAO,MAAM,CAAC;AAAA,MAChB;AAEA,YAAM,SAAS,QACZ,OAAO,CAAC,CAAC,UAAU,MAAM,WAAW,WAAW,GAAG,IAAI,GAAG,CAAC,EAC1D,IAAI,CAAC,CAAC,YAAY,KAAK,MAAM;AAC5B,cAAM,SAAS,WAAW,MAAM,KAAK,SAAS,CAAC;AAC/C,eAAO,CAAC,OAAO,SAAS,QAAQ,EAAE,GAAG,KAAK;AAAA,MAC5C,CAAC,EACA,OAAO,CAAC,CAAC,KAAK,MAAM,OAAO,UAAU,KAAK,CAAC,EAC3C,KAAK,CAAC,MAAM,UAAU,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC;AAE3C,UAAI,OAAO,SAAS,GAAG;AACrB,eAAO,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,KAAK,EAAE,KAAK,EAAE;AAAA,MACjD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACzSA,SAAS,YAAY,mBAAmB;AAoBxC,IAAM,2CAA2C;AACjD,IAAM,sCAAsC,IAAI,KAAK,KAAK,KAAK;AAE/D,SAAS,uBAAuB,OAAuB;AACrD,SAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACxD;AAEA,SAAS,6BAA6B,QAAgB,QAAwB;AAC5E,SAAO,GAAG,MAAM,GAAG,MAAM;AAC3B;AAEA,eAAsB,yBACpB,SAC6C;AAC7C,QAAM,mBAAmB,QAAQ,oBAAoB;AACrD,QAAM,aAAa,6BAA6B,kBAAkB,QAAQ,MAAM;AAChF,QAAM,QAAQ,YAAY,EAAE,EAAE,SAAS,KAAK;AAC5C,QAAM,YAAY,IAAI,KAAK,KAAK,IAAI,KAAK,QAAQ,cAAc,oCAAoC;AAEnG,QAAM,QAAQ,OAAO,kBAAkB,WAAW;AAAA,IAChD,OAAO;AAAA,MACL,IAAI,CAAC,EAAE,WAAW,GAAG,EAAE,SAAS,EAAE,IAAI,oBAAI,KAAK,EAAE,EAAE,CAAC;AAAA,IACtD;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,OAAO,kBAAkB,OAAO;AAAA,IAC5C,MAAM;AAAA,MACJ;AAAA,MACA,OAAO,uBAAuB,KAAK;AAAA,MACnC,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,SAAO,EAAE,OAAO,UAAU;AAC5B;AAEA,eAAsB,wBACpB,SACsC;AACtC,QAAM,mBAAmB,QAAQ,oBAAoB;AACrD,QAAM,oBAAoB,MAAM,QAAQ,OAAO,kBAAkB,WAAW;AAAA,IAC1E,OAAO,EAAE,OAAO,uBAAuB,QAAQ,KAAK,EAAE;AAAA,IACtD,QAAQ,EAAE,YAAY,MAAM,SAAS,KAAK;AAAA,EAC5C,CAAC;AAED,MACE,CAAC,qBACD,kBAAkB,WAAW,oBAAI,KAAK,KACtC,CAAC,kBAAkB,WAAW,WAAW,gBAAgB,GACzD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,kBAAkB,WAAW,MAAM,iBAAiB,MAAM;AACzE,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,MAAM,QAAQ,OAAO,KAAK,WAAW;AAAA,IAChD,OAAO,EAAE,IAAI,OAAO;AAAA,IACpB,QAAQ;AAAA,MACN,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,MACN,cAAc;AAAA,MACd,eAAe;AAAA,MACf,UAAU;AAAA,QACR,QAAQ,EAAE,IAAI,KAAK;AAAA,QACnB,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,CAAC,MAAM,OAAO;AAChB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;;;ACrGA,SAAS,cAAAA,aAAY,eAAAC,oBAAmB;AAExC,SAAS,KAAAC,UAAS;AAqDlB,IAAM,wBAAwB,CAAC,UAAkB,MAAM,KAAK;AAC5D,IAAM,uCAAuC;AAC7C,IAAM,kBAAqC;AAAA,EACzC,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,iBAAiB;AAAA,EACjB,0BAA0B;AAAA,EAC1B,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,uBAAuB;AACzB;AAEA,SAAS,uBAAuB,OAAuB;AACrD,SAAOC,YAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACxD;AAEA,SAAS,6BAA6B,QAAgB,QAAwB;AAC5E,SAAO,GAAG,MAAM,GAAG,MAAM;AAC3B;AAEO,SAAS,sBAAsB,SAA6C;AACjF,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,kBAAkB,QAAQ,mBAAmB;AACnD,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,QAAM,iBAAiB,QAAQ,mBAAmB,CAAC,aAAqB,QAAQ,QAAQ,QAAQ;AAChG,QAAM,qBAAqB,QAAQ,uBAAuB,CAAC,UAAkB,SAAiB,QAAQ,QAAQ,aAAa,IAAI;AAC/H,QAAM,gCAAgC,QAAQ,eAAe,oBAAoB;AACjF,QAAM,gCAAgC,QAAQ,eAAe,oBAAoB;AACjF,QAAM,WAAW,EAAE,GAAG,iBAAiB,GAAI,QAAQ,YAAY,CAAC,EAAG;AAEnE,QAAM,eAAe,CAAC,YAAoB;AAAA,IACxC,cAAcC,aAAY,EAAE,EAAE,SAAS,KAAK;AAAA,IAC5C;AAAA,IACA,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AAAA,EACzD;AAEA,QAAM,qBAAqB,CAAC,KAAU,YAAqD;AACzF,QAAI,OAAO,QAAQ,mBAAmB,QAAQ,cAAc;AAAA,MAC1D,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,SAAS,QAAQ;AAAA,IACnB,CAAC;AAAA,EACH;AAEA,QAAM,kBAAkB,OAAO,UAAkB;AAC/C,UAAM,aAAa,eAAe,KAAK;AACvC,UAAM,UAAU,WAAW,YAAY;AAEvC,WAAO,QAAQ,OAAO,KAAK,UAAU;AAAA,MACnC,OAAO;AAAA,QACL,IAAI,YAAY,aAAa,CAAC,EAAE,OAAO,WAAW,CAAC,IAAI,CAAC,EAAE,OAAO,WAAW,GAAG,EAAE,OAAO,QAAQ,CAAC;AAAA,MACnG;AAAA,MACA,QAAQ;AAAA,QACN,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,QACP,cAAc;AAAA,QACd,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,0BAA0B,OAC9B,aAOG;AACH,UAAM,oBAAoB,MAAM,QAAQ,OAAO,kBAAkB,WAAW;AAAA,MAC1E,OAAO,EAAE,OAAO,uBAAuB,QAAQ,EAAE;AAAA,MACjD,QAAQ,EAAE,YAAY,MAAM,SAAS,KAAK;AAAA,IAC5C,CAAC;AAED,QACE,CAAC,qBACD,kBAAkB,WAAW,oBAAI,KAAK,KACtC,CAAC,kBAAkB,WAAW,WAAW,6BAA6B,GACtE;AACA,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,kBAAkB,WAAW,MAAM,8BAA8B,MAAM;AACtF,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,MAAM,QAAQ,OAAO,KAAK,WAAW;AAAA,MAChD,OAAO,EAAE,IAAI,OAAO;AAAA,MACpB,QAAQ;AAAA,QACN,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,MAAM,OAAO;AAChB,aAAO;AAAA,IACT;AAEA,WAAO,EAAE,mBAAmB,KAAK;AAAA,EACnC;AAEA,UAAQ,IAAI,IAAI,cAAc,QAAQ,WAAW;AAEjD,UAAQ,IAAI,IAAI,GAAG,eAAe,cAAc,CAAC,MAAM,QAAQ;AAC7D,QAAI,KAAK,QAAQ,qBAAqB;AAAA,EACxC,CAAC;AAED,UAAQ,IAAI,KAAK,GAAG,eAAe,aAAa,OAAO,KAAK,QAAQ;AAClE,UAAM,SAASC,GACZ,OAAO;AAAA,MACN,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,MAC9B,OAAOA,GAAE,OAAO,EAAE,MAAM;AAAA,MACxB,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC5B,CAAC,EACA,UAAU,IAAI,IAAI;AAErB,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,eAAe,CAAC;AAAA,IAChE;AAEA,UAAM,QAAQ,eAAe,OAAO,KAAK,KAAK;AAC9C,UAAM,SAAS,MAAM,gBAAgB,KAAK;AAC1C,QAAI,QAAQ;AACV,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,iBAAiB,CAAC;AAAA,IAClE;AAEA,UAAM,eAAe,MAAM,eAAe,OAAO,KAAK,QAAQ;AAC9D,UAAM,UAAU,MAAM,QAAQ,OAAO,KAAK,OAAO;AAAA,MAC/C,MAAM;AAAA,QACJ,MAAM,OAAO,KAAK;AAAA,QAClB;AAAA,QACA;AAAA,MACF;AAAA,MACA,QAAQ,EAAE,IAAI,MAAM,OAAO,MAAM,MAAM,KAAK;AAAA,IAC9C,CAAC;AAED,UAAM,QAAQ,mBAAmB,OAAO;AACxC,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK,OAAO;AAAA,EACrC,CAAC;AAED,UAAQ,IAAI,KAAK,GAAG,eAAe,UAAU,OAAO,KAAK,QAAQ;AAC/D,UAAM,SAASA,GACZ,OAAO;AAAA,MACN,OAAOA,GAAE,OAAO,EAAE,MAAM;AAAA,MACxB,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC5B,CAAC,EACA,UAAU,IAAI,IAAI;AAErB,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,eAAe,CAAC;AAAA,IAChE;AAEA,UAAM,QAAQ,eAAe,OAAO,KAAK,KAAK;AAC9C,UAAM,OAAO,MAAM,gBAAgB,KAAK;AACxC,QAAI,CAAC,MAAM;AACT,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,gBAAgB,CAAC;AAAA,IACjE;AAEA,QAAI,CAAC,KAAK,cAAc;AACtB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,oBAAoB,CAAC;AAAA,IACrE;AAEA,UAAM,QAAQ,MAAM,mBAAmB,OAAO,KAAK,UAAU,KAAK,YAAY;AAC9E,QAAI,CAAC,OAAO;AACV,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,gBAAgB,CAAC;AAAA,IACjE;AAEA,UAAM,UAAU,aAAa,KAAK,EAAE;AACpC,UAAM,QAAQ,OAAO,QAAQ,OAAO;AAAA,MAClC,MAAM;AAAA,IACR,CAAC;AACD,uBAAmB,KAAK,OAAO;AAE/B,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1C,CAAC;AAED,UAAQ,IAAI,KAAK,GAAG,eAAe,2BAA2B,OAAO,KAAK,QAAQ;AAChF,UAAM,SAASA,GACZ,OAAO;AAAA,MACN,OAAOA,GAAE,OAAO,EAAE,MAAM;AAAA,IAC1B,CAAC,EACA,UAAU,IAAI,IAAI;AAErB,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,eAAe,CAAC;AAAA,IAChE;AAEA,QAAI,CAAC,QAAQ,eAAe,SAAS;AACnC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,yBAAyB,CAAC;AAAA,IAC1E;AAEA,UAAM,QAAQ,eAAe,OAAO,KAAK,KAAK;AAC9C,UAAM,OAAO,MAAM,gBAAgB,KAAK;AACxC,QAAI,CAAC,MAAM,OAAO;AAChB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,IAC1C;AAEA,UAAM,WAAWD,aAAY,EAAE,EAAE,SAAS,KAAK;AAC/C,UAAM,aAAa,6BAA6B,+BAA+B,KAAK,EAAE;AACtF,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,KAAK,QAAQ,cAAc,cAAc,IAAI,KAAK,KAAK,IAAK;AAChG,UAAM,WAAW,QAAQ,cAAc,cAAc,QAAQ;AAC7D,UAAM,qBAAqB,CAAC,KAAK;AAEjC,UAAM,QAAQ,OAAO,kBAAkB,WAAW;AAAA,MAChD,OAAO;AAAA,QACL,IAAI,CAAC,EAAE,WAAW,GAAG,EAAE,SAAS,EAAE,IAAI,oBAAI,KAAK,EAAE,EAAE,CAAC;AAAA,MACtD;AAAA,IACF,CAAC;AAED,UAAM,QAAQ,OAAO,kBAAkB,OAAO;AAAA,MAC5C,MAAM;AAAA,QACJ;AAAA,QACA,OAAO,uBAAuB,QAAQ;AAAA,QACtC,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAED,UAAM,QAAQ,cAAc,YAAY;AAAA,MACtC,MAAM;AAAA,QACJ,IAAI,KAAK;AAAA,QACT,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,cAAc,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1C,CAAC;AAED,UAAQ,IAAI,IAAI,GAAG,eAAe,4BAA4B,OAAO,KAAK,QAAQ;AAChF,QAAI,CAAC,QAAQ,eAAe,SAAS;AACnC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,iBAAiB,CAAC;AAAA,IAClE;AAEA,UAAM,SAASC,GAAE,OAAO,EAAE,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,UAAU;AAAA,MAC9D,OAAO,MAAM,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,MAAM,CAAC,IAAI,IAAI,MAAM;AAAA,IACzE,CAAC;AAED,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,iBAAiB,CAAC;AAAA,IAClE;AAEA,UAAM,UAAU,MAAM,wBAAwB,OAAO,KAAK,KAAK;AAC/D,QAAI,CAAC,SAAS;AACZ,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,iBAAiB,CAAC;AAAA,IAClE;AAEA,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MAC1B,IAAI;AAAA,MACJ,OAAO,QAAQ,KAAK;AAAA,MACpB,MAAM,QAAQ,KAAK,eAAe,UAAU;AAAA,IAC9C,CAAC;AAAA,EACH,CAAC;AAED,UAAQ,IAAI,KAAK,GAAG,eAAe,2BAA2B,OAAO,KAAK,QAAQ;AAChF,QAAI,CAAC,QAAQ,eAAe,SAAS;AACnC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,iBAAiB,CAAC;AAAA,IAClE;AAEA,UAAM,SAASA,GACZ,OAAO;AAAA,MACN,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,MACvB,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC5B,CAAC,EACA,UAAU,IAAI,IAAI;AAErB,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,eAAe,CAAC;AAAA,IAChE;AAEA,UAAM,UAAU,MAAM,wBAAwB,OAAO,KAAK,KAAK;AAC/D,QAAI,CAAC,SAAS;AACZ,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,iBAAiB,CAAC;AAAA,IAClE;AAEA,UAAM,eAAe,MAAM,eAAe,OAAO,KAAK,QAAQ;AAC9D,UAAM,QAAQ,OAAO,aAAa;AAAA,MAChC,QAAQ,OAAO,kBAAkB,WAAW;AAAA,QAC1C,OAAO,EAAE,YAAY,QAAQ,kBAAkB,WAAW;AAAA,MAC5D,CAAC;AAAA,MACD,QAAQ,OAAO,QAAQ,WAAW;AAAA,QAChC,OAAO,EAAE,QAAQ,QAAQ,KAAK,GAAG;AAAA,MACnC,CAAC;AAAA,MACD,QAAQ,OAAO,KAAK,OAAO;AAAA,QACzB,OAAO,EAAE,IAAI,QAAQ,KAAK,GAAG;AAAA,QAC7B,MAAM;AAAA,UACJ;AAAA,UACA,eAAe,QAAQ,KAAK,iBAAiB,oBAAI,KAAK;AAAA,QACxD;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,UAAM,QAAQ,2BAA2B,QAAQ,IAAI;AACrD,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1C,CAAC;AAED,UAAQ,IAAI,IAAI,GAAG,eAAe,oBAAoB,OAAO,KAAK,QAAQ;AACxE,QAAI,CAAC,QAAQ,eAAe,SAAS;AACnC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,kBAAkB,CAAC;AAAA,IACnE;AAEA,UAAM,SAASA,GAAE,OAAO,EAAE,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,UAAU;AAAA,MAC9D,OAAO,MAAM,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,MAAM,CAAC,IAAI,IAAI,MAAM;AAAA,IACzE,CAAC;AAED,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,kBAAkB,CAAC;AAAA,IACnE;AAEA,UAAM,UAAU,MAAM,wBAAwB;AAAA,MAC5C,QAAQ,QAAQ;AAAA,MAChB,OAAO,OAAO,KAAK;AAAA,MACnB,kBAAkB;AAAA,IACpB,CAAC;AAED,QAAI,CAAC,SAAS;AACZ,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,kBAAkB,CAAC;AAAA,IACnE;AAEA,QAAI,QAAQ,KAAK,gBAAgB,QAAQ,KAAK,SAAS,SAAS,GAAG;AACjE,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,sBAAsB,CAAC;AAAA,IACvE;AAEA,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MAC1B,IAAI;AAAA,MACJ,OAAO,QAAQ,KAAK;AAAA,MACpB,MAAM,QAAQ,KAAK;AAAA,IACrB,CAAC;AAAA,EACH,CAAC;AAED,UAAQ,IAAI,KAAK,GAAG,eAAe,kBAAkB,OAAO,KAAK,QAAQ;AACvE,QAAI,CAAC,QAAQ,eAAe,SAAS;AACnC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,kBAAkB,CAAC;AAAA,IACnE;AAEA,UAAM,SAASA,GACZ,OAAO;AAAA,MACN,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,MACvB,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,MAC9B,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC5B,CAAC,EACA,UAAU,IAAI,IAAI;AAErB,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,eAAe,CAAC;AAAA,IAChE;AAEA,UAAM,UAAU,MAAM,wBAAwB;AAAA,MAC5C,QAAQ,QAAQ;AAAA,MAChB,OAAO,OAAO,KAAK;AAAA,MACnB,kBAAkB;AAAA,IACpB,CAAC;AAED,QAAI,CAAC,SAAS;AACZ,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,kBAAkB,CAAC;AAAA,IACnE;AAEA,QAAI,QAAQ,KAAK,gBAAgB,QAAQ,KAAK,SAAS,SAAS,GAAG;AACjE,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,SAAS,sBAAsB,CAAC;AAAA,IACvE;AAEA,UAAM,eAAe,MAAM,eAAe,OAAO,KAAK,QAAQ;AAC9D,UAAM,UAAU,aAAa,QAAQ,KAAK,EAAE;AAE5C,UAAM,QAAQ,OAAO,aAAa;AAAA,MAChC,QAAQ,OAAO,kBAAkB,WAAW;AAAA,QAC1C,OAAO,EAAE,YAAY,QAAQ,kBAAkB,WAAW;AAAA,MAC5D,CAAC;AAAA,MACD,QAAQ,OAAO,QAAQ,OAAO;AAAA,QAC5B,MAAM;AAAA,MACR,CAAC;AAAA,MACD,QAAQ,OAAO,KAAK,OAAO;AAAA,QACzB,OAAO,EAAE,IAAI,QAAQ,KAAK,GAAG;AAAA,QAC7B,MAAM;AAAA,UACJ,MAAM,OAAO,KAAK;AAAA,UAClB;AAAA,UACA,eAAe,QAAQ,KAAK,iBAAiB,oBAAI,KAAK;AAAA,QACxD;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,uBAAmB,KAAK,OAAO;AAC/B,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1C,CAAC;AAED,UAAQ,IAAI,KAAK,GAAG,eAAe,WAAW,OAAO,KAAK,QAAQ;AAChE,UAAM,QAAQ,QAAQ,oBAAoB,IAAI,QAAQ,MAAM;AAE5D,QAAI,OAAO;AACT,YAAM,QAAQ,OAAO,QAAQ,WAAW,EAAE,OAAO,EAAE,cAAc,MAAM,EAAE,CAAC;AAAA,IAC5E;AAEA,UAAM,qBAAqB;AAAA,MACzB,QAAQ;AAAA,MACR,GAAI,QAAQ,2BAA2B,CAAC;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,eAAW,cAAc,oBAAoB;AAC3C,UAAI,YAAY,YAAY,EAAE,MAAM,IAAI,CAAC;AAAA,IAC3C;AAEA,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1C,CAAC;AAED,UAAQ,IAAI,IAAI,QAAQ,QAAQ,gBAAgB,OAAO,KAAK,QAAQ;AAClE,QAAI,KAAK,EAAE,MAAO,IAA+B,SAAS,CAAC;AAAA,EAC7D,CAAC;AACH;","names":["createHash","randomBytes","z","createHash","randomBytes","z"]} \ No newline at end of file +{"version":3,"sources":["../../server/module.ts","../../server/invites.ts","../../server/routes.ts"],"sourcesContent":["import { ExpressAuth } from \"@auth/express\";\nimport Credentials from \"@auth/express/providers/credentials\";\nimport Google from \"@auth/express/providers/google\";\nimport Slack from \"@auth/express/providers/slack\";\nimport { PrismaAdapter } from \"@auth/prisma-adapter\";\nimport type { Request, RequestHandler } from \"express\";\nimport { z } from \"zod\";\n\ntype CredentialUser = {\n id: string;\n name: string | null;\n email: string | null;\n image?: string | null;\n passwordHash: string | null;\n};\n\ntype CreateAuthModuleOptions = {\n prisma: any;\n clientUrl: string;\n sessionCookieName: string;\n sessionCookieSecure: boolean;\n authUrl?: string;\n authDebug?: boolean;\n authSecret?: string;\n trustHost?: boolean;\n extraSessionCookieNames?: string[];\n signInPath?: string;\n authenticatedRedirectPath?: string;\n googleClientId?: string;\n googleClientSecret?: string;\n slackClientId?: string;\n slackClientSecret?: string;\n findCredentialsUserByEmail: (email: string) => Promise;\n comparePassword: (password: string, passwordHash: string) => Promise;\n sessionUserSelect: Record;\n mapSessionUser: (user: any) => TAuthUser;\n onSessionValidated?: (user: TAuthUser) => Promise | void;\n};\n\nfunction parseBoolean(value: string | undefined, fallback: boolean): boolean {\n if (value === undefined) {\n return fallback;\n }\n const normalized = value.trim().toLowerCase();\n if ([\"1\", \"true\", \"yes\", \"on\"].includes(normalized)) {\n return true;\n }\n if ([\"0\", \"false\", \"no\", \"off\"].includes(normalized)) {\n return false;\n }\n return fallback;\n}\n\nexport function createAuthModule(options: CreateAuthModuleOptions) {\n const signInPath = options.signInPath ?? \"/login\";\n const authenticatedRedirectPath = options.authenticatedRedirectPath ?? \"/chat\";\n const googleAuthEnabled = Boolean(options.googleClientId && options.googleClientSecret);\n const slackAuthEnabled = Boolean(options.slackClientId && options.slackClientSecret);\n\n const providers: any[] = [\n Credentials({\n name: \"Email et mot de passe\",\n credentials: {\n email: { label: \"Email\", type: \"email\" },\n password: { label: \"Password\", type: \"password\" }\n },\n authorize: async (rawCredentials) => {\n const parsed = z\n .object({\n email: z.string().email(),\n password: z.string().min(8)\n })\n .safeParse(rawCredentials);\n\n if (!parsed.success) {\n return null;\n }\n\n const user = await options.findCredentialsUserByEmail(parsed.data.email);\n if (!user?.passwordHash) {\n return null;\n }\n\n const valid = await options.comparePassword(parsed.data.password, user.passwordHash);\n if (!valid) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n email: user.email,\n image: user.image ?? null\n };\n }\n })\n ];\n\n if (googleAuthEnabled) {\n providers.push(\n Google({\n clientId: options.googleClientId!,\n clientSecret: options.googleClientSecret!,\n authorization: {\n params: {\n prompt: \"select_account\"\n }\n },\n allowDangerousEmailAccountLinking: true\n })\n );\n }\n\n if (slackAuthEnabled) {\n providers.push(\n Slack({\n clientId: options.slackClientId!,\n clientSecret: options.slackClientSecret!,\n allowDangerousEmailAccountLinking: true\n })\n );\n }\n\n const authConfig = {\n adapter: PrismaAdapter(options.prisma),\n trustHost: options.trustHost ?? parseBoolean(process.env.AUTH_TRUST_HOST, true),\n debug: options.authDebug ?? parseBoolean(process.env.AUTH_DEBUG, false),\n logger: options.authDebug\n ? {\n error(error: Error) {\n console.error(\"[authjs:error]\", error.name, error.message, error.cause ?? \"\");\n },\n warn(code: string) {\n console.warn(\"[authjs:warn]\", code);\n },\n debug(message: string, metadata?: unknown) {\n console.log(\"[authjs:debug]\", message, metadata ?? \"\");\n }\n }\n : undefined,\n session: { strategy: \"database\" as const },\n secret: options.authSecret ?? process.env.AUTH_SECRET,\n cookies: {\n sessionToken: {\n name: options.sessionCookieName,\n options: {\n httpOnly: true,\n sameSite: \"lax\" as const,\n path: \"/\",\n secure: options.sessionCookieSecure\n }\n }\n },\n providers,\n pages: {\n signIn: signInPath\n },\n callbacks: {\n redirect: async ({ url, baseUrl }: { url: string; baseUrl: string }) => {\n const clientOrigin = new URL(options.clientUrl).origin;\n const successUrl = new URL(authenticatedRedirectPath, clientOrigin).toString();\n\n const shouldForceChat = (pathname: string, searchParams: URLSearchParams): boolean => {\n if (pathname !== \"/\" && pathname !== signInPath) {\n return false;\n }\n return !searchParams.has(\"error\");\n };\n\n if (url.startsWith(\"/\")) {\n const relative = new URL(url, clientOrigin);\n if (shouldForceChat(relative.pathname, relative.searchParams)) {\n return successUrl;\n }\n return `${clientOrigin}${relative.pathname}${relative.search}${relative.hash}`;\n }\n\n try {\n const target = new URL(url);\n const base = new URL(baseUrl);\n\n if (target.origin === clientOrigin) {\n if (shouldForceChat(target.pathname, target.searchParams)) {\n return successUrl;\n }\n return target.toString();\n }\n\n if (target.origin === base.origin) {\n if (shouldForceChat(target.pathname, target.searchParams)) {\n return successUrl;\n }\n return `${clientOrigin}${target.pathname}${target.search}${target.hash}`;\n }\n } catch {\n return successUrl;\n }\n\n return successUrl;\n }\n }\n };\n\n const authHandler = ExpressAuth(authConfig);\n\n const requireSession: RequestHandler = async (req, res, next) => {\n const token = extractSessionToken(req.headers.cookie);\n const authDebug = options.authDebug ?? parseBoolean(process.env.AUTH_DEBUG, false);\n\n if (!token) {\n const payload: { error: string; reason?: string } = { error: \"Unauthorized\" };\n if (authDebug) {\n payload.reason = \"missing_session_cookie\";\n }\n return res.status(401).json(payload);\n }\n\n const session = await options.prisma.session.findUnique({\n where: { sessionToken: token },\n include: {\n user: {\n select: options.sessionUserSelect\n }\n }\n });\n\n if (!session || session.expires <= new Date()) {\n const payload: { error: string; reason?: string } = { error: \"Unauthorized\" };\n if (authDebug) {\n payload.reason = !session ? \"session_not_found\" : \"session_expired\";\n }\n return res.status(401).json(payload);\n }\n\n const authUser = options.mapSessionUser(session.user);\n (req as Request & { authUser?: TAuthUser }).authUser = authUser;\n await options.onSessionValidated?.(authUser);\n next();\n };\n\n const extractSessionToken = (cookieHeader: string | undefined): string | null => {\n if (!cookieHeader) {\n return null;\n }\n\n const cookies = cookieHeader\n .split(\";\")\n .map((part) => part.trim())\n .map((part) => {\n const index = part.indexOf(\"=\");\n if (index < 0) {\n return null;\n }\n return [part.slice(0, index), decodeURIComponent(part.slice(index + 1))] as const;\n })\n .filter((entry): entry is readonly [string, string] => entry !== null);\n\n const possibleNames = [\n options.sessionCookieName,\n ...(options.extraSessionCookieNames ?? []),\n \"__Secure-authjs.session-token\",\n \"authjs.session-token\",\n \"__Secure-next-auth.session-token\",\n \"next-auth.session-token\"\n ];\n\n for (const name of possibleNames) {\n const exact = cookies.find(([cookieName]) => cookieName === name);\n if (exact) {\n return exact[1];\n }\n\n const chunks = cookies\n .filter(([cookieName]) => cookieName.startsWith(`${name}.`))\n .map(([cookieName, value]) => {\n const suffix = cookieName.slice(name.length + 1);\n return [Number.parseInt(suffix, 10), value] as const;\n })\n .filter(([index]) => Number.isInteger(index))\n .sort((left, right) => left[0] - right[0]);\n\n if (chunks.length > 0) {\n return chunks.map(([, value]) => value).join(\"\");\n }\n }\n\n return null;\n };\n\n return {\n authConfig,\n authHandler,\n requireSession,\n extractSessionToken,\n googleAuthEnabled,\n slackAuthEnabled\n };\n}\n","import { createHash, randomBytes } from \"node:crypto\";\n\ntype AccountInviteContext = {\n verificationToken: { identifier: string; expires: Date };\n user: {\n id: string;\n email: string | null;\n name: string | null;\n passwordHash: string | null;\n emailVerified: Date | null;\n accounts: Array<{ id: string }>;\n };\n};\n\ntype AccountInviteOptions = {\n prisma: any;\n tokenTtlMs?: number;\n identifierPrefix?: string;\n};\n\nconst DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX = \"account-invite:\";\nconst DEFAULT_ACCOUNT_INVITE_TOKEN_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\nfunction hashAccountInviteToken(token: string): string {\n return createHash(\"sha256\").update(token).digest(\"hex\");\n}\n\nfunction buildAccountInviteIdentifier(prefix: string, userId: string): string {\n return `${prefix}${userId}`;\n}\n\nexport async function createAccountInviteToken(\n options: AccountInviteOptions & { userId: string }\n): Promise<{ token: string; expiresAt: Date }> {\n const identifierPrefix = options.identifierPrefix ?? DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX;\n const identifier = buildAccountInviteIdentifier(identifierPrefix, options.userId);\n const token = randomBytes(32).toString(\"hex\");\n const expiresAt = new Date(Date.now() + (options.tokenTtlMs ?? DEFAULT_ACCOUNT_INVITE_TOKEN_TTL_MS));\n\n await options.prisma.verificationToken.deleteMany({\n where: {\n OR: [{ identifier }, { expires: { lt: new Date() } }]\n }\n });\n\n await options.prisma.verificationToken.create({\n data: {\n identifier,\n token: hashAccountInviteToken(token),\n expires: expiresAt\n }\n });\n\n return { token, expiresAt };\n}\n\nexport async function getAccountInviteContext(\n options: AccountInviteOptions & { token: string }\n): Promise {\n const identifierPrefix = options.identifierPrefix ?? DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX;\n const verificationToken = await options.prisma.verificationToken.findUnique({\n where: { token: hashAccountInviteToken(options.token) },\n select: { identifier: true, expires: true }\n });\n\n if (\n !verificationToken ||\n verificationToken.expires <= new Date() ||\n !verificationToken.identifier.startsWith(identifierPrefix)\n ) {\n return null;\n }\n\n const userId = verificationToken.identifier.slice(identifierPrefix.length);\n if (!userId) {\n return null;\n }\n\n const user = await options.prisma.user.findUnique({\n where: { id: userId },\n select: {\n id: true,\n email: true,\n name: true,\n passwordHash: true,\n emailVerified: true,\n accounts: {\n select: { id: true },\n take: 1\n }\n }\n });\n\n if (!user?.email) {\n return null;\n }\n\n return {\n verificationToken,\n user\n };\n}\n\nexport {\n DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX,\n DEFAULT_ACCOUNT_INVITE_TOKEN_TTL_MS,\n buildAccountInviteIdentifier,\n hashAccountInviteToken\n};\n","import { createHash, randomBytes } from \"node:crypto\";\nimport type { Express, RequestHandler } from \"express\";\nimport { z } from \"zod\";\nimport { DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX, getAccountInviteContext } from \"./invites.js\";\n\ntype RegisterAuthApiRoutesOptions = {\n app: Express;\n prisma: any;\n authHandler: RequestHandler;\n requireSession: RequestHandler;\n extractSessionToken: (cookieHeader: string | undefined) => string | null;\n providersAvailability: Record;\n sessionCookieName: string;\n sessionCookieSecure: boolean;\n extraCookieNamesToClear?: string[];\n messages?: Partial;\n authBasePath?: string;\n authApiBasePath?: string;\n mePath?: string;\n normalizeEmail?: (email: string) => string;\n passwordHasher?: (password: string) => Promise;\n passwordComparator?: (password: string, passwordHash: string) => Promise;\n passwordReset?: {\n enabled: boolean;\n tokenTtlMs?: number;\n identifierPrefix?: string;\n buildResetUrl: (token: string) => string;\n sendMessage: (input: {\n user: { id: string; email: string; name: string | null; passwordHash: string | null };\n resetUrl: string;\n isPasswordCreation: boolean;\n expiresAt: Date;\n }) => Promise;\n };\n accountInvite?: {\n enabled: boolean;\n identifierPrefix?: string;\n };\n onUserRegistered?: (user: { id: string; email: string | null; name: string | null }) => Promise | void;\n onPasswordResetConfirmed?: (user: { id: string; email: string | null; name: string | null }) => Promise | void;\n};\n\ntype AuthRouteMessages = {\n invalidPayload: string;\n emailAlreadyUsed: string;\n accountNotFound: string;\n externalAccountOnly: string;\n invalidPassword: string;\n passwordResetUnavailable: string;\n invalidResetLink: string;\n expiredResetLink: string;\n invalidInviteLink: string;\n inviteAlreadyAccepted: string;\n};\n\nconst defaultNormalizeEmail = (email: string) => email.trim();\nconst defaultPasswordResetIdentifierPrefix = \"password-reset:\";\nconst defaultMessages: AuthRouteMessages = {\n invalidPayload: \"Invalid payload\",\n emailAlreadyUsed: \"Email already used\",\n accountNotFound: \"Account not found\",\n externalAccountOnly: \"This account uses an external sign-in provider.\",\n invalidPassword: \"Invalid password\",\n passwordResetUnavailable: \"Email service is not configured.\",\n invalidResetLink: \"Invalid reset link\",\n expiredResetLink: \"Invalid or expired reset link\",\n invalidInviteLink: \"Invalid or expired invite link\",\n inviteAlreadyAccepted: \"This invite has already been accepted\"\n};\n\nfunction hashPasswordResetToken(token: string): string {\n return createHash(\"sha256\").update(token).digest(\"hex\");\n}\n\nfunction buildPasswordResetIdentifier(prefix: string, userId: string): string {\n return `${prefix}${userId}`;\n}\n\nexport function registerAuthApiRoutes(options: RegisterAuthApiRoutesOptions): void {\n const authBasePath = options.authBasePath ?? \"/auth\";\n const authApiBasePath = options.authApiBasePath ?? \"/api/auth\";\n const mePath = options.mePath ?? \"/api/me\";\n const normalizeEmail = options.normalizeEmail ?? defaultNormalizeEmail;\n const passwordHasher = options.passwordHasher ?? ((password: string) => Promise.resolve(password));\n const passwordComparator = options.passwordComparator ?? ((password: string, hash: string) => Promise.resolve(password === hash));\n const passwordResetIdentifierPrefix = options.passwordReset?.identifierPrefix ?? defaultPasswordResetIdentifierPrefix;\n const accountInviteIdentifierPrefix = options.accountInvite?.identifierPrefix ?? DEFAULT_ACCOUNT_INVITE_IDENTIFIER_PREFIX;\n const messages = { ...defaultMessages, ...(options.messages ?? {}) };\n\n const buildSession = (userId: string) => ({\n sessionToken: randomBytes(32).toString(\"hex\"),\n userId,\n expires: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)\n });\n\n const applySessionCookie = (res: any, session: { sessionToken: string; expires: Date }) => {\n res.cookie(options.sessionCookieName, session.sessionToken, {\n httpOnly: true,\n sameSite: \"lax\",\n secure: options.sessionCookieSecure,\n path: \"/\",\n expires: session.expires\n });\n };\n\n const findUserByEmail = async (email: string) => {\n const normalized = normalizeEmail(email);\n const lowered = normalized.toLowerCase();\n\n return options.prisma.user.findFirst({\n where: {\n OR: lowered === normalized ? [{ email: normalized }] : [{ email: normalized }, { email: lowered }]\n },\n select: {\n id: true,\n email: true,\n name: true,\n image: true,\n passwordHash: true,\n emailVerified: true\n }\n });\n };\n\n const getPasswordResetContext = async (\n rawToken: string\n ): Promise<\n | {\n verificationToken: { identifier: string; expires: Date };\n user: { id: string; email: string | null; name: string | null; passwordHash: string | null; emailVerified: Date | null };\n }\n | null\n > => {\n const verificationToken = await options.prisma.verificationToken.findUnique({\n where: { token: hashPasswordResetToken(rawToken) },\n select: { identifier: true, expires: true }\n });\n\n if (\n !verificationToken ||\n verificationToken.expires <= new Date() ||\n !verificationToken.identifier.startsWith(passwordResetIdentifierPrefix)\n ) {\n return null;\n }\n\n const userId = verificationToken.identifier.slice(passwordResetIdentifierPrefix.length);\n if (!userId) {\n return null;\n }\n\n const user = await options.prisma.user.findUnique({\n where: { id: userId },\n select: {\n id: true,\n email: true,\n name: true,\n passwordHash: true,\n emailVerified: true\n }\n });\n\n if (!user?.email) {\n return null;\n }\n\n return { verificationToken, user };\n };\n\n options.app.use(authBasePath, options.authHandler);\n\n options.app.get(`${authApiBasePath}/providers`, (_req, res) => {\n res.json(options.providersAvailability);\n });\n\n options.app.post(`${authApiBasePath}/register`, async (req, res) => {\n const parsed = z\n .object({\n name: z.string().min(2).max(60),\n email: z.string().email(),\n password: z.string().min(8)\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n const email = normalizeEmail(parsed.data.email);\n const exists = await findUserByEmail(email);\n if (exists) {\n return res.status(409).json({ error: messages.emailAlreadyUsed });\n }\n\n const passwordHash = await passwordHasher(parsed.data.password);\n const created = await options.prisma.user.create({\n data: {\n name: parsed.data.name,\n email,\n passwordHash\n },\n select: { id: true, email: true, name: true }\n });\n\n await options.onUserRegistered?.(created);\n return res.status(201).json(created);\n });\n\n options.app.post(`${authApiBasePath}/login`, async (req, res) => {\n const parsed = z\n .object({\n email: z.string().email(),\n password: z.string().min(8)\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n const email = normalizeEmail(parsed.data.email);\n const user = await findUserByEmail(email);\n if (!user) {\n return res.status(404).json({ error: messages.accountNotFound });\n }\n\n if (!user.passwordHash) {\n return res.status(400).json({ error: messages.externalAccountOnly });\n }\n\n const valid = await passwordComparator(parsed.data.password, user.passwordHash);\n if (!valid) {\n return res.status(401).json({ error: messages.invalidPassword });\n }\n\n const session = buildSession(user.id);\n await options.prisma.session.create({\n data: session\n });\n applySessionCookie(res, session);\n\n return res.status(200).json({ ok: true });\n });\n\n options.app.post(`${authApiBasePath}/password-reset/request`, async (req, res) => {\n const parsed = z\n .object({\n email: z.string().email()\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n if (!options.passwordReset?.enabled) {\n return res.status(503).json({ error: messages.passwordResetUnavailable });\n }\n\n const email = normalizeEmail(parsed.data.email);\n const user = await findUserByEmail(email);\n if (!user?.email) {\n return res.status(200).json({ ok: true });\n }\n\n const rawToken = randomBytes(32).toString(\"hex\");\n const identifier = buildPasswordResetIdentifier(passwordResetIdentifierPrefix, user.id);\n const expiresAt = new Date(Date.now() + (options.passwordReset.tokenTtlMs ?? 2 * 60 * 60 * 1000));\n const resetUrl = options.passwordReset.buildResetUrl(rawToken);\n const isPasswordCreation = !user.passwordHash;\n\n await options.prisma.verificationToken.deleteMany({\n where: {\n OR: [{ identifier }, { expires: { lt: new Date() } }]\n }\n });\n\n await options.prisma.verificationToken.create({\n data: {\n identifier,\n token: hashPasswordResetToken(rawToken),\n expires: expiresAt\n }\n });\n\n await options.passwordReset.sendMessage({\n user: {\n id: user.id,\n email: user.email,\n name: user.name,\n passwordHash: user.passwordHash\n },\n resetUrl,\n isPasswordCreation,\n expiresAt\n });\n\n return res.status(200).json({ ok: true });\n });\n\n options.app.get(`${authApiBasePath}/password-reset/validate`, async (req, res) => {\n if (!options.passwordReset?.enabled) {\n return res.status(400).json({ error: messages.expiredResetLink });\n }\n\n const parsed = z.object({ token: z.string().min(1) }).safeParse({\n token: Array.isArray(req.query.token) ? req.query.token[0] : req.query.token\n });\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidResetLink });\n }\n\n const context = await getPasswordResetContext(parsed.data.token);\n if (!context) {\n return res.status(400).json({ error: messages.expiredResetLink });\n }\n\n return res.status(200).json({\n ok: true,\n email: context.user.email,\n mode: context.user.passwordHash ? \"reset\" : \"create\"\n });\n });\n\n options.app.post(`${authApiBasePath}/password-reset/confirm`, async (req, res) => {\n if (!options.passwordReset?.enabled) {\n return res.status(400).json({ error: messages.expiredResetLink });\n }\n\n const parsed = z\n .object({\n token: z.string().min(1),\n password: z.string().min(8)\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n const context = await getPasswordResetContext(parsed.data.token);\n if (!context) {\n return res.status(400).json({ error: messages.expiredResetLink });\n }\n\n const passwordHash = await passwordHasher(parsed.data.password);\n await options.prisma.$transaction([\n options.prisma.verificationToken.deleteMany({\n where: { identifier: context.verificationToken.identifier }\n }),\n options.prisma.session.deleteMany({\n where: { userId: context.user.id }\n }),\n options.prisma.user.update({\n where: { id: context.user.id },\n data: {\n passwordHash,\n emailVerified: context.user.emailVerified ?? new Date()\n }\n })\n ]);\n\n await options.onPasswordResetConfirmed?.(context.user);\n return res.status(200).json({ ok: true });\n });\n\n options.app.get(`${authApiBasePath}/invite/validate`, async (req, res) => {\n if (!options.accountInvite?.enabled) {\n return res.status(404).json({ error: messages.invalidInviteLink });\n }\n\n const parsed = z.object({ token: z.string().min(1) }).safeParse({\n token: Array.isArray(req.query.token) ? req.query.token[0] : req.query.token\n });\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidInviteLink });\n }\n\n const context = await getAccountInviteContext({\n prisma: options.prisma,\n token: parsed.data.token,\n identifierPrefix: accountInviteIdentifierPrefix\n });\n\n if (!context) {\n return res.status(400).json({ error: messages.invalidInviteLink });\n }\n\n if (context.user.passwordHash || context.user.accounts.length > 0) {\n return res.status(409).json({ error: messages.inviteAlreadyAccepted });\n }\n\n return res.status(200).json({\n ok: true,\n email: context.user.email,\n name: context.user.name\n });\n });\n\n options.app.post(`${authApiBasePath}/invite/accept`, async (req, res) => {\n if (!options.accountInvite?.enabled) {\n return res.status(404).json({ error: messages.invalidInviteLink });\n }\n\n const parsed = z\n .object({\n token: z.string().min(1),\n name: z.string().min(2).max(60),\n password: z.string().min(8)\n })\n .safeParse(req.body);\n\n if (!parsed.success) {\n return res.status(400).json({ error: messages.invalidPayload });\n }\n\n const context = await getAccountInviteContext({\n prisma: options.prisma,\n token: parsed.data.token,\n identifierPrefix: accountInviteIdentifierPrefix\n });\n\n if (!context) {\n return res.status(400).json({ error: messages.invalidInviteLink });\n }\n\n if (context.user.passwordHash || context.user.accounts.length > 0) {\n return res.status(409).json({ error: messages.inviteAlreadyAccepted });\n }\n\n const passwordHash = await passwordHasher(parsed.data.password);\n const session = buildSession(context.user.id);\n\n await options.prisma.$transaction([\n options.prisma.verificationToken.deleteMany({\n where: { identifier: context.verificationToken.identifier }\n }),\n options.prisma.session.create({\n data: session\n }),\n options.prisma.user.update({\n where: { id: context.user.id },\n data: {\n name: parsed.data.name,\n passwordHash,\n emailVerified: context.user.emailVerified ?? new Date()\n }\n })\n ]);\n\n applySessionCookie(res, session);\n return res.status(200).json({ ok: true });\n });\n\n options.app.post(`${authApiBasePath}/logout`, async (req, res) => {\n const token = options.extractSessionToken(req.headers.cookie);\n\n if (token) {\n await options.prisma.session.deleteMany({ where: { sessionToken: token } });\n }\n\n const cookieNamesToClear = [\n options.sessionCookieName,\n ...(options.extraCookieNamesToClear ?? []),\n \"authjs.session-token\",\n \"__Secure-authjs.session-token\",\n \"next-auth.session-token\",\n \"__Secure-next-auth.session-token\"\n ];\n\n for (const cookieName of cookieNamesToClear) {\n res.clearCookie(cookieName, { path: \"/\" });\n }\n\n return res.status(200).json({ ok: true });\n });\n\n options.app.get(mePath, options.requireSession, async (req, res) => {\n const authUser = (req as { authUser?: { id?: unknown } }).authUser;\n\n if (typeof authUser?.id === \"string\") {\n try {\n await options.prisma.user.update({\n where: { id: authUser.id },\n data: { lastConnectionAt: new Date() }\n });\n } catch {\n // Ignore when the consumer schema does not expose lastConnectionAt.\n }\n }\n\n res.json({ user: authUser });\n });\n}\n"],"mappings":"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","names":["createHash","randomBytes","z","createHash","randomBytes","z"]} \ No newline at end of file diff --git a/server/routes.ts b/server/routes.ts index 693aaf4..472b2e2 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -478,6 +478,19 @@ export function registerAuthApiRoutes(options: RegisterAuthApiRoutesOptions): vo }); options.app.get(mePath, options.requireSession, async (req, res) => { - res.json({ user: (req as { authUser?: unknown }).authUser }); + const authUser = (req as { authUser?: { id?: unknown } }).authUser; + + if (typeof authUser?.id === "string") { + try { + await options.prisma.user.update({ + where: { id: authUser.id }, + data: { lastConnectionAt: new Date() } + }); + } catch { + // Ignore when the consumer schema does not expose lastConnectionAt. + } + } + + res.json({ user: authUser }); }); }