// Zwei Instanzen, eine Oberfläche (User-Entscheid 24.09.2026): Die Seite kommt von der KI-Box // (Rolle „box“) oder später vom Container auf dem Proxmox-PC (Rolle „homelab“). Der Homelab-Bereich // fragt unter /api/homelab/…, alles andere gehört zum Box-Wart. Was die ausliefernde Instanz nicht // selbst beantwortet, geht über /api/partner/… an die andere — das entscheidet zielPfad(). export type Rolle = "box" | "homelab" /** Beantwortet immer die Instanz, die die Seite ausliefert. */ const IMMER_LOKAL = ["/api/instanz", "/api/partner", "/api/health"] const unter = (pfad: string, basis: string) => pfad === basis || pfad.startsWith(`${basis}/`) || pfad.startsWith(`${basis}?`) /** Wohin eine Anfrage der Oberfläche geht, je nach Rolle der Instanz, die die Seite ausliefert. */ export function zielPfad(pfad: string, eigene: Rolle): string { if (!pfad.startsWith("/api/") || IMMER_LOKAL.some((b) => unter(pfad, b))) return pfad const bereich: Rolle = unter(pfad, "/api/homelab") ? "homelab" : "box" return bereich === eigene ? pfad : `/api/partner${pfad.slice(4)}` } let rolle: Promise | null = null /** Rolle der ausliefernden Instanz, einmal gefragt. Scheitert die Frage, gilt „box“ (so war es bis * Phase 2) — und beim nächsten Mal wird neu gefragt. */ export function eigeneRolle(): Promise { rolle ??= fetch("/api/instanz", { headers: { Accept: "application/json" } }) .then((r) => (r.ok ? r.json() : Promise.reject(new Error(String(r.status))))) .then((d: { rolle?: string }) => (d.rolle === "homelab" ? "homelab" : "box") as Rolle) .catch(() => { rolle = null return "box" as Rolle }) return rolle } /** Nur für Tests: vergessene Rolle. */ export function rolleVergessen() { rolle = null }