65 lines
2.5 KiB
JavaScript
65 lines
2.5 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.createServer = createServer;
|
|
/**
|
|
* ABE API Server — Express app factory.
|
|
* Middleware order matters: requestId → helmet → cors → rateLimit → body → routes → notFound → errorHandler
|
|
*/
|
|
const express_1 = __importDefault(require("express"));
|
|
const cors_1 = __importDefault(require("cors"));
|
|
const helmet_1 = __importDefault(require("helmet"));
|
|
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
const requestId_1 = require("./middleware/requestId");
|
|
const notFound_1 = require("./middleware/notFound");
|
|
const errorHandler_1 = require("./middleware/errorHandler");
|
|
const router_1 = require("./router");
|
|
function createServer(deps) {
|
|
const app = (0, express_1.default)();
|
|
// 1. Request ID — must be first so all logs have requestId
|
|
app.use((0, requestId_1.createRequestIdMiddleware)(deps.logger));
|
|
// 2. Security headers
|
|
app.use((0, helmet_1.default)({
|
|
contentSecurityPolicy: {
|
|
directives: {
|
|
defaultSrc: ["'self'"],
|
|
connectSrc: ["'self'", 'ws:', 'wss:'],
|
|
scriptSrc: ["'self'", "'unsafe-inline'"],
|
|
},
|
|
},
|
|
}));
|
|
// 3. CORS
|
|
app.use((0, cors_1.default)({ origin: deps.config.cors.origin, credentials: true }));
|
|
// 4. Rate limiting
|
|
app.use((0, express_rate_limit_1.default)({
|
|
windowMs: deps.config.api.rateLimitWindowMs,
|
|
max: deps.config.api.rateLimitMax,
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
}));
|
|
// 5. Body parsing
|
|
app.use(express_1.default.json({ limit: '10mb' }));
|
|
// 6. Health endpoints — no auth required
|
|
app.get('/health/live', (_req, res) => {
|
|
res.json({ status: 'ok', uptime: process.uptime() });
|
|
});
|
|
app.get('/health/ready', async (_req, res) => {
|
|
try {
|
|
await deps.db.selectFrom('sessions').select('id').limit(1).execute();
|
|
res.json({ status: 'ready', db: 'connected' });
|
|
}
|
|
catch (err) {
|
|
res.status(503).json({ status: 'not_ready', db: 'disconnected', error: String(err) });
|
|
}
|
|
});
|
|
// 7. Module routes
|
|
app.use('/api', (0, router_1.createRouter)(deps));
|
|
// 8. 404 handler
|
|
app.use(notFound_1.notFoundMiddleware);
|
|
// 9. Global error handler — always last
|
|
app.use(errorHandler_1.globalErrorHandler);
|
|
return app;
|
|
}
|