import { negotiateMarkdown, type MarkdownDecision } from 'common/markdown-negotiation' import { NextResponse, type NextRequest } from 'next/server' import MARKDOWN_SLUGS from '@/public/markdown/manifest.json' const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH ?? '/library' const DOCS_PATH = `${BASE_PATH}/docs` const MARKDOWN_SLUG_SET = new Set(MARKDOWN_SLUGS) // The homepage catalog, generated by scripts/build-markdown-index.ts. const HOME_PATHS = new Set([BASE_PATH, `${BASE_PATH}/`, `${BASE_PATH}/index.md`]) export function middleware(request: NextRequest) { const url = new URL(request.url) const { pathname } = url // Server Actions POST to the page URL with `Accept: text/x-component`, which // matches none of the types these routes negotiate and would 406. Let Next.js // handle them. if (request.headers.get('next-action')) { return NextResponse.next() } const acceptHeader = request.headers.get('accept') ?? '' if (HOME_PATHS.has(pathname)) { return respond( negotiateMarkdown( { acceptHeader }, { hasMarkdownVariant: true, isMarkdownSuffix: pathname.endsWith('.md') } ), url, `${BASE_PATH}/api/index-md` ) } if (!pathname.startsWith(`${DOCS_PATH}/`)) { return NextResponse.next() } const isMdSuffix = pathname.endsWith('.md') const slug = pathname.replace(`${DOCS_PATH}/`, '').replace(/\.md$/, '') const decision = negotiateMarkdown( { acceptHeader }, { hasMarkdownVariant: MARKDOWN_SLUG_SET.has(slug), isMarkdownSuffix: isMdSuffix } ) return respond(decision, url, `${BASE_PATH}/api/docs-md/${slug}`) } function respond(decision: MarkdownDecision, url: URL, markdownPathname: string) { if (decision === 'not-acceptable') { return new NextResponse('Not Acceptable', { status: 406, headers: { 'Cache-Control': 'no-store', Vary: 'Accept' }, }) } if (decision === 'markdown') { const rewriteUrl = new URL(url) rewriteUrl.pathname = markdownPathname return NextResponse.rewrite(rewriteUrl) } return NextResponse.next() } export const config = { matcher: ['/', '/index.md', '/docs/:path*'], }