- options (cms alias of public.seo.enabled, breadcrumbs, links.newTabHint,
rootFiles, resolveFiles), the new runtime keys and the moved purge keys
- the resolve and site answer contract, one JSON-LD graph, root files,
the purge route, 404 report, labels and tokens, the smoke runs
- useSeoLabels(): the L8 dictionary (en, pl) of the page's content locale
(resolve locale, then html_lang, then en), overridable and extendable in
app.config.ts under seo.labels; no i18n dependency
- seo-tokens.css (spacing, colour, small type, breadcrumb separator) and
seo-base.css (.seo-visually-hidden, the focus ring of layer links), loaded
before the app's CSS and styling only .seo-* classes
- server/middleware/seo-root.ts proxies /robots.txt, /sitemap.xml,
/sitemap-<name>.xml, /llms.txt and the verification and IndexNow key
files the site answer lists in root_files, with the backend's status,
content type and X-Robots-Tag; a backend failure is 503 Retry-After 60
- server/lib/site.ts caches GET /_seo/api/v1/site (300 s, cleared by the
purge); a backend without it (404) keeps the v0.1.1 behaviour: no root
proxies, the verification lookup by name
- the 404 report and the verification lookup honour seo.cms and rootFiles
- smoke runs for the layer off (seo.cms and the v0.1.1 enabled switch), the
CMS down (fail open) and no 404 token; npm run purge:check
- 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
- the Nitro middleware answers redirect (301/302, Location from the answer
only, same-site targets as paths as in v0.1.1) and gone (410) before the
render and the route cache, sets X-Robots-Tag, and answers 404 for a
pagination.invalid answer; other not_found answers stay with Nuxt
- resolve answers cached in an LRU (seo.resolveCacheTtl, default 60 s,
1000 entries) with in-flight de-duplication; a clear detaches loads in
flight so no answer fetched before a purge is stored after it
- the playground route-caches /blog/** (swr 300)
- Nitro middleware resolves page requests once and hands the answer to the
render (event.context.seo); the route middleware reuses it
- useCmsSeo: html lang, hreflang links, og:locale and exactly one JSON-LD
script with one @graph (CMS nodes plus useSchemaNode nodes, merged by @id)
- local module (configKey seo): cms (alias of public.seo.enabled),
breadcrumbs, links.newTabHint, rootFiles, resolveFiles
- GET /api/__seo__/resolve for client navigation through the Nuxt server
- smoke harness: count=, exact header=, noheader=, reqheader=, repeated
options, resolves/apicalls/noreport lines, --no-site; v0.1.1 suite runs
unchanged against a backend without /site