@pnpm/resolving.npm-resolver 1102.1.2 → 1102.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/fetch.d.ts DELETED
@@ -1,37 +0,0 @@
1
- import { FetchError, type FetchErrorRequest, type FetchErrorResponse } from '@pnpm/error';
2
- import type { FetchFromRegistry, RetryTimeoutOptions } from '@pnpm/fetching.types';
3
- import type { PackageMeta } from '@pnpm/resolving.registry.types';
4
- export interface FetchMetadataResult {
5
- meta: PackageMeta;
6
- /**
7
- * The raw registry response body, used only to mirror the response to disk
8
- * without re-serializing `meta`. A fresh fetch always sets it, but it
9
- * reaches only the caller that initiated the request: the phase-long memo
10
- * cache holds a body-less clone (see memoizeFetchMetadata.ts), so cache
11
- * hits see `undefined` and the cache never pins the body.
12
- */
13
- jsonText: string | undefined;
14
- etag?: string;
15
- notModified?: false;
16
- }
17
- export interface FetchMetadataNotModifiedResult {
18
- notModified: true;
19
- }
20
- export declare class RegistryResponseError extends FetchError {
21
- readonly pkgName: string;
22
- constructor(request: FetchErrorRequest, response: FetchErrorResponse, pkgName: string);
23
- }
24
- export interface FetchMetadataFromFromRegistryOptions {
25
- fetch: FetchFromRegistry;
26
- retry: RetryTimeoutOptions;
27
- timeout: number;
28
- fetchWarnTimeoutMs: number;
29
- }
30
- export interface FetchMetadataOptions {
31
- registry: string;
32
- authHeaderValue?: string;
33
- fullMetadata?: boolean;
34
- etag?: string;
35
- modified?: string;
36
- }
37
- export declare function fetchMetadataFromFromRegistry(fetchOpts: FetchMetadataFromFromRegistryOptions, pkgName: string, { authHeaderValue, etag: cachedEtag, fullMetadata, modified: cachedModified, registry, }: FetchMetadataOptions): Promise<FetchMetadataResult | FetchMetadataNotModifiedResult>;
package/lib/fetch.js DELETED
@@ -1,209 +0,0 @@
1
- import url from 'node:url';
2
- import util from 'node:util';
3
- import { requestRetryLogger } from '@pnpm/core-loggers';
4
- import { FetchError, PnpmError, redactUrlCredentials, } from '@pnpm/error';
5
- import { globalWarn } from '@pnpm/logger';
6
- import * as retry from '@zkochan/retry';
7
- import semver from 'semver';
8
- import { clearMeta } from './clearMeta.js';
9
- /**
10
- * Content type of an abbreviated (install-oriented) package metadata document.
11
- * A spec-compliant registry echoes this in the response `Content-Type` when it
12
- * honors the abbreviated `Accept` header. Its absence signals that the registry
13
- * ignored the header and served the full document instead.
14
- * https://github.com/npm/registry/blob/main/docs/responses/package-metadata.md
15
- */
16
- const ABBREVIATED_META_CONTENT_TYPE = 'application/vnd.npm.install-v1+json';
17
- export class RegistryResponseError extends FetchError {
18
- pkgName;
19
- constructor(request, response, pkgName) {
20
- let hint;
21
- if (response.status === 404) {
22
- hint = `${pkgName} is not in the npm registry, or you have no permission to fetch it.`;
23
- const nameWithoutVersion = stripTrailingSemverSuffix(pkgName);
24
- if (nameWithoutVersion != null) {
25
- hint += ` Did you mean ${nameWithoutVersion}?`;
26
- }
27
- }
28
- super(request, response, hint);
29
- this.pkgName = pkgName;
30
- }
31
- }
32
- /**
33
- * Detect when a package name accidentally includes a `<version>` suffix
34
- * (e.g. `lodash@4.17.21` or `lodash4.17.21`) and return the part before the
35
- * version. Returns `undefined` when no semver suffix is present.
36
- *
37
- * Implemented as an O(n) scan to avoid polynomial backtracking on adversarial
38
- * input (CodeQL: js/polynomial-redos).
39
- */
40
- function stripTrailingSemverSuffix(pkgName) {
41
- // Common case: "name@version" – split on the rightmost '@'.
42
- // `atIdx > 0` rules out the leading '@' of scoped names like '@scope/foo'.
43
- const atIdx = pkgName.lastIndexOf('@');
44
- if (atIdx > 0 && semver.valid(pkgName.slice(atIdx + 1)) != null) {
45
- return pkgName.slice(0, atIdx);
46
- }
47
- // Fallback: detect a trailing "<digits>.<digits>.<digits>" appended to a name
48
- // with no separator (e.g. "foo1.0.0"). We walk backwards through three
49
- // digit-blocks separated by dots; this is O(n) and free of regex backtracking.
50
- let i = pkgName.length;
51
- i = consumeTrailingDigits(pkgName, i);
52
- if (i === pkgName.length || i === 0 || pkgName.charCodeAt(i - 1) !== 46 /* '.' */)
53
- return undefined;
54
- i--;
55
- const beforePatch = i;
56
- i = consumeTrailingDigits(pkgName, i);
57
- if (i === beforePatch || i === 0 || pkgName.charCodeAt(i - 1) !== 46)
58
- return undefined;
59
- i--;
60
- const beforeMinor = i;
61
- i = consumeTrailingDigits(pkgName, i);
62
- if (i === beforeMinor || i === 0)
63
- return undefined;
64
- if (semver.valid(pkgName.slice(i)) == null)
65
- return undefined;
66
- let prefix = pkgName.slice(0, i);
67
- if (prefix.endsWith('@'))
68
- prefix = prefix.slice(0, -1);
69
- return prefix.length > 0 ? prefix : undefined;
70
- }
71
- function consumeTrailingDigits(s, end) {
72
- let i = end;
73
- while (i > 0) {
74
- const c = s.charCodeAt(i - 1);
75
- if (c < 48 || c > 57)
76
- break;
77
- i--;
78
- }
79
- return i;
80
- }
81
- export async function fetchMetadataFromFromRegistry(fetchOpts, pkgName, { authHeaderValue, etag: cachedEtag, fullMetadata, modified: cachedModified, registry, }) {
82
- const uri = toUri(pkgName, registry);
83
- const op = retry.operation(fetchOpts.retry);
84
- return new Promise((resolve, reject) => {
85
- op.attempt(async (attempt) => {
86
- let response;
87
- const startTime = Date.now();
88
- try {
89
- response = await fetchOpts.fetch(uri, {
90
- authHeaderValue,
91
- compress: true,
92
- fullMetadata,
93
- ifNoneMatch: cachedEtag,
94
- ifModifiedSince: cachedModified ? new Date(cachedModified).toUTCString() : undefined,
95
- retry: fetchOpts.retry,
96
- timeout: fetchOpts.timeout,
97
- });
98
- }
99
- catch (error) { // eslint-disable-line
100
- // Redact credentials embedded in the URL from the cause as well, not
101
- // just the top-level message: a reporter or debugger that renders
102
- // `error.cause` would otherwise print the raw URL-bearing message. The
103
- // `stack` string embeds the original (pre-mutation) message, so redact
104
- // it too — mutating `message` alone leaves the credentials in `stack`.
105
- if (util.types.isNativeError(error)) {
106
- if (typeof error.message === 'string')
107
- error.message = redactUrlCredentials(error.message);
108
- if (typeof error.stack === 'string')
109
- error.stack = redactUrlCredentials(error.stack);
110
- }
111
- reject(new PnpmError('META_FETCH_FAIL', redactUrlCredentials(`GET ${uri}: ${error.message}`), { attempts: attempt, cause: error }));
112
- return;
113
- }
114
- if (response.status === 304) {
115
- resolve({ notModified: true });
116
- return;
117
- }
118
- if (response.status >= 400) {
119
- const request = {
120
- authHeaderValue,
121
- url: uri,
122
- };
123
- reject(new RegistryResponseError(request, response, pkgName));
124
- return;
125
- }
126
- // Here we only retry broken JSON responses.
127
- // Other HTTP issues are retried by the @pnpm/network.fetch library
128
- try {
129
- const jsonText = await response.text();
130
- const meta = JSON.parse(jsonText);
131
- // Check if request took longer than expected
132
- const elapsedMs = Date.now() - startTime;
133
- if (elapsedMs > fetchOpts.fetchWarnTimeoutMs) {
134
- globalWarn(`Request took ${elapsedMs}ms: ${uri}`);
135
- }
136
- resolve({
137
- ...normalizeAbbreviatedResponse({ fullMetadata, meta, jsonText, response }),
138
- etag: response.headers.get('etag') ?? undefined,
139
- });
140
- }
141
- catch (error) { // eslint-disable-line
142
- const timeout = op.retry(new PnpmError('BROKEN_METADATA_JSON', error.message));
143
- if (timeout === false) {
144
- reject(op.mainError());
145
- return;
146
- }
147
- // Extract error properties into a plain object because Error properties
148
- // are non-enumerable and don't serialize well through the logging system
149
- const errorInfo = {
150
- name: error.name,
151
- message: error.message,
152
- code: error.code,
153
- errno: error.errno,
154
- };
155
- requestRetryLogger.debug({
156
- attempt,
157
- error: errorInfo,
158
- maxRetries: fetchOpts.retry.retries,
159
- method: 'GET',
160
- timeout,
161
- url: uri,
162
- });
163
- }
164
- });
165
- });
166
- }
167
- /**
168
- * When the resolver asked for abbreviated metadata but the registry ignored the
169
- * `Accept` header and returned the full document (detected via the response
170
- * `Content-Type`), strip it down to the abbreviated field set so downstream
171
- * consumers — the in-memory cache, the on-disk mirror, and the resolver — never
172
- * carry the megabytes of install-irrelevant data (scripts, exports, readme,
173
- * custom fields) that a full document contains.
174
- *
175
- * Registries that honor the header (e.g. the npm registry) echo the abbreviated
176
- * `Content-Type`, so this is a no-op for them: no re-serialization, no field
177
- * stripping — the happy path pays nothing.
178
- */
179
- function normalizeAbbreviatedResponse({ fullMetadata, meta, jsonText, response }) {
180
- if (fullMetadata)
181
- return { meta, jsonText };
182
- if (parseMediaType(response.headers.get('content-type')) === ABBREVIATED_META_CONTENT_TYPE)
183
- return { meta, jsonText };
184
- const normalized = clearMeta(meta);
185
- return { meta: normalized, jsonText: JSON.stringify(normalized) };
186
- }
187
- /**
188
- * Extracts the media type from a `Content-Type` header value, dropping
189
- * parameters such as `; charset=utf-8`. Media types are case-insensitive
190
- * (RFC 9110 §8.3.1), so the result is lowercased for comparison.
191
- */
192
- function parseMediaType(contentType) {
193
- if (contentType == null)
194
- return undefined;
195
- const semicolonIndex = contentType.indexOf(';');
196
- const mediaType = semicolonIndex === -1 ? contentType : contentType.slice(0, semicolonIndex);
197
- return mediaType.trim().toLowerCase();
198
- }
199
- function toUri(pkgName, registry) {
200
- let encodedName;
201
- if (pkgName[0] === '@') {
202
- encodedName = `@${encodeURIComponent(pkgName.slice(1))}`;
203
- }
204
- else {
205
- encodedName = encodeURIComponent(pkgName);
206
- }
207
- return new url.URL(encodedName, registry.endsWith('/') ? registry : `${registry}/`).toString();
208
- }
209
- //# sourceMappingURL=fetch.js.map
@@ -1,31 +0,0 @@
1
- import type { FetchMetadataFromFromRegistryOptions } from './fetch.js';
2
- /**
3
- * Per-version publish timestamp from npm's attestation endpoint —
4
- * `/-/npm/v1/attestations/<name>@<version>`.
5
- *
6
- * The response is a small JSON document containing one or more Sigstore
7
- * bundles. We read `bundle.verificationMaterial.tlogEntries[].integratedTime`
8
- * (the Rekor inclusion time) and surface it as an ISO date. This is a
9
- * couple of seconds after the actual publish — close enough for a
10
- * release-age policy that operates in minutes/hours/days.
11
- *
12
- * We deliberately do **not** verify the Sigstore signature here: the
13
- * trust model is identical to reading the registry's `time` field on
14
- * the full metadata document. The win is bandwidth — the attestation
15
- * payload is tens of KB versus the multi-MB full metadata document, so
16
- * cold-cache + `--frozen-lockfile` installs against a fleet of
17
- * provenance-published packages pay far less to verify timestamps.
18
- *
19
- * Returns `undefined` when:
20
- *
21
- * - The package has no published attestations (`404`).
22
- * - The response is malformed or missing the timestamp.
23
- * - The request itself fails (network error, registry 5xx).
24
- *
25
- * In all of those cases the caller falls back to fetching full metadata.
26
- */
27
- export interface FetchAttestationOptions {
28
- registry: string;
29
- authHeaderValue?: string;
30
- }
31
- export declare function fetchAttestationPublishedAt(fetchOpts: FetchMetadataFromFromRegistryOptions, pkgName: string, version: string, opts: FetchAttestationOptions): Promise<string | undefined>;
@@ -1,99 +0,0 @@
1
- import * as retry from '@zkochan/retry';
2
- export async function fetchAttestationPublishedAt(fetchOpts, pkgName, version, opts) {
3
- const url = `${opts.registry.replace(/\/$/, '')}/-/npm/v1/attestations/${pkgName}@${version}`;
4
- const retryOperation = retry.operation(fetchOpts.retry);
5
- return new Promise((resolve) => {
6
- retryOperation.attempt(async () => {
7
- let response;
8
- try {
9
- response = await fetchOpts.fetch(url, {
10
- authHeaderValue: opts.authHeaderValue,
11
- retry: fetchOpts.retry,
12
- timeout: fetchOpts.timeout,
13
- });
14
- }
15
- catch {
16
- // Network errors fall through to the full-metadata path; the
17
- // caller's `fetchFullMetadataCached` has its own retry policy.
18
- resolve(undefined);
19
- return;
20
- }
21
- // 404 = package never published attestations. Other 4xx/5xx also
22
- // mean "can't get an answer from this endpoint, fall back."
23
- if (response.status >= 400) {
24
- resolve(undefined);
25
- return;
26
- }
27
- let body;
28
- try {
29
- body = await response.json();
30
- }
31
- catch {
32
- resolve(undefined);
33
- return;
34
- }
35
- resolve(extractPublishedAt(body));
36
- });
37
- });
38
- }
39
- /**
40
- * Pull the earliest `integratedTime` across every attestation bundle in
41
- * the response and convert it to an ISO timestamp. Earliest is the
42
- * conservative choice: if two attestations disagree (e.g. publish
43
- * v0.1 vs SLSA provenance v1), we attribute the publish to the older
44
- * Rekor entry. The Rekor timestamp is what tells us when the artifact
45
- * existed in a transparency log — that's the floor on publish time.
46
- */
47
- function extractPublishedAt(body) {
48
- if (!body || typeof body !== 'object')
49
- return undefined;
50
- const attestations = body.attestations;
51
- if (!Array.isArray(attestations))
52
- return undefined;
53
- let earliestSeconds;
54
- for (const attestation of attestations) {
55
- const seconds = readEarliestIntegratedTime(attestation);
56
- if (seconds == null)
57
- continue;
58
- if (earliestSeconds == null || seconds < earliestSeconds) {
59
- earliestSeconds = seconds;
60
- }
61
- }
62
- if (earliestSeconds == null)
63
- return undefined;
64
- return new Date(earliestSeconds * 1000).toISOString();
65
- }
66
- function readEarliestIntegratedTime(attestation) {
67
- if (!attestation || typeof attestation !== 'object')
68
- return undefined;
69
- const bundle = attestation.bundle;
70
- if (!bundle || typeof bundle !== 'object')
71
- return undefined;
72
- const verificationMaterial = bundle.verificationMaterial;
73
- if (!verificationMaterial || typeof verificationMaterial !== 'object')
74
- return undefined;
75
- const tlogEntries = verificationMaterial.tlogEntries;
76
- if (!Array.isArray(tlogEntries))
77
- return undefined;
78
- let earliest;
79
- for (const entry of tlogEntries) {
80
- if (!entry || typeof entry !== 'object')
81
- continue;
82
- const rawIntegratedTime = entry.integratedTime;
83
- // npm serializes integratedTime as a string ("1778583836") to avoid
84
- // JSON precision loss; accept either string or number defensively.
85
- const seconds = parseIntegratedTimeSeconds(rawIntegratedTime);
86
- if (seconds == null)
87
- continue;
88
- if (earliest == null || seconds < earliest)
89
- earliest = seconds;
90
- }
91
- return earliest;
92
- }
93
- function parseIntegratedTimeSeconds(raw) {
94
- const seconds = typeof raw === 'string' ? Number(raw) : typeof raw === 'number' ? raw : NaN;
95
- if (!Number.isFinite(seconds) || seconds <= 0)
96
- return undefined;
97
- return seconds;
98
- }
99
- //# sourceMappingURL=fetchAttestationPublishedAt.js.map
@@ -1,33 +0,0 @@
1
- import type { PackageMeta } from '@pnpm/resolving.registry.types';
2
- import { type FetchMetadataFromFromRegistryOptions } from './fetch.js';
3
- export interface FetchMetadataCachedOptions {
4
- registry: string;
5
- authHeaderValue?: string;
6
- /**
7
- * pnpm's on-disk cache directory. When set, the call issues a conditional
8
- * GET against the matching mirror the resolver populates: a 304 Not
9
- * Modified response serves the body from disk, a 200 writes the new body
10
- * back. Omit to disable caching — every call re-fetches.
11
- */
12
- cacheDir?: string;
13
- }
14
- export type FetchFullMetadataCachedOptions = FetchMetadataCachedOptions;
15
- /**
16
- * Fetch a full registry metadata document for `pkgName`, reusing pnpm's
17
- * shared on-disk metadata mirror when `cacheDir` is supplied. Built for the
18
- * `minimumReleaseAge` lockfile revalidation gate, which needs the `time`
19
- * field that abbreviated metadata omits; the cache reuse keeps repeat
20
- * installs from re-downloading the same multi-megabyte document for every
21
- * locked package.
22
- */
23
- export declare function fetchFullMetadataCached(fetchOpts: FetchMetadataFromFromRegistryOptions, pkgName: string, opts: FetchFullMetadataCachedOptions): Promise<PackageMeta>;
24
- /**
25
- * Sibling of {@link fetchFullMetadataCached} that hits the abbreviated
26
- * metadata endpoint (`Accept: application/vnd.npm.install-v1+json`) and
27
- * caches under `ABBREVIATED_META_DIR` — the same mirror the resolver
28
- * populates by default. Used by the lockfile verification gate as a
29
- * cheap upper-bound check: if the package's `modified` field is older
30
- * than the policy cutoff, every version in it predates the cutoff and
31
- * no per-version timestamp lookup is needed.
32
- */
33
- export declare function fetchAbbreviatedMetadataCached(fetchOpts: FetchMetadataFromFromRegistryOptions, pkgName: string, opts: FetchMetadataCachedOptions): Promise<PackageMeta>;
@@ -1,63 +0,0 @@
1
- import { ABBREVIATED_META_DIR, FULL_META_DIR } from '@pnpm/constants';
2
- import { PnpmError } from '@pnpm/error';
3
- import { fetchMetadataFromFromRegistry } from './fetch.js';
4
- import { getPkgMirrorPath, loadMeta, loadMetaHeaders, prepareJsonForDisk, saveMeta } from './pickPackage.js';
5
- /**
6
- * Fetch a full registry metadata document for `pkgName`, reusing pnpm's
7
- * shared on-disk metadata mirror when `cacheDir` is supplied. Built for the
8
- * `minimumReleaseAge` lockfile revalidation gate, which needs the `time`
9
- * field that abbreviated metadata omits; the cache reuse keeps repeat
10
- * installs from re-downloading the same multi-megabyte document for every
11
- * locked package.
12
- */
13
- export async function fetchFullMetadataCached(fetchOpts, pkgName, opts) {
14
- return fetchMetadataCached(fetchOpts, pkgName, { ...opts, fullMetadata: true, metaDir: FULL_META_DIR });
15
- }
16
- /**
17
- * Sibling of {@link fetchFullMetadataCached} that hits the abbreviated
18
- * metadata endpoint (`Accept: application/vnd.npm.install-v1+json`) and
19
- * caches under `ABBREVIATED_META_DIR` — the same mirror the resolver
20
- * populates by default. Used by the lockfile verification gate as a
21
- * cheap upper-bound check: if the package's `modified` field is older
22
- * than the policy cutoff, every version in it predates the cutoff and
23
- * no per-version timestamp lookup is needed.
24
- */
25
- export async function fetchAbbreviatedMetadataCached(fetchOpts, pkgName, opts) {
26
- return fetchMetadataCached(fetchOpts, pkgName, { ...opts, fullMetadata: false, metaDir: ABBREVIATED_META_DIR });
27
- }
28
- async function fetchMetadataCached(fetchOpts, pkgName, opts) {
29
- const pkgMirror = opts.cacheDir != null
30
- ? getPkgMirrorPath(opts.cacheDir, opts.metaDir, opts.registry, pkgName)
31
- : null;
32
- const cacheHeaders = pkgMirror != null ? await loadMetaHeaders(pkgMirror) : null;
33
- const result = await fetchMetadataFromFromRegistry(fetchOpts, pkgName, {
34
- registry: opts.registry,
35
- authHeaderValue: opts.authHeaderValue,
36
- fullMetadata: opts.fullMetadata,
37
- etag: cacheHeaders?.etag,
38
- modified: cacheHeaders?.modified,
39
- });
40
- if ('notModified' in result && result.notModified) {
41
- if (pkgMirror == null) {
42
- // We didn't send conditional headers (no cacheDir), but the registry
43
- // returned 304 anyway. There's no body to fall back on.
44
- throw new PnpmError('META_NOT_MODIFIED_WITHOUT_CACHE', `Registry returned 304 for ${pkgName} without an existing cache to refresh.`);
45
- }
46
- const meta = await loadMeta(pkgMirror);
47
- if (meta == null) {
48
- // Cache file vanished between header-load and meta-load (concurrent
49
- // store cleanup, antivirus, etc.).
50
- throw new PnpmError('META_CACHE_MISSING_AFTER_304', `Metadata cache for ${pkgName} disappeared between headers read and full read.`);
51
- }
52
- return meta;
53
- }
54
- if (pkgMirror != null) {
55
- // Persist so the next install can do a headers-only conditional GET.
56
- // Fire-and-forget — a cache-write failure isn't a reason to fail the
57
- // caller; the next install just won't get the speedup.
58
- const json = prepareJsonForDisk(result.meta, result.etag, result.jsonText);
59
- saveMeta(pkgMirror, json).catch(() => { });
60
- }
61
- return result.meta;
62
- }
63
- //# sourceMappingURL=fetchFullMetadataCached.js.map
package/lib/index.d.ts DELETED
@@ -1,133 +0,0 @@
1
- import { PnpmError } from '@pnpm/error';
2
- import type { FetchFromRegistry, GetAuthHeader, RetryTimeoutOptions } from '@pnpm/fetching.types';
3
- import type { PackageMeta } from '@pnpm/resolving.registry.types';
4
- import type { DirectoryResolution, LatestInfo, LatestQuery, PkgResolutionId, PreferredVersions, ResolveOptions, ResolveResult, TarballResolution, WantedDependency, WorkspacePackages } from '@pnpm/resolving.resolver-base';
5
- import type { DependencyManifest, PackageVersionPolicy, PinnedVersion, Registries, TrustPolicy } from '@pnpm/types';
6
- import { fetchMetadataFromFromRegistry, type FetchMetadataFromFromRegistryOptions, RegistryResponseError } from './fetch.js';
7
- import { BUILTIN_NAMED_REGISTRIES, parseBareSpecifier, type RegistryPackageSpec } from './parseBareSpecifier.js';
8
- import { type PackageMetaCache, pickPackage, type PickPackageOptions } from './pickPackage.js';
9
- import { pickPackageFromMeta, pickVersionByVersionRange } from './pickPackageFromMeta.js';
10
- import { workspacePrefToNpm } from './workspacePrefToNpm.js';
11
- export interface NoMatchingVersionErrorOptions {
12
- wantedDependency: WantedDependency;
13
- packageMeta: PackageMeta;
14
- registry: string;
15
- }
16
- export declare class NoMatchingVersionError extends PnpmError {
17
- readonly packageMeta: PackageMeta;
18
- constructor(opts: NoMatchingVersionErrorOptions);
19
- }
20
- export declare function formatTimeAgo(date: Date): string | null;
21
- export { BUILTIN_NAMED_REGISTRIES, fetchMetadataFromFromRegistry, type FetchMetadataFromFromRegistryOptions, type PackageMeta, type PackageMetaCache, parseBareSpecifier, pickPackageFromMeta, pickVersionByVersionRange, type RegistryPackageSpec, RegistryResponseError, workspacePrefToNpm, };
22
- export { createNpmResolutionVerifier, type CreateNpmResolutionVerifierOptions } from './createNpmResolutionVerifier.js';
23
- export { MINIMUM_RELEASE_AGE_VIOLATION_CODE, TRUST_DOWNGRADE_VIOLATION_CODE, } from './violationCodes.js';
24
- export { whichVersionIsPinned } from './whichVersionIsPinned.js';
25
- export interface ResolverFactoryOptions {
26
- cacheDir: string;
27
- storeDir?: string;
28
- frozenStore?: boolean;
29
- fullMetadata?: boolean;
30
- filterMetadata?: boolean;
31
- offline?: boolean;
32
- preferOffline?: boolean;
33
- retry?: RetryTimeoutOptions;
34
- timeout?: number;
35
- registries: Registries;
36
- namedRegistries?: Record<string, string>;
37
- saveWorkspaceProtocol?: boolean | 'rolling';
38
- preserveAbsolutePaths?: boolean;
39
- ignoreMissingTimeField?: boolean;
40
- fetchWarnTimeoutMs?: number;
41
- /** Pre-populated metadata cache. When provided, the resolver uses this
42
- * instead of creating a new LRU cache. Useful for servers that keep
43
- * metadata in SQLite or persist it across requests. */
44
- metaCache?: PackageMetaCache;
45
- }
46
- export interface NpmResolveResult extends ResolveResult {
47
- latest?: string;
48
- manifest: DependencyManifest;
49
- resolution: TarballResolution;
50
- resolvedVia: 'npm-registry';
51
- }
52
- export interface JsrResolveResult extends ResolveResult {
53
- alias: string;
54
- manifest: DependencyManifest;
55
- resolution: TarballResolution;
56
- resolvedVia: 'jsr-registry';
57
- }
58
- export interface NamedRegistryResolveResult extends ResolveResult {
59
- alias: string;
60
- /** The named-registry alias that was matched, e.g. `gh` or a user-defined name. */
61
- registryName: string;
62
- manifest: DependencyManifest;
63
- resolution: TarballResolution;
64
- resolvedVia: 'named-registry';
65
- }
66
- export interface WorkspaceResolveResult extends ResolveResult {
67
- manifest: DependencyManifest;
68
- resolution: DirectoryResolution;
69
- resolvedVia: 'workspace';
70
- }
71
- export type NpmResolver = (wantedDependency: WantedDependency & {
72
- optional?: boolean;
73
- }, opts: ResolveFromNpmOptions) => Promise<NpmResolveResult | JsrResolveResult | NamedRegistryResolveResult | WorkspaceResolveResult | null>;
74
- export type ResolveLatestFromNpmStyle = (query: LatestQuery, opts: ResolveOptions) => Promise<LatestInfo | undefined>;
75
- export declare function createNpmResolver(fetchFromRegistry: FetchFromRegistry, getAuthHeader: GetAuthHeader, opts: ResolverFactoryOptions): {
76
- resolveFromNpm: NpmResolver;
77
- resolveFromJsr: NpmResolver;
78
- resolveFromNamedRegistry: NpmResolver;
79
- resolveLatestFromNpm: ResolveLatestFromNpmStyle;
80
- resolveLatestFromJsr: ResolveLatestFromNpmStyle;
81
- resolveLatestFromNamedRegistry: ResolveLatestFromNpmStyle;
82
- clearCache: () => void;
83
- };
84
- export interface ResolveFromNpmContext {
85
- pickPackage: (spec: RegistryPackageSpec, opts: PickPackageOptions) => ReturnType<typeof pickPackage>;
86
- getAuthHeaderValueByURI: GetAuthHeader;
87
- registries: Registries;
88
- namedRegistries: Record<string, string>;
89
- namedRegistryNames: ReadonlySet<string>;
90
- saveWorkspaceProtocol?: boolean | 'rolling';
91
- peekManifestFromStore?: (opts: {
92
- id: PkgResolutionId;
93
- integrity: string;
94
- name?: string;
95
- version?: string;
96
- }) => Promise<DependencyManifest | undefined>;
97
- /** Deduplicates the held-back-update warning per `(name, picked, preferred)`. */
98
- warnedHeldBackUpdates: Set<string>;
99
- }
100
- export type ResolveFromNpmOptions = {
101
- alwaysTryWorkspacePackages?: boolean;
102
- defaultTag?: string;
103
- publishedBy?: Date;
104
- publishedByExclude?: PackageVersionPolicy;
105
- pickLowestVersion?: boolean;
106
- trustPolicy?: TrustPolicy;
107
- trustPolicyExclude?: PackageVersionPolicy;
108
- trustPolicyIgnoreAfter?: number;
109
- dryRun?: boolean;
110
- lockfileDir?: string;
111
- preferredVersions?: PreferredVersions;
112
- preferWorkspacePackages?: boolean;
113
- update?: false | 'compatible' | 'latest';
114
- updateRequested?: boolean;
115
- updateChecksums?: boolean;
116
- injectWorkspacePackages?: boolean;
117
- calcSpecifier?: boolean;
118
- pinnedVersion?: PinnedVersion;
119
- } & ({
120
- projectDir?: string;
121
- workspacePackages?: undefined;
122
- } | {
123
- projectDir: string;
124
- workspacePackages: WorkspacePackages;
125
- });
126
- /**
127
- * Construct the LRU `PackageMetaCache` instance the resolver uses by
128
- * default. Exported so the install layer can build one cache and hand
129
- * the same reference to both the resolver and the verifier — the
130
- * verifier's fast path reads from it when the resolver has already
131
- * fetched a packument during the same install.
132
- */
133
- export declare function createDefaultPackageMetaCache(): PackageMetaCache;
@@ -1,24 +0,0 @@
1
- import type { FetchMetadataNotModifiedResult, FetchMetadataOptions, FetchMetadataResult } from './fetch.js';
2
- export type FetchMetadata = (pkgName: string, opts: FetchMetadataOptions) => Promise<FetchMetadataResult | FetchMetadataNotModifiedResult>;
3
- export interface MemoizedFetchMetadata {
4
- fetch: FetchMetadata;
5
- clear: () => void;
6
- }
7
- /**
8
- * Memoizes metadata fetches for the whole resolution phase (cleared via
9
- * `clear`, see `clearResolutionCache`), deduplicating concurrent and repeat
10
- * requests for the same package.
11
- *
12
- * Unlike plain memoization, the cache holds a body-less clone of each result:
13
- * `jsonText` — the raw registry response body, up to tens of MB for a popular
14
- * package — reaches only the caller that initiated the fetch, which is the
15
- * caller that writes the disk mirror. A phase-long cache that kept the bodies
16
- * would pin hundreds of MB on large cold-cache graphs. A cache-hit caller
17
- * that also writes the mirror falls back to `JSON.stringify(meta)` in
18
- * `prepareJsonForDisk`, which is equivalent on read: `loadMeta` re-derives
19
- * `etag` from the headers line.
20
- *
21
- * A rejected fetch is evicted so a transient network failure is retried by
22
- * the next request instead of being cached for the rest of the phase.
23
- */
24
- export declare function memoizeFetchMetadata(fetch: FetchMetadata): MemoizedFetchMetadata;
@@ -1,37 +0,0 @@
1
- /**
2
- * Memoizes metadata fetches for the whole resolution phase (cleared via
3
- * `clear`, see `clearResolutionCache`), deduplicating concurrent and repeat
4
- * requests for the same package.
5
- *
6
- * Unlike plain memoization, the cache holds a body-less clone of each result:
7
- * `jsonText` — the raw registry response body, up to tens of MB for a popular
8
- * package — reaches only the caller that initiated the fetch, which is the
9
- * caller that writes the disk mirror. A phase-long cache that kept the bodies
10
- * would pin hundreds of MB on large cold-cache graphs. A cache-hit caller
11
- * that also writes the mirror falls back to `JSON.stringify(meta)` in
12
- * `prepareJsonForDisk`, which is equivalent on read: `loadMeta` re-derives
13
- * `etag` from the headers line.
14
- *
15
- * A rejected fetch is evicted so a transient network failure is retried by
16
- * the next request instead of being cached for the rest of the phase.
17
- */
18
- export function memoizeFetchMetadata(fetch) {
19
- const cache = new Map();
20
- return {
21
- fetch: (pkgName, opts) => {
22
- const key = JSON.stringify([pkgName, opts]);
23
- const cached = cache.get(key);
24
- if (cached != null)
25
- return cached;
26
- const pending = fetch(pkgName, opts);
27
- const bodiless = pending.then((result) => result.notModified ? result : { ...result, jsonText: undefined });
28
- bodiless.catch(() => cache.delete(key));
29
- cache.set(key, bodiless);
30
- return pending;
31
- },
32
- clear: () => {
33
- cache.clear();
34
- },
35
- };
36
- }
37
- //# sourceMappingURL=memoizeFetchMetadata.js.map