// Dünner Zugriff auf das MC2-Backend. Bewusst ohne Anmelde- oder Geheimnis-Felder: // Nichts, was der Browser speichert, reist hier mit (Lehre aus v3-Umbau P1). export class ApiFehler extends Error { constructor( public status: number, public detail: string, ) { super(detail) this.name = "ApiFehler" } } /** FastAPI legt Fehlertexte in `detail` ab — manchmal als Text, manchmal als Liste. */ function detailAus(body: unknown, status: number): string { if (body && typeof body === "object" && "detail" in body) { const d = (body as { detail: unknown }).detail if (typeof d === "string") return d if (Array.isArray(d)) return d.map((x) => (x as { msg?: string }).msg ?? String(x)).join("; ") } return `Die Box antwortet mit Fehler ${status}.` } export async function api(pfad: string, init: RequestInit = {}): Promise { let antwort: Response try { antwort = await fetch(pfad, { ...init, headers: { "Content-Type": "application/json", Accept: "application/json", ...init.headers }, }) } catch { throw new ApiFehler(0, "MC2 ist nicht erreichbar. Läuft die Box?") } const text = await antwort.text() const body = text ? safeJson(text) : null if (!antwort.ok) throw new ApiFehler(antwort.status, detailAus(body, antwort.status)) // Kommt statt JSON eine HTML-Seite (alter Server, falscher Pfad), ist das ein Fehler — // sonst rechnen die Ansichten mit einem Text, als wären es Daten. if (typeof body === "string") throw new ApiFehler(antwort.status, "Die Box antwortet nicht mit Daten.") return body as T } function safeJson(text: string): unknown { try { return JSON.parse(text) } catch { return text } } export const post = (pfad: string, daten?: unknown) => api(pfad, { method: "POST", body: daten === undefined ? undefined : JSON.stringify(daten) })