pnpm 12.15.0 → 12.16.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +213 -0
  2. package/README.md +4 -4
  3. package/bin/pnpm.mjs +11 -233
  4. package/dist/node_modules/.pnpm-workspace-state-v1.json +97 -269
  5. package/dist/node_modules/confbox/LICENSE +27 -0
  6. package/dist/node_modules/confbox/dist/_chunks/_format.d.mts +22 -0
  7. package/dist/node_modules/confbox/dist/_chunks/_format.mjs +1 -0
  8. package/dist/node_modules/confbox/dist/_chunks/libs/detect-indent.mjs +1 -0
  9. package/dist/node_modules/confbox/dist/_chunks/libs/ini.mjs +3 -0
  10. package/dist/node_modules/confbox/dist/_chunks/libs/js-yaml.d.mts +33 -0
  11. package/dist/node_modules/confbox/dist/_chunks/libs/js-yaml.mjs +38 -0
  12. package/dist/node_modules/confbox/dist/_chunks/libs/json5.mjs +14 -0
  13. package/dist/node_modules/confbox/dist/_chunks/libs/smol-toml.mjs +11 -0
  14. package/dist/node_modules/confbox/dist/_chunks/libs/strip-json-comments.mjs +4 -0
  15. package/dist/node_modules/confbox/dist/_chunks/rolldown-runtime.mjs +1 -0
  16. package/dist/node_modules/confbox/dist/index.d.mts +7 -0
  17. package/dist/node_modules/confbox/dist/index.mjs +1 -0
  18. package/dist/node_modules/confbox/dist/ini.d.mts +59 -0
  19. package/dist/node_modules/confbox/dist/ini.mjs +1 -0
  20. package/dist/node_modules/confbox/dist/json.d.mts +25 -0
  21. package/dist/node_modules/confbox/dist/json.mjs +1 -0
  22. package/dist/node_modules/confbox/dist/json5.d.mts +55 -0
  23. package/dist/node_modules/confbox/dist/json5.mjs +1 -0
  24. package/dist/node_modules/confbox/dist/jsonc.d.mts +29 -0
  25. package/dist/node_modules/confbox/dist/jsonc.mjs +1 -0
  26. package/dist/node_modules/confbox/dist/toml.d.mts +20 -0
  27. package/dist/node_modules/confbox/dist/toml.mjs +1 -0
  28. package/dist/node_modules/confbox/dist/yaml.d.mts +101 -0
  29. package/dist/node_modules/confbox/dist/yaml.mjs +1 -0
  30. package/dist/node_modules/confbox/package.json +68 -0
  31. package/dist/node_modules/get-pnpm/lib/corepack.js +79 -0
  32. package/dist/node_modules/get-pnpm/lib/downloadExecutable.js +10 -4
  33. package/dist/node_modules/get-pnpm/lib/extractTarballMember.js +45 -35
  34. package/dist/node_modules/get-pnpm/lib/index.js +3 -219
  35. package/dist/node_modules/get-pnpm/lib/install.js +293 -0
  36. package/dist/node_modules/get-pnpm/lib/npmConfig.js +280 -0
  37. package/dist/node_modules/get-pnpm/lib/npmSigningKeys.js +2 -6
  38. package/dist/node_modules/get-pnpm/lib/platformPackageName.js +11 -7
  39. package/dist/node_modules/get-pnpm/lib/pnpmConfig.js +297 -0
  40. package/dist/node_modules/get-pnpm/lib/projectPin.js +201 -0
  41. package/dist/node_modules/get-pnpm/lib/registry.js +265 -41
  42. package/dist/node_modules/get-pnpm/lib/resolveVersion.js +19 -2
  43. package/dist/node_modules/get-pnpm/lib/sameFileContents.js +31 -27
  44. package/dist/node_modules/get-pnpm/lib/shadowingPnpm.js +174 -0
  45. package/dist/node_modules/get-pnpm/lib/undoHint.js +12 -0
  46. package/dist/node_modules/get-pnpm/package.json +20 -14
  47. package/package.json +15 -15
@@ -0,0 +1,293 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { extractTarball } from './extractTarball.js';
6
+ import { registryConfigFromEnv } from './npmConfig.js';
7
+ import { isMusl, platformPackageName } from './platformPackageName.js';
8
+ import { readProjectPin } from './projectPin.js';
9
+ import { downloadTarball, fetchPackument, fetchSignatures, fetchVersionMeta, useCertificateAuthorities, useProxyFromEnv } from './registry.js';
10
+ import { majorVersion, resolveVersion } from './resolveVersion.js';
11
+ import { findShadowingPnpm, pnpmHomeDir, renderShadowingPnpmWarning } from './shadowingPnpm.js';
12
+ import { renderUndoHint } from './undoHint.js';
13
+ import { verifyRegistrySignature } from './verifySignature.js';
14
+ /**
15
+ * The package whose dist-tags name every pnpm release. `@pnpm/exe` carries the
16
+ * same versions today, but only `pnpm` is published from v12 onward, so its
17
+ * tags are the ones that cannot go stale.
18
+ */
19
+ const CLI_PKG_NAME = 'pnpm';
20
+ /** Holds the unpacked tarballs while the installation is assembled beside it. */
21
+ const UNPACK_DIR = '.unpack';
22
+ /** Where the `dist/` tree that ships beside the executable is published. */
23
+ function wrapperPackageName(major) {
24
+ return major >= 12 ? CLI_PKG_NAME : '@pnpm/exe';
25
+ }
26
+ const USAGE = `Usage: npx get-pnpm [version]
27
+
28
+ Installs pnpm as a standalone executable and adds it to your PATH.
29
+
30
+ Arguments:
31
+ version An exact version (11.20.0), a major (12), a semver range
32
+ (^12.1.0), or a dist-tag (latest, next-12). Defaults to
33
+ $PNPM_VERSION, then the version the project in the current
34
+ directory pins, then "latest".
35
+
36
+ The project's pin is read from devEngines.packageManager
37
+ or packageManager in its manifest, or the workspace
38
+ root's for a workspace project, the way pnpm reads it. A
39
+ range resolves to the version pnpm-lock.yaml records
40
+ while that is still in range.
41
+
42
+ Environment variables:
43
+ PNPM_VERSION Version to install when no argument is given.
44
+ PNPM_HOME Directory to install pnpm into.
45
+ npm_config_registry Registry to download pnpm from.
46
+ npm_config_*:_authToken
47
+ Registry-scoped bearer token. Project, user, and
48
+ global .npmrc auth tokens are also read.
49
+ npm_config_ca, npm_config_cafile
50
+ CA certificates to trust for the registry, besides
51
+ Node.js's own. Project, user, and global .npmrc ca,
52
+ ca[], and cafile settings, top-level or scoped to the
53
+ registry, are also read. Node 22.19/24.5 or later.
54
+ HTTPS_PROXY Proxy to download through (HTTP_PROXY for an http://
55
+ registry); NO_PROXY names hosts to reach directly.
56
+ Node 24.14 or later.
57
+ `;
58
+ export async function runCli(argv) {
59
+ const positional = [];
60
+ for (const arg of argv) {
61
+ if (arg === '--help' || arg === '-h') {
62
+ console.log(USAGE);
63
+ return 0;
64
+ }
65
+ if (arg.startsWith('-')) {
66
+ throw new Error(`Unknown option "${arg}".\n\n${USAGE}`);
67
+ }
68
+ positional.push(arg);
69
+ }
70
+ if (positional.length > 1) {
71
+ throw new Error(`Expected at most one version, got ${positional.length}.\n\n${USAGE}`);
72
+ }
73
+ const registryConfig = registryConfigFromEnv();
74
+ return installPnpm({
75
+ versionSpec: positional[0] ?? process.env.PNPM_VERSION ?? projectVersionSpec(process.cwd()) ?? 'latest',
76
+ ...registryConfig,
77
+ });
78
+ }
79
+ /** The version `readProjectPin` finds for `dir`, saying where it comes from. */
80
+ function projectVersionSpec(dir) {
81
+ const pin = readProjectPin(dir);
82
+ if (pin == null)
83
+ return undefined;
84
+ const locked = pin.lockedVersion == null ? '' : `, locked to ${pin.lockedVersion} in pnpm-lock.yaml`;
85
+ console.log(`==> ${pin.manifestPath} pins pnpm ${pin.spec} in ${pin.field}${locked}`);
86
+ return pin.lockedVersion ?? pin.spec;
87
+ }
88
+ /**
89
+ * Downloads the pnpm executable and hands over to `pnpm setup`, which installs
90
+ * it globally and puts it on the PATH.
91
+ *
92
+ * Every download is checked against the checksum the registry published for it,
93
+ * and that checksum against npm's signature — see `verifyRegistrySignature`.
94
+ *
95
+ * The temporary directory is assembled to look like the release tarball that
96
+ * https://get.pnpm.io/install.sh downloads — the executable next to its `dist/`
97
+ * tree — because `pnpm setup` installs that directory as-is.
98
+ *
99
+ * @returns the exit code of `pnpm setup`.
100
+ */
101
+ export async function installPnpm(opts) {
102
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pnpm-install-'));
103
+ const removeTmpDir = () => {
104
+ fs.rmSync(tmpDir, { recursive: true, force: true });
105
+ };
106
+ // Registered for the duration of the call and no longer: this is also a
107
+ // library function, and handlers left behind would accumulate and outlive the
108
+ // directory they exist to clean up.
109
+ const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
110
+ const onSignal = () => {
111
+ removeTmpDir();
112
+ // eslint-disable-next-line n/no-process-exit -- a signal listener replaces the default handling, which would have ended the process
113
+ process.exit(1);
114
+ };
115
+ for (const signal of signals) {
116
+ process.once(signal, onSignal);
117
+ }
118
+ try {
119
+ const { binPath } = await downloadPnpm({ ...opts, dest: tmpDir });
120
+ const { error, status } = spawnSync(binPath, ['setup', '--force'], { stdio: 'inherit' });
121
+ if (error != null)
122
+ throw error;
123
+ if (status === 0) {
124
+ console.log(renderUndoHint(pnpmHomeDir()));
125
+ warnIfPnpmIsShadowed();
126
+ }
127
+ return status ?? 1;
128
+ }
129
+ finally {
130
+ for (const signal of signals) {
131
+ process.off(signal, onSignal);
132
+ }
133
+ removeTmpDir();
134
+ }
135
+ }
136
+ /**
137
+ * Says so when the pnpm `pnpm setup` just installed is not the one PATH
138
+ * resolves, or the success above is the last thing the person reads before
139
+ * `pnpm --version` prints the old version again.
140
+ */
141
+ function warnIfPnpmIsShadowed() {
142
+ const pnpmHome = pnpmHomeDir();
143
+ const shadowing = findShadowingPnpm(pnpmHome, { pathEnv: readPathEnv(process.env) });
144
+ if (shadowing != null) {
145
+ console.error(renderShadowingPnpmWarning(shadowing, pnpmHome));
146
+ }
147
+ }
148
+ /** Windows spells the variable `Path`, and the environment is case-insensitive there. */
149
+ function readPathEnv(env) {
150
+ if (process.platform !== 'win32')
151
+ return env.PATH;
152
+ const key = Object.keys(env).find((name) => name.toUpperCase() === 'PATH');
153
+ return key != null ? env[key] : undefined;
154
+ }
155
+ /**
156
+ * Downloads the pnpm executable into `dest`, laid out the way the release
157
+ * tarball lays it out — the executable next to the `dist/` tree it loads.
158
+ *
159
+ * Every download is checked against the checksum the registry published for it,
160
+ * and that checksum against npm's signature; see `verifyRegistrySignature`.
161
+ * Nothing outside `dest` is touched, so a caller that manages its own PATH — a
162
+ * CI action, say — can use this without the global install `installPnpm` does.
163
+ *
164
+ * @returns the version installed and the path to the executable.
165
+ */
166
+ export async function downloadPnpm(opts) {
167
+ const restoreProxy = useProxyFromEnv();
168
+ try {
169
+ const restoreCertificates = useCertificateAuthorities(opts.ca);
170
+ try {
171
+ return await fetchPnpm(opts);
172
+ }
173
+ finally {
174
+ restoreCertificates();
175
+ }
176
+ }
177
+ finally {
178
+ restoreProxy();
179
+ }
180
+ }
181
+ async function fetchPnpm(opts) {
182
+ const packument = await fetchPackument(opts.registry, CLI_PKG_NAME, opts.headers, opts.authPath);
183
+ const version = resolveVersion(packument, opts.versionSpec);
184
+ const major = majorVersion(version);
185
+ const platformPkgName = platformPackageName({
186
+ major,
187
+ platform: process.platform,
188
+ arch: process.arch,
189
+ musl: isMusl(),
190
+ });
191
+ const { dest } = opts;
192
+ fs.mkdirSync(dest, { recursive: true });
193
+ try {
194
+ console.log(`==> Downloading pnpm ${version}`);
195
+ const executable = process.platform === 'win32' ? 'pnpm.exe' : 'pnpm';
196
+ const fetchPackage = verifiedPackageFetcher({
197
+ dir: dest,
198
+ registry: opts.registry,
199
+ version,
200
+ authPath: opts.authPath,
201
+ headers: opts.headers,
202
+ keys: opts.keys,
203
+ });
204
+ const { platformPkg, wrapperPkg } = await fetchPackages(fetchPackage, platformPkgName, major);
205
+ const binPath = path.join(dest, executable);
206
+ fs.renameSync(path.join(platformPkg.dir, executable), binPath);
207
+ fs.chmodSync(binPath, 0o755);
208
+ if (wrapperPkg != null) {
209
+ fs.rmSync(path.join(dest, 'dist'), { recursive: true, force: true });
210
+ fs.renameSync(path.join(wrapperPkg.dir, 'dist'), path.join(dest, 'dist'));
211
+ writeManifest({ dest, executable, version, wrapperDir: wrapperPkg.dir, major });
212
+ }
213
+ return { version, binPath };
214
+ }
215
+ finally {
216
+ // `pnpm setup` installs this directory as a package, so nothing may be left
217
+ // in it that does not belong in the installation.
218
+ fs.rmSync(path.join(dest, UNPACK_DIR), { recursive: true, force: true });
219
+ }
220
+ }
221
+ async function fetchPackages(fetchPackage, platformPkgName, major) {
222
+ // Settled, not `all`: a rejection there would leave the other fetch writing
223
+ // into the directory the caller is about to remove.
224
+ const [platformResult, wrapperResult] = await Promise.allSettled([
225
+ fetchPackage(platformPkgName),
226
+ // v11 was the first release to keep files next to the executable; up to
227
+ // v10 the executable is self-contained and ships no `dist/`.
228
+ major >= 11 ? fetchPackage(wrapperPackageName(major)) : Promise.resolve(undefined),
229
+ ]);
230
+ if (platformResult.status === 'rejected')
231
+ throw platformResult.reason;
232
+ if (wrapperResult.status === 'rejected')
233
+ throw wrapperResult.reason;
234
+ return { platformPkg: platformResult.value, wrapperPkg: wrapperResult.value };
235
+ }
236
+ /**
237
+ * `pnpm setup` installs the directory as a package, writing a minimal manifest
238
+ * when there is none — which is what the release tarball relies on. That
239
+ * tarball bundles the runtime dependencies inside `dist/`; the registry copy
240
+ * declares them instead, so up to v11 they have to be declared here or the
241
+ * install silently loses them (`@reflink/reflink`, and with it copy-on-write
242
+ * cloning). From v12 the `dist/` tree is self-contained again, so the manifest
243
+ * `setup` writes is left to it.
244
+ */
245
+ function writeManifest(opts) {
246
+ if (opts.major >= 12)
247
+ return;
248
+ const wrapper = JSON.parse(fs.readFileSync(path.join(opts.wrapperDir, 'package.json'), 'utf8'));
249
+ if (wrapper.dependencies == null)
250
+ return;
251
+ fs.writeFileSync(path.join(opts.dest, 'package.json'), JSON.stringify({
252
+ name: '@pnpm/exe',
253
+ version: opts.version,
254
+ type: 'module',
255
+ bin: { pnpm: opts.executable, pn: opts.executable },
256
+ dependencies: wrapper.dependencies,
257
+ }));
258
+ }
259
+ /** Downloads packages of one version into one directory, verifying each. */
260
+ function verifiedPackageFetcher(opts) {
261
+ return async function fetchPackage(pkgName) {
262
+ const meta = await fetchVersionMeta(opts.registry, pkgName, opts.version, opts.headers, opts.authPath);
263
+ if (!meta.dist.integrity) {
264
+ throw new Error(`The npm registry published no checksum for ${pkgName}@${opts.version}, so it cannot be verified.`);
265
+ }
266
+ verifyRegistrySignature({
267
+ name: pkgName,
268
+ version: opts.version,
269
+ integrity: meta.dist.integrity,
270
+ signatures: await fetchSignatures(meta, {
271
+ registry: opts.registry,
272
+ pkgName,
273
+ version: opts.version,
274
+ headers: opts.headers,
275
+ headersPath: opts.authPath,
276
+ }),
277
+ keys: opts.keys,
278
+ });
279
+ // Unpack away from the directory being assembled: `pnpm` is both a package
280
+ // name and the name of the executable that ends up beside it.
281
+ const unpackDir = path.join(opts.dir, UNPACK_DIR, pkgName.replaceAll('/', '-'));
282
+ const tarball = `${unpackDir}.tgz`;
283
+ fs.mkdirSync(path.dirname(tarball), { recursive: true });
284
+ await downloadTarball(meta, tarball, {
285
+ registry: opts.registry,
286
+ headers: opts.headers,
287
+ headersPath: opts.authPath,
288
+ });
289
+ extractTarball(tarball, unpackDir);
290
+ fs.rmSync(tarball);
291
+ return { dir: path.join(unpackDir, 'package') };
292
+ };
293
+ }
@@ -0,0 +1,280 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { DEFAULT_REGISTRY, isUrlSecureForCredentials, normalizeRegistry } from './registry.js';
5
+ export function registryConfigFromEnv(opts = {}) {
6
+ const env = opts.env ?? process.env;
7
+ const cwd = opts.cwd ?? process.cwd();
8
+ const rawRegistry = env.npm_config_registry ?? env.NPM_CONFIG_REGISTRY ?? DEFAULT_REGISTRY;
9
+ const embedded = registryAndEmbeddedAuth(rawRegistry);
10
+ const registry = embedded.registry;
11
+ // Highest precedence first, as npm layers them.
12
+ const sources = [
13
+ envSource(env, cwd),
14
+ ...[
15
+ ...projectNpmrcs(cwd, env),
16
+ userNpmrc(opts, env),
17
+ globalNpmrc(opts, env),
18
+ ].map((candidate) => readNpmrc(candidate, env)),
19
+ ];
20
+ const ca = certificateAuthorities(registry, sources);
21
+ const auth = embedded.headers != null ? embedded : tokenAuth(registry, sources);
22
+ return { ...auth, ...(ca.length > 0 ? { ca } : {}) };
23
+ }
24
+ function tokenAuth(registry, sources) {
25
+ if (!isUrlSecureForCredentials(new URL(registry)))
26
+ return { registry };
27
+ const token = mostSpecificToken(sources.map((source) => tokenForRegistry(registry, source.entries)));
28
+ return token == null
29
+ ? { registry }
30
+ : {
31
+ registry,
32
+ authPath: token.pathname,
33
+ headers: { authorization: `Bearer ${token.token}` },
34
+ };
35
+ }
36
+ function registryAndEmbeddedAuth(rawRegistry) {
37
+ const url = new URL(normalizeRegistry(rawRegistry));
38
+ if (!url.username && !url.password)
39
+ return { registry: url.href };
40
+ const username = decodeURIComponent(url.username);
41
+ const password = decodeURIComponent(url.password);
42
+ url.username = '';
43
+ url.password = '';
44
+ return {
45
+ registry: url.href,
46
+ authPath: normalizedPath(url.pathname),
47
+ headers: {
48
+ authorization: `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`,
49
+ },
50
+ };
51
+ }
52
+ /**
53
+ * The `npm_config_*` variables. npm sets them for the programs it runs, a
54
+ * `ca` array joined into one value.
55
+ */
56
+ function envSource(env, cwd) {
57
+ const entries = [];
58
+ for (const [name, value] of Object.entries(env)) {
59
+ if (value == null || !name.toLowerCase().startsWith('npm_config_'))
60
+ continue;
61
+ const key = name.slice('npm_config_'.length);
62
+ // npm's own names are lowercase; only a URL-scoped key keeps its case.
63
+ entries.push([key.startsWith('//') ? key : key.toLowerCase(), value]);
64
+ }
65
+ return { dir: cwd, entries };
66
+ }
67
+ function readNpmrc(npmrc, env) {
68
+ const dir = path.dirname(npmrc.path);
69
+ const text = readNpmrcText(npmrc);
70
+ if (text == null)
71
+ return { dir, entries: [] };
72
+ const entries = [];
73
+ for (const rawLine of text.split(/\r?\n/)) {
74
+ const entry = parseNpmrcLine(rawLine.trim(), env);
75
+ if (entry != null)
76
+ entries.push(entry);
77
+ }
78
+ return { dir, entries };
79
+ }
80
+ /** The text of `npmrc`, or `undefined` when there is none to read. */
81
+ function readNpmrcText(npmrc) {
82
+ try {
83
+ return fs.readFileSync(npmrc.path, 'utf8');
84
+ }
85
+ catch (err) {
86
+ if (isErrno(err, 'ENOENT'))
87
+ return undefined;
88
+ if (npmrc.ignoreUnreadable && isUnreadableNpmrcError(err))
89
+ return undefined;
90
+ throw err;
91
+ }
92
+ }
93
+ function parseNpmrcLine(line, env) {
94
+ if (!line || line.startsWith('#') || line.startsWith(';'))
95
+ return undefined;
96
+ const separator = line.indexOf('=');
97
+ if (separator === -1)
98
+ return undefined;
99
+ const key = line.slice(0, separator).trim();
100
+ const value = expandEnv(stripQuotes(line.slice(separator + 1).trim()), env);
101
+ return value == null ? undefined : [key, value];
102
+ }
103
+ function tokenForRegistry(registry, entries) {
104
+ const registryUrl = new URL(registry);
105
+ let best;
106
+ for (const [key, token] of entries) {
107
+ if (token === '')
108
+ continue;
109
+ const scope = authTokenScope(key, registryUrl.protocol);
110
+ if (scope == null || !scopeCovers(scope, registryUrl))
111
+ continue;
112
+ // A longer prefix wins; at equal length, the later entry does.
113
+ if (best == null || scope.pathname.length >= best.pathname.length) {
114
+ best = { pathname: scope.pathname, token };
115
+ }
116
+ }
117
+ return best;
118
+ }
119
+ function mostSpecificToken(candidates) {
120
+ let best;
121
+ for (const candidate of candidates) {
122
+ if (candidate == null)
123
+ continue;
124
+ if (best == null || candidate.pathname.length > best.pathname.length)
125
+ best = candidate;
126
+ }
127
+ return best;
128
+ }
129
+ function authTokenScope(key, protocol) {
130
+ return registryScope(key, ':_authtoken', protocol);
131
+ }
132
+ /**
133
+ * The CA certificates the config adds for `registry`: those of the
134
+ * highest-precedence source that sets a top-level `ca`, `ca[]`, or `cafile`,
135
+ * and those scoped to the longest `//host/path/` prefix of `registry`. A
136
+ * `cafile` that cannot be read adds nothing, as in pnpm.
137
+ */
138
+ export function certificateAuthorities(registry, sources) {
139
+ const topLevel = sources.find((source) => source.entries.some(([key]) => CA_SETTINGS.includes(key)));
140
+ const settings = (topLevel?.entries ?? [])
141
+ .filter(([key]) => CA_SETTINGS.includes(key))
142
+ .map(([setting, value]) => ({ dir: topLevel.dir, setting, value }));
143
+ settings.push(...scopedCaSettings(registry, sources));
144
+ return settings.flatMap(({ dir, setting, value }) => pemCertificates(setting === 'cafile' ? readCaFile(path.resolve(dir, value)) : value.replaceAll('\\n', '\n')));
145
+ }
146
+ const CA_SETTINGS = ['ca', 'ca[]', 'cafile'];
147
+ /** A longer prefix wins; at equal length, the higher-precedence source does. */
148
+ function scopedCaSettings(registry, sources) {
149
+ const registryUrl = new URL(registry);
150
+ const scoped = sources.flatMap((source, sourceIndex) => source.entries.flatMap(([key, value]) => {
151
+ const scope = value === '' ? undefined : caSettingScope(key, registryUrl);
152
+ return scope == null ? [] : [{ sourceIndex, dir: source.dir, value, ...scope }];
153
+ }));
154
+ const longest = Math.max(...scoped.map(({ pathname }) => pathname.length));
155
+ const winner = scoped.find(({ pathname }) => pathname.length === longest);
156
+ return scoped.filter(({ sourceIndex, pathname }) => sourceIndex === winner?.sourceIndex && pathname.length === longest);
157
+ }
158
+ /** The CA setting `key` scopes to a prefix of `registryUrl`, if it is one. */
159
+ function caSettingScope(key, registryUrl) {
160
+ for (const setting of CA_SETTINGS) {
161
+ const scope = registryScope(key, `:${setting}`, registryUrl.protocol);
162
+ if (scope == null)
163
+ continue;
164
+ return scopeCovers(scope, registryUrl) ? { pathname: scope.pathname, setting } : undefined;
165
+ }
166
+ return undefined;
167
+ }
168
+ function scopeCovers(scope, registryUrl) {
169
+ return scope.host === registryUrl.host.toLowerCase() && registryUrl.pathname.startsWith(scope.pathname);
170
+ }
171
+ function readCaFile(file) {
172
+ try {
173
+ return fs.readFileSync(file, 'utf8');
174
+ }
175
+ catch {
176
+ return '';
177
+ }
178
+ }
179
+ function pemCertificates(text) {
180
+ return text.match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g) ?? [];
181
+ }
182
+ function registryScope(key, suffix, protocol) {
183
+ const lower = key.toLowerCase();
184
+ if (!lower.endsWith(suffix))
185
+ return undefined;
186
+ const rawScope = key.slice(0, -suffix.length);
187
+ if (!rawScope.startsWith('//'))
188
+ return undefined;
189
+ try {
190
+ const url = new URL(`${protocol}${rawScope}`);
191
+ return {
192
+ host: url.host.toLowerCase(),
193
+ pathname: normalizedPath(url.pathname),
194
+ };
195
+ }
196
+ catch {
197
+ return undefined;
198
+ }
199
+ }
200
+ function projectNpmrcs(cwd, env) {
201
+ const configured = env.npm_config_local_prefix ?? env.NPM_CONFIG_LOCAL_PREFIX;
202
+ if (configured != null) {
203
+ return [{ path: path.join(configured, '.npmrc'), ignoreUnreadable: false }];
204
+ }
205
+ const current = path.resolve(cwd);
206
+ const root = findProjectRoot(current);
207
+ const paths = [path.join(current, '.npmrc')];
208
+ if (root !== current)
209
+ paths.push(path.join(root, '.npmrc'));
210
+ return paths.map((npmrcPath) => ({ path: npmrcPath, ignoreUnreadable: true }));
211
+ }
212
+ function findProjectRoot(cwd) {
213
+ const start = path.resolve(cwd);
214
+ let current = start;
215
+ while (true) {
216
+ if (fs.existsSync(path.join(current, 'package.json')))
217
+ return current;
218
+ const parent = path.dirname(current);
219
+ if (parent === current)
220
+ return start;
221
+ current = parent;
222
+ }
223
+ }
224
+ function userNpmrc(opts, env) {
225
+ const configured = env.npm_config_userconfig ?? env.NPM_CONFIG_USERCONFIG;
226
+ return configured != null
227
+ ? { path: configured, ignoreUnreadable: false }
228
+ : { path: path.join(npmHomeDir(opts, env), '.npmrc'), ignoreUnreadable: true };
229
+ }
230
+ function globalNpmrc(opts, env) {
231
+ const configured = env.npm_config_globalconfig ?? env.NPM_CONFIG_GLOBALCONFIG;
232
+ if (configured != null)
233
+ return { path: configured, ignoreUnreadable: false };
234
+ const platform = opts.platform ?? process.platform;
235
+ const homeDir = npmHomeDir(opts, env);
236
+ const prefix = env.npm_config_prefix ??
237
+ env.NPM_CONFIG_PREFIX ??
238
+ (platform === 'win32'
239
+ ? path.join(env.APPDATA ?? path.join(homeDir, 'AppData', 'Roaming'), 'npm')
240
+ : path.dirname(path.dirname(opts.execPath ?? process.execPath)));
241
+ return { path: path.join(prefix, 'etc', 'npmrc'), ignoreUnreadable: true };
242
+ }
243
+ function npmHomeDir(opts, env) {
244
+ if (opts.homeDir != null)
245
+ return opts.homeDir;
246
+ const platform = opts.platform ?? process.platform;
247
+ if (platform === 'win32')
248
+ return env.USERPROFILE ?? env.HOME ?? os.homedir();
249
+ return env.HOME ?? os.homedir();
250
+ }
251
+ function normalizedPath(pathname) {
252
+ return pathname.endsWith('/') ? pathname : `${pathname}/`;
253
+ }
254
+ export function stripQuotes(value) {
255
+ if (value.length < 2)
256
+ return value;
257
+ const first = value[0];
258
+ const last = value[value.length - 1];
259
+ return (first === last && (first === '"' || first === "'")) ? value.slice(1, -1) : value;
260
+ }
261
+ function expandEnv(value, env) {
262
+ let missing = false;
263
+ // `${NAME?}` is npm's spelling for "empty when unset"; a bare `${NAME}` that
264
+ // is unset drops the entry rather than sending the placeholder as a token.
265
+ const expanded = value.replace(/\$\{([^${}?]+)(\?)?\}/g, (_match, name, optional) => {
266
+ const resolved = env[name];
267
+ if (resolved != null)
268
+ return resolved;
269
+ if (optional == null)
270
+ missing = true;
271
+ return '';
272
+ });
273
+ return missing ? undefined : expanded;
274
+ }
275
+ function isUnreadableNpmrcError(err) {
276
+ return ['EACCES', 'EISDIR', 'EPERM'].some((code) => isErrno(err, code));
277
+ }
278
+ function isErrno(err, code) {
279
+ return err instanceof Error && 'code' in err && err.code === code;
280
+ }
@@ -1,10 +1,6 @@
1
1
  /* eslint-disable */
2
- // GENERATED — npm's public registry signing keys, mirrored from
3
- // https://registry.npmjs.org/-/npm/v1/keys
4
- //
5
- // Refresh with: node scripts/update-npm-keys.mjs --update
6
- // A scheduled workflow runs the check, so a rotation arrives as a pull request
7
- // rather than as a failed install.
2
+ // GENERATED from .config/npm-signing-keys.json by the meta-updater. Refresh the
3
+ // keys with `pnpm update:npm-signing-keys`, then `pnpm update-manifests`.
8
4
  export const NPM_SIGNING_KEYS = [
9
5
  {
10
6
  "expires": null,
@@ -27,6 +27,16 @@ export function platformPackageName({ major, platform, arch, musl }) {
27
27
 
28
28
  npx get-pnpm 12`);
29
29
  }
30
+ assertBinaryIsPublished({ major, platform, arch });
31
+ const linuxMusl = platform === 'linux' && musl;
32
+ if (major >= 12) {
33
+ return `@pnpm/exe.${platform}-${arch}${linuxMusl ? '-musl' : ''}`;
34
+ }
35
+ return `@pnpm/${legacyOsSegment(platform, linuxMusl)}-${arch}`;
36
+ }
37
+ /** Throws for the hosts outside v12's own targets that a release leaves out. */
38
+ function assertBinaryIsPublished({ major, platform, arch }) {
39
+ const target = `${platform}-${arch}`;
30
40
  if ((arch !== 'x64' && arch !== 'arm64') ||
31
41
  (platform !== 'darwin' && platform !== 'linux' && platform !== 'win32')) {
32
42
  throw new Error(`Sorry! pnpm does not provide a pre-built binary for ${target}.`);
@@ -41,11 +51,6 @@ Install pnpm a different way instead:
41
51
 
42
52
  More context: https://github.com/pnpm/pnpm/issues/11423`);
43
53
  }
44
- const linuxMusl = platform === 'linux' && musl;
45
- if (major >= 12) {
46
- return `@pnpm/exe.${platform}-${arch}${linuxMusl ? '-musl' : ''}`;
47
- }
48
- return `@pnpm/${legacyOsSegment(platform, linuxMusl)}-${arch}`;
49
54
  }
50
55
  function legacyOsSegment(platform, isMusl) {
51
56
  switch (platform) {
@@ -59,8 +64,7 @@ function legacyOsSegment(platform, isMusl) {
59
64
  *
60
65
  * Probed the way pnpm's own wrappers do it rather than through a dependency:
61
66
  * glibc builds report a `glibcVersionRuntime`, musl builds leave it unset.
62
- * Keeping this package dependency-free means `npx` fetches one thing before
63
- * pnpm exists.
67
+ * Every dependency is one more package `npx` fetches before pnpm exists.
64
68
  */
65
69
  export function isMusl() {
66
70
  if (process.platform !== 'linux')