@pnpm/releasing.commands 1100.2.18 → 1100.3.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.
- package/lib/deploy/deploy.js +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/publish/otp.d.ts +2 -0
- package/lib/publish/pack.d.ts +1 -1
- package/lib/publish/pack.js +9 -1
- package/lib/publish/publish.d.ts +2 -2
- package/lib/publish/publish.js +5 -0
- package/lib/publish/publishPackedPkg.d.ts +3 -29
- package/lib/publish/publishPackedPkg.js +16 -26
- package/lib/publish/recursivePublish.js +2 -1
- package/lib/stage/approve.d.ts +2 -0
- package/lib/stage/approve.js +14 -0
- package/lib/stage/context.d.ts +14 -0
- package/lib/stage/context.js +25 -0
- package/lib/stage/download.d.ts +2 -0
- package/lib/stage/download.js +25 -0
- package/lib/stage/errors.d.ts +15 -0
- package/lib/stage/errors.js +17 -0
- package/lib/stage/help.d.ts +1 -0
- package/lib/stage/help.js +84 -0
- package/lib/stage/index.d.ts +13 -0
- package/lib/stage/index.js +57 -0
- package/lib/stage/list.d.ts +2 -0
- package/lib/stage/list.js +44 -0
- package/lib/stage/parsing.d.ts +6 -0
- package/lib/stage/parsing.js +27 -0
- package/lib/stage/publish.d.ts +7 -0
- package/lib/stage/publish.js +38 -0
- package/lib/stage/reject.d.ts +2 -0
- package/lib/stage/reject.js +16 -0
- package/lib/stage/rendering.d.ts +11 -0
- package/lib/stage/rendering.js +52 -0
- package/lib/stage/request.d.ts +29 -0
- package/lib/stage/request.js +110 -0
- package/lib/stage/types.d.ts +38 -0
- package/lib/stage/types.js +3 -0
- package/lib/stage/view.d.ts +2 -0
- package/lib/stage/view.js +14 -0
- package/lib/tarball/index.d.ts +2 -0
- package/lib/tarball/index.js +3 -0
- package/lib/tarball/publishSummary.d.ts +39 -0
- package/lib/tarball/publishSummary.js +16 -0
- package/lib/tarball/summarizeTarball.d.ts +12 -0
- package/lib/tarball/summarizeTarball.js +86 -0
- package/package.json +40 -39
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PnpmError } from '@pnpm/error';
|
|
2
|
+
import npa from '@pnpm/npm-package-arg';
|
|
3
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4
|
+
export function parseStagePackageSpec(rawSpec) {
|
|
5
|
+
let spec;
|
|
6
|
+
try {
|
|
7
|
+
spec = npa(rawSpec);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
throw new PnpmError('INVALID_PACKAGE_SPEC', `Invalid package spec: ${rawSpec}`);
|
|
11
|
+
}
|
|
12
|
+
if (!spec.name) {
|
|
13
|
+
throw new PnpmError('INVALID_PACKAGE_SPEC', `Invalid package spec: ${rawSpec}`);
|
|
14
|
+
}
|
|
15
|
+
return { name: spec.name, rawSpec: spec.rawSpec };
|
|
16
|
+
}
|
|
17
|
+
export function requireStageId(params, subcommand) {
|
|
18
|
+
if (!params[0]) {
|
|
19
|
+
throw new PnpmError('STAGE_ID_REQUIRED', `Missing required <stage-id> for "pnpm stage ${subcommand}"`);
|
|
20
|
+
}
|
|
21
|
+
const stageId = params[0];
|
|
22
|
+
if (!UUID_REGEX.test(stageId)) {
|
|
23
|
+
throw new PnpmError('INVALID_STAGE_ID', 'stage-id must be a valid UUID');
|
|
24
|
+
}
|
|
25
|
+
return stageId;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=parsing.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as publishCommand from '../publish/publish.js';
|
|
2
|
+
import { renderStagePublishSummary } from './rendering.js';
|
|
3
|
+
export async function stagePublish(opts, params) {
|
|
4
|
+
const result = await publishCommand.publish({
|
|
5
|
+
...opts,
|
|
6
|
+
stage: true,
|
|
7
|
+
}, params);
|
|
8
|
+
if (opts.json) {
|
|
9
|
+
if (result.publishSummary) {
|
|
10
|
+
return { output: JSON.stringify(keyByPackageName([result.publishSummary]), null, 2), exitCode: 0 };
|
|
11
|
+
}
|
|
12
|
+
if (result.publishedPackages) {
|
|
13
|
+
return { output: JSON.stringify(keyByPackageName(result.publishedPackages), null, 2), exitCode: result.exitCode ?? 0 };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const publishedPackages = result.publishSummary
|
|
17
|
+
? [result.publishSummary]
|
|
18
|
+
: result.publishedPackages ?? [];
|
|
19
|
+
if (publishedPackages.length > 0) {
|
|
20
|
+
return {
|
|
21
|
+
output: publishedPackages.map((summary) => renderStagePublishSummary(summary, { dryRun: opts.dryRun === true })).join('\n'),
|
|
22
|
+
exitCode: result.exitCode ?? 0,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (result.exitCode)
|
|
26
|
+
return { exitCode: result.exitCode };
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
function keyByPackageName(packages) {
|
|
30
|
+
const keyed = {};
|
|
31
|
+
for (const pkg of packages) {
|
|
32
|
+
const key = pkg.name ?? ('id' in pkg ? pkg.id : undefined);
|
|
33
|
+
if (key)
|
|
34
|
+
keyed[key] = pkg;
|
|
35
|
+
}
|
|
36
|
+
return keyed;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { globalWarn } from '@pnpm/logger';
|
|
2
|
+
import { createStageContext } from './context.js';
|
|
3
|
+
import { requireStageId } from './parsing.js';
|
|
4
|
+
import { stageRequestWithOtp } from './request.js';
|
|
5
|
+
export async function stageReject(opts, params) {
|
|
6
|
+
const stageId = requireStageId(params, 'reject');
|
|
7
|
+
const context = createStageContext(opts);
|
|
8
|
+
globalWarn('Rejecting will permanently delete this staged publish record and tarball from the registry.');
|
|
9
|
+
await stageRequestWithOtp(context, {
|
|
10
|
+
url: new URL(`-/stage/${stageId}`, context.registry).href,
|
|
11
|
+
init: { method: 'DELETE' },
|
|
12
|
+
action: `reject staged package ${stageId}`,
|
|
13
|
+
});
|
|
14
|
+
return `Staged package ${stageId} has been rejected.`;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=reject.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PublishSummary } from '../tarball/publishSummary.js';
|
|
2
|
+
import type { StageItem } from './types.js';
|
|
3
|
+
export declare function renderStageItem(item: StageItem): string;
|
|
4
|
+
export declare function renderTarballSummary(summary: PublishSummary): string;
|
|
5
|
+
export declare function renderStagePublishSummary(summary: PublishSummary | {
|
|
6
|
+
name?: string;
|
|
7
|
+
version?: string;
|
|
8
|
+
}, opts: {
|
|
9
|
+
dryRun: boolean;
|
|
10
|
+
}): string;
|
|
11
|
+
export declare function normalizePackageName(name: string): string;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export function renderStageItem(item) {
|
|
2
|
+
const { id, packageName, version, tag, createdAt, actor, actorType, shasum, ...rest } = item;
|
|
3
|
+
return renderKeyValues({
|
|
4
|
+
id,
|
|
5
|
+
'package name': packageName,
|
|
6
|
+
version,
|
|
7
|
+
tag,
|
|
8
|
+
'date staged': createdAt,
|
|
9
|
+
'staged by': actorType ? `${actor ?? ''} (${actorType})` : actor,
|
|
10
|
+
shasum,
|
|
11
|
+
...rest,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export function renderTarballSummary(summary) {
|
|
15
|
+
return `package: ${summary.name}@${summary.version}
|
|
16
|
+
Tarball Contents
|
|
17
|
+
${summary.files.map(({ path }) => path).join('\n')}
|
|
18
|
+
Tarball Details
|
|
19
|
+
name: ${summary.name}
|
|
20
|
+
version: ${summary.version}
|
|
21
|
+
filename: ${summary.filename}
|
|
22
|
+
package size: ${summary.size}
|
|
23
|
+
unpacked size: ${summary.unpackedSize}
|
|
24
|
+
shasum: ${summary.shasum}
|
|
25
|
+
integrity: ${summary.integrity}
|
|
26
|
+
total files: ${summary.entryCount}`;
|
|
27
|
+
}
|
|
28
|
+
export function renderStagePublishSummary(summary, opts) {
|
|
29
|
+
const id = 'id' in summary && summary.id
|
|
30
|
+
? summary.id
|
|
31
|
+
: summary.name && summary.version
|
|
32
|
+
? `${summary.name}@${summary.version}`
|
|
33
|
+
: summary.name ?? '<unknown package>';
|
|
34
|
+
if (opts.dryRun)
|
|
35
|
+
return `+ ${id} (would stage)`;
|
|
36
|
+
if ('stageId' in summary && summary.stageId) {
|
|
37
|
+
return `+ ${id} (staged with id ${summary.stageId})`;
|
|
38
|
+
}
|
|
39
|
+
return `+ ${id} (staged)`;
|
|
40
|
+
}
|
|
41
|
+
export function normalizePackageName(name) {
|
|
42
|
+
return name.replace('@', '').replace('/', '-');
|
|
43
|
+
}
|
|
44
|
+
function renderKeyValues(values) {
|
|
45
|
+
return Object.entries(values)
|
|
46
|
+
.flatMap(([key, value]) => value == null ? [] : [`${key}: ${renderValue(value)}`])
|
|
47
|
+
.join('\n');
|
|
48
|
+
}
|
|
49
|
+
function renderValue(value) {
|
|
50
|
+
return typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=rendering.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { StageContext } from './context.js';
|
|
2
|
+
export interface StageRequestInit {
|
|
3
|
+
body?: string;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
method: 'DELETE' | 'GET' | 'POST';
|
|
6
|
+
}
|
|
7
|
+
interface StageRequestParams {
|
|
8
|
+
url: string;
|
|
9
|
+
action: string;
|
|
10
|
+
init?: StageRequestInit;
|
|
11
|
+
otp?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function stageJsonRequest<T>(context: StageContext, params: {
|
|
14
|
+
url: string;
|
|
15
|
+
action: string;
|
|
16
|
+
}): Promise<T>;
|
|
17
|
+
/**
|
|
18
|
+
* Wraps {@link stageRequest} with OTP / web-auth handling. The first attempt
|
|
19
|
+
* carries any user-configured `--otp`; if the registry responds with an OTP
|
|
20
|
+
* challenge, `withOtpHandling` drives the browser-based authentication flow
|
|
21
|
+
* and retries the operation with the resulting token.
|
|
22
|
+
*/
|
|
23
|
+
export declare function stageRequestWithOtp(context: StageContext, params: {
|
|
24
|
+
url: string;
|
|
25
|
+
init: StageRequestInit;
|
|
26
|
+
action: string;
|
|
27
|
+
}): Promise<Response>;
|
|
28
|
+
export declare function stageRequest(context: StageContext, params: StageRequestParams): Promise<Response>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { globalWarn } from '@pnpm/logger';
|
|
2
|
+
import { SyntheticOtpError, withOtpHandling } from '@pnpm/network.web-auth';
|
|
3
|
+
import { createPublishContext } from '../publish/publishPackedPkg.js';
|
|
4
|
+
import { StageRegistryError } from './errors.js';
|
|
5
|
+
export async function stageJsonRequest(context, params) {
|
|
6
|
+
const response = await stageRequest(context, {
|
|
7
|
+
url: params.url,
|
|
8
|
+
action: params.action,
|
|
9
|
+
init: { method: 'GET' },
|
|
10
|
+
});
|
|
11
|
+
return await response.json();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Wraps {@link stageRequest} with OTP / web-auth handling. The first attempt
|
|
15
|
+
* carries any user-configured `--otp`; if the registry responds with an OTP
|
|
16
|
+
* challenge, `withOtpHandling` drives the browser-based authentication flow
|
|
17
|
+
* and retries the operation with the resulting token.
|
|
18
|
+
*/
|
|
19
|
+
export async function stageRequestWithOtp(context, params) {
|
|
20
|
+
return withOtpHandling({
|
|
21
|
+
context: createPublishContext(context.opts),
|
|
22
|
+
fetchOptions: createWebAuthFetchOptions(context.opts),
|
|
23
|
+
operation: async (otp) => stageRequest(context, {
|
|
24
|
+
url: params.url,
|
|
25
|
+
action: params.action,
|
|
26
|
+
init: params.init,
|
|
27
|
+
otp: otp ?? getConfiguredOtp(context.opts),
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export async function stageRequest(context, params) {
|
|
32
|
+
const init = params.init ?? { method: 'GET' };
|
|
33
|
+
const response = await context.fetchFromRegistry(params.url, {
|
|
34
|
+
authHeaderValue: context.authHeaderValue,
|
|
35
|
+
body: init.body,
|
|
36
|
+
fullMetadata: true,
|
|
37
|
+
headers: {
|
|
38
|
+
'npm-auth-type': 'web',
|
|
39
|
+
'npm-command': 'stage',
|
|
40
|
+
...init.headers,
|
|
41
|
+
...(params.otp != null ? { 'npm-otp': params.otp } : {}),
|
|
42
|
+
},
|
|
43
|
+
method: init.method,
|
|
44
|
+
timeout: context.opts.fetchTimeout,
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
await throwOnErrorResponse(response, params.action);
|
|
48
|
+
}
|
|
49
|
+
return response;
|
|
50
|
+
}
|
|
51
|
+
async function throwOnErrorResponse(response, action) {
|
|
52
|
+
let text = '';
|
|
53
|
+
try {
|
|
54
|
+
text = await response.text();
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = text ? JSON.parse(text) : undefined;
|
|
60
|
+
}
|
|
61
|
+
catch { }
|
|
62
|
+
if (response.status === 401 && isOtpChallenge(response, parsed)) {
|
|
63
|
+
throw SyntheticOtpError.fromUnknownBody(globalWarn, parsed);
|
|
64
|
+
}
|
|
65
|
+
throw new StageRegistryError({
|
|
66
|
+
action,
|
|
67
|
+
status: response.status,
|
|
68
|
+
statusText: response.statusText,
|
|
69
|
+
text,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Identify a 401 response as an OTP / web-auth challenge.
|
|
74
|
+
*
|
|
75
|
+
* Two signals are accepted because the npm registry uses one or both in
|
|
76
|
+
* practice: the legacy `www-authenticate: otp` header for classic TOTP,
|
|
77
|
+
* and a JSON body containing `authUrl` + `doneUrl` for the browser-based
|
|
78
|
+
* web-auth flow.
|
|
79
|
+
*/
|
|
80
|
+
function isOtpChallenge(response, body) {
|
|
81
|
+
if (hasWebAuthUrls(body))
|
|
82
|
+
return true;
|
|
83
|
+
const wwwAuthenticate = response.headers.get('www-authenticate')?.toLowerCase();
|
|
84
|
+
return wwwAuthenticate?.includes('otp') === true;
|
|
85
|
+
}
|
|
86
|
+
function hasWebAuthUrls(body) {
|
|
87
|
+
if (body == null || typeof body !== 'object')
|
|
88
|
+
return false;
|
|
89
|
+
const record = body;
|
|
90
|
+
return typeof record.authUrl === 'string' && typeof record.doneUrl === 'string';
|
|
91
|
+
}
|
|
92
|
+
function getConfiguredOtp(opts) {
|
|
93
|
+
if (typeof opts.otp === 'string')
|
|
94
|
+
return opts.otp;
|
|
95
|
+
const cliOtp = opts.cliOptions?.otp;
|
|
96
|
+
return typeof cliOtp === 'string' ? cliOtp : undefined;
|
|
97
|
+
}
|
|
98
|
+
function createWebAuthFetchOptions(opts) {
|
|
99
|
+
return {
|
|
100
|
+
method: 'GET',
|
|
101
|
+
retry: {
|
|
102
|
+
factor: opts.fetchRetryFactor,
|
|
103
|
+
maxTimeout: opts.fetchRetryMaxtimeout,
|
|
104
|
+
minTimeout: opts.fetchRetryMintimeout,
|
|
105
|
+
retries: opts.fetchRetries,
|
|
106
|
+
},
|
|
107
|
+
timeout: opts.fetchTimeout,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as publishCommand from '../publish/publish.js';
|
|
2
|
+
export declare const STAGE_SUBCOMMANDS: readonly ['publish', 'list', 'view', 'approve', 'reject', 'download'];
|
|
3
|
+
export type StageSubcommand = (typeof STAGE_SUBCOMMANDS)[number];
|
|
4
|
+
/**
|
|
5
|
+
* Options accepted by every `pnpm stage` subcommand.
|
|
6
|
+
*
|
|
7
|
+
* `pnpm stage publish` forwards to {@link publishCommand.publish}, so we
|
|
8
|
+
* intentionally inherit that command's option contract. The remaining
|
|
9
|
+
* subcommands need only a subset (registry/auth/fetch/retry settings),
|
|
10
|
+
* but accepting the full set keeps a single type across the dispatcher.
|
|
11
|
+
*/
|
|
12
|
+
export type StageOptions = Parameters<typeof publishCommand.publish>[0] & {
|
|
13
|
+
cliOptions?: Record<string, unknown>;
|
|
14
|
+
json?: boolean;
|
|
15
|
+
otp?: string;
|
|
16
|
+
registry?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Single staged package version as returned by the registry's `-/stage` and
|
|
20
|
+
* `-/stage/<id>` endpoints. Every field is optional because the registry's
|
|
21
|
+
* exact schema is not pinned, and the index signature keeps future fields
|
|
22
|
+
* available to display without a code change.
|
|
23
|
+
*/
|
|
24
|
+
export interface StageItem {
|
|
25
|
+
id?: string;
|
|
26
|
+
packageName?: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
tag?: string;
|
|
29
|
+
createdAt?: string;
|
|
30
|
+
actor?: string;
|
|
31
|
+
actorType?: string;
|
|
32
|
+
shasum?: string;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
export interface StageListResponse {
|
|
36
|
+
items: StageItem[];
|
|
37
|
+
total: number;
|
|
38
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createStageContext } from './context.js';
|
|
2
|
+
import { requireStageId } from './parsing.js';
|
|
3
|
+
import { renderStageItem } from './rendering.js';
|
|
4
|
+
import { stageJsonRequest } from './request.js';
|
|
5
|
+
export async function stageView(opts, params) {
|
|
6
|
+
const stageId = requireStageId(params, 'view');
|
|
7
|
+
const context = createStageContext(opts);
|
|
8
|
+
const item = await stageJsonRequest(context, {
|
|
9
|
+
url: new URL(`-/stage/${stageId}`, context.registry).href,
|
|
10
|
+
action: `view staged package ${stageId}`,
|
|
11
|
+
});
|
|
12
|
+
return opts.json ? JSON.stringify(item, null, 2) : renderStageItem(item);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-package summary describing a successful publish, modeled after `npm publish --json`.
|
|
3
|
+
* Returned to callers and serialized to stdout when `pnpm publish --json` is used.
|
|
4
|
+
*/
|
|
5
|
+
export interface PublishSummary {
|
|
6
|
+
/** Human-readable identifier `${name}@${version}`. */
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
/** Compressed tarball size in bytes. */
|
|
11
|
+
size: number;
|
|
12
|
+
/** Total uncompressed size of all files in the tarball, in bytes. */
|
|
13
|
+
unpackedSize: number;
|
|
14
|
+
/** Lowercase hex SHA-1 digest of the tarball. */
|
|
15
|
+
shasum: string;
|
|
16
|
+
/** SRI-formatted SHA-512 digest of the tarball (e.g. `sha512-...`). */
|
|
17
|
+
integrity: string;
|
|
18
|
+
/** Tarball file basename (e.g. `pkg-1.0.0.tgz`). */
|
|
19
|
+
filename: string;
|
|
20
|
+
/** Files inside the tarball, in the same shape `pnpm pack --json` emits. */
|
|
21
|
+
files: Array<{
|
|
22
|
+
path: string;
|
|
23
|
+
}>;
|
|
24
|
+
/** Number of files inside the tarball. */
|
|
25
|
+
entryCount: number;
|
|
26
|
+
/** Names of bundled dependencies included in the tarball (typically empty). */
|
|
27
|
+
bundled: string[];
|
|
28
|
+
/** Staged publish identifier returned by the registry. Only present for staged publishes. */
|
|
29
|
+
stageId?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Normalize the two equivalent manifest keys (`bundledDependencies` and `bundleDependencies`)
|
|
33
|
+
* into a flat list of dependency names, matching npm's interpretation.
|
|
34
|
+
*/
|
|
35
|
+
export declare function extractBundledDependencies(manifest: {
|
|
36
|
+
bundledDependencies?: unknown;
|
|
37
|
+
bundleDependencies?: unknown;
|
|
38
|
+
dependencies?: Record<string, unknown>;
|
|
39
|
+
}): string[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize the two equivalent manifest keys (`bundledDependencies` and `bundleDependencies`)
|
|
3
|
+
* into a flat list of dependency names, matching npm's interpretation.
|
|
4
|
+
*/
|
|
5
|
+
export function extractBundledDependencies(manifest) {
|
|
6
|
+
const raw = manifest.bundledDependencies ?? manifest.bundleDependencies;
|
|
7
|
+
if (!raw)
|
|
8
|
+
return [];
|
|
9
|
+
if (Array.isArray(raw))
|
|
10
|
+
return raw.filter((name) => typeof name === 'string');
|
|
11
|
+
// `true` means "bundle every dependency" per npm's semantics; expand it to the dependency names.
|
|
12
|
+
if (raw === true)
|
|
13
|
+
return Object.keys(manifest.dependencies ?? {});
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=publishSummary.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type PublishSummary } from './publishSummary.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a packed (gzipped or plain) tarball buffer and return the same
|
|
4
|
+
* {@link PublishSummary} shape that `pnpm publish --json` emits.
|
|
5
|
+
*
|
|
6
|
+
* Used when we hold the tarball bytes already and need a summary without
|
|
7
|
+
* re-packing — e.g. inspecting a staged publish via `pnpm stage download`.
|
|
8
|
+
*
|
|
9
|
+
* @throws {@link PnpmError} with code `STAGE_TARBALL_MANIFEST_NOT_FOUND` when the tarball
|
|
10
|
+
* does not contain `package/package.json`, or when that file is unparseable JSON.
|
|
11
|
+
*/
|
|
12
|
+
export declare function summarizeTarball(tarballData: Buffer): Promise<PublishSummary>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { gunzipSync } from 'node:zlib';
|
|
3
|
+
import { PnpmError } from '@pnpm/error';
|
|
4
|
+
import tar from 'tar-stream';
|
|
5
|
+
import { extractBundledDependencies } from './publishSummary.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parse a packed (gzipped or plain) tarball buffer and return the same
|
|
8
|
+
* {@link PublishSummary} shape that `pnpm publish --json` emits.
|
|
9
|
+
*
|
|
10
|
+
* Used when we hold the tarball bytes already and need a summary without
|
|
11
|
+
* re-packing — e.g. inspecting a staged publish via `pnpm stage download`.
|
|
12
|
+
*
|
|
13
|
+
* @throws {@link PnpmError} with code `STAGE_TARBALL_MANIFEST_NOT_FOUND` when the tarball
|
|
14
|
+
* does not contain `package/package.json`, or when that file is unparseable JSON.
|
|
15
|
+
*/
|
|
16
|
+
export async function summarizeTarball(tarballData) {
|
|
17
|
+
const extract = tar.extract();
|
|
18
|
+
const files = [];
|
|
19
|
+
const bundled = new Set();
|
|
20
|
+
let manifest;
|
|
21
|
+
let entryCount = 0;
|
|
22
|
+
let unpackedSize = 0;
|
|
23
|
+
await new Promise((resolve, reject) => {
|
|
24
|
+
extract.on('entry', (header, stream, next) => {
|
|
25
|
+
const chunks = [];
|
|
26
|
+
if (header.type === 'file') {
|
|
27
|
+
entryCount++;
|
|
28
|
+
unpackedSize += header.size ?? 0;
|
|
29
|
+
files.push({ path: header.name.replace(/^package\//, '') });
|
|
30
|
+
const bundledMatch = /^package\/node_modules\/((?:@[^/]+\/)?[^/]+)/.exec(header.name);
|
|
31
|
+
if (bundledMatch?.[1]) {
|
|
32
|
+
bundled.add(bundledMatch[1]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (header.name === 'package/package.json') {
|
|
36
|
+
stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
|
|
37
|
+
}
|
|
38
|
+
stream.on('error', reject);
|
|
39
|
+
stream.on('end', () => {
|
|
40
|
+
if (header.name === 'package/package.json') {
|
|
41
|
+
try {
|
|
42
|
+
manifest = JSON.parse(Buffer.concat(chunks).toString());
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
reject(error);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
next();
|
|
50
|
+
});
|
|
51
|
+
stream.resume();
|
|
52
|
+
});
|
|
53
|
+
extract.on('error', reject);
|
|
54
|
+
extract.on('finish', resolve);
|
|
55
|
+
extract.end(maybeGunzip(tarballData));
|
|
56
|
+
});
|
|
57
|
+
if (!manifest?.name || !manifest.version) {
|
|
58
|
+
throw new PnpmError('STAGE_TARBALL_MANIFEST_NOT_FOUND', 'Could not read package.json from tarball');
|
|
59
|
+
}
|
|
60
|
+
files.sort((a, b) => a.path.localeCompare(b.path, 'en'));
|
|
61
|
+
return {
|
|
62
|
+
id: manifest._id ?? `${manifest.name}@${manifest.version}`,
|
|
63
|
+
name: manifest.name,
|
|
64
|
+
version: manifest.version,
|
|
65
|
+
size: tarballData.byteLength,
|
|
66
|
+
unpackedSize,
|
|
67
|
+
shasum: createHash('sha1').update(tarballData).digest('hex'),
|
|
68
|
+
integrity: `sha512-${createHash('sha512').update(tarballData).digest('base64')}`,
|
|
69
|
+
filename: `${normalizePackageName(manifest.name)}-${manifest.version}.tgz`,
|
|
70
|
+
files,
|
|
71
|
+
entryCount,
|
|
72
|
+
bundled: bundled.size > 0 ? Array.from(bundled).sort() : extractBundledDependencies(manifest),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function maybeGunzip(tarballData) {
|
|
76
|
+
try {
|
|
77
|
+
return gunzipSync(tarballData);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return tarballData;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function normalizePackageName(name) {
|
|
84
|
+
return name.replace('@', '').replace('/', '-');
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=summarizeTarball.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/releasing.commands",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.3.1",
|
|
4
4
|
"description": "Commands for deploy, pack, and publish",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -27,58 +27,59 @@
|
|
|
27
27
|
"@pnpm/npm-package-arg": "^2.0.0",
|
|
28
28
|
"@types/normalize-path": "^3.0.2",
|
|
29
29
|
"@zkochan/rimraf": "^4.0.0",
|
|
30
|
-
"chalk": "^5.6.
|
|
31
|
-
"ci-info": "^4.
|
|
32
|
-
"detect-libc": "^2.
|
|
30
|
+
"chalk": "^5.6.2",
|
|
31
|
+
"ci-info": "^4.4.0",
|
|
32
|
+
"detect-libc": "^2.1.2",
|
|
33
33
|
"enquirer": "^2.4.1",
|
|
34
34
|
"execa": "npm:safe-execa@0.3.0",
|
|
35
|
-
"libnpmpublish": "^11.
|
|
35
|
+
"libnpmpublish": "^11.2.0",
|
|
36
36
|
"normalize-path": "^3.0.0",
|
|
37
37
|
"normalize-registry-url": "2.0.1",
|
|
38
38
|
"p-filter": "^4.1.0",
|
|
39
|
-
"p-limit": "^7.
|
|
39
|
+
"p-limit": "^7.3.0",
|
|
40
40
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
41
41
|
"realpath-missing": "^2.0.0",
|
|
42
42
|
"render-help": "^2.0.0",
|
|
43
|
-
"semver": "^7.
|
|
44
|
-
"tar-stream": "^3.
|
|
43
|
+
"semver": "^7.8.1",
|
|
44
|
+
"tar-stream": "^3.2.0",
|
|
45
45
|
"tempy": "3.0.0",
|
|
46
|
-
"tinyglobby": "^0.2.
|
|
46
|
+
"tinyglobby": "^0.2.16",
|
|
47
47
|
"validate-npm-package-name": "7.0.2",
|
|
48
48
|
"write-json-file": "^7.0.0",
|
|
49
49
|
"write-yaml-file": "^6.0.0",
|
|
50
50
|
"@pnpm/catalogs.types": "1100.0.0",
|
|
51
|
-
"@pnpm/
|
|
52
|
-
"@pnpm/config.pick-registry-for-package": "1100.0.5",
|
|
53
|
-
"@pnpm/cli.utils": "1101.0.6",
|
|
51
|
+
"@pnpm/cli.utils": "1101.0.8",
|
|
54
52
|
"@pnpm/cli.common-cli-options-help": "1100.0.1",
|
|
55
|
-
"@pnpm/config.reader": "1101.
|
|
56
|
-
"@pnpm/
|
|
53
|
+
"@pnpm/config.reader": "1101.4.1",
|
|
54
|
+
"@pnpm/config.pick-registry-for-package": "1100.0.6",
|
|
55
|
+
"@pnpm/deps.path": "1100.0.5",
|
|
57
56
|
"@pnpm/constants": "1100.0.0",
|
|
58
|
-
"@pnpm/engine.runtime.commands": "1100.0.16",
|
|
59
57
|
"@pnpm/error": "1100.0.0",
|
|
60
|
-
"@pnpm/exec.lifecycle": "1100.0.
|
|
61
|
-
"@pnpm/engine.runtime.node-resolver": "1101.1.0",
|
|
58
|
+
"@pnpm/exec.lifecycle": "1100.0.14",
|
|
62
59
|
"@pnpm/exec.pnpm-cli-runner": "1100.0.1",
|
|
63
|
-
"@pnpm/
|
|
64
|
-
"@pnpm/
|
|
65
|
-
"@pnpm/
|
|
66
|
-
"@pnpm/
|
|
60
|
+
"@pnpm/engine.runtime.commands": "1100.1.0",
|
|
61
|
+
"@pnpm/bins.resolver": "1100.0.5",
|
|
62
|
+
"@pnpm/fs.indexed-pkg-importer": "1100.0.10",
|
|
63
|
+
"@pnpm/fetching.directory-fetcher": "1100.0.13",
|
|
64
|
+
"@pnpm/installing.client": "1100.2.3",
|
|
65
|
+
"@pnpm/engine.runtime.node-resolver": "1101.1.2",
|
|
67
66
|
"@pnpm/fs.packlist": "1100.0.1",
|
|
68
|
-
"@pnpm/
|
|
67
|
+
"@pnpm/fs.is-empty-dir-or-nothing": "1100.0.0",
|
|
68
|
+
"@pnpm/installing.commands": "1100.6.0",
|
|
69
|
+
"@pnpm/lockfile.types": "1100.0.8",
|
|
70
|
+
"@pnpm/lockfile.fs": "1100.1.2",
|
|
71
|
+
"@pnpm/network.fetch": "1100.0.7",
|
|
69
72
|
"@pnpm/network.git-utils": "1100.0.1",
|
|
70
|
-
"@pnpm/lockfile.types": "1100.0.7",
|
|
71
|
-
"@pnpm/network.fetch": "1100.0.6",
|
|
72
|
-
"@pnpm/types": "1101.1.1",
|
|
73
|
-
"@pnpm/workspace.projects-filter": "1100.0.14",
|
|
74
|
-
"@pnpm/releasing.exportable-manifest": "1100.0.7",
|
|
75
|
-
"@pnpm/resolving.resolver-base": "1100.3.0",
|
|
76
|
-
"@pnpm/workspace.projects-sorter": "1100.0.3",
|
|
77
73
|
"@pnpm/network.web-auth": "1101.0.0",
|
|
78
|
-
"@pnpm/
|
|
74
|
+
"@pnpm/releasing.exportable-manifest": "1100.1.1",
|
|
75
|
+
"@pnpm/network.auth-header": "1101.0.0",
|
|
76
|
+
"@pnpm/resolving.resolver-base": "1100.3.1",
|
|
77
|
+
"@pnpm/types": "1101.2.0",
|
|
78
|
+
"@pnpm/workspace.projects-filter": "1100.0.16",
|
|
79
|
+
"@pnpm/workspace.projects-sorter": "1100.0.4"
|
|
79
80
|
},
|
|
80
81
|
"peerDependencies": {
|
|
81
|
-
"@pnpm/logger": "
|
|
82
|
+
"@pnpm/logger": "^1001.0.1"
|
|
82
83
|
},
|
|
83
84
|
"devDependencies": {
|
|
84
85
|
"@jest/globals": "30.3.0",
|
|
@@ -92,21 +93,21 @@
|
|
|
92
93
|
"@types/tar": "^7.0.87",
|
|
93
94
|
"@types/tar-stream": "^3.1.4",
|
|
94
95
|
"@types/validate-npm-package-name": "^4.0.2",
|
|
95
|
-
"ci-info": "^4.
|
|
96
|
+
"ci-info": "^4.4.0",
|
|
96
97
|
"cross-spawn": "^7.0.6",
|
|
97
98
|
"is-windows": "^1.0.2",
|
|
98
99
|
"load-json-file": "^7.0.1",
|
|
99
|
-
"tar": "^7.5.
|
|
100
|
-
"undici": "^7.
|
|
100
|
+
"tar": "^7.5.15",
|
|
101
|
+
"undici": "^7.26.0",
|
|
101
102
|
"write-yaml-file": "^6.0.0",
|
|
102
|
-
"@pnpm/
|
|
103
|
-
"@pnpm/
|
|
104
|
-
"@pnpm/prepare": "1100.0.10",
|
|
103
|
+
"@pnpm/assert-project": "1100.0.11",
|
|
104
|
+
"@pnpm/hooks.pnpmfile": "1100.0.11",
|
|
105
105
|
"@pnpm/logger": "1100.0.0",
|
|
106
|
+
"@pnpm/releasing.commands": "1100.3.1",
|
|
106
107
|
"@pnpm/test-fixtures": "1100.0.0",
|
|
107
|
-
"@pnpm/releasing.commands": "1100.2.18",
|
|
108
|
-
"@pnpm/test-ipc-server": "1100.0.0",
|
|
109
108
|
"@pnpm/catalogs.config": "1100.0.0",
|
|
109
|
+
"@pnpm/prepare": "1100.0.11",
|
|
110
|
+
"@pnpm/test-ipc-server": "1100.0.0",
|
|
110
111
|
"@pnpm/testing.command-defaults": "1100.0.1"
|
|
111
112
|
},
|
|
112
113
|
"engines": {
|