// POST /api/__journal__/cache/purge: removes every Nitro route-cache entry // (pages, _payload.json and feeds), so a Journal save in the admin shows on // the next page view. The backend calls it on loopback after the save // commits, with `Authorization: Bearer ` // and the body {"kind":"post"|"category","slug":""}; the answer is // {"purged":}. // // 404 without a token of at least 32 characters, and for any request that // came through a reverse proxy (X-Forwarded-For, X-Real-IP or Forwarded); // 401 for a missing or wrong bearer token. The layer's routeRules keep this // route out of the route cache. import { authorizePurge, parsePurgeEvent, purgeRouteCache } from '../../../../app/utils/siteCache.ts' const PROXY_HEADERS = ['x-forwarded-for', 'x-real-ip', 'forwarded'] export default defineEventHandler(async (event) => { setResponseHeader(event, 'cache-control', 'no-store') const config = useRuntimeConfig(event) const verdict = authorizePurge({ token: (config.journal as { cachePurgeToken?: unknown }).cachePurgeToken, authorization: getRequestHeader(event, 'authorization'), proxied: PROXY_HEADERS.some((name) => getRequestHeader(event, name) !== undefined), }) if (verdict === 'disabled' || verdict === 'proxied') { throw createError({ statusCode: 404, statusMessage: 'Not Found' }) } if (verdict === 'unauthorized') { throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) } const { kind, slug } = parsePurgeEvent(await readBody(event).catch(() => null)) const purged = await purgeRouteCache(useStorage('cache')) console.info(`[journal] cache purge: removed ${purged} route cache entries (${kind} ${slug})`) return { purged } })