export class ApiError extends Error { constructor( public readonly status: number, message: string, ) { super(message); } } export async function fetchJson(path: string, init?: RequestInit): Promise { const res = await fetch(path, { ...init, headers: { ...(init?.body ? { 'Content-Type': 'application/json' } : {}), ...init?.headers, }, }); const body = await res.json().catch(() => null); if (!res.ok) { const message = Array.isArray(body?.message) ? body.message.join('; ') : body?.message || `Request failed (${res.status})`; throw new ApiError(res.status, message); } return body as T; } export const api = { get: (path: string) => fetchJson(path), post: (path: string, data: unknown) => fetchJson(path, { method: 'POST', body: JSON.stringify(data) }), patch: (path: string, data: unknown) => fetchJson(path, { method: 'PATCH', body: JSON.stringify(data) }), delete: (path: string) => fetchJson(path, { method: 'DELETE' }), };