@pnpm/releasing.commands 1100.0.1 → 1100.1.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/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/pack-app/index.d.ts +2 -0
- package/lib/pack-app/index.js +3 -0
- package/lib/pack-app/packApp.d.ts +22 -0
- package/lib/pack-app/packApp.js +398 -0
- package/lib/version/index.d.ts +7 -6
- package/lib/version/index.js +93 -25
- package/package.json +29 -26
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Config } from '@pnpm/config.reader';
|
|
2
|
+
export declare const commandNames: string[];
|
|
3
|
+
export declare function rcOptionsTypes(): Record<string, unknown>;
|
|
4
|
+
export declare function cliOptionsTypes(): Record<string, unknown>;
|
|
5
|
+
export declare const shorthands: Record<string, string>;
|
|
6
|
+
export declare function help(): string;
|
|
7
|
+
export type PackAppOptions = Pick<Config, 'dir' | 'pnpmHomeDir'> & Partial<Pick<Config, 'ca' | 'cert' | 'configByUri' | 'httpProxy' | 'httpsProxy' | 'key' | 'localAddress' | 'nodeDownloadMirrors' | 'noProxy' | 'strictSsl' | 'userAgent'>> & {
|
|
8
|
+
entry?: string;
|
|
9
|
+
target?: string | string[];
|
|
10
|
+
nodeVersion?: string;
|
|
11
|
+
outputDir?: string;
|
|
12
|
+
outputName?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function handler(opts: PackAppOptions, params: string[]): Promise<string>;
|
|
15
|
+
/** Fields pack-app reads from `pnpm.app` in package.json. */
|
|
16
|
+
export interface ProjectAppConfig {
|
|
17
|
+
entry?: string;
|
|
18
|
+
targets?: string[];
|
|
19
|
+
nodeVersion?: string;
|
|
20
|
+
outputDir?: string;
|
|
21
|
+
outputName?: string;
|
|
22
|
+
}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { docsUrl } from '@pnpm/cli.utils';
|
|
6
|
+
import { getNodeMirror, parseNodeSpecifier, resolveNodeVersion, } from '@pnpm/engine.runtime.node-resolver';
|
|
7
|
+
import { PnpmError } from '@pnpm/error';
|
|
8
|
+
import { runPnpmCli } from '@pnpm/exec.pnpm-cli-runner';
|
|
9
|
+
import { createFetchFromRegistry } from '@pnpm/network.fetch';
|
|
10
|
+
import { familySync } from 'detect-libc';
|
|
11
|
+
import { safeExeca as execa } from 'execa';
|
|
12
|
+
import { renderHelp } from 'render-help';
|
|
13
|
+
/** Minimum Node.js version that supports `node --build-sea`. */
|
|
14
|
+
const MIN_BUILDER_VERSION = { major: 25, minor: 5 };
|
|
15
|
+
// Range to download when the running Node is too old. Constrained to the
|
|
16
|
+
// current major so we don't silently jump majors across releases, and pinned
|
|
17
|
+
// above MIN_BUILDER_VERSION.minor so older point releases (e.g. 25.0.x) that
|
|
18
|
+
// don't support `--build-sea` aren't picked.
|
|
19
|
+
const DEFAULT_BUILDER_SPEC = `>=${MIN_BUILDER_VERSION.major}.${MIN_BUILDER_VERSION.minor}.0 <${MIN_BUILDER_VERSION.major + 1}.0.0`;
|
|
20
|
+
// Target OS names match `process.platform`. That keeps the CLI surface
|
|
21
|
+
// consistent with pnpm's own `--os` flag (which also takes platform constants)
|
|
22
|
+
// and with `supportedArchitectures.os` in pnpm-workspace.yaml.
|
|
23
|
+
const SUPPORTED_OS = ['linux', 'darwin', 'win32'];
|
|
24
|
+
const SUPPORTED_TARGETS = 'linux-x64, linux-x64-musl, linux-arm64, linux-arm64-musl, darwin-x64, darwin-arm64, win32-x64, win32-arm64';
|
|
25
|
+
export const commandNames = ['pack-app'];
|
|
26
|
+
export function rcOptionsTypes() {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
export function cliOptionsTypes() {
|
|
30
|
+
return {
|
|
31
|
+
entry: String,
|
|
32
|
+
target: [String, Array],
|
|
33
|
+
'node-version': String,
|
|
34
|
+
'output-dir': String,
|
|
35
|
+
'output-name': String,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export const shorthands = {
|
|
39
|
+
t: '--target',
|
|
40
|
+
o: '--output-dir',
|
|
41
|
+
};
|
|
42
|
+
export function help() {
|
|
43
|
+
return renderHelp({
|
|
44
|
+
description: 'Pack a CommonJS entry file into a standalone executable for one or more target platforms.\n\n' +
|
|
45
|
+
'The executable embeds a Node.js binary via the Node.js Single Executable Applications API.\n' +
|
|
46
|
+
`Requires Node.js v${MIN_BUILDER_VERSION.major}.${MIN_BUILDER_VERSION.minor}+ to perform ` +
|
|
47
|
+
'the injection. The running Node.js is used when it is new enough; otherwise, the ' +
|
|
48
|
+
`latest Node.js v${MIN_BUILDER_VERSION.major}.${MIN_BUILDER_VERSION.minor}+ in the ` +
|
|
49
|
+
`v${MIN_BUILDER_VERSION.major}.x line is downloaded automatically.\n\n` +
|
|
50
|
+
'Defaults for --entry, --target, --node-version, --output-dir, and --output-name can be ' +
|
|
51
|
+
'set in the package.json under "pnpm.app". CLI flags override the config; --target entirely ' +
|
|
52
|
+
'replaces the configured list so you can narrow it at invocation time.',
|
|
53
|
+
url: docsUrl('pack-app'),
|
|
54
|
+
usages: [
|
|
55
|
+
'pnpm pack-app --entry dist/index.cjs --target linux-x64 --target win32-x64',
|
|
56
|
+
'pnpm pack-app --entry dist/index.cjs --target linux-x64-musl --node-version 22',
|
|
57
|
+
],
|
|
58
|
+
descriptionLists: [
|
|
59
|
+
{
|
|
60
|
+
title: 'Options',
|
|
61
|
+
list: [
|
|
62
|
+
{
|
|
63
|
+
description: 'Path to the CJS entry file to embed in the executable',
|
|
64
|
+
name: '--entry',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
description: `Target to build for. May be specified multiple times. Supported: ${SUPPORTED_TARGETS}`,
|
|
68
|
+
name: '--target',
|
|
69
|
+
shortAlias: '-t',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
description: 'Node.js version to embed in the output executables (e.g. "22", "22.0.0", "lts"). ' +
|
|
73
|
+
'Defaults to the running Node.js version.',
|
|
74
|
+
name: '--node-version',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
description: 'Output directory for the built executables. Defaults to "dist-app".',
|
|
78
|
+
name: '--output-dir',
|
|
79
|
+
shortAlias: '-o',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
description: 'Name for the output executable (without extension). Defaults to the unscoped package name.',
|
|
83
|
+
name: '--output-name',
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export async function handler(opts, params) {
|
|
91
|
+
// pnpm.app in package.json supplies defaults for every flag. CLI flags win,
|
|
92
|
+
// but `--target` entirely replaces the config list (additive merging would
|
|
93
|
+
// prevent narrowing from the CLI). See ProjectAppConfig below for the shape.
|
|
94
|
+
const project = await readProjectAppConfig(opts.dir);
|
|
95
|
+
const entryPath = opts.entry ?? params[0] ?? project.app?.entry;
|
|
96
|
+
if (!entryPath) {
|
|
97
|
+
throw new PnpmError('PACK_APP_MISSING_ENTRY', '"pnpm pack-app" requires a CJS entry file — pass --entry <path> or set "pnpm.app.entry" in package.json.');
|
|
98
|
+
}
|
|
99
|
+
const resolvedEntry = path.resolve(opts.dir, entryPath);
|
|
100
|
+
let entryStat;
|
|
101
|
+
try {
|
|
102
|
+
entryStat = fs.statSync(resolvedEntry);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
throw new PnpmError('PACK_APP_ENTRY_NOT_FOUND', `Entry file not found: ${resolvedEntry}`);
|
|
106
|
+
}
|
|
107
|
+
if (!entryStat.isFile()) {
|
|
108
|
+
throw new PnpmError('PACK_APP_ENTRY_NOT_FILE', `Entry path must be a regular file: ${resolvedEntry}`);
|
|
109
|
+
}
|
|
110
|
+
const cliTargets = opts.target == null
|
|
111
|
+
? undefined
|
|
112
|
+
: Array.isArray(opts.target) ? opts.target : [opts.target];
|
|
113
|
+
const rawTargets = cliTargets ?? project.app?.targets ?? [];
|
|
114
|
+
if (rawTargets.length === 0) {
|
|
115
|
+
throw new PnpmError('PACK_APP_MISSING_TARGET', `"pnpm pack-app" requires at least one target — pass --target <triplet> or set "pnpm.app.targets" in package.json. Supported: ${SUPPORTED_TARGETS}`);
|
|
116
|
+
}
|
|
117
|
+
const targets = rawTargets.map(parseTarget);
|
|
118
|
+
const outputDir = path.resolve(opts.dir, opts.outputDir ?? project.app?.outputDir ?? 'dist-app');
|
|
119
|
+
await mkdir(outputDir, { recursive: true });
|
|
120
|
+
const outputName = validateOutputName(opts.outputName ?? project.app?.outputName ?? deriveOutputNameFromPackage(project, opts.dir));
|
|
121
|
+
const requestedNodeSpec = opts.nodeVersion ?? project.app?.nodeVersion ?? process.version.slice(1);
|
|
122
|
+
const fetch = createFetchFromRegistry(opts);
|
|
123
|
+
const buildRoot = path.join(opts.pnpmHomeDir, 'pack-app');
|
|
124
|
+
const builderBin = await resolveBuilderBinary({ fetch, nodeDownloadMirrors: opts.nodeDownloadMirrors, buildRoot });
|
|
125
|
+
const resolvedTargetVersion = await resolveVersion(fetch, requestedNodeSpec, opts.nodeDownloadMirrors);
|
|
126
|
+
const results = [];
|
|
127
|
+
for (const target of targets) {
|
|
128
|
+
// eslint-disable-next-line no-await-in-loop
|
|
129
|
+
const embeddedNodeBin = await ensureNodeRuntime({
|
|
130
|
+
buildRoot,
|
|
131
|
+
version: resolvedTargetVersion,
|
|
132
|
+
platform: target.platform,
|
|
133
|
+
arch: target.arch,
|
|
134
|
+
libc: target.libc,
|
|
135
|
+
});
|
|
136
|
+
const targetOutputDir = path.join(outputDir, target.raw);
|
|
137
|
+
// eslint-disable-next-line no-await-in-loop
|
|
138
|
+
await mkdir(targetOutputDir, { recursive: true });
|
|
139
|
+
const outputFile = target.platform === 'win32'
|
|
140
|
+
? path.join(targetOutputDir, `${outputName}.exe`)
|
|
141
|
+
: path.join(targetOutputDir, outputName);
|
|
142
|
+
const seaConfig = {
|
|
143
|
+
main: resolvedEntry,
|
|
144
|
+
output: outputFile,
|
|
145
|
+
executable: embeddedNodeBin,
|
|
146
|
+
disableExperimentalSEAWarning: true,
|
|
147
|
+
useCodeCache: false,
|
|
148
|
+
useSnapshot: false,
|
|
149
|
+
};
|
|
150
|
+
// Write the SEA config into a fresh, unpredictable temp directory (0700
|
|
151
|
+
// by default) rather than a predictable path under os.tmpdir(). Avoids
|
|
152
|
+
// TOCTOU/symlink attacks on multi-user systems.
|
|
153
|
+
// eslint-disable-next-line no-await-in-loop
|
|
154
|
+
const tmpConfigDir = await mkdtemp(path.join(os.tmpdir(), 'pnpm-pack-app-'));
|
|
155
|
+
const configPath = path.join(tmpConfigDir, 'sea-config.json');
|
|
156
|
+
// eslint-disable-next-line no-await-in-loop
|
|
157
|
+
await writeFile(configPath, JSON.stringify(seaConfig, null, 2), { flag: 'wx' });
|
|
158
|
+
try {
|
|
159
|
+
// eslint-disable-next-line no-await-in-loop
|
|
160
|
+
await execa(builderBin, ['--build-sea', configPath], { stdio: 'inherit' });
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
// eslint-disable-next-line no-await-in-loop
|
|
164
|
+
await rm(tmpConfigDir, { recursive: true, force: true }).catch(() => { });
|
|
165
|
+
}
|
|
166
|
+
// eslint-disable-next-line no-await-in-loop
|
|
167
|
+
await adHocSignMacBinary(target, outputFile);
|
|
168
|
+
results.push(` ${target.raw}: ${outputFile} (Node.js ${resolvedTargetVersion})`);
|
|
169
|
+
}
|
|
170
|
+
return `Built ${targets.length} executable${targets.length === 1 ? '' : 's'}:\n${results.join('\n')}`;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Returns a Node.js binary that supports `--build-sea`. Prefers the running
|
|
174
|
+
* interpreter to avoid a download; falls back to downloading Node.js v25.
|
|
175
|
+
*/
|
|
176
|
+
async function resolveBuilderBinary(ctx) {
|
|
177
|
+
if (runningNodeCanBuildSea()) {
|
|
178
|
+
return process.execPath;
|
|
179
|
+
}
|
|
180
|
+
const version = await resolveVersion(ctx.fetch, DEFAULT_BUILDER_SPEC, ctx.nodeDownloadMirrors);
|
|
181
|
+
return ensureNodeRuntime({
|
|
182
|
+
buildRoot: ctx.buildRoot,
|
|
183
|
+
version,
|
|
184
|
+
platform: process.platform,
|
|
185
|
+
arch: process.arch,
|
|
186
|
+
// Pin libc to the host's. Otherwise a caller that had set
|
|
187
|
+
// supportedArchitectures.libc=musl in their config would cause the
|
|
188
|
+
// glibc host to download a musl Node that it cannot execute.
|
|
189
|
+
libc: hostLinuxLibc(),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
function hostLinuxLibc() {
|
|
193
|
+
if (process.platform !== 'linux')
|
|
194
|
+
return undefined;
|
|
195
|
+
const family = familySync();
|
|
196
|
+
return family === 'musl' ? 'musl' : 'glibc';
|
|
197
|
+
}
|
|
198
|
+
function runningNodeCanBuildSea() {
|
|
199
|
+
const [majorStr, minorStr] = process.version.slice(1).split('.');
|
|
200
|
+
const major = Number(majorStr);
|
|
201
|
+
const minor = Number(minorStr);
|
|
202
|
+
return (major > MIN_BUILDER_VERSION.major ||
|
|
203
|
+
(major === MIN_BUILDER_VERSION.major && minor >= MIN_BUILDER_VERSION.minor));
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Fetches a Node.js runtime into a dedicated per-target directory under the
|
|
207
|
+
* pnpm home, reusing the cached binary if already present. Actual files are
|
|
208
|
+
* hardlinked from pnpm's content-addressable store, so repeated calls are
|
|
209
|
+
* cheap and `pnpm store prune` can reclaim them.
|
|
210
|
+
*/
|
|
211
|
+
async function ensureNodeRuntime(opts) {
|
|
212
|
+
// Linux variants always need a libc pin (glibc or musl) so that variant
|
|
213
|
+
// selection is deterministic and doesn't depend on the host's detected
|
|
214
|
+
// libc or the user's supportedArchitectures.libc config.
|
|
215
|
+
const libc = opts.platform === 'linux' ? opts.libc ?? 'glibc' : opts.libc;
|
|
216
|
+
const targetId = [opts.platform, opts.arch, libc].filter(Boolean).join('-');
|
|
217
|
+
const installDir = path.join(opts.buildRoot, `${targetId}-${opts.version}`);
|
|
218
|
+
const nodeDir = path.join(installDir, 'node_modules', 'node');
|
|
219
|
+
const binaryPath = nodeBinaryPath(nodeDir, opts.platform);
|
|
220
|
+
if (fs.existsSync(binaryPath))
|
|
221
|
+
return binaryPath;
|
|
222
|
+
await mkdir(installDir, { recursive: true });
|
|
223
|
+
await writeFile(path.join(installDir, 'package.json'), `${JSON.stringify({ name: `pnpm-pack-app-${targetId}`, private: true }, null, 2)}\n`);
|
|
224
|
+
// Flags that select the target variant must come before the positional
|
|
225
|
+
// package spec; otherwise `pnpm add` silently installs the host variant.
|
|
226
|
+
const args = [
|
|
227
|
+
'add',
|
|
228
|
+
'--ignore-scripts',
|
|
229
|
+
'--ignore-workspace',
|
|
230
|
+
`--os=${opts.platform}`,
|
|
231
|
+
`--cpu=${opts.arch}`,
|
|
232
|
+
];
|
|
233
|
+
if (libc != null) {
|
|
234
|
+
args.push(`--libc=${libc}`);
|
|
235
|
+
}
|
|
236
|
+
args.push(`node@runtime:${opts.version}`);
|
|
237
|
+
runPnpmCli(args, { cwd: installDir });
|
|
238
|
+
if (!fs.existsSync(binaryPath)) {
|
|
239
|
+
throw new PnpmError('PACK_APP_NODE_BINARY_MISSING', `Expected Node.js binary at ${binaryPath} after installing node@runtime:${opts.version}, but it was not found.`);
|
|
240
|
+
}
|
|
241
|
+
return binaryPath;
|
|
242
|
+
}
|
|
243
|
+
function nodeBinaryPath(nodeDir, platform) {
|
|
244
|
+
return platform === 'win32'
|
|
245
|
+
? path.join(nodeDir, 'node.exe')
|
|
246
|
+
: path.join(nodeDir, 'bin', 'node');
|
|
247
|
+
}
|
|
248
|
+
async function resolveVersion(fetch, specifier, nodeDownloadMirrors) {
|
|
249
|
+
const { releaseChannel, versionSpecifier } = parseNodeSpecifier(specifier);
|
|
250
|
+
const nodeMirrorBaseUrl = getNodeMirror(nodeDownloadMirrors, releaseChannel);
|
|
251
|
+
const version = await resolveNodeVersion(fetch, versionSpecifier, nodeMirrorBaseUrl);
|
|
252
|
+
if (!version) {
|
|
253
|
+
throw new PnpmError('PACK_APP_NODE_VERSION_NOT_FOUND', `Could not find a Node.js version that satisfies "${specifier}"`);
|
|
254
|
+
}
|
|
255
|
+
return version;
|
|
256
|
+
}
|
|
257
|
+
// Parsed triplet must match this shape exactly. We anchor and constrain each
|
|
258
|
+
// segment so that inputs like `linux-x64-musl-../../outside` are rejected
|
|
259
|
+
// outright — otherwise `target.raw` would later flow into path.join for the
|
|
260
|
+
// output directory and could escape it.
|
|
261
|
+
const TARGET_PATTERN = /^(linux|darwin|win32)-(x64|arm64)(?:-(musl))?$/;
|
|
262
|
+
function parseTarget(raw) {
|
|
263
|
+
const match = TARGET_PATTERN.exec(raw);
|
|
264
|
+
if (!match) {
|
|
265
|
+
throw new PnpmError('PACK_APP_INVALID_TARGET', `Invalid target: "${raw}". Expected format: <os>-<arch>[-<libc>] where <os> is ${SUPPORTED_OS.join('|')}, <arch> is x64|arm64, optional <libc> is musl (linux only).`);
|
|
266
|
+
}
|
|
267
|
+
const [, platform, arch, libc] = match;
|
|
268
|
+
if (libc === 'musl' && platform !== 'linux') {
|
|
269
|
+
throw new PnpmError('PACK_APP_INVALID_TARGET', `The "musl" libc suffix is only valid for linux targets (got "${raw}").`);
|
|
270
|
+
}
|
|
271
|
+
return { raw, platform, arch, libc: libc || undefined };
|
|
272
|
+
}
|
|
273
|
+
// Characters that Win32 rejects in filenames, plus NUL. Path separators are
|
|
274
|
+
// checked separately via `path.basename` so the message is crisp.
|
|
275
|
+
const INVALID_FILENAME_CHARS = /[<>:"|?*\0]/;
|
|
276
|
+
// Win32 reserved device names (case-insensitive, with or without an extension).
|
|
277
|
+
const RESERVED_WINDOWS_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/i;
|
|
278
|
+
// Reject anything that would let the output escape its target directory, or
|
|
279
|
+
// that would fail filesystem-level validation on any supported host. This
|
|
280
|
+
// surfaces problems at `pack-app` invocation time instead of letting them
|
|
281
|
+
// blow up later in `writeFile(outputFile, …)`.
|
|
282
|
+
function validateOutputName(name) {
|
|
283
|
+
if (name !== path.basename(name) ||
|
|
284
|
+
name === '' || name === '.' || name === '..' ||
|
|
285
|
+
name.includes('/') || name.includes('\\') ||
|
|
286
|
+
INVALID_FILENAME_CHARS.test(name) ||
|
|
287
|
+
RESERVED_WINDOWS_NAME.test(name) ||
|
|
288
|
+
/[. ]$/.test(name)) {
|
|
289
|
+
throw new PnpmError('PACK_APP_INVALID_OUTPUT_NAME', `Invalid --output-name "${name}". The name must be a plain filename without path separators, Windows-reserved names (e.g. CON, NUL), characters like <>:"|?* or NUL, and must not end in a dot or space.`);
|
|
290
|
+
}
|
|
291
|
+
return name;
|
|
292
|
+
}
|
|
293
|
+
// A narrow reader just for this command. Using readProjectManifest from
|
|
294
|
+
// @pnpm/cli.utils would pull in the installable/engine checks, which are
|
|
295
|
+
// irrelevant here: pack-app doesn't need the current project to be installable
|
|
296
|
+
// under the running Node, just to have a package.json with optional settings.
|
|
297
|
+
async function readProjectAppConfig(dir) {
|
|
298
|
+
let raw;
|
|
299
|
+
try {
|
|
300
|
+
raw = await readFile(path.join(dir, 'package.json'), 'utf8');
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return {};
|
|
304
|
+
}
|
|
305
|
+
let manifest;
|
|
306
|
+
try {
|
|
307
|
+
manifest = JSON.parse(raw);
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
throw new PnpmError('PACK_APP_INVALID_PACKAGE_JSON', `Failed to parse ${path.join(dir, 'package.json')}: ${err.message}`);
|
|
311
|
+
}
|
|
312
|
+
if (!isObject(manifest))
|
|
313
|
+
return {};
|
|
314
|
+
const name = typeof manifest.name === 'string' && manifest.name !== '' ? manifest.name : undefined;
|
|
315
|
+
const pnpmField = isObject(manifest.pnpm) ? manifest.pnpm : undefined;
|
|
316
|
+
const appField = pnpmField && isObject(pnpmField.app) ? pnpmField.app : undefined;
|
|
317
|
+
if (!appField)
|
|
318
|
+
return { name };
|
|
319
|
+
return { name, app: validateAppConfig(appField) };
|
|
320
|
+
}
|
|
321
|
+
function validateAppConfig(raw) {
|
|
322
|
+
const known = new Set(['entry', 'targets', 'nodeVersion', 'outputDir', 'outputName']);
|
|
323
|
+
for (const key of Object.keys(raw)) {
|
|
324
|
+
if (!known.has(key)) {
|
|
325
|
+
throw new PnpmError('PACK_APP_INVALID_CONFIG', `Unknown "pnpm.app.${key}" setting in package.json. Allowed keys: ${Array.from(known).join(', ')}.`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const config = {};
|
|
329
|
+
if (raw.entry != null) {
|
|
330
|
+
if (typeof raw.entry !== 'string') {
|
|
331
|
+
throw new PnpmError('PACK_APP_INVALID_CONFIG', '"pnpm.app.entry" must be a string.');
|
|
332
|
+
}
|
|
333
|
+
config.entry = raw.entry;
|
|
334
|
+
}
|
|
335
|
+
if (raw.targets != null) {
|
|
336
|
+
if (!Array.isArray(raw.targets) || !raw.targets.every((t) => typeof t === 'string')) {
|
|
337
|
+
throw new PnpmError('PACK_APP_INVALID_CONFIG', '"pnpm.app.targets" must be an array of strings.');
|
|
338
|
+
}
|
|
339
|
+
config.targets = raw.targets;
|
|
340
|
+
}
|
|
341
|
+
if (raw.nodeVersion != null) {
|
|
342
|
+
if (typeof raw.nodeVersion !== 'string') {
|
|
343
|
+
throw new PnpmError('PACK_APP_INVALID_CONFIG', '"pnpm.app.nodeVersion" must be a string.');
|
|
344
|
+
}
|
|
345
|
+
config.nodeVersion = raw.nodeVersion;
|
|
346
|
+
}
|
|
347
|
+
if (raw.outputDir != null) {
|
|
348
|
+
if (typeof raw.outputDir !== 'string') {
|
|
349
|
+
throw new PnpmError('PACK_APP_INVALID_CONFIG', '"pnpm.app.outputDir" must be a string.');
|
|
350
|
+
}
|
|
351
|
+
config.outputDir = raw.outputDir;
|
|
352
|
+
}
|
|
353
|
+
if (raw.outputName != null) {
|
|
354
|
+
if (typeof raw.outputName !== 'string') {
|
|
355
|
+
throw new PnpmError('PACK_APP_INVALID_CONFIG', '"pnpm.app.outputName" must be a string.');
|
|
356
|
+
}
|
|
357
|
+
config.outputName = raw.outputName;
|
|
358
|
+
}
|
|
359
|
+
return config;
|
|
360
|
+
}
|
|
361
|
+
function deriveOutputNameFromPackage(project, dir) {
|
|
362
|
+
if (!project.name) {
|
|
363
|
+
throw new PnpmError('PACK_APP_NO_OUTPUT_NAME', `Could not determine the output name: package.json in ${dir} has no "name" field.`, { hint: 'Pass --output-name <name> or set "pnpm.app.outputName" in package.json.' });
|
|
364
|
+
}
|
|
365
|
+
// Strip @scope/ prefix from scoped packages so the binary name is a plain
|
|
366
|
+
// filename instead of "scope/name". The second validateOutputName() pass
|
|
367
|
+
// downstream rejects any leftover path separators.
|
|
368
|
+
return project.name.replace(/^@[^/]+\//, '');
|
|
369
|
+
}
|
|
370
|
+
function isObject(value) {
|
|
371
|
+
return value != null && typeof value === 'object' && !Array.isArray(value);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* SEA injection invalidates the existing code signature on macOS binaries, so
|
|
375
|
+
* the output must be re-signed. Native macOS hosts use `codesign`; Linux hosts
|
|
376
|
+
* cross-signing a darwin target use `ldid`. Windows hosts have no readily
|
|
377
|
+
* available ad-hoc signer, so we refuse to produce an unsigned output silently
|
|
378
|
+
* and tell the user to re-sign on macOS or Linux.
|
|
379
|
+
*/
|
|
380
|
+
async function adHocSignMacBinary(target, outputFile) {
|
|
381
|
+
if (target.platform !== 'darwin')
|
|
382
|
+
return;
|
|
383
|
+
if (process.platform === 'darwin') {
|
|
384
|
+
await execa('codesign', ['--sign', '-', outputFile], { stdio: 'inherit' });
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (process.platform === 'linux') {
|
|
388
|
+
try {
|
|
389
|
+
await execa('ldid', ['-S', outputFile], { stdio: 'inherit' });
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
throw new PnpmError('PACK_APP_MACOS_SIGN_FAILED', `Cross-compiled macOS binary at ${outputFile} could not be ad-hoc signed with "ldid".`, { hint: 'Install ldid (https://github.com/ProcursusTeam/ldid) or re-sign the binary on macOS with "codesign --sign - <file>".' });
|
|
393
|
+
}
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
throw new PnpmError('PACK_APP_MACOS_SIGN_UNSUPPORTED_HOST', `Cannot ad-hoc sign the macOS binary at ${outputFile} on a ${process.platform} host.`, { hint: 'Build macOS targets on a macOS or Linux host, or re-sign the produced binary yourself with "codesign --sign -" on macOS.' });
|
|
397
|
+
}
|
|
398
|
+
//# sourceMappingURL=packApp.js.map
|
package/lib/version/index.d.ts
CHANGED
|
@@ -5,14 +5,15 @@ export declare const commandNames: string[];
|
|
|
5
5
|
export declare function help(): string;
|
|
6
6
|
interface VersionHandlerOptions extends Config {
|
|
7
7
|
allowSameVersion?: boolean;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
commitHooks?: boolean;
|
|
9
|
+
gitChecks?: boolean;
|
|
10
|
+
gitTagVersion?: boolean;
|
|
11
|
+
json?: boolean;
|
|
12
|
+
message?: string;
|
|
11
13
|
preid?: string;
|
|
12
|
-
tagVersionPrefix?: string;
|
|
13
14
|
recursive?: boolean;
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
signGitTag?: boolean;
|
|
16
|
+
tagVersionPrefix?: string;
|
|
16
17
|
}
|
|
17
18
|
export declare function handler(opts: VersionHandlerOptions, params: string[]): Promise<string | {
|
|
18
19
|
output?: string;
|
package/lib/version/index.js
CHANGED
|
@@ -1,34 +1,42 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
1
2
|
import { readProjectManifest } from '@pnpm/cli.utils';
|
|
2
3
|
import { types as allTypes } from '@pnpm/config.reader';
|
|
3
4
|
import { PnpmError } from '@pnpm/error';
|
|
4
5
|
import { isGitRepo, isWorkingTreeClean } from '@pnpm/network.git-utils';
|
|
5
6
|
import { filterProjectsFromDir } from '@pnpm/workspace.projects-filter';
|
|
7
|
+
import { safeExeca as execa } from 'execa';
|
|
6
8
|
import { pick } from 'ramda';
|
|
7
9
|
import { renderHelp } from 'render-help';
|
|
8
10
|
import { inc, valid } from 'semver';
|
|
9
11
|
export function rcOptionsTypes() {
|
|
10
12
|
return pick([
|
|
13
|
+
'allow-same-version',
|
|
14
|
+
'commit-hooks',
|
|
11
15
|
'git-checks',
|
|
16
|
+
'git-tag-version',
|
|
17
|
+
'message',
|
|
18
|
+
'sign-git-tag',
|
|
19
|
+
'tag-version-prefix',
|
|
12
20
|
], allTypes);
|
|
13
21
|
}
|
|
14
22
|
export function cliOptionsTypes() {
|
|
15
23
|
return {
|
|
16
24
|
...rcOptionsTypes(),
|
|
17
|
-
'allow-same-version': Boolean,
|
|
18
|
-
'no-git-checks': Boolean,
|
|
19
|
-
'no-commit-hooks': Boolean,
|
|
20
|
-
'no-strict': Boolean,
|
|
21
|
-
'preid': String,
|
|
22
|
-
'tag-version-prefix': String,
|
|
23
|
-
recursive: Boolean,
|
|
24
25
|
json: Boolean,
|
|
26
|
+
preid: String,
|
|
27
|
+
recursive: Boolean,
|
|
25
28
|
};
|
|
26
29
|
}
|
|
27
30
|
export const commandNames = ['version'];
|
|
31
|
+
const BUMP_TYPES = ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease'];
|
|
32
|
+
function isBumpType(value) {
|
|
33
|
+
return BUMP_TYPES.includes(value);
|
|
34
|
+
}
|
|
28
35
|
export function help() {
|
|
29
36
|
return renderHelp({
|
|
30
37
|
description: 'Bumps the version of a package.',
|
|
31
38
|
usages: [
|
|
39
|
+
'pnpm version <newversion>',
|
|
32
40
|
'pnpm version <major|minor|patch|premajor|preminor|prepatch|prerelease>',
|
|
33
41
|
],
|
|
34
42
|
descriptionLists: [
|
|
@@ -44,7 +52,7 @@ export function help() {
|
|
|
44
52
|
name: '--preid <preid>',
|
|
45
53
|
},
|
|
46
54
|
{
|
|
47
|
-
description: 'Sets the tag prefix
|
|
55
|
+
description: 'Sets the tag prefix. Default is "v". Set to empty string to remove the prefix.',
|
|
48
56
|
name: '--tag-version-prefix <prefix>',
|
|
49
57
|
},
|
|
50
58
|
{
|
|
@@ -52,9 +60,21 @@ export function help() {
|
|
|
52
60
|
name: '--allow-same-version',
|
|
53
61
|
},
|
|
54
62
|
{
|
|
55
|
-
description: '
|
|
63
|
+
description: 'Commit message. "%s" is replaced with the new version. Default is "%s".',
|
|
64
|
+
name: '--message <message>',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
description: "Don't create a commit or tag for the version bump. Git commits and tags are always skipped in recursive mode.",
|
|
68
|
+
name: '--no-git-tag-version',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
description: 'Skip running git commit hooks when committing the version bump',
|
|
56
72
|
name: '--no-commit-hooks',
|
|
57
73
|
},
|
|
74
|
+
{
|
|
75
|
+
description: 'Sign the generated git tag with GPG',
|
|
76
|
+
name: '--sign-git-tag',
|
|
77
|
+
},
|
|
58
78
|
{
|
|
59
79
|
description: 'Filter packages by name (glob pattern)',
|
|
60
80
|
name: '--filter <pattern>',
|
|
@@ -73,19 +93,22 @@ export function help() {
|
|
|
73
93
|
});
|
|
74
94
|
}
|
|
75
95
|
export async function handler(opts, params) {
|
|
76
|
-
const
|
|
77
|
-
if (!
|
|
78
|
-
throw new PnpmError('INVALID_VERSION_BUMP', '
|
|
96
|
+
const rawBump = params[0];
|
|
97
|
+
if (!rawBump) {
|
|
98
|
+
throw new PnpmError('INVALID_VERSION_BUMP', 'A version argument is required. Must be a valid semver version (e.g. 1.2.3) or one of: major, minor, patch, premajor, preminor, prepatch, prerelease');
|
|
79
99
|
}
|
|
80
|
-
|
|
81
|
-
if (!
|
|
82
|
-
|
|
100
|
+
const explicitVersion = valid(rawBump);
|
|
101
|
+
if (!explicitVersion && !isBumpType(rawBump)) {
|
|
102
|
+
throw new PnpmError('INVALID_VERSION_BUMP', `Invalid version argument: ${rawBump}. Must be a valid semver version (e.g. 1.2.3) or one of: major, minor, patch, premajor, preminor, prepatch, prerelease`);
|
|
103
|
+
}
|
|
104
|
+
const gitCwd = opts.workspaceDir ?? opts.dir;
|
|
105
|
+
if (opts.gitChecks !== false && await isGitRepo({ cwd: gitCwd })) {
|
|
106
|
+
if (!await isWorkingTreeClean({ cwd: gitCwd })) {
|
|
83
107
|
throw new PnpmError('UNCLEAN_WORKING_TREE', 'Working tree is not clean. Commit or stash your changes.');
|
|
84
108
|
}
|
|
85
109
|
}
|
|
86
110
|
const changes = [];
|
|
87
111
|
if (opts.recursive) {
|
|
88
|
-
// Handle workspace versioning
|
|
89
112
|
const workspaceDir = opts.workspaceDir || opts.dir;
|
|
90
113
|
const filters = [];
|
|
91
114
|
if (opts.filter && opts.filter.length > 0) {
|
|
@@ -101,7 +124,7 @@ export async function handler(opts, params) {
|
|
|
101
124
|
prefix: opts.dir,
|
|
102
125
|
});
|
|
103
126
|
const pkgDirs = Object.keys(result.selectedProjectsGraph);
|
|
104
|
-
const bumpResults = await Promise.all(pkgDirs.map(pkgDir => bumpPackageVersion(pkgDir,
|
|
127
|
+
const bumpResults = await Promise.all(pkgDirs.map(pkgDir => bumpPackageVersion(pkgDir, rawBump, explicitVersion, opts)));
|
|
105
128
|
for (const change of bumpResults) {
|
|
106
129
|
if (change) {
|
|
107
130
|
changes.push(change);
|
|
@@ -109,8 +132,7 @@ export async function handler(opts, params) {
|
|
|
109
132
|
}
|
|
110
133
|
}
|
|
111
134
|
else {
|
|
112
|
-
|
|
113
|
-
const change = await bumpPackageVersion(opts.dir, bumpType, opts);
|
|
135
|
+
const change = await bumpPackageVersion(opts.dir, rawBump, explicitVersion, opts);
|
|
114
136
|
if (change) {
|
|
115
137
|
changes.push(change);
|
|
116
138
|
}
|
|
@@ -118,9 +140,14 @@ export async function handler(opts, params) {
|
|
|
118
140
|
if (changes.length === 0) {
|
|
119
141
|
throw new PnpmError('NO_PACKAGES_TO_VERSION', 'No packages to version');
|
|
120
142
|
}
|
|
121
|
-
//
|
|
143
|
+
// In recursive mode, multiple packages can be bumped to different versions
|
|
144
|
+
// in a single run, and there is no obvious single version to tag the commit
|
|
145
|
+
// with. Skip the git commit and tag entirely in that case.
|
|
146
|
+
if (!opts.recursive && opts.gitTagVersion !== false && await isGitRepo({ cwd: gitCwd })) {
|
|
147
|
+
await commitAndTag(changes, { ...opts, cwd: gitCwd });
|
|
148
|
+
}
|
|
122
149
|
if (opts.json) {
|
|
123
|
-
return JSON.stringify(changes, null, 2);
|
|
150
|
+
return JSON.stringify(changes.map(({ manifestPath: _manifestPath, ...change }) => change), null, 2);
|
|
124
151
|
}
|
|
125
152
|
let output = 'Version bumped successfully:\n';
|
|
126
153
|
for (const change of changes) {
|
|
@@ -128,8 +155,8 @@ export async function handler(opts, params) {
|
|
|
128
155
|
}
|
|
129
156
|
return output;
|
|
130
157
|
}
|
|
131
|
-
async function bumpPackageVersion(pkgDir,
|
|
132
|
-
const { manifest, writeProjectManifest } = await readProjectManifest(pkgDir);
|
|
158
|
+
async function bumpPackageVersion(pkgDir, rawBump, explicitVersion, opts) {
|
|
159
|
+
const { manifest, writeProjectManifest, fileName } = await readProjectManifest(pkgDir);
|
|
133
160
|
if (!manifest.name || !manifest.version) {
|
|
134
161
|
return null;
|
|
135
162
|
}
|
|
@@ -137,9 +164,9 @@ async function bumpPackageVersion(pkgDir, bumpType, opts) {
|
|
|
137
164
|
if (!valid(currentVersion)) {
|
|
138
165
|
throw new PnpmError('INVALID_VERSION', `Invalid version in ${pkgDir}: ${currentVersion}`);
|
|
139
166
|
}
|
|
140
|
-
const newVersion = inc(currentVersion,
|
|
167
|
+
const newVersion = explicitVersion ?? inc(currentVersion, rawBump, false, opts.preid);
|
|
141
168
|
if (!newVersion) {
|
|
142
|
-
throw new PnpmError('VERSION_BUMP_FAILED', `Failed to bump version from ${currentVersion} using ${
|
|
169
|
+
throw new PnpmError('VERSION_BUMP_FAILED', `Failed to bump version from ${currentVersion} using ${rawBump}`);
|
|
143
170
|
}
|
|
144
171
|
if (newVersion === currentVersion && !opts.allowSameVersion) {
|
|
145
172
|
throw new PnpmError('VERSION_NOT_CHANGED', `Version was not changed: ${currentVersion}`);
|
|
@@ -151,8 +178,49 @@ async function bumpPackageVersion(pkgDir, bumpType, opts) {
|
|
|
151
178
|
currentVersion,
|
|
152
179
|
newVersion,
|
|
153
180
|
path: pkgDir,
|
|
181
|
+
manifestPath: path.join(pkgDir, fileName),
|
|
154
182
|
};
|
|
155
183
|
}
|
|
184
|
+
async function commitAndTag(changes, opts) {
|
|
185
|
+
const resolvedCwd = path.resolve(opts.cwd);
|
|
186
|
+
const [change] = changes;
|
|
187
|
+
const rawMessage = opts.message ?? '%s';
|
|
188
|
+
const message = rawMessage.replace(/%s/g, change.newVersion);
|
|
189
|
+
const tagPrefix = opts.tagVersionPrefix ?? 'v';
|
|
190
|
+
const tagName = `${tagPrefix}${change.newVersion}`;
|
|
191
|
+
const execOpts = { cwd: opts.cwd };
|
|
192
|
+
const resolvedManifestPath = path.resolve(change.manifestPath);
|
|
193
|
+
const relativeManifestPath = path.relative(resolvedCwd, resolvedManifestPath);
|
|
194
|
+
if (relativeManifestPath === '' ||
|
|
195
|
+
path.isAbsolute(relativeManifestPath) ||
|
|
196
|
+
relativeManifestPath.startsWith(`..${path.sep}`) ||
|
|
197
|
+
relativeManifestPath === '..') {
|
|
198
|
+
throw new PnpmError('INVALID_MANIFEST_PATH', `Cannot stage manifest outside of git cwd: ${change.manifestPath}`);
|
|
199
|
+
}
|
|
200
|
+
const manifestPath = relativeManifestPath.split(path.sep).join('/');
|
|
201
|
+
await execa('git', ['add', manifestPath], execOpts);
|
|
202
|
+
const commitArgs = ['commit', '-m', message];
|
|
203
|
+
if (opts.commitHooks === false) {
|
|
204
|
+
commitArgs.push('--no-verify');
|
|
205
|
+
}
|
|
206
|
+
// writeProjectManifest skips writing when the new content matches the existing
|
|
207
|
+
// file, so an --allow-same-version run can leave nothing staged and fail the
|
|
208
|
+
// commit. Pass --allow-empty in that case to let the tag point at the current
|
|
209
|
+
// HEAD as a deliberate marker.
|
|
210
|
+
if (opts.allowSameVersion) {
|
|
211
|
+
commitArgs.push('--allow-empty');
|
|
212
|
+
}
|
|
213
|
+
await execa('git', commitArgs, execOpts);
|
|
214
|
+
const tagArgs = ['tag'];
|
|
215
|
+
if (opts.signGitTag) {
|
|
216
|
+
tagArgs.push('-s');
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
tagArgs.push('-a');
|
|
220
|
+
}
|
|
221
|
+
tagArgs.push(tagName, '-m', message);
|
|
222
|
+
await execa('git', tagArgs, execOpts);
|
|
223
|
+
}
|
|
156
224
|
export const version = {
|
|
157
225
|
handler,
|
|
158
226
|
help,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/releasing.commands",
|
|
3
|
-
"version": "1100.0
|
|
3
|
+
"version": "1100.1.0",
|
|
4
4
|
"description": "Commands for deploy, pack, and publish",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"@zkochan/rimraf": "^4.0.0",
|
|
30
30
|
"chalk": "^5.6.0",
|
|
31
31
|
"ci-info": "^4.3.0",
|
|
32
|
+
"detect-libc": "^2.0.3",
|
|
32
33
|
"enquirer": "^2.4.1",
|
|
33
34
|
"execa": "npm:safe-execa@0.3.0",
|
|
34
35
|
"libnpmpublish": "^11.1.3",
|
|
@@ -47,32 +48,34 @@
|
|
|
47
48
|
"write-json-file": "^7.0.0",
|
|
48
49
|
"write-yaml-file": "^6.0.0",
|
|
49
50
|
"@pnpm/bins.resolver": "1100.0.1",
|
|
51
|
+
"@pnpm/cli.utils": "1101.0.0",
|
|
50
52
|
"@pnpm/cli.common-cli-options-help": "1100.0.0",
|
|
51
|
-
"@pnpm/catalogs.types": "1100.0.0",
|
|
52
|
-
"@pnpm/cli.utils": "1100.0.1",
|
|
53
|
-
"@pnpm/config.reader": "1100.0.1",
|
|
54
53
|
"@pnpm/config.pick-registry-for-package": "1100.0.1",
|
|
55
|
-
"@pnpm/deps.path": "1100.0.1",
|
|
56
54
|
"@pnpm/constants": "1100.0.0",
|
|
55
|
+
"@pnpm/engine.runtime.node-resolver": "1100.0.3",
|
|
57
56
|
"@pnpm/error": "1100.0.0",
|
|
58
|
-
"@pnpm/fetching.directory-fetcher": "1100.0.
|
|
59
|
-
"@pnpm/exec.
|
|
60
|
-
"@pnpm/
|
|
61
|
-
"@pnpm/
|
|
57
|
+
"@pnpm/fetching.directory-fetcher": "1100.0.3",
|
|
58
|
+
"@pnpm/exec.pnpm-cli-runner": "1100.0.0",
|
|
59
|
+
"@pnpm/exec.lifecycle": "1100.0.3",
|
|
60
|
+
"@pnpm/deps.path": "1100.0.1",
|
|
61
|
+
"@pnpm/installing.client": "1100.0.3",
|
|
62
62
|
"@pnpm/fs.is-empty-dir-or-nothing": "1100.0.0",
|
|
63
|
-
"@pnpm/installing.client": "1100.0.1",
|
|
64
63
|
"@pnpm/fs.packlist": "1100.0.0",
|
|
65
|
-
"@pnpm/
|
|
66
|
-
"@pnpm/
|
|
67
|
-
"@pnpm/
|
|
68
|
-
"@pnpm/lockfile.
|
|
69
|
-
"@pnpm/network.git-utils": "1100.0.0",
|
|
64
|
+
"@pnpm/catalogs.types": "1100.0.0",
|
|
65
|
+
"@pnpm/fs.indexed-pkg-importer": "1100.0.2",
|
|
66
|
+
"@pnpm/engine.runtime.commands": "1100.0.3",
|
|
67
|
+
"@pnpm/lockfile.types": "1100.0.2",
|
|
70
68
|
"@pnpm/network.web-auth": "1101.0.0",
|
|
71
|
-
"@pnpm/
|
|
69
|
+
"@pnpm/network.git-utils": "1100.0.0",
|
|
70
|
+
"@pnpm/releasing.exportable-manifest": "1100.0.2",
|
|
72
71
|
"@pnpm/types": "1101.0.0",
|
|
73
|
-
"@pnpm/resolving.resolver-base": "1100.0
|
|
74
|
-
"@pnpm/
|
|
75
|
-
"@pnpm/workspace.projects-
|
|
72
|
+
"@pnpm/resolving.resolver-base": "1100.1.0",
|
|
73
|
+
"@pnpm/lockfile.fs": "1100.0.2",
|
|
74
|
+
"@pnpm/workspace.projects-filter": "1100.0.3",
|
|
75
|
+
"@pnpm/workspace.projects-sorter": "1100.0.1",
|
|
76
|
+
"@pnpm/network.fetch": "1100.0.1",
|
|
77
|
+
"@pnpm/config.reader": "1101.1.0",
|
|
78
|
+
"@pnpm/installing.commands": "1100.1.1"
|
|
76
79
|
},
|
|
77
80
|
"peerDependencies": {
|
|
78
81
|
"@pnpm/logger": ">=1001.0.0 <1002.0.0"
|
|
@@ -95,15 +98,15 @@
|
|
|
95
98
|
"load-json-file": "^7.0.1",
|
|
96
99
|
"tar": "^7.5.10",
|
|
97
100
|
"write-yaml-file": "^6.0.0",
|
|
98
|
-
"@pnpm/
|
|
99
|
-
"@pnpm/
|
|
100
|
-
"@pnpm/
|
|
101
|
+
"@pnpm/hooks.pnpmfile": "1100.0.2",
|
|
102
|
+
"@pnpm/prepare": "1100.0.2",
|
|
103
|
+
"@pnpm/assert-project": "1100.0.2",
|
|
104
|
+
"@pnpm/releasing.commands": "1100.1.0",
|
|
101
105
|
"@pnpm/logger": "1100.0.0",
|
|
102
|
-
"@pnpm/prepare": "1100.0.1",
|
|
103
|
-
"@pnpm/releasing.commands": "1100.0.1",
|
|
104
106
|
"@pnpm/test-fixtures": "1100.0.0",
|
|
105
|
-
"@pnpm/
|
|
106
|
-
"@pnpm/
|
|
107
|
+
"@pnpm/testing.command-defaults": "1100.0.1",
|
|
108
|
+
"@pnpm/catalogs.config": "1100.0.0",
|
|
109
|
+
"@pnpm/test-ipc-server": "1100.0.0"
|
|
107
110
|
},
|
|
108
111
|
"engines": {
|
|
109
112
|
"node": ">=22.13"
|