Resolver for npm-hosted packages with caching, offline support, and registry authentication
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The version selection system handles intelligent package version resolution based on preferences, constraints, and semantic versioning rules with support for tags, ranges, and exact versions.
Core types used for version resolution within the resolver.
/**
* Structured package specification for version resolution
*/
interface RegistryPackageSpec {
/** Type of specification */
type: 'tag' | 'version' | 'range';
/** Package name */
name: string;
/** Specification string to match against */
fetchSpec: string;
/** Normalized preference for caching */
normalizedPref?: string;
}Configure preferred versions for specific packages during resolution.
/**
* Version preference configuration for specific packages
*/
interface PreferredVersions {
[packageName: string]: {
/** Version selector (exact version, range, or tag) */
selector: string;
/** Type of version selector */
type: 'version' | 'range' | 'tag';
};
}
/**
* Options for package resolution
*/
interface ResolveOptions {
/** Default tag when no preference specified */
defaultTag?: string;
/** Registry URL to resolve from */
registry: string;
/** Preferred versions for specific packages */
preferredVersions?: PreferredVersions;
/** Project root prefix */
prefix: string;
/** Available local packages for fallback */
localPackages?: LocalPackages;
}The resolver internally handles package version selection from metadata based on the specification type and preferred versions configuration. This process is handled automatically when calling the resolver function.
import createResolveFromNpm from '@pnpm/npm-resolver';
const resolve = createResolveFromNpm({
metaCache: new Map(),
store: './pnpm-store',
rawNpmConfig: { registry: 'https://registry.npmjs.org/' },
});
// Exact version
const exactResult = await resolve(
{ alias: 'lodash', pref: '4.17.21' },
{
registry: 'https://registry.npmjs.org/',
prefix: process.cwd()
}
);
// Semantic version range
const rangeResult = await resolve(
{ alias: 'express', pref: '^4.18.0' },
{
registry: 'https://registry.npmjs.org/',
prefix: process.cwd()
}
);
// Tag-based selection
const tagResult = await resolve(
{ alias: 'react', pref: 'beta' },
{
registry: 'https://registry.npmjs.org/',
prefix: process.cwd()
}
);
console.log(`Exact: ${exactResult?.package.version}`);
console.log(`Range: ${rangeResult?.package.version}`);
console.log(`Tag: ${tagResult?.package.version}`);// Complex version ranges
const complexRanges = [
{ alias: 'typescript', pref: '~4.9.0' }, // Patch-level changes
{ alias: 'webpack', pref: '^5.0.0' }, // Compatible changes
{ alias: 'eslint', pref: '>=8.0.0 <9.0.0' }, // Range with constraints
{ alias: 'prettier', pref: '2.x' }, // Major version wildcard
];
for (const dep of complexRanges) {
const result = await resolve(dep, {
registry: 'https://registry.npmjs.org/',
prefix: process.cwd()
});
if (result) {
console.log(`${dep.alias}@${dep.pref} -> ${result.package.version}`);
}
}// Configure preferred versions for specific packages
const preferredVersions = {
'react': {
selector: '17.0.2', // Prefer specific stable version
type: 'version' as const
},
'lodash': {
selector: '^4.17.0', // Prefer range within 4.17.x
type: 'range' as const
},
'typescript': {
selector: 'beta', // Prefer beta releases
type: 'tag' as const
}
};
const result = await resolve(
{ alias: 'react', pref: '^17.0.0' },
{
registry: 'https://registry.npmjs.org/',
prefix: process.cwd(),
preferredVersions
}
);
// Will prefer 17.0.2 even though range allows newer versions
console.log(`Selected version: ${result?.package.version}`);// Working with distribution tags
const tagExamples = [
{ alias: 'next', pref: 'canary' }, // Canary releases
{ alias: 'vue', pref: 'beta' }, // Beta releases
{ alias: 'angular', pref: 'next' }, // Next major version
{ alias: 'react', pref: 'experimental' }, // Experimental features
];
for (const dep of tagExamples) {
try {
const result = await resolve(dep, {
registry: 'https://registry.npmjs.org/',
prefix: process.cwd()
});
if (result) {
console.log(`${dep.alias}@${dep.pref}: ${result.package.version}`);
console.log(`Latest: ${result.latest}`);
}
} catch (error) {
console.error(`Tag ${dep.pref} not found for ${dep.alias}`);
}
}// Try multiple version preferences with fallback
async function resolveWithFallback(packageName: string, preferences: string[]) {
for (const pref of preferences) {
try {
const result = await resolve(
{ alias: packageName, pref },
{
registry: 'https://registry.npmjs.org/',
prefix: process.cwd()
}
);
if (result) {
console.log(`Resolved ${packageName}@${pref} -> ${result.package.version}`);
return result;
}
} catch (error) {
console.log(`Failed to resolve ${packageName}@${pref}: ${error.message}`);
}
}
throw new Error(`Could not resolve ${packageName} with any preference`);
}
// Try beta first, fallback to latest
const result = await resolveWithFallback('typescript', ['beta', 'rc', 'latest']);The resolver supports various version specification formats:
// Different preference formats supported
const supportedFormats = [
'1.2.3', // Exact version
'^1.2.0', // Caret range - compatible within major version
'~1.2.0', // Tilde range - compatible within minor version
'>=1.0.0 <2.0.0', // Range expression with constraints
'latest', // Distribution tag
'beta', // Beta distribution tag
'next', // Next distribution tag
];
// Example resolution with different formats
for (const pref of supportedFormats) {
const result = await resolve(
{ alias: 'example-package', pref },
{
registry: 'https://registry.npmjs.org/',
prefix: process.cwd()
}
);
if (result) {
console.log(`"${pref}" resolved to: ${result.package.version}`);
}
}// Define local packages for development
const localPackages = {
'my-lib': {
'1.0.0': {
directory: '/workspace/my-lib',
package: { name: 'my-lib', version: '1.0.0' }
},
'1.1.0-dev': {
directory: '/workspace/my-lib',
package: { name: 'my-lib', version: '1.1.0-dev' }
}
}
};
// Prefer local development version over registry
const devResult = await resolve(
{ alias: 'my-lib', pref: '^1.0.0' },
{
registry: 'https://registry.npmjs.org/',
prefix: process.cwd(),
localPackages
}
);
if (devResult?.resolvedVia === 'local-filesystem') {
console.log(`Using local development version: ${devResult.package.version}`);
console.log(`Location: ${devResult.resolution.directory}`);
} else {
console.log(`Using registry version: ${devResult?.package.version}`);
}// Validate version preferences through resolution attempt
async function validateVersionPreference(alias: string, pref: string): Promise<boolean> {
try {
const result = await resolve(
{ alias, pref },
{
registry: 'https://registry.npmjs.org/',
prefix: process.cwd()
}
);
return result !== null;
} catch (error) {
// Invalid preference or resolution failed
return false;
}
}
// Test various preferences
const testPreferences = [
{ alias: 'lodash', pref: '4.17.21' }, // Valid exact version
{ alias: 'lodash', pref: '^4.0.0' }, // Valid range
{ alias: 'lodash', pref: 'latest' }, // Valid tag
{ alias: 'lodash', pref: 'invalid' }, // Invalid tag
];
for (const { alias, pref } of testPreferences) {
const isValid = await validateVersionPreference(alias, pref);
console.log(`${alias}@${pref}: ${isValid ? 'valid' : 'invalid'}`);
}Install with Tessl CLI
npx tessl i tessl/npm-pnpm--npm-resolver