const { ValidationError, UniqueConstraintError } = require("sequelize"); const { ZodError } = require("zod"); class AppError extends Error { constructor(status, code, message, details) { super(message); this.status = status; this.code = code; this.details = details; } } const notFound = (req, _res, next) => next(new AppError(404, "NOT_FOUND", "Route not found")); const errorHandler = (error, req, res, _next) => { let status = error.status || error.statusCode || 500; let code = error.code || "INTERNAL_ERROR"; let message = error.message || "An unexpected error occurred"; let details = error.details; if (error instanceof ZodError) { status = 400; code = "VALIDATION_ERROR"; message = "Invalid request data"; details = error.issues.map(({ path, message: detailMessage }) => ({ field: path.join("."), message: detailMessage })); } else if (error instanceof UniqueConstraintError) { status = 409; code = "CONFLICT"; message = "A record with these values already exists"; details = error.errors?.map(({ path, message: detailMessage }) => ({ field: path, message: detailMessage })); } else if (error instanceof ValidationError) { status = 400; code = "VALIDATION_ERROR"; message = "Invalid request data"; details = error.errors?.map(({ path, message: detailMessage }) => ({ field: path, message: detailMessage })); } else if (error.type === "entity.too.large") { status = 413; code = "PAYLOAD_TOO_LARGE"; message = "Request body is too large"; } else if (error.name === "UnauthorizedError" || error.name === "JsonWebTokenError") { status = 401; code = "UNAUTHORIZED"; message = "Authentication failed"; } if (status >= 500) { console.error(`[${req.id || "no-request-id"}] Request failed`, { name: error.name, message: error.message }); if (process.env.NODE_ENV === "production") message = "An unexpected error occurred"; } const payload = { success: false, error: { code, message }, requestId: req.id }; if (details && status < 500) payload.error.details = details; res.status(status).json(payload); }; module.exports = { AppError, notFound, errorHandler };