Skip to content

Commit 8d4f5a9

Browse files
committed
feat(llms-txt): support shorthand URL redirects for llms.txt paths
Extend canonical redirect regexes with optional /llms.txt and /llms_full.txt suffix capture groups so shorthand URLs like /nuxt/llms.txt redirect to /package/nuxt/llms.txt. Add explicit /llms.txt root path skip to prevent it matching as a package name.
1 parent fcd8ca1 commit 8d4f5a9

1 file changed

Lines changed: 21 additions & 5 deletions

File tree

server/middleware/canonical-redirects.global.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,26 +46,42 @@ export default defineEventHandler(async event => {
4646
return
4747
}
4848

49+
// /llms.txt at root is handled by the llms-txt middleware
50+
if (path === '/llms.txt') {
51+
return
52+
}
53+
4954
// /@org/pkg or /pkg → /package/org/pkg or /package/pkg
50-
let pkgMatch = path.match(/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)$/)
55+
// Also handles trailing /llms.txt or /llms_full.txt suffixes
56+
let pkgMatch = path.match(
57+
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)(?<suffix>\/(?:llms\.txt|llms_full\.txt))?$/,
58+
)
5159
if (pkgMatch?.groups) {
5260
const args = [pkgMatch.groups.org, pkgMatch.groups.name].filter(Boolean).join('/')
61+
const suffix = pkgMatch.groups.suffix ?? ''
5362
setHeader(event, 'cache-control', cacheControl)
54-
return sendRedirect(event, `/package/${args}` + (query ? '?' + query : ''), 301)
63+
return sendRedirect(event, `/package/${args}${suffix}` + (query ? '?' + query : ''), 301)
5564
}
5665

5766
// /@org/pkg/v/version or /@org/pkg@version → /package/org/pkg/v/version
5867
// /pkg/v/version or /pkg@version → /package/pkg/v/version
68+
// Also handles trailing /llms.txt or /llms_full.txt suffixes
5969
const pkgVersionMatch =
60-
path.match(/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)\/v\/(?<version>[^/]+)$/) ||
61-
path.match(/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)@(?<version>[^/]+)$/)
70+
path.match(
71+
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)\/v\/(?<version>[^/]+)(?<suffix>\/(?:llms\.txt|llms_full\.txt))?$/,
72+
) ||
73+
path.match(
74+
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)@(?<version>[^/]+)(?<suffix>\/(?:llms\.txt|llms_full\.txt))?$/,
75+
)
6276

6377
if (pkgVersionMatch?.groups) {
6478
const args = [pkgVersionMatch.groups.org, pkgVersionMatch.groups.name].filter(Boolean).join('/')
79+
const versionSuffix = pkgVersionMatch.groups.suffix ?? ''
6580
setHeader(event, 'cache-control', cacheControl)
6681
return sendRedirect(
6782
event,
68-
`/package/${args}/v/${pkgVersionMatch.groups.version}` + (query ? '?' + query : ''),
83+
`/package/${args}/v/${pkgVersionMatch.groups.version}${versionSuffix}` +
84+
(query ? '?' + query : ''),
6985
301,
7086
)
7187
}

0 commit comments

Comments
 (0)