/** * HTTPError — error HTTP con status code. * Lanzado por fetchJSON cuando la respuesta no es ok. */ export class HTTPError extends Error { constructor(public status: number, message: string) { super(message); this.name = "HTTPError"; } } /** * fetchJSON — wrapper de fetch que parsea JSON, lanza HTTPError en errores HTTP * y retorna undefined en 204 No Content. * * URL final: `${baseUrl ?? ""}${path}`. * Headers default: `{ "Content-Type": "application/json" }`, mergeables via init.headers. * credentials: "include" por defecto, sobreescribible via init. */ export async function fetchJSON( path: string, init?: RequestInit, baseUrl?: string, ): Promise { const res = await fetch(`${baseUrl ?? ""}${path}`, { credentials: "include", ...init, headers: { "Content-Type": "application/json", ...(init?.headers ?? {}), }, }); if (!res.ok) { const err = await res.json().catch(() => ({ Message: res.statusText })); throw new HTTPError( res.status, err.Message ?? err.message ?? res.statusText, ); } if (res.status === 204) return undefined as T; return res.json() as Promise; }