Files
vue-seo-layer/lib/options.ts
Jakub Zych 3abc986f42 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
2026-11-04 11:49:21 +01:00

37 lines
1.8 KiB
TypeScript

// The layer's pagination and HTML-sitemap module options normalised for
// the runtime config (lib/seo-module.ts) and their readers in app and
// server code. Pure, so `node --test` drives it.
export interface SeoPaginationOption {
form: 'query' | 'path'
param: string
segments: Record<string, string>
}
export type SeoHtmlSitemapOption = { paths: Record<string, string> } | false
/** The pagination option with its defaults, as the runtime config carries it. */
export function paginationOption(value: unknown): SeoPaginationOption {
const v = value !== null && typeof value === 'object' ? (value as Record<string, unknown>) : {}
const segments: Record<string, string> = {}
const raw = v.segments !== null && typeof v.segments === 'object' ? (v.segments as Record<string, unknown>) : {}
for (const [locale, segment] of Object.entries(raw)) if (typeof segment === 'string' && /^[\p{L}\p{N}_-]+$/u.test(segment)) segments[locale] = segment
return {
form: v.form === 'path' ? 'path' : 'query',
param: typeof v.param === 'string' && /^[A-Za-z0-9_-]+$/.test(v.param) ? v.param : 'page',
segments,
}
}
/** The HTML sitemap option: false, or the paths (each '/' plus at least one character). */
export function htmlSitemapOption(value: unknown): SeoHtmlSitemapOption {
if (value === false) return false
const v = value !== null && typeof value === 'object' ? (value as Record<string, unknown>) : {}
const paths: Record<string, string> = {}
const raw = v.paths !== null && typeof v.paths === 'object' ? (v.paths as Record<string, unknown>) : {}
for (const [locale, path] of Object.entries(raw)) {
if (typeof path === 'string' && /^\/[^?#\s]+$/.test(path) && !path.includes(':') && !path.includes('*')) paths[locale] = path.replace(/\/+$/, '')
}
return { paths }
}