Files
windwiderstand.de/src/lib/cms-cache.ts
T

78 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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<void> {
if (!existsSync(CACHE_DIR)) {
await mkdir(CACHE_DIR, { recursive: true });
}
}
interface CachedResponse {
status: number;
body: string;
}
async function getCached(key: string): Promise<CachedResponse | null> {
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<void> {
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<Response> {
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.`);
}
}