From b9ce911a0932783465b6ce18020b0eea7f54129e Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Tue, 18 Aug 2026 22:25:37 +1000 Subject: [PATCH] fix(seo): emit a single H1 on generated API reference pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TypeDoc's reflection template writes `# ` as the first line of each generated page's body, and the docs route renders `page.data.title` through Fumadocs' `` as an

above it. Both resolve to the same string, so all 23 API reference pages shipped two identical H1s — every multiple-H1 warning in the site audit, and nothing else. Set `hidePageTitle: true` so TypeDoc omits its copy. Verified against a minimal TypeDoc project run with the option both ways: the only difference in the output is the removal of the `# ` line and its trailing blank. Member headings stay at `##`, so page anchors — and the two `#createencryptionoperators`/`#encryptedindexes` deep links in the Drizzle guide — are unaffected. Worth flagging for the next reader: this is `hidePageTitle`, not the `hidePageHeader` sitting directly above it. The heading in `reflection.template.js` is gated on the former; `hidePageHeader` controls the breadcrumb/navigation block, which is a different thing. The raw-markdown mirrors improve too. `getLLMText` prepends `# ${page.data.title}` to the processed body, so those files carried the same duplicate; they now have one H1 as well. Claude-Session: https://claude.ai/code/session_01Rvx5yeC4Vy2svyohuVvxWj --- scripts/lib/docs-generator.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/lib/docs-generator.ts b/scripts/lib/docs-generator.ts index ce45804..6f95215 100644 --- a/scripts/lib/docs-generator.ts +++ b/scripts/lib/docs-generator.ts @@ -521,7 +521,16 @@ export async function generateDocsForTag( expandObjects: true, hideBreadcrumbs: true, hidePageHeader: false, - hidePageTitle: false, + // The page template emits `# ` as the body's first line, and + // Fumadocs renders `page.data.title` as an

above it — the same string + // twice, so every generated page shipped two H1s. Suppressing TypeDoc's + // copy leaves Fumadocs' as the only one; the text is identical, so nothing + // changes visually. + // + // This is `hidePageTitle`, not the `hidePageHeader` above it: the heading + // in typedoc-plugin-markdown's `reflection.template.js` is gated on the + // former. `hidePageHeader` controls the breadcrumb/navigation block. + hidePageTitle: true, parametersFormat: "list", expandParameters: false, useHTMLEncodedBrackets: true,