
Security News
GitHub Actions Adds cache-mode to Limit Cache Poisoning Risk
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.
@socketregistry/packageurl-js
Advanced tools
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.
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.
Vers, VersConstraint, VersWildcard)withVersion, withNamespace, withQualifier, withQualifiers, withSubpathtryFromString, tryFromJSON, tryFromObject, isValid, fromUrlpnpm install @socketregistry/packageurl-js
Drop-in replacement via package override:
{
"pnpm": {
"overrides": {
"packageurl-js": "npm:@socketregistry/packageurl-js@^1"
}
}
}
Requirements: Node >= 18.20.8
Parse npm specifiers:
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' }
stringify, equals, compareimport { compare, equals, stringify } from '@socketregistry/packageurl-js'
stringify(purl)
// -> 'pkg:npm/lodash@4.17.21'
equals(purl1, purl2) // -> boolean
compare(purl1, purl2) // -> -1 | 0 | 1
compare returns a sort-friendly ordering, so an array of PURLs sorts with
purls.sort(compare).
Parse and build:
import { PackageURL } from '@socketregistry/packageurl-js'
// Parse strings
const purl = PackageURL.fromString('pkg:npm/lodash@4.17.21')
console.log(purl.name) // 'lodash'
console.log(purl.version) // '4.17.21'
// Parse npm specifiers
PackageURL.fromNpm('lodash@4.17.21')
PackageURL.fromNpm('@babel/core@^7.0.0')
// Constructor
new PackageURL('npm', null, 'express', '4.18.2')
// -> 'pkg:npm/express@4.18.2'
PurlBuilder, for assembling a PURL piece by pieceimport { PurlBuilder } from '@socketregistry/packageurl-js'
PurlBuilder.npm().name('lodash').version('4.17.21').build()
// -> 'pkg:npm/lodash@4.17.21'
import { UrlConverter } from '@socketregistry/packageurl-js'
// PackageURL -> URL
UrlConverter.toRepositoryUrl(purl)
// -> 'https://github.com/lodash/lodash'
UrlConverter.toDownloadUrl(purl)
// -> 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz'
// URL -> PackageURL
UrlConverter.fromUrl('https://www.npmjs.com/package/lodash')
// -> PackageURL for pkg:npm/lodash
// fromUrl also recognizes distribution (download) URLs and bare paths
UrlConverter.fromUrl(
'/packages/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.whl',
)
// -> PackageURL for pkg:pypi/orjson@3.11.9
fromUrl tries hostname-based parsers first, then falls back to
distribution-filename parsing. The individual parsers are also exposed when you
know the shape:
// Per-ecosystem aggregators (try the ecosystem's known URL shapes)
UrlConverter.fromNpmUrl(url) // registry metadata/tarball or npmjs.com page
UrlConverter.fromPypiUrl(url) // project page or wheel/sdist filename
UrlConverter.fromGemUrl(url) // gem page or .gem / .gemspec.rz
UrlConverter.fromGolangUrl(url) // pkg.go.dev page or module-proxy archive
UrlConverter.fromCargoUrl(url) // crate page or download path
// Distribution (download) URLs/paths, host-independent
UrlConverter.fromDownloadUrl(
'/packages/numpy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl',
)
// -> PackageURL for pkg:pypi/numpy@2.3.0
// Single-shape host parsers: fromGitHubUrl, fromGitlabUrl, fromBitbucketUrl,
// fromComposerUrl, fromHexUrl, fromPubUrl, fromDockerUrl, fromCocoapodsUrl,
// fromHackageUrl, fromCranUrl, fromCondaUrl, fromCpanUrl, fromHuggingfaceUrl,
// fromLuarocksUrl, fromSwiftUrl, fromVscodeMarketplaceUrl, fromOpenVsxUrl
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'
// Check if package exists in its registry
await purlExists(purl)
// -> { exists: true, latestVersion: '4.17.21' }
// Type-specific checks (modular)
await npmExists('lodash')
await npmExists('core', { namespace: '@babel' }) // scoped package
await npmExists('lodash', { version: '4.17.21' }) // validate version
// Supported registries:
// npmExists, pypiExists, cargoExists, gemExists,
// mavenExists, nugetExists, golangExists, packagistExists,
// cocoapodsExists, pubExists, hexExists, cpanExists,
// cranExists, hackageExists, condaExists, dockerExists,
// vscodeExtensionExists
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') // -> true
range.contains('2.0.0') // -> false
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')
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) // -> boolean
PackageURL.fromUrl('https://github.com/lodash/lodash') // infers purl from URL
// fromUrl also recognizes distribution (download) URLs and bare paths:
// wheels, sdists, tarballs, gems, and module-proxy archives.
PackageURL.fromUrl(
'/packages/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.whl',
) // -> pkg:pypi/orjson@3.11.9
Every type is exported, so nothing needs to be re-declared to annotate a value this library hands back.
PackageURLObject, NpmPackageComponents, and the restimport type {
ComponentEncoder,
DownloadUrl,
NpmPackageComponents,
PackageURLObject,
ParsedPurlComponents,
QualifiersObject,
RepositoryUrl,
} from '@socketregistry/packageurl-js'
// Type-safe npm package parsing
const components: NpmPackageComponents = parseNpmSpecifier('lodash@4.17.21')
// Type-safe PURL objects
const obj: PackageURLObject = purl.toObject()
PurlQualifierNames and PURL_Type, instead of bare stringsimport { PURL_Type, PurlQualifierNames } from '@socketregistry/packageurl-js'
// Standard qualifier keys
PurlQualifierNames.Checksum // 'checksum'
PurlQualifierNames.RepositoryUrl // 'repository_url'
// Package types
PURL_Type.NPM // 'npm'
PURL_Type.PYPI // 'pypi'
See docs/types.md for the complete type reference.
pnpm install # Install dependencies
pnpm build # Build
pnpm test # Test
pnpm check # Lint + typecheck
MIT
FAQs
Socket.dev optimized package override for packageurl-js
The npm package @socketregistry/packageurl-js receives a total of 17,966 weekly downloads. As such, @socketregistry/packageurl-js popularity was classified as popular.
We found that @socketregistry/packageurl-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.

Company News
Allow myself to introduce... myself.

Research
/Security News
A Twitch browser extension on Chrome and Firefox forwards users’ live OAuth session tokens through proxies controlled by a Russian bot service.