1- import * as v from 'valibot'
2- import { PackageRouteParamsSchema } from '#shared/schemas/package'
3- import {
4- CACHE_MAX_AGE_ONE_HOUR ,
5- NPM_MISSING_README_SENTINEL ,
6- ERROR_NPM_FETCH_FAILED ,
7- } from '#shared/utils/constants'
8-
9- /** Standard README filenames to try when fetching from jsdelivr (case-sensitive CDN) */
10- const standardReadmeFilenames = [
11- 'README.md' ,
12- 'readme.md' ,
13- 'Readme.md' ,
14- 'README' ,
15- 'readme' ,
16- 'README.markdown' ,
17- 'readme.markdown' ,
18- ]
19-
20- /** Matches standard README filenames (case-insensitive, for checking registry metadata) */
21- const standardReadmePattern = / ^ r e a d m e (?: \. m d | \. m a r k d o w n ) ? $ / i
22-
23- /**
24- * Fetch README from jsdelivr CDN for a specific package version.
25- * Falls back through common README filenames.
26- */
27- async function fetchReadmeFromJsdelivr (
28- packageName : string ,
29- readmeFilenames : string [ ] ,
30- version ?: string ,
31- ) : Promise < string | null > {
32- const versionSuffix = version ? `@${ version } ` : ''
33-
34- for ( const filename of readmeFilenames ) {
35- try {
36- const url = `https://cdn.jsdelivr.net/npm/${ packageName } ${ versionSuffix } /${ filename } `
37- const response = await fetch ( url )
38- if ( response . ok ) {
39- return await response . text ( )
40- }
41- } catch {
42- // Try next filename
43- }
44- }
45-
46- return null
47- }
1+ import { CACHE_MAX_AGE_ONE_HOUR , ERROR_NPM_FETCH_FAILED } from '#shared/utils/constants'
2+ import { resolvePackageReadmeSource } from '#server/utils/readme-loaders'
483
494/**
505 * Returns rendered README HTML for a package.
@@ -57,63 +12,15 @@ async function fetchReadmeFromJsdelivr(
5712 */
5813export default defineCachedEventHandler (
5914 async event => {
60- // Parse package name and optional version from URL segments
61- // Patterns: [pkg] or [pkg, 'v', version] or [@scope, pkg] or [@scope, pkg, 'v', version]
62- const pkgParamSegments = getRouterParam ( event , 'pkg' ) ?. split ( '/' ) ?? [ ]
63-
64- const { rawPackageName, rawVersion } = parsePackageParams ( pkgParamSegments )
65-
6615 try {
67- // 1. Validate
68- const { packageName, version } = v . parse ( PackageRouteParamsSchema , {
69- packageName : rawPackageName ,
70- version : rawVersion ,
71- } )
72-
73- const packageData = await fetchNpmPackage ( packageName )
16+ const packagePath = getRouterParam ( event , 'pkg' ) ?? ''
17+ const { packageName, markdown, repoInfo } = await resolvePackageReadmeSource ( packagePath )
7418
75- let readmeContent : string | undefined
76- let readmeFilename : string | undefined
77-
78- // If a specific version is requested, get README from that version
79- if ( version ) {
80- const versionData = packageData . versions [ version ]
81- if ( versionData ) {
82- readmeContent = versionData . readme
83- readmeFilename = versionData . readmeFilename
84- }
85- } else {
86- // Use the packument-level readme (from latest version)
87- readmeContent = packageData . readme
88- readmeFilename = packageData . readmeFilename
19+ if ( ! markdown ) {
20+ return { html : '' , mdExists : false , playgroundLinks : [ ] , toc : [ ] }
8921 }
9022
91- const hasValidNpmReadme = readmeContent && readmeContent !== NPM_MISSING_README_SENTINEL
92-
93- // If no README in packument, or if readmeFilename is non-standard (e.g., README.zh-TW.md),
94- // try fetching a standard README from jsdelivr (package tarball).
95- // Note: When readmeFilename is missing, we defensively fetch from jsdelivr to ensure
96- // we get a standard English README if one exists.
97- if ( ! hasValidNpmReadme || ! isStandardReadme ( readmeFilename ) ) {
98- const jsdelivrReadme = await fetchReadmeFromJsdelivr (
99- packageName ,
100- standardReadmeFilenames ,
101- version ,
102- )
103- // Only replace npm content if jsdelivr returned something
104- if ( jsdelivrReadme ) {
105- readmeContent = jsdelivrReadme
106- }
107- }
108-
109- if ( ! readmeContent || readmeContent === NPM_MISSING_README_SENTINEL ) {
110- return { html : '' , playgroundLinks : [ ] , toc : [ ] }
111- }
112-
113- // Parse repository info for resolving relative URLs to GitHub
114- const repoInfo = parseRepositoryInfo ( packageData . repository )
115-
116- return await renderReadmeHtml ( readmeContent , packageName , repoInfo )
23+ return await renderReadmeHtml ( markdown , packageName , repoInfo )
11724 } catch ( error : unknown ) {
11825 handleApiError ( error , {
11926 statusCode : 502 ,
@@ -130,7 +37,3 @@ export default defineCachedEventHandler(
13037 } ,
13138 } ,
13239)
133-
134- function isStandardReadme ( filename : string | undefined ) : boolean {
135- return ! ! filename && standardReadmePattern . test ( filename )
136- }
0 commit comments