import { Router } from 'express'; import { and, eq } from 'drizzle-orm'; import { z } from 'zod'; import { db } from '../db/client'; import { users } from '../db/schema'; import { requireAuth } from '../middleware/auth'; import { signAccessToken } from '../utils/jwt'; import { hashPassword, verifyPassword } from '../utils/password'; const router = Router(); const registerSchema = z.object({ email: z.email().trim().toLowerCase(), password: z.string().min(8), name: z.string().trim().min(1).max(255), }); const loginSchema = z.object({ email: z.email().trim().toLowerCase(), password: z.string().min(1), }); router.post('/register', async (req, res) => { const parsed = registerSchema.safeParse(req.body); if (!parsed.success) { res.status(400).json({ message: 'Invalid request body', errors: parsed.error.flatten() }); return; } const { email, password, name } = parsed.data; const existingUser = await db.query.users.findFirst({ where: eq(users.email, email), }); if (existingUser) { res.status(409).json({ message: 'Email already in use' }); return; } const passwordHash = await hashPassword(password); const [newUser] = await db .insert(users) .values({ email, name, passwordHash, }) .returning({ id: users.id, email: users.email, name: users.name, createdAt: users.createdAt, }); if (!newUser) { res.status(500).json({ message: 'Failed to create user' }); return; } const token = signAccessToken({ userId: newUser.id, email: newUser.email }); res.status(201).json({ token, user: newUser }); }); router.post('/login', async (req, res) => { const parsed = loginSchema.safeParse(req.body); if (!parsed.success) { res.status(400).json({ message: 'Invalid request body', errors: parsed.error.flatten() }); return; } const { email, password } = parsed.data; const user = await db.query.users.findFirst({ where: eq(users.email, email), }); if (!user) { res.status(401).json({ message: 'Invalid email or password' }); return; } const isPasswordValid = await verifyPassword(password, user.passwordHash); if (!isPasswordValid) { res.status(401).json({ message: 'Invalid email or password' }); return; } const token = signAccessToken({ userId: user.id, email: user.email }); res.json({ token, user: { id: user.id, email: user.email, name: user.name, createdAt: user.createdAt, }, }); }); router.get('/me', requireAuth, async (req, res) => { const authenticatedUser = req.user; if (!authenticatedUser) { res.status(401).json({ message: 'Unauthorized' }); return; } const user = await db.query.users.findFirst({ where: and(eq(users.id, authenticatedUser.userId), eq(users.email, authenticatedUser.email)), columns: { id: true, email: true, name: true, createdAt: true, }, }); if (!user) { res.status(404).json({ message: 'User not found' }); return; } res.json({ user }); }); export default router;