pnpm 12.4.1 → 12.5.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.
- package/CHANGELOG.md +287 -0
- package/dist/node_modules/.bin/get-pnpm +17 -4
- package/dist/node_modules/.bin/node-gyp +17 -4
- package/dist/node_modules/.bin/node-which +17 -4
- package/dist/node_modules/.bin/nopt +17 -4
- package/dist/node_modules/.bin/semver +17 -4
- package/dist/node_modules/.pnpm-workspace-state-v1.json +10 -12
- package/dist/node_modules/get-pnpm/lib/downloadExecutable.js +12 -3
- package/dist/node_modules/get-pnpm/lib/index.js +14 -2
- package/dist/node_modules/get-pnpm/lib/platformPackageName.js +21 -6
- package/dist/node_modules/get-pnpm/lib/registry.js +43 -0
- package/dist/node_modules/get-pnpm/package.json +1 -1
- package/package.json +15 -15
- package/pn +35 -1
- package/pnpm +13 -3
- package/pnpx +35 -1
- package/pnx +35 -1
- package/dist/node_modules/.package-map.json +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,292 @@
|
|
|
1
1
|
# pnpm
|
|
2
2
|
|
|
3
|
+
## 12.5.0
|
|
4
|
+
|
|
5
|
+
pnpm 12.5.0 makes Python a first-class ecosystem, accepts Package URLs in `pnpm add`, names whole platforms in `supportedArchitectures`, and gives tasks machine-wide concurrency limits. It also fixes an install that could reuse one package's downloaded tarball for another.
|
|
6
|
+
|
|
7
|
+
### Minor Changes
|
|
8
|
+
|
|
9
|
+
#### Installing packages
|
|
10
|
+
|
|
11
|
+
- `pnpm add` accepts a [Package URL](https://github.com/package-url/purl-spec) in place of a package name. `pnpm add pkg:npm/express@4.18.2` saves `express` to `package.json`. `pnpm add pkg:cargo/serde@1.0.188` saves `serde` to `Cargo.toml`. `pnpm add pkg:pypi/requests@2.31.0` saves `requests` to `pyproject.toml`. `pkg` is now a reserved specifier prefix, whatever case it is written in, so a named registry can no longer be called `pkg`.
|
|
12
|
+
|
|
13
|
+
- A `registries` entry can now name the ecosystem it serves.
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
registries:
|
|
17
|
+
https://internal.example/simple/:
|
|
18
|
+
ecosystem: pypi
|
|
19
|
+
https://pypi.org/simple/:
|
|
20
|
+
ecosystem: pypi
|
|
21
|
+
https://index.crates.io/:
|
|
22
|
+
ecosystem: cargo
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`ecosystem` accepts `npm`, `cargo` and `pypi`. An entry that does not name one serves npm, as every entry did before.
|
|
26
|
+
|
|
27
|
+
An ecosystem with several indexes searches them in the order they are declared. The first index that has a package supplies it, so the one declared last answers what none before it had.
|
|
28
|
+
|
|
29
|
+
A `registries` entry may not carry credentials. pnpm reads them from `.npmrc`, matched by origin, for a PyPI index as for every other package source.
|
|
30
|
+
|
|
31
|
+
#### Configuring pnpm
|
|
32
|
+
|
|
33
|
+
- `supportedArchitectures` now accepts a list of platforms, in place of the `os`, `cpu` and `libc` axes.
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
supportedArchitectures:
|
|
37
|
+
- linux-x64
|
|
38
|
+
- darwin-arm64
|
|
39
|
+
- win32-x64
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
An install prepares for the platforms the list names, and for those only. A platform reads as `<os>-<cpu>`, with a C library on Linux, as in `linux-x64-musl` or `linux-x64-manylinux_2_28`. The Rust target triple of the same machine is accepted too, so `x86_64-unknown-linux-gnu` names the platform `linux-x64` names. A Linux platform that names no C library is the glibc platform. `current` is the platform the install runs on.
|
|
43
|
+
|
|
44
|
+
The `os`, `cpu` and `libc` mapping keeps working and keeps its meaning.
|
|
45
|
+
|
|
46
|
+
- Added concurrency groups for tasks. A task in `pnpm-workspace.yaml` can name a `concurrencyGroup`. The new `concurrencyGroups` setting gives each group a limit. At most that many tasks of the group run at once on the machine, counted across every pnpm process, `pnpm pipeline` included. A task past the limit waits for a running one to finish. A script that calls `pnpm run` for a task of the same group runs under the slot its parent holds.
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
tasks:
|
|
50
|
+
test:rust:
|
|
51
|
+
concurrencyGroup: cargo
|
|
52
|
+
concurrencyGroups:
|
|
53
|
+
cargo: 2
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- `tools` names the programs pnpm downloads, and `mirror` says where each one comes from.
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
tools:
|
|
60
|
+
node:
|
|
61
|
+
mirror: https://mirror.example.com/node/download
|
|
62
|
+
channels:
|
|
63
|
+
nightly: https://nightly.example.com/
|
|
64
|
+
bun:
|
|
65
|
+
mirror: https://mirror.example.com/bun
|
|
66
|
+
python:
|
|
67
|
+
mirror: https://mirror.example.com/python-build-standalone/releases
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`node`, `bun` and `python` can be named. Any other tool is refused.
|
|
71
|
+
|
|
72
|
+
`mirror` is the base a tool's own layout hangs off.
|
|
73
|
+
|
|
74
|
+
`channels` sends one release channel elsewhere. A channel neither it nor `node-mirror:<channel>` names is left to `mirror`. Only `node` publishes channels, so naming them for another tool is refused.
|
|
75
|
+
|
|
76
|
+
Set it in the global `config.yaml` or in `PNPM_CONFIG_TOOLS`. A `pnpm-workspace.yaml` that names a tool mirror is ignored.
|
|
77
|
+
|
|
78
|
+
`pnpm pack-app` downloads the Node.js it embeds through `tools.node`. `node-mirror:<channel>` keeps working and names the same thing as an entry under `channels`.
|
|
79
|
+
|
|
80
|
+
#### Python interpreters and environments
|
|
81
|
+
|
|
82
|
+
- `pnpm install` now chooses a Python interpreter for each project instead of installing every project with one interpreter [#14945](https://github.com/pnpm/pnpm/issues/14945). A project is installed with the first interpreter on the machine that its `requires-python` accepts, so a workspace can hold projects that support different Python versions. pnpm reads `.python-version` too, and prefers the version it asks for. Set `python.executable` in `pnpm-workspace.yaml` to name one interpreter for every project.
|
|
83
|
+
|
|
84
|
+
- `pnpm install` now installs a Python interpreter when no interpreter on the machine fits the project [#14945](https://github.com/pnpm/pnpm/issues/14945). The builds are [python-build-standalone](https://github.com/astral-sh/python-build-standalone)'s, which uv and rye install too. One interpreter is shared by every project on the machine, and a later install uses it without downloading anything. `runtimeOnFail` decides what an install with no interpreter that fits does, the way it does for a Node.js runtime. `error` reports the project instead of installing one. `warn` and `ignore` install with an interpreter the machine has that the project's `requires-python` rejects. `tools.python.mirror` names a mirror.
|
|
85
|
+
|
|
86
|
+
- Python environments now live in the store. Each project keeps only its `.venv` link, which points at the project's current environment generation under `python-envs` in the store. A repository with many Python projects no longer holds a `.pnpm/python-envs` directory in each of them. The next install relinks a `.venv` that an earlier release published. The old `.pnpm/python-envs` directory is left in place, since a running program may still use it, and can be deleted once none does. With `frozenStore` set, pnpm writes nothing to the store, so environments stay in the project's `.pnpm/python-envs` [#15014](https://github.com/pnpm/pnpm/issues/15014).
|
|
87
|
+
|
|
88
|
+
- Python environments now use `packageImportMethod` to import wheel files from the store. Use `clone-or-copy` for copy-on-write clones with a copy fallback, or `copy` for independent files. Hardlinked files share writes with the store and other environments.
|
|
89
|
+
|
|
90
|
+
Isolated Python build environments keep backend writes private with copy-on-write clones or copies.
|
|
91
|
+
|
|
92
|
+
#### Python projects and workspaces
|
|
93
|
+
|
|
94
|
+
- `pnpm install` now installs a Python project's own package, so the project can be imported and the commands in `[project.scripts]` run right after an install [#14945](https://github.com/pnpm/pnpm/issues/14945). The installed package points at the source tree, so an edit to a module takes effect without another install. pnpm installs the package of a project that declares a `[build-system]`. `tool.uv.package` overrides that either way.
|
|
95
|
+
|
|
96
|
+
- `pnpm install` now installs a Python project in the workspace from its own source. Declare it under `[tool.uv.sources]`, as `shared = { workspace = true }` or `shared = { path = "../shared", editable = true }`. pnpm builds the project with the backend it declares. It installs the build editable, so an edit to the project takes effect without another install.
|
|
97
|
+
|
|
98
|
+
Approve the build backend under `allowBuilds` in `pnpm-workspace.yaml` as a Package URL, as `pkg:pypi/hatchling: true`. An install that has not approved a backend does not build the projects that need it. The message names the key to add.
|
|
99
|
+
|
|
100
|
+
`pnpm install` now refuses a requirement that names a project in the workspace when nothing declares where it comes from. It used to take that name from the index.
|
|
101
|
+
|
|
102
|
+
- The members of a uv workspace can now share one Python environment. Set `shared-environment = true` under `[tool.pnpm.python]` in the `pyproject.toml` that declares `[tool.uv.workspace]`. `pnpm install` then resolves every member as one graph into one `pylock.toml` and one `.venv` at the workspace root. Two members that require versions of a distribution no release satisfies at once are refused with an error naming both. Each project still gets an environment of its own by default [#15015](https://github.com/pnpm/pnpm/issues/15015).
|
|
103
|
+
|
|
104
|
+
- Python projects can now select extras and dependency groups through `[tool.pnpm.python]` in `pyproject.toml` [#14945](https://github.com/pnpm/pnpm/issues/14945). Workspace `python.extras` and `python.groups` defaults now skip names a project does not define.
|
|
105
|
+
|
|
106
|
+
- `pnpm install` now reads dynamic Python project metadata from the build backend [#14945](https://github.com/pnpm/pnpm/issues/14945). Projects with only a `requirements.txt` file now get a Python environment and lockfile.
|
|
107
|
+
|
|
108
|
+
#### Python dependencies and lockfiles
|
|
109
|
+
|
|
110
|
+
- pnpm can now resolve `pylock.toml` for several platforms and Python versions at once. `supportedArchitectures` names the platforms to lock for and `python.versions` the versions. Every platform is paired with every version. One committed lockfile then serves Linux CI and macOS or Windows contributors [#14945](https://github.com/pnpm/pnpm/issues/14945).
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
supportedArchitectures:
|
|
114
|
+
- linux-x64-manylinux_2_28
|
|
115
|
+
- darwin-arm64
|
|
116
|
+
- win32-x64
|
|
117
|
+
python:
|
|
118
|
+
enabled: true
|
|
119
|
+
versions: ['3.12', '3.13']
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The lockfile pins the wheel each environment takes for a distribution. It marks a package only some environments install. `pnpm install` takes the packages and wheels of the environment its interpreter matches, and refuses an interpreter none of them stand for. pnpm resolves a project that declares environments itself, not through the server `pnprServer` names. Naming neither setting locks for the interpreter running the install.
|
|
123
|
+
|
|
124
|
+
- `python.overrides` and `python.constraints` pin the versions a Python resolution may pick [#14945](https://github.com/pnpm/pnpm/issues/14945). pnpm reads uv's own overrides and constraints from `pyproject.toml` too.
|
|
125
|
+
|
|
126
|
+
- `pnpm install` now supports Python dependencies from Git repositories [#14945](https://github.com/pnpm/pnpm/issues/14945). Direct wheel URLs are also supported. Sources can be declared in `[tool.uv.sources]`. Git dependencies require `allowBuilds` approval.
|
|
127
|
+
|
|
128
|
+
- `pnpm install` can install a Python release that publishes no wheel this interpreter accepts, by building the source distribution the index serves beside it [#14945](https://github.com/pnpm/pnpm/issues/14945). The archive is pinned in `pylock.toml` by name and SHA-256. A later install replays it from the store, offline included. Building a source distribution runs the release's own build backend. Approve it with `pkg:pypi/<distribution>: true` under `allowBuilds`.
|
|
129
|
+
|
|
130
|
+
A resolution that finds no version of a distribution now says why. It tells apart a distribution no index publishes, one whose releases publish nothing this interpreter can install, and one whose versions the project's requirements exclude.
|
|
131
|
+
|
|
132
|
+
### Patch Changes
|
|
133
|
+
|
|
134
|
+
#### Installing packages
|
|
135
|
+
|
|
136
|
+
- pnpm no longer reuses one package's downloaded tarball for another package whose resolution pins a different integrity hash to the same URL [#15021](https://github.com/pnpm/pnpm/issues/15021).
|
|
137
|
+
|
|
138
|
+
- `pnpm install` and `pnpm add` now report an error when `package.json`, `pnpm-lock.yaml`, `pyproject.toml` or another file they snapshot before installing is a named pipe or a device. The command used to wait forever for something to write to it.
|
|
139
|
+
|
|
140
|
+
- `pnpm install --prod` and `pnpm install --dev` now record every dependency group in `pnpm-lock.yaml`. `node_modules` still holds only the groups the filter selects. They used to write the filter into the lockfile, so a later `pnpm install --frozen-lockfile` rejected it. `pnpm prune --prod`, `pnpm prune --dev`, and `pnpm prune --no-optional` behave the same way [#14912](https://github.com/pnpm/pnpm/issues/14912).
|
|
141
|
+
|
|
142
|
+
- POSIX bin shims now convert a Windows-form path such as `C:\node_modules\.bin\tsc` correctly. The shim mangled the backslashes in such a path and could not reach the package it runs. Installing again replaces the shims already in `node_modules` [#14867](https://github.com/pnpm/pnpm/issues/14867).
|
|
143
|
+
|
|
144
|
+
- Two pnpm processes installing one workspace at the same time no longer fail on Windows with "Access is denied" while writing `node_modules/.pnpm-workspace-state-v1.json`. The write now retries the transient lock the other process holds, as pnpm's other file writes do.
|
|
145
|
+
|
|
146
|
+
- pnpm now reads the manifest from the tarball when a pnpmfile `resolvers` hook returns a resolution without one. Such a package installed alone, with none of its own dependencies and no warning [#15000](https://github.com/pnpm/pnpm/issues/15000).
|
|
147
|
+
|
|
148
|
+
- `pnpm install` now merges Git conflict markers in `pnpm-lock.yaml`. It parses both sides of the conflict and keeps the versions they locked. A conflict in the config dependencies recorded at the top of the lockfile is merged too [#14880](https://github.com/pnpm/pnpm/issues/14880).
|
|
149
|
+
|
|
150
|
+
#### Cargo projects
|
|
151
|
+
|
|
152
|
+
- `pnpm install` can now generate `Cargo.lock` for workspaces with path or Git `[patch]` and `[replace]` overrides. Adding, removing, and updating crates also preserve these overrides [#14950](https://github.com/pnpm/pnpm/issues/14950).
|
|
153
|
+
|
|
154
|
+
Cargo lockfile resolution blocks unsupported Git transport helpers declared by transitive dependencies.
|
|
155
|
+
|
|
156
|
+
- `pnpm install` now vendors recursive Git submodules for Cargo dependencies at their pinned commits. Cargo builds can use these sources offline. Set Git's `protocol.file.allow` to `always` to fetch local file submodules. pnpm fetches cached Git crates again on the first online install [#14951](https://github.com/pnpm/pnpm/issues/14951).
|
|
157
|
+
|
|
158
|
+
- `pnpm install` now generates `Cargo.lock` for workspaces with Git dependencies, including a dependency that omits a package version. It also downloads the Rust standard library's dependencies when Cargo configuration enables `build-std` [#14944](https://github.com/pnpm/pnpm/issues/14944).
|
|
159
|
+
|
|
160
|
+
- `pnpm install` now handles weak Cargo features, written `crate?/feature`. Resolution failed when one dependency turned on an optional crate and another asked for a weak feature of it [#14960](https://github.com/pnpm/pnpm/issues/14960). The generated `Cargo.lock` now also includes the dependencies weak features reference, which Cargo rejected with `--locked` for crates such as `uuid` [#14978](https://github.com/pnpm/pnpm/issues/14978).
|
|
161
|
+
|
|
162
|
+
- `pnpm install` now generates `Cargo.lock` when a crate version it considers depends on a release the registry carries only as yanked. pnpm rules that version out and resolves the rest of the graph. Resolution failed with an error such as `no non-yanked version of napi-build satisfies ^3.0.0-beta` [#14952](https://github.com/pnpm/pnpm/issues/14952).
|
|
163
|
+
|
|
164
|
+
- `pnpm install` now falls back to an older semver-incompatible version of a crate when the newest one a dependency range allows cannot be resolved. Ranges such as `>=1, <3` span several of them [#14962](https://github.com/pnpm/pnpm/issues/14962).
|
|
165
|
+
|
|
166
|
+
#### Python projects
|
|
167
|
+
|
|
168
|
+
- `pnpm install` now honors uv workspace members when discovering Python projects. When no uv workspace declares a project, pnpm skips projects under conventional example, demo, documentation, template, `test`, `tests`, and test fixture directories [#15058](https://github.com/pnpm/pnpm/issues/15058).
|
|
169
|
+
|
|
170
|
+
- `pnpm install --filter <selector>` now installs only the Python projects the selection asks for. A Python project that shares a directory with an npm workspace project is selected with that project. A Python project in a directory of its own is selected by the distribution it declares, by its path, or through the `[tool.uv.sources]` entries that reach it. Under `--fail-if-no-match`, a selector that names only a Python project is a match. `pnpm add --filter <selector> pypi:<package>` writes the requirement to every selected project [#14945](https://github.com/pnpm/pnpm/issues/14945).
|
|
171
|
+
|
|
172
|
+
- `pnpm install` now installs wheels whose `RECORD` hashes disagree with their contents. The wheel archive's locked SHA-256 hash remains verified. pnpm writes correct hashes to the installed `RECORD` [#15061](https://github.com/pnpm/pnpm/issues/15061).
|
|
173
|
+
|
|
174
|
+
- `pnpm install` now installs a Python wheel whose `WHEEL` file lists tags that differ from the ones in its filename. A wheel whose filename tags were changed after the build, such as `mysql-connector-python`, was rejected [#14945](https://github.com/pnpm/pnpm/issues/14945).
|
|
175
|
+
|
|
176
|
+
- A Python release whose wheel metadata declares a requirement pnpm cannot read no longer fails the install. pnpm now resolves the project against the other releases of that package, and reports the unreadable requirement when none of them works.
|
|
177
|
+
|
|
178
|
+
- `pnpm install` no longer fails when a Python index lists a file pnpm cannot use, such as a release with no SHA-256 digest or an unreadable wheel filename. That file is left out and the project resolves against the remaining releases.
|
|
179
|
+
|
|
180
|
+
- `pnpm add pypi:<package>` in a directory that has no `pyproject.toml` now names the missing file and says where to run the command. It used to fail with a bare `No such file or directory (os error 2)` [#14945](https://github.com/pnpm/pnpm/issues/14945).
|
|
181
|
+
|
|
182
|
+
#### Performance
|
|
183
|
+
|
|
184
|
+
- `pnpm audit` no longer hangs on dependency graphs with many shared dependencies [#15005](https://github.com/pnpm/pnpm/issues/15005).
|
|
185
|
+
|
|
186
|
+
- Sped up `pnpm install` in Python workspaces with many projects. Projects now prepare concurrently. Projects with identical registry requirements also share fresh dependency resolutions [#14945](https://github.com/pnpm/pnpm/issues/14945).
|
|
187
|
+
|
|
188
|
+
- Repeat installs through the Node-API bindings now return "Already up to date" when the project manifests still match `pnpm-lock.yaml`. Before, every such install reinstalled the whole tree. An install also no longer reinstalls when `pnpm-lock.yaml` differs from the installed dependencies only by packages no project depends on or by top-level keys pnpm does not define.
|
|
189
|
+
|
|
190
|
+
#### Other commands
|
|
191
|
+
|
|
192
|
+
- `pnpm deploy` now links commands exposed by workspace dependencies into the deployed project's `node_modules/.bin` directory [#14899](https://github.com/pnpm/pnpm/issues/14899).
|
|
193
|
+
|
|
194
|
+
- `pnpm dlx` and `pnx` now prompt to approve dependency build scripts in interactive terminals [#14943](https://github.com/pnpm/pnpm/issues/14943). Cached packages with pending builds also prompt for approval. Without an interactive terminal, use `--allow-build` to allow the required builds.
|
|
195
|
+
|
|
196
|
+
- `pnpm add -g` and `pnpm update -g` now ignore incomplete unrelated global package groups when every command from the replaced group is retained. Operations that could remove a global command still require complete ownership information.
|
|
197
|
+
|
|
198
|
+
- `pnpm pack` now writes tarball entries grouped by file extension and file name, the order npm uses. Packages that ship many same-named files, such as template collections, pack much smaller [#14766](https://github.com/pnpm/pnpm/issues/14766).
|
|
199
|
+
|
|
200
|
+
- `pnpm outdated --long` fills the Details column with the package homepage again [#14886](https://github.com/pnpm/pnpm/issues/14886).
|
|
201
|
+
|
|
202
|
+
## 12.4.2
|
|
203
|
+
|
|
204
|
+
pnpm 12.4.2 includes security fixes for executable shims and GitHub Actions links, more reliable installs, faster peer dependency checks in workspaces, and Python lockfiles that work across compatible targets.
|
|
205
|
+
|
|
206
|
+
### Patch Changes
|
|
207
|
+
|
|
208
|
+
#### Security
|
|
209
|
+
|
|
210
|
+
- Dependency executables can no longer take over another package's POSIX bin shim through its shell helpers. Reinstall dependencies to replace existing shims [#14837](https://github.com/pnpm/pnpm/issues/14837).
|
|
211
|
+
|
|
212
|
+
On Cygwin, MSYS2, and WSL, shims still use `PATH` for Windows path conversion, so dependency executables can still redirect them there.
|
|
213
|
+
|
|
214
|
+
- GitHub Actions homepage links no longer expose server credentials. GitHub server URLs now require HTTPS, with HTTP allowed only for loopback hosts.
|
|
215
|
+
|
|
216
|
+
#### Installing packages
|
|
217
|
+
|
|
218
|
+
- pnpm no longer crashes at startup on FreeBSD and other Unix-like platforms. Platforms other than Windows and macOS use `~/.local/share/pnpm/store` by default [#14859](https://github.com/pnpm/pnpm/issues/14859).
|
|
219
|
+
|
|
220
|
+
- `pnpm install` on Windows no longer fails with `ERR_PNPM_PACKAGE_MANAGER_REMOVE_MODULES_DIR` when clearing `node_modules` containing linked dependencies, such as when changing `nodeLinker` [#14790](https://github.com/pnpm/pnpm/issues/14790).
|
|
221
|
+
|
|
222
|
+
- `pnpm install <pkg>` now accepts `--prod` and `--dev`, including `--prod=false` [#14868](https://github.com/pnpm/pnpm/issues/14868).
|
|
223
|
+
|
|
224
|
+
- `pnpm install` and `pnpm update` now honor `--ignore-workspace` in nested projects excluded from the surrounding workspace. The flag also skips that workspace's settings during the `packageManager` check [#14809](https://github.com/pnpm/pnpm/issues/14809).
|
|
225
|
+
|
|
226
|
+
- `pnpm install` on macOS no longer reuses stale files for `file:` tarball or git-hosted tarball dependencies.
|
|
227
|
+
|
|
228
|
+
- `pnpm install` in a single-project directory now detects `package.json` edits made while the previous install was finishing [#14890](https://github.com/pnpm/pnpm/issues/14890).
|
|
229
|
+
|
|
230
|
+
- `pnpm install --frozen-lockfile` now removes packages no longer reachable from any project in `pnpm-lock.yaml`. This also prevents repeated lifecycle script execution and unnecessary installs before `pnpm run` and `pnpm exec` with `verifyDepsBeforeRun` [#14891](https://github.com/pnpm/pnpm/issues/14891).
|
|
231
|
+
|
|
232
|
+
#### Resolving and updating dependencies
|
|
233
|
+
|
|
234
|
+
- Node.js runtime resolution now reports network failures from unofficial-builds.nodejs.org. These failures previously omitted musl builds from `pnpm-lock.yaml`, making its contents depend on network access [#14813](https://github.com/pnpm/pnpm/issues/14813).
|
|
235
|
+
|
|
236
|
+
- `pnpm install` now rejects invalid `peerDependencies` specifiers with `ERR_PNPM_INVALID_PEER_DEPENDENCY_SPECIFICATION`. A value such as `"foo": "foo@1.0.0"` previously created a broken directory link [#14791](https://github.com/pnpm/pnpm/issues/14791).
|
|
237
|
+
|
|
238
|
+
- `pnpm deploy` now writes plain registry versions in the deployed `package.json`, without peer dependency suffixes. The lockfile retains peer bindings, and npm aliases retain their target package names [#14873](https://github.com/pnpm/pnpm/issues/14873).
|
|
239
|
+
|
|
240
|
+
- `pnpm add <git repository>` now names repositories without a `package.json` as `@owner/repo`, allowing dependencies on equally named repositories from different owners [#14870](https://github.com/pnpm/pnpm/issues/14870).
|
|
241
|
+
|
|
242
|
+
- Peer dependency resolution now deduplicates packages whose child dependency resolves an optional peer in only some workspace projects, such as `next` with `styled-jsx`'s optional `babel-plugin-macros` peer [#14800](https://github.com/pnpm/pnpm/issues/14800).
|
|
243
|
+
|
|
244
|
+
- `pnpm update` now settles the lockfile in one run when an upgrade removes the package providing an optional peer dependency [#14895](https://github.com/pnpm/pnpm/issues/14895).
|
|
245
|
+
|
|
246
|
+
- `pnpm update --no-save` now preserves override-applied specifiers for dependencies it is not updating, preventing subsequent frozen installs from failing with `ERR_PNPM_OUTDATED_LOCKFILE` [#14836](https://github.com/pnpm/pnpm/issues/14836).
|
|
247
|
+
|
|
248
|
+
- `pnpm update --no-save` now succeeds under `minimumReleaseAgeStrict` when every resolved version is old enough [#14835](https://github.com/pnpm/pnpm/issues/14835).
|
|
249
|
+
|
|
250
|
+
#### Performance
|
|
251
|
+
|
|
252
|
+
- Workspace installs and `pnpm peers check` are faster when projects depend on each other, fixing a slowdown introduced in 12.3.0. Unmet peer dependencies of workspace packages are now reported only under projects that link them directly [#14906](https://github.com/pnpm/pnpm/issues/14906).
|
|
253
|
+
|
|
254
|
+
- Hoisted installs use less memory when packages are cached. Frozen-lockfile hoisted installs on macOS are also faster when reusable package directories are cached.
|
|
255
|
+
|
|
256
|
+
#### Python projects
|
|
257
|
+
|
|
258
|
+
- `pnpm install --frozen-lockfile` now reuses `pylock.toml` across compatible Python targets, including after kernel updates. Reuse requires unchanged requirements, index, and `requires-python`, compatible wheels, and a locked dependency graph matching the target's markers [#14843](https://github.com/pnpm/pnpm/issues/14843).
|
|
259
|
+
|
|
260
|
+
The lockfile's `environments` marker now includes only the interpreter version and marker variables used by the dependency graph. Without `--frozen-lockfile`, pnpm warns and resolves again when the locked graph no longer matches the target.
|
|
261
|
+
|
|
262
|
+
- Python resolution no longer fails on malformed `Requires-Python` values, such as the trailing comma in `openpyxl` 3.0.x. pnpm treats these releases as declaring no interpreter range [#14910](https://github.com/pnpm/pnpm/issues/14910).
|
|
263
|
+
|
|
264
|
+
- `pnpm add pypi:...` now rejects unsupported `--save-prefix` values before editing the manifest or resolving dependencies.
|
|
265
|
+
|
|
266
|
+
#### Workspaces and scripts
|
|
267
|
+
|
|
268
|
+
- Scripts listed in `syncInjectedDepsAfterScripts` no longer fail with `ERR_PNPM_INJECTED_DEPS_SYNC_READ_DIR` when the lockfile contains an injected package copy that no project depends on.
|
|
269
|
+
|
|
270
|
+
- `shellEmulator` now expands `${VAR}`, `${VAR:-default}`, and `${VAR:+alternative}` in scripts [#14814](https://github.com/pnpm/pnpm/issues/14814).
|
|
271
|
+
|
|
272
|
+
- Cargo and Python project discovery now honors `!` exclusions in `pnpm-workspace.yaml` `packages`, skipping both parsing and generated source configuration for excluded projects [#14844](https://github.com/pnpm/pnpm/issues/14844).
|
|
273
|
+
|
|
274
|
+
- `pnpm --filter "./packages/{app,lib}"` now selects either alternative. Brace alternatives can nest, span path separators, and combine with other wildcards.
|
|
275
|
+
|
|
276
|
+
- GitHub Actions updates now stop if an action reference changes during version resolution, and preserve unrelated workflow edits.
|
|
277
|
+
|
|
278
|
+
#### CLI and output
|
|
279
|
+
|
|
280
|
+
- `pn`, `pnpx`, and `pnx` now run the pnpm installed alongside them, even when that directory is absent from `PATH` or another pnpm comes first [#14803](https://github.com/pnpm/pnpm/issues/14803).
|
|
281
|
+
|
|
282
|
+
- `pnpm --version` now reports failures to install or record a project's pinned pnpm, then prints the running CLI's version. It also honors `--store-dir` and `--store` [#14831](https://github.com/pnpm/pnpm/issues/14831).
|
|
283
|
+
|
|
284
|
+
- `pnpm self-update` no longer reinstalls the active version when it was installed by the standalone installation script [#14823](https://github.com/pnpm/pnpm/issues/14823).
|
|
285
|
+
|
|
286
|
+
- `pnpm t` and `pnpm tst` work again as aliases for `pnpm test`.
|
|
287
|
+
|
|
288
|
+
- `pnpm sbom` now emits valid repository URLs in CycloneDX `externalReferences[].url` and SPDX `homepage`. Shorthands such as `vercel/ms` become `git+https` URLs, embedded credentials are removed, and invalid repository values are omitted [#14773](https://github.com/pnpm/pnpm/issues/14773).
|
|
289
|
+
|
|
3
290
|
## 12.4.1
|
|
4
291
|
|
|
5
292
|
pnpm 12.4.1 fixes installs that failed on filesystems refusing hard links or clones, on Android, and under `nodeLinker: hoisted`. Repeat installs are faster.
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Resolve $0 through symlinks so basedir is the shim's real directory.
|
|
3
3
|
# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.
|
|
4
|
+
#
|
|
5
|
+
# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed, and
|
|
6
|
+
# uname go through `command -p`, which searches the system default path instead.
|
|
7
|
+
# A dependency's bin cannot stand in for one of them and take over the shim
|
|
8
|
+
# before it reaches its target. Directories come from `${link%/*}`, which needs
|
|
9
|
+
# no helper at all.
|
|
4
10
|
link="$0"
|
|
11
|
+
# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup
|
|
12
|
+
# and stands for a file in the current directory.
|
|
13
|
+
case "$link" in
|
|
14
|
+
*/*|*\\*) ;;
|
|
15
|
+
*) link="./$link" ;;
|
|
16
|
+
esac
|
|
5
17
|
hops=0
|
|
6
18
|
while [ -L "$link" ] && [ "$hops" -lt 40 ]; do
|
|
7
19
|
hops=$((hops+1))
|
|
8
|
-
target=$(readlink "$link")
|
|
20
|
+
target=$(command -p readlink "$link")
|
|
9
21
|
case "$target" in
|
|
10
22
|
/*) link="$target" ;;
|
|
11
|
-
*) link="$
|
|
23
|
+
*) link="${link%/*}/$target" ;;
|
|
12
24
|
esac
|
|
13
25
|
done
|
|
14
|
-
basedir=$(
|
|
26
|
+
basedir=$(echo "$link" | command -p sed -e 's,\\,/,g')
|
|
27
|
+
basedir="${basedir%/*}"
|
|
15
28
|
basedir_win="$basedir"
|
|
16
29
|
exe=""
|
|
17
30
|
msys=""
|
|
18
31
|
|
|
19
|
-
case `uname -a` in
|
|
32
|
+
case `command -p uname -a` in
|
|
20
33
|
*CYGWIN*|*MINGW*|*MSYS*)
|
|
21
34
|
if command -v cygpath > /dev/null 2>&1; then
|
|
22
35
|
basedir_win=`cygpath -w "$basedir"`
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Resolve $0 through symlinks so basedir is the shim's real directory.
|
|
3
3
|
# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.
|
|
4
|
+
#
|
|
5
|
+
# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed, and
|
|
6
|
+
# uname go through `command -p`, which searches the system default path instead.
|
|
7
|
+
# A dependency's bin cannot stand in for one of them and take over the shim
|
|
8
|
+
# before it reaches its target. Directories come from `${link%/*}`, which needs
|
|
9
|
+
# no helper at all.
|
|
4
10
|
link="$0"
|
|
11
|
+
# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup
|
|
12
|
+
# and stands for a file in the current directory.
|
|
13
|
+
case "$link" in
|
|
14
|
+
*/*|*\\*) ;;
|
|
15
|
+
*) link="./$link" ;;
|
|
16
|
+
esac
|
|
5
17
|
hops=0
|
|
6
18
|
while [ -L "$link" ] && [ "$hops" -lt 40 ]; do
|
|
7
19
|
hops=$((hops+1))
|
|
8
|
-
target=$(readlink "$link")
|
|
20
|
+
target=$(command -p readlink "$link")
|
|
9
21
|
case "$target" in
|
|
10
22
|
/*) link="$target" ;;
|
|
11
|
-
*) link="$
|
|
23
|
+
*) link="${link%/*}/$target" ;;
|
|
12
24
|
esac
|
|
13
25
|
done
|
|
14
|
-
basedir=$(
|
|
26
|
+
basedir=$(echo "$link" | command -p sed -e 's,\\,/,g')
|
|
27
|
+
basedir="${basedir%/*}"
|
|
15
28
|
basedir_win="$basedir"
|
|
16
29
|
exe=""
|
|
17
30
|
msys=""
|
|
18
31
|
|
|
19
|
-
case `uname -a` in
|
|
32
|
+
case `command -p uname -a` in
|
|
20
33
|
*CYGWIN*|*MINGW*|*MSYS*)
|
|
21
34
|
if command -v cygpath > /dev/null 2>&1; then
|
|
22
35
|
basedir_win=`cygpath -w "$basedir"`
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Resolve $0 through symlinks so basedir is the shim's real directory.
|
|
3
3
|
# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.
|
|
4
|
+
#
|
|
5
|
+
# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed, and
|
|
6
|
+
# uname go through `command -p`, which searches the system default path instead.
|
|
7
|
+
# A dependency's bin cannot stand in for one of them and take over the shim
|
|
8
|
+
# before it reaches its target. Directories come from `${link%/*}`, which needs
|
|
9
|
+
# no helper at all.
|
|
4
10
|
link="$0"
|
|
11
|
+
# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup
|
|
12
|
+
# and stands for a file in the current directory.
|
|
13
|
+
case "$link" in
|
|
14
|
+
*/*|*\\*) ;;
|
|
15
|
+
*) link="./$link" ;;
|
|
16
|
+
esac
|
|
5
17
|
hops=0
|
|
6
18
|
while [ -L "$link" ] && [ "$hops" -lt 40 ]; do
|
|
7
19
|
hops=$((hops+1))
|
|
8
|
-
target=$(readlink "$link")
|
|
20
|
+
target=$(command -p readlink "$link")
|
|
9
21
|
case "$target" in
|
|
10
22
|
/*) link="$target" ;;
|
|
11
|
-
*) link="$
|
|
23
|
+
*) link="${link%/*}/$target" ;;
|
|
12
24
|
esac
|
|
13
25
|
done
|
|
14
|
-
basedir=$(
|
|
26
|
+
basedir=$(echo "$link" | command -p sed -e 's,\\,/,g')
|
|
27
|
+
basedir="${basedir%/*}"
|
|
15
28
|
basedir_win="$basedir"
|
|
16
29
|
exe=""
|
|
17
30
|
msys=""
|
|
18
31
|
|
|
19
|
-
case `uname -a` in
|
|
32
|
+
case `command -p uname -a` in
|
|
20
33
|
*CYGWIN*|*MINGW*|*MSYS*)
|
|
21
34
|
if command -v cygpath > /dev/null 2>&1; then
|
|
22
35
|
basedir_win=`cygpath -w "$basedir"`
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Resolve $0 through symlinks so basedir is the shim's real directory.
|
|
3
3
|
# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.
|
|
4
|
+
#
|
|
5
|
+
# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed, and
|
|
6
|
+
# uname go through `command -p`, which searches the system default path instead.
|
|
7
|
+
# A dependency's bin cannot stand in for one of them and take over the shim
|
|
8
|
+
# before it reaches its target. Directories come from `${link%/*}`, which needs
|
|
9
|
+
# no helper at all.
|
|
4
10
|
link="$0"
|
|
11
|
+
# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup
|
|
12
|
+
# and stands for a file in the current directory.
|
|
13
|
+
case "$link" in
|
|
14
|
+
*/*|*\\*) ;;
|
|
15
|
+
*) link="./$link" ;;
|
|
16
|
+
esac
|
|
5
17
|
hops=0
|
|
6
18
|
while [ -L "$link" ] && [ "$hops" -lt 40 ]; do
|
|
7
19
|
hops=$((hops+1))
|
|
8
|
-
target=$(readlink "$link")
|
|
20
|
+
target=$(command -p readlink "$link")
|
|
9
21
|
case "$target" in
|
|
10
22
|
/*) link="$target" ;;
|
|
11
|
-
*) link="$
|
|
23
|
+
*) link="${link%/*}/$target" ;;
|
|
12
24
|
esac
|
|
13
25
|
done
|
|
14
|
-
basedir=$(
|
|
26
|
+
basedir=$(echo "$link" | command -p sed -e 's,\\,/,g')
|
|
27
|
+
basedir="${basedir%/*}"
|
|
15
28
|
basedir_win="$basedir"
|
|
16
29
|
exe=""
|
|
17
30
|
msys=""
|
|
18
31
|
|
|
19
|
-
case `uname -a` in
|
|
32
|
+
case `command -p uname -a` in
|
|
20
33
|
*CYGWIN*|*MINGW*|*MSYS*)
|
|
21
34
|
if command -v cygpath > /dev/null 2>&1; then
|
|
22
35
|
basedir_win=`cygpath -w "$basedir"`
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Resolve $0 through symlinks so basedir is the shim's real directory.
|
|
3
3
|
# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.
|
|
4
|
+
#
|
|
5
|
+
# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed, and
|
|
6
|
+
# uname go through `command -p`, which searches the system default path instead.
|
|
7
|
+
# A dependency's bin cannot stand in for one of them and take over the shim
|
|
8
|
+
# before it reaches its target. Directories come from `${link%/*}`, which needs
|
|
9
|
+
# no helper at all.
|
|
4
10
|
link="$0"
|
|
11
|
+
# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup
|
|
12
|
+
# and stands for a file in the current directory.
|
|
13
|
+
case "$link" in
|
|
14
|
+
*/*|*\\*) ;;
|
|
15
|
+
*) link="./$link" ;;
|
|
16
|
+
esac
|
|
5
17
|
hops=0
|
|
6
18
|
while [ -L "$link" ] && [ "$hops" -lt 40 ]; do
|
|
7
19
|
hops=$((hops+1))
|
|
8
|
-
target=$(readlink "$link")
|
|
20
|
+
target=$(command -p readlink "$link")
|
|
9
21
|
case "$target" in
|
|
10
22
|
/*) link="$target" ;;
|
|
11
|
-
*) link="$
|
|
23
|
+
*) link="${link%/*}/$target" ;;
|
|
12
24
|
esac
|
|
13
25
|
done
|
|
14
|
-
basedir=$(
|
|
26
|
+
basedir=$(echo "$link" | command -p sed -e 's,\\,/,g')
|
|
27
|
+
basedir="${basedir%/*}"
|
|
15
28
|
basedir_win="$basedir"
|
|
16
29
|
exe=""
|
|
17
30
|
msys=""
|
|
18
31
|
|
|
19
|
-
case `uname -a` in
|
|
32
|
+
case `command -p uname -a` in
|
|
20
33
|
*CYGWIN*|*MINGW*|*MSYS*)
|
|
21
34
|
if command -v cygpath > /dev/null 2>&1; then
|
|
22
35
|
basedir_win=`cygpath -w "$basedir"`
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"lastValidatedTimestamp":
|
|
2
|
+
"lastValidatedTimestamp": 1789748282784,
|
|
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.5.0"
|
|
7
7
|
}
|
|
8
8
|
},
|
|
9
9
|
"pnpmfiles": [],
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@pnpm/tabtab": "^0.5.4",
|
|
49
49
|
"@pnpm/tgz-fixtures": "0.0.0",
|
|
50
50
|
"@reflink/reflink": "0.1.19",
|
|
51
|
-
"@rushstack/worker-pool": "0.7.
|
|
51
|
+
"@rushstack/worker-pool": "0.7.27",
|
|
52
52
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
53
53
|
"@types/adm-zip": "^0.5.8",
|
|
54
54
|
"@types/archy": "0.0.36",
|
|
@@ -94,12 +94,11 @@
|
|
|
94
94
|
"@yarnpkg/lockfile": "^1.1.0",
|
|
95
95
|
"@yarnpkg/nm": "4.1.1",
|
|
96
96
|
"@yarnpkg/pnp": "^4.1.7",
|
|
97
|
-
"@zkochan/cmd-shim": "^9.0.7",
|
|
98
97
|
"@zkochan/retry": "^0.2.0",
|
|
99
98
|
"@zkochan/rimraf": "^4.0.0",
|
|
100
99
|
"@zkochan/table": "^2.0.1",
|
|
101
|
-
"adm-zip": "^0.6.
|
|
102
|
-
"amaro": "^1.
|
|
100
|
+
"adm-zip": "^0.6.1",
|
|
101
|
+
"amaro": "^1.2.0",
|
|
103
102
|
"ansi-diff": "^1.2.0",
|
|
104
103
|
"archy": "^1.0.0",
|
|
105
104
|
"better-path-resolve": "2.0.0",
|
|
@@ -142,7 +141,7 @@
|
|
|
142
141
|
"fast-glob": "^3.3.3",
|
|
143
142
|
"fs-extra": "^11.4.0",
|
|
144
143
|
"fuse-native": "^2.2.6",
|
|
145
|
-
"get-pnpm": "^0.0.
|
|
144
|
+
"get-pnpm": "^0.0.5",
|
|
146
145
|
"get-port": "^7.2.0",
|
|
147
146
|
"ghooks": "2.0.4",
|
|
148
147
|
"graceful-fs": "^4.2.11",
|
|
@@ -172,6 +171,7 @@
|
|
|
172
171
|
"lru-cache": "^11.5.2",
|
|
173
172
|
"make-empty-dir": "^4.0.0",
|
|
174
173
|
"mdast-util-to-string": "^4.0.0",
|
|
174
|
+
"memfs": "^4.78.0",
|
|
175
175
|
"memoize": "^11.0.0",
|
|
176
176
|
"micromatch": "^4.0.8",
|
|
177
177
|
"msgpackr": "2.1.0",
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
"npm-packlist": "10.0.4",
|
|
185
185
|
"npm-registry-fetch": "^19.0.0",
|
|
186
186
|
"object-hash": "3.0.0",
|
|
187
|
-
"open": "^11.0.
|
|
187
|
+
"open": "^11.0.4",
|
|
188
188
|
"openpgp": "^6.3.1",
|
|
189
189
|
"p-defer": "^4.0.1",
|
|
190
190
|
"p-every": "^2.0.0",
|
|
@@ -259,7 +259,7 @@
|
|
|
259
259
|
"write-json5-file": "^4.0.0",
|
|
260
260
|
"write-package": "7.2.0",
|
|
261
261
|
"write-yaml-file": "^6.0.0",
|
|
262
|
-
"yaml": "^2.9.
|
|
262
|
+
"yaml": "^2.9.1",
|
|
263
263
|
"yaml-tag": "1.1.0"
|
|
264
264
|
}
|
|
265
265
|
},
|
|
@@ -311,15 +311,13 @@
|
|
|
311
311
|
"write-ini-file",
|
|
312
312
|
"write-json5-file",
|
|
313
313
|
"write-yaml-file",
|
|
314
|
-
"http-proxy-middleware@3.0.7"
|
|
315
|
-
"get-pnpm@0.0.3"
|
|
314
|
+
"http-proxy-middleware@3.0.7"
|
|
316
315
|
],
|
|
317
316
|
"minimumReleaseAgeIgnoreMissingTime": true,
|
|
318
317
|
"minimumReleaseAgeStrict": true,
|
|
319
318
|
"nodeLinker": "hoisted",
|
|
320
319
|
"optional": true,
|
|
321
320
|
"patchedDependencies": {
|
|
322
|
-
"adm-zip@0.6.0": "../../../../__patches__/adm-zip@0.6.0.patch",
|
|
323
321
|
"graceful-fs@4.2.11": "../../../../__patches__/graceful-fs@4.2.11.patch",
|
|
324
322
|
"normalize-registry-url@2.0.1": "../../../../__patches__/normalize-registry-url@2.0.1.patch"
|
|
325
323
|
},
|
|
@@ -3,7 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { extractTarballMember } from './extractTarballMember.js';
|
|
5
5
|
import { isMusl, platformPackageName } from './platformPackageName.js';
|
|
6
|
-
import { downloadTarball, fetchVersionMeta, normalizeRegistry } from './registry.js';
|
|
6
|
+
import { downloadTarball, fetchVersionMeta, normalizeRegistry, useProxyFromEnv } from './registry.js';
|
|
7
7
|
import { majorVersion } from './resolveVersion.js';
|
|
8
8
|
import { sameFileContents } from './sameFileContents.js';
|
|
9
9
|
import { verifyRegistrySignature } from './verifySignature.js';
|
|
@@ -31,14 +31,23 @@ function executableName() {
|
|
|
31
31
|
* @returns the package the executable came from.
|
|
32
32
|
*/
|
|
33
33
|
export async function downloadPnpmExecutable(opts) {
|
|
34
|
-
const { version, destPath } = opts;
|
|
35
34
|
const registry = normalizeRegistry(opts.registry);
|
|
36
35
|
const packageName = platformPackageName({
|
|
37
|
-
major: majorVersion(version),
|
|
36
|
+
major: majorVersion(opts.version),
|
|
38
37
|
platform: process.platform,
|
|
39
38
|
arch: process.arch,
|
|
40
39
|
musl: isMusl(),
|
|
41
40
|
});
|
|
41
|
+
const restoreProxy = useProxyFromEnv();
|
|
42
|
+
try {
|
|
43
|
+
return await fetchExecutable({ ...opts, registry, packageName });
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
restoreProxy();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function fetchExecutable(opts) {
|
|
50
|
+
const { version, destPath, registry, packageName } = opts;
|
|
42
51
|
const meta = await fetchVersionMeta(registry, packageName, version, opts.headers);
|
|
43
52
|
if (!meta.dist.integrity) {
|
|
44
53
|
throw new Error(`The npm registry published no checksum for ${packageName}@${version}, so it cannot be verified.`);
|
|
@@ -4,13 +4,13 @@ import os from 'node:os';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { extractTarball } from './extractTarball.js';
|
|
6
6
|
import { isMusl, platformPackageName } from './platformPackageName.js';
|
|
7
|
-
import { downloadTarball, fetchPackument, fetchVersionMeta, registryFromEnv } from './registry.js';
|
|
7
|
+
import { downloadTarball, fetchPackument, fetchVersionMeta, registryFromEnv, useProxyFromEnv } from './registry.js';
|
|
8
8
|
import { majorVersion, resolveVersion } from './resolveVersion.js';
|
|
9
9
|
import { verifyRegistrySignature } from './verifySignature.js';
|
|
10
10
|
export { downloadPnpmExecutable } from './downloadExecutable.js';
|
|
11
11
|
export { extractTarballMember } from './extractTarballMember.js';
|
|
12
12
|
export { isMusl, platformPackageName } from './platformPackageName.js';
|
|
13
|
-
export { DEFAULT_REGISTRY, registryFromEnv } from './registry.js';
|
|
13
|
+
export { DEFAULT_REGISTRY, registryFromEnv, useProxyFromEnv } from './registry.js';
|
|
14
14
|
export { majorVersion, resolveVersion } from './resolveVersion.js';
|
|
15
15
|
export { verifyRegistrySignature } from './verifySignature.js';
|
|
16
16
|
/**
|
|
@@ -37,6 +37,9 @@ Environment variables:
|
|
|
37
37
|
PNPM_VERSION Version to install when no argument is given.
|
|
38
38
|
PNPM_HOME Directory to install pnpm into.
|
|
39
39
|
npm_config_registry Registry to download pnpm from.
|
|
40
|
+
HTTPS_PROXY Proxy to download through (HTTP_PROXY for an http://
|
|
41
|
+
registry); NO_PROXY names hosts to reach directly.
|
|
42
|
+
Node 24.14 or later.
|
|
40
43
|
`;
|
|
41
44
|
export async function runCli(argv) {
|
|
42
45
|
const positional = [];
|
|
@@ -113,6 +116,15 @@ export async function installPnpm(opts) {
|
|
|
113
116
|
* @returns the version installed and the path to the executable.
|
|
114
117
|
*/
|
|
115
118
|
export async function downloadPnpm(opts) {
|
|
119
|
+
const restoreProxy = useProxyFromEnv();
|
|
120
|
+
try {
|
|
121
|
+
return await fetchPnpm(opts);
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
restoreProxy();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function fetchPnpm(opts) {
|
|
116
128
|
const packument = await fetchPackument(opts.registry, CLI_PKG_NAME);
|
|
117
129
|
const version = resolveVersion(packument, opts.versionSpec);
|
|
118
130
|
const major = majorVersion(version);
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
const V12_ONLY_TARGETS = new Set([
|
|
2
|
+
'android-arm64',
|
|
3
|
+
'android-x64',
|
|
4
|
+
'freebsd-x64',
|
|
5
|
+
'linux-ppc64',
|
|
6
|
+
'linux-riscv64',
|
|
7
|
+
'linux-s390x',
|
|
8
|
+
]);
|
|
1
9
|
/**
|
|
2
10
|
* Name of the npm package that carries the pnpm executable for `target`.
|
|
3
11
|
*
|
|
@@ -6,15 +14,22 @@
|
|
|
6
14
|
* publishes `@pnpm/exe.<process.platform>-<arch>[-musl]`, while v11 and older
|
|
7
15
|
* publish `@pnpm/<macos|win|linux|linuxstatic>-<arch>`.
|
|
8
16
|
*
|
|
9
|
-
* @throws if pnpm publishes no binary for the host —
|
|
10
|
-
*
|
|
17
|
+
* @throws if pnpm publishes no binary for the host — because the host is not
|
|
18
|
+
* built for at all, because the binary arrived in v12 and an older major was
|
|
19
|
+
* asked for, or because of the v11-only Intel macOS gap.
|
|
11
20
|
*/
|
|
12
21
|
export function platformPackageName({ major, platform, arch, musl }) {
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
const target = `${platform}-${arch}`;
|
|
23
|
+
if (V12_ONLY_TARGETS.has(target)) {
|
|
24
|
+
if (major >= 12)
|
|
25
|
+
return `@pnpm/exe.${target}`;
|
|
26
|
+
throw new Error(`pnpm v${major} does not provide a pre-built binary for ${target}. pnpm 12 does:
|
|
27
|
+
|
|
28
|
+
npx get-pnpm 12`);
|
|
15
29
|
}
|
|
16
|
-
if (
|
|
17
|
-
|
|
30
|
+
if ((arch !== 'x64' && arch !== 'arm64') ||
|
|
31
|
+
(platform !== 'darwin' && platform !== 'linux' && platform !== 'win32')) {
|
|
32
|
+
throw new Error(`Sorry! pnpm does not provide a pre-built binary for ${target}.`);
|
|
18
33
|
}
|
|
19
34
|
if (platform === 'darwin' && arch === 'x64' && major === 11) {
|
|
20
35
|
throw new Error(`pnpm v11 does not provide a working binary for Intel macOS (darwin-x64) due to an upstream Node.js SEA bug.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { createWriteStream } from 'node:fs';
|
|
3
|
+
import http from 'node:http';
|
|
3
4
|
import { pipeline } from 'node:stream/promises';
|
|
4
5
|
const ABBREVIATED_PACKUMENT = 'application/vnd.npm.install-v1+json';
|
|
5
6
|
export const DEFAULT_REGISTRY = 'https://registry.npmjs.org/';
|
|
@@ -16,6 +17,48 @@ export function registryFromEnv() {
|
|
|
16
17
|
export function normalizeRegistry(registry) {
|
|
17
18
|
return registry.endsWith('/') ? registry : `${registry}/`;
|
|
18
19
|
}
|
|
20
|
+
const PROXY_VARS = ['https_proxy', 'HTTPS_PROXY', 'http_proxy', 'HTTP_PROXY'];
|
|
21
|
+
/**
|
|
22
|
+
* Routes every request made until the returned function is called through the
|
|
23
|
+
* proxy the environment names in `HTTPS_PROXY`/`HTTP_PROXY`, honouring
|
|
24
|
+
* `NO_PROXY`. A no-op when the environment names none.
|
|
25
|
+
*
|
|
26
|
+
* `fetch` reads those variables only when Node was started with
|
|
27
|
+
* `NODE_USE_ENV_PROXY=1`, which nothing that embeds this package controls:
|
|
28
|
+
* Corepack starts the process that runs pnpm's launcher. On a network that
|
|
29
|
+
* allows no other route out, the download then fails with a bare
|
|
30
|
+
* `fetch failed`, while everything before it went through the proxy fine,
|
|
31
|
+
* Corepack's own download of the `pnpm` package included.
|
|
32
|
+
*
|
|
33
|
+
* Node before 24.14 has no way to apply the proxy after startup, so the
|
|
34
|
+
* request goes direct there, as it always has.
|
|
35
|
+
*
|
|
36
|
+
* The setting is process-global, so overlapping downloads share one
|
|
37
|
+
* activation: the first call applies the proxy and the last of the returned
|
|
38
|
+
* functions to run puts the agents back, never one in the middle.
|
|
39
|
+
*/
|
|
40
|
+
export function useProxyFromEnv() {
|
|
41
|
+
if (!PROXY_VARS.some((name) => process.env[name]))
|
|
42
|
+
return () => { };
|
|
43
|
+
const { setGlobalProxyFromEnv } = http;
|
|
44
|
+
if (setGlobalProxyFromEnv == null)
|
|
45
|
+
return () => { };
|
|
46
|
+
// Counted only once the activation took: a call that threw on a malformed
|
|
47
|
+
// proxy URL holds nothing to release, and a retry after a fix has to activate.
|
|
48
|
+
if (proxyUsers === 0)
|
|
49
|
+
restoreProxy = setGlobalProxyFromEnv(process.env);
|
|
50
|
+
proxyUsers++;
|
|
51
|
+
let released = false;
|
|
52
|
+
return () => {
|
|
53
|
+
if (released)
|
|
54
|
+
return;
|
|
55
|
+
released = true;
|
|
56
|
+
if (--proxyUsers === 0)
|
|
57
|
+
restoreProxy();
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
let proxyUsers = 0;
|
|
61
|
+
let restoreProxy = () => { };
|
|
19
62
|
// Node's fetch applies no timeout of its own: a registry that accepts the
|
|
20
63
|
// connection and then stalls would hang the install with no output. Metadata is
|
|
21
64
|
// small and quick; the tarball budget has to survive a slow connection carrying
|
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.5.0",
|
|
13
13
|
"description": "Fast, disk space efficient package manager",
|
|
14
14
|
"keywords": [
|
|
15
15
|
"pnpm",
|
|
@@ -46,20 +46,20 @@
|
|
|
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-riscv64": "12.
|
|
56
|
-
"@pnpm/exe.linux-ppc64": "12.
|
|
57
|
-
"@pnpm/exe.linux-s390x": "12.
|
|
58
|
-
"@pnpm/exe.linux-x64-musl": "12.
|
|
59
|
-
"@pnpm/exe.linux-arm64-musl": "12.
|
|
60
|
-
"@pnpm/exe.freebsd-x64": "12.
|
|
61
|
-
"@pnpm/exe.android-arm64": "12.
|
|
62
|
-
"@pnpm/exe.android-x64": "12.
|
|
49
|
+
"@pnpm/exe.win32-x64": "12.5.0",
|
|
50
|
+
"@pnpm/exe.win32-arm64": "12.5.0",
|
|
51
|
+
"@pnpm/exe.darwin-x64": "12.5.0",
|
|
52
|
+
"@pnpm/exe.darwin-arm64": "12.5.0",
|
|
53
|
+
"@pnpm/exe.linux-x64": "12.5.0",
|
|
54
|
+
"@pnpm/exe.linux-arm64": "12.5.0",
|
|
55
|
+
"@pnpm/exe.linux-riscv64": "12.5.0",
|
|
56
|
+
"@pnpm/exe.linux-ppc64": "12.5.0",
|
|
57
|
+
"@pnpm/exe.linux-s390x": "12.5.0",
|
|
58
|
+
"@pnpm/exe.linux-x64-musl": "12.5.0",
|
|
59
|
+
"@pnpm/exe.linux-arm64-musl": "12.5.0",
|
|
60
|
+
"@pnpm/exe.freebsd-x64": "12.5.0",
|
|
61
|
+
"@pnpm/exe.android-arm64": "12.5.0",
|
|
62
|
+
"@pnpm/exe.android-x64": "12.5.0"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"preinstall": "node install.js",
|
package/pn
CHANGED
|
@@ -1,2 +1,36 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
|
|
2
|
+
# `pn` is `pnpm`. The pnpm it hands over to is the one installed alongside it,
|
|
3
|
+
# found relative to this file: a `PATH` lookup would run whatever other pnpm
|
|
4
|
+
# comes first there, and would find nothing at all when the directory holding
|
|
5
|
+
# these bins is not on `PATH`.
|
|
6
|
+
#
|
|
7
|
+
# $0 is whatever shim or symlink `pn` was launched through, so walk to the file
|
|
8
|
+
# itself first. The hop cap matches the kernel's ELOOP limit, so a cycle cannot
|
|
9
|
+
# hang the script. Directories come from `${self%/*}` and `readlink` runs through
|
|
10
|
+
# `command -p`, so the caller's `PATH` decides nothing here.
|
|
11
|
+
self=$0
|
|
12
|
+
# `${self%/*}` needs a slash to strip. A bare name came from a `PATH` lookup and
|
|
13
|
+
# stands for a file in the current directory.
|
|
14
|
+
case $self in
|
|
15
|
+
*/*) ;;
|
|
16
|
+
*) self=./$self ;;
|
|
17
|
+
esac
|
|
18
|
+
hops=0
|
|
19
|
+
while [ -L "$self" ] && [ "$hops" -lt 40 ]; do
|
|
20
|
+
hops=$((hops + 1))
|
|
21
|
+
link=$(command -p readlink "$self")
|
|
22
|
+
case $link in
|
|
23
|
+
/*) self=$link ;;
|
|
24
|
+
*) self=${self%/*}/$link ;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
# The walk has to end at a regular file. Running out of hops leaves $self a
|
|
28
|
+
# symlink; a chain that changed under us can leave it dangling or a directory, and
|
|
29
|
+
# a failed readlink leaves a trailing slash. Each case would take `pnpm` from the
|
|
30
|
+
# wrong directory — the substitution this script exists to prevent.
|
|
31
|
+
if [ -L "$self" ] || [ ! -f "$self" ]; then
|
|
32
|
+
echo "pn: could not resolve $0 to a regular file within 40 symlink hops." >&2
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
exec "${self%/*}/pnpm" "$@"
|
package/pnpm
CHANGED
|
@@ -24,15 +24,25 @@ fi
|
|
|
24
24
|
# $0 is whatever shim or symlink pnpm was launched through; ./bin/pnpm.mjs is
|
|
25
25
|
# found relative to this file. The hop cap matches the kernel's ELOOP limit, so
|
|
26
26
|
# a cycle cannot hang the script.
|
|
27
|
+
#
|
|
28
|
+
# `readlink` runs through `command -p`, which searches the system default path,
|
|
29
|
+
# and directories come from `${self%/*}`, which runs nothing at all. The caller's
|
|
30
|
+
# PATH therefore decides only which `node` runs, which is what it is for.
|
|
27
31
|
self=$0
|
|
32
|
+
# `${self%/*}` needs a slash to strip. A bare name came from a PATH lookup and
|
|
33
|
+
# stands for a file in the current directory.
|
|
34
|
+
case $self in
|
|
35
|
+
*/*) ;;
|
|
36
|
+
*) self=./$self ;;
|
|
37
|
+
esac
|
|
28
38
|
hops=0
|
|
29
39
|
while [ -L "$self" ] && [ "$hops" -lt 40 ]; do
|
|
30
40
|
hops=$((hops + 1))
|
|
31
|
-
link=$(readlink "$self")
|
|
41
|
+
link=$(command -p readlink "$self")
|
|
32
42
|
case $link in
|
|
33
43
|
/*) self=$link ;;
|
|
34
|
-
*) self=$
|
|
44
|
+
*) self=${self%/*}/$link ;;
|
|
35
45
|
esac
|
|
36
46
|
done
|
|
37
47
|
|
|
38
|
-
exec node "$
|
|
48
|
+
exec node "${self%/*}/bin/pnpm.mjs" "$@"
|
package/pnpx
CHANGED
|
@@ -1,2 +1,36 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
|
|
2
|
+
# `pnpx` is `pnpm dlx`. The pnpm it hands over to is the one installed alongside
|
|
3
|
+
# it, found relative to this file: a `PATH` lookup would run whatever other pnpm
|
|
4
|
+
# comes first there, and would find nothing at all when the directory holding
|
|
5
|
+
# these bins is not on `PATH`.
|
|
6
|
+
#
|
|
7
|
+
# $0 is whatever shim or symlink `pnpx` was launched through, so walk to the file
|
|
8
|
+
# itself first. The hop cap matches the kernel's ELOOP limit, so a cycle cannot
|
|
9
|
+
# hang the script. Directories come from `${self%/*}` and `readlink` runs through
|
|
10
|
+
# `command -p`, so the caller's `PATH` decides nothing here.
|
|
11
|
+
self=$0
|
|
12
|
+
# `${self%/*}` needs a slash to strip. A bare name came from a `PATH` lookup and
|
|
13
|
+
# stands for a file in the current directory.
|
|
14
|
+
case $self in
|
|
15
|
+
*/*) ;;
|
|
16
|
+
*) self=./$self ;;
|
|
17
|
+
esac
|
|
18
|
+
hops=0
|
|
19
|
+
while [ -L "$self" ] && [ "$hops" -lt 40 ]; do
|
|
20
|
+
hops=$((hops + 1))
|
|
21
|
+
link=$(command -p readlink "$self")
|
|
22
|
+
case $link in
|
|
23
|
+
/*) self=$link ;;
|
|
24
|
+
*) self=${self%/*}/$link ;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
# The walk has to end at a regular file. Running out of hops leaves $self a
|
|
28
|
+
# symlink; a chain that changed under us can leave it dangling or a directory, and
|
|
29
|
+
# a failed readlink leaves a trailing slash. Each case would take `pnpm` from the
|
|
30
|
+
# wrong directory — the substitution this script exists to prevent.
|
|
31
|
+
if [ -L "$self" ] || [ ! -f "$self" ]; then
|
|
32
|
+
echo "pnpx: could not resolve $0 to a regular file within 40 symlink hops." >&2
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
exec "${self%/*}/pnpm" dlx "$@"
|
package/pnx
CHANGED
|
@@ -1,2 +1,36 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
|
|
2
|
+
# `pnx` is `pnpm dlx`. The pnpm it hands over to is the one installed alongside
|
|
3
|
+
# it, found relative to this file: a `PATH` lookup would run whatever other pnpm
|
|
4
|
+
# comes first there, and would find nothing at all when the directory holding
|
|
5
|
+
# these bins is not on `PATH`.
|
|
6
|
+
#
|
|
7
|
+
# $0 is whatever shim or symlink `pnx` was launched through, so walk to the file
|
|
8
|
+
# itself first. The hop cap matches the kernel's ELOOP limit, so a cycle cannot
|
|
9
|
+
# hang the script. Directories come from `${self%/*}` and `readlink` runs through
|
|
10
|
+
# `command -p`, so the caller's `PATH` decides nothing here.
|
|
11
|
+
self=$0
|
|
12
|
+
# `${self%/*}` needs a slash to strip. A bare name came from a `PATH` lookup and
|
|
13
|
+
# stands for a file in the current directory.
|
|
14
|
+
case $self in
|
|
15
|
+
*/*) ;;
|
|
16
|
+
*) self=./$self ;;
|
|
17
|
+
esac
|
|
18
|
+
hops=0
|
|
19
|
+
while [ -L "$self" ] && [ "$hops" -lt 40 ]; do
|
|
20
|
+
hops=$((hops + 1))
|
|
21
|
+
link=$(command -p readlink "$self")
|
|
22
|
+
case $link in
|
|
23
|
+
/*) self=$link ;;
|
|
24
|
+
*) self=${self%/*}/$link ;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
# The walk has to end at a regular file. Running out of hops leaves $self a
|
|
28
|
+
# symlink; a chain that changed under us can leave it dangling or a directory, and
|
|
29
|
+
# a failed readlink leaves a trailing slash. Each case would take `pnpm` from the
|
|
30
|
+
# wrong directory — the substitution this script exists to prevent.
|
|
31
|
+
if [ -L "$self" ] || [ ! -f "$self" ]; then
|
|
32
|
+
echo "pnx: could not resolve $0 to a regular file within 40 symlink hops." >&2
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
exec "${self%/*}/pnpm" dlx "$@"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"packages":{".":{"url":"..","dependencies":{"get-pnpm":"get-pnpm","node-gyp":"node-gyp","pacquet":"."}},"@isaacs/fs-minipass":{"url":"./@isaacs/fs-minipass","dependencies":{"@isaacs/fs-minipass":"@isaacs/fs-minipass","minipass":"minipass"}},"abbrev":{"url":"./abbrev","dependencies":{"abbrev":"abbrev"}},"chownr":{"url":"./chownr","dependencies":{"chownr":"chownr"}},"env-paths":{"url":"./env-paths","dependencies":{"env-paths":"env-paths"}},"exponential-backoff":{"url":"./exponential-backoff","dependencies":{"exponential-backoff":"exponential-backoff"}},"fdir":{"url":"./fdir","dependencies":{"fdir":"fdir","picomatch":"picomatch"}},"get-pnpm":{"url":"./get-pnpm","dependencies":{"get-pnpm":"get-pnpm"}},"graceful-fs":{"url":"./graceful-fs","dependencies":{"graceful-fs":"graceful-fs"}},"isexe":{"url":"./isexe","dependencies":{"isexe":"isexe"}},"minipass":{"url":"./minipass","dependencies":{"minipass":"minipass"}},"minizlib":{"url":"./minizlib","dependencies":{"minipass":"minipass","minizlib":"minizlib"}},"node-gyp":{"url":"./node-gyp","dependencies":{"env-paths":"env-paths","exponential-backoff":"exponential-backoff","graceful-fs":"graceful-fs","node-gyp":"node-gyp","nopt":"nopt","proc-log":"proc-log","semver":"semver","tar":"tar","tinyglobby":"tinyglobby","undici":"undici","which":"which"}},"nopt":{"url":"./nopt","dependencies":{"abbrev":"abbrev","nopt":"nopt"}},"picomatch":{"url":"./picomatch","dependencies":{"picomatch":"picomatch"}},"proc-log":{"url":"./proc-log","dependencies":{"proc-log":"proc-log"}},"semver":{"url":"./semver","dependencies":{"semver":"semver"}},"tar":{"url":"./tar","dependencies":{"@isaacs/fs-minipass":"@isaacs/fs-minipass","chownr":"chownr","minipass":"minipass","minizlib":"minizlib","tar":"tar","yallist":"yallist"}},"tinyglobby":{"url":"./tinyglobby","dependencies":{"fdir":"fdir","picomatch":"picomatch","tinyglobby":"tinyglobby"}},"undici":{"url":"./undici","dependencies":{"undici":"undici"}},"which":{"url":"./which","dependencies":{"isexe":"isexe","which":"which"}},"yallist":{"url":"./yallist","dependencies":{"yallist":"yallist"}}}}
|