import axios, { AxiosError, type AxiosInstance } from 'axios'; import { ApiClientError, apiBaseUrl, handlers } from './base'; export const http: AxiosInstance = axios.create({ baseURL: apiBaseUrl, withCredentials: true, headers: { 'Content-Type': 'application/json', }, }); function extractMessage(details: unknown, fallback: string): string { if (typeof details === 'object' && details) { if ('message' in details && typeof details.message === 'string') { return details.message; } if ('detail' in details && typeof details.detail === 'string') { return details.detail; } if ('error' in details && typeof details.error === 'object' && details.error) { const zodError = details.error as Record; if (Array.isArray(zodError.issues) && zodError.issues.length > 0) { const firstIssue = zodError.issues[0] as { message?: string }; if (typeof firstIssue.message === 'string') return firstIssue.message; } if (typeof zodError.message === 'string') { try { const parsed = JSON.parse(zodError.message); if ( Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0]?.message === 'string' ) { return parsed[0].message; } } catch { /* not JSON, use raw string */ } return zodError.message; } } } return fallback; } function normalizeError(error: unknown): ApiClientError { if (error instanceof ApiClientError) return error; if (axios.isAxiosError(error)) { const status = error.response?.status; const details = error.response?.data; return new ApiClientError(extractMessage(details, error.message || 'Request failed'), { status, details, causeError: error, }); } if (error instanceof Error) { return new ApiClientError(error.message, { causeError: error }); } return new ApiClientError('Error inesperado.', { causeError: error }); } http.interceptors.response.use( (response) => response, async (error: AxiosError) => { const normalized = normalizeError(error); if (normalized.status === 403 && handlers.onForbidden) { await handlers.onForbidden(normalized); } if (handlers.onError) { await handlers.onError(normalized); } return Promise.reject(normalized); } );