function getPublicUiError(status: number): string { // Message volontairement generique pour eviter les erreurs techniques en UI. if (status === 429) { return "Service momentanément indisponible. Merci de réessayer."; } return "Une erreur temporaire est survenue. Merci de réessayer."; } function extractApiMessage(payload: unknown, status: number): string { // Priorite aux messages explicites fournis par l'API. if (payload && typeof payload === "object") { const record = payload as Record; const detail = record.detail; if (typeof detail === "string" && detail.trim()) { return detail; } if (detail && typeof detail === "object") { const detailRecord = detail as Record; if (typeof detailRecord.message === "string" && detailRecord.message.trim()) { return detailRecord.message; } } } return getPublicUiError(status); } async function readJsonSafely(response: Response): Promise { // Evite les crashes JSON.parse quand le backend repond en texte/plain. const raw = await response.text(); if (!raw) { return null; } try { return JSON.parse(raw); } catch { return null; } } export async function postJson(url: string, body: unknown): Promise { // Client HTTP robuste: jamais d'erreur de parsing brute exposee a l'utilisateur. const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const data = await readJsonSafely(response); if (!response.ok) { throw new Error(extractApiMessage(data, response.status)); } if (data === null) { throw new Error(getPublicUiError(500)); } return data as T; } export async function getJson(url: string): Promise { // Lecture GET robuste avec meme convention de message UI. const response = await fetch(url, { method: "GET" }); const data = await readJsonSafely(response); if (!response.ok) { throw new Error(extractApiMessage(data, response.status)); } if (data === null) { throw new Error(getPublicUiError(500)); } return data as T; }