import express, { type Request, type Response, type NextFunction } from 'express' import path from 'path' import { appConfig, isDevelopment, printConfig, validateConfig } from '../config/app' import { corsMiddleware } from '../middlewares/cors' import { errorHandler, notFoundHandler } from '../middlewares/error-handler' import routes from '../routes' interface LoggerLike { info(message: string, meta?: unknown): void error(message: string, meta?: unknown): void } function requestLoggerFactory(logger: LoggerLike) { return function requestLogger(req: Request, res: Response, next: NextFunction): void { const start = Date.now() res.on('finish', () => { const duration = Date.now() - start if (!req.path.includes('/jobs/')) { logger.info('Request completed', { method: req.method, path: req.path, status: res.statusCode, duration: `${duration}ms` }) } }) next() } } export async function initializeExpressApp(app: express.Express, logger: LoggerLike): Promise { validateConfig() printConfig() app.use(express.json({ limit: '10mb' })) app.use(express.urlencoded({ extended: true, limit: '10mb' })) app.use(corsMiddleware) app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => { if (err instanceof SyntaxError && 'body' in err) { logger.error('JSON 解析错误', { method: req.method, path: req.path, error: err.message, body: req.body }) return res.status(400).json({ error: 'Invalid JSON', message: err.message }) } next(err) }) if (isDevelopment()) { app.use(requestLoggerFactory(logger)) } app.use('/images', express.static(path.join(process.cwd(), 'public', 'images'), { fallthrough: false })) app.use('/videos', express.static(path.join(process.cwd(), 'public', 'videos'), { fallthrough: false })) app.use(express.static('public')) app.use(routes) app.get('*', (req, res) => { if (req.path.startsWith('/health') || req.path.startsWith('/api')) { return notFoundHandler(req, res, () => {}) } if (path.extname(req.path)) { return notFoundHandler(req, res, () => {}) } const indexPath = path.join(__dirname, '..', '..', 'public', 'index.html') res.sendFile(indexPath, (err) => { if (err) { return notFoundHandler(req, res, () => {}) } }) }) app.use(errorHandler) } export { appConfig }