from __future__ import annotations from starlette.types import ASGIApp, Receive, Scope, Send NO_CACHE = b"no-cache, must-revalidate" NO_STORE = b"no-store" IMMUTABLE = b"public, max-age=31536000, immutable" def _cache_control_for_path(path: str) -> bytes | None: if path in ("/sw.js", "/index.html", "/manifest.json"): return NO_CACHE if path == "/version.json": return NO_STORE if path.startswith("/assets/"): return IMMUTABLE if path.endswith((".js", ".css")) and not path.startswith("/assets/"): return NO_CACHE return None class CacheControlMiddleware: def __init__(self, app: ASGIApp) -> None: self.app = app async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if scope["type"] != "http": await self.app(scope, receive, send) return path = scope.get("path", "") cache_control = _cache_control_for_path(path) async def send_wrapper(message: dict) -> None: if message["type"] == "http.response.start" and cache_control is not None: headers = list(message.get("headers", [])) headers = [(k, v) for k, v in headers if k.lower() != b"cache-control"] headers.append((b"cache-control", cache_control)) message = {**message, "headers": headers} await send(message) await self.app(scope, receive, send_wrapper)