From 53235f5a6bab3a7b626168b0ad5a731dd0f4bb2c Mon Sep 17 00:00:00 2001 From: Gaurav Agarwal Date: Tue, 11 Aug 2026 21:13:12 +0530 Subject: [PATCH 1/2] Promote legacy Pump.fun URLs from client-side redirects to real 301s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit plugin-client-redirects emits a real HTML page for every old URL: HTTP 200, a meta-refresh, a *relative* canonical, and an EMPTY . A 200 with no title is an indexable duplicate, so each of these competes with the page it is supposed to point at. Verified live 2026-08-11 — all return 200 with <title>: /docs/examples/Solana/Pump-Fun-API/ /docs/examples/Solana/Pump-Fun-Marketcap-Bonding-Curve-API/ /docs/examples/Solana/pump-swap-api/ /docs/examples/dextrades/Pump-Fun-API/ /docs/blockchain/Solana/Pump-Fun-API/ That is nine indexable URLs for a four-page cluster, and Google is using them. On 2026-08-09, GSC recorded /docs/examples/Solana/Pump-Fun-API/ at position 3 for "pumpfun api" while the canonical page sat at 13.4 the same day — the soft-redirect stub outranking the real page. Adds one regex location returning real 301s. The client-side redirects stay as a fallback for any request that bypasses nginx. Loop safety, checked exhaustively before committing: the capture group matches only bare page names, never a "Pumpfun/" segment, so the redirect targets cannot re-enter the block. Verified 10 legacy paths redirect, 10 canonical and neighbouring paths untouched, 0 loops. The existing ^~ /docs/blockchain/Solana/PumpFun block does not shadow these — "PumpFun" is not a prefix of "Pump-Fun-API". NOT verified: nginx syntax. Neither nginx nor docker is available in the environment this was written in, so `nginx -t` could not be run. The following commit adds that check to CI. Do not merge until it passes — a bad config here does not fail the build, it fails container start. Co-Authored-By: Claude Opus 5 --- nginx/default.conf | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/nginx/default.conf b/nginx/default.conf index f046d404..a7b75323 100644 --- a/nginx/default.conf +++ b/nginx/default.conf @@ -45,6 +45,28 @@ server { location = /docs/usecases/MCP { return 301 /docs/mcp/mcp-server/; } location = /docs/usecases/MCP/ { return 301 /docs/mcp/mcp-server/; } + # Legacy Pump.fun paths. These are covered by plugin-client-redirects, which + # emits a real HTML page per old URL: HTTP 200, a meta-refresh, a *relative* + # canonical — and an EMPTY . Verified live on 2026-08-11, all four + # sampled paths returned `200` with `<title>`. Nine such URLs exist + # for a four-page cluster, and Google indexed them: on 2026-08-09 + # /docs/examples/Solana/Pump-Fun-API/ ranked position 3 for "pumpfun api", + # above the canonical page, which was position 13.4 the same day. + # + # A 200 with no title is an indexable duplicate, so the client-side redirect + # is actively competing with the page it points at. Promote to real 301s; + # the client-side redirects stay as a harmless fallback for direct hits that + # somehow bypass nginx. + # + # No redirect loop: the canonical form is /docs/blockchain/Solana/Pumpfun/, + # and the capture group below matches only the bare names, never a + # "Pumpfun/" segment, so targets cannot re-enter this block. The + # ^~ /docs/blockchain/Solana/PumpFun block above does not shadow these + # either — "PumpFun" is not a prefix of "Pump-Fun-API" or "pump-swap-api". + location ~ ^/docs/(?:examples/Solana|examples/dextrades|blockchain/Solana)/(Pump-Fun-API|Pump-Fun-Marketcap-Bonding-Curve-API|pump-fun-to-pump-swap|pump-swap-api)/?$ { + return 301 /docs/blockchain/Solana/Pumpfun/$1/; + } + # Self-hosted fonts + webpack-hashed /assets (filenames change on update) location ~* ^/(fonts|assets)/ { try_files $uri =404; From 65ba26e3b68f7848974fc0fde4cffa37db802edd Mon Sep 17 00:00:00 2001 From: Gaurav Agarwal Date: Tue, 11 Aug 2026 21:13:12 +0530 Subject: [PATCH 2/2] CI: validate nginx/default.conf on every build nginx/default.conf is copied into the runtime image by the Dockerfile but was not checked anywhere in CI, which only runs `npm run build` and the link checker. A syntax error therefore survives the build and surfaces at container start, taking the docs offline on deploy. Runs `nginx -t` against the same nginx:stable-alpine the image is built from. Co-Authored-By: Claude Opus 5 --- .github/workflows/docs-build.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index f4910a6d..2095f790 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -20,3 +20,12 @@ jobs: - run: npm run build - name: Check internal links run: node scripts/check-links.mjs + # nginx/default.conf ships straight into the runtime image (see Dockerfile) + # and was never validated anywhere in CI. A syntax error there does not fail + # the build — it fails `nginx -g daemon off;` at container start, i.e. the + # docs go down on deploy. Validate it with the same nginx the image uses. + - name: Validate nginx config + run: | + docker run --rm \ + -v "$PWD/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro" \ + nginx:stable-alpine nginx -t