-
-
Notifications
You must be signed in to change notification settings - Fork 427
Expand file tree
/
Copy pathcanonical-redirects.global.ts
More file actions
99 lines (89 loc) · 3 KB
/
canonical-redirects.global.ts
File metadata and controls
99 lines (89 loc) · 3 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
/**
* Redirect legacy/shorthand URLs to canonical paths.
*
* Handled here:
* - /@org/pkg or /pkg → /package/@org/pkg or /package/pkg
* - /@org/pkg/v/ver or /pkg@ver → /package/@org/pkg/v/ver or /package/pkg/v/ver
* - /@org → /org/org
*
* Handled via route aliases (not here):
* - /package/code/* → /package-code/*
* - /code/* → /package-code/*
* - /package/docs/* → /package-docs/*
* - /docs/* → /package-docs/*
*/
const pages = [
'/oauth-client-metadata.json',
'/200.html',
'/opensearch.xml',
'/about',
'/accessibility',
'/blog',
'/compare',
'/org',
'/package',
'/package-code',
'/package-docs',
'/pds',
'/privacy',
'/search',
'/settings',
'/recharging',
]
const cacheControl = 's-maxage=3600, stale-while-revalidate=36000'
export default defineEventHandler(async event => {
const routeRules = getRouteRules(event)
if (Object.keys(routeRules).length > 1) {
return
}
const [path = '/', query] = event.path.split('?')
// username
if (path.startsWith('/~') || path.startsWith('/_')) {
return
}
if (pages.some(page => path === page || path.startsWith(page + '/'))) {
return
}
// /llms.txt at root is handled by the llm-docs middleware
if (path === '/llms.txt') {
return
}
// /@org/pkg or /pkg → /package/org/pkg or /package/pkg
// Also handles trailing /llms.txt or /llms-full.txt suffixes
let pkgMatch = path.match(
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+?)(?<suffix>\.md|\/(?:llms\.txt|llms-full\.txt))?$/,
)
if (pkgMatch?.groups) {
const args = [pkgMatch.groups.org, pkgMatch.groups.name].filter(Boolean).join('/')
const suffix = pkgMatch.groups.suffix ?? ''
setHeader(event, 'cache-control', cacheControl)
return sendRedirect(event, `/package/${args}${suffix}` + (query ? '?' + query : ''), 301)
}
// /@org/pkg/v/version or /@org/pkg@version → /package/org/pkg/v/version
// /pkg/v/version or /pkg@version → /package/pkg/v/version
// Also handles trailing /llms.txt or /llms-full.txt suffixes
const pkgVersionMatch =
path.match(
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)\/v\/(?<version>[^/]+)(?<suffix>\/(?:llms\.txt|llms-full\.txt))?$/,
) ||
path.match(
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)@(?<version>[^/]+)(?<suffix>\/(?:llms\.txt|llms-full\.txt))?$/,
)
if (pkgVersionMatch?.groups) {
const args = [pkgVersionMatch.groups.org, pkgVersionMatch.groups.name].filter(Boolean).join('/')
const versionSuffix = pkgVersionMatch.groups.suffix ?? ''
setHeader(event, 'cache-control', cacheControl)
return sendRedirect(
event,
`/package/${args}/v/${pkgVersionMatch.groups.version}${versionSuffix}` +
(query ? '?' + query : ''),
301,
)
}
// /@org → /org/org
const orgMatch = path.match(/^\/@(?<org>[^/]+)$/)
if (orgMatch?.groups) {
setHeader(event, 'cache-control', cacheControl)
return sendRedirect(event, `/org/${orgMatch.groups.org}` + (query ? '?' + query : ''), 301)
}
})