Files
vue-seo-layer/nuxt.config.ts
Jakub Zych 691fa09b0f feat: shared site cache purge route clears the SEO caches
- POST /api/__site__/cache/purge, its library and the site config plugin
  moved from vue-journal-layer with the same contract (token rules, 404 for
  proxied requests unless allowProxied, deprecated siteCache names); the
  route also clears the resolve cache
- server/plugins/seo-cache-purge.ts clears the SEO caches after any 200
  purge, so an app whose journal, menu or FAQ layer copy of the route wins
  keeps fresh SEO answers until those copies are removed
- cachePurge and siteCache runtime keys; /api/__site__/** never cached
- testing/purge-check.mjs (CMS answer change, plus a redirect added for a
  route-cached page applying at once) and purge-token-check.mjs
2026-11-04 09:23:15 +01:00

102 lines
4.6 KiB
TypeScript

// vue-seo-layer: the frontend half of the SummerCMS SEO plugin
// (golem15.seo). For every page it asks GET /_seo/api/v1/resolve?url=…,
// enforces the redirect and 410 decisions, and sets the head (title,
// description, canonical, robots, Open Graph, X/Twitter, verification,
// hreflang, <html lang> and one JSON-LD @graph) from the answer with priority
// over the page's own tags. It also reports 404s to the plugin's log and
// serves the site's root files (verification files and, with a backend that
// answers /_seo/api/v1/site, robots.txt, the sitemaps, llms.txt and the
// IndexNow key). An app consumes it with `extends: ['vue-seo-layer']`.
//
// Every path below is absolute and built from this file's directory: a
// relative or ~ path in a layer config resolves against the consuming
// project, not the layer. The layer's only module is its own local one
// (lib/seo-module.ts); it pulls in no package.
import { fileURLToPath } from 'node:url'
const currentDir = fileURLToPath(new URL('.', import.meta.url))
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: false },
modules: [`${currentDir}lib/seo-module.ts`],
runtimeConfig: {
seo: {
// Server-only base for SSR calls (NUXT_SEO_API_BASE). It never comes
// from request input.
apiBase: 'http://127.0.0.1:8096/_seo/api/v1',
// Server-only origin of the Go binary for the root files
// (NUXT_SEO_BACKEND_BASE). Empty: apiBase without /_seo/api/v1, so
// http://127.0.0.1:8096 by default.
backendBase: '',
// Server-only bearer token of POST /notfound (NUXT_SEO_NOTFOUND_TOKEN),
// the backend's golem15.seo.notfound_token. Empty: 404s are not
// reported. Not under NUXT_SITE_: nuxt-site-config copies every
// NUXT_SITE_* variable into the site config, which is published in
// every page's payload.
notfoundToken: '',
// Server-only bearer token of the route report
// (NUXT_SEO_ROUTE_REPORT_TOKEN). Empty: notfoundToken is used.
routeReportToken: '',
// How long a resolve call may take before the page renders without it
// (NUXT_SEO_TIMEOUT_MS).
timeoutMs: 1500,
// Seconds a resolve answer stays in the layer's cache
// (NUXT_SEO_RESOLVE_CACHE_TTL); the site cache purge clears it. 0
// turns the cache off.
resolveCacheTtl: 60,
},
// The shared site cache purge route POST /api/__site__/cache/purge
// (moved here from the journal, menu and FAQ layers, same contract).
cachePurge: {
// Server-only bearer token (NUXT_CACHE_PURGE_TOKEN), the backend's
// site_cache.purge_token. Shorter than 32 characters, the route
// answers 404. Not under NUXT_SITE_: nuxt-site-config copies every
// NUXT_SITE_* variable into the site config, which is published in
// every page's payload.
token: '',
// NUXT_CACHE_PURGE_ALLOW_PROXIED: set it to true when the backend
// reaches the site through a TLS-terminating proxy (an https
// site_cache.purge_url on another host), which adds X-Forwarded-For,
// X-Real-IP or Forwarded. The route then accepts proxied requests and
// the bearer token is the only gate; unset, it answers 404 to any
// proxied request.
allowProxied: false,
},
// Deprecated (one release): the earlier names of cachePurge.token
// (NUXT_SITE_CACHE_PURGE_TOKEN) and cachePurge.allowProxied
// (NUXT_SITE_CACHE_ALLOW_PROXIED), read when the new ones are unset. The
// layer's server/plugins/site-cache-purge.ts strips them from the site
// config and logs a deprecation warning.
siteCache: {
purgeToken: '',
allowProxied: false,
},
public: {
seo: {
// Same-origin base for browser navigations (NUXT_PUBLIC_SEO_API_BASE).
// The site's proxy routes GET <base>/resolve to the backend; set it
// to /api/__seo__ to resolve through the Nuxt server instead.
apiBase: '/_seo/api/v1',
// NUXT_PUBLIC_SEO_ENABLED=false turns the layer off: no resolve
// calls, no head, no redirects, no root files, no 404 reports. The
// module option seo.cms (NUXT_PUBLIC_SEO_CMS) is an alias.
enabled: true,
},
},
},
// The layer's routes and the shared site routes are never route-cached.
// Nitro wraps every handler matching an app rule such as '/**': { swr } in
// its cached handler, which keys by path, does not skip POST and hides
// request headers, so the purge route would answer from the cache without
// running.
routeRules: {
'/api/__seo__/**': { cache: false },
'/api/__site__/**': { cache: false },
},
})