feat: route report and drift check at server start

- the module writes #seo-routes (static paths and route patterns) from the
  resolved pages; options seo.routeReport, seo.pagination and
  seo.htmlSitemap reach the public runtime config
- seo-route-report: POST /registry/routes once per process with the
  route-report token, one retry after 60 s on failure, nothing without a
  token, with the layer off or with routeReport false
- seo-drift: one "[vue-seo-layer] drift:" warning per mismatch between
  the CMS's site answer (URL patterns, pagination, HTML sitemap paths)
  and the build
- GET /api/__seo__/site and useSeoSite()
- smoke grammar routereport and log, fixture registry route, drift run
This commit is contained in:
Jakub Zych
2026-11-04 11:49:21 +01:00
parent 9cc2cda924
commit 3abc986f42
21 changed files with 599 additions and 20 deletions

View File

@@ -0,0 +1,18 @@
// GET /api/__seo__/site: the CMS's site answer (GET <apiBase>/site, SEO
// plugin v0.2.0) through the layer's server and its cache, for useSeoSite()
// on the server and in the browser. Always 200 with {site: <answer> | null}:
// null with the layer off, with a backend before v0.2.0 (its /site answers
// 404) or with a backend that has not answered since start. Never
// route-cached ('/api/__seo__/**' cache false) and never indexed.
import { seoServerConfig } from '../../lib/config.ts'
import { siteAnswer } from '../../lib/site.ts'
export default defineEventHandler(async (event) => {
setResponseHeaders(event, { 'cache-control': 'no-store', 'x-robots-tag': 'noindex' })
const cfg = seoServerConfig(useRuntimeConfig(event))
if (!cfg.enabled) return { site: null }
const forwarded = event.context.seoForwardedFor as string | undefined
const state = await siteAnswer(cfg, forwarded ? { 'x-forwarded-for': forwarded } : {})
return { site: state.state === 'ok' ? state.site : null }
})