/** * Custom error class for application errors */ class AppError extends Error { constructor(message, statusCode = 500, isOperational = true) { super(message); this.statusCode = statusCode; this.isOperational = isOperational; Error.captureStackTrace(this, this.constructor); } } /** * Global error handling middleware */ function errorHandler(err, req, res, next) { let { statusCode = 500, message } = err; // Log error for debugging if (process.env.NODE_ENV === 'development') { console.error('❌ Error:', err); } // Don't leak error details in production for operational errors if (process.env.NODE_ENV === 'production' && !err.isOperational) { message = 'Something went wrong'; } // Prepare response const response = { status: 'error', message }; // Add stack trace in development if (process.env.NODE_ENV === 'development') { response.stack = err.stack; } res.status(statusCode).json(response); } /** * Handle 404 errors */ function notFoundHandler(req, res, next) { res.status(404).json({ status: 'error', message: 'Route not found' }); } /** * Async wrapper to catch errors in async route handlers */ function asyncHandler(fn) { return (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; } module.exports = { AppError, errorHandler, notFoundHandler, asyncHandler };