Update npm-registry-client to version 7.3.0 🚀#437
Merged
Conversation
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
…ce A) (pnpm#457) ## Summary Slice A of pnpm#437. Adds the lockfile types pnpm v11 writes for runtime dependencies (`node@runtime:`, `deno@runtime:`, `bun@runtime:`); the install pipeline doesn't dispatch them yet (subsequent slices). No new workspace deps. - **`BinaryResolution { url, integrity, bin, archive, prefix? }`** — mirrors upstream's [`BinaryResolution`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L41-L49). `bin` is `BinarySpec::Single(String) | BinarySpec::Map(BTreeMap)` (untagged); `archive` is the lowercase `BinaryArchive::Tarball | BinaryArchive::Zip` discriminator; `prefix` (only set on the `.zip` branch upstream) skips serialization when `None`. - **`PlatformAssetTarget { os, cpu, libc? }`** + **`PlatformAssetResolution { resolution, targets }`** per [`resolver-base`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L60-L69). `libc` is `Option<String>` (not an enum) so an upstream addition beyond the current `musl` value lands without a serde migration. - **`VariationsResolution { variants }`** + the `LockfileResolution`/`TaggedResolution` arms routing both new shapes through the existing `from/into ResolutionSerde` round-trip. - **Lockfile major stays at 9** — confirmed against [`core/constants/src/index.ts`](https://github.com/pnpm/pnpm/blob/94240bc046/core/constants/src/index.ts) (`LOCKFILE_MAJOR_VERSION = '9'`), so the existing `lockfile_version.major == 9` assertion holds for v11 lockfiles carrying runtime entries. **Install-dispatch stubs.** `install_package_by_snapshot.rs` and `create_virtual_store.rs` raise `InstallPackageBySnapshotError::UnsupportedResolution { kind: "binary" | "variations" }` until Slice D wires the fetcher. Adding these arms keeps the workspace compiling without forcing the full install path to land in this slice. The warm-prefetch path returns `Ok(None)` for `Variations`, routing through the cold dispatcher where the unsupported-kind error fires; upstream unwraps `Variations` before this layer ever sees one, so the branch is unreachable on well-formed input.
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
slice B) (pnpm#466) * feat(lockfile): select_platform_variant + PlatformSelector (pnpm#437 slice B) Add the variant-picking logic for `VariationsResolution` ahead of Slice D's install-pipeline dispatch: - `PlatformSelector { os, cpu, libc: Option<String> }` mirrors upstream's [`PlatformSelector`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L78-L83). The `libc` tri-state encodes pnpm's `string | null | undefined` shape: `None` (host doesn't care about libc — macOS/Windows/BSD) and `Some("glibc")` collapse to the same matching arm (variant must have no `libc:` annotation); `Some("musl")` requires an exact `libc: "musl"` annotation so the glibc default doesn't silently win on a musl host. - `select_platform_variant(variants, selector)` ports [`selectPlatformVariant`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L92-L98). Iterates `variants` in declaration order and returns the first variant whose `targets[]` contains an `(os, cpu, libc)` triple matching the selector. Targets-array scan is linear because real archives ship 1–3 target entries per variant; quadratic cost is immaterial. - `libc_matches(variant_libc, requested_libc)` is the asymmetric helper from [`libcMatches`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L100-L107). Crate-private so the matching policy isn't part of the public API. Lives in `pacquet-lockfile` next to the variant types (mirrors upstream's `resolver-base` package boundary). The host-platform side (constructing the `PlatformSelector` from `pacquet-graph-hasher`'s existing `host_platform/arch/libc` helpers) lands at the install dispatcher in Slice D — keeps `pacquet-lockfile` free of the `graph-hasher` dep and lets tests drive the picker with synthetic hosts. Tests: first-match wins, multi-target variant matches any host triple, no-match returns `None`, musl-host rejects glibc-default variant, musl-host matches musl-annotated variant, and a six-row `libc_matches` truth table (None / "glibc" / "musl" / unknown-future-libc on both sides) pinning the asymmetric contract from upstream. Part of pnpm#437. --- Written by an agent (Claude Code, claude-opus-4-7). * docs: refresh stale references + add declaration-order tie-breaker test Two follow-ups from Copilot review on PR pnpm#466: - `resolution.rs:152-154` claimed "the variant picker checks at runtime that the resolved inner is atomic", but `select_platform_variant` does not. Reword to describe the actual contract: pacquet's `PlatformAssetResolution.resolution` is typed as the full `LockfileResolution` for serde uniformity, and the lockfile is trusted to honor upstream's atomic-inner invariant. No infinite-recursion risk because the install dispatcher doesn't call back into `select_platform_variant` for non-`Variations` inputs. - `resolution.rs:169` referenced `pick_variant` in `pacquet-package-manager`, but the picker actually lives in this module as `select_platform_variant`. Updated the pointer. - `pick_returns_first_when_multiple_variants_match` test: two variants both list the same `(darwin, arm64)` target; the test asserts the first one wins, pinning the `Array.prototype.find` semantics. Pnpm-written lockfiles can rely on declaration order (e.g., listing a preferred build before a fallback) — without this test, a future refactor that switched the iteration to a triple-keyed `BTreeMap` would silently break that. No behavior change; doc-comment text + test addition. --- Written by an agent (Claude Code, claude-opus-4-7).
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
…pm#472) Slice C of [pnpm#437](pnpm/pacquet#437) — the zip half of pnpm's binary fetcher. Slices A (lockfile types) and B (variant picker) have landed; this slice adds the per-archive download and CAS-extraction pipeline. The install-dispatch site (slice D) and the `--no-runtime` flag (slice E) will follow. Mirrors upstream's [`downloadAndUnpackZip` / `extractZipToTarget`](https://github.com/pnpm/pnpm/blob/94240bc046/fetching/binary-fetcher/src/index.ts): - `extract_zip_entries` walks every entry. Path validation runs *before* the `is_dir()` early-skip so directory entries like `../evil/` still surface `PATH_TRAVERSAL`. The canonical `cas_paths` / `pkg_files_idx` key is built from `enclosed_name()` rebuilt as `Normal` components joined with `/` — `.` segments collapse, separators are cross-platform consistent, and the ignore filter sees the same string the map is keyed by. - `DownloadZipArchiveToStore` is the public sibling of `DownloadTarballToStore` — same store-index lookup, prefetch cache reuse, store-index writer queue. The retry policy, network-permit shape, and post-download semaphore gating exactly match the tarball path. - `ignore_file_pattern` is `Option<Arc<IgnoreEntryFilter>>` on both `DownloadTarballToStore` and `DownloadZipArchiveToStore`, so the Slice D dispatcher can construct a filter per fetch from runtime config without pinning to `'static`. Cloned per retry attempt; the inner trait object is shared. - `run_with_mem_cache` doc-blocks the "stable filter per URL" invariant: the cache keys solely on `package_url` (matching pnpm's `tarballCache`), and callers keep the (URL, filter) relation functional. Upstream's `archiveFilters` is keyed by `pkg.name`, and tarball URLs encode `(name, version, integrity)`, so this naturally holds. - New `TarballError::ReadZipEntries(std::io::Error)` for zip per-entry I/O failures (`try_reserve` / `read_to_end`); maps to `ERR_PACQUET_ZIP` in the retry classifier, distinct from the tar-specific `ERR_PACQUET_TARBALL_TAR`. Zip `unix_mode()` is masked to `0o777` before write so `CafsFileInfo.mode` stays permission-only (matches `store_dir::add_files_from_dir::file_mode_from`). `TarballError::TarballTooLarge` display generalized from "Tarball at …" to "Archive at …" so the zip pipeline's OOM path doesn't surface a misleading message. - Adds `zip = "5", default-features = false, features = ["deflate"]` to the workspace; reused in `pacquet-tarball`.
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
…pnpm#437 slice D1) (pnpm#492) Replace the cold-path `UnsupportedResolution` arms for `LockfileResolution::{Binary, Variations}` with actual fetcher dispatch. Slice C wired the per-archive download (`DownloadTarballToStore` / `DownloadZipArchiveToStore`); this slice routes lockfile resolutions through them. - `Binary(b)` dispatches on `b.archive` (`Tarball` / `Zip`): - `Tarball` → `DownloadTarballToStore` (same shape as registry / tarball entries minus the `package_unpacked_size` hint). - `Zip` → `DownloadZipArchiveToStore` with `archive_prefix: b.prefix.as_deref()` so the runtime archive's top-level wrapper (e.g. `node-vX.Y.Z-darwin-arm64/`) is stripped before the CAS keys are written. - `Variations(v)` runs `select_platform_variant` against a freshly-built `PlatformSelector` (`pacquet_graph_hasher`'s `host_platform` / `host_arch` / `host_libc`, mapping `"unknown"` → `None` per upstream's `process.platform === 'linux' ? family : null` convention). The picked variant's inner resolution must be `Binary`; any other shape (corrupt lockfile or a future shape pacquet hasn't learned about) raises the typed `VariantHasNonBinaryResolution` error rather than silently routing. - `create_virtual_store::snapshot_cache_key` returns the proper warm-cache key for both new arms: `Binary` uses `store_index_key(integrity, pkg_id)`; `Variations` runs the same selector and keys off the picked variant. A miss on variant selection or a non-`Binary` inner shape returns `Ok(None)` and lets the cold path raise the typed error. - Two new error variants on `InstallPackageBySnapshotError`: - `NoMatchingPlatformVariant { package_key, host_os, host_cpu, host_libc, available_targets }` — fires when no variant matches the host; carries the host triple + the rendered available target list so the user can see at a glance why. - `VariantHasNonBinaryResolution { package_key, inner_kind }` — defensive guard for malformed lockfiles. The Node-runtime `NODE_EXTRAS_IGNORE_PATTERN` filter (strips bundled `npm` / `corepack` from the archive) and bin-link cmd-shims for runtime executables will land in Slice D2; the filter slot stays `None` for now and `BinaryResolution::bin` is read but not yet acted on. Slice E adds `--no-runtime` and Slice F adds the end-to-end install fixtures. Two new unit tests cover the helpers: - `host_platform_selector_omits_libc_on_non_linux_hosts` — pins the `host_libc() == "unknown"` ⇔ `selector.libc.is_none()` relationship without needing platform-gated tests. - `render_variant_targets_formats_each_triple_with_optional_libc` — locks in the `os/cpu[+libc]` rendering used by the `NoMatchingPlatformVariant` error message.
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
…pnpm#437 slice D2) (pnpm#496) Construct the per-archive ignore filter at the install dispatcher. For unscoped `node` the filter matches upstream's [`NODE_EXTRAS_IGNORE_PATTERN`](https://github.com/pnpm/pnpm/blob/94240bc046/engine/runtime/node-resolver/src/index.ts), which strips bundled `npm` / `corepack` from the Node.js runtime archive during the CAS write — pnpm (and pacquet) install pnpm itself as the package manager, so the bundled tooling is dead weight and would shadow the user's pnpm via `node_modules/.bin/`. Wiring matches upstream's [`archiveFilters: { node: NODE_EXTRAS_IGNORE_PATTERN }`](https://github.com/pnpm/pnpm/blob/94240bc046/installing/client/src/index.ts): the per-package-name table is keyed by `pkg.name`, so `@foo/node` and other packages keep `None` and the full archive lands unfiltered. Pacquet uses a hand-coded matcher rather than the upstream regex so `pacquet-tarball` doesn't have to pull in a regex engine. The three branches mirror the regex alternation exactly: 1. `^(?:lib/)?node_modules/(?:npm|corepack)(?:/|$)` 2. `^bin/(?:npm|npx|corepack)$` 3. `^(?:npm|npx|corepack)(?:\.(?:cmd|ps1))?$` A `OnceLock` caches the `Arc<IgnoreEntryFilter>` so per-snapshot clones share one trait object. Unit tests pin every branch of the alternation plus the negative cases (e.g. `lib/node_modules/yarn/...` is *not* matched, `bin/npm.cmd` is *not* matched — the regex's `$` and arm-specific extension rules are deliberately asymmetric). Verified by temporarily collapsing the `bin/` branch to a no-op — the test fails as expected. Bin-link cmd-shims for the runtime executables and `@runtime:` substring handling in skip lists / reporter prefixes are Slice D3. End-to-end runtime install fixtures land in Slice F.
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
…e D3 + E) (pnpm#506) * feat(package-manager): runtime bin-link + --no-runtime (pnpm#437 slice D3 + E) Closes the install-pipeline side of pnpm#437: **Slice D3 — runtime bin-link integration.** Runtime archives (`node@runtime:`, etc.) don't ship a `package.json`, so the existing bin-link step had nothing to consume off the slot. `fetch_binary_resolution_to_cas` now synthesizes one in the same shape upstream's `appendManifest` does: { "name": "<pkg.name>", "version": "<pkg.version>", "bin": <BinarySpec> } The bytes go through `StoreDir::write_cas_file` (same content- addressing as every other CAS-imported file), the resulting cas-path is inserted into the snapshot's `cas_paths` under `package.json`, and the existing `link_bins_of_packages` flow picks it up. `link_bins::build_has_bin_set` now includes `Binary` / `Variations` resolutions unconditionally — pnpm v11 doesn't emit `hasBin: true` on runtime metadata, but the synthesized manifest always carries bins, so the lookup must not be gated on the metadata flag. **Slice E — `--no-runtime` flag.** New `Config::skip_runtimes` (default false) and `InstallArgs::no_runtime` CLI flag. The CLI computes `config.skip_runtimes || --no-runtime` and threads it through `Install` → `InstallFrozenLockfile`. When set, every snapshot whose metadata resolution is `Binary` or `Variations` is added to the install-time skip set (re-using `add_optional_excluded` since the bucket count and `.modules.yaml.skipped` semantics line up with `--no-optional`). **Unit tests.** - `synthesize_runtime_manifest_emits_name_version_and_bin_single` — pins `BinarySpec::Single` → JSON string. - `synthesize_runtime_manifest_emits_name_version_and_bin_map` — pins `BinarySpec::Map` → JSON object with all bin entries. - `synthesize_runtime_manifest_preserves_scoped_name` — `@scope/name` round-trips through the `name` field. - `build_has_bin_set_includes_runtime_resolutions_even_when_has_bin_is_absent` — pins the runtime arm. Verified by removing the arm — test fails as expected. End-to-end install fixtures (slice F's remaining items — recorded-archive frozen-lockfile install, variant-mismatch error, `--no-runtime` integration, integrity-mismatch path) need a small recorded Node archive in the repo (or a mockable `pnpm-resolution-mirror`). Tracking them as a separate follow-up so this PR stays reviewable. * fix(package-manager): narrow --no-runtime to importer-direct deps Address CodeRabbit review on pnpm#506: my initial implementation iterated `packages` (every metadata entry) and added all `Binary` / `Variations` snapshots to the skip set, which widened the behavior beyond pnpm's `skipRuntimes`. Per the cardinal rule (CLAUDE.md: "Port behavior faithfully. ... Do not invent behavior that pnpm does not have."), match upstream exactly. Upstream's filter at [`installing/deps-installer/src/install/index.ts`](https://github.com/pnpm/pnpm/blob/94240bc046/installing/deps-installer/src/install/index.ts#L1374-L1387) iterates `dependenciesByProjectId` (per-importer direct deps) and adds `depPath` to `ctx.skipped` when `depPath.includes('@runtime:')`. Transitive runtime entries — unusual but possible — stay in the install. Pacquet now mirrors that exactly: walk each importer's `dependencies` / `dev_dependencies` / `optional_dependencies`, build the candidate snapshot key from `(alias, version)`, check for the `@runtime:` substring, and only add the metadata-confirmed `Binary` / `Variations` keys to `skipped`. Aliased runtime deps (unusual) fall through the same way upstream does — pnpm's lookup is by depPath, not by alias.
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
…m#512) Pnpm v11 writes runtime depPaths with a scheme prefix in front of the semver — e.g. `node@runtime:22.0.0` in `packages:` / `snapshots:` keys, and `runtime:22.0.0` in importer `dependencies:` values. Pacquet's `PkgVerPeer` parser previously accepted only bare semver and rejected the prefix, so it couldn't load any v11 lockfile containing a runtime dependency. Extend `PkgVerPeer` to recognise a leading `runtime:` (closed enum `Prefix::{None, Runtime}`) and preserve it through `Display` / `serde`. The version + peer parts continue to parse the same way — the prefix-strip happens once up front, after which the parenthesis-based peer-suffix detection is unchanged. Touch points: - Added `Prefix` enum with `as_str()` and `Display`. - `PkgVerPeer::prefix()` exposes the variant so downstream consumers can discriminate runtime entries without substring-searching the depPath. - `PkgVerPeer::into_tuple()` keeps the `(Version, String)` shape for backward compatibility — pre-runtime callers don't see the prefix. 5 new unit tests pin: bare-semver no-prefix, runtime no-peer, runtime with peer-suffix, runtime-substring-mid-version is NOT a prefix (anchored at start), and serde round-trip on the runtime form. All 100 existing `pacquet-lockfile` tests still pass. Unblocks pnpm#437 slice F (end-to-end install fixtures) — pacquet's lockfile loader now accepts `node@runtime:X.Y.Z`-shaped keys.
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
…npm#437 slice F) (pnpm#516) * test(package-manager): variant-mismatch + --no-runtime install tests (pnpm#437 slice F) Two end-to-end install tests for the runtime-dependency pipeline, now that pnpm#512 (`PkgVerPeer::Prefix::Runtime`) unblocked fixture-lockfile parsing. - `frozen_lockfile_install_errors_when_no_variant_matches_host`: Lockfile with a `VariationsResolution` whose only variant targets `aix/ppc64` (a platform pacquet CI never runs on). Install fails with `NoMatchingPlatformVariant` from the cold-batch dispatcher. Variant selection runs before any network fetch, so the bogus archive URL is never read — the test stays hermetic. Closes the variant-mismatch checkbox. - `frozen_lockfile_install_skips_runtime_when_skip_runtimes_set`: Same lockfile, but with `skip_runtimes: true`. The `--no-runtime` filter iterates importer-direct deps, builds `node@runtime:22.0.0` from `(alias, version)`, sees the `@runtime:` substring, and adds the snapshot to the skip set — so variant selection never runs and the unmatchable variant doesn't fail the install. Asserts both the runtime slot and the direct-dep symlink are absent. Closes the `--no-runtime` checkbox. Both tests were verified to catch their respective regressions (disable the `skip_runtimes` filter → the second test fails with `NoMatchingPlatformVariant` instead of succeeding). Required a fix in `PkgNameVerPeer::without_peer`: the existing implementation dropped the `Prefix::Runtime` when stripping the peer-dependency suffix, so a runtime snapshot key like `node@runtime:22.0.0(some@peer)` would resolve to the non-existent `node@22.0.0` `packages:` entry. Now preserves the prefix through the strip. Slice F's remaining items (happy-path archive fetch, integrity mismatch, NODE_EXTRAS verified end-to-end, TEST_PORTING.md entries) need a mock HTTP server + recorded archive fixture, so defer to a follow-up — keeping this PR reviewable. * test(package-manager): use symlink_metadata for absent-entry checks Address CodeRabbit review on pnpm#516: `Path::exists()` follows symlinks, so a regression that created a *dangling* symlink at `<modules_dir>/node` would still pass the `!direct_dep.exists()` assertion — the install would have created the entry the skip set was supposed to suppress, but the test wouldn't notice. Switch both "must NOT exist" assertions to `std::fs::symlink_metadata(...).is_err()` so the entry-level check catches dangling symlinks too.
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
…ce A) (pnpm#457) ## Summary Slice A of pnpm#437. Adds the lockfile types pnpm v11 writes for runtime dependencies (`node@runtime:`, `deno@runtime:`, `bun@runtime:`); the install pipeline doesn't dispatch them yet (subsequent slices). No new workspace deps. - **`BinaryResolution { url, integrity, bin, archive, prefix? }`** — mirrors upstream's [`BinaryResolution`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L41-L49). `bin` is `BinarySpec::Single(String) | BinarySpec::Map(BTreeMap)` (untagged); `archive` is the lowercase `BinaryArchive::Tarball | BinaryArchive::Zip` discriminator; `prefix` (only set on the `.zip` branch upstream) skips serialization when `None`. - **`PlatformAssetTarget { os, cpu, libc? }`** + **`PlatformAssetResolution { resolution, targets }`** per [`resolver-base`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L60-L69). `libc` is `Option<String>` (not an enum) so an upstream addition beyond the current `musl` value lands without a serde migration. - **`VariationsResolution { variants }`** + the `LockfileResolution`/`TaggedResolution` arms routing both new shapes through the existing `from/into ResolutionSerde` round-trip. - **Lockfile major stays at 9** — confirmed against [`core/constants/src/index.ts`](https://github.com/pnpm/pnpm/blob/94240bc046/core/constants/src/index.ts) (`LOCKFILE_MAJOR_VERSION = '9'`), so the existing `lockfile_version.major == 9` assertion holds for v11 lockfiles carrying runtime entries. **Install-dispatch stubs.** `install_package_by_snapshot.rs` and `create_virtual_store.rs` raise `InstallPackageBySnapshotError::UnsupportedResolution { kind: "binary" | "variations" }` until Slice D wires the fetcher. Adding these arms keeps the workspace compiling without forcing the full install path to land in this slice. The warm-prefetch path returns `Ok(None)` for `Variations`, routing through the cold dispatcher where the unsupported-kind error fires; upstream unwraps `Variations` before this layer ever sees one, so the branch is unreachable on well-formed input.
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
slice B) (pnpm#466) * feat(lockfile): select_platform_variant + PlatformSelector (pnpm#437 slice B) Add the variant-picking logic for `VariationsResolution` ahead of Slice D's install-pipeline dispatch: - `PlatformSelector { os, cpu, libc: Option<String> }` mirrors upstream's [`PlatformSelector`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L78-L83). The `libc` tri-state encodes pnpm's `string | null | undefined` shape: `None` (host doesn't care about libc — macOS/Windows/BSD) and `Some("glibc")` collapse to the same matching arm (variant must have no `libc:` annotation); `Some("musl")` requires an exact `libc: "musl"` annotation so the glibc default doesn't silently win on a musl host. - `select_platform_variant(variants, selector)` ports [`selectPlatformVariant`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L92-L98). Iterates `variants` in declaration order and returns the first variant whose `targets[]` contains an `(os, cpu, libc)` triple matching the selector. Targets-array scan is linear because real archives ship 1–3 target entries per variant; quadratic cost is immaterial. - `libc_matches(variant_libc, requested_libc)` is the asymmetric helper from [`libcMatches`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L100-L107). Crate-private so the matching policy isn't part of the public API. Lives in `pacquet-lockfile` next to the variant types (mirrors upstream's `resolver-base` package boundary). The host-platform side (constructing the `PlatformSelector` from `pacquet-graph-hasher`'s existing `host_platform/arch/libc` helpers) lands at the install dispatcher in Slice D — keeps `pacquet-lockfile` free of the `graph-hasher` dep and lets tests drive the picker with synthetic hosts. Tests: first-match wins, multi-target variant matches any host triple, no-match returns `None`, musl-host rejects glibc-default variant, musl-host matches musl-annotated variant, and a six-row `libc_matches` truth table (None / "glibc" / "musl" / unknown-future-libc on both sides) pinning the asymmetric contract from upstream. Part of pnpm#437. --- Written by an agent (Claude Code, claude-opus-4-7). * docs: refresh stale references + add declaration-order tie-breaker test Two follow-ups from Copilot review on PR pnpm#466: - `resolution.rs:152-154` claimed "the variant picker checks at runtime that the resolved inner is atomic", but `select_platform_variant` does not. Reword to describe the actual contract: pacquet's `PlatformAssetResolution.resolution` is typed as the full `LockfileResolution` for serde uniformity, and the lockfile is trusted to honor upstream's atomic-inner invariant. No infinite-recursion risk because the install dispatcher doesn't call back into `select_platform_variant` for non-`Variations` inputs. - `resolution.rs:169` referenced `pick_variant` in `pacquet-package-manager`, but the picker actually lives in this module as `select_platform_variant`. Updated the pointer. - `pick_returns_first_when_multiple_variants_match` test: two variants both list the same `(darwin, arm64)` target; the test asserts the first one wins, pinning the `Array.prototype.find` semantics. Pnpm-written lockfiles can rely on declaration order (e.g., listing a preferred build before a fallback) — without this test, a future refactor that switched the iteration to a triple-keyed `BTreeMap` would silently break that. No behavior change; doc-comment text + test addition. --- Written by an agent (Claude Code, claude-opus-4-7).
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
…pm#472) Slice C of [pnpm#437](pnpm/pacquet#437) — the zip half of pnpm's binary fetcher. Slices A (lockfile types) and B (variant picker) have landed; this slice adds the per-archive download and CAS-extraction pipeline. The install-dispatch site (slice D) and the `--no-runtime` flag (slice E) will follow. Mirrors upstream's [`downloadAndUnpackZip` / `extractZipToTarget`](https://github.com/pnpm/pnpm/blob/94240bc046/fetching/binary-fetcher/src/index.ts): - `extract_zip_entries` walks every entry. Path validation runs *before* the `is_dir()` early-skip so directory entries like `../evil/` still surface `PATH_TRAVERSAL`. The canonical `cas_paths` / `pkg_files_idx` key is built from `enclosed_name()` rebuilt as `Normal` components joined with `/` — `.` segments collapse, separators are cross-platform consistent, and the ignore filter sees the same string the map is keyed by. - `DownloadZipArchiveToStore` is the public sibling of `DownloadTarballToStore` — same store-index lookup, prefetch cache reuse, store-index writer queue. The retry policy, network-permit shape, and post-download semaphore gating exactly match the tarball path. - `ignore_file_pattern` is `Option<Arc<IgnoreEntryFilter>>` on both `DownloadTarballToStore` and `DownloadZipArchiveToStore`, so the Slice D dispatcher can construct a filter per fetch from runtime config without pinning to `'static`. Cloned per retry attempt; the inner trait object is shared. - `run_with_mem_cache` doc-blocks the "stable filter per URL" invariant: the cache keys solely on `package_url` (matching pnpm's `tarballCache`), and callers keep the (URL, filter) relation functional. Upstream's `archiveFilters` is keyed by `pkg.name`, and tarball URLs encode `(name, version, integrity)`, so this naturally holds. - New `TarballError::ReadZipEntries(std::io::Error)` for zip per-entry I/O failures (`try_reserve` / `read_to_end`); maps to `ERR_PACQUET_ZIP` in the retry classifier, distinct from the tar-specific `ERR_PACQUET_TARBALL_TAR`. Zip `unix_mode()` is masked to `0o777` before write so `CafsFileInfo.mode` stays permission-only (matches `store_dir::add_files_from_dir::file_mode_from`). `TarballError::TarballTooLarge` display generalized from "Tarball at …" to "Archive at …" so the zip pipeline's OOM path doesn't surface a misleading message. - Adds `zip = "5", default-features = false, features = ["deflate"]` to the workspace; reused in `pacquet-tarball`.
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
…pnpm#437 slice D1) (pnpm#492) Replace the cold-path `UnsupportedResolution` arms for `LockfileResolution::{Binary, Variations}` with actual fetcher dispatch. Slice C wired the per-archive download (`DownloadTarballToStore` / `DownloadZipArchiveToStore`); this slice routes lockfile resolutions through them. - `Binary(b)` dispatches on `b.archive` (`Tarball` / `Zip`): - `Tarball` → `DownloadTarballToStore` (same shape as registry / tarball entries minus the `package_unpacked_size` hint). - `Zip` → `DownloadZipArchiveToStore` with `archive_prefix: b.prefix.as_deref()` so the runtime archive's top-level wrapper (e.g. `node-vX.Y.Z-darwin-arm64/`) is stripped before the CAS keys are written. - `Variations(v)` runs `select_platform_variant` against a freshly-built `PlatformSelector` (`pacquet_graph_hasher`'s `host_platform` / `host_arch` / `host_libc`, mapping `"unknown"` → `None` per upstream's `process.platform === 'linux' ? family : null` convention). The picked variant's inner resolution must be `Binary`; any other shape (corrupt lockfile or a future shape pacquet hasn't learned about) raises the typed `VariantHasNonBinaryResolution` error rather than silently routing. - `create_virtual_store::snapshot_cache_key` returns the proper warm-cache key for both new arms: `Binary` uses `store_index_key(integrity, pkg_id)`; `Variations` runs the same selector and keys off the picked variant. A miss on variant selection or a non-`Binary` inner shape returns `Ok(None)` and lets the cold path raise the typed error. - Two new error variants on `InstallPackageBySnapshotError`: - `NoMatchingPlatformVariant { package_key, host_os, host_cpu, host_libc, available_targets }` — fires when no variant matches the host; carries the host triple + the rendered available target list so the user can see at a glance why. - `VariantHasNonBinaryResolution { package_key, inner_kind }` — defensive guard for malformed lockfiles. The Node-runtime `NODE_EXTRAS_IGNORE_PATTERN` filter (strips bundled `npm` / `corepack` from the archive) and bin-link cmd-shims for runtime executables will land in Slice D2; the filter slot stays `None` for now and `BinaryResolution::bin` is read but not yet acted on. Slice E adds `--no-runtime` and Slice F adds the end-to-end install fixtures. Two new unit tests cover the helpers: - `host_platform_selector_omits_libc_on_non_linux_hosts` — pins the `host_libc() == "unknown"` ⇔ `selector.libc.is_none()` relationship without needing platform-gated tests. - `render_variant_targets_formats_each_triple_with_optional_libc` — locks in the `os/cpu[+libc]` rendering used by the `NoMatchingPlatformVariant` error message.
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
…pnpm#437 slice D2) (pnpm#496) Construct the per-archive ignore filter at the install dispatcher. For unscoped `node` the filter matches upstream's [`NODE_EXTRAS_IGNORE_PATTERN`](https://github.com/pnpm/pnpm/blob/94240bc046/engine/runtime/node-resolver/src/index.ts), which strips bundled `npm` / `corepack` from the Node.js runtime archive during the CAS write — pnpm (and pacquet) install pnpm itself as the package manager, so the bundled tooling is dead weight and would shadow the user's pnpm via `node_modules/.bin/`. Wiring matches upstream's [`archiveFilters: { node: NODE_EXTRAS_IGNORE_PATTERN }`](https://github.com/pnpm/pnpm/blob/94240bc046/installing/client/src/index.ts): the per-package-name table is keyed by `pkg.name`, so `@foo/node` and other packages keep `None` and the full archive lands unfiltered. Pacquet uses a hand-coded matcher rather than the upstream regex so `pacquet-tarball` doesn't have to pull in a regex engine. The three branches mirror the regex alternation exactly: 1. `^(?:lib/)?node_modules/(?:npm|corepack)(?:/|$)` 2. `^bin/(?:npm|npx|corepack)$` 3. `^(?:npm|npx|corepack)(?:\.(?:cmd|ps1))?$` A `OnceLock` caches the `Arc<IgnoreEntryFilter>` so per-snapshot clones share one trait object. Unit tests pin every branch of the alternation plus the negative cases (e.g. `lib/node_modules/yarn/...` is *not* matched, `bin/npm.cmd` is *not* matched — the regex's `$` and arm-specific extension rules are deliberately asymmetric). Verified by temporarily collapsing the `bin/` branch to a no-op — the test fails as expected. Bin-link cmd-shims for the runtime executables and `@runtime:` substring handling in skip lists / reporter prefixes are Slice D3. End-to-end runtime install fixtures land in Slice F.
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
…e D3 + E) (pnpm#506) * feat(package-manager): runtime bin-link + --no-runtime (pnpm#437 slice D3 + E) Closes the install-pipeline side of pnpm#437: **Slice D3 — runtime bin-link integration.** Runtime archives (`node@runtime:`, etc.) don't ship a `package.json`, so the existing bin-link step had nothing to consume off the slot. `fetch_binary_resolution_to_cas` now synthesizes one in the same shape upstream's `appendManifest` does: { "name": "<pkg.name>", "version": "<pkg.version>", "bin": <BinarySpec> } The bytes go through `StoreDir::write_cas_file` (same content- addressing as every other CAS-imported file), the resulting cas-path is inserted into the snapshot's `cas_paths` under `package.json`, and the existing `link_bins_of_packages` flow picks it up. `link_bins::build_has_bin_set` now includes `Binary` / `Variations` resolutions unconditionally — pnpm v11 doesn't emit `hasBin: true` on runtime metadata, but the synthesized manifest always carries bins, so the lookup must not be gated on the metadata flag. **Slice E — `--no-runtime` flag.** New `Config::skip_runtimes` (default false) and `InstallArgs::no_runtime` CLI flag. The CLI computes `config.skip_runtimes || --no-runtime` and threads it through `Install` → `InstallFrozenLockfile`. When set, every snapshot whose metadata resolution is `Binary` or `Variations` is added to the install-time skip set (re-using `add_optional_excluded` since the bucket count and `.modules.yaml.skipped` semantics line up with `--no-optional`). **Unit tests.** - `synthesize_runtime_manifest_emits_name_version_and_bin_single` — pins `BinarySpec::Single` → JSON string. - `synthesize_runtime_manifest_emits_name_version_and_bin_map` — pins `BinarySpec::Map` → JSON object with all bin entries. - `synthesize_runtime_manifest_preserves_scoped_name` — `@scope/name` round-trips through the `name` field. - `build_has_bin_set_includes_runtime_resolutions_even_when_has_bin_is_absent` — pins the runtime arm. Verified by removing the arm — test fails as expected. End-to-end install fixtures (slice F's remaining items — recorded-archive frozen-lockfile install, variant-mismatch error, `--no-runtime` integration, integrity-mismatch path) need a small recorded Node archive in the repo (or a mockable `pnpm-resolution-mirror`). Tracking them as a separate follow-up so this PR stays reviewable. * fix(package-manager): narrow --no-runtime to importer-direct deps Address CodeRabbit review on pnpm#506: my initial implementation iterated `packages` (every metadata entry) and added all `Binary` / `Variations` snapshots to the skip set, which widened the behavior beyond pnpm's `skipRuntimes`. Per the cardinal rule (CLAUDE.md: "Port behavior faithfully. ... Do not invent behavior that pnpm does not have."), match upstream exactly. Upstream's filter at [`installing/deps-installer/src/install/index.ts`](https://github.com/pnpm/pnpm/blob/94240bc046/installing/deps-installer/src/install/index.ts#L1374-L1387) iterates `dependenciesByProjectId` (per-importer direct deps) and adds `depPath` to `ctx.skipped` when `depPath.includes('@runtime:')`. Transitive runtime entries — unusual but possible — stay in the install. Pacquet now mirrors that exactly: walk each importer's `dependencies` / `dev_dependencies` / `optional_dependencies`, build the candidate snapshot key from `(alias, version)`, check for the `@runtime:` substring, and only add the metadata-confirmed `Binary` / `Variations` keys to `skipped`. Aliased runtime deps (unusual) fall through the same way upstream does — pnpm's lookup is by depPath, not by alias.
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
…m#512) Pnpm v11 writes runtime depPaths with a scheme prefix in front of the semver — e.g. `node@runtime:22.0.0` in `packages:` / `snapshots:` keys, and `runtime:22.0.0` in importer `dependencies:` values. Pacquet's `PkgVerPeer` parser previously accepted only bare semver and rejected the prefix, so it couldn't load any v11 lockfile containing a runtime dependency. Extend `PkgVerPeer` to recognise a leading `runtime:` (closed enum `Prefix::{None, Runtime}`) and preserve it through `Display` / `serde`. The version + peer parts continue to parse the same way — the prefix-strip happens once up front, after which the parenthesis-based peer-suffix detection is unchanged. Touch points: - Added `Prefix` enum with `as_str()` and `Display`. - `PkgVerPeer::prefix()` exposes the variant so downstream consumers can discriminate runtime entries without substring-searching the depPath. - `PkgVerPeer::into_tuple()` keeps the `(Version, String)` shape for backward compatibility — pre-runtime callers don't see the prefix. 5 new unit tests pin: bare-semver no-prefix, runtime no-peer, runtime with peer-suffix, runtime-substring-mid-version is NOT a prefix (anchored at start), and serde round-trip on the runtime form. All 100 existing `pacquet-lockfile` tests still pass. Unblocks pnpm#437 slice F (end-to-end install fixtures) — pacquet's lockfile loader now accepts `node@runtime:X.Y.Z`-shaped keys.
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
…npm#437 slice F) (pnpm#516) * test(package-manager): variant-mismatch + --no-runtime install tests (pnpm#437 slice F) Two end-to-end install tests for the runtime-dependency pipeline, now that pnpm#512 (`PkgVerPeer::Prefix::Runtime`) unblocked fixture-lockfile parsing. - `frozen_lockfile_install_errors_when_no_variant_matches_host`: Lockfile with a `VariationsResolution` whose only variant targets `aix/ppc64` (a platform pacquet CI never runs on). Install fails with `NoMatchingPlatformVariant` from the cold-batch dispatcher. Variant selection runs before any network fetch, so the bogus archive URL is never read — the test stays hermetic. Closes the variant-mismatch checkbox. - `frozen_lockfile_install_skips_runtime_when_skip_runtimes_set`: Same lockfile, but with `skip_runtimes: true`. The `--no-runtime` filter iterates importer-direct deps, builds `node@runtime:22.0.0` from `(alias, version)`, sees the `@runtime:` substring, and adds the snapshot to the skip set — so variant selection never runs and the unmatchable variant doesn't fail the install. Asserts both the runtime slot and the direct-dep symlink are absent. Closes the `--no-runtime` checkbox. Both tests were verified to catch their respective regressions (disable the `skip_runtimes` filter → the second test fails with `NoMatchingPlatformVariant` instead of succeeding). Required a fix in `PkgNameVerPeer::without_peer`: the existing implementation dropped the `Prefix::Runtime` when stripping the peer-dependency suffix, so a runtime snapshot key like `node@runtime:22.0.0(some@peer)` would resolve to the non-existent `node@22.0.0` `packages:` entry. Now preserves the prefix through the strip. Slice F's remaining items (happy-path archive fetch, integrity mismatch, NODE_EXTRAS verified end-to-end, TEST_PORTING.md entries) need a mock HTTP server + recorded archive fixture, so defer to a follow-up — keeping this PR reviewable. * test(package-manager): use symlink_metadata for absent-entry checks Address CodeRabbit review on pnpm#516: `Path::exists()` follows symlinks, so a regression that created a *dangling* symlink at `<modules_dir>/node` would still pass the `!direct_dep.exists()` assertion — the install would have created the entry the skip set was supposed to suppress, but the test wouldn't notice. Switch both "must NOT exist" assertions to `std::fs::symlink_metadata(...).is_err()` so the entry-level check catches dangling symlinks too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hello lovely humans,
npm-registry-client just published its new version 7.3.0.
This version is not covered by your current version range.
Without accepting this pull request your project will work just like it did before. There might be a bunch of new features, fixes and perf improvements that the maintainers worked on for you though.
I recommend you look into these changes and try to get onto the latest version of npm-registry-client.
Given that you have a decent test suite, a passing build is a strong indicator that you can take advantage of these changes by merging the proposed change into your project. Otherwise this branch is a great starting point for you to work on the update.
Do you have any ideas how I could improve these pull requests? Did I report anything you think isn’t right?
Are you unsure about how things are supposed to work?
There is a collection of frequently asked questions and while I’m just a bot, there is a group of people who are happy to teach me new things. Let them know.
Good luck with your project ✨
You rock!
🌴
This pull request was created by greenkeeper.io.
Tired of seeing this sponsor message? ⚡
greenkeeper upgrade