@pnpm/engine.pm.commands 1101.1.2 → 1101.1.4

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.
@@ -6,6 +6,7 @@ import { parsePackageManager, types as allTypes } from '@pnpm/config.reader';
6
6
  import { PnpmError } from '@pnpm/error';
7
7
  import { createResolver } from '@pnpm/installing.client';
8
8
  import { resolvePackageManagerIntegrities } from '@pnpm/installing.env-installer';
9
+ import { readEnvLockfile } from '@pnpm/lockfile.fs';
9
10
  import { globalInfo, globalWarn } from '@pnpm/logger';
10
11
  import { whichVersionIsPinned } from '@pnpm/resolving.npm-resolver';
11
12
  import { createStoreController } from '@pnpm/store.connection-manager';
@@ -51,6 +52,12 @@ export async function handler(opts, params) {
51
52
  globalInfo('Checking for updates...');
52
53
  const { resolve } = createResolver({ ...opts, configByUri: opts.configByUri });
53
54
  const pkgName = 'pnpm';
55
+ // `pnpm self-update` (no args) defaults to the `latest` dist-tag, but we
56
+ // refuse to downgrade in that case — `latest` on the registry can lag the
57
+ // installed version when a new major has shipped without being tagged.
58
+ // `pnpm self-update latest` (explicit) bypasses the guard so users can
59
+ // still force a downgrade when they want one.
60
+ const isImplicitLatest = params.length === 0;
54
61
  const bareSpecifier = params[0] ?? 'latest';
55
62
  const resolution = await resolve({ alias: pkgName, bareSpecifier }, {
56
63
  lockfileDir: opts.lockfileDir ?? opts.dir,
@@ -87,6 +94,15 @@ export async function handler(opts, params) {
87
94
  }
88
95
  if (opts.wantedPackageManager?.name === packageManager.name) {
89
96
  if (opts.wantedPackageManager?.version !== resolution.manifest.version) {
97
+ if (isImplicitLatest) {
98
+ // Prefer the lockfile-pinned version when available — for range
99
+ // specs like `>=8.0.0`, the spec's lower bound understates the
100
+ // version that was actually installed (see #11418 review).
101
+ const projectCurrentVersion = await readProjectPinnedPnpmVersion(opts.rootProjectManifestDir, opts.wantedPackageManager?.version);
102
+ if (projectCurrentVersion != null && semver.lt(resolution.manifest.version, projectCurrentVersion)) {
103
+ return `The current project is set to use pnpm v${projectCurrentVersion}, which is newer than the "latest" version on the registry (v${resolution.manifest.version}). No update performed. Run "pnpm self-update latest" to downgrade.`;
104
+ }
105
+ }
90
106
  const { manifest, writeProjectManifest } = await readProjectManifest(opts.rootProjectManifestDir);
91
107
  if (manifest.devEngines?.packageManager) {
92
108
  let manifestChanged = false;
@@ -143,6 +159,9 @@ export async function handler(opts, params) {
143
159
  if (resolution.manifest.version === packageManager.version) {
144
160
  return `The currently active ${packageManager.name} v${packageManager.version} is already "${bareSpecifier}" and doesn't need an update`;
145
161
  }
162
+ if (isImplicitLatest && semver.lt(resolution.manifest.version, packageManager.version)) {
163
+ return `The currently active ${packageManager.name} v${packageManager.version} is newer than the "latest" version on the registry (v${resolution.manifest.version}). No update performed. Run "pnpm self-update latest" to downgrade.`;
164
+ }
146
165
  globalInfo(`Updating pnpm from v${packageManager.version} to v${resolution.manifest.version}...`);
147
166
  const store = await createStoreController(opts);
148
167
  // Resolve integrities and write env lockfile to pnpm-lock.yaml
@@ -196,4 +215,32 @@ function versionSpecFromPinned(version, pinnedVersion) {
196
215
  case 'patch': return version;
197
216
  }
198
217
  }
218
+ async function readProjectPinnedPnpmVersion(rootProjectManifestDir, spec) {
219
+ // The env lockfile is the most accurate source for the actually-installed
220
+ // pnpm version when the spec is a range. Fall back to the spec's minimum
221
+ // version when there's no lockfile entry (e.g. exact `packageManager` pins
222
+ // below v12 don't write to the lockfile). Take the max of the two so we
223
+ // pick whichever signal is more restrictive.
224
+ let lockfilePinned;
225
+ try {
226
+ const envLockfile = await readEnvLockfile(rootProjectManifestDir);
227
+ lockfilePinned = envLockfile?.importers['.'].packageManagerDependencies?.pnpm?.version;
228
+ }
229
+ catch {
230
+ // ignore — fall through to spec min version
231
+ }
232
+ let specMin;
233
+ if (spec != null) {
234
+ try {
235
+ specMin = semver.minVersion(spec)?.version;
236
+ }
237
+ catch {
238
+ // invalid range — ignore
239
+ }
240
+ }
241
+ if (lockfilePinned != null && specMin != null) {
242
+ return semver.gt(lockfilePinned, specMin) ? lockfilePinned : specMin;
243
+ }
244
+ return lockfilePinned ?? specMin;
245
+ }
199
246
  //# sourceMappingURL=selfUpdate.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/engine.pm.commands",
3
- "version": "1101.1.2",
3
+ "version": "1101.1.4",
4
4
  "description": "pnpm commands for self-updating and setting up pnpm",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -32,25 +32,26 @@
32
32
  "render-help": "^2.0.0",
33
33
  "semver": "^7.7.2",
34
34
  "symlink-dir": "^10.0.1",
35
- "@pnpm/bins.linker": "1100.0.2",
36
- "@pnpm/building.policy": "1100.0.1",
37
- "@pnpm/cli.meta": "1100.0.1",
38
- "@pnpm/cli.utils": "1101.0.1",
39
- "@pnpm/config.reader": "1101.1.2",
40
- "@pnpm/global.commands": "1100.0.7",
35
+ "@pnpm/bins.linker": "1100.0.3",
36
+ "@pnpm/building.policy": "1100.0.2",
37
+ "@pnpm/cli.meta": "1100.0.2",
38
+ "@pnpm/config.reader": "1101.1.4",
39
+ "@pnpm/deps.graph-hasher": "1100.1.2",
41
40
  "@pnpm/error": "1100.0.0",
42
- "@pnpm/installing.client": "1100.0.6",
43
- "@pnpm/global.packages": "1100.0.1",
44
- "@pnpm/installing.deps-restorer": "1101.0.2",
45
- "@pnpm/installing.env-installer": "1101.0.2",
46
- "@pnpm/resolving.npm-resolver": "1101.0.0",
47
- "@pnpm/lockfile.types": "1100.0.2",
48
- "@pnpm/deps.graph-hasher": "1100.1.1",
49
- "@pnpm/shell.path": "1100.0.0",
50
- "@pnpm/store.controller": "1101.0.1",
41
+ "@pnpm/cli.utils": "1101.0.2",
42
+ "@pnpm/global.commands": "1100.0.9",
43
+ "@pnpm/installing.client": "1100.0.8",
44
+ "@pnpm/global.packages": "1100.0.2",
45
+ "@pnpm/installing.deps-restorer": "1101.0.4",
46
+ "@pnpm/installing.env-installer": "1101.0.3",
47
+ "@pnpm/lockfile.fs": "1100.0.4",
48
+ "@pnpm/lockfile.types": "1100.0.3",
49
+ "@pnpm/shell.path": "1100.0.1",
50
+ "@pnpm/store.connection-manager": "1100.0.9",
51
+ "@pnpm/store.controller": "1101.0.2",
51
52
  "@pnpm/types": "1101.0.0",
52
- "@pnpm/store.connection-manager": "1100.0.7",
53
- "@pnpm/workspace.project-manifest-reader": "1100.0.2"
53
+ "@pnpm/workspace.project-manifest-reader": "1100.0.3",
54
+ "@pnpm/resolving.npm-resolver": "1101.0.1"
54
55
  },
55
56
  "peerDependencies": {
56
57
  "@pnpm/logger": ">=1001.0.0 <1002.0.0"
@@ -60,12 +61,12 @@
60
61
  "@types/cross-spawn": "^6.0.6",
61
62
  "@types/ramda": "0.31.1",
62
63
  "@types/semver": "7.7.1",
63
- "@pnpm/error": "1100.0.0",
64
- "@pnpm/engine.pm.commands": "1101.1.2",
65
64
  "@pnpm/constants": "1100.0.0",
65
+ "@pnpm/engine.pm.commands": "1101.1.4",
66
+ "@pnpm/error": "1100.0.0",
66
67
  "@pnpm/logger": "1100.0.0",
67
- "@pnpm/prepare": "1100.0.3",
68
- "@pnpm/testing.mock-agent": "1100.0.1"
68
+ "@pnpm/prepare": "1100.0.4",
69
+ "@pnpm/testing.mock-agent": "1100.0.2"
69
70
  },
70
71
  "engines": {
71
72
  "node": ">=22.13"