// Canonical error envelope for server loaders/actions. Always pair a stable // error code with an i18n messageKey from the "errors" namespace so the client // can render in the active locale. See docs/security/threat-model.md for the // Tampering/Repudiation mitigation context. export type ApiErrorCode = | "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "BAD_REQUEST" | "PRECONDITION_FAILED" | "SERVICE_UNAVAILABLE"; export type ErrorEnvelope = { error: { code: ApiErrorCode | string; messageKey: string; details?: Record; }; }; export function errorEnvelope(code: ApiErrorCode | string, messageKey: string, details?: Record): ErrorEnvelope { const envelope: ErrorEnvelope = { error: { code, messageKey } }; if (details) envelope.error.details = details; return envelope; } export const NOT_FOUND_ENVELOPE = errorEnvelope("NOT_FOUND", "errors.notFound"); export const BAD_REQUEST_ENVELOPE = errorEnvelope("BAD_REQUEST", "errors.badRequest");