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[]; 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 { 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(",")); u.searchParams.set("_resolve", options.resolve.join(","));
return fetch(u.toString()); return fetch(u.toString());
}; };
let res = await trySlug(slug); const normSlug = normalizePageSlug(slug);
console.log(`[getPageBySlug] slug="${slug}" first=${res.status}`); let res = await trySlug(normSlug);
if (res.status === 404 && !slug.startsWith("/")) { if (res.status === 404) {
res = await trySlug("/" + slug); res = await trySlug("/" + normSlug);
console.log(`[getPageBySlug] slug="${slug}" leading-slash=${res.status}`);
} }
if (res.status === 404) { if (res.status === 404) {
const items = await getPages(); const items = await getPages();
const norm = normalizePageSlug(slug);
console.log(`[getPageBySlug] fallback items=${items.length} norm="${norm}"`);
const match = items.find( const match = items.find(
(p) => (p) =>
normalizePageSlug(p.slug) === norm || normalizePageSlug(p.slug) === normSlug ||
normalizePageSlug(p._slug) === norm || normalizePageSlug(p._slug) === normSlug,
p._slug === slug ||
p.slug === slug,
); );
console.log(`[getPageBySlug] match=${match?._slug ?? 'NONE'}`);
if (match?._slug) { if (match?._slug) {
res = await trySlug(match._slug); res = await trySlug(match._slug);
console.log(`[getPageBySlug] match fetch=${res.status}`);
} }
} }
if (res.status === 404) return null; if (res.status === 404) return null;
@@ -427,9 +420,9 @@ export async function getFooterBySlug(
/** Post-Eintrag (Single Source of Truth: RustyCMS OpenAPI). */ /** Post-Eintrag (Single Source of Truth: RustyCMS OpenAPI). */
export type PostEntry = components["schemas"]["post"]; 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 { 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(",")); u.searchParams.set("_resolve", options.resolve.join(","));
return fetch(u.toString()); return fetch(u.toString());
}; };
let res = await trySlug(slug); const normSlug = normalizePostSlug(slug);
if (res.status === 404 && !slug.startsWith("/")) { let res = await trySlug(normSlug);
res = await trySlug("/" + slug); if (res.status === 404) {
res = await trySlug("/" + normSlug);
} }
if (res.status === 404) { if (res.status === 404) {
const items = await getPosts(); const items = await getPosts();
const norm = normalizePostSlug(slug);
const match = items.find( const match = items.find(
(p) => (p) =>
normalizePostSlug(p.slug) === norm || normalizePostSlug(p.slug) === normSlug ||
normalizePostSlug(p._slug) === norm || normalizePostSlug(p._slug) === normSlug,
p._slug === slug ||
p.slug === slug,
); );
if (match?._slug) { if (match?._slug) {
res = await trySlug(match._slug); res = await trySlug(match._slug);