import type { Stats } from "node:fs"; import { stat } from "node:fs/promises"; export type StaticContentEncoding = "br" | "gzip" | "identity"; export type StaticAssetRepresentation = { encoding: StaticContentEncoding; filePath: string; stat: Stats; }; export type StaticAssetMetadata = { identity: StaticAssetRepresentation; br?: StaticAssetRepresentation; gzip?: StaticAssetRepresentation; }; const metadataCache = new Map>(); export async function getStaticAssetMetadata(filePath: string): Promise { const cached = metadataCache.get(filePath); if (cached) { return cached; } const pending = loadStaticAssetMetadata(filePath); metadataCache.set(filePath, pending); const metadata = await pending; if (metadata === null) { // Do not let attacker-controlled misses grow a process-lifetime cache. metadataCache.delete(filePath); } return metadata; } async function loadStaticAssetMetadata(filePath: string): Promise { const identityStat = await stat(filePath).catch(() => null); if (!identityStat?.isFile()) { return null; } const [brStat, gzipStat] = await Promise.all([stat(`${filePath}.br`).catch(() => null), stat(`${filePath}.gz`).catch(() => null)]); return { identity: { encoding: "identity", filePath, stat: identityStat }, ...(brStat?.isFile() ? { br: { encoding: "br" as const, filePath: `${filePath}.br`, stat: brStat } } : {}), ...(gzipStat?.isFile() ? { gzip: { encoding: "gzip" as const, filePath: `${filePath}.gz`, stat: gzipStat } } : {}), }; } export function selectStaticRepresentation(metadata: StaticAssetMetadata, acceptEncoding: string | undefined): StaticAssetRepresentation { const accepted = parseAcceptEncoding(acceptEncoding); const candidates = [ metadata.br ? { quality: accepted.get("br") ?? accepted.get("*") ?? 0, representation: metadata.br, preference: 2 } : null, metadata.gzip ? { quality: accepted.get("gzip") ?? accepted.get("*") ?? 0, representation: metadata.gzip, preference: 1 } : null, ] .filter((candidate): candidate is NonNullable => candidate !== null && candidate.quality > 0) .sort((left, right) => right.quality - left.quality || right.preference - left.preference); return candidates[0]?.representation ?? metadata.identity; } function parseAcceptEncoding(value: string | undefined): Map { const accepted = new Map(); for (const item of value?.split(",") ?? []) { const [rawEncoding, ...parameters] = item.trim().toLowerCase().split(";"); if (!rawEncoding) continue; let quality = 1; for (const parameter of parameters) { const match = /^q\s*=\s*(0(?:\.\d+)?|1(?:\.0+)?)$/.exec(parameter.trim()); if (match) { quality = Number(match[1]); } } accepted.set(rawEncoding, quality); } return accepted; } export function createStaticEtag(representation: StaticAssetRepresentation): string { const size = representation.stat.size.toString(16); const modified = Math.trunc(representation.stat.mtimeMs).toString(16); return `W/"${size}-${modified}-${representation.encoding}"`; } export function isStaticAssetNotModified(input: { etag: string; ifModifiedSince?: string; ifNoneMatch?: string; mtimeMs: number }): boolean { if (input.ifNoneMatch !== undefined) { const expected = normalizeWeakEtag(input.etag); return input.ifNoneMatch .split(",") .map((value) => value.trim()) .some((value) => value === "*" || normalizeWeakEtag(value) === expected); } if (input.ifModifiedSince === undefined) { return false; } const since = Date.parse(input.ifModifiedSince); if (!Number.isFinite(since)) { return false; } return Math.floor(input.mtimeMs / 1000) <= Math.floor(since / 1000); } function normalizeWeakEtag(value: string): string { return value.trim().replace(/^W\//i, ""); } export function getStaticCacheControl(pathname: string, localeIsRevisioned: boolean): string { if (pathname === "/assets" || pathname.startsWith("/assets/")) { return "public, max-age=31536000, immutable"; } if (pathname === "/locales" || pathname.startsWith("/locales/")) { return localeIsRevisioned ? "public, max-age=31536000, immutable" : "public, max-age=300, must-revalidate, stale-while-revalidate=86400"; } if (pathname === "/fonts" || pathname.startsWith("/fonts/") || pathname === "/images" || pathname.startsWith("/images/")) { return "public, max-age=86400, stale-while-revalidate=604800"; } return "public, max-age=0, must-revalidate"; } export function hasCompressedRepresentation(metadata: StaticAssetMetadata): boolean { return metadata.br !== undefined || metadata.gzip !== undefined; } /** Test-only hook for deterministic metadata-cache assertions. */ export function __resetStaticAssetMetadataCacheForTests(): void { metadataCache.clear(); }