1+ import * as v from 'valibot'
2+ import { PackageRouteParamsSchema } from '#shared/schemas/package'
13import type { PackageAnalysis , ExtendedPackageJson } from '#shared/utils/package-analysis'
24import {
35 analyzePackage ,
46 getTypesPackageName ,
57 hasBuiltInTypes ,
68} from '#shared/utils/package-analysis'
7-
8- const NPM_REGISTRY = 'https://registry.npmjs.org'
9+ import {
10+ NPM_REGISTRY ,
11+ CACHE_MAX_AGE_ONE_DAY ,
12+ ERROR_PACKAGE_ANALYSIS_FAILED ,
13+ } from '#shared/utils/constants'
914
1015export default defineCachedEventHandler (
1116 async event => {
12- const pkgParam = getRouterParam ( event , 'pkg' )
13- if ( ! pkgParam ) {
14- throw createError ( { statusCode : 400 , message : 'Package name is required' } )
15- }
16-
1717 // Parse package name and optional version from path
1818 // e.g., "vue" or "vue/v/3.4.0" or "@nuxt/kit" or "@nuxt/kit/v/1.0.0"
19- const segments = pkgParam . split ( '/' )
20- let packageName : string
21- let version : string | undefined
19+ const pkgParamSegments = getRouterParam ( event , 'pkg' ) ?. split ( '/' ) ?? [ ]
2220
23- const vIndex = segments . indexOf ( 'v' )
24- if ( vIndex !== - 1 && vIndex < segments . length - 1 ) {
25- packageName = segments . slice ( 0 , vIndex ) . join ( '/' )
26- version = segments . slice ( vIndex + 1 ) . join ( '/' )
27- } else {
28- packageName = segments . join ( '/' )
29- }
21+ const { rawPackageName, rawVersion } = parsePackageParams ( pkgParamSegments )
3022
3123 try {
24+ const { packageName, version } = v . parse ( PackageRouteParamsSchema , {
25+ packageName : rawPackageName ,
26+ version : rawVersion ,
27+ } )
28+
3229 // Fetch package data
3330 const encodedName = encodePackageName ( packageName )
3431 const versionSuffix = version ? `/${ version } ` : '/latest'
@@ -39,8 +36,8 @@ export default defineCachedEventHandler(
3936 // Only check for @types package if the package doesn't ship its own types
4037 let typesPackageExists = false
4138 if ( ! hasBuiltInTypes ( pkg ) ) {
42- const typesPackageName = getTypesPackageName ( packageName )
43- typesPackageExists = await checkPackageExists ( typesPackageName )
39+ const typesPkgName = getTypesPackageName ( packageName )
40+ typesPackageExists = await checkPackageExists ( typesPkgName )
4441 }
4542
4643 const analysis = analyzePackage ( pkg , { typesPackageExists } )
@@ -50,20 +47,20 @@ export default defineCachedEventHandler(
5047 version : pkg . version ?? version ?? 'latest' ,
5148 ...analysis ,
5249 } satisfies PackageAnalysisResponse
53- } catch ( error ) {
54- if ( error && typeof error === 'object' && 'statusCode' in error ) {
55- throw error
56- }
57- throw createError ( {
50+ } catch ( error : unknown ) {
51+ handleApiError ( error , {
5852 statusCode : 502 ,
59- message : 'Failed to analyze package' ,
53+ message : ERROR_PACKAGE_ANALYSIS_FAILED ,
6054 } )
6155 }
6256 } ,
6357 {
64- maxAge : 60 * 60 * 24 , // 24 hours - analysis rarely changes
58+ maxAge : CACHE_MAX_AGE_ONE_DAY , // 24 hours - analysis rarely changes
6559 swr : true ,
66- getKey : event => getRouterParam ( event , 'pkg' ) ?? '' ,
60+ getKey : event => {
61+ const pkg = getRouterParam ( event , 'pkg' ) ?? ''
62+ return `analysis:v1:${ pkg . replace ( / \/ + $ / , '' ) . trim ( ) } `
63+ } ,
6764 } ,
6865)
6966
0 commit comments