-
Notifications
You must be signed in to change notification settings - Fork 235
Expand file tree
/
Copy pathproxy.ts
More file actions
116 lines (105 loc) · 3.54 KB
/
proxy.ts
File metadata and controls
116 lines (105 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { createI18nMiddleware } from 'fumadocs-core/i18n/middleware';
import { isMarkdownPreferred, rewritePath } from 'fumadocs-core/negotiation';
import {
type NextFetchEvent,
type NextRequest,
NextResponse,
} from 'next/server';
import { i18n } from '@/lib/geistdocs/i18n';
import { trackMdRequest } from '@/lib/md-tracking';
import { isAIAgent } from '@/lib/ai-agent-detection';
const { rewrite: rewriteLLM } = rewritePath(
'/docs/*path',
`/${i18n.defaultLanguage}/llms.mdx/*path`
);
const internationalizer = createI18nMiddleware(i18n);
const proxy = (request: NextRequest, context: NextFetchEvent) => {
const pathname = request.nextUrl.pathname;
// Track llms.txt requests
if (pathname === '/llms.txt') {
context.waitUntil(
trackMdRequest({
path: '/llms.txt',
userAgent: request.headers.get('user-agent'),
referer: request.headers.get('referer'),
acceptHeader: request.headers.get('accept'),
})
);
}
// Handle .md/.mdx URL requests before i18n runs
if (
(pathname === '/docs.md' ||
pathname === '/docs.mdx' ||
pathname.startsWith('/docs/')) &&
(pathname.endsWith('.md') || pathname.endsWith('.mdx'))
) {
const stripped = pathname.replace(/\.mdx?$/, '');
const result =
stripped === '/docs'
? `/${i18n.defaultLanguage}/llms.mdx`
: rewriteLLM(stripped);
if (result) {
context.waitUntil(
trackMdRequest({
path: pathname,
userAgent: request.headers.get('user-agent'),
referer: request.headers.get('referer'),
acceptHeader: request.headers.get('accept'),
})
);
return NextResponse.rewrite(new URL(result, request.nextUrl));
}
}
// AI agent detection — rewrite docs pages to markdown for agents
// so they always get structured content without needing .md URLs or Accept headers
if (
(pathname === '/docs' || pathname.startsWith('/docs/')) &&
!pathname.includes('/llms.mdx/')
) {
const agentResult = isAIAgent(request);
if (agentResult.detected && !isMarkdownPreferred(request)) {
const result =
pathname === '/docs'
? `/${i18n.defaultLanguage}/llms.mdx`
: rewriteLLM(pathname);
if (result) {
context.waitUntil(
trackMdRequest({
path: pathname,
userAgent: request.headers.get('user-agent'),
referer: request.headers.get('referer'),
acceptHeader: request.headers.get('accept'),
requestType: 'agent-rewrite',
detectionMethod: agentResult.method,
})
);
return NextResponse.rewrite(new URL(result, request.nextUrl));
}
}
}
// Handle Accept header content negotiation and track the request
if (isMarkdownPreferred(request)) {
const result = rewriteLLM(pathname);
if (result) {
context.waitUntil(
trackMdRequest({
path: pathname,
userAgent: request.headers.get('user-agent'),
referer: request.headers.get('referer'),
acceptHeader: request.headers.get('accept'),
requestType: 'header-negotiated',
})
);
return NextResponse.rewrite(new URL(result, request.nextUrl));
}
}
// Fallback to i18n middleware
return internationalizer(request, context);
};
export const config = {
// Matcher ignoring `/_next/`, `/api/`, static assets, favicon, sitemap, robots, etc.
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|og|.*\\.tgz$|.*\\.svg$|.*\\.zip$).*)',
],
};
export default proxy;