import express, { Request, Response, NextFunction } from 'express'; import cors from 'cors'; import swaggerUi from 'swagger-ui-express'; import config from './config'; import { swaggerSpec } from './config/swagger'; // Routes import publicRoutes from './routes/public'; import webhookRoutes from './routes/webhooks'; import userRoutes from './routes/user'; import adminRoutes from './routes/admin'; // Middleware import { generalRateLimiter } from './middleware/rateLimit'; const app = express(); // Trust proxy for rate limiting (needed when behind reverse proxy) if (config.app.nodeEnv === 'production') { app.set('trust proxy', 1); // Trust first proxy } // CORS configuration app.use(cors({ origin: config.app.nodeEnv === 'production' ? config.cors.allowedOrigins : true, credentials: true, })); // Body parser app.use(express.json()); app.use(express.urlencoded({ extended: true })); // General rate limiting app.use(generalRateLimiter); // Swagger API Documentation app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, { customCss: '.swagger-ui .topbar { display: none }', customSiteTitle: 'Lightning Lottery API Docs', })); // Swagger JSON endpoint app.get('/api-docs.json', (req: Request, res: Response) => { res.setHeader('Content-Type', 'application/json'); res.send(swaggerSpec); }); // Health check endpoint app.get('/health', async (req: Request, res: Response) => { const { db } = await import('./database'); const { lnbitsService } = await import('./services/lnbits'); const dbHealth = await db.healthCheck(); const lnbitsHealth = await lnbitsService.healthCheck(); const healthy = dbHealth && lnbitsHealth; res.status(healthy ? 200 : 503).json({ version: '1.0', status: healthy ? 'healthy' : 'unhealthy', checks: { database: dbHealth ? 'ok' : 'failed', lnbits: lnbitsHealth ? 'ok' : 'failed', }, timestamp: new Date().toISOString(), }); }); // API routes app.use('/', publicRoutes); app.use('/webhooks', webhookRoutes); app.use('/', userRoutes); app.use('/admin', adminRoutes); // 404 handler app.use((req: Request, res: Response) => { res.status(404).json({ version: '1.0', error: 'NOT_FOUND', message: 'Endpoint not found', }); }); // Error handler app.use((err: Error, req: Request, res: Response, next: NextFunction) => { console.error('Unhandled error:', err); res.status(500).json({ version: '1.0', error: 'INTERNAL_ERROR', message: config.app.nodeEnv === 'production' ? 'An internal error occurred' : err.message, }); }); export default app;