File
Blob: src/worker/cache/policy.ts
| 1 | import type { CacheContext } from "./cache"; |
| 2 | |
| 3 | // Cache-policy discriminator used by visibility-aware request paths to |
| 4 | // decide whether the shared Workers Cache may be read or written. Public |
| 5 | // repositories cache freely; private repositories must bypass shared |
| 6 | // cache reads/writes regardless of upstream success. |
| 7 | export type SharedCachePolicy = "allow-shared-cache" | "bypass-shared-cache"; |
| 8 | |
| 9 | // CacheContext memo flag tags. `no-cache-read`/`no-cache-write` are honored |
| 10 | // by the shared cache helpers; route handlers that mark a request private |
| 11 | // must set both before calling any cache-aware loader. |
| 12 | const NO_CACHE_READ = "no-cache-read"; |
| 13 | const NO_CACHE_WRITE = "no-cache-write"; |
| 14 | |
| 15 | // Marks a request as private so any downstream shared-cache lookup or |
| 16 | // write is skipped. Idempotent: callers can mark private once at gate |
| 17 | // time and trust that all subsequent helpers honor it. |
| 18 | export function markRequestPrivate(cacheCtx: CacheContext): void { |
| 19 | cacheCtx.memo = cacheCtx.memo || {}; |
| 20 | cacheCtx.memo.flags = cacheCtx.memo.flags || new Set<string>(); |
| 21 | cacheCtx.memo.flags.add(NO_CACHE_READ); |
| 22 | cacheCtx.memo.flags.add(NO_CACHE_WRITE); |
| 23 | } |
| 24 | |
| 25 | // Returns true if the request was marked private (private repo, sensitive |
| 26 | // data path, etc.). Used to gate shared-cache reads/writes and to pick the |
| 27 | // `Cache-Control` response header. |
| 28 | export function isRequestPrivate(cacheCtx: CacheContext | undefined): boolean { |
| 29 | return cacheCtx?.memo?.flags?.has(NO_CACHE_READ) === true; |
| 30 | } |
| 31 | |
| 32 | // HTTP `Cache-Control` value for responses serving repo data over Git or |
| 33 | // data APIs: |
| 34 | // - `mutating: true` -> always "no-store" (credentialed mutating paths |
| 35 | // such as receive-pack must never sit in shared caches). |
| 36 | // - private (membership-derived) request -> "no-store". |
| 37 | // - otherwise -> "no-cache" so downstream caches re-validate but may |
| 38 | // reuse bodies briefly. |
| 39 | export function responseCacheControl( |
| 40 | cacheCtx: CacheContext | undefined, |
| 41 | options?: { mutating?: boolean } |
| 42 | ): "no-store" | "no-cache" { |
| 43 | if (options?.mutating) return "no-store"; |
| 44 | return isRequestPrivate(cacheCtx) ? "no-store" : "no-cache"; |
| 45 | } |