/** * DashCaddy Error Handler Middleware * Centralizes error handling logic to eliminate duplicate catch blocks */ const { AppError } = require('./errors'); const { logError } = require('./error-logger'); /** * Async route handler wrapper * Automatically catches errors and passes to error middleware * Usage: app.get('/route', asyncHandler(async (req, res) => { ... })) */ function asyncHandler(fn) { return (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; } /** * Global error handling middleware * MUST be registered after all routes in server.js */ function errorMiddleware(err, req, res, next) { // Log all errors with request context logError(req.path, err, { method: req.method, ip: req.ip, userId: req.user?.id, body: req.body }); // Determine if this is an operational error (AppError) or programming error const isOperational = err.isOperational || err instanceof AppError; // Status code const statusCode = err.statusCode || 500; // Error code (DC-XXX format) const code = err.code || `DC-${statusCode}`; // Build response const response = { success: false, error: isOperational ? err.message : 'Internal server error', code }; // Add optional fields if present if (err.requiresTotp) response.requiresTotp = true; if (err.retryAfter) response.retryAfter = err.retryAfter; if (err.field) response.field = err.field; if (err.resource) response.resource = err.resource; if (err.details && Object.keys(err.details).length > 0) response.details = err.details; // Development mode: include stack trace if (process.env.NODE_ENV === 'development') { response.stack = err.stack; } // Send response res.status(statusCode).json(response); // For non-operational errors, log as fatal if (!isOperational) { console.error('FATAL: Non-operational error detected', { error: err.message, stack: err.stack, path: req.path }); } } /** * 404 handler for routes not found * Register this before the global error handler */ function notFoundHandler(req, res, next) { const { NotFoundError } = require('./errors'); next(new NotFoundError(`Route ${req.method} ${req.path}`)); } module.exports = { asyncHandler, errorMiddleware, notFoundHandler };