@@ -54,18 +54,47 @@ function isAIOrDevTool(userAgent: string): boolean {
5454 return patterns . some ( pattern => pattern . test ( userAgent ) ) ;
5555}
5656
57+ /**
58+ * Detects if client wants markdown via Accept header (standards-compliant)
59+ */
60+ function wantsMarkdownViaAccept ( acceptHeader : string ) : boolean {
61+ return acceptHeader . includes ( 'text/markdown' ) ||
62+ acceptHeader . includes ( 'text/x-markdown' ) ;
63+ }
64+
65+ /**
66+ * Detects if client wants markdown via Accept header or user-agent
67+ */
68+ function wantsMarkdown ( request : NextRequest ) : boolean {
69+ const userAgent = request . headers . get ( 'user-agent' ) || '' ;
70+ const acceptHeader = request . headers . get ( 'accept' ) || '' ;
71+
72+ // Strategy 1: Accept header content negotiation (standards-compliant)
73+ if ( wantsMarkdownViaAccept ( acceptHeader ) ) {
74+ return true ;
75+ }
76+
77+ // Strategy 2: User-agent detection (fallback for tools that don't set Accept)
78+ return isAIOrDevTool ( userAgent ) ;
79+ }
80+
5781/**
5882 * Handles redirection to markdown versions for AI/LLM clients
5983 */
6084const handleAIClientRedirect = ( request : NextRequest ) => {
6185 const userAgent = request . headers . get ( 'user-agent' ) || '' ;
86+ const acceptHeader = request . headers . get ( 'accept' ) || '' ;
6287 const url = request . nextUrl ;
6388
6489 // Determine if this will be served as markdown
6590 const forceMarkdown = url . searchParams . get ( 'format' ) === 'md' ;
66- const isAIClient = isAIOrDevTool ( userAgent ) ;
91+ const clientWantsMarkdown = wantsMarkdown ( request ) ;
6792 const willServeMarkdown =
68- ( isAIClient || forceMarkdown ) && ! url . pathname . endsWith ( '.md' ) ;
93+ ( clientWantsMarkdown || forceMarkdown ) && ! url . pathname . endsWith ( '.md' ) ;
94+
95+ // Determine detection method for logging
96+ const detectionMethod = wantsMarkdownViaAccept ( acceptHeader ) ? 'Accept header' :
97+ isAIOrDevTool ( userAgent ) ? 'User-agent' : 'Manual' ;
6998
7099 // Log user agent for debugging (only for non-static assets)
71100 if (
@@ -74,8 +103,9 @@ const handleAIClientRedirect = (request: NextRequest) => {
74103 ! url . pathname . startsWith ( '/api/' )
75104 ) {
76105 const contentType = willServeMarkdown ? '📄 MARKDOWN' : '🌐 HTML' ;
106+ const methodInfo = willServeMarkdown ? ` (${ detectionMethod } )` : '' ;
77107 console . log (
78- `[Middleware] ${ url . pathname } - ${ contentType } - User-Agent: ${ userAgent } `
108+ `[Middleware] ${ url . pathname } - ${ contentType } ${ methodInfo } - User-Agent: ${ userAgent } `
79109 ) ;
80110 }
81111
@@ -95,12 +125,11 @@ const handleAIClientRedirect = (request: NextRequest) => {
95125 return undefined ;
96126 }
97127
98- // Check for AI client detection
99-
100- if ( isAIClient || forceMarkdown ) {
128+ // Check for markdown request (Accept header, user-agent, or manual)
129+ if ( clientWantsMarkdown || forceMarkdown ) {
101130 // Log the redirect for debugging
102131 console . log (
103- `[Middleware] Redirecting to markdown: ${ isAIClient ? 'AI client detected' : ' Manual format=md'} `
132+ `[Middleware] Redirecting to markdown: ${ forceMarkdown ? 'Manual format=md' : detectionMethod } `
104133 ) ;
105134
106135 // Create new URL with .md extension
0 commit comments