UNPKG

npm-install-size

Version:

Check the install size of any NPM package before installing it.

73 lines (67 loc) 2.63 kB
import fetch from 'node-fetch'; import tar from 'tar'; import fs from 'fs/promises'; export async function retry(fn, retries = 3, delay = 500) { let lastErr; for (let i = 0; i < retries; i++) { try { return await fn(); } catch (err) { lastErr = err; if (i < retries - 1) await new Promise(res => setTimeout(res, delay)); } } throw lastErr; } export function parsePkgArg(arg) { // Handles scoped packages and version, e.g. @babel/core@7.0.0 const match = arg.match(/^(@[^/]+\/[^@]+|[^@]+)(?:@(.*))?$/); if (!match) return { name: arg, version: undefined }; return { name: match[1], version: match[2] }; } export async function getLatestTarballUrl(pkgArg) { const { name, version } = parsePkgArg(pkgArg); const encoded = encodeURIComponent(name); const url = `https://registry.npmjs.org/${encoded}`; const res = await retry(() => fetch(url)); if (!res.ok) throw new Error(`Package not found`); const data = await res.json(); let ver = version || data['dist-tags']?.latest; if (!ver || !data.versions[ver]) throw new Error(`Version not found`); return { tarball: data.versions[ver].dist.tarball, version: ver }; } export async function downloadAndExtractTarball(tarballUrl, destDir) { const res = await retry(() => fetch(tarballUrl)); if (!res.ok) throw new Error(`Failed to download tarball`); await fs.mkdir(destDir, { recursive: true }); return new Promise((resolve, reject) => { const extractStream = tar.x({ cwd: destDir, strip: 1 }); res.body.pipe(extractStream); res.body.on('error', reject); extractStream.on('finish', resolve); extractStream.on('error', reject); }); } export async function fetchPackageVersions(pkgName) { const encoded = encodeURIComponent(pkgName); const url = `https://registry.npmjs.org/${encoded}`; const res = await retry(() => fetch(url)); if (!res.ok) throw new Error(`Package not found`); const data = await res.json(); return Object.keys(data.versions).sort((a, b) => { // Sort semver descending return b.localeCompare(a, undefined, { numeric: true, sensitivity: 'base' }); }); } export async function fetchPackageMeta(pkgArg) { const { name, version } = parsePkgArg(pkgArg); const encoded = encodeURIComponent(name); const url = `https://registry.npmjs.org/${encoded}`; const res = await retry(() => fetch(url)); if (!res.ok) throw new Error(`Package not found`); const data = await res.json(); if (version && data.versions[version]) { return data.versions[version]; } return data; }