import 'dotenv/config'; import express from 'express'; import type { Response, NextFunction } from 'express'; import cors from 'cors'; import { z } from 'zod'; import swaggerUi from 'swagger-ui-express'; import { prisma } from './src/utils/prisma.js'; import { createOpenAPIDocument } from './src/openapi/registry.js'; import requestsRouter from './src/routes/requests.routes.js'; import itemsRouter from './src/routes/items.routes.js'; import catalogRouter from './src/routes/catalog.routes.js'; // ---------- App ---------- const app = express(); app.use(cors()); app.use(express.json()); // ---------- Health Check ---------- app.get('/health', (_req, res) => res.json({ ok: true, time: new Date().toISOString() })); // ---------- Routes ---------- app.use('/api/consumable-temp-requests', requestsRouter); app.use('/api/consumable-temp-items', itemsRouter); app.use('/api/consumable-temp-catalog', catalogRouter); // ---------- OpenAPI Documentation ---------- const openApiDocument = createOpenAPIDocument(); app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openApiDocument, { customSiteTitle: '智能配送 API 文档', customCss: '.swagger-ui .topbar { display: none }', swaggerOptions: { persistAuthorization: true, displayRequestDuration: true } })); app.get('/openapi.json', (_req, res) => { res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(openApiDocument, null, 2)); }); // ---------- Error Handler ---------- // eslint-disable-next-line @typescript-eslint/no-unused-vars app.use((err: any, _req: any, res: Response, _next: NextFunction) => { if (err instanceof z.ZodError) { return res.status(400).json({ error: 'VALIDATION_ERROR', details: err.flatten() }); } if (err.message === 'NOT_FOUND') return res.status(404).json({ error: 'Not Found' }); console.error('Unhandled Error:', err); res.status(500).json({ error: 'INTERNAL_ERROR' }); }); // ---------- Start Server ---------- const PORT = Number(process.env.PORT) || 3000; app.listen(PORT, () => { console.log(`Consumable Temp Request API listening on :${PORT}`); }); // ---------- Graceful Shutdown ---------- process.on('SIGINT', async () => { await prisma.$disconnect(); process.exit(0); }); process.on('SIGTERM', async () => { await prisma.$disconnect(); process.exit(0); });