Complete API documentation for @socketregistry/packageurl-js.
- Modular Functions
- PackageURL Class
- PurlBuilder Class
- UrlConverter Class
- Registry Existence Checks
- Type Constants
Tree-shakeable functions for optimal bundle size.
Parse npm package specifier into components.
Parameters:
specifier: unknown- npm package specifier string
Returns: NpmPackageComponents
{
namespace: string | undefined // e.g., '@babel' for scoped packages
name: string // package name
version: string | undefined // version without range prefixes
}Example:
import { parseNpmSpecifier } from '@socketregistry/packageurl-js'
parseNpmSpecifier('lodash@4.17.21')
// -> { namespace: undefined, name: 'lodash', version: '4.17.21' }
parseNpmSpecifier('@babel/core@^7.0.0')
// -> { namespace: '@babel', name: 'core', version: '7.0.0' }Features:
- Strips version range prefixes (
^,~,>=, etc.) - Handles dist-tags (
latest,next,beta) - Supports scoped packages
Convert PackageURL instance to canonical PURL string.
Parameters:
purl: PackageURL- PackageURL instance
Returns: string - Canonical PURL string
Example:
import { stringify } from '@socketregistry/packageurl-js'
const purl = new PackageURL('npm', undefined, 'lodash', '4.17.21')
stringify(purl)
// -> 'pkg:npm/lodash@4.17.21'Compare two PackageURLs for equality.
Parameters:
a: PackageURL- First PURLb: PackageURL- Second PURL
Returns: boolean - true if equal
Example:
import { equals } from '@socketregistry/packageurl-js'
const purl1 = PackageURL.fromString('pkg:npm/lodash@4.17.21')
const purl2 = PackageURL.fromString('pkg:npm/lodash@4.17.21')
equals(purl1, purl2) // -> trueCompare two PackageURLs for sorting.
Parameters:
a: PackageURL- First PURLb: PackageURL- Second PURL
Returns: -1 | 0 | 1 - Sort order indicator
Example:
import { compare } from '@socketregistry/packageurl-js'
const purls = [purl3, purl1, purl2]
purls.sort(compare) // Sort alphabeticallyMain class for parsing and constructing Package URLs.
new PackageURL(type, namespace, name, version, qualifiers, subpath)Parameters:
type: unknown- Package ecosystem type (e.g., 'npm', 'pypi')namespace: unknown- Optional namespace/scopename: unknown- Package name (required)version: unknown- Optional versionqualifiers: unknown- Optional key-value pairssubpath: unknown- Optional subpath
Example:
new PackageURL('npm', '@babel', 'core', '7.20.0', null, null)
// -> 'pkg:npm/%40babel/core@7.20.0'Parse PURL string into PackageURL instance.
Parameters:
purlStr: unknown- PURL string
Returns: PackageURL
Example:
PackageURL.fromString('pkg:npm/lodash@4.17.21')Create PackageURL from npm package specifier.
Parameters:
specifier: unknown- npm package specifier
Returns: PackageURL
Example:
PackageURL.fromNpm('lodash@4.17.21')
PackageURL.fromNpm('@types/node@^18.0.0')Create PackageURL from ecosystem-specific specifier.
Parameters:
type: string- Package type ('npm', etc.)specifier: unknown- Ecosystem-specific specifier
Returns: PackageURL
Example:
PackageURL.fromSpec('npm', 'lodash@4.17.21')Currently supported: npm only
Parse PackageURL from JSON string.
Parameters:
json: unknown- JSON string
Returns: PackageURL
Example:
const json = '{"type":"npm","name":"lodash","version":"4.17.21"}'
PackageURL.fromJSON(json)Parse PURL string into component array.
Parameters:
purlStr: unknown- PURL string
Returns: ParsedPurlComponents - Tuple of components
Example:
const [type, namespace, name, version, qualifiers, subpath] =
PackageURL.parseString('pkg:npm/lodash@4.17.21')Convert to canonical PURL string.
Returns: string
Convert to JSON-serializable object.
Returns: string - JSON string
Convert to plain object.
Returns: PackageURLObject
Compare with another PackageURL.
Parameters:
other: PackageURL
Returns: boolean
Compare for sorting.
Parameters:
other: PackageURL
Returns: -1 | 0 | 1
All properties are string | undefined:
type- Package ecosystem typenamespace- Optional namespace/scopename- Package nameversion- Optional versionqualifiers- Optional key-value pairssubpath- Optional subpath
Fluent builder API for constructing PURLs.
new PurlBuilder()Create a new empty builder instance.
Returns: PurlBuilder
Example:
const builder = PurlBuilder.create().type('npm').name('lodash').build()Create a builder from an existing PackageURL instance.
Parameters:
purl: PackageURL- Existing PackageURL to copy properties from
Returns: PurlBuilder - Builder with all properties pre-populated
Example:
const originalPurl = PackageURL.fromString('pkg:npm/lodash@4.17.21')
const modifiedPurl = PurlBuilder.from(originalPurl)
.version('4.18.0')
.qualifier('arch', 'x64')
.build()
console.log(modifiedPurl.toString())
// -> 'pkg:npm/lodash@4.18.0?arch=x64'Use cases:
- Modify existing PURLs while preserving most properties
- Create variants of a PURL with different versions or qualifiers
- Clone and customize PURLs
Create builders with type preset:
PurlBuilder.npm()
PurlBuilder.pypi()
PurlBuilder.maven()
PurlBuilder.gem()
PurlBuilder.cargo()
PurlBuilder.composer()
PurlBuilder.golang()
PurlBuilder.nuget()
// ... and 30+ more ecosystemsExample:
const purl = PurlBuilder.npm().name('lodash').version('4.17.21').build()All methods return this for chaining:
Set package type.
Set namespace/scope.
Set package name (required).
Set version.
Add a qualifier key-value pair.
Set all qualifiers at once.
Set subpath.
Build and return PackageURL instance.
Returns: PackageURL
import { PurlBuilder } from '@socketregistry/packageurl-js'
const purl = PurlBuilder.maven()
.namespace('org.springframework')
.name('spring-core')
.version('5.3.21')
.qualifier('classifier', 'sources')
.build()
console.log(purl.toString())
// -> 'pkg:maven/org.springframework/spring-core@5.3.21?classifier=sources'Convert PURLs to repository and download URLs.
Convert to repository URL.
Parameters:
purl: PackageURL
Returns: RepositoryUrl | null
Example:
import { UrlConverter } from '@socketregistry/packageurl-js'
const purl = PackageURL.fromString('pkg:npm/lodash@4.17.21')
UrlConverter.toRepositoryUrl(purl)
// -> { type: 'git', url: 'https://github.com/lodash/lodash' }Convert to download URL.
Parameters:
purl: PackageURL
Returns: DownloadUrl | null
Example:
UrlConverter.toDownloadUrl(purl)
// -> { type: 'tarball', url: 'https://registry.npmjs.org/...' }Modular functions to verify package existence across 14 package registries. Each function queries the official registry API to check if a package exists and optionally validates a specific version.
Generic wrapper that dispatches to type-specific existence checks based on the PackageURL type.
Parameters:
purl: PackageURL- PackageURL instance to checkoptions?: ExistsOptions- Optional configurationcache?: TtlCache- Optional TTL cache for caching responses
Returns: Promise<ExistsResult>
{
exists: boolean // Whether the package exists
latestVersion?: string // Latest version from registry
error?: string // Error message if check failed
}Example:
import { purlExists, PackageURL } from '@socketregistry/packageurl-js'
const purl = PackageURL.fromString('pkg:npm/lodash@4.17.21')
const result = await purlExists(purl)
// -> { exists: true, latestVersion: '4.17.21' }
// With caching
import { createTtlCache } from '@socketsecurity/lib/cache-with-ttl'
const cache = createTtlCache({ ttl: 5 * 60 * 1000 })
await purlExists(purl, { cache })Supported types: npm, pypi, cargo, gem, maven, nuget, golang, composer, cocoapods, pub, hex, cpan, cran, hackage
All registry functions follow the same signature pattern and return ExistsResult.
Check npm packages from registry.npmjs.org.
Example:
import { npmExists } from '@socketregistry/packageurl-js'
await npmExists('lodash')
// -> { exists: true, latestVersion: '4.17.21' }
await npmExists('core', '@babel') // scoped package
// -> { exists: true, latestVersion: '7.23.0' }
await npmExists('lodash', undefined, '4.17.21') // validate version
// -> { exists: true, latestVersion: '4.17.21' }Check Python packages from pypi.org.
Example:
import { pypiExists } from '@socketregistry/packageurl-js'
await pypiExists('requests')
// -> { exists: true, latestVersion: '2.31.0' }Check Rust crates from crates.io.
Example:
import { cargoExists } from '@socketregistry/packageurl-js'
await cargoExists('serde')
// -> { exists: true, latestVersion: '1.0.197' }Check Ruby gems from rubygems.org.
Example:
import { gemExists } from '@socketregistry/packageurl-js'
await gemExists('rails')
// -> { exists: true, latestVersion: '7.1.3' }Check Java packages from Maven Central. Requires namespace (group ID).
Example:
import { mavenExists } from '@socketregistry/packageurl-js'
await mavenExists('commons-lang3', 'org.apache.commons')
// -> { exists: true, latestVersion: '3.12.0' }Check .NET packages from nuget.org.
Example:
import { nugetExists } from '@socketregistry/packageurl-js'
await nugetExists('Newtonsoft.Json')
// -> { exists: true, latestVersion: '13.0.3' }Check Go modules from proxy.golang.org.
Example:
import { golangExists } from '@socketregistry/packageurl-js'
await golangExists('github.com/gorilla/mux')
// -> { exists: true, latestVersion: 'v1.8.0' }
await golangExists('mux', 'github.com/gorilla') // with namespace
// -> { exists: true, latestVersion: 'v1.8.0' }Check PHP/Composer packages from packagist.org. Requires namespace (vendor).
Example:
import { packagistExists } from '@socketregistry/packageurl-js'
await packagistExists('http-foundation', 'symfony')
// -> { exists: true, latestVersion: 'v6.3.0' }Check iOS/macOS pods from trunk.cocoapods.org.
Example:
import { cocoapodsExists } from '@socketregistry/packageurl-js'
await cocoapodsExists('Alamofire')
// -> { exists: true, latestVersion: '5.8.1' }Check Dart/Flutter packages from pub.dev.
Example:
import { pubExists } from '@socketregistry/packageurl-js'
await pubExists('flutter_bloc')
// -> { exists: true, latestVersion: '8.1.3' }Check Elixir/Erlang packages from hex.pm.
Example:
import { hexExists } from '@socketregistry/packageurl-js'
await hexExists('phoenix')
// -> { exists: true, latestVersion: '1.7.10' }Check Perl modules from metacpan.org.
Example:
import { cpanExists } from '@socketregistry/packageurl-js'
await cpanExists('Moose')
// -> { exists: true, latestVersion: '2.2206' }Check R packages from cran.r-universe.dev.
Example:
import { cranExists } from '@socketregistry/packageurl-js'
await cranExists('ggplot2')
// -> { exists: true, latestVersion: '3.4.4' }Check Haskell packages from hackage.haskell.org.
Example:
import { hackageExists } from '@socketregistry/packageurl-js'
await hackageExists('aeson')
// -> { exists: true, latestVersion: '2.2.0.0' }Enum-like object with all supported PURL types:
import { PURL_Type } from '@socketregistry/packageurl-js'
PURL_Type.NPM // 'npm'
PURL_Type.PYPI // 'pypi'
PURL_Type.MAVEN // 'maven'
PURL_Type.CARGO // 'cargo'
// ... 35+ typesConstants for standard PURL qualifier keys as defined in the purl-spec.
import { PurlQualifierNames } from '@socketregistry/packageurl-js'
PurlQualifierNames.RepositoryUrl // 'repository_url'
PurlQualifierNames.DownloadUrl // 'download_url'
PurlQualifierNames.VcsUrl // 'vcs_url'
PurlQualifierNames.FileName // 'file_name'
PurlQualifierNames.Checksum // 'checksum'Usage:
const purl = PurlBuilder.maven()
.namespace('org.apache.commons')
.name('commons-lang3')
.version('3.12.0')
.qualifier(PurlQualifierNames.Checksum, 'sha256:abc123')
.qualifier(PurlQualifierNames.DownloadUrl, 'https://repo1.maven.org/...')
.build()Known qualifiers:
repository_url- URL to package repository homepagedownload_url- Direct download URL for the package artifactvcs_url- Version control system URL (git, svn, etc.)file_name- Name of the package file or artifactchecksum- Checksum value in the formatalgorithm:value(e.g.,sha256:abc123)
Object with type-specific normalization and validation:
import { PurlType } from '@socketregistry/packageurl-js'
PurlType.npm.normalize(purl)
PurlType.npm.validate(purl)Type-specific rules:
npm:
- Name: Lowercased, namespace preserved with
@prefix - Version: Requires valid semver format
- Namespace: Used for scoped packages (e.g.,
@types)
pypi:
- Name: Lowercased, underscores replaced with dashes
- Namespace: Must be empty
- Version: Normalized according to PEP 440
maven:
- Name: Preserved as-is
- Namespace: Required (groupId)
- Case-sensitive
cargo:
- Name: Lowercased
- Namespace: Must be empty
- Version: Follows semver
Component encoding/decoding utilities:
import { PurlComponent } from '@socketregistry/packageurl-js'
PurlComponent.name.encode('my-package')
PurlComponent.name.decode('my-package')Available components:
type- Package ecosystem typenamespace- Optional namespace/scopename- Package name (required)version- Package versionqualifiers- Key-value pairssubpath- Path within package
Encoding rules:
- UTF-8 characters are percent-encoded
- Forward slashes in namespaces become encoded
@in npm scopes is encoded as%40- Special characters in names/versions are encoded per spec
Custom error class for PURL-specific errors.
import { PurlError } from '@socketregistry/packageurl-js'
try {
PackageURL.fromString('invalid')
} catch (error) {
if (error instanceof PurlError) {
console.error('PURL error:', error.message)
}
}The library performs strict validation on all components:
Type validation:
- Required for all PURLs
- Must be lowercase letters, numbers,
.,+, or- - Cannot be empty
- Example errors:
'type' is a required component'type' component must be lowercase
Name validation:
- Required for all PURLs
- Cannot contain whitespace (some types)
- Cannot be empty
- Type-specific rules apply (e.g., npm name validation)
- Example errors:
'name' is a required componentnpm 'name' component cannot contain whitespace
Namespace validation:
- Optional for most types, required for some (e.g., maven)
- Type-specific rules apply
- Cannot contain whitespace (some types)
- Example errors:
maven requires a 'namespace' componentnpm 'namespace' component cannot contain whitespace
Version validation:
- Optional for most types
- Type-specific format requirements (e.g., semver for npm)
- Example errors:
npm 'version' component must be valid semver'version' component cannot be empty
Qualifiers validation:
- Keys must be lowercase alphanumeric with
.,-, or_ - Values must not be empty strings
- Example errors:
qualifier 'Arch' must be lowercasequalifier 'os' must not be empty
Subpath validation:
- Must not start with
/ - Cannot contain
..segments - Example errors:
'subpath' component cannot start with '/''subpath' component cannot contain '..' segments
Invalid PURL string:
// Missing 'pkg:' scheme
PackageURL.fromString('npm/lodash')
// -> PurlError: missing required "pkg" scheme component
// Missing type
PackageURL.fromString('pkg:/lodash')
// -> PurlError: 'type' is a required component
// Missing name
PackageURL.fromString('pkg:npm/')
// -> PurlError: 'name' is a required componentType-specific violations:
// npm requires valid semver
new PackageURL('npm', undefined, 'lodash', 'latest')
// -> PurlError: npm 'version' component must be valid semver
// maven requires namespace
new PackageURL('maven', undefined, 'commons-lang3', '3.12.0')
// -> PurlError: maven requires a 'namespace' componentInvalid qualifiers:
const purl = PurlBuilder.npm()
.name('lodash')
.qualifier('Arch', 'x64') // Uppercase not allowed
.build()
// -> PurlError: qualifier 'Arch' must be lowercaseFunctional error handling with Result<T, E> type:
import { ok, err, ResultUtils } from '@socketregistry/packageurl-js'
const result = ok('success')
result.isOk() // -> true
result.unwrap() // -> 'success'
const failure = err(new Error('failed'))
failure.isErr() // -> true
failure.unwrap() // throws ErrorSee types.md for complete type definitions.