Commit Graph
67 Commits
Author SHA1 Message Date
Zoltan Kochanandgithub-actions[bot] 91774e72a0 chore(release): 11.28.7, pacquet 12.15.0, pnpr 0.1.0-alpha.16 (#17187)
* 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>
2026-10-21 12:15:12 +02:00
Zoltan Kochan 85cd31b9e5 feat(pnpr): settle Section A production readiness requirements (#17112)
Complete production-readiness requirements for pnpr Section A.

- Persisted-document format versions: introduce formatVersion to packuments,
  OCI images, crate documents, and state journals, rejecting documents written
  by newer format versions.
- CLI surface grammar: support `pnpr serve` subcommand, and add parse_cli_interval
  for duration units (s/m/h/d) on --packument-ttl, --min-age, and --max-age.
- Strict config validation: reject unknown fields, disallow removed configuration
  blocks, and normalize field naming across config and CLI flags.
- Client protocol versioning: add capability handshake at /-/pnpr, v0 resolve
  and publish endpoints, policy echo in done frames, and structured error codes.
- Distribution improvements: add Node.js fallback wrapper, fix engines range,
  and package tini in pnpr Docker container.

Relates to pnpm/tasks#131.
2026-10-19 09:20:12 +02:00
Zoltan Kochan 7b0d6873a6 feat: pin tar hashes with lockfile.integrityTarget and address revisions by tar digest (#17092)
lockfile.integrityTarget: tar makes the integrity of every package tarball
entry the hash of its uncompressed tar, recorded as settings.integrityTarget.
The lockfile then survives a registry recompressing its tarballs, switching
to tar resources, or being replaced by a mirror that does either. A lockfile
recorded under another target is stale: a frozen install fails with
ERR_PNPM_LOCKFILE_CONFIG_MISMATCH, and any other install re-resolves with
update-checksums semantics so no hash of the old kind carries forward. The
setting is opt-in and the lockfile version is unchanged.

The tarball crate now reports both hashes of every extraction: the resource
after content decoding, and the tar a .tgz decodes to. A pin names one of
them (IntegrityKind::Resource / Tar), or either at resolution, where a locked
or published integrity may be of either kind (ResourceOrTar, sha512 only).
Under a tar pin every gzip member is decoded and nothing may follow the tar.
The resource pin keeps today's behaviour, extracting the first member and
tolerating trailing data, but then records no tar.

Store rows extracted from a .tgz record tarIntegrity and get an alias under
the tar key, in a table pnpm v11 never reads. Store lookups follow aliases,
so a tar-pinned frozen install is served offline by a store that .tgz
installs populated, and resolution takes a version's tar hash from its row
before downloading anything.

Registry revisions now always pin their tar, revision 0 included, and are
fetched with a tar pin, so the digest route can use any content coding.
Revision metadata must list revision 0 and the selected revision, and a
digest-route URL without a revision is rejected. pnpr keys its digest
references by tar hash on every registry format, serves the route as a
negotiated tar resource, and projects revision 0 explicitly. pnpm v11 cannot
extract tar resources, so it now rejects revisions with
ERR_PNPM_REGISTRY_REVISIONS_UNSUPPORTED.

Implements pnpm/rfcs text/0000-tar-integrity-for-every-source.md and
pnpm/rfcs#42.
2026-10-18 17:36:30 +02:00
Zoltan Kochan cb31e127a0 docs(pnpr): remove stale duplicated docs and fix drifted claims (#16926)
* docs(pnpr): remove stale duplicated docs and fix drifted claims

The crate README and OIDC.md under pnpr/crates/pnpr duplicated the website
docs and had drifted: a compilerCaches key that no longer exists, hardcoded
quota numbers, the old registry/ path. The pnpr.client README used the
pre-rename remoteSideEffectsCache spellings and claimed the artifact owner
must equal the username. Point both at pnpr/docs instead.

Also fix claims the code contradicts: the handshake is served when any
surface is enabled and advertises ecosystems, publish, and pipeline; the
resolve request field is registries, not namedRegistries; pnpm does not
call the handshake before an npm resolve; there is no config reload; the
packument TTL has no config key; and the --config help still described a
verdaccio-shaped file.

Install instructions now name the next dist-tag, because latest still
points at a July 2026 pre-alpha snapshot.

* docs(pnpr): address review on handshake, verify order, and root-mounted endpoints

* docs(pnpr): document the /npm/ registry bases on multi-ecosystem servers
2026-10-14 12:56:39 +02:00
68112bada4 chore(release): 11.28.5, pacquet 12.10.0 (#16637)
* 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>
2026-10-06 02:00:03 +02:00
5dafb09800 chore(release): 11.28.4, pacquet 12.9.1 (#16567)
* 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>
2026-10-03 22:13:02 +02:00
de9611cf28 chore(release): 11.28.3 (#16444)
* 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>
2026-09-30 16:56:44 +02:00
Zoltan Kochan 4edeef9176 style(ts): port the perfectionist lint rules to ESLint (#16415)
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.
2026-09-30 15:10:08 +02:00
9ce8c2e734 chore(release): 11.28.1, pacquet 12.8.0, pnpr 0.1.0-alpha.14 (#16312)
* 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>
2026-09-28 08:57:31 +02:00
Zoltan Kochan e495640b20 fix(store): share build-created symlinks through the remote side-effects cache (#16249)
pnpm/pnpm#16238 kept build-created symlinks out of the remote
side-effects cache: pnpm v12 did not publish a diff that records one
and rejected an artifact that carries one, and both clients' artifact
validators refused the mode. The guards protected clients that would
restore such an entry as a regular file. No client has shipped the
remote cache, so there is no such client, and builds that create links
were never shared.

Let a remote artifact carry a symlink entry with the shape the local
side-effects diff already uses: the mode carries the S_IFLNK file-type
bits and the blob is the link target. The shared-artifact protocol owns
SYMLINK_MODE, and the store crate re-exports it. The artifact key stays
at v1, because no artifact of the old shape exists outside tests.

Both clients derive a resolved artifact's overlay the way they derive a
persisted store row's, so a link is restored under the same rules or the
artifact is quarantined: pnpm v12 through the store crate's
side_effects_overlay, pnpm v11 through toSideEffectsFilesMap in
@pnpm/store.cafs. The persisted-row blob check accounts for a link's
target blob, which the overlay names by the link rather than by path.

Each reader tells a recorded link apart from a file inside the loop it
already runs over the diff, in both stacks: pnpm v11 feeds a
SideEffectsFilesMapBuilder from its verification, path-mapping and
artifact-hydration loops, and the Rust overlay builder branches on the
mode in its one pass.
2026-09-27 10:34:58 +02:00
kudaliarandHermes Agent b079732099 fix(pnpr): link workspace projects at their publish directory (#15841)
A project that publishes from a subdirectory reached the pnpr server without
its publishConfig, so the server rebuilt the project's package.json as
publishing from its own root: the lockfile recorded no publishDirectory,
dependents linked the project root and served sources instead of the built
directory, and a lockfile written that way failed the next frozen install
with ERR_PNPM_OUTDATED_LOCKFILE.

Send publishConfig.directory (with linkDirectory) with every project from both
clients, pacquet and `@pnpm/pnpr.client`, and keep it in the resolution cache
key so a changed publish directory cannot reuse a cached resolution. The field
stays optional on the wire: a project without a publish directory sends the
body servers already accept, and a server that predates the field ignores it.

Forwarding only fixes installs whose server is upgraded too, so both clients
now also check the returned lockfile the way the project transforms are
checked — an importer the server returns without the requested publish
directory fails the resolve instead of being merged, which is what the issue
asks for when a server cannot honour the setting. An importer the response
does not carry at all is left alone: a partial install only ever merges the
importers that came back.

A publish directory that escapes its project — absolute, drive- or
UNC-bearing, or carrying a `..` component — is rejected among the request's
other refusals, before any resolve path runs, so the new field cannot address
a link target outside the workspace the server resolves in and the frozen fast
path cannot return a lockfile it never checked. The rule rejects escapes only:
a local install accepts `./dist`, so the pnpr path must not fail where it
succeeds.

`@pnpm/pnpr.client` takes a minor changeset because the option joins the public
`ResolveViaPnprServerOptions` surface; the other four packages keep a patch
bump.

resolve_project moves from pnpr_resolution.rs to pnpr_request.rs, next to the
two functions that call it: the new field pushed the former past the
400-code-line file limit the perfectionist dylint enforces.

Related to pnpm/pnpm#14460.

Co-authored-by: Hermes Agent <210416642+0xNoramiya@users.noreply.github.com>
2026-09-27 01:58:25 +02:00
b341f5ada2 chore(release): 11.28.0, pacquet 12.7.0, pnpr 0.1.0-alpha.13 (#15647)
* 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>
2026-09-25 12:01:04 +02:00
Altay b3d4aad89b fix(pnpr): install the peer dependencies of a peer-only project (#15577)
The pnpr resolve request carried only dependencies, devDependencies,
and optionalDependencies, so the server synthesized importer manifests
without peerDependencies. Under autoInstallPeers the local install
expects those peers in the importer, so a peer-only project resolved
to an empty importer: the v12 frozen link failed with
ERR_PNPM_OUTDATED_LOCKFILE, and v11 linked without the peers.

Both clients now send peerDependencies and the server writes them
into the synthesized manifest, the resolution cache key, the fetchable
spec validation, and the frozen fast-path manifest check. The Rust
client omits an empty map, so the request body is unchanged for
projects without peers.

Closes pnpm/pnpm#14833
2026-09-25 01:05:11 +02:00
Zoltan Kochanandgithub-actions[bot] 201f9fc51f chore(release): 11.27.1 (#15185)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-20 23:11:14 +02:00
Zoltan Kochanandgithub-actions[bot] b62f5b004f chore(release): 11.27.0 (#14856)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-12 12:01:04 +02:00
Zoltan Kochan f00e7680aa chore(release): 11.26.0 (#14638) 2026-09-07 01:30:44 +02:00
Zoltan Kochan 6d90c71efd chore(release): 11.25.0, pacquet 12.1.0, pnpr 0.1.0-alpha.9 (#14306) 2026-08-29 15:50:36 +02:00
Zoltan Kochan 7dc607a15d revert(artifacts): drop shared artifact lockfile pins (#14319)
pnpm/pnpm#14243 recorded every verified shared build artifact's envelope
digest in the consuming package snapshot, keyed by input key, artifact
owner, and consumer platform fingerprint. Reproducibility is now enforced
by the registry instead: a published artifact occupies a write-once slot
per input key and compatibility set, so the digest a lockfile would have
pinned is the only one that entry can ever serve.

That makes the pins pure lockfile churn. They were per-machine — a
platform fingerprint only the machines sharing it could write — so a
lockfile grew an entry per package, per owner, and per platform in the
team, and no two contributors produced the same diff.

Remove the `artifactPins` snapshot field, the `pnpm update
--build-artifacts` mode that rewrote it, and the pin plumbing through
resolution, materialization, and the pnpr client in both stacks. Stored
artifacts are still reverified against current trust, policy, platform,
and source before reuse; that check now reports a verdict rather than
returning the digest that fed a pin.

The feature was never released, so no changeset records its removal.

Related to pnpm/pnpm#13771.
2026-08-29 13:04:46 +02:00
Zoltan Kochan 8aa1e35ace feat: unite the side-effects cache settings into one declaration (#14285)
`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.
2026-08-28 21:51:36 +02:00
Zoltan Kochan 75f7a1fd94 feat(artifacts): generalize shared artifact subjects (#14267)
The shared-artifact protocol encoded package identity and source integrity at the top level of every candidate and signed payload. That shape could only represent dependency side effects, even though task caching is designed to reuse the same transport and trust model.

Move those fields into a discriminated subject shared by the Rust and TypeScript implementations. Dependency artifacts retain their package and source integrity, while workspace-task artifacts identify a workspace-relative project and task. Validate each subject against its artifact kind, input-key domain, and allowed owner type, and include the subject in pnpr's entry identity and candidate matching.

This intentionally changes the experimental wire format, so pnpr servers and clients must be upgraded together.

Related to pnpm/rfcs#22.
2026-08-28 12:18:26 +02:00
Zoltan Kochan e972cb5012 feat: support macOS and Windows shared build artifacts (#14263)
Teach the shared-artifact protocol to recognize additive v1 Darwin and Windows tags that encode architecture, Node major, and a minimum operating-system version.

Select exact supported tags before version floors, then choose the greatest compatible floor and keep universal artifacts as the final fallback. Detect macOS product versions with the absolute system `sw_vers` path and Windows NT kernel versions with the platform APIs. Enable restoration and publishing on Darwin and Windows x64 and arm64.

Implement the same protocol, fingerprints, selection, and host-detection behavior in the TypeScript CLI and pacquet. Keep all existing Linux tags and fingerprints stable.

Related to pnpm/pnpm#13771 and pnpm/rfcs#24.
2026-08-28 03:00:08 +02:00
Zoltan Kochan d6061d8f83 feat: persist verified remote build artifacts (#14259)
Persist the signed origin metadata for hydrated remote build artifacts in each package's store-index row. This lets later installs reuse a verified artifact without contacting pnpr, while preserving enough evidence to reevaluate the artifact under the consumer's current trust configuration.

Before reuse, verify the envelope signature, signer, owner, package identity, source integrity, input key, compatibility constraints, lockfile pin, builder profile, manifest-to-diff mapping, and the digest and size of every stored CAS blob. Remote entries do not pass through the ordinary local side-effects-cache path when this verification is unavailable or fails.

Track trusted invalid manifests and corrupt remote blobs in a bounded per-channel quarantine stored alongside the package index. Keep transient network, server, and local filesystem failures out of quarantine so they can recover normally. Frozen stores may reuse valid persisted artifacts but do not hydrate, persist, or quarantine.

Apply the same behavior and serialized metadata shape to the TypeScript CLI and pacquet.

Related to pnpm/pnpm#13771.
2026-08-28 01:22:37 +02:00
Zoltan Kochan 5dd145394b feat: pin shared build artifacts in the lockfile (#14243)
Persist verified shared build artifact envelope digests in the package snapshot
that consumed them. Scope each pin by dependency input key, artifact owner, and
consumer platform so compatible variants remain independently reproducible.

Apply pins only after the existing trust and compatibility checks. A missing
pinned artifact is a remote-cache miss and falls back to a local build; frozen
installs enforce pins without mutating the wanted lockfile.

Add `pnpm update --build-artifacts` as an explicit update mode that clears
existing pins, forces materialization, and records only artifacts that complete
verification and hydration without changing package versions. Reject command
combinations that cannot safely write or verify the lockfile.

Implement the lockfile format, install plumbing, update mode, and tests in both
TypeScript pnpm and pacquet.

Related to pnpm/pnpm#13771.
2026-08-27 23:08:19 +02:00
Zoltan Kochan d278429ba9 refactor: give the artifact blob digest one name and one guard (#14241)
Two leftovers from pnpm/pnpm#14189, both behaviour-neutral.

`artifactBlobDigest` was a pass-through around a private `blobId` that did
the actual work, so the digest had two names and the doc comment sat on
neither the definition nor every call site. There is now one exported
function; the three call sites that only wanted the integrity validated
call it and discard the result, as they did before under the other name.

The restore's store lookup tested `!downloaded.contains_key` and then the
download below tested it again, so a reader had to hold both in mind to see
that the lookup only runs when the bytes are not already in memory. Folding
the lookup into the download's own branch says it once. `blob_id`'s error is
propagated rather than swallowed by `if let Ok(..)`: the manifest validator
rejects a malformed integrity long before hydration, so this is unreachable,
and a silent fall-through to downloading is a worse way to express that than
a `?`.

Follow-up to pnpm/pnpm#14189.
2026-08-27 18:47:06 +02:00
Zoltan Kochan a83487c2f8 perf: reuse store content when restoring a remote build (#14189)
Reuse store content when restoring a remote build.

A remote side-effects restore downloaded every file of the artifact, then handed the bytes to the store, which addresses content by the very digest the artifact manifest already carries. A built package's files are mostly its own, and artifacts share files with one another, so most of what was transferred was content the store already had.

Ask the store first. `locateFileInStore` answers with the path it holds for a digest and mode, or nothing, and the restore only fetches what is missing. The store keeps executable and non-executable content apart, so the mode is part of the question.

Nothing is trusted that was not trusted before: the store addresses content by its hash, so a file it holds under an artifact's digest is that artifact's bytes.

The pacquet side already had the store helper this needs; its test pins the part that could silently drift — a digest or executable-bit rule diverging between the write side and the artifact side would not fail anything, it would just make the lookup always miss.

Follow-up to pnpm/pnpm#14171.
2026-08-27 18:11:52 +02:00
Zoltan Kochan e322d08690 fix(pnpr): reclaim orphaned shared artifact blobs (#14232)
Ambiguous object-store failures can commit a shared-artifact blob while returning an error. Conservatively retaining the reserved quota prevents limit bypasses, but can permanently charge storage that no committed envelope references.

Register each publication in the conditionally written quota document before it reads or creates immutable objects. When an ambiguous failure marks reclamation as necessary, let one replica acquire a token after all active publications drain. The token blocks new publications while the collector derives reachability from stored envelopes, removes unreferenced blobs, rescans physical usage, and atomically replaces the quota state. Preserve the retry marker when collection fails, retry transient cleanup failures from live requests, jitter conditional-write backoff, and retain the documented quiesced quota-reset procedure for registrations or tokens left by terminated processes.

Also synchronize the recursive-run bail summary regression with bounded marker waits so it deterministically exercises recording a task that was in flight when another task failed without risking a hung test.

On Windows, a competing `create_dir` can report `AccessDenied` while the prior lock directory is delete-pending. Retry that platform-specific transient error within the caller's wait and a one-second release budget, while continuing to report persistent permission failures.

Related to pnpm/pnpm#14220.
2026-08-27 16:55:59 +02:00
Zoltan Kochan bff7a17261 fix(pnpr): retain quota after ambiguous artifact writes (#14228)
Object-store write errors do not prove that a create-only write failed. A
backend can commit an artifact and then return a transport error, so releasing
that object reservation can make the quota counter smaller than physical
storage.

Retain quota for every attempted object on non-conflict errors while still
releasing the reservation for later, unattempted objects. This deliberately
prefers conservative overcounting to allowing the storage limits to be
exceeded. Document the recovery procedure and cover both pre-commit and
post-commit failure paths.

Follow-up to pnpm/pnpm#14222.
2026-08-27 15:29:54 +02:00
Zoltan Kochan 6632c9acc1 feat(pnpr): scale shared artifact storage horizontally (#14222)
Promote the signed shared-artifact service from a resolver sub-feature to an independent pnpr surface, allowing artifact-only deployments.

Use the configured object store for immutable artifact blobs and envelopes. Coordinate the durable quota counter with conditional writes so concurrent replicas cannot lose updates, while retaining the existing local cache layout and a small local quota lock for filesystem deployments. Apply the protocol's variant bound while resolving instead of serializing publishers.

Closes pnpm/pnpm#14220.
2026-08-27 15:01:52 +02:00
Zoltan Kochan 83350dea56 feat: integrate the remote side-effects cache with install (#14171)
Integrate the remote side-effects cache proof of concept with dependency installation in both TypeScript pnpm and pacquet.

Plan eligible build candidates before contacting pnpr, batch lookup requests, verify the configured P-256 trust keys and artifact integrity, hydrate verified files into CAFS, and select the restored side-effects map before lifecycle scripts run. Fall back to the ordinary local build on all cache failures.

Configure the feature through the remoteSideEffectsCache setting, assembled by the config reader from the workspace file, the global config file and the environment. A repository declares which organization and packages are eligible and nothing else: everything describing the act of signing stays with the machine holding the key, so a cloned repository cannot turn that key into a signing oracle.

Capture and publish the actual post-build diff from trusted builders. Bound artifact hydration and blob downloads, retain CAFS paths instead of downloaded buffers, and withhold direct store writes from a store opened read-only. Add transactional owner and global storage accounting to pnpr alongside request, response, timeout, streaming-memory, manifest, variant, descriptor, lock-namespace, concurrency, and crash-residue bounds.

Keep the proof of concept organization-scoped and Linux glibc-only. Defer lockfile pinning, persistent quarantine, publisher ownership, and key lifecycle policy to the RFC.

Related to pnpm/rfcs#20.
2026-08-26 15:49:39 +02:00
Zoltan Kochan 0ec67d0fcf feat: refresh registry revisions through pnpr (#14180)
Allow revision-only updates to delegate dependency resolution to pnpr.

Carry updatePatches across both pnpr clients and map it server-side to pacquet's RefreshRevisions seed policy. Explicit refreshes bypass frozen reuse and pnpr's whole-resolution cache, while the registry resolver revalidates metadata even when its in-memory or disk cache is warm.

Route both pnpm implementations through their existing pnpr install and materialization paths. The Rust update command accepts --pnpr-server, and partial TypeScript workspace refreshes continue locally so unselected importers are not refreshed.

Follow-up to https://github.com/pnpm/pnpm/pull/14175.
Related to https://github.com/pnpm/rfcs/pull/19.
2026-08-26 12:29:51 +02:00
Zoltan Kochan 6b521cdc32 fix: preserve patches and package extensions with pnpr (#14181)
The pnpr resolution protocol omitted patchedDependencies and packageExtensions. Its fast path therefore returned an untransformed lockfile, while bypassing pnpr for these projects would sacrifice the remote-resolution performance the setting exists to provide.

Compute patch hashes on the client and send only the ordered selector-to-hash map to pnpr. The server uses those hashes to key patched snapshots in the lockfile, while the client retains the local paths and applies the patch files during materialization. Send package extensions and unused-patch policy alongside them so pnpr resolves the same transformed dependency graph as local resolution.

Key pnpr's interned configuration and resolution cache by the forwarded transforms, validate patch digests at the protocol boundary, and scan package-extension dependency URLs through the existing fetch allowlist and inline-credential checks. Implement the protocol in both TypeScript and Rust clients and cover it with live server-to-client tests. Both clients validate the returned transform metadata so older servers that ignore the new request fields fail with a stable protocol error instead of silently returning an untransformed lockfile. pnpr advertises transform support in the HTTP response headers, allowing the Rust client to validate compatibility before consuming any package frames. Current servers retain streaming prefetch performance; older servers fail before they can trigger downloads or unbounded hint buffering.

Fixes pnpm/pnpm#14177.
2026-08-26 12:23:10 +02:00
Zoltan Kochanandgithub-actions[bot] e3cb54258c chore(release): 11.24.0, pacquet 12.0.0-rc.10 (#14134)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-24 15:53:03 +02:00
Zoltan Kochanandgithub-actions[bot] 726d6b4a04 chore(release): 11.23.0 (#14111)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-23 15:47:36 +02:00
Zoltan Kochan 6261b7f388 fix(pnpr): resolve in the client's resolutionMode (#13958)
A resolve request carried the client's `minimumReleaseAge` and
`trustPolicy` but not its `resolutionMode`, and `intern_config` never
set `config.resolution_mode`, so every pnpr-delegated resolve ran on the
server's `highest` default. A project configured for `time-based` or
`lowest-direct` got a lockfile pinning the highest satisfying version of
everything, with nothing to show that the setting had been dropped.

The mode now travels with the request and reaches the interned config,
which is what `PickPolicy::from_config` reads on the server side. It
also joins both cache keys — the interned-config key and the resolution
cache key — so two modes can neither share a config nor replay each
other's resolution.

`VerifyLockfileOptions` deliberately does not carry it: verification
judges an existing lockfile against the client's policy and picks no
version.
2026-08-17 13:31:24 +02:00
Edward LongandZoltan Kochan c5fadf15d6 fix(pnpr): forward client resolver settings (#13730)
Source the fallback for an omitted setting from the config's own
defaults rather than a hardcoded copy of them, and restore the
rationale for gating the input-lockfile fallback on a frozen request.

Send the three settings inline like every other optional field of the
resolve request: the server reads an explicit null the same as an
absent key, so the manual inserts bought nothing.

Give the resolver settings their own forwarding test instead of
folding them into the verification-policy one.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-08-17 10:45:33 +02:00
Zoltan Kochan c9b8632ea6 feat(config): declare each registry once in the registries setting (#13942)
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.

Closes pnpm/get-npm-tarball-url#16. Supersedes pnpm/pnpm#13920.
2026-08-17 01:28:21 +02:00
Zoltan Kochanandgithub-actions[bot] 93fcba4224 chore(release): 11.22.0, pacquet 12.0.0-rc.6 (#13926)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-15 18:50:30 +02:00
Zoltan Kochanandgithub-actions[bot] 8adb97ed05 chore(release): 11.21.0, pacquet 12.0.0-rc.2 (#13742)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-09 16:02:53 +02:00
Zoltan Kochanandgithub-actions[bot] ebc48abdc5 chore(release): 11.20.0, pacquet 12.0.0-beta.4 (#13608)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-03 15:48:54 +02:00
Zoltan Kochan 536b7a2c8a chore(release): 11.19.0 (#13524) 2026-07-31 10:46:26 +02:00
Zoltan Kochanandgithub-actions[bot] 925c33d780 chore(release): 11.18.0, pacquet 12.0.0-beta.0 (#13481)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-29 09:29:53 +02:00
Zoltan Kochan 089ebad918 fix(pnpr): send the full request both clients owe the server (policy, catalogs, resolution mode) (#13279)
pnpr resolves and enforces policy server-side, and neither client runs its own
verifyLockfileResolutions when a pnpr server is configured. The server assigns
each field from the request unconditionally, so a field a client omits is cleared
rather than defaulted, and the server resolves under inputs the user never chose.

The TypeScript client sent only minimumReleaseAge of the verification policy, so
minimumReleaseAgeExclude entries stopped applying and the input-lockfile verifier
could reject a lockfile whose entries the user had explicitly excluded. It also
never sent the resolution mode, so --frozen-lockfile silently resolved and rewrote
the lockfile it promises to leave alone.

pacquet never sent catalogs, so every catalog: specifier failed to resolve — the
bug #13233 fixed for the TypeScript client and the server, leaving the Rust client
behind.

Drop the TRUST_POLICY_INCOMPATIBLE_WITH_PNPR guard, written before the server
gained trust-policy enforcement and refusing an install pacquet runs happily.
2026-07-25 10:56:36 +02:00
Zoltan Kochanandgithub-actions[bot] 454e7d62b3 chore(release): 11.17.0, pacquet 12.0.0-alpha.19, pnpr 0.1.0-alpha.5 (#13237)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-23 17:07:05 +02:00
Zoltan Kochan c3c3e6b643 fix: resolve catalog references when installing via a pnpr server (#13233)
A `catalog:` specifier in a workspace's dependencies or overrides failed to
resolve when the install was routed through a pnpr server, erroring with
"No catalog entry '<name>' was found for catalog 'default'." even though the
catalog entry existed.

The pnpr server reconstructs the requested workspace in a temp dir from the
resolve request. That reconstruction wrote a pnpm-workspace.yaml with only a
packages: section and no catalog definitions, and passed catalogs_override:
None to the install — so the server had no catalogs and could not resolve any
catalog: specifier, in dependencies or overrides.

Forward the client's workspace catalogs in the resolve request and use them as
the install's catalogs_override, which feeds both dependency and override
catalog resolution. The client now sends its raw overrides (the server resolves
their catalog: references) instead of pre-resolving them locally.

Closes pnpm/pnpm#13232
2026-07-23 16:04:43 +02:00
Zoltan Kochanandgithub-actions[bot] d1edab423e chore(release): 11.16.0, pacquet 12.0.0-alpha.18 (#13216)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-22 21:58:38 +02:00
Zoltan Kochanandgithub-actions[bot] 32a30c4d70 chore(release): 11.15.0, pacquet 12.0.0-alpha.15, pnpr 0.1.0-alpha.4 (#13126)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-18 14:19:57 +02:00
Zoltan Kochan f4948525df chore: remove repository changelogs (#13119)
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.
2026-07-18 13:10:25 +02:00
YES!HYUNGSEOKandZoltan Kochan 9657c883bf fix(pacquet): honor workspace install filters (#13030)
Pacquet's recursive command pipeline previously dispatched selected projects independently or lost the selection before package-manager execution. This could overwrite earlier manifest mutations, truncate workspace lockfile state, or materialize projects outside the requested filter.

Thread one workspace selection through command dispatch and package-manager execution, batch manifest mutations into a single install, retain the complete wanted lockfile, and derive current-lockfile and node_modules state from the selected dependency closure. Apply the same workspace root and selection semantics to query, state, global, deploy, and pnpr-backed paths.

Keep full-workspace recursive installs on the ordinary unfiltered fast and frozen paths, and add regression coverage for filtering, lockfile preservation, dependency closure materialization, pnpr multi-importer responses, and TypeScript parity edge cases.

Depends on pnpm/pnpm#13016.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-07-18 13:06:37 +02:00
Zoltan Kochanandgithub-actions[bot] f8b08ea63f chore(release): 11.14.0, pacquet 12.0.0-alpha.14 (#13113)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-18 00:01:20 +02:00
Zoltan Kochanandgithub-actions[bot] 682f57e773 chore(release): 11.13.0, pacquet 12.0.0-alpha.9, pnpr 0.1.0-alpha.1 (#12986)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-13 22:19:04 +02:00