@pnpm/releasing.commands 1100.7.0 → 1100.8.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.
Files changed (97) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/lib/change/index.d.ts +42 -0
  3. package/lib/change/index.js +250 -0
  4. package/lib/deploy/createDeployFiles.d.ts +26 -0
  5. package/lib/deploy/createDeployFiles.js +255 -0
  6. package/lib/deploy/deploy.d.ts +12 -0
  7. package/lib/deploy/deploy.js +398 -0
  8. package/lib/deploy/deployHook.d.ts +2 -0
  9. package/lib/deploy/deployHook.js +15 -0
  10. package/lib/deploy/index.d.ts +2 -0
  11. package/lib/deploy/index.js +3 -0
  12. package/lib/index.d.ts +7 -0
  13. package/lib/lane/index.d.ts +24 -0
  14. package/lib/lane/index.js +157 -0
  15. package/lib/pack-app/index.d.ts +2 -0
  16. package/lib/pack-app/index.js +3 -0
  17. package/lib/pack-app/packApp.d.ts +22 -0
  18. package/lib/pack-app/packApp.js +558 -0
  19. package/lib/publish/FailedToPublishError.d.ts +22 -0
  20. package/lib/publish/FailedToPublishError.js +40 -0
  21. package/lib/publish/batchPublish.d.ts +20 -0
  22. package/lib/publish/batchPublish.js +201 -0
  23. package/lib/publish/displayError.d.ts +1 -0
  24. package/lib/publish/displayError.js +23 -0
  25. package/lib/publish/executeTokenHelper.d.ts +4 -0
  26. package/lib/publish/executeTokenHelper.js +17 -0
  27. package/lib/publish/extractManifestFromPacked.d.ts +19 -0
  28. package/lib/publish/extractManifestFromPacked.js +110 -0
  29. package/lib/publish/index.d.ts +3 -0
  30. package/lib/publish/index.js +4 -0
  31. package/lib/publish/oidc/authToken.d.ts +73 -0
  32. package/lib/publish/oidc/authToken.js +97 -0
  33. package/lib/publish/oidc/idToken.d.ts +76 -0
  34. package/lib/publish/oidc/idToken.js +90 -0
  35. package/lib/publish/oidc/provenance.d.ts +73 -0
  36. package/lib/publish/oidc/provenance.js +91 -0
  37. package/lib/publish/otp.d.ts +38 -0
  38. package/lib/publish/otp.js +41 -0
  39. package/lib/publish/otpEnv.d.ts +7 -0
  40. package/lib/publish/otpEnv.js +5 -0
  41. package/lib/publish/pack.d.ts +34 -0
  42. package/lib/publish/pack.js +425 -0
  43. package/lib/publish/previousChangelog.d.ts +25 -0
  44. package/lib/publish/previousChangelog.js +194 -0
  45. package/lib/publish/publish.d.ts +40 -0
  46. package/lib/publish/publish.js +256 -0
  47. package/lib/publish/publishPackedPkg.d.ts +79 -0
  48. package/lib/publish/publishPackedPkg.js +298 -0
  49. package/lib/publish/recursivePublish.d.ts +18 -0
  50. package/lib/publish/recursivePublish.js +135 -0
  51. package/lib/publish/registryConfigKeys.d.ts +30 -0
  52. package/lib/publish/registryConfigKeys.js +50 -0
  53. package/lib/publish/utils/shared-context.d.ts +7 -0
  54. package/lib/publish/utils/shared-context.js +20 -0
  55. package/lib/publishedNames.d.ts +18 -0
  56. package/lib/publishedNames.js +29 -0
  57. package/lib/resolveUnpublishedDirs.d.ts +18 -0
  58. package/lib/resolveUnpublishedDirs.js +20 -0
  59. package/lib/stage/approve.d.ts +2 -0
  60. package/lib/stage/approve.js +14 -0
  61. package/lib/stage/context.d.ts +14 -0
  62. package/lib/stage/context.js +25 -0
  63. package/lib/stage/download.d.ts +2 -0
  64. package/lib/stage/download.js +32 -0
  65. package/lib/stage/errors.d.ts +15 -0
  66. package/lib/stage/errors.js +17 -0
  67. package/lib/stage/help.d.ts +1 -0
  68. package/lib/stage/help.js +84 -0
  69. package/lib/stage/index.d.ts +13 -0
  70. package/lib/stage/index.js +57 -0
  71. package/lib/stage/list.d.ts +2 -0
  72. package/lib/stage/list.js +49 -0
  73. package/lib/stage/parsing.d.ts +6 -0
  74. package/lib/stage/parsing.js +27 -0
  75. package/lib/stage/publish.d.ts +7 -0
  76. package/lib/stage/publish.js +38 -0
  77. package/lib/stage/reject.d.ts +2 -0
  78. package/lib/stage/reject.js +16 -0
  79. package/lib/stage/rendering.d.ts +11 -0
  80. package/lib/stage/rendering.js +50 -0
  81. package/lib/stage/request.d.ts +29 -0
  82. package/lib/stage/request.js +110 -0
  83. package/lib/stage/types.d.ts +38 -0
  84. package/lib/stage/types.js +3 -0
  85. package/lib/stage/view.d.ts +2 -0
  86. package/lib/stage/view.js +14 -0
  87. package/lib/tarball/index.d.ts +2 -0
  88. package/lib/tarball/index.js +3 -0
  89. package/lib/tarball/publishSummary.d.ts +47 -0
  90. package/lib/tarball/publishSummary.js +36 -0
  91. package/lib/tarball/safeTarballFilename.d.ts +8 -0
  92. package/lib/tarball/safeTarballFilename.js +21 -0
  93. package/lib/tarball/summarizeTarball.d.ts +12 -0
  94. package/lib/tarball/summarizeTarball.js +84 -0
  95. package/lib/version/index.d.ts +35 -0
  96. package/lib/version/index.js +364 -0
  97. package/package.json +49 -49
@@ -0,0 +1,18 @@
1
+ import type { Config, ConfigContext } from '@pnpm/config.reader';
2
+ import type { PublishPackedPkgOptions, PublishSummary } from './publishPackedPkg.js';
3
+ export type PublishRecursiveOpts = Required<Pick<Config, 'bin' | 'cacheDir' | 'dir' | 'pnpmHomeDir' | 'configByUri' | 'registries' | 'workspaceDir'>> & Required<Pick<ConfigContext, 'cliOptions'>> & Partial<Pick<Config, 'tag' | 'ca' | 'catalogs' | 'cert' | 'fetchTimeout' | 'force' | 'dryRun' | 'extraBinPaths' | 'extraEnv' | 'fetchRetries' | 'fetchRetryFactor' | 'fetchRetryMaxtimeout' | 'fetchRetryMintimeout' | 'key' | 'httpProxy' | 'httpsProxy' | 'localAddress' | 'lockfileDir' | 'noProxy' | 'npmPath' | 'offline' | 'strictSsl' | 'unsafePerm' | 'userAgent' | 'verifyStoreIntegrity' | 'versioning'>> & Partial<Pick<ConfigContext, 'selectedProjectsGraph' | 'allProjectsGraph' | 'prodAllProjectsGraph' | 'prodOnlySelectedProjectDirs'>> & {
4
+ access?: 'public' | 'restricted';
5
+ argv: {
6
+ original: string[];
7
+ };
8
+ batch?: boolean;
9
+ reportSummary?: boolean;
10
+ } & PublishPackedPkgOptions;
11
+ export type RecursivePublishedPackage = PublishSummary | {
12
+ name?: string;
13
+ version?: string;
14
+ };
15
+ export declare function recursivePublish(opts: PublishRecursiveOpts & Required<Pick<ConfigContext, 'selectedProjectsGraph'>>): Promise<{
16
+ exitCode: number;
17
+ publishedPackages: RecursivePublishedPackage[];
18
+ }>;
@@ -0,0 +1,135 @@
1
+ import path from 'node:path';
2
+ import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
3
+ import { createResolver } from '@pnpm/installing.client';
4
+ import { logger } from '@pnpm/logger';
5
+ import { sortFilteredProjects } from '@pnpm/workspace.projects-sorter';
6
+ import pFilter from 'p-filter';
7
+ import { pick } from 'ramda';
8
+ import { writeJsonFile } from 'write-json-file';
9
+ import { publishedName } from '../publishedNames.js';
10
+ import { batchPublishPackages } from './batchPublish.js';
11
+ import { publish } from './publish.js';
12
+ export async function recursivePublish(opts) {
13
+ const pkgs = Object.values(opts.selectedProjectsGraph).map((wsPkg) => wsPkg.package);
14
+ const { resolve } = createResolver({
15
+ ...opts,
16
+ configByUri: opts.configByUri,
17
+ retry: {
18
+ factor: opts.fetchRetryFactor,
19
+ maxTimeout: opts.fetchRetryMaxtimeout,
20
+ minTimeout: opts.fetchRetryMintimeout,
21
+ retries: opts.fetchRetries,
22
+ },
23
+ timeout: opts.fetchTimeout,
24
+ });
25
+ const pkgsToPublish = await pFilter(pkgs, async (pkg) => {
26
+ if (!pkg.manifest.name || !pkg.manifest.version || pkg.manifest.private)
27
+ return false;
28
+ if (opts.force)
29
+ return true;
30
+ return !(await isAlreadyPublished({
31
+ dir: pkg.rootDir,
32
+ lockfileDir: opts.lockfileDir ?? pkg.rootDir,
33
+ registries: opts.registries,
34
+ resolve,
35
+ }, publishedName(pkg.manifest), pkg.manifest.version));
36
+ });
37
+ const publishedPkgDirs = new Set(pkgsToPublish.map(({ rootDir }) => rootDir));
38
+ const publishedPackages = [];
39
+ if (publishedPkgDirs.size === 0) {
40
+ logger.info({
41
+ message: 'There are no new packages that should be published',
42
+ prefix: opts.dir,
43
+ });
44
+ }
45
+ else {
46
+ const appendedArgs = [];
47
+ if (opts.cliOptions['access']) {
48
+ appendedArgs.push(`--access=${opts.cliOptions['access']}`);
49
+ }
50
+ if (opts.dryRun) {
51
+ appendedArgs.push('--dry-run');
52
+ }
53
+ if (opts.force) {
54
+ appendedArgs.push('--force');
55
+ }
56
+ if (opts.cliOptions['otp']) {
57
+ appendedArgs.push(`--otp=${opts.cliOptions['otp']}`);
58
+ }
59
+ const chunks = sortFilteredProjects(opts);
60
+ const tag = opts.tag ?? 'latest';
61
+ if (opts.batch) {
62
+ const sortedPkgs = chunks
63
+ .flat()
64
+ .filter((pkgDir) => publishedPkgDirs.has(pkgDir))
65
+ .map((pkgDir) => opts.selectedProjectsGraph[pkgDir].package);
66
+ publishedPackages.push(...await batchPublishPackages(sortedPkgs, { ...opts, tag }));
67
+ }
68
+ else {
69
+ const commandArgs = opts.stage ? ['stage', 'publish'] : ['publish'];
70
+ for (const chunk of chunks) {
71
+ // We can't run publish concurrently due to the npm CLI asking for OTP.
72
+ // NOTE: If we solve the OTP issue, we still need to limit packages concurrency.
73
+ // Otherwise, publishing will consume too much resources.
74
+ // See related issue: https://github.com/pnpm/pnpm/issues/6968
75
+ for (const pkgDir of chunk) {
76
+ if (!publishedPkgDirs.has(pkgDir))
77
+ continue;
78
+ const pkg = opts.selectedProjectsGraph[pkgDir].package;
79
+ // The registry is picked by scope, so a `publishConfig.name` that
80
+ // moves the package to another scope has to route by the new one.
81
+ const registry = pkg.manifest.publishConfig?.registry ?? pickRegistryForPackage(opts.registries, publishedName(pkg.manifest));
82
+ // eslint-disable-next-line no-await-in-loop
83
+ const publishResult = await publish({
84
+ ...opts,
85
+ dir: pkg.rootDir,
86
+ argv: {
87
+ original: [
88
+ ...commandArgs,
89
+ '--tag',
90
+ tag,
91
+ '--registry',
92
+ registry,
93
+ ...appendedArgs,
94
+ ],
95
+ },
96
+ gitChecks: false,
97
+ recursive: false,
98
+ }, [pkg.rootDir]);
99
+ if (publishResult?.publishSummary != null) {
100
+ publishedPackages.push(publishResult.publishSummary);
101
+ }
102
+ else {
103
+ // Fallback for paths that don't produce a full PublishSummary (e.g. dry run via the
104
+ // legacy npm-CLI bridge, or future call sites that bypass publishPackedPkg).
105
+ const publishedManifest = publishResult?.publishedManifest ?? publishResult?.manifest;
106
+ if (publishedManifest != null) {
107
+ publishedPackages.push(pick(['name', 'version'], publishedManifest));
108
+ }
109
+ else if (publishResult?.exitCode) {
110
+ return { exitCode: publishResult.exitCode, publishedPackages };
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ if (opts.reportSummary) {
118
+ await writeJsonFile(path.join(opts.lockfileDir ?? opts.dir, 'pnpm-publish-summary.json'), { publishedPackages });
119
+ }
120
+ return { exitCode: 0, publishedPackages };
121
+ }
122
+ async function isAlreadyPublished(opts, pkgName, pkgVersion) {
123
+ try {
124
+ await opts.resolve({ alias: pkgName, bareSpecifier: pkgVersion }, {
125
+ lockfileDir: opts.lockfileDir,
126
+ preferredVersions: {},
127
+ projectDir: opts.dir,
128
+ });
129
+ return true;
130
+ }
131
+ catch (err) { // eslint-disable-line
132
+ return false;
133
+ }
134
+ }
135
+ //# sourceMappingURL=recursivePublish.js.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Protocols currently supported.
3
+ */
4
+ type SupportedRegistryScheme = 'http' | 'https';
5
+ /**
6
+ * A registry URL that has been normalized to match its corresponding {@link RegistryConfigKey}.
7
+ */
8
+ export type NormalizedRegistryUrl = `${SupportedRegistryScheme}://${string}/`;
9
+ /**
10
+ * A config key of a registry url is a key on the `.npmrc` file. This key starts with
11
+ * a "//" prefix followed by a hostname and the rest of the URI and ends with a "/".
12
+ * They usually specify authentication information.
13
+ */
14
+ export type RegistryConfigKey = `//${string}/`;
15
+ export interface SupportedRegistryUrlInfo {
16
+ normalizedUrl: NormalizedRegistryUrl;
17
+ longestConfigKey: RegistryConfigKey;
18
+ }
19
+ /**
20
+ * If the {@link registryUrl} is an HTTP or an HTTPS registry url, return the longest
21
+ * {@link RegistryConfigKey} that corresponds to the registry url and a {@link NormalizedRegistryUrl}
22
+ * that matches it.
23
+ */
24
+ export declare function parseSupportedRegistryUrl(registryUrl: string): SupportedRegistryUrlInfo | undefined;
25
+ /**
26
+ * Generate all {@link RegistryConfigKey} of the same hostname from the longest to the shortest,
27
+ * including {@link longest} itself.
28
+ */
29
+ export declare function allRegistryConfigKeys(longest: RegistryConfigKey): Generator<RegistryConfigKey, void, void>;
30
+ export {};
@@ -0,0 +1,50 @@
1
+ import normalizeRegistryUrl from 'normalize-registry-url';
2
+ /**
3
+ * If {@link text} starts with {@link oldPrefix}, replace it with {@link newPrefix}.
4
+ * Otherwise, return `undefined`.
5
+ */
6
+ const replacePrefix = (text, oldPrefix, newPrefix) => text.startsWith(oldPrefix)
7
+ ? text.replace(oldPrefix, newPrefix)
8
+ : undefined;
9
+ /**
10
+ * If {@link text} already ends with {@link suffix}, return it.
11
+ * Otherwise, append {@link suffix} to {@link text} and return it.
12
+ */
13
+ const ensureSuffix = (text, suffix) => text.endsWith(suffix) ? text : `${text}${suffix}`;
14
+ /**
15
+ * If the {@link registryUrl} is an HTTP or an HTTPS registry url, return the longest
16
+ * {@link RegistryConfigKey} that corresponds to the registry url and a {@link NormalizedRegistryUrl}
17
+ * that matches it.
18
+ */
19
+ export function parseSupportedRegistryUrl(registryUrl) {
20
+ registryUrl = normalizeRegistryUrl(registryUrl);
21
+ const keyPrefix = replacePrefix(registryUrl, 'http://', '//') ?? replacePrefix(registryUrl, 'https://', '//');
22
+ if (!keyPrefix)
23
+ return undefined;
24
+ const normalizedUrl = ensureSuffix(registryUrl, '/');
25
+ const longestConfigKey = ensureSuffix(keyPrefix, '/');
26
+ return { normalizedUrl, longestConfigKey };
27
+ }
28
+ /**
29
+ * This value is used for termination check in {@link allRegistryConfigKeys} only.
30
+ * It is not actually a valid {@link RegistryConfigKey}.
31
+ */
32
+ const EMPTY_REGISTRY_CONFIG_KEY = '///';
33
+ /**
34
+ * Generate all {@link RegistryConfigKey} of the same hostname from the longest to the shortest,
35
+ * including {@link longest} itself.
36
+ */
37
+ export function* allRegistryConfigKeys(longest) {
38
+ if (!longest.startsWith('//')) {
39
+ throw new RangeError(`The string ${JSON.stringify(longest)} is not a valid registry config key`);
40
+ }
41
+ if (longest === EMPTY_REGISTRY_CONFIG_KEY) {
42
+ throw new RangeError('Registry config key cannot be without hostname');
43
+ }
44
+ if (longest.length <= EMPTY_REGISTRY_CONFIG_KEY.length)
45
+ return;
46
+ yield longest;
47
+ const next = longest.replace(/[^/]*\/$/, '');
48
+ yield* allRegistryConfigKeys(next);
49
+ }
50
+ //# sourceMappingURL=registryConfigKeys.js.map
@@ -0,0 +1,7 @@
1
+ import type { AuthTokenContext } from '../oidc/authToken.js';
2
+ import type { IdTokenContext } from '../oidc/idToken.js';
3
+ import type { ProvenanceContext } from '../oidc/provenance.js';
4
+ import type { OtpContext } from '../otp.js';
5
+ type SharedContext = AuthTokenContext & IdTokenContext & ProvenanceContext & OtpContext;
6
+ export declare const SHARED_CONTEXT: SharedContext;
7
+ export {};
@@ -0,0 +1,20 @@
1
+ import readline from 'node:readline';
2
+ import { input } from '@inquirer/prompts';
3
+ import { globalInfo, globalWarn } from '@pnpm/logger';
4
+ import { fetch } from '@pnpm/network.fetch';
5
+ import ciInfo from 'ci-info';
6
+ import { publish as _publish } from 'libnpmpublish';
7
+ const publish = _publish;
8
+ export const SHARED_CONTEXT = {
9
+ Date,
10
+ createReadlineInterface: readline.createInterface.bind(null, { input: process.stdin }),
11
+ ciInfo,
12
+ enquirer: { input },
13
+ fetch,
14
+ globalInfo,
15
+ globalWarn,
16
+ process,
17
+ publish,
18
+ setTimeout,
19
+ };
20
+ //# sourceMappingURL=shared-context.js.map
@@ -0,0 +1,18 @@
1
+ import type { WorkspaceProject } from '@pnpm/releasing.versioning';
2
+ import type { BaseManifest } from '@pnpm/types';
3
+ /**
4
+ * The name a manifest publishes under — its `publishConfig.name` rename, or
5
+ * the name it carries in the workspace.
6
+ *
7
+ * The workspace — and so every parked changelog section, the ledger, every
8
+ * intent, and every dependent — keys on the manifest name, while the registry
9
+ * only ever sees the published one. Anything that addresses a project *at the
10
+ * registry* has to resolve the name through here first.
11
+ */
12
+ export declare function publishedName(manifest: Pick<BaseManifest, 'name' | 'publishConfig'>): string | undefined;
13
+ /**
14
+ * Manifest name → published name, for every project that renames itself.
15
+ * Projects that publish under their manifest name are absent, so a lookup miss
16
+ * means "no rename". For call sites that hold a name rather than a manifest.
17
+ */
18
+ export declare function publishedNameByManifestName(projects: WorkspaceProject[]): Map<string, string>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The name a manifest publishes under — its `publishConfig.name` rename, or
3
+ * the name it carries in the workspace.
4
+ *
5
+ * The workspace — and so every parked changelog section, the ledger, every
6
+ * intent, and every dependent — keys on the manifest name, while the registry
7
+ * only ever sees the published one. Anything that addresses a project *at the
8
+ * registry* has to resolve the name through here first.
9
+ */
10
+ export function publishedName(manifest) {
11
+ const renamed = manifest.publishConfig?.name;
12
+ return typeof renamed === 'string' && renamed !== '' ? renamed : manifest.name;
13
+ }
14
+ /**
15
+ * Manifest name → published name, for every project that renames itself.
16
+ * Projects that publish under their manifest name are absent, so a lookup miss
17
+ * means "no rename". For call sites that hold a name rather than a manifest.
18
+ */
19
+ export function publishedNameByManifestName(projects) {
20
+ const renames = new Map();
21
+ for (const { manifest } of projects) {
22
+ const published = publishedName(manifest);
23
+ if (manifest.name && published != null && published !== manifest.name) {
24
+ renames.set(manifest.name, published);
25
+ }
26
+ }
27
+ return renames;
28
+ }
29
+ //# sourceMappingURL=publishedNames.js.map
@@ -0,0 +1,18 @@
1
+ import type { ReleasePlan } from '@pnpm/releasing.versioning';
2
+ import { type PreviousChangelogOptions } from './publish/previousChangelog.js';
3
+ export type CheckVersionPublished = (pkgName: string, version: string) => Promise<boolean>;
4
+ export type UnpublishedProbeOptions = PreviousChangelogOptions & {
5
+ /** Overridable for tests; production probes the registry. */
6
+ checkVersionPublished?: CheckVersionPublished;
7
+ networkConcurrency?: number;
8
+ /** Manifest name → published name, from `publishedNameByManifestName`. */
9
+ publishedNames?: ReadonlyMap<string, string>;
10
+ };
11
+ /**
12
+ * The releases in `plan` whose current version the registry does not have — {@link assembleReleasePlan}'s `unpublishedDirs`.
13
+ *
14
+ * A release is keyed by its manifest name, so `publishedNames` translates it
15
+ * for the probe; without that a renamed project reads as never published and
16
+ * debuts at its manifest version on every release.
17
+ */
18
+ export declare function resolveUnpublishedDirs(plan: ReleasePlan, opts: UnpublishedProbeOptions): Promise<Set<string>>;
@@ -0,0 +1,20 @@
1
+ import pLimit from 'p-limit';
2
+ import { createVersionPublishedChecker } from './publish/previousChangelog.js';
3
+ const DEFAULT_NETWORK_CONCURRENCY = 16;
4
+ /**
5
+ * The releases in `plan` whose current version the registry does not have — {@link assembleReleasePlan}'s `unpublishedDirs`.
6
+ *
7
+ * A release is keyed by its manifest name, so `publishedNames` translates it
8
+ * for the probe; without that a renamed project reads as never published and
9
+ * debuts at its manifest version on every release.
10
+ */
11
+ export async function resolveUnpublishedDirs(plan, opts) {
12
+ const checkVersionPublished = opts.checkVersionPublished ?? createVersionPublishedChecker(opts);
13
+ const limit = pLimit(opts.networkConcurrency ?? DEFAULT_NETWORK_CONCURRENCY);
14
+ const probed = await Promise.all(plan.releases.map((release) => limit(async () => ({
15
+ dir: release.dir,
16
+ published: await checkVersionPublished(opts.publishedNames?.get(release.name) ?? release.name, release.currentVersion),
17
+ }))));
18
+ return new Set(probed.filter(({ published }) => !published).map(({ dir }) => dir));
19
+ }
20
+ //# sourceMappingURL=resolveUnpublishedDirs.js.map
@@ -0,0 +1,2 @@
1
+ import type { StageOptions } from './types.js';
2
+ export declare function stageApprove(opts: StageOptions, params: string[]): Promise<string>;
@@ -0,0 +1,14 @@
1
+ import { createStageContext } from './context.js';
2
+ import { requireStageId } from './parsing.js';
3
+ import { stageRequestWithOtp } from './request.js';
4
+ export async function stageApprove(opts, params) {
5
+ const stageId = requireStageId(params, 'approve');
6
+ const context = createStageContext(opts);
7
+ await stageRequestWithOtp(context, {
8
+ url: new URL(`-/stage/${stageId}/approve`, context.registry).href,
9
+ init: { method: 'POST' },
10
+ action: `approve staged package ${stageId}`,
11
+ });
12
+ return `Staged package ${stageId} approved and published successfully.`;
13
+ }
14
+ //# sourceMappingURL=approve.js.map
@@ -0,0 +1,14 @@
1
+ import { createFetchFromRegistry } from '@pnpm/network.fetch';
2
+ import type { StageOptions } from './types.js';
3
+ /**
4
+ * Shared per-subcommand request context. Created once at the entry of each stage
5
+ * subcommand so that paginated calls (e.g. `stageList`) reuse a single
6
+ * `fetchFromRegistry` instance and a precomputed auth header.
7
+ */
8
+ export interface StageContext {
9
+ opts: StageOptions;
10
+ registry: string;
11
+ authHeaderValue: string | undefined;
12
+ fetchFromRegistry: ReturnType<typeof createFetchFromRegistry>;
13
+ }
14
+ export declare function createStageContext(opts: StageOptions, packageName?: string): StageContext;
@@ -0,0 +1,25 @@
1
+ import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
2
+ import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header';
3
+ import { createFetchFromRegistry } from '@pnpm/network.fetch';
4
+ const DEFAULT_REGISTRY = 'https://registry.npmjs.org/';
5
+ export function createStageContext(opts, packageName) {
6
+ const registry = getStageRegistry(opts, packageName);
7
+ const getAuthHeaderByUri = createGetAuthHeaderByURI(opts.configByUri ?? {});
8
+ return {
9
+ opts,
10
+ registry,
11
+ authHeaderValue: packageName ? getAuthHeaderByUri(registry, { pkgName: packageName }) : getAuthHeaderByUri(registry),
12
+ fetchFromRegistry: createFetchFromRegistry(opts),
13
+ };
14
+ }
15
+ function getStageRegistry(opts, packageName) {
16
+ const registries = getRegistries(opts);
17
+ const registry = packageName
18
+ ? pickRegistryForPackage(registries, packageName)
19
+ : registries.default;
20
+ return registry.endsWith('/') ? registry : `${registry}/`;
21
+ }
22
+ function getRegistries(opts) {
23
+ return opts.registries ?? { default: opts.registry ?? DEFAULT_REGISTRY };
24
+ }
25
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1,2 @@
1
+ import type { StageOptions } from './types.js';
2
+ export declare function stageDownload(opts: StageOptions, params: string[]): Promise<string>;
@@ -0,0 +1,32 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { PnpmError } from '@pnpm/error';
4
+ import { createTarballFilename } from '../tarball/safeTarballFilename.js';
5
+ import { summarizeTarball } from '../tarball/summarizeTarball.js';
6
+ import { createStageContext } from './context.js';
7
+ import { requireStageId } from './parsing.js';
8
+ import { renderTarballSummary } from './rendering.js';
9
+ import { stageRequest } from './request.js';
10
+ export async function stageDownload(opts, params) {
11
+ const stageId = requireStageId(params, 'download');
12
+ const context = createStageContext(opts);
13
+ const response = await stageRequest(context, {
14
+ url: new URL(`-/stage/${stageId}/tarball`, context.registry).href,
15
+ init: { method: 'GET' },
16
+ action: `download staged package ${stageId}`,
17
+ });
18
+ const tarballData = Buffer.from(await response.arrayBuffer());
19
+ const summary = await summarizeTarball(tarballData);
20
+ const filename = createTarballFilename({ name: summary.name, version: summary.version, suffix: stageId });
21
+ const downloadedSummary = { ...summary, filename };
22
+ const downloadDir = path.resolve(opts.dir ?? process.cwd());
23
+ const outputPath = path.resolve(downloadDir, filename);
24
+ if (path.dirname(outputPath) !== downloadDir) {
25
+ throw new PnpmError('INVALID_TARBALL_FILENAME', `Invalid tarball filename "${filename}".`);
26
+ }
27
+ await fs.writeFile(outputPath, tarballData);
28
+ if (opts.json)
29
+ return JSON.stringify({ [summary.name]: downloadedSummary }, null, 2);
30
+ return `${renderTarballSummary(downloadedSummary)}\n${filename}`;
31
+ }
32
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1,15 @@
1
+ import { PnpmError } from '@pnpm/error';
2
+ interface StageRegistryErrorProperties {
3
+ readonly action: string;
4
+ readonly status: number;
5
+ readonly statusText: string;
6
+ readonly text: string;
7
+ }
8
+ export declare class StageRegistryError extends PnpmError implements StageRegistryErrorProperties {
9
+ readonly action: string;
10
+ readonly status: number;
11
+ readonly statusText: string;
12
+ readonly text: string;
13
+ constructor(opts: StageRegistryErrorProperties);
14
+ }
15
+ export {};
@@ -0,0 +1,17 @@
1
+ import { PnpmError } from '@pnpm/error';
2
+ export class StageRegistryError extends PnpmError {
3
+ action;
4
+ status;
5
+ statusText;
6
+ text;
7
+ constructor(opts) {
8
+ const statusDisplay = opts.statusText ? `${opts.status} ${opts.statusText}` : opts.status.toString();
9
+ const trimmedText = opts.text.trim();
10
+ super('STAGE_REGISTRY_ERROR', `Failed to ${opts.action} (status ${statusDisplay})${trimmedText ? `: ${trimmedText}` : ''}`);
11
+ this.action = opts.action;
12
+ this.status = opts.status;
13
+ this.statusText = opts.statusText;
14
+ this.text = opts.text;
15
+ }
16
+ }
17
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ export declare function help(): string;
@@ -0,0 +1,84 @@
1
+ import { FILTERING } from '@pnpm/cli.common-cli-options-help';
2
+ import { docsUrl } from '@pnpm/cli.utils';
3
+ import { renderHelp } from 'render-help';
4
+ export function help() {
5
+ return renderHelp({
6
+ description: 'Stage packages for publishing, deferring proof-of-presence (2FA) to a later point in time.',
7
+ descriptionLists: [
8
+ {
9
+ title: 'Subcommands',
10
+ list: [
11
+ {
12
+ description: 'Stage a package for publishing.',
13
+ name: 'publish',
14
+ },
15
+ {
16
+ description: 'List all staged package versions.',
17
+ name: 'list',
18
+ },
19
+ {
20
+ description: 'View details of a specific staged package.',
21
+ name: 'view',
22
+ },
23
+ {
24
+ description: 'Approve a staged package, publishing it to the npm registry.',
25
+ name: 'approve',
26
+ },
27
+ {
28
+ description: 'Reject a staged package, removing it from the registry.',
29
+ name: 'reject',
30
+ },
31
+ {
32
+ description: 'Download the tarball of a staged package for inspection.',
33
+ name: 'download',
34
+ },
35
+ ],
36
+ },
37
+ {
38
+ title: 'Options',
39
+ list: [
40
+ {
41
+ description: 'The base URL of the npm registry.',
42
+ name: '--registry <url>',
43
+ },
44
+ {
45
+ description: 'Show information in JSON format for list, view, publish, and download.',
46
+ name: '--json',
47
+ },
48
+ {
49
+ description: 'Registers the staged package with the given tag. By default, the "latest" tag is used.',
50
+ name: '--tag <tag>',
51
+ },
52
+ {
53
+ description: 'Tells the registry whether the staged package should be public or restricted.',
54
+ name: '--access <public|restricted>',
55
+ },
56
+ {
57
+ description: 'Does everything stage publish would do except uploading to the registry.',
58
+ name: '--dry-run',
59
+ },
60
+ {
61
+ description: 'One-time password for approve and reject.',
62
+ name: '--otp',
63
+ },
64
+ {
65
+ description: 'Stage all publishable packages from the workspace.',
66
+ name: '--recursive',
67
+ shortAlias: '-r',
68
+ },
69
+ ],
70
+ },
71
+ FILTERING,
72
+ ],
73
+ url: docsUrl('stage'),
74
+ usages: [
75
+ 'pnpm stage publish [<tarball>|<dir>] [--tag <tag>] [--access <public|restricted>] [options]',
76
+ 'pnpm stage list [<package-spec>]',
77
+ 'pnpm stage view <stage-id>',
78
+ 'pnpm stage approve <stage-id>',
79
+ 'pnpm stage reject <stage-id>',
80
+ 'pnpm stage download <stage-id>',
81
+ ],
82
+ });
83
+ }
84
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1,13 @@
1
+ import { help } from './help.js';
2
+ import { type StageOptions } from './types.js';
3
+ export { help };
4
+ export declare function rcOptionsTypes(): Record<string, unknown>;
5
+ export declare function cliOptionsTypes(): Record<string, unknown>;
6
+ export declare const commandNames: string[];
7
+ export declare const completion: (_cliOpts: Record<string, unknown>, params: string[]) => Promise<Array<{
8
+ name: string;
9
+ }>>;
10
+ export declare function handler(opts: StageOptions, params: string[]): Promise<{
11
+ exitCode?: number;
12
+ output?: string;
13
+ } | string | undefined>;
@@ -0,0 +1,57 @@
1
+ import { types as allTypes } from '@pnpm/config.reader';
2
+ import { PnpmError } from '@pnpm/error';
3
+ import { pick } from 'ramda';
4
+ import * as publishCommand from '../publish/publish.js';
5
+ import { stageApprove } from './approve.js';
6
+ import { stageDownload } from './download.js';
7
+ import { help } from './help.js';
8
+ import { stageList } from './list.js';
9
+ import { stagePublish } from './publish.js';
10
+ import { stageReject } from './reject.js';
11
+ import { STAGE_SUBCOMMANDS } from './types.js';
12
+ import { stageView } from './view.js';
13
+ export { help };
14
+ export function rcOptionsTypes() {
15
+ return {
16
+ ...publishCommand.rcOptionsTypes(),
17
+ ...pick([
18
+ 'registry',
19
+ ], allTypes),
20
+ };
21
+ }
22
+ export function cliOptionsTypes() {
23
+ return publishCommand.cliOptionsTypes();
24
+ }
25
+ export const commandNames = ['stage'];
26
+ export const completion = async (_cliOpts, params) => {
27
+ if (params.length > 0)
28
+ return [];
29
+ return STAGE_SUBCOMMANDS.map((name) => ({ name }));
30
+ };
31
+ export async function handler(opts, params) {
32
+ const subcommand = params[0];
33
+ const subcommandParams = params.slice(1);
34
+ switch (subcommand) {
35
+ case 'publish':
36
+ return stagePublish(opts, subcommandParams);
37
+ case 'list':
38
+ return stageList(opts, subcommandParams);
39
+ case 'view':
40
+ return stageView(opts, subcommandParams);
41
+ case 'approve':
42
+ return stageApprove(opts, subcommandParams);
43
+ case 'reject':
44
+ return stageReject(opts, subcommandParams);
45
+ case 'download':
46
+ return stageDownload(opts, subcommandParams);
47
+ case undefined:
48
+ throw new PnpmError('STAGE_SUBCOMMAND_REQUIRED', 'Stage subcommand is required', {
49
+ hint: `Use one of: ${STAGE_SUBCOMMANDS.join(', ')}`,
50
+ });
51
+ default:
52
+ throw new PnpmError('STAGE_UNKNOWN_SUBCOMMAND', `Unknown stage subcommand "${subcommand}"`, {
53
+ hint: `Use one of: ${STAGE_SUBCOMMANDS.join(', ')}`,
54
+ });
55
+ }
56
+ }
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,2 @@
1
+ import type { StageOptions } from './types.js';
2
+ export declare function stageList(opts: StageOptions, params: string[]): Promise<string>;