pnpm 12.2.1 → 12.3.1
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.
- package/CHANGELOG.md +108 -0
- package/bin/pnpm.mjs +6 -3
- package/dist/node_modules/.pnpm-workspace-state-v1.json +6 -6
- package/install.js +53 -12
- package/native-binary.mjs +32 -6
- package/package.json +10 -9
- package/pnpm +21 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,113 @@
|
|
|
1
1
|
# pnpm
|
|
2
2
|
|
|
3
|
+
## 12.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Sped up installs in large workspaces: the anchor for re-rendering workspace `link:` targets is now derived once per project instead of once per dependency edge, and project ordering hashes paths by their raw bytes [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
8
|
+
|
|
9
|
+
- After a self-update from pnpm 12.2 to 12.3, global commands such as `node`, `npm`, and `yarn` failed with `unexpected argument '--shim' found`. Global commands now launch normally, and their first launch migrates the global bin directory to native shims. When self-update downgrades to pnpm 12.2 or older, it keeps the newer native shims so those commands continue to work.
|
|
10
|
+
|
|
11
|
+
- Sped up installs in large workspaces. The check that verifies each project against the lockfile now runs the projects in parallel [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
12
|
+
|
|
13
|
+
## 12.3.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- Every context-aware global command (`node`, `deno`, `bun`, and the shims created with `pnpm shim add`) is now a native executable on every platform, so environment variables whose names are not valid shell identifiers reach these commands. On Windows, `<name>.exe` replaces the `.cmd` and `.ps1` shims for them. Shims written by earlier pnpm 12 releases are migrated on the next global install or self-update.
|
|
18
|
+
|
|
19
|
+
- `pnpm remove` and `pnpm update` now accept `--trust-lockfile`, `--no-trust-lockfile`, `--trust-policy`, `--trust-policy-exclude` and `--trust-policy-ignore-after`, the same flags `pnpm install` and `pnpm add` take, so the supply-chain settings can be overridden for a single run. `pnpm remove` verifies the lockfile against the active policies the way `pnpm install` does, and `--trust-lockfile` skips that pass for every entry, not only the package being removed.
|
|
20
|
+
|
|
21
|
+
`pnpm` now also honors `--config.trust-lockfile=<value>`, and accepts the bare `--trust-lockfile` / `--no-trust-lockfile` spelling on the commands that previously took the setting from the config file alone.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- `pnpm add <local directory>`, `pnpm add <local tarball>`, `pnpm add file:<path>` and `pnpm add <tarball URL>` work again. A specifier given without a `<name>@` prefix is no longer read as a registry package name and rejected with `ERR_PNPM_PACKAGE_MANAGER_ADD_RESOLVE_LATEST` [#14437](https://github.com/pnpm/pnpm/issues/14437).
|
|
26
|
+
|
|
27
|
+
- Fixed `pnpm deploy --legacy` ignoring `allowUnusedPatches` supplied through `--config.allow-unused-patches` or the `PNPM_CONFIG_ALLOW_UNUSED_PATCHES` environment variable [pnpm/pnpm#14450](https://github.com/pnpm/pnpm/issues/14450).
|
|
28
|
+
|
|
29
|
+
- Fixed `pnpm install --lockfile-only` writing a lockfile that referenced a missing peer-suffixed snapshot when an npm-aliased dependency took part in a cyclic peer dependency graph. The following `pnpm install --frozen-lockfile` failed with `ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY` [#14449](https://github.com/pnpm/pnpm/issues/14449).
|
|
30
|
+
|
|
31
|
+
- `pnpm config` now accepts `-g`/`--global`, `--location`, and `--json` before its subcommand [pnpm/pnpm#14421](https://github.com/pnpm/pnpm/issues/14421).
|
|
32
|
+
|
|
33
|
+
- `pnpm dedupe` now converges in one pass when it re-resolves a lockfile created by pnpm 11, so a second run no longer changes the lockfile [#14455](https://github.com/pnpm/pnpm/issues/14455).
|
|
34
|
+
|
|
35
|
+
- Fixed detached child processes being terminated on Windows when another program launches `pnpm` directly, without a shell, as `nr` from `@antfu/ni` does [#14447](https://github.com/pnpm/pnpm/issues/14447).
|
|
36
|
+
|
|
37
|
+
- Fixed `pnpm docs <package>@<version>` ignoring the requested version. It now opens the selected version's homepage and reports a missing version instead of opening the package-level homepage [pnpm/pnpm#14428](https://github.com/pnpm/pnpm/issues/14428).
|
|
38
|
+
|
|
39
|
+
- Sped up installs in large workspaces. `pnpm-lock.yaml` is now read while the workspace projects are being discovered [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
40
|
+
|
|
41
|
+
- Fixed filtered and recursive `pnpm run` and `pnpm exec` hanging when a script reads from the terminal. Interactive prompts work again in a script that pnpm never runs alongside another one, such as a single `--filter`ed project, `--workspace-concurrency=1`, a dependency chain, or a task declaring `concurrency: 1` [#14397](https://github.com/pnpm/pnpm/issues/14397).
|
|
42
|
+
|
|
43
|
+
- Fixed false unmet peer errors for auto-installed peers in linked workspace packages.
|
|
44
|
+
|
|
45
|
+
- Fixed npm global installs on Windows so the PowerShell shims invoke `pnpm.exe`.
|
|
46
|
+
|
|
47
|
+
- Fixed `pnpm with current <command>` when global options precede it, such as `pnpm --workspace-root with current --version` [pnpm/pnpm#14413](https://github.com/pnpm/pnpm/issues/14413).
|
|
48
|
+
|
|
49
|
+
A short-option cluster that mixes a global flag with an option owned by the command, such as `pnpm -ro dist pack-app`, is now parsed like the same options written after the command.
|
|
50
|
+
|
|
51
|
+
An option written before the command name is now reported as an unknown option unless that command accepts it, instead of being taken for the command to run. `pnpm -P exec echo` and `pnpm -z exec echo` fail the way `pnpm --tag next exec echo` does.
|
|
52
|
+
|
|
53
|
+
- Apply pure insertions in zero-context patches at the correct line instead of one line early.
|
|
54
|
+
|
|
55
|
+
- Improved peer dependency resolution performance when many packages reuse the same peer ranges.
|
|
56
|
+
|
|
57
|
+
- `pnpm outdated` and `pnpm update` now follow local actions and reusable workflows referenced with GitHub's self-repository syntax (`uses: $/.github/actions/setup`) when looking for outdated GitHub Actions, the same way they follow `./` references.
|
|
58
|
+
|
|
59
|
+
- The `pnpm install --help` descriptions of `--prod` and `--dev` no longer claim that the flags take precedence over `NODE_ENV`. pnpm does not read `NODE_ENV` when selecting which dependency groups to install [#14445](https://github.com/pnpm/pnpm/issues/14445).
|
|
60
|
+
|
|
61
|
+
- Sped up installs in large workspaces. The check that decides whether the lockfile needs updating no longer compares every project against every lockfile entry [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
62
|
+
|
|
63
|
+
- Sped up dependency resolution in large workspaces that use `link:` dependencies [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
64
|
+
|
|
65
|
+
- On Linux, pnpm now resolves registry hostnames through the system resolver (`getaddrinfo`), as it already does on macOS and Windows and as pnpm 11 did. Previously, an `/etc/resolv.conf` containing an option the bundled pure-Rust resolver did not recognize, such as `options no_tld_query`, made pnpm ignore the configured nameservers and silently query Google's public DNS instead [#14469](https://github.com/pnpm/pnpm/issues/14469).
|
|
66
|
+
|
|
67
|
+
- Sped up dependency resolution in large workspaces. The resolver builds fewer lookup keys for each dependency [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
68
|
+
|
|
69
|
+
- `catalogMode` and `--save-catalog` no longer move a local path, tarball, or `workspace:<path>` specifier into a catalog. Such a specifier is resolved against the project that declares it, so one catalog entry cannot mean the same directory for every project that references it [#14437](https://github.com/pnpm/pnpm/issues/14437).
|
|
70
|
+
|
|
71
|
+
- Sped up installs in large workspaces. The workspace dependency graph is now built once per run instead of twice [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
72
|
+
|
|
73
|
+
- Sped up writing `pnpm-lock.yaml` in large workspaces [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
74
|
+
|
|
75
|
+
- Fixed non-frozen installs through a pnpr server failing instead of regenerating a conflicted lockfile.
|
|
76
|
+
|
|
77
|
+
- `pnpm update --interactive` renders its checklist the way pnpm 11 does. Group headings and column headers are separators the cursor skips instead of checkboxes that select nothing. The columns of one group line up with the next. `a` toggles all and `i` inverts the selection. The confirmed selection is echoed as a list of package names [#14423](https://github.com/pnpm/pnpm/issues/14423).
|
|
78
|
+
|
|
79
|
+
- Fixed `pnpm config` commands targeting global configuration to skip project package manager version switching, allowing registry authentication to be configured before pnpm downloads a project-pinned version [pnpm/pnpm#14463](https://github.com/pnpm/pnpm/issues/14463).
|
|
80
|
+
|
|
81
|
+
- Fixed pnpm retaining the surrounding quotes in `.npmrc` values, including auth tokens expanded from environment variables. This restores authentication with registries configured using `:_authToken="${TOKEN}"` [pnpm/pnpm#14427](https://github.com/pnpm/pnpm/issues/14427).
|
|
82
|
+
|
|
83
|
+
- Fetch and tarball errors no longer print the secrets of the URL they name. Inline `user:pass@` credentials and the query string or fragment of a signed URL are hidden, so a failed install or `pnpm add <url>` cannot leak them into terminal scrollback or CI logs.
|
|
84
|
+
|
|
85
|
+
- When `dist-tags.latest` names a version whose manifest pnpm cannot read, the error now names that version and the field it could not decode, instead of reporting the tag as empty.
|
|
86
|
+
|
|
87
|
+
- Retry transient Windows file-lock errors, including sharing violations, while linking dependencies with the default (isolated) `nodeLinker`. This fixes [pnpm/pnpm#14407](https://github.com/pnpm/pnpm/issues/14407).
|
|
88
|
+
|
|
89
|
+
- `pnpm run`, `pnpm exec`, `pnpm rebuild`, and the script shortcuts such as `pnpm test` now load the pnpmfile, so `updateConfig` hook settings such as `extraEnv` and `extraBinPaths` reach the scripts they spawn [#14433](https://github.com/pnpm/pnpm/issues/14433).
|
|
90
|
+
|
|
91
|
+
- The `pnpm` executable of the npm package now works when the package was installed without running its install scripts, as under `--ignore-scripts` or the default build-script block of pnpm and Bun [#14346](https://github.com/pnpm/pnpm/issues/14346). In that case it runs through Node.js and, in a terminal, says how to switch to the native binary.
|
|
92
|
+
|
|
93
|
+
- Sped up installs in large workspaces. The resolver no longer copies the whole lockfile before resolving [#14352](https://github.com/pnpm/pnpm/issues/14352).
|
|
94
|
+
|
|
95
|
+
- `minimumReleaseAgeStrict` now defaults to `true` when `minimumReleaseAge` is explicitly configured, whether in `pnpm-workspace.yaml`, the global `config.yaml`, a `PNPM_CONFIG_*` variable, or a CLI flag. The built-in 1440-minute default stays non-strict. Previously an explicit cutoff was treated as non-strict, so immature versions were silently added to `minimumReleaseAgeExclude` instead of being gated with a prompt [#14409](https://github.com/pnpm/pnpm/issues/14409).
|
|
96
|
+
|
|
97
|
+
- Preserve environment variables whose names are not valid shell identifiers when launching Node.js installed by `pnpm runtime set node --global` on Unix [pnpm/pnpm#14417](https://github.com/pnpm/pnpm/issues/14417).
|
|
98
|
+
|
|
99
|
+
- Fixed `pnpm repo` and `pnpm docs` failing to open the Windows browser from WSL [pnpm/pnpm#14467](https://github.com/pnpm/pnpm/issues/14467).
|
|
100
|
+
|
|
101
|
+
- `pnpm link`, `pnpm outdated`, and `pnpm import` now apply pnpmfile `updateConfig` hooks before resolving dependencies.
|
|
102
|
+
|
|
103
|
+
- Fixed standalone installations to preserve the bundled `node-gyp` files used to build native dependencies.
|
|
104
|
+
|
|
105
|
+
- Fixed resolution against registries whose version manifests carry `_npmUser`, `dist.attestations`, `dist.unpackedSize`, `dist.fileCount`, or `peerDependenciesMeta` in a shape npm does not use. Such a version was skipped as though it had never been published, so `pnpm add` could fail with "no version found for the latest tag" even though the registry served it.
|
|
106
|
+
|
|
107
|
+
- `pnpm unpublish` now completes the two-factor authentication a registry asks for instead of failing with `ERR_PNPM_UNAUTHORIZED` while logged in. A 401 that is an OTP challenge starts the web-based authentication flow, or prompts for a classic one-time password. The obtained password is reused by every request of the run [#14464](https://github.com/pnpm/pnpm/issues/14464).
|
|
108
|
+
|
|
109
|
+
- On Windows, pnpm now resolves host names through the system resolver instead of its own DNS client. The built-in client bound a UDP socket for every lookup, which made Windows Defender Firewall ask to allow `pnpm.exe` again after every `pnpm self-update` [#14405](https://github.com/pnpm/pnpm/issues/14405).
|
|
110
|
+
|
|
3
111
|
## 12.2.1
|
|
4
112
|
|
|
5
113
|
### Patch Changes
|
package/bin/pnpm.mjs
CHANGED
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
// `./bin/pnpx.mjs` for every pnpm >=11 (see its `config.json`) and loads them
|
|
4
4
|
// into its own Node.js process, which a native executable cannot be loaded into.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
6
|
+
// The `pnpm` placeholder bin runs it too, when the install script that
|
|
7
|
+
// replaces it with the native binary did not run (build scripts blocked). An
|
|
8
|
+
// ordinary `npm install -g pnpm` never pays for a Node.js startup:
|
|
9
|
+
// `package.json#bin` points at the native binary.
|
|
8
10
|
//
|
|
9
11
|
// Corepack installs no dependencies and runs no lifecycle scripts, so the
|
|
10
12
|
// `@pnpm/exe.<target>` package that carries the binary is absent and
|
|
11
13
|
// `install.js` never ran. The binary is therefore downloaded on first use and
|
|
12
14
|
// kept next to this wrapper — where the native binary also finds the `dist/`
|
|
13
|
-
// payload it ships node-gyp in.
|
|
15
|
+
// payload it ships node-gyp in. The placeholder's installs usually do carry
|
|
16
|
+
// that package, and the binary is taken from there.
|
|
14
17
|
//
|
|
15
18
|
// The download itself is `get-pnpm`, the package behind https://get.pnpm.io,
|
|
16
19
|
// which already knows how to verify one; it travels in that same `dist/`
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"lastValidatedTimestamp":
|
|
2
|
+
"lastValidatedTimestamp": 1788394737104,
|
|
3
3
|
"projects": {
|
|
4
4
|
"/home/runner/_work/pnpm/pnpm/pnpm/npm/pnpm/temp-deploy": {
|
|
5
5
|
"name": "pacquet",
|
|
6
|
-
"version": "12.
|
|
6
|
+
"version": "12.3.1"
|
|
7
7
|
}
|
|
8
8
|
},
|
|
9
9
|
"pnpmfiles": [],
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"@types/write-file-atomic": "^4.0.3",
|
|
88
88
|
"@types/yarnpkg__lockfile": "^1.1.9",
|
|
89
89
|
"@types/zkochan__table": "npm:@types/table@6.3.2",
|
|
90
|
-
"@typescript-eslint/utils": "^8.
|
|
90
|
+
"@typescript-eslint/utils": "^8.69.0",
|
|
91
91
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
92
92
|
"@yarnpkg/core": "4.9.1",
|
|
93
93
|
"@yarnpkg/extensions": "2.0.7",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"escape-string-regexp": "^5.0.0",
|
|
133
133
|
"eslint": "^10.9.1",
|
|
134
134
|
"eslint-plugin-import-x": "^4.17.1",
|
|
135
|
-
"eslint-plugin-jest": "^29.16.
|
|
135
|
+
"eslint-plugin-jest": "^29.16.6",
|
|
136
136
|
"eslint-plugin-n": "^18.3.0",
|
|
137
137
|
"eslint-plugin-promise": "^7.3.0",
|
|
138
138
|
"eslint-plugin-regexp": "^3.1.1",
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
"p-defer": "^4.0.1",
|
|
191
191
|
"p-every": "^2.0.0",
|
|
192
192
|
"p-filter": "^4.1.0",
|
|
193
|
-
"p-limit": "^7.3.
|
|
193
|
+
"p-limit": "^7.3.2",
|
|
194
194
|
"p-queue": "^9.3.3",
|
|
195
195
|
"parse-json": "^8.3.0",
|
|
196
196
|
"parse-npm-tarball-url": "^5.0.0",
|
|
@@ -247,7 +247,7 @@
|
|
|
247
247
|
"tree-kill": "^1.2.2",
|
|
248
248
|
"ts-jest-resolver": "2.0.1",
|
|
249
249
|
"typescript": "6.0.3",
|
|
250
|
-
"typescript-eslint": "^8.
|
|
250
|
+
"typescript-eslint": "^8.69.0",
|
|
251
251
|
"undici": "^7.29.0",
|
|
252
252
|
"unified": "^11.0.5",
|
|
253
253
|
"validate-npm-package-name": "7.0.2",
|
package/install.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Preinstall for the pnpm v12 wrapper (shared verbatim by `pnpm` and
|
|
3
|
-
// `@pnpm/exe`): replace the
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
3
|
+
// `@pnpm/exe`): replace the placeholder bins with the host's native binary so
|
|
4
|
+
// `pnpm` runs directly, no Node startup per call. Package managers write bin
|
|
5
|
+
// shims after preinstall, so the shims are made from the binary; where build
|
|
6
|
+
// scripts are blocked (`--ignore-scripts`, the pnpm/Bun default) the
|
|
7
|
+
// placeholder stays and runs pnpm through Node.js (see the `pnpm` file). npm
|
|
8
|
+
// does not re-read the rewritten `bin` during the same install pass, so on a
|
|
9
|
+
// global Windows install, postinstall asks it to relink.
|
|
8
10
|
//
|
|
9
11
|
// `pn`/`pnpx`/`pnx` are committed `#!/bin/sh` scripts on Unix (so only `pnpm` is
|
|
10
12
|
// relinked); on Windows the native binary is hardlinked onto each and
|
|
@@ -14,6 +16,7 @@
|
|
|
14
16
|
// Corepack runs no lifecycle scripts, so it never gets here; it enters through
|
|
15
17
|
// `bin/pnpm.mjs` instead.
|
|
16
18
|
import console from 'node:console'
|
|
19
|
+
import { spawnSync } from 'node:child_process'
|
|
17
20
|
import fs from 'node:fs'
|
|
18
21
|
import path from 'node:path'
|
|
19
22
|
import process from 'node:process'
|
|
@@ -27,7 +30,11 @@ import {
|
|
|
27
30
|
|
|
28
31
|
const BIN_NAMES = ['pnpm', 'pn', 'pnpx', 'pnx']
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
if (process.env.npm_lifecycle_event === 'postinstall') {
|
|
34
|
+
relinkNpmWindowsShims()
|
|
35
|
+
} else {
|
|
36
|
+
setup()
|
|
37
|
+
}
|
|
31
38
|
|
|
32
39
|
function setup () {
|
|
33
40
|
// The committed manifest has no `optionalDependencies`; generate-packages.mjs
|
|
@@ -93,9 +100,7 @@ function placeBinary (nativeBinary, destPath, mode) {
|
|
|
93
100
|
}
|
|
94
101
|
fs.renameSync(tempPath, destPath)
|
|
95
102
|
} catch (err) {
|
|
96
|
-
|
|
97
|
-
fs.rmSync(tempPath, { force: true })
|
|
98
|
-
} catch {}
|
|
103
|
+
removeFileIfPossible(tempPath)
|
|
99
104
|
fail(`Could not install the pnpm binary at ${destPath}: ${err.message}`)
|
|
100
105
|
}
|
|
101
106
|
}
|
|
@@ -110,9 +115,45 @@ function rewriteBin (binMap) {
|
|
|
110
115
|
fs.writeFileSync(tempPath, JSON.stringify(pkg, null, 2))
|
|
111
116
|
fs.renameSync(tempPath, pkgJsonPath)
|
|
112
117
|
} catch {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
removeFileIfPossible(tempPath)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function relinkNpmWindowsShims () {
|
|
123
|
+
const npmExecPath = process.env.npm_execpath
|
|
124
|
+
if (
|
|
125
|
+
process.platform !== 'win32' ||
|
|
126
|
+
process.env.npm_config_global !== 'true' ||
|
|
127
|
+
npmExecPath == null ||
|
|
128
|
+
path.basename(npmExecPath).toLowerCase() !== 'npm-cli.js'
|
|
129
|
+
) {
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const packageName = readWrapperManifest().name
|
|
134
|
+
if (typeof packageName !== 'string') {
|
|
135
|
+
fail('Could not determine the pnpm wrapper package name when regenerating npm shims.')
|
|
136
|
+
}
|
|
137
|
+
const result = spawnSync(process.execPath, [
|
|
138
|
+
npmExecPath,
|
|
139
|
+
'rebuild',
|
|
140
|
+
'--global',
|
|
141
|
+
'--ignore-scripts',
|
|
142
|
+
packageName,
|
|
143
|
+
], { stdio: 'inherit' })
|
|
144
|
+
if (result.error != null) {
|
|
145
|
+
fail(`Could not regenerate the npm shims for pnpm: ${result.error.message}`)
|
|
146
|
+
}
|
|
147
|
+
if (result.status !== 0) {
|
|
148
|
+
fail('npm could not regenerate the shims for pnpm.')
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function removeFileIfPossible (filePath) {
|
|
153
|
+
try {
|
|
154
|
+
fs.rmSync(filePath, { force: true })
|
|
155
|
+
} catch {
|
|
156
|
+
return
|
|
116
157
|
}
|
|
117
158
|
}
|
|
118
159
|
|
package/native-binary.mjs
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
// (`install.js`), which links it over the placeholder bins, and by the Corepack
|
|
3
3
|
// entry (`bin/pnpm.mjs`), which spawns it.
|
|
4
4
|
import fs from 'node:fs'
|
|
5
|
-
import { createRequire } from 'node:module'
|
|
6
5
|
import path from 'node:path'
|
|
7
6
|
import process from 'node:process'
|
|
8
7
|
import { fileURLToPath } from 'node:url'
|
|
9
8
|
|
|
10
|
-
const require = createRequire(import.meta.url)
|
|
11
9
|
const { platform, arch } = process
|
|
12
10
|
|
|
13
11
|
/** Directory of the published wrapper; the native binary lives next to it. */
|
|
@@ -69,7 +67,14 @@ export function splitBinSpecifier (specifier) {
|
|
|
69
67
|
|
|
70
68
|
/**
|
|
71
69
|
* Path to the native binary of whichever platform package the package manager
|
|
72
|
-
* installed, or `null` when none is present (Corepack,
|
|
70
|
+
* installed with this wrapper, or `null` when none is present (Corepack,
|
|
71
|
+
* `--no-optional`).
|
|
72
|
+
*
|
|
73
|
+
* Only the wrapper's own `node_modules` and the one it was installed into are
|
|
74
|
+
* searched, which is where every package manager puts an optional dependency
|
|
75
|
+
* of the wrapper. A `require` walk would also reach the ancestors' `node_modules`,
|
|
76
|
+
* which belong to whatever project the wrapper sits under and are not to be
|
|
77
|
+
* run in its name.
|
|
73
78
|
*
|
|
74
79
|
* @returns {string | null}
|
|
75
80
|
*/
|
|
@@ -77,13 +82,34 @@ export function resolveInstalledBinary () {
|
|
|
77
82
|
// Use whichever platform package the package manager installed: it already
|
|
78
83
|
// filtered by `os`/`cpu`/`libc`, more reliable than re-deriving the host.
|
|
79
84
|
for (const specifier of getBinCandidates()) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
const { packageName, binFile } = splitBinSpecifier(specifier)
|
|
86
|
+
for (const modulesDir of installedModulesDirs()) {
|
|
87
|
+
const candidate = path.join(modulesDir, ...packageName.split('/'), binFile)
|
|
88
|
+
if (fs.statSync(candidate, { throwIfNoEntry: false })?.isFile() === true) {
|
|
89
|
+
return candidate
|
|
90
|
+
}
|
|
91
|
+
}
|
|
83
92
|
}
|
|
84
93
|
return null
|
|
85
94
|
}
|
|
86
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Where a platform package installed for this wrapper can be: the `node_modules`
|
|
98
|
+
* nested in the wrapper, then the one the wrapper was installed into (two levels
|
|
99
|
+
* up for the scoped `@pnpm/exe`). Neither need exist. Throws only when the
|
|
100
|
+
* wrapper's manifest is unreadable, see {@link readWrapperManifest}.
|
|
101
|
+
*
|
|
102
|
+
* @returns {string[]}
|
|
103
|
+
*/
|
|
104
|
+
function installedModulesDirs () {
|
|
105
|
+
const { name } = readWrapperManifest()
|
|
106
|
+
const segments = typeof name === 'string' ? name.split('/').length : 1
|
|
107
|
+
return [
|
|
108
|
+
path.join(wrapperDir, 'node_modules'),
|
|
109
|
+
path.resolve(wrapperDir, ...Array(segments).fill('..')),
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
|
|
87
113
|
// A successful read with no optionalDependencies is the dev checkout (there is
|
|
88
114
|
// no native binary to link there); a read/parse failure is a corrupt published
|
|
89
115
|
// package and must not be silently swallowed into that same path.
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"./dist/node_modules/node-gyp/gyp/gyp"
|
|
10
10
|
]
|
|
11
11
|
},
|
|
12
|
-
"version": "12.
|
|
12
|
+
"version": "12.3.1",
|
|
13
13
|
"description": "Fast, disk space efficient package manager",
|
|
14
14
|
"keywords": [
|
|
15
15
|
"pnpm",
|
|
@@ -46,17 +46,18 @@
|
|
|
46
46
|
"THIRD-PARTY-NOTICES.md"
|
|
47
47
|
],
|
|
48
48
|
"optionalDependencies": {
|
|
49
|
-
"@pnpm/exe.win32-x64": "12.
|
|
50
|
-
"@pnpm/exe.win32-arm64": "12.
|
|
51
|
-
"@pnpm/exe.darwin-x64": "12.
|
|
52
|
-
"@pnpm/exe.darwin-arm64": "12.
|
|
53
|
-
"@pnpm/exe.linux-x64": "12.
|
|
54
|
-
"@pnpm/exe.linux-arm64": "12.
|
|
55
|
-
"@pnpm/exe.linux-x64-musl": "12.
|
|
56
|
-
"@pnpm/exe.linux-arm64-musl": "12.
|
|
49
|
+
"@pnpm/exe.win32-x64": "12.3.1",
|
|
50
|
+
"@pnpm/exe.win32-arm64": "12.3.1",
|
|
51
|
+
"@pnpm/exe.darwin-x64": "12.3.1",
|
|
52
|
+
"@pnpm/exe.darwin-arm64": "12.3.1",
|
|
53
|
+
"@pnpm/exe.linux-x64": "12.3.1",
|
|
54
|
+
"@pnpm/exe.linux-arm64": "12.3.1",
|
|
55
|
+
"@pnpm/exe.linux-x64-musl": "12.3.1",
|
|
56
|
+
"@pnpm/exe.linux-arm64-musl": "12.3.1"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"preinstall": "node install.js",
|
|
60
|
+
"postinstall": "node install.js",
|
|
60
61
|
"bundle-node-gyp": "node scripts/bundle-node-gyp.mjs"
|
|
61
62
|
}
|
|
62
63
|
}
|
package/pnpm
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// pnpm's native binary replaces this file during installation (see
|
|
3
|
+
// ./install.js). If this is running, that install script did not — build
|
|
4
|
+
// scripts were blocked (pnpm and Bun block them by default) or skipped
|
|
5
|
+
// (`--ignore-scripts`) — so pnpm runs through Node.js instead: `bin/pnpm.mjs`
|
|
6
|
+
// finds the installed binary, or downloads one, and spawns it.
|
|
7
|
+
//
|
|
8
|
+
// Package managers write bin shims after preinstall has had its chance to run,
|
|
9
|
+
// so a shim made from this file's shebang exists only where the binary never
|
|
10
|
+
// arrived. That is also why this file is left in place once it is running: a
|
|
11
|
+
// binary put here under such a shim would be run through `node`.
|
|
12
|
+
import process from 'node:process'
|
|
13
|
+
|
|
14
|
+
if (process.stderr.isTTY) {
|
|
15
|
+
process.stderr.write(
|
|
16
|
+
'pnpm is running through Node.js because the script that installs its native binary was skipped. ' +
|
|
17
|
+
'Reinstall pnpm with its build scripts allowed to run the binary directly.\n'
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
await import('./bin/pnpm.mjs')
|