Skip to content

Commit d6e2e1a

Browse files
authored
fix: prevent 404 on code viewer direct URL access (#630)
1 parent 2317d7c commit d6e2e1a

File tree

2 files changed

+69
-104
lines changed

2 files changed

+69
-104
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import type { H3Event } from 'h3'
2+
import * as v from 'valibot'
3+
import { PackageRouteParamsSchema } from '#shared/schemas/package'
4+
import { SkillNameSchema } from '#shared/schemas/skills'
5+
import { CACHE_MAX_AGE_ONE_HOUR, CACHE_MAX_AGE_ONE_YEAR } from '#shared/utils/constants'
6+
7+
/**
8+
* Serves /.well-known/skills endpoints for `npx skills add` CLI.
9+
* Middleware pattern allows non-matching paths to pass through to Nuxt.
10+
*/
11+
export default defineEventHandler(event => {
12+
const url = getRequestURL(event)
13+
const match = url.pathname.match(/^\/(.+?)\/\.well-known\/skills\/(.*)$/)
14+
if (!match) return
15+
16+
return cachedHandler(event)
17+
})
18+
19+
const cachedHandler = defineCachedEventHandler(
20+
async (event: H3Event) => {
21+
const url = getRequestURL(event)
22+
const match = url.pathname.match(/^\/(.+?)\/\.well-known\/skills\/(.*)$/)!
23+
const [, pkgPath, skillsPath] = match
24+
25+
const validated = v.parse(PackageRouteParamsSchema, {
26+
packageName: pkgPath,
27+
version: undefined,
28+
})
29+
const packument = await fetchNpmPackage(validated.packageName)
30+
const version = packument['dist-tags']?.latest
31+
if (!version) throw createError({ statusCode: 404, message: 'No latest version found' })
32+
33+
if (skillsPath === 'index.json' || skillsPath === '') {
34+
const fileTree = await getPackageFileTree(validated.packageName, version)
35+
const skillDirs = findSkillDirs(fileTree.tree)
36+
const skills = skillDirs.length
37+
? await fetchSkillsListForWellKnown(
38+
validated.packageName,
39+
version,
40+
skillDirs.map(s => s.name),
41+
)
42+
: []
43+
setHeader(event, 'Cache-Control', `public, max-age=${CACHE_MAX_AGE_ONE_HOUR}`)
44+
setHeader(event, 'Content-Type', 'application/json')
45+
return { skills }
46+
}
47+
48+
const [skillName, ...rest] = skillsPath!.split('/')
49+
const fileName = rest.join('/')
50+
if (fileName === 'SKILL.md' || fileName === '') {
51+
const content = await fetchSkillFile(
52+
validated.packageName,
53+
version,
54+
`skills/${v.parse(SkillNameSchema, skillName)}/SKILL.md`,
55+
)
56+
setHeader(event, 'Cache-Control', `public, max-age=${CACHE_MAX_AGE_ONE_YEAR}, immutable`)
57+
setHeader(event, 'Content-Type', 'text/markdown; charset=utf-8')
58+
return content
59+
}
60+
61+
throw createError({ statusCode: 404, message: 'File not found' })
62+
},
63+
{
64+
maxAge: CACHE_MAX_AGE_ONE_HOUR,
65+
swr: true,
66+
getKey: (event: H3Event) =>
67+
`well-known-skills:v1:${getRequestURL(event).pathname.replace(/\/+$/, '')}`,
68+
},
69+
)

server/routes/[...path].get.ts

Lines changed: 0 additions & 104 deletions
This file was deleted.

0 commit comments

Comments
 (0)