feat: browsers revalidate route-cached pages; document the site cache purge
- privateRevalidate sets max-age=0 on cache-control values with s-maxage - server/plugins/journal-revalidate.ts wraps res.setHeader per request, so Nitro's 200 and h3's 304 answers both carry it - purge-check: max-age=0 on 200 and 304, purged _payload.json, a second purge after re-caching, X-Real-IP refused, 404 on a server without a token - README: cachePurgeToken row and a Site cache purge section
This commit is contained in:
29
server/plugins/journal-revalidate.ts
Normal file
29
server/plugins/journal-revalidate.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// Browser revalidation of route-cached pages. Nitro's route cache answers
|
||||
// 200 with `cache-control: s-maxage=<n>, stale-while-revalidate`, which
|
||||
// gives browsers no max-age, so they apply heuristic freshness from
|
||||
// Last-Modified; a conditional request it answers 304 with
|
||||
// `public, max-age=<n>, s-maxage=<n>`, so after one revalidation a browser
|
||||
// could reuse its copy for the whole TTL, past any site cache purge.
|
||||
//
|
||||
// This plugin passes every cache-control value a response sets through
|
||||
// privateRevalidate: values with s-maxage get max-age=0, so browsers ask on
|
||||
// each view (a cheap 304 while the page is unchanged) and shared caches keep
|
||||
// s-maxage. The 304 path ends the response before any beforeResponse hook
|
||||
// runs, so the rewrite wraps the request's res.setHeader instead. Static
|
||||
// assets carry no s-maxage and are untouched.
|
||||
|
||||
import { privateRevalidate } from '../../app/utils/siteCache.ts'
|
||||
|
||||
export default defineNitroPlugin((nitroApp) => {
|
||||
nitroApp.hooks.hook('request', (event) => {
|
||||
const res = event.node.res
|
||||
const setHeader = res.setHeader
|
||||
res.setHeader = function (name, value) {
|
||||
if (typeof name === 'string' && name.toLowerCase() === 'cache-control') {
|
||||
if (typeof value === 'string') value = privateRevalidate(value)
|
||||
else if (Array.isArray(value)) value = value.map((v) => privateRevalidate(String(v)))
|
||||
}
|
||||
return setHeader.call(this, name, value)
|
||||
} as typeof res.setHeader
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user