@socketregistry/packageurl-js


TypeScript Package URL (purl) parser and builder.
Drop-in replacement for packageurl-js with full type safety, zero dependencies, and spec compliance with the Package URL specification.
@socketregistry/packageurl-js is the Socket-maintained drop-in replacement for packageurl-js - same API, but ships with built-in TypeScript types, zero runtime dependencies, full purl-spec coverage, and first-class VERS support. It exists because the upstream package lacked types and a maintained tree-shakeable surface; this fork closes both gaps without breaking compatibility.
What is a PURL?
A Package URL (purl) standardizes how to identify software packages:
pkg:npm/lodash@4.17.21
pkg:pypi/requests@2.28.1
pkg:maven/org.springframework/spring-core@5.3.21
Format breakdown:
pkg:type/namespace/name@version?qualifiers#subpath
│ │ │ │ │ │ │
│ │ │ │ │ │ └─ Optional subpath
│ │ │ │ │ └──────────── Optional key=value pairs
│ │ │ │ └──────────────────── Optional version
│ │ │ └───────────────────────── Required package name
│ │ └─────────────────────────────────── Optional namespace/scope
│ └──────────────────────────────────────── Required package type
└──────────────────────────────────────────── Scheme (always "pkg:")
Supports 40+ ecosystems: npm, pypi, maven, gem, cargo, nuget, composer, golang, docker, and more.
Features
- ✅ Modular & tree-shakeable - Import only what you need
- ✅ Full TypeScript support - Comprehensive type exports
- ✅ Zero dependencies - Lightweight and secure
- ✅ Spec compliant - Follows purl-spec v1.0.0, published as ECMA-427
- ✅ 100% test coverage - Over 1,000 passing tests
- ✅ Multiple APIs - Functional, class-based, and builder patterns
- ✅ URL conversion - Convert to repository and download URLs
- ✅ Registry checks - Verify package existence across 17 registries
- ✅ VERS support - First-class implementation of the VERS companion spec (
Vers, VersConstraint, VersWildcard)
- ✅ Immutable updates -
withVersion, withNamespace, withQualifier, withQualifiers, withSubpath
- ✅ Result-based parsing -
tryFromString, tryFromJSON, tryFromObject, isValid, fromUrl
Install
pnpm install @socketregistry/packageurl-js
Drop-in replacement via package override:
{
"pnpm": {
"overrides": {
"packageurl-js": "npm:@socketregistry/packageurl-js@^1"
}
}
}
Requirements: Node >= 18.20.8
Usage
Modular Functions (Tree-shakeable)
Parse npm specifiers:
import { parseNpmSpecifier } from '@socketregistry/packageurl-js'
parseNpmSpecifier('lodash@4.17.21')
parseNpmSpecifier('@babel/core@^7.0.0')
Stringify and compare - stringify, equals, compare
import { compare, equals, stringify } from '@socketregistry/packageurl-js'
stringify(purl)
equals(purl1, purl2)
compare(purl1, purl2)
compare returns a sort-friendly ordering, so an array of PURLs sorts with
purls.sort(compare).
Class API
Parse and build:
import { PackageURL } from '@socketregistry/packageurl-js'
const purl = PackageURL.fromString('pkg:npm/lodash@4.17.21')
console.log(purl.name)
console.log(purl.version)
PackageURL.fromNpm('lodash@4.17.21')
PackageURL.fromNpm('@babel/core@^7.0.0')
new PackageURL('npm', null, 'express', '4.18.2')
Builder pattern - PurlBuilder, for assembling a PURL piece by piece
import { PurlBuilder } from '@socketregistry/packageurl-js'
PurlBuilder.npm().name('lodash').version('4.17.21').build()
URL conversion - PURL to repository/download URL, and back from a URL or bare filename
import { UrlConverter } from '@socketregistry/packageurl-js'
UrlConverter.toRepositoryUrl(purl)
UrlConverter.toDownloadUrl(purl)
UrlConverter.fromUrl('https://www.npmjs.com/package/lodash')
UrlConverter.fromUrl(
'/packages/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.whl',
)
fromUrl tries hostname-based parsers first, then falls back to
distribution-filename parsing. The individual parsers are also exposed when you
know the shape:
UrlConverter.fromNpmUrl(url)
UrlConverter.fromPypiUrl(url)
UrlConverter.fromGemUrl(url)
UrlConverter.fromGolangUrl(url)
UrlConverter.fromCargoUrl(url)
UrlConverter.fromDownloadUrl(
'/packages/numpy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl',
)
Registry existence checks - does this package actually exist, across 17 registries
Network calls, so they live in a separate /exists entry point and stay out of
the main bundle.
import { purlExists, npmExists } from '@socketregistry/packageurl-js/exists'
await purlExists(purl)
await npmExists('lodash')
await npmExists('core', { namespace: '@babel' })
await npmExists('lodash', { version: '4.17.21' })
VERS (Version Range Specifier)
First-class implementation of the VERS companion spec:
import { Vers } from '@socketregistry/packageurl-js'
const range = Vers.parse('vers:npm/>=1.0.0|<2.0.0')
range.contains('1.5.0')
range.contains('2.0.0')
Immutable updates
PackageURL instances are immutable; with* methods return a new instance:
const next = purl
.withVersion('5.0.0')
.withQualifier('repository_url', 'https://github.com/lodash/lodash')
Result-based parsing
Parse untrusted input without try/catch:
import { PackageURL } from '@socketregistry/packageurl-js'
const result = PackageURL.tryFromString(userInput)
if (result.isOk()) {
use(result.value)
} else {
log(result.error)
}
PackageURL.isValid(userInput)
PackageURL.fromUrl('https://github.com/lodash/lodash')
PackageURL.fromUrl(
'/packages/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.whl',
)
TypeScript Types
Every type is exported, so nothing needs to be re-declared to annotate a value
this library hands back.
Type imports - PackageURLObject, NpmPackageComponents, and the rest
import type {
ComponentEncoder,
DownloadUrl,
NpmPackageComponents,
PackageURLObject,
ParsedPurlComponents,
QualifiersObject,
RepositoryUrl,
} from '@socketregistry/packageurl-js'
const components: NpmPackageComponents = parseNpmSpecifier('lodash@4.17.21')
const obj: PackageURLObject = purl.toObject()
Constants - PurlQualifierNames and PURL_Type, instead of bare strings
import { PURL_Type, PurlQualifierNames } from '@socketregistry/packageurl-js'
PurlQualifierNames.Checksum
PurlQualifierNames.RepositoryUrl
PURL_Type.NPM
PURL_Type.PYPI
See docs/types.md for the complete type reference.
API Reference
Development
Contributor commands
pnpm install
pnpm build
pnpm test
pnpm check
License
MIT