@pnpm/installing.deps-installer 1102.1.0 → 1102.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,7 +19,7 @@ import { extendProjectsWithTargetDirs, headlessInstall } from '@pnpm/installing.
19
19
  import { readModulesManifest, writeModulesManifest } from '@pnpm/installing.modules-yaml';
20
20
  import { cleanGitBranchLockfiles, getWantedLockfileName, isEmptyLockfile, readEnvLockfile, readWantedLockfile, readWantedLockfileFile, writeCurrentLockfile, writeEnvLockfile, writeLockfiles, writeWantedLockfile, } from '@pnpm/lockfile.fs';
21
21
  import { getPreferredVersionsFromLockfileAndManifests } from '@pnpm/lockfile.preferred-versions';
22
- import { calcPatchHashes, createOverridesMapFromParsed, getOutdatedLockfileSetting, } from '@pnpm/lockfile.settings-checker';
22
+ import { calcPatchHashes, createOverridesMapFromParsed, getOutdatedLockfileSetting, resolvePatchedDependencies, } from '@pnpm/lockfile.settings-checker';
23
23
  import { PACKAGE_MAP_FILENAME, writePackageMap, writePnpFile } from '@pnpm/lockfile.to-pnp';
24
24
  import { allProjectsAreUpToDate, satisfiesPackageManifest } from '@pnpm/lockfile.verification';
25
25
  import { globalInfo, logger, streamParser } from '@pnpm/logger';
@@ -399,20 +399,17 @@ export async function mutateModules(projects, maybeOpts) {
399
399
  }
400
400
  const packageExtensionsChecksum = hashObjectNullableWithPrefix(opts.packageExtensions);
401
401
  const pnpmfileChecksum = await opts.hooks.calculatePnpmfileChecksum?.();
402
+ const resolvedPatchedDeps = resolvePatchedDependencies(opts.patchedDependencies, opts.lockfileDir);
402
403
  const patchedDependencies = opts.ignorePackageManifest
403
404
  ? ctx.wantedLockfile.patchedDependencies
404
- : (opts.patchedDependencies ? await calcPatchHashes(opts.patchedDependencies) : {});
405
- const patchGroupInput = opts.patchedDependencies
405
+ : (resolvedPatchedDeps ? await calcPatchHashes(resolvedPatchedDeps) : {});
406
+ const patchGroupInput = resolvedPatchedDeps
406
407
  ? Object.fromEntries(Object.entries(patchedDependencies ?? {}).map(([key, hash]) => {
407
- let patchFilePath = opts.patchedDependencies[key]
408
- ? path.resolve(opts.lockfileDir, opts.patchedDependencies[key])
409
- : undefined;
408
+ let patchFilePath = resolvedPatchedDeps[key];
410
409
  if (!patchFilePath) {
411
410
  const lastAt = key.lastIndexOf('@');
412
411
  const pkgName = lastAt > 0 ? key.slice(0, lastAt) : key;
413
- if (opts.patchedDependencies[pkgName]) {
414
- patchFilePath = path.resolve(opts.lockfileDir, opts.patchedDependencies[pkgName]);
415
- }
412
+ patchFilePath = resolvedPatchedDeps[pkgName];
416
413
  }
417
414
  return [key, { hash, patchFilePath }];
418
415
  }))
@@ -1069,10 +1066,23 @@ const _installInContext = async (projects, ctx, opts) => {
1069
1066
  prefix: ctx.lockfileDir,
1070
1067
  stage: 'resolution_started',
1071
1068
  });
1072
- const update = projects.some((project) => project.update);
1073
- const preferredVersions = opts.preferredVersions ?? (!update
1074
- ? getPreferredVersionsFromLockfileAndManifests(ctx.wantedLockfile.packages, Object.values(ctx.projects).map(({ manifest }) => manifest))
1075
- : undefined);
1069
+ // Always seed preferred versions from the lockfile, even for update
1070
+ // mutations. Gating this on `update` (the previous behavior) nullified
1071
+ // the seed globally during `pnpm up -r <pkg>`, so unrelated packages
1072
+ // with open ranges lost their pins and re-resolved to newest-in-range
1073
+ // (pnpm/pnpm#10662). The targeted package still bumps: `updateRequested`
1074
+ // at the npm picker subtracts the lockfile-derived weight from its pins,
1075
+ // so the target re-resolves exactly as a fresh install would after its
1076
+ // lockfile entries were deleted.
1077
+ // Caller-supplied preferred versions (audit-fix vulnerability penalties)
1078
+ // layer on top of the seed per package name — replacing the seed with
1079
+ // them would unpin every unrelated package.
1080
+ // Null-prototype merge target so a crafted package name (e.g. `__proto__`)
1081
+ // lands as a plain own key instead of invoking the prototype setter.
1082
+ const preferredVersions = Object.assign(Object.create(null), getPreferredVersionsFromLockfileAndManifests(ctx.wantedLockfile.packages, Object.values(ctx.projects).map(({ manifest }) => manifest)));
1083
+ for (const [pkgName, selectors] of Object.entries(opts.preferredVersions ?? {})) {
1084
+ preferredVersions[pkgName] = { ...preferredVersions[pkgName], ...selectors };
1085
+ }
1076
1086
  const forceFullResolution = ctx.wantedLockfile.lockfileVersion !== LOCKFILE_VERSION ||
1077
1087
  !opts.currentLockfileIsUpToDate ||
1078
1088
  opts.force ||
@@ -2043,12 +2053,11 @@ async function installViaPnprServer(manifest, rootDir, opts, allInstallProjects)
2043
2053
  throw new PnpmError('TRUST_POLICY_INCOMPATIBLE_WITH_PNPR', 'The pnpr server does not yet enforce `trustPolicy: no-downgrade`, so running an install through it under this policy would produce a lockfile that the local verifier rejects.', { hint: 'Unset `trustPolicy` for this install, or disable the pnpr server (unset `--pnpr-server` / `pnprServer` in pnpm-workspace.yaml) so resolution runs locally and the trust check applies.' });
2044
2054
  }
2045
2055
  const { resolveViaPnprServer } = await import('@pnpm/pnpr.client');
2046
- const { createGetAuthHeaderByURI, getAuthHeadersByScope, getAuthHeadersFromCreds } = await import('@pnpm/network.auth-header');
2047
- // Forward the whole credential map (the registries a graph touches
2048
- // aren't known up front), so the server attaches the right token per
2049
- // URL. `authorization` also identifies the caller to pnpr's gate.
2056
+ const { createGetAuthHeaderByURI } = await import('@pnpm/network.auth-header');
2057
+ // Identify the caller to pnpr's gate. The client does not forward its
2058
+ // upstream registry credentials: pnpr selects upstream credentials from
2059
+ // its own route policy, so they never travel in the request body.
2050
2060
  const configByUri = opts.configByUri ?? {};
2051
- const forwardedAuthHeaders = getAuthHeadersFromCreds(configByUri);
2052
2061
  const pnprAuthorization = createGetAuthHeaderByURI(configByUri)(opts.pnprServer);
2053
2062
  try {
2054
2063
  const lockfileDir = opts.lockfileDir ?? rootDir;
@@ -2079,7 +2088,6 @@ async function installViaPnprServer(manifest, rootDir, opts, allInstallProjects)
2079
2088
  projects: projectsList,
2080
2089
  registry: opts.registries?.default,
2081
2090
  namedRegistries: opts.namedRegistries,
2082
- authHeaders: getAuthHeadersByScope(forwardedAuthHeaders),
2083
2091
  authorization: pnprAuthorization,
2084
2092
  overrides: opts.overrides,
2085
2093
  minimumReleaseAge: opts.minimumReleaseAge,
@@ -205,6 +205,10 @@ function buildVerificationError(violations) {
205
205
  const details = omitted > 0
206
206
  ? `${breakdown}\n …and ${omitted} more`
207
207
  : breakdown;
208
+ // Registry fetch failures (auth/network/5xx) don't reach this batch — the
209
+ // verifier throws the registry's own error and the gate aborts with it. So
210
+ // every violation here is a genuine policy rejection, and the hint points at
211
+ // the lockfile rather than at connectivity.
208
212
  return new PnpmError(errorCode, `${violations.length} lockfile entries failed verification:\n${details}`, {
209
213
  hint: 'The lockfile contains entries that the active policies reject. ' +
210
214
  'This can mean the lockfile is stale, or that someone committed a ' +
@@ -346,22 +350,41 @@ function pushInvalidAliases(deps, invalid) {
346
350
  }
347
351
  async function iterateLockfileViolations(candidates, verifiers, concurrency) {
348
352
  const violations = [];
353
+ // A verifier may throw rather than return a violation when it can't reach the
354
+ // registry to verify an entry (auth/network/5xx) — that's not a per-entry
355
+ // policy pick, it's an incomplete verification, so the registry's own error
356
+ // should abort the install. Capture the first such error and rethrow it after
357
+ // the fan-out settles: rethrowing straight into Promise.all would leave the
358
+ // sibling tasks (all failing against the same dead registry) as unhandled
359
+ // rejections once Promise.all rejects on the first.
360
+ let fetchError;
349
361
  const limit = pLimit(concurrency ?? DEFAULT_CONCURRENCY);
350
362
  await Promise.all(Array.from(candidates.values(), ({ name, version, nonSemverVersion, resolution }) => limit(async () => {
351
- // Fan out across every active verifier; each handles its own
352
- // protocol short-circuit (e.g. the npm verifier returns ok:true for
353
- // git resolutions). We stop at the first failure per entry so a
354
- // multi-verifier setup doesn't produce duplicate violations for the
355
- // same (name, version).
356
- for (const verifier of verifiers) {
357
- // eslint-disable-next-line no-await-in-loop
358
- const result = await verifier.verify(resolution, { name, version, nonSemverVersion });
359
- if (!result.ok) {
360
- violations.push({ name, version, resolution, code: result.code, reason: result.reason });
361
- break;
363
+ try {
364
+ // Fan out across every active verifier; each handles its own
365
+ // protocol short-circuit (e.g. the npm verifier returns ok:true for
366
+ // git resolutions). We stop at the first failure per entry so a
367
+ // multi-verifier setup doesn't produce duplicate violations for the
368
+ // same (name, version).
369
+ for (const verifier of verifiers) {
370
+ // eslint-disable-next-line no-await-in-loop
371
+ const result = await verifier.verify(resolution, { name, version, nonSemverVersion });
372
+ if (!result.ok) {
373
+ violations.push({ name, version, resolution, code: result.code, reason: result.reason });
374
+ break;
375
+ }
362
376
  }
363
377
  }
378
+ catch (err) {
379
+ fetchError ??= err;
380
+ }
364
381
  })));
382
+ // A registry that couldn't be reached takes precedence over collected
383
+ // violations: the run never finished verifying, so the batch is incomplete
384
+ // and the actionable failure is the transport error. Once it's resolved the
385
+ // re-run surfaces any remaining violations.
386
+ if (fetchError != null)
387
+ throw fetchError;
365
388
  return violations;
366
389
  }
367
390
  //# sourceMappingURL=verifyLockfileResolutions.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/installing.deps-installer",
3
- "version": "1102.1.0",
3
+ "version": "1102.2.0",
4
4
  "description": "Fast, disk space efficient installation engine",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -30,9 +30,9 @@
30
30
  "funding": "https://opencollective.com/pnpm",
31
31
  "repository": {
32
32
  "type": "git",
33
- "url": "https://github.com/pnpm/pnpm/tree/main/installing/deps-installer"
33
+ "url": "https://github.com/pnpm/pnpm/tree/main/pnpm11/installing/deps-installer"
34
34
  },
35
- "homepage": "https://github.com/pnpm/pnpm/tree/main/installing/deps-installer#readme",
35
+ "homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/installing/deps-installer#readme",
36
36
  "bugs": {
37
37
  "url": "https://github.com/pnpm/pnpm/issues"
38
38
  },
@@ -65,62 +65,62 @@
65
65
  "ramda": "npm:@pnpm/ramda@0.28.1",
66
66
  "run-groups": "^5.0.0",
67
67
  "semver": "^7.8.4",
68
- "@pnpm/bins.linker": "1100.0.15",
69
- "@pnpm/building.after-install": "1102.0.1",
70
- "@pnpm/building.during-install": "1102.0.1",
71
- "@pnpm/building.policy": "1100.0.10",
72
- "@pnpm/catalogs.config": "1100.0.1",
68
+ "@pnpm/bins.remover": "1100.0.12",
69
+ "@pnpm/building.during-install": "1102.0.3",
70
+ "@pnpm/bins.linker": "1100.0.16",
71
+ "@pnpm/building.policy": "1100.0.11",
73
72
  "@pnpm/catalogs.protocol-parser": "1100.0.0",
74
- "@pnpm/catalogs.resolver": "1100.0.0",
73
+ "@pnpm/catalogs.config": "1100.0.2",
74
+ "@pnpm/building.after-install": "1102.0.3",
75
75
  "@pnpm/config.matcher": "1100.0.1",
76
+ "@pnpm/catalogs.types": "1100.0.0",
76
77
  "@pnpm/config.normalize-registries": "1100.0.8",
77
- "@pnpm/config.parse-overrides": "1100.0.1",
78
- "@pnpm/core-loggers": "1100.2.1",
79
78
  "@pnpm/constants": "1100.0.0",
80
- "@pnpm/bins.remover": "1100.0.10",
81
- "@pnpm/deps.graph-hasher": "1100.2.5",
82
- "@pnpm/catalogs.types": "1100.0.0",
79
+ "@pnpm/config.parse-overrides": "1100.0.2",
80
+ "@pnpm/core-loggers": "1100.2.1",
81
+ "@pnpm/crypto.hash": "1100.0.1",
83
82
  "@pnpm/crypto.object-hasher": "1100.0.0",
84
83
  "@pnpm/deps.graph-sequencer": "1100.0.0",
85
84
  "@pnpm/deps.path": "1100.0.8",
86
- "@pnpm/error": "1100.0.0",
87
- "@pnpm/exec.lifecycle": "1100.1.0",
85
+ "@pnpm/error": "1100.0.1",
86
+ "@pnpm/exec.lifecycle": "1100.1.2",
87
+ "@pnpm/hooks.read-package-hook": "1100.0.9",
88
88
  "@pnpm/fs.read-modules-dir": "1100.0.1",
89
- "@pnpm/fs.symlink-dependency": "1100.0.10",
90
- "@pnpm/hooks.types": "1100.0.12",
91
- "@pnpm/installing.context": "1100.0.19",
92
- "@pnpm/installing.deps-resolver": "1100.2.4",
93
- "@pnpm/crypto.hash": "1100.0.1",
94
- "@pnpm/installing.deps-restorer": "1102.1.0",
95
- "@pnpm/installing.linking.hoist": "1100.0.15",
96
- "@pnpm/installing.linking.modules-cleaner": "1100.1.8",
97
- "@pnpm/installing.package-requester": "1102.0.0",
89
+ "@pnpm/installing.context": "1100.0.21",
90
+ "@pnpm/catalogs.resolver": "1100.0.0",
91
+ "@pnpm/deps.graph-hasher": "1100.2.7",
92
+ "@pnpm/installing.deps-resolver": "1100.2.6",
93
+ "@pnpm/installing.deps-restorer": "1102.1.2",
98
94
  "@pnpm/installing.linking.direct-dep-linker": "1100.0.10",
95
+ "@pnpm/installing.linking.modules-cleaner": "1100.1.10",
96
+ "@pnpm/hooks.types": "1100.1.1",
97
+ "@pnpm/installing.package-requester": "1102.1.1",
99
98
  "@pnpm/installing.modules-yaml": "1100.0.9",
100
- "@pnpm/lockfile.filtering": "1100.1.7",
101
- "@pnpm/lockfile.preferred-versions": "1100.0.16",
102
- "@pnpm/lockfile.fs": "1100.1.6",
103
- "@pnpm/lockfile.pruner": "1100.0.11",
104
- "@pnpm/lockfile.to-pnp": "1100.1.0",
105
- "@pnpm/lockfile.verification": "1100.0.19",
106
- "@pnpm/lockfile.settings-checker": "1100.0.19",
107
- "@pnpm/lockfile.utils": "1100.0.13",
108
- "@pnpm/network.auth-header": "1101.1.2",
109
- "@pnpm/patching.config": "1100.0.8",
110
- "@pnpm/pkg-manifest.utils": "1100.2.5",
111
- "@pnpm/pnpr.client": "1.2.2",
112
- "@pnpm/resolving.resolver-base": "1100.4.2",
113
- "@pnpm/store.controller-types": "1100.1.5",
99
+ "@pnpm/lockfile.filtering": "1100.1.9",
100
+ "@pnpm/lockfile.preferred-versions": "1100.0.18",
101
+ "@pnpm/lockfile.pruner": "1100.0.13",
102
+ "@pnpm/lockfile.settings-checker": "1100.1.0",
103
+ "@pnpm/installing.linking.hoist": "1100.0.16",
104
+ "@pnpm/lockfile.utils": "1100.1.1",
105
+ "@pnpm/lockfile.verification": "1100.0.21",
106
+ "@pnpm/network.auth-header": "1101.1.3",
107
+ "@pnpm/lockfile.walker": "1100.0.13",
108
+ "@pnpm/patching.config": "1100.0.9",
109
+ "@pnpm/lockfile.fs": "1100.1.8",
110
+ "@pnpm/fs.symlink-dependency": "1100.0.10",
111
+ "@pnpm/pkg-manifest.utils": "1100.2.6",
112
+ "@pnpm/resolving.resolver-base": "1100.5.1",
114
113
  "@pnpm/resolving.parse-wanted-dependency": "1100.0.1",
114
+ "@pnpm/store.controller-types": "1100.1.7",
115
115
  "@pnpm/types": "1101.3.2",
116
- "@pnpm/workspace.project-manifest-reader": "1100.0.13",
117
- "@pnpm/hooks.read-package-hook": "1100.0.8",
118
- "@pnpm/lockfile.walker": "1100.0.11",
119
- "@pnpm/store.index": "1100.2.0"
116
+ "@pnpm/pnpr.client": "1.3.0",
117
+ "@pnpm/store.index": "1100.2.1",
118
+ "@pnpm/lockfile.to-pnp": "1100.1.2",
119
+ "@pnpm/workspace.project-manifest-reader": "1100.0.14"
120
120
  },
121
121
  "peerDependencies": {
122
122
  "@pnpm/logger": "^1100.0.0",
123
- "@pnpm/worker": "^1100.2.1"
123
+ "@pnpm/worker": "^1100.2.3"
124
124
  },
125
125
  "devDependencies": {
126
126
  "@jest/globals": "30.4.1",
@@ -141,22 +141,22 @@
141
141
  "symlink-dir": "^10.0.1",
142
142
  "write-json-file": "^7.0.0",
143
143
  "write-yaml-file": "^6.0.0",
144
- "@pnpm/assert-project": "1100.0.16",
145
- "@pnpm/installing.deps-installer": "1102.1.0",
146
- "@pnpm/assert-store": "1100.0.16",
147
- "@pnpm/lockfile.types": "1100.0.11",
144
+ "@pnpm/assert-project": "1100.0.18",
145
+ "@pnpm/assert-store": "1100.0.18",
146
+ "@pnpm/lockfile.types": "1100.0.13",
147
+ "@pnpm/installing.deps-installer": "1102.2.0",
148
148
  "@pnpm/logger": "1100.0.0",
149
- "@pnpm/prepare": "1100.0.16",
150
- "@pnpm/store.cafs": "1100.1.10",
151
- "@pnpm/pkg-manifest.reader": "1100.0.8",
152
- "@pnpm/store.path": "1100.0.1",
153
- "@pnpm/test-ipc-server": "1100.0.0",
154
- "@pnpm/test-fixtures": "1100.0.0",
149
+ "@pnpm/pkg-manifest.reader": "1100.0.9",
155
150
  "@pnpm/network.git-utils": "1100.0.2",
156
- "@pnpm/testing.mock-agent": "1101.0.3",
151
+ "@pnpm/prepare": "1100.0.18",
152
+ "@pnpm/test-fixtures": "1100.0.0",
153
+ "@pnpm/store.path": "1100.0.2",
154
+ "@pnpm/store.cafs": "1100.1.12",
155
+ "@pnpm/test-ipc-server": "1100.0.0",
156
+ "@pnpm/testing.temp-store": "1100.1.12",
157
157
  "@pnpm/resolving.registry.types": "1100.1.3",
158
- "@pnpm/testing.temp-store": "1100.1.10",
159
- "@pnpm/testing.registry-mock": "1100.0.6"
158
+ "@pnpm/testing.mock-agent": "1101.0.4",
159
+ "@pnpm/testing.registry-mock": "1100.0.8"
160
160
  },
161
161
  "engines": {
162
162
  "node": ">=22.13"