@pnpm/resolving.npm-resolver 1104.0.0 → 1104.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/lib/createNpmResolutionVerifier.js +131 -23
- package/lib/index.d.ts +1 -0
- package/lib/index.js +170 -25
- package/lib/parseBareSpecifier.d.ts +1 -0
- package/lib/parseBareSpecifier.js +30 -6
- package/lib/violationCodes.d.ts +1 -0
- package/lib/violationCodes.js +1 -0
- package/package.json +19 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @pnpm/npm-resolver
|
|
2
2
|
|
|
3
|
+
## 1104.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added explicit registry revision selection with `<version>+rN` and `pnpm update --patches` for refreshing revision artifacts without changing package versions. Registry-backed lockfile policy checks recognize historical revisions, and pnpr now preserves safe revision histories from upstream registries.
|
|
8
|
+
|
|
9
|
+
- Added support for registry replacement tarballs using standard integrity values, explicit revision fields, registry routing from the `registries` setting, non-redirecting integrity-addressed URLs, canonical safe-integer revision numbers, and pnpr proxying for immutable upstream revision artifacts.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies:
|
|
14
|
+
- @pnpm/config.normalize-registries@1101.0.1
|
|
15
|
+
- @pnpm/config.pick-registry-for-package@1101.0.1
|
|
16
|
+
- @pnpm/config.version-policy@1100.2.2
|
|
17
|
+
- @pnpm/core-loggers@1100.3.4
|
|
18
|
+
- @pnpm/crypto.hash@1100.0.3
|
|
19
|
+
- @pnpm/deps.path@1101.0.1
|
|
20
|
+
- @pnpm/fs.graceful-fs@1100.2.0
|
|
21
|
+
- @pnpm/pkg-manifest.utils@1100.4.2
|
|
22
|
+
- @pnpm/resolving.registry.pkg-metadata-filter@1100.0.18
|
|
23
|
+
- @pnpm/resolving.registry.types@1100.2.0
|
|
24
|
+
- @pnpm/resolving.resolver-base@1101.2.0
|
|
25
|
+
- @pnpm/resolving.tarball-url@1101.1.0
|
|
26
|
+
- @pnpm/store.cafs@1100.3.0
|
|
27
|
+
- @pnpm/store.index@1100.3.0
|
|
28
|
+
- @pnpm/types@1102.1.0
|
|
29
|
+
|
|
3
30
|
## 1104.0.0
|
|
4
31
|
|
|
5
32
|
### Major Changes
|
|
@@ -5,13 +5,14 @@ import { createPackageVersionPolicy } from '@pnpm/config.version-policy';
|
|
|
5
5
|
import { FULL_META_DIR } from '@pnpm/constants';
|
|
6
6
|
import { PnpmError } from '@pnpm/error';
|
|
7
7
|
import { isGitHostedTarballUrl, } from '@pnpm/resolving.resolver-base';
|
|
8
|
+
import { isIntegrityAddressedRegistryTarballUrl, isValidTarballRevision, } from '@pnpm/resolving.tarball-url';
|
|
8
9
|
import semver from 'semver';
|
|
9
10
|
import { fetchAttestationPublishedAt } from './fetchAttestationPublishedAt.js';
|
|
10
11
|
import { fetchAbbreviatedMetadataCached, fetchFullMetadataCached, } from './fetchFullMetadataCached.js';
|
|
11
12
|
import { normalizeRegistryUrl } from './normalizeRegistryUrl.js';
|
|
12
13
|
import { getPkgMetaCacheKey, getPkgMirrorPath, loadMeta, warnMissingTimeFieldOnce } from './pickPackage.js';
|
|
13
14
|
import { failIfTrustDowngraded } from './trustChecks.js';
|
|
14
|
-
import { MINIMUM_RELEASE_AGE_VIOLATION_CODE, MISSING_NAMED_REGISTRY_VIOLATION_CODE, MISSING_TARBALL_INTEGRITY_VIOLATION_CODE, TARBALL_URL_MISMATCH_VIOLATION_CODE, TRUST_DOWNGRADE_VIOLATION_CODE, } from './violationCodes.js';
|
|
15
|
+
import { MINIMUM_RELEASE_AGE_VIOLATION_CODE, MISSING_NAMED_REGISTRY_VIOLATION_CODE, MISSING_TARBALL_INTEGRITY_VIOLATION_CODE, TARBALL_REVISION_MISMATCH_VIOLATION_CODE, TARBALL_URL_MISMATCH_VIOLATION_CODE, TRUST_DOWNGRADE_VIOLATION_CODE, } from './violationCodes.js';
|
|
15
16
|
/**
|
|
16
17
|
* Returns a `ResolutionVerifier` for npm-registry-resolved lockfile
|
|
17
18
|
* entries. It always binds each entry's recorded tarball URL to the
|
|
@@ -113,7 +114,7 @@ export function createNpmResolutionVerifier(opts) {
|
|
|
113
114
|
return {
|
|
114
115
|
ok: false,
|
|
115
116
|
code: MISSING_NAMED_REGISTRY_VIOLATION_CODE,
|
|
116
|
-
reason: `
|
|
117
|
+
reason: `has registry prefix '${registryName}:', which is not declared by the registries setting`,
|
|
117
118
|
};
|
|
118
119
|
}
|
|
119
120
|
registry = namedRegistry;
|
|
@@ -129,13 +130,14 @@ export function createNpmResolutionVerifier(opts) {
|
|
|
129
130
|
// narrowed by their exclude lists, since it guards integrity rather
|
|
130
131
|
// than maturity/trust. Registry entries with no tarball URL reconstruct
|
|
131
132
|
// it from name+version+registry, so they're inherently bound.
|
|
132
|
-
|
|
133
|
-
const urlViolation = await runTarballUrlCheck(lookupContext, registry, name, version, tarballUrl);
|
|
134
|
-
if (urlViolation)
|
|
135
|
-
return urlViolation;
|
|
136
|
-
}
|
|
133
|
+
const rawRevision = resolution.revision;
|
|
137
134
|
const ageApplies = ageCheckActive && !isExcluded(excludePolicy, name, version);
|
|
138
135
|
const trustApplies = trustCheckActive && !isExcluded(trustExcludePolicy, name, version);
|
|
136
|
+
if (tarballUrl != null || (rawRevision != null && (ageApplies || trustApplies))) {
|
|
137
|
+
const artifactViolation = await runRegistryArtifactCheck(lookupContext, registry, name, version, integrity, rawRevision, tarballUrl);
|
|
138
|
+
if (artifactViolation)
|
|
139
|
+
return artifactViolation;
|
|
140
|
+
}
|
|
139
141
|
if (!ageApplies && !trustApplies)
|
|
140
142
|
return { ok: true };
|
|
141
143
|
if (ageApplies) {
|
|
@@ -178,6 +180,7 @@ export function createNpmResolutionVerifier(opts) {
|
|
|
178
180
|
// applies the binding — otherwise an upgrade could keep trusting a
|
|
179
181
|
// lockfile that was only ever age/trust-checked.
|
|
180
182
|
tarballUrlBinding: true,
|
|
183
|
+
revisionHistoryBinding: true,
|
|
181
184
|
// Same cache identity rule for the missing-integrity structural check.
|
|
182
185
|
integrityRequired: true,
|
|
183
186
|
namedRegistriesRouting,
|
|
@@ -193,6 +196,8 @@ export function createNpmResolutionVerifier(opts) {
|
|
|
193
196
|
// didn't record it can't be trusted to have enforced it.
|
|
194
197
|
if (cached.tarballUrlBinding !== true)
|
|
195
198
|
return false;
|
|
199
|
+
if (cached.revisionHistoryBinding !== true)
|
|
200
|
+
return false;
|
|
196
201
|
// The missing-integrity check is also unconditional; older cache records
|
|
197
202
|
// without the flag cannot prove they rejected unverifiable tarballs.
|
|
198
203
|
if (cached.integrityRequired !== true)
|
|
@@ -309,7 +314,7 @@ async function runAgeCheck(context, registry, name, version, cutoff, ignoreMissi
|
|
|
309
314
|
* a tampered lockfile could smuggle a malicious URL past the check by
|
|
310
315
|
* pointing it at a `name@version` the registry can't vouch for.
|
|
311
316
|
*/
|
|
312
|
-
async function
|
|
317
|
+
async function runRegistryArtifactCheck(context, registry, name, version, lockfileIntegrity, rawRevision, lockfileTarball) {
|
|
313
318
|
const { meta, error } = await fetchAbbreviatedMeta(context, registry, name);
|
|
314
319
|
if (error != null) {
|
|
315
320
|
// Couldn't reach the registry to verify (auth/network/5xx). Propagate the
|
|
@@ -319,17 +324,107 @@ async function runTarballUrlCheck(context, registry, name, version, lockfileTarb
|
|
|
319
324
|
// error — still fail-closed, the entry never reaches the filesystem.
|
|
320
325
|
throw error;
|
|
321
326
|
}
|
|
322
|
-
const
|
|
323
|
-
if (
|
|
324
|
-
|
|
327
|
+
const artifact = meta?.versionArtifacts?.get(version);
|
|
328
|
+
if (artifact == null) {
|
|
329
|
+
if (lockfileTarball == null && rawRevision == null)
|
|
330
|
+
return undefined;
|
|
331
|
+
return {
|
|
332
|
+
ok: false,
|
|
333
|
+
code: lockfileTarball == null
|
|
334
|
+
? TARBALL_REVISION_MISMATCH_VIOLATION_CODE
|
|
335
|
+
: TARBALL_URL_MISMATCH_VIOLATION_CODE,
|
|
336
|
+
reason: "could not be verified against the registry's published metadata",
|
|
337
|
+
};
|
|
325
338
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
339
|
+
const metadataRevision = artifact.current.revision;
|
|
340
|
+
const revisionAware = rawRevision != null || metadataRevision !== undefined || artifact.revisions.length > 0;
|
|
341
|
+
if (!revisionAware) {
|
|
342
|
+
if (lockfileTarball == null)
|
|
343
|
+
return undefined;
|
|
344
|
+
if (typeof artifact.current.tarball === 'string' && sameTarballUrl(lockfileTarball, artifact.current.tarball)) {
|
|
345
|
+
return undefined;
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
ok: false,
|
|
349
|
+
code: TARBALL_URL_MISMATCH_VIOLATION_CODE,
|
|
350
|
+
reason: typeof artifact.current.tarball !== 'string'
|
|
351
|
+
? "could not be verified against the registry's published metadata"
|
|
352
|
+
: `has a tarball URL (${lockfileTarball}) that does not match the registry's published metadata (${artifact.current.tarball})`,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
if (rawRevision != null && !isValidTarballRevision(rawRevision)) {
|
|
356
|
+
return {
|
|
357
|
+
ok: false,
|
|
358
|
+
code: TARBALL_REVISION_MISMATCH_VIOLATION_CODE,
|
|
359
|
+
reason: `has an invalid revision (${String(rawRevision)})`,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
let currentRevision = 0;
|
|
363
|
+
if (metadataRevision !== undefined) {
|
|
364
|
+
if (!isValidTarballRevision(metadataRevision)) {
|
|
365
|
+
return {
|
|
366
|
+
ok: false,
|
|
367
|
+
code: TARBALL_REVISION_MISMATCH_VIOLATION_CODE,
|
|
368
|
+
reason: `registry metadata has an invalid current revision (${String(metadataRevision)})`,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
currentRevision = metadataRevision;
|
|
372
|
+
const currentHistory = artifact.revisions.filter(candidate => candidate.revision === currentRevision);
|
|
373
|
+
if (currentHistory.length !== 1 ||
|
|
374
|
+
currentHistory[0].integrity !== artifact.current.integrity ||
|
|
375
|
+
typeof currentHistory[0].tarball !== 'string' ||
|
|
376
|
+
typeof artifact.current.tarball !== 'string' ||
|
|
377
|
+
typeof artifact.current.integrity !== 'string' ||
|
|
378
|
+
!isIntegrityAddressedRegistryTarballUrl(normalizeRegistryUrl(artifact.current.tarball), artifact.current.integrity, registry) ||
|
|
379
|
+
!sameTarballUrl(currentHistory[0].tarball, artifact.current.tarball)) {
|
|
380
|
+
return {
|
|
381
|
+
ok: false,
|
|
382
|
+
code: TARBALL_REVISION_MISMATCH_VIOLATION_CODE,
|
|
383
|
+
reason: `registry metadata revision ${currentRevision} does not have exactly one matching history entry`,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
const revision = typeof rawRevision === 'number' ? rawRevision : 0;
|
|
388
|
+
const currentMatches = currentRevision === revision;
|
|
389
|
+
const historicalCandidates = artifact.revisions.filter(candidate => candidate.revision === revision);
|
|
390
|
+
if (historicalCandidates.length > 1) {
|
|
391
|
+
return {
|
|
392
|
+
ok: false,
|
|
393
|
+
code: TARBALL_REVISION_MISMATCH_VIOLATION_CODE,
|
|
394
|
+
reason: `revision ${revision} is advertised more than once in the registry's history`,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
const historical = historicalCandidates[0];
|
|
398
|
+
const selected = currentMatches ? artifact.current : historical;
|
|
399
|
+
if (selected == null ||
|
|
400
|
+
selected.integrity !== lockfileIntegrity ||
|
|
401
|
+
(currentMatches && historical != null && historical.integrity !== lockfileIntegrity)) {
|
|
402
|
+
return {
|
|
403
|
+
ok: false,
|
|
404
|
+
code: TARBALL_REVISION_MISMATCH_VIOLATION_CODE,
|
|
405
|
+
reason: `has revision ${revision} with an integrity that does not match the registry's current or historical metadata`,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
if (revision > 0 || !currentMatches) {
|
|
409
|
+
if (typeof selected.tarball !== 'string' ||
|
|
410
|
+
!isIntegrityAddressedRegistryTarballUrl(normalizeRegistryUrl(selected.tarball), lockfileIntegrity, registry)) {
|
|
411
|
+
return {
|
|
412
|
+
ok: false,
|
|
413
|
+
code: TARBALL_REVISION_MISMATCH_VIOLATION_CODE,
|
|
414
|
+
reason: `has revision ${revision} that is not addressed by its complete sha512 integrity`,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (lockfileTarball != null && (typeof selected.tarball !== 'string' || !sameTarballUrl(lockfileTarball, selected.tarball))) {
|
|
419
|
+
return {
|
|
420
|
+
ok: false,
|
|
421
|
+
code: TARBALL_URL_MISMATCH_VIOLATION_CODE,
|
|
422
|
+
reason: typeof selected.tarball !== 'string'
|
|
423
|
+
? "could not be verified against the registry's published metadata"
|
|
424
|
+
: `has a tarball URL (${lockfileTarball}) that does not match the registry's published metadata (${selected.tarball})`,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
return undefined;
|
|
333
428
|
}
|
|
334
429
|
function sameTarballUrl(a, b) {
|
|
335
430
|
return canonicalTarballUrl(a) === canonicalTarballUrl(b);
|
|
@@ -549,7 +644,7 @@ async function tryAbbreviatedModifiedShortcut(context, registry, name, version)
|
|
|
549
644
|
// publish time — but only for versions the registry currently lists.
|
|
550
645
|
// An unpublished or never-published pin would otherwise pass the gate
|
|
551
646
|
// on a stale package-level timestamp.
|
|
552
|
-
if (!meta?.
|
|
647
|
+
if (!meta?.versionArtifacts?.has(version))
|
|
553
648
|
return undefined;
|
|
554
649
|
return modified;
|
|
555
650
|
}
|
|
@@ -633,16 +728,29 @@ function validateSharedMeta(meta, name) {
|
|
|
633
728
|
// lockfile (see #11860). The full document is GC-able as soon as this
|
|
634
729
|
// closure returns; only the short tarball-URL strings are retained.
|
|
635
730
|
function projectAbbreviatedMeta(meta) {
|
|
636
|
-
let
|
|
731
|
+
let versionArtifacts;
|
|
637
732
|
if (meta.versions) {
|
|
638
|
-
|
|
733
|
+
versionArtifacts = new Map();
|
|
639
734
|
for (const [version, manifest] of Object.entries(meta.versions)) {
|
|
640
|
-
|
|
735
|
+
versionArtifacts.set(version, {
|
|
736
|
+
current: {
|
|
737
|
+
revision: manifest.dist?.revision,
|
|
738
|
+
integrity: manifest.dist?.integrity,
|
|
739
|
+
tarball: manifest.dist?.tarball,
|
|
740
|
+
},
|
|
741
|
+
revisions: Array.isArray(manifest.dist?.revisions)
|
|
742
|
+
? manifest.dist.revisions.map(revision => ({
|
|
743
|
+
revision: revision.revision,
|
|
744
|
+
integrity: revision.integrity,
|
|
745
|
+
tarball: revision.tarball,
|
|
746
|
+
}))
|
|
747
|
+
: [],
|
|
748
|
+
});
|
|
641
749
|
}
|
|
642
750
|
}
|
|
643
751
|
return {
|
|
644
752
|
modified: meta.modified,
|
|
645
|
-
|
|
753
|
+
versionArtifacts,
|
|
646
754
|
};
|
|
647
755
|
}
|
|
648
756
|
function readLocalMetaTime(context, registry, name) {
|
package/lib/index.d.ts
CHANGED
|
@@ -123,6 +123,7 @@ export type ResolveFromNpmOptions = {
|
|
|
123
123
|
preferredVersions?: PreferredVersions;
|
|
124
124
|
preferWorkspacePackages?: boolean;
|
|
125
125
|
update?: false | 'compatible' | 'latest';
|
|
126
|
+
updatePatches?: boolean;
|
|
126
127
|
updateRequested?: boolean;
|
|
127
128
|
updateChecksums?: boolean;
|
|
128
129
|
injectWorkspacePackages?: boolean;
|
package/lib/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
|
|
3
3
|
import { isWellFormedRegistryName, RESERVED_VERSION_PREFIXES } from '@pnpm/deps.path';
|
|
4
|
-
import { PnpmError } from '@pnpm/error';
|
|
4
|
+
import { PnpmError, redactUrlForDisplay } from '@pnpm/error';
|
|
5
5
|
import { globalWarn } from '@pnpm/logger';
|
|
6
6
|
import { calcVersionRange, inferRangeSpecStyle, rangeSpecGranularity, versionWithRangeSpecStyle } from '@pnpm/pkg-manifest.utils';
|
|
7
7
|
import { EXISTING_VERSION_SELECTOR_WEIGHT, } from '@pnpm/resolving.resolver-base';
|
|
8
|
+
import { isIntegrityAddressedRegistryTarballUrl, isValidTarballRevision, } from '@pnpm/resolving.tarball-url';
|
|
8
9
|
import { storeIndexKey } from '@pnpm/store.index';
|
|
9
10
|
import { readPkgFromCafs, } from '@pnpm/worker';
|
|
10
11
|
import { resolveWorkspaceRange } from '@pnpm/workspace.range-resolver';
|
|
@@ -332,12 +333,15 @@ async function resolveNpm(ctx, wantedDependency, opts) {
|
|
|
332
333
|
return resolvedFromWorkspace;
|
|
333
334
|
}
|
|
334
335
|
}
|
|
335
|
-
const
|
|
336
|
+
const canKeepWorkspaceResolution = opts.currentPkg == null || opts.currentPkg.resolution.type === 'directory';
|
|
336
337
|
const spec = wantedDependency.bareSpecifier
|
|
337
338
|
? parseBareSpecifier(wantedDependency.bareSpecifier, wantedDependency.alias, defaultTag, registry)
|
|
338
339
|
: defaultTagForAlias(wantedDependency.alias, defaultTag);
|
|
339
340
|
if (spec == null)
|
|
340
341
|
return null;
|
|
342
|
+
const workspacePackages = spec.revision == null && (!opts.updatePatches || canKeepWorkspaceResolution) && opts.alwaysTryWorkspacePackages !== false
|
|
343
|
+
? opts.workspacePackages
|
|
344
|
+
: undefined;
|
|
341
345
|
// Fast path: if we have a current resolution with integrity, try to peek the manifest from the store.
|
|
342
346
|
// This avoids the expensive metadata fetch from the registry.
|
|
343
347
|
// We do this AFTER ensuring the spec is valid for this resolver to avoids hijacking other resolvers.
|
|
@@ -347,10 +351,12 @@ async function resolveNpm(ctx, wantedDependency, opts) {
|
|
|
347
351
|
if (ctx.peekManifestFromStore &&
|
|
348
352
|
opts.currentPkg?.resolution &&
|
|
349
353
|
!opts.update &&
|
|
354
|
+
!opts.updatePatches &&
|
|
355
|
+
spec.revision == null &&
|
|
350
356
|
(opts.publishedBy == null || opts.currentPkg.publishedAt != null)) {
|
|
351
357
|
const currentResolution = opts.currentPkg.resolution;
|
|
352
358
|
// Only use this optimization for tarball resolutions with integrity (npm packages)
|
|
353
|
-
if ('tarball' in currentResolution && currentResolution.integrity) {
|
|
359
|
+
if ('tarball' in currentResolution && typeof currentResolution.integrity === 'string') {
|
|
354
360
|
const manifest = await ctx.peekManifestFromStore({
|
|
355
361
|
id: opts.currentPkg.id,
|
|
356
362
|
integrity: currentResolution.integrity,
|
|
@@ -398,7 +404,7 @@ async function resolveNpm(ctx, wantedDependency, opts) {
|
|
|
398
404
|
!opts.updateChecksums &&
|
|
399
405
|
opts.injectWorkspacePackages !== true &&
|
|
400
406
|
!wantedDependency.injected) {
|
|
401
|
-
const workspacePkgsMatchingName = workspacePackages.get(spec.name);
|
|
407
|
+
const workspacePkgsMatchingName = spec.revision == null ? workspacePackages.get(spec.name) : undefined;
|
|
402
408
|
if (workspacePkgsMatchingName?.size === 1) {
|
|
403
409
|
const localVersion = pickMatchingLocalVersionOrNull(workspacePkgsMatchingName, spec);
|
|
404
410
|
if (localVersion != null) {
|
|
@@ -426,7 +432,7 @@ async function resolveNpm(ctx, wantedDependency, opts) {
|
|
|
426
432
|
preferredVersionSelectors: preferredVersionSelectorsFor(opts, spec.name),
|
|
427
433
|
registry,
|
|
428
434
|
includeLatestTag: opts.update === 'latest',
|
|
429
|
-
updateChecksums: opts.updateChecksums,
|
|
435
|
+
updateChecksums: opts.updateChecksums || opts.updatePatches,
|
|
430
436
|
optional: wantedDependency.optional,
|
|
431
437
|
trustPolicy: opts.trustPolicy,
|
|
432
438
|
});
|
|
@@ -491,7 +497,7 @@ async function resolveNpm(ctx, wantedDependency, opts) {
|
|
|
491
497
|
});
|
|
492
498
|
}
|
|
493
499
|
const latest = latestAllowedByPolicy(meta, opts);
|
|
494
|
-
const workspacePkgsMatchingName = workspacePackages?.get(pickedPackage.name);
|
|
500
|
+
const workspacePkgsMatchingName = spec.revision == null ? workspacePackages?.get(pickedPackage.name) : undefined;
|
|
495
501
|
if (workspacePkgsMatchingName && opts.projectDir) {
|
|
496
502
|
const matchedPkg = workspacePkgsMatchingName.get(pickedPackage.version);
|
|
497
503
|
if (matchedPkg) {
|
|
@@ -525,11 +531,9 @@ async function resolveNpm(ctx, wantedDependency, opts) {
|
|
|
525
531
|
}
|
|
526
532
|
}
|
|
527
533
|
warnOnceOnHeldBackUpdate(ctx, opts, spec, meta, pickedPackage.version);
|
|
534
|
+
const selectedPackage = selectPackageRevision(pickedPackage, spec, registry);
|
|
528
535
|
const id = `${pickedPackage.name}@${pickedPackage.version}`;
|
|
529
|
-
const resolution =
|
|
530
|
-
integrity: getIntegrity(pickedPackage.dist),
|
|
531
|
-
tarball: normalizeRegistryUrl(pickedPackage.dist.tarball),
|
|
532
|
-
};
|
|
536
|
+
const resolution = createRegistryTarballResolution(selectedPackage.dist, registry);
|
|
533
537
|
let normalizedBareSpecifier;
|
|
534
538
|
if (opts.calcSpecifier) {
|
|
535
539
|
normalizedBareSpecifier = spec.normalizedBareSpecifier ?? calcSpecifier({
|
|
@@ -543,7 +547,7 @@ async function resolveNpm(ctx, wantedDependency, opts) {
|
|
|
543
547
|
return {
|
|
544
548
|
id,
|
|
545
549
|
latest,
|
|
546
|
-
manifest:
|
|
550
|
+
manifest: selectedPackage,
|
|
547
551
|
resolution,
|
|
548
552
|
resolvedVia: 'npm-registry',
|
|
549
553
|
publishedAt,
|
|
@@ -568,7 +572,14 @@ async function resolveJsr(ctx, wantedDependency, opts) {
|
|
|
568
572
|
return {
|
|
569
573
|
...picked,
|
|
570
574
|
normalizedBareSpecifier: opts.calcSpecifier
|
|
571
|
-
? calcPrefixedSpecifier(
|
|
575
|
+
? calcPrefixedSpecifier({
|
|
576
|
+
prefix: 'jsr:',
|
|
577
|
+
pkgName: spec.jsrPkgName,
|
|
578
|
+
wantedDependency,
|
|
579
|
+
version: picked.manifest.version,
|
|
580
|
+
revision: spec.revision,
|
|
581
|
+
defaultRangeSpecStyle: opts.rangeSpecStyle,
|
|
582
|
+
})
|
|
572
583
|
: undefined,
|
|
573
584
|
resolvedVia: 'jsr-registry',
|
|
574
585
|
alias: spec.jsrPkgName,
|
|
@@ -590,7 +601,7 @@ function mergeNamedRegistries(userDefined) {
|
|
|
590
601
|
if (RESERVED_VERSION_PREFIXES.has(alias) || !isWellFormedRegistryName(alias)) {
|
|
591
602
|
throw new PnpmError('RESERVED_NAMED_REGISTRY_NAME', RESERVED_VERSION_PREFIXES.has(alias)
|
|
592
603
|
? `'${alias}' cannot be used as a named registry alias: it is a reserved dependency specifier prefix.`
|
|
593
|
-
: `'${alias}' cannot be used as a named registry alias: aliases must start with a letter and contain only letters, digits, ".", "_", and "-".`, { hint: '
|
|
604
|
+
: `'${alias}' cannot be used as a named registry alias: aliases must start with a letter and contain only letters, digits, ".", "_", and "-".`, { hint: 'Change the prefix on the corresponding registries entry.' });
|
|
594
605
|
}
|
|
595
606
|
if (typeof url !== 'string' || !isValidHttpUrl(url)) {
|
|
596
607
|
throw new PnpmError('INVALID_NAMED_REGISTRY_URL', `The named registry alias '${alias}' is mapped to '${String(url)}', which is not a valid http(s) URL.`, { hint: 'Provide a URL that starts with http:// or https://, e.g. https://npm.pkg.example.com/' });
|
|
@@ -633,7 +644,14 @@ async function resolveFromNamedRegistry(ctx, wantedDependency, opts) {
|
|
|
633
644
|
// decides the tarball both consumers get.
|
|
634
645
|
id: `${picked.manifest.name}@${spec.registryName}:${picked.manifest.version}`,
|
|
635
646
|
normalizedBareSpecifier: opts.calcSpecifier
|
|
636
|
-
? calcPrefixedSpecifier(
|
|
647
|
+
? calcPrefixedSpecifier({
|
|
648
|
+
prefix: `${spec.registryName}:`,
|
|
649
|
+
pkgName: spec.name,
|
|
650
|
+
wantedDependency,
|
|
651
|
+
version: picked.manifest.version,
|
|
652
|
+
revision: spec.revision,
|
|
653
|
+
defaultRangeSpecStyle: opts.rangeSpecStyle,
|
|
654
|
+
})
|
|
637
655
|
: undefined,
|
|
638
656
|
resolvedVia: 'named-registry',
|
|
639
657
|
registryName: spec.registryName,
|
|
@@ -657,7 +675,7 @@ async function pickFromSimpleRegistry(ctx, wantedDependency, opts, spec, registr
|
|
|
657
675
|
preferredVersionSelectors: preferredVersionSelectorsFor(opts, spec.name),
|
|
658
676
|
registry,
|
|
659
677
|
includeLatestTag: opts.update === 'latest',
|
|
660
|
-
updateChecksums: opts.updateChecksums,
|
|
678
|
+
updateChecksums: opts.updateChecksums || opts.updatePatches,
|
|
661
679
|
optional: wantedDependency.optional,
|
|
662
680
|
trustPolicy: opts.trustPolicy,
|
|
663
681
|
});
|
|
@@ -665,15 +683,13 @@ async function pickFromSimpleRegistry(ctx, wantedDependency, opts, spec, registr
|
|
|
665
683
|
throw new NoMatchingVersionError({ wantedDependency, packageMeta: meta, registry });
|
|
666
684
|
}
|
|
667
685
|
warnOnceOnHeldBackUpdate(ctx, opts, spec, meta, pickedPackage.version);
|
|
668
|
-
const
|
|
669
|
-
|
|
670
|
-
tarball: normalizeRegistryUrl(pickedPackage.dist.tarball),
|
|
671
|
-
};
|
|
686
|
+
const selectedPackage = selectPackageRevision(pickedPackage, spec, registry);
|
|
687
|
+
const resolution = createRegistryTarballResolution(selectedPackage.dist, registry);
|
|
672
688
|
const publishedAt = meta.time?.[pickedPackage.version];
|
|
673
689
|
return {
|
|
674
690
|
id: `${pickedPackage.name}@${pickedPackage.version}`,
|
|
675
691
|
latest: latestAllowedByPolicy(meta, opts),
|
|
676
|
-
manifest:
|
|
692
|
+
manifest: selectedPackage,
|
|
677
693
|
resolution,
|
|
678
694
|
publishedAt,
|
|
679
695
|
policyViolation: detectMinReleaseAgeViolation({
|
|
@@ -690,13 +706,25 @@ async function pickFromSimpleRegistry(ctx, wantedDependency, opts, spec, registr
|
|
|
690
706
|
// when the dependency alias matches the package name). Shared between the
|
|
691
707
|
// jsr and named-registry resolvers since they only differ in `prefix` and
|
|
692
708
|
// which spec field holds the package name.
|
|
693
|
-
function calcPrefixedSpecifier(
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
709
|
+
function calcPrefixedSpecifier(opts) {
|
|
710
|
+
if (opts.revision != null) {
|
|
711
|
+
const target = `${opts.version}+r${opts.revision}`;
|
|
712
|
+
if (!opts.wantedDependency.alias || opts.pkgName === opts.wantedDependency.alias)
|
|
713
|
+
return `${opts.prefix}${target}`;
|
|
714
|
+
return `${opts.prefix}${opts.pkgName}@${target}`;
|
|
715
|
+
}
|
|
716
|
+
const range = calcRange(opts.version, opts.wantedDependency, opts.defaultRangeSpecStyle);
|
|
717
|
+
if (!opts.wantedDependency.alias || opts.pkgName === opts.wantedDependency.alias)
|
|
718
|
+
return `${opts.prefix}${range}`;
|
|
719
|
+
return `${opts.prefix}${opts.pkgName}@${range}`;
|
|
698
720
|
}
|
|
699
721
|
function calcSpecifier({ wantedDependency, spec, version, defaultRangeSpecStyle, }) {
|
|
722
|
+
if (spec.revision != null) {
|
|
723
|
+
const target = `${version}+r${spec.revision}`;
|
|
724
|
+
if (!wantedDependency.alias || spec.name === wantedDependency.alias)
|
|
725
|
+
return target;
|
|
726
|
+
return `npm:${spec.name}@${target}`;
|
|
727
|
+
}
|
|
700
728
|
if (wantedDependency.prevSpecifier === wantedDependency.bareSpecifier && wantedDependency.prevSpecifier && versionSelectorType(wantedDependency.prevSpecifier)?.type === 'tag') {
|
|
701
729
|
return wantedDependency.prevSpecifier;
|
|
702
730
|
}
|
|
@@ -916,6 +944,123 @@ function getIntegrity(dist) {
|
|
|
916
944
|
}
|
|
917
945
|
return integrity.toString();
|
|
918
946
|
}
|
|
947
|
+
function createRegistryTarballResolution(dist, registry) {
|
|
948
|
+
const integrity = getIntegrity(dist);
|
|
949
|
+
const tarball = normalizeRegistryUrl(dist.tarball);
|
|
950
|
+
if (dist.revision == null) {
|
|
951
|
+
return { integrity, tarball };
|
|
952
|
+
}
|
|
953
|
+
if (!isValidTarballRevision(dist.revision)) {
|
|
954
|
+
throw new PnpmError('MALFORMED_METADATA', `Tarball "${redactUrlForDisplay(dist.tarball)}" has an invalid revision in its metadata: ${String(dist.revision)}`);
|
|
955
|
+
}
|
|
956
|
+
if (integrity == null ||
|
|
957
|
+
!isIntegrityAddressedRegistryTarballUrl(tarball, integrity, registry)) {
|
|
958
|
+
throw new PnpmError('MALFORMED_METADATA', `Tarball "${redactUrlForDisplay(dist.tarball)}" has revision ${dist.revision} but is not addressed by its complete integrity.`);
|
|
959
|
+
}
|
|
960
|
+
return {
|
|
961
|
+
integrity,
|
|
962
|
+
revision: dist.revision,
|
|
963
|
+
tarball,
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
const REVISION_MANIFEST_FIELDS = [
|
|
967
|
+
'bin',
|
|
968
|
+
'bundleDependencies',
|
|
969
|
+
'bundledDependencies',
|
|
970
|
+
'cpu',
|
|
971
|
+
'dependencies',
|
|
972
|
+
'engines',
|
|
973
|
+
'hasInstallScript',
|
|
974
|
+
'libc',
|
|
975
|
+
'optionalDependencies',
|
|
976
|
+
'os',
|
|
977
|
+
'peerDependencies',
|
|
978
|
+
'peerDependenciesMeta',
|
|
979
|
+
];
|
|
980
|
+
function selectPackageRevision(pickedPackage, spec, registry) {
|
|
981
|
+
validateCurrentPackageRevision(pickedPackage, registry);
|
|
982
|
+
if (spec.revision == null)
|
|
983
|
+
return pickedPackage;
|
|
984
|
+
const revisions = pickedPackage.dist.revisions;
|
|
985
|
+
if (revisions == null) {
|
|
986
|
+
if (spec.revision === 0 && pickedPackage.dist.revision == null)
|
|
987
|
+
return pickedPackage;
|
|
988
|
+
throw new PnpmError('NO_MATCHING_REVISION', `No revision ${spec.revision} is advertised for ${pickedPackage.name}@${pickedPackage.version}`);
|
|
989
|
+
}
|
|
990
|
+
if (!Array.isArray(revisions)) {
|
|
991
|
+
throw malformedRevisionHistory(pickedPackage, 'the revisions field is not an array');
|
|
992
|
+
}
|
|
993
|
+
const matches = revisions.filter((entry) => isRevisionNumber(entry?.revision) && entry.revision === spec.revision);
|
|
994
|
+
if (matches.length === 0) {
|
|
995
|
+
throw new PnpmError('NO_MATCHING_REVISION', `No revision ${spec.revision} is advertised for ${pickedPackage.name}@${pickedPackage.version}`);
|
|
996
|
+
}
|
|
997
|
+
if (matches.length !== 1) {
|
|
998
|
+
throw malformedRevisionHistory(pickedPackage, `revision ${spec.revision} is advertised more than once`);
|
|
999
|
+
}
|
|
1000
|
+
const selectedRevision = matches[0];
|
|
1001
|
+
validatePackageRevision(pickedPackage, selectedRevision, registry);
|
|
1002
|
+
const selectedPackage = { ...pickedPackage };
|
|
1003
|
+
for (const field of REVISION_MANIFEST_FIELDS) {
|
|
1004
|
+
delete selectedPackage[field];
|
|
1005
|
+
const value = selectedRevision.manifest[field];
|
|
1006
|
+
if (value !== undefined) {
|
|
1007
|
+
selectedPackage[field] = value;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
selectedPackage.dist = {
|
|
1011
|
+
...pickedPackage.dist,
|
|
1012
|
+
integrity: selectedRevision.integrity,
|
|
1013
|
+
tarball: selectedRevision.tarball,
|
|
1014
|
+
};
|
|
1015
|
+
if (spec.revision === 0) {
|
|
1016
|
+
delete selectedPackage.dist.revision;
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
selectedPackage.dist.revision = spec.revision;
|
|
1020
|
+
}
|
|
1021
|
+
return selectedPackage;
|
|
1022
|
+
}
|
|
1023
|
+
function validateCurrentPackageRevision(pickedPackage, registry) {
|
|
1024
|
+
const revision = pickedPackage.dist.revision;
|
|
1025
|
+
if (revision == null)
|
|
1026
|
+
return;
|
|
1027
|
+
if (!isValidTarballRevision(revision)) {
|
|
1028
|
+
throw malformedRevisionHistory(pickedPackage, `current revision ${String(revision)} is not a canonical positive safe integer`);
|
|
1029
|
+
}
|
|
1030
|
+
const revisions = pickedPackage.dist.revisions;
|
|
1031
|
+
if (!Array.isArray(revisions)) {
|
|
1032
|
+
throw malformedRevisionHistory(pickedPackage, 'the current revision has no revision history');
|
|
1033
|
+
}
|
|
1034
|
+
const matches = revisions.filter(entry => entry?.revision === revision);
|
|
1035
|
+
if (matches.length !== 1) {
|
|
1036
|
+
throw malformedRevisionHistory(pickedPackage, `current revision ${revision} does not have exactly one history entry`);
|
|
1037
|
+
}
|
|
1038
|
+
const current = matches[0];
|
|
1039
|
+
validatePackageRevision(pickedPackage, current, registry);
|
|
1040
|
+
if (pickedPackage.dist.integrity !== current.integrity ||
|
|
1041
|
+
normalizeRegistryUrl(pickedPackage.dist.tarball) !== normalizeRegistryUrl(current.tarball)) {
|
|
1042
|
+
throw malformedRevisionHistory(pickedPackage, `revision ${revision} does not match the current artifact`);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
function validatePackageRevision(pickedPackage, revision, registry) {
|
|
1046
|
+
if (!isRevisionNumber(revision.revision)) {
|
|
1047
|
+
throw malformedRevisionHistory(pickedPackage, `revision ${String(revision.revision)} is not a canonical safe integer`);
|
|
1048
|
+
}
|
|
1049
|
+
if (typeof revision.integrity !== 'string' ||
|
|
1050
|
+
typeof revision.tarball !== 'string' ||
|
|
1051
|
+
!isIntegrityAddressedRegistryTarballUrl(normalizeRegistryUrl(revision.tarball), revision.integrity, registry)) {
|
|
1052
|
+
throw malformedRevisionHistory(pickedPackage, `revision ${revision.revision} is not addressed by its complete sha512 integrity`);
|
|
1053
|
+
}
|
|
1054
|
+
if (revision.manifest == null || typeof revision.manifest !== 'object' || Array.isArray(revision.manifest)) {
|
|
1055
|
+
throw malformedRevisionHistory(pickedPackage, `revision ${revision.revision} has an invalid manifest`);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
function isRevisionNumber(revision) {
|
|
1059
|
+
return revision === 0 || isValidTarballRevision(revision);
|
|
1060
|
+
}
|
|
1061
|
+
function malformedRevisionHistory(pickedPackage, reason) {
|
|
1062
|
+
return new PnpmError('MALFORMED_METADATA', `The revision history for ${pickedPackage.name}@${pickedPackage.version} is invalid: ${reason}.`);
|
|
1063
|
+
}
|
|
919
1064
|
/**
|
|
920
1065
|
* Construct the LRU `PackageMetaCache` instance the resolver uses by
|
|
921
1066
|
* default. Exported so the install layer can build one cache and hand
|
|
@@ -2,6 +2,7 @@ export interface RegistryPackageSpec {
|
|
|
2
2
|
type: 'tag' | 'version' | 'range';
|
|
3
3
|
name: string;
|
|
4
4
|
fetchSpec: string;
|
|
5
|
+
revision?: number;
|
|
5
6
|
normalizedBareSpecifier?: string;
|
|
6
7
|
}
|
|
7
8
|
export declare function parseBareSpecifier(bareSpecifier: string, alias: string | undefined, defaultTag: string, registry: string): RegistryPackageSpec | null;
|
|
@@ -31,9 +31,8 @@ export function parseBareSpecifier(bareSpecifier, alias, defaultTag, registry) {
|
|
|
31
31
|
const selector = getVersionSelectorType(bareSpecifier);
|
|
32
32
|
if (selector != null) {
|
|
33
33
|
return {
|
|
34
|
-
|
|
34
|
+
...parseRevisionSelector(selector, bareSpecifier),
|
|
35
35
|
name,
|
|
36
|
-
type: selector.type,
|
|
37
36
|
};
|
|
38
37
|
}
|
|
39
38
|
}
|
|
@@ -58,9 +57,8 @@ export function parseJsrSpecifierToRegistryPackageSpec(rawSpecifier, alias, defa
|
|
|
58
57
|
if (selector == null)
|
|
59
58
|
return null;
|
|
60
59
|
return {
|
|
61
|
-
|
|
60
|
+
...parseRevisionSelector(selector, spec.versionSelector ?? defaultTag),
|
|
62
61
|
name: spec.npmPkgName,
|
|
63
|
-
type: selector.type,
|
|
64
62
|
jsrPkgName: spec.jsrPkgName,
|
|
65
63
|
};
|
|
66
64
|
}
|
|
@@ -132,10 +130,36 @@ export function parseNamedRegistrySpecifierToRegistryPackageSpec(rawSpecifier, k
|
|
|
132
130
|
if (selector == null)
|
|
133
131
|
return null;
|
|
134
132
|
return {
|
|
135
|
-
|
|
133
|
+
...parseRevisionSelector(selector, versionSelector ?? defaultTag),
|
|
136
134
|
name: pkgName,
|
|
137
|
-
type: selector.type,
|
|
138
135
|
registryName,
|
|
139
136
|
};
|
|
140
137
|
}
|
|
138
|
+
function parseRevisionSelector(selector, rawSelector) {
|
|
139
|
+
if (selector.type !== 'version') {
|
|
140
|
+
return { fetchSpec: selector.normalized, type: selector.type };
|
|
141
|
+
}
|
|
142
|
+
const normalizedInput = rawSelector.trim();
|
|
143
|
+
const buildIndex = normalizedInput.indexOf('+');
|
|
144
|
+
if (buildIndex === -1) {
|
|
145
|
+
return { fetchSpec: selector.normalized, type: selector.type };
|
|
146
|
+
}
|
|
147
|
+
const build = normalizedInput.slice(buildIndex + 1);
|
|
148
|
+
if (build.length < 2 || build[0] !== 'r' || build.includes('.')) {
|
|
149
|
+
return { fetchSpec: selector.normalized, type: selector.type };
|
|
150
|
+
}
|
|
151
|
+
const digits = build.slice(1);
|
|
152
|
+
if (![...digits].every((char) => char >= '0' && char <= '9')) {
|
|
153
|
+
return { fetchSpec: selector.normalized, type: selector.type };
|
|
154
|
+
}
|
|
155
|
+
const revision = Number(digits);
|
|
156
|
+
if ((digits.length > 1 && digits[0] === '0') || !Number.isSafeInteger(revision)) {
|
|
157
|
+
throw new PnpmError('INVALID_REVISION_SPEC', `Invalid registry revision in version specifier "${rawSelector}"`);
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
fetchSpec: selector.normalized,
|
|
161
|
+
revision,
|
|
162
|
+
type: selector.type,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
141
165
|
//# sourceMappingURL=parseBareSpecifier.js.map
|
package/lib/violationCodes.d.ts
CHANGED
|
@@ -11,5 +11,6 @@
|
|
|
11
11
|
export declare const MINIMUM_RELEASE_AGE_VIOLATION_CODE = "MINIMUM_RELEASE_AGE_VIOLATION";
|
|
12
12
|
export declare const TRUST_DOWNGRADE_VIOLATION_CODE = "TRUST_DOWNGRADE";
|
|
13
13
|
export declare const TARBALL_URL_MISMATCH_VIOLATION_CODE = "TARBALL_URL_MISMATCH";
|
|
14
|
+
export declare const TARBALL_REVISION_MISMATCH_VIOLATION_CODE = "TARBALL_REVISION_MISMATCH";
|
|
14
15
|
export declare const MISSING_TARBALL_INTEGRITY_VIOLATION_CODE = "MISSING_TARBALL_INTEGRITY";
|
|
15
16
|
export declare const MISSING_NAMED_REGISTRY_VIOLATION_CODE = "MISSING_NAMED_REGISTRY";
|
package/lib/violationCodes.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
export const MINIMUM_RELEASE_AGE_VIOLATION_CODE = 'MINIMUM_RELEASE_AGE_VIOLATION';
|
|
12
12
|
export const TRUST_DOWNGRADE_VIOLATION_CODE = 'TRUST_DOWNGRADE';
|
|
13
13
|
export const TARBALL_URL_MISMATCH_VIOLATION_CODE = 'TARBALL_URL_MISMATCH';
|
|
14
|
+
export const TARBALL_REVISION_MISMATCH_VIOLATION_CODE = 'TARBALL_REVISION_MISMATCH';
|
|
14
15
|
export const MISSING_TARBALL_INTEGRITY_VIOLATION_CODE = 'MISSING_TARBALL_INTEGRITY';
|
|
15
16
|
export const MISSING_NAMED_REGISTRY_VIOLATION_CODE = 'MISSING_NAMED_REGISTRY';
|
|
16
17
|
//# sourceMappingURL=violationCodes.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/resolving.npm-resolver",
|
|
3
|
-
"version": "1104.
|
|
3
|
+
"version": "1104.1.0",
|
|
4
4
|
"description": "Resolver for npm-hosted packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -29,24 +29,25 @@
|
|
|
29
29
|
"!*.map"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@pnpm/config.normalize-registries": "1101.0.
|
|
33
|
-
"@pnpm/config.pick-registry-for-package": "1101.0.
|
|
34
|
-
"@pnpm/config.version-policy": "1100.2.
|
|
32
|
+
"@pnpm/config.normalize-registries": "1101.0.1",
|
|
33
|
+
"@pnpm/config.pick-registry-for-package": "1101.0.1",
|
|
34
|
+
"@pnpm/config.version-policy": "1100.2.2",
|
|
35
35
|
"@pnpm/constants": "1102.0.0",
|
|
36
|
-
"@pnpm/core-loggers": "1100.3.
|
|
37
|
-
"@pnpm/crypto.hash": "1100.0.
|
|
38
|
-
"@pnpm/deps.path": "1101.0.
|
|
36
|
+
"@pnpm/core-loggers": "1100.3.4",
|
|
37
|
+
"@pnpm/crypto.hash": "1100.0.3",
|
|
38
|
+
"@pnpm/deps.path": "1101.0.1",
|
|
39
39
|
"@pnpm/error": "1100.1.3",
|
|
40
40
|
"@pnpm/fetching.types": "1100.0.3",
|
|
41
|
-
"@pnpm/fs.graceful-fs": "1100.
|
|
42
|
-
"@pnpm/pkg-manifest.utils": "1100.4.
|
|
41
|
+
"@pnpm/fs.graceful-fs": "1100.2.0",
|
|
42
|
+
"@pnpm/pkg-manifest.utils": "1100.4.2",
|
|
43
43
|
"@pnpm/resolving.jsr-specifier-parser": "1100.0.6",
|
|
44
|
-
"@pnpm/resolving.registry.pkg-metadata-filter": "1100.0.
|
|
45
|
-
"@pnpm/resolving.registry.types": "1100.
|
|
46
|
-
"@pnpm/resolving.resolver-base": "1101.
|
|
47
|
-
"@pnpm/
|
|
48
|
-
"@pnpm/store.
|
|
49
|
-
"@pnpm/
|
|
44
|
+
"@pnpm/resolving.registry.pkg-metadata-filter": "1100.0.18",
|
|
45
|
+
"@pnpm/resolving.registry.types": "1100.2.0",
|
|
46
|
+
"@pnpm/resolving.resolver-base": "1101.2.0",
|
|
47
|
+
"@pnpm/resolving.tarball-url": "1101.1.0",
|
|
48
|
+
"@pnpm/store.cafs": "1100.3.0",
|
|
49
|
+
"@pnpm/store.index": "1100.3.0",
|
|
50
|
+
"@pnpm/types": "1102.1.0",
|
|
50
51
|
"@pnpm/workspace.range-resolver": "1100.0.3",
|
|
51
52
|
"@pnpm/workspace.spec-parser": "1100.0.1",
|
|
52
53
|
"@zkochan/retry": "^0.2.0",
|
|
@@ -65,13 +66,13 @@
|
|
|
65
66
|
},
|
|
66
67
|
"peerDependencies": {
|
|
67
68
|
"@pnpm/logger": "^1100.0.0",
|
|
68
|
-
"@pnpm/worker": "^1100.
|
|
69
|
+
"@pnpm/worker": "^1100.4.0"
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
|
71
72
|
"@jest/globals": "30.4.1",
|
|
72
73
|
"@pnpm/logger": "1100.0.0",
|
|
73
|
-
"@pnpm/network.fetch": "1100.1.
|
|
74
|
-
"@pnpm/resolving.npm-resolver": "1104.
|
|
74
|
+
"@pnpm/network.fetch": "1100.1.14",
|
|
75
|
+
"@pnpm/resolving.npm-resolver": "1104.1.0",
|
|
75
76
|
"@pnpm/test-fixtures": "1100.0.1",
|
|
76
77
|
"@pnpm/testing.mock-agent": "1101.0.7",
|
|
77
78
|
"@types/normalize-path": "^3.0.2",
|