@nomicfoundation/hardhat-utils 3.0.0-next.3 → 3.0.0-next.30

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 (48) hide show
  1. package/README.md +3 -3
  2. package/dist/src/bigint.d.ts.map +1 -1
  3. package/dist/src/bigint.js +1 -0
  4. package/dist/src/bigint.js.map +1 -1
  5. package/dist/src/crypto.d.ts +7 -0
  6. package/dist/src/crypto.d.ts.map +1 -1
  7. package/dist/src/crypto.js +10 -0
  8. package/dist/src/crypto.js.map +1 -1
  9. package/dist/src/debug.d.ts.map +1 -1
  10. package/dist/src/error.d.ts +19 -2
  11. package/dist/src/error.d.ts.map +1 -1
  12. package/dist/src/error.js +22 -2
  13. package/dist/src/error.js.map +1 -1
  14. package/dist/src/fs.d.ts +12 -3
  15. package/dist/src/fs.d.ts.map +1 -1
  16. package/dist/src/fs.js +60 -34
  17. package/dist/src/fs.js.map +1 -1
  18. package/dist/src/internal/bytecode.d.ts +1 -1
  19. package/dist/src/internal/bytecode.d.ts.map +1 -1
  20. package/dist/src/package.d.ts +12 -0
  21. package/dist/src/package.d.ts.map +1 -1
  22. package/dist/src/package.js.map +1 -1
  23. package/dist/src/path.d.ts +2 -2
  24. package/dist/src/path.d.ts.map +1 -1
  25. package/dist/src/path.js +12 -3
  26. package/dist/src/path.js.map +1 -1
  27. package/dist/src/request.d.ts +16 -6
  28. package/dist/src/request.d.ts.map +1 -1
  29. package/dist/src/request.js +12 -4
  30. package/dist/src/request.js.map +1 -1
  31. package/dist/src/stream.d.ts +1 -1
  32. package/dist/src/stream.js +1 -1
  33. package/dist/src/subprocess.js +1 -1
  34. package/dist/src/subprocess.js.map +1 -1
  35. package/dist/src/synchronization.js +4 -4
  36. package/dist/src/synchronization.js.map +1 -1
  37. package/package.json +5 -13
  38. package/src/bigint.ts +1 -0
  39. package/src/crypto.ts +11 -0
  40. package/src/error.ts +26 -2
  41. package/src/fs.ts +76 -40
  42. package/src/internal/bytecode.ts +1 -1
  43. package/src/package.ts +26 -0
  44. package/src/path.ts +16 -6
  45. package/src/request.ts +24 -8
  46. package/src/stream.ts +1 -1
  47. package/src/subprocess.ts +1 -1
  48. package/src/synchronization.ts +4 -4
package/src/fs.ts CHANGED
@@ -2,13 +2,14 @@ import type { JsonTypes, ParsedElementInfo } from "@streamparser/json-node";
2
2
  import type { FileHandle } from "node:fs/promises";
3
3
 
4
4
  import fsPromises from "node:fs/promises";
5
+ import { tmpdir } from "node:os";
5
6
  import path from "node:path";
6
7
  import { pipeline } from "node:stream/promises";
7
8
 
8
9
  import { JSONParser } from "@streamparser/json-node";
9
10
  import { JsonStreamStringify } from "json-stream-stringify";
10
11
 
11
- import { ensureError } from "./error.js";
12
+ import { ensureError, ensureNodeErrnoExceptionError } from "./error.js";
12
13
  import {
13
14
  FileNotFoundError,
14
15
  FileSystemAccessError,
@@ -31,7 +32,7 @@ export async function getRealPath(absolutePath: string): Promise<string> {
31
32
  try {
32
33
  return await fsPromises.realpath(path.normalize(absolutePath));
33
34
  } catch (e) {
34
- ensureError<NodeJS.ErrnoException>(e);
35
+ ensureNodeErrnoExceptionError(e);
35
36
  if (e.code === "ENOENT") {
36
37
  throw new FileNotFoundError(absolutePath, e);
37
38
  }
@@ -46,6 +47,7 @@ export async function getRealPath(absolutePath: string): Promise<string> {
46
47
  *
47
48
  * @param dirFrom The absolute path of the directory to start the search from.
48
49
  * @param matches A function to filter files (not directories).
50
+ * @param directoryFilter A function to filter which directories to recurse into
49
51
  * @returns An array of absolute paths. Each file has its true case, except
50
52
  * for the initial dirFrom part, which preserves the given casing.
51
53
  * No order is guaranteed. If dirFrom doesn't exist `[]` is returned.
@@ -54,7 +56,8 @@ export async function getRealPath(absolutePath: string): Promise<string> {
54
56
  */
55
57
  export async function getAllFilesMatching(
56
58
  dirFrom: string,
57
- matches?: (absolutePathToFile: string) => boolean,
59
+ matches?: (absolutePathToFile: string) => Promise<boolean> | boolean,
60
+ directoryFilter?: (absolutePathToDir: string) => Promise<boolean> | boolean,
58
61
  ): Promise<string[]> {
59
62
  const dirContent = await readdirOrEmpty(dirFrom);
60
63
 
@@ -62,8 +65,19 @@ export async function getAllFilesMatching(
62
65
  dirContent.map(async (file) => {
63
66
  const absolutePathToFile = path.join(dirFrom, file);
64
67
  if (await isDirectory(absolutePathToFile)) {
65
- return getAllFilesMatching(absolutePathToFile, matches);
66
- } else if (matches === undefined || matches(absolutePathToFile)) {
68
+ if (
69
+ directoryFilter === undefined ||
70
+ (await directoryFilter(absolutePathToFile))
71
+ ) {
72
+ return getAllFilesMatching(
73
+ absolutePathToFile,
74
+ matches,
75
+ directoryFilter,
76
+ );
77
+ }
78
+
79
+ return [];
80
+ } else if (matches === undefined || (await matches(absolutePathToFile))) {
67
81
  return absolutePathToFile;
68
82
  } else {
69
83
  return [];
@@ -79,7 +93,7 @@ export async function getAllFilesMatching(
79
93
  * satisfy the specified condition, returning their absolute paths. Once a
80
94
  * directory is found, its subdirectories are not searched.
81
95
  *
82
- * Note: dirFrom is never returned, nor `matches` is called on it.
96
+ * Note: dirFrom is never returned, nor is `matches` called on it.
83
97
  *
84
98
  * @param dirFrom The absolute path of the directory to start the search from.
85
99
  * @param matches A function to filter directories (not files).
@@ -91,7 +105,7 @@ export async function getAllFilesMatching(
91
105
  */
92
106
  export async function getAllDirectoriesMatching(
93
107
  dirFrom: string,
94
- matches?: (absolutePathToDir: string) => boolean,
108
+ matches?: (absolutePathToDir: string) => Promise<boolean> | boolean,
95
109
  ): Promise<string[]> {
96
110
  const dirContent = await readdirOrEmpty(dirFrom);
97
111
 
@@ -102,7 +116,7 @@ export async function getAllDirectoriesMatching(
102
116
  return [];
103
117
  }
104
118
 
105
- if (matches === undefined || matches(absolutePathToFile)) {
119
+ if (matches === undefined || (await matches(absolutePathToFile))) {
106
120
  return absolutePathToFile;
107
121
  }
108
122
 
@@ -165,7 +179,7 @@ export async function isDirectory(absolutePath: string): Promise<boolean> {
165
179
  try {
166
180
  return (await fsPromises.lstat(absolutePath)).isDirectory();
167
181
  } catch (e) {
168
- ensureError<NodeJS.ErrnoException>(e);
182
+ ensureNodeErrnoExceptionError(e);
169
183
  if (e.code === "ENOENT") {
170
184
  throw new FileNotFoundError(absolutePath, e);
171
185
  }
@@ -189,7 +203,7 @@ export async function readJsonFile<T>(absolutePathToFile: string): Promise<T> {
189
203
  try {
190
204
  return JSON.parse(content.toString());
191
205
  } catch (e) {
192
- ensureError<NodeJS.ErrnoException>(e);
206
+ ensureError(e);
193
207
  throw new InvalidFileFormatError(absolutePathToFile, e);
194
208
  }
195
209
  }
@@ -241,19 +255,22 @@ export async function readJsonFileAsStream<T>(
241
255
 
242
256
  return result;
243
257
  } catch (e) {
244
- ensureError<NodeJS.ErrnoException>(e);
258
+ ensureError(e);
245
259
 
246
- if (e.code === "ENOENT") {
247
- throw new FileNotFoundError(absolutePathToFile, e);
248
- }
260
+ // If the code is defined, we assume the error to be related to the file system
261
+ if ("code" in e) {
262
+ if (e.code === "ENOENT") {
263
+ throw new FileNotFoundError(absolutePathToFile, e);
264
+ }
249
265
 
250
- if (e.code === "EISDIR") {
251
- throw new IsDirectoryError(absolutePathToFile, e);
252
- }
266
+ if (e.code === "EISDIR") {
267
+ throw new IsDirectoryError(absolutePathToFile, e);
268
+ }
253
269
 
254
- // If the code is defined, we assume the error to be related to the file system
255
- if (e.code !== undefined) {
256
- throw new FileSystemAccessError(absolutePathToFile, e);
270
+ // If the code is defined, we assume the error to be related to the file system
271
+ if (e.code !== undefined) {
272
+ throw new FileSystemAccessError(absolutePathToFile, e);
273
+ }
257
274
  }
258
275
 
259
276
  // Otherwise, we assume the error to be related to the file formatting
@@ -281,7 +298,7 @@ export async function writeJsonFile<T>(
281
298
  try {
282
299
  content = JSON.stringify(object, null, 2);
283
300
  } catch (e) {
284
- ensureError<NodeJS.ErrnoException>(e);
301
+ ensureError(e);
285
302
  throw new JsonSerializationError(absolutePathToFile, e);
286
303
  }
287
304
 
@@ -318,17 +335,17 @@ export async function writeJsonFileAsStream<T>(
318
335
 
319
336
  await pipeline(jsonStream, fileWriteStream);
320
337
  } catch (e) {
321
- ensureError<NodeJS.ErrnoException>(e);
338
+ ensureError(e);
322
339
  // if the directory was created, we should remove it
323
340
  if (dirExists === false) {
324
341
  try {
325
342
  await remove(dirPath);
326
343
  // we don't want to override the original error
327
- } catch (err) {}
344
+ } catch (_error) {}
328
345
  }
329
346
 
330
347
  // If the code is defined, we assume the error to be related to the file system
331
- if (e.code !== undefined) {
348
+ if ("code" in e && e.code !== undefined) {
332
349
  throw new FileSystemAccessError(e.message, e);
333
350
  }
334
351
 
@@ -356,7 +373,7 @@ export async function readUtf8File(
356
373
  try {
357
374
  return await fsPromises.readFile(absolutePathToFile, { encoding: "utf8" });
358
375
  } catch (e) {
359
- ensureError<NodeJS.ErrnoException>(e);
376
+ ensureNodeErrnoExceptionError(e);
360
377
 
361
378
  if (e.code === "ENOENT") {
362
379
  throw new FileNotFoundError(absolutePathToFile, e);
@@ -398,13 +415,13 @@ export async function writeUtf8File(
398
415
  flag,
399
416
  });
400
417
  } catch (e) {
401
- ensureError<NodeJS.ErrnoException>(e);
418
+ ensureNodeErrnoExceptionError(e);
402
419
  // if the directory was created, we should remove it
403
420
  if (dirExists === false) {
404
421
  try {
405
422
  await remove(dirPath);
406
423
  // we don't want to override the original error
407
- } catch (err) {}
424
+ } catch (_error) {}
408
425
  }
409
426
 
410
427
  if (e.code === "ENOENT") {
@@ -436,7 +453,7 @@ export async function readBinaryFile(
436
453
  const buffer = await fsPromises.readFile(absolutePathToFile);
437
454
  return new Uint8Array(buffer);
438
455
  } catch (e) {
439
- ensureError<NodeJS.ErrnoException>(e);
456
+ ensureNodeErrnoExceptionError(e);
440
457
 
441
458
  if (e.code === "ENOENT") {
442
459
  throw new FileNotFoundError(absolutePathToFile, e);
@@ -463,7 +480,7 @@ export async function readdir(absolutePathToDir: string): Promise<string[]> {
463
480
  try {
464
481
  return await fsPromises.readdir(absolutePathToDir);
465
482
  } catch (e) {
466
- ensureError<NodeJS.ErrnoException>(e);
483
+ ensureNodeErrnoExceptionError(e);
467
484
  if (e.code === "ENOENT") {
468
485
  throw new FileNotFoundError(absolutePathToDir, e);
469
486
  }
@@ -503,7 +520,7 @@ export async function mkdir(absolutePath: string): Promise<void> {
503
520
  try {
504
521
  await fsPromises.mkdir(absolutePath, { recursive: true });
505
522
  } catch (e) {
506
- ensureError<NodeJS.ErrnoException>(e);
523
+ ensureNodeErrnoExceptionError(e);
507
524
  throw new FileSystemAccessError(e.message, e);
508
525
  }
509
526
  }
@@ -514,6 +531,24 @@ export async function mkdir(absolutePath: string): Promise<void> {
514
531
  */
515
532
  export const ensureDir: typeof mkdir = mkdir;
516
533
 
534
+ /**
535
+ * Creates a temporary directory with the specified prefix.
536
+ *
537
+ * @param prefix The prefix to use for the temporary directory.
538
+ * @returns The absolute path to the created temporary directory.
539
+ * @throws FileSystemAccessError for any error.
540
+ */
541
+ export async function mkdtemp(prefix: string): Promise<string> {
542
+ try {
543
+ return await getRealPath(
544
+ await fsPromises.mkdtemp(path.join(tmpdir(), prefix)),
545
+ );
546
+ } catch (e) {
547
+ ensureNodeErrnoExceptionError(e);
548
+ throw new FileSystemAccessError(e.message, e);
549
+ }
550
+ }
551
+
517
552
  /**
518
553
  * Retrieves the last change time of a file or directory's properties.
519
554
  * This includes changes to the file's metadata or contents.
@@ -528,7 +563,7 @@ export async function getChangeTime(absolutePath: string): Promise<Date> {
528
563
  const stats = await fsPromises.stat(absolutePath);
529
564
  return stats.ctime;
530
565
  } catch (e) {
531
- ensureError<NodeJS.ErrnoException>(e);
566
+ ensureNodeErrnoExceptionError(e);
532
567
  if (e.code === "ENOENT") {
533
568
  throw new FileNotFoundError(absolutePath, e);
534
569
  }
@@ -550,7 +585,7 @@ export async function getAccessTime(absolutePath: string): Promise<Date> {
550
585
  const stats = await fsPromises.stat(absolutePath);
551
586
  return stats.atime;
552
587
  } catch (e) {
553
- ensureError<NodeJS.ErrnoException>(e);
588
+ ensureNodeErrnoExceptionError(e);
554
589
  if (e.code === "ENOENT") {
555
590
  throw new FileNotFoundError(absolutePath, e);
556
591
  }
@@ -572,7 +607,7 @@ export async function getFileSize(absolutePath: string): Promise<number> {
572
607
  const stats = await fsPromises.stat(absolutePath);
573
608
  return stats.size;
574
609
  } catch (e) {
575
- ensureError<NodeJS.ErrnoException>(e);
610
+ ensureNodeErrnoExceptionError(e);
576
611
  if (e.code === "ENOENT") {
577
612
  throw new FileNotFoundError(absolutePath, e);
578
613
  }
@@ -591,7 +626,7 @@ export async function exists(absolutePath: string): Promise<boolean> {
591
626
  try {
592
627
  await fsPromises.access(absolutePath);
593
628
  return true;
594
- } catch (e) {
629
+ } catch (_error) {
595
630
  return false;
596
631
  }
597
632
  }
@@ -610,7 +645,7 @@ export async function copy(source: string, destination: string): Promise<void> {
610
645
  try {
611
646
  await fsPromises.copyFile(source, destination);
612
647
  } catch (e) {
613
- ensureError<NodeJS.ErrnoException>(e);
648
+ ensureNodeErrnoExceptionError(e);
614
649
  if (e.code === "ENOENT") {
615
650
  if (!(await exists(source))) {
616
651
  throw new FileNotFoundError(source, e);
@@ -654,7 +689,7 @@ export async function move(source: string, destination: string): Promise<void> {
654
689
  try {
655
690
  await fsPromises.rename(source, destination);
656
691
  } catch (e) {
657
- ensureError<NodeJS.ErrnoException>(e);
692
+ ensureNodeErrnoExceptionError(e);
658
693
  if (e.code === "ENOENT") {
659
694
  if (!(await exists(source))) {
660
695
  throw new FileNotFoundError(source, e);
@@ -689,9 +724,10 @@ export async function remove(absolutePath: string): Promise<void> {
689
724
  recursive: true,
690
725
  force: true,
691
726
  maxRetries: 3,
727
+ retryDelay: 300,
692
728
  });
693
729
  } catch (e) {
694
- ensureError<NodeJS.ErrnoException>(e);
730
+ ensureNodeErrnoExceptionError(e);
695
731
  throw new FileSystemAccessError(e.message, e);
696
732
  }
697
733
  }
@@ -711,7 +747,7 @@ export async function chmod(
711
747
  try {
712
748
  await fsPromises.chmod(absolutePath, mode);
713
749
  } catch (e) {
714
- ensureError<NodeJS.ErrnoException>(e);
750
+ ensureNodeErrnoExceptionError(e);
715
751
  if (e.code === "ENOENT") {
716
752
  throw new FileNotFoundError(absolutePath, e);
717
753
  }
@@ -748,7 +784,7 @@ export async function emptyDir(absolutePath: string): Promise<void> {
748
784
  isDir = stats.isDirectory();
749
785
  mode = stats.mode;
750
786
  } catch (e) {
751
- ensureError<NodeJS.ErrnoException>(e);
787
+ ensureNodeErrnoExceptionError(e);
752
788
  if (e.code === "ENOENT") {
753
789
  await mkdir(absolutePath);
754
790
  return;
@@ -763,7 +799,7 @@ export async function emptyDir(absolutePath: string): Promise<void> {
763
799
 
764
800
  await remove(absolutePath);
765
801
  await mkdir(absolutePath);
766
- // eslint-disable-next-line no-bitwise -- Bitwise as common in fs permissions
802
+ // eslint-disable-next-line no-bitwise -- Bitwise is common in fs permissions
767
803
  await chmod(absolutePath, mode & 0o777);
768
804
  }
769
805
 
@@ -12,7 +12,7 @@ import { isAddress } from "../eth.js";
12
12
  export interface Artifact {
13
13
  bytecode: string;
14
14
  linkReferences: {
15
- [sourceName: string]: {
15
+ [inputSourceName: string]: {
16
16
  [libraryName: string]: Array<{ start: number; length: number }>;
17
17
  };
18
18
  };
package/src/package.ts CHANGED
@@ -10,6 +10,31 @@ import { exists, findUp, getRealPath, readJsonFile } from "./fs.js";
10
10
  import { getFilePath } from "./internal/package.js";
11
11
  import { ensureTrailingSlash } from "./string.js";
12
12
 
13
+ /* Adapted from `resolve.exports`. License: https://github.com/lukeed/resolve.exports/blob/master/license */
14
+
15
+ export type PackageExports =
16
+ | PackageExportPath
17
+ | {
18
+ [path: PackageExportsEntry]: PackageExportsValue;
19
+ [condition: string]: PackageExportsValue;
20
+ };
21
+
22
+ /** Allows "." and "./{name}" */
23
+ export type PackageExportsEntry = `.${string}`;
24
+
25
+ /** Internal path */
26
+ export type PackageExportPath = `./${string}`;
27
+
28
+ export type PackageExportsValue =
29
+ | PackageExportPath
30
+ | null
31
+ | {
32
+ [condition: string]: PackageExportsValue;
33
+ }
34
+ | PackageExportsValue[];
35
+
36
+ /* End of `resolve.exports` adaptation */
37
+
13
38
  /**
14
39
  * The structure of a `package.json` file. This is a subset of the actual
15
40
  * `package.json` file, if you need to access other fields you add them here.
@@ -22,6 +47,7 @@ export interface PackageJson {
22
47
  engines?: {
23
48
  node?: string;
24
49
  };
50
+ exports?: PackageExports;
25
51
  dependencies?: Record<string, string>;
26
52
  devDependencies?: Record<string, string>;
27
53
  peerDependencies?: Record<string, string>;
package/src/path.ts CHANGED
@@ -22,7 +22,7 @@ export function resolveFromRoot(root: string, target: string): string {
22
22
  * Tries to return a shorter version of the path if its inside the given folder.
23
23
  *
24
24
  * This is useful for displaying paths in the terminal, as they can be shorter
25
- * when they are insidde the current working directory. For example, if the
25
+ * when they are inside the current working directory. For example, if the
26
26
  * current working directory is `/home/user/project`, and the path is
27
27
  * `/home/user/project/contracts/File.sol`, the shorter path is
28
28
  * `contracts/File.sol`.
@@ -31,11 +31,21 @@ export function resolveFromRoot(root: string, target: string): string {
31
31
  * @param folder The absolute path to the folder.
32
32
  * @returns The shorter path, if possible, or the original path.
33
33
  */
34
- export function shortenPath(
35
- absolutePath: string,
36
- folder: string = process.cwd(),
37
- ): string {
38
- const relativePath = path.relative(folder, absolutePath);
34
+ export function shortenPath(absolutePath: string): string {
35
+ const cwd = process.cwd();
36
+ let relativePath = path.relative(cwd, absolutePath);
37
+
38
+ if (relativePath === "..") {
39
+ return ".." + path.sep;
40
+ }
41
+
42
+ if (
43
+ !relativePath.startsWith(".." + path.sep) &&
44
+ !relativePath.startsWith("." + path.sep) &&
45
+ !path.isAbsolute(relativePath)
46
+ ) {
47
+ relativePath = "." + path.sep + relativePath;
48
+ }
39
49
 
40
50
  if (relativePath.length < absolutePath.length) {
41
51
  return relativePath;
package/src/request.ts CHANGED
@@ -62,13 +62,22 @@ export interface RequestOptions {
62
62
  abortSignal?: AbortSignal | EventEmitter;
63
63
  }
64
64
 
65
+ export interface HttpResponse {
66
+ statusCode: number;
67
+ body: {
68
+ json(): Promise<any>;
69
+ text(): Promise<string>;
70
+ };
71
+ }
72
+
65
73
  /**
66
74
  * Performs a HTTP request.
67
75
  *
68
76
  * @param url The url to make the request to.
69
77
  * @param requestOptions The options to configure the request. See {@link RequestOptions}.
70
78
  * @param dispatcherOrDispatcherOptions Either a dispatcher or dispatcher options. See {@link DispatcherOptions}.
71
- * @returns The response data object. See {@link https://undici.nodejs.org/#/docs/api/Dispatcher?id=parameter-responsedata}.
79
+ * @returns An object containing the status code and the response body. The body can be accessed as JSON or text.
80
+ * `body` can not be consumed twice. For example, calling `text()` after `json()` throws `TypeError`.
72
81
  * @throws ConnectionRefusedError If the connection is refused by the server.
73
82
  * @throws RequestTimeoutError If the request times out.
74
83
  * @throws RequestError If the request fails for any other reason.
@@ -77,7 +86,7 @@ export async function getRequest(
77
86
  url: string,
78
87
  requestOptions: RequestOptions = {},
79
88
  dispatcherOrDispatcherOptions?: UndiciT.Dispatcher | DispatcherOptions,
80
- ): Promise<UndiciT.Dispatcher.ResponseData> {
89
+ ): Promise<HttpResponse> {
81
90
  const { request } = await import("undici");
82
91
 
83
92
  try {
@@ -106,7 +115,8 @@ export async function getRequest(
106
115
  * @param body The body of the request, represented as an object.
107
116
  * @param requestOptions The options to configure the request. See {@link RequestOptions}.
108
117
  * @param dispatcherOrDispatcherOptions Either a dispatcher or dispatcher options. See {@link DispatcherOptions}.
109
- * @returns The response data object. See {@link https://undici.nodejs.org/#/docs/api/Dispatcher?id=parameter-responsedata}.
118
+ * @returns An object containing the status code and the response body. The body can be accessed as JSON or text.
119
+ * `body` can not be consumed twice. For example, calling `text()` after `json()` throws `TypeError`.
110
120
  * @throws ConnectionRefusedError If the connection is refused by the server.
111
121
  * @throws RequestTimeoutError If the request times out.
112
122
  * @throws RequestError If the request fails for any other reason.
@@ -116,7 +126,7 @@ export async function postJsonRequest(
116
126
  body: unknown,
117
127
  requestOptions: RequestOptions = {},
118
128
  dispatcherOrDispatcherOptions?: UndiciT.Dispatcher | DispatcherOptions,
119
- ): Promise<UndiciT.Dispatcher.ResponseData> {
129
+ ): Promise<HttpResponse> {
120
130
  const { request } = await import("undici");
121
131
 
122
132
  try {
@@ -150,7 +160,8 @@ export async function postJsonRequest(
150
160
  * @param body The body of the request, represented as an object.
151
161
  * @param requestOptions The options to configure the request. See {@link RequestOptions}.
152
162
  * @param dispatcherOrDispatcherOptions Either a dispatcher or dispatcher options. See {@link DispatcherOptions}.
153
- * @returns The response data object. See {@link https://undici.nodejs.org/#/docs/api/Dispatcher?id=parameter-responsedata}.
163
+ * @returns An object containing the status code and the response body. The body can be accessed as JSON or text.
164
+ * `body` can not be consumed twice. For example, calling `text()` after `json()` throws `TypeError`.
154
165
  * @throws ConnectionRefusedError If the connection is refused by the server.
155
166
  * @throws RequestTimeoutError If the request times out.
156
167
  * @throws RequestError If the request fails for any other reason.
@@ -160,7 +171,7 @@ export async function postFormRequest(
160
171
  body: unknown,
161
172
  requestOptions: RequestOptions = {},
162
173
  dispatcherOrDispatcherOptions?: UndiciT.Dispatcher | DispatcherOptions,
163
- ): Promise<UndiciT.Dispatcher.ResponseData> {
174
+ ): Promise<HttpResponse> {
164
175
  const { request } = await import("undici");
165
176
 
166
177
  try {
@@ -208,11 +219,16 @@ export async function download(
208
219
  let statusCode: number | undefined;
209
220
 
210
221
  try {
211
- const response = await getRequest(
222
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
223
+ -- We need the full Dispatcher.ResponseData here for stream.pipeline,
224
+ but HttpResponse doesn’t expose the raw ReadableStream.
225
+ TODO: wrap undici's request so we can keep the public API
226
+ strictly typed without falling back to Undici types. */
227
+ const response = (await getRequest(
212
228
  url,
213
229
  requestOptions,
214
230
  dispatcherOrDispatcherOptions,
215
- );
231
+ )) as UndiciT.Dispatcher.ResponseData;
216
232
  const { body } = response;
217
233
  statusCode = response.statusCode;
218
234
 
package/src/stream.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Writable } from "node:stream";
2
2
 
3
3
  /**
4
- * Creates a Tansform that writes everything to actualWritable, without closing it
4
+ * Creates a Transform that writes everything to actualWritable, without closing it
5
5
  * when finished.
6
6
  *
7
7
  * This is useful to pipe things to stdout, without closing it, while being
package/src/subprocess.ts CHANGED
@@ -33,7 +33,7 @@ export async function spawnDetachedSubProcess(
33
33
  const subprocessArgs = [absolutePathToSubProcessFile, ...args];
34
34
 
35
35
  if (absolutePathToSubProcessFile.endsWith(".ts")) {
36
- subprocessArgs.unshift("--import", "tsx/esm");
36
+ subprocessArgs.unshift("--import", import.meta.resolve("tsx/esm"));
37
37
  }
38
38
 
39
39
  const subprocess = spawn(process.execPath, subprocessArgs, {
@@ -13,7 +13,7 @@ import path from "node:path";
13
13
 
14
14
  import debug from "debug";
15
15
 
16
- import { ensureError } from "./error.js";
16
+ import { ensureNodeErrnoExceptionError } from "./error.js";
17
17
  import { FileSystemAccessError } from "./errors/fs.js";
18
18
  import { sleep } from "./lang.js";
19
19
 
@@ -62,7 +62,7 @@ export class MultiProcessMutex {
62
62
  fs.writeFileSync(this.#mutexFilePath, "", { flag: "wx+" });
63
63
  return true;
64
64
  } catch (e) {
65
- ensureError<NodeJS.ErrnoException>(e);
65
+ ensureNodeErrnoExceptionError(e);
66
66
 
67
67
  if (e.code === "EEXIST") {
68
68
  // File already exists, so the mutex is already acquired
@@ -91,7 +91,7 @@ export class MultiProcessMutex {
91
91
  try {
92
92
  fileStat = fs.statSync(this.#mutexFilePath);
93
93
  } catch (e) {
94
- ensureError<NodeJS.ErrnoException>(e);
94
+ ensureNodeErrnoExceptionError(e);
95
95
 
96
96
  if (e.code === "ENOENT") {
97
97
  // The file might have been deleted by another process while this function was trying to access it.
@@ -113,7 +113,7 @@ export class MultiProcessMutex {
113
113
  log(`Deleting mutex file at path '${this.#mutexFilePath}'`);
114
114
  fs.unlinkSync(this.#mutexFilePath);
115
115
  } catch (e) {
116
- ensureError<NodeJS.ErrnoException>(e);
116
+ ensureNodeErrnoExceptionError(e);
117
117
 
118
118
  if (e.code === "ENOENT") {
119
119
  // The file might have been deleted by another process while this function was trying to access it.