Skip to content

Commit 00566e0

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 7a57b2c commit 00566e0

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
@@ -50,26 +50,42 @@ export default defineEventHandler(async event => {
5050
return
5151
}
5252

53+
// /llms.txt at root is handled by the llms-txt middleware
54+
if (path === '/llms.txt') {
55+
return
56+
}
57+
5358
// /@org/pkg or /pkg → /package/org/pkg or /package/pkg
54-
let pkgMatch = path.match(/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)$/)
59+
// Also handles trailing /llms.txt or /llms_full.txt suffixes
60+
let pkgMatch = path.match(
61+
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)(?<suffix>\/(?:llms\.txt|llms_full\.txt))?$/,
62+
)
5563
if (pkgMatch?.groups) {
5664
const args = [pkgMatch.groups.org, pkgMatch.groups.name].filter(Boolean).join('/')
65+
const suffix = pkgMatch.groups.suffix ?? ''
5766
setHeader(event, 'cache-control', cacheControl)
58-
return sendRedirect(event, `/package/${args}` + (query ? '?' + query : ''), 301)
67+
return sendRedirect(event, `/package/${args}${suffix}` + (query ? '?' + query : ''), 301)
5968
}
6069

6170
// /@org/pkg/v/version or /@org/pkg@version → /package/org/pkg/v/version
6271
// /pkg/v/version or /pkg@version → /package/pkg/v/version
72+
// Also handles trailing /llms.txt or /llms_full.txt suffixes
6373
const pkgVersionMatch =
64-
path.match(/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)\/v\/(?<version>[^/]+)$/) ||
65-
path.match(/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)@(?<version>[^/]+)$/)
74+
path.match(
75+
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)\/v\/(?<version>[^/]+)(?<suffix>\/(?:llms\.txt|llms_full\.txt))?$/,
76+
) ||
77+
path.match(
78+
/^\/(?:(?<org>@[^/]+)\/)?(?<name>[^/@]+)@(?<version>[^/]+)(?<suffix>\/(?:llms\.txt|llms_full\.txt))?$/,
79+
)
6680

6781
if (pkgVersionMatch?.groups) {
6882
const args = [pkgVersionMatch.groups.org, pkgVersionMatch.groups.name].filter(Boolean).join('/')
83+
const versionSuffix = pkgVersionMatch.groups.suffix ?? ''
6984
setHeader(event, 'cache-control', cacheControl)
7085
return sendRedirect(
7186
event,
72-
`/package/${args}/v/${pkgVersionMatch.groups.version}` + (query ? '?' + query : ''),
87+
`/package/${args}/v/${pkgVersionMatch.groups.version}${versionSuffix}` +
88+
(query ? '?' + query : ''),
7389
301,
7490
)
7591
}

0 commit comments

Comments
 (0)