import 'dotenv/config' import express from 'express' import helmet from 'helmet' import morgan from 'morgan' import { initFirebase } from './config/firebase' import { startAnswerListener } from './listeners/answerListener' import { validateEnv } from './config/env' import { webhookLimiter, healthLimiter } from './middleware/rateLimiter' import healthRouter from './routes/health' import webhooksRouter from './routes/webhooks' // Validate required env vars before starting try { validateEnv() } catch (err) { console.error('[startup] Env validation failed:') console.error(err) process.exit(1) } initFirebase() const app = express() const PORT = parseInt(process.env.PORT ?? '8080', 10) // Capture raw body BEFORE express.json() for webhook signature verification app.use(express.json({ verify: (req: express.Request, res: express.Response, body: Buffer) => { (req as any).rawBody = body }, })) app.use(helmet()) app.use(morgan('combined')) // Rate limiting middleware (applied before routes) app.use('/webhooks', webhookLimiter) app.use('/health', healthLimiter) app.use('/health', healthRouter) app.use('/webhooks', webhooksRouter) const server = app.listen(PORT, () => { console.log(`[server] listening on port ${PORT}`) startAnswerListener() }) // Graceful shutdown process.on('SIGTERM', () => { console.log('[server] SIGTERM received, shutting down') server.close(() => process.exit(0)) }) process.on('SIGINT', () => { console.log('[server] SIGINT received, shutting down') server.close(() => process.exit(0)) })