import type { TranslateFn } from '../i18nFactory'; /** * Traduce un error desconocido a un mensaje que se le pueda mostrar a un usuario. * * El kit hacía `toast.error('Error', { description: err.message })`, así que al * usuario le llegaba el texto técnico de JavaScript en crudo — "Cannot read * properties of undefined", "Failed to fetch" — que además nunca está traducido. * * Orden de precedencia: * * 1. **Texto del backend.** Si el error trae `detail` / `message` / `title` de un * `ProblemDetails`, gana: el backend recibe `Accept-Language` y lo devuelve ya * traducido, y es más específico que cualquier cosa que el kit pueda inferir. * 2. **Código HTTP.** Sin texto del backend, el status se mapea a una clave del * catálogo (403, 404, 409, 422, 5xx). * 3. **Fallo de red.** `TypeError: Failed to fetch` y equivalentes. * 4. **Genérico.** Cualquier otra cosa: mensaje genérico, y el texto técnico se * devuelve aparte en `technical` para diagnóstico, nunca para la UI. * * Es una función pura y recibe `t`, para poder usarse desde hooks y desde módulos * sin acceso al contexto de React. * * ⚠️ El paso 1 tiene que reconocer TODAS las formas en que un adapter lanza, no * solo la de axios. `leerTextoBackend` nacía mirando únicamente las bolsas * `response.data` / `data` / `problem`, y con eso se le escapaban dos formas que * el propio kit produce y consume: * * · `ApiError` del adapter por defecto, que deja el problem-details en `.body` * (ver `adapter/createDefaultAdapter.ts`); * · el error **plano**, que trae `status` + `code` + `detail` en la raíz porque * el host ya normalizó la respuesta en su interceptor HTTP. * * En ambos casos el `detail` del backend existía y no se mostraba: el usuario veía * el mensaje por status ("Revisa los datos ingresados") o el genérico, y la causa * real —"Esta acción no está disponible para la clase de documento de esta * factura"— solo aparecía en la consola del navegador. `isConflictError` ya hacía * el duck-typing completo sobre esas mismas formas; este módulo tenía que ser * simétrico con él, no un subconjunto. * * @see src/components/MasterDocument/smart/conflictError.ts - mismo duck-typing sobre las formas de lanzar * @see src/components/MasterDocument/smart/crossingFetch.ts - mismo criterio para los errores de cruce */ /** Error ya listo para mostrar. */ export interface ClassifiedError { /** Texto para el usuario. Siempre presente y siempre en el idioma activo. */ message: string; /** Clave usada, o `undefined` si el texto lo puso el backend. */ messageKey?: string; /** Texto técnico original. Para `console.error`, jamás para la UI. */ technical?: string; } /** * Clasifica un error para mostrarlo al usuario. * * @example * ```ts * const { message, technical } = classifyError(err, t); * if (technical) console.error('[MasterDocument]', technical); * toast.error(t('master_document.chrome.error'), { description: message }); * ``` */ export declare function classifyError(err: unknown, t: TranslateFn): ClassifiedError; //# sourceMappingURL=userFacingError.d.ts.map