diff --git a/src/hooks.server.ts b/src/hooks.server.ts index ed4cf451d..bbff925bd 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -32,6 +32,10 @@ import { OAUTH_DEVICE_AUTHORIZATION_ENDPOINT_PATH, OAUTH_TOKEN_ENDPOINT_PATH, } from "@/lib/oauth/constants"; +import { + PRIVATE_LOCALE_CATALOG_HEADERS, + PUBLIC_LOCALE_CATALOG_PAGE_HEADERS, +} from "@/lib/public-cache-control"; import { buildContentSecurityPolicy, createScriptNonce, @@ -110,6 +114,35 @@ function isHtmlResponse(response: Response) { return response.headers.get("content-type")?.includes("text/html"); } +function isCatalogPageRequest(event: Parameters[0]["event"]) { + return ( + event.request.method === "GET" && + (event.url.pathname === "/catalog" || + event.url.pathname.startsWith("/catalog/")) + ); +} + +// Catalog pages render identical content for every anonymous viewer, so let +// the CDN cache them briefly instead of re-running SSR for every crawler hit. +// Requests carrying an auth signal stay private/no-store so personalized +// renders can never be cached. +function applyCatalogCacheControl( + headers: Headers, + input: { hasAuthSignal: boolean; isCatalogPage: boolean }, +) { + if (!input.isCatalogPage) { + headers.set("Cache-Control", "no-store"); + return; + } + + const catalogHeaders = input.hasAuthSignal + ? PRIVATE_LOCALE_CATALOG_HEADERS + : PUBLIC_LOCALE_CATALOG_PAGE_HEADERS; + for (const [name, value] of Object.entries(catalogHeaders)) { + headers.set(name, value); + } +} + function addScriptNonce(html: string, nonce: string) { return html.replace(/]*\bnonce=)/g, `