[Docs][Util] - LLMs markdown with accept header (#1010)

<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md

-->


LLMs are served the .mdx file, rather than any HTML, this is done with
the accept header.

<img width="570" height="179" alt="image"
src="https://github.com/user-attachments/assets/044f1477-4983-4c4c-8b3b-7a843bfb56a1"
/>

HTML still accessible, but `text/html` must be first in the accept
header:

<img width="570" height="147" alt="image"
src="https://github.com/user-attachments/assets/db516335-517d-488c-a58f-fc0d024badd9"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## 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.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- CURSOR_SUMMARY -->
---

> [!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*`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
837b218b37. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Konsti Wohlwend <n2d4xc@gmail.com>
This commit is contained in:
Madison 2025-11-12 14:31:03 -06:00 committed by GitHub
parent e843a2b637
commit 9030eee4dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

45
docs/src/middleware.ts Normal file
View File

@ -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*',
],
};