fix: strip trailing slash in normalize helpers
Deploy / verify (push) Successful in 36s
Deploy / deploy (push) Successful in 52s

trailingSlash='always' caused [...slug] rest-param to capture with
trailing slash. normalizePageSlug/normalizePostSlug only stripped
leading slash, so fallback match failed and pages 404'd.

Strip both leading and trailing slashes; normalize once at entry of
getPageBySlug/getPostBySlug.
This commit is contained in:
Peter Meier
2026-04-17 22:50:21 +02:00
parent 5469b4c197
commit 8dcfeb64c7
+16 -25
View File
@@ -230,9 +230,9 @@ export type ContentGetOptions = {
resolve?: string[];
};
/** Führenden Slash entfernen (CMS kann "slug": "/about" liefern). */
/** Führenden + abschließenden Slash entfernen (CMS "slug": "/about"; Route-Param mit trailing slash). */
function normalizePageSlug(s: string | undefined): string {
return (s ?? "").replace(/^\//, "").trim();
return (s ?? "").replace(/^\/+|\/+$/g, "").trim();
}
/**
@@ -253,27 +253,20 @@ export async function getPageBySlug(
u.searchParams.set("_resolve", options.resolve.join(","));
return fetch(u.toString());
};
let res = await trySlug(slug);
console.log(`[getPageBySlug] slug="${slug}" first=${res.status}`);
if (res.status === 404 && !slug.startsWith("/")) {
res = await trySlug("/" + slug);
console.log(`[getPageBySlug] slug="${slug}" leading-slash=${res.status}`);
const normSlug = normalizePageSlug(slug);
let res = await trySlug(normSlug);
if (res.status === 404) {
res = await trySlug("/" + normSlug);
}
if (res.status === 404) {
const items = await getPages();
const norm = normalizePageSlug(slug);
console.log(`[getPageBySlug] fallback items=${items.length} norm="${norm}"`);
const match = items.find(
(p) =>
normalizePageSlug(p.slug) === norm ||
normalizePageSlug(p._slug) === norm ||
p._slug === slug ||
p.slug === slug,
normalizePageSlug(p.slug) === normSlug ||
normalizePageSlug(p._slug) === normSlug,
);
console.log(`[getPageBySlug] match=${match?._slug ?? 'NONE'}`);
if (match?._slug) {
res = await trySlug(match._slug);
console.log(`[getPageBySlug] match fetch=${res.status}`);
}
}
if (res.status === 404) return null;
@@ -427,9 +420,9 @@ export async function getFooterBySlug(
/** Post-Eintrag (Single Source of Truth: RustyCMS OpenAPI). */
export type PostEntry = components["schemas"]["post"];
/** Normalisiert Post-Slug für URL (führenden Slash entfernen). */
/** Normalisiert Post-Slug für URL (führenden + trailing Slash entfernen). */
function normalizePostSlug(s: string | undefined): string {
return (s ?? "").replace(/^\//, "").trim();
return (s ?? "").replace(/^\/+|\/+$/g, "").trim();
}
/**
@@ -450,19 +443,17 @@ export async function getPostBySlug(
u.searchParams.set("_resolve", options.resolve.join(","));
return fetch(u.toString());
};
let res = await trySlug(slug);
if (res.status === 404 && !slug.startsWith("/")) {
res = await trySlug("/" + slug);
const normSlug = normalizePostSlug(slug);
let res = await trySlug(normSlug);
if (res.status === 404) {
res = await trySlug("/" + normSlug);
}
if (res.status === 404) {
const items = await getPosts();
const norm = normalizePostSlug(slug);
const match = items.find(
(p) =>
normalizePostSlug(p.slug) === norm ||
normalizePostSlug(p._slug) === norm ||
p._slug === slug ||
p.slug === slug,
normalizePostSlug(p.slug) === normSlug ||
normalizePostSlug(p._slug) === normSlug,
);
if (match?._slug) {
res = await trySlug(match._slug);