import express, { Express, Request, Response, NextFunction } from 'express'; import cors from 'cors'; import dotenv from 'dotenv'; import helmet from 'helmet'; import morgan from 'morgan'; dotenv.config(); const app: Express = express(); /** * Core middleware */ app.use(helmet()); app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev')); app.use(cors({ origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',').map(s => s.trim()) : true, credentials: true, })); app.use(express.json({ limit: '1mb' })); /** * Health + root */ app.get('/api/health', (req: Request, res: Response) => { res.status(200).json({ status: 'ok' }); }); app.get('/', (req: Request, res: Response) => { res.send('Node.js Backend says Hello! Generated by Backlist.'); }); // INJECT:ROUTES /** * 404 handler (must be after routes) */ app.use((req: Request, res: Response) => { res.status(404).json({ message: 'Route not found' }); }); /** * Global error handler (must be last) */ app.use((err: any, req: Request, res: Response, _next: NextFunction) => { // Log full error on server console.error(err); res.status(err?.statusCode || 500).json({ message: err?.message || 'Internal Server Error', }); }); const PORT: number | string = process.env.PORT || 8000; const server = app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); }); /** * Graceful shutdown (Docker / Ctrl+C) */ function shutdown(signal: string) { console.log(`Received ${signal}. Shutting down...`); server.close(() => { console.log('HTTP server closed.'); process.exit(0); }); } process.on('SIGINT', () => shutdown('SIGINT')); process.on('SIGTERM', () => shutdown('SIGTERM'));