function toHeadersObject(headers?: HeadersInit): Record { if (!headers) { return {} } if (headers instanceof Headers) { return Object.fromEntries(headers.entries()) } if (Array.isArray(headers)) { return Object.fromEntries(headers) } return { ...headers } } function getDownloadFileName(contentDisposition: string | null, fallback: string) { if (!contentDisposition) { return fallback } const utf8Match = contentDisposition.match(/filename\*=UTF-8''([^;]+)/i) if (utf8Match?.[1]) { return decodeURIComponent(utf8Match[1]) } const asciiMatch = contentDisposition.match(/filename="([^"]+)"/i) if (asciiMatch?.[1]) { return asciiMatch[1] } return fallback } export function withApiAuth(init: RequestInit = {}) { // Les appels frontend reutilisent les cookies httpOnly poses cote serveur. return { ...init, headers: { ...toHeadersObject(init.headers) } } } export const apiFetch = $fetch.create({}) export function apiRequest(input: RequestInfo | URL, init: RequestInit = {}) { return fetch(input, withApiAuth(init)) } export async function downloadApiFile(url: string, fileNameFallback: string) { // Les telechargements passent aussi par fetch pour pouvoir recuperer // le contenu et le nom de fichier renvoye par l'API. const response = await apiRequest(url) if (!response.ok) { throw new Error(`HTTP ${response.status}`) } const blob = await response.blob() const objectUrl = URL.createObjectURL(blob) const fileName = getDownloadFileName( response.headers.get("content-disposition"), fileNameFallback ) const link = document.createElement("a") link.href = objectUrl link.download = fileName link.style.display = "none" document.body.appendChild(link) link.click() link.remove() URL.revokeObjectURL(objectUrl) }