if (process.env.NODE_ENV !== "test") require("server-only"); import getPool from "@/lib/server/db"; import { createSession, getSessionTtlMs, hashPassword, hashToken, verifyPassword } from "@/lib/server/auth"; import { apiError } from "@/lib/server/errors"; export async function registerUser(input: { email: string; password: string; displayName?: string }) { const pool = getPool(); const email = input.email.trim().toLowerCase(); const existing = await pool.query("select id from users where email=$1", [email]); if (existing.rows.length > 0) apiError("EMAIL_EXISTS", { email }); const passwordHash = await hashPassword(input.password); let rows; try { const result = await pool.query( "insert into users(email, display_name, password_hash) values($1,$2,$3) returning id, email, display_name", [email, input.displayName || null, passwordHash] ); rows = result.rows; } catch (error) { if (typeof error === "object" && error && "code" in error && error.code === "23505") apiError("EMAIL_EXISTS", { email }); throw error; } const user = rows[0]; const session = await createSession(user.id); return { user: { id: user.id, email: user.email, displayName: user.display_name }, session }; } export async function loginUser(input: { email: string; password: string; remember: boolean }) { const pool = getPool(); const email = input.email.trim().toLowerCase(); const { rows } = await pool.query( "select id, email, display_name, password_hash from users where email=$1", [email] ); const user = rows[0]; if (!user) apiError("INVALID_CREDENTIALS", { email }); const ok = await verifyPassword(input.password, user.password_hash); if (!ok) apiError("INVALID_CREDENTIALS", { email }); const shortTtlMs = 24 * 60 * 60 * 1000; const session = await createSession(user.id, input.remember ? undefined : { ttlMs: shortTtlMs }); const ttlMs = input.remember ? getSessionTtlMs() : shortTtlMs; return { user: { id: user.id, email: user.email, displayName: user.display_name }, session: { ...session, ttlMs } }; } export async function logoutUser(token: string) { const pool = getPool(); await pool.query("delete from sessions where token_hash=$1", [hashToken(token)]); }