* chore(release): 11.28.7, pacquet 12.15.0, pnpr 0.1.0-alpha.16
* docs(release): curate 11.28.7, pacquet 12.15.0, and pnpr 0.1.0-alpha.16 release notes
Add lead paragraphs and group the patch entries by what the reader was
doing, with security fixes first on each page.
- v11: lead with the registry metadata name check, pinned pnpm
trustPolicy check, maxTarballUnpackedSize, and the removal of registry
revisions; merge overlapping entries for minimumReleaseAge metadata
revalidation, frozen-lockfile directory dependency checks,
syncInjectedDepsAfterScripts, verifyDepsBeforeRun, pnpm sbom, and
unreadable config settings.
- v12: order minor highlights from config includes and
lockfile.integrityTarget down to interactive update styling; drop the
pnpr-only distribution note from the CLI changelog; merge overlapping
entries for workspace and pnpr install speedups, minimumReleaseAge and
If-Modified-Since revalidation, frozen-lockfile and injected package
checks, verifyDepsBeforeRun, pnpm prune, pnpm pack, pnpm licenses
list, pnpm self-update, pinned pnpm flag forwarding, and WebContainer
fixes.
- pnpr: lead the minor section with the breaking ecosystem URL prefix,
hosted storage layout, artifacts.orgs, and strict config schema
changes; fold dist.pnpr tarball metadata into one entry and drop the
redundant /metrics note; lead the patch section with reserved-username
and auth security fixes.
- Use one issue-link label style across the release pages.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* chore(release): 11.28.6, pacquet 12.14.0
* docs(release): curate 11.28.6 and pacquet 12.14.0 release notes
Add lead paragraphs and group the patch entries by what the reader was
doing, with security first on the v11 page.
- v11: lead with the NPM_ID_TOKEN audience check and the invalid file
name warning as security fixes; say the `pnpm setup` message was
printed, since v11 reports it as a warning.
- v12: merge the stdout and stderr broken-pipe entries and the two
optional-peer entries; say the Windows Rust toolchain change undoes
the MinGW fallback a MinGW-built pnpm used since 12.13.0; correct the
`browser` packing claim; drop the reference to another release line.
- Use one issue-link label style on both pages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): smooth two sentences in the 11.28.6 and 12.14.0 notes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): say sideEffectsCache.exclude covers the local and remote cache
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: give sideEffectsCache.exclude an example a cache key cannot cover
An environment variable such as JAVA_HOME could be added to the cache
key, so it does not justify excluding a package. Name the system
libraries a native addon links against instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(release): 11.28.5, pacquet 12.10.0
* docs(release): curate the 11.28.5 and 12.10.0 release notes
Add a lead paragraph to each page and group the patch entries under
subject headings, with the security fixes first.
- Merge the unpublish path-boundary fix into the unpublish entry, the
legacy metadata cache prune into the metadata cache entry, the two
binary size entries, and the two 64 MiB archive limits on the v11 page.
- Drop the manifest-utils saveType entry from the CLI page: the CLI
only passes saveType values derived from its own flags, so no CLI user
can reach the fixed path.
- Rewrite mechanism-only entries (PAX header validation, bundled
dependency symlinks, custom resolutions under name@version keys, proxy
setting validation) in terms of what the user sees.
- Use one link style for pnpm/pnpm issues.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(release): 11.28.4, pacquet 12.9.1
* docs(release): curate 11.28.4 and pacquet 12.9.1 release notes
Add a lead paragraph to both pages. Move the two credential-leak fixes
in 11.28.4 to the top and group the remaining 27 entries by what the
reader was doing. Merge entries that described one change: the two
INVALID_SETTING validations, the two metadata revalidation fixes, the
two hoisted filtered-install fixes, and, in pacquet 12.9.1, the two
[<since>] selector fixes. Order pacquet 12.9.1 so the `@pnpm/wasm` move,
which WebContainer users must act on, comes first.
Normalize issue links to the [#N] form and link the ETag fix to
pnpm/pnpm#16506.
Every fix was checked against the code released in 11.28.3 and
pacquet 12.9.0; none fixes a defect that never shipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): describe the frozen-lockfile fixes accurately in the 11.28.4 lead
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* docs(agents): add the documentation and comment principles
Import the principles that transfer from KSXGitHub/perfectionist's
contributor guide, plus four of our own: concise and non-repeating text,
structured text over prose, removal over addition when reviewing or
fixing nitpicks, and a definition of the user-facing text that must not
name implementation details.
The root guide's "Comments" section gains "Register", "Prose that cannot
go stale", "User-facing text", and "Reviewing documentation and
comments". The pacquet style guide adds the Rust specifics (clap and
napi doc comments are user-facing; a default is documented on the
field, not the variant). DOCUMENTATION.md gains the renderer and link
table for each markdown surface.
The guides themselves are brought in line: counts over growable lists
become plain references, a quoted heading becomes an anchor link, and
the size limits are stated once, in the style guide, instead of three
times.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs: keep user-facing text free of implementation names
The `@pnpm/napi` README and type declarations named the Rust engine, the
in-repo package name, and TypeScript internals (`filterPkgsDiff`,
`nameFormatter`) that a user of the addon cannot reach. The pnpmfile
page in both docs trees explained a limitation by the IPC mechanism
behind it. Four changesets named the release line or implementation,
which the package targets already express.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut restating and stale comments in pack, modules-yaml and nine more crates
Apply the comment principles to pack, versioning, pnpr-client,
package-is-installable, fs-packlist, workspace-task-scheduler,
engine-runtime-node-resolver, exportable-manifest, modules-yaml,
pnpr-registry, and pnpr-auth. Removed: call-site comments that repeat
the callee's doc, module rosters of exports that the `pub use` lines
already list, "not yet implemented" notes for behaviour that exists
(`beforePacking`, `hoistedLocations`), body narration, and history
framing. Comment-only; no code changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut restating and stale comments in the small resolver, catalog and pnpr crates
Apply the comment principles to the local, tarball, default, deno and
jsr resolvers, the catalog crates, detect-libc, config-parse-overrides,
env-replace, git-utils, matcher, diagnostics, and the pnpr policy,
cargo, error, osv and fixture crates. Removed: parentheticals that
repeat a `#[diagnostic(code)]` attribute, counts over lists of
variants, callers and entry points, rosters of callers, doc paragraphs
that repeat a sibling's or the module's text, comments narrating the
match arms or condition below them, and history framing. The
`pnpr-prepare --help` text no longer names the test harness.
Comment-only; no code changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut restating and stale comments in publish, workspace, registry and graph-hasher
Apply the comment principles to publish, auth-commands, registry,
workspace, lockfile-verification, default-reporter, the git resolver,
deps-inspection, hooks, graph-hasher, package-manifest, and the pnpr
shared-artifacts and route crates. Removed: a module roster of every
export, counts over lists, plan notes for work that landed ("Phase 5",
"Phase 6"), call-site comments repeating the callee's doc, docs
narrating match arms, a default claim on a `#[default]` variant, a
misattached doc, and history framing. Comment-only; no code changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut restating comments in napi, reporter and pnpr crates
Apply the comment principles to napi, reporter, resolving-resolver-base,
real-hoist, git-fetcher, workspace-manifest-writer, and the pnpr config
and storage crates. Removed: "Mirrors X in index.d.ts" sentences on
`#[napi]` items and other implementation names in addon-facing docs,
stale "not emitted yet" and "when it lands" notes for behaviour that
exists, step-by-step comments narrating the body, emit-site and caller
rosters, docs duplicated from a sibling or the module, a doc attached to
the wrong item, and history framing. Comment-only; no code changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs: cut restating and stale comments across the remaining crates and pnpm11
Apply the comment principles to the rest of the Rust workspace and to the
TypeScript CLI: the cli crate and its clap definitions, package-manager,
config, patching, the deps resolver, lockfile, pnpr, the npm resolver,
tarball, network, executor, cmd-shim, the benchmark and fixture tooling,
and the pnpm11 packages.
Removed: comments narrating the body, docs repeating a callee's, a
sibling's or the module's text, counts over growable lists, rosters of
callers and exports, "not yet implemented" notes for behaviour that
exists, history framing, and `@param` lines restating a signature.
One exception to comment-only: in `pnpr/crates/pnpr/src/resolver/resolve.rs`
the `Workspace` struct sat inside the doc block written for `resolve`, so
the struct moved above it and each doc now attaches to its own item.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut body narration and duplicated docs in resolver, fs and package-manager
Removed: a numbered "Sequence:" list narrating `ensure_file`'s body and
the paragraph restating its backoff constants, the stress-test module
doc's roster of its own tests, refactor-history paragraphs in the peer
walk's finalize pass, call-site and caller-side copies of a callee's doc
(the `optional` AND-fold stays documented on `register_seeded_package`
and on `ResolvedPackage`), a verbatim quotation of a TypeScript test's
expected output in the pnpr search module doc, and field and digest-input
rosters in the package-manager.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(deps-restorer): cut plan references and re-attach misplaced docs
Removed the "slice 4" plan references and the comments narrating the
bodies they sat above. The `Auto` downgrade-chain doc moved from
`copy_and_log` to `auto_link`, the function it describes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(deps-restorer): cut the remaining body narration in the hoist path
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs: cut the last body narration and a history clause in the cmd-shim test
`build_graph.rs` kept a `patches` parameter doc that re-derived what
`BuildOptions::patches` documents. The PowerShell-arguments test on main
said the arguments survived "before the shim ended its batch context
too", which describes the change rather than the behaviour.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(cmd-shim): point the PowerShell-shim link at its current module
Main moved `wants_powershell_shim` into `windows_shim_policy`, so the
shim writer's link to it no longer resolved and `cargo doc` failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(cli): link the fixture the ignored-build setup installs
The shortened doc named `workspace_with_unapproved_build` in backticks,
which `perfectionist::bare_identifier_reference` rejects for an item that
resolves in scope. It is an intra-doc link now.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): restore two contracts and fix four dangling references
A review of this branch's sweep flagged seven places. Six needed a
change:
- `from_ini` documents again that a relative `cafile=` resolves against
`npmrc_dir`, a precondition its callers have to honour.
- `hash_object` documents again that the private serializer's bytestream
has to match pnpm 11's, because the digest is persisted and read by
both.
- The hooked-manifests note no longer says "above" of a gate that lives
in another module.
- The store-dir race test states its synchronization contract instead of
labelling it "Post-Option-C".
- `GraphNodeHashOptions.nodeVersion` keeps `undefined` as a literal.
- The pnpr streaming module drops the sentence fragment that introduced
its list.
The seventh, a `beforePacking` limitation in exportable-manifest, stays
removed: the note said the pnpmfile bridge cannot supply that hook, and
`pnpm_pack::lifecycle::apply_before_packing` has been running it since
before this branch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(cli): say in `pnpm why --help` that `--exclude-peers` is ignored
Demoting the caveat to an ordinary comment took it out of the help,
which then advertised a flag that does nothing: `WhyArgs::run` never
reads `exclude_peers`, and pnpm 11's `why` handler never forwards its
`excludePeers` either. The doc comment states that behavior in the words
a user sees, and the parity reason stays in a comment beside it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(cli): drop the doc comment that described the wrong module
The comment described the `pnpm_deps_inspection as deps_tree` re-export
above it, but a doc comment attaches to the item that follows, so rustdoc
showed it as the description of `mod dispatch`. The `use` item already
names the alias, so the comment goes rather than moving.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
---------
Co-authored-by: Claude <noreply@anthropic.com>
* chore(release): 11.28.3
* docs(changelog): curate the 11.28.3 release notes
Merge the eleven entries about names such as `constructor` into one,
group the patch changes by what the reader was doing, and add a lead
paragraph.
Drop the zlib-rs entry: that change only touched Cargo.toml, and the
TypeScript CLI does not use the Rust engine. It belongs to the next
pacquet release.
Rewrite the store index entry for CLI users. `ReadOnlyStoreIndex` and
`ImmutableStoreIndex` are library API documented in the
`@pnpm/store.index` changelog.
Say what the store prune mark-phase fix changes for the user.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Add TypeScript ports of the perfectionist rules that the Rust workspace
enforces through dylint.toml to @pnpm/eslint-config, with the same limits,
and fix every finding that needs no refactor.
The size and shape rules (function length, cognitive complexity, nesting,
local bindings, file length) are enforced for packages that already meet
them. The packages that do not are listed in PENDING_SIZE_AND_SHAPE_REFACTOR
in eslint.config.mjs and are refactored in follow-up changes.
The custom rules mirror perfectionist's semantics rather than reusing
sonarjs or max-lines-per-function, so that one limit means the same thing
in both codebases: a closure is a level of the body that contains it, a
nested function declaration is measured on its own, and a test-framework
callback plays the role of a #[test] function.
Bugs found and fixed along the way:
- a registry error body cut at exactly 64 KiB lost its truncation marker
- removing a dependency could leave dangling .bin shims
- constructor/__proto__ names crashed the projects graph, were skipped by
the injected-deps syncer, and were dropped from writeWantedLockfile's
returned lockfile
The CI chunk runner learns to run the node:test suite of the ESLint
config package.
* chore(release): 11.28.1, pacquet 12.8.0, pnpr 0.1.0-alpha.14
* docs(release): park Rust changelogs and curate release notes
The release bump ran with pnpm 12.7.0, which since pnpm/pnpm#14934
writes the changelog of every private project to a committed
CHANGELOG.md. pacquet, `@pnpm/napi` and `@pnpm/pnpr` are private
in-repo but published, and release.yml and the publish-time changelog
composer both read their parked section. Move the three sections back
to .changeset/changelogs so the GitHub release bodies and the npm
tarball changelogs are not empty. The tooling follow-up is recorded
on pnpm/tasks#38.
Curate the pnpm 11.28.1, pnpm 12.8.0 and pnpr 0.1.0-alpha.14 pages:
add lead paragraphs, group patch entries by subject, merge entries
describing one change, drop internals no CLI user sees, and fix
"instead of" tails, implementation names and link placement. This
addresses both Qodo findings on the catalog entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
StackBlitz WebContainers reject asynchronous fs calls with errors that
inherit from Error but were not created by the native constructor, so
util.types.isNativeError() returns false for them. pnpm used that check
to recognize ENOENT and other codes, so a missing pnpm-lock.yaml was
rethrown and pnpm install failed on any project without a lockfile.
Add isError() to @pnpm/error, which accepts a native error or any
instanceof Error, and use it at every non-test call site. The native
check alone is still needed for Jest, where errors from another realm
fail instanceof. Update the AGENTS.md guidance to match.
Closespnpm/pnpm#15649
`fs.promises.realpath` is the native realpath, which on Windows expands 8.3
short names such as `RUNNER~1`. The install dir of the global node group
then no longer looked like a subdirectory of the configured global dir, so
`removeGlobalGroups` removed the hash link but kept the install dir. Use the
JS realpath (promisified callback `fs.realpath`), as `scanGlobalPackages`
does through `fs.realpathSync`.
`pnpm env use --global` still requires a global bin directory that pnpm owns and that is on PATH. Removing a Node version only deletes copies pnpm already stored under its home (`nodejs/<version>`), and listing versions does not link a binary, so those commands no longer stop when the global bin is missing or not on PATH.
The TypeScript CLI skips the global-bin PATH check for `env remove` and `env list` (and their aliases) before config loading, because that check ran before the env handler and rejected brew and npm installs. The handler still throws `ERR_PNPM_CANNOT_MANAGE_NODE` for `env use` when there is no global bin. The Rust CLI applies the same split: `use` still returns `CannotManageNode` without a global bin, and `remove` still deletes the store when `global_dirs` cannot be resolved.
Removing the active global `node` package no longer spawns `pnpm remove --global node`, because that child process ran the PATH check again and failed. The TypeScript CLI splits `removeGlobalGroups` out of `handleGlobalRemove` and calls it in-process with the group `env remove` detected. The Rust CLI splits `remove_global_groups` out of `handle_global_remove` the same way. Both still unlink the package's bins when a global bin directory exists.
Closespnpm/pnpm#8357
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix: key built packages by the root project's runtime Node
The engine part of a global virtual store slot's hash and of the
side-effects cache key came from the first `node@runtime:` entry in the
lockfile. A dependency that declares its own `engines.runtime` adds such
an entry too, so the key could name that dependency's Node while every
other package's build scripts ran the root project's Node. pnpm v12
iterated a randomly ordered map, so the key and the slot paths could
also change from one install to the next.
Take the install-wide Node version from the root importer's `node`
runtime dependency in both CLIs. That is the Node on the PATH of
dependency builds: the root's `node_modules/.bin` in v11 and with a
local virtual store, and the directory pnpm v12 adds under the global
virtual store. A dependency's own pin still keys that dependency's own
hash.
pnpm v12 reuses the root-importer lookup behind
`find_root_runtime_node_version`. pnpm v11 reuses
`findLockedRootNodeRuntime` and drops `findRuntimeNodeVersion`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(graph-builder): pin the root runtime through the GVS path
The lockfile.utils test exercised `findLockedRootNodeRuntime`, which
existed before, so reverting the v11 call sites left it passing. Test
through `iteratePkgsForVirtualStore` instead: a built package's global
virtual store path must change with the root project's pin while a
dependency's own pin sorts first. The old first-key selection fails it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(release): 11.28.0, pacquet 12.7.0, pnpr 0.1.0-alpha.13
* docs(release): curate the 11.28.0 and 12.7.0 release pages
Group both pages under subject headings with a lead paragraph that
names the headline changes and the security fixes, and move the
security entries to the top of the patch section.
Merge entries that describe one change: the node shim version files,
ranged selectors without a package.json, SemVer build metadata,
completion injection, custom modulesDir command lookup,
list --only-projects, store status, npm_execpath, catalog and npm-alias
workspace edges, the macOS CA fallback, and the prepare/devPreinstall
skips.
Drop entries that describe no change a published version could show:
the test-only --no-optional entry on both pages, the exported
CreateNewStoreControllerOptions type, the publish availability-probe
fix for a flag first shipping in 12.7.0, and the executable-bit check
the Rust CLI never had wrong.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): describe the bin shim part of the modulesDir entry accurately
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Node.js publishes native `win-arm64.zip` archives starting with Node.js 20. Prior releases only publish `win-x64.zip` archives and execute under Windows on ARM emulation.
This change updates architecture normalization and target matching for `win32-arm64`:
- Resolves native `node-v${version}-win-arm64.zip` for Node >= 20.
- Falls back to `node-v${version}-win-x64.zip` for Node < 20.
- Implements this behavior in both the TypeScript pnpm 11 engine-runtime-node-resolver and the Rust pnpm 12 engine-runtime-node-resolver.
Closespnpm/pnpm#7123
When removing a Node.js runtime version via `pnpm env remove` (or `pnpm env rm`),
clean up legacy nodejs directories, active symlinks, and dangling shims/symlinks
in global bin and pnpm home directories.
Closespnpm/pnpm#6122
Only HTTP 404 from unofficial-builds.nodejs.org is ignored when reading the
musl assets of a Node.js release, since that is how the mirror reports a
release it never built. Every other status and every transport error now
aborts the resolve, so a blocked or unreachable mirror can no longer leave
the musl assets out of the lockfile on one machine and not another
pnpm/pnpm#14813.
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Reuse the existing URL-scoped registry credential lookup for every Node.js mirror request instead of introducing a separate authentication setting.
This covers release indexes, SHASUMS files and signatures, and runtime archives in both implementations while retaining longest-path-prefix scoping and cross-origin redirect protections. Authenticated checksum metadata bypasses the URL-keyed disk cache so it cannot cross credential contexts.
Closespnpm/pnpm#14334.
`sideEffectsCache` now carries the whole story — whether a build is
restored, whether one is saved, and the remote tier that shares it
between machines. `remoteSideEffectsCache` broke the rule that a setting
extending another starts with its name, sorting away from the family it
belongs to; uniting the three rather than renaming one follows what the
registries settings did. The remote tier's `organization` becomes `org`,
which is what pnpr calls that namespace and what its endpoints are built
from.
Both spellings shipped in pacquet 12.0.0 but in no released pnpm 11, so
the TypeScript side is a free rename and only pacquet needs the aliases.
Every older spelling keeps working. Precedence is per field rather than
per section, and does not depend on key order: the two spellings
accumulate separately, `organization` is resolved to `org` per source,
and they are combined once after every source has been read. The Rust
side uses an explicit field rather than a serde alias, which would make a
file carrying both keys a duplicate-field parse error.
Two behaviours move toward pacquet, which already had them right:
`sideEffectsCacheReadonly` blocks writing, and setting it alongside
`sideEffectsCache: false` gives a read-only view rather than switching
the cache off. The declaration can also express writing without reading,
which the Rust `cache`/`readonly` pair had no spelling for, so `Config`
gained the two settings its helpers now prefer.
Registries do not all lay out tarball URLs the way the npm registry does.
JFrog Artifactory repeats the scope in a scoped package's tarball filename
(`@acme/widget/-/@acme/widget-1.0.0.tgz`) where npm strips it. pnpm cannot
rebuild such a URL, so it writes it out for every scoped package instead of
omitting it, and the lockfile carries a host-specific URL per dependency.
pnpm had no place to record such a fact, because it had no place to
describe a registry at all — only three ways to name one. `registries`
mapped a scope to a URL, `namedRegistries` mapped a bare-specifier prefix
to a URL, and neither could carry anything else.
`registries` now declares a registry once, keyed by its URL, with every
fact about it in the entry: a `serverType`, the `scopes` routed to it,
and the `prefix` it answers to. `serverType` has three states:
undeclared strict; only the exact canonical URL is reconstructible
npm also serves the percent-encoded scoped path
artifactory repeats the scope in the tarball filename
registry.npmjs.org resolves to `npm` as a built-in, so its behavior is
unchanged and the old hostname check becomes that one default rather than a
special case in the predicate. `npm` cannot be the default: asserting
npmjs-compatibility is a claim only the operator can make.
The URL is the key because every fact in an entry is a fact about that
server. Keying the layout by scope would bind it to whoever the scope
currently points at, so two developers whose scope resolves differently
would write lockfiles that disagree about which URLs may be omitted.
`scopes` and `prefix` are routes to the registry and are inverted at
config-read time into the two lookups the rest of pnpm already queries,
leaving the resolver, installer, and lockfile layers untouched and the
precedence chain (builtin < .npmrc < yaml < `_auth` < CLI) unchanged.
The layout is declared, never inferred. Sniffing the registry URL cannot work:
a virtual repository serves both layouts at once, depending on whether each
package was synced from upstream or published locally, so no registry-level
signal — route, response header, or probe — decides it. Declaring it also
keeps a wrong guess a fixable misconfiguration instead of a silent breakage.
`serverType` feeds a single URL builder that both sides of the lockfile use:
the writer omits a tarball URL only when the builder reproduces it, and the
reader rebuilds it with the same call. They therefore agree by construction,
so pnpm never has to assume a registry serves some second URL as well.
The setting lives in pnpm-workspace.yaml rather than .npmrc because the
lockfile depends on it: one developer omitting URLs that another reconstructs
differently would break a frozen install. A `serverType` in the global
config.yaml is ignored for the same reason, while the routes declared
alongside it are kept. Credentials are rejected there — the file is
committed — and still belong in .npmrc. The registry URL is the map key, so
the request-destination env gate applies to keys as well as values.
Credentials and unknown fields are refused after parsing, since a parse
error renders the offending source line verbatim.
A map whose values are all strings is the older `<scope>: <url>` shape and
is still read as one. Mixing the two shapes in one map is refused, and so is
a URL-keyed entry written as a string. `namedRegistries` is deprecated in
favor of `prefix` and is read only for prefixes `registries` does not
declare; a prefix stays singular because it is the registry's identity in a
lockfile dep path.
An entry that routes nothing to itself and matches no configured registry is
reported as a warning rather than silently ignored; it is a warning and not
an error because a shared config dependency can legitimately describe
registries a given project does not use.
Config dependencies and pnpr-server-mode resolution pass no server type; in
both, the writer and the reader share that default, so they stay consistent.
Closespnpm/get-npm-tarball-url#16. Supersedes pnpm/pnpm#13920.
The first node shim run in a project pinning a runtime through
devEngines.runtime took ~650ms even when the exact version was already
in the store. ~530ms of that was network, re-downloading immutable and
already-verified release metadata: a cold index.json fetch during
pre-save specifier normalization, a second index.json fetch in the
resolver, the SHASUMS256.txt + signature fetch, and a cold connection to
unofficial-builds.nodejs.org for the musl SHASUMS.
Two changes, mirrored in both stacks:
- Exact stable-release specifiers (runtime:22.23.2) skip the release
index: the specifier is its own resolution and existence is proven by
the asset-list fetch. When that fetch fails, the index is consulted
after the fact so a nonexistent version still raises
ERR_PNPM_NODEJS_VERSION_NOT_FOUND. The pacquet-only pre-save
normalization takes the same shortcut.
- Per-version SHASUMS256.txt bodies are cached under
<cacheDir>/v11/runtime-shasums/<host>/<url path>. The URLs are
version-pinned and immutable; signed bodies are cached only after
their OpenPGP signature verified, and a cached body is trusted like
the registry metadata mirror (no re-verification on read). Both
stacks share the layout.
With a warm store, the first shim run drops from ~650ms to ~100ms — the
remainder is materializing the runtime tree into the global virtual
store — and no longer needs the network at all.
Closespnpm/pnpm#13899.
Both utilities lived in the pnpm/components Bit workspace, where their
component names collide with same-named components elsewhere in the Bit
registry. Move the code here and publish it under new names:
`@pnpm/util.lex-comparator` -> `@pnpm/text.ordinal-comparator`
`@pnpm/config.nerf-dart` -> `@pnpm/config.registry-auth-key`
The new names describe what the utilities do: the comparator is ordinal
rather than locale-aware, and the mapped URL is the key that registry
settings are stored under in `.npmrc`. The exported functions keep their
names, so consumers only change their import specifiers.
Implementations and tests are carried over unchanged. The rationale from
the components' docs pages moves into doc comments: why `localeCompare`
cannot be used for values compared across machines, and where `nerfDart`
originates.
No pacquet counterpart is needed. The Rust stack has its own
implementations of both and no user-visible behavior changes.
Remove the legacy repository changelog files now that release changelog storage defaults to the registry. The publish path composes and injects CHANGELOG.md into release tarballs, so keeping historical copies in source control duplicates generated release data.
Update adm-zip to the patched 0.6 release and override vulnerable transitive versions after the dependency audit began rejecting versions below 0.6.0.
`pnpm runtime set <name> <version> -g` now installs the runtime
(Node/Deno/Bun) into the global packages directory and links its binary
into the global bin directory, matching the TypeScript pnpm CLI. It
previously errored with a "not supported yet" stub.
The `<name>@runtime:<version>` selector is routed through the existing
global-add pipeline. The wrinkle: pacquet's manifest writer folds a
`runtime:<version>` dependency into `engines.runtime` on save, so a
globally-installed runtime lands under `engines.runtime` with an empty
`dependencies` map. The global scanner and bin-linker read `dependencies`,
so without a fix they would link no binary. The global crate now reifies
`engines.runtime` / `devEngines.runtime` back into dependencies when
reading a group manifest — the same conversion the package manifest
reader already applies — so an installed runtime is treated as the direct
dependency it is. `list -g`, `remove -g`, and `update -g` therefore see
it too.
The TypeScript pnpm CLI already ships this feature, so this brings pacquet
to parity and needs no TypeScript change; pacquet crates are unpublished,
so no changeset is required.
Normalize blank and whitespace-only runtime selectors consistently in pnpm and pacquet.
The runtime command can produce `runtime:` when no version is provided, and hand-edited manifests may contain whitespace-only selectors. Treat those cases as `latest` in the TypeScript runtime resolvers, the pacquet runtime resolvers, and the manifest conversion helpers.
Also make manifest writeback reject malformed dependency fields before pruning managed runtime entries. This prevents a non-object dependency field from being interpreted as a removed runtime dependency and causing silent data loss during save.
The TypeScript pnpm CLI freezes at v11; pnpm 12 will be the Rust pacquet
port. To make that split legible, all TypeScript source, test, and build
directories move under a new top-level pnpm11/ directory. The name states
the version boundary rather than implying a behavioral fork, since the two
stacks are meant to behave identically.
Scope is source-only: the shared workspace root stays at the repo root.
pnpm-workspace.yaml, package.json, pnpm-lock.yaml, .pnpmfile.cjs,
.meta-updater, __patches__, .changeset, .husky, and the lint/spell configs
remain in place, so one pnpm workspace and one Cargo workspace still span
all three products. pnpr/client and pacquet/tasks/registry-mock stay as
cross-product workspace members.
Rewiring the move required:
- pnpm-workspace.yaml globs prefixed with pnpm11/
- root package.json script paths, eslint.config.mjs, tsconfig.lint.json,
.gitignore, and CODEOWNERS updated
- .meta-updater/src/index.ts literals repointed (pnpm11/pnpm/package.json,
pnpm11/__utils__, pnpm11/__typings__, and the main package directory)
- regenerated every moved package's repository/homepage URL via meta-updater
- pnpm11/pnpm/bundle-deps.ts and __utils__/scripts/src/typecheck-only.ts
climb one more level to reach the repo root
.meta-updater stays at the repo root because @pnpm/meta-updater resolves
its config at <cwd>/.meta-updater/main.mjs.
TS CI (.github/workflows/ci.yml) now only runs when pnpm11/-relevant paths
change, via a dorny/paths-filter changes job plus a TS CI / Success
aggregate gate; branch protection should require only that gate.