103 lines
3.0 KiB
JavaScript
103 lines
3.0 KiB
JavaScript
/**
|
|
* Express 应用入口
|
|
* 处理持久化 API 路由
|
|
*/
|
|
|
|
import express from 'express';
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname, join } from 'path';
|
|
import { prisma } from './db/client.js';
|
|
import { requireAuth } from './auth/middleware.js';
|
|
|
|
// 导入路由(稍后创建)
|
|
import documentsRouter from './routes/documents.js';
|
|
import userRouter from './routes/user.js';
|
|
import glossaryRouter from './routes/glossary.js';
|
|
import chatRouter from './routes/chat.js';
|
|
import referencesRouter from './routes/references.js';
|
|
import promptPoolRouter from './routes/prompt-pool.js';
|
|
|
|
const app = express();
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
const projectRoot = join(__dirname, '..');
|
|
|
|
// ==================== 中间件配置 ====================
|
|
|
|
// JSON 解析
|
|
app.use(express.json({ limit: '50mb' }));
|
|
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
|
|
|
|
// CORS
|
|
app.use((req, res, next) => {
|
|
const origin = req.headers.origin || '*';
|
|
res.header('Access-Control-Allow-Origin', origin);
|
|
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key');
|
|
res.header('Access-Control-Expose-Headers', 'Content-Length, Content-Range');
|
|
|
|
if (req.method === 'OPTIONS') {
|
|
return res.sendStatus(200);
|
|
}
|
|
next();
|
|
});
|
|
|
|
// 请求日志(开发环境)
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
app.use((req, res, next) => {
|
|
console.log(`[Express] ${req.method} ${req.path}`);
|
|
next();
|
|
});
|
|
}
|
|
|
|
// 开发模式下让 Vite 代理过来的 PDF.js 静态资源可用。
|
|
app.use('/pdfjs', express.static(join(projectRoot, 'pdfjs')));
|
|
|
|
// ==================== 路由注册 ====================
|
|
|
|
// 健康检查(无需认证)
|
|
app.get('/health', async (req, res) => {
|
|
try {
|
|
// 测试数据库连接
|
|
await prisma.$queryRaw`SELECT 1`;
|
|
res.json({
|
|
status: 'ok',
|
|
database: 'connected',
|
|
authDisabled: process.env.AUTH_DISABLED === 'true',
|
|
timestamp: Date.now()
|
|
});
|
|
} catch (error) {
|
|
res.json({
|
|
status: 'ok',
|
|
database: 'disconnected',
|
|
authDisabled: process.env.AUTH_DISABLED === 'true',
|
|
timestamp: Date.now()
|
|
});
|
|
}
|
|
});
|
|
|
|
// 持久化路由(需要认证)
|
|
app.use('/api/documents', requireAuth, documentsRouter);
|
|
app.use('/api/user', requireAuth, userRouter);
|
|
app.use('/api/glossary', requireAuth, glossaryRouter);
|
|
app.use('/api/chat', requireAuth, chatRouter);
|
|
app.use('/api/references', requireAuth, referencesRouter);
|
|
app.use('/api/prompt-pool', requireAuth, promptPoolRouter);
|
|
|
|
// ==================== 错误处理 ====================
|
|
|
|
// 404
|
|
app.use((req, res) => {
|
|
res.status(404).json({ error: 'Not Found' });
|
|
});
|
|
|
|
// 统一错误处理
|
|
app.use((err, req, res, next) => {
|
|
console.error('[Express] Error:', err.message);
|
|
res.status(err.status || 500).json({
|
|
error: err.message || 'Internal Server Error'
|
|
});
|
|
});
|
|
|
|
export default app;
|