@socketsecurity/lib 5.5.3 → 5.7.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 +95 -1
- package/dist/cache-with-ttl.js +5 -1
- package/dist/dlx/binary.d.ts +47 -52
- package/dist/dlx/binary.js +129 -134
- package/dist/dlx/detect.d.ts +8 -8
- package/dist/dlx/detect.js +18 -18
- package/dist/dlx/manifest.d.ts +43 -36
- package/dist/dlx/manifest.js +114 -112
- package/dist/dlx/package.d.ts +55 -0
- package/dist/dlx/package.js +89 -79
- package/dist/env/ci.js +1 -2
- package/dist/env/rewire.d.ts +33 -22
- package/dist/env/rewire.js +20 -7
- package/dist/env/socket-cli.d.ts +24 -24
- package/dist/env/socket-cli.js +12 -12
- package/dist/env/temp-dir.d.ts +6 -6
- package/dist/env/temp-dir.js +4 -4
- package/dist/env/windows.d.ts +6 -6
- package/dist/env/windows.js +4 -4
- package/dist/external/libnpmexec.js +2 -2
- package/dist/github.js +10 -1
- package/dist/http-request.d.ts +79 -63
- package/dist/http-request.js +203 -159
- package/dist/packages/specs.js +1 -1
- package/dist/releases/github.d.ts +18 -7
- package/dist/releases/github.js +94 -92
- package/package.json +4 -4
package/dist/http-request.d.ts
CHANGED
|
@@ -435,46 +435,6 @@ export interface HttpDownloadResult {
|
|
|
435
435
|
*/
|
|
436
436
|
size: number;
|
|
437
437
|
}
|
|
438
|
-
/**
|
|
439
|
-
* Make an HTTP/HTTPS request with retry logic and redirect support.
|
|
440
|
-
* Provides a fetch-like API using Node.js native http/https modules.
|
|
441
|
-
*
|
|
442
|
-
* This is the main entry point for making HTTP requests. It handles retries,
|
|
443
|
-
* redirects, timeouts, and provides a fetch-compatible response interface.
|
|
444
|
-
*
|
|
445
|
-
* @param url - The URL to request (must start with http:// or https://)
|
|
446
|
-
* @param options - Request configuration options
|
|
447
|
-
* @returns Promise resolving to response object with `.json()`, `.text()`, etc.
|
|
448
|
-
* @throws {Error} When all retries are exhausted, timeout occurs, or non-retryable error happens
|
|
449
|
-
*
|
|
450
|
-
* @example
|
|
451
|
-
* ```ts
|
|
452
|
-
* // Simple GET request
|
|
453
|
-
* const response = await httpRequest('https://api.example.com/data')
|
|
454
|
-
* const data = response.json()
|
|
455
|
-
*
|
|
456
|
-
* // POST with JSON body
|
|
457
|
-
* const response = await httpRequest('https://api.example.com/users', {
|
|
458
|
-
* method: 'POST',
|
|
459
|
-
* headers: { 'Content-Type': 'application/json' },
|
|
460
|
-
* body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
|
|
461
|
-
* })
|
|
462
|
-
*
|
|
463
|
-
* // With retries and timeout
|
|
464
|
-
* const response = await httpRequest('https://api.example.com/data', {
|
|
465
|
-
* retries: 3,
|
|
466
|
-
* retryDelay: 1000,
|
|
467
|
-
* timeout: 60000
|
|
468
|
-
* })
|
|
469
|
-
*
|
|
470
|
-
* // Don't follow redirects
|
|
471
|
-
* const response = await httpRequest('https://example.com/redirect', {
|
|
472
|
-
* followRedirects: false
|
|
473
|
-
* })
|
|
474
|
-
* console.log(response.status) // 301, 302, etc.
|
|
475
|
-
* ```
|
|
476
|
-
*/
|
|
477
|
-
export declare function httpRequest(url: string, options?: HttpRequestOptions | undefined): Promise<HttpResponse>;
|
|
478
438
|
/**
|
|
479
439
|
* Download a file from a URL to a local path with redirect support, retry logic, and progress callbacks.
|
|
480
440
|
* Uses streaming to avoid loading entire file in memory.
|
|
@@ -533,8 +493,12 @@ export declare function httpRequest(url: string, options?: HttpRequestOptions |
|
|
|
533
493
|
*/
|
|
534
494
|
export declare function httpDownload(url: string, destPath: string, options?: HttpDownloadOptions | undefined): Promise<HttpDownloadResult>;
|
|
535
495
|
/**
|
|
536
|
-
* Perform
|
|
537
|
-
* Convenience wrapper around `httpRequest` for
|
|
496
|
+
* Perform an HTTP request and parse JSON response.
|
|
497
|
+
* Convenience wrapper around `httpRequest` for JSON API calls.
|
|
498
|
+
* Automatically sets appropriate headers for JSON requests:
|
|
499
|
+
* - `Accept: application/json` (always)
|
|
500
|
+
* - `Content-Type: application/json` (when body is present)
|
|
501
|
+
* User-provided headers override these defaults.
|
|
538
502
|
*
|
|
539
503
|
* @template T - Expected JSON response type (defaults to `unknown`)
|
|
540
504
|
* @param url - The URL to request (must start with http:// or https://)
|
|
@@ -544,34 +508,79 @@ export declare function httpDownload(url: string, destPath: string, options?: Ht
|
|
|
544
508
|
*
|
|
545
509
|
* @example
|
|
546
510
|
* ```ts
|
|
547
|
-
* // Simple JSON GET
|
|
548
|
-
* const data = await
|
|
511
|
+
* // Simple JSON GET (automatically sets Accept: application/json)
|
|
512
|
+
* const data = await httpJson('https://api.example.com/data')
|
|
549
513
|
* console.log(data)
|
|
550
514
|
*
|
|
551
515
|
* // With type safety
|
|
552
516
|
* interface User { id: number; name: string; email: string }
|
|
553
|
-
* const user = await
|
|
517
|
+
* const user = await httpJson<User>('https://api.example.com/user/123')
|
|
554
518
|
* console.log(user.name, user.email)
|
|
555
519
|
*
|
|
556
|
-
* //
|
|
557
|
-
* const
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
* 'Accept': 'application/json'
|
|
561
|
-
* }
|
|
520
|
+
* // POST with JSON body (automatically sets Content-Type: application/json)
|
|
521
|
+
* const result = await httpJson('https://api.example.com/users', {
|
|
522
|
+
* method: 'POST',
|
|
523
|
+
* body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
|
|
562
524
|
* })
|
|
563
525
|
*
|
|
564
|
-
* // With retries
|
|
565
|
-
* const data = await
|
|
526
|
+
* // With custom headers and retries
|
|
527
|
+
* const data = await httpJson('https://api.example.com/data', {
|
|
528
|
+
* headers: {
|
|
529
|
+
* 'Authorization': 'Bearer token123'
|
|
530
|
+
* },
|
|
566
531
|
* retries: 3,
|
|
567
532
|
* retryDelay: 1000
|
|
568
533
|
* })
|
|
569
534
|
* ```
|
|
570
535
|
*/
|
|
571
|
-
export declare function
|
|
536
|
+
export declare function httpJson<T = unknown>(url: string, options?: HttpRequestOptions | undefined): Promise<T>;
|
|
537
|
+
/**
|
|
538
|
+
* Make an HTTP/HTTPS request with retry logic and redirect support.
|
|
539
|
+
* Provides a fetch-like API using Node.js native http/https modules.
|
|
540
|
+
*
|
|
541
|
+
* This is the main entry point for making HTTP requests. It handles retries,
|
|
542
|
+
* redirects, timeouts, and provides a fetch-compatible response interface.
|
|
543
|
+
*
|
|
544
|
+
* @param url - The URL to request (must start with http:// or https://)
|
|
545
|
+
* @param options - Request configuration options
|
|
546
|
+
* @returns Promise resolving to response object with `.json()`, `.text()`, etc.
|
|
547
|
+
* @throws {Error} When all retries are exhausted, timeout occurs, or non-retryable error happens
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```ts
|
|
551
|
+
* // Simple GET request
|
|
552
|
+
* const response = await httpRequest('https://api.example.com/data')
|
|
553
|
+
* const data = response.json()
|
|
554
|
+
*
|
|
555
|
+
* // POST with JSON body
|
|
556
|
+
* const response = await httpRequest('https://api.example.com/users', {
|
|
557
|
+
* method: 'POST',
|
|
558
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
559
|
+
* body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
|
|
560
|
+
* })
|
|
561
|
+
*
|
|
562
|
+
* // With retries and timeout
|
|
563
|
+
* const response = await httpRequest('https://api.example.com/data', {
|
|
564
|
+
* retries: 3,
|
|
565
|
+
* retryDelay: 1000,
|
|
566
|
+
* timeout: 60000
|
|
567
|
+
* })
|
|
568
|
+
*
|
|
569
|
+
* // Don't follow redirects
|
|
570
|
+
* const response = await httpRequest('https://example.com/redirect', {
|
|
571
|
+
* followRedirects: false
|
|
572
|
+
* })
|
|
573
|
+
* console.log(response.status) // 301, 302, etc.
|
|
574
|
+
* ```
|
|
575
|
+
*/
|
|
576
|
+
export declare function httpRequest(url: string, options?: HttpRequestOptions | undefined): Promise<HttpResponse>;
|
|
572
577
|
/**
|
|
573
|
-
* Perform
|
|
578
|
+
* Perform an HTTP request and return text response.
|
|
574
579
|
* Convenience wrapper around `httpRequest` for fetching text content.
|
|
580
|
+
* Automatically sets appropriate headers for text requests:
|
|
581
|
+
* - `Accept: text/plain` (always)
|
|
582
|
+
* - `Content-Type: text/plain` (when body is present)
|
|
583
|
+
* User-provided headers override these defaults.
|
|
575
584
|
*
|
|
576
585
|
* @param url - The URL to request (must start with http:// or https://)
|
|
577
586
|
* @param options - Request configuration options
|
|
@@ -580,25 +589,32 @@ export declare function httpGetJson<T = unknown>(url: string, options?: HttpRequ
|
|
|
580
589
|
*
|
|
581
590
|
* @example
|
|
582
591
|
* ```ts
|
|
583
|
-
* // Fetch HTML
|
|
584
|
-
* const html = await
|
|
592
|
+
* // Fetch HTML (automatically sets Accept: text/plain)
|
|
593
|
+
* const html = await httpText('https://example.com')
|
|
585
594
|
* console.log(html.includes('<!DOCTYPE html>'))
|
|
586
595
|
*
|
|
587
596
|
* // Fetch plain text
|
|
588
|
-
* const text = await
|
|
597
|
+
* const text = await httpText('https://example.com/file.txt')
|
|
589
598
|
* console.log(text)
|
|
590
599
|
*
|
|
591
|
-
* //
|
|
592
|
-
* const
|
|
600
|
+
* // POST with text body (automatically sets Content-Type: text/plain)
|
|
601
|
+
* const result = await httpText('https://example.com/api', {
|
|
602
|
+
* method: 'POST',
|
|
603
|
+
* body: 'raw text data'
|
|
604
|
+
* })
|
|
605
|
+
*
|
|
606
|
+
* // With custom headers (override defaults)
|
|
607
|
+
* const text = await httpText('https://example.com/data.txt', {
|
|
593
608
|
* headers: {
|
|
594
|
-
* 'Authorization': 'Bearer token123'
|
|
609
|
+
* 'Authorization': 'Bearer token123',
|
|
610
|
+
* 'Accept': 'text/html' // Override default Accept header
|
|
595
611
|
* }
|
|
596
612
|
* })
|
|
597
613
|
*
|
|
598
614
|
* // With timeout
|
|
599
|
-
* const text = await
|
|
615
|
+
* const text = await httpText('https://example.com/large-file.txt', {
|
|
600
616
|
* timeout: 60000 // 1 minute
|
|
601
617
|
* })
|
|
602
618
|
* ```
|
|
603
619
|
*/
|
|
604
|
-
export declare function
|
|
620
|
+
export declare function httpText(url: string, options?: HttpRequestOptions | undefined): Promise<string>;
|
package/dist/http-request.js
CHANGED
|
@@ -20,9 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var http_request_exports = {};
|
|
21
21
|
__export(http_request_exports, {
|
|
22
22
|
httpDownload: () => httpDownload,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
httpJson: () => httpJson,
|
|
24
|
+
httpRequest: () => httpRequest,
|
|
25
|
+
httpText: () => httpText
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(http_request_exports);
|
|
28
28
|
let _fs;
|
|
@@ -49,38 +49,131 @@ function getHttps() {
|
|
|
49
49
|
}
|
|
50
50
|
return _https;
|
|
51
51
|
}
|
|
52
|
-
async function
|
|
52
|
+
async function httpDownloadAttempt(url, destPath, options) {
|
|
53
53
|
const {
|
|
54
|
-
body,
|
|
55
54
|
followRedirects = true,
|
|
56
55
|
headers = {},
|
|
57
56
|
maxRedirects = 5,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
retryDelay = 1e3,
|
|
61
|
-
timeout = 3e4
|
|
57
|
+
onProgress,
|
|
58
|
+
timeout = 12e4
|
|
62
59
|
} = { __proto__: null, ...options };
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
60
|
+
return await new Promise((resolve, reject) => {
|
|
61
|
+
const parsedUrl = new URL(url);
|
|
62
|
+
const isHttps = parsedUrl.protocol === "https:";
|
|
63
|
+
const httpModule = isHttps ? /* @__PURE__ */ getHttps() : /* @__PURE__ */ getHttp();
|
|
64
|
+
const requestOptions = {
|
|
65
|
+
headers: {
|
|
66
|
+
"User-Agent": "socket-registry/1.0",
|
|
67
|
+
...headers
|
|
68
|
+
},
|
|
69
|
+
hostname: parsedUrl.hostname,
|
|
70
|
+
method: "GET",
|
|
71
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
72
|
+
port: parsedUrl.port,
|
|
73
|
+
timeout
|
|
74
|
+
};
|
|
75
|
+
const { createWriteStream } = /* @__PURE__ */ getFs();
|
|
76
|
+
let fileStream;
|
|
77
|
+
let streamClosed = false;
|
|
78
|
+
const closeStream = () => {
|
|
79
|
+
if (!streamClosed && fileStream) {
|
|
80
|
+
streamClosed = true;
|
|
81
|
+
fileStream.close();
|
|
78
82
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
};
|
|
84
|
+
const request = httpModule.request(
|
|
85
|
+
requestOptions,
|
|
86
|
+
(res) => {
|
|
87
|
+
if (followRedirects && res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
88
|
+
if (maxRedirects <= 0) {
|
|
89
|
+
reject(
|
|
90
|
+
new Error(
|
|
91
|
+
`Too many redirects (exceeded maximum: ${maxRedirects})`
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const redirectUrl = res.headers.location.startsWith("http") ? res.headers.location : new URL(res.headers.location, url).toString();
|
|
97
|
+
resolve(
|
|
98
|
+
httpDownloadAttempt(redirectUrl, destPath, {
|
|
99
|
+
followRedirects,
|
|
100
|
+
headers,
|
|
101
|
+
maxRedirects: maxRedirects - 1,
|
|
102
|
+
onProgress,
|
|
103
|
+
timeout
|
|
104
|
+
})
|
|
105
|
+
);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
|
|
109
|
+
closeStream();
|
|
110
|
+
reject(
|
|
111
|
+
new Error(
|
|
112
|
+
`Download failed: HTTP ${res.statusCode} ${res.statusMessage}`
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const totalSize = Number.parseInt(
|
|
118
|
+
res.headers["content-length"] || "0",
|
|
119
|
+
10
|
|
120
|
+
);
|
|
121
|
+
let downloadedSize = 0;
|
|
122
|
+
fileStream = createWriteStream(destPath);
|
|
123
|
+
fileStream.on("error", (error) => {
|
|
124
|
+
closeStream();
|
|
125
|
+
const err = new Error(`Failed to write file: ${error.message}`, {
|
|
126
|
+
cause: error
|
|
127
|
+
});
|
|
128
|
+
reject(err);
|
|
129
|
+
});
|
|
130
|
+
res.on("data", (chunk) => {
|
|
131
|
+
downloadedSize += chunk.length;
|
|
132
|
+
if (onProgress && totalSize > 0) {
|
|
133
|
+
onProgress(downloadedSize, totalSize);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
res.on("end", () => {
|
|
137
|
+
fileStream?.close(() => {
|
|
138
|
+
streamClosed = true;
|
|
139
|
+
resolve({
|
|
140
|
+
path: destPath,
|
|
141
|
+
size: downloadedSize
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
res.on("error", (error) => {
|
|
146
|
+
closeStream();
|
|
147
|
+
reject(error);
|
|
148
|
+
});
|
|
149
|
+
res.pipe(fileStream);
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
request.on("error", (error) => {
|
|
153
|
+
closeStream();
|
|
154
|
+
const code = error.code;
|
|
155
|
+
let message = `HTTP download failed for ${url}: ${error.message}
|
|
156
|
+
`;
|
|
157
|
+
if (code === "ENOTFOUND") {
|
|
158
|
+
message += "DNS lookup failed. Check the hostname and your network connection.";
|
|
159
|
+
} else if (code === "ECONNREFUSED") {
|
|
160
|
+
message += "Connection refused. Verify the server is running and accessible.";
|
|
161
|
+
} else if (code === "ETIMEDOUT") {
|
|
162
|
+
message += "Request timed out. Check your network or increase the timeout value.";
|
|
163
|
+
} else if (code === "ECONNRESET") {
|
|
164
|
+
message += "Connection reset. The server may have closed the connection unexpectedly.";
|
|
165
|
+
} else {
|
|
166
|
+
message += "Check your network connection and verify the URL is correct.";
|
|
167
|
+
}
|
|
168
|
+
reject(new Error(message, { cause: error }));
|
|
169
|
+
});
|
|
170
|
+
request.on("timeout", () => {
|
|
171
|
+
request.destroy();
|
|
172
|
+
closeStream();
|
|
173
|
+
reject(new Error(`Download timed out after ${timeout}ms`));
|
|
174
|
+
});
|
|
175
|
+
request.end();
|
|
176
|
+
});
|
|
84
177
|
}
|
|
85
178
|
async function httpRequestAttempt(url, options) {
|
|
86
179
|
const {
|
|
@@ -236,134 +329,30 @@ async function httpDownload(url, destPath, options) {
|
|
|
236
329
|
}
|
|
237
330
|
throw lastError || new Error("Download failed after retries");
|
|
238
331
|
}
|
|
239
|
-
async function
|
|
332
|
+
async function httpJson(url, options) {
|
|
240
333
|
const {
|
|
241
|
-
|
|
334
|
+
body,
|
|
242
335
|
headers = {},
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const { createWriteStream } = /* @__PURE__ */ getFs();
|
|
263
|
-
let fileStream;
|
|
264
|
-
let streamClosed = false;
|
|
265
|
-
const closeStream = () => {
|
|
266
|
-
if (!streamClosed && fileStream) {
|
|
267
|
-
streamClosed = true;
|
|
268
|
-
fileStream.close();
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
const request = httpModule.request(
|
|
272
|
-
requestOptions,
|
|
273
|
-
(res) => {
|
|
274
|
-
if (followRedirects && res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
275
|
-
if (maxRedirects <= 0) {
|
|
276
|
-
reject(
|
|
277
|
-
new Error(
|
|
278
|
-
`Too many redirects (exceeded maximum: ${maxRedirects})`
|
|
279
|
-
)
|
|
280
|
-
);
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
const redirectUrl = res.headers.location.startsWith("http") ? res.headers.location : new URL(res.headers.location, url).toString();
|
|
284
|
-
resolve(
|
|
285
|
-
httpDownloadAttempt(redirectUrl, destPath, {
|
|
286
|
-
followRedirects,
|
|
287
|
-
headers,
|
|
288
|
-
maxRedirects: maxRedirects - 1,
|
|
289
|
-
onProgress,
|
|
290
|
-
timeout
|
|
291
|
-
})
|
|
292
|
-
);
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
|
|
296
|
-
closeStream();
|
|
297
|
-
reject(
|
|
298
|
-
new Error(
|
|
299
|
-
`Download failed: HTTP ${res.statusCode} ${res.statusMessage}`
|
|
300
|
-
)
|
|
301
|
-
);
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
const totalSize = Number.parseInt(
|
|
305
|
-
res.headers["content-length"] || "0",
|
|
306
|
-
10
|
|
307
|
-
);
|
|
308
|
-
let downloadedSize = 0;
|
|
309
|
-
fileStream = createWriteStream(destPath);
|
|
310
|
-
fileStream.on("error", (error) => {
|
|
311
|
-
closeStream();
|
|
312
|
-
const err = new Error(`Failed to write file: ${error.message}`, {
|
|
313
|
-
cause: error
|
|
314
|
-
});
|
|
315
|
-
reject(err);
|
|
316
|
-
});
|
|
317
|
-
res.on("data", (chunk) => {
|
|
318
|
-
downloadedSize += chunk.length;
|
|
319
|
-
if (onProgress && totalSize > 0) {
|
|
320
|
-
onProgress(downloadedSize, totalSize);
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
res.on("end", () => {
|
|
324
|
-
fileStream?.close(() => {
|
|
325
|
-
streamClosed = true;
|
|
326
|
-
resolve({
|
|
327
|
-
path: destPath,
|
|
328
|
-
size: downloadedSize
|
|
329
|
-
});
|
|
330
|
-
});
|
|
331
|
-
});
|
|
332
|
-
res.on("error", (error) => {
|
|
333
|
-
closeStream();
|
|
334
|
-
reject(error);
|
|
335
|
-
});
|
|
336
|
-
res.pipe(fileStream);
|
|
337
|
-
}
|
|
338
|
-
);
|
|
339
|
-
request.on("error", (error) => {
|
|
340
|
-
closeStream();
|
|
341
|
-
const code = error.code;
|
|
342
|
-
let message = `HTTP download failed for ${url}: ${error.message}
|
|
343
|
-
`;
|
|
344
|
-
if (code === "ENOTFOUND") {
|
|
345
|
-
message += "DNS lookup failed. Check the hostname and your network connection.";
|
|
346
|
-
} else if (code === "ECONNREFUSED") {
|
|
347
|
-
message += "Connection refused. Verify the server is running and accessible.";
|
|
348
|
-
} else if (code === "ETIMEDOUT") {
|
|
349
|
-
message += "Request timed out. Check your network or increase the timeout value.";
|
|
350
|
-
} else if (code === "ECONNRESET") {
|
|
351
|
-
message += "Connection reset. The server may have closed the connection unexpectedly.";
|
|
352
|
-
} else {
|
|
353
|
-
message += "Check your network connection and verify the URL is correct.";
|
|
354
|
-
}
|
|
355
|
-
reject(new Error(message, { cause: error }));
|
|
356
|
-
});
|
|
357
|
-
request.on("timeout", () => {
|
|
358
|
-
request.destroy();
|
|
359
|
-
closeStream();
|
|
360
|
-
reject(new Error(`Download timed out after ${timeout}ms`));
|
|
361
|
-
});
|
|
362
|
-
request.end();
|
|
336
|
+
...restOptions
|
|
337
|
+
} = {
|
|
338
|
+
__proto__: null,
|
|
339
|
+
...options
|
|
340
|
+
};
|
|
341
|
+
const defaultHeaders = {
|
|
342
|
+
Accept: "application/json"
|
|
343
|
+
};
|
|
344
|
+
if (body) {
|
|
345
|
+
defaultHeaders["Content-Type"] = "application/json";
|
|
346
|
+
}
|
|
347
|
+
const mergedHeaders = {
|
|
348
|
+
...defaultHeaders,
|
|
349
|
+
...headers
|
|
350
|
+
};
|
|
351
|
+
const response = await httpRequest(url, {
|
|
352
|
+
body,
|
|
353
|
+
headers: mergedHeaders,
|
|
354
|
+
...restOptions
|
|
363
355
|
});
|
|
364
|
-
}
|
|
365
|
-
async function httpGetJson(url, options) {
|
|
366
|
-
const response = await httpRequest(url, { ...options, method: "GET" });
|
|
367
356
|
if (!response.ok) {
|
|
368
357
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
369
358
|
}
|
|
@@ -373,8 +362,63 @@ async function httpGetJson(url, options) {
|
|
|
373
362
|
throw new Error("Failed to parse JSON response", { cause: e });
|
|
374
363
|
}
|
|
375
364
|
}
|
|
376
|
-
async function
|
|
377
|
-
const
|
|
365
|
+
async function httpRequest(url, options) {
|
|
366
|
+
const {
|
|
367
|
+
body,
|
|
368
|
+
followRedirects = true,
|
|
369
|
+
headers = {},
|
|
370
|
+
maxRedirects = 5,
|
|
371
|
+
method = "GET",
|
|
372
|
+
retries = 0,
|
|
373
|
+
retryDelay = 1e3,
|
|
374
|
+
timeout = 3e4
|
|
375
|
+
} = { __proto__: null, ...options };
|
|
376
|
+
let lastError;
|
|
377
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
378
|
+
try {
|
|
379
|
+
return await httpRequestAttempt(url, {
|
|
380
|
+
body,
|
|
381
|
+
followRedirects,
|
|
382
|
+
headers,
|
|
383
|
+
maxRedirects,
|
|
384
|
+
method,
|
|
385
|
+
timeout
|
|
386
|
+
});
|
|
387
|
+
} catch (e) {
|
|
388
|
+
lastError = e;
|
|
389
|
+
if (attempt === retries) {
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
const delayMs = retryDelay * 2 ** attempt;
|
|
393
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
throw lastError || new Error("Request failed after retries");
|
|
397
|
+
}
|
|
398
|
+
async function httpText(url, options) {
|
|
399
|
+
const {
|
|
400
|
+
body,
|
|
401
|
+
headers = {},
|
|
402
|
+
...restOptions
|
|
403
|
+
} = {
|
|
404
|
+
__proto__: null,
|
|
405
|
+
...options
|
|
406
|
+
};
|
|
407
|
+
const defaultHeaders = {
|
|
408
|
+
Accept: "text/plain"
|
|
409
|
+
};
|
|
410
|
+
if (body) {
|
|
411
|
+
defaultHeaders["Content-Type"] = "text/plain";
|
|
412
|
+
}
|
|
413
|
+
const mergedHeaders = {
|
|
414
|
+
...defaultHeaders,
|
|
415
|
+
...headers
|
|
416
|
+
};
|
|
417
|
+
const response = await httpRequest(url, {
|
|
418
|
+
body,
|
|
419
|
+
headers: mergedHeaders,
|
|
420
|
+
...restOptions
|
|
421
|
+
});
|
|
378
422
|
if (!response.ok) {
|
|
379
423
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
380
424
|
}
|
|
@@ -383,7 +427,7 @@ async function httpGetText(url, options) {
|
|
|
383
427
|
// Annotate the CommonJS export names for ESM import in node:
|
|
384
428
|
0 && (module.exports = {
|
|
385
429
|
httpDownload,
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
430
|
+
httpJson,
|
|
431
|
+
httpRequest,
|
|
432
|
+
httpText
|
|
389
433
|
});
|
package/dist/packages/specs.js
CHANGED
|
@@ -43,7 +43,7 @@ var import_strings = require("../strings");
|
|
|
43
43
|
function getRepoUrlDetails(repoUrl = "") {
|
|
44
44
|
const userAndRepo = repoUrl.replace(/^.+github.com\//, "").split("/");
|
|
45
45
|
const user = userAndRepo[0] || "";
|
|
46
|
-
const project = userAndRepo.length > 1 ? userAndRepo[1]?.slice(0, -
|
|
46
|
+
const project = userAndRepo.length > 1 ? (userAndRepo[1]?.endsWith(".git") ? userAndRepo[1].slice(0, -4) : userAndRepo[1]) || "" : "";
|
|
47
47
|
return { user, project };
|
|
48
48
|
}
|
|
49
49
|
// @__NO_SIDE_EFFECTS__
|
|
@@ -68,6 +68,24 @@ export declare const SOCKET_BTM_REPO: {
|
|
|
68
68
|
readonly owner: "SocketDev";
|
|
69
69
|
readonly repo: "socket-btm";
|
|
70
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Create a matcher function for a pattern using picomatch for glob patterns
|
|
73
|
+
* or simple prefix/suffix matching for object patterns.
|
|
74
|
+
*
|
|
75
|
+
* @param pattern - Pattern to match (string glob, prefix/suffix object, or RegExp)
|
|
76
|
+
* @returns Function that tests if a string matches the pattern
|
|
77
|
+
*/
|
|
78
|
+
export declare function createAssetMatcher(pattern: string | {
|
|
79
|
+
prefix: string;
|
|
80
|
+
suffix: string;
|
|
81
|
+
} | RegExp): (input: string) => boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Download a binary from any GitHub repository with version caching.
|
|
84
|
+
*
|
|
85
|
+
* @param config - Download configuration
|
|
86
|
+
* @returns Path to the downloaded binary
|
|
87
|
+
*/
|
|
88
|
+
export declare function downloadGitHubRelease(config: DownloadGitHubReleaseConfig): Promise<string>;
|
|
71
89
|
/**
|
|
72
90
|
* Download a specific release asset.
|
|
73
91
|
* Supports pattern matching for dynamic asset discovery.
|
|
@@ -115,10 +133,3 @@ export declare function getLatestRelease(toolPrefix: string, repoConfig: RepoCon
|
|
|
115
133
|
export declare function getReleaseAssetUrl(tag: string, assetPattern: string | AssetPattern, repoConfig: RepoConfig, options?: {
|
|
116
134
|
quiet?: boolean;
|
|
117
135
|
}): 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>;
|