@@ -9,6 +9,7 @@ import { handleApiError } from '#server/utils/error-handler'
99const NPM_DOWNLOADS_API = 'https://api.npmjs.org/downloads/point'
1010const OSV_QUERY_API = 'https://api.osv.dev/v1/query'
1111const BUNDLEPHOBIA_API = 'https://bundlephobia.com/api/size'
12+ const NPMS_API = 'https://api.npms.io/v2/package'
1213
1314const QUERY_SCHEMA = v . object ( {
1415 color : v . optional ( v . string ( ) ) ,
@@ -63,7 +64,7 @@ function getLatestVersion(pkgData: globalThis.Packument): string | undefined {
6364
6465async function fetchDownloads (
6566 packageName : string ,
66- period : 'last-month ' | 'last-week' ,
67+ period : 'last-day ' | 'last-week' | 'last-month' | 'last-year ',
6768) : Promise < number > {
6869 try {
6970 const response = await fetch ( `${ NPM_DOWNLOADS_API } /${ period } /${ packageName } ` )
@@ -74,6 +75,16 @@ async function fetchDownloads(
7475 }
7576}
7677
78+ async function fetchNpmsScore ( packageName : string ) {
79+ try {
80+ const response = await fetch ( `${ NPMS_API } /${ encodeURIComponent ( packageName ) } ` )
81+ const data = await response . json ( )
82+ return data . score
83+ } catch {
84+ return null
85+ }
86+ }
87+
7788async function fetchVulnerabilities ( packageName : string , version : string ) : Promise < number > {
7889 try {
7990 const response = await fetch ( OSV_QUERY_API , {
@@ -116,15 +127,11 @@ const badgeStrategies = {
116127 'size' : async ( pkgData : globalThis . Packument ) => {
117128 const latest = getLatestVersion ( pkgData )
118129 const versionData = latest ? pkgData . versions ?. [ latest ] : undefined
119-
120- // Fallback to unpacked size if bundlephobia fails or latest is missing
121130 let bytes = versionData ?. dist ?. unpackedSize ?? 0
122-
123131 if ( latest ) {
124132 const installSize = await fetchInstallSize ( pkgData . name , latest )
125133 if ( installSize !== null ) bytes = installSize
126134 }
127-
128135 return { label : 'install size' , value : formatBytes ( bytes ) , color : COLORS . purple }
129136 } ,
130137
@@ -133,11 +140,26 @@ const badgeStrategies = {
133140 return { label : 'downloads/mo' , value : formatNumber ( count ) , color : COLORS . orange }
134141 } ,
135142
143+ 'downloads-day' : async ( pkgData : globalThis . Packument ) => {
144+ const count = await fetchDownloads ( pkgData . name , 'last-day' )
145+ return { label : 'downloads/day' , value : formatNumber ( count ) , color : COLORS . orange }
146+ } ,
147+
136148 'downloads-week' : async ( pkgData : globalThis . Packument ) => {
137149 const count = await fetchDownloads ( pkgData . name , 'last-week' )
138150 return { label : 'downloads/wk' , value : formatNumber ( count ) , color : COLORS . orange }
139151 } ,
140152
153+ 'downloads-month' : async ( pkgData : globalThis . Packument ) => {
154+ const count = await fetchDownloads ( pkgData . name , 'last-month' )
155+ return { label : 'downloads/mo' , value : formatNumber ( count ) , color : COLORS . orange }
156+ } ,
157+
158+ 'downloads-year' : async ( pkgData : globalThis . Packument ) => {
159+ const count = await fetchDownloads ( pkgData . name , 'last-year' )
160+ return { label : 'downloads/yr' , value : formatNumber ( count ) , color : COLORS . orange }
161+ } ,
162+
141163 'vulnerabilities' : async ( pkgData : globalThis . Packument ) => {
142164 const latest = getLatestVersion ( pkgData )
143165 const count = latest ? await fetchVulnerabilities ( pkgData . name , latest ) : 0
@@ -192,9 +214,33 @@ const badgeStrategies = {
192214 color : isDeprecated ? COLORS . red : COLORS . green ,
193215 }
194216 } ,
217+
218+ 'quality' : async ( pkgData : globalThis . Packument ) => {
219+ const score = await fetchNpmsScore ( pkgData . name )
220+ const value = score ? `${ Math . round ( score . detail . quality * 100 ) } %` : 'unknown'
221+ return { label : 'quality' , value, color : COLORS . purple }
222+ } ,
223+
224+ 'popularity' : async ( pkgData : globalThis . Packument ) => {
225+ const score = await fetchNpmsScore ( pkgData . name )
226+ const value = score ? `${ Math . round ( score . detail . popularity * 100 ) } %` : 'unknown'
227+ return { label : 'popularity' , value, color : COLORS . cyan }
228+ } ,
229+
230+ 'maintenance' : async ( pkgData : globalThis . Packument ) => {
231+ const score = await fetchNpmsScore ( pkgData . name )
232+ const value = score ? `${ Math . round ( score . detail . maintenance * 100 ) } %` : 'unknown'
233+ return { label : 'maintenance' , value, color : COLORS . yellow }
234+ } ,
235+
236+ 'score' : async ( pkgData : globalThis . Packument ) => {
237+ const score = await fetchNpmsScore ( pkgData . name )
238+ const value = score ? `${ Math . round ( score . final * 100 ) } %` : 'unknown'
239+ return { label : 'score' , value, color : COLORS . blue }
240+ } ,
195241}
196242
197- const BadgeTypeSchema = v . picklist ( Object . keys ( badgeStrategies ) )
243+ const BadgeTypeSchema = v . picklist ( Object . keys ( badgeStrategies ) as [ string , ... string [ ] ] )
198244
199245export default defineCachedEventHandler (
200246 async event => {
0 commit comments