Struct NpmRegistry
pub struct NpmRegistry { /* private fields */ }Expand description
Client for interacting with the npm registry.
Uses the npm registry API for package metadata and search. All requests are cached via the provided HttpCache.
Implementations§
§impl NpmRegistry
impl NpmRegistry
pub fn new(cache: Arc<HttpCache>) -> NpmRegistry
pub fn new(cache: Arc<HttpCache>) -> NpmRegistry
Creates a new npm registry client with the given HTTP cache.
pub fn with_registry_base(
cache: Arc<HttpCache>,
registry_base: String,
) -> NpmRegistry
pub fn with_registry_base( cache: Arc<HttpCache>, registry_base: String, ) -> NpmRegistry
Creates a new npm registry client pointed at a custom registry base URL, for pointing at a mockito server in tests.
pub but gated behind cfg(test)/the test-util feature (M7/#312) rather than
unconditionally public API: it exists purely so other workspace crates’ own test
builds can construct a mockable NpmRegistry (cfg(test) alone would not apply
there, since deps-npm is a normal, non-dev dependency for e.g. deps-deno) —
enabled via deps-npm = { workspace = true, features = ["test-util"] } under
[dev-dependencies], mirroring deps-core’s own test-util feature. Never
reachable from a non-test build of a downstream crate.
Always Public-tier: this is the pre-existing entry point every non-alternate-registry
test in the workspace already uses (fetches through the ungated transport). A test
exercising the .npmrc-alternate-registry path constructs its mock client via
Self::with_base instead, so it goes through the workspace-gated transport (FR-008)
and exercises the same production routing.
pub fn with_base(cache: Arc<HttpCache>, index: &NpmRegistryIndex) -> NpmRegistry
pub fn with_base(cache: Arc<HttpCache>, index: &NpmRegistryIndex) -> NpmRegistry
Creates an NpmRegistry client for a resolved .npmrc alternate registry — an
ordinary production constructor (unlike Self::with_registry_base, not gated).
No AlternateNpmClient type exists: an alternate client is an NpmRegistry with
a different base and tier: WorkspaceDeclared, so it fetches through
HttpCache::get_cached_workspace_with_headers (FR-008’s redirect-hop gating) instead
of the ungated transport. Its own alternates map is always empty — only the root
(Public-tier) registry this was registered on ever registers further alternates.
pub fn register_alternate(&self, index: NpmRegistryIndex)
pub fn register_alternate(&self, index: NpmRegistryIndex)
Registers (or reuses an existing registration for) index as an alternate registry
client, callable via Self::alternate_client.
A no-op when index is already registered — the first successful registration for a
given index URL sticks for the process lifetime. Also a no-op, with a
tracing::warn!, once MAX_ALTERNATE_REGISTRIES is reached and index is not
already present: the dependency stays unregistered (fails closed to
DepsError::PackageNotFound at fetch time, spec FR-010) rather than evicting an
existing, possibly still-in-use, client.
Called only from NpmEcosystem::parse_manifest over NpmParseResult::resolved_registries
— the one place a per-document .npmrc resolution and this long-lived shared router
meet. Registration is parse-time-only; there is no lazy creation on the fetch path
(spec FR-010 dispatch table).
pub fn alternate_client(&self, index: &str) -> Option<Arc<NpmRegistry>>
pub fn alternate_client(&self, index: &str) -> Option<Arc<NpmRegistry>>
The registered client for index, if any — read-only, performs no registration, no
validation. index only ever originates from an already-validated
[NpmRegistryIndex::as_str], on both sides (registration above, and a dependency’s
own resolved DependencySource::AlternateRegistry index string), so lookup stays
a plain map read.
pub async fn get_versions(
&self,
name: &str,
) -> Result<Vec<NpmVersion>, DepsError>
pub async fn get_versions( &self, name: &str, ) -> Result<Vec<NpmVersion>, DepsError>
Fetches all versions for a package from the npm registry.
Requests the abbreviated packument (Accept: application/vnd.npm.install-v1+json), which omits README, changelog,
and other fields get_versions doesn’t need while keeping per-version
deprecated status.
Returns versions sorted newest-first. Includes deprecated versions.
§Errors
Returns an error if:
- HTTP request fails
- Response body is invalid UTF-8
- JSON parsing fails
- Package does not exist
name’s scope or package segment is exactly.or..(#341) — rejected asDepsError::PackageNotFoundrather than encoded, since percent-encoding alone does not stop the URL parser’s dot-segment normalization from retargeting the request
§Examples
let cache = Arc::new(HttpCache::new());
let registry = NpmRegistry::new(cache);
let versions = registry.get_versions("express").await.unwrap();
assert!(!versions.is_empty());pub async fn get_latest_matching(
&self,
name: &str,
req_str: &str,
) -> Result<Option<NpmVersion>, DepsError>
pub async fn get_latest_matching( &self, name: &str, req_str: &str, ) -> Result<Option<NpmVersion>, DepsError>
Finds the latest version matching the given npm semver requirement.
Only returns non-deprecated, non-prerelease versions unless explicitly requested in
the version requirement (e.g. ^1.0.0-beta.1 legitimately matches and returns
1.0.0-beta.2), with one exception: under a wildcard/empty requirement
("*"/""), which answers “does this package exist / what is its newest version”
for existence checks rather than “what should I recommend installing”. That call
prefers the newest non-deprecated, non-prerelease version; if none exists it falls
straight through to the newest version overall — deprecated, a prerelease, or both
(#338 NFR-001) — rather than reporting “no version found” for a package that
genuinely exists. Mirrors
Registry::select_latest_matching’s
wildcard branch exactly, so the two never disagree on the same input; hover
(generate_hover) resolves “latest” through that same method rather than
re-deriving it, so hover, diagnostics, and this fallback can never disagree either
(#347/#348 S1).
§Errors
Returns an error if:
- HTTP request fails
- Package does not exist
§Examples
let cache = Arc::new(HttpCache::new());
let registry = NpmRegistry::new(cache);
let latest = registry.get_latest_matching("express", "^4.0.0").await.unwrap();
assert!(latest.is_some());pub async fn search(
&self,
query: &str,
limit: usize,
) -> Result<Vec<NpmPackage>, DepsError>
pub async fn search( &self, query: &str, limit: usize, ) -> Result<Vec<NpmPackage>, DepsError>
Searches for packages by name/keywords.
Returns up to limit results sorted by relevance.
§Errors
Returns an error if:
- HTTP request fails
- JSON parsing fails
§Examples
let cache = Arc::new(HttpCache::new());
let registry = NpmRegistry::new(cache);
let results = registry.search("express", 10).await.unwrap();
assert!(!results.is_empty());Trait Implementations§
§impl Clone for NpmRegistry
impl Clone for NpmRegistry
§fn clone(&self) -> NpmRegistry
fn clone(&self) -> NpmRegistry
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more§impl Registry for NpmRegistry
impl Registry for NpmRegistry
§fn get_versions_from<'a>(
&'a self,
name: &'a PackageName,
source: &'a DependencySource,
freshness: FreshnessSettings,
) -> Pin<Box<dyn Future<Output = Result<Vec<Box<dyn Version>>, DepsError>> + Send + 'a>>
fn get_versions_from<'a>( &'a self, name: &'a PackageName, source: &'a DependencySource, freshness: FreshnessSettings, ) -> Pin<Box<dyn Future<Output = Result<Vec<Box<dyn Version>>, DepsError>> + Send + 'a>>
Dispatches by source (spec FR-010): an AlternateRegistry whose index has a
registered client routes there; one with no registered client is
PackageNotFound, never a fall back to registry.npmjs.org (npm always sets
mirrors_crates_io: false, so Cargo’s mirror-degradation arm is dead here and must
not be written — falling back would send a private package name to the public
registry, the exact #248-class leak the rest of this spec closes). Every other source
keeps today’s public-registry path unchanged.
§fn get_latest_matching_from<'a>(
&'a self,
name: &'a PackageName,
source: &'a DependencySource,
req: &'a VersionReq,
_minimum_stability: Option<&'a str>,
) -> Pin<Box<dyn Future<Output = Result<Option<Box<dyn Version>>, DepsError>> + Send + 'a>>
fn get_latest_matching_from<'a>( &'a self, name: &'a PackageName, source: &'a DependencySource, req: &'a VersionReq, _minimum_stability: Option<&'a str>, ) -> Pin<Box<dyn Future<Output = Result<Option<Box<dyn Version>>, DepsError>> + Send + 'a>>
get_versions_from’s get_latest_matching-shaped counterpart — same three-arm
dispatch, same N-S1 “must never fall back to the public registry” invariant for an
unregistered AlternateRegistry index.
§fn get_versions<'a>(
&'a self,
name: &'a PackageName,
) -> Pin<Box<dyn Future<Output = Result<Vec<Box<dyn Version>>, DepsError>> + Send + 'a>>
fn get_versions<'a>( &'a self, name: &'a PackageName, ) -> Pin<Box<dyn Future<Output = Result<Vec<Box<dyn Version>>, DepsError>> + Send + 'a>>
§fn get_versions_with<'a>(
&'a self,
name: &'a PackageName,
freshness: FreshnessSettings,
) -> Pin<Box<dyn Future<Output = Result<Vec<Box<dyn Version>>, DepsError>> + Send + 'a>>
fn get_versions_with<'a>( &'a self, name: &'a PackageName, freshness: FreshnessSettings, ) -> Pin<Box<dyn Future<Output = Result<Vec<Box<dyn Version>>, DepsError>> + Send + 'a>>
get_versions, but lets a registry that can obtain
Version::published_at only through an extra request gate that request behind
freshness.enabled instead of always paying for it. Read more§fn get_latest_matching<'a>(
&'a self,
name: &'a PackageName,
req: &'a VersionReq,
) -> Pin<Box<dyn Future<Output = Result<Option<Box<dyn Version>>, DepsError>> + Send + 'a>>
fn get_latest_matching<'a>( &'a self, name: &'a PackageName, req: &'a VersionReq, ) -> Pin<Box<dyn Future<Output = Result<Option<Box<dyn Version>>, DepsError>> + Send + 'a>>
§fn search<'a>(
&'a self,
query: &'a str,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<Box<dyn Metadata>>, DepsError>> + Send + 'a>>
fn search<'a>( &'a self, query: &'a str, limit: usize, ) -> Pin<Box<dyn Future<Output = Result<Vec<Box<dyn Metadata>>, DepsError>> + Send + 'a>>
§fn select_latest_matching(
&self,
versions: &[Box<dyn Version>],
req: &VersionReq,
) -> Option<usize>
fn select_latest_matching( &self, versions: &[Box<dyn Version>], req: &VersionReq, ) -> Option<usize>
§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Source§fn get_latest_matching_with_context<'a>(
&'a self,
name: &'a PackageName,
req: &'a VersionReq,
minimum_stability: Option<&'a str>,
) -> Pin<Box<dyn Future<Output = Result<Option<Box<dyn Version>>, DepsError>> + Send + 'a>>
fn get_latest_matching_with_context<'a>( &'a self, name: &'a PackageName, req: &'a VersionReq, minimum_stability: Option<&'a str>, ) -> Pin<Box<dyn Future<Output = Result<Option<Box<dyn Version>>, DepsError>> + Send + 'a>>
get_latest_matching, but lets a registry whose
“latest matching” selection can be refined by ecosystem-specific manifest state (e.g.
Composer’s minimum-stability field, #424) read it, alongside req. Read moreSource§fn select_latest_matching_with_context(
&self,
versions: &[Box<dyn Version>],
req: &VersionReq,
minimum_stability: Option<&str>,
) -> Option<usize>
fn select_latest_matching_with_context( &self, versions: &[Box<dyn Version>], req: &VersionReq, minimum_stability: Option<&str>, ) -> Option<usize>
select_latest_matching, but lets a registry
whose selection can be refined by ecosystem-specific manifest state (e.g. Composer’s
minimum-stability field, #424) read it, alongside versions and req. See
get_latest_matching_with_context for why
minimum_stability is an opaque per-ecosystem string rather than a shared type. Read moreSource§fn reports_yanked(&self) -> bool
fn reports_yanked(&self) -> bool
get_versions results carry meaningful
per-version yank/deprecation data via Version::removal_status. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for NpmRegistry
impl !UnwindSafe for NpmRegistry
impl Freeze for NpmRegistry
impl Send for NpmRegistry
impl Sync for NpmRegistry
impl Unpin for NpmRegistry
impl UnsafeUnpin for NpmRegistry
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more