From 9030eee4dc644d4966472e851e9231e5e96df262 Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 12 Nov 2025 14:31:03 -0600 Subject: [PATCH] [Docs][Util] - LLMs markdown with accept header (#1010) LLMs are served the .mdx file, rather than any HTML, this is done with the accept header. image HTML still accessible, but `text/html` must be first in the accept header: image ## Summary by CodeRabbit * **New Features** * Docs and API endpoints now honor Accept headers to deliver Markdown when clients prefer text/markdown or text/plain; other requests continue to receive HTML. --- > [!NOTE] > Adds middleware that rewrites /docs and /api requests to LLM-focused markdown when Accept prefers text/plain or text/markdown over text/html. > > - **Docs Middleware (`docs/src/middleware.ts`)**: > - Detects `/docs` and `/api` requests (excluding `.mdx`). > - Parses `Accept` header; if `text/plain` or `text/markdown` appears before `text/html`, rewrites to `/llms.mdx...` while preserving query params. > - Adds `config.matcher` for `/docs/:path*` and `/api/:path*`. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 837b218b37d41969ccb012ae8d087dbbb102820b. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --------- Co-authored-by: Konsti Wohlwend --- docs/src/middleware.ts | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 docs/src/middleware.ts diff --git a/docs/src/middleware.ts b/docs/src/middleware.ts new file mode 100644 index 000000000..68adf1b96 --- /dev/null +++ b/docs/src/middleware.ts @@ -0,0 +1,45 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export function middleware(request: NextRequest) { + const { pathname } = request.nextUrl; + + // Only apply to docs and api pages (not already .mdx requests) + // Match /docs, /docs/, /docs/... and /api, /api/, /api/... + const isDocsPath = pathname === '/docs' || pathname.startsWith('/docs/'); + const isApiPath = pathname === '/api' || pathname.startsWith('/api/'); + + if ((isDocsPath || isApiPath) && !pathname.endsWith('.mdx')) { + const acceptHeader = request.headers.get('accept') || ''; + + // Parse Accept header by splitting on commas to properly handle MIME type ordering + const acceptTypes = acceptHeader.split(',').map(t => t.trim().split(';')[0]); + + // Find the index of each MIME type in the Accept header + const plainIndex = acceptTypes.findIndex( + (t) => t === 'text/plain' || t === 'text/markdown' + ); + const htmlIndex = acceptTypes.findIndex((t) => t === 'text/html'); + + // Prefer markdown if text/plain or text/markdown appears before text/html (or text/html doesn't exist) + const prefersMarkdown = plainIndex !== -1 && (htmlIndex === -1 || plainIndex < htmlIndex); + + if (prefersMarkdown) { + // Rewrite to the LLM markdown endpoint + const url = request.nextUrl.clone(); + url.pathname = `/llms.mdx${pathname.replace(/^\/(docs|api)/, '')}`; + + // Preserve query parameters (platform, framework, etc.) + return NextResponse.rewrite(url); + } + } + + return NextResponse.next(); +} + +export const config = { + matcher: [ + '/docs/:path*', + '/api/:path*', + ], +}; +