@socketsecurity/lib 5.9.0 → 5.10.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/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [5.10.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.10.0) - 2026-03-14
9
+
10
+ ### Changed
11
+
12
+ - **releases/socket-btm**: Refactored `downloadSocketBtmRelease()` API for caller-controlled download paths
13
+ - Tool name moved from config object to required first parameter
14
+ - Config object is now optional second parameter (was required)
15
+ - Removed automatic `/${toolName}/${platformArch}` directory nesting - callers now have full control over download directory structure
16
+ - All optional parameters in config types now explicitly typed as `| undefined`
17
+ - Migration example:
18
+ - Before: `downloadSocketBtmRelease({ tool: 'lief', downloadDir: 'build' })`
19
+ - After: `downloadSocketBtmRelease('lief', { downloadDir: 'build' })`
20
+ - Rationale: Previous automatic path nesting created unexpected directory structures (e.g., `build/downloaded/lief/darwin-arm64/lief/assets/`) making it impossible for callers to predict exact file locations
21
+
22
+ ## [5.9.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.9.1) - 2026-03-14
23
+
24
+ ### Fixed
25
+
26
+ - **fs**: `safeDelete()` and `safeDeleteSync()` now properly implement retry logic
27
+ - Previously `maxRetries` was incorrectly passed as `concurrency` to del (parallelism, not retries)
28
+ - `safeDelete()` now wraps `deleteAsync()` with `pRetry()` for exponential backoff
29
+ - `safeDeleteSync()` implements sync retry loop with `Atomics.wait()` for non-blocking sleep
30
+ - Both use `backoffFactor: 2` (delay doubles each retry: 200ms → 400ms → 800ms by default)
31
+ - `maxRetries` and `retryDelay` options in `RemoveOptions` now work as documented
32
+
8
33
  ## [5.9.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.9.0) - 2026-03-14
9
34
 
10
35
  ### Changed
package/dist/fs.js CHANGED
@@ -53,6 +53,7 @@ module.exports = __toCommonJS(fs_exports);
53
53
  var import_process = require("./constants/process");
54
54
  var import_arrays = require("./arrays");
55
55
  var import_del = require("./external/del");
56
+ var import_promises = require("./promises");
56
57
  var import_globs = require("./globs");
57
58
  var import_parse = require("./json/parse");
58
59
  var import_objects = require("./objects");
@@ -527,12 +528,23 @@ async function safeDelete(filepath, options) {
527
528
  shouldForce = true;
528
529
  }
529
530
  }
530
- await (0, import_del.deleteAsync)(patterns, {
531
- concurrency: opts.maxRetries || defaultRemoveOptions.maxRetries,
532
- dryRun: false,
533
- force: shouldForce,
534
- onlyFiles: false
535
- });
531
+ const maxRetries = opts.maxRetries ?? defaultRemoveOptions.maxRetries;
532
+ const retryDelay = opts.retryDelay ?? defaultRemoveOptions.retryDelay;
533
+ await (0, import_promises.pRetry)(
534
+ async () => {
535
+ await (0, import_del.deleteAsync)(patterns, {
536
+ dryRun: false,
537
+ force: shouldForce,
538
+ onlyFiles: false
539
+ });
540
+ },
541
+ {
542
+ retries: maxRetries,
543
+ baseDelayMs: retryDelay,
544
+ backoffFactor: 2,
545
+ signal: opts.signal
546
+ }
547
+ );
536
548
  }
537
549
  function safeDeleteSync(filepath, options) {
538
550
  const opts = { __proto__: null, ...options };
@@ -557,12 +569,30 @@ function safeDeleteSync(filepath, options) {
557
569
  shouldForce = true;
558
570
  }
559
571
  }
560
- (0, import_del.deleteSync)(patterns, {
561
- concurrency: opts.maxRetries || defaultRemoveOptions.maxRetries,
562
- dryRun: false,
563
- force: shouldForce,
564
- onlyFiles: false
565
- });
572
+ const maxRetries = opts.maxRetries ?? defaultRemoveOptions.maxRetries;
573
+ const retryDelay = opts.retryDelay ?? defaultRemoveOptions.retryDelay;
574
+ let lastError;
575
+ let delay = retryDelay;
576
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
577
+ try {
578
+ (0, import_del.deleteSync)(patterns, {
579
+ dryRun: false,
580
+ force: shouldForce,
581
+ onlyFiles: false
582
+ });
583
+ return;
584
+ } catch (error) {
585
+ lastError = error;
586
+ if (attempt < maxRetries) {
587
+ const waitMs = delay;
588
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, waitMs);
589
+ delay *= 2;
590
+ }
591
+ }
592
+ }
593
+ if (lastError) {
594
+ throw lastError;
595
+ }
566
596
  }
567
597
  async function safeMkdir(path, options) {
568
598
  const fs = /* @__PURE__ */ getFs();
@@ -121,7 +121,7 @@ async function downloadGitHubRelease(config) {
121
121
  }
122
122
  const path = /* @__PURE__ */ getPath();
123
123
  const resolvedDownloadDir = path.isAbsolute(downloadDir) ? downloadDir : path.join(cwd, downloadDir);
124
- const binaryDir = path.join(resolvedDownloadDir, toolName, platformArch);
124
+ const binaryDir = resolvedDownloadDir;
125
125
  const binaryPath = path.join(binaryDir, binaryName);
126
126
  const versionPath = path.join(binaryDir, ".version");
127
127
  const fs = /* @__PURE__ */ getFs();
@@ -13,25 +13,23 @@ export interface SocketBtmAssetConfig {
13
13
  /** @internal Discriminator fields */
14
14
  bin?: never;
15
15
  /** Working directory (defaults to process.cwd()). */
16
- cwd?: string;
16
+ cwd?: string | undefined;
17
17
  /** Download destination directory. @default 'build/downloaded' */
18
- downloadDir?: string;
18
+ downloadDir?: string | undefined;
19
19
  /** @internal Discriminator fields */
20
20
  libc?: never;
21
21
  /** Output filename. @default resolved asset name */
22
- output?: string;
22
+ output?: string | undefined;
23
23
  /** Suppress log messages. @default false */
24
- quiet?: boolean;
24
+ quiet?: boolean | undefined;
25
25
  /** Remove macOS quarantine attribute after download. @default false */
26
- removeMacOSQuarantine?: boolean;
26
+ removeMacOSQuarantine?: boolean | undefined;
27
27
  /** Specific release tag to download. */
28
- tag?: string;
28
+ tag?: string | undefined;
29
29
  /** @internal Discriminator fields */
30
30
  targetArch?: never;
31
31
  /** @internal Discriminator fields */
32
32
  targetPlatform?: never;
33
- /** Tool/package name for directory structure and release matching. */
34
- tool: string;
35
33
  }
36
34
  /**
37
35
  * Configuration for downloading socket-btm binary releases.
@@ -40,25 +38,23 @@ export interface SocketBtmBinaryConfig {
40
38
  /** @internal Discriminator field */
41
39
  asset?: never;
42
40
  /** Binary/executable name (without extension). @default tool */
43
- bin?: string;
41
+ bin?: string | undefined;
44
42
  /** Working directory (defaults to process.cwd()). */
45
- cwd?: string;
43
+ cwd?: string | undefined;
46
44
  /** Download destination directory. @default 'build/downloaded' */
47
- downloadDir?: string;
45
+ downloadDir?: string | undefined;
48
46
  /** Linux libc variant. Auto-detected if not specified. */
49
- libc?: Libc;
47
+ libc?: Libc | undefined;
50
48
  /** Suppress log messages. @default false */
51
- quiet?: boolean;
49
+ quiet?: boolean | undefined;
52
50
  /** Remove macOS quarantine attribute after download. @default true */
53
- removeMacOSQuarantine?: boolean;
51
+ removeMacOSQuarantine?: boolean | undefined;
54
52
  /** Specific release tag to download. */
55
- tag?: string;
53
+ tag?: string | undefined;
56
54
  /** Target architecture (defaults to current arch). */
57
- targetArch?: Arch;
55
+ targetArch?: Arch | undefined;
58
56
  /** Target platform (defaults to current platform). */
59
- targetPlatform?: Platform;
60
- /** Tool/package name for directory structure and release matching. */
61
- tool: string;
57
+ targetPlatform?: Platform | undefined;
62
58
  }
63
59
  /**
64
60
  * Configuration for downloading socket-btm releases (binary or asset).
@@ -74,10 +70,11 @@ export declare function detectLibc(): Libc | undefined;
74
70
  /**
75
71
  * Download a release from socket-btm.
76
72
  *
77
- * @param config - Download configuration
73
+ * @param tool - Tool/package name for release matching (e.g., 'lief', 'curl')
74
+ * @param options - Download configuration
78
75
  * @returns Path to the downloaded file
79
76
  */
80
- export declare function downloadSocketBtmRelease(config: SocketBtmReleaseConfig): Promise<string>;
77
+ export declare function downloadSocketBtmRelease(tool: string, options: SocketBtmReleaseConfig | undefined): Promise<string>;
81
78
  /**
82
79
  * Get asset name for a socket-btm binary.
83
80
  *
@@ -69,16 +69,17 @@ function detectLibc() {
69
69
  return "glibc";
70
70
  }
71
71
  }
72
- async function downloadSocketBtmRelease(config) {
73
- const { cwd, downloadDir, quiet = false, tag, tool } = config;
72
+ async function downloadSocketBtmRelease(tool, options) {
73
+ const config = Object.assign(/* @__PURE__ */ Object.create(null), options);
74
+ const { cwd, downloadDir, quiet = false, tag } = config;
74
75
  const toolPrefix = `${tool}-`;
75
76
  let downloadConfig;
76
- if ("asset" in config) {
77
- const {
78
- asset,
79
- output,
80
- removeMacOSQuarantine = false
81
- } = config;
77
+ if (options && "asset" in options) {
78
+ const assetConfig = Object.assign(
79
+ /* @__PURE__ */ Object.create(null),
80
+ options
81
+ );
82
+ const { asset, output, removeMacOSQuarantine = false } = assetConfig;
82
83
  let resolvedAsset;
83
84
  let resolvedTag = tag;
84
85
  const isExactMatch = typeof asset === "string" && !asset.includes("*");
@@ -127,13 +128,17 @@ async function downloadSocketBtmRelease(config) {
127
128
  removeMacOSQuarantine
128
129
  };
129
130
  } else {
131
+ const binaryConfig = Object.assign(
132
+ /* @__PURE__ */ Object.create(null),
133
+ options
134
+ );
130
135
  const {
131
136
  bin,
132
137
  libc = detectLibc(),
133
138
  removeMacOSQuarantine = true,
134
139
  targetArch = (0, import_platform.getArch)(),
135
140
  targetPlatform = (0, import_platform.getPlatform)()
136
- } = config;
141
+ } = binaryConfig;
137
142
  const baseName = bin || tool;
138
143
  const assetName = getBinaryAssetName(
139
144
  baseName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@socketsecurity/lib",
3
- "version": "5.9.0",
3
+ "version": "5.10.0",
4
4
  "packageManager": "pnpm@10.32.1",
5
5
  "license": "MIT",
6
6
  "description": "Core utilities and infrastructure for Socket.dev security tools",
@@ -734,7 +734,7 @@
734
734
  "@socketregistry/is-unicode-supported": "1.0.5",
735
735
  "@socketregistry/packageurl-js": "1.3.5",
736
736
  "@socketregistry/yocto-spinner": "1.0.25",
737
- "@socketsecurity/lib-stable": "npm:@socketsecurity/lib@5.8.2",
737
+ "@socketsecurity/lib-stable": "npm:@socketsecurity/lib@5.9.0",
738
738
  "@types/node": "24.9.2",
739
739
  "@typescript/native-preview": "7.0.0-dev.20250920.1",
740
740
  "@vitest/coverage-v8": "4.0.3",