-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Expand file tree
/
Copy pathproxy.ts
More file actions
129 lines (116 loc) · 3.23 KB
/
Copy pathproxy.ts
File metadata and controls
129 lines (116 loc) · 3.23 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
117
118
119
120
121
122
123
124
125
126
127
128
129
import { precompute } from "flags/next"
import { NextRequest, NextResponse } from "next/server"
import createMiddleware from "next-intl/middleware"
import { routing } from "./src/i18n/routing"
import { AB_CODE_SEGMENT, encodeABCode } from "./src/lib/ab-testing/constants"
import { abTestRoutes } from "./src/lib/ab-testing/flags"
import { DEFAULT_LOCALE } from "./src/lib/constants"
import { getFirstSegment } from "./src/lib/utils/url"
const handleI18nRouting = createMiddleware(routing)
// Locales that have been removed but may have external links pointing to them
const DEPRECATED_LOCALES = new Set([
// Previously deprecated
"pcm",
"fil",
"ph",
// Removed in locale reduction (67 → 25)
"am",
"az",
"be",
"bg",
"bs",
"ca",
"da",
"el",
"fa",
"fi",
"ga",
"gl",
"gu",
"ha",
"he",
"hr",
"hu",
"hy-am",
"ig",
"ka",
"kk",
"km",
"kn",
"lt",
"ml",
"ms",
"nb",
"ne-np",
"nl",
"no",
"pt",
"ro",
"se",
"sk",
"sl",
"sn",
"sr",
"sv",
"th",
"tk",
"tl",
"tw",
"uz",
"yo",
])
function redirectTo(request: NextRequest, pathname: string, status: number) {
const url = request.nextUrl.clone()
url.pathname = pathname
return NextResponse.redirect(url, status)
}
export default async function proxy(request: NextRequest) {
const { pathname } = request.nextUrl
const lowerPath = pathname.toLowerCase()
if (pathname !== lowerPath) {
return redirectTo(request, lowerPath, 301)
}
const firstSegment = getFirstSegment(lowerPath)
if (firstSegment && DEPRECATED_LOCALES.has(firstSegment)) {
// Strip deprecated locale and redirect to default locale version
const rest = lowerPath.slice(firstSegment.length + 1)
const newPath = !rest ? "/" : rest
return redirectTo(request, newPath, 301)
}
// A/B testing: precompute flag variants and rewrite to the coded route,
// which serves a statically generated page per variant permutation.
// Only exact canonical paths match (non-canonical forms fall through and
// get slash-normalized first). Only the default locale is A/B tested:
// English URLs are unprefixed, so locale-prefixed paths never match.
// On failure, fall through to normal i18n handling (original variant).
const routeFlags = abTestRoutes[pathname]
if (routeFlags?.length) {
try {
const code = await precompute(routeFlags)
const url = request.nextUrl.clone()
const suffix = pathname === "/" ? "" : pathname
url.pathname = `/${DEFAULT_LOCALE}/${AB_CODE_SEGMENT}/${encodeABCode(code)}${suffix}`
return NextResponse.rewrite(url)
} catch (error) {
console.error("[proxy] A/B precompute failed:", error)
}
}
// Handle i18n routing
const response = handleI18nRouting(request)
// Upgrade default-locale strip redirects from 307 to 301 for SEO
if (response.status === 307) {
const pathname = request.nextUrl.pathname
const defaultPrefix = `/${DEFAULT_LOCALE}`
if (
pathname === defaultPrefix ||
pathname.startsWith(`${defaultPrefix}/`)
) {
return new NextResponse(null, { status: 301, headers: response.headers })
}
}
return response
}
// Simplified matcher pattern
export const config = {
matcher: ["/((?!api|_next|_vercel|.well-known|.*\\.[^/]*$).*)"],
}