npm_utils/lib.rs
1//! Pure-Rust utilities for the npm registry and web assets.
2//!
3//! Building blocks for fetching browser/JS dependencies at build time without
4//! Node or npm:
5//!
6//! - [`registry`] — talk to an npm registry: build tarball URLs, fetch a
7//! package's metadata, resolve the newest version matching a semver range, and
8//! search the registry ([`Registry::search`](registry::Registry::search)).
9//! - [`download`] — fetch bytes over HTTP (with a retry) and build GitHub
10//! archive URLs.
11//! - [`extract`] — unpack `.tar.gz` and `.zip` archives into a destination
12//! directory, selecting all files, an explicit file map, or a predicate, with
13//! path-traversal protection.
14//! - [`path_safety`] — the path-traversal hardening shared by `extract` and
15//! `install`: reject `..`/absolute paths and refuse symlink-redirected writes.
16//! - [`cache`] — content-hash markers, a cross-process build lock, and directory
17//! helpers for skip-if-unchanged download caches.
18//! - [`package_json`] — read pinned dependency versions from a `package.json`, and
19//! resolve its `exports`/`module`/`browser`/`main` to browser entry points (for
20//! generating an ES-module import map).
21//! - [`resolve`] — locate files inside an installed dependency under `node_modules/`:
22//! walk up to `node_modules/<name>` and map a `<name>/<subpath>` to a real file,
23//! honoring the package's `exports` when declared.
24//! - [`install`] — produce a real `node_modules/` directory, pure Rust, with every tarball
25//! sha512-verified: resolve a `package.json`'s transitive `dependencies` against the registry
26//! ([`install::node_modules`]), or install the exact tree a `package-lock.json` pins —
27//! devDependencies included, `.bin` shims and all — an `npm ci` in Rust
28//! ([`install::from_lockfile`]).
29//! - [`project`] — mutate a `package.json` project: keep the lock + `node_modules/` in sync
30//! ([`project::sync`]), upgrade dependencies within their ranges with a dry-run plan
31//! ([`project::plan_upgrade`] / [`project::upgrade`]), and remove them ([`project::remove`]).
32//! - [`integrity`] — verify a downloaded tarball's `sha512` Subresource-Integrity (both
33//! install paths check it before trusting bytes).
34//! - [`sbom`] — render the packages a `package-lock.json` pins as a license summary, a CycloneDX
35//! 1.6 document, or an SPDX 2.3 document — compliance artifacts, pure Rust, no Node.
36//! - [`audit`] — check those same pinned packages against vulnerability advisories from multiple
37//! sources (npm's registry endpoint, OSV) behind a small source trait — `npm audit`, pure Rust.
38//!
39//! ```no_run
40//! use npm_utils::{download, extract, registry::Registry};
41//!
42//! # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
43//! let reg = Registry::npm();
44//! let lit = reg.resolve("lit", &"^3".parse()?)?;
45//! let tgz = download::fetch(&lit.tarball_url)?;
46//! extract::tar_gz(&tgz, "dist/lit".as_ref(), Some("package/"), extract::Select::All)?;
47//! # Ok(()) }
48//! ```
49
50#![forbid(unsafe_code)]
51
52/// The crate's boxed, thread-safe error type. A single alias so the whole crate shares one error
53/// spelling, errors cross thread boundaries, and a future switch to a structured enum is one edit.
54pub type Error = Box<dyn std::error::Error + Send + Sync>;
55/// The crate's result type, defaulting the error to [`Error`].
56pub type Result<T, E = Error> = std::result::Result<T, E>;
57
58// Vulnerability auditing (`npm audit`, pure Rust): check the packages a `package-lock.json` pins
59// against multiple advisory sources (npm's registry endpoint, OSV) behind a small source trait.
60pub mod audit;
61pub mod cache;
62// The command-line tool (`npm-utils` / `cargo npm-utils`), behind the `cli` feature so a default
63// library build pulls no `clap`. Drives the primitives below — `registry`, `install`, `project`, and
64// the `package_json` manifest/lock writers — for `install`/`ci`/`add`/`remove`/`init`/`upgrade`.
65#[cfg(feature = "cli")]
66pub mod cli;
67pub mod download;
68pub mod extract;
69pub mod install;
70pub mod integrity;
71// The npm `package.json` / `package-lock.json` schemas — a pure-parsing module (no IO),
72// modeled on the npm specs, with strict spec-conformance tests living beside it.
73pub mod package_json;
74pub mod path_safety;
75// Project mutations (`sync` / `upgrade` / `remove`) that keep package.json + lock + node_modules in
76// step — the IO orchestration over the pure `package_json` transforms and `registry`/`install`.
77pub mod project;
78pub mod registry;
79// Locate files inside an installed `node_modules/<name>`: walk up to the package and map a
80// `<name>/<subpath>` to a real file on disk, honoring `exports`. The IO counterpart to the pure
81// `package_json` resolver, and the foundation web_modules builds `npm://` asset references on.
82pub mod resolve;
83// License/SBOM output (license summary · CycloneDX · SPDX) for a parsed `package-lock.json`.
84pub mod sbom;
85// Crate-internal `npm-utils:` warning routing — the CLI installs a sink so library warnings print
86// above a live progress region instead of corrupting it.
87mod warn;