- 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
37 lines
1.8 KiB
TypeScript
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 }
|
|
}
|