@socketsecurity/lib 5.14.0 → 5.16.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.
Files changed (85) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +2 -2
  3. package/dist/abort.d.ts +13 -0
  4. package/dist/agent.d.ts +81 -0
  5. package/dist/ansi.d.ts +13 -0
  6. package/dist/archives.d.ts +31 -0
  7. package/dist/argv/flags.d.ts +91 -0
  8. package/dist/argv/parse.d.ts +31 -0
  9. package/dist/bin.d.ts +54 -0
  10. package/dist/cacache.d.ts +38 -0
  11. package/dist/cache-with-ttl.d.ts +7 -0
  12. package/dist/colors.d.ts +12 -0
  13. package/dist/cover/formatters.d.ts +18 -0
  14. package/dist/debug.d.ts +6 -0
  15. package/dist/dlx/binary.d.ts +84 -0
  16. package/dist/dlx/cache.d.ts +6 -0
  17. package/dist/dlx/detect.d.ts +33 -0
  18. package/dist/dlx/dir.d.ts +34 -0
  19. package/dist/dlx/manifest.d.ts +16 -0
  20. package/dist/dlx/package.d.ts +43 -0
  21. package/dist/dlx/packages.d.ts +36 -0
  22. package/dist/dlx/paths.d.ts +20 -0
  23. package/dist/dlx/paths.js +1 -1
  24. package/dist/effects/pulse-frames.d.ts +6 -0
  25. package/dist/effects/text-shimmer.d.ts +9 -0
  26. package/dist/effects/ultra.d.ts +6 -0
  27. package/dist/env/ci.d.ts +14 -0
  28. package/dist/env/debug.d.ts +13 -0
  29. package/dist/env/github.d.ts +80 -0
  30. package/dist/env/helpers.d.ts +45 -0
  31. package/dist/env/home.d.ts +13 -0
  32. package/dist/env/locale.d.ts +30 -0
  33. package/dist/env/node-auth-token.d.ts +13 -0
  34. package/dist/env/node-env.d.ts +13 -0
  35. package/dist/env/npm.d.ts +50 -0
  36. package/dist/env/path.d.ts +13 -0
  37. package/dist/env/pre-commit.d.ts +14 -0
  38. package/dist/env/rewire.d.ts +38 -0
  39. package/dist/env/shell.d.ts +13 -0
  40. package/dist/env/socket-cli-shadow.d.ts +43 -0
  41. package/dist/env/socket-cli.d.ts +116 -0
  42. package/dist/env/socket.d.ts +153 -0
  43. package/dist/env/temp-dir.d.ts +30 -0
  44. package/dist/env/term.d.ts +13 -0
  45. package/dist/env/test.d.ts +32 -0
  46. package/dist/env/windows.d.ts +40 -0
  47. package/dist/env/xdg.d.ts +30 -0
  48. package/dist/env.d.ts +40 -0
  49. package/dist/external/npm-pack.js +202 -291
  50. package/dist/external/tar-fs.js +27 -7
  51. package/dist/fs.d.ts +13 -0
  52. package/dist/functions.d.ts +30 -0
  53. package/dist/globs.d.ts +27 -0
  54. package/dist/http-request.d.ts +40 -18
  55. package/dist/http-request.js +84 -129
  56. package/dist/json/format.d.ts +18 -0
  57. package/dist/memoization.d.ts +5 -0
  58. package/dist/packages/edit.d.ts +28 -0
  59. package/dist/packages/exports.d.ts +40 -0
  60. package/dist/packages/licenses.d.ts +59 -0
  61. package/dist/packages/manifest.d.ts +18 -0
  62. package/dist/packages/normalize.d.ts +22 -0
  63. package/dist/packages/operations.d.ts +51 -0
  64. package/dist/packages/provenance.d.ts +11 -0
  65. package/dist/packages/specs.d.ts +30 -0
  66. package/dist/packages/validation.d.ts +18 -0
  67. package/dist/paths/normalize.d.ts +49 -5
  68. package/dist/paths/normalize.js +13 -0
  69. package/dist/paths/rewire.js +12 -3
  70. package/dist/regexps.d.ts +7 -0
  71. package/dist/releases/github.d.ts +63 -0
  72. package/dist/releases/socket-btm.d.ts +31 -0
  73. package/dist/sea.d.ts +15 -0
  74. package/dist/shadow.d.ts +7 -0
  75. package/dist/signal-exit.d.ts +27 -0
  76. package/dist/sorts.d.ts +33 -0
  77. package/dist/spawn.d.ts +9 -0
  78. package/dist/stdio/mask.d.ts +26 -0
  79. package/dist/streams.d.ts +28 -0
  80. package/dist/suppress-warnings.d.ts +7 -0
  81. package/dist/temporary-executor.d.ts +7 -0
  82. package/dist/url.d.ts +59 -0
  83. package/dist/versions.d.ts +119 -0
  84. package/dist/words.d.ts +20 -0
  85. package/package.json +8 -58
@@ -547,9 +547,9 @@ var require_text_decoder = __commonJS({
547
547
  }
548
548
  });
549
549
 
550
- // node_modules/.pnpm/streamx@2.23.0/node_modules/streamx/index.js
550
+ // node_modules/.pnpm/streamx@2.25.0/node_modules/streamx/index.js
551
551
  var require_streamx = __commonJS({
552
- "node_modules/.pnpm/streamx@2.23.0/node_modules/streamx/index.js"(exports2, module2) {
552
+ "node_modules/.pnpm/streamx@2.25.0/node_modules/streamx/index.js"(exports2, module2) {
553
553
  var { EventEmitter } = require_default();
554
554
  var STREAM_DESTROYED = new Error("Stream was destroyed");
555
555
  var PREMATURE_CLOSE = new Error("Premature close");
@@ -660,6 +660,9 @@ var require_streamx = __commonJS({
660
660
  this.afterWrite = afterWrite.bind(this);
661
661
  this.afterUpdateNextTick = updateWriteNT.bind(this);
662
662
  }
663
+ get ending() {
664
+ return (this.stream._duplexState & WRITE_FINISHING) !== 0;
665
+ }
663
666
  get ended() {
664
667
  return (this.stream._duplexState & WRITE_DONE) !== 0;
665
668
  }
@@ -761,6 +764,9 @@ var require_streamx = __commonJS({
761
764
  this.afterRead = afterRead.bind(this);
762
765
  this.afterUpdateNextTick = updateReadNT.bind(this);
763
766
  }
767
+ get ending() {
768
+ return (this.stream._duplexState & READ_ENDING) !== 0;
769
+ }
764
770
  get ended() {
765
771
  return (this.stream._duplexState & READ_DONE) !== 0;
766
772
  }
@@ -825,7 +831,8 @@ var require_streamx = __commonJS({
825
831
  const stream = this.stream;
826
832
  if ((stream._duplexState & READ_STATUS) === READ_QUEUED) {
827
833
  const data = this.shift();
828
- if (this.pipeTo !== null && this.pipeTo.write(data) === false) stream._duplexState &= READ_PIPE_NOT_DRAINED;
834
+ if (this.pipeTo !== null && this.pipeTo.write(data) === false)
835
+ stream._duplexState &= READ_PIPE_NOT_DRAINED;
829
836
  if ((stream._duplexState & READ_EMIT_DATA) !== 0) stream.emit("data", data);
830
837
  return data;
831
838
  }
@@ -839,7 +846,8 @@ var require_streamx = __commonJS({
839
846
  const stream = this.stream;
840
847
  while ((stream._duplexState & READ_STATUS) === READ_QUEUED && (stream._duplexState & READ_FLOWING) !== 0) {
841
848
  const data = this.shift();
842
- if (this.pipeTo !== null && this.pipeTo.write(data) === false) stream._duplexState &= READ_PIPE_NOT_DRAINED;
849
+ if (this.pipeTo !== null && this.pipeTo.write(data) === false)
850
+ stream._duplexState &= READ_PIPE_NOT_DRAINED;
843
851
  if ((stream._duplexState & READ_EMIT_DATA) !== 0) stream.emit("data", data);
844
852
  }
845
853
  }
@@ -1001,7 +1009,8 @@ var require_streamx = __commonJS({
1001
1009
  function afterRead(err) {
1002
1010
  if (err) this.stream.destroy(err);
1003
1011
  this.stream._duplexState &= READ_NOT_ACTIVE;
1004
- if (this.readAhead === false && (this.stream._duplexState & READ_RESUMED) === 0) this.stream._duplexState &= READ_NO_READ_AHEAD;
1012
+ if (this.readAhead === false && (this.stream._duplexState & READ_RESUMED) === 0)
1013
+ this.stream._duplexState &= READ_NO_READ_AHEAD;
1005
1014
  this.updateCallback();
1006
1015
  }
1007
1016
  __name(afterRead, "afterRead");
@@ -1265,7 +1274,8 @@ var require_streamx = __commonJS({
1265
1274
  function ondata(data) {
1266
1275
  if (promiseReject === null) return;
1267
1276
  if (error) promiseReject(error);
1268
- else if (data === null && (stream._duplexState & READ_DONE) === 0) promiseReject(STREAM_DESTROYED);
1277
+ else if (data === null && (stream._duplexState & READ_DONE) === 0)
1278
+ promiseReject(STREAM_DESTROYED);
1269
1279
  else promiseResolve({ value: data, done: data === null });
1270
1280
  promiseReject = promiseResolve = null;
1271
1281
  }
@@ -1512,10 +1522,18 @@ var require_streamx = __commonJS({
1512
1522
  return typeof stream._duplexState === "number" && isStream(stream);
1513
1523
  }
1514
1524
  __name(isStreamx, "isStreamx");
1525
+ function isEnding(stream) {
1526
+ return !!stream._readableState && stream._readableState.ending;
1527
+ }
1528
+ __name(isEnding, "isEnding");
1515
1529
  function isEnded(stream) {
1516
1530
  return !!stream._readableState && stream._readableState.ended;
1517
1531
  }
1518
1532
  __name(isEnded, "isEnded");
1533
+ function isFinishing(stream) {
1534
+ return !!stream._writableState && stream._writableState.ending;
1535
+ }
1536
+ __name(isFinishing, "isFinishing");
1519
1537
  function isFinished(stream) {
1520
1538
  return !!stream._writableState && stream._writableState.ended;
1521
1539
  }
@@ -1530,7 +1548,7 @@ var require_streamx = __commonJS({
1530
1548
  }
1531
1549
  __name(isReadStreamx, "isReadStreamx");
1532
1550
  function isDisturbed(stream) {
1533
- return (stream._duplexState & OPENING) !== OPENING || (stream._duplexState & ACTIVE_OR_TICKING) !== 0;
1551
+ return (stream._duplexState & OPENING) !== OPENING || (stream._duplexState & DESTROYING) === DESTROYING || (stream._duplexState & ACTIVE_OR_TICKING) !== 0;
1534
1552
  }
1535
1553
  __name(isDisturbed, "isDisturbed");
1536
1554
  function isTypedArray(data) {
@@ -1557,7 +1575,9 @@ var require_streamx = __commonJS({
1557
1575
  pipelinePromise,
1558
1576
  isStream,
1559
1577
  isStreamx,
1578
+ isEnding,
1560
1579
  isEnded,
1580
+ isFinishing,
1561
1581
  isFinished,
1562
1582
  isDisturbed,
1563
1583
  getStreamError,
package/dist/fs.d.ts CHANGED
@@ -283,6 +283,12 @@ export declare function findUpSync(name: string | string[] | readonly string[],
283
283
  * Called automatically by the paths/rewire module when paths are overridden in tests.
284
284
  *
285
285
  * @internal Used for test rewiring
286
+ *
287
+ * @example
288
+ * ```typescript
289
+ * invalidatePathCache()
290
+ * // Cached allowed directories are now cleared
291
+ * ```
286
292
  */
287
293
  export declare function invalidatePathCache(): void;
288
294
  /**
@@ -382,6 +388,13 @@ export declare function normalizeEncoding(enc: BufferEncoding | string | null |
382
388
  *
383
389
  * @param enc - Encoding to normalize
384
390
  * @returns Normalized encoding string, defaults to 'utf8' for unknown encodings
391
+ *
392
+ * @example
393
+ * ```typescript
394
+ * normalizeEncodingSlow('ucs2') // 'utf16le'
395
+ * normalizeEncodingSlow('LATIN1') // 'latin1'
396
+ * normalizeEncodingSlow('binary') // 'latin1'
397
+ * ```
385
398
  */
386
399
  /*@__NO_SIDE_EFFECTS__*/
387
400
  export declare function normalizeEncodingSlow(enc: string): BufferEncoding;
@@ -7,21 +7,51 @@ export type AsyncFunction<TArgs extends unknown[], TResult> = (...args: TArgs) =
7
7
  export type AnyFunction = (...args: unknown[]) => unknown;
8
8
  /**
9
9
  * A no-op function that does nothing.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const callback = noop
14
+ * callback() // does nothing
15
+ * ```
10
16
  */
11
17
  /*@__NO_SIDE_EFFECTS__*/
12
18
  export declare function noop(): void;
13
19
  /**
14
20
  * Create a function that only executes once.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const init = once(() => Math.random())
25
+ * init() // 0.456 (random value)
26
+ * init() // 0.456 (same value, not recalculated)
27
+ * ```
15
28
  */
16
29
  /*@__NO_SIDE_EFFECTS__*/
17
30
  export declare function once<T extends AnyFunction>(fn: T): T;
18
31
  /**
19
32
  * Wrap an async function to silently catch and ignore errors.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const safeFetch = silentWrapAsync(async (url: string) => {
37
+ * const res = await fetch(url)
38
+ * return res.json()
39
+ * })
40
+ * await safeFetch('https://example.com') // result or undefined on error
41
+ * ```
20
42
  */
21
43
  /*@__NO_SIDE_EFFECTS__*/
22
44
  export declare function silentWrapAsync<TArgs extends unknown[], TResult>(fn: AsyncFunction<TArgs, TResult>): (...args: TArgs) => Promise<TResult | undefined>;
23
45
  /**
24
46
  * Execute a function with tail call optimization via trampoline.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const factorial = trampoline((n: number, acc = 1): any =>
51
+ * n <= 1 ? acc : () => factorial(n - 1, n * acc)
52
+ * )
53
+ * factorial(5) // 120
54
+ * ```
25
55
  */
26
56
  /*@__NO_SIDE_EFFECTS__*/
27
57
  export declare function trampoline<T extends AnyFunction>(fn: T): T;
package/dist/globs.d.ts CHANGED
@@ -32,11 +32,26 @@ export type { Pattern, FastGlobOptions };
32
32
  export declare const defaultIgnore: readonly string[];
33
33
  /**
34
34
  * Create a stream of license file paths matching glob patterns.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const stream = globStreamLicenses('/tmp/my-package')
39
+ * for await (const licensePath of stream) {
40
+ * console.log(licensePath)
41
+ * }
42
+ * ```
35
43
  */
36
44
  /*@__NO_SIDE_EFFECTS__*/
37
45
  export declare function globStreamLicenses(dirname: string, options?: GlobOptions): NodeJS.ReadableStream;
38
46
  /**
39
47
  * Get a cached glob matcher function.
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const isMatch = getGlobMatcher('*.ts')
52
+ * isMatch('index.ts') // true
53
+ * isMatch('index.js') // false
54
+ * ```
40
55
  */
41
56
  /*@__NO_SIDE_EFFECTS__*/
42
57
  export declare function getGlobMatcher(glob: Pattern | Pattern[], options?: {
@@ -47,12 +62,24 @@ export declare function getGlobMatcher(glob: Pattern | Pattern[], options?: {
47
62
  /**
48
63
  * Asynchronously find files matching glob patterns.
49
64
  * Wrapper around fast-glob.
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const files = await glob('src/*.ts', { cwd: '/tmp/project' })
69
+ * console.log(files) // ['src/index.ts', 'src/utils.ts']
70
+ * ```
50
71
  */
51
72
  /*@__NO_SIDE_EFFECTS__*/
52
73
  export declare function glob(patterns: Pattern | Pattern[], options?: FastGlobOptions): Promise<string[]>;
53
74
  /**
54
75
  * Synchronously find files matching glob patterns.
55
76
  * Wrapper around fast-glob.sync.
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const files = globSync('*.json', { cwd: '/tmp/project' })
81
+ * console.log(files) // ['package.json', 'tsconfig.json']
82
+ * ```
56
83
  */
57
84
  /*@__NO_SIDE_EFFECTS__*/
58
85
  export declare function globSync(patterns: Pattern | Pattern[], options?: FastGlobOptions): string[];
@@ -277,6 +277,20 @@ export interface HttpRequestOptions {
277
277
  * })
278
278
  * ```
279
279
  */
280
+ /**
281
+ * When true, resolve with an HttpResponse whose body is NOT buffered.
282
+ * The `rawResponse` property contains the unconsumed IncomingResponse
283
+ * stream for piping to files or other destinations.
284
+ *
285
+ * `body`, `text()`, `json()`, and `arrayBuffer()` return empty/zero
286
+ * values since the stream has not been read.
287
+ *
288
+ * Incompatible with `maxResponseSize` (size enforcement requires
289
+ * reading the body).
290
+ *
291
+ * @default false
292
+ */
293
+ stream?: boolean | undefined;
280
294
  throwOnError?: boolean | undefined;
281
295
  /**
282
296
  * Request timeout in milliseconds.
@@ -415,6 +429,13 @@ export interface HttpResponse {
415
429
  * `httpRequest()` (e.g., multipart form-data uploads via `http.request()`,
416
430
  * or responses from third-party HTTP libraries) and need to convert it
417
431
  * into the standard HttpResponse interface.
432
+ *
433
+ * @example
434
+ * ```typescript
435
+ * const raw = await makeRawRequest('https://example.com/api')
436
+ * const response = await readIncomingResponse(raw)
437
+ * console.log(response.status, response.body.toString('utf8'))
438
+ * ```
418
439
  */
419
440
  export declare function readIncomingResponse(msg: IncomingResponse): Promise<HttpResponse>;
420
441
  /**
@@ -657,26 +678,18 @@ export interface HttpDownloadOptions {
657
678
  * Result of a successful file download.
658
679
  */
659
680
  export interface HttpDownloadResult {
660
- /**
661
- * Absolute path where the file was saved.
662
- *
663
- * @example
664
- * ```ts
665
- * const result = await httpDownload('https://example.com/file.zip', '/tmp/file.zip')
666
- * console.log(`Downloaded to: ${result.path}`)
667
- * ```
668
- */
681
+ /** HTTP response headers from the final response (after redirects). */
682
+ headers: IncomingHttpHeaders;
683
+ /** Whether the download succeeded (status 200-299). Always true on success (non-2xx throws). */
684
+ ok: true;
685
+ /** Absolute path where the file was saved. */
669
686
  path: string;
670
- /**
671
- * Total size of downloaded file in bytes.
672
- *
673
- * @example
674
- * ```ts
675
- * const result = await httpDownload('https://example.com/file.zip', '/tmp/file.zip')
676
- * console.log(`Downloaded ${result.size} bytes`)
677
- * ```
678
- */
687
+ /** Total size of downloaded file in bytes. */
679
688
  size: number;
689
+ /** HTTP status code from the final response (after redirects). */
690
+ status: number;
691
+ /** HTTP status message from the final response (after redirects). */
692
+ statusText: string;
680
693
  }
681
694
  /**
682
695
  * Map of filenames to their SHA256 hashes.
@@ -766,6 +779,15 @@ export declare function fetchChecksums(url: string, options?: FetchChecksumsOpti
766
779
  /**
767
780
  * Build an enriched error message based on the error code.
768
781
  * Generic guidance (no product-specific branding).
782
+ *
783
+ * @example
784
+ * ```typescript
785
+ * try {
786
+ * await fetch('https://api.example.com')
787
+ * } catch (err) {
788
+ * console.error(enrichErrorMessage('https://api.example.com', 'GET', err))
789
+ * }
790
+ * ```
769
791
  */
770
792
  export declare function enrichErrorMessage(url: string, method: string, error: NodeJS.ErrnoException): string;
771
793
  /**
@@ -193,135 +193,61 @@ async function httpDownloadAttempt(url, destPath, options) {
193
193
  onProgress,
194
194
  timeout = 12e4
195
195
  } = { __proto__: null, ...options };
196
+ const response = await httpRequestAttempt(url, {
197
+ ca,
198
+ followRedirects,
199
+ headers,
200
+ maxRedirects,
201
+ method: "GET",
202
+ stream: true,
203
+ timeout
204
+ });
205
+ if (!response.ok) {
206
+ throw new Error(
207
+ `Download failed: HTTP ${response.status} ${response.statusText}`
208
+ );
209
+ }
210
+ const res = response.rawResponse;
211
+ if (!res) {
212
+ throw new Error("Stream response missing rawResponse");
213
+ }
214
+ const { createWriteStream } = /* @__PURE__ */ getFs();
215
+ const totalSize = Number.parseInt(
216
+ response.headers["content-length"] || "0",
217
+ 10
218
+ );
196
219
  return await new Promise((resolve, reject) => {
197
- const parsedUrl = new URL(url);
198
- const isHttps = parsedUrl.protocol === "https:";
199
- const httpModule = isHttps ? /* @__PURE__ */ getHttps() : /* @__PURE__ */ getHttp();
200
- const requestOptions = {
201
- headers: {
202
- "User-Agent": "socket-registry/1.0",
203
- ...headers
204
- },
205
- hostname: parsedUrl.hostname,
206
- method: "GET",
207
- path: parsedUrl.pathname + parsedUrl.search,
208
- port: parsedUrl.port,
209
- timeout
210
- };
211
- if (ca && isHttps) {
212
- requestOptions["ca"] = ca;
213
- }
214
- const { createWriteStream } = /* @__PURE__ */ getFs();
215
- let fileStream;
216
- let streamClosed = false;
217
- const closeStream = () => {
218
- if (!streamClosed && fileStream) {
219
- streamClosed = true;
220
- fileStream.close();
220
+ let downloadedSize = 0;
221
+ const fileStream = createWriteStream(destPath);
222
+ fileStream.on("error", (error) => {
223
+ fileStream.close();
224
+ reject(
225
+ new Error(`Failed to write file: ${error.message}`, { cause: error })
226
+ );
227
+ });
228
+ res.on("data", (chunk) => {
229
+ downloadedSize += chunk.length;
230
+ if (onProgress && totalSize > 0) {
231
+ onProgress(downloadedSize, totalSize);
221
232
  }
222
- };
223
- const request = httpModule.request(
224
- requestOptions,
225
- (res) => {
226
- if (followRedirects && res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
227
- if (maxRedirects <= 0) {
228
- reject(
229
- new Error(
230
- `Too many redirects (exceeded maximum: ${maxRedirects})`
231
- )
232
- );
233
- return;
234
- }
235
- const redirectUrl = res.headers.location.startsWith("http") ? res.headers.location : new URL(res.headers.location, url).toString();
236
- const redirectParsed = new URL(redirectUrl);
237
- if (isHttps && redirectParsed.protocol !== "https:") {
238
- reject(
239
- new Error(
240
- `Redirect from HTTPS to HTTP is not allowed: ${redirectUrl}`
241
- )
242
- );
243
- return;
244
- }
245
- resolve(
246
- httpDownloadAttempt(redirectUrl, destPath, {
247
- ca,
248
- followRedirects,
249
- headers,
250
- maxRedirects: maxRedirects - 1,
251
- onProgress,
252
- timeout
253
- })
254
- );
255
- return;
256
- }
257
- if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
258
- closeStream();
259
- reject(
260
- new Error(
261
- `Download failed: HTTP ${res.statusCode} ${res.statusMessage}`
262
- )
263
- );
264
- return;
265
- }
266
- const totalSize = Number.parseInt(
267
- res.headers["content-length"] || "0",
268
- 10
269
- );
270
- let downloadedSize = 0;
271
- fileStream = createWriteStream(destPath);
272
- fileStream.on("error", (error) => {
273
- closeStream();
274
- const err = new Error(`Failed to write file: ${error.message}`, {
275
- cause: error
276
- });
277
- reject(err);
278
- });
279
- res.on("data", (chunk) => {
280
- downloadedSize += chunk.length;
281
- if (onProgress && totalSize > 0) {
282
- onProgress(downloadedSize, totalSize);
283
- }
284
- });
285
- res.on("end", () => {
286
- fileStream?.close(() => {
287
- streamClosed = true;
288
- resolve({
289
- path: destPath,
290
- size: downloadedSize
291
- });
292
- });
293
- });
294
- res.on("error", (error) => {
295
- closeStream();
296
- reject(error);
233
+ });
234
+ res.on("end", () => {
235
+ fileStream.close(() => {
236
+ resolve({
237
+ headers: response.headers,
238
+ ok: true,
239
+ path: destPath,
240
+ size: downloadedSize,
241
+ status: response.status,
242
+ statusText: response.statusText
297
243
  });
298
- res.pipe(fileStream);
299
- }
300
- );
301
- request.on("error", (error) => {
302
- closeStream();
303
- const code = error.code;
304
- let message = `HTTP download failed for ${url}: ${error.message}
305
- `;
306
- if (code === "ENOTFOUND") {
307
- message += "DNS lookup failed. Check the hostname and your network connection.";
308
- } else if (code === "ECONNREFUSED") {
309
- message += "Connection refused. Verify the server is running and accessible.";
310
- } else if (code === "ETIMEDOUT") {
311
- message += "Request timed out. Check your network or increase the timeout value.";
312
- } else if (code === "ECONNRESET") {
313
- message += "Connection reset. The server may have closed the connection unexpectedly.";
314
- } else {
315
- message += "Check your network connection and verify the URL is correct.";
316
- }
317
- reject(new Error(message, { cause: error }));
244
+ });
318
245
  });
319
- request.on("timeout", () => {
320
- request.destroy();
321
- closeStream();
322
- reject(new Error(`Download timed out after ${timeout}ms`));
246
+ res.on("error", (error) => {
247
+ fileStream.close();
248
+ reject(error);
323
249
  });
324
- request.end();
250
+ res.pipe(fileStream);
325
251
  });
326
252
  }
327
253
  function enrichErrorMessage(url, method, error) {
@@ -355,6 +281,7 @@ async function httpRequestAttempt(url, options) {
355
281
  maxRedirects = 5,
356
282
  maxResponseSize,
357
283
  method = "GET",
284
+ stream = false,
358
285
  timeout = 3e4
359
286
  } = { __proto__: null, ...options };
360
287
  const startTime = Date.now();
@@ -452,11 +379,37 @@ async function httpRequestAttempt(url, options) {
452
379
  maxRedirects: maxRedirects - 1,
453
380
  maxResponseSize,
454
381
  method,
382
+ stream,
455
383
  timeout
456
384
  })
457
385
  );
458
386
  return;
459
387
  }
388
+ if (stream) {
389
+ const status = res.statusCode || 0;
390
+ const statusText = res.statusMessage || "";
391
+ const ok = status >= 200 && status < 300;
392
+ emitResponse({
393
+ headers: res.headers,
394
+ status,
395
+ statusText
396
+ });
397
+ const emptyBody = Buffer.alloc(0);
398
+ resolveOnce({
399
+ arrayBuffer: () => emptyBody.buffer,
400
+ body: emptyBody,
401
+ headers: res.headers,
402
+ json: () => {
403
+ throw new Error("Cannot parse JSON from a streaming response");
404
+ },
405
+ ok,
406
+ rawResponse: res,
407
+ status,
408
+ statusText,
409
+ text: () => ""
410
+ });
411
+ return;
412
+ }
460
413
  const chunks = [];
461
414
  let totalBytes = 0;
462
415
  res.on("data", (chunk) => {
@@ -533,12 +486,12 @@ async function httpRequestAttempt(url, options) {
533
486
  });
534
487
  if (body) {
535
488
  if (typeof body === "object" && typeof body.pipe === "function") {
536
- const stream = body;
537
- stream.on("error", (err) => {
489
+ const stream2 = body;
490
+ stream2.on("error", (err) => {
538
491
  request.destroy();
539
492
  rejectOnce(err);
540
493
  });
541
- stream.pipe(request);
494
+ stream2.pipe(request);
542
495
  return;
543
496
  }
544
497
  request.write(body);
@@ -613,8 +566,8 @@ Computed: ${computedHash}`
613
566
  }
614
567
  await fs.promises.rename(tempPath, destPath);
615
568
  return {
616
- path: destPath,
617
- size: result.size
569
+ ...result,
570
+ path: destPath
618
571
  };
619
572
  } catch (e) {
620
573
  lastError = e;
@@ -676,6 +629,7 @@ async function httpRequest(url, options) {
676
629
  onRetry,
677
630
  retries = 0,
678
631
  retryDelay = 1e3,
632
+ stream = false,
679
633
  throwOnError = false,
680
634
  timeout = 3e4
681
635
  } = { __proto__: null, ...options };
@@ -696,6 +650,7 @@ async function httpRequest(url, options) {
696
650
  maxRedirects,
697
651
  maxResponseSize,
698
652
  method,
653
+ stream,
699
654
  timeout
700
655
  };
701
656
  let lastError;
@@ -69,6 +69,12 @@ export declare function extractFormatting(json: string): JsonFormatting;
69
69
  * Get default formatting for JSON files.
70
70
  *
71
71
  * @returns Default formatting (2 spaces, LF line endings)
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const fmt = getDefaultFormatting()
76
+ * // { indent: 2, newline: '\n' }
77
+ * ```
72
78
  */
73
79
  export declare function getDefaultFormatting(): JsonFormatting;
74
80
  /**
@@ -109,6 +115,12 @@ export declare function stringifyWithFormatting(content: Record<string, unknown>
109
115
  *
110
116
  * @param content - Content object with potential symbol properties
111
117
  * @returns Object with symbols removed
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * const obj = { key: "value", [Symbol.for("indent")]: 2 }
122
+ * stripFormattingSymbols(obj) // { key: "value" }
123
+ * ```
112
124
  */
113
125
  export declare function stripFormattingSymbols(content: Record<string | symbol, unknown>): Record<string, unknown>;
114
126
  /**
@@ -116,6 +128,12 @@ export declare function stripFormattingSymbols(content: Record<string | symbol,
116
128
  *
117
129
  * @param content - Content object with Symbol.for('indent') and Symbol.for('newline')
118
130
  * @returns Formatting metadata, or defaults if symbols not present
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * const content = { [Symbol.for("indent")]: 4, [Symbol.for("newline")]: "\r\n" }
135
+ * getFormattingFromContent(content) // { indent: 4, newline: "\r\n" }
136
+ * ```
119
137
  */
120
138
  export declare function getFormattingFromContent(content: Record<string | symbol, unknown>): JsonFormatting;
121
139
  /**
@@ -79,6 +79,11 @@ export declare function Memoize(options?: MemoizeOptions<unknown[], unknown>): (
79
79
  /**
80
80
  * Clear all memoization caches.
81
81
  * Useful for testing or when you need to force recomputation.
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * clearAllMemoizationCaches()
86
+ * ```
82
87
  */
83
88
  export declare function clearAllMemoizationCaches(): void;
84
89
  /**