@pnpm/installing.package-requester 1102.0.0 → 1102.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.
@@ -7,7 +7,7 @@ import { PnpmError } from '@pnpm/error';
7
7
  import { pickFetcher } from '@pnpm/fetching.pick-fetcher';
8
8
  import gfs from '@pnpm/fs.graceful-fs';
9
9
  import { logger } from '@pnpm/logger';
10
- import { resolvePlatformSelector, selectPlatformVariant, } from '@pnpm/resolving.resolver-base';
10
+ import { classifyResolution, resolvePlatformSelector, selectPlatformVariant, } from '@pnpm/resolving.resolver-base';
11
11
  import { normalizeBundledManifest, } from '@pnpm/store.cafs';
12
12
  import { pickStoreIndexKey } from '@pnpm/store.index';
13
13
  import { calcMaxWorkers, readPkgFromCafs as _readPkgFromCafs, } from '@pnpm/worker';
@@ -65,6 +65,8 @@ export function createPackageRequester(opts) {
65
65
  requestsQueue,
66
66
  resolve: opts.resolve,
67
67
  storeDir: opts.storeDir,
68
+ fetchers: opts.fetchers,
69
+ customFetchers: opts.customFetchers,
68
70
  });
69
71
  return Object.assign(requestPackage, {
70
72
  fetchPackageToStore,
@@ -157,9 +159,19 @@ async function resolveAndFetch(ctx, wantedDependency, options) {
157
159
  optional: wantedDependency.optional === true,
158
160
  supportedArchitectures: options.supportedArchitectures,
159
161
  })));
160
- // We can skip fetching the package only if the manifest
161
- // is present after resolution AND the content of the package has not changed
162
- if ((options.skipFetch === true || isInstallable === false) && !integrityChanged && (manifest != null)) {
162
+ const fetcherForResolution = resolution.type === 'variations'
163
+ ? undefined
164
+ : await pickFetcher(ctx.fetchers, resolution, {
165
+ customFetchers: ctx.customFetchers,
166
+ packageId: id,
167
+ });
168
+ const resolutionNeedsFetchHook = fetcherForResolution?.resolutionNeedsFetch;
169
+ const resolutionNeedsFetch = typeof resolutionNeedsFetchHook === 'function'
170
+ ? resolutionNeedsFetchHook(resolution)
171
+ : false;
172
+ // Fetching can be skipped only when the manifest is available, the package content
173
+ // did not change, and the resolution does not need fetch-derived data.
174
+ if ((options.skipFetch === true || isInstallable === false) && !resolutionNeedsFetch && !integrityChanged && (manifest != null)) {
163
175
  return {
164
176
  body: {
165
177
  id,
@@ -182,6 +194,8 @@ async function resolveAndFetch(ctx, wantedDependency, options) {
182
194
  allowBuild: options.allowBuild,
183
195
  fetchRawManifest: true,
184
196
  force: integrityChanged,
197
+ populateMissingIntegrity: resolutionNeedsFetch,
198
+ pickedFetcher: fetcherForResolution,
185
199
  ignoreScripts: options.ignoreScripts,
186
200
  lockfileDir: options.lockfileDir,
187
201
  pkg: {
@@ -207,11 +221,29 @@ async function resolveAndFetch(ctx, wantedDependency, options) {
207
221
  manifest = loadedManifest;
208
222
  }
209
223
  }
210
- // Add integrity to resolution if it was computed during fetching (only for TarballResolution)
211
- if (fetchedResult.integrity && !resolution.type && !resolution.integrity) {
224
+ // Add computed integrity to tarball resolutions. `variations` spans multiple
225
+ // platform variants, so do not write one machine's integrity into the shared resolution.
226
+ if (resolution.type !== 'variations' && fetchedResult.integrity != null && getExpectedIntegrity(resolution) == null) {
212
227
  resolution.integrity = fetchedResult.integrity;
213
228
  }
214
229
  }
230
+ let fetching = fetchResult.fetching;
231
+ if (resolutionNeedsFetch) {
232
+ let populating;
233
+ fetching = () => {
234
+ populating ??= fetchResult.fetching().then((fetchedResult) => {
235
+ if (fetchedResult.integrity != null && getExpectedIntegrity(resolution) == null) {
236
+ resolution.integrity = fetchedResult.integrity;
237
+ }
238
+ return fetchedResult;
239
+ }).catch((err) => {
240
+ // Cache only fulfilled fetches; rejected fetches may be retried.
241
+ populating = undefined;
242
+ throw err;
243
+ });
244
+ return populating;
245
+ };
246
+ }
215
247
  // Check installability now that we have the manifest (for git/tarball packages without registry metadata)
216
248
  if (isInstallable === undefined && manifest != null) {
217
249
  isInstallable = ctx.force === true || packageIsInstallable(id, manifest, {
@@ -237,8 +269,9 @@ async function resolveAndFetch(ctx, wantedDependency, options) {
237
269
  alias,
238
270
  policyViolation,
239
271
  },
240
- fetching: fetchResult.fetching,
272
+ fetching,
241
273
  filesIndexFile: fetchResult.filesIndexFile,
274
+ resolutionNeedsFetch,
242
275
  };
243
276
  }
244
277
  function getFilesIndexFilePath(ctx, opts) {
@@ -357,7 +390,13 @@ function fetchToStore(ctx, opts) {
357
390
  try {
358
391
  const isLocalTarballDep = opts.pkg.id.startsWith('file:');
359
392
  const isLocalPkg = resolution.type === 'directory';
393
+ const populateMissingIntegrity = opts.populateMissingIntegrity === true;
394
+ if (!populateMissingIntegrity) {
395
+ assertFetchableResolution(opts.pkg.id, resolution);
396
+ }
397
+ let refetchingStoredPackage = false;
360
398
  if (!opts.force &&
399
+ !populateMissingIntegrity &&
361
400
  (!isLocalTarballDep ||
362
401
  await tarballIsUpToDate(opts.pkg.resolution, target, opts.lockfileDir) // eslint-disable-line
363
402
  ) &&
@@ -373,12 +412,13 @@ function fetchToStore(ctx, opts) {
373
412
  });
374
413
  return;
375
414
  }
376
- if ((files?.filesMap) != null) {
377
- packageRequestLogger.warn({
378
- message: `Refetching ${target} to store. It was either modified or had no integrity checksums`,
379
- prefix: opts.lockfileDir,
380
- });
381
- }
415
+ refetchingStoredPackage = (files?.filesMap) != null;
416
+ }
417
+ if (refetchingStoredPackage) {
418
+ packageRequestLogger.warn({
419
+ message: `Refetching ${target} to store. It was either modified or had no integrity checksums`,
420
+ prefix: opts.lockfileDir,
421
+ });
382
422
  }
383
423
  // We fetch into targetStage directory first and then fs.rename() it to the
384
424
  // target directory.
@@ -411,8 +451,8 @@ function fetchToStore(ctx, opts) {
411
451
  name: opts.pkg.name,
412
452
  version: opts.pkg.version,
413
453
  },
414
- }), { priority });
415
- const integrity = opts.pkg.resolution.integrity ?? fetchedPackage.integrity;
454
+ }, opts.pickedFetcher), { priority });
455
+ const integrity = getExpectedIntegrity(opts.pkg.resolution) ?? fetchedPackage.integrity;
416
456
  if (isLocalTarballDep && integrity) {
417
457
  await fs.mkdir(target, { recursive: true });
418
458
  await gfs.writeFile(path.join(target, TARBALL_INTEGRITY_FILENAME), integrity, 'utf8');
@@ -436,6 +476,19 @@ function fetchToStore(ctx, opts) {
436
476
  async function readBundledManifest(pkgJsonPath) {
437
477
  return normalizeBundledManifest(await loadJsonFile(pkgJsonPath));
438
478
  }
479
+ function getExpectedIntegrity(resolution) {
480
+ const integrity = resolution.integrity;
481
+ return typeof integrity === 'string' && integrity.length > 0
482
+ ? integrity
483
+ : undefined;
484
+ }
485
+ function assertFetchableResolution(depPath, resolution) {
486
+ if (classifyResolution(resolution) !== 'remoteTarball')
487
+ return;
488
+ if (getExpectedIntegrity(resolution) != null)
489
+ return;
490
+ throw new PnpmError('MISSING_TARBALL_INTEGRITY', `Cannot fetch package "${depPath}" from the lockfile: it has no "integrity" field, so the downloaded tarball cannot be verified. Run a fresh install to repair the lockfile.`);
491
+ }
439
492
  async function tarballIsUpToDate(resolution, pkgInStoreLocation, lockfileDir) {
440
493
  let currentIntegrity;
441
494
  try {
@@ -455,10 +508,9 @@ async function tarballIsUpToDate(resolution, pkgInStoreLocation, lockfileDir) {
455
508
  return false;
456
509
  }
457
510
  }
458
- async function fetcher(fetcherByHostingType, cafs, customFetchers, packageId, resolution, opts) {
511
+ async function fetcher(fetcherByHostingType, cafs, customFetchers, packageId, resolution, opts, pickedFetcher) {
459
512
  try {
460
- // pickFetcher now handles custom fetcher hooks internally
461
- const fetch = await pickFetcher(fetcherByHostingType, resolution, {
513
+ const fetch = pickedFetcher ?? await pickFetcher(fetcherByHostingType, resolution, {
462
514
  customFetchers,
463
515
  packageId,
464
516
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/installing.package-requester",
3
- "version": "1102.0.0",
3
+ "version": "1102.1.0",
4
4
  "description": "Concurrent downloader of npm-compatible packages",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -12,9 +12,9 @@
12
12
  "funding": "https://opencollective.com/pnpm",
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "https://github.com/pnpm/pnpm/tree/main/installing/package-requester"
15
+ "url": "https://github.com/pnpm/pnpm/tree/main/pnpm11/installing/package-requester"
16
16
  },
17
- "homepage": "https://github.com/pnpm/pnpm/tree/main/installing/package-requester#readme",
17
+ "homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/installing/package-requester#readme",
18
18
  "bugs": {
19
19
  "url": "https://github.com/pnpm/pnpm/issues"
20
20
  },
@@ -38,23 +38,23 @@
38
38
  "ramda": "npm:@pnpm/ramda@0.28.1",
39
39
  "semver": "^7.8.4",
40
40
  "ssri": "13.0.1",
41
- "@pnpm/config.package-is-installable": "1100.0.11",
41
+ "@pnpm/config.package-is-installable": "1100.0.12",
42
+ "@pnpm/core-loggers": "1100.2.1",
42
43
  "@pnpm/deps.path": "1100.0.8",
43
- "@pnpm/error": "1100.0.0",
44
- "@pnpm/fetching.pick-fetcher": "1100.0.12",
44
+ "@pnpm/error": "1100.0.1",
45
+ "@pnpm/fetching.fetcher-base": "1100.2.0",
46
+ "@pnpm/fetching.pick-fetcher": "1100.0.13",
45
47
  "@pnpm/fs.graceful-fs": "1100.1.0",
46
- "@pnpm/fetching.fetcher-base": "1100.1.9",
47
- "@pnpm/hooks.types": "1100.0.12",
48
- "@pnpm/store.cafs": "1100.1.10",
49
- "@pnpm/core-loggers": "1100.2.1",
50
- "@pnpm/store.controller-types": "1100.1.5",
51
- "@pnpm/store.index": "1100.2.0",
52
- "@pnpm/types": "1101.3.2",
53
- "@pnpm/resolving.resolver-base": "1100.4.2"
48
+ "@pnpm/hooks.types": "1100.1.0",
49
+ "@pnpm/resolving.resolver-base": "1100.5.0",
50
+ "@pnpm/store.cafs": "1100.1.11",
51
+ "@pnpm/store.controller-types": "1100.1.6",
52
+ "@pnpm/store.index": "1100.2.1",
53
+ "@pnpm/types": "1101.3.2"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@pnpm/logger": "^1100.0.0",
57
- "@pnpm/worker": "^1100.2.0"
57
+ "@pnpm/worker": "^1100.2.2"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@jest/globals": "30.4.1",
@@ -65,14 +65,14 @@
65
65
  "delay": "^7.0.0",
66
66
  "normalize-path": "^3.0.0",
67
67
  "tempy": "3.0.0",
68
- "@pnpm/installing.client": "1100.2.8",
69
- "@pnpm/logger": "1100.0.0",
68
+ "@pnpm/installing.client": "1100.2.10",
69
+ "@pnpm/installing.package-requester": "1102.1.0",
70
70
  "@pnpm/store.cafs-types": "1100.0.1",
71
- "@pnpm/store.create-cafs-store": "1100.0.14",
71
+ "@pnpm/logger": "1100.0.0",
72
+ "@pnpm/store.create-cafs-store": "1100.0.16",
73
+ "@pnpm/testing.mock-agent": "1101.0.4",
72
74
  "@pnpm/test-fixtures": "1100.0.0",
73
- "@pnpm/testing.mock-agent": "1101.0.3",
74
- "@pnpm/testing.registry-mock": "1100.0.6",
75
- "@pnpm/installing.package-requester": "1102.0.0"
75
+ "@pnpm/testing.registry-mock": "1100.0.7"
76
76
  },
77
77
  "engines": {
78
78
  "node": ">=22.13"