fase(7): api server refactor with composition root
This commit is contained in:
64
dist/api/server.js
vendored
Normal file
64
dist/api/server.js
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
"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;
|
||||
}
|
||||
Reference in New Issue
Block a user