/** * Cache für CMS-API-Responses (nur serverseitig, Node fs/crypto). * Wird ausschließlich per dynamic import aus cms.ts geladen – nie von Layout/Middleware, * damit es nicht ins Client-Bundle gelangt. Flag/State: cms-cache-state.ts. */ import { createHash } from "node:crypto"; import { readFile, writeFile, mkdir } from "node:fs/promises"; import { existsSync } from "node:fs"; import { setCmsFromCacheUsed } from "./cms-cache-state"; const CACHE_DIR = `${process.cwd()}/.cache/cms`; function cacheKeyFromUrl(url: string): string { return createHash("sha256").update(url).digest("hex"); } async function ensureCacheDir(): Promise { if (!existsSync(CACHE_DIR)) { await mkdir(CACHE_DIR, { recursive: true }); } } interface CachedResponse { status: number; body: string; } async function getCached(key: string): Promise { try { const path = `${CACHE_DIR}/${key}.json`; if (!existsSync(path)) return null; const raw = await readFile(path, "utf-8"); const data = JSON.parse(raw) as CachedResponse; return data?.body != null ? data : null; } catch { return null; } } async function setCached(key: string, data: CachedResponse): Promise { try { await ensureCacheDir(); const path = `${CACHE_DIR}/${key}.json`; await writeFile(path, JSON.stringify(data), "utf-8"); } catch { // Cache schreiben optional } } /** * Fetch mit Cache: bei Erfolg wird die Response in .cache/cms gespeichert (überschreibt vorhanden). * Bei Fehler wird versucht, aus dem Cache zu lesen; wenn gefunden, wird usedCacheThisRequest gesetzt. */ export async function cachedFetch(url: string): Promise { const key = cacheKeyFromUrl(url); try { const res = await fetch(url); const body = await res.text(); await setCached(key, { status: res.status, body }); return new Response(body, { status: res.status, headers: res.headers, }); } catch { const cached = await getCached(key); if (cached) { setCmsFromCacheUsed(); return new Response(cached.body, { status: cached.status, headers: { "Content-Type": "application/json" }, }); } throw new Error(`CMS nicht erreichbar (${url}) und kein Cache für diese Anfrage.`); } }