@pnpm/releasing.commands 1100.6.0 → 1100.6.2

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 (93) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/package.json +23 -23
  3. package/lib/change/index.d.ts +0 -41
  4. package/lib/change/index.js +0 -245
  5. package/lib/deploy/createDeployFiles.d.ts +0 -26
  6. package/lib/deploy/createDeployFiles.js +0 -255
  7. package/lib/deploy/deploy.d.ts +0 -12
  8. package/lib/deploy/deploy.js +0 -398
  9. package/lib/deploy/deployHook.d.ts +0 -2
  10. package/lib/deploy/deployHook.js +0 -15
  11. package/lib/deploy/index.d.ts +0 -2
  12. package/lib/deploy/index.js +0 -3
  13. package/lib/index.d.ts +0 -7
  14. package/lib/lane/index.d.ts +0 -24
  15. package/lib/lane/index.js +0 -157
  16. package/lib/pack-app/index.d.ts +0 -2
  17. package/lib/pack-app/index.js +0 -3
  18. package/lib/pack-app/packApp.d.ts +0 -22
  19. package/lib/pack-app/packApp.js +0 -558
  20. package/lib/publish/FailedToPublishError.d.ts +0 -22
  21. package/lib/publish/FailedToPublishError.js +0 -40
  22. package/lib/publish/batchPublish.d.ts +0 -20
  23. package/lib/publish/batchPublish.js +0 -201
  24. package/lib/publish/displayError.d.ts +0 -1
  25. package/lib/publish/displayError.js +0 -23
  26. package/lib/publish/executeTokenHelper.d.ts +0 -4
  27. package/lib/publish/executeTokenHelper.js +0 -17
  28. package/lib/publish/extractManifestFromPacked.d.ts +0 -19
  29. package/lib/publish/extractManifestFromPacked.js +0 -110
  30. package/lib/publish/index.d.ts +0 -3
  31. package/lib/publish/index.js +0 -4
  32. package/lib/publish/oidc/authToken.d.ts +0 -73
  33. package/lib/publish/oidc/authToken.js +0 -97
  34. package/lib/publish/oidc/idToken.d.ts +0 -76
  35. package/lib/publish/oidc/idToken.js +0 -90
  36. package/lib/publish/oidc/provenance.d.ts +0 -73
  37. package/lib/publish/oidc/provenance.js +0 -91
  38. package/lib/publish/otp.d.ts +0 -38
  39. package/lib/publish/otp.js +0 -41
  40. package/lib/publish/otpEnv.d.ts +0 -7
  41. package/lib/publish/otpEnv.js +0 -5
  42. package/lib/publish/pack.d.ts +0 -34
  43. package/lib/publish/pack.js +0 -408
  44. package/lib/publish/previousChangelog.d.ts +0 -19
  45. package/lib/publish/previousChangelog.js +0 -182
  46. package/lib/publish/publish.d.ts +0 -40
  47. package/lib/publish/publish.js +0 -256
  48. package/lib/publish/publishPackedPkg.d.ts +0 -79
  49. package/lib/publish/publishPackedPkg.js +0 -298
  50. package/lib/publish/recursivePublish.d.ts +0 -18
  51. package/lib/publish/recursivePublish.js +0 -132
  52. package/lib/publish/registryConfigKeys.d.ts +0 -30
  53. package/lib/publish/registryConfigKeys.js +0 -50
  54. package/lib/publish/utils/shared-context.d.ts +0 -7
  55. package/lib/publish/utils/shared-context.js +0 -20
  56. package/lib/stage/approve.d.ts +0 -2
  57. package/lib/stage/approve.js +0 -14
  58. package/lib/stage/context.d.ts +0 -14
  59. package/lib/stage/context.js +0 -25
  60. package/lib/stage/download.d.ts +0 -2
  61. package/lib/stage/download.js +0 -32
  62. package/lib/stage/errors.d.ts +0 -15
  63. package/lib/stage/errors.js +0 -17
  64. package/lib/stage/help.d.ts +0 -1
  65. package/lib/stage/help.js +0 -84
  66. package/lib/stage/index.d.ts +0 -13
  67. package/lib/stage/index.js +0 -57
  68. package/lib/stage/list.d.ts +0 -2
  69. package/lib/stage/list.js +0 -49
  70. package/lib/stage/parsing.d.ts +0 -6
  71. package/lib/stage/parsing.js +0 -27
  72. package/lib/stage/publish.d.ts +0 -7
  73. package/lib/stage/publish.js +0 -38
  74. package/lib/stage/reject.d.ts +0 -2
  75. package/lib/stage/reject.js +0 -16
  76. package/lib/stage/rendering.d.ts +0 -11
  77. package/lib/stage/rendering.js +0 -50
  78. package/lib/stage/request.d.ts +0 -29
  79. package/lib/stage/request.js +0 -110
  80. package/lib/stage/types.d.ts +0 -38
  81. package/lib/stage/types.js +0 -3
  82. package/lib/stage/view.d.ts +0 -2
  83. package/lib/stage/view.js +0 -14
  84. package/lib/tarball/index.d.ts +0 -2
  85. package/lib/tarball/index.js +0 -3
  86. package/lib/tarball/publishSummary.d.ts +0 -47
  87. package/lib/tarball/publishSummary.js +0 -36
  88. package/lib/tarball/safeTarballFilename.d.ts +0 -8
  89. package/lib/tarball/safeTarballFilename.js +0 -21
  90. package/lib/tarball/summarizeTarball.d.ts +0 -12
  91. package/lib/tarball/summarizeTarball.js +0 -84
  92. package/lib/version/index.d.ts +0 -33
  93. package/lib/version/index.js +0 -337
@@ -1,408 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { createGzip } from 'node:zlib';
4
- import { getBinsFromPackageManifest } from '@pnpm/bins.resolver';
5
- import { FILTERING } from '@pnpm/cli.common-cli-options-help';
6
- import { readProjectManifest } from '@pnpm/cli.utils';
7
- import { getDefaultWorkspaceConcurrency, getWorkspaceConcurrency, types as allTypes } from '@pnpm/config.reader';
8
- import { PnpmError } from '@pnpm/error';
9
- import { packlist } from '@pnpm/fs.packlist';
10
- import { logger } from '@pnpm/logger';
11
- import { createExportableManifest, readReadmeFile } from '@pnpm/releasing.exportable-manifest';
12
- import { changelogStorage, readPendingChangelog, renderChangelog } from '@pnpm/releasing.versioning';
13
- import { sortFilteredProjects } from '@pnpm/workspace.projects-sorter';
14
- import chalk from 'chalk';
15
- import pLimit from 'p-limit';
16
- import { pick } from 'ramda';
17
- import { realpathMissing } from 'realpath-missing';
18
- import { renderHelp } from 'render-help';
19
- import tar from 'tar-stream';
20
- import { glob } from 'tinyglobby';
21
- import validateNpmPackageName from 'validate-npm-package-name';
22
- import { fetchPreviousChangelog } from './previousChangelog.js';
23
- import { runScriptsIfPresent } from './publish.js';
24
- const LICENSE_GLOB = 'LICEN{S,C}E{,.*}'; // cspell:disable-line
25
- export function rcOptionsTypes() {
26
- return {
27
- ...cliOptionsTypes(),
28
- ...pick([
29
- 'npm-path',
30
- 'skip-manifest-obfuscation',
31
- ], allTypes),
32
- };
33
- }
34
- export function cliOptionsTypes() {
35
- return {
36
- out: String,
37
- recursive: Boolean,
38
- ...pick([
39
- 'dry-run',
40
- 'pack-destination',
41
- 'pack-gzip-level',
42
- 'json',
43
- 'skip-manifest-obfuscation',
44
- 'workspace-concurrency',
45
- ], allTypes),
46
- };
47
- }
48
- export const commandNames = ['pack'];
49
- export function help() {
50
- return renderHelp({
51
- description: 'Create a tarball from a package',
52
- usages: ['pnpm pack'],
53
- descriptionLists: [
54
- {
55
- title: 'Options',
56
- list: [
57
- {
58
- description: 'Does everything `pnpm pack` would do except actually writing the tarball to disk.',
59
- name: '--dry-run',
60
- },
61
- {
62
- description: 'Directory in which `pnpm pack` will save tarballs. The default is the current working directory.',
63
- name: '--pack-destination <dir>',
64
- },
65
- {
66
- description: 'Prints the packed tarball and contents in the json format.',
67
- name: '--json',
68
- },
69
- {
70
- description: 'Customizes the output path for the tarball. Use `%s` and `%v` to include the package name and version, e.g., `%s.tgz` or `some-dir/%s-%v.tgz`. By default, the tarball is saved in the current working directory with the name `<package-name>-<version>.tgz`.',
71
- name: '--out <path>',
72
- },
73
- {
74
- description: 'Pack all packages from the workspace',
75
- name: '--recursive',
76
- shortAlias: '-r',
77
- },
78
- {
79
- description: 'Skip pnpm\'s manifest obfuscation: keep the original `packageManager` field and publish lifecycle scripts in the packed manifest instead of stripping them. The pnpm-specific `pnpm` field is still omitted.',
80
- name: '--skip-manifest-obfuscation',
81
- },
82
- {
83
- description: `Set the maximum number of concurrency. Default is ${getDefaultWorkspaceConcurrency()}. For unlimited concurrency use Infinity.`,
84
- name: '--workspace-concurrency <number>',
85
- },
86
- ],
87
- },
88
- FILTERING,
89
- ],
90
- });
91
- }
92
- export async function handler(opts) {
93
- const packedPackages = [];
94
- if (opts.recursive) {
95
- const selectedProjectsGraph = opts.selectedProjectsGraph;
96
- const pkgsToPack = [];
97
- for (const { package: pkg } of Object.values(selectedProjectsGraph)) {
98
- if (pkg.manifest.name && pkg.manifest.version) {
99
- pkgsToPack.push(pkg);
100
- }
101
- }
102
- const packedPkgDirs = new Set(pkgsToPack.map(({ rootDir }) => rootDir));
103
- if (packedPkgDirs.size === 0) {
104
- logger.info({
105
- message: 'There are no packages that should be packed',
106
- prefix: opts.dir,
107
- });
108
- }
109
- const chunks = sortFilteredProjects({
110
- selectedProjectsGraph,
111
- allProjectsGraph: opts.allProjectsGraph,
112
- prodAllProjectsGraph: opts.prodAllProjectsGraph,
113
- prodOnlySelectedProjectDirs: opts.prodOnlySelectedProjectDirs,
114
- });
115
- const limitPack = pLimit(getWorkspaceConcurrency(opts.workspaceConcurrency));
116
- const resolvedOpts = { ...opts };
117
- if (opts.out) {
118
- resolvedOpts.out = path.resolve(opts.dir, opts.out);
119
- }
120
- else if (opts.packDestination) {
121
- resolvedOpts.packDestination = path.resolve(opts.dir, opts.packDestination);
122
- }
123
- else {
124
- resolvedOpts.packDestination = path.resolve(opts.dir);
125
- }
126
- for (const chunk of chunks) {
127
- // eslint-disable-next-line no-await-in-loop
128
- await Promise.all(chunk.map(pkgDir => limitPack(async () => {
129
- if (!packedPkgDirs.has(pkgDir))
130
- return;
131
- const pkg = selectedProjectsGraph[pkgDir].package;
132
- const packResult = await api({
133
- ...resolvedOpts,
134
- dir: pkg.rootDir,
135
- });
136
- packedPackages.push(toPackResultJson(packResult));
137
- })));
138
- }
139
- }
140
- else {
141
- const packResult = await api(opts);
142
- packedPackages.push(toPackResultJson(packResult));
143
- }
144
- if (opts.json) {
145
- return JSON.stringify(packedPackages.length > 1 ? packedPackages : packedPackages[0], null, 2);
146
- }
147
- return packedPackages.map(({ name, version, filename, files }) => `${opts.unicode ? '📦 ' : 'package:'} ${name}@${version}
148
- ${chalk.blueBright('Tarball Contents')}
149
- ${files.map(({ path }) => path).join('\n')}
150
- ${chalk.blueBright('Tarball Details')}
151
- ${filename}`).join('\n\n');
152
- }
153
- export async function api(opts) {
154
- const { manifest: entryManifest, fileName: manifestFileName } = await readProjectManifest(opts.dir, opts);
155
- preventBundledDependenciesWithoutHoistedNodeLinker(opts.nodeLinker, entryManifest);
156
- const _runScriptsIfPresent = runScriptsIfPresent.bind(null, {
157
- depPath: opts.dir,
158
- extraBinPaths: opts.extraBinPaths,
159
- extraEnv: opts.extraEnv,
160
- pkgRoot: opts.dir,
161
- rootModulesDir: await realpathMissing(path.join(opts.dir, 'node_modules')),
162
- stdio: 'inherit',
163
- unsafePerm: true, // when running scripts explicitly, assume that they're trusted.
164
- userAgent: opts.userAgent,
165
- });
166
- if (!opts.ignoreScripts) {
167
- await _runScriptsIfPresent([
168
- 'prepack',
169
- 'prepare',
170
- ], entryManifest);
171
- }
172
- const dir = entryManifest.publishConfig?.directory
173
- ? path.join(opts.dir, entryManifest.publishConfig.directory)
174
- : opts.dir;
175
- // always read the latest manifest, as "prepack" or "prepare" script may modify package manifest.
176
- const { manifest } = await readProjectManifest(dir, opts);
177
- preventBundledDependenciesWithoutHoistedNodeLinker(opts.nodeLinker, manifest);
178
- if (!manifest.name) {
179
- throw new PnpmError('PACKAGE_NAME_NOT_FOUND', `Package name is not defined in the ${manifestFileName}.`);
180
- }
181
- if (!validateNpmPackageName(manifest.name).validForOldPackages) {
182
- throw new PnpmError('INVALID_PACKAGE_NAME', `Invalid package name "${manifest.name}".`);
183
- }
184
- if (!manifest.version) {
185
- throw new PnpmError('PACKAGE_VERSION_NOT_FOUND', `Package version is not defined in the ${manifestFileName}.`);
186
- }
187
- const publishManifest = await createPublishManifest({
188
- projectDir: dir,
189
- modulesDir: path.join(opts.dir, 'node_modules'),
190
- manifest,
191
- embedReadme: opts.embedReadme,
192
- catalogs: opts.catalogs ?? {},
193
- hooks: opts.hooks,
194
- skipManifestObfuscation: opts.skipManifestObfuscation,
195
- });
196
- // Strip semver build metadata (the `+<build>` segment) from the published version so that
197
- // the tarball, the manifest packed inside it, and the metadata sent to the registry all agree.
198
- // libnpmpublish runs `semver.clean()` on `manifest.version` before computing the provenance
199
- // subject, which removes build metadata. Leaving it in here would mismatch the version embedded
200
- // in the tarball's package.json and cause the registry to reject the publish with a 422 when
201
- // verifying the sigstore provenance bundle. See https://github.com/pnpm/pnpm/issues/11518.
202
- publishManifest.version = stripBuildMetadata(publishManifest.version);
203
- let tarballName;
204
- let packDestination;
205
- const normalizedName = manifest.name.replace('@', '').replace('/', '-');
206
- if (opts.out) {
207
- if (opts.packDestination) {
208
- throw new PnpmError('INVALID_OPTION', 'Cannot use --pack-destination and --out together');
209
- }
210
- const preparedOut = opts.out.replaceAll('%s', normalizedName).replaceAll('%v', publishManifest.version);
211
- const parsedOut = path.parse(preparedOut);
212
- packDestination = parsedOut.dir ? parsedOut.dir : opts.packDestination;
213
- tarballName = parsedOut.base;
214
- }
215
- else {
216
- tarballName = `${normalizedName}-${publishManifest.version}.tgz`;
217
- packDestination = opts.packDestination;
218
- }
219
- const files = await packlist(dir, {
220
- manifest: publishManifest,
221
- workspaceDir: opts.workspaceDir,
222
- });
223
- const filesMap = Object.fromEntries(files.map((file) => [`package/${file}`, path.join(dir, file)]));
224
- // cspell:disable-next-line
225
- if (opts.workspaceDir != null && dir !== opts.workspaceDir && !files.some((file) => /LICEN[CS]E(?:\..+)?/i.test(file))) {
226
- const { workspaceDir } = opts;
227
- const licenses = await glob([LICENSE_GLOB], { cwd: workspaceDir, expandDirectories: false });
228
- await Promise.all(licenses.map(async (license) => {
229
- const licensePath = path.join(workspaceDir, license);
230
- // Only inject a regular file. A symlink could point outside the workspace and leak its
231
- // target's bytes into the published tarball, so `lstat()` (which does not follow symlinks)
232
- // rejects it — matching pacquet's inject_workspace_license.
233
- const stats = await fs.promises.lstat(licensePath);
234
- if (stats.isFile()) {
235
- filesMap[`package/${license}`] = licensePath;
236
- }
237
- }));
238
- }
239
- // In `registry` changelog storage the package carries no committed
240
- // CHANGELOG.md; its section was parked at `pnpm version -r` time and is
241
- // composed here on top of the previously published version's changelog and
242
- // packed in. A composed entry supersedes any stale committed CHANGELOG.md.
243
- const injectedEntries = {};
244
- const composedChangelog = await composeRegistryChangelog(opts, manifest.name, manifest.version);
245
- if (composedChangelog != null) {
246
- delete filesMap['package/CHANGELOG.md'];
247
- injectedEntries['package/CHANGELOG.md'] = composedChangelog;
248
- }
249
- const destDir = packDestination
250
- ? (path.isAbsolute(packDestination) ? packDestination : path.join(dir, packDestination ?? '.'))
251
- : dir;
252
- if (!opts.dryRun) {
253
- await fs.promises.mkdir(destDir, { recursive: true });
254
- }
255
- // Derive `contents` and `unpackedSize` from `filesMap` (the full set of tar entries) rather than
256
- // from `files` (the packlist subset) so that:
257
- // - workspace LICENSE files appended to `filesMap` after the packlist call are included; and
258
- // - `package.yaml` / `package.json5` entries are reported under the name they actually have in
259
- // the tar (`package.json`), since `packPkg()` rewrites them.
260
- // The `stat()` pass must run before `postpack`, which may delete prepack-generated files that
261
- // were packed. See https://github.com/pnpm/pnpm/issues/12775.
262
- const sizes = await Promise.all(Object.entries(filesMap).map(async ([name, source]) => {
263
- if (isManifestEntry(name)) {
264
- return Buffer.byteLength(JSON.stringify(publishManifest, null, 2));
265
- }
266
- const stat = await fs.promises.stat(source);
267
- return stat.size;
268
- }));
269
- const injectedSize = Object.values(injectedEntries).reduce((acc, content) => acc + Buffer.byteLength(content), 0);
270
- const unpackedSize = sizes.reduce((acc, size) => acc + size, 0) + injectedSize;
271
- const packedContents = Array.from(new Set([
272
- ...Object.keys(filesMap).map((name) => isManifestEntry(name)
273
- ? 'package.json'
274
- : name.replace(/^package\//, '')),
275
- ...Object.keys(injectedEntries).map((name) => name.replace(/^package\//, '')),
276
- ])).sort((a, b) => a.localeCompare(b, 'en'));
277
- if (!opts.dryRun) {
278
- await packPkg({
279
- destFile: path.join(destDir, tarballName),
280
- filesMap,
281
- injectedEntries,
282
- modulesDir: path.join(opts.dir, 'node_modules'),
283
- packGzipLevel: opts.packGzipLevel,
284
- manifest: publishManifest,
285
- bins: [
286
- ...(await getBinsFromPackageManifest(publishManifest, dir)).map(({ path }) => path),
287
- ...(manifest.publishConfig?.executableFiles ?? [])
288
- .map((executableFile) => path.join(dir, executableFile)),
289
- ],
290
- });
291
- if (!opts.ignoreScripts) {
292
- await _runScriptsIfPresent(['postpack'], entryManifest);
293
- }
294
- }
295
- let packedTarballPath;
296
- if (opts.dir !== destDir) {
297
- packedTarballPath = path.join(destDir, tarballName);
298
- }
299
- else {
300
- packedTarballPath = path.relative(opts.dir, path.join(dir, tarballName));
301
- }
302
- return {
303
- publishedManifest: await withRegistryReadme(publishManifest, dir),
304
- contents: packedContents,
305
- tarballPath: packedTarballPath,
306
- unpackedSize,
307
- };
308
- }
309
- /**
310
- * The readme is always sent to the registry as package metadata, matching the npm CLI, so that
311
- * registries can render it on the package page. The `embed-readme` setting only controls whether
312
- * the readme is additionally written into the `package.json` inside the tarball (via
313
- * `createExportableManifest`), which is why it is added to the returned manifest here rather than
314
- * to the packed one.
315
- */
316
- async function withRegistryReadme(manifest, projectDir) {
317
- if (manifest.readme != null)
318
- return manifest;
319
- const readme = await readReadmeFile(projectDir);
320
- if (readme == null)
321
- return manifest;
322
- return { ...manifest, readme };
323
- }
324
- // True when a `package/<path>` tar key names the package manifest, which is
325
- // packed as a single serialized `package/package.json` entry and reported as
326
- // `package.json` in the contents listing regardless of the source file name.
327
- function isManifestEntry(name) {
328
- return name === 'package/package.json' || name === 'package/package.json5' || name === 'package/package.yaml';
329
- }
330
- /**
331
- * The CHANGELOG.md to pack for a `registry`-storage release: its parked
332
- * section (written at `pnpm version -r` time) rendered on top of the
333
- * previously published version's changelog. `undefined` when storage is
334
- * `repository`, there is no workspace, or the release has no parked section
335
- * (an ordinary `pnpm pack` of a package that is not mid-release).
336
- */
337
- async function composeRegistryChangelog(opts, pkgName, version) {
338
- if (changelogStorage(opts.versioning) !== 'registry' || opts.workspaceDir == null)
339
- return undefined;
340
- const section = await readPendingChangelog(opts.workspaceDir, pkgName, version);
341
- if (section == null)
342
- return undefined;
343
- const previous = opts.registries != null
344
- ? await fetchPreviousChangelog(opts, pkgName, version)
345
- : undefined;
346
- return renderChangelog(previous ?? null, pkgName, section);
347
- }
348
- function stripBuildMetadata(version) {
349
- const plusIndex = version.indexOf('+');
350
- return plusIndex === -1 ? version : version.slice(0, plusIndex);
351
- }
352
- function preventBundledDependenciesWithoutHoistedNodeLinker(nodeLinker, manifest) {
353
- if (nodeLinker === 'hoisted')
354
- return;
355
- for (const key of ['bundledDependencies', 'bundleDependencies']) {
356
- const bundledDependencies = manifest[key];
357
- if (bundledDependencies) {
358
- throw new PnpmError('BUNDLED_DEPENDENCIES_WITHOUT_HOISTED', `${key} does not work with "nodeLinker: ${nodeLinker}"`, {
359
- hint: `Add "nodeLinker: hoisted" to pnpm-workspace.yaml or delete ${key} from the root package.json to resolve this error`,
360
- });
361
- }
362
- }
363
- }
364
- async function packPkg(opts) {
365
- const { destFile, filesMap, injectedEntries, bins, manifest, } = opts;
366
- const mtime = new Date('1985-10-26T08:15:00.000Z');
367
- const pack = tar.pack();
368
- await Promise.all(Object.entries(filesMap).map(async ([name, source]) => {
369
- const isExecutable = bins.some((bin) => path.relative(bin, source) === '');
370
- const mode = isExecutable ? 0o755 : 0o644;
371
- if (isManifestEntry(name)) {
372
- pack.entry({ mode, mtime, name: 'package/package.json' }, JSON.stringify(manifest, null, 2));
373
- return;
374
- }
375
- pack.entry({ mode, mtime, name }, fs.readFileSync(source));
376
- }));
377
- for (const [name, content] of Object.entries(injectedEntries ?? {})) {
378
- pack.entry({ mode: 0o644, mtime, name }, content);
379
- }
380
- const tarball = fs.createWriteStream(destFile);
381
- pack.pipe(createGzip({ level: opts.packGzipLevel })).pipe(tarball);
382
- pack.finalize();
383
- return new Promise((resolve, reject) => {
384
- tarball.on('close', () => {
385
- resolve();
386
- }).on('error', reject);
387
- });
388
- }
389
- async function createPublishManifest(opts) {
390
- const { projectDir, embedReadme, modulesDir, manifest, catalogs, hooks, skipManifestObfuscation } = opts;
391
- return createExportableManifest(projectDir, manifest, {
392
- catalogs,
393
- hooks,
394
- embedReadme,
395
- modulesDir,
396
- skipManifestObfuscation,
397
- });
398
- }
399
- function toPackResultJson(packResult) {
400
- const { publishedManifest, contents, tarballPath } = packResult;
401
- return {
402
- name: publishedManifest.name,
403
- version: publishedManifest.version,
404
- filename: tarballPath,
405
- files: contents.map((file) => ({ path: file })),
406
- };
407
- }
408
- //# sourceMappingURL=pack.js.map
@@ -1,19 +0,0 @@
1
- import type { Config } from '@pnpm/config.reader';
2
- import { type CreateFetchFromRegistryOptions } from '@pnpm/network.fetch';
3
- export type PreviousChangelogOptions = CreateFetchFromRegistryOptions & Pick<Config, 'registries' | 'fetchRetries' | 'fetchRetryFactor' | 'fetchRetryMaxtimeout' | 'fetchRetryMintimeout' | 'fetchTimeout'>;
4
- /**
5
- * The `CHANGELOG.md` packed into the highest published version of `pkgName`
6
- * that is semver-lower than `version` — the changelog the section for
7
- * `version` is prepended onto in `registry` storage. `undefined` when the
8
- * package is new, has no earlier published version, or that version's tarball
9
- * carried no changelog.
10
- */
11
- export declare function fetchPreviousChangelog(opts: PreviousChangelogOptions, pkgName: string, version: string): Promise<string | undefined>;
12
- /**
13
- * The `CHANGELOG.md` packed into the published `pkgName@version` exactly, or
14
- * `undefined` when that version is not published (or carried no changelog).
15
- * Used to confirm a release actually carries its composed section before the
16
- * intents behind it are garbage-collected.
17
- */
18
- export declare function fetchPublishedChangelog(opts: PreviousChangelogOptions, pkgName: string, version: string): Promise<string | undefined>;
19
- export declare function changelogHasSection(changelog: string, section: string): boolean;
@@ -1,182 +0,0 @@
1
- import { gunzipSync } from 'node:zlib';
2
- import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
3
- import { PnpmError } from '@pnpm/error';
4
- import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header';
5
- import { createFetchFromRegistry } from '@pnpm/network.fetch';
6
- import { fetchMetadataFromFromRegistry } from '@pnpm/resolving.npm-resolver';
7
- import { lt, rsort, valid } from 'semver';
8
- import tar from 'tar-stream';
9
- const CHANGELOG_ENTRY = 'package/CHANGELOG.md';
10
- /**
11
- * Caps the previous tarball we buffer and decompress to compose the changelog.
12
- * The bytes come from a registry/proxy, so an unbounded read or a highly
13
- * compressible ("gzip bomb") tarball could OOM release automation. A composed
14
- * changelog is best-effort — exceeding the cap just skips the history prepend —
15
- * so this bound can be generous while still defeating the amplification attack.
16
- */
17
- const MAX_TARBALL_BYTES = 256 * 1024 * 1024;
18
- function createRegistryClient(opts) {
19
- return {
20
- fetch: createFetchFromRegistry(opts),
21
- getAuthHeader: createGetAuthHeaderByURI(opts.configByUri ?? {}),
22
- };
23
- }
24
- /**
25
- * The `CHANGELOG.md` packed into the highest published version of `pkgName`
26
- * that is semver-lower than `version` — the changelog the section for
27
- * `version` is prepended onto in `registry` storage. `undefined` when the
28
- * package is new, has no earlier published version, or that version's tarball
29
- * carried no changelog.
30
- */
31
- export async function fetchPreviousChangelog(opts, pkgName, version) {
32
- const client = createRegistryClient(opts);
33
- const meta = await fetchPackument(client, opts, pkgName);
34
- if (meta == null)
35
- return undefined;
36
- const previousVersion = pickPreviousVersion(meta, version);
37
- if (previousVersion == null)
38
- return undefined;
39
- return downloadTarballChangelog(client, pkgName, meta, previousVersion);
40
- }
41
- /**
42
- * The `CHANGELOG.md` packed into the published `pkgName@version` exactly, or
43
- * `undefined` when that version is not published (or carried no changelog).
44
- * Used to confirm a release actually carries its composed section before the
45
- * intents behind it are garbage-collected.
46
- */
47
- export async function fetchPublishedChangelog(opts, pkgName, version) {
48
- const client = createRegistryClient(opts);
49
- const meta = await fetchPackument(client, opts, pkgName);
50
- if (meta?.versions[version] == null)
51
- return undefined;
52
- return downloadTarballChangelog(client, pkgName, meta, version);
53
- }
54
- export function changelogHasSection(changelog, section) {
55
- return changelog.includes(section.trim());
56
- }
57
- async function fetchPackument(client, opts, pkgName) {
58
- const registry = pickRegistryForPackage(opts.registries, pkgName);
59
- let fetchResult;
60
- try {
61
- fetchResult = await fetchMetadataFromFromRegistry({
62
- fetch: client.fetch,
63
- retry: {
64
- factor: opts.fetchRetryFactor,
65
- maxTimeout: opts.fetchRetryMaxtimeout,
66
- minTimeout: opts.fetchRetryMintimeout,
67
- retries: opts.fetchRetries,
68
- },
69
- timeout: opts.fetchTimeout ?? 60000,
70
- fetchWarnTimeoutMs: 10000,
71
- }, pkgName, {
72
- registry,
73
- authHeaderValue: client.getAuthHeader(registry, { pkgName }),
74
- fullMetadata: false,
75
- });
76
- }
77
- catch (err) {
78
- // A package with no published version yet has no changelog to build on.
79
- if (err != null && typeof err === 'object' && 'code' in err && err.code === 'ERR_PNPM_FETCH_404') {
80
- return undefined;
81
- }
82
- throw err;
83
- }
84
- return fetchResult.notModified ? undefined : fetchResult.meta;
85
- }
86
- /** Highest published version of the package that is semver-lower than `version`. */
87
- function pickPreviousVersion(meta, version) {
88
- const candidates = Object.keys(meta.versions).filter((candidate) => valid(candidate) != null && lt(candidate, version));
89
- return candidates.length > 0 ? rsort(candidates)[0] : undefined;
90
- }
91
- async function downloadTarballChangelog(client, pkgName, meta, version) {
92
- const tarballUrl = meta.versions[version]?.dist?.tarball;
93
- if (tarballUrl == null)
94
- return undefined;
95
- const response = await client.fetch(tarballUrl, { authHeaderValue: client.getAuthHeader(tarballUrl, { pkgName }) });
96
- if (!response.ok) {
97
- throw new PnpmError('CHANGELOG_TARBALL_FETCH_FAILED', `Failed to download ${pkgName}@${version} tarball (${response.status}) to compose the changelog: ${tarballUrl}`);
98
- }
99
- const tarballData = await readCapped(response, MAX_TARBALL_BYTES);
100
- if (tarballData == null)
101
- return undefined;
102
- return extractTarballEntry(tarballData, CHANGELOG_ENTRY);
103
- }
104
- /**
105
- * Reads a response body into a buffer, stopping (and returning `undefined`) as
106
- * soon as it exceeds `maxBytes` — bounding the actual download rather than
107
- * trusting a `content-length` header, which may be absent or lie.
108
- */
109
- async function readCapped(response, maxBytes) {
110
- const reader = response.body?.getReader();
111
- if (reader == null) {
112
- const buffer = Buffer.from(await response.arrayBuffer());
113
- return buffer.byteLength > maxBytes ? undefined : buffer;
114
- }
115
- const chunks = [];
116
- let total = 0;
117
- for (;;) {
118
- // Streaming a body is inherently sequential — each read must await the
119
- // previous chunk — so the successive awaits here are intentional.
120
- // eslint-disable-next-line no-await-in-loop
121
- const { done, value } = await reader.read();
122
- if (done)
123
- break;
124
- total += value.byteLength;
125
- if (total > maxBytes) {
126
- // Best-effort cleanup: a cancel failure must not turn the over-cap path
127
- // into a hard error — the caller just gets no changelog either way.
128
- // eslint-disable-next-line no-await-in-loop
129
- await reader.cancel().catch(() => { });
130
- return undefined;
131
- }
132
- chunks.push(Buffer.from(value));
133
- }
134
- return Buffer.concat(chunks);
135
- }
136
- /**
137
- * Reads one entry's contents out of a (optionally gzipped) tarball buffer.
138
- * Composing the changelog is best-effort, so any decode/parse failure —
139
- * including a gzip bomb tripping the inflate cap — resolves to `undefined`
140
- * (no history prepend) rather than throwing.
141
- */
142
- async function extractTarballEntry(tarballData, entryName) {
143
- const tarData = gunzipCapped(tarballData);
144
- if (tarData == null)
145
- return undefined;
146
- const extract = tar.extract();
147
- return new Promise((resolve) => {
148
- let contents;
149
- extract.on('entry', (header, stream, next) => {
150
- if (header.name !== entryName) {
151
- stream.resume();
152
- stream.on('end', next);
153
- stream.on('error', () => resolve(undefined));
154
- return;
155
- }
156
- const chunks = [];
157
- stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
158
- stream.on('error', () => resolve(undefined));
159
- stream.on('end', () => {
160
- contents = Buffer.concat(chunks).toString('utf8');
161
- next();
162
- });
163
- });
164
- extract.on('error', () => resolve(undefined));
165
- extract.on('finish', () => resolve(contents));
166
- extract.end(tarData);
167
- });
168
- }
169
- /**
170
- * Inflates a published `.tgz`, capped at `MAX_TARBALL_BYTES` of output so a
171
- * gzip bomb throws rather than ballooning memory. Returns `undefined` on that
172
- * cap or any other decode failure — the caller treats it as no changelog.
173
- */
174
- function gunzipCapped(tarballData) {
175
- try {
176
- return gunzipSync(tarballData, { maxOutputLength: MAX_TARBALL_BYTES });
177
- }
178
- catch {
179
- return undefined;
180
- }
181
- }
182
- //# sourceMappingURL=previousChangelog.js.map
@@ -1,40 +0,0 @@
1
- import { type Config, type ConfigContext } from '@pnpm/config.reader';
2
- import { type RunLifecycleHookOptions } from '@pnpm/exec.lifecycle';
3
- import type { ExportedManifest } from '@pnpm/releasing.exportable-manifest';
4
- import type { ProjectManifest } from '@pnpm/types';
5
- import { type PublishSummary } from './publishPackedPkg.js';
6
- import { type PublishRecursiveOpts, type RecursivePublishedPackage } from './recursivePublish.js';
7
- export declare function rcOptionsTypes(): Record<string, unknown>;
8
- export declare function cliOptionsTypes(): Record<string, unknown>;
9
- export declare const commandNames: string[];
10
- export declare function help(): string;
11
- export declare function handler(opts: Omit<PublishRecursiveOpts, 'workspaceDir'> & {
12
- argv: {
13
- original: string[];
14
- };
15
- engineStrict?: boolean;
16
- json?: boolean;
17
- recursive?: boolean;
18
- workspaceDir?: string;
19
- } & Pick<Config, 'bin' | 'gitChecks' | 'ignoreScripts' | 'pnpmHomeDir' | 'publishBranch' | 'embedReadme' | 'skipManifestObfuscation' | 'versioning'> & Pick<ConfigContext, 'allProjects'>, params: string[]): Promise<{
20
- exitCode?: number;
21
- output?: string;
22
- } | undefined>;
23
- export interface PublishResult {
24
- exitCode?: number;
25
- manifest?: ProjectManifest;
26
- publishedManifest?: ExportedManifest;
27
- /** Per-package summary in the npm-CLI `--json` shape; only populated for single-package publish. */
28
- publishSummary?: PublishSummary;
29
- /** Per-package summaries collected by recursive publish. */
30
- publishedPackages?: RecursivePublishedPackage[];
31
- }
32
- export declare function publish(opts: Omit<PublishRecursiveOpts, 'workspaceDir'> & {
33
- argv: {
34
- original: string[];
35
- };
36
- engineStrict?: boolean;
37
- recursive?: boolean;
38
- workspaceDir?: string;
39
- } & Pick<Config, 'bin' | 'gitChecks' | 'ignoreScripts' | 'pnpmHomeDir' | 'publishBranch' | 'embedReadme' | 'packGzipLevel' | 'skipManifestObfuscation' | 'versioning'> & Pick<ConfigContext, 'allProjects'>, params: string[]): Promise<PublishResult>;
40
- export declare function runScriptsIfPresent(opts: RunLifecycleHookOptions, scriptNames: string[], manifest: ProjectManifest): Promise<void>;