Files
pnpm/pnpm11
C. Spencer Beggs 252f15e583 fix(resolver): stop hoisted peers from ignoring the declared peer range (#12932)
When deduplicating a missing peer onto the workspace's preferred
versions, hoistPeers matched candidates against '*' unless the wanted
range was an exact version. In a multi-importer workspace,
allPreferredVersions aggregates versions from every importer, so a peer
declared as ^1.0.0 inside one importer's closure could be auto-installed
as a 2.x resolved for another importer, silently producing a peer graph
that mixes incompatible majors. This survived pnpm/pnpm#12847 (which
fixed the single-importer case in resolvePeers) and is independent of
the pnpm/pnpm#12921 deadlock fix: the wrong version is chosen upstream
of peer resolution, during peer hoisting.

Both stacks now dedupe onto the highest preferred version that
satisfies the wanted range and fall back to resolving the range from
the registry when no candidate satisfies it. Non-semver specifiers
(workspace:, npm: aliases, dist-tags) keep the dedupe-to-highest
behavior.

Fixing this exposed a pacquet-only divergence the old behavior masked:
resolve_peers indexed a node's children into ParentRefs only by their
install alias, so an npm-alias child could never provide a peer under
its real package name below the importer level, and the binding fell
through to the importer-level hoisted entry. Descent-time children are
now indexed by both alias and real name, matching resolvePeers.ts.

Measured on the multi-importer reproduction: 46 poisoned snapshots on
pnpm 11.11.0, 0 with this change, in both the TypeScript CLI and
pacquet.

Additionally, hoistPeers now binds the same peer on a re-resolve with
an existing lockfile as on a fresh install of the same manifest: root
dependencies reused from the lockfile skip full resolution and were
invisible to the workspace-root branch of the hoist, so the picked
version depended on whether a lockfile was present. The root-dep table
falls back to the importer's wanted specifiers, and its entry type is
narrowed to HoistableRootDep — the fields hoistPeers reads, matching
the Rust port's WorkspaceRootDep.

Related to pnpm/pnpm#12847 and pnpm/pnpm#12921.

---------

Signed-off-by: C. Spencer Beggs <spencer@beggs.codes>
Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-07-11 11:17:21 +02:00
..
2026-07-04 21:05:03 +02:00
2026-07-09 22:29:10 +02:00
2026-07-09 22:29:10 +02:00
2026-06-23 17:16:24 +02:00
2026-07-09 22:29:10 +02:00
2026-06-23 17:16:24 +02:00
2026-07-04 21:05:03 +02:00
2026-07-09 22:29:10 +02:00
2026-07-09 22:29:10 +02:00
2026-06-23 17:16:24 +02:00
2026-07-09 22:29:10 +02:00
2026-07-09 22:29:10 +02:00
2026-07-04 21:05:03 +02:00