fix(core): strip YAML frontmatter in getDocument before web/MCP render

getDocument preferred the on-disk file via readFileSync (raw), returning
the full frontmatter block as visible text on doc pages and MCP resources.
ReactMarkdown rendered the '---' delimiters as <hr/>, exposing YAML keys
(id/title/type/etc.) as plain paragraphs.

Root cause: getDocument bypassed parseFile's gray-matter stripping.
The indexer correctly stripped frontmatter (DB body was clean), but
getDocument read raw from disk for the 'source of truth' path.

Fix: use parseFile(abs, relPath).body (same as the indexer) so the
on-disk path returns frontmatter-free markdown. DB fallback unchanged.

Affects web doc pages + MCP mcpedia://docs/{+slug} and /chunks resources.
Verified: frontmatter leakage 0/9 doc pages, headings render as <h2>,
browser snapshot clean.
This commit is contained in:
asepharyana
2026-08-20 11:45:37 +07:00
parent 76f778c10d
commit ca2bd19c48
+11 -2
View File
@@ -2,7 +2,8 @@ import { and, eq, sql } from "drizzle-orm";
import { db } from "@mcpedia/db";
import { documentChunks, documents } from "@mcpedia/db/schema";
import { CONTENT_ROOT } from "@mcpedia/config";
import { existsSync, readFileSync } from "node:fs";
import { parseFile } from "@mcpedia/parser";
import { existsSync } from "node:fs";
import { join } from "node:path";
import type {
Document,
@@ -33,8 +34,16 @@ export async function getDocument(slug: string): Promise<Document | null> {
const [row] = await db.select().from(documents).where(eq(documents.slug, slug));
if (!row) return null;
// Prefer the on-disk file (source of truth); fall back to stored body.
// Use parseFile (gray-matter) so the frontmatter is stripped — matches what
// the indexer stores and what ReactMarkdown expects.
const abs = join(CONTENT_ROOT, row.path);
const body = existsSync(abs) ? readFileSync(abs, "utf8") : row.body;
let body: string;
if (existsSync(abs)) {
const { body: parsedBody } = parseFile(abs, row.path);
body = parsedBody;
} else {
body = row.body;
}
return { ...toMeta(row), body };
}