import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; import { compare as bcryptCompare } from 'bcryptjs'; interface LoginBody { username: string; password: string; } export async function authRoutes(fastify: FastifyInstance) { // POST /api/auth/login fastify.post<{ Body: LoginBody }>( '/login', { schema: { body: { type: 'object', required: ['username', 'password'], properties: { username: { type: 'string' }, password: { type: 'string' }, }, }, }, }, async (request: FastifyRequest<{ Body: LoginBody }>, reply: FastifyReply) => { const { username, password } = request.body; const user = await fastify.prisma.user.findUnique({ where: { username } }); if (!user) { return reply.status(401).send({ error: 'Invalid credentials' }); } const valid = await bcryptCompare(password, user.passwordHash); if (!valid) { return reply.status(401).send({ error: 'Invalid credentials' }); } const token = fastify.jwt.sign( { id: user.id, username: user.username }, { expiresIn: '12h' } ); return reply.send({ token, user: { id: user.id, username: user.username } }); } ); // GET /api/auth/me — verify token and return current user fastify.get( '/me', { preHandler: [fastify.authenticate] }, async (request: FastifyRequest, reply: FastifyReply) => { const payload = request.user as { id: string; username: string }; const user = await fastify.prisma.user.findUnique({ where: { id: payload.id } }); if (!user) return reply.status(404).send({ error: 'User not found' }); return reply.send({ id: user.id, username: user.username }); } ); }