Skip to content

Comments

feat: add package download button#1586

Open
Adebesin-Cell wants to merge 5 commits intonpmx-dev:mainfrom
Adebesin-Cell:feat/download-button
Open

feat: add package download button#1586
Adebesin-Cell wants to merge 5 commits intonpmx-dev:mainfrom
Adebesin-Cell:feat/download-button

Conversation

@Adebesin-Cell
Copy link
Contributor

🔗 Linked issue

resolves #1528

🧭 Context

There was previously no way to directly download a package tarball or fetch all dependencies from the package detail page.

This PR introduces a Download button to make that happen.

📚 Description

This change adds a new Download button to the package detail page. The button includes a dropdown menu with two options:

  • Download the package .tgz tarball directly.
  • Generate and download a .sh script to fetch all dependencies.

Screenshot

Screenshot 2026-02-22 at 21 36 23

@vercel
Copy link

vercel bot commented Feb 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Feb 24, 2026 8:21pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 24, 2026 8:21pm
npmx-lunaria Ignored Ignored Feb 24, 2026 8:21pm

Request Review

@github-actions
Copy link

github-actions bot commented Feb 22, 2026

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
lunaria/files/en-GB.json Localization changed, will be marked as complete. 🔄️
lunaria/files/en-US.json Source changed, localizations will be marked as outdated.
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@Adebesin-Cell Adebesin-Cell changed the title feat: Add package download button feat: add package download button Feb 22, 2026
@codecov
Copy link

codecov bot commented Feb 22, 2026

Codecov Report

❌ Patch coverage is 16.80672% with 99 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/components/Package/DownloadButton.vue 17.09% 85 Missing and 12 partials ⚠️
app/pages/package/[[org]]/[name].vue 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 22, 2026

📝 Walkthrough

Walkthrough

Adds a subtle variant to the Button component and adjusts its border and sizing class logic. Introduces a new Package DownloadButton Vue component (teleported dropdown) to download package tarballs or a dependencies script with keyboard, focus and accessibility handling. Integrates the download button into the package detail page. Moves install-size types into shared/types, adds tarballUrl to resolved/dependency structures and test fixtures, and adds i18n keys and schema entries for download-related labels.

Possibly related PRs

Suggested labels

front, a11y

Suggested reviewers

  • danielroe
  • graphieros
  • knowler
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is directly related to the changeset, describing the new Download button feature with context and screenshots.
Linked Issues check ✅ Passed The PR successfully implements the core requirement from issue #1528: a button to download a package and optionally its dependencies.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing the download button feature; no unrelated modifications detected across components, types, i18n, tests, or utilities.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
app/pages/package/[[org]]/[name].vue (1)

1144-1154: Consider showing the download button without waiting for install-size.
Right now the button only appears once install-size resolves; if the fetch is slow or fails, users lose direct tarball download. Consider rendering on displayVersion and disabling the dependencies action until installSize arrives.

Possible tweak
-            <PackageDownloadButton
-              v-if="displayVersion && installSize"
+            <PackageDownloadButton
+              v-if="displayVersion"
               :package-name="pkg.name"
               :version="displayVersion"
-              :install-size="installSize"
+              :install-size="installSize ?? undefined"
               size="small"
             />

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
app/components/Package/DownloadButton.vue (1)

185-187: Use same-name shorthand for size binding.

This can be simplified with Vue’s same-name shorthand.

♻️ Suggested tweak
-    :size="size"
+    :size

Based on learnings, "In Vue 3.4 and later, you can use same-name shorthand for attribute bindings: use :attributeName instead of :attributeName="attributeName" when binding to a variable with the same name in scope. Apply this shorthand in .vue components."


ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 07261cb and dafc475.

📒 Files selected for processing (3)
  • app/components/Button/Base.vue
  • app/components/Package/DownloadButton.vue
  • test/nuxt/a11y.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/components/Button/Base.vue

Comment on lines +25 to +28
const menuItems = computed(() => [
{ id: 'package', label: t('package.download.package'), icon: 'i-lucide:package' },
{ id: 'dependencies', label: t('package.download.dependencies'), icon: 'i-lucide:list-tree' },
])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Hide or disable “Dependencies” when install size data is missing.

Right now the menu always shows the dependencies option, but downloadDependenciesScript() becomes a no-op when installSize is null, which feels like a dead action. Consider filtering it out (or disabling it) when install size data is unavailable.

🔧 Suggested tweak
-const menuItems = computed(() => [
-  { id: 'package', label: t('package.download.package'), icon: 'i-lucide:package' },
-  { id: 'dependencies', label: t('package.download.dependencies'), icon: 'i-lucide:list-tree' },
-])
+const menuItems = computed(() => {
+  const items = [{ id: 'package', label: t('package.download.package'), icon: 'i-lucide:package' }]
+  if (props.installSize) {
+    items.push({
+      id: 'dependencies',
+      label: t('package.download.dependencies'),
+      icon: 'i-lucide:list-tree',
+    })
+  }
+  return items
+})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const menuItems = computed(() => [
{ id: 'package', label: t('package.download.package'), icon: 'i-lucide:package' },
{ id: 'dependencies', label: t('package.download.dependencies'), icon: 'i-lucide:list-tree' },
])
const menuItems = computed(() => {
const items = [{ id: 'package', label: t('package.download.package'), icon: 'i-lucide:package' }]
if (props.installSize) {
items.push({
id: 'dependencies',
label: t('package.download.dependencies'),
icon: 'i-lucide:list-tree',
})
}
return items
})

Comment on lines +109 to +112
try {
const response = await fetch(tarballUrl)
const blob = await response.blob()
const url = URL.createObjectURL(blob)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard against non-OK fetch responses to avoid downloading error HTML.

If the registry returns 4xx/5xx, the blob can still be created and saved as a .tgz, which is misleading. Check response.ok and throw to trigger the fallback path.

🔧 Suggested tweak
   try {
     const response = await fetch(tarballUrl)
+    if (!response.ok) {
+      throw new Error(`Failed to fetch tarball (${response.status})`)
+    }
     const blob = await response.blob()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
const response = await fetch(tarballUrl)
const blob = await response.blob()
const url = URL.createObjectURL(blob)
try {
const response = await fetch(tarballUrl)
if (!response.ok) {
throw new Error(`Failed to fetch tarball (${response.status})`)
}
const blob = await response.blob()
const url = URL.createObjectURL(blob)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Add a button to direct download a dependency

1 participant