rfc(pnpr): registries declare their namespace; rename mounts to registries#16
Conversation
A concrete mount now declares the package-name patterns it serves — its namespace — enforced at the mount itself on reads and writes, on every path to it. Routers drop per-route patterns and become ordered sources: lists; a package resolves to the first source whose patterns claim it. This closes the gaps of the route-level-pattern iteration: a hosted mount could accept a publish of any name (dormant squatting surfaced by later route edits, silent typo publishes), a private upstream would fetch arbitrary public names through its server-owned credential, and the same patterns were restated by every router.
|
Warning Review limit reached
Next review available in: 38 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Summary by QodoRFC: move package patterns onto mounts and simplify routers to ordered sources
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Every explanation of a mount began "a mount is a full npm registry at..." — name it what it is. The former blocker, the top-level registry: surface toggle, was removed separately (pnpm/pnpm#12767). mounts: -> registries:, defaultTarget: -> defaultRegistry:. The vocabulary is now two terms: a registry is a named surface pnpr serves at /~<name>/; an origin is the external URL an upstream registry fetches from. The old name is recorded as a rejected alternative.
pnpm/rfcs#16 was updated to rename the config surface: every explanation of a mount began "a mount is a full npm registry at...", so the unit is now simply a **registry**. `mounts:` becomes `registries:` and `defaultTarget:` becomes `defaultRegistry:` (npm's own concept), aligning the server with the client-side `namedRegistries`. pnpr is pre-1.0, so the old keys are replaced outright with no compatibility mode. The Rust surface follows the RFC's reference sketch: `MountKind` → `Registry`, `Mounts` → `Registries`, `MountConfigError` → `RegistryConfigError`, the `mount` module → `registry`, `Config.mounts` → `Config.registries`, and prose/error messages now say "registry" ("name a hosted registry", `/~<name>/`). The axum-level "routes are mounted" wording is kept — that is framework vocabulary, not the renamed concept. The vocabulary is now: **registry** — a named surface pnpr serves; **origin** — the external URL an upstream registry fetches from; "uplink" remains only as the internal upstream-backend term.
… sources (#12778) Implements the revised model from pnpm/rfcs#16, replacing the route-level-pattern shape outright (pre-1.0, no compatibility mode). The config surface is renamed per the RFC: `mounts:` -> `registries:`, `defaultTarget:` -> `defaultRegistry:`, and the Rust types follow (`MountKind` -> `Registry`, `Mounts` -> `Registries`, the `mount` module -> `registry`). The vocabulary is now: registry — a named surface pnpr serves; origin — the external URL an upstream registry fetches from. Hosted and upstream registries take an optional `patterns:` list — their declared namespace (omitted = every name) — and a router collapses to an ordered `sources:` list: a package resolves to the first listed source whose patterns claim it. The namespace is enforced at the registry, on every path to it: an off-pattern read is a definitive 404 answered before storage or the upstream is consulted, and an off-pattern publish is rejected with a clear reason — through a router and at the registry's own `/~<name>/` URL alike. This closes the open hosted namespace (no dormant stored state that a later source edit would surface as authoritative) and stops an authorized caller from pulling arbitrary public names through a private upstream's server-owned credential. Validation translates to the same `covers()` machinery: unreachable sources (all claims covered by earlier sources' union, including a non-last pattern-less source), per-pattern shadowing across sources (identical claims by two sources rejected, so bidirectionally-overlapping namespaces fail in either order), duplicate sources per router, duplicate patterns per registry, plus the carried-over unknown/self-referential/ router-as-source/empty-router checks. A registry's own internally redundant patterns are allowed and do not count as self-shadowing. Patterns live only in the registry graph (`Config::registries`), not duplicated into the hosted/uplink tables: enforcement happens in `Registries::resolve`, which every read, write, search, and cache-header decision flows through, so the namespace is one declaration. The bundled config.yaml moves the registry-mock fixture list onto the `local` registry, and `Config::proxy` / `Config::static_serve` build the equivalent graphs programmatically.
Two revisions to the registry-mounts RFC, now reflecting the model as named registries:
1. Patterns move onto the concrete registries; routers become ordered source lists
Every concrete registry (hosted or upstream) declares the package-name
patterns:it serves — its namespace — enforced at the registry itself, on every path to it: an off-pattern publish is rejected and an off-pattern read is a definitive 404, whether the request came through a router or addressed/~<name>/directly. A router collapses tosources: [a, b, c]: the first source whose patterns claim the name wins, authoritatively. A pattern-less registry serves every name (the catch-all) and must be listed last.This closes the gaps of the route-level-pattern iteration (implemented by pnpm/pnpm#12747):
access:admitted;Routing is now derived from declared ownership — a router orders competing claims but can never assign a name to a registry that doesn't claim it. Validation translates to the same
covers()machinery: unreachable sources (including a non-last catch-all), shadowed patterns, duplicate sources/patterns, non-concrete sources — all startup/reload errors. Registries whose namespaces overlap in both directions cannot be ordered at all and fail validation as genuinely ambiguous provenance.2. Rename:
mounts:→registries:,defaultTarget:→defaultRegistry:Every explanation of a mount began "a mount is a full npm registry at…" — when every definition of X starts with "X is really a Y", the name should be Y. The rename aligns the server config with the client's
namedRegistries, anddefaultRegistryis instantly legible because it is npm's own concept. The former blocker — the top-levelregistry:surface toggle as a sibling key — was removed separately (pnpm/pnpm#12767), freeing the name.The RFC's vocabulary is now two terms: a registry is a named surface pnpr serves at
/~<name>/; an origin is the external URL an upstream registry fetches from. Both prior shapes are recorded as rejected alternatives in the Rationale section (route-level patterns; themounts:name), and the Implementation section states that pnpm/pnpm#12747 shipped the earlier shape and this revision replaces it outright (pre-1.0, no compatibility mode).Trade-offs recorded: per-router narrowing is no longer expressible (covered by the
packages:ACL in the identity dimension; two upstream registries over one URL where truly needed); a follow-up question notes the specificity-based (order-free) source-selection alternative and why declared order is kept.The file keeps its
0000-pnpr-registry-mounts.mdname so existing links don't break.