import { goto } from '$app/navigation'; import { browser } from '$app/environment'; import { getToken, clearAuth } from './auth'; const BASE = '/api/v1'; export class ApiError extends Error { status: number; code: string; constructor(status: number, code: string, message: string) { super(message); this.status = status; this.code = code; } } async function request( method: string, path: string, body?: unknown ): Promise { const headers: Record = {}; const token = getToken(); if (token) { headers['Authorization'] = `Bearer ${token}`; } if (body !== undefined) { headers['Content-Type'] = 'application/json'; } const res = await fetch(`${BASE}${path}`, { method, headers, body: body !== undefined ? JSON.stringify(body) : undefined }); if (res.status === 204) { return undefined as T; } const data = await res.json(); if (!res.ok) { if (res.status === 401) { clearAuth(); // Don't strand the user on a now-unauthenticated page with no nav — // send them to /join. Guard against loops on the auth screens. if (browser && !/^\/(join|recover|admin\/login)/.test(window.location.pathname)) { void goto('/join'); } } throw new ApiError(res.status, data.error ?? 'unknown', data.message ?? 'Fehler'); } return data as T; } export const api = { get: (path: string) => request('GET', path), post: (path: string, body?: unknown) => request('POST', path, body), patch: (path: string, body?: unknown) => request('PATCH', path, body), delete: (path: string) => request('DELETE', path) };