11<script setup lang="ts">
2- import type { PackumentVersion } from ' #shared/types'
2+ import type { PackumentVersion , NpmVersionDist } from ' #shared/types'
33
44const route = useRoute (' package-name' )
55
@@ -124,6 +124,14 @@ function getDependencyCount(version: PackumentVersion | null): number {
124124 return Object .keys (version .dependencies ).length
125125}
126126
127+ // Check if a version has provenance/attestations
128+ // The dist object may have attestations that aren't in the base type
129+ function hasProvenance(version : PackumentVersion | null ): boolean {
130+ if (! version ?.dist ) return false
131+ const dist = version .dist as NpmVersionDist
132+ return !! dist .attestations
133+ }
134+
127135// Package manager install commands
128136const packageManagers = [
129137 { id: ' npm' , label: ' npm' , action: ' install' },
@@ -229,16 +237,26 @@ defineOgImageComponent('Package', {
229237 <h1 class =" font-mono text-2xl sm:text-3xl font-medium" >
230238 {{ pkg.name }}
231239 </h1 >
232- <span
240+ <a
233241 v-if =" displayVersion"
234- class =" shrink-0 px-3 py-1 font-mono text-sm bg-bg-muted border border-border rounded-md"
242+ :href =" hasProvenance(displayVersion) ? `https://www.npmjs.com/package/${pkg.name}/v/${displayVersion.version}#provenance` : undefined"
243+ :target =" hasProvenance(displayVersion) ? '_blank' : undefined"
244+ :rel =" hasProvenance(displayVersion) ? 'noopener noreferrer' : undefined"
245+ class =" shrink-0 inline-flex items-center gap-1.5 px-3 py-1 font-mono text-sm bg-bg-muted border border-border rounded-md transition-colors duration-200"
246+ :class =" hasProvenance(displayVersion) ? 'hover:border-border-hover cursor-pointer' : 'cursor-default'"
247+ :title =" hasProvenance(displayVersion) ? 'Verified provenance' : undefined"
235248 >
236249 v{{ displayVersion.version }}
237250 <span
238251 v-if =" requestedVersion && latestVersion && displayVersion.version !== latestVersion.version"
239252 class =" text-fg-subtle"
240253 >(not latest)</span >
241- </span >
254+ <span
255+ v-if =" hasProvenance(displayVersion)"
256+ class =" i-solar-shield-check-outline w-4 h-4 text-fg-muted"
257+ aria-label =" Verified provenance"
258+ />
259+ </a >
242260 </div >
243261 <!-- Fixed height description container to prevent CLS -->
244262 <div
@@ -479,7 +497,7 @@ defineOgImageComponent('Package', {
479497 </div >
480498 <div class =" flex items-center gap-2 px-4 pt-3 pb-4" >
481499 <span class =" text-fg-subtle font-mono text-sm select-none" >$</span >
482- <code class =" font-mono text-sm" ><ClientOnly ><span class =" text-fg" >{{ selectedPMLabel }}</span > <span class =" text-fg-muted" >{{ selectedPMAction }}</span ><span
500+ <code class =" font-mono text-sm" ><ClientOnly ><span class =" text-fg" >{{ selectedPMLabel }}</span > <span class =" text-fg-muted" >{{ selectedPMAction }}</span > <span
483501 v-if =" selectedPM !== 'deno'"
484502 class =" text-fg-muted"
485503 > {{ pkg.name }}</span ><span
@@ -609,25 +627,33 @@ defineOgImageComponent('Package', {
609627 <div
610628 v-for =" version in sortedVersions.slice(0, 10)"
611629 :key =" version"
612- class =" flex items-center justify-between py-1.5 text-sm"
630+ class =" flex items-center justify-between py-1.5 text-sm gap-2 "
613631 >
614632 <NuxtLink
615633 :to =" `/package/${pkg.name}/v/${version}`"
616- class =" font-mono text-fg-muted hover:text-fg transition-colors duration-200"
634+ class =" font-mono text-fg-muted hover:text-fg transition-colors duration-200 min-w-0 "
617635 >
618636 {{ version }}
619637 <span
620638 v-if =" pkg['dist-tags']?.latest === version"
621639 class =" ml-1 text-xs text-fg-subtle"
622640 >(latest)</span >
623641 </NuxtLink >
624- <time
625- v-if =" pkg.time[version]"
626- :datetime =" pkg.time[version]"
627- class =" text-xs text-fg-subtle"
628- >
629- {{ formatDate(pkg.time[version]) }}
630- </time >
642+ <div class =" flex items-center gap-2 shrink-0" >
643+ <time
644+ v-if =" pkg.time[version]"
645+ :datetime =" pkg.time[version]"
646+ class =" text-xs text-fg-subtle"
647+ >
648+ {{ formatDate(pkg.time[version]) }}
649+ </time >
650+ <ProvenanceBadge
651+ v-if =" pkg.versions[version] && hasProvenance(pkg.versions[version])"
652+ :package-name =" pkg.name"
653+ :version =" version"
654+ compact
655+ />
656+ </div >
631657 </div >
632658 </div >
633659 </section >
@@ -648,11 +674,13 @@ defineOgImageComponent('Package', {
648674 :href =" `https://npmgraph.js.org/?q=${pkg.name}`"
649675 target =" _blank"
650676 rel =" noopener noreferrer"
651- class =" link-subtle"
677+ class =" link-subtle text-fg-subtle "
652678 aria-label =" View dependency graph"
653679 title =" View dependency graph"
654680 >
655- <span class =" i-carbon-network-3 w-4 h-4 inline-block" />
681+ <span class =" text-xs uppercase tracking-wider" >
682+ Graph
683+ </span >
656684 </a >
657685 </div >
658686 <ul class =" space-y-1 list-none m-0 p-0" >
0 commit comments