import 'express-async-errors'; import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; import compression from 'compression'; import rateLimit from 'express-rate-limit'; import { env } from './config/env'; import { logger } from './utils/logger'; import { errorHandler } from './middleware/error-handler'; // Route imports import authRoutes from './modules/auth/auth.routes'; import instanceRoutes from './modules/instances/instances.routes'; import settingsRoutes from './modules/settings/settings.routes'; import healthRoutes from './modules/health/health.routes'; import auditRoutes from './modules/audit/audit.routes'; import backupRoutes from './modules/backups/backup.routes'; import eventsRoutes, { instanceEventsRouter } from './modules/events/events.routes'; import { startHealthScheduler } from './services/health.service'; import { autoDiscoverOnStartup } from './services/discovery.service'; const app = express(); // Global middleware app.use(helmet()); app.use(compression()); app.use(express.json({ limit: '10mb' })); app.use( cors({ origin: env.CORS_ORIGINS.split(',').map((s) => s.trim()), credentials: true, }) ); // Rate limiters const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 15, // 15 attempts per window standardHeaders: true, legacyHeaders: false, message: { error: { message: 'Too many attempts, please try again later', code: 'RATE_LIMITED' } }, }); // Global API rate limiter — safety net against resource exhaustion const apiLimiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: 300, // 300 req/min per IP (generous for a control panel) standardHeaders: true, legacyHeaders: false, message: { error: { message: 'Too many requests, please try again later', code: 'RATE_LIMITED' } }, }); // Routes app.use('/api', apiLimiter); app.use('/api/auth', authLimiter, authRoutes); app.use('/api/instances', instanceRoutes); app.use('/api/settings', settingsRoutes); app.use('/api/health', healthRoutes); app.use('/api/audit', auditRoutes); app.use('/api/backups', backupRoutes); app.use('/api/events', eventsRoutes); app.use('/api/instances/:id/events', instanceEventsRouter); // Error handler (must be last) app.use(errorHandler); app.listen(env.PORT, () => { logger.info(`CCP API listening on port ${env.PORT} (${env.NODE_ENV})`); startHealthScheduler(env.HEALTH_CHECK_INTERVAL_MS); // Auto-discover parent CML instance on first boot (5s delay for DB readiness) setTimeout(() => { autoDiscoverOnStartup().catch((err) => logger.error(`[discovery] Auto-discovery failed: ${(err as Error).message}`) ); }, 5_000); }); export default app;