mirror of
https://github.com/vercel-labs/json-render.git
synced 2026-09-14 13:41:32 +08:00
801708a128
* react native * fixes * pop/push * fixes * rename data -> state * remove . tsbuildinfo * fixes * fixes * user prompt * fixes * $id * combine catalog.ts * better actions * repeat * fix docs * fixes * fixes * fixes * better stream * catalog * fixes * fixes * fixes * dialog * sonner * accordion * catalog on homepage * fixes * more catalog * fixes * fixes * refactor * mv * 404 * fixes * nested * fixes * fixes * fixes * fixes * mobile playground * mdx * fix mdx * fixes * streamdown * fixes * use haiku * fixes * great * fixes * fix ... * fixes * fixes * fix build * fix lint * fix lint * fix lint * fix tests
56 lines
1.5 KiB
TypeScript
56 lines
1.5 KiB
TypeScript
import { readFile } from "fs/promises";
|
|
import { join } from "path";
|
|
import { NextRequest, NextResponse } from "next/server";
|
|
import { mdxToCleanMarkdown } from "@/lib/mdx-to-markdown";
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const { searchParams } = new URL(req.url);
|
|
const docPath = searchParams.get("path");
|
|
|
|
if (!docPath) {
|
|
return NextResponse.json(
|
|
{ error: "Missing ?path= parameter" },
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
// Sanitize path: only allow docs paths, no traversal
|
|
const normalized = docPath
|
|
.replace(/^\//, "")
|
|
.replace(/\.\./g, "")
|
|
.replace(/[^a-zA-Z0-9/-]/g, "");
|
|
|
|
if (!normalized.startsWith("docs")) {
|
|
return NextResponse.json({ error: "Invalid path" }, { status: 400 });
|
|
}
|
|
|
|
// Map URL path to file path
|
|
// /docs -> /app/(main)/docs/page.mdx
|
|
// /docs/installation -> /app/(main)/docs/installation/page.mdx
|
|
const slug = normalized === "docs" ? "" : normalized.replace(/^docs\/?/, "");
|
|
const filePath = slug
|
|
? join(
|
|
process.cwd(),
|
|
"app",
|
|
"(main)",
|
|
"docs",
|
|
...slug.split("/"),
|
|
"page.mdx",
|
|
)
|
|
: join(process.cwd(), "app", "(main)", "docs", "page.mdx");
|
|
|
|
try {
|
|
const raw = await readFile(filePath, "utf-8");
|
|
const markdown = mdxToCleanMarkdown(raw);
|
|
|
|
return new NextResponse(markdown, {
|
|
headers: {
|
|
"Content-Type": "text/markdown; charset=utf-8",
|
|
"Cache-Control": "public, max-age=3600",
|
|
},
|
|
});
|
|
} catch {
|
|
return NextResponse.json({ error: "Page not found" }, { status: 404 });
|
|
}
|
|
}
|