@pnpm/lockfile.utils 1100.0.12 → 1100.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/lib/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export { packageIdFromSnapshot } from './packageIdFromSnapshot.js';
4
4
  export { packageIsIndependent } from './packageIsIndependent.js';
5
5
  export { pkgSnapshotToResolution } from './pkgSnapshotToResolution.js';
6
6
  export { refIsLocalDirectory, refIsLocalTarball } from './refIsLocalTarball.js';
7
- export { isGitHostedTarballUrl, toLockfileResolution } from './toLockfileResolution.js';
7
+ export { toLockfileResolution } from './toLockfileResolution.js';
8
8
  export * from '@pnpm/lockfile.types';
9
+ export { isGitHostedTarballUrl } from '@pnpm/resolving.resolver-base';
9
10
  export declare const getPkgShortId: typeof refToRelative;
package/lib/index.js CHANGED
@@ -4,8 +4,9 @@ export { packageIdFromSnapshot } from './packageIdFromSnapshot.js';
4
4
  export { packageIsIndependent } from './packageIsIndependent.js';
5
5
  export { pkgSnapshotToResolution } from './pkgSnapshotToResolution.js';
6
6
  export { refIsLocalDirectory, refIsLocalTarball } from './refIsLocalTarball.js';
7
- export { isGitHostedTarballUrl, toLockfileResolution } from './toLockfileResolution.js';
7
+ export { toLockfileResolution } from './toLockfileResolution.js';
8
8
  export * from '@pnpm/lockfile.types';
9
+ export { isGitHostedTarballUrl } from '@pnpm/resolving.resolver-base';
9
10
  // for backward compatibility
10
11
  export const getPkgShortId = refToRelative;
11
12
  //# sourceMappingURL=index.js.map
@@ -1,38 +1,21 @@
1
1
  import url from 'node:url';
2
2
  import * as dp from '@pnpm/deps.path';
3
3
  import { PnpmError } from '@pnpm/error';
4
- import getNpmTarballUrl from 'get-npm-tarball-url';
4
+ import { getNpmTarballUrl } from '@pnpm/resolving.tarball-url';
5
5
  import { nameVerFromPkgSnapshot } from './nameVerFromPkgSnapshot.js';
6
- import { isGitHostedTarballUrl } from './toLockfileResolution.js';
7
6
  export function pkgSnapshotToResolution(depPath, pkgSnapshot, registries) {
8
7
  const resolution = pkgSnapshot.resolution;
9
- // Tarball-shaped resolutions (no `type` field) must carry `integrity`,
10
- // except where the URL itself anchors the bytes:
11
- // - `file:` tarballs (local file on the user's machine; integrity
12
- // adds nothing the user doesn't already control).
13
- // - Git-hosted tarballs (URL contains the commit SHA; git's content-
14
- // addressed model binds the bytes to the commit). The `gitHosted`
15
- // flag may be absent on legacy lockfiles, so fall back to a URL
16
- // match — same logic as `toLockfileResolution`.
17
- // For any other tarball entry a missing integrity is what a tampered
18
- // lockfile looks like: the worker would mint a fresh integrity from
19
- // whatever bytes the URL returned, so we fail closed here. Pacquet
20
- // enforces the same invariant via
21
- // `pacquet_package_manager::missing_tarball_integrity`.
22
- if (resolution.type == null &&
23
- resolution.integrity == null &&
24
- !resolution.tarball?.startsWith('file:') &&
25
- !(resolution.gitHosted === true || (resolution.tarball != null && isGitHostedTarballUrl(resolution.tarball)))) {
26
- throw new PnpmError('MISSING_TARBALL_INTEGRITY', `Cannot install package "${depPath}": its lockfile entry has no "integrity" field, so pnpm cannot verify the downloaded tarball.`, { hint: 'The lockfile may be corrupted or have been tampered with. Restore it from a trusted source, or delete it and re-run installation without --frozen-lockfile to regenerate.' });
8
+ if (resolution.tarball != null && typeof resolution.tarball !== 'string') {
9
+ // Avoid URL string-coercion from malformed YAML lockfile values.
10
+ throw new PnpmError('INVALID_TARBALL_RESOLUTION', `Cannot install package "${depPath}": its lockfile entry has a non-string "tarball" field.`);
27
11
  }
28
12
  if (Boolean(resolution.type) ||
29
13
  resolution.tarball?.startsWith('file:') ||
30
14
  resolution.gitHosted === true) {
31
15
  return pkgSnapshot.resolution;
32
16
  }
33
- // Recover the tarball field for `file:` snapshots whose resolution lost
34
- // its tarball (e.g. lockfiles written by an earlier pnpm 11 version that
35
- // dropped the tarball under `lockfile-include-tarball-url=false`).
17
+ // Recover the tarball field for `file:` snapshots whose depPath is the only
18
+ // source of the local tarball reference.
36
19
  const nonSemverVersion = dp.parse(depPath).nonSemverVersion;
37
20
  if (nonSemverVersion?.startsWith('file:')) {
38
21
  return {
@@ -51,11 +34,11 @@ export function pkgSnapshotToResolution(depPath, pkgSnapshot, registries) {
51
34
  registry = registries.default;
52
35
  }
53
36
  let tarball;
54
- if (!pkgSnapshot.resolution.tarball) {
37
+ if (!resolution.tarball) {
55
38
  tarball = getTarball(registry);
56
39
  }
57
40
  else {
58
- tarball = new url.URL(pkgSnapshot.resolution.tarball, registry.endsWith('/') ? registry : `${registry}/`).toString();
41
+ tarball = new url.URL(resolution.tarball, registry.endsWith('/') ? registry : `${registry}/`).toString();
59
42
  }
60
43
  return {
61
44
  ...pkgSnapshot.resolution,
@@ -1,7 +1,6 @@
1
1
  import type { LockfileResolution } from '@pnpm/lockfile.types';
2
- import type { Resolution } from '@pnpm/resolving.resolver-base';
2
+ import { type Resolution } from '@pnpm/resolving.resolver-base';
3
3
  export declare function toLockfileResolution(pkg: {
4
4
  name: string;
5
5
  version: string;
6
6
  }, resolution: Resolution, registry: string, lockfileIncludeTarballUrl?: boolean): LockfileResolution;
7
- export declare function isGitHostedTarballUrl(url: string): boolean;
@@ -1,4 +1,5 @@
1
- import getNpmTarballUrl from 'get-npm-tarball-url';
1
+ import { isGitHostedTarballUrl } from '@pnpm/resolving.resolver-base';
2
+ import { isCanonicalRegistryTarballUrl } from '@pnpm/resolving.tarball-url';
2
3
  export function toLockfileResolution(pkg, resolution, registry, lockfileIncludeTarballUrl) {
3
4
  if (resolution.type !== undefined || !resolution['integrity']) {
4
5
  return resolution;
@@ -15,60 +16,29 @@ export function toLockfileResolution(pkg, resolution, registry, lockfileIncludeT
15
16
  // legacy lockfiles read by callers that don't enrich the field).
16
17
  const gitHosted = resolution.gitHosted === true ||
17
18
  isGitHostedTarballUrl(tarball);
18
- if (lockfileIncludeTarballUrl) {
19
- return preservingGitHosted({
20
- integrity: resolution['integrity'],
21
- tarball,
22
- }, gitHosted);
23
- }
24
- // Tarball URLs that cannot be reconstructed from the package name, version,
25
- // and registry must always stay in the lockfile, otherwise the package can
26
- // no longer be re-fetched. This covers local `file:` tarballs and tarballs
27
- // served by git providers (GitHub, GitLab, Bitbucket).
28
- if (tarball.startsWith('file:') || gitHosted) {
29
- return preservingGitHosted({
30
- integrity: resolution['integrity'],
31
- tarball,
32
- }, gitHosted);
33
- }
34
- // Sometimes packages are hosted under non-standard tarball URLs.
35
- // For instance, when they are hosted on npm Enterprise. See https://github.com/pnpm/pnpm/issues/867
36
- // Or in other weird cases, like https://github.com/pnpm/pnpm/issues/1072.
37
- // Even when the user explicitly sets `lockfileIncludeTarballUrl: false`, we
38
- // must preserve such URLs — otherwise the package cannot be re-fetched on a
39
- // frozen-lockfile install (e.g. GitHub Packages tarballs at
40
- // `https://npm.pkg.github.com/download/<scope>/<name>/<version>/<hash>`).
41
- // `lockfileIncludeTarballUrl` only controls whether URLs that *can* be
42
- // derived from name+version+registry are written.
43
- const expectedTarball = getNpmTarballUrl(pkg.name, pkg.version, { registry });
44
- const actualTarball = tarball.replaceAll('%2f', '/');
45
- if (removeProtocol(expectedTarball) !== removeProtocol(actualTarball)) {
46
- return preservingGitHosted({
47
- integrity: resolution['integrity'],
48
- tarball,
49
- }, gitHosted);
19
+ // A standard registry tarball whose URL can be rebuilt from the package name,
20
+ // version, and registry is written as just `{ integrity }` — pnpm derives the
21
+ // URL on demand. Every other tarball must keep its URL or it can no longer be
22
+ // re-fetched on a frozen-lockfile install: `file:` tarballs, git-provider
23
+ // tarballs (GitHub/GitLab/Bitbucket), and non-standard registry URLs such as
24
+ // npm Enterprise (https://github.com/pnpm/pnpm/issues/867) or GitHub Packages
25
+ // `/download/` URLs. `lockfileIncludeTarballUrl` forces the URL to be kept.
26
+ if (!lockfileIncludeTarballUrl &&
27
+ !gitHosted &&
28
+ !tarball.startsWith('file:') &&
29
+ isCanonicalRegistryTarballUrl(tarball, pkg, registry)) {
30
+ return { integrity: resolution['integrity'] };
50
31
  }
32
+ // The kept-URL form carries the `gitHosted` marker and the subdirectory `path`
33
+ // (`repo#commit&path:/sub/dir`, only ever set on git-hosted tarballs) so a
34
+ // git-hosted monorepo tarball still unpacks the right subfolder.
35
+ // See https://github.com/pnpm/pnpm/issues/12304.
36
+ const { path } = resolution;
51
37
  return {
52
38
  integrity: resolution['integrity'],
39
+ tarball,
40
+ ...(gitHosted ? { gitHosted: true } : {}),
41
+ ...(path == null ? {} : { path }),
53
42
  };
54
43
  }
55
- function preservingGitHosted(resolution, gitHosted) {
56
- return gitHosted ? { ...resolution, gitHosted: true } : resolution;
57
- }
58
- // Inlined to avoid pulling @pnpm/fetching.pick-fetcher into the lockfile-utils
59
- // dep graph. Used as a fallback when callers haven't pre-set the
60
- // `gitHosted` field on TarballResolution.
61
- export function isGitHostedTarballUrl(url) {
62
- // Schemes and hostnames are case-insensitive, so match against a lowercased
63
- // copy: a tampered `https://CODELOAD.GITHUB.COM/...` must not slip past as a
64
- // non-git-hosted (and therefore registry-trusted) tarball. Only the
65
- // lowercased copy is inspected; the original URL is never rewritten.
66
- const lowerUrl = url.toLowerCase();
67
- return (lowerUrl.startsWith('https://codeload.github.com/') ||
68
- lowerUrl.startsWith('https://bitbucket.org/') ||
69
- lowerUrl.startsWith('https://gitlab.com/')) && lowerUrl.includes('tar.gz');
70
- }
71
- function removeProtocol(url) {
72
- return url.split('://')[1];
73
- }
74
44
  //# sourceMappingURL=toLockfileResolution.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/lockfile.utils",
3
- "version": "1100.0.12",
3
+ "version": "1100.1.0",
4
4
  "description": "Utils for dealing with pnpm-lock.yaml",
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/lockfile/utils"
15
+ "url": "https://github.com/pnpm/pnpm/tree/main/pnpm11/lockfile/utils"
16
16
  },
17
- "homepage": "https://github.com/pnpm/pnpm/tree/main/lockfile/utils#readme",
17
+ "homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/lockfile/utils#readme",
18
18
  "bugs": {
19
19
  "url": "https://github.com/pnpm/pnpm/issues"
20
20
  },
@@ -29,22 +29,22 @@
29
29
  "!*.map"
30
30
  ],
31
31
  "dependencies": {
32
- "get-npm-tarball-url": "^2.1.0",
33
32
  "ramda": "npm:@pnpm/ramda@0.28.1",
34
- "@pnpm/deps.path": "1100.0.7",
35
- "@pnpm/lockfile.types": "1100.0.10",
36
- "@pnpm/resolving.resolver-base": "1100.4.1",
37
- "@pnpm/types": "1101.3.1",
38
- "@pnpm/hooks.types": "1100.0.11",
39
- "@pnpm/error": "1100.0.0"
33
+ "@pnpm/error": "1100.0.1",
34
+ "@pnpm/hooks.types": "1100.1.0",
35
+ "@pnpm/resolving.resolver-base": "1100.5.0",
36
+ "@pnpm/lockfile.types": "1100.0.12",
37
+ "@pnpm/resolving.tarball-url": "1100.0.0",
38
+ "@pnpm/deps.path": "1100.0.8",
39
+ "@pnpm/types": "1101.3.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@jest/globals": "30.3.0",
42
+ "@jest/globals": "30.4.1",
43
43
  "@types/ramda": "0.31.1",
44
44
  "tempy": "3.0.0",
45
45
  "write-yaml-file": "^6.0.0",
46
46
  "yaml-tag": "1.1.0",
47
- "@pnpm/lockfile.utils": "1100.0.12"
47
+ "@pnpm/lockfile.utils": "1100.1.0"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=22.13"