@pnpm/resolving.npm-resolver 1103.1.0 → 1103.2.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/CHANGELOG.md +29 -0
- package/lib/createNpmResolutionVerifier.d.ts +5 -0
- package/lib/createNpmResolutionVerifier.js +12 -6
- package/lib/fetchFullMetadataCached.d.ts +4 -0
- package/lib/fetchFullMetadataCached.js +9 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.js +19 -13
- package/lib/pickPackage.js +9 -7
- package/lib/pickPackageFromMeta.d.ts +23 -0
- package/lib/pickPackageFromMeta.js +35 -20
- package/package.json +12 -13
- package/lib/inferRangeSpecStyle.d.ts +0 -2
- package/lib/inferRangeSpecStyle.js +0 -39
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @pnpm/npm-resolver
|
|
2
2
|
|
|
3
|
+
## 1103.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- `pnpm add` no longer re-resolves the dependency graph when `pnpm-lock.yaml` already holds a version satisfying the request — promoting a transitive dependency to a direct one, or adding to a second workspace package what a first one already depends on, now only saves the dependency in `package.json` and records its importer entry. A satisfying locked version is necessary but not sufficient: the install still falls back to a full resolution for a dist tag, an alias, a `workspace:`/`catalog:`/git/tarball specifier, `--save-peer`, an overridden package, a `catalogMode` other than `manual`, and — under `resolutionMode: time-based` or `lowest-direct`, which resolve a direct dependency to the low end of its range — a range several locked versions satisfy.
|
|
8
|
+
|
|
9
|
+
- `resolutionMode` is no longer ignored when `minimumReleaseAge` is in effect. `lowest-direct` and `time-based` pick the lowest satisfying version of a direct dependency again; previously any active release-age cutoff — including the built-in default — silently forced the highest, so `resolutionMode` only worked when `minimumReleaseAge: 0` was set explicitly [#13752](https://github.com/pnpm/pnpm/issues/13752).
|
|
10
|
+
|
|
11
|
+
- Updated dependencies:
|
|
12
|
+
- @pnpm/config.version-policy@1100.2.0
|
|
13
|
+
- @pnpm/error@1100.1.2
|
|
14
|
+
- @pnpm/pkg-manifest.utils@1100.4.0
|
|
15
|
+
- @pnpm/resolving.jsr-specifier-parser@1100.0.5
|
|
16
|
+
- @pnpm/store.cafs@1100.1.19
|
|
17
|
+
- @pnpm/store.index@1100.2.4
|
|
18
|
+
|
|
19
|
+
## 1103.2.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- Lockfile verification now honors offline mode by using cached registry metadata instead of reaching the registry. When the required metadata is not available locally, verification reports the same `ERR_PNPM_NO_OFFLINE_META` condition used by offline resolution.
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- The held-back-update warning printed by `pnpm update` no longer fires when `minimumReleaseAge` is the actual reason a newer version was not picked. The warning's baseline now applies the same maturity cutoff as the pick itself, so it no longer wrongly attributes the hold-back to "your manifests and already installed dependencies" or recommends an override that would defeat the age gate. See pnpm/pnpm#13071.
|
|
28
|
+
|
|
29
|
+
- Updated dependencies:
|
|
30
|
+
- @pnpm/resolving.registry.pkg-metadata-filter@1100.0.16
|
|
31
|
+
|
|
3
32
|
## 1103.1.0
|
|
4
33
|
|
|
5
34
|
### Minor Changes
|
|
@@ -58,6 +58,11 @@ export interface CreateNpmResolutionVerifierOptions {
|
|
|
58
58
|
fetchOpts: FetchMetadataFromFromRegistryOptions;
|
|
59
59
|
getAuthHeaderValueByURI: GetAuthHeader;
|
|
60
60
|
cacheDir?: FetchFullMetadataCachedOptions['cacheDir'];
|
|
61
|
+
/**
|
|
62
|
+
* When true, verifier metadata lookups must use the local mirror
|
|
63
|
+
* only and never reach the registry or attestation endpoint.
|
|
64
|
+
*/
|
|
65
|
+
offline?: boolean;
|
|
61
66
|
/**
|
|
62
67
|
* Per-install LRU shared with the npm resolver's `pickPackage`
|
|
63
68
|
* (`{ get, set }` over `PackageMeta`). When provided, the verifier
|
|
@@ -53,6 +53,7 @@ export function createNpmResolutionVerifier(opts) {
|
|
|
53
53
|
fetchOpts: opts.fetchOpts,
|
|
54
54
|
getAuthHeaderValueByURI: opts.getAuthHeaderValueByURI,
|
|
55
55
|
cacheDir: opts.cacheDir,
|
|
56
|
+
offline: opts.offline === true,
|
|
56
57
|
cutoffMs: cutoff,
|
|
57
58
|
sharedMetaCache: opts.metaCache,
|
|
58
59
|
abbreviatedMetaCache: new Map(),
|
|
@@ -391,6 +392,7 @@ function fetchFullMetaForTrust(context, registry, name) {
|
|
|
391
392
|
registry,
|
|
392
393
|
authHeaderValue: context.getAuthHeaderValueByURI(registry, { pkgName: name }),
|
|
393
394
|
cacheDir: context.cacheDir,
|
|
395
|
+
offline: context.offline,
|
|
394
396
|
}).then(projectTrustMeta);
|
|
395
397
|
}
|
|
396
398
|
context.fullMetaForTrustCache.set(cacheKey, cachedPromise);
|
|
@@ -485,12 +487,14 @@ async function resolvePublishedAt(context, registry, name, version) {
|
|
|
485
487
|
const localTime = await readLocalMetaTime(context, registry, name);
|
|
486
488
|
if (localTime?.[version])
|
|
487
489
|
return localTime[version];
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
490
|
+
if (!context.offline) {
|
|
491
|
+
const attestationTime = await fetchAttestationPublishedAt(context.fetchOpts, name, version, {
|
|
492
|
+
registry,
|
|
493
|
+
authHeaderValue: context.getAuthHeaderValueByURI(registry, { pkgName: name }),
|
|
494
|
+
});
|
|
495
|
+
if (attestationTime != null)
|
|
496
|
+
return attestationTime;
|
|
497
|
+
}
|
|
494
498
|
const fullMetaTime = await fetchFullMetaTime(context, registry, name);
|
|
495
499
|
return fullMetaTime?.[version];
|
|
496
500
|
}
|
|
@@ -555,6 +559,7 @@ function fetchAbbreviatedMeta(context, registry, name) {
|
|
|
555
559
|
registry,
|
|
556
560
|
authHeaderValue: context.getAuthHeaderValueByURI(registry, { pkgName: name }),
|
|
557
561
|
cacheDir: context.cacheDir,
|
|
562
|
+
offline: context.offline,
|
|
558
563
|
}).then((meta) => ({ meta: projectAbbreviatedMeta(meta) }), (error) => ({ error }));
|
|
559
564
|
}
|
|
560
565
|
context.abbreviatedMetaCache.set(cacheKey, cachedPromise);
|
|
@@ -646,6 +651,7 @@ function fetchFullMetaTime(context, registry, name) {
|
|
|
646
651
|
registry,
|
|
647
652
|
authHeaderValue: context.getAuthHeaderValueByURI(registry, { pkgName: name }),
|
|
648
653
|
cacheDir: context.cacheDir,
|
|
654
|
+
offline: context.offline,
|
|
649
655
|
}).then((meta) => meta.time);
|
|
650
656
|
context.fullMetaCache.set(cacheKey, cachedPromise);
|
|
651
657
|
}
|
|
@@ -10,6 +10,10 @@ export interface FetchMetadataCachedOptions {
|
|
|
10
10
|
* back. Omit to disable caching — every call re-fetches.
|
|
11
11
|
*/
|
|
12
12
|
cacheDir?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Use only pnpm's on-disk metadata mirror and never reach the registry.
|
|
15
|
+
*/
|
|
16
|
+
offline?: boolean;
|
|
13
17
|
}
|
|
14
18
|
export type FetchFullMetadataCachedOptions = FetchMetadataCachedOptions;
|
|
15
19
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ABBREVIATED_META_DIR, FULL_META_DIR } from '@pnpm/constants';
|
|
2
|
+
import { PnpmError } from '@pnpm/error';
|
|
2
3
|
import { fetchMetadataFromFromRegistry, } from './fetch.js';
|
|
3
4
|
import { getPkgMirrorPath, loadMeta, loadMetaHeaders, prepareJsonForDisk, saveMeta } from './pickPackage.js';
|
|
4
5
|
/**
|
|
@@ -28,6 +29,14 @@ async function fetchMetadataCached(fetchOpts, pkgName, opts) {
|
|
|
28
29
|
const pkgMirror = opts.cacheDir != null
|
|
29
30
|
? getPkgMirrorPath(opts.cacheDir, opts.metaDir, opts.registry, pkgName)
|
|
30
31
|
: null;
|
|
32
|
+
if (opts.offline === true) {
|
|
33
|
+
if (pkgMirror != null) {
|
|
34
|
+
const cached = await loadMeta(pkgMirror);
|
|
35
|
+
if (cached != null)
|
|
36
|
+
return cached;
|
|
37
|
+
}
|
|
38
|
+
throw new PnpmError('NO_OFFLINE_META', `Failed to resolve ${pkgName} in package mirror ${pkgMirror ?? ''}`);
|
|
39
|
+
}
|
|
31
40
|
const cacheHeaders = pkgMirror != null ? await loadMetaHeaders(pkgMirror) : null;
|
|
32
41
|
const conditional = await fetchMetadataFromFromRegistry(fetchOpts, pkgName, {
|
|
33
42
|
registry: opts.registry,
|
package/lib/index.d.ts
CHANGED
|
@@ -20,7 +20,6 @@ export declare class NoMatchingVersionError extends PnpmError {
|
|
|
20
20
|
export declare function formatTimeAgo(date: Date): string | null;
|
|
21
21
|
export { BUILTIN_NAMED_REGISTRIES, fetchMetadataFromFromRegistry, type FetchMetadataFromFromRegistryOptions, type PackageMeta, type PackageMetaCache, parseBareSpecifier, pickPackageFromMeta, pickVersionByVersionRange, type RegistryPackageSpec, RegistryResponseError, workspacePrefToNpm, };
|
|
22
22
|
export { createNpmResolutionVerifier, type CreateNpmResolutionVerifierOptions } from './createNpmResolutionVerifier.js';
|
|
23
|
-
export { inferRangeSpecStyle } from './inferRangeSpecStyle.js';
|
|
24
23
|
export { MINIMUM_RELEASE_AGE_VIOLATION_CODE, TRUST_DOWNGRADE_VIOLATION_CODE, } from './violationCodes.js';
|
|
25
24
|
export interface ResolverFactoryOptions {
|
|
26
25
|
cacheDir: string;
|
package/lib/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
|
|
|
3
3
|
import { isWellFormedRegistryName, RESERVED_VERSION_PREFIXES } from '@pnpm/deps.path';
|
|
4
4
|
import { PnpmError } from '@pnpm/error';
|
|
5
5
|
import { globalWarn } from '@pnpm/logger';
|
|
6
|
-
import { rangeSpecGranularity, versionWithRangeSpecStyle } from '@pnpm/pkg-manifest.utils';
|
|
6
|
+
import { calcVersionRange, inferRangeSpecStyle, rangeSpecGranularity, versionWithRangeSpecStyle } from '@pnpm/pkg-manifest.utils';
|
|
7
7
|
import { EXISTING_VERSION_SELECTOR_WEIGHT, } from '@pnpm/resolving.resolver-base';
|
|
8
8
|
import { storeIndexKey } from '@pnpm/store.index';
|
|
9
9
|
import { readPkgFromCafs, } from '@pnpm/worker';
|
|
@@ -16,12 +16,11 @@ import ssri from 'ssri';
|
|
|
16
16
|
import versionSelectorType from 'version-selector-type';
|
|
17
17
|
import { clearMeta, retainsFullMeta } from './clearMeta.js';
|
|
18
18
|
import { fetchMetadataFromFromRegistry, RegistryResponseError } from './fetch.js';
|
|
19
|
-
import { inferRangeSpecStyle } from './inferRangeSpecStyle.js';
|
|
20
19
|
import { memoizeFetchMetadata } from './memoizeFetchMetadata.js';
|
|
21
20
|
import { normalizeRegistryUrl } from './normalizeRegistryUrl.js';
|
|
22
21
|
import { BUILTIN_NAMED_REGISTRIES, parseBareSpecifier, parseJsrSpecifierToRegistryPackageSpec, parseNamedRegistrySpecifierToRegistryPackageSpec, } from './parseBareSpecifier.js';
|
|
23
22
|
import { pickPackage, } from './pickPackage.js';
|
|
24
|
-
import { pickPackageFromMeta, pickVersionByVersionRange } from './pickPackageFromMeta.js';
|
|
23
|
+
import { applyPublishedByPolicy, pickPackageFromMeta, pickVersionByVersionRange } from './pickPackageFromMeta.js';
|
|
25
24
|
import { failIfTrustDowngraded } from './trustChecks.js';
|
|
26
25
|
import { MINIMUM_RELEASE_AGE_VIOLATION_CODE } from './violationCodes.js';
|
|
27
26
|
import { workspacePrefToNpm } from './workspacePrefToNpm.js';
|
|
@@ -66,7 +65,6 @@ export function formatTimeAgo(date) {
|
|
|
66
65
|
}
|
|
67
66
|
export { BUILTIN_NAMED_REGISTRIES, fetchMetadataFromFromRegistry, parseBareSpecifier, pickPackageFromMeta, pickVersionByVersionRange, RegistryResponseError, workspacePrefToNpm, };
|
|
68
67
|
export { createNpmResolutionVerifier } from './createNpmResolutionVerifier.js';
|
|
69
|
-
export { inferRangeSpecStyle } from './inferRangeSpecStyle.js';
|
|
70
68
|
export { MINIMUM_RELEASE_AGE_VIOLATION_CODE, TRUST_DOWNGRADE_VIOLATION_CODE, } from './violationCodes.js';
|
|
71
69
|
export function createNpmResolver(fetchFromRegistry, getAuthHeader, opts) {
|
|
72
70
|
if (typeof opts.cacheDir !== 'string') {
|
|
@@ -212,7 +210,10 @@ function stripLockfileVersionPins(selectors) {
|
|
|
212
210
|
* The baseline for "held back" is the pick with only the non-pin selectors
|
|
213
211
|
* applied — `range`/`tag` selectors such as the `pnpm audit --fix`
|
|
214
212
|
* vulnerability penalties steer the baseline too, so the warning never
|
|
215
|
-
* recommends a version those selectors avoid.
|
|
213
|
+
* recommends a version those selectors avoid. The baseline also honors the
|
|
214
|
+
* `publishedBy` maturity cutoff the actual pick applied: a version blocked
|
|
215
|
+
* by `minimumReleaseAge` is not an update the manifests held back, and
|
|
216
|
+
* recommending an override for it would defeat the age gate.
|
|
216
217
|
*
|
|
217
218
|
* The recommended override is scoped to the declared range being resolved
|
|
218
219
|
* (`name@<range>`), so applying it can never violate any consumer's range:
|
|
@@ -233,8 +234,14 @@ function warnOnceOnHeldBackUpdate(ctx, opts, spec, meta, pickedVersion) {
|
|
|
233
234
|
nonPinSelectors ??= Object.create(null);
|
|
234
235
|
nonPinSelectors[selector] = value;
|
|
235
236
|
}
|
|
237
|
+
// `needsFullMetadata` is not this caller's problem: the pick already
|
|
238
|
+
// succeeded on this metadata, which for an abbreviated packument means
|
|
239
|
+
// every version cleared the cutoff, so `meta` is the filtered view.
|
|
240
|
+
const baselineMeta = opts.publishedBy != null
|
|
241
|
+
? applyPublishedByPolicy(meta, opts.publishedBy, opts.publishedByExclude).meta
|
|
242
|
+
: meta;
|
|
236
243
|
const preferred = pickVersionByVersionRange({
|
|
237
|
-
meta,
|
|
244
|
+
meta: baselineMeta,
|
|
238
245
|
versionRange: spec.fetchSpec,
|
|
239
246
|
preferredVersionSelectors: nonPinSelectors,
|
|
240
247
|
});
|
|
@@ -657,14 +664,13 @@ function calcSpecifier({ wantedDependency, spec, version, defaultRangeSpecStyle,
|
|
|
657
664
|
return range;
|
|
658
665
|
return `npm:${spec.name}@${range}`;
|
|
659
666
|
}
|
|
667
|
+
/** The manifest range `version` is saved as; see {@link calcVersionRange}. */
|
|
660
668
|
function calcRange(version, wantedDependency, defaultRangeSpecStyle) {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
defaultRangeSpecStyle;
|
|
667
|
-
return versionWithRangeSpecStyle(version, rangeSpecStyle ?? 'major');
|
|
669
|
+
return calcVersionRange(version, {
|
|
670
|
+
prevSpecifier: wantedDependency.prevSpecifier,
|
|
671
|
+
bareSpecifier: wantedDependency.bareSpecifier,
|
|
672
|
+
defaultRangeSpecStyle,
|
|
673
|
+
});
|
|
668
674
|
}
|
|
669
675
|
function tryResolveFromWorkspace(wantedDependency, opts) {
|
|
670
676
|
if (!wantedDependency.bareSpecifier?.startsWith('workspace:')) {
|
package/lib/pickPackage.js
CHANGED
|
@@ -58,15 +58,17 @@ function pickMax(a, b) {
|
|
|
58
58
|
}
|
|
59
59
|
const pickHighest = pickPackageFromMeta.bind(null, pickVersionByVersionRange);
|
|
60
60
|
const pickLowest = pickPackageFromMeta.bind(null, pickLowestVersionByVersionRange);
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
61
|
+
// `minimumReleaseAge` narrows which versions are on offer; `pickLowestVersion`
|
|
62
|
+
// decides which end of what is left to take. The fallback deliberately drops
|
|
63
|
+
// the maturity filter so a range no mature version satisfies still yields a
|
|
64
|
+
// pick, which the install layer reports as a violation rather than this layer
|
|
65
|
+
// throwing.
|
|
65
66
|
function pickRespectingMinReleaseAge(pickerOpts, spec, meta) {
|
|
66
67
|
return runPicker(pickerOpts, spec, (targetSpec) => {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
const pickMature = pickerOpts.pickLowestVersion ? pickLowest : pickHighest;
|
|
69
|
+
const mature = pickMature(pickerOpts, meta, targetSpec);
|
|
70
|
+
if (mature)
|
|
71
|
+
return mature;
|
|
70
72
|
return pickLowest({
|
|
71
73
|
preferredVersionSelectors: pickerOpts.preferredVersionSelectors,
|
|
72
74
|
}, meta, targetSpec);
|
|
@@ -15,6 +15,29 @@ export interface PickPackageFromMetaOptions {
|
|
|
15
15
|
publishedByExclude?: PackageVersionPolicy;
|
|
16
16
|
}
|
|
17
17
|
export declare function pickPackageFromMeta(pickVersionByVersionRangeFn: PickVersionByVersionRange, { preferredVersionSelectors, publishedBy, publishedByExclude, }: PickPackageFromMetaOptions, meta: PackageMeta, spec: RegistryPackageSpec): PackageInRegistry | null;
|
|
18
|
+
export interface PublishedByView {
|
|
19
|
+
/** The metadata the cutoff leaves visible. `meta` itself when nothing is filtered out. */
|
|
20
|
+
meta: PackageMeta;
|
|
21
|
+
/**
|
|
22
|
+
* The cutoff could not be applied: the metadata is abbreviated, so there
|
|
23
|
+
* are no per-version timestamps to filter on. Whether that is fatal is the
|
|
24
|
+
* caller's call — the pick needs full metadata to honor the cutoff, while a
|
|
25
|
+
* caller reasoning about a pick that already succeeded knows the versions
|
|
26
|
+
* cleared the cutoff some other way.
|
|
27
|
+
*/
|
|
28
|
+
needsFullMetadata: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Narrows `meta` to the versions the `publishedBy` cutoff admits, honoring
|
|
32
|
+
* `publishedByExclude`: a package the policy excludes wholesale keeps its
|
|
33
|
+
* unfiltered metadata, and versions the policy names explicitly stay in
|
|
34
|
+
* regardless of their age.
|
|
35
|
+
*
|
|
36
|
+
* Every consumer of the cutoff goes through here so they agree on what the
|
|
37
|
+
* policy admits — a baseline that filters differently from the pick would
|
|
38
|
+
* misreport why a version was chosen.
|
|
39
|
+
*/
|
|
40
|
+
export declare function applyPublishedByPolicy(meta: PackageMeta, publishedBy: Date, publishedByExclude?: PackageVersionPolicy): PublishedByView;
|
|
18
41
|
export declare function assertMetaHasTime(meta: PackageMeta): asserts meta is PackageMetaWithTime;
|
|
19
42
|
export declare function pickLowestVersionByVersionRange({ meta, versionRange, preferredVersionSelectors }: PickVersionByVersionRangeOptions): string | null;
|
|
20
43
|
export declare function pickVersionByVersionRange({ meta, versionRange, preferredVersionSelectors }: PickVersionByVersionRangeOptions): string | null;
|
|
@@ -4,28 +4,20 @@ import { filterPkgMetadataByPublishDate } from '@pnpm/resolving.registry.pkg-met
|
|
|
4
4
|
import semver from 'semver';
|
|
5
5
|
export function pickPackageFromMeta(pickVersionByVersionRangeFn, { preferredVersionSelectors, publishedBy, publishedByExclude, }, meta, spec) {
|
|
6
6
|
if (publishedBy) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const view = applyPublishedByPolicy(meta, publishedBy, publishedByExclude);
|
|
8
|
+
meta = view.meta;
|
|
9
|
+
if (view.needsFullMetadata) {
|
|
10
|
+
const modifiedDate = parseModifiedDate(meta.modified);
|
|
11
|
+
if (modifiedDate == null || modifiedDate > publishedBy) {
|
|
12
|
+
// The package was modified after the cutoff (or carries no usable
|
|
13
|
+
// `modified`), so which of its versions are mature is unknowable
|
|
14
|
+
// from abbreviated metadata. The error tells the caller to refetch.
|
|
11
15
|
assertMetaHasTime(meta);
|
|
12
|
-
const trustedVersions = Array.isArray(excludeResult) ? excludeResult : undefined;
|
|
13
|
-
meta = filterPkgMetadataByPublishDate(meta, publishedBy, trustedVersions);
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
const modifiedDate = parseModifiedDate(meta.modified);
|
|
17
|
-
if (modifiedDate == null || modifiedDate > publishedBy) {
|
|
18
|
-
// Abbreviated metadata without per-version timestamps, and the package
|
|
19
|
-
// was recently modified (or has no/invalid modified field). We cannot determine
|
|
20
|
-
// which individual versions are mature enough — need full metadata.
|
|
21
|
-
assertMetaHasTime(meta);
|
|
22
|
-
}
|
|
23
|
-
// else: meta.modified <= publishedBy — every version was published at or
|
|
24
|
-
// before the cutoff (modified is an upper bound on per-version time), so
|
|
25
|
-
// they all pass the per-version `<=` maturity filter and no filtering is
|
|
26
|
-
// needed. Inclusive at the boundary on purpose so this branch matches the
|
|
27
|
-
// per-version filter in `filterPkgMetadataByPublishDate`.
|
|
28
16
|
}
|
|
17
|
+
// else: `modified` is an upper bound on every per-version timestamp, so
|
|
18
|
+
// `modified <= publishedBy` means they all pass the maturity filter and
|
|
19
|
+
// nothing would be dropped. Inclusive at the boundary on purpose, to
|
|
20
|
+
// match the per-version `<=` in `filterPkgMetadataByPublishDate`.
|
|
29
21
|
}
|
|
30
22
|
}
|
|
31
23
|
if ((!meta.versions || Object.keys(meta.versions).length === 0) && !publishedBy) {
|
|
@@ -77,6 +69,29 @@ export function pickPackageFromMeta(pickVersionByVersionRangeFn, { preferredVers
|
|
|
77
69
|
throw new PnpmError('MALFORMED_METADATA', `Received malformed metadata for "${spec.name}"`, { hint: 'This might mean that the package was unpublished from the registry', cause: err });
|
|
78
70
|
}
|
|
79
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Narrows `meta` to the versions the `publishedBy` cutoff admits, honoring
|
|
74
|
+
* `publishedByExclude`: a package the policy excludes wholesale keeps its
|
|
75
|
+
* unfiltered metadata, and versions the policy names explicitly stay in
|
|
76
|
+
* regardless of their age.
|
|
77
|
+
*
|
|
78
|
+
* Every consumer of the cutoff goes through here so they agree on what the
|
|
79
|
+
* policy admits — a baseline that filters differently from the pick would
|
|
80
|
+
* misreport why a version was chosen.
|
|
81
|
+
*/
|
|
82
|
+
export function applyPublishedByPolicy(meta, publishedBy, publishedByExclude) {
|
|
83
|
+
const excludeResult = publishedByExclude?.(meta.name) ?? false;
|
|
84
|
+
if (excludeResult === true)
|
|
85
|
+
return { meta, needsFullMetadata: false };
|
|
86
|
+
if (meta.time == null)
|
|
87
|
+
return { meta, needsFullMetadata: true };
|
|
88
|
+
assertMetaHasTime(meta);
|
|
89
|
+
const trustedVersions = Array.isArray(excludeResult) ? excludeResult : undefined;
|
|
90
|
+
return {
|
|
91
|
+
meta: filterPkgMetadataByPublishDate(meta, publishedBy, trustedVersions),
|
|
92
|
+
needsFullMetadata: false,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
80
95
|
export function assertMetaHasTime(meta) {
|
|
81
96
|
if (meta.time == null) {
|
|
82
97
|
throw new PnpmError('MISSING_TIME', `The metadata of ${meta.name} is missing the "time" field`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/resolving.npm-resolver",
|
|
3
|
-
"version": "1103.1
|
|
3
|
+
"version": "1103.2.1",
|
|
4
4
|
"description": "Resolver for npm-hosted packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -31,21 +31,21 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@pnpm/config.normalize-registries": "1100.1.0",
|
|
33
33
|
"@pnpm/config.pick-registry-for-package": "1100.1.0",
|
|
34
|
-
"@pnpm/config.version-policy": "1100.
|
|
34
|
+
"@pnpm/config.version-policy": "1100.2.0",
|
|
35
35
|
"@pnpm/constants": "1101.0.0",
|
|
36
36
|
"@pnpm/core-loggers": "1100.3.2",
|
|
37
37
|
"@pnpm/crypto.hash": "1100.0.2",
|
|
38
38
|
"@pnpm/deps.path": "1100.1.0",
|
|
39
|
-
"@pnpm/error": "1100.1.
|
|
39
|
+
"@pnpm/error": "1100.1.2",
|
|
40
40
|
"@pnpm/fetching.types": "1100.0.3",
|
|
41
41
|
"@pnpm/fs.graceful-fs": "1100.1.1",
|
|
42
|
-
"@pnpm/pkg-manifest.utils": "1100.
|
|
43
|
-
"@pnpm/resolving.jsr-specifier-parser": "1100.0.
|
|
44
|
-
"@pnpm/resolving.registry.pkg-metadata-filter": "1100.0.
|
|
42
|
+
"@pnpm/pkg-manifest.utils": "1100.4.0",
|
|
43
|
+
"@pnpm/resolving.jsr-specifier-parser": "1100.0.5",
|
|
44
|
+
"@pnpm/resolving.registry.pkg-metadata-filter": "1100.0.16",
|
|
45
45
|
"@pnpm/resolving.registry.types": "1100.1.9",
|
|
46
46
|
"@pnpm/resolving.resolver-base": "1101.1.0",
|
|
47
|
-
"@pnpm/store.cafs": "1100.1.
|
|
48
|
-
"@pnpm/store.index": "1100.2.
|
|
47
|
+
"@pnpm/store.cafs": "1100.1.19",
|
|
48
|
+
"@pnpm/store.index": "1100.2.4",
|
|
49
49
|
"@pnpm/types": "1101.9.0",
|
|
50
50
|
"@pnpm/workspace.range-resolver": "1100.0.3",
|
|
51
51
|
"@pnpm/workspace.spec-parser": "1100.0.1",
|
|
@@ -59,25 +59,24 @@
|
|
|
59
59
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
60
60
|
"rename-overwrite": "^7.0.1",
|
|
61
61
|
"semver": "^7.8.5",
|
|
62
|
-
"semver-utils": "^1.1.4",
|
|
63
62
|
"ssri": "13.0.1",
|
|
64
63
|
"validate-npm-package-name": "7.0.2",
|
|
65
64
|
"version-selector-type": "^3.0.0"
|
|
66
65
|
},
|
|
67
66
|
"peerDependencies": {
|
|
68
67
|
"@pnpm/logger": "^1100.0.0",
|
|
69
|
-
"@pnpm/worker": "^1100.2.
|
|
68
|
+
"@pnpm/worker": "^1100.2.11"
|
|
70
69
|
},
|
|
71
70
|
"devDependencies": {
|
|
72
71
|
"@jest/globals": "30.4.1",
|
|
73
72
|
"@pnpm/logger": "1100.0.0",
|
|
74
|
-
"@pnpm/network.fetch": "1100.1.
|
|
75
|
-
"@pnpm/resolving.npm-resolver": "1103.1
|
|
73
|
+
"@pnpm/network.fetch": "1100.1.12",
|
|
74
|
+
"@pnpm/resolving.npm-resolver": "1103.2.1",
|
|
76
75
|
"@pnpm/test-fixtures": "1100.0.1",
|
|
77
76
|
"@pnpm/testing.mock-agent": "1101.0.7",
|
|
78
77
|
"@types/normalize-path": "^3.0.2",
|
|
79
78
|
"@types/ramda": "0.32.0",
|
|
80
|
-
"@types/semver": "7.
|
|
79
|
+
"@types/semver": "7.8.0",
|
|
81
80
|
"@types/ssri": "^7.1.5",
|
|
82
81
|
"@types/validate-npm-package-name": "^4.0.2",
|
|
83
82
|
"load-json-file": "^7.0.1",
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { parseRange } from 'semver-utils';
|
|
2
|
-
export function inferRangeSpecStyle(spec) {
|
|
3
|
-
// A catalog reference carries no version pinning of its own; the pinning is
|
|
4
|
-
// defined by the catalog entry it points to. Bail out so a catalog name that
|
|
5
|
-
// happens to look like a version (e.g. "catalog:express4-21") isn't misread
|
|
6
|
-
// as a pinned version.
|
|
7
|
-
if (spec.startsWith('catalog:'))
|
|
8
|
-
return undefined;
|
|
9
|
-
const colonIndex = spec.indexOf(':');
|
|
10
|
-
if (colonIndex !== -1) {
|
|
11
|
-
spec = spec.substring(colonIndex + 1);
|
|
12
|
-
}
|
|
13
|
-
const index = spec.lastIndexOf('@');
|
|
14
|
-
if (index !== -1) {
|
|
15
|
-
spec = spec.slice(index + 1);
|
|
16
|
-
}
|
|
17
|
-
if (spec === '*')
|
|
18
|
-
return 'none';
|
|
19
|
-
const parsedRange = parseRange(spec);
|
|
20
|
-
if (parsedRange.length !== 1)
|
|
21
|
-
return undefined;
|
|
22
|
-
const versionObject = parsedRange[0];
|
|
23
|
-
switch (versionObject.operator) {
|
|
24
|
-
case '~': return 'minor';
|
|
25
|
-
case '^': return 'major';
|
|
26
|
-
// A bare '=' before a full version is an explicit exact pin; a partial
|
|
27
|
-
// '=' pins the same way the plain version it prefixes does.
|
|
28
|
-
case '=':
|
|
29
|
-
case undefined:
|
|
30
|
-
if (versionObject.patch)
|
|
31
|
-
return versionObject.operator === '=' ? 'exact' : 'patch';
|
|
32
|
-
if (versionObject.minor)
|
|
33
|
-
return 'minor';
|
|
34
|
-
if (versionObject.major)
|
|
35
|
-
return 'major';
|
|
36
|
-
}
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
//# sourceMappingURL=inferRangeSpecStyle.js.map
|