@nomicfoundation/hardhat-utils 3.0.0-next.0 → 3.0.0-next.10

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/src/fs.ts CHANGED
@@ -1,7 +1,15 @@
1
+ import type { JsonTypes, ParsedElementInfo } from "@streamparser/json-node";
2
+ import type { FileHandle } from "node:fs/promises";
3
+
1
4
  import fsPromises from "node:fs/promises";
5
+ import { tmpdir } from "node:os";
2
6
  import path from "node:path";
7
+ import { pipeline } from "node:stream/promises";
8
+
9
+ import { JSONParser } from "@streamparser/json-node";
10
+ import { JsonStreamStringify } from "json-stream-stringify";
3
11
 
4
- import { ensureError } from "./error.js";
12
+ import { ensureError, ensureNodeErrnoExceptionError } from "./error.js";
5
13
  import {
6
14
  FileNotFoundError,
7
15
  FileSystemAccessError,
@@ -24,7 +32,7 @@ export async function getRealPath(absolutePath: string): Promise<string> {
24
32
  try {
25
33
  return await fsPromises.realpath(path.normalize(absolutePath));
26
34
  } catch (e) {
27
- ensureError<NodeJS.ErrnoException>(e);
35
+ ensureNodeErrnoExceptionError(e);
28
36
  if (e.code === "ENOENT") {
29
37
  throw new FileNotFoundError(absolutePath, e);
30
38
  }
@@ -39,6 +47,7 @@ export async function getRealPath(absolutePath: string): Promise<string> {
39
47
  *
40
48
  * @param dirFrom The absolute path of the directory to start the search from.
41
49
  * @param matches A function to filter files (not directories).
50
+ * @param directoryFilter A function to filter which directories to recurse into
42
51
  * @returns An array of absolute paths. Each file has its true case, except
43
52
  * for the initial dirFrom part, which preserves the given casing.
44
53
  * No order is guaranteed. If dirFrom doesn't exist `[]` is returned.
@@ -48,6 +57,7 @@ export async function getRealPath(absolutePath: string): Promise<string> {
48
57
  export async function getAllFilesMatching(
49
58
  dirFrom: string,
50
59
  matches?: (absolutePathToFile: string) => boolean,
60
+ directoryFilter?: (absolutePathToDir: string) => boolean,
51
61
  ): Promise<string[]> {
52
62
  const dirContent = await readdirOrEmpty(dirFrom);
53
63
 
@@ -55,7 +65,18 @@ export async function getAllFilesMatching(
55
65
  dirContent.map(async (file) => {
56
66
  const absolutePathToFile = path.join(dirFrom, file);
57
67
  if (await isDirectory(absolutePathToFile)) {
58
- return getAllFilesMatching(absolutePathToFile, matches);
68
+ if (
69
+ directoryFilter === undefined ||
70
+ directoryFilter(absolutePathToFile)
71
+ ) {
72
+ return getAllFilesMatching(
73
+ absolutePathToFile,
74
+ matches,
75
+ directoryFilter,
76
+ );
77
+ }
78
+
79
+ return [];
59
80
  } else if (matches === undefined || matches(absolutePathToFile)) {
60
81
  return absolutePathToFile;
61
82
  } else {
@@ -158,7 +179,7 @@ export async function isDirectory(absolutePath: string): Promise<boolean> {
158
179
  try {
159
180
  return (await fsPromises.lstat(absolutePath)).isDirectory();
160
181
  } catch (e) {
161
- ensureError<NodeJS.ErrnoException>(e);
182
+ ensureNodeErrnoExceptionError(e);
162
183
  if (e.code === "ENOENT") {
163
184
  throw new FileNotFoundError(absolutePath, e);
164
185
  }
@@ -182,8 +203,81 @@ export async function readJsonFile<T>(absolutePathToFile: string): Promise<T> {
182
203
  try {
183
204
  return JSON.parse(content.toString());
184
205
  } catch (e) {
185
- ensureError<NodeJS.ErrnoException>(e);
206
+ ensureError(e);
207
+ throw new InvalidFileFormatError(absolutePathToFile, e);
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Reads a JSON file as a stream and parses it. The encoding used is "utf8".
213
+ * This function should be used when parsing very large JSON files.
214
+ *
215
+ * @param absolutePathToFile The path to the file.
216
+ * @returns The parsed JSON object.
217
+ * @throws FileNotFoundError if the file doesn't exist.
218
+ * @throws InvalidFileFormatError if the file is not a valid JSON file.
219
+ * @throws IsDirectoryError if the path is a directory instead of a file.
220
+ * @throws FileSystemAccessError for any other error.
221
+ */
222
+ export async function readJsonFileAsStream<T>(
223
+ absolutePathToFile: string,
224
+ ): Promise<T> {
225
+ let fileHandle: FileHandle | undefined;
226
+
227
+ try {
228
+ fileHandle = await fsPromises.open(absolutePathToFile, "r");
229
+
230
+ const fileReadStream = fileHandle.createReadStream();
231
+
232
+ // NOTE: We set a separator to disable self-closing to be able to use the parser
233
+ // in the stream.pipeline context; see https://github.com/juanjoDiaz/streamparser-json/issues/47
234
+ const jsonParser = new JSONParser({
235
+ separator: "",
236
+ });
237
+
238
+ const result: T | undefined = await pipeline(
239
+ fileReadStream,
240
+ jsonParser,
241
+ async (
242
+ elements: AsyncIterable<ParsedElementInfo.ParsedElementInfo>,
243
+ ): Promise<any | undefined> => {
244
+ let value: JsonTypes.JsonPrimitive | JsonTypes.JsonStruct | undefined;
245
+ for await (const element of elements) {
246
+ value = element.value;
247
+ }
248
+ return value;
249
+ },
250
+ );
251
+
252
+ if (result === undefined) {
253
+ throw new Error("No data");
254
+ }
255
+
256
+ return result;
257
+ } catch (e) {
258
+ ensureError(e);
259
+
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
+ }
265
+
266
+ if (e.code === "EISDIR") {
267
+ throw new IsDirectoryError(absolutePathToFile, e);
268
+ }
269
+
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
+ }
274
+ }
275
+
276
+ // Otherwise, we assume the error to be related to the file formatting
186
277
  throw new InvalidFileFormatError(absolutePathToFile, e);
278
+ } finally {
279
+ // Explicitly closing the file handle to fully release the underlying resources
280
+ await fileHandle?.close();
187
281
  }
188
282
  }
189
283
 
@@ -204,13 +298,66 @@ export async function writeJsonFile<T>(
204
298
  try {
205
299
  content = JSON.stringify(object, null, 2);
206
300
  } catch (e) {
207
- ensureError<NodeJS.ErrnoException>(e);
301
+ ensureError(e);
208
302
  throw new JsonSerializationError(absolutePathToFile, e);
209
303
  }
210
304
 
211
305
  await writeUtf8File(absolutePathToFile, content);
212
306
  }
213
307
 
308
+ /**
309
+ * Writes an object to a JSON file as stream. The encoding used is "utf8" and the file is overwritten.
310
+ * If part of the path doesn't exist, it will be created.
311
+ * This function should be used when stringifying very large JSON objects.
312
+ *
313
+ * @param absolutePathToFile The path to the file. If the file exists, it will be overwritten.
314
+ * @param object The object to write.
315
+ * @throws JsonSerializationError if the object can't be serialized to JSON.
316
+ * @throws FileSystemAccessError for any other error.
317
+ */
318
+ export async function writeJsonFileAsStream<T>(
319
+ absolutePathToFile: string,
320
+ object: T,
321
+ ): Promise<void> {
322
+ const dirPath = path.dirname(absolutePathToFile);
323
+ const dirExists = await exists(dirPath);
324
+ if (!dirExists) {
325
+ await mkdir(dirPath);
326
+ }
327
+
328
+ let fileHandle: FileHandle | undefined;
329
+
330
+ try {
331
+ fileHandle = await fsPromises.open(absolutePathToFile, "w");
332
+
333
+ const jsonStream = new JsonStreamStringify(object);
334
+ const fileWriteStream = fileHandle.createWriteStream();
335
+
336
+ await pipeline(jsonStream, fileWriteStream);
337
+ } catch (e) {
338
+ ensureError(e);
339
+ // if the directory was created, we should remove it
340
+ if (dirExists === false) {
341
+ try {
342
+ await remove(dirPath);
343
+ // we don't want to override the original error
344
+ } catch (_error) {}
345
+ }
346
+
347
+ // If the code is defined, we assume the error to be related to the file system
348
+ if ("code" in e && e.code !== undefined) {
349
+ throw new FileSystemAccessError(e.message, e);
350
+ }
351
+
352
+ // Otherwise, we assume the error to be related to the file formatting
353
+ throw new JsonSerializationError(absolutePathToFile, e);
354
+ } finally {
355
+ // NOTE: Historically, not closing the file handle caused issues on Windows,
356
+ // for example, when trying to move the file previously written to by this function
357
+ await fileHandle?.close();
358
+ }
359
+ }
360
+
214
361
  /**
215
362
  * Reads a file and returns its content as a string. The encoding used is "utf8".
216
363
  *
@@ -226,7 +373,7 @@ export async function readUtf8File(
226
373
  try {
227
374
  return await fsPromises.readFile(absolutePathToFile, { encoding: "utf8" });
228
375
  } catch (e) {
229
- ensureError<NodeJS.ErrnoException>(e);
376
+ ensureNodeErrnoExceptionError(e);
230
377
 
231
378
  if (e.code === "ENOENT") {
232
379
  throw new FileNotFoundError(absolutePathToFile, e);
@@ -268,13 +415,13 @@ export async function writeUtf8File(
268
415
  flag,
269
416
  });
270
417
  } catch (e) {
271
- ensureError<NodeJS.ErrnoException>(e);
418
+ ensureNodeErrnoExceptionError(e);
272
419
  // if the directory was created, we should remove it
273
420
  if (dirExists === false) {
274
421
  try {
275
422
  await remove(dirPath);
276
423
  // we don't want to override the original error
277
- } catch (err) {}
424
+ } catch (_error) {}
278
425
  }
279
426
 
280
427
  if (e.code === "ENOENT") {
@@ -306,7 +453,7 @@ export async function readBinaryFile(
306
453
  const buffer = await fsPromises.readFile(absolutePathToFile);
307
454
  return new Uint8Array(buffer);
308
455
  } catch (e) {
309
- ensureError<NodeJS.ErrnoException>(e);
456
+ ensureNodeErrnoExceptionError(e);
310
457
 
311
458
  if (e.code === "ENOENT") {
312
459
  throw new FileNotFoundError(absolutePathToFile, e);
@@ -333,7 +480,7 @@ export async function readdir(absolutePathToDir: string): Promise<string[]> {
333
480
  try {
334
481
  return await fsPromises.readdir(absolutePathToDir);
335
482
  } catch (e) {
336
- ensureError<NodeJS.ErrnoException>(e);
483
+ ensureNodeErrnoExceptionError(e);
337
484
  if (e.code === "ENOENT") {
338
485
  throw new FileNotFoundError(absolutePathToDir, e);
339
486
  }
@@ -373,7 +520,7 @@ export async function mkdir(absolutePath: string): Promise<void> {
373
520
  try {
374
521
  await fsPromises.mkdir(absolutePath, { recursive: true });
375
522
  } catch (e) {
376
- ensureError<NodeJS.ErrnoException>(e);
523
+ ensureNodeErrnoExceptionError(e);
377
524
  throw new FileSystemAccessError(e.message, e);
378
525
  }
379
526
  }
@@ -384,6 +531,22 @@ export async function mkdir(absolutePath: string): Promise<void> {
384
531
  */
385
532
  export const ensureDir: typeof mkdir = mkdir;
386
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 fsPromises.mkdtemp(path.join(tmpdir(), prefix));
544
+ } catch (e) {
545
+ ensureNodeErrnoExceptionError(e);
546
+ throw new FileSystemAccessError(e.message, e);
547
+ }
548
+ }
549
+
387
550
  /**
388
551
  * Retrieves the last change time of a file or directory's properties.
389
552
  * This includes changes to the file's metadata or contents.
@@ -398,7 +561,7 @@ export async function getChangeTime(absolutePath: string): Promise<Date> {
398
561
  const stats = await fsPromises.stat(absolutePath);
399
562
  return stats.ctime;
400
563
  } catch (e) {
401
- ensureError<NodeJS.ErrnoException>(e);
564
+ ensureNodeErrnoExceptionError(e);
402
565
  if (e.code === "ENOENT") {
403
566
  throw new FileNotFoundError(absolutePath, e);
404
567
  }
@@ -420,7 +583,7 @@ export async function getAccessTime(absolutePath: string): Promise<Date> {
420
583
  const stats = await fsPromises.stat(absolutePath);
421
584
  return stats.atime;
422
585
  } catch (e) {
423
- ensureError<NodeJS.ErrnoException>(e);
586
+ ensureNodeErrnoExceptionError(e);
424
587
  if (e.code === "ENOENT") {
425
588
  throw new FileNotFoundError(absolutePath, e);
426
589
  }
@@ -442,7 +605,7 @@ export async function getFileSize(absolutePath: string): Promise<number> {
442
605
  const stats = await fsPromises.stat(absolutePath);
443
606
  return stats.size;
444
607
  } catch (e) {
445
- ensureError<NodeJS.ErrnoException>(e);
608
+ ensureNodeErrnoExceptionError(e);
446
609
  if (e.code === "ENOENT") {
447
610
  throw new FileNotFoundError(absolutePath, e);
448
611
  }
@@ -461,7 +624,7 @@ export async function exists(absolutePath: string): Promise<boolean> {
461
624
  try {
462
625
  await fsPromises.access(absolutePath);
463
626
  return true;
464
- } catch (e) {
627
+ } catch (_error) {
465
628
  return false;
466
629
  }
467
630
  }
@@ -480,7 +643,7 @@ export async function copy(source: string, destination: string): Promise<void> {
480
643
  try {
481
644
  await fsPromises.copyFile(source, destination);
482
645
  } catch (e) {
483
- ensureError<NodeJS.ErrnoException>(e);
646
+ ensureNodeErrnoExceptionError(e);
484
647
  if (e.code === "ENOENT") {
485
648
  if (!(await exists(source))) {
486
649
  throw new FileNotFoundError(source, e);
@@ -524,7 +687,7 @@ export async function move(source: string, destination: string): Promise<void> {
524
687
  try {
525
688
  await fsPromises.rename(source, destination);
526
689
  } catch (e) {
527
- ensureError<NodeJS.ErrnoException>(e);
690
+ ensureNodeErrnoExceptionError(e);
528
691
  if (e.code === "ENOENT") {
529
692
  if (!(await exists(source))) {
530
693
  throw new FileNotFoundError(source, e);
@@ -537,7 +700,9 @@ export async function move(source: string, destination: string): Promise<void> {
537
700
  // On linux, trying to move a non-empty directory will throw ENOTEMPTY,
538
701
  // while on Windows it will throw EPERM.
539
702
  if (e.code === "ENOTEMPTY" || e.code === "EPERM") {
540
- throw new DirectoryNotEmptyError(destination, e);
703
+ if (await isDirectory(source)) {
704
+ throw new DirectoryNotEmptyError(destination, e);
705
+ }
541
706
  }
542
707
 
543
708
  throw new FileSystemAccessError(e.message, e);
@@ -557,9 +722,10 @@ export async function remove(absolutePath: string): Promise<void> {
557
722
  recursive: true,
558
723
  force: true,
559
724
  maxRetries: 3,
725
+ retryDelay: 300,
560
726
  });
561
727
  } catch (e) {
562
- ensureError<NodeJS.ErrnoException>(e);
728
+ ensureNodeErrnoExceptionError(e);
563
729
  throw new FileSystemAccessError(e.message, e);
564
730
  }
565
731
  }
@@ -579,7 +745,7 @@ export async function chmod(
579
745
  try {
580
746
  await fsPromises.chmod(absolutePath, mode);
581
747
  } catch (e) {
582
- ensureError<NodeJS.ErrnoException>(e);
748
+ ensureNodeErrnoExceptionError(e);
583
749
  if (e.code === "ENOENT") {
584
750
  throw new FileNotFoundError(absolutePath, e);
585
751
  }
@@ -616,7 +782,7 @@ export async function emptyDir(absolutePath: string): Promise<void> {
616
782
  isDir = stats.isDirectory();
617
783
  mode = stats.mode;
618
784
  } catch (e) {
619
- ensureError<NodeJS.ErrnoException>(e);
785
+ ensureNodeErrnoExceptionError(e);
620
786
  if (e.code === "ENOENT") {
621
787
  await mkdir(absolutePath);
622
788
  return;
@@ -631,7 +797,7 @@ export async function emptyDir(absolutePath: string): Promise<void> {
631
797
 
632
798
  await remove(absolutePath);
633
799
  await mkdir(absolutePath);
634
- // eslint-disable-next-line no-bitwise -- Bitwise as common in fs permissions
800
+ // eslint-disable-next-line no-bitwise -- Bitwise is common in fs permissions
635
801
  await chmod(absolutePath, mode & 0o777);
636
802
  }
637
803
 
package/src/global-dir.ts CHANGED
@@ -1,7 +1,6 @@
1
+ import { ensureDir } from "./fs.js";
1
2
  import { generatePaths, HARDHAT_PACKAGE_NAME } from "./internal/global-dir.js";
2
3
 
3
- import { ensureDir } from "@nomicfoundation/hardhat-utils/fs";
4
-
5
4
  /**
6
5
  * Returns the configuration directory path for a given package (defaults to "hardhat").
7
6
  * Ensures that the directory exists before returning the path.
@@ -1,5 +1,7 @@
1
1
  import type rfdcT from "rfdc";
2
2
 
3
+ import { isObject } from "../lang.js";
4
+
3
5
  let clone: ReturnType<typeof rfdcT> | null = null;
4
6
  export async function getDeepCloneFunction(): Promise<<T>(input: T) => T> {
5
7
  const { default: rfdc } = await import("rfdc");
@@ -10,3 +12,39 @@ export async function getDeepCloneFunction(): Promise<<T>(input: T) => T> {
10
12
 
11
13
  return clone;
12
14
  }
15
+
16
+ export function deepMergeImpl<T extends object, U extends object>(
17
+ target: T,
18
+ source: U,
19
+ ): T & U {
20
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
21
+ -- The result is expected to include properties from both target and source,
22
+ but initially only target is spread in, so a cast is needed. */
23
+ const result = { ...target } as T & U;
24
+
25
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
26
+ -- TypeScript cannot infer the correct union of string and symbol keys, but all keys come from U */
27
+ const keys = [
28
+ ...Object.keys(source),
29
+ ...Object.getOwnPropertySymbols(source),
30
+ ] as Array<keyof U>;
31
+
32
+ for (const key of keys) {
33
+ if (
34
+ isObject(source[key]) &&
35
+ // Only merge recursively objects that are not class instances
36
+ Object.getPrototypeOf(source[key]) === Object.prototype
37
+ ) {
38
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
39
+ -- The call signature expects the second argument to be of type U; the type is correct, but TypeScript can't infer it here. */
40
+ result[key] = deepMergeImpl(result[key] ?? {}, source[key] as U) as (T &
41
+ U)[Extract<keyof U, string>];
42
+ } else {
43
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
44
+ -- Cast required because TypeScript can't guarantee that a dynamic key from `U` exists in `T & U` or has the correct value type. */
45
+ result[key] = source[key] as (T & U)[Extract<keyof U, string>];
46
+ }
47
+ }
48
+
49
+ return result;
50
+ }
package/src/lang.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { getDeepCloneFunction } from "./internal/lang.js";
1
+ import { deepMergeImpl, getDeepCloneFunction } from "./internal/lang.js";
2
2
 
3
3
  /**
4
4
  * Creates a deep clone of the provided value.
@@ -25,6 +25,31 @@ export async function deepEqual<T>(x: T, y: T): Promise<boolean> {
25
25
  return _deepEqual(x, y);
26
26
  }
27
27
 
28
+ /**
29
+ * Deeply merges two objects.
30
+ *
31
+ * @remarks
32
+ * - Arrays or `undefined` values are not valid inputs.
33
+ * - Functions: If a function exists in both the target and source, the source function overwrites the target.
34
+ * - Symbol properties: Symbol-keyed properties are merged just like string keys.
35
+ * - Class instances: Class instances are not merged recursively. If a class instance exists in the source, it will replace the one in the target.
36
+ *
37
+ * @param target The target object to merge into.
38
+ * @param source The source object to merge from.
39
+ * @returns A new object containing the deeply merged properties.
40
+ *
41
+ * @example
42
+ * deepMerge({ a: { b: 1 } }, { a: { c: 2 } }) // => { a: { b: 1, c: 2 } }
43
+ *
44
+ * deepMerge({ a: { fn: () => "from target" } }, { a: { fn: () => "from source" } }) // => { a: { fn: () => "from source" } }
45
+ */
46
+ export function deepMerge<T extends object, U extends object>(
47
+ target: T,
48
+ source: U,
49
+ ): T & U {
50
+ return deepMergeImpl(target, source);
51
+ }
52
+
28
53
  /**
29
54
  * Checks if a value is an object. This function returns false for arrays.
30
55
  *
package/src/request.ts CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  handleError,
24
24
  } from "./internal/request.js";
25
25
 
26
- export const DEFAULT_TIMEOUT_IN_MILLISECONDS = 30_000;
26
+ export const DEFAULT_TIMEOUT_IN_MILLISECONDS = 300_000; // Aligned with unidici
27
27
  export const DEFAULT_MAX_REDIRECTS = 10;
28
28
  export const DEFAULT_POOL_MAX_CONNECTIONS = 128;
29
29
  export const DEFAULT_USER_AGENT = "Hardhat";
@@ -4,8 +4,8 @@
4
4
  // ATTENTION: in the current implementation, there's still a risk of two processes running simultaneously.
5
5
  // For example, if processA has locked the mutex and is running, processB will wait.
6
6
  // During this wait, processB continuously checks the elapsed time since the mutex lock file was created.
7
- // If an excessive amount of time has passed, processB will assume ownership of the mutex to avoid stale locks.
8
- // However, there's a possibility that processB might take ownership because the mutex creation file is outdated, even though processA is still running
7
+ // If an excessive amount of time has passed, processB will assume ownership of the mutex to prevent stale locks, even if processA is still running.
8
+ // As a result, two processes will be running simultaneously in what is theoretically a mutex-locked section.
9
9
 
10
10
  import fs from "node:fs";
11
11
  import os from "node:os";
@@ -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.