@hyperfrontend/versioning/registryregistry/
Package registry abstractions for querying npm and other package registries.
Overview
Unified interface for querying package registries with in-memory caching. Validates all user inputs before shell execution to prevent injection attacks.
Usage Examples
Querying npm Registry
import { createNpmRegistry } from '@hyperfrontend/versioning'
const registry = createNpmRegistry()
// Get latest version
const latest = await registry.getLatestVersion('@hyperfrontend/utils')
console.log(latest) // '1.2.3'
// Check if version is published
const exists = await registry.isVersionPublished('lodash', '4.17.21')
console.log(exists) // true
// Get full package info
const info = await registry.getPackageInfo('typescript')
console.log(info?.versions) // ['4.0.0', '4.1.0', ...]
console.log(info?.latestVersion) // '5.4.0'
Using the Factory
import { createRegistry } from '@hyperfrontend/versioning'
// Create registry by type
const registry = createRegistry('npm', {
timeout: 5000,
cacheTtl: 30000,
})
const versions = await registry.listVersions('react')
Custom Cache Configuration
import { createNpmRegistry } from '@hyperfrontend/versioning'
// 5 minute cache, 30 second timeout
const registry = createNpmRegistry({
cacheTtl: 300000,
timeout: 30000,
})
Version-Specific Information
import { createNpmRegistry } from '@hyperfrontend/versioning'
const registry = createNpmRegistry()
const versionInfo = await registry.getVersionInfo('lodash', '4.17.21')
console.log(versionInfo?.publishedAt) // '2021-02-20T15:42:16.891Z'
console.log(versionInfo?.dependencies) // { ... }
console.log(versionInfo?.engines) // { node: '>=0.10.0' }
Security
Input Validation
All package names and versions are validated character-by-character before being used in shell commands:
- Package names: Only
a-z,A-Z,0-9,@,/,-,_,.allowed - Versions: Only
0-9,a-z,A-Z,.,-,+allowed - Length limits: Package names max 214 chars, versions max 256 chars
Invalid characters throw descriptive errors:
import { escapePackageName } from '@hyperfrontend/versioning'
escapePackageName('lodash') // 'lodash'
escapePackageName('@scope/pkg') // '@scope/pkg'
escapePackageName('pkg; rm -rf /') // throws Error
Caching
Responses are cached in memory to reduce registry load:
- Default TTL: 60 seconds
- Expired entries are cleaned up on access
- Cache can be configured per-client
See Also
- semver/: Version parsing for registry queries
- flow/: Fetches registry versions in workflows
- workspace/: Package discovery and metadata
- Main README: Package overview and quick start
- ARCHITECTURE.md: Design principles and data flow
API Reference§
ƒ Functions
Decides whether a failed
Only a 404 from the registry proves absence, and npm reports both a missing package and a missing version that way. Every other outcome, including a timeout that produces no output at all, leaves the published state unknown and must not be read as "not published".
npm view proves absence or leaves the answer unknown. Only a 404 from the registry proves absence, and npm reports both a missing package and a missing version that way. Every other outcome, including a timeout that produces no output at all, leaves the published state unknown and must not be read as "not published".
Parameters
| Name | Type | Description |
|---|---|---|
§error | unknown | The error thrown by the invocation |
Returns
NpmLookupFailureWhether the package is absent, or why the registry could not answer
Example
Classifying a lookup failure
try {
execFileSync('npm', ['view', name, 'version'])
} catch (error) {
const failure = classifyNpmError(error)
if (failure.kind === 'absent') return null
throw createRegistryUnavailableError({ ...failure, packageName: name })
}Creates a new cache instance.
Parameters
| Name | Type | Description |
|---|---|---|
§ttl | number | Time-to-live in milliseconds (default: 60000 = 1 minute)(default: 60000) |
Returns
CacheA new Cache instance
Example
Using a cache with custom TTL
const cache = createCache(30000) // 30 second TTL
cache.set('key', { data: 'value' })
const value = cache.get<{ data: string }>('key')Creates an npm registry client.
Parameters
| Name | Type | Description |
|---|---|---|
§config | RegistryConfig | Registry configuration(default: {}) |
Returns
RegistryA Registry implementation for npm
Example
Creating an npm registry client
const registry = createNpmRegistry()
const version = await registry.getLatestVersion('@hyperfrontend/utils')Creates a new PackageInfo object.
Parameters
| Name | Type | Description |
|---|---|---|
§options | CreatePackageInfoOptions | Configuration for the package info |
Returns
PackageInfoA new PackageInfo object
Example
Creating package info from registry data
const info = createPackageInfo({
name: '@scope/my-package',
latestVersion: '2.0.0',
versions: ['1.0.0', '1.1.0', '2.0.0'],
license: 'MIT'
})Creates a registry client.
Parameters
| Name | Type | Description |
|---|---|---|
§type | "npm" | Type of registry to create(default: 'npm') |
§config | RegistryConfig | Registry configuration(default: {}) |
Returns
RegistryA Registry instance
Example
Creating an npm registry client
const registry = createRegistry('npm')
const version = await registry.getLatestVersion('lodash')Creates a new VersionInfo object.
Parameters
| Name | Type | Description |
|---|---|---|
§options | CreateVersionInfoOptions | Configuration for the release info |
Returns
VersionInfoA new VersionInfo object
Example
Creating version info from registry data
const release = createVersionInfo({
version: '1.2.3',
publishedAt: '2024-01-15T10:30:00Z',
tarball: 'https://registry.npmjs.org/pkg/-/pkg-1.2.3.tgz'
})Escapes a package name for safe use in shell commands. Uses character-by-character validation to prevent injection.
Parameters
| Name | Type | Description |
|---|---|---|
§name | string | Package name to escape |
Returns
stringSafe package name
Example
Validating package names for shell safety
escapePackageName('@scope/package') // => '@scope/package'
escapePackageName('simple-pkg') // => 'simple-pkg'
escapePackageName('pkg$invalid') // throws - '$' is invalidEscapes a version string for safe use in shell commands.
Parameters
| Name | Type | Description |
|---|---|---|
§version | string | Version string to escape |
Returns
stringSafe version string
Example
Validating version strings for shell safety
escapeVersion('1.2.3') // => '1.2.3'
escapeVersion('1.0.0-beta.1') // => '1.0.0-beta.1'
escapeVersion('1.0.0+build') // => '1.0.0+build'◈ Interfaces
The registry answered and the package or version is not there.
Properties
Cache entry with data and expiration time.
Maintainer information.
Package information from a registry.
Properties
Abstract interface for package registries.
Registry configuration options.
Properties
Version-specific information from a registry.
Properties
§
NOTE: This value comes from npm registry, making it immutable and independent of local git state.
readonly gitHead?:stringGit commit hash at publish time. Used to determine commit range for changelog generation. NOTE: This value comes from npm registry, making it immutable and independent of local git state.
◆ Types
Outcome of a failed
npm view invocation.type NpmLookupFailure = AbsentLookupFailure | UnavailableLookupFailureWhy a registry could not answer a lookup.
Every value here means the answer is unknown, never that the package or version is absent. An absent package is a successful lookup with a negative answer, and is reported through the normal return value instead.
Every value here means the answer is unknown, never that the package or version is absent. An absent package is a successful lookup with a negative answer, and is reported through the normal return value instead.
type RegistryFailureReason = "network" | "authentication" | "rate-limit" | "server" | "timeout" | "unknown"● Variables
Name carried by every error this module raises, used to identify it across module boundaries.