diff --git a/src/gateway/public-gateway.mjs b/src/gateway/public-gateway.mjs index b6c45ff..c83eacd 100644 --- a/src/gateway/public-gateway.mjs +++ b/src/gateway/public-gateway.mjs @@ -317,11 +317,27 @@ function rewriteBnsLinks(html) { } ); } -// Apply both transforms (base first, then link rewrite) — order doesn't -// matter because they touch disjoint constructs, but grouping them here -// means every text/html response goes through the same path. +// Strip `.html` from relative link targets in served HTML — so a link +// written as href="tld.html" reads as href="tld" in the browser bar. +// Only touches non-absolute URLs (leaves `https://…/x.html` alone — +// those are external and often out of our control). Preserves anchor +// and query, and skips the ".html" that's part of a filename like +// "foo.htmlx" (regex requires end/? / #). +function stripHtmlExt(html) { + return html.replace( + /\b(href\s*=\s*")([^"#?][^"#?]*)\.html(?=["#?])/gi, + (m, prefix, path) => { + if (/^\s*[a-z][a-z0-9+.-]*:/i.test(path)) return m; // absolute URL — leave alone + return prefix + path; + } + ); +} +// Apply the three transforms (base first, link rewrite, extension strip). +// Order doesn't matter across them because they touch disjoint constructs, +// but grouping them here means every text/html response goes through the +// same path. function transformHtml(html, baseHref) { - return rewriteBnsLinks(injectBase(html, baseHref)); + return stripHtmlExt(rewriteBnsLinks(injectBase(html, baseHref))); } const nx = (h) => `
${h} is not registered on the Bitcoin Cash chain.