import { serveStatic } from '@hono/node-server/serve-static'; import { Hono } from 'hono'; import { readOnlyMiddleware } from './middleware/read-only.js'; import { cors } from 'hono/cors'; import authRouter from './auth/login.js'; import { authMiddleware } from './middleware/auth.js'; import eleRouter from './routes/ele/routes.js'; import energyRouter from './routes/energy/index.js'; import feedbackRouter from './routes/feedback/routes.js'; import hydrogenHeatmapRouter from './routes/hydrogen-heatmap/routes.js'; import mileageRouter from './routes/mileage/index.js'; import schedulingRouter from './routes/scheduling/index.js'; import vehicleHeatmapRouter from './routes/vehicle-heatmap/routes.js'; import vehiclesRouter from './routes/vehicles/routes.js'; /** * 创建 HTTP 应用,但不监听端口、不访问数据库,也不启动后台任务。 * 保持应用装配无副作用后,测试可以安全导入路由而不会挂住进程。 */ export function createApp(): Hono { const app = new Hono(); app.use('/api/*', cors()); app.use('/api/*', readOnlyMiddleware); // 登录接口公开,其余 API 统一经过认证与数据权限检查。 app.route('/api/auth', authRouter); app.use('/api/*', authMiddleware); app.route('/api/vehicles', vehiclesRouter); app.route('/api/mileage', mileageRouter); app.route('/api/scheduling', schedulingRouter); app.route('/api/energy', energyRouter); app.route('/api/ele', eleRouter); app.route('/api/feedback', feedbackRouter); app.route('/api/vehicle-heatmap', vehicleHeatmapRouter); app.route('/api/hydrogen-heatmap', hydrogenHeatmapRouter); app.get('/api/health', (context) => context.json({ status: 'ok', time: new Date().toISOString(), })); // 未匹配的 /api/* 必须返回 JSON 404。若落到下面的静态回退,会返回 // 200 + index.html,让前端 res.ok 为真、再在 res.json() 处抛解析错误, // 把"路由不存在"伪装成数据问题。 app.all('/api/*', (context) => context.json({ error: 'Not Found' }, 404)); // 兜底错误处理:统一返回 JSON,避免把栈信息或 HTML 暴露给调用方。 app.onError((error, context) => { console.error(`[server] unhandled error on ${context.req.method} ${context.req.path}:`, error); return context.json({ error: 'Internal Server Error' }, 500); }); // 生产环境由同一进程托管 Vite 构建产物,并回退到单页应用入口。 app.use('/*', serveStatic({ root: './dist' })); app.use('/*', serveStatic({ root: './dist', path: 'index.html' })); return app; }