'use strict'; /* ── Error handling middleware ───────────────────────────────────────────── requestId — attach X-Request-Id to every request (use early in middleware chain) errorHandler — 4-arg Express error handler (use as last app.use) ──────────────────────────────────────────────────────────────────────── */ const crypto = require('crypto'); const logger = require('../utils/logger'); let _errorLogStmt = null; function getErrorLogStmt() { if (!_errorLogStmt) { try { const db = require('../db/db'); _errorLogStmt = db.prepare( 'INSERT INTO error_log (level, message, stack, route, method, user_id) VALUES (?, ?, ?, ?, ?, ?)' ); } catch {} } return _errorLogStmt; } /** * Attaches a unique request ID to req.requestId and sets X-Request-Id header. * Honour an incoming X-Request-Id from trusted proxies/gateways when present. */ function requestId(req, res, next) { const id = crypto.randomUUID(); req.requestId = id; res.setHeader('X-Request-Id', id); next(); } /** * Global error handler — must be registered AFTER all routes. * * Classifies errors: * operational (4xx) — expected client errors → warn level, message returned as-is * programmer (5xx) — unexpected bugs → error level, stack logged, message hidden in prod */ function errorHandler(err, req, res, _next) { const status = err.status || err.statusCode || 500; const isOperational = status >= 400 && status < 500; const isProd = process.env.NODE_ENV === 'production'; const meta = { requestId: req.requestId, method: req.method, path: req.path, status, userId: req.user?.id, role: req.user?.role, }; if (isOperational) { logger.warn(err.message || 'Client error', meta); } else { logger.error(err.message || 'Unhandled error', { ...meta, stack: !isProd ? err.stack : undefined, }); // Persist to error_log table for admin dashboard try { const s = getErrorLogStmt(); if (s) s.run('error', (err.message || 'Unknown').slice(0, 1000), (err.stack || '').slice(0, 4000), req.path, req.method, req.user?.id || null); } catch {} } const message = isProd && !isOperational ? 'Internal server error' : (err.message || 'Server error'); if (res.headersSent) return; res.status(status).json({ error: message, requestId: req.requestId }); } module.exports = { requestId, errorHandler };