import { Router, type Request, type Response } from 'express'; import { z } from 'zod'; import { createLogger } from '../lib/logger.js'; import { getTripStore } from '../lib/tripStore.js'; const log = createLogger('trips-api'); const router = Router(); const TripBodySchema = z.object({ title: z.string().min(1).max(200), vehicleModel: z.string().min(1).max(120), rangeMi: z.number().int().nonnegative(), itinerary: z.unknown().transform((v) => v ?? null), status: z.string().max(40).optional(), isPublic: z.boolean().optional(), }); const TripPatchSchema = TripBodySchema.partial(); const ANONYMOUS_USER_ID = 'anonymous'; function resolveUserId(req: Request): string { return req.auth?.userId ?? ANONYMOUS_USER_ID; } router.get('/', async (req, res) => { const userId = resolveUserId(req); const trips = await getTripStore().list(userId); res.json({ trips }); }); router.get('/:id', async (req, res) => { const userId = resolveUserId(req); const trip = await getTripStore().get(String(req.params.id), userId); if (!trip) return res.status(404).json({ error: 'Trip not found' }); res.json(trip); }); router.post('/', async (req, res) => { const parsed = TripBodySchema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ error: 'Invalid trip', issues: parsed.error.format() }); } const userId = resolveUserId(req); const trip = await getTripStore().create({ ...parsed.data, userId, status: parsed.data.status ?? 'planning', isPublic: parsed.data.isPublic ?? false, }); log.info({ tripId: trip.id, userId }, 'Trip created'); res.status(201).json(trip); }); router.patch('/:id', async (req, res) => { const parsed = TripPatchSchema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ error: 'Invalid trip patch', issues: parsed.error.format() }); } const userId = resolveUserId(req); const trip = await getTripStore().update(String(req.params.id), userId, parsed.data); if (!trip) return res.status(404).json({ error: 'Trip not found' }); res.json(trip); }); router.delete('/:id', async (req: Request, res: Response) => { const userId = resolveUserId(req); const removed = await getTripStore().remove(String(req.params.id), userId); if (!removed) return res.status(404).json({ error: 'Trip not found' }); res.status(204).end(); }); export default router;