From 1f6f1712aae08c63573c253240d7b4b1bb4009f0 Mon Sep 17 00:00:00 2001 From: shigahi Date: Mon, 2 Mar 2026 21:50:32 +0100 Subject: [PATCH] Fix slug rewriting for *.notion.site users Two issues prevented slugs from working on *.notion.site: 1. Server-side: slug matching triggered a 302 redirect to /, which allowed Notion's client-side app to overwrite the URL with username-prefixed paths (e.g., /philipb/Page-Title-). Now the Worker fetches the Notion page directly and serves it at the slug URL without a redirect. 2. Client-side: the MutationObserver that triggers updateSlug() only fires when .notion-topbar appears, but published *.notion.site pages may not have this element. Added a 2-second fallback timer to ensure slug rewriting and popstate handling are initialized. Closes #55 Co-Authored-By: Claude Opus 4.6 --- src/code.ts | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/code.ts b/src/code.ts index 50c940f..28ee1ab 100644 --- a/src/code.ts +++ b/src/code.ts @@ -626,8 +626,18 @@ ${ const response = await fetch(url, rewriteImageOptions()); return applyCacheHeaders(response, url, 'image'); } else if (slugs.indexOf(url.pathname.slice(1)) > -1) { - const pageId = SLUG_TO_PAGE[url.pathname.slice(1)]; - return Response.redirect('https://' + MY_DOMAIN + '/' + pageId, 302); + const matchedSlug = url.pathname.slice(1); + const pageId = SLUG_TO_PAGE[matchedSlug]; + url.pathname = '/' + pageId; + response = await fetch(url.toString(), { + body: request.body, + headers: request.headers, + method: request.method, + }); + response = new Response(response.body, response); + response.headers.delete('Content-Security-Policy'); + response.headers.delete('X-Content-Security-Policy'); + return appendJavascript(response, SLUG_TO_PAGE, matchedSlug, url); } else { response = await fetch(url.toString(), { body: request.body, @@ -991,6 +1001,23 @@ ${ childList: true, subtree: true, }); + setTimeout(function() { + if (!redirected) { + redirected = true; + updateSlug(); + const onpopstate = window.onpopstate; + window.onpopstate = function() { + if (slugs.includes(getSlug())) { + const page = SLUG_TO_PAGE[getSlug()]; + if (page) { + history.replaceState(history.state, 'bypass', '/' + page); + } + } + onpopstate.apply(this, [].slice.call(arguments)); + updateSlug(); + }; + } + }, 2000); const replaceState = window.history.replaceState; window.history.replaceState = function(state) { if (arguments[1] !== 'bypass' && slugs.includes(getSlug())) return;