@socketsecurity/lib 5.3.0 → 5.4.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 +16 -0
- package/dist/cover/code.js +12 -4
- package/dist/dlx/cache.js +10 -2
- package/dist/dlx/manifest.js +45 -41
- package/dist/env/rewire.js +10 -2
- package/dist/external/@inquirer/checkbox.js +4 -2528
- package/dist/external/@inquirer/confirm.js +4 -2371
- package/dist/external/@inquirer/input.js +4 -2395
- package/dist/external/@inquirer/password.js +4 -2503
- package/dist/external/@inquirer/search.js +4 -2500
- package/dist/external/@inquirer/select.js +4 -2617
- package/dist/external/del.js +4 -7139
- package/dist/external/fast-glob.js +4 -5776
- package/dist/external/inquirer-pack.js +4610 -0
- package/dist/external/npm-core.js +3 -1
- package/dist/external/pico-pack.js +7162 -0
- package/dist/external/picomatch.js +4 -1523
- package/dist/external/spdx-correct.js +4 -1384
- package/dist/external/spdx-expression-parse.js +4 -1047
- package/dist/external/spdx-pack.js +1640 -0
- package/dist/external/validate-npm-package-name.js +4 -104
- package/dist/http-request.js +10 -2
- package/dist/ipc.js +53 -29
- package/dist/packages/isolation.js +45 -23
- package/dist/packages/licenses.js +10 -2
- package/dist/paths/socket.d.ts +2 -2
- package/dist/paths/socket.js +27 -21
- package/dist/process-lock.js +23 -14
- package/dist/releases/github.d.ts +67 -41
- package/dist/releases/github.js +142 -100
- package/dist/releases/socket-btm.d.ts +40 -33
- package/dist/releases/socket-btm.js +45 -5
- package/dist/spawn.js +10 -3
- package/dist/stdio/mask.d.ts +6 -21
- package/dist/stdio/mask.js +18 -14
- package/dist/themes/context.js +10 -2
- package/package.json +2 -1
package/dist/process-lock.js
CHANGED
|
@@ -22,11 +22,20 @@ __export(process_lock_exports, {
|
|
|
22
22
|
processLock: () => processLock
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(process_lock_exports);
|
|
25
|
-
var import_fs = require("fs");
|
|
26
|
-
var import_fs2 = require("./fs");
|
|
25
|
+
var import_fs = require("./fs");
|
|
27
26
|
var import_logger = require("./logger");
|
|
28
27
|
var import_promises = require("./promises");
|
|
29
28
|
var import_signal_exit = require("./signal-exit");
|
|
29
|
+
let _fs;
|
|
30
|
+
// @__NO_SIDE_EFFECTS__
|
|
31
|
+
function getFs() {
|
|
32
|
+
if (_fs === void 0) {
|
|
33
|
+
_fs = require("fs");
|
|
34
|
+
}
|
|
35
|
+
return _fs;
|
|
36
|
+
}
|
|
37
|
+
const fs = /* @__PURE__ */ getFs();
|
|
38
|
+
const { existsSync, mkdirSync, statSync, utimesSync } = fs;
|
|
30
39
|
const logger = (0, import_logger.getDefaultLogger)();
|
|
31
40
|
class ProcessLockManager {
|
|
32
41
|
activeLocks = /* @__PURE__ */ new Set();
|
|
@@ -47,8 +56,8 @@ class ProcessLockManager {
|
|
|
47
56
|
this.touchTimers.clear();
|
|
48
57
|
for (const lockPath of this.activeLocks) {
|
|
49
58
|
try {
|
|
50
|
-
if (
|
|
51
|
-
(0,
|
|
59
|
+
if (existsSync(lockPath)) {
|
|
60
|
+
(0, import_fs.safeDeleteSync)(lockPath, { recursive: true });
|
|
52
61
|
}
|
|
53
62
|
} catch {
|
|
54
63
|
}
|
|
@@ -64,9 +73,9 @@ class ProcessLockManager {
|
|
|
64
73
|
*/
|
|
65
74
|
touchLock(lockPath) {
|
|
66
75
|
try {
|
|
67
|
-
if (
|
|
76
|
+
if (existsSync(lockPath)) {
|
|
68
77
|
const now = /* @__PURE__ */ new Date();
|
|
69
|
-
|
|
78
|
+
utimesSync(lockPath, now, now);
|
|
70
79
|
}
|
|
71
80
|
} catch (error) {
|
|
72
81
|
logger.warn(
|
|
@@ -114,10 +123,10 @@ class ProcessLockManager {
|
|
|
114
123
|
*/
|
|
115
124
|
isStale(lockPath, staleMs) {
|
|
116
125
|
try {
|
|
117
|
-
if (!
|
|
126
|
+
if (!existsSync(lockPath)) {
|
|
118
127
|
return false;
|
|
119
128
|
}
|
|
120
|
-
const stats =
|
|
129
|
+
const stats = statSync(lockPath);
|
|
121
130
|
const ageSeconds = Math.floor((Date.now() - stats.mtime.getTime()) / 1e3);
|
|
122
131
|
const staleSeconds = Math.floor(staleMs / 1e3);
|
|
123
132
|
return ageSeconds > staleSeconds;
|
|
@@ -160,17 +169,17 @@ class ProcessLockManager {
|
|
|
160
169
|
return await (0, import_promises.pRetry)(
|
|
161
170
|
async () => {
|
|
162
171
|
try {
|
|
163
|
-
if (
|
|
172
|
+
if (existsSync(lockPath) && this.isStale(lockPath, staleMs)) {
|
|
164
173
|
logger.log(`Removing stale lock: ${lockPath}`);
|
|
165
174
|
try {
|
|
166
|
-
(0,
|
|
175
|
+
(0, import_fs.safeDeleteSync)(lockPath, { recursive: true });
|
|
167
176
|
} catch {
|
|
168
177
|
}
|
|
169
178
|
}
|
|
170
|
-
if (
|
|
179
|
+
if (existsSync(lockPath)) {
|
|
171
180
|
throw new Error(`Lock already exists: ${lockPath}`);
|
|
172
181
|
}
|
|
173
|
-
|
|
182
|
+
mkdirSync(lockPath, { recursive: true });
|
|
174
183
|
this.activeLocks.add(lockPath);
|
|
175
184
|
this.startTouchTimer(lockPath, touchIntervalMs);
|
|
176
185
|
return () => this.release(lockPath);
|
|
@@ -246,8 +255,8 @@ To resolve:
|
|
|
246
255
|
release(lockPath) {
|
|
247
256
|
this.stopTouchTimer(lockPath);
|
|
248
257
|
try {
|
|
249
|
-
if (
|
|
250
|
-
(0,
|
|
258
|
+
if (existsSync(lockPath)) {
|
|
259
|
+
(0, import_fs.safeDeleteSync)(lockPath, { recursive: true });
|
|
251
260
|
}
|
|
252
261
|
this.activeLocks.delete(lockPath);
|
|
253
262
|
} catch (error) {
|
|
@@ -1,69 +1,84 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*
|
|
2
|
+
* Pattern for matching release assets.
|
|
3
|
+
* Can be either:
|
|
4
|
+
* - A string with glob pattern syntax
|
|
5
|
+
* - A prefix/suffix pair for explicit matching (backward compatible)
|
|
6
|
+
* - A RegExp for complex patterns
|
|
7
|
+
*
|
|
8
|
+
* String patterns support full glob syntax via picomatch.
|
|
9
|
+
* Examples:
|
|
10
|
+
* - Simple wildcard: yoga-sync-*.mjs matches yoga-sync-abc123.mjs
|
|
11
|
+
* - Complex: models-*.tar.gz matches models-2024-01-15.tar.gz
|
|
12
|
+
* - Prefix wildcard: *-models.tar.gz matches foo-models.tar.gz
|
|
13
|
+
* - Suffix wildcard: yoga-* matches yoga-layout
|
|
14
|
+
* - Brace expansion: {yoga,models}-*.{mjs,js} matches yoga-abc.mjs or models-xyz.js
|
|
15
|
+
*
|
|
16
|
+
* For backward compatibility, prefix/suffix objects are still supported but glob patterns are recommended.
|
|
10
17
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
owner: string;
|
|
16
|
-
/**
|
|
17
|
-
* GitHub repository name.
|
|
18
|
-
*/
|
|
19
|
-
repo: string;
|
|
20
|
-
}
|
|
18
|
+
export type AssetPattern = string | {
|
|
19
|
+
prefix: string;
|
|
20
|
+
suffix: string;
|
|
21
|
+
} | RegExp;
|
|
21
22
|
/**
|
|
22
23
|
* Configuration for downloading a GitHub release.
|
|
23
24
|
*/
|
|
24
25
|
export interface DownloadGitHubReleaseConfig {
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
|
|
26
|
+
/** Asset name on GitHub. */
|
|
27
|
+
assetName: string;
|
|
28
|
+
/** Binary filename (e.g., 'node', 'binject'). */
|
|
29
|
+
binaryName: string;
|
|
29
30
|
/** Working directory (defaults to process.cwd()). */
|
|
30
31
|
cwd?: string;
|
|
31
32
|
/** Download destination directory. @default 'build/downloaded' */
|
|
32
33
|
downloadDir?: string;
|
|
33
|
-
/**
|
|
34
|
-
|
|
34
|
+
/** GitHub repository owner/organization. */
|
|
35
|
+
owner: string;
|
|
35
36
|
/** Platform-arch identifier (e.g., 'linux-x64-musl'). */
|
|
36
37
|
platformArch: string;
|
|
37
|
-
/** Binary filename (e.g., 'node', 'binject'). */
|
|
38
|
-
binaryName: string;
|
|
39
|
-
/** Asset name on GitHub. */
|
|
40
|
-
assetName: string;
|
|
41
|
-
/** Tool prefix for finding latest release. */
|
|
42
|
-
toolPrefix?: string;
|
|
43
|
-
/** Specific release tag to download. */
|
|
44
|
-
tag?: string;
|
|
45
38
|
/** Suppress log messages. @default false */
|
|
46
39
|
quiet?: boolean;
|
|
47
40
|
/** Remove macOS quarantine attribute after download. @default true */
|
|
48
41
|
removeMacOSQuarantine?: boolean;
|
|
42
|
+
/** GitHub repository name. */
|
|
43
|
+
repo: string;
|
|
44
|
+
/** Specific release tag to download. */
|
|
45
|
+
tag?: string;
|
|
46
|
+
/** Tool name for directory structure. */
|
|
47
|
+
toolName: string;
|
|
48
|
+
/** Tool prefix for finding latest release. */
|
|
49
|
+
toolPrefix?: string;
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* @param config - Download configuration
|
|
54
|
-
* @returns Path to the downloaded binary
|
|
52
|
+
* Configuration for repository access.
|
|
55
53
|
*/
|
|
56
|
-
export
|
|
54
|
+
export interface RepoConfig {
|
|
55
|
+
/**
|
|
56
|
+
* GitHub repository owner/organization.
|
|
57
|
+
*/
|
|
58
|
+
owner: string;
|
|
59
|
+
/**
|
|
60
|
+
* GitHub repository name.
|
|
61
|
+
*/
|
|
62
|
+
repo: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Socket-btm GitHub repository configuration.
|
|
66
|
+
*/
|
|
67
|
+
export declare const SOCKET_BTM_REPO: {
|
|
68
|
+
readonly owner: "SocketDev";
|
|
69
|
+
readonly repo: "socket-btm";
|
|
70
|
+
};
|
|
57
71
|
/**
|
|
58
72
|
* Download a specific release asset.
|
|
73
|
+
* Supports pattern matching for dynamic asset discovery.
|
|
59
74
|
*
|
|
60
75
|
* @param tag - Release tag name
|
|
61
|
-
* @param
|
|
76
|
+
* @param assetPattern - Asset name or pattern (glob string, prefix/suffix object, or RegExp)
|
|
62
77
|
* @param outputPath - Path to write the downloaded file
|
|
63
78
|
* @param repoConfig - Repository configuration (owner/repo)
|
|
64
79
|
* @param options - Additional options
|
|
65
80
|
*/
|
|
66
|
-
export declare function downloadReleaseAsset(tag: string,
|
|
81
|
+
export declare function downloadReleaseAsset(tag: string, assetPattern: string | AssetPattern, outputPath: string, repoConfig: RepoConfig, options?: {
|
|
67
82
|
quiet?: boolean;
|
|
68
83
|
}): Promise<void>;
|
|
69
84
|
/**
|
|
@@ -75,24 +90,35 @@ export declare function downloadReleaseAsset(tag: string, assetName: string, out
|
|
|
75
90
|
export declare function getAuthHeaders(): Record<string, string>;
|
|
76
91
|
/**
|
|
77
92
|
* Get latest release tag matching a tool prefix.
|
|
93
|
+
* Optionally filter by releases containing a matching asset.
|
|
78
94
|
*
|
|
79
95
|
* @param toolPrefix - Tool name prefix to search for (e.g., 'node-smol-')
|
|
80
96
|
* @param repoConfig - Repository configuration (owner/repo)
|
|
81
97
|
* @param options - Additional options
|
|
98
|
+
* @param options.assetPattern - Optional pattern to filter releases by matching asset
|
|
82
99
|
* @returns Latest release tag or null if not found
|
|
83
100
|
*/
|
|
84
101
|
export declare function getLatestRelease(toolPrefix: string, repoConfig: RepoConfig, options?: {
|
|
102
|
+
assetPattern?: AssetPattern;
|
|
85
103
|
quiet?: boolean;
|
|
86
104
|
}): Promise<string | null>;
|
|
87
105
|
/**
|
|
88
106
|
* Get download URL for a specific release asset.
|
|
107
|
+
* Supports pattern matching for dynamic asset discovery.
|
|
89
108
|
*
|
|
90
109
|
* @param tag - Release tag name
|
|
91
|
-
* @param
|
|
110
|
+
* @param assetPattern - Asset name or pattern (glob string, prefix/suffix object, or RegExp)
|
|
92
111
|
* @param repoConfig - Repository configuration (owner/repo)
|
|
93
112
|
* @param options - Additional options
|
|
94
113
|
* @returns Browser download URL for the asset
|
|
95
114
|
*/
|
|
96
|
-
export declare function getReleaseAssetUrl(tag: string,
|
|
115
|
+
export declare function getReleaseAssetUrl(tag: string, assetPattern: string | AssetPattern, repoConfig: RepoConfig, options?: {
|
|
97
116
|
quiet?: boolean;
|
|
98
117
|
}): Promise<string | null>;
|
|
118
|
+
/**
|
|
119
|
+
* Download a binary from any GitHub repository with version caching.
|
|
120
|
+
*
|
|
121
|
+
* @param config - Download configuration
|
|
122
|
+
* @returns Path to the downloaded binary
|
|
123
|
+
*/
|
|
124
|
+
export declare function downloadGitHubRelease(config: DownloadGitHubReleaseConfig): Promise<string>;
|
package/dist/releases/github.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/* Socket Lib - Built with esbuild */
|
|
3
|
+
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
9
|
var __export = (target, all) => {
|
|
8
10
|
for (var name in all)
|
|
@@ -16,6 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
var github_exports = {};
|
|
21
31
|
__export(github_exports, {
|
|
@@ -27,26 +37,13 @@ __export(github_exports, {
|
|
|
27
37
|
getReleaseAssetUrl: () => getReleaseAssetUrl
|
|
28
38
|
});
|
|
29
39
|
module.exports = __toCommonJS(github_exports);
|
|
30
|
-
var
|
|
31
|
-
var
|
|
32
|
-
var import_fs2 = require("../fs.js");
|
|
40
|
+
var import_picomatch = __toESM(require("../external/picomatch.js"));
|
|
41
|
+
var import_fs = require("../fs.js");
|
|
33
42
|
var import_http_request = require("../http-request.js");
|
|
34
43
|
var import_logger = require("../logger.js");
|
|
35
|
-
var
|
|
44
|
+
var import_promises = require("../promises.js");
|
|
36
45
|
var import_spawn = require("../spawn.js");
|
|
37
46
|
const logger = (0, import_logger.getDefaultLogger)();
|
|
38
|
-
let _path;
|
|
39
|
-
// @__NO_SIDE_EFFECTS__
|
|
40
|
-
function getPath() {
|
|
41
|
-
if (_path === void 0) {
|
|
42
|
-
_path = require("path");
|
|
43
|
-
}
|
|
44
|
-
return _path;
|
|
45
|
-
}
|
|
46
|
-
const SOCKET_BTM_REPO = {
|
|
47
|
-
owner: "SocketDev",
|
|
48
|
-
repo: "socket-btm"
|
|
49
|
-
};
|
|
50
47
|
const RETRY_CONFIG = Object.freeze({
|
|
51
48
|
__proto__: null,
|
|
52
49
|
// Exponential backoff: delay doubles with each retry (5s, 10s, 20s).
|
|
@@ -56,93 +53,52 @@ const RETRY_CONFIG = Object.freeze({
|
|
|
56
53
|
// Maximum number of retry attempts (excluding initial request).
|
|
57
54
|
retries: 2
|
|
58
55
|
});
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
owner,
|
|
66
|
-
platformArch,
|
|
67
|
-
quiet = false,
|
|
68
|
-
removeMacOSQuarantine = true,
|
|
69
|
-
repo,
|
|
70
|
-
tag: explicitTag,
|
|
71
|
-
toolName,
|
|
72
|
-
toolPrefix
|
|
73
|
-
} = config;
|
|
74
|
-
let tag;
|
|
75
|
-
if (explicitTag) {
|
|
76
|
-
tag = explicitTag;
|
|
77
|
-
} else if (toolPrefix) {
|
|
78
|
-
const latestTag = await getLatestRelease(
|
|
79
|
-
toolPrefix,
|
|
80
|
-
{ owner, repo },
|
|
81
|
-
{ quiet }
|
|
82
|
-
);
|
|
83
|
-
if (!latestTag) {
|
|
84
|
-
throw new Error(`No ${toolPrefix} release found in ${owner}/${repo}`);
|
|
85
|
-
}
|
|
86
|
-
tag = latestTag;
|
|
87
|
-
} else {
|
|
88
|
-
throw new Error("Either toolPrefix or tag must be provided");
|
|
89
|
-
}
|
|
90
|
-
const path = /* @__PURE__ */ getPath();
|
|
91
|
-
const resolvedDownloadDir = path.isAbsolute(downloadDir) ? downloadDir : path.join(cwd, downloadDir);
|
|
92
|
-
const binaryDir = path.join(resolvedDownloadDir, toolName, platformArch);
|
|
93
|
-
const binaryPath = path.join(binaryDir, binaryName);
|
|
94
|
-
const versionPath = path.join(binaryDir, ".version");
|
|
95
|
-
if ((0, import_fs.existsSync)(versionPath) && (0, import_fs.existsSync)(binaryPath)) {
|
|
96
|
-
const cachedVersion = (await (0, import_promises.readFile)(versionPath, "utf8")).trim();
|
|
97
|
-
if (cachedVersion === tag) {
|
|
98
|
-
if (!quiet) {
|
|
99
|
-
logger.info(`Using cached ${toolName} (${platformArch}): ${binaryPath}`);
|
|
100
|
-
}
|
|
101
|
-
return binaryPath;
|
|
102
|
-
}
|
|
56
|
+
let _fs;
|
|
57
|
+
let _path;
|
|
58
|
+
function createMatcher(pattern) {
|
|
59
|
+
if (typeof pattern === "string") {
|
|
60
|
+
const isMatch = (0, import_picomatch.default)(pattern);
|
|
61
|
+
return (input) => isMatch(input);
|
|
103
62
|
}
|
|
104
|
-
if (
|
|
105
|
-
|
|
63
|
+
if (pattern instanceof RegExp) {
|
|
64
|
+
return (input) => pattern.test(input);
|
|
106
65
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const isWindows = binaryName.endsWith(".exe");
|
|
115
|
-
if (!isWindows) {
|
|
116
|
-
(0, import_fs.chmodSync)(binaryPath, 493);
|
|
117
|
-
if (removeMacOSQuarantine && process.platform === "darwin" && platformArch.startsWith("darwin")) {
|
|
118
|
-
try {
|
|
119
|
-
await (0, import_spawn.spawn)("xattr", ["-d", "com.apple.quarantine", binaryPath], {
|
|
120
|
-
stdio: "ignore"
|
|
121
|
-
});
|
|
122
|
-
} catch {
|
|
123
|
-
}
|
|
124
|
-
}
|
|
66
|
+
const { prefix, suffix } = pattern;
|
|
67
|
+
return (input) => input.startsWith(prefix) && input.endsWith(suffix);
|
|
68
|
+
}
|
|
69
|
+
// @__NO_SIDE_EFFECTS__
|
|
70
|
+
function getFs() {
|
|
71
|
+
if (_fs === void 0) {
|
|
72
|
+
_fs = require("fs");
|
|
125
73
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
74
|
+
return _fs;
|
|
75
|
+
}
|
|
76
|
+
// @__NO_SIDE_EFFECTS__
|
|
77
|
+
function getPath() {
|
|
78
|
+
if (_path === void 0) {
|
|
79
|
+
_path = require("path");
|
|
129
80
|
}
|
|
130
|
-
return
|
|
81
|
+
return _path;
|
|
131
82
|
}
|
|
132
|
-
|
|
83
|
+
const SOCKET_BTM_REPO = {
|
|
84
|
+
owner: "SocketDev",
|
|
85
|
+
repo: "socket-btm"
|
|
86
|
+
};
|
|
87
|
+
async function downloadReleaseAsset(tag, assetPattern, outputPath, repoConfig, options = {}) {
|
|
133
88
|
const { owner, repo } = repoConfig;
|
|
134
89
|
const { quiet = false } = options;
|
|
135
90
|
const downloadUrl = await getReleaseAssetUrl(
|
|
136
91
|
tag,
|
|
137
|
-
|
|
92
|
+
assetPattern,
|
|
138
93
|
{ owner, repo },
|
|
139
94
|
{ quiet }
|
|
140
95
|
);
|
|
141
96
|
if (!downloadUrl) {
|
|
142
|
-
|
|
97
|
+
const patternDesc = typeof assetPattern === "string" ? assetPattern : "matching pattern";
|
|
98
|
+
throw new Error(`Asset ${patternDesc} not found in release ${tag}`);
|
|
143
99
|
}
|
|
144
100
|
const path = /* @__PURE__ */ getPath();
|
|
145
|
-
await (0,
|
|
101
|
+
await (0, import_fs.safeMkdir)(path.dirname(outputPath));
|
|
146
102
|
await (0, import_http_request.httpDownload)(downloadUrl, outputPath, {
|
|
147
103
|
logger: quiet ? void 0 : logger,
|
|
148
104
|
progressInterval: 10,
|
|
@@ -162,9 +118,10 @@ function getAuthHeaders() {
|
|
|
162
118
|
return headers;
|
|
163
119
|
}
|
|
164
120
|
async function getLatestRelease(toolPrefix, repoConfig, options = {}) {
|
|
121
|
+
const { assetPattern, quiet = false } = options;
|
|
165
122
|
const { owner, repo } = repoConfig;
|
|
166
|
-
const
|
|
167
|
-
return await (0,
|
|
123
|
+
const isMatch = assetPattern ? createMatcher(assetPattern) : void 0;
|
|
124
|
+
return await (0, import_promises.pRetry)(
|
|
168
125
|
async () => {
|
|
169
126
|
const response = await (0, import_http_request.httpRequest)(
|
|
170
127
|
`https://api.github.com/repos/${owner}/${repo}/releases?per_page=100`,
|
|
@@ -177,13 +134,22 @@ async function getLatestRelease(toolPrefix, repoConfig, options = {}) {
|
|
|
177
134
|
}
|
|
178
135
|
const releases = JSON.parse(response.body.toString("utf8"));
|
|
179
136
|
for (const release of releases) {
|
|
180
|
-
const { tag_name: tag } = release;
|
|
181
|
-
if (tag.startsWith(toolPrefix)) {
|
|
182
|
-
|
|
183
|
-
|
|
137
|
+
const { assets, tag_name: tag } = release;
|
|
138
|
+
if (!tag.startsWith(toolPrefix)) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (isMatch) {
|
|
142
|
+
const hasMatchingAsset = assets.some(
|
|
143
|
+
(a) => isMatch(a.name)
|
|
144
|
+
);
|
|
145
|
+
if (!hasMatchingAsset) {
|
|
146
|
+
continue;
|
|
184
147
|
}
|
|
185
|
-
return tag;
|
|
186
148
|
}
|
|
149
|
+
if (!quiet) {
|
|
150
|
+
logger.info(`Found release: ${tag}`);
|
|
151
|
+
}
|
|
152
|
+
return tag;
|
|
187
153
|
}
|
|
188
154
|
if (!quiet) {
|
|
189
155
|
logger.info(`No ${toolPrefix} release found in latest 100 releases`);
|
|
@@ -206,10 +172,11 @@ async function getLatestRelease(toolPrefix, repoConfig, options = {}) {
|
|
|
206
172
|
}
|
|
207
173
|
);
|
|
208
174
|
}
|
|
209
|
-
async function getReleaseAssetUrl(tag,
|
|
175
|
+
async function getReleaseAssetUrl(tag, assetPattern, repoConfig, options = {}) {
|
|
210
176
|
const { owner, repo } = repoConfig;
|
|
211
177
|
const { quiet = false } = options;
|
|
212
|
-
|
|
178
|
+
const isMatch = typeof assetPattern === "string" && !assetPattern.includes("*") && !assetPattern.includes("{") ? (input) => input === assetPattern : createMatcher(assetPattern);
|
|
179
|
+
return await (0, import_promises.pRetry)(
|
|
213
180
|
async () => {
|
|
214
181
|
const response = await (0, import_http_request.httpRequest)(
|
|
215
182
|
`https://api.github.com/repos/${owner}/${repo}/releases/tags/${tag}`,
|
|
@@ -222,13 +189,14 @@ async function getReleaseAssetUrl(tag, assetName, repoConfig, options = {}) {
|
|
|
222
189
|
}
|
|
223
190
|
const release = JSON.parse(response.body.toString("utf8"));
|
|
224
191
|
const asset = release.assets.find(
|
|
225
|
-
(a) => a.name
|
|
192
|
+
(a) => isMatch(a.name)
|
|
226
193
|
);
|
|
227
194
|
if (!asset) {
|
|
228
|
-
|
|
195
|
+
const patternDesc = typeof assetPattern === "string" ? assetPattern : "matching pattern";
|
|
196
|
+
throw new Error(`Asset ${patternDesc} not found in release ${tag}`);
|
|
229
197
|
}
|
|
230
198
|
if (!quiet) {
|
|
231
|
-
logger.info(`Found asset: ${
|
|
199
|
+
logger.info(`Found asset: ${asset.name}`);
|
|
232
200
|
}
|
|
233
201
|
return asset.browser_download_url;
|
|
234
202
|
},
|
|
@@ -248,6 +216,80 @@ async function getReleaseAssetUrl(tag, assetName, repoConfig, options = {}) {
|
|
|
248
216
|
}
|
|
249
217
|
);
|
|
250
218
|
}
|
|
219
|
+
async function downloadGitHubRelease(config) {
|
|
220
|
+
const {
|
|
221
|
+
assetName,
|
|
222
|
+
binaryName,
|
|
223
|
+
cwd = process.cwd(),
|
|
224
|
+
downloadDir = "build/downloaded",
|
|
225
|
+
owner,
|
|
226
|
+
platformArch,
|
|
227
|
+
quiet = false,
|
|
228
|
+
removeMacOSQuarantine = true,
|
|
229
|
+
repo,
|
|
230
|
+
tag: explicitTag,
|
|
231
|
+
toolName,
|
|
232
|
+
toolPrefix
|
|
233
|
+
} = config;
|
|
234
|
+
let tag;
|
|
235
|
+
if (explicitTag) {
|
|
236
|
+
tag = explicitTag;
|
|
237
|
+
} else if (toolPrefix) {
|
|
238
|
+
const latestTag = await getLatestRelease(
|
|
239
|
+
toolPrefix,
|
|
240
|
+
{ owner, repo },
|
|
241
|
+
{ quiet }
|
|
242
|
+
);
|
|
243
|
+
if (!latestTag) {
|
|
244
|
+
throw new Error(`No ${toolPrefix} release found in ${owner}/${repo}`);
|
|
245
|
+
}
|
|
246
|
+
tag = latestTag;
|
|
247
|
+
} else {
|
|
248
|
+
throw new Error("Either toolPrefix or tag must be provided");
|
|
249
|
+
}
|
|
250
|
+
const path = /* @__PURE__ */ getPath();
|
|
251
|
+
const resolvedDownloadDir = path.isAbsolute(downloadDir) ? downloadDir : path.join(cwd, downloadDir);
|
|
252
|
+
const binaryDir = path.join(resolvedDownloadDir, toolName, platformArch);
|
|
253
|
+
const binaryPath = path.join(binaryDir, binaryName);
|
|
254
|
+
const versionPath = path.join(binaryDir, ".version");
|
|
255
|
+
const fs = /* @__PURE__ */ getFs();
|
|
256
|
+
if (fs.existsSync(versionPath) && fs.existsSync(binaryPath)) {
|
|
257
|
+
const cachedVersion = (await fs.promises.readFile(versionPath, "utf8")).trim();
|
|
258
|
+
if (cachedVersion === tag) {
|
|
259
|
+
if (!quiet) {
|
|
260
|
+
logger.info(`Using cached ${toolName} (${platformArch}): ${binaryPath}`);
|
|
261
|
+
}
|
|
262
|
+
return binaryPath;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (!quiet) {
|
|
266
|
+
logger.info(`Downloading ${toolName} for ${platformArch}...`);
|
|
267
|
+
}
|
|
268
|
+
await downloadReleaseAsset(
|
|
269
|
+
tag,
|
|
270
|
+
assetName,
|
|
271
|
+
binaryPath,
|
|
272
|
+
{ owner, repo },
|
|
273
|
+
{ quiet }
|
|
274
|
+
);
|
|
275
|
+
const isWindows = binaryName.endsWith(".exe");
|
|
276
|
+
if (!isWindows) {
|
|
277
|
+
fs.chmodSync(binaryPath, 493);
|
|
278
|
+
if (removeMacOSQuarantine && process.platform === "darwin" && platformArch.startsWith("darwin")) {
|
|
279
|
+
try {
|
|
280
|
+
await (0, import_spawn.spawn)("xattr", ["-d", "com.apple.quarantine", binaryPath], {
|
|
281
|
+
stdio: "ignore"
|
|
282
|
+
});
|
|
283
|
+
} catch {
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
await fs.promises.writeFile(versionPath, tag, "utf8");
|
|
288
|
+
if (!quiet) {
|
|
289
|
+
logger.info(`Downloaded ${toolName} to ${binaryPath}`);
|
|
290
|
+
}
|
|
291
|
+
return binaryPath;
|
|
292
|
+
}
|
|
251
293
|
// Annotate the CommonJS export names for ESM import in node:
|
|
252
294
|
0 && (module.exports = {
|
|
253
295
|
SOCKET_BTM_REPO,
|
|
@@ -1,57 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Socket-btm release download utilities.
|
|
3
|
+
*/
|
|
1
4
|
import { type Arch, type Libc, type Platform } from '../constants/platform.js';
|
|
5
|
+
import { type AssetPattern } from './github.js';
|
|
2
6
|
export type { Arch, Libc, Platform };
|
|
3
7
|
/**
|
|
4
|
-
* Configuration for downloading socket-btm
|
|
8
|
+
* Configuration for downloading socket-btm generic assets.
|
|
5
9
|
*/
|
|
6
|
-
export interface
|
|
10
|
+
export interface SocketBtmAssetConfig {
|
|
11
|
+
/** Asset name or pattern on GitHub. */
|
|
12
|
+
asset: string | AssetPattern;
|
|
13
|
+
/** @internal Discriminator fields */
|
|
14
|
+
bin?: never;
|
|
7
15
|
/** Working directory (defaults to process.cwd()). */
|
|
8
16
|
cwd?: string;
|
|
9
17
|
/** Download destination directory. @default 'build/downloaded' */
|
|
10
18
|
downloadDir?: string;
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
/** Target platform (defaults to current platform). */
|
|
16
|
-
targetPlatform?: Platform;
|
|
17
|
-
/** Target architecture (defaults to current arch). */
|
|
18
|
-
targetArch?: Arch;
|
|
19
|
-
/** Linux libc variant. Auto-detected if not specified. */
|
|
20
|
-
libc?: Libc;
|
|
21
|
-
/** Specific release tag to download. */
|
|
22
|
-
tag?: string;
|
|
19
|
+
/** @internal Discriminator fields */
|
|
20
|
+
libc?: never;
|
|
21
|
+
/** Output filename. @default resolved asset name */
|
|
22
|
+
output?: string;
|
|
23
23
|
/** Suppress log messages. @default false */
|
|
24
24
|
quiet?: boolean;
|
|
25
|
-
/** Remove macOS quarantine attribute after download. @default
|
|
25
|
+
/** Remove macOS quarantine attribute after download. @default false */
|
|
26
26
|
removeMacOSQuarantine?: boolean;
|
|
27
|
-
/**
|
|
28
|
-
|
|
27
|
+
/** Specific release tag to download. */
|
|
28
|
+
tag?: string;
|
|
29
|
+
/** @internal Discriminator fields */
|
|
30
|
+
targetArch?: never;
|
|
31
|
+
/** @internal Discriminator fields */
|
|
32
|
+
targetPlatform?: never;
|
|
33
|
+
/** Tool/package name for directory structure and release matching. */
|
|
34
|
+
tool: string;
|
|
29
35
|
}
|
|
30
36
|
/**
|
|
31
|
-
* Configuration for downloading socket-btm
|
|
37
|
+
* Configuration for downloading socket-btm binary releases.
|
|
32
38
|
*/
|
|
33
|
-
export interface
|
|
39
|
+
export interface SocketBtmBinaryConfig {
|
|
40
|
+
/** @internal Discriminator field */
|
|
41
|
+
asset?: never;
|
|
42
|
+
/** Binary/executable name (without extension). @default tool */
|
|
43
|
+
bin?: string;
|
|
34
44
|
/** Working directory (defaults to process.cwd()). */
|
|
35
45
|
cwd?: string;
|
|
36
46
|
/** Download destination directory. @default 'build/downloaded' */
|
|
37
47
|
downloadDir?: string;
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
/** Asset name pattern on GitHub. */
|
|
41
|
-
asset: string;
|
|
42
|
-
/** Output filename. @default asset */
|
|
43
|
-
output?: string;
|
|
44
|
-
/** Specific release tag to download. */
|
|
45
|
-
tag?: string;
|
|
48
|
+
/** Linux libc variant. Auto-detected if not specified. */
|
|
49
|
+
libc?: Libc;
|
|
46
50
|
/** Suppress log messages. @default false */
|
|
47
51
|
quiet?: boolean;
|
|
48
|
-
/** Remove macOS quarantine attribute after download. @default
|
|
52
|
+
/** Remove macOS quarantine attribute after download. @default true */
|
|
49
53
|
removeMacOSQuarantine?: boolean;
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
targetArch?:
|
|
54
|
-
|
|
54
|
+
/** Specific release tag to download. */
|
|
55
|
+
tag?: string;
|
|
56
|
+
/** Target architecture (defaults to current arch). */
|
|
57
|
+
targetArch?: Arch;
|
|
58
|
+
/** Target platform (defaults to current platform). */
|
|
59
|
+
targetPlatform?: Platform;
|
|
60
|
+
/** Tool/package name for directory structure and release matching. */
|
|
61
|
+
tool: string;
|
|
55
62
|
}
|
|
56
63
|
/**
|
|
57
64
|
* Configuration for downloading socket-btm releases (binary or asset).
|