Files
pnpm/justfile
Zoltan Kochan add6c794f1 feat(registry): implement pnpm-registry server and adopt it in pacquet's test mock (#11898)
Creates a working pnpm-compatible npm registry server (verdaccio analogue, in Rust) — and replaces `@pnpm/registry-mock`'s Node + Verdaccio launcher in pacquet's test setup with the new binary, against `@pnpm/registry-mock`'s shipped storage.

### What `pnpm-registry` does
- **HTTP server** (axum + tower-http) with the three endpoints pnpm/npm clients need:
  - `GET /<pkg>` — packument (`/{name}` and `/{scope}/{name}`)
  - `GET /<pkg>/<version-or-tag>` — single-version manifest, resolves `dist-tags` and rewrites `dist.tarball` to point at this server
  - `GET /<pkg>/-/<tarball>` — tarball, streamed
- **Two modes:**
  - **Proxy** — fetches missing packuments/tarballs from a configurable upstream (defaults to `https://registry.npmjs.org`), caches to disk
  - **Static** (`--static`) — serves the storage directory verbatim, 404s on cache miss
- **Verdaccio-shaped on-disk storage** (`<root>/<pkg>/package.json` + flat tarballs) — drop-in compatible with the storage `@pnpm/registry-mock` publishes
- **Tarball streaming** — cache hits stream off disk; cache misses tee upstream chunks into a temp file via an mpsc channel and forward them to the client at the same time, atomically renaming on success and abandoning on upstream error or client disconnect
- **Tuned HTTP client** — wraps `pacquet_network::ThrottledClient::new_for_installs()`, inheriting pnpm's tuned defaults (`User-Agent: pnpm`, HTTP/1.1, hickory DNS, connection-pool tuning, concurrency semaphore)
- **Gateway-style status mapping** — `is_timeout()` → 504, `is_connect()` → 503, everything else (incl. upstream 5xx) → 502. No proxy-side retry (the pnpm client already has `fetch-retries`; stacking retries would only multiply latency on real failures).

### What changed in pacquet
- `pacquet/tasks/registry-mock` now spawns `pnpm-registry` against `node_modules/@pnpm/registry-mock/registry/storage-cache` (proxy mode with `npmjs.org` upstream and a 1-year packument TTL — matching `@pnpm/registry-mock`'s `'**': proxy: npmjs` verdaccio config). No more Node, no more Verdaccio, no more `launch.mjs`, no more process-tree walk to kill child verdaccios.
- `@pnpm/registry-mock` stays as a devDep — only for the storage data it ships, not the launcher.

### Tests
- **36 pnpm-registry tests** (12 unit + 7 against `@pnpm/registry-mock` storage in static mode + 17 mockito-based proxy/cache/streaming): packument rewrite, version-manifest resolution, tarball streaming (large body, cache finalize, mid-stream upstream error, client disconnect mid-stream, concurrent fetches → one cache file), gateway status mapping (504/503/502), stale-cache fallback on upstream failure, TTL refresh, invalid-package-name 400, scoped vs unscoped routing.
- **Full pacquet test suite** (2043 tests) runs green against `pnpm-registry`-backed mock.

### CI
- `pacquet-ci.yml` and `pacquet-codecov.yml` path filters now include `registry/**` (so registry-only PRs trigger the workspace CI); typos checker covers `registry` too. The workflow name stays "Pacquet CI" but a header comment explains the intentional cross-stack scope.
- `just registry-mock launch` pre-builds with `cargo nextest run --no-run` (workspace-wide) so its fingerprint matches what `just test` will later need — without this, Windows MSVC fails with `os error 5` trying to re-link the running `pnpm-registry.exe`.

### Crates.io name reservations (from the original scaffold commit)
- [`pnpm-registry`](https://crates.io/crates/pnpm-registry) — published from this repo
- [`pnpm-registry-cli`](https://crates.io/crates/pnpm-registry-cli) / [`pnpm-registry-server`](https://crates.io/crates/pnpm-registry-server) — placeholder stubs, name reservation only
2026-05-24 21:18:09 +02:00

111 lines
3.4 KiB
Makefile

#!/usr/bin/env -S just --justfile
_default:
just --list -u
alias r := ready
alias c := codecov
alias t := test
# Initialize the project by installing all the necessary tools.
# Make sure you have cargo-binstall installed.
# You can download the pre-compiled binary from <https://github.com/cargo-bins/cargo-binstall#installation>
# or install via `cargo install cargo-binstall`
init:
cargo binstall cargo-nextest cargo-watch cargo-insta typos-cli taplo-cli wasm-pack cargo-llvm-cov -y
just install-hooks
# Point git at pacquet/.githooks/ so the tracked pre-push format check runs on `git push`.
install-hooks:
git config core.hooksPath pacquet/.githooks
# When ready, run the same CI commands
ready:
typos
cargo fmt
just check
just test
just lint
git status
# Update our local branch with the remote branch (this is for you to sync the submodules)
update:
git pull
git submodule update --init
# Install necessary dependencies.
# `pacquet/tasks/registry-mock` is a member of the root pnpm workspace,
# so the root install populates its node_modules.
install:
pnpm install --frozen-lockfile --prefer-offline
# Run `cargo watch`
# --no-vcs-ignores: cargo-watch has a bug loading all .gitignores, including the ones listed in .gitignore
# use .ignore file getting the ignore list
watch command:
cargo watch --no-vcs-ignores -x '{{command}}'
# Format all files
fmt:
cargo fmt
taplo format
# Run cargo check
check:
cargo check --locked --workspace --all-targets
# Run all the tests.
test:
cargo nextest run
# List expected-failing test ports
[unix]
known-failures:
@cargo test --workspace known_failures -- --list 2>/dev/null | rg '^known_failures::'
[windows]
known-failures:
@cargo test --workspace known_failures -- --list 2>nul | rg '^known_failures::'
# Lint the whole project
lint:
cargo clippy --locked --workspace --all-targets -- --deny warnings
# Run perfectionist dylint rules. Requires `cargo-dylint` and `dylint-link`
# (install with `cargo binstall cargo-dylint dylint-link`). The lint library
# is pinned in `dylint.toml`.
dylint:
env RUSTFLAGS="-D warnings" cargo dylint --all -- --all-targets --workspace
# Get code coverage
codecov:
cargo codecov --html
# Run the benchmarks. See `tasks/benchmark`
micro-benchmark:
cargo run --bin=micro-benchmark --release
# Manage registry-mock. The launcher spawns `pnpm-registry`; on
# Windows you can't overwrite a running .exe, so we pre-build all
# the test artifacts a subsequent `just test` will need with the
# exact same invocation. A `-p pnpm-registry`-scoped pre-build is
# not enough — workspace-wide feature unification gives a
# different fingerprint and nextest would still try to re-link the
# running binary, failing with `os error 5` on Windows MSVC.
registry-mock +args:
cargo nextest run --no-run
cargo run --bin=pacquet-registry-mock -- {{args}}
# The benchmark may auto-spawn the registry mock (via
# `AutoMockInstance::load_or_init()`), so make sure `pnpm-registry`
# is built before the executor runs — otherwise the spawn step
# aborts with "binary not found". Built with `--release` so the
# mock serves at optimized perf; a debug build would put the
# Rust mock at a multi-second handicap vs verdaccio, which V8
# always JITs, polluting the install-perf signal.
integrated-benchmark +args:
cargo build --release --bin=pnpm-registry
cargo run --bin=integrated-benchmark -- {{args}}
cli +args:
cargo run --bin pacquet -- {{args}}