@socketsecurity/lib 5.20.1 → 5.23.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +116 -95
  2. package/README.md +24 -181
  3. package/dist/archives.js +13 -0
  4. package/dist/cacache.js +6 -8
  5. package/dist/cache-with-ttl.js +1 -1
  6. package/dist/constants/socket.js +1 -1
  7. package/dist/dlx/detect.js +25 -8
  8. package/dist/dlx/manifest.js +8 -19
  9. package/dist/dlx/package.js +16 -2
  10. package/dist/env/socket-cli.d.ts +4 -3
  11. package/dist/env/socket-cli.js +1 -1
  12. package/dist/errors.d.ts +96 -2
  13. package/dist/errors.js +55 -0
  14. package/dist/external/pony-cause.js +12 -11
  15. package/dist/fs.js +8 -2
  16. package/dist/github.js +3 -2
  17. package/dist/globs.js +5 -1
  18. package/dist/ipc.js +2 -2
  19. package/dist/json/edit.js +3 -2
  20. package/dist/json/parse.d.ts +47 -2
  21. package/dist/json/parse.js +40 -2
  22. package/dist/json/types.d.ts +49 -0
  23. package/dist/memoization.d.ts +4 -23
  24. package/dist/memoization.js +14 -54
  25. package/dist/packages/isolation.js +4 -4
  26. package/dist/packages/specs.js +9 -2
  27. package/dist/performance.js +3 -2
  28. package/dist/process-lock.js +4 -12
  29. package/dist/promise-queue.d.ts +9 -4
  30. package/dist/promise-queue.js +9 -7
  31. package/dist/promises.d.ts +41 -0
  32. package/dist/promises.js +19 -2
  33. package/dist/regexps.d.ts +4 -13
  34. package/dist/regexps.js +60 -3
  35. package/dist/releases/github.js +3 -2
  36. package/dist/releases/socket-btm.d.ts +61 -5
  37. package/dist/releases/socket-btm.js +2 -2
  38. package/dist/schema/parse.d.ts +26 -0
  39. package/dist/schema/parse.js +38 -0
  40. package/dist/schema/types.d.ts +121 -0
  41. package/dist/schema/validate.d.ts +35 -0
  42. package/dist/{validation/validate-schema.js → schema/validate.js} +4 -14
  43. package/dist/suppress-warnings.js +0 -2
  44. package/dist/url.js +5 -1
  45. package/dist/versions.js +2 -2
  46. package/dist/words.js +4 -7
  47. package/package.json +15 -15
  48. package/dist/validation/json-parser.d.ts +0 -58
  49. package/dist/validation/json-parser.js +0 -63
  50. package/dist/validation/types.d.ts +0 -118
  51. package/dist/validation/validate-schema.d.ts +0 -124
  52. /package/dist/{validation → schema}/types.js +0 -0
@@ -84,7 +84,7 @@ function createTtlCache(options) {
84
84
  }
85
85
  const escaped = fullPattern.replaceAll(/[.+?^${}()|[\]\\]/g, "\\$&");
86
86
  const regexPattern = escaped.replaceAll("*", ".*");
87
- const regex = new RegExp(`^${regexPattern}`);
87
+ const regex = new RegExp(`^${regexPattern}$`);
88
88
  return (key) => regex.test(key);
89
89
  }
90
90
  async function get(key) {
@@ -77,7 +77,7 @@ const SOCKET_FIREWALL_APP_NAME = "sfw";
77
77
  const SOCKET_REGISTRY_APP_NAME = "registry";
78
78
  const SOCKET_APP_PREFIX = "_";
79
79
  const SOCKET_LIB_NAME = "@socketsecurity/lib";
80
- const SOCKET_LIB_VERSION = "5.20.1";
80
+ const SOCKET_LIB_VERSION = "5.23.0";
81
81
  const SOCKET_LIB_URL = "https://github.com/SocketDev/socket-lib";
82
82
  const SOCKET_LIB_USER_AGENT = `socketsecurity-lib/${SOCKET_LIB_VERSION} (${SOCKET_LIB_URL})`;
83
83
  const SOCKET_IPC_HANDSHAKE = "SOCKET_IPC_HANDSHAKE";
@@ -33,7 +33,20 @@ var import_socket = require("../paths/socket");
33
33
  let _fs;
34
34
  let _path;
35
35
  const NODE_JS_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs"]);
36
+ const PACKAGE_JSON_PATH_CACHE_MAX_SIZE = 200;
37
+ const PACKAGE_JSON_NEGATIVE_TTL_MS = 1e4;
36
38
  const packageJsonPathCache = /* @__PURE__ */ new Map();
39
+ function packageJsonPathCacheSet(key, value) {
40
+ if (packageJsonPathCache.has(key)) {
41
+ packageJsonPathCache.delete(key);
42
+ } else if (packageJsonPathCache.size >= PACKAGE_JSON_PATH_CACHE_MAX_SIZE) {
43
+ const oldest = packageJsonPathCache.keys().next().value;
44
+ if (oldest !== void 0) {
45
+ packageJsonPathCache.delete(oldest);
46
+ }
47
+ }
48
+ packageJsonPathCache.set(key, { path: value, at: Date.now() });
49
+ }
37
50
  const packageJsonContentCache = /* @__PURE__ */ new Map();
38
51
  function findPackageJson(filePath) {
39
52
  const fs = /* @__PURE__ */ getFs();
@@ -41,25 +54,29 @@ function findPackageJson(filePath) {
41
54
  const startDir = path.dirname(path.resolve(filePath));
42
55
  const cached = packageJsonPathCache.get(startDir);
43
56
  if (cached !== void 0) {
44
- if (cached === null) {
45
- return void 0;
46
- }
47
- if (fs.existsSync(cached)) {
48
- return cached;
57
+ if (cached.path === null) {
58
+ if (Date.now() - cached.at < PACKAGE_JSON_NEGATIVE_TTL_MS) {
59
+ return void 0;
60
+ }
61
+ packageJsonPathCache.delete(startDir);
62
+ } else if (fs.existsSync(cached.path)) {
63
+ packageJsonPathCacheSet(startDir, cached.path);
64
+ return cached.path;
65
+ } else {
66
+ packageJsonPathCache.delete(startDir);
49
67
  }
50
- packageJsonPathCache.delete(startDir);
51
68
  }
52
69
  let currentDir = startDir;
53
70
  const root = path.parse(currentDir).root;
54
71
  while (currentDir !== root) {
55
72
  const packageJsonPath = path.join(currentDir, "package.json");
56
73
  if (fs.existsSync(packageJsonPath)) {
57
- packageJsonPathCache.set(startDir, packageJsonPath);
74
+ packageJsonPathCacheSet(startDir, packageJsonPath);
58
75
  return packageJsonPath;
59
76
  }
60
77
  currentDir = path.dirname(currentDir);
61
78
  }
62
- packageJsonPathCache.set(startDir, null);
79
+ packageJsonPathCacheSet(startDir, null);
63
80
  return void 0;
64
81
  }
65
82
  // @__NO_SIDE_EFFECTS__
@@ -26,6 +26,7 @@ __export(manifest_exports, {
26
26
  isPackageEntry: () => isPackageEntry
27
27
  });
28
28
  module.exports = __toCommonJS(manifest_exports);
29
+ var import_errors = require("../errors");
29
30
  var import_fs = require("../fs");
30
31
  var import_logger = require("../logger");
31
32
  var import_socket = require("../paths/socket");
@@ -79,9 +80,7 @@ class DlxManifest {
79
80
  }
80
81
  return JSON.parse(content);
81
82
  } catch (error) {
82
- logger.warn(
83
- `Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`
84
- );
83
+ logger.warn(`Failed to read manifest: ${(0, import_errors.errorMessage)(error)}`);
85
84
  return { __proto__: null };
86
85
  }
87
86
  }
@@ -94,9 +93,7 @@ class DlxManifest {
94
93
  try {
95
94
  (0, import_fs.safeMkdirSync)(manifestDir, { recursive: true });
96
95
  } catch (error) {
97
- logger.warn(
98
- `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
99
- );
96
+ logger.warn(`Failed to create manifest directory: ${(0, import_errors.errorMessage)(error)}`);
100
97
  }
101
98
  const content = JSON.stringify(data, null, 2);
102
99
  const tempPath = `${this.manifestPath}.tmp`;
@@ -130,9 +127,7 @@ class DlxManifest {
130
127
  delete data[name];
131
128
  await this.writeManifest(data);
132
129
  } catch (error) {
133
- logger.warn(
134
- `Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`
135
- );
130
+ logger.warn(`Failed to clear cache for ${name}: ${(0, import_errors.errorMessage)(error)}`);
136
131
  }
137
132
  });
138
133
  }
@@ -146,9 +141,7 @@ class DlxManifest {
146
141
  fs.unlinkSync(this.manifestPath);
147
142
  }
148
143
  } catch (error) {
149
- logger.warn(
150
- `Failed to clear all cache: ${error instanceof Error ? error.message : String(error)}`
151
- );
144
+ logger.warn(`Failed to clear all cache: ${(0, import_errors.errorMessage)(error)}`);
152
145
  }
153
146
  });
154
147
  }
@@ -180,9 +173,7 @@ class DlxManifest {
180
173
  const data = JSON.parse(content);
181
174
  return Object.keys(data);
182
175
  } catch (error) {
183
- logger.warn(
184
- `Failed to get package list: ${error instanceof Error ? error.message : String(error)}`
185
- );
176
+ logger.warn(`Failed to get package list: ${(0, import_errors.errorMessage)(error)}`);
186
177
  return [];
187
178
  }
188
179
  }
@@ -224,9 +215,7 @@ class DlxManifest {
224
215
  }
225
216
  }
226
217
  } catch (error) {
227
- logger.warn(
228
- `Failed to read existing manifest: ${error instanceof Error ? error.message : String(error)}`
229
- );
218
+ logger.warn(`Failed to read existing manifest: ${(0, import_errors.errorMessage)(error)}`);
230
219
  }
231
220
  data[name] = record;
232
221
  const manifestDir = path.dirname(this.manifestPath);
@@ -234,7 +223,7 @@ class DlxManifest {
234
223
  (0, import_fs.safeMkdirSync)(manifestDir, { recursive: true });
235
224
  } catch (error) {
236
225
  logger.warn(
237
- `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
226
+ `Failed to create manifest directory: ${(0, import_errors.errorMessage)(error)}`
238
227
  );
239
228
  }
240
229
  const content = JSON.stringify(data, null, 2);
@@ -43,6 +43,7 @@ __export(package_exports, {
43
43
  module.exports = __toCommonJS(package_exports);
44
44
  var import_platform = require("../constants/platform");
45
45
  var import_socket = require("../constants/socket");
46
+ var import_errors = require("../errors");
46
47
  var import_arborist = __toESM(require("../external/@npmcli/arborist"));
47
48
  var import_libnpmexec = __toESM(require("../external/libnpmexec"));
48
49
  var import_npm_package_arg = __toESM(require("../external/npm-package-arg"));
@@ -62,7 +63,19 @@ const FIREWALL_BLOCK_SEVERITIES = /* @__PURE__ */ new Set([
62
63
  "critical",
63
64
  "high"
64
65
  ]);
66
+ const BINARY_PATH_CACHE_MAX_SIZE = 200;
65
67
  const binaryPathCache = /* @__PURE__ */ new Map();
68
+ function binaryPathCacheSet(key, value) {
69
+ if (binaryPathCache.has(key)) {
70
+ binaryPathCache.delete(key);
71
+ } else if (binaryPathCache.size >= BINARY_PATH_CACHE_MAX_SIZE) {
72
+ const oldest = binaryPathCache.keys().next().value;
73
+ if (oldest !== void 0) {
74
+ binaryPathCache.delete(oldest);
75
+ }
76
+ }
77
+ binaryPathCache.set(key, value);
78
+ }
66
79
  async function checkFirewallPurls(arb, requestedPackage) {
67
80
  const idealTree = arb.idealTree;
68
81
  if (!idealTree) {
@@ -264,7 +277,7 @@ Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`
264
277
  await checkFirewallPurls(arb, packageName);
265
278
  await arb.reify({ save: true });
266
279
  } catch (e) {
267
- if (e instanceof Error && e.message.startsWith("Socket Firewall blocked")) {
280
+ if ((0, import_errors.isError)(e) && e.message.startsWith("Socket Firewall blocked")) {
268
281
  throw e;
269
282
  }
270
283
  const code = e?.code;
@@ -431,6 +444,7 @@ function resolveBinaryPath(basePath) {
431
444
  const cached = binaryPathCache.get(basePath);
432
445
  if (cached) {
433
446
  if (fs.existsSync(cached)) {
447
+ binaryPathCacheSet(basePath, cached);
434
448
  return cached;
435
449
  }
436
450
  binaryPathCache.delete(basePath);
@@ -439,7 +453,7 @@ function resolveBinaryPath(basePath) {
439
453
  for (const ext of extensions) {
440
454
  const testPath = basePath + ext;
441
455
  if (fs.existsSync(testPath)) {
442
- binaryPathCache.set(basePath, testPath);
456
+ binaryPathCacheSet(basePath, testPath);
443
457
  return testPath;
444
458
  }
445
459
  }
@@ -63,9 +63,10 @@ export declare function getSocketCliApiProxy(): string | undefined;
63
63
  */
64
64
  export declare function getSocketCliApiTimeout(): number;
65
65
  /**
66
- * Socket CLI API authentication token (alternative name).
67
- * Checks SOCKET_CLI_API_TOKEN, SOCKET_CLI_API_KEY, SOCKET_SECURITY_API_TOKEN, SOCKET_SECURITY_API_KEY.
68
- * Maintains full v1.x backward compatibility.
66
+ * Socket CLI API authentication token.
67
+ * Checks SOCKET_API_TOKEN (canonical), then the legacy names
68
+ * SOCKET_CLI_API_TOKEN, SOCKET_CLI_API_KEY, SOCKET_SECURITY_API_TOKEN,
69
+ * SOCKET_SECURITY_API_KEY. Maintains full v1.x backward compatibility.
69
70
  *
70
71
  * @returns API token or undefined
71
72
  *
@@ -56,7 +56,7 @@ function getSocketCliApiTimeout() {
56
56
  }
57
57
  // @__NO_SIDE_EFFECTS__
58
58
  function getSocketCliApiToken() {
59
- return (0, import_rewire.getEnvValue)("SOCKET_CLI_API_TOKEN") || (0, import_rewire.getEnvValue)("SOCKET_CLI_API_KEY") || (0, import_rewire.getEnvValue)("SOCKET_SECURITY_API_TOKEN") || (0, import_rewire.getEnvValue)("SOCKET_SECURITY_API_KEY");
59
+ return (0, import_rewire.getEnvValue)("SOCKET_API_TOKEN") || (0, import_rewire.getEnvValue)("SOCKET_CLI_API_TOKEN") || (0, import_rewire.getEnvValue)("SOCKET_CLI_API_KEY") || (0, import_rewire.getEnvValue)("SOCKET_SECURITY_API_TOKEN") || (0, import_rewire.getEnvValue)("SOCKET_SECURITY_API_KEY");
60
60
  }
61
61
  // @__NO_SIDE_EFFECTS__
62
62
  function getSocketCliBootstrapCacheDir() {
package/dist/errors.d.ts CHANGED
@@ -1,6 +1,100 @@
1
1
  /**
2
2
  * @fileoverview Error utilities with cause chain support.
3
- * Provides helpers for working with error causes and stack traces.
3
+ *
4
+ * Provides:
5
+ * - `isError(value)` — cross-realm-safe Error check (ES2025 `Error.isError`
6
+ * when available, `@@toStringTag` fallback otherwise).
7
+ * - `errorMessage(value)` — read the message (with cause chain) from any
8
+ * caught value, falling back to the shared `UNKNOWN_ERROR` sentinel.
9
+ * - `errorStack(value)` — read the stack (with cause chain) from any
10
+ * caught value, or `undefined` for non-Errors.
11
+ *
12
+ * `messageWithCauses` / `stackWithCauses` are re-exported from pony-cause;
13
+ * a patched copy recognizes cross-realm Errors via `isError`.
4
14
  */
15
+ import { UNKNOWN_ERROR } from './constants/core';
5
16
  import { messageWithCauses, stackWithCauses } from './external/pony-cause';
6
- export { messageWithCauses, stackWithCauses };
17
+ export { UNKNOWN_ERROR, messageWithCauses, stackWithCauses };
18
+ /**
19
+ * Spec-compliant [`Error.isError`](https://tc39.es/ecma262/#sec-error.iserror)
20
+ * with a fallback shim for engines that don't ship it yet.
21
+ *
22
+ * Returns `true` for Errors from any realm (worker threads, vm contexts,
23
+ * iframes) — things same-realm `instanceof Error` misses. Plain objects
24
+ * with `name` + `message` properties are **not** recognized.
25
+ *
26
+ * @example
27
+ * try {
28
+ * await doWork()
29
+ * } catch (e) {
30
+ * if (isError(e)) {
31
+ * logger.error(e.message)
32
+ * } else {
33
+ * logger.error(String(e))
34
+ * }
35
+ * }
36
+ */
37
+ /**
38
+ * `Error.isError` fallback shim — the in-language approximation used
39
+ * when the native ES2025 method isn't available.
40
+ *
41
+ * Exported separately so test suites on engines that ship the native
42
+ * method can still exercise the shim branch directly. Consumers should
43
+ * prefer {@link isError}, which picks the native method when present.
44
+ */
45
+ export declare function isErrorShim(value: unknown): value is Error;
46
+ /**
47
+ * Reference to the native ES2025 `Error.isError` when the running
48
+ * engine ships it, otherwise `undefined`. Exposed separately so tests
49
+ * and callers can detect the fast-path without re-probing.
50
+ */
51
+ export declare const isErrorBuiltin: ((value: unknown) => value is Error) | undefined;
52
+ /**
53
+ * Prefer the native ES2025 `Error.isError` when available (exact
54
+ * `[[ErrorData]]` slot check, cross-realm-safe); fall back to
55
+ * {@link isErrorShim} otherwise.
56
+ */
57
+ export declare const isError: (value: unknown) => value is Error;
58
+ /**
59
+ * Narrow a caught value to a Node.js `ErrnoException` — an Error with a
60
+ * `.code` string set by libuv/syscall failures (e.g. `'ENOENT'`,
61
+ * `'EACCES'`, `'EBUSY'`, `'EPERM'`). Cross-realm safe (builds on
62
+ * {@link isError}), and checks that `code` is a string so a merely
63
+ * branded Error without a real errno code returns `false`.
64
+ *
65
+ * @example
66
+ * try {
67
+ * await fsPromises.readFile(path)
68
+ * } catch (e) {
69
+ * if (isErrnoException(e) && e.code === 'ENOENT') {
70
+ * // … retry, or return default …
71
+ * } else {
72
+ * throw e
73
+ * }
74
+ * }
75
+ */
76
+ export declare function isErrnoException(value: unknown): value is NodeJS.ErrnoException;
77
+ /**
78
+ * Extract a human-readable message from any caught value.
79
+ *
80
+ * Walks the `cause` chain for Errors (via {@link messageWithCauses});
81
+ * coerces primitives and objects to string; returns
82
+ * {@link UNKNOWN_ERROR} for `null`, `undefined`, empty strings,
83
+ * `[object Object]`, or Errors with no message.
84
+ *
85
+ * @example
86
+ * try {
87
+ * await readConfig(path)
88
+ * } catch (e) {
89
+ * throw new Error(`Failed to read ${path}: ${errorMessage(e)}`, { cause: e })
90
+ * }
91
+ */
92
+ export declare function errorMessage(value: unknown): string;
93
+ /**
94
+ * Extract a stack trace (with causes) from any caught value.
95
+ *
96
+ * Returns the cause-aware stack via {@link stackWithCauses} for Errors;
97
+ * returns `undefined` for non-Error values, so callers can
98
+ * `logger.error(msg, { stack: errorStack(e) })` safely.
99
+ */
100
+ export declare function errorStack(value: unknown): string | undefined;
package/dist/errors.js CHANGED
@@ -20,13 +20,68 @@ var __copyProps = (to, from, except, desc) => {
20
20
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
21
  var errors_exports = {};
22
22
  __export(errors_exports, {
23
+ UNKNOWN_ERROR: () => import_core.UNKNOWN_ERROR,
24
+ errorMessage: () => errorMessage,
25
+ errorStack: () => errorStack,
26
+ isErrnoException: () => isErrnoException,
27
+ isError: () => isError,
28
+ isErrorBuiltin: () => isErrorBuiltin,
29
+ isErrorShim: () => isErrorShim,
23
30
  messageWithCauses: () => import_pony_cause.messageWithCauses,
24
31
  stackWithCauses: () => import_pony_cause.stackWithCauses
25
32
  });
26
33
  module.exports = __toCommonJS(errors_exports);
34
+ var import_core = require("./constants/core");
27
35
  var import_pony_cause = require("./external/pony-cause");
36
+ const ObjectPrototypeToString = Object.prototype.toString;
37
+ const ReflectApply = Reflect.apply;
38
+ function isErrorShim(value) {
39
+ if (value === null || typeof value !== "object") {
40
+ return false;
41
+ }
42
+ return ReflectApply(ObjectPrototypeToString, value, []) === "[object Error]";
43
+ }
44
+ const isErrorBuiltin = Error.isError;
45
+ const isError = isErrorBuiltin ?? isErrorShim;
46
+ function isErrnoException(value) {
47
+ if (!isError(value)) {
48
+ return false;
49
+ }
50
+ const code = value.code;
51
+ if (typeof code !== "string" || code.length === 0) {
52
+ return false;
53
+ }
54
+ const first = code.charCodeAt(0);
55
+ return first >= 65 && first <= 90;
56
+ }
57
+ function errorMessage(value) {
58
+ if (isError(value)) {
59
+ return (0, import_pony_cause.messageWithCauses)(value) || import_core.UNKNOWN_ERROR;
60
+ }
61
+ if (value === null || value === void 0) {
62
+ return import_core.UNKNOWN_ERROR;
63
+ }
64
+ const s = String(value);
65
+ if (s === "" || s === "[object Object]") {
66
+ return import_core.UNKNOWN_ERROR;
67
+ }
68
+ return s;
69
+ }
70
+ function errorStack(value) {
71
+ if (isError(value)) {
72
+ return (0, import_pony_cause.stackWithCauses)(value);
73
+ }
74
+ return void 0;
75
+ }
28
76
  // Annotate the CommonJS export names for ESM import in node:
29
77
  0 && (module.exports = {
78
+ UNKNOWN_ERROR,
79
+ errorMessage,
80
+ errorStack,
81
+ isErrnoException,
82
+ isError,
83
+ isErrorBuiltin,
84
+ isErrorShim,
30
85
  messageWithCauses,
31
86
  stackWithCauses
32
87
  });
@@ -11,9 +11,9 @@ var __commonJS = (cb, mod) => function __require() {
11
11
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
12
12
  };
13
13
 
14
- // node_modules/.pnpm/pony-cause@2.1.11/node_modules/pony-cause/lib/error-with-cause.js
14
+ // node_modules/.pnpm/pony-cause@2.1.11_patch_hash=39b2eb2567818b7c60126d03e252dbbabd8738082fca850582300d45b0a8cfb8/node_modules/pony-cause/lib/error-with-cause.js
15
15
  var require_error_with_cause = __commonJS({
16
- "node_modules/.pnpm/pony-cause@2.1.11/node_modules/pony-cause/lib/error-with-cause.js"(exports2, module2) {
16
+ "node_modules/.pnpm/pony-cause@2.1.11_patch_hash=39b2eb2567818b7c60126d03e252dbbabd8738082fca850582300d45b0a8cfb8/node_modules/pony-cause/lib/error-with-cause.js"(exports2, module2) {
17
17
  "use strict";
18
18
  var ErrorWithCause = class _ErrorWithCause extends Error {
19
19
  static {
@@ -41,13 +41,14 @@ var require_error_with_cause = __commonJS({
41
41
  }
42
42
  });
43
43
 
44
- // node_modules/.pnpm/pony-cause@2.1.11/node_modules/pony-cause/lib/helpers.js
44
+ // node_modules/.pnpm/pony-cause@2.1.11_patch_hash=39b2eb2567818b7c60126d03e252dbbabd8738082fca850582300d45b0a8cfb8/node_modules/pony-cause/lib/helpers.js
45
45
  var require_helpers = __commonJS({
46
- "node_modules/.pnpm/pony-cause@2.1.11/node_modules/pony-cause/lib/helpers.js"(exports2, module2) {
46
+ "node_modules/.pnpm/pony-cause@2.1.11_patch_hash=39b2eb2567818b7c60126d03e252dbbabd8738082fca850582300d45b0a8cfb8/node_modules/pony-cause/lib/helpers.js"(exports2, module2) {
47
47
  "use strict";
48
+ var isError = typeof Error.isError === "function" ? Error.isError : (v) => v !== null && typeof v === "object" && Object.prototype.toString.call(v) === "[object Error]";
48
49
  var findCauseByReference = /* @__PURE__ */ __name((err, reference) => {
49
50
  if (!err || !reference) return;
50
- if (!(err instanceof Error)) return;
51
+ if (!isError(err)) return;
51
52
  if (!(reference.prototype instanceof Error) && // @ts-ignore
52
53
  reference !== Error) return;
53
54
  const seen = /* @__PURE__ */ new Set();
@@ -66,13 +67,13 @@ var require_helpers = __commonJS({
66
67
  }
67
68
  if (typeof err.cause === "function") {
68
69
  const causeResult = err.cause();
69
- return causeResult instanceof Error ? causeResult : void 0;
70
+ return isError(causeResult) ? causeResult : void 0;
70
71
  } else {
71
- return err.cause instanceof Error ? err.cause : void 0;
72
+ return isError(err.cause) ? err.cause : void 0;
72
73
  }
73
74
  }, "getErrorCause");
74
75
  var _stackWithCauses = /* @__PURE__ */ __name((err, seen) => {
75
- if (!(err instanceof Error)) return "";
76
+ if (!isError(err)) return "";
76
77
  const stack = err.stack || "";
77
78
  if (seen.has(err)) {
78
79
  return stack + "\ncauses have become circular...";
@@ -87,7 +88,7 @@ var require_helpers = __commonJS({
87
88
  }, "_stackWithCauses");
88
89
  var stackWithCauses = /* @__PURE__ */ __name((err) => _stackWithCauses(err, /* @__PURE__ */ new Set()), "stackWithCauses");
89
90
  var _messageWithCauses = /* @__PURE__ */ __name((err, seen, skip) => {
90
- if (!(err instanceof Error)) return "";
91
+ if (!isError(err)) return "";
91
92
  const message = skip ? "" : err.message || "";
92
93
  if (seen.has(err)) {
93
94
  return message + ": ...";
@@ -116,9 +117,9 @@ var require_helpers = __commonJS({
116
117
  }
117
118
  });
118
119
 
119
- // node_modules/.pnpm/pony-cause@2.1.11/node_modules/pony-cause/index.js
120
+ // node_modules/.pnpm/pony-cause@2.1.11_patch_hash=39b2eb2567818b7c60126d03e252dbbabd8738082fca850582300d45b0a8cfb8/node_modules/pony-cause/index.js
120
121
  var require_pony_cause = __commonJS({
121
- "node_modules/.pnpm/pony-cause@2.1.11/node_modules/pony-cause/index.js"(exports2, module2) {
122
+ "node_modules/.pnpm/pony-cause@2.1.11_patch_hash=39b2eb2567818b7c60126d03e252dbbabd8738082fca850582300d45b0a8cfb8/node_modules/pony-cause/index.js"(exports2, module2) {
122
123
  "use strict";
123
124
  var { ErrorWithCause } = require_error_with_cause();
124
125
  var {
package/dist/fs.js CHANGED
@@ -167,7 +167,7 @@ async function findUp(name, options) {
167
167
  let dir = path.resolve(cwd);
168
168
  const { root } = path.parse(dir);
169
169
  const names = (0, import_arrays.isArray)(name) ? name : [name];
170
- while (dir && dir !== root) {
170
+ while (dir) {
171
171
  for (const n of names) {
172
172
  if (signal?.aborted) {
173
173
  return void 0;
@@ -184,6 +184,9 @@ async function findUp(name, options) {
184
184
  } catch {
185
185
  }
186
186
  }
187
+ if (dir === root) {
188
+ break;
189
+ }
187
190
  dir = path.dirname(dir);
188
191
  }
189
192
  return void 0;
@@ -210,7 +213,7 @@ function findUpSync(name, options) {
210
213
  const { root } = path.parse(dir);
211
214
  const stopDir = stopAt ? path.resolve(stopAt) : void 0;
212
215
  const names = (0, import_arrays.isArray)(name) ? name : [name];
213
- while (dir && dir !== root) {
216
+ while (dir) {
214
217
  if (stopDir && dir === stopDir) {
215
218
  for (const n of names) {
216
219
  const thePath = path.join(dir, n);
@@ -240,6 +243,9 @@ function findUpSync(name, options) {
240
243
  } catch {
241
244
  }
242
245
  }
246
+ if (dir === root) {
247
+ break;
248
+ }
243
249
  dir = path.dirname(dir);
244
250
  }
245
251
  return void 0;
package/dist/github.js CHANGED
@@ -45,6 +45,7 @@ var import_node_process = __toESM(require("node:process"));
45
45
  var import_cache_with_ttl = require("./cache-with-ttl");
46
46
  var import_github = require("./env/github");
47
47
  var import_socket_cli = require("./env/socket-cli");
48
+ var import_errors = require("./errors");
48
49
  var import_http_request = require("./http-request");
49
50
  var import_spawn = require("./spawn");
50
51
  const GITHUB_API_BASE_URL = "https://api.github.com";
@@ -80,7 +81,7 @@ async function fetchRefSha(owner, repo, ref, options) {
80
81
  return commitData.sha;
81
82
  } catch (e) {
82
83
  throw new Error(
83
- `failed to resolve ref "${ref}" for ${owner}/${repo}: ${e instanceof Error ? e.message : String(e)}`
84
+ `failed to resolve ref "${ref}" for ${owner}/${repo}: ${(0, import_errors.errorMessage)(e)}`
84
85
  );
85
86
  }
86
87
  }
@@ -165,7 +166,7 @@ async function fetchGitHub(url, options) {
165
166
  return JSON.parse(response.body.toString("utf8"));
166
167
  } catch (error) {
167
168
  throw new Error(
168
- `Failed to parse GitHub API response: ${error instanceof Error ? error.message : String(error)}
169
+ `Failed to parse GitHub API response: ${(0, import_errors.errorMessage)(error)}
169
170
  URL: ${url}
170
171
  Response may be malformed or incomplete.`,
171
172
  { cause: error }
package/dist/globs.js CHANGED
@@ -91,7 +91,11 @@ function getPicomatch() {
91
91
  function getGlobMatcher(glob2, options) {
92
92
  const patterns = Array.isArray(glob2) ? glob2 : [glob2];
93
93
  const sortedPatterns = [...patterns].sort();
94
- const sortedOptions = options ? Object.keys(options).sort().map((k) => `${k}:${JSON.stringify(options[k])}`).join(",") : "";
94
+ const sortedOptions = options ? Object.keys(options).sort().map((k) => {
95
+ const value = options[k];
96
+ const normalized = Array.isArray(value) ? [...value].sort() : value;
97
+ return `${k}:${JSON.stringify(normalized)}`;
98
+ }).join(",") : "";
95
99
  const key = `${sortedPatterns.join("|")}:${sortedOptions}`;
96
100
  const existing = matcherCache.get(key);
97
101
  if (existing) {
package/dist/ipc.js CHANGED
@@ -37,7 +37,7 @@ module.exports = __toCommonJS(ipc_exports);
37
37
  var import_node_process = __toESM(require("node:process"));
38
38
  var import_typebox = require("./external/@sinclair/typebox");
39
39
  var import_socket = require("./paths/socket");
40
- var import_validate_schema = require("./validation/validate-schema");
40
+ var import_parse = require("./schema/parse");
41
41
  const IpcStubSchema = import_typebox.Type.Object({
42
42
  /** Process ID that created the stub. */
43
43
  pid: import_typebox.Type.Integer({ minimum: 1 }),
@@ -100,7 +100,7 @@ async function writeIpcStub(appName, data) {
100
100
  pid: import_node_process.default.pid,
101
101
  timestamp: Date.now()
102
102
  };
103
- const validated = (0, import_validate_schema.parseSchema)(IpcStubSchema, ipcData);
103
+ const validated = (0, import_parse.parseSchema)(IpcStubSchema, ipcData);
104
104
  const fs = /* @__PURE__ */ getFs();
105
105
  const flags = fs.constants.O_CREAT | fs.constants.O_WRONLY | fs.constants.O_EXCL | fs.constants.O_NOFOLLOW;
106
106
  let handle;
package/dist/json/edit.js CHANGED
@@ -35,6 +35,7 @@ __export(edit_exports, {
35
35
  module.exports = __toCommonJS(edit_exports);
36
36
  var import_node_process = __toESM(require("node:process"));
37
37
  var import_promises = require("node:timers/promises");
38
+ var import_errors = require("../errors");
38
39
  var import_format = require("./format");
39
40
  const identSymbol = import_format.INDENT_SYMBOL;
40
41
  const newlineSymbol = import_format.NEWLINE_SYMBOL;
@@ -59,7 +60,7 @@ async function readFile(filepath) {
59
60
  return await fsPromises.readFile(filepath, "utf8");
60
61
  } catch (err) {
61
62
  const isLastAttempt = attempt === maxRetries;
62
- const isEnoent = err instanceof Error && "code" in err && err.code === "ENOENT";
63
+ const isEnoent = (0, import_errors.isErrnoException)(err) && err.code === "ENOENT";
63
64
  if (!isEnoent || isLastAttempt) {
64
65
  throw err;
65
66
  }
@@ -92,7 +93,7 @@ async function retryWrite(filepath, content, retries = 3, baseDelay = 10) {
92
93
  return;
93
94
  } catch (err) {
94
95
  const isLastAttempt = attempt === retries;
95
- const isRetriableError = err instanceof Error && "code" in err && (err.code === "EPERM" || err.code === "EBUSY" || err.code === "ENOENT");
96
+ const isRetriableError = (0, import_errors.isErrnoException)(err) && (err.code === "EPERM" || err.code === "EBUSY" || err.code === "ENOENT");
96
97
  if (!isRetriableError || isLastAttempt) {
97
98
  throw err;
98
99
  }
@@ -1,8 +1,11 @@
1
1
  /**
2
2
  * @fileoverview JSON parsing utilities with Buffer detection and BOM stripping.
3
- * Provides safe JSON parsing with automatic encoding handling.
3
+ * Provides safe JSON parsing with automatic encoding handling, plus
4
+ * `safeJsonParse` for untrusted input (prototype-pollution protection +
5
+ * size limits + optional schema validation).
4
6
  */
5
- import type { JsonParseOptions, JsonPrimitive, JsonValue } from './types';
7
+ import type { Schema } from '../schema/types';
8
+ import type { JsonParseOptions, JsonPrimitive, JsonValue, SafeJsonParseOptions } from './types';
6
9
  /**
7
10
  * Check if a value is a JSON primitive type.
8
11
  * JSON primitives are: `null`, `boolean`, `number`, or `string`.
@@ -76,3 +79,45 @@ export declare function isJsonPrimitive(value: unknown): value is JsonPrimitive;
76
79
  * ```
77
80
  */
78
81
  export declare function jsonParse(content: string | Buffer, options?: JsonParseOptions | undefined): JsonValue | undefined;
82
+ /**
83
+ * Safely parse JSON with optional schema validation and security controls.
84
+ * Throws on parse failure, validation failure, or security violation.
85
+ *
86
+ * Recommended for parsing untrusted JSON (user input, network payloads,
87
+ * anything beyond a trust boundary). Layers:
88
+ * 1. Size cap (default 10 MB) prevents memory exhaustion.
89
+ * 2. Prototype-pollution reviver rejects `__proto__` / `constructor` /
90
+ * `prototype` keys at any depth (unless `allowPrototype: true`).
91
+ * 3. Optional Zod-shaped schema validation via
92
+ * `@socketsecurity/lib/schema/validate`.
93
+ *
94
+ * For trusted-source reads (package.json, local config files), prefer
95
+ * `jsonParse()` — it offers Buffer/BOM handling and filepath-aware error
96
+ * messages, without the untrusted-input overhead.
97
+ *
98
+ * @throws {Error} When `jsonString` exceeds `maxSize`.
99
+ * @throws {Error} When JSON parsing fails.
100
+ * @throws {Error} When prototype-pollution keys are detected (and
101
+ * `allowPrototype` is not `true`).
102
+ * @throws {Error} When schema validation fails.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * // Basic parsing with type inference.
107
+ * const data = safeJsonParse<User>('{"name":"Alice","age":30}')
108
+ *
109
+ * // With schema validation.
110
+ * import { z } from 'zod'
111
+ * const userSchema = z.object({ name: z.string(), age: z.number() })
112
+ * const user = safeJsonParse('{"name":"Alice","age":30}', userSchema)
113
+ *
114
+ * // With size limit.
115
+ * const data = safeJsonParse(jsonString, undefined, { maxSize: 1024 })
116
+ *
117
+ * // Allow prototype keys (DANGEROUS — only for trusted sources).
118
+ * const data = safeJsonParse('{"__proto__":{}}', undefined, {
119
+ * allowPrototype: true,
120
+ * })
121
+ * ```
122
+ */
123
+ export declare function safeJsonParse<T = unknown>(jsonString: string, schema?: Schema<T> | undefined, options?: SafeJsonParseOptions): T;