Skip to content

Point generated info_path at a URL path, not the plugin outputDir - #194

Merged
zoltan-baba merged 2 commits into
mainfrom
fix/api-info-path-locale-prefix
Aug 19, 2026
Merged

Point generated info_path at a URL path, not the plugin outputDir#194
zoltan-baba merged 2 commits into
mainfrom
fix/api-info-path-locale-prefix

Conversation

@ilanazholobovsky

@ilanazholobovsky ilanazholobovsky commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

What

info_path on all 164 generated *.api.mdx pages currently points at a filesystem path instead of a route, so the security-scheme link in the API Explorer resolves to a 404 on every API reference page. This fixes the pages and stops the next spec sync reintroducing it.

Where to see it. On any API reference page, the right-hand API Explorer panel has a header bar reading AUTHORIZATION: AUTHORIZATION, and under it a box listing name: Authorization / type: apiKey / in: header. The Authorization value next to name: is a link — the theme renders it as <Link to={infoAuthPath}>{name ?? key}</Link>, so the label is the security scheme's name from the spec, not the word "authentication". Only the href contains #authentication.

Live on docs.bitrise.ioactivity-list:

link text: "Authorization"
href:      /en/docs/bitrise-api/api-reference/bitrise-api#authentication  →  404

Scale honestly: it's a small link (80×13px, no underline, in a corner panel) so few readers will have hit it. It is wrong on all 164 pages, and the underlying value is what every future spec sync will keep corrupting — that's the reason to fix it rather than the click-through volume.

Why it broke

docusaurus-plugin-openapi-docs builds the value from its outputDir option, which is a filesystem path. It does have logic to turn that into a route — but the logic is guarded (src/index.ts, v5.0.2):

let infoBasePath = `${outputDir}/${item.infoId}`;
if (docRouteBasePath) {
  // ...strip docPath, rebuild from docRouteBasePath...
}
if (item.infoId) item.infoPath = infoBasePath;

docRouteBasePath is our docs.routeBasePath, which #186 changed from 'en' to ''. Empty string is falsy, so the guard stopped firing and the raw outputDir path started being written out.

That's why the value was correct before and wrong after: while routeBasePath was 'en' the block ran and produced en/bitrise-api/…. #186 set it to '', and the next regeneration — #192 (44 files) and #193 (120 files), merged today — wrote docs/bitrise-api/….

Why a bare path, not en/

The theme renders the value through Docusaurus's <Link> (docusaurus-theme-openapi-docs, theme/ApiExplorer/SecuritySchemes/index.tsx):

const infoAuthPath = `/${props.infoPath}#authentication`;
// ...
<Link to={infoAuthPath}>{name ?? key}</Link>

<Link> prepends the active locale's baseUrl unless the path already starts with it. So the value must be a bare route path with no locale prefix — same convention as body links, and for the same reason sync_mcp_docs.py's rewrite_internal_links gives in #189: a hardcoded en/ renders as /ja/en/… under the ja locale, which doesn't exist.

The first commit on this branch got that wrong and used en/. The second commit corrects it to a bare path. Verified on the deploy preview, all four combinations:

Build Reference Rendered href Status
en Bitrise CI /en/bitrise-api/api-reference/bitrise-api#authentication 200
ja Bitrise CI /ja/bitrise-api/api-reference/bitrise-api#authentication 200
en RDE /en/bitrise-rde-api/…/bitrise-remote-dev-environments-api#authentication 200
ja RDE /ja/bitrise-rde-api/…/bitrise-remote-dev-environments-api#authentication 200

Why the fix goes in patch-api-info.js

sync-api-references.yml runs clean-api-docsgen-api-docspatch-api-info.js on every spec change, so editing the generated files alone would be undone by the next sync. patch-api-info.js already exists to reapply what the plugin discards (displayed_sidebar, licence name, duplicate sidebar labels) — this is step 4 in the same pattern, idempotent and existsSync-guarded like the rest.

The expected value is derived from each target's own infoFile relative to docs.path, not hardcoded, so a future outputDir change can't silently reintroduce a filesystem prefix.

Fixing the plugin's falsy check upstream would be the real solution. This keeps us correct in the meantime without pinning or patching the package.

Why CI didn't catch it

Nothing reads info_path. scripts/check-links-source.js doesn't parse frontmatter at all, and it skips anchor validation under /bitrise-api/api-reference and /bitrise-rde-api/api-reference (GENERATED_ANCHOR_ROUTE_PREFIXES). Raised as TW-1815 — this is the third /en/-prefix bug in two days (cf. #186, #189), and the checker gap is what lets the class through.

Testing

  • Script run twice: second run reports "already correct" and writes nothing.
  • Diff is exactly one line per page, 164 pages, no collateral changes.
  • Merges cleanly into main.

Not verified: I confirmed the broken and fixed hrefs by reading the rendered DOM and fetching the target URLs, on production and on the preview. I did not get a click on the link itself to navigate — the element is small and may be overlapped. If that matters for review, worth a manual click on the preview.

The openapi-docs plugin derives each *.api.mdx's `info_path` frontmatter
from its `outputDir` option, which is a filesystem path
('docs/bitrise-api/api-reference'), and writes it out unchanged. The theme
then consumes that value as a URL rather than a doc id —
docusaurus-theme-openapi-docs, theme/ApiExplorer/SecuritySchemes/index.tsx:

    const infoAuthPath = `/${props.infoPath}#authentication`;

The href is emitted verbatim, so it never goes through Docusaurus's
locale/routeBasePath resolution and has to carry the locale prefix itself.
With `routeBasePath: ''` and `i18n.localeConfigs.en.baseUrl: '/en/'`, the
generated value resolves to /docs/... and 404s, breaking the Authentication
link on all 164 API reference pages.

Verified against production:
  /en/bitrise-api/api-reference/bitrise-api    -> 200
  /docs/bitrise-api/api-reference/bitrise-api  -> 404

Fixing the files alone would not hold: the sync workflow runs
clean-api-docs + gen-api-docs on every spec change, so the wrong value is
reintroduced each time. patch-api-info.js already exists to reapply fixes
the plugin discards, so the normalisation belongs there as step 4. The
expected value is derived from each target's own infoFile rather than
hardcoded, so a future outputDir change can't silently reintroduce it.

- patch-api-info.js: add step 4, idempotent, existsSync-guarded
- Regenerate the 164 affected *.api.mdx via the script (one line each)
@github-actions

Copy link
Copy Markdown

@ilanazholobovsky

Copy link
Copy Markdown
Collaborator Author

Verified on the deploy preview:

Authentication link href Result
Preview — activity-list /en/bitrise-api/api-reference/bitrise-api#authentication loads, #authentication anchor present
Preview — codespaces-service-list-sessions /en/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api#authentication 200
Production today /en/docs/bitrise-api/api-reference/bitrise-api#authentication 404

Correction to the description above: the broken URL is /en/docs/…, not /docs/….
Docusaurus's baseUrl helper prepends /en/ when the path doesn't already start
with it — which is also why en/… is safe and doesn't become /en/en/….

The previous commit set `info_path` to `en/...`. That fixes the en build but
breaks the ja one, and it contradicts the convention #189 established.

The theme renders the value through Docusaurus's <Link>:

    const infoAuthPath = `/${props.infoPath}#authentication`;
    <Link to={infoAuthPath}>...</Link>

<Link> prepends the active locale's baseUrl unless the path already starts
with it. So `en/...` renders as /en/... on the en build (correct, since it
already carries the prefix) but as /ja/en/... on the ja build, which doesn't
exist. Verified on the deploy preview:

    /ja/bitrise-api/api-reference/activity-list
      -> Authentication href /ja/en/bitrise-api/api-reference/bitrise-api  -> 404

That is the exact failure mode sync_mcp_docs.py's rewrite_internal_links
warns about, and the reason #189 stripped hardcoded /en/ from synced links.

A bare route path is correct for every locale, because <Link> supplies the
prefix. Both info pages exist under both locales today (the ja build falls
back to the untranslated source), verified on the same preview:

    /en/bitrise-api/api-reference/bitrise-api                          -> 200
    /ja/bitrise-api/api-reference/bitrise-api                          -> 200
    /en/bitrise-rde-api/.../bitrise-remote-dev-environments-api        -> 200
    /ja/bitrise-rde-api/.../bitrise-remote-dev-environments-api        -> 200

Also corrects the root-cause note in the script's header. The plugin does
have logic to turn outputDir into a route, but it is guarded (plugin
src/index.ts, v5.0.2):

    let infoBasePath = `${outputDir}/${item.infoId}`;
    if (docRouteBasePath) { ...rebuild from docRouteBasePath... }

`docs.routeBasePath` is '' here, which is falsy, so the guard never fires and
the raw filesystem path is written. This was latent until routeBasePath
changed from 'en' to '' — which is why the value was correct before the
change and wrong after the next regeneration.

- EN_ROUTE_PREFIX -> ROUTE_BASE_PATH, mirroring docs.routeBasePath
- Regenerate the 164 *.api.mdx via the script (one line each)
@zoltan-baba
zoltan-baba merged commit 62d5bbd into main Aug 19, 2026
4 checks passed
@zoltan-baba
zoltan-baba deleted the fix/api-info-path-locale-prefix branch August 19, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants