@pnpm/error 1100.2.0 → 1100.2.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @pnpm/error
2
2
 
3
+ ## 1100.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies:
8
+ - @pnpm/constants@1102.0.1
9
+
10
+ ## 1100.2.1
11
+
12
+ ### Patch Changes
13
+
14
+ - `pnpm install` now works in StackBlitz WebContainers on projects without a lockfile. It used to fail there with `ENOENT ... pnpm-lock.yaml`, because pnpm did not recognize the errors that WebContainers return from asynchronous file system calls [#15649](https://github.com/pnpm/pnpm/issues/15649).
15
+
3
16
  ## 1100.2.0
4
17
 
5
18
  ### Minor Changes
package/lib/index.d.ts CHANGED
@@ -38,6 +38,19 @@ export declare class FetchTimeoutError extends PnpmError {
38
38
  cause: unknown;
39
39
  });
40
40
  }
41
+ /**
42
+ * Strip `user:pass@` (or `user@`) userinfo that follows a URL scheme in any
43
+ * text, e.g. `GET https://user:pass@host/pkg: ...` → `GET https://host/pkg: ...`.
44
+ * A registry configured as `https://user:pass@host/` would otherwise leak its
45
+ * embedded basic-auth credentials into every error message that interpolates
46
+ * the request URL (terminal output, CI logs). `FetchError` already hides the
47
+ * auth *header*; this covers credentials carried in the URL itself.
48
+ *
49
+ * Implemented as a single forward scan rather than a regex: `text` is
50
+ * uncontrolled (it interpolates the request URL), so a backtracking pattern is
51
+ * a ReDoS vector, and the scan strips up to the **last** `@` in the authority
52
+ * so a raw `@` inside the password (`user:p@ss@host`) doesn't leak its tail.
53
+ */
41
54
  export declare function redactUrlCredentials(text: string): string;
42
55
  /**
43
56
  * Make untrusted, URL-bearing text safe to print or log: redact inline
@@ -68,3 +81,13 @@ export declare function redactAndSanitizeMultiline(text: string): string;
68
81
  export declare class LockfileMissingDependencyError extends PnpmError {
69
82
  constructor(depPath: string);
70
83
  }
84
+ /**
85
+ * Whether `value` is an `Error`, whichever way the runtime created it.
86
+ *
87
+ * `util.types.isNativeError` misses the errors that StackBlitz WebContainers
88
+ * reject asynchronous `fs` calls with: they inherit from `Error`, but the
89
+ * native constructor did not create them. `instanceof Error` misses errors
90
+ * from another realm, such as the ones code under Jest's VM contexts catches.
91
+ * Either check passing is enough.
92
+ */
93
+ export declare function isError(value: unknown): value is Error;
package/lib/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import util from 'node:util';
1
2
  import { WANTED_LOCKFILE } from '@pnpm/constants';
2
3
  export class PnpmError extends Error {
3
4
  code;
@@ -67,19 +68,6 @@ export class FetchTimeoutError extends PnpmError {
67
68
  });
68
69
  }
69
70
  }
70
- /**
71
- * Strip `user:pass@` (or `user@`) userinfo that follows a URL scheme in any
72
- * text, e.g. `GET https://user:pass@host/pkg: …` → `GET https://host/pkg: …`.
73
- * A registry configured as `https://user:pass@host/` would otherwise leak its
74
- * embedded basic-auth credentials into every error message that interpolates
75
- * the request URL (terminal output, CI logs). `FetchError` already hides the
76
- * auth *header*; this covers credentials carried in the URL itself.
77
- *
78
- * Implemented as a single forward scan rather than a regex: `text` is
79
- * uncontrolled (it interpolates the request URL), so a backtracking pattern is
80
- * a ReDoS vector, and the scan strips up to the **last** `@` in the authority
81
- * so a raw `@` inside the password (`user:p@ss@host`) doesn't leak its tail.
82
- */
83
71
  /**
84
72
  * A request URL made safe to print: its `user:pass@` userinfo and control
85
73
  * characters redacted ({@link redactAndSanitize}), then everything from the
@@ -106,6 +94,19 @@ function redactUrlSecrets(url) {
106
94
  return '[hidden]';
107
95
  return sanitized.split(/[?#]/)[0];
108
96
  }
97
+ /**
98
+ * Strip `user:pass@` (or `user@`) userinfo that follows a URL scheme in any
99
+ * text, e.g. `GET https://user:pass@host/pkg: ...` → `GET https://host/pkg: ...`.
100
+ * A registry configured as `https://user:pass@host/` would otherwise leak its
101
+ * embedded basic-auth credentials into every error message that interpolates
102
+ * the request URL (terminal output, CI logs). `FetchError` already hides the
103
+ * auth *header*; this covers credentials carried in the URL itself.
104
+ *
105
+ * Implemented as a single forward scan rather than a regex: `text` is
106
+ * uncontrolled (it interpolates the request URL), so a backtracking pattern is
107
+ * a ReDoS vector, and the scan strips up to the **last** `@` in the authority
108
+ * so a raw `@` inside the password (`user:p@ss@host`) doesn't leak its tail.
109
+ */
109
110
  export function redactUrlCredentials(text) {
110
111
  let result = '';
111
112
  let cursor = 0;
@@ -121,21 +122,23 @@ export function redactUrlCredentials(text) {
121
122
  // bare `://` in the text is left untouched.
122
123
  if (schemeSep === 0 || !isSchemeTailChar(text.charCodeAt(schemeSep - 1)))
123
124
  continue;
124
- // Userinfo runs to the last `@` within the authority, which itself ends at
125
- // the first `/`, `?`, `#`, or whitespace.
126
- let lastAt = -1;
127
- for (let i = authorityStart; i < text.length; i++) {
128
- const code = text.charCodeAt(i);
129
- if (code === 0x2f || code === 0x3f || code === 0x23 || isAsciiWhitespace(code))
130
- break;
131
- if (code === 0x40)
132
- lastAt = i;
133
- }
134
- if (lastAt !== -1)
135
- cursor = lastAt + 1;
125
+ const userinfoEnd = findAuthorityUserinfoEnd(text, authorityStart);
126
+ if (userinfoEnd !== -1)
127
+ cursor = userinfoEnd;
136
128
  }
137
129
  return result;
138
130
  }
131
+ function findAuthorityUserinfoEnd(text, authorityStart) {
132
+ let lastAt = -1;
133
+ for (let index = authorityStart; index < text.length; index++) {
134
+ const code = text.charCodeAt(index);
135
+ if (code === 0x2f || code === 0x3f || code === 0x23 || isAsciiWhitespace(code))
136
+ break;
137
+ if (code === 0x40)
138
+ lastAt = index;
139
+ }
140
+ return lastAt === -1 ? -1 : lastAt + 1;
141
+ }
139
142
  /**
140
143
  * Make untrusted, URL-bearing text safe to print or log: redact inline
141
144
  * `user:pass@` credentials ({@link redactUrlCredentials}) and strip every
@@ -219,4 +222,16 @@ export class LockfileMissingDependencyError extends PnpmError {
219
222
  });
220
223
  }
221
224
  }
225
+ /**
226
+ * Whether `value` is an `Error`, whichever way the runtime created it.
227
+ *
228
+ * `util.types.isNativeError` misses the errors that StackBlitz WebContainers
229
+ * reject asynchronous `fs` calls with: they inherit from `Error`, but the
230
+ * native constructor did not create them. `instanceof Error` misses errors
231
+ * from another realm, such as the ones code under Jest's VM contexts catches.
232
+ * Either check passing is enough.
233
+ */
234
+ export function isError(value) {
235
+ return util.types.isNativeError(value) || value instanceof Error;
236
+ }
222
237
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/error",
3
- "version": "1100.2.0",
3
+ "version": "1100.2.2",
4
4
  "description": "An error class for pnpm errors",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -28,11 +28,11 @@
28
28
  "!*.map"
29
29
  ],
30
30
  "dependencies": {
31
- "@pnpm/constants": "1102.0.0"
31
+ "@pnpm/constants": "1102.0.1"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@jest/globals": "30.4.1",
35
- "@pnpm/error": "1100.2.0"
35
+ "@pnpm/error": "1100.2.2"
36
36
  },
37
37
  "engines": {
38
38
  "node": ">=22.13"