/** * Error Codes Catalog — T-22 * * Centralized error code registry for consistent API error responses. * Each code has a category prefix, numeric ID, message, and HTTP status. * * Usage: * import { ERROR_CODES, createErrorResponse } from "@/shared/constants/errorCodes"; * return createErrorResponse("AUTH_001", { detail: "Token expired" }); * * @module shared/constants/errorCodes */ // @ts-check /** * @typedef {Object} ErrorCodeDef * @property {string} code - Error code (e.g. "AUTH_001") * @property {string} message - Human-readable message * @property {number} httpStatus - HTTP status code * @property {string} category - Category (AUTH, PROXY, RATE_LIMIT, etc.) */ /** @type {Record} */ export const ERROR_CODES = { // ── Auth ── AUTH_001: { code: "AUTH_001", message: "Authentication required", httpStatus: 401, category: "AUTH" }, AUTH_002: { code: "AUTH_002", message: "Invalid API key", httpStatus: 401, category: "AUTH" }, AUTH_003: { code: "AUTH_003", message: "API key expired", httpStatus: 401, category: "AUTH" }, AUTH_004: { code: "AUTH_004", message: "Insufficient permissions", httpStatus: 403, category: "AUTH" }, AUTH_005: { code: "AUTH_005", message: "Account locked", httpStatus: 423, category: "AUTH" }, AUTH_006: { code: "AUTH_006", message: "No credentials for provider", httpStatus: 400, category: "AUTH" }, // ── Proxy ── PROXY_001: { code: "PROXY_001", message: "Proxy connection failed", httpStatus: 502, category: "PROXY" }, PROXY_002: { code: "PROXY_002", message: "Proxy timeout", httpStatus: 504, category: "PROXY" }, PROXY_003: { code: "PROXY_003", message: "All proxies exhausted", httpStatus: 503, category: "PROXY" }, // ── Rate Limiting ── RATE_001: { code: "RATE_001", message: "Rate limit exceeded", httpStatus: 429, category: "RATE_LIMIT" }, RATE_002: { code: "RATE_002", message: "Daily budget exceeded", httpStatus: 429, category: "RATE_LIMIT" }, RATE_003: { code: "RATE_003", message: "All accounts rate-limited", httpStatus: 503, category: "RATE_LIMIT" }, // ── Model / Routing ── MODEL_001: { code: "MODEL_001", message: "Model not found", httpStatus: 404, category: "MODEL" }, MODEL_002: { code: "MODEL_002", message: "Ambiguous model identifier", httpStatus: 400, category: "MODEL" }, MODEL_003: { code: "MODEL_003", message: "Model temporarily unavailable", httpStatus: 503, category: "MODEL" }, // ── Provider ── PROVIDER_001: { code: "PROVIDER_001", message: "Provider error", httpStatus: 502, category: "PROVIDER" }, PROVIDER_002: { code: "PROVIDER_002", message: "Provider timeout", httpStatus: 504, category: "PROVIDER" }, PROVIDER_003: { code: "PROVIDER_003", message: "Provider not configured", httpStatus: 400, category: "PROVIDER" }, // ── Validation ── VALID_001: { code: "VALID_001", message: "Invalid request body", httpStatus: 400, category: "VALIDATION" }, VALID_002: { code: "VALID_002", message: "Missing required field", httpStatus: 400, category: "VALIDATION" }, VALID_003: { code: "VALID_003", message: "Input sanitization blocked", httpStatus: 400, category: "VALIDATION" }, // ── Internal ── INTERNAL_001: { code: "INTERNAL_001", message: "Internal server error", httpStatus: 500, category: "INTERNAL" }, INTERNAL_002: { code: "INTERNAL_002", message: "Database error", httpStatus: 500, category: "INTERNAL" }, INTERNAL_003: { code: "INTERNAL_003", message: "Circuit breaker open", httpStatus: 503, category: "INTERNAL" }, }; /** * Create a standardized error response. * * @param {string} code - Error code from ERROR_CODES * @param {Object} [details] - Additional error details * @param {string} [details.detail] - Extra detail message * @param {string} [details.requestId] - Correlation request ID * @param {number} [details.retryAfter] - Retry-After seconds * @returns {{ error: { code: string, message: string, category: string, detail?: string, requestId?: string }, status: number, retryAfter?: number }} */ export function createErrorResponse(code, details = {}) { const def = ERROR_CODES[code]; if (!def) { return { error: { code: "INTERNAL_001", message: `Unknown error code: ${code}`, category: "INTERNAL", }, status: 500, }; } const response = { error: { code: def.code, message: def.message, category: def.category, ...(details.detail ? { detail: details.detail } : {}), ...(details.requestId ? { requestId: details.requestId } : {}), }, status: def.httpStatus, }; if (details.retryAfter) { response.retryAfter = details.retryAfter; } return response; } /** * Get all error codes for a category. * * @param {string} category * @returns {ErrorCodeDef[]} */ export function getErrorsByCategory(category) { return Object.values(ERROR_CODES).filter((e) => e.category === category); }