diff --git a/packages/docs-redirect/README.md b/packages/docs-redirect/README.md index 75d7dd02..0af6900e 100644 --- a/packages/docs-redirect/README.md +++ b/packages/docs-redirect/README.md @@ -18,12 +18,22 @@ A tiny redirect service that replaces the old documentation site at symbol in the new tree; - anything without an exact new page (a handful of removed API symbols such as the `meta` module and `Presenter`) falls back to the closest section index. -- **`src/redirects.json`** — the generated map (committed). Regenerate with - `npm run build` whenever the docs are restructured. +- **`src/redirects.json`** — the generated map (committed), and the source of + truth the server reads at runtime. Regenerate with `npm run build` whenever + the docs are restructured, then commit the result. - **`src/server.mjs`** — a zero-dependency HTTP server that looks up the request path and issues the redirect. Unknown paths fall back to the docs home. Runs under Node or Bun. +> **Deploying / regenerating:** the TypeDoc API pages under +> `packages/docs/src/content/api-reference/**` are generated by the docs build +> (`npm run api:generate`) and are **not** committed. `build-map.mjs` therefore +> refuses to overwrite `redirects.json` when that content is missing (it warns +> and keeps the committed map), so a deploy that runs `npm run build` without +> the docs toolchain still serves the correct committed map instead of dropping +> every `/api/*` redirect to the docs home. To actually regenerate, run it from +> a full checkout where the docs `api:generate` has run. + ## Usage ```bash diff --git a/packages/docs-redirect/src/build-map.mjs b/packages/docs-redirect/src/build-map.mjs index c11af2e6..995cb1a0 100644 --- a/packages/docs-redirect/src/build-map.mjs +++ b/packages/docs-redirect/src/build-map.mjs @@ -11,8 +11,14 @@ // // Run: npm run build (from packages/docs-redirect) -import {readdirSync, readFileSync, statSync, writeFileSync} from 'node:fs'; -import {dirname, join, relative} from 'node:path'; +import { + existsSync, + readdirSync, + readFileSync, + statSync, + writeFileSync, +} from 'node:fs'; +import {basename, dirname, join, relative} from 'node:path'; import {fileURLToPath} from 'node:url'; const here = dirname(fileURLToPath(import.meta.url)); @@ -136,7 +142,41 @@ function collectRoutes(dir) { return routes; } +// The TypeDoc API pages (api-reference/**) are generated by the docs build +// (`npm run api:generate` in packages/docs) and are NOT committed to git. If this +// script runs where the docs content is missing or incomplete (e.g. a standalone +// deploy of this service), regenerating would silently drop every /api/* redirect +// to the docs home. Guard against that by keeping the committed redirects.json +// rather than overwriting it with a broken map. +function keepCommittedOrFail(reason) { + console.warn(`[build-map] ${reason}`); + if (existsSync(OUT)) { + console.warn( + `[build-map] keeping the committed ${basename(OUT)} unchanged.`, + ); + process.exit(0); + } + console.error( + `[build-map] no existing ${basename(OUT)} to preserve. Run the docs build ` + + `(npm run api:generate in packages/docs) before generating the map.`, + ); + process.exit(1); +} + +if (!existsSync(CONTENT_DIR)) { + keepCommittedOrFail(`docs content dir not found at ${CONTENT_DIR}.`); +} const routes = collectRoutes(CONTENT_DIR); +const apiPageCount = [...routes].filter(r => + r.startsWith('api-reference/'), +).length; +if (apiPageCount < 200) { + keepCommittedOrFail( + `docs content looks incomplete: found ${apiPageCount} api-reference ` + + `pages (expected 400+); the generated TypeDoc pages are probably missing.`, + ); +} + const has = route => routes.has(route); const toUrl = route => TARGET_ORIGIN + NEW_BASE + (route ? '/' + route : '');