export type ApiError = { code: string; message: string; status: number; }; export type User = { id: string; username: string; is_admin: boolean; }; export type LoginResponse = { token: string; user: User; }; export async function apiFetch(path: string, init?: RequestInit): Promise { const res = await fetch(path, { credentials: 'same-origin', headers: { 'Content-Type': 'application/json', ...(init?.headers ?? {}) }, ...init }); const body = res.status === 204 ? null : await res.json().catch(() => null); if (!res.ok) { if (res.status === 401) { // Lazy import: auth/store imports from this file, so a top-level // import would be circular. By the time any 401 actually happens // at runtime, both modules have finished loading. const { logout } = await import('$lib/auth/store.svelte'); await logout({ silent: true }); } const envelope = body && (body as { error?: { code?: string; message?: string } }).error; const err: ApiError = { code: envelope?.code ?? 'unknown', message: envelope?.message ?? res.statusText, status: res.status }; throw err; } return body; } export const api = { get: (path: string): Promise => apiFetch(path) as Promise, post: (path: string, body: unknown): Promise => apiFetch(path, { method: 'POST', body: JSON.stringify(body) }) as Promise, put: (path: string, body: unknown): Promise => apiFetch(path, { method: 'PUT', body: JSON.stringify(body) }) as Promise, del: (path: string): Promise => apiFetch(path, { method: 'DELETE' }) as Promise };