mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-07 08:47:11 -04:00
fix: propagate error cause when throwing PnpmError in @pnpm/npm-resolver (#10990)
Cherry-picked from main (831f574330).
This commit is contained in:
6
.changeset/deep-ads-hope.md
Normal file
6
.changeset/deep-ads-hope.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/npm-resolver": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
When package metadata is malformed or can't be fetched, the error thrown will now show the originating error.
|
||||
5
.changeset/stale-regions-like.md
Normal file
5
.changeset/stale-regions-like.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/error": minor
|
||||
---
|
||||
|
||||
The `PnpmError` class now accepts an optional `cause` argument.
|
||||
37
.claude.bak/settings.local.json
Normal file
37
.claude.bak/settings.local.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git show:*)",
|
||||
"Bash(pnpm --filter @pnpm/reviewing.dependencies-hierarchy test)",
|
||||
"Bash(git stash:*)",
|
||||
"Bash(pnpm --filter @pnpm/list test:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(npm info:*)",
|
||||
"Bash(node -e:*)",
|
||||
"Bash(pnpm --filter @pnpm/reviewing.dependencies-hierarchy run compile:*)",
|
||||
"Bash(pnpm run compile:*)",
|
||||
"Bash(pnpm exec tsc:*)",
|
||||
"Bash(pnpm install:*)",
|
||||
"Bash(CI=true pnpm install:*)",
|
||||
"Bash(pnpm --filter @pnpm/list run compile:*)",
|
||||
"Bash(pnpm --filter @pnpm/reviewing.dependencies-hierarchy test -- test/getTree.test.ts)",
|
||||
"Bash(git cherry-pick:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(pnpm -w lint:*)",
|
||||
"Bash(pnpm:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(find:*)",
|
||||
"Bash(node:*)",
|
||||
"Bash(git status:*)",
|
||||
"Bash(gh issue view:*)",
|
||||
"Bash(/Users/zoltan/Library/pnpm/.tools/pnpm-exe/10.30.2/pnpm:*)",
|
||||
"Bash(gh:*)",
|
||||
"Bash(git log:*)",
|
||||
"Bash(npx jest:*)",
|
||||
"Bash(cd /Volumes/src/pnpm/pnpm/v10 && node -e \"console.log\\(require\\('path'\\).resolve\\('pnpm/dist/pnpm.cjs'\\)\\)\")",
|
||||
"Bash(cd /tmp/cdxgen-test && npx pnpm@10.32.0 install 2>&1 | tail -20)",
|
||||
"Bash(cd /tmp/cdxgen-test && npx pnpm@10.32.0 install 2>&1 | tail -25)",
|
||||
"Bash(cd /tmp/cdxgen-test && COREPACK_ENABLE_STRICT=0 npx pnpm@10.32.0 install --config.manage-package-manager-versions=false 2>&1 | tail -25)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,10 @@ export class PnpmError extends Error {
|
||||
opts?: {
|
||||
attempts?: number
|
||||
hint?: string
|
||||
cause?: unknown
|
||||
}
|
||||
) {
|
||||
super(message)
|
||||
super(message, { cause: opts?.cause })
|
||||
this.code = code.startsWith('ERR_PNPM_') ? code : `ERR_PNPM_${code}`
|
||||
this.hint = opts?.hint
|
||||
this.attempts = opts?.attempts
|
||||
|
||||
@@ -1,4 +1,22 @@
|
||||
import { FetchError } from '@pnpm/error'
|
||||
import { FetchError, PnpmError } from '@pnpm/error'
|
||||
|
||||
test('PnpmError exposes cause when provided', () => {
|
||||
const cause = new Error('original failure')
|
||||
const error = new PnpmError('TEST_CODE', 'something went wrong', { cause })
|
||||
expect(error.cause).toBe(cause)
|
||||
expect(error.message).toBe('something went wrong')
|
||||
expect(error.code).toBe('ERR_PNPM_TEST_CODE')
|
||||
})
|
||||
|
||||
test('PnpmError cause is undefined when omitted', () => {
|
||||
const error = new PnpmError('TEST_CODE', 'something went wrong')
|
||||
expect(error.cause).toBeUndefined()
|
||||
})
|
||||
|
||||
test('PnpmError cause works with non-Error values', () => {
|
||||
const error = new PnpmError('TEST_CODE', 'something went wrong', { cause: 'string cause' })
|
||||
expect(error.cause).toBe('string cause')
|
||||
})
|
||||
|
||||
test('FetchError escapes auth tokens', () => {
|
||||
const error = new FetchError(
|
||||
|
||||
94
pnpm-lock.yaml
generated
94
pnpm-lock.yaml
generated
@@ -1,3 +1,97 @@
|
||||
---
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
configDependencies: {}
|
||||
packageManagerDependencies:
|
||||
'@pnpm/exe':
|
||||
specifier: 10.32.0
|
||||
version: 10.32.0
|
||||
pnpm:
|
||||
specifier: 10.32.0
|
||||
version: 10.32.0
|
||||
|
||||
packages:
|
||||
|
||||
'@pnpm/exe@10.32.0':
|
||||
resolution: {integrity: sha512-H31SnAhyywSTVWoefDAGOgHHBtVcct8i1YI5/lx6crzGN62ZAZtXmJEJuMVeU6oP/H7Qu/CHiR5bXO1jENlT1Q==}
|
||||
hasBin: true
|
||||
|
||||
'@pnpm/linux-arm64@10.32.0':
|
||||
resolution: {integrity: sha512-wvzrCqm8IsE4sT4wdcCSJ1DDqTte7hylbCePyT19/Y7p4upGOi9QUap6ktHzPhpvBCsEaavLW6fdOUg+n6NFkw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
hasBin: true
|
||||
|
||||
'@pnpm/linux-x64@10.32.0':
|
||||
resolution: {integrity: sha512-a1VRqz/NTTR+L9WMNT5MxFtBIo4pi3TdvhCyqqrCjyw7X/g2bkEJPI0vRfSLcJfs3pSqxSUEsYh+qHHxYBiFHA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
hasBin: true
|
||||
|
||||
'@pnpm/macos-arm64@10.32.0':
|
||||
resolution: {integrity: sha512-4y3SRDTrwk/URktsPSkjS/JgjjnTvy1UcdJ7ezCKAfw5IQSvVvT6a69x3QU3bXw4iOaQKJ7qHr5efX66Z8Zq/A==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
hasBin: true
|
||||
|
||||
'@pnpm/macos-x64@10.32.0':
|
||||
resolution: {integrity: sha512-0/iounIfwFuCp2guNXy9hWFcwSK2erTGlmErbRH6nk+HFr7wyBOfIAiOBFW0695FENjLg+OuVSFW8Xy+86+amA==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
hasBin: true
|
||||
|
||||
'@pnpm/win-arm64@10.32.0':
|
||||
resolution: {integrity: sha512-54hfmPtrzV3I1pI7v/kgOVqjzhoIQruIl+7zWcAR3XPlugNXU9Y4jP64tIXViTwQd/PXreBKfaD5gVID/Pr2VA==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
hasBin: true
|
||||
|
||||
'@pnpm/win-x64@10.32.0':
|
||||
resolution: {integrity: sha512-PTZOFFCiDuMZ++OxYtXEx12syUsEAeBm8eGUReVOZwbfx+Jo9sSyGaV0UuP6c06Hc2uispLeU56d2/6VSGgs3w==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
hasBin: true
|
||||
|
||||
pnpm@10.32.0:
|
||||
resolution: {integrity: sha512-myY0uz/tVgHDNjPy2SWT9QYnCjljuMUdKy1qgo2mFc5One6++WFMzrvBOsjTwPnJzM61g8achXhDb6R327INcA==}
|
||||
engines: {node: '>=18.12'}
|
||||
hasBin: true
|
||||
|
||||
snapshots:
|
||||
|
||||
'@pnpm/exe@10.32.0':
|
||||
optionalDependencies:
|
||||
'@pnpm/linux-arm64': 10.32.0
|
||||
'@pnpm/linux-x64': 10.32.0
|
||||
'@pnpm/macos-arm64': 10.32.0
|
||||
'@pnpm/macos-x64': 10.32.0
|
||||
'@pnpm/win-arm64': 10.32.0
|
||||
'@pnpm/win-x64': 10.32.0
|
||||
|
||||
'@pnpm/linux-arm64@10.32.0':
|
||||
optional: true
|
||||
|
||||
'@pnpm/linux-x64@10.32.0':
|
||||
optional: true
|
||||
|
||||
'@pnpm/macos-arm64@10.32.0':
|
||||
optional: true
|
||||
|
||||
'@pnpm/macos-x64@10.32.0':
|
||||
optional: true
|
||||
|
||||
'@pnpm/win-arm64@10.32.0':
|
||||
optional: true
|
||||
|
||||
'@pnpm/win-x64@10.32.0':
|
||||
optional: true
|
||||
|
||||
pnpm@10.32.0: {}
|
||||
|
||||
---
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
|
||||
@@ -79,7 +79,7 @@ export async function fetchMetadataFromFromRegistry (
|
||||
timeout: fetchOpts.timeout,
|
||||
}) as RegistryResponse
|
||||
} catch (error: any) { // eslint-disable-line
|
||||
reject(new PnpmError('META_FETCH_FAIL', `GET ${uri}: ${error.message as string}`, { attempts: attempt }))
|
||||
reject(new PnpmError('META_FETCH_FAIL', `GET ${uri}: ${error.message as string}`, { attempts: attempt, cause: error }))
|
||||
return
|
||||
}
|
||||
if (response.status > 400) {
|
||||
|
||||
@@ -88,7 +88,7 @@ export function pickPackageFromMeta (
|
||||
}
|
||||
throw new PnpmError('MALFORMED_METADATA',
|
||||
`Received malformed metadata for "${spec.name}"`,
|
||||
{ hint: 'This might mean that the package was unpublished from the registry' }
|
||||
{ hint: 'This might mean that the package was unpublished from the registry', cause: err }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,8 +799,19 @@ test('error is thrown when registry not responding', async () => {
|
||||
default: notExistingRegistry,
|
||||
},
|
||||
})
|
||||
await expect(resolveFromNpm({ alias: notExistingPackage, bareSpecifier: '1.0.0' }, {})).rejects
|
||||
.toThrow(new PnpmError('META_FETCH_FAIL', `GET ${notExistingRegistry}/${notExistingPackage}: request to ${notExistingRegistry}/${notExistingPackage} failed, reason: getaddrinfo ENOTFOUND not-existing.pnpm.io`, { attempts: 1 }))
|
||||
|
||||
let thrown: any // eslint-disable-line
|
||||
try {
|
||||
await resolveFromNpm({ alias: notExistingPackage, bareSpecifier: '1.0.0' }, {})
|
||||
} catch (err) {
|
||||
thrown = err
|
||||
}
|
||||
expect(thrown).toBeTruthy()
|
||||
expect(thrown.code).toBe('ERR_PNPM_META_FETCH_FAIL')
|
||||
expect(thrown.message).toContain(`GET ${notExistingRegistry}/${notExistingPackage}:`)
|
||||
expect(thrown.message).toContain('ENOTFOUND')
|
||||
expect(thrown.cause).toBeTruthy()
|
||||
expect(thrown.cause.code).toBe('ENOTFOUND')
|
||||
})
|
||||
|
||||
test('extra info is shown if package has valid semver appended', async () => {
|
||||
@@ -1836,10 +1847,18 @@ test('request to a package with no dist-tags', async () => {
|
||||
registries,
|
||||
})
|
||||
|
||||
await expect(resolveFromNpm({ alias: 'is-positive' }, {})).rejects
|
||||
.toThrow(
|
||||
new PnpmError('MALFORMED_METADATA', 'Received malformed metadata for "is-positive"')
|
||||
)
|
||||
let thrown: any // eslint-disable-line
|
||||
try {
|
||||
await resolveFromNpm({ alias: 'is-positive' }, {})
|
||||
} catch (err) {
|
||||
thrown = err
|
||||
}
|
||||
expect(thrown).toBeTruthy()
|
||||
expect(thrown.code).toBe('ERR_PNPM_MALFORMED_METADATA')
|
||||
expect(thrown.message).toBe('Received malformed metadata for "is-positive"')
|
||||
expect(thrown.hint).toBe('This might mean that the package was unpublished from the registry')
|
||||
expect(thrown.cause).toBeTruthy()
|
||||
expect(thrown.cause.message).toContain("Cannot read properties of undefined (reading 'latest')")
|
||||
})
|
||||
|
||||
test('resolveFromNpm() does not fail if the meta file contains no integrity information', async () => {
|
||||
|
||||
Reference in New Issue
Block a user