@socketsecurity/lib 5.9.1 → 5.11.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 +29 -0
- package/dist/cache-with-ttl.js +8 -2
- package/dist/http-request.d.ts +103 -0
- package/dist/http-request.js +62 -2
- package/dist/releases/github.js +1 -1
- package/dist/releases/socket-btm.d.ts +18 -21
- package/dist/releases/socket-btm.js +14 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,35 @@ 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.11.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.11.0) - 2026-03-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **http-request**: Checksum verification for secure downloads
|
|
13
|
+
- `parseChecksums(text)`: Parse checksums file text into filename→hash map
|
|
14
|
+
- Supports GNU style (`hash filename`), BSD style (`SHA256 (file) = hash`), and single-space format
|
|
15
|
+
- Handles Windows CRLF and Unix LF line endings
|
|
16
|
+
- Returns null-prototype object to prevent prototype pollution
|
|
17
|
+
- `fetchChecksums(url, options?)`: Fetch and parse checksums from URL
|
|
18
|
+
- Supports `headers` and `timeout` options
|
|
19
|
+
- `httpDownload` now accepts `sha256` option to verify downloaded files
|
|
20
|
+
- Verification happens before atomic rename (file not saved if hash mismatches)
|
|
21
|
+
- Accepts uppercase hashes (normalized to lowercase internally)
|
|
22
|
+
|
|
23
|
+
## [5.10.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.10.0) - 2026-03-14
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **releases/socket-btm**: Refactored `downloadSocketBtmRelease()` API for caller-controlled download paths
|
|
28
|
+
- Tool name moved from config object to required first parameter
|
|
29
|
+
- Config object is now optional second parameter (was required)
|
|
30
|
+
- Removed automatic `/${toolName}/${platformArch}` directory nesting - callers now have full control over download directory structure
|
|
31
|
+
- All optional parameters in config types now explicitly typed as `| undefined`
|
|
32
|
+
- Migration example:
|
|
33
|
+
- Before: `downloadSocketBtmRelease({ tool: 'lief', downloadDir: 'build' })`
|
|
34
|
+
- After: `downloadSocketBtmRelease('lief', { downloadDir: 'build' })`
|
|
35
|
+
- 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
|
|
36
|
+
|
|
8
37
|
## [5.9.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.9.1) - 2026-03-14
|
|
9
38
|
|
|
10
39
|
### Fixed
|
package/dist/cache-with-ttl.js
CHANGED
|
@@ -99,7 +99,10 @@ function createTtlCache(options) {
|
|
|
99
99
|
}
|
|
100
100
|
return entry.data;
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
try {
|
|
103
|
+
await cacache.remove(fullKey);
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
103
106
|
}
|
|
104
107
|
return void 0;
|
|
105
108
|
}
|
|
@@ -206,7 +209,10 @@ function createTtlCache(options) {
|
|
|
206
209
|
}
|
|
207
210
|
const fullKey = buildKey(key);
|
|
208
211
|
memoCache.delete(fullKey);
|
|
209
|
-
|
|
212
|
+
try {
|
|
213
|
+
await cacache.remove(fullKey);
|
|
214
|
+
} catch {
|
|
215
|
+
}
|
|
210
216
|
}
|
|
211
217
|
async function deleteAll(pattern) {
|
|
212
218
|
const fullPrefix = pattern ? `${opts.prefix}:${pattern}` : opts.prefix;
|
package/dist/http-request.d.ts
CHANGED
|
@@ -409,6 +409,29 @@ export interface HttpDownloadOptions {
|
|
|
409
409
|
* ```
|
|
410
410
|
*/
|
|
411
411
|
timeout?: number | undefined;
|
|
412
|
+
/**
|
|
413
|
+
* Expected SHA256 hash of the downloaded file.
|
|
414
|
+
* If provided, the download will fail if the computed hash doesn't match.
|
|
415
|
+
* The hash should be a lowercase hex string (64 characters).
|
|
416
|
+
*
|
|
417
|
+
* Use `fetchChecksums()` to fetch hashes from a checksums URL, then pass
|
|
418
|
+
* the specific hash here.
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```ts
|
|
422
|
+
* // Verify download integrity with direct hash
|
|
423
|
+
* await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {
|
|
424
|
+
* sha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
|
425
|
+
* })
|
|
426
|
+
*
|
|
427
|
+
* // Verify using checksums from a URL
|
|
428
|
+
* const checksums = await fetchChecksums('https://example.com/checksums.txt')
|
|
429
|
+
* await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {
|
|
430
|
+
* sha256: checksums['file.zip']
|
|
431
|
+
* })
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
434
|
+
sha256?: string | undefined;
|
|
412
435
|
}
|
|
413
436
|
/**
|
|
414
437
|
* Result of a successful file download.
|
|
@@ -435,6 +458,86 @@ export interface HttpDownloadResult {
|
|
|
435
458
|
*/
|
|
436
459
|
size: number;
|
|
437
460
|
}
|
|
461
|
+
/**
|
|
462
|
+
* Map of filenames to their SHA256 hashes.
|
|
463
|
+
* Keys are filenames (not paths), values are lowercase hex-encoded SHA256 hashes.
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```ts
|
|
467
|
+
* const checksums: Checksums = {
|
|
468
|
+
* 'file.zip': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
|
|
469
|
+
* 'other.tar.gz': 'abc123...'
|
|
470
|
+
* }
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
export type Checksums = Record<string, string>;
|
|
474
|
+
/**
|
|
475
|
+
* Parse a checksums file text into a filename-to-hash map.
|
|
476
|
+
*
|
|
477
|
+
* Supports standard checksums file formats:
|
|
478
|
+
* - BSD style: "SHA256 (filename) = hash"
|
|
479
|
+
* - GNU style: "hash filename" (two spaces)
|
|
480
|
+
* - Simple style: "hash filename" (single space)
|
|
481
|
+
*
|
|
482
|
+
* Lines starting with '#' are treated as comments and ignored.
|
|
483
|
+
* Empty lines are ignored.
|
|
484
|
+
*
|
|
485
|
+
* @param text - Raw text content of a checksums file
|
|
486
|
+
* @returns Map of filenames to lowercase SHA256 hashes
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* ```ts
|
|
490
|
+
* const text = `
|
|
491
|
+
* # SHA256 checksums
|
|
492
|
+
* e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 file.zip
|
|
493
|
+
* abc123def456... other.tar.gz
|
|
494
|
+
* `
|
|
495
|
+
* const checksums = parseChecksums(text)
|
|
496
|
+
* console.log(checksums['file.zip']) // 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
|
497
|
+
* ```
|
|
498
|
+
*/
|
|
499
|
+
export declare function parseChecksums(text: string): Checksums;
|
|
500
|
+
/**
|
|
501
|
+
* Options for fetching checksums from a URL.
|
|
502
|
+
*/
|
|
503
|
+
export interface FetchChecksumsOptions {
|
|
504
|
+
/**
|
|
505
|
+
* HTTP headers to send with the request.
|
|
506
|
+
*/
|
|
507
|
+
headers?: Record<string, string> | undefined;
|
|
508
|
+
/**
|
|
509
|
+
* Request timeout in milliseconds.
|
|
510
|
+
* @default 30000
|
|
511
|
+
*/
|
|
512
|
+
timeout?: number | undefined;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Fetch and parse a checksums file from a URL.
|
|
516
|
+
*
|
|
517
|
+
* This is useful for verifying downloads from GitHub releases which typically
|
|
518
|
+
* publish a checksums.txt file alongside release assets.
|
|
519
|
+
*
|
|
520
|
+
* @param url - URL to the checksums file
|
|
521
|
+
* @param options - Request options
|
|
522
|
+
* @returns Map of filenames to lowercase SHA256 hashes
|
|
523
|
+
* @throws {Error} When the checksums file cannot be fetched
|
|
524
|
+
*
|
|
525
|
+
* @example
|
|
526
|
+
* ```ts
|
|
527
|
+
* // Fetch checksums from GitHub release
|
|
528
|
+
* const checksums = await fetchChecksums(
|
|
529
|
+
* 'https://github.com/org/repo/releases/download/v1.0.0/checksums.txt'
|
|
530
|
+
* )
|
|
531
|
+
*
|
|
532
|
+
* // Use with httpDownload
|
|
533
|
+
* await httpDownload(
|
|
534
|
+
* 'https://github.com/org/repo/releases/download/v1.0.0/tool_linux.tar.gz',
|
|
535
|
+
* '/tmp/tool.tar.gz',
|
|
536
|
+
* { sha256: checksums['tool_linux.tar.gz'] }
|
|
537
|
+
* )
|
|
538
|
+
* ```
|
|
539
|
+
*/
|
|
540
|
+
export declare function fetchChecksums(url: string, options?: FetchChecksumsOptions | undefined): Promise<Checksums>;
|
|
438
541
|
/**
|
|
439
542
|
* Download a file from a URL to a local path with redirect support, retry logic, and progress callbacks.
|
|
440
543
|
* Uses streaming to avoid loading entire file in memory.
|
package/dist/http-request.js
CHANGED
|
@@ -19,10 +19,12 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
19
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
20
|
var http_request_exports = {};
|
|
21
21
|
__export(http_request_exports, {
|
|
22
|
+
fetchChecksums: () => fetchChecksums,
|
|
22
23
|
httpDownload: () => httpDownload,
|
|
23
24
|
httpJson: () => httpJson,
|
|
24
25
|
httpRequest: () => httpRequest,
|
|
25
|
-
httpText: () => httpText
|
|
26
|
+
httpText: () => httpText,
|
|
27
|
+
parseChecksums: () => parseChecksums
|
|
26
28
|
});
|
|
27
29
|
module.exports = __toCommonJS(http_request_exports);
|
|
28
30
|
var import_fs = require("./fs.js");
|
|
@@ -34,9 +36,17 @@ function getFs() {
|
|
|
34
36
|
}
|
|
35
37
|
return _fs;
|
|
36
38
|
}
|
|
39
|
+
let _crypto;
|
|
37
40
|
let _http;
|
|
38
41
|
let _https;
|
|
39
42
|
// @__NO_SIDE_EFFECTS__
|
|
43
|
+
function getCrypto() {
|
|
44
|
+
if (_crypto === void 0) {
|
|
45
|
+
_crypto = require("crypto");
|
|
46
|
+
}
|
|
47
|
+
return _crypto;
|
|
48
|
+
}
|
|
49
|
+
// @__NO_SIDE_EFFECTS__
|
|
40
50
|
function getHttp() {
|
|
41
51
|
if (_http === void 0) {
|
|
42
52
|
_http = require("http");
|
|
@@ -50,6 +60,40 @@ function getHttps() {
|
|
|
50
60
|
}
|
|
51
61
|
return _https;
|
|
52
62
|
}
|
|
63
|
+
function parseChecksums(text) {
|
|
64
|
+
const checksums = { __proto__: null };
|
|
65
|
+
for (const line of text.split("\n")) {
|
|
66
|
+
const trimmed = line.trim();
|
|
67
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const bsdMatch = trimmed.match(
|
|
71
|
+
/^SHA256\s+\((.+)\)\s+=\s+([a-fA-F0-9]{64})$/
|
|
72
|
+
);
|
|
73
|
+
if (bsdMatch) {
|
|
74
|
+
checksums[bsdMatch[1]] = bsdMatch[2].toLowerCase();
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const gnuMatch = trimmed.match(/^([a-fA-F0-9]{64})\s+(.+)$/);
|
|
78
|
+
if (gnuMatch) {
|
|
79
|
+
checksums[gnuMatch[2]] = gnuMatch[1].toLowerCase();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return checksums;
|
|
83
|
+
}
|
|
84
|
+
async function fetchChecksums(url, options) {
|
|
85
|
+
const { headers = {}, timeout = 3e4 } = {
|
|
86
|
+
__proto__: null,
|
|
87
|
+
...options
|
|
88
|
+
};
|
|
89
|
+
const response = await httpRequest(url, { headers, timeout });
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Failed to fetch checksums from ${url}: ${response.status} ${response.statusText}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return parseChecksums(response.body.toString("utf8"));
|
|
96
|
+
}
|
|
53
97
|
async function httpDownloadAttempt(url, destPath, options) {
|
|
54
98
|
const {
|
|
55
99
|
followRedirects = true,
|
|
@@ -292,6 +336,7 @@ async function httpDownload(url, destPath, options) {
|
|
|
292
336
|
progressInterval = 10,
|
|
293
337
|
retries = 0,
|
|
294
338
|
retryDelay = 1e3,
|
|
339
|
+
sha256,
|
|
295
340
|
timeout = 12e4
|
|
296
341
|
} = { __proto__: null, ...options };
|
|
297
342
|
let progressCallback;
|
|
@@ -324,6 +369,19 @@ async function httpDownload(url, destPath, options) {
|
|
|
324
369
|
onProgress: progressCallback,
|
|
325
370
|
timeout
|
|
326
371
|
});
|
|
372
|
+
if (sha256) {
|
|
373
|
+
const crypto = /* @__PURE__ */ getCrypto();
|
|
374
|
+
const fileContent = await fs.promises.readFile(tempPath);
|
|
375
|
+
const computedHash = crypto.createHash("sha256").update(fileContent).digest("hex");
|
|
376
|
+
if (computedHash !== sha256.toLowerCase()) {
|
|
377
|
+
await (0, import_fs.safeDelete)(tempPath);
|
|
378
|
+
throw new Error(
|
|
379
|
+
`Checksum verification failed for ${url}
|
|
380
|
+
Expected: ${sha256.toLowerCase()}
|
|
381
|
+
Computed: ${computedHash}`
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
327
385
|
await fs.promises.rename(tempPath, destPath);
|
|
328
386
|
return {
|
|
329
387
|
path: destPath,
|
|
@@ -440,8 +498,10 @@ async function httpText(url, options) {
|
|
|
440
498
|
}
|
|
441
499
|
// Annotate the CommonJS export names for ESM import in node:
|
|
442
500
|
0 && (module.exports = {
|
|
501
|
+
fetchChecksums,
|
|
443
502
|
httpDownload,
|
|
444
503
|
httpJson,
|
|
445
504
|
httpRequest,
|
|
446
|
-
httpText
|
|
505
|
+
httpText,
|
|
506
|
+
parseChecksums
|
|
447
507
|
});
|
package/dist/releases/github.js
CHANGED
|
@@ -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 =
|
|
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
|
|
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(
|
|
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(
|
|
73
|
-
const
|
|
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
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
} =
|
|
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
|
-
} =
|
|
141
|
+
} = binaryConfig;
|
|
137
142
|
const baseName = bin || tool;
|
|
138
143
|
const assetName = getBinaryAssetName(
|
|
139
144
|
baseName,
|