@pnpm/error 1000.1.0 → 1100.0.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/README.md +1 -1
- package/lib/index.d.ts +14 -0
- package/lib/index.js +55 -12
- package/package.json +15 -11
- package/lib/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> An error class for pnpm errors
|
|
4
4
|
|
|
5
5
|
<!--@shields('npm')-->
|
|
6
|
-
[](https://
|
|
6
|
+
[](https://npmx.dev/package/@pnpm/error)
|
|
7
7
|
<!--/@-->
|
|
8
8
|
|
|
9
9
|
## Installation
|
package/lib/index.d.ts
CHANGED
|
@@ -27,6 +27,20 @@ export declare class FetchError extends PnpmError {
|
|
|
27
27
|
readonly request: FetchErrorRequest;
|
|
28
28
|
constructor(request: FetchErrorRequest, response: FetchErrorResponse, hint?: string);
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Strip `user:pass@` (or `user@`) userinfo that follows a URL scheme in any
|
|
32
|
+
* text, e.g. `GET https://user:pass@host/pkg: …` → `GET https://host/pkg: …`.
|
|
33
|
+
* A registry configured as `https://user:pass@host/` would otherwise leak its
|
|
34
|
+
* embedded basic-auth credentials into every error message that interpolates
|
|
35
|
+
* the request URL (terminal output, CI logs). `FetchError` already hides the
|
|
36
|
+
* auth *header*; this covers credentials carried in the URL itself.
|
|
37
|
+
*
|
|
38
|
+
* Implemented as a single forward scan rather than a regex: `text` is
|
|
39
|
+
* uncontrolled (it interpolates the request URL), so a backtracking pattern is
|
|
40
|
+
* a ReDoS vector, and the scan strips up to the **last** `@` in the authority
|
|
41
|
+
* so a raw `@` inside the password (`user:p@ss@host`) doesn't leak its tail.
|
|
42
|
+
*/
|
|
43
|
+
export declare function redactUrlCredentials(text: string): string;
|
|
30
44
|
export declare class LockfileMissingDependencyError extends PnpmError {
|
|
31
45
|
constructor(depPath: string);
|
|
32
46
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.LockfileMissingDependencyError = exports.FetchError = exports.PnpmError = void 0;
|
|
4
|
-
const constants_1 = require("@pnpm/constants");
|
|
5
|
-
class PnpmError extends Error {
|
|
1
|
+
import { WANTED_LOCKFILE } from '@pnpm/constants';
|
|
2
|
+
export class PnpmError extends Error {
|
|
6
3
|
code;
|
|
7
4
|
hint;
|
|
8
5
|
attempts;
|
|
@@ -15,8 +12,7 @@ class PnpmError extends Error {
|
|
|
15
12
|
this.attempts = opts?.attempts;
|
|
16
13
|
}
|
|
17
14
|
}
|
|
18
|
-
|
|
19
|
-
class FetchError extends PnpmError {
|
|
15
|
+
export class FetchError extends PnpmError {
|
|
20
16
|
response;
|
|
21
17
|
request;
|
|
22
18
|
constructor(request, response, hint) {
|
|
@@ -26,7 +22,7 @@ class FetchError extends PnpmError {
|
|
|
26
22
|
if (request.authHeaderValue) {
|
|
27
23
|
_request.authHeaderValue = hideAuthInformation(request.authHeaderValue);
|
|
28
24
|
}
|
|
29
|
-
const message = `GET ${request.url}: ${response.statusText} - ${response.status}`;
|
|
25
|
+
const message = `GET ${redactUrlCredentials(request.url)}: ${response.statusText} - ${response.status}`;
|
|
30
26
|
// NOTE: For security reasons, some registries respond with 404 on authentication errors as well.
|
|
31
27
|
// So we print authorization info on 404 errors as well.
|
|
32
28
|
if (response.status === 401 || response.status === 403 || response.status === 404) {
|
|
@@ -43,7 +39,55 @@ class FetchError extends PnpmError {
|
|
|
43
39
|
this.response = response;
|
|
44
40
|
}
|
|
45
41
|
}
|
|
46
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Strip `user:pass@` (or `user@`) userinfo that follows a URL scheme in any
|
|
44
|
+
* text, e.g. `GET https://user:pass@host/pkg: …` → `GET https://host/pkg: …`.
|
|
45
|
+
* A registry configured as `https://user:pass@host/` would otherwise leak its
|
|
46
|
+
* embedded basic-auth credentials into every error message that interpolates
|
|
47
|
+
* the request URL (terminal output, CI logs). `FetchError` already hides the
|
|
48
|
+
* auth *header*; this covers credentials carried in the URL itself.
|
|
49
|
+
*
|
|
50
|
+
* Implemented as a single forward scan rather than a regex: `text` is
|
|
51
|
+
* uncontrolled (it interpolates the request URL), so a backtracking pattern is
|
|
52
|
+
* a ReDoS vector, and the scan strips up to the **last** `@` in the authority
|
|
53
|
+
* so a raw `@` inside the password (`user:p@ss@host`) doesn't leak its tail.
|
|
54
|
+
*/
|
|
55
|
+
export function redactUrlCredentials(text) {
|
|
56
|
+
let result = '';
|
|
57
|
+
let cursor = 0;
|
|
58
|
+
while (cursor < text.length) {
|
|
59
|
+
const schemeSep = text.indexOf('://', cursor);
|
|
60
|
+
if (schemeSep === -1)
|
|
61
|
+
return result + text.slice(cursor);
|
|
62
|
+
const authorityStart = schemeSep + 3;
|
|
63
|
+
result += text.slice(cursor, authorityStart);
|
|
64
|
+
cursor = authorityStart;
|
|
65
|
+
// Only treat `://` as a URL authority boundary when a scheme character
|
|
66
|
+
// (schemes end in an ASCII alphanumeric) sits right before it; otherwise a
|
|
67
|
+
// bare `://` in the text is left untouched.
|
|
68
|
+
if (schemeSep === 0 || !isSchemeTailChar(text.charCodeAt(schemeSep - 1)))
|
|
69
|
+
continue;
|
|
70
|
+
// Userinfo runs to the last `@` within the authority, which itself ends at
|
|
71
|
+
// the first `/`, `?`, `#`, or whitespace.
|
|
72
|
+
let lastAt = -1;
|
|
73
|
+
for (let i = authorityStart; i < text.length; i++) {
|
|
74
|
+
const code = text.charCodeAt(i);
|
|
75
|
+
if (code === 0x2f || code === 0x3f || code === 0x23 || isAsciiWhitespace(code))
|
|
76
|
+
break;
|
|
77
|
+
if (code === 0x40)
|
|
78
|
+
lastAt = i;
|
|
79
|
+
}
|
|
80
|
+
if (lastAt !== -1)
|
|
81
|
+
cursor = lastAt + 1;
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
function isSchemeTailChar(code) {
|
|
86
|
+
return (code >= 0x30 && code <= 0x39) || (code >= 0x41 && code <= 0x5a) || (code >= 0x61 && code <= 0x7a);
|
|
87
|
+
}
|
|
88
|
+
function isAsciiWhitespace(code) {
|
|
89
|
+
return code === 0x20 || code === 0x09 || code === 0x0a || code === 0x0b || code === 0x0c || code === 0x0d;
|
|
90
|
+
}
|
|
47
91
|
function hideAuthInformation(authHeaderValue) {
|
|
48
92
|
const [authType, token] = authHeaderValue.split(' ');
|
|
49
93
|
if (token == null)
|
|
@@ -53,14 +97,13 @@ function hideAuthInformation(authHeaderValue) {
|
|
|
53
97
|
}
|
|
54
98
|
return `${authType} ${token.substring(0, 4)}[hidden]`;
|
|
55
99
|
}
|
|
56
|
-
class LockfileMissingDependencyError extends PnpmError {
|
|
100
|
+
export class LockfileMissingDependencyError extends PnpmError {
|
|
57
101
|
constructor(depPath) {
|
|
58
|
-
const message = `Broken lockfile: no entry for '${depPath}' in ${
|
|
102
|
+
const message = `Broken lockfile: no entry for '${depPath}' in ${WANTED_LOCKFILE}`;
|
|
59
103
|
super('LOCKFILE_MISSING_DEPENDENCY', message, {
|
|
60
104
|
hint: 'This issue is probably caused by a badly resolved merge conflict.\n' +
|
|
61
105
|
'To fix the lockfile, run \'pnpm install --no-frozen-lockfile\'.',
|
|
62
106
|
});
|
|
63
107
|
}
|
|
64
108
|
}
|
|
65
|
-
exports.LockfileMissingDependencyError = LockfileMissingDependencyError;
|
|
66
109
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/error",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1100.0.1",
|
|
4
4
|
"description": "An error class for pnpm errors",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
7
|
-
"
|
|
7
|
+
"pnpm11",
|
|
8
8
|
"error"
|
|
9
9
|
],
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"funding": "https://opencollective.com/pnpm",
|
|
12
|
-
"repository":
|
|
13
|
-
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/pnpm/pnpm/tree/main/pnpm11/core/error"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/core/error#readme",
|
|
14
17
|
"bugs": {
|
|
15
18
|
"url": "https://github.com/pnpm/pnpm/issues"
|
|
16
19
|
},
|
|
17
|
-
"type": "
|
|
20
|
+
"type": "module",
|
|
18
21
|
"main": "lib/index.js",
|
|
19
22
|
"types": "lib/index.d.ts",
|
|
20
23
|
"exports": {
|
|
@@ -25,21 +28,22 @@
|
|
|
25
28
|
"!*.map"
|
|
26
29
|
],
|
|
27
30
|
"dependencies": {
|
|
28
|
-
"@pnpm/constants": "
|
|
31
|
+
"@pnpm/constants": "1100.0.0"
|
|
29
32
|
},
|
|
30
33
|
"devDependencies": {
|
|
31
|
-
"@
|
|
34
|
+
"@jest/globals": "30.4.1",
|
|
35
|
+
"@pnpm/error": "1100.0.1"
|
|
32
36
|
},
|
|
33
37
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
38
|
+
"node": ">=22.13"
|
|
35
39
|
},
|
|
36
40
|
"jest": {
|
|
37
41
|
"preset": "@pnpm/jest-config"
|
|
38
42
|
},
|
|
39
43
|
"scripts": {
|
|
40
44
|
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
45
|
+
"test": "pn compile && pn .test",
|
|
46
|
+
"compile": "tsgo --build && pn lint --fix",
|
|
47
|
+
".test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
|
|
44
48
|
}
|
|
45
49
|
}
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+CAAiD;AAEjD,MAAa,SAAU,SAAQ,KAAK;IAClB,IAAI,CAAQ;IACZ,IAAI,CAAS;IACtB,QAAQ,CAAS;IACjB,MAAM,CAAS;IACf,SAAS,CAAuD;IACvE,YACE,IAAY,EACZ,OAAe,EACf,IAIC;QAED,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,CAAA;QACpE,IAAI,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,CAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,IAAI,EAAE,QAAQ,CAAA;IAChC,CAAC;CACF;AApBD,8BAoBC;AAMD,MAAa,UAAW,SAAQ,SAAS;IACvB,QAAQ,CAAoB;IAC5B,OAAO,CAAmB;IAE1C,YACE,OAA0B,EAC1B,QAA4B,EAC5B,IAAa;QAEb,MAAM,QAAQ,GAAsB;YAClC,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAA;QACD,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAC5B,QAAQ,CAAC,eAAe,GAAG,mBAAmB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;QACzE,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAA;QACjF,iGAAiG;QACjG,wDAAwD;QACxD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAClF,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;YAChC,IAAI,QAAQ,CAAC,eAAe,EAAE,CAAC;gBAC7B,IAAI,IAAI,qCAAqC,QAAQ,CAAC,eAAe,EAAE,CAAA;YACzE,CAAC;iBAAM,CAAC;gBACN,IAAI,IAAI,kDAAkD,CAAA;YAC5D,CAAC;QACH,CAAC;QACD,KAAK,CAAC,SAAS,QAAQ,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAA;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;CACF;AA9BD,gCA8BC;AAED,SAAS,mBAAmB,CAAE,eAAuB;IACnD,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACpD,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,UAAU,CAAA;IACpC,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACtB,OAAO,GAAG,QAAQ,WAAW,CAAA;IAC/B,CAAC;IACD,OAAO,GAAG,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAA;AACvD,CAAC;AAED,MAAa,8BAA+B,SAAQ,SAAS;IAC3D,YAAa,OAAe;QAC1B,MAAM,OAAO,GAAG,kCAAkC,OAAO,QAAQ,2BAAe,EAAE,CAAA;QAClF,KAAK,CAAC,6BAA6B,EAAE,OAAO,EAAE;YAC5C,IAAI,EAAE,qEAAqE;gBACzE,iEAAiE;SACpE,CAAC,CAAA;IACJ,CAAC;CACF;AARD,wEAQC"}
|