import type { FastifyInstance } from 'fastify'; import { AuthService } from '../services/auth/auth.service.js'; const registerSchema = { body: { type: 'object', required: ['email', 'password', 'nickname'], properties: { email: { type: 'string', minLength: 1 }, password: { type: 'string', minLength: 8 }, nickname: { type: 'string', minLength: 2, maxLength: 30 }, }, }, }; const loginSchema = { body: { type: 'object', required: ['email', 'password'], properties: { email: { type: 'string', minLength: 1 }, password: { type: 'string' }, }, }, }; const refreshTokenSchema = { body: { type: 'object', required: ['refreshToken'], properties: { refreshToken: { type: 'string' }, }, }, }; const logoutSchema = refreshTokenSchema; const verifyEmailSchema = { body: { type: 'object', required: ['userId', 'code'], properties: { userId: { type: 'string', minLength: 1 }, code: { type: 'string', minLength: 1, maxLength: 10 }, }, }, }; const forgotPasswordSchema = { body: { type: 'object', required: ['email'], properties: { email: { type: 'string', minLength: 1 }, }, }, }; const resetPasswordSchema = { body: { type: 'object', required: ['token', 'newPassword'], properties: { token: { type: 'string' }, newPassword: { type: 'string', minLength: 8 }, }, }, }; export async function authRoutes(app: FastifyInstance) { const authService = new AuthService(app.db); const { rateLimitOptions } = app; app.post( '/register', { schema: registerSchema, config: { rateLimit: rateLimitOptions.register } }, async (req, reply) => { const body = req.body as { email: string; password: string; nickname: string }; const { userId, verificationCode } = await authService.register(body); return reply.status(201).send({ userId, message: 'Registration successful. Please verify your email.', verificationCode, }); }, ); app.post( '/login', { schema: loginSchema, config: { rateLimit: rateLimitOptions.login } }, async (req, reply) => { const body = req.body as { email: string; password: string }; const userAgent = req.headers['user-agent']; const ipAddress = req.ip; const result = await authService.login({ email: body.email, password: body.password, userAgent, ipAddress, }); return reply.send(result); }, ); app.post( '/logout', { schema: logoutSchema, config: { rateLimit: rateLimitOptions.apiGuest } }, async (req, reply) => { const body = req.body as { refreshToken: string }; await authService.logout(body.refreshToken); return reply.status(204).send(); }, ); app.post( '/refresh', { schema: refreshTokenSchema, config: { rateLimit: rateLimitOptions.apiGuest } }, async (req, reply) => { const body = req.body as { refreshToken: string }; const userAgent = req.headers['user-agent']; const ipAddress = req.ip; const result = await authService.refresh({ refreshToken: body.refreshToken, userAgent, ipAddress, }); return reply.send(result); }, ); app.post( '/verify-email', { schema: verifyEmailSchema, config: { rateLimit: rateLimitOptions.verifyEmail } }, async (req, reply) => { const body = req.body as { userId: string; code: string }; await authService.verifyEmail(body.userId, body.code); return reply.send({ message: 'Email verified successfully' }); }, ); app.post( '/forgot-password', { schema: forgotPasswordSchema, config: { rateLimit: rateLimitOptions.forgotPassword } }, async (req, reply) => { const body = req.body as { email: string }; await authService.forgotPassword(body.email); return reply.send({ message: 'If the email exists, a reset link has been sent.', }); }, ); app.post( '/reset-password', { schema: resetPasswordSchema, config: { rateLimit: rateLimitOptions.forgotPassword } }, async (req, reply) => { const body = req.body as { token: string; newPassword: string }; await authService.resetPassword(body.token, body.newPassword); return reply.send({ message: 'Password reset successfully' }); }, ); }