feat(19.3-04): shared site cache purge route POST /api/__site__/cache/purge
- server/lib/siteCachePurge.ts: authorizeSitePurge, purgeSiteRouteCache,
parseSitePurgeEvent (kinds: lower-case letters and underscores)
- the route reads runtimeConfig.siteCache.purgeToken
(NUXT_SITE_CACHE_PURGE_TOKEN), 404 when off or proxied, 401 unauthorized
- route rule '/api/__site__/**': { cache: false }
- sitePurge specs with sha256 pins of the two shared files
- version 0.2.0
This commit is contained in:
24
README.md
24
README.md
@@ -3,7 +3,7 @@
|
||||
A Nuxt 4 layer that renders a FAQ of the SummerCMS FAQ plugin as native `<details>` items.
|
||||
|
||||
```bash
|
||||
pnpm add git+https://git.golem15.com/golem15/vue-faq-layer.git#v0.1.0
|
||||
pnpm add git+https://git.golem15.com/golem15/vue-faq-layer.git#v0.2.0
|
||||
```
|
||||
|
||||
## Overview
|
||||
@@ -18,6 +18,7 @@ The layer is neutral: it ships no site colours, no site copy and no Nuxt modules
|
||||
- **`FaqList`** and **`FaqItem`**: one native `<details>` per question in API order, the question in `<summary>` with a CSS chevron (no animation under `prefers-reduced-motion`), the answer below. All items start closed (`openFirst` opens the first). With `exclusive`, the items share a `name`, so the browser keeps one open at a time.
|
||||
- **HTML**: the description and answers are HTML the FAQ API sanitizes on output; the layer renders them with `v-html` and adds no client sanitizer. Questions are plain text.
|
||||
- **Empty states**: a missing FAQ (404), a failed request or a FAQ without items renders nothing, or the `#fallback` slot. There is never an empty heading.
|
||||
- **Site cache purge**: the shared route `POST /api/__site__/cache/purge` drops the site's route cache when the backend saves a FAQ (or a menu or post, through the other core layers). See [Site cache purge](#site-cache-purge).
|
||||
- **Rate limits**: server-side fetches forward the visitor's `x-forwarded-for` (also on route-cached renders), so the API's per-client throttle sees visitors, not the Nuxt server.
|
||||
|
||||
## Usage
|
||||
@@ -58,8 +59,27 @@ export default defineNuxtConfig({
|
||||
| `runtimeConfig.faq.apiBase` | `http://127.0.0.1:8096/_faq/api/v1` | `NUXT_FAQ_API_BASE` (server only, used for SSR) |
|
||||
| `runtimeConfig.public.faq.apiBase` | `/_faq/api/v1` | `NUXT_PUBLIC_FAQ_API_BASE` (browser, same origin) |
|
||||
|
||||
| `runtimeConfig.siteCache.purgeToken` | `''` (route off) | `NUXT_SITE_CACHE_PURGE_TOKEN` (server only; at least 32 characters) |
|
||||
|
||||
The base URLs always come from runtime config, never from request input. In production the web server routes `/_faq/` to the SummerCMS binary.
|
||||
|
||||
## Site cache purge
|
||||
|
||||
A site that route-caches its pages (for example `routeRules: { '/**': { swr: 300 } }`) shows an admin edit only when the cache window ends. The layer ships the shared purge route that the SummerCMS backend calls after an admin save commits:
|
||||
|
||||
```
|
||||
POST /api/__site__/cache/purge
|
||||
Authorization: Bearer <NUXT_SITE_CACHE_PURGE_TOKEN>
|
||||
{"kind":"faq","slug":"shipping"}
|
||||
→ {"purged": <n>}
|
||||
```
|
||||
|
||||
- It removes every entry of Nitro's route cache (pages, their `_payload.json` and feeds) and logs `[site-cache] purge: …` with the kind and slug.
|
||||
- Set `NUXT_SITE_CACHE_PURGE_TOKEN` to the backend's `site_cache.purge_token` (at least 32 characters) and point the backend's `site_cache.purge_url` at `http://127.0.0.1:<port>/api/__site__/cache/purge`. Without a token of that length the route answers 404.
|
||||
- It answers 404 to any request that came through a reverse proxy (`X-Forwarded-For`, `X-Real-IP` or `Forwarded`), so only the backend on the same machine reaches it, and 401 to a missing or wrong bearer token (compared in constant time).
|
||||
- The layer adds the route rule `'/api/__site__/**': { cache: false }`; without it, a site-wide `swr` rule would answer the purge from the cache.
|
||||
- vue-journal-layer, vue-menu-layer and vue-faq-layer ship the same `server/lib/siteCachePurge.ts` and `server/api/__site__/cache/purge.post.ts` byte for byte (a test pins their sha256), so a site that extends several of them gets one route, whichever copy Nitro keeps.
|
||||
|
||||
## API
|
||||
|
||||
The layer expects the FAQ plugin's public API:
|
||||
@@ -108,6 +128,6 @@ Commit, tag `vX.Y.Z` (annotated) and push the tag; apps pin `#vX.Y.Z` in their d
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
pnpm test # node --test: the client
|
||||
pnpm test # node --test: the client and the site cache purge
|
||||
pnpm build:playground && pnpm smoke:ssr # SSR of the playground against testing/fixture-api.mjs
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user