Spaces:
Sleeping
Sleeping
| import express, { Express, Request, Response, NextFunction } from 'express'; | |
| import { config } from '../config'; | |
| import { logger } from '../utils/logger'; | |
| import healthRouter from './routes/health'; | |
| import submitRouter from './routes/submit'; | |
| import internalRouter from './routes/internal'; | |
| import reportsRouter from './routes/reports'; | |
| import accountsRouter from './routes/accounts'; | |
| import adminUsersRouter from './routes/admin-users'; | |
| /** | |
| * Create and configure the Express application with all routes and middleware. | |
| */ | |
| export function createApp(): Express { | |
| const app = express(); | |
| app.disable('x-powered-by'); | |
| app.use((req: Request, res: Response, next: NextFunction) => { | |
| const origin = req.headers.origin; | |
| const allowOrigin = | |
| origin && | |
| (config.allowedOrigins.length === 0 || config.allowedOrigins.includes(origin)); | |
| if (allowOrigin) { | |
| res.setHeader('Access-Control-Allow-Origin', origin); | |
| res.setHeader('Vary', 'Origin'); | |
| } | |
| res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS'); | |
| res.setHeader('Access-Control-Allow-Headers', 'Authorization,Content-Type,Idempotency-Key,X-Admin-Secret'); | |
| res.setHeader('Access-Control-Max-Age', '86400'); | |
| res.setHeader('X-Content-Type-Options', 'nosniff'); | |
| res.setHeader('Referrer-Policy', 'no-referrer'); | |
| if (req.method === 'OPTIONS') { | |
| res.status(204).end(); | |
| return; | |
| } | |
| next(); | |
| }); | |
| // --- Body parsers --- | |
| app.use(express.json({ limit: '1mb' })); | |
| // --- Routes --- | |
| app.use(healthRouter); | |
| app.use(submitRouter); | |
| app.use(reportsRouter); | |
| app.use(accountsRouter); | |
| app.use(adminUsersRouter); | |
| app.use(internalRouter); | |
| app.use((req: Request, res: Response) => { | |
| res.status(404).json({ error: 'Not found' }); | |
| }); | |
| // --- Global error handler --- | |
| app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => { | |
| logger.error('Unhandled server error', { | |
| error: err.message, | |
| stack: err.stack, | |
| }); | |
| res.status(500).json({ error: 'Internal server error' }); | |
| }); | |
| return app; | |
| } | |