@@ -17,6 +17,16 @@ definePageMeta({
1717 name: ' package-versions' ,
1818})
1919
20+ interface NpmWebsiteVersionDownload {
21+ version: string
22+ downloads: number
23+ }
24+
25+ interface NpmWebsiteVersionsResponse {
26+ weeklyDownloads? : number
27+ versions: NpmWebsiteVersionDownload []
28+ }
29+
2030/** Number of flat items (headers + version rows) to render statically during SSR */
2131const SSR_COUNT = 20
2232
@@ -49,6 +59,47 @@ const distTags = computed(() => versionSummary.value?.distTags ?? {})
4959const versionStrings = computed (() => versionSummary .value ?.versions ?? [])
5060const versionTimes = computed (() => versionSummary .value ?.time ?? {})
5161
62+ const { data : npmWebsiteVersions } = useLazyFetch <NpmWebsiteVersionsResponse >(
63+ () => ` /api/registry/npmjs-versions/${encodeURIComponent (packageName .value )} ` ,
64+ {
65+ key : () => ` npmjs-versions:${packageName .value } ` ,
66+ deep: false ,
67+ default : () => ({ versions: [] }),
68+ getCachedData(key , nuxtApp ) {
69+ return nuxtApp .static .data [key ] ?? nuxtApp .payload .data [key ]
70+ },
71+ },
72+ )
73+
74+ const numberFormatter = useNumberFormatter ()
75+ const versionDownloadsMap = computed (
76+ () =>
77+ new Map (
78+ (npmWebsiteVersions .value ?.versions ?? []).map (({ version , downloads }) => [
79+ version ,
80+ downloads ,
81+ ]),
82+ ),
83+ )
84+
85+ function getVersionDownloads(version : string ): number | undefined {
86+ return versionDownloadsMap .value .get (version )
87+ }
88+
89+ function getGroupDownloads(versions : string []): number | undefined {
90+ let total = 0
91+ let hasValue = false
92+
93+ for (const version of versions ) {
94+ const downloads = getVersionDownloads (version )
95+ if (downloads === undefined ) continue
96+ total += downloads
97+ hasValue = true
98+ }
99+
100+ return hasValue ? total : undefined
101+ }
102+
52103// ─── Phase 2: full metadata (loaded on first group expand) ────────────────────
53104// Fetches deprecated status, provenance, and exact times needed for version rows.
54105
@@ -241,6 +292,14 @@ const flatItems = computed<FlatItem[]>(() => {
241292 >
242293 </div >
243294 <!-- Right: date + provenance -->
295+ <div
296+ v-if =" getVersionDownloads(latestTagRow!.version) !== undefined"
297+ class =" text-sm font-medium text-fg tabular-nums shrink-0"
298+ :aria-label =" $t('package.downloads.title')"
299+ dir =" ltr"
300+ >
301+ {{ numberFormatter.format(getVersionDownloads(latestTagRow!.version)!) }}
302+ </div >
244303 <div class =" flex flex-col items-end gap-1.5 shrink-0 relative z-10" >
245304 <ProvenanceBadge
246305 v-if =" fullVersionMap?.get(latestTagRow!.version)?.hasProvenance"
@@ -290,6 +349,14 @@ const flatItems = computed<FlatItem[]>(() => {
290349 </LinkBase >
291350
292351 <!-- Date -->
352+ <span
353+ v-if =" getVersionDownloads(row.version) !== undefined"
354+ class =" text-xs text-fg-muted shrink-0 tabular-nums w-24 text-end"
355+ :aria-label =" $t('package.downloads.title')"
356+ dir =" ltr"
357+ >
358+ {{ numberFormatter.format(getVersionDownloads(row.version)!) }}
359+ </span >
293360 <DateTime
294361 v-if =" getVersionTime(row.version)"
295362 :datetime =" getVersionTime(row.version)!"
@@ -373,7 +440,15 @@ const flatItems = computed<FlatItem[]>(() => {
373440 </span >
374441 <span class =" text-sm font-medium" >{{ item.label }}</span >
375442 <span class =" text-xs text-fg-subtle" >({{ item.versions.length }})</span >
376- <span class =" ms-auto flex items-center gap-3 shrink-0" >
443+ <span
444+ v-if =" getGroupDownloads(item.versions) !== undefined"
445+ class =" ms-auto text-xs text-fg-muted tabular-nums w-24 text-end"
446+ :aria-label =" $t('package.downloads.title')"
447+ dir =" ltr"
448+ >
449+ {{ numberFormatter.format(getGroupDownloads(item.versions)!) }}
450+ </span >
451+ <span class =" flex items-center gap-3 shrink-0" >
377452 <span class =" text-xs text-fg-muted" dir =" ltr" >{{ item.versions[0] }}</span >
378453 <DateTime
379454 v-if =" getVersionTime(item.versions[0])"
@@ -437,8 +512,16 @@ const flatItems = computed<FlatItem[]>(() => {
437512 </span >
438513 </div >
439514
515+ <span
516+ v-if =" getVersionDownloads(item.version) !== undefined"
517+ class =" text-xs text-fg-muted tabular-nums w-24 text-end shrink-0"
518+ :aria-label =" $t('package.downloads.title')"
519+ dir =" ltr"
520+ >
521+ {{ numberFormatter.format(getVersionDownloads(item.version)!) }}
522+ </span >
440523 <!-- Right side -->
441- <div class =" flex items-center gap-2 shrink-0 relative z-10" >
524+ <div class =" flex items-center gap-2 shrink-0 relative z-10 w-36 justify-end " >
442525 <!-- Metadata: date + provenance -->
443526 <DateTime
444527 v-if =" getVersionTime(item.version)"
@@ -477,7 +560,15 @@ const flatItems = computed<FlatItem[]>(() => {
477560 </span >
478561 <span class =" text-sm font-medium" >{{ item.label }}</span >
479562 <span class =" text-xs text-fg-subtle" >({{ item.versions.length }})</span >
480- <span class =" ms-auto flex items-center gap-3 shrink-0" >
563+ <span
564+ v-if =" getGroupDownloads(item.versions) !== undefined"
565+ class =" ms-auto text-xs text-fg-muted tabular-nums w-24 text-end"
566+ :aria-label =" $t('package.downloads.title')"
567+ dir =" ltr"
568+ >
569+ {{ numberFormatter.format(getGroupDownloads(item.versions)!) }}
570+ </span >
571+ <span class =" flex items-center gap-3 shrink-0" >
481572 <span class =" text-xs text-fg-muted" dir =" ltr" >{{ item.versions[0] }}</span >
482573 <DateTime
483574 v-if =" getVersionTime(item.versions[0] ?? '')"
0 commit comments