// User service import { db } from "./db"; import type { AuthUser, UserRole, RegisterRequest } from "../types/auth"; interface UserRow { id: string; email: string; password_hash: string; role: string; created_at: string; updated_at: string; } function rowToUser(row: UserRow): AuthUser & { passwordHash: string } { return { id: row.id, email: row.email, passwordHash: row.password_hash, role: row.role as UserRole, createdAt: new Date(row.created_at), updatedAt: new Date(row.updated_at), }; } export async function hashPassword(password: string): Promise { return await Bun.password.hash(password, { algorithm: "argon2id", memoryCost: 65536, timeCost: 2, }); } export async function verifyPassword( password: string, hash: string ): Promise { return await Bun.password.verify(password, hash); } export async function findUserByEmail( email: string ): Promise<(AuthUser & { passwordHash: string }) | null> { const row = db.query("SELECT * FROM users WHERE email = ?").get(email.toLowerCase()) as UserRow | null; return row ? rowToUser(row) : null; } export async function findUserById(id: string): Promise { const row = db.query("SELECT * FROM users WHERE id = ?").get(id) as UserRow | null; if (!row) return null; const user = rowToUser(row); const { passwordHash, ...userWithoutPassword } = user; return userWithoutPassword; } export async function createUser( data: RegisterRequest ): Promise<{ user: AuthUser; error?: never } | { user?: never; error: string }> { const email = data.email.toLowerCase().trim(); const existing = db.query("SELECT id FROM users WHERE email = ?").get(email); if (existing) { return { error: "User with this email already exists" }; } const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { return { error: "Invalid email format" }; } if (data.password.length < 8) { return { error: "Password must be at least 8 characters long" }; } const passwordHash = await hashPassword(data.password); const now = new Date().toISOString(); const userId = crypto.randomUUID(); db.prepare(` INSERT INTO users (id, email, password_hash, role, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?) `).run(userId, email, passwordHash, "user", now, now); return { user: { id: userId, email, role: "user" as UserRole, createdAt: new Date(now), updatedAt: new Date(now), }, }; } export async function authenticateUser( email: string, password: string ): Promise<{ user: AuthUser; error?: never } | { user?: never; error: string }> { const user = await findUserByEmail(email); if (!user) { return { error: "Invalid email or password" }; } const isValidPassword = await verifyPassword(password, user.passwordHash); if (!isValidPassword) { return { error: "Invalid email or password" }; } const { passwordHash, ...userWithoutPassword } = user; return { user: userWithoutPassword }; }