Skip to content

feat(docs): ship the translated docs mirrors in the npm package and Docker image - #18869

Merged
diegosouzapw merged 5 commits into
release/v3.8.53from
feat/ship-docs-mirrors-npm-docker-1103
Nov 4, 2026
Merged

diegosouzapw merged 5 commits into
release/v3.8.53from
feat/ship-docs-mirrors-npm-docker-1103

Conversation

@diegosouzapw

@diegosouzapw diegosouzapw commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

⚠️ base-red inherited: #18791

#18768 made /docs/<section>/<PAGE> serve the translated mirror when the NEXT_LOCALE cookie asks for it, but npm and Docker installs carried no mirrors, so they always served English. The owner decided both should ship them. This PR does that, and ships only the mirrors the route can actually serve.

What ships

scripts/build/docsMirrorRuntime.mjs defines the set: docs/i18n/<locale>/docs/<section>/<PAGE>.md for the 11 sections source.config.ts compiles, minus the 4 operator-internal security pages it excludes (STEALTH_GUIDE, SOCKET_DEV_FINDINGS, MITM-TPROXY-DECRYPT, PUBLIC_CREDS). On the current tree that is 8,885 files. The README, CHANGELOG, AGENTS/CLAUDE/GEMINI, llm.txt and other locale-root mirrors, plus the features/ and plans/ mirrors the route never reaches, stay out. The renderer loads images from raw.githubusercontent.com, so no local asset is needed.

npm

  • pack-artifact-policy.ts gets path matchers next to its exact and prefix lists. The staging prune and the publish gate both allow exactly that set under dist/, nothing else under docs/i18n, and never at the tarball root. Every other guard is unchanged: node_modules ban, test leaks, MCP closure, provenance.
  • dist/docs/i18n/pt-BR/docs/getting-started/QUICK-START.md is now a required path, so the gate fails if the mirrors stop reaching dist/. They arrive through the standalone's docs/ copy, which already happened, and were pruned until now.
  • jsdom moves from devDependencies to dependencies. docsSanitizer.ts imports it, and npm never packs node_modules, so on an npm install the import failed and every translated page fell back to English. The lockfile diff only moves the root entry and drops "dev": true from jsdom and the 33 packages it pulls in (36.6 MiB on disk). No versions changed.
  • check:pack-boot now also asserts that the installed package has a mirror and node_modules/jsdom.

Docker

  • .dockerignore keeps docs/i18n/**, re-includes the 11 sections with !docs/i18n/*/docs/<section>/**/*.md, then re-excludes the 4 security pages. Docker applies these rules in order and the last match wins.
  • The Dockerfile needs no change. COPY . ./ brings the mirrors in, build-next-isolated copies docs/ into the standalone, and assembleStandalone already colocates jsdom whenever the bundle has docs/i18n (fix(docs): serve translated /docs pages for the selected locale #18768). The builder's npm ci installs dev dependencies, so jsdom is there either way. The runner copies the whole standalone. Dockerfile.bun follows the same path.

Sizes

Before After Delta
npm tarball, compressed 112,231,386 B 191,126,733 B +78.9 MB (+70%)
npm tarball, unpacked 526,860,583 B 900,877,139 B +374.0 MB
Tarball entries 33,956 42,841 +8,885
Installed package (npm install -g) 2,263 MB 2,656 MB +393 MB (mirrors + jsdom closure)
Docker build context, docs/i18n 0 files 8,885 files, 374.0 MB about 84 MB gzipped

For reference, the published 3.8.52 tarball is 114,391,796 B with 29,296 entries. The Docker numbers come from evaluating .dockerignore statically. I couldn't build the image here because there is no Docker daemon, so the image delta is estimated: the runner gets the same 374 MB through the standalone copy, plus jsdom's closure.

Pack and install time

Measured on a shared 18-core machine with load between 7 and 58 while other sessions were building, so treat these as rough:

Before After
build:cli 158 s 761 s (under heavier load; the only code-path difference is a smaller prune)
npm pack (staged copy, see below) 2,823 s 2,861 s
npm install -g from the tarball 2,144 s 1,171 s

npm pack run straight from the worktree went past 40 minutes without finishing. With the inspector attached, npm-packlist's ignore-walk was spending its time in minimatch, matching every entry against the ignore rules, and dist/.build/next/server/chunks alone has 20,615 entries. I packed a copy staged from files[] instead, with node_modules left out (npm never packs it). The before and after times are about the same because the 8,885 new files are small directories that cost far less than that chunk directory. This is relevant to #18791 (check:pack-artifact timing out): the cost is in the walk over dist/.build, not in this change.

Live test

I installed each tarball into a temporary prefix outside the repo, started omniroute serve from there on its own port with an isolated DATA_DIR, and stopped it by its process group when done.

Request Cookie Before (base) After
getting-started/QUICK-START none English, lang=en English, lang=en
getting-started/QUICK-START pt-BR English article, lang=pt-BR Portuguese article ("Etapa 1: Instale o OmniRoute")
getting-started/QUICK-START fa English article, dir=rtl Persian article, dir=rtl
getting-started/QUICK-START xx English, lang=en English, lang=en
architecture/RESILIENCE_GUIDE pt-BR English Portuguese (underscore file name)
getting-started/SELF_HOST_GUIDE (no fa mirror) fa English English article, lang=fa, dir=rtl
security/PUBLIC_CREDS pt-BR not found not found, byte-identical page; the mirror isn't in the tarball

The installed package also passes the publish policy's checks on the real tarball listing: no unexpected paths, nothing required missing, and no test leaks.

Tests

  • New tests/unit/docs-mirror-runtime-shipping.test.ts:
    • pins the sections and exclusions to source.config.ts;
    • checks that every shipped mirror resolves through the route's own path guard;
    • checks that the staging prune and the publish policy keep exactly the runtime set out of the real docs/i18n tree (10,273 files);
    • checks that .dockerignore, evaluated with Docker's ordering and parent-directory rules, lets exactly that set into the context;
    • checks that jsdom is a runtime dependency.
  • tests/helpers/dockerignore.ts holds that Docker-semantics evaluator. dockerignore-docs-coverage.test.ts now uses it in place of its own matcher, which ignored rule order and so would have let the security mirrors through. Its "excludes the heavy i18n tree" assertion now checks the locale-root and plans/ mirrors, plus that a page mirror is included, because the old assertion is exactly the behavior the owner changed.
  • pack-artifact-policy.test.ts: its pinned missing-required list gains the new required path.
  • check-pack-boot.test.ts: covers the new runtime contract.
  • assemble-standalone-docs-sanitizer-18699.test.ts: comments and one test name updated to say that Docker now carries mirrors. The assertions are unchanged.

No size ceilings changed. I found no tarball size or file-count budget in the repo. The pack gate's only limit is the Release-Green 60 min timeout, and check:build-scope counts only TS/JS files (12,620 of 13,500).

Ran: the focused unit files above plus electron-packaging, the pack closure suites and log-export-child-runner (all pass); the vitest suite docs-translated-page-18699 (16/16); check:build-scope; check:docs-all; Prettier and ESLint on the changed files (0 errors).

Not verified

  • No Docker image was built (no daemon here). The context is proven statically above; the CI Docker jobs will build it.
  • check:pack-artifact and check:pack-policy were not run as scripts, because they call the same slow npm pack --dry-run walk. I applied their path checks to the real tarball listing instead. The MCP closure check was not rerun; this change doesn't touch the MCP files.
  • Electron is unchanged. It still keeps all of docs/i18n/<locale>/docs/**, including the security-page mirrors this PR keeps out of npm and Docker.

Docs

docs/guides/I18N.md has a new "Translated /docs pages" subsection. Its 66 mirrors are not updated here.


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

…ocker image

The /docs route serves docs/i18n/<locale>/docs/<section>/<PAGE>.md when the
NEXT_LOCALE cookie asks for it (#18768), but npm and Docker installs carried no
mirrors and always fell back to English.

- scripts/build/docsMirrorRuntime.mjs defines the mirrors the route can serve:
  the sections source.config.ts compiles, minus its operator-internal pages.
- The pack policy allows exactly those under dist/ (path matchers), requires one
  sample mirror, and prepublish keeps them while pruning the rest of docs/i18n.
- .dockerignore re-includes the same set; assembleStandalone already colocates
  jsdom when a bundle carries mirrors.
- jsdom moves to dependencies: npm never packs node_modules, so the sanitizer
  import would otherwise fail on every npm install.
- check:pack-boot asserts the installed package has a mirror and jsdom.
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@diegosouzapw diegosouzapw added the queue Owner-approved: enter the Mergify merge queue (the label IS the merge approval) label Nov 3, 2026
@mergify

mergify Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

❌ Left the queue · checks interrupted

13 min in the queue, 1 min of it CI.

So far

Reason

The merge conditions cannot be satisfied: the checks were interrupted before producing a result

  • Merge integrity (changelog + generated skills)

Failing checks:

Hint

An interrupted check reported no result, so it says nothing about this pull request.
Look at the check run to find out why it stopped. A reclaimed runner or a cancelled workflow run are the usual causes.
You can then requeue the pull request, without updating it, by posting a @mergifyio queue comment.

Merge conditions not met when it left the queue

  • #check-pending=0
  • #check-success>=1
  • check-success=Gate / CI
  • check-success=Gate / Quality
  • check-success=Merge integrity (changelog + generated skills)
  • any of:
    • #check-failure=0
    • all of:
      • #check-failure=1
      • check-failure=Build (advisory)

Tick the box to put this pull request back in the merge queue (same as @mergifyio queue).

  • Requeue this pull request
1 merge condition met

Times in UTC · dashboard · how the merge queue works

@mergify mergify Bot added the queued label Nov 3, 2026
@mergify mergify Bot added dequeued and removed queued labels Nov 3, 2026
@mergify mergify Bot removed the dequeued label Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

CI Coverage Report

  • Coverage job: success
  • PR test policy: success

Coverage artifact was not available for this run.

@diegosouzapw
diegosouzapw merged commit b55b274 into release/v3.8.53 Nov 4, 2026
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

queue Owner-approved: enter the Mergify merge queue (the label IS the merge approval)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant