chore: Update markdown middleware

This commit is contained in:
Jeremias Menichelli
2026-04-30 16:49:05 +02:00
parent 4b706a5cba
commit 29fa209178
3 changed files with 62 additions and 13 deletions

View File

@@ -1,4 +1,10 @@
{
"permissions": {
"allow": [
"Bash(node -e \":*)",
"Bash(grep -rn \"guides-md\\\\|api/md\\\\|copyAsMarkdown\\\\|copy-as-markdown\\\\|CopyAsMarkdown\" /Users/jeremias/supabase/supabase/apps/docs/ --include=*.ts --include=*.tsx -l)"
]
},
"hooks": {
"SessionStart": [
{
@@ -23,10 +29,5 @@
]
}
]
},
"permissions": {
"allow": [
"Bash(node -e \":*)"
]
}
}

View File

@@ -0,0 +1,40 @@
import { promises as fs } from 'fs'
import path from 'path'
import { BASE_PATH } from '~/lib/constants'
import { NextResponse } from 'next/server'
const BASE_DIR = path.join(process.cwd(), 'public/docs')
export async function GET(request: Request, { params }: { params: Promise<{ slug: string[] }> }) {
const { slug } = await params
const slugPath = slug.join('/')
// Resolve candidate paths: exact match first, then index fallback for directory-style routes
const candidates = [
path.join(BASE_DIR, `${slugPath}.md`),
path.join(BASE_DIR, slugPath, 'index.md'),
]
for (const filePath of candidates) {
// Prevent path traversal
if (!filePath.startsWith(BASE_DIR + path.sep)) continue
try {
const content = await fs.readFile(filePath, 'utf-8')
return new NextResponse(content, {
headers: {
'Content-Type': 'text/markdown; charset=utf-8',
'Cache-Control': 'public, max-age=86400, stale-while-revalidate=3600',
},
})
} catch {
// Try next candidate
}
}
// Markdown file not found — redirect to the original page so HTML is served instead.
// nomd=1 tells the middleware to skip markdown interception and avoid an infinite loop.
const pageUrl = new URL(`${BASE_PATH ?? ''}/${slugPath}`, request.url)
pageUrl.searchParams.set('nomd', '1')
return NextResponse.redirect(pageUrl, { status: 302 })
}

View File

@@ -1,8 +1,7 @@
import { isbot } from 'isbot'
import { NextResponse, type NextRequest } from 'next/server'
import { clientSdkIds } from '~/content/navigation.references'
import { BASE_PATH } from '~/lib/constants'
import { isbot } from 'isbot'
import { NextResponse, type NextRequest } from 'next/server'
const REFERENCE_PATH = `${BASE_PATH ?? ''}/reference`
@@ -11,14 +10,23 @@ const GUIDES_PATH = `${BASE_PATH ?? ''}/guides`
export function middleware(request: NextRequest) {
const url = new URL(request.url)
// nomd=1 is set by the /api/md route when a markdown file is not found,
// so the middleware skips interception and the normal HTML page is served.
const requestsMarkdown =
request.headers.get('Accept')?.includes('text/markdown') || url.pathname.endsWith('.md')
!url.searchParams.has('nomd') &&
(request.headers.get('Accept')?.includes('text/markdown') || url.pathname.endsWith('.md'))
// Serve pre-generated .md files before the [[...slug]] page route can intercept them
if (url.pathname.startsWith(GUIDES_PATH + '/') && requestsMarkdown) {
const slug = url.pathname.replace(`${GUIDES_PATH}/`, '').replace(/\.md$/, '')
// Serve pre-generated .md files for guides and reference routes.
// The slug is the full path relative to BASE_PATH (e.g. guides/foo or reference/javascript).
if (
(url.pathname.startsWith(GUIDES_PATH + '/') ||
url.pathname.startsWith(REFERENCE_PATH + '/') ||
url.pathname === REFERENCE_PATH) &&
requestsMarkdown
) {
const slug = url.pathname.replace(`${BASE_PATH ?? ''}/`, '').replace(/\.md$/, '')
const rewriteUrl = new URL(url)
rewriteUrl.pathname = `${BASE_PATH ?? ''}/api/guides-md/${slug}`
rewriteUrl.pathname = `${BASE_PATH ?? ''}/api/md/${slug}`
return NextResponse.rewrite(rewriteUrl)
}