pnpm 12.14.0 → 12.16.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 +378 -0
- package/README.md +4 -4
- package/bin/pnpm.mjs +11 -233
- package/dist/node_modules/.pnpm-workspace-state-v1.json +97 -271
- package/dist/node_modules/confbox/LICENSE +27 -0
- package/dist/node_modules/confbox/dist/_chunks/_format.d.mts +22 -0
- package/dist/node_modules/confbox/dist/_chunks/_format.mjs +1 -0
- package/dist/node_modules/confbox/dist/_chunks/libs/detect-indent.mjs +1 -0
- package/dist/node_modules/confbox/dist/_chunks/libs/ini.mjs +3 -0
- package/dist/node_modules/confbox/dist/_chunks/libs/js-yaml.d.mts +33 -0
- package/dist/node_modules/confbox/dist/_chunks/libs/js-yaml.mjs +38 -0
- package/dist/node_modules/confbox/dist/_chunks/libs/json5.mjs +14 -0
- package/dist/node_modules/confbox/dist/_chunks/libs/smol-toml.mjs +11 -0
- package/dist/node_modules/confbox/dist/_chunks/libs/strip-json-comments.mjs +4 -0
- package/dist/node_modules/confbox/dist/_chunks/rolldown-runtime.mjs +1 -0
- package/dist/node_modules/confbox/dist/index.d.mts +7 -0
- package/dist/node_modules/confbox/dist/index.mjs +1 -0
- package/dist/node_modules/confbox/dist/ini.d.mts +59 -0
- package/dist/node_modules/confbox/dist/ini.mjs +1 -0
- package/dist/node_modules/confbox/dist/json.d.mts +25 -0
- package/dist/node_modules/confbox/dist/json.mjs +1 -0
- package/dist/node_modules/confbox/dist/json5.d.mts +55 -0
- package/dist/node_modules/confbox/dist/json5.mjs +1 -0
- package/dist/node_modules/confbox/dist/jsonc.d.mts +29 -0
- package/dist/node_modules/confbox/dist/jsonc.mjs +1 -0
- package/dist/node_modules/confbox/dist/toml.d.mts +20 -0
- package/dist/node_modules/confbox/dist/toml.mjs +1 -0
- package/dist/node_modules/confbox/dist/yaml.d.mts +101 -0
- package/dist/node_modules/confbox/dist/yaml.mjs +1 -0
- package/dist/node_modules/confbox/package.json +68 -0
- package/dist/node_modules/get-pnpm/lib/corepack.js +79 -0
- package/dist/node_modules/get-pnpm/lib/downloadExecutable.js +10 -4
- package/dist/node_modules/get-pnpm/lib/extractTarballMember.js +45 -35
- package/dist/node_modules/get-pnpm/lib/index.js +3 -219
- package/dist/node_modules/get-pnpm/lib/install.js +293 -0
- package/dist/node_modules/get-pnpm/lib/npmConfig.js +280 -0
- package/dist/node_modules/get-pnpm/lib/npmSigningKeys.js +2 -6
- package/dist/node_modules/get-pnpm/lib/platformPackageName.js +11 -7
- package/dist/node_modules/get-pnpm/lib/pnpmConfig.js +297 -0
- package/dist/node_modules/get-pnpm/lib/projectPin.js +201 -0
- package/dist/node_modules/get-pnpm/lib/registry.js +265 -41
- package/dist/node_modules/get-pnpm/lib/resolveVersion.js +19 -2
- package/dist/node_modules/get-pnpm/lib/sameFileContents.js +31 -27
- package/dist/node_modules/get-pnpm/lib/shadowingPnpm.js +174 -0
- package/dist/node_modules/get-pnpm/lib/undoHint.js +12 -0
- package/dist/node_modules/get-pnpm/package.json +20 -14
- package/dist/node_modules/undici/lib/dispatcher/agent.js +6 -2
- package/dist/node_modules/undici/lib/dispatcher/client-h1.js +0 -2
- package/dist/node_modules/undici/lib/dispatcher/client-h2.js +0 -4
- package/dist/node_modules/undici/lib/dispatcher/client.js +3 -2
- package/dist/node_modules/undici/lib/dispatcher/dispatcher-base.js +9 -0
- package/dist/node_modules/undici/lib/web/eventsource/eventsource-stream.js +91 -10
- package/dist/node_modules/undici/lib/web/eventsource/eventsource.js +4 -1
- package/dist/node_modules/undici/lib/web/fetch/index.js +7 -9
- package/dist/node_modules/undici/lib/web/websocket/receiver.js +14 -0
- package/dist/node_modules/undici/package.json +1 -1
- package/package.json +16 -16
package/bin/pnpm.mjs
CHANGED
|
@@ -15,15 +15,13 @@
|
|
|
15
15
|
// payload it ships node-gyp in. The placeholder's installs usually do carry
|
|
16
16
|
// that package, and the binary is taken from there.
|
|
17
17
|
//
|
|
18
|
-
// The download itself is `get-pnpm`, the
|
|
18
|
+
// The download itself is `get-pnpm`, the installer in ../../get-pnpm,
|
|
19
19
|
// which already knows how to verify one; it travels in that same `dist/`
|
|
20
|
-
// payload
|
|
21
|
-
//
|
|
22
|
-
import { Buffer } from 'node:buffer'
|
|
20
|
+
// payload, and reads the registry, credentials, and signing keys from pnpm's
|
|
21
|
+
// and Corepack's config.
|
|
23
22
|
import { spawnSync } from 'node:child_process'
|
|
24
23
|
import console from 'node:console'
|
|
25
24
|
import fs from 'node:fs'
|
|
26
|
-
import net from 'node:net'
|
|
27
25
|
import os from 'node:os'
|
|
28
26
|
import path from 'node:path'
|
|
29
27
|
import process from 'node:process'
|
|
@@ -37,7 +35,6 @@ const DOWNLOADED_BINARY = path.join(
|
|
|
37
35
|
process.platform === 'win32' ? 'pnpm-native.exe' : 'pnpm-native'
|
|
38
36
|
)
|
|
39
37
|
const GET_PNPM = new URL('../dist/node_modules/get-pnpm/lib/index.js', import.meta.url)
|
|
40
|
-
const DEFAULT_REGISTRY = 'https://registry.npmjs.org'
|
|
41
38
|
|
|
42
39
|
if ('webcontainer' in process.versions) {
|
|
43
40
|
fail('The pnpm package runs a native binary, which WebContainers cannot execute. Install @pnpm/wasm instead.')
|
|
@@ -70,242 +67,23 @@ async function nativeBinary () {
|
|
|
70
67
|
return DOWNLOADED_BINARY
|
|
71
68
|
}
|
|
72
69
|
|
|
73
|
-
if (process.env.COREPACK_ENABLE_NETWORK === '0') {
|
|
74
|
-
fail('Network access is disabled by the environment, so the pnpm binary cannot be downloaded.')
|
|
75
|
-
}
|
|
76
|
-
|
|
77
70
|
const { version } = readWrapperManifest()
|
|
78
|
-
|
|
79
|
-
const { downloadPnpmExecutable } = await import(GET_PNPM).catch((err) => {
|
|
71
|
+
const { corepackDownloadOptions, downloadPnpmExecutable } = await import(GET_PNPM).catch((err) => {
|
|
80
72
|
fail(`This copy of the pnpm package is missing the downloader it needs: ${err.message}`)
|
|
81
73
|
})
|
|
82
|
-
|
|
74
|
+
let options
|
|
83
75
|
try {
|
|
84
|
-
|
|
85
|
-
version,
|
|
86
|
-
destPath: DOWNLOADED_BINARY,
|
|
87
|
-
...registryAccess({ readProjectNpmrc: signature.verifySignature !== false }),
|
|
88
|
-
...signature,
|
|
89
|
-
})
|
|
76
|
+
options = corepackDownloadOptions()
|
|
90
77
|
} catch (err) {
|
|
91
|
-
fail(
|
|
92
|
-
}
|
|
93
|
-
return DOWNLOADED_BINARY
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* The registry to download from, and the headers to send it. Corepack's
|
|
98
|
-
* `COREPACK_NPM_REGISTRY` wins. Otherwise npm's sources decide, highest first:
|
|
99
|
-
* the environment, the project `.npmrc`, the user `.npmrc`.
|
|
100
|
-
*
|
|
101
|
-
* The project `.npmrc` is read only with `readProjectNpmrc`, which the caller
|
|
102
|
-
* passes while the download is checked against npm's signature. The signature
|
|
103
|
-
* pins the bytes, so a repository picks only where they come from. Unchecked,
|
|
104
|
-
* it would pick the binary itself, which is kept next to this wrapper and run
|
|
105
|
-
* in every later project (GHSA-j2hc-m6cf-6jm8). `get-pnpm` keeps the headers on
|
|
106
|
-
* the registry's origin, so a download host it names never receives them.
|
|
107
|
-
*/
|
|
108
|
-
function registryAccess ({ readProjectNpmrc }) {
|
|
109
|
-
const corepackRegistry = process.env.COREPACK_NPM_REGISTRY
|
|
110
|
-
if (corepackRegistry) {
|
|
111
|
-
return { registry: corepackRegistry, headers: corepackHeaders() }
|
|
78
|
+
fail(err.message)
|
|
112
79
|
}
|
|
113
|
-
|
|
114
|
-
if (readProjectNpmrc) {
|
|
115
|
-
Object.assign(npmrc, readNpmrc(path.join(projectDir(), '.npmrc'), projectEntry))
|
|
116
|
-
}
|
|
117
|
-
const registry = npmrc['@pnpm:registry'] || settingFromEnv('registry') || npmrc.registry
|
|
118
|
-
if (!registry) {
|
|
119
|
-
return { registry: DEFAULT_REGISTRY, headers: corepackHeaders() }
|
|
120
|
-
}
|
|
121
|
-
return { registry, headers: npmrcHeaders(npmrc, registry) }
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Credentials for Corepack's registry, read the way Corepack reads its own. */
|
|
125
|
-
function corepackHeaders () {
|
|
126
|
-
const { COREPACK_NPM_TOKEN, COREPACK_NPM_USERNAME, COREPACK_NPM_PASSWORD } = process.env
|
|
127
|
-
if (COREPACK_NPM_TOKEN) {
|
|
128
|
-
return { authorization: `Bearer ${COREPACK_NPM_TOKEN}` }
|
|
129
|
-
}
|
|
130
|
-
if (COREPACK_NPM_USERNAME && COREPACK_NPM_PASSWORD) {
|
|
131
|
-
return { authorization: `Basic ${base64(`${COREPACK_NPM_USERNAME}:${COREPACK_NPM_PASSWORD}`)}` }
|
|
132
|
-
}
|
|
133
|
-
return undefined
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function settingFromEnv (key) {
|
|
137
|
-
const upper = key.toUpperCase()
|
|
138
|
-
const { env } = process
|
|
139
|
-
return env[`pnpm_config_${key}`] || env[`PNPM_CONFIG_${upper}`] ||
|
|
140
|
-
env[`npm_config_${key}`] || env[`NPM_CONFIG_${upper}`] || undefined
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** The user `.npmrc`, with `${VAR}` placeholders expanded. */
|
|
144
|
-
function readUserNpmrc () {
|
|
145
|
-
return readNpmrc(
|
|
146
|
-
settingFromEnv('userconfig') || path.join(os.homedir(), '.npmrc'),
|
|
147
|
-
(key, value) => [expandEnv(key), expandEnv(value)]
|
|
148
|
-
)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* A project `.npmrc` entry, which is not expanded. One with a `${VAR}`
|
|
153
|
-
* placeholder in a registry setting or a credential is dropped, as pnpm drops
|
|
154
|
-
* it: a repository must not route the user's environment to a registry.
|
|
155
|
-
*/
|
|
156
|
-
function projectEntry (key, value, file) {
|
|
157
|
-
if (!key.includes('${') && !value.includes('${')) {
|
|
158
|
-
return [key, value]
|
|
159
|
-
}
|
|
160
|
-
if (key.startsWith('//') || key === 'registry' || key.endsWith(':registry')) {
|
|
161
|
-
console.error(`Ignored ${key} from ${file}: a project .npmrc cannot use environment variables in registry settings or credentials.`)
|
|
162
|
-
}
|
|
163
|
-
return undefined
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/** Where pnpm reads the project `.npmrc`: the workspace root, or else the current directory. */
|
|
167
|
-
function projectDir () {
|
|
168
|
-
const cwd = process.cwd()
|
|
169
|
-
for (let dir = cwd; ; dir = path.dirname(dir)) {
|
|
170
|
-
if (fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
|
|
171
|
-
return dir
|
|
172
|
-
}
|
|
173
|
-
if (path.dirname(dir) === dir) {
|
|
174
|
-
return cwd
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* The top-level settings of the `.npmrc` at `file`, each passed through
|
|
181
|
-
* `parseEntry`, which returns the `[key, value]` to keep or `undefined`.
|
|
182
|
-
*/
|
|
183
|
-
function readNpmrc (file, parseEntry) {
|
|
184
|
-
const settings = Object.create(null)
|
|
185
|
-
let text
|
|
186
|
-
try {
|
|
187
|
-
text = fs.readFileSync(file, 'utf8')
|
|
188
|
-
} catch (err) {
|
|
189
|
-
if (err.code !== 'ENOENT' && err.code !== 'EISDIR') {
|
|
190
|
-
console.error(`Could not read ${file}, so its settings are not used: ${err.message}`)
|
|
191
|
-
}
|
|
192
|
-
return settings
|
|
193
|
-
}
|
|
194
|
-
for (const rawLine of text.split(/\r?\n/)) {
|
|
195
|
-
const line = rawLine.trim()
|
|
196
|
-
// Settings under a `[section]` are not top-level ones.
|
|
197
|
-
if (line.startsWith('[')) {
|
|
198
|
-
break
|
|
199
|
-
}
|
|
200
|
-
const separator = line.indexOf('=')
|
|
201
|
-
if (separator === -1 || line.startsWith(';') || line.startsWith('#')) {
|
|
202
|
-
continue
|
|
203
|
-
}
|
|
204
|
-
const entry = parseEntry(line.slice(0, separator).trim(), unquote(line.slice(separator + 1).trim()), file)
|
|
205
|
-
if (entry != null) {
|
|
206
|
-
settings[entry[0]] = entry[1]
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return settings
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function unquote (value) {
|
|
213
|
-
const quoted = value.length >= 2 && (value[0] === '"' || value[0] === "'") && value.at(-1) === value[0]
|
|
214
|
-
return quoted ? value.slice(1, -1) : value
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function expandEnv (value) {
|
|
218
|
-
return value.replace(/\$\{([^${}]+)\}/g, (_, name) => process.env[name] ?? '')
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* The credentials the `.npmrc` holds for `registry`, looked up as pnpm looks
|
|
223
|
-
* them up for an `@pnpm` package: the `@pnpm` scope's own credentials first,
|
|
224
|
-
* then the registry-wide ones. Each is the longest `//host[:port]/path/`
|
|
225
|
-
* prefix of the registry URL that has any, then the same without the port.
|
|
226
|
-
* They are sent only over HTTPS or to the local machine.
|
|
227
|
-
*/
|
|
228
|
-
function npmrcHeaders (npmrc, registry) {
|
|
229
|
-
const url = new URL(registry.endsWith('/') ? registry : `${registry}/`)
|
|
230
|
-
if (url.protocol !== 'https:' && !(url.protocol === 'http:' && isLoopback(url.hostname))) {
|
|
231
|
-
return undefined
|
|
232
|
-
}
|
|
233
|
-
const prefixes = []
|
|
234
|
-
for (const host of new Set([url.host, url.hostname])) {
|
|
235
|
-
for (let pathname = url.pathname; ; pathname = pathname.slice(0, pathname.lastIndexOf('/', pathname.length - 2) + 1)) {
|
|
236
|
-
prefixes.push(`//${host}${pathname}`)
|
|
237
|
-
if (pathname === '/') {
|
|
238
|
-
break
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
for (const scope of [':@pnpm', '']) {
|
|
243
|
-
for (const prefix of prefixes) {
|
|
244
|
-
const authorization = npmrcAuthorization(npmrc, `${prefix}${scope}`)
|
|
245
|
-
if (authorization != null) {
|
|
246
|
-
return { authorization }
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return undefined
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function isLoopback (hostname) {
|
|
254
|
-
return hostname === 'localhost' || hostname === '[::1]' ||
|
|
255
|
-
(net.isIPv4(hostname) && hostname.startsWith('127.'))
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function npmrcAuthorization (npmrc, prefix) {
|
|
259
|
-
const token = npmrc[`${prefix}:_authToken`]
|
|
260
|
-
if (token) {
|
|
261
|
-
return `Bearer ${token}`
|
|
262
|
-
}
|
|
263
|
-
const auth = npmrc[`${prefix}:_auth`]
|
|
264
|
-
if (auth) {
|
|
265
|
-
return `Basic ${auth}`
|
|
266
|
-
}
|
|
267
|
-
const username = npmrc[`${prefix}:username`]
|
|
268
|
-
const password = npmrc[`${prefix}:_password`]
|
|
269
|
-
if (username && password) {
|
|
270
|
-
return `Basic ${base64(`${username}:${Buffer.from(password, 'base64').toString('utf8')}`)}`
|
|
271
|
-
}
|
|
272
|
-
return undefined
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function base64 (text) {
|
|
276
|
-
return Buffer.from(text, 'utf8').toString('base64')
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Whose signature over the download to trust, following `COREPACK_INTEGRITY_KEYS`
|
|
281
|
-
* exactly as Corepack does: npm's own keys when it is unset, the keys it names
|
|
282
|
-
* when it holds a key set, and no signature check at all when it is `0` or
|
|
283
|
-
* empty — which is the state a registry that re-publishes packages, and
|
|
284
|
-
* therefore carries no npm signatures, already has to be in for Corepack to
|
|
285
|
-
* have installed this wrapper from it.
|
|
286
|
-
*/
|
|
287
|
-
function signaturePolicy () {
|
|
288
|
-
const configured = process.env.COREPACK_INTEGRITY_KEYS
|
|
289
|
-
if (configured == null) {
|
|
290
|
-
return {}
|
|
291
|
-
}
|
|
292
|
-
if (configured === '' || configured === '0') {
|
|
293
|
-
return { verifySignature: false }
|
|
294
|
-
}
|
|
295
|
-
let keys
|
|
80
|
+
console.error(`Downloading the pnpm ${version} binary for ${process.platform}-${process.arch}...`)
|
|
296
81
|
try {
|
|
297
|
-
|
|
82
|
+
await downloadPnpmExecutable({ version, destPath: DOWNLOADED_BINARY, ...options })
|
|
298
83
|
} catch (err) {
|
|
299
|
-
fail(`
|
|
300
|
-
}
|
|
301
|
-
// An absent or malformed `npm` entry would otherwise be passed on as no keys
|
|
302
|
-
// at all, which falls back to npm's own — the opposite of what setting the
|
|
303
|
-
// variable asked for. An empty set is left alone: it names no key to trust,
|
|
304
|
-
// and Corepack reads it the same way, so every download is refused.
|
|
305
|
-
if (!Array.isArray(keys)) {
|
|
306
|
-
fail('COREPACK_INTEGRITY_KEYS holds no "npm" key set to verify the pnpm binary against.')
|
|
84
|
+
fail(`Could not download the pnpm ${version} binary: ${err.message}`)
|
|
307
85
|
}
|
|
308
|
-
return
|
|
86
|
+
return DOWNLOADED_BINARY
|
|
309
87
|
}
|
|
310
88
|
|
|
311
89
|
function fail (message) {
|