@socketsecurity/lib 5.7.0 → 5.8.1
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 +48 -2
- package/README.md +190 -18
- package/dist/archives.d.ts +58 -0
- package/dist/archives.js +313 -0
- package/dist/arrays.js +2 -3
- package/dist/bin.js +100 -23
- package/dist/cache-with-ttl.js +21 -6
- package/dist/constants/agents.d.ts +0 -1
- package/dist/constants/agents.js +8 -8
- package/dist/constants/node.js +2 -1
- package/dist/cover/formatters.js +5 -3
- package/dist/dlx/detect.js +39 -13
- package/dist/dlx/package.js +10 -1
- package/dist/external/@npmcli/package-json.js +352 -824
- package/dist/external/adm-zip.js +2695 -0
- package/dist/external/debug.js +183 -7
- package/dist/external/external-pack.js +19 -1409
- package/dist/external/libnpmexec.js +2 -2
- package/dist/external/npm-pack.js +18777 -19997
- package/dist/external/pico-pack.js +29 -5
- package/dist/external/spdx-pack.js +41 -263
- package/dist/external/tar-fs.js +3053 -0
- package/dist/git.js +63 -23
- package/dist/github.js +7 -8
- package/dist/globs.js +20 -1
- package/dist/http-request.js +1 -1
- package/dist/memoization.js +22 -13
- package/dist/package-extensions.js +4 -2
- package/dist/packages/normalize.js +3 -0
- package/dist/process-lock.js +7 -5
- package/dist/releases/github.d.ts +40 -0
- package/dist/releases/github.js +122 -22
- package/dist/spawn.js +31 -6
- package/dist/spinner.js +1 -1
- package/dist/stdio/progress.js +2 -2
- package/package.json +38 -15
package/dist/git.js
CHANGED
|
@@ -34,6 +34,7 @@ __export(git_exports, {
|
|
|
34
34
|
isUnstagedSync: () => isUnstagedSync
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(git_exports);
|
|
37
|
+
var import_bin = require("./bin");
|
|
37
38
|
var import_debug = require("./debug");
|
|
38
39
|
var import_globs = require("./globs");
|
|
39
40
|
var import_normalize = require("./paths/normalize");
|
|
@@ -56,8 +57,38 @@ function getPath() {
|
|
|
56
57
|
return _path;
|
|
57
58
|
}
|
|
58
59
|
const gitDiffCache = /* @__PURE__ */ new Map();
|
|
60
|
+
const gitDiffAccessOrder = [];
|
|
61
|
+
const GIT_CACHE_MAX_SIZE = 100;
|
|
62
|
+
function evictLRUGitCache() {
|
|
63
|
+
if (gitDiffCache.size >= GIT_CACHE_MAX_SIZE && gitDiffAccessOrder.length > 0) {
|
|
64
|
+
const oldest = gitDiffAccessOrder.shift();
|
|
65
|
+
if (oldest) {
|
|
66
|
+
gitDiffCache.delete(oldest);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
let _gitPath;
|
|
71
|
+
const realpathCache = /* @__PURE__ */ new Map();
|
|
72
|
+
const gitRootCache = /* @__PURE__ */ new Map();
|
|
73
|
+
function getCachedRealpath(pathname) {
|
|
74
|
+
const fs = /* @__PURE__ */ getFs();
|
|
75
|
+
const cached = realpathCache.get(pathname);
|
|
76
|
+
if (cached) {
|
|
77
|
+
if (fs.existsSync(cached)) {
|
|
78
|
+
return cached;
|
|
79
|
+
}
|
|
80
|
+
realpathCache.delete(pathname);
|
|
81
|
+
}
|
|
82
|
+
const resolved = fs.realpathSync(pathname);
|
|
83
|
+
realpathCache.set(pathname, resolved);
|
|
84
|
+
return resolved;
|
|
85
|
+
}
|
|
59
86
|
function getGitPath() {
|
|
60
|
-
|
|
87
|
+
if (_gitPath === void 0) {
|
|
88
|
+
const resolved = (0, import_bin.whichSync)("git", { nothrow: true });
|
|
89
|
+
_gitPath = typeof resolved === "string" ? resolved : "git";
|
|
90
|
+
}
|
|
91
|
+
return _gitPath;
|
|
61
92
|
}
|
|
62
93
|
function getCwd() {
|
|
63
94
|
return (/* @__PURE__ */ getFs()).realpathSync(process.cwd());
|
|
@@ -114,7 +145,9 @@ async function innerDiff(args, options) {
|
|
|
114
145
|
return [];
|
|
115
146
|
}
|
|
116
147
|
if (cache && cacheKey) {
|
|
148
|
+
evictLRUGitCache();
|
|
117
149
|
gitDiffCache.set(cacheKey, result);
|
|
150
|
+
gitDiffAccessOrder.push(cacheKey);
|
|
118
151
|
}
|
|
119
152
|
return result;
|
|
120
153
|
}
|
|
@@ -144,18 +177,28 @@ function innerDiffSync(args, options) {
|
|
|
144
177
|
return [];
|
|
145
178
|
}
|
|
146
179
|
if (cache && cacheKey) {
|
|
180
|
+
evictLRUGitCache();
|
|
147
181
|
gitDiffCache.set(cacheKey, result);
|
|
182
|
+
gitDiffAccessOrder.push(cacheKey);
|
|
148
183
|
}
|
|
149
184
|
return result;
|
|
150
185
|
}
|
|
151
186
|
function findGitRoot(startPath) {
|
|
152
187
|
const fs = /* @__PURE__ */ getFs();
|
|
153
188
|
const path = /* @__PURE__ */ getPath();
|
|
189
|
+
const cached = gitRootCache.get(startPath);
|
|
190
|
+
if (cached) {
|
|
191
|
+
if (fs.existsSync(path.join(cached, ".git"))) {
|
|
192
|
+
return cached;
|
|
193
|
+
}
|
|
194
|
+
gitRootCache.delete(startPath);
|
|
195
|
+
}
|
|
154
196
|
let currentPath = startPath;
|
|
155
197
|
while (true) {
|
|
156
198
|
try {
|
|
157
199
|
const gitPath = path.join(currentPath, ".git");
|
|
158
200
|
if (fs.existsSync(gitPath)) {
|
|
201
|
+
gitRootCache.set(startPath, currentPath);
|
|
159
202
|
return currentPath;
|
|
160
203
|
}
|
|
161
204
|
} catch {
|
|
@@ -175,9 +218,8 @@ function parseGitDiffStdout(stdout, options, spawnCwd) {
|
|
|
175
218
|
porcelain = false,
|
|
176
219
|
...matcherOptions
|
|
177
220
|
} = { __proto__: null, ...options };
|
|
178
|
-
const fs = /* @__PURE__ */ getFs();
|
|
179
221
|
const path = /* @__PURE__ */ getPath();
|
|
180
|
-
const cwd = cwdOption === defaultRoot ? defaultRoot :
|
|
222
|
+
const cwd = cwdOption === defaultRoot ? defaultRoot : getCachedRealpath(cwdOption);
|
|
181
223
|
const rootPath = defaultRoot;
|
|
182
224
|
let rawFiles = stdout ? (0, import_strings.stripAnsi)(stdout).split("\n").map((line) => line.trimEnd()).filter((line) => line) : [];
|
|
183
225
|
if (porcelain) {
|
|
@@ -241,10 +283,9 @@ async function isChanged(pathname, options) {
|
|
|
241
283
|
...options,
|
|
242
284
|
absolute: false
|
|
243
285
|
});
|
|
244
|
-
const fs = /* @__PURE__ */ getFs();
|
|
245
286
|
const path = /* @__PURE__ */ getPath();
|
|
246
|
-
const resolvedPathname =
|
|
247
|
-
const baseCwd = options?.cwd ?
|
|
287
|
+
const resolvedPathname = getCachedRealpath(pathname);
|
|
288
|
+
const baseCwd = options?.cwd ? getCachedRealpath(options["cwd"]) : getCwd();
|
|
248
289
|
const relativePath = (0, import_normalize.normalizePath)(path.relative(baseCwd, resolvedPathname));
|
|
249
290
|
return files.includes(relativePath);
|
|
250
291
|
}
|
|
@@ -254,12 +295,15 @@ function isChangedSync(pathname, options) {
|
|
|
254
295
|
...options,
|
|
255
296
|
absolute: false
|
|
256
297
|
});
|
|
257
|
-
const fs = /* @__PURE__ */ getFs();
|
|
258
298
|
const path = /* @__PURE__ */ getPath();
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
299
|
+
try {
|
|
300
|
+
const resolvedPathname = getCachedRealpath(pathname);
|
|
301
|
+
const baseCwd = options?.cwd ? getCachedRealpath(options["cwd"]) : getCwd();
|
|
302
|
+
const relativePath = (0, import_normalize.normalizePath)(path.relative(baseCwd, resolvedPathname));
|
|
303
|
+
return files.includes(relativePath);
|
|
304
|
+
} catch {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
263
307
|
}
|
|
264
308
|
async function isUnstaged(pathname, options) {
|
|
265
309
|
const files = await getUnstagedFiles({
|
|
@@ -267,10 +311,9 @@ async function isUnstaged(pathname, options) {
|
|
|
267
311
|
...options,
|
|
268
312
|
absolute: false
|
|
269
313
|
});
|
|
270
|
-
const fs = /* @__PURE__ */ getFs();
|
|
271
314
|
const path = /* @__PURE__ */ getPath();
|
|
272
|
-
const resolvedPathname =
|
|
273
|
-
const baseCwd = options?.cwd ?
|
|
315
|
+
const resolvedPathname = getCachedRealpath(pathname);
|
|
316
|
+
const baseCwd = options?.cwd ? getCachedRealpath(options["cwd"]) : getCwd();
|
|
274
317
|
const relativePath = (0, import_normalize.normalizePath)(path.relative(baseCwd, resolvedPathname));
|
|
275
318
|
return files.includes(relativePath);
|
|
276
319
|
}
|
|
@@ -280,10 +323,9 @@ function isUnstagedSync(pathname, options) {
|
|
|
280
323
|
...options,
|
|
281
324
|
absolute: false
|
|
282
325
|
});
|
|
283
|
-
const fs = /* @__PURE__ */ getFs();
|
|
284
326
|
const path = /* @__PURE__ */ getPath();
|
|
285
|
-
const resolvedPathname =
|
|
286
|
-
const baseCwd = options?.cwd ?
|
|
327
|
+
const resolvedPathname = getCachedRealpath(pathname);
|
|
328
|
+
const baseCwd = options?.cwd ? getCachedRealpath(options["cwd"]) : getCwd();
|
|
287
329
|
const relativePath = (0, import_normalize.normalizePath)(path.relative(baseCwd, resolvedPathname));
|
|
288
330
|
return files.includes(relativePath);
|
|
289
331
|
}
|
|
@@ -293,10 +335,9 @@ async function isStaged(pathname, options) {
|
|
|
293
335
|
...options,
|
|
294
336
|
absolute: false
|
|
295
337
|
});
|
|
296
|
-
const fs = /* @__PURE__ */ getFs();
|
|
297
338
|
const path = /* @__PURE__ */ getPath();
|
|
298
|
-
const resolvedPathname =
|
|
299
|
-
const baseCwd = options?.cwd ?
|
|
339
|
+
const resolvedPathname = getCachedRealpath(pathname);
|
|
340
|
+
const baseCwd = options?.cwd ? getCachedRealpath(options["cwd"]) : getCwd();
|
|
300
341
|
const relativePath = (0, import_normalize.normalizePath)(path.relative(baseCwd, resolvedPathname));
|
|
301
342
|
return files.includes(relativePath);
|
|
302
343
|
}
|
|
@@ -306,10 +347,9 @@ function isStagedSync(pathname, options) {
|
|
|
306
347
|
...options,
|
|
307
348
|
absolute: false
|
|
308
349
|
});
|
|
309
|
-
const fs = /* @__PURE__ */ getFs();
|
|
310
350
|
const path = /* @__PURE__ */ getPath();
|
|
311
|
-
const resolvedPathname =
|
|
312
|
-
const baseCwd = options?.cwd ?
|
|
351
|
+
const resolvedPathname = getCachedRealpath(pathname);
|
|
352
|
+
const baseCwd = options?.cwd ? getCachedRealpath(options["cwd"]) : getCwd();
|
|
313
353
|
const relativePath = (0, import_normalize.normalizePath)(path.relative(baseCwd, resolvedPathname));
|
|
314
354
|
return files.includes(relativePath);
|
|
315
355
|
}
|
package/dist/github.js
CHANGED
|
@@ -189,15 +189,14 @@ async function fetchGhsaDetails(ghsaId, options) {
|
|
|
189
189
|
async function cacheFetchGhsa(ghsaId, options) {
|
|
190
190
|
const cache = getGithubCache();
|
|
191
191
|
const key = `ghsa:${ghsaId}`;
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
if (cached) {
|
|
195
|
-
return JSON.parse(cached);
|
|
196
|
-
}
|
|
192
|
+
if (process.env["DISABLE_GITHUB_CACHE"]) {
|
|
193
|
+
return await fetchGhsaDetails(ghsaId, options);
|
|
197
194
|
}
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
195
|
+
const cached = await cache.getOrFetch(key, async () => {
|
|
196
|
+
const data = await fetchGhsaDetails(ghsaId, options);
|
|
197
|
+
return JSON.stringify(data);
|
|
198
|
+
});
|
|
199
|
+
return JSON.parse(cached);
|
|
201
200
|
}
|
|
202
201
|
// Annotate the CommonJS export names for ESM import in node:
|
|
203
202
|
0 && (module.exports = {
|
package/dist/globs.js
CHANGED
|
@@ -107,15 +107,33 @@ function globStreamLicenses(dirname, options) {
|
|
|
107
107
|
}
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
|
+
const MATCHER_CACHE_MAX_SIZE = 100;
|
|
110
111
|
const matcherCache = /* @__PURE__ */ new Map();
|
|
112
|
+
const matcherAccessOrder = [];
|
|
113
|
+
function evictLRUMatcher() {
|
|
114
|
+
if (matcherCache.size >= MATCHER_CACHE_MAX_SIZE && matcherAccessOrder.length > 0) {
|
|
115
|
+
const oldest = matcherAccessOrder.shift();
|
|
116
|
+
if (oldest) {
|
|
117
|
+
matcherCache.delete(oldest);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
111
121
|
// @__NO_SIDE_EFFECTS__
|
|
112
122
|
function getGlobMatcher(glob2, options) {
|
|
113
123
|
const patterns = Array.isArray(glob2) ? glob2 : [glob2];
|
|
114
|
-
const
|
|
124
|
+
const sortedPatterns = [...patterns].sort();
|
|
125
|
+
const sortedOptions = options ? Object.keys(options).sort().map((k) => `${k}:${JSON.stringify(options[k])}`).join(",") : "";
|
|
126
|
+
const key = `${sortedPatterns.join("|")}:${sortedOptions}`;
|
|
115
127
|
let matcher = matcherCache.get(key);
|
|
116
128
|
if (matcher) {
|
|
129
|
+
const index = matcherAccessOrder.indexOf(key);
|
|
130
|
+
if (index !== -1) {
|
|
131
|
+
matcherAccessOrder.splice(index, 1);
|
|
132
|
+
matcherAccessOrder.push(key);
|
|
133
|
+
}
|
|
117
134
|
return matcher;
|
|
118
135
|
}
|
|
136
|
+
evictLRUMatcher();
|
|
119
137
|
const positivePatterns = patterns.filter((p) => !p.startsWith("!"));
|
|
120
138
|
const negativePatterns = patterns.filter((p) => p.startsWith("!")).map((p) => p.slice(1));
|
|
121
139
|
const matchOptions = {
|
|
@@ -129,6 +147,7 @@ function getGlobMatcher(glob2, options) {
|
|
|
129
147
|
matchOptions
|
|
130
148
|
);
|
|
131
149
|
matcherCache.set(key, matcher);
|
|
150
|
+
matcherAccessOrder.push(key);
|
|
132
151
|
return matcher;
|
|
133
152
|
}
|
|
134
153
|
// @__NO_SIDE_EFFECTS__
|
package/dist/http-request.js
CHANGED
|
@@ -299,7 +299,7 @@ async function httpDownload(url, destPath, options) {
|
|
|
299
299
|
} else if (logger) {
|
|
300
300
|
let lastPercent = 0;
|
|
301
301
|
progressCallback = (downloaded, total) => {
|
|
302
|
-
const percent = Math.floor(downloaded / total * 100);
|
|
302
|
+
const percent = total === 0 ? 0 : Math.floor(downloaded / total * 100);
|
|
303
303
|
if (percent >= lastPercent + progressInterval) {
|
|
304
304
|
logger.log(
|
|
305
305
|
` Progress: ${percent}% (${(downloaded / 1024 / 1024).toFixed(1)} MB / ${(total / 1024 / 1024).toFixed(1)} MB)`
|
package/dist/memoization.js
CHANGED
|
@@ -36,6 +36,9 @@ function memoize(fn, options = {}) {
|
|
|
36
36
|
name = fn.name || "anonymous",
|
|
37
37
|
ttl = Number.POSITIVE_INFINITY
|
|
38
38
|
} = options;
|
|
39
|
+
if (ttl < 0) {
|
|
40
|
+
throw new TypeError("TTL must be non-negative");
|
|
41
|
+
}
|
|
39
42
|
const cache = /* @__PURE__ */ new Map();
|
|
40
43
|
const accessOrder = [];
|
|
41
44
|
function evictLRU() {
|
|
@@ -123,7 +126,24 @@ function memoizeAsync(fn, options = {}) {
|
|
|
123
126
|
return await cached.value;
|
|
124
127
|
}
|
|
125
128
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] miss`, { key });
|
|
126
|
-
const promise = fn(...args)
|
|
129
|
+
const promise = fn(...args).then(
|
|
130
|
+
(result) => {
|
|
131
|
+
const entry = cache.get(key);
|
|
132
|
+
if (entry) {
|
|
133
|
+
entry.value = Promise.resolve(result);
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
},
|
|
137
|
+
(error) => {
|
|
138
|
+
cache.delete(key);
|
|
139
|
+
const index = accessOrder.indexOf(key);
|
|
140
|
+
if (index !== -1) {
|
|
141
|
+
accessOrder.splice(index, 1);
|
|
142
|
+
}
|
|
143
|
+
(0, import_debug.debugLog)(`[memoizeAsync:${name}] error`, { key, error });
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
);
|
|
127
147
|
evictLRU();
|
|
128
148
|
cache.set(key, {
|
|
129
149
|
value: promise,
|
|
@@ -132,18 +152,7 @@ function memoizeAsync(fn, options = {}) {
|
|
|
132
152
|
});
|
|
133
153
|
accessOrder.push(key);
|
|
134
154
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] set`, { key, cacheSize: cache.size });
|
|
135
|
-
|
|
136
|
-
const result = await promise;
|
|
137
|
-
return result;
|
|
138
|
-
} catch (e) {
|
|
139
|
-
cache.delete(key);
|
|
140
|
-
const orderIndex = accessOrder.indexOf(key);
|
|
141
|
-
if (orderIndex !== -1) {
|
|
142
|
-
accessOrder.splice(orderIndex, 1);
|
|
143
|
-
}
|
|
144
|
-
(0, import_debug.debugLog)(`[memoizeAsync:${name}] clear`, { key, reason: "error" });
|
|
145
|
-
throw e;
|
|
146
|
-
}
|
|
155
|
+
return await promise;
|
|
147
156
|
};
|
|
148
157
|
}
|
|
149
158
|
function Memoize(options = {}) {
|
|
@@ -64,8 +64,10 @@ const packageExtensions = ObjectFreeze(
|
|
|
64
64
|
}
|
|
65
65
|
]
|
|
66
66
|
].sort((a_, b_) => {
|
|
67
|
-
const
|
|
68
|
-
const
|
|
67
|
+
const aIndex = a_[0].lastIndexOf("@");
|
|
68
|
+
const bIndex = b_[0].lastIndexOf("@");
|
|
69
|
+
const a = aIndex === -1 ? a_[0] : a_[0].slice(0, aIndex);
|
|
70
|
+
const b = bIndex === -1 ? b_[0] : b_[0].slice(0, bIndex);
|
|
69
71
|
if (a < b) {
|
|
70
72
|
return -1;
|
|
71
73
|
}
|
|
@@ -91,6 +91,9 @@ function resolveOriginalPackageName(sockRegPkgName) {
|
|
|
91
91
|
}
|
|
92
92
|
// @__NO_SIDE_EFFECTS__
|
|
93
93
|
function unescapeScope(escapedScope) {
|
|
94
|
+
if (escapedScope.length < import_socket.REGISTRY_SCOPE_DELIMITER.length) {
|
|
95
|
+
return `@${escapedScope}`;
|
|
96
|
+
}
|
|
94
97
|
return `@${escapedScope.slice(0, -import_socket.REGISTRY_SCOPE_DELIMITER.length)}`;
|
|
95
98
|
}
|
|
96
99
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/process-lock.js
CHANGED
|
@@ -123,10 +123,10 @@ class ProcessLockManager {
|
|
|
123
123
|
*/
|
|
124
124
|
isStale(lockPath, staleMs) {
|
|
125
125
|
try {
|
|
126
|
-
|
|
126
|
+
const stats = statSync(lockPath, { throwIfNoEntry: false });
|
|
127
|
+
if (!stats) {
|
|
127
128
|
return false;
|
|
128
129
|
}
|
|
129
|
-
const stats = statSync(lockPath);
|
|
130
130
|
const ageSeconds = Math.floor((Date.now() - stats.mtime.getTime()) / 1e3);
|
|
131
131
|
const staleSeconds = Math.floor(staleMs / 1e3);
|
|
132
132
|
return ageSeconds > staleSeconds;
|
|
@@ -169,7 +169,7 @@ class ProcessLockManager {
|
|
|
169
169
|
return await (0, import_promises.pRetry)(
|
|
170
170
|
async () => {
|
|
171
171
|
try {
|
|
172
|
-
if (
|
|
172
|
+
if (this.isStale(lockPath, staleMs)) {
|
|
173
173
|
logger.log(`Removing stale lock: ${lockPath}`);
|
|
174
174
|
try {
|
|
175
175
|
(0, import_fs.safeDeleteSync)(lockPath, { recursive: true });
|
|
@@ -204,7 +204,8 @@ class ProcessLockManager {
|
|
|
204
204
|
);
|
|
205
205
|
}
|
|
206
206
|
if (code === "ENOTDIR") {
|
|
207
|
-
const
|
|
207
|
+
const lastSlashIndex = lockPath.lastIndexOf("/");
|
|
208
|
+
const parentDir = lastSlashIndex === -1 ? "." : lockPath.slice(0, lastSlashIndex);
|
|
208
209
|
throw new Error(
|
|
209
210
|
`Cannot create lock directory: ${lockPath}
|
|
210
211
|
A path component is a file when it should be a directory.
|
|
@@ -217,7 +218,8 @@ To resolve:
|
|
|
217
218
|
);
|
|
218
219
|
}
|
|
219
220
|
if (code === "ENOENT") {
|
|
220
|
-
const
|
|
221
|
+
const lastSlashIndex = lockPath.lastIndexOf("/");
|
|
222
|
+
const parentDir = lastSlashIndex === -1 ? "." : lockPath.slice(0, lastSlashIndex);
|
|
221
223
|
throw new Error(
|
|
222
224
|
`Cannot create lock directory: ${lockPath}
|
|
223
225
|
Parent directory does not exist: ${parentDir}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ArchiveFormat } from '../archives.js';
|
|
1
2
|
/**
|
|
2
3
|
* Pattern for matching release assets.
|
|
3
4
|
* Can be either:
|
|
@@ -133,3 +134,42 @@ export declare function getLatestRelease(toolPrefix: string, repoConfig: RepoCon
|
|
|
133
134
|
export declare function getReleaseAssetUrl(tag: string, assetPattern: string | AssetPattern, repoConfig: RepoConfig, options?: {
|
|
134
135
|
quiet?: boolean;
|
|
135
136
|
}): Promise<string | null>;
|
|
137
|
+
/**
|
|
138
|
+
* Download and extract a zip file from a GitHub release.
|
|
139
|
+
* Automatically handles downloading, extracting, and cleanup.
|
|
140
|
+
*
|
|
141
|
+
* @param tag - Release tag name
|
|
142
|
+
* @param assetPattern - Asset name or pattern (glob string, prefix/suffix object, or RegExp)
|
|
143
|
+
* @param outputDir - Directory to extract the zip contents to
|
|
144
|
+
* @param repoConfig - Repository configuration (owner/repo)
|
|
145
|
+
* @param options - Additional options
|
|
146
|
+
* @param options.quiet - Suppress log messages
|
|
147
|
+
* @param options.cleanup - Remove downloaded zip file after extraction (default: true)
|
|
148
|
+
* @returns Path to the extraction directory
|
|
149
|
+
*/
|
|
150
|
+
export declare function downloadAndExtractZip(tag: string, assetPattern: string | AssetPattern, outputDir: string, repoConfig: RepoConfig, options?: {
|
|
151
|
+
cleanup?: boolean;
|
|
152
|
+
quiet?: boolean;
|
|
153
|
+
}): Promise<string>;
|
|
154
|
+
/**
|
|
155
|
+
* Download and extract an archive from a GitHub release.
|
|
156
|
+
* Supports zip, tar, tar.gz, and tgz formats.
|
|
157
|
+
* Automatically handles downloading, extracting, and cleanup.
|
|
158
|
+
*
|
|
159
|
+
* @param tag - Release tag name
|
|
160
|
+
* @param assetPattern - Asset name or pattern (glob string, prefix/suffix object, or RegExp)
|
|
161
|
+
* @param outputDir - Directory to extract the archive contents to
|
|
162
|
+
* @param repoConfig - Repository configuration (owner/repo)
|
|
163
|
+
* @param options - Additional options
|
|
164
|
+
* @param options.quiet - Suppress log messages
|
|
165
|
+
* @param options.cleanup - Remove downloaded archive after extraction (default: true)
|
|
166
|
+
* @param options.strip - Strip leading path components (like tar --strip-components)
|
|
167
|
+
* @param options.format - Archive format (auto-detected if not specified)
|
|
168
|
+
* @returns Path to the extraction directory
|
|
169
|
+
*/
|
|
170
|
+
export declare function downloadAndExtractArchive(tag: string, assetPattern: string | AssetPattern, outputDir: string, repoConfig: RepoConfig, options?: {
|
|
171
|
+
cleanup?: boolean;
|
|
172
|
+
format?: ArchiveFormat;
|
|
173
|
+
quiet?: boolean;
|
|
174
|
+
strip?: number;
|
|
175
|
+
}): Promise<string>;
|
package/dist/releases/github.js
CHANGED
|
@@ -31,6 +31,8 @@ var github_exports = {};
|
|
|
31
31
|
__export(github_exports, {
|
|
32
32
|
SOCKET_BTM_REPO: () => SOCKET_BTM_REPO,
|
|
33
33
|
createAssetMatcher: () => createAssetMatcher,
|
|
34
|
+
downloadAndExtractArchive: () => downloadAndExtractArchive,
|
|
35
|
+
downloadAndExtractZip: () => downloadAndExtractZip,
|
|
34
36
|
downloadGitHubRelease: () => downloadGitHubRelease,
|
|
35
37
|
downloadReleaseAsset: () => downloadReleaseAsset,
|
|
36
38
|
getAuthHeaders: () => getAuthHeaders,
|
|
@@ -39,6 +41,7 @@ __export(github_exports, {
|
|
|
39
41
|
});
|
|
40
42
|
module.exports = __toCommonJS(github_exports);
|
|
41
43
|
var import_picomatch = __toESM(require("../external/picomatch.js"));
|
|
44
|
+
var import_archives = require("../archives.js");
|
|
42
45
|
var import_fs = require("../fs.js");
|
|
43
46
|
var import_http_request = require("../http-request.js");
|
|
44
47
|
var import_logger = require("../logger.js");
|
|
@@ -207,27 +210,33 @@ async function getLatestRelease(toolPrefix, repoConfig, options = {}) {
|
|
|
207
210
|
if (!response.ok) {
|
|
208
211
|
throw new Error(`Failed to fetch releases: ${response.status}`);
|
|
209
212
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
|
|
213
|
+
let releases;
|
|
214
|
+
try {
|
|
215
|
+
releases = JSON.parse(response.body.toString("utf8"));
|
|
216
|
+
} catch (cause) {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`Failed to parse GitHub releases response from https://api.github.com/repos/${owner}/${repo}/releases`,
|
|
219
|
+
{ cause }
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
const matchingReleases = releases.filter((release) => {
|
|
223
|
+
const { assets, tag_name: tag2 } = release;
|
|
224
|
+
if (!tag2.startsWith(toolPrefix)) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
if (!assets || assets.length === 0) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
if (isMatch) {
|
|
231
|
+
const hasMatchingAsset = assets.some(
|
|
232
|
+
(a) => isMatch(a.name)
|
|
233
|
+
);
|
|
234
|
+
if (!hasMatchingAsset) {
|
|
218
235
|
return false;
|
|
219
236
|
}
|
|
220
|
-
if (isMatch) {
|
|
221
|
-
const hasMatchingAsset = assets.some(
|
|
222
|
-
(a) => isMatch(a.name)
|
|
223
|
-
);
|
|
224
|
-
if (!hasMatchingAsset) {
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return true;
|
|
229
237
|
}
|
|
230
|
-
|
|
238
|
+
return true;
|
|
239
|
+
});
|
|
231
240
|
if (matchingReleases.length === 0) {
|
|
232
241
|
if (!quiet) {
|
|
233
242
|
logger.info(`No ${toolPrefix} release found in latest 100 releases`);
|
|
@@ -275,10 +284,16 @@ async function getReleaseAssetUrl(tag, assetPattern, repoConfig, options = {}) {
|
|
|
275
284
|
if (!response.ok) {
|
|
276
285
|
throw new Error(`Failed to fetch release ${tag}: ${response.status}`);
|
|
277
286
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
)
|
|
287
|
+
let release;
|
|
288
|
+
try {
|
|
289
|
+
release = JSON.parse(response.body.toString("utf8"));
|
|
290
|
+
} catch (cause) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
`Failed to parse GitHub release response for tag ${tag}`,
|
|
293
|
+
{ cause }
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
const asset = release.assets.find((a) => isMatch(a.name));
|
|
282
297
|
if (!asset) {
|
|
283
298
|
const patternDesc = typeof assetPattern === "string" ? assetPattern : "matching pattern";
|
|
284
299
|
throw new Error(`Asset ${patternDesc} not found in release ${tag}`);
|
|
@@ -304,10 +319,95 @@ async function getReleaseAssetUrl(tag, assetPattern, repoConfig, options = {}) {
|
|
|
304
319
|
}
|
|
305
320
|
);
|
|
306
321
|
}
|
|
322
|
+
async function downloadAndExtractZip(tag, assetPattern, outputDir, repoConfig, options = {}) {
|
|
323
|
+
const { cleanup = true, quiet = false } = options;
|
|
324
|
+
const path = /* @__PURE__ */ getPath();
|
|
325
|
+
const fs = /* @__PURE__ */ getFs();
|
|
326
|
+
await (0, import_fs.safeMkdir)(outputDir);
|
|
327
|
+
const zipPath = path.join(outputDir, "__temp_download__.zip");
|
|
328
|
+
if (!quiet) {
|
|
329
|
+
logger.info(`Downloading zip asset from release ${tag}...`);
|
|
330
|
+
}
|
|
331
|
+
await downloadReleaseAsset(tag, assetPattern, zipPath, repoConfig, { quiet });
|
|
332
|
+
if (!quiet) {
|
|
333
|
+
logger.info(`Extracting zip to ${outputDir}...`);
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
await (0, import_archives.extractArchive)(zipPath, outputDir, { quiet });
|
|
337
|
+
if (!quiet) {
|
|
338
|
+
logger.info(`Extracted zip contents to ${outputDir}`);
|
|
339
|
+
}
|
|
340
|
+
} catch (cause) {
|
|
341
|
+
throw new Error(`Failed to extract zip file: ${zipPath}`, { cause });
|
|
342
|
+
} finally {
|
|
343
|
+
if (cleanup) {
|
|
344
|
+
try {
|
|
345
|
+
await fs.promises.unlink(zipPath);
|
|
346
|
+
if (!quiet) {
|
|
347
|
+
logger.info("Cleaned up temporary zip file");
|
|
348
|
+
}
|
|
349
|
+
} catch (error) {
|
|
350
|
+
if (!quiet) {
|
|
351
|
+
logger.warn(`Failed to cleanup zip file: ${error}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return outputDir;
|
|
357
|
+
}
|
|
358
|
+
async function downloadAndExtractArchive(tag, assetPattern, outputDir, repoConfig, options = {}) {
|
|
359
|
+
const { cleanup = true, format, quiet = false, strip } = options;
|
|
360
|
+
const path = /* @__PURE__ */ getPath();
|
|
361
|
+
const fs = /* @__PURE__ */ getFs();
|
|
362
|
+
await (0, import_fs.safeMkdir)(outputDir);
|
|
363
|
+
let ext = ".archive";
|
|
364
|
+
if (format) {
|
|
365
|
+
ext = format === "tar.gz" ? ".tar.gz" : `.${format}`;
|
|
366
|
+
} else if (typeof assetPattern === "string") {
|
|
367
|
+
const detectedFormat = (0, import_archives.detectArchiveFormat)(assetPattern);
|
|
368
|
+
if (detectedFormat) {
|
|
369
|
+
ext = detectedFormat === "tar.gz" ? ".tar.gz" : `.${detectedFormat}`;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const archivePath = path.join(outputDir, `__temp_download__${ext}`);
|
|
373
|
+
if (!quiet) {
|
|
374
|
+
logger.info(`Downloading archive from release ${tag}...`);
|
|
375
|
+
}
|
|
376
|
+
await downloadReleaseAsset(tag, assetPattern, archivePath, repoConfig, {
|
|
377
|
+
quiet
|
|
378
|
+
});
|
|
379
|
+
if (!quiet) {
|
|
380
|
+
logger.info(`Extracting archive to ${outputDir}...`);
|
|
381
|
+
}
|
|
382
|
+
try {
|
|
383
|
+
await (0, import_archives.extractArchive)(archivePath, outputDir, { quiet, strip });
|
|
384
|
+
if (!quiet) {
|
|
385
|
+
logger.info(`Extracted archive contents to ${outputDir}`);
|
|
386
|
+
}
|
|
387
|
+
} catch (cause) {
|
|
388
|
+
throw new Error(`Failed to extract archive: ${archivePath}`, { cause });
|
|
389
|
+
} finally {
|
|
390
|
+
if (cleanup) {
|
|
391
|
+
try {
|
|
392
|
+
await fs.promises.unlink(archivePath);
|
|
393
|
+
if (!quiet) {
|
|
394
|
+
logger.info("Cleaned up temporary archive file");
|
|
395
|
+
}
|
|
396
|
+
} catch (error) {
|
|
397
|
+
if (!quiet) {
|
|
398
|
+
logger.warn(`Failed to cleanup archive file: ${error}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return outputDir;
|
|
404
|
+
}
|
|
307
405
|
// Annotate the CommonJS export names for ESM import in node:
|
|
308
406
|
0 && (module.exports = {
|
|
309
407
|
SOCKET_BTM_REPO,
|
|
310
408
|
createAssetMatcher,
|
|
409
|
+
downloadAndExtractArchive,
|
|
410
|
+
downloadAndExtractZip,
|
|
311
411
|
downloadGitHubRelease,
|
|
312
412
|
downloadReleaseAsset,
|
|
313
413
|
getAuthHeaders,
|