From b4934a95383f9eac211c5016a0802798f7e3e1b9 Mon Sep 17 00:00:00 2001 From: lucasrodes Date: Tue, 19 May 2026 15:31:46 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A4=96=20301=20legacy=20/en/l?= =?UTF-8?q?atest=20URLs=20to=20canonical=20paths?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Existing inbound links from blog posts, Slack, bookmarks etc. point at the ReadTheDocs URL shape (/en/latest/...). Strip that segment in the umbrella router before subproject routing so links continue to resolve on docs-cf.owid.io and the eventual docs.owid.io cut-over. Examples: /projects/etl/en/latest/ → /projects/etl/ /projects/owid-grapher-py/en/latest/x → /projects/owid-grapher-py/x /en/latest/ → / Co-Authored-By: Claude Opus 4.7 (1M context) --- _worker.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/_worker.js b/_worker.js index 8d2f99f..737835a 100644 --- a/_worker.js +++ b/_worker.js @@ -17,10 +17,20 @@ const SUBPROJECTS = { "/projects/owid-grapher-py/": "https://owid-grapher-py-docs.pages.dev", }; +// Legacy ReadTheDocs URLs include an /en/latest segment (e.g. +// /projects/etl/en/latest/, /en/latest/). 301 to the canonical form so +// existing inbound links from blog posts / Slack / bookmarks keep working. +const RTD_LEGACY = /\/en\/latest(\/|$)/; + export default { async fetch(request, env) { const url = new URL(request.url); + if (RTD_LEGACY.test(url.pathname)) { + url.pathname = url.pathname.replace(RTD_LEGACY, "$1") || "/"; + return Response.redirect(url.toString(), 301); + } + for (const [prefix, origin] of Object.entries(SUBPROJECTS)) { if (url.pathname.startsWith(prefix)) { const target = `${origin}${url.pathname}${url.search}`;