@socketsecurity/lib 5.1.1 → 5.1.3
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 +21 -0
- package/dist/http-request.d.ts +47 -1
- package/dist/http-request.js +27 -0
- package/dist/paths/socket.d.ts +7 -5
- package/dist/paths/socket.js +11 -6
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,27 @@ 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.1.3](https://github.com/SocketDev/socket-lib/releases/tag/v5.1.3) - 2025-12-29
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **http-request**: Fixed `httpDownload()` to properly handle HTTP redirects (3xx status codes)
|
|
13
|
+
- Added `followRedirects` option (default: `true`) to enable automatic redirect following
|
|
14
|
+
- Added `maxRedirects` option (default: `5`) to limit redirect chain length
|
|
15
|
+
- Now supports downloading from services that use CDN redirects, such as GitHub release assets
|
|
16
|
+
- Prevents GitHub API quota exhaustion by following `browser_download_url` redirects instead of using API endpoints
|
|
17
|
+
- Resolves "Request quota exhausted" errors when downloading GitHub release assets
|
|
18
|
+
|
|
19
|
+
## [5.1.2](https://github.com/SocketDev/socket-lib/releases/tag/v5.1.2) - 2025-12-28
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **paths**: Fixed missing `getPathValue()` caching in `getSocketDlxDir()`
|
|
24
|
+
- Now uses `getPathValue()` for performance, consistent with `getSocketUserDir()` and `getSocketCacacheDir()`
|
|
25
|
+
- Adds test override support via `setPath('socket-dlx-dir', ...)`
|
|
26
|
+
- Test helper `mockHomeDir()` now properly invalidates path cache with `resetPaths()` calls
|
|
27
|
+
- Resolves cache persistence issues in test environments
|
|
28
|
+
|
|
8
29
|
## [5.1.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.1.1) - 2025-12-28
|
|
9
30
|
|
|
10
31
|
### Added
|
package/dist/http-request.d.ts
CHANGED
|
@@ -257,6 +257,28 @@ export interface HttpResponse {
|
|
|
257
257
|
* Configuration options for file downloads.
|
|
258
258
|
*/
|
|
259
259
|
export interface HttpDownloadOptions {
|
|
260
|
+
/**
|
|
261
|
+
* Whether to automatically follow HTTP redirects (3xx status codes).
|
|
262
|
+
* This is essential for downloading from services that use CDN redirects,
|
|
263
|
+
* such as GitHub release assets which return HTTP 302 to their CDN.
|
|
264
|
+
*
|
|
265
|
+
* @default true
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```ts
|
|
269
|
+
* // Follow redirects (default) - works with GitHub releases
|
|
270
|
+
* await httpDownload(
|
|
271
|
+
* 'https://github.com/org/repo/releases/download/v1.0.0/file.zip',
|
|
272
|
+
* '/tmp/file.zip'
|
|
273
|
+
* )
|
|
274
|
+
*
|
|
275
|
+
* // Don't follow redirects
|
|
276
|
+
* await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {
|
|
277
|
+
* followRedirects: false
|
|
278
|
+
* })
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
followRedirects?: boolean | undefined;
|
|
260
282
|
/**
|
|
261
283
|
* HTTP headers to send with the download request.
|
|
262
284
|
* A `User-Agent` header is automatically added if not provided.
|
|
@@ -292,6 +314,21 @@ export interface HttpDownloadOptions {
|
|
|
292
314
|
* ```
|
|
293
315
|
*/
|
|
294
316
|
logger?: Logger | undefined;
|
|
317
|
+
/**
|
|
318
|
+
* Maximum number of redirects to follow before throwing an error.
|
|
319
|
+
* Only relevant when `followRedirects` is `true`.
|
|
320
|
+
*
|
|
321
|
+
* @default 5
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```ts
|
|
325
|
+
* // Allow up to 10 redirects
|
|
326
|
+
* await httpDownload('https://example.com/many-redirects/file.zip', '/tmp/file.zip', {
|
|
327
|
+
* maxRedirects: 10
|
|
328
|
+
* })
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
maxRedirects?: number | undefined;
|
|
295
332
|
/**
|
|
296
333
|
* Callback for tracking download progress.
|
|
297
334
|
* Called periodically as data is received.
|
|
@@ -439,12 +476,15 @@ export interface HttpDownloadResult {
|
|
|
439
476
|
*/
|
|
440
477
|
export declare function httpRequest(url: string, options?: HttpRequestOptions | undefined): Promise<HttpResponse>;
|
|
441
478
|
/**
|
|
442
|
-
* Download a file from a URL to a local path with retry logic and progress callbacks.
|
|
479
|
+
* Download a file from a URL to a local path with redirect support, retry logic, and progress callbacks.
|
|
443
480
|
* Uses streaming to avoid loading entire file in memory.
|
|
444
481
|
*
|
|
445
482
|
* The download is streamed directly to disk, making it memory-efficient even for
|
|
446
483
|
* large files. Progress callbacks allow for real-time download status updates.
|
|
447
484
|
*
|
|
485
|
+
* Automatically follows HTTP redirects (3xx status codes) by default, making it suitable
|
|
486
|
+
* for downloading from services like GitHub releases that redirect to CDN URLs.
|
|
487
|
+
*
|
|
448
488
|
* @param url - The URL to download from (must start with http:// or https://)
|
|
449
489
|
* @param destPath - Absolute path where the file should be saved
|
|
450
490
|
* @param options - Download configuration options
|
|
@@ -460,6 +500,12 @@ export declare function httpRequest(url: string, options?: HttpRequestOptions |
|
|
|
460
500
|
* )
|
|
461
501
|
* console.log(`Downloaded ${result.size} bytes to ${result.path}`)
|
|
462
502
|
*
|
|
503
|
+
* // Download from GitHub releases (handles 302 redirect automatically)
|
|
504
|
+
* await httpDownload(
|
|
505
|
+
* 'https://github.com/org/repo/releases/download/v1.0.0/binary.tar.gz',
|
|
506
|
+
* '/tmp/binary.tar.gz'
|
|
507
|
+
* )
|
|
508
|
+
*
|
|
463
509
|
* // With progress tracking
|
|
464
510
|
* await httpDownload(
|
|
465
511
|
* 'https://example.com/large-file.zip',
|
package/dist/http-request.js
CHANGED
|
@@ -183,8 +183,10 @@ async function httpRequestAttempt(url, options) {
|
|
|
183
183
|
}
|
|
184
184
|
async function httpDownload(url, destPath, options) {
|
|
185
185
|
const {
|
|
186
|
+
followRedirects = true,
|
|
186
187
|
headers = {},
|
|
187
188
|
logger,
|
|
189
|
+
maxRedirects = 5,
|
|
188
190
|
onProgress,
|
|
189
191
|
progressInterval = 10,
|
|
190
192
|
retries = 0,
|
|
@@ -210,7 +212,9 @@ async function httpDownload(url, destPath, options) {
|
|
|
210
212
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
211
213
|
try {
|
|
212
214
|
return await httpDownloadAttempt(url, destPath, {
|
|
215
|
+
followRedirects,
|
|
213
216
|
headers,
|
|
217
|
+
maxRedirects,
|
|
214
218
|
onProgress: progressCallback,
|
|
215
219
|
timeout
|
|
216
220
|
});
|
|
@@ -227,7 +231,9 @@ async function httpDownload(url, destPath, options) {
|
|
|
227
231
|
}
|
|
228
232
|
async function httpDownloadAttempt(url, destPath, options) {
|
|
229
233
|
const {
|
|
234
|
+
followRedirects = true,
|
|
230
235
|
headers = {},
|
|
236
|
+
maxRedirects = 5,
|
|
231
237
|
onProgress,
|
|
232
238
|
timeout = 12e4
|
|
233
239
|
} = { __proto__: null, ...options };
|
|
@@ -257,6 +263,27 @@ async function httpDownloadAttempt(url, destPath, options) {
|
|
|
257
263
|
const request = httpModule.request(
|
|
258
264
|
requestOptions,
|
|
259
265
|
(res) => {
|
|
266
|
+
if (followRedirects && res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
267
|
+
if (maxRedirects <= 0) {
|
|
268
|
+
reject(
|
|
269
|
+
new Error(
|
|
270
|
+
`Too many redirects (exceeded maximum: ${maxRedirects})`
|
|
271
|
+
)
|
|
272
|
+
);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const redirectUrl = res.headers.location.startsWith("http") ? res.headers.location : new URL(res.headers.location, url).toString();
|
|
276
|
+
resolve(
|
|
277
|
+
httpDownloadAttempt(redirectUrl, destPath, {
|
|
278
|
+
followRedirects,
|
|
279
|
+
headers,
|
|
280
|
+
maxRedirects: maxRedirects - 1,
|
|
281
|
+
onProgress,
|
|
282
|
+
timeout
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
260
287
|
if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
|
|
261
288
|
closeStream();
|
|
262
289
|
reject(
|
package/dist/paths/socket.d.ts
CHANGED
|
@@ -42,13 +42,15 @@ export declare function getSocketAppDir(appName: string): string;
|
|
|
42
42
|
export declare function getSocketCacacheDir(): string;
|
|
43
43
|
/**
|
|
44
44
|
* Get the Socket DLX directory (~/.socket/_dlx).
|
|
45
|
-
* Can be overridden with environment
|
|
45
|
+
* Can be overridden with SOCKET_DLX_DIR environment variable or via setPath() for testing.
|
|
46
|
+
* Result is cached via getPathValue for performance.
|
|
46
47
|
*
|
|
47
48
|
* Priority order:
|
|
48
|
-
* 1.
|
|
49
|
-
* 2.
|
|
50
|
-
* 3.
|
|
51
|
-
* 4.
|
|
49
|
+
* 1. Test override via setPath('socket-dlx-dir', ...)
|
|
50
|
+
* 2. SOCKET_DLX_DIR - Full override of DLX cache directory
|
|
51
|
+
* 3. SOCKET_HOME/_dlx - Base directory override (inherits from getSocketUserDir)
|
|
52
|
+
* 4. Default: $HOME/.socket/_dlx
|
|
53
|
+
* 5. Fallback: /tmp/.socket/_dlx (Unix) or %TEMP%\.socket\_dlx (Windows)
|
|
52
54
|
*/
|
|
53
55
|
export declare function getSocketDlxDir(): string;
|
|
54
56
|
/**
|
package/dist/paths/socket.js
CHANGED
|
@@ -88,12 +88,17 @@ function getSocketCacacheDir() {
|
|
|
88
88
|
});
|
|
89
89
|
}
|
|
90
90
|
function getSocketDlxDir() {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
return (0, import_rewire.getPathValue)("socket-dlx-dir", () => {
|
|
92
|
+
if ((0, import_socket2.getSocketDlxDirEnv)()) {
|
|
93
|
+
return (0, import_normalize.normalizePath)((0, import_socket2.getSocketDlxDirEnv)());
|
|
94
|
+
}
|
|
95
|
+
return (0, import_normalize.normalizePath)(
|
|
96
|
+
path.join(
|
|
97
|
+
getSocketUserDir(),
|
|
98
|
+
`${import_socket.SOCKET_APP_PREFIX}${import_socket.SOCKET_DLX_APP_NAME}`
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
});
|
|
97
102
|
}
|
|
98
103
|
function getSocketAppCacheDir(appName) {
|
|
99
104
|
return (0, import_normalize.normalizePath)(path.join(getSocketAppDir(appName), import_dirnames.CACHE_DIR));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socketsecurity/lib",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.3",
|
|
4
4
|
"packageManager": "pnpm@10.26.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Core utilities and infrastructure for Socket.dev security tools",
|
|
@@ -714,7 +714,7 @@
|
|
|
714
714
|
"@socketregistry/is-unicode-supported": "1.0.5",
|
|
715
715
|
"@socketregistry/packageurl-js": "1.3.5",
|
|
716
716
|
"@socketregistry/yocto-spinner": "1.0.25",
|
|
717
|
-
"@socketsecurity/lib-stable": "npm:@socketsecurity/lib@5.1.
|
|
717
|
+
"@socketsecurity/lib-stable": "npm:@socketsecurity/lib@5.1.2",
|
|
718
718
|
"@types/node": "24.9.2",
|
|
719
719
|
"@typescript/native-preview": "7.0.0-dev.20250920.1",
|
|
720
720
|
"@vitest/coverage-v8": "4.0.3",
|