const Koa = require('koa') const Router = require('koa-router') const https = require('https') const fs = require('fs') const cors = require('@koa/cors') const bodyParser = require('koa-bodyparser') const path = require('path') require('dotenv').config() const app = new Koa() const router = new Router() const ALLOWED_ORIGINS = (process.env.CORS_ORIGIN || '') .split(',') .map(s => s.trim()) .filter(Boolean) const IS_PROD = process.env.NODE_ENV === 'production' if (IS_PROD && ALLOWED_ORIGINS.length === 0) { console.error('CORS_ORIGIN is required in production. Set comma-separated allowlist in .env') } function corsOriginCheck(ctx) { const reqOrigin = ctx.request.header.origin || '' if (ALLOWED_ORIGINS.length === 0) { return IS_PROD ? '' : reqOrigin || '*' } if (ALLOWED_ORIGINS.includes('*')) return reqOrigin return ALLOWED_ORIGINS.includes(reqOrigin) ? reqOrigin : '' } app.use(cors({ origin: corsOriginCheck, credentials: true, allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowHeaders: ['Content-Type', 'Authorization'] })) app.use(bodyParser({ jsonLimit: '5mb', formLimit: '5mb' })) app.use(require('koa-static')(path.join(__dirname, 'public'))) const errorHandler = async (ctx, next) => { try { await next() if (ctx.status === 404) { ctx.body = { code: 404, message: '接口不存在' } ctx.status = 404 } } catch (error) { console.error('Server error:', error) ctx.status = error.status || 500 ctx.body = { code: ctx.status, message: IS_PROD ? '服务器内部错误' : error.message } } } app.use(errorHandler) const orderRoutes = require('./routes/orders') const categoryRoutes = require('./routes/categories') const goodsRoutes = require('./routes/goods') const userRoutes = require('./routes/users') const uploadRoutes = require('./routes/upload') const stockRoutes = require('./routes/stock') const aiRoutes = require('./routes/ai') const supplierRoutes = require('./routes/suppliers') const purchaseRoutes = require('./routes/purchases') const pointsGoodsRoutes = require('./routes/points-goods') const statsRoutes = require('./routes/stats') const priceListRoutes = require('./routes/price-list') const pointsLogsRoutes = require('./routes/points-logs') const recognizeRoutes = require('./routes/recognize') const reportRoutes = require('./routes/reports') const exportRoutes = require('./routes/export') const subscribeRoutes = require('./routes/subscribe') const addressRoutes = require('./routes/addresses') const goodsSpecRoutes = require('./routes/goods-specs') const cartRoutes = require('./routes/carts') const refundRoutes = require('./routes/refunds') const homeCategoryRoutes = require('./routes/homeCategories') const paymentRoutes = require('./routes/payment') router.use('/api/orders', orderRoutes) router.use('/api/categories', categoryRoutes) router.use('/api/goods', goodsRoutes) router.use('/api/users', userRoutes) router.use('/api/upload', uploadRoutes) router.use('/api/stock', stockRoutes) router.use('/api/ai', aiRoutes) router.use('/api/suppliers', supplierRoutes) router.use('/api/purchases', purchaseRoutes) router.use('/api/points-goods', pointsGoodsRoutes) router.use('/api/stats', statsRoutes) router.use('/api/price-list', priceListRoutes) router.use('/api/points/logs', pointsLogsRoutes) router.use('/api/recognize', recognizeRoutes) router.use('/api/reports', reportRoutes) router.use('/api/export', exportRoutes) router.use('/api/subscribe', subscribeRoutes) router.use('/api/addresses', addressRoutes) router.use('/api/goods-specs', goodsSpecRoutes) router.use('/api/cart', cartRoutes) router.use('/api/refunds', refundRoutes) router.use('/api/home', homeCategoryRoutes) router.use('/api/payment', paymentRoutes) app.use(router.routes()) app.use(router.allowedMethods()) const { startHealthCheck } = require('./config/database') const PORT = parseInt(process.env.PORT) || 3006 const HTTPS_ENABLED = process.env.HTTPS_ENABLED === '1' const SSL_KEY = process.env.SSL_KEY_PATH const SSL_CERT = process.env.SSL_CERT_PATH if (HTTPS_ENABLED) { if (!SSL_KEY || !SSL_CERT || !fs.existsSync(SSL_KEY) || !fs.existsSync(SSL_CERT)) { console.error('HTTPS_ENABLED=1 but SSL_KEY_PATH / SSL_CERT_PATH missing or files not found') process.exit(1) } const options = { key: fs.readFileSync(SSL_KEY), cert: fs.readFileSync(SSL_CERT) } https.createServer(options, app.callback()).listen(PORT, () => { console.log(`HTTPS server running on port ${PORT}`) startHealthCheck(30000) }) } else { if (IS_PROD) { console.warn('Running HTTP in production. Set HTTPS_ENABLED=1 + SSL_KEY_PATH/SSL_CERT_PATH') } app.listen(PORT, () => { console.log(`Server running on port ${PORT}`) startHealthCheck(30000) }) }