/** * Health-Probe für die RustyCMS API. Ergebnisse werden kurz gecacht, damit nicht * jeder Request einen extra Roundtrip auslöst. Bei Negativ-Status kürzere TTL, * damit das Frontend zügig wieder hochkommt sobald das CMS antwortet. */ import { env } from '$env/dynamic/public'; const HEALTHY_TTL_MS = 10_000; const UNHEALTHY_TTL_MS = 3_000; const PROBE_TIMEOUT_MS = 1_500; type CacheEntry = { healthy: boolean; expires: number }; let cached: CacheEntry | null = null; let inflight: Promise | null = null; function getBaseUrl(): string { const url = env.PUBLIC_CMS_URL || 'http://localhost:3000'; return url.replace(/\/$/, ''); } async function probe(): Promise { const base = getBaseUrl(); const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), PROBE_TIMEOUT_MS); try { const res = await fetch(`${base}/api-docs/openapi.json`, { method: 'GET', signal: ctrl.signal, }); return res.ok; } catch { return false; } finally { clearTimeout(timer); } } export async function isCmsAvailable(): Promise { const now = Date.now(); if (cached && cached.expires > now) return cached.healthy; if (inflight) return inflight; const p = (async () => { const healthy = await probe(); cached = { healthy, expires: Date.now() + (healthy ? HEALTHY_TTL_MS : UNHEALTHY_TTL_MS), }; return healthy; })(); inflight = p; p.finally(() => { if (inflight === p) inflight = null; }); return p; } export function resetCmsHealthCache(): void { cached = null; }