@socketsecurity/lib 5.0.0 → 5.0.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 +11 -0
- package/README.md +1 -1
- package/dist/fs.d.ts +31 -19
- package/dist/http-request.d.ts +46 -0
- package/dist/http-request.js +18 -1
- package/dist/json/edit.js +35 -4
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ 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.0.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.0.1) - 2025-12-11
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **http-request**: Enhanced `httpDownload()` with automatic progress logging via Logger integration
|
|
13
|
+
- New `logger` option: Pass a Logger instance for automatic progress tracking
|
|
14
|
+
- New `progressInterval` option: Configure progress reporting frequency (default: 10%)
|
|
15
|
+
- Progress format: `Progress: XX% (Y.Y MB / Z.Z MB)`
|
|
16
|
+
- `onProgress` callback takes precedence over `logger` when both are provided
|
|
17
|
+
- Commit: [`91e5db5`](https://github.com/SocketDev/socket-lib/commit/91e5db5)
|
|
18
|
+
|
|
8
19
|
## [5.0.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.0.0) - 2025-12-04
|
|
9
20
|
|
|
10
21
|
### Added
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://socket.dev/npm/package/@socketsecurity/lib)
|
|
4
4
|
[](https://github.com/SocketDev/socket-lib/actions/workflows/ci.yml)
|
|
5
|
-

|
|
6
6
|
|
|
7
7
|
[](https://twitter.com/SocketSecurity)
|
|
8
8
|
[](https://bsky.app/profile/socket.dev)
|
package/dist/fs.d.ts
CHANGED
|
@@ -578,51 +578,63 @@ export declare function readJson(filepath: PathLike, options?: ReadJsonOptions |
|
|
|
578
578
|
export declare function readJsonSync(filepath: PathLike, options?: ReadJsonOptions | string | undefined): import("./json/types").JsonValue;
|
|
579
579
|
/**
|
|
580
580
|
* Safely delete a file or directory asynchronously with built-in protections.
|
|
581
|
-
*
|
|
582
|
-
*
|
|
581
|
+
*
|
|
582
|
+
* Uses [`del`](https://socket.dev/npm/package/del/overview/8.0.1) for safer deletion with these safety features:
|
|
583
|
+
* - By default, prevents deleting the current working directory (cwd) and above
|
|
584
|
+
* - Allows deleting within cwd (descendant paths) without force option
|
|
585
|
+
* - Automatically uses force: true for temp directory, cacache, and ~/.socket subdirectories
|
|
586
|
+
* - Protects against accidental deletion of parent directories via `../` paths
|
|
583
587
|
*
|
|
584
588
|
* @param filepath - Path or array of paths to delete (supports glob patterns)
|
|
585
589
|
* @param options - Deletion options including force, retries, and recursion
|
|
590
|
+
* @param options.force - Set to true to allow deleting cwd and above (use with caution)
|
|
586
591
|
* @throws {Error} When attempting to delete protected paths without force option
|
|
587
592
|
*
|
|
588
593
|
* @example
|
|
589
594
|
* ```ts
|
|
590
|
-
* // Delete
|
|
591
|
-
* await safeDelete('./
|
|
592
|
-
*
|
|
593
|
-
* // Delete a directory recursively
|
|
594
|
-
* await safeDelete('./build', { recursive: true })
|
|
595
|
+
* // Delete files within cwd (safe by default)
|
|
596
|
+
* await safeDelete('./build')
|
|
597
|
+
* await safeDelete('./dist')
|
|
595
598
|
*
|
|
596
|
-
* // Delete
|
|
597
|
-
* await safeDelete(['./
|
|
599
|
+
* // Delete with glob patterns
|
|
600
|
+
* await safeDelete(['./temp/**', '!./temp/keep.txt'])
|
|
598
601
|
*
|
|
599
602
|
* // Delete with custom retry settings
|
|
600
603
|
* await safeDelete('./flaky-dir', { maxRetries: 5, retryDelay: 500 })
|
|
604
|
+
*
|
|
605
|
+
* // Force delete cwd or above (requires explicit force: true)
|
|
606
|
+
* await safeDelete('../parent-dir', { force: true })
|
|
601
607
|
* ```
|
|
602
608
|
*/
|
|
603
609
|
export declare function safeDelete(filepath: PathLike | PathLike[], options?: RemoveOptions | undefined): Promise<void>;
|
|
604
610
|
/**
|
|
605
611
|
* Safely delete a file or directory synchronously with built-in protections.
|
|
606
|
-
*
|
|
607
|
-
*
|
|
612
|
+
*
|
|
613
|
+
* Uses [`del`](https://socket.dev/npm/package/del/overview/8.0.1) for safer deletion with these safety features:
|
|
614
|
+
* - By default, prevents deleting the current working directory (cwd) and above
|
|
615
|
+
* - Allows deleting within cwd (descendant paths) without force option
|
|
616
|
+
* - Automatically uses force: true for temp directory, cacache, and ~/.socket subdirectories
|
|
617
|
+
* - Protects against accidental deletion of parent directories via `../` paths
|
|
608
618
|
*
|
|
609
619
|
* @param filepath - Path or array of paths to delete (supports glob patterns)
|
|
610
620
|
* @param options - Deletion options including force, retries, and recursion
|
|
621
|
+
* @param options.force - Set to true to allow deleting cwd and above (use with caution)
|
|
611
622
|
* @throws {Error} When attempting to delete protected paths without force option
|
|
612
623
|
*
|
|
613
624
|
* @example
|
|
614
625
|
* ```ts
|
|
615
|
-
* // Delete
|
|
616
|
-
* safeDeleteSync('./
|
|
626
|
+
* // Delete files within cwd (safe by default)
|
|
627
|
+
* safeDeleteSync('./build')
|
|
628
|
+
* safeDeleteSync('./dist')
|
|
617
629
|
*
|
|
618
|
-
* // Delete
|
|
619
|
-
* safeDeleteSync('./
|
|
630
|
+
* // Delete with glob patterns
|
|
631
|
+
* safeDeleteSync(['./temp/**', '!./temp/keep.txt'])
|
|
620
632
|
*
|
|
621
|
-
* // Delete multiple paths
|
|
622
|
-
* safeDeleteSync(['./
|
|
633
|
+
* // Delete multiple paths
|
|
634
|
+
* safeDeleteSync(['./coverage', './reports'])
|
|
623
635
|
*
|
|
624
|
-
* // Force delete
|
|
625
|
-
* safeDeleteSync('
|
|
636
|
+
* // Force delete cwd or above (requires explicit force: true)
|
|
637
|
+
* safeDeleteSync('../parent-dir', { force: true })
|
|
626
638
|
* ```
|
|
627
639
|
*/
|
|
628
640
|
export declare function safeDeleteSync(filepath: PathLike | PathLike[], options?: RemoveOptions | undefined): void;
|
package/dist/http-request.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logger } from './logger.js';
|
|
1
2
|
/**
|
|
2
3
|
* Configuration options for HTTP/HTTPS requests.
|
|
3
4
|
*/
|
|
@@ -270,9 +271,31 @@ export interface HttpDownloadOptions {
|
|
|
270
271
|
* ```
|
|
271
272
|
*/
|
|
272
273
|
headers?: Record<string, string> | undefined;
|
|
274
|
+
/**
|
|
275
|
+
* Logger instance for automatic progress logging.
|
|
276
|
+
* When provided with `progressInterval`, will automatically log download progress.
|
|
277
|
+
* If both `onProgress` and `logger` are provided, `onProgress` takes precedence.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* import { getDefaultLogger } from '@socketsecurity/lib/logger'
|
|
282
|
+
*
|
|
283
|
+
* const logger = getDefaultLogger()
|
|
284
|
+
* await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {
|
|
285
|
+
* logger,
|
|
286
|
+
* progressInterval: 10 // Log every 10%
|
|
287
|
+
* })
|
|
288
|
+
* // Output:
|
|
289
|
+
* // Progress: 10% (5.2 MB / 52.0 MB)
|
|
290
|
+
* // Progress: 20% (10.4 MB / 52.0 MB)
|
|
291
|
+
* // ...
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
logger?: Logger | undefined;
|
|
273
295
|
/**
|
|
274
296
|
* Callback for tracking download progress.
|
|
275
297
|
* Called periodically as data is received.
|
|
298
|
+
* Takes precedence over `logger` if both are provided.
|
|
276
299
|
*
|
|
277
300
|
* @param downloaded - Number of bytes downloaded so far
|
|
278
301
|
* @param total - Total file size in bytes (from Content-Length header)
|
|
@@ -288,6 +311,29 @@ export interface HttpDownloadOptions {
|
|
|
288
311
|
* ```
|
|
289
312
|
*/
|
|
290
313
|
onProgress?: ((downloaded: number, total: number) => void) | undefined;
|
|
314
|
+
/**
|
|
315
|
+
* Progress reporting interval as a percentage (0-100).
|
|
316
|
+
* Only used when `logger` is provided.
|
|
317
|
+
* Progress will be logged each time the download advances by this percentage.
|
|
318
|
+
*
|
|
319
|
+
* @default 10
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```ts
|
|
323
|
+
* // Log every 10%
|
|
324
|
+
* await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {
|
|
325
|
+
* logger: getDefaultLogger(),
|
|
326
|
+
* progressInterval: 10
|
|
327
|
+
* })
|
|
328
|
+
*
|
|
329
|
+
* // Log every 25%
|
|
330
|
+
* await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {
|
|
331
|
+
* logger: getDefaultLogger(),
|
|
332
|
+
* progressInterval: 25
|
|
333
|
+
* })
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
progressInterval?: number | undefined;
|
|
291
337
|
/**
|
|
292
338
|
* Number of retry attempts for failed downloads.
|
|
293
339
|
* Uses exponential backoff: delay = `retryDelay` * 2^attempt.
|
package/dist/http-request.js
CHANGED
|
@@ -184,17 +184,34 @@ async function httpRequestAttempt(url, options) {
|
|
|
184
184
|
async function httpDownload(url, destPath, options) {
|
|
185
185
|
const {
|
|
186
186
|
headers = {},
|
|
187
|
+
logger,
|
|
187
188
|
onProgress,
|
|
189
|
+
progressInterval = 10,
|
|
188
190
|
retries = 0,
|
|
189
191
|
retryDelay = 1e3,
|
|
190
192
|
timeout = 12e4
|
|
191
193
|
} = { __proto__: null, ...options };
|
|
194
|
+
let progressCallback;
|
|
195
|
+
if (onProgress) {
|
|
196
|
+
progressCallback = onProgress;
|
|
197
|
+
} else if (logger) {
|
|
198
|
+
let lastPercent = 0;
|
|
199
|
+
progressCallback = (downloaded, total) => {
|
|
200
|
+
const percent = Math.floor(downloaded / total * 100);
|
|
201
|
+
if (percent >= lastPercent + progressInterval) {
|
|
202
|
+
logger.log(
|
|
203
|
+
` Progress: ${percent}% (${(downloaded / 1024 / 1024).toFixed(1)} MB / ${(total / 1024 / 1024).toFixed(1)} MB)`
|
|
204
|
+
);
|
|
205
|
+
lastPercent = percent;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
192
209
|
let lastError;
|
|
193
210
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
194
211
|
try {
|
|
195
212
|
return await httpDownloadAttempt(url, destPath, {
|
|
196
213
|
headers,
|
|
197
|
-
onProgress,
|
|
214
|
+
onProgress: progressCallback,
|
|
198
215
|
timeout
|
|
199
216
|
});
|
|
200
217
|
} catch (e) {
|
package/dist/json/edit.js
CHANGED
|
@@ -22,6 +22,7 @@ __export(edit_exports, {
|
|
|
22
22
|
getEditableJsonClass: () => getEditableJsonClass
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(edit_exports);
|
|
25
|
+
var import_promises = require("node:timers/promises");
|
|
25
26
|
var import_format = require("./format");
|
|
26
27
|
const identSymbol = import_format.INDENT_SYMBOL;
|
|
27
28
|
const newlineSymbol = import_format.NEWLINE_SYMBOL;
|
|
@@ -40,15 +41,31 @@ async function retryWrite(filepath, content, retries = 3, baseDelay = 10) {
|
|
|
40
41
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
41
42
|
try {
|
|
42
43
|
await fsPromises.writeFile(filepath, content);
|
|
44
|
+
if (process.platform === "win32") {
|
|
45
|
+
await (0, import_promises.setTimeout)(50);
|
|
46
|
+
let accessRetries = 0;
|
|
47
|
+
const maxAccessRetries = 5;
|
|
48
|
+
while (accessRetries < maxAccessRetries) {
|
|
49
|
+
try {
|
|
50
|
+
await fsPromises.access(filepath);
|
|
51
|
+
await (0, import_promises.setTimeout)(10);
|
|
52
|
+
break;
|
|
53
|
+
} catch {
|
|
54
|
+
const delay = 20 * (accessRetries + 1);
|
|
55
|
+
await (0, import_promises.setTimeout)(delay);
|
|
56
|
+
accessRetries++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
43
60
|
return;
|
|
44
61
|
} catch (err) {
|
|
45
62
|
const isLastAttempt = attempt === retries;
|
|
46
|
-
const
|
|
47
|
-
if (!
|
|
63
|
+
const isRetriableError = err instanceof Error && "code" in err && (err.code === "EPERM" || err.code === "EBUSY" || err.code === "ENOENT");
|
|
64
|
+
if (!isRetriableError || isLastAttempt) {
|
|
48
65
|
throw err;
|
|
49
66
|
}
|
|
50
67
|
const delay = baseDelay * 2 ** attempt;
|
|
51
|
-
await
|
|
68
|
+
await (0, import_promises.setTimeout)(delay);
|
|
52
69
|
}
|
|
53
70
|
}
|
|
54
71
|
}
|
|
@@ -57,7 +74,21 @@ function parseJson(content) {
|
|
|
57
74
|
}
|
|
58
75
|
async function readFile(filepath) {
|
|
59
76
|
const { promises: fsPromises } = /* @__PURE__ */ getFs();
|
|
60
|
-
|
|
77
|
+
const maxRetries = process.platform === "win32" ? 5 : 1;
|
|
78
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
79
|
+
try {
|
|
80
|
+
return await fsPromises.readFile(filepath, "utf8");
|
|
81
|
+
} catch (err) {
|
|
82
|
+
const isLastAttempt = attempt === maxRetries;
|
|
83
|
+
const isEnoent = err instanceof Error && "code" in err && err.code === "ENOENT";
|
|
84
|
+
if (!isEnoent || isLastAttempt) {
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
const delay = process.platform === "win32" ? 50 * (attempt + 1) : 20;
|
|
88
|
+
await (0, import_promises.setTimeout)(delay);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
throw new Error("Unreachable code");
|
|
61
92
|
}
|
|
62
93
|
// @__NO_SIDE_EFFECTS__
|
|
63
94
|
function getEditableJsonClass() {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socketsecurity/lib",
|
|
3
|
-
"version": "5.0.
|
|
4
|
-
"packageManager": "pnpm@10.
|
|
3
|
+
"version": "5.0.1",
|
|
4
|
+
"packageManager": "pnpm@10.25.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Core utilities and infrastructure for Socket.dev security tools",
|
|
7
7
|
"keywords": [
|
|
@@ -677,7 +677,7 @@
|
|
|
677
677
|
],
|
|
678
678
|
"engines": {
|
|
679
679
|
"node": ">=22",
|
|
680
|
-
"pnpm": ">=10.
|
|
680
|
+
"pnpm": ">=10.25.0"
|
|
681
681
|
},
|
|
682
682
|
"sideEffects": false,
|
|
683
683
|
"scripts": {
|
|
@@ -742,6 +742,7 @@
|
|
|
742
742
|
"lint-staged": "15.2.11",
|
|
743
743
|
"magic-string": "0.30.17",
|
|
744
744
|
"make-fetch-happen": "15.0.2",
|
|
745
|
+
"nock": "14.0.10",
|
|
745
746
|
"normalize-package-data": "8.0.0",
|
|
746
747
|
"npm-package-arg": "13.0.0",
|
|
747
748
|
"pacote": "21.0.1",
|
|
@@ -750,7 +751,7 @@
|
|
|
750
751
|
"spdx-correct": "3.2.0",
|
|
751
752
|
"spdx-expression-parse": "4.0.0",
|
|
752
753
|
"streaming-iterables": "8.0.1",
|
|
753
|
-
"taze": "19.
|
|
754
|
+
"taze": "19.9.2",
|
|
754
755
|
"trash": "10.0.0",
|
|
755
756
|
"type-coverage": "2.29.7",
|
|
756
757
|
"typescript": "5.9.2",
|