JavaScript package downloader and fetcher that serves as the core package handling library for npm
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Core package operations for fetching, extracting, and resolving packages from any source that npm supports. These functions work with any package specifier that npm can install - registry packages, git repositories, local files, directories, and remote tarballs.
Resolves a package specifier to a tarball URL, file path, or git repository with commit hash.
/**
* Resolve a package specifier to a concrete location
* @param {string} spec - Package specifier (name@version, git URL, file path, etc.)
* @param {Object} opts - Configuration options
* @returns {Promise<string>} Resolved tarball URL, file path, or git repo URL
*/
function resolve(spec, opts);Usage Examples:
const pacote = require('pacote');
// Resolve registry package
const url = await pacote.resolve('lodash@4.17.21');
// Returns: 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz'
// Resolve git repository
const gitUrl = await pacote.resolve('github:facebook/react#v18.0.0');
// Returns: 'git+ssh://git@github.com/facebook/react.git#v18.0.0'
// Resolve with options
const resolved = await pacote.resolve('express@latest', {
registry: 'https://registry.npmjs.org'
});Extracts a package's tarball into a destination folder with proper file permissions.
/**
* Extract a package to a destination directory
* @param {string} spec - Package specifier
* @param {string} dest - Destination directory path
* @param {Object} opts - Configuration options
* @returns {Promise<ExtractionResult>} Extraction metadata
*/
function extract(spec, dest, opts);
interface ExtractionResult {
from: string; // Original package specifier
resolved: string; // Resolved package URL
integrity: string; // Package integrity hash
}Usage Examples:
const pacote = require('pacote');
const path = require('path');
// Extract package to directory
const result = await pacote.extract('react@18.0.0', './node_modules/react');
console.log('Extracted:', result.from);
console.log('From URL:', result.resolved);
console.log('Integrity:', result.integrity);
// Extract with custom options
await pacote.extract('lodash@latest', './packages/lodash', {
cache: './custom-cache',
umask: 0o022
});
// Extract git repository
await pacote.extract('github:npm/cli', './packages/npm-cli', {
before: '2023-01-01T00:00:00.000Z'
});Fetches (or simulates) a package's manifest - essentially the package.json file plus additional metadata.
/**
* Fetch a package manifest
* @param {string} spec - Package specifier
* @param {Object} opts - Configuration options
* @returns {Promise<PackageManifest>} Package manifest with metadata
*/
function manifest(spec, opts);
interface PackageManifest {
name: string;
version: string;
description?: string;
main?: string;
dependencies?: { [name: string]: string };
devDependencies?: { [name: string]: string };
scripts?: { [name: string]: string };
_resolved: string; // Tarball URL or file path
_from: string; // Normalized spec
_integrity: string; // Integrity hash
_id: string; // Canonical spec (name@version)
// ... plus all other standard package.json fields
}Usage Examples:
const pacote = require('pacote');
// Get manifest for latest version
const manifest = await pacote.manifest('express@latest');
console.log('Name:', manifest.name);
console.log('Version:', manifest.version);
console.log('Dependencies:', manifest.dependencies);
// Get manifest with full metadata
const fullManifest = await pacote.manifest('lodash@4.17.21', {
fullMetadata: true,
fullReadJson: true
});
// Get manifest for git repository
const gitManifest = await pacote.manifest('github:facebook/react#main');
console.log('Git package:', gitManifest.name);Fetches (or simulates) a package's packument - the top-level package document listing all available versions and metadata.
/**
* Fetch a package packument (full package document)
* @param {string} spec - Package specifier
* @param {Object} opts - Configuration options
* @returns {Promise<Packument>} Full package document
*/
function packument(spec, opts);
interface Packument {
name: string;
versions: { [version: string]: PackageManifest };
'dist-tags': { [tag: string]: string };
time?: { [version: string]: string };
_contentLength: number;
// ... additional registry metadata
}Usage Examples:
const pacote = require('pacote');
// Get packument for registry package
const packument = await pacote.packument('express');
console.log('Available versions:', Object.keys(packument.versions));
console.log('Latest version:', packument['dist-tags'].latest);
console.log('Beta version:', packument['dist-tags'].beta);
// Get packument with full metadata
const fullPackument = await pacote.packument('lodash', {
fullMetadata: true
});
// Use packument cache to avoid duplicate requests
const cache = new Map();
const pack1 = await pacote.packument('react', { packumentCache: cache });
const pack2 = await pacote.packument('react', { packumentCache: cache }); // Uses cacheGet package tarball data as a buffer, stream it through a handler, or save it to a file.
/**
* Get package tarball data as a buffer
* @param {string} spec - Package specifier
* @param {Object} opts - Configuration options
* @returns {Promise<TarballResult>} Tarball buffer with metadata
*/
function tarball(spec, opts);
/**
* Stream tarball through a handler function
* @param {string} spec - Package specifier
* @param {Function} handler - Stream handler function
* @param {Object} opts - Configuration options
* @returns {Promise<void>} Promise resolving when handler completes
*/
function tarball.stream(spec, handler, opts);
/**
* Save tarball to a file
* @param {string} spec - Package specifier
* @param {string} dest - Destination file path
* @param {Object} opts - Configuration options
* @returns {Promise<TarballResult>} Tarball metadata
*/
function tarball.file(spec, dest, opts);
interface TarballResult extends Buffer {
from: string; // Original package specifier
resolved: string; // Resolved package URL
integrity: string; // Package integrity hash
}Usage Examples:
const pacote = require('pacote');
const fs = require('fs');
// Get tarball as buffer
const tarballData = await pacote.tarball('express@4.18.0');
console.log('Tarball size:', tarballData.length, 'bytes');
console.log('From:', tarballData.from);
console.log('Integrity:', tarballData.integrity);
// Stream tarball data
await pacote.tarball.stream('lodash@latest', async (stream) => {
const writeStream = fs.createWriteStream('./lodash.tgz');
stream.pipe(writeStream);
return new Promise((resolve, reject) => {
writeStream.on('finish', resolve);
writeStream.on('error', reject);
});
});
// Save tarball to file
const result = await pacote.tarball.file('react@18.0.0', './react-18.0.0.tgz');
console.log('Saved tarball with integrity:', result.integrity);
// Download git repository as tarball
await pacote.tarball.file('github:npm/cli#latest', './npm-cli.tgz', {
cache: './git-cache'
});All core functions can throw various errors that should be handled appropriately:
const pacote = require('pacote');
try {
const manifest = await pacote.manifest('nonexistent-package@1.0.0');
} catch (error) {
if (error.code === 'E404') {
console.log('Package not found');
} else if (error.code === 'EINTEGRITY') {
console.log('Integrity verification failed');
} else if (error.code === 'ENOTFOUND') {
console.log('Network error or registry unavailable');
} else if (error.code === 'EMISSINGSIGNATUREKEY') {
console.log('Missing signature verification key');
} else if (error.code === 'EEXPIREDSIGNATUREKEY') {
console.log('Signature verification key expired');
} else if (error.code === 'EINTEGRITYSIGNATURE') {
console.log('Invalid registry signature');
} else if (error.code === 'EATTESTATIONSUBJECT') {
console.log('Attestation subject mismatch');
} else if (error.code === 'EATTESTATIONVERIFY') {
console.log('Attestation verification failed');
} else {
console.log('Unexpected error:', error.message);
}
}Common error codes:
E404: Package or version not foundEINTEGRITY: Integrity verification failedENOTFOUND: Network error or DNS resolution failedETIMEDOUT: Request timeoutEACCES: Permission denied (file system operations)ENOENT: File or directory not found (local operations)EMISSINGSIGNATUREKEY: Missing signature keys for verificationEEXPIREDSIGNATUREKEY: Expired signature keysEINTEGRITYSIGNATURE: Invalid registry signaturesEATTESTATIONSUBJECT: Attestation subject mismatchEATTESTATIONVERIFY: Attestation verification failureconst pacote = require('pacote');
// Handle retriable vs non-retriable errors
try {
const result = await pacote.extract('package@1.0.0', './dest');
} catch (error) {
const fetcher = pacote.FetcherBase.get('package@1.0.0', {});
if (fetcher.isRetriableError(error)) {
console.log('Error can be retried:', error.message);
// Implement retry logic
} else if (fetcher.isDataCorruptionError(error)) {
console.log('Data corruption detected:', error.message);
// Clear cache and retry
await fetcher.cleanupCached();
} else {
console.log('Permanent error:', error.message);
throw error;
}
}
// Security-related error handling
try {
await pacote.manifest('package@1.0.0', {
verifySignatures: true,
verifyAttestations: true
});
} catch (error) {
if (error.code.startsWith('ESIGNATURE') || error.code.startsWith('EATTESTATION')) {
console.log('Security verification failed - package may be compromised');
// Handle security failure appropriately
}
}Install with Tessl CLI
npx tessl i tessl/npm-pacote