import type { ErrorResponse } from "./types"; export class ApiError extends Error { constructor( public status: number, public error: string, message?: string, ) { super(message ?? error); this.name = "ApiError"; } } async function request(url: string, options?: RequestInit): Promise { const res = await fetch(url, { ...options, credentials: "include", headers: { "Content-Type": "application/json", ...options?.headers, }, }); if (res.status === 401) { throw new ApiError(401, "unauthorized"); } if (!res.ok) { let body: ErrorResponse | undefined; try { body = (await res.json()) as ErrorResponse; } catch { // non-JSON error response } throw new ApiError( res.status, body?.error ?? `HTTP ${res.status}`, body?.message, ); } if (res.status === 204) { return undefined as T; } return res.json() as Promise; } export function get(url: string): Promise { return request(url); } export function post(url: string, body?: unknown): Promise { return request(url, { method: "POST", body: body != null ? JSON.stringify(body) : undefined, }); } export function put(url: string, body?: unknown): Promise { return request(url, { method: "PUT", body: body != null ? JSON.stringify(body) : undefined, }); } export function del(url: string): Promise { return request(url, { method: "DELETE" }); }