@lodestar/utils 1.35.0-dev.e18102ed8c → 1.35.0-dev.f2a741bbe4

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 (67) hide show
  1. package/lib/assert.d.ts.map +1 -0
  2. package/lib/base64.d.ts.map +1 -0
  3. package/lib/bytes/browser.d.ts.map +1 -0
  4. package/lib/bytes/index.d.ts.map +1 -0
  5. package/lib/bytes/nodejs.d.ts.map +1 -0
  6. package/lib/bytes.d.ts.map +1 -0
  7. package/lib/command.d.ts.map +1 -0
  8. package/lib/diff.d.ts.map +1 -0
  9. package/lib/err.d.ts.map +1 -0
  10. package/lib/errors.d.ts.map +1 -0
  11. package/lib/ethConversion.d.ts.map +1 -0
  12. package/lib/fetch.d.ts.map +1 -0
  13. package/lib/format.d.ts.map +1 -0
  14. package/lib/index.d.ts.map +1 -0
  15. package/lib/iterator.d.ts.map +1 -0
  16. package/lib/logger.d.ts.map +1 -0
  17. package/lib/map.d.ts.map +1 -0
  18. package/lib/math.d.ts.map +1 -0
  19. package/lib/metrics.d.ts.map +1 -0
  20. package/lib/notNullish.d.ts.map +1 -0
  21. package/lib/objects.d.ts.map +1 -0
  22. package/lib/promise.d.ts.map +1 -0
  23. package/lib/retry.d.ts.map +1 -0
  24. package/lib/sleep.d.ts.map +1 -0
  25. package/lib/sort.d.ts.map +1 -0
  26. package/lib/timeout.d.ts.map +1 -0
  27. package/lib/types.d.ts.map +1 -0
  28. package/lib/url.d.ts.map +1 -0
  29. package/lib/verifyMerkleBranch.d.ts.map +1 -0
  30. package/lib/waitFor.d.ts.map +1 -0
  31. package/lib/yaml/index.d.ts.map +1 -0
  32. package/lib/yaml/int.d.ts.map +1 -0
  33. package/lib/yaml/schema.d.ts.map +1 -0
  34. package/package.json +11 -8
  35. package/src/assert.ts +86 -0
  36. package/src/base64.ts +9 -0
  37. package/src/bytes/browser.ts +123 -0
  38. package/src/bytes/index.ts +29 -0
  39. package/src/bytes/nodejs.ts +63 -0
  40. package/src/bytes.ts +84 -0
  41. package/src/command.ts +74 -0
  42. package/src/diff.ts +234 -0
  43. package/src/err.ts +105 -0
  44. package/src/errors.ts +73 -0
  45. package/src/ethConversion.ts +12 -0
  46. package/src/fetch.ts +188 -0
  47. package/src/format.ts +119 -0
  48. package/src/index.ts +28 -0
  49. package/src/iterator.ts +10 -0
  50. package/src/logger.ts +20 -0
  51. package/src/map.ts +108 -0
  52. package/src/math.ts +55 -0
  53. package/src/metrics.ts +73 -0
  54. package/src/notNullish.ts +11 -0
  55. package/src/objects.ts +102 -0
  56. package/src/promise.ts +163 -0
  57. package/src/retry.ts +75 -0
  58. package/src/sleep.ts +32 -0
  59. package/src/sort.ts +9 -0
  60. package/src/timeout.ts +27 -0
  61. package/src/types.ts +48 -0
  62. package/src/url.ts +29 -0
  63. package/src/verifyMerkleBranch.ts +27 -0
  64. package/src/waitFor.ts +87 -0
  65. package/src/yaml/index.ts +12 -0
  66. package/src/yaml/int.ts +190 -0
  67. package/src/yaml/schema.ts +8 -0
package/src/command.ts ADDED
@@ -0,0 +1,74 @@
1
+ import type {Argv, Options} from "yargs";
2
+
3
+ export interface CliExample {
4
+ command: string;
5
+ title?: string;
6
+ description?: string;
7
+ }
8
+
9
+ // biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
10
+ export interface CliOptionDefinition<T = any> extends Options {
11
+ example?: Omit<CliExample, "title">;
12
+ // Ensure `type` property matches type of `T`
13
+ type: T extends string
14
+ ? "string"
15
+ : T extends number
16
+ ? "number"
17
+ : T extends boolean
18
+ ? "boolean"
19
+ : T extends Array<unknown>
20
+ ? "array"
21
+ : never;
22
+ }
23
+
24
+ export type CliCommandOptions<OwnArgs> = Required<{
25
+ [K in keyof OwnArgs]: undefined extends OwnArgs[K]
26
+ ? CliOptionDefinition<OwnArgs[K]>
27
+ : // If arg cannot be undefined it must specify a default value or be provided by the user
28
+ CliOptionDefinition<OwnArgs[K]> & (Required<Pick<Options, "default">> | {demandOption: true});
29
+ }>;
30
+
31
+ // biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
32
+ export interface CliCommand<OwnArgs = Record<never, never>, ParentArgs = Record<never, never>, R = any> {
33
+ command: string;
34
+ describe: string;
35
+ /**
36
+ * The folder in docs/pages that the cli.md should be placed in. If not provided no
37
+ * cli flags page will be generated for the command
38
+ */
39
+ docsFolder?: string;
40
+ examples?: CliExample[];
41
+ options?: CliCommandOptions<OwnArgs>;
42
+ // 1st arg: any = free own sub command options
43
+ // 2nd arg: subcommand parent options is = to this command options + parent options
44
+ // biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
45
+ subcommands?: CliCommand<any, OwnArgs & ParentArgs>[];
46
+ handler?: (args: OwnArgs & ParentArgs) => Promise<R>;
47
+ }
48
+
49
+ /**
50
+ * Register a CliCommand type to yargs. Recursively registers subcommands too.
51
+ * @param yargs
52
+ * @param cliCommand
53
+ */
54
+
55
+ // biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
56
+ export function registerCommandToYargs(yargs: Argv, cliCommand: CliCommand<any, any>): void {
57
+ yargs.command({
58
+ command: cliCommand.command,
59
+ describe: cliCommand.describe,
60
+ builder: (yargsBuilder) => {
61
+ yargsBuilder.options(cliCommand.options ?? {});
62
+ for (const subcommand of cliCommand.subcommands ?? []) {
63
+ registerCommandToYargs(yargsBuilder, subcommand);
64
+ }
65
+ if (cliCommand.examples) {
66
+ for (const example of cliCommand.examples) {
67
+ yargsBuilder.example(`$0 ${example.command}`, example.description ?? "");
68
+ }
69
+ }
70
+ return yargs;
71
+ },
72
+ handler: cliCommand.handler ?? function emptyHandler(): void {},
73
+ });
74
+ }
package/src/diff.ts ADDED
@@ -0,0 +1,234 @@
1
+ import fs from "node:fs";
2
+
3
+ const primitiveTypeof = ["number", "string", "bigint", "boolean"];
4
+ export type BufferType = Uint8Array | Uint32Array;
5
+ export type PrimitiveType = number | string | bigint | boolean | BufferType;
6
+ export type DiffableCollection = Record<string | number, PrimitiveType>;
7
+ export type Diffable = PrimitiveType | Array<PrimitiveType> | DiffableCollection;
8
+
9
+ export interface Diff {
10
+ objectPath: string;
11
+ errorMessage?: string;
12
+ val1: Diffable;
13
+ val2: Diffable;
14
+ }
15
+
16
+ export function diffUint8Array(val1: Uint8Array, val2: PrimitiveType, objectPath: string): Diff[] {
17
+ if (!(val2 instanceof Uint8Array)) {
18
+ return [
19
+ {
20
+ objectPath,
21
+ errorMessage: `val1${objectPath} is a Uint8Array, but val2${objectPath} is not`,
22
+ val1,
23
+ val2,
24
+ },
25
+ ];
26
+ }
27
+ const hex1 = Buffer.from(val1).toString("hex");
28
+ const hex2 = Buffer.from(val2).toString("hex");
29
+ if (hex1 !== hex2) {
30
+ return [
31
+ {
32
+ objectPath,
33
+ val1: `0x${hex1}`,
34
+ val2: `0x${hex2}`,
35
+ },
36
+ ];
37
+ }
38
+ return [];
39
+ }
40
+
41
+ export function diffUint32Array(val1: Uint32Array, val2: PrimitiveType, objectPath: string): Diff[] {
42
+ if (!(val2 instanceof Uint32Array)) {
43
+ return [
44
+ {
45
+ objectPath,
46
+ errorMessage: `val1${objectPath} is a Uint32Array, but val2${objectPath} is not`,
47
+ val1,
48
+ val2,
49
+ },
50
+ ];
51
+ }
52
+ const diffs: Diff[] = [];
53
+ val1.forEach((value, index) => {
54
+ const value2 = val2[index];
55
+ if (value !== value2) {
56
+ diffs.push({
57
+ objectPath: `${objectPath}[${index}]`,
58
+ val1: `0x${value.toString(16).padStart(8, "0")}`,
59
+ val2: value2 ? `0x${val2[index].toString(16).padStart(8, "0")}` : "undefined",
60
+ });
61
+ }
62
+ });
63
+ return diffs;
64
+ }
65
+
66
+ function diffPrimitiveValue(val1: PrimitiveType, val2: PrimitiveType, objectPath: string): Diff[] {
67
+ if (val1 instanceof Uint8Array) {
68
+ return diffUint8Array(val1, val2, objectPath);
69
+ }
70
+ if (val1 instanceof Uint32Array) {
71
+ return diffUint32Array(val1, val2, objectPath);
72
+ }
73
+
74
+ const diff = {objectPath, val1, val2} as Diff;
75
+ const type1 = typeof val1;
76
+ if (!primitiveTypeof.includes(type1)) {
77
+ diff.errorMessage = `val1${objectPath} is not a supported type`;
78
+ }
79
+ const type2 = typeof val2;
80
+ if (!primitiveTypeof.includes(type2)) {
81
+ diff.errorMessage = `val2${objectPath} is not a supported type`;
82
+ }
83
+ if (type1 !== type2) {
84
+ diff.errorMessage = `val1${objectPath} is not the same type as val2${objectPath}`;
85
+ }
86
+ if (val1 !== val2) {
87
+ return [diff];
88
+ }
89
+ return [];
90
+ }
91
+
92
+ function isPrimitiveValue(val: unknown): val is PrimitiveType {
93
+ if (Array.isArray(val)) return false;
94
+ if (typeof val === "object") {
95
+ return val instanceof Uint8Array || val instanceof Uint32Array;
96
+ }
97
+ return true;
98
+ }
99
+
100
+ function isDiffable(val: unknown): val is Diffable {
101
+ return !(typeof val === "function" || typeof val === "symbol" || typeof val === "undefined" || val === null);
102
+ }
103
+
104
+ export function getDiffs(val1: Diffable, val2: Diffable, objectPath: string): Diff[] {
105
+ if (isPrimitiveValue(val1)) {
106
+ if (!isPrimitiveValue(val2)) {
107
+ return [
108
+ {
109
+ objectPath,
110
+ errorMessage: `val1${objectPath} is a primitive value and val2${objectPath} is not`,
111
+ val1,
112
+ val2,
113
+ },
114
+ ];
115
+ }
116
+ return diffPrimitiveValue(val1, val2, objectPath);
117
+ }
118
+
119
+ const isArray = Array.isArray(val1);
120
+ let errorMessage: string | undefined;
121
+ if (isArray && !Array.isArray(val2)) {
122
+ errorMessage = `val1${objectPath} is an array and val2${objectPath} is not`;
123
+ } else if (typeof val1 === "object" && typeof val2 !== "object") {
124
+ errorMessage = `val1${objectPath} is a nested object and val2${objectPath} is not`;
125
+ }
126
+ if (errorMessage) {
127
+ return [
128
+ {
129
+ objectPath,
130
+ errorMessage,
131
+ val1,
132
+ val2,
133
+ },
134
+ ];
135
+ }
136
+
137
+ const diffs: Diff[] = [];
138
+ for (const [index, value] of Object.entries(val1)) {
139
+ if (!isDiffable(value)) {
140
+ diffs.push({objectPath, val1, val2, errorMessage: `val1${objectPath} is not Diffable`});
141
+ continue;
142
+ }
143
+ const value2 = (val2 as DiffableCollection)[index];
144
+ if (!isDiffable(value2)) {
145
+ diffs.push({objectPath, val1, val2, errorMessage: `val2${objectPath} is not Diffable`});
146
+ continue;
147
+ }
148
+ const innerPath = isArray ? `${objectPath}[${index}]` : `${objectPath}.${index}`;
149
+ diffs.push(...getDiffs(value, value2, innerPath));
150
+ }
151
+ return diffs;
152
+ }
153
+
154
+ /**
155
+ * Find the different values on complex, nested objects. Outputs the path through the object to
156
+ * each value that does not match from val1 and val2. Optionally can output the values that differ.
157
+ *
158
+ * For objects that differ greatly, can write to a file instead of the terminal for analysis
159
+ *
160
+ * ## Example
161
+ * ```ts
162
+ * const obj1 = {
163
+ * key1: {
164
+ * key2: [
165
+ * { key3: 1 },
166
+ * { key3: new Uint8Array([1, 2, 3]) }
167
+ * ]
168
+ * },
169
+ * key4: new Uint32Array([1, 2, 3]),
170
+ * key5: 362436
171
+ * };
172
+ *
173
+ * const obj2 = {
174
+ * key1: {
175
+ * key2: [
176
+ * { key3: 1 },
177
+ * { key3: new Uint8Array([1, 2, 4]) }
178
+ * ]
179
+ * },
180
+ * key4: new Uint32Array([1, 2, 4])
181
+ * key5: true
182
+ * };
183
+ *
184
+ * diffObjects(obj1, obj2, true);
185
+ *
186
+ *
187
+ * ```
188
+ *
189
+ * ## Output
190
+ * ```sh
191
+ * val.key1.key2[1].key3
192
+ * - 0x010203
193
+ * - 0x010204
194
+ * val.key4[2]
195
+ * - 0x00000003
196
+ * - 0x00000004
197
+ * val.key5
198
+ * val1.key5 is not the same type as val2.key5
199
+ * - 362436
200
+ * - true
201
+ * ```
202
+ */
203
+ export function diff(val1: unknown, val2: unknown, outputValues = false, filename?: string): void {
204
+ if (!isDiffable(val1)) {
205
+ // biome-ignore lint/suspicious/noConsole: We need to log to the console
206
+ console.log("val1 is not Diffable");
207
+ return;
208
+ }
209
+ if (!isDiffable(val2)) {
210
+ // biome-ignore lint/suspicious/noConsole: We need to log to the console
211
+ console.log("val2 is not Diffable");
212
+ return;
213
+ }
214
+ const diffs = getDiffs(val1, val2, "");
215
+ let output = "";
216
+ if (diffs.length) {
217
+ for (const diff of diffs) {
218
+ let diffOutput = `value${diff.objectPath}`;
219
+ if (diff.errorMessage) {
220
+ diffOutput += `\n ${diff.errorMessage}`;
221
+ }
222
+ if (outputValues) {
223
+ diffOutput += `\n - ${diff.val1.toString()}\n - ${diff.val2.toString()}\n`;
224
+ }
225
+ output += `${diffOutput}\n`;
226
+ }
227
+ if (filename) {
228
+ fs.writeFileSync(filename, output);
229
+ } else {
230
+ // biome-ignore lint/suspicious/noConsole: We need to log to the console
231
+ console.log(output);
232
+ }
233
+ }
234
+ }
package/src/err.ts ADDED
@@ -0,0 +1,105 @@
1
+ const symErr = Symbol("err");
2
+
3
+ export type Err<T> = {[symErr]: true; error: T};
4
+
5
+ export type Result<T, E> = T | Err<E>;
6
+
7
+ export function Err<T>(error: T): Err<T> {
8
+ return {[symErr]: true, error};
9
+ }
10
+
11
+ /**
12
+ * Typeguard for Err<T>. Allows the pattern
13
+ * ```ts
14
+ * function getNumSquare(): Result<number, Error> {
15
+ * const value = getNum();
16
+ * if (isErr(value)) {
17
+ * return value; // return as error
18
+ * }
19
+ * return value ** 2;
20
+ * }
21
+ * function getNum(): Result<number, Error>
22
+ * ```
23
+ * Since the non-error is not wrapped, it uses a symbol to prevent collisions
24
+ */
25
+ export function isErr<T, E>(result: Result<T, E>): result is Err<E> {
26
+ return result !== null && typeof result === "object" && (result as Err<E>)[symErr] === true;
27
+ }
28
+
29
+ /**
30
+ * Given an array of results, run a function only on an array of ok results.
31
+ * Returns a new array of results with same length as `results` where the ok
32
+ * value may be Err or T2.
33
+ */
34
+ export function mapOkResults<T1, T2, E>(
35
+ results: Result<T1, E>[],
36
+ fn: (items: T1[]) => Result<T2, E>[]
37
+ ): Result<T2, E>[] {
38
+ const oks: T1[] = [];
39
+
40
+ for (let i = 0; i < results.length; i++) {
41
+ const result = results[i];
42
+
43
+ if (!isErr(result)) {
44
+ oks.push(result);
45
+ }
46
+ }
47
+
48
+ const outOksResults = fn(oks);
49
+ if (outOksResults.length !== oks.length) {
50
+ throw Error("mapOkResults fn must return same length");
51
+ }
52
+
53
+ const outResults: Result<T2, E>[] = [];
54
+
55
+ for (let i = 0, j = 0; i < results.length; i++) {
56
+ const result = results[i];
57
+
58
+ if (isErr(result)) {
59
+ outResults.push(result);
60
+ } else {
61
+ outResults.push(outOksResults[j]);
62
+ j++;
63
+ }
64
+ }
65
+
66
+ return outResults;
67
+ }
68
+
69
+ /**
70
+ * See {@link mapOkResults} but `fn` is async
71
+ */
72
+ export async function mapOkResultsAsync<T1, T2, E>(
73
+ results: Result<T1, E>[],
74
+ fn: (items: T1[]) => Promise<Result<T2, E>[]>
75
+ ): Promise<Result<T2, E>[]> {
76
+ const oks: T1[] = [];
77
+
78
+ for (let i = 0; i < results.length; i++) {
79
+ const result = results[i];
80
+
81
+ if (!isErr(result)) {
82
+ oks.push(result);
83
+ }
84
+ }
85
+
86
+ const outOksResults = await fn(oks);
87
+ if (outOksResults.length !== oks.length) {
88
+ throw Error("mapOkResults fn must return same length");
89
+ }
90
+
91
+ const outResults: Result<T2, E>[] = [];
92
+
93
+ for (let i = 0, j = 0; i < results.length; i++) {
94
+ const result = results[i];
95
+
96
+ if (isErr(result)) {
97
+ outResults.push(result);
98
+ } else {
99
+ outResults.push(outOksResults[j]);
100
+ j++;
101
+ }
102
+ }
103
+
104
+ return outResults;
105
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,73 @@
1
+ export type LodestarErrorMetaData = Record<string, string | number | null>;
2
+ export type LodestarErrorObject = {
3
+ message: string;
4
+ stack: string;
5
+ className: string;
6
+ type: LodestarErrorMetaData;
7
+ };
8
+ export type FromObjectFn = (object: LodestarErrorObject) => Error;
9
+
10
+ /**
11
+ * Generic Lodestar error with attached metadata
12
+ */
13
+ export class LodestarError<T extends {code: string}> extends Error {
14
+ type: T;
15
+ constructor(type: T, message?: string, stack?: string) {
16
+ super(message || type.code);
17
+ this.type = type;
18
+ if (stack) this.stack = stack;
19
+ }
20
+
21
+ getMetadata(): LodestarErrorMetaData {
22
+ return this.type;
23
+ }
24
+
25
+ /**
26
+ * Get the metadata and the stacktrace for the error.
27
+ */
28
+ toObject(): LodestarErrorObject {
29
+ return {
30
+ type: this.getMetadata(),
31
+ message: this.message ?? "",
32
+ stack: this.stack ?? "",
33
+ className: this.constructor.name,
34
+ };
35
+ }
36
+
37
+ static fromObject(obj: LodestarErrorObject): LodestarError<{code: string}> {
38
+ return new LodestarError(obj.type as {code: string}, obj.message, obj.stack);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Throw this error when an upstream abort signal aborts
44
+ */
45
+ export class ErrorAborted extends Error {
46
+ constructor(message?: string) {
47
+ super(`Aborted ${message || ""}`);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Throw this error when wrapped timeout expires
53
+ */
54
+ export class TimeoutError extends Error {
55
+ constructor(message?: string) {
56
+ super(`Timeout ${message || ""}`);
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Returns true if arg `e` is an instance of `ErrorAborted`
62
+ */
63
+ export function isErrorAborted(e: unknown): e is ErrorAborted {
64
+ return e instanceof ErrorAborted;
65
+ }
66
+
67
+ /**
68
+ * Extend an existing error by appending a string to its `e.message`
69
+ */
70
+ export function extendError(e: Error, appendMessage: string): Error {
71
+ e.message = `${e.message} - ${appendMessage}`;
72
+ return e;
73
+ }
@@ -0,0 +1,12 @@
1
+ export const ETH_TO_GWEI = BigInt(10 ** 9);
2
+ export const GWEI_TO_WEI = BigInt(10 ** 9);
3
+ export const ETH_TO_WEI = ETH_TO_GWEI * GWEI_TO_WEI;
4
+
5
+ type EthNumeric = bigint;
6
+
7
+ /**
8
+ * Convert gwei to wei.
9
+ */
10
+ export function gweiToWei(gwei: EthNumeric): EthNumeric {
11
+ return gwei * GWEI_TO_WEI;
12
+ }
package/src/fetch.ts ADDED
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Native fetch with transparent and consistent error handling
3
+ *
4
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/fetch)
5
+ */
6
+ async function wrappedFetch(url: string | URL, init?: RequestInit): Promise<Response> {
7
+ try {
8
+ // This function wraps global `fetch` which should only be directly called here
9
+ // biome-ignore lint/style/noRestrictedGlobals: We need to use global `fetch`
10
+ return await fetch(url, init);
11
+ } catch (e) {
12
+ throw new FetchError(url, e);
13
+ }
14
+ }
15
+
16
+ export {wrappedFetch as fetch};
17
+
18
+ export function isFetchError(e: unknown): e is FetchError {
19
+ return e instanceof FetchError;
20
+ }
21
+
22
+ export type FetchErrorType = "failed" | "input" | "aborted" | "timeout" | "unknown";
23
+
24
+ type FetchErrorCause = NativeFetchFailedError["cause"] | NativeFetchInputError["cause"];
25
+
26
+ export class FetchError extends Error {
27
+ type: FetchErrorType;
28
+ code: string;
29
+ cause?: FetchErrorCause;
30
+
31
+ constructor(url: string | URL, e: unknown) {
32
+ if (isNativeFetchFailedError(e)) {
33
+ super(`Request to ${url.toString()} failed, reason: ${e.cause.message}`);
34
+ this.type = "failed";
35
+ this.code = e.cause.code || "ERR_FETCH_FAILED";
36
+ this.cause = e.cause;
37
+ } else if (isNativeFetchInputError(e)) {
38
+ // For input errors the e.message is more detailed
39
+ super(e.message);
40
+ this.type = "input";
41
+ this.code = e.cause.code || "ERR_INVALID_INPUT";
42
+ this.cause = e.cause;
43
+ } else if (isNativeFetchAbortError(e)) {
44
+ super(`Request to ${url.toString()} was aborted`);
45
+ this.type = "aborted";
46
+ this.code = "ERR_ABORTED";
47
+ } else if (isNativeFetchTimeoutError(e)) {
48
+ super(`Request to ${url.toString()} timed out`);
49
+ this.type = "timeout";
50
+ this.code = "ERR_TIMEOUT";
51
+ }
52
+ // There are few incompatibilities related to `fetch` with NodeJS
53
+ // So we have to wrap those cases here explicitly
54
+ // https://github.com/oven-sh/bun/issues/20486
55
+ else if (isBunError(e) && e.code === "ConnectionRefused") {
56
+ super("TypeError: fetch failed");
57
+ this.type = "failed";
58
+ this.code = "ENOTFOUND";
59
+ this.cause = e as unknown as FetchErrorCause;
60
+ } else if (isBunError(e) && e.code === "ECONNRESET") {
61
+ super("TypeError: fetch failed");
62
+ this.type = "failed";
63
+ this.code = "UND_ERR_SOCKET";
64
+ this.cause = e as unknown as FetchErrorCause;
65
+ } else if (isBun && (e as Error).message.includes("protocol must be")) {
66
+ super("fetch failed");
67
+ this.type = "failed";
68
+ this.code = "ERR_FETCH_FAILED";
69
+ this.cause = e as unknown as FetchErrorCause;
70
+ } else if ((e as Error).message.includes("URL is invalid")) {
71
+ super("Failed to parse URL from invalid-url");
72
+ this.type = "input";
73
+ this.code = "ERR_INVALID_URL";
74
+ this.cause = e as unknown as FetchErrorCause;
75
+ } else {
76
+ super((e as Error).message);
77
+ this.type = "unknown";
78
+ this.code = "ERR_UNKNOWN";
79
+ }
80
+ this.name = this.constructor.name;
81
+ }
82
+ }
83
+
84
+ type NativeFetchError = TypeError & {
85
+ cause: Error & {
86
+ code?: string;
87
+ };
88
+ };
89
+
90
+ /**
91
+ * ```
92
+ * TypeError: fetch failed
93
+ * cause: Error: connect ECONNREFUSED 127.0.0.1:9596
94
+ * errno: -111,
95
+ * code: 'ECONNREFUSED',
96
+ * syscall: 'connect',
97
+ * address: '127.0.0.1',
98
+ * port: 9596
99
+ * ---------------------------
100
+ * TypeError: fetch failed
101
+ * cause: Error: getaddrinfo ENOTFOUND non-existent-domain
102
+ * errno: -3008,
103
+ * code: 'ENOTFOUND',
104
+ * syscall: 'getaddrinfo',
105
+ * hostname: 'non-existent-domain'
106
+ * ---------------------------
107
+ * TypeError: fetch failed
108
+ * cause: SocketError: other side closed
109
+ * code: 'UND_ERR_SOCKET',
110
+ * socket: {}
111
+ * ---------------------------
112
+ * TypeError: fetch failed
113
+ * cause: Error: unknown scheme
114
+ * [cause]: undefined
115
+ * ```
116
+ */
117
+ type NativeFetchFailedError = NativeFetchError & {
118
+ message: "fetch failed";
119
+ cause: {
120
+ errno?: string;
121
+ syscall?: string;
122
+ address?: string;
123
+ port?: string;
124
+ hostname?: string;
125
+ socket?: object;
126
+ [prop: string]: unknown;
127
+ };
128
+ };
129
+
130
+ /**
131
+ * ```
132
+ * TypeError: Failed to parse URL from invalid-url
133
+ * [cause]: TypeError [ERR_INVALID_URL]: Invalid URL
134
+ * input: 'invalid-url',
135
+ * code: 'ERR_INVALID_URL'
136
+ * ```
137
+ */
138
+ type NativeFetchInputError = NativeFetchError & {
139
+ cause: {
140
+ input: unknown;
141
+ };
142
+ };
143
+
144
+ /**
145
+ * ```
146
+ * DOMException [AbortError]: This operation was aborted
147
+ * ```
148
+ */
149
+ type NativeFetchAbortError = DOMException & {
150
+ name: "AbortError";
151
+ };
152
+
153
+ /**
154
+ * ```
155
+ * DOMException [TimeoutError]: The operation was aborted due to timeout
156
+ * ```
157
+ */
158
+ type NativeFetchTimeoutError = DOMException & {
159
+ name: "TimeoutError";
160
+ };
161
+
162
+ function isNativeFetchError(e: unknown): e is NativeFetchError {
163
+ return e instanceof TypeError && (e as NativeFetchError).cause instanceof Error;
164
+ }
165
+
166
+ function isNativeFetchFailedError(e: unknown): e is NativeFetchFailedError {
167
+ return isNativeFetchError(e) && (e as NativeFetchFailedError).message === "fetch failed";
168
+ }
169
+
170
+ function isNativeFetchInputError(e: unknown): e is NativeFetchInputError {
171
+ return isNativeFetchError(e) && (e as NativeFetchInputError).cause.input !== undefined;
172
+ }
173
+
174
+ function isNativeFetchAbortError(e: unknown): e is NativeFetchAbortError {
175
+ return e instanceof DOMException && (e as NativeFetchAbortError).name === "AbortError";
176
+ }
177
+
178
+ function isNativeFetchTimeoutError(e: unknown): e is NativeFetchTimeoutError {
179
+ return e instanceof DOMException && (e as NativeFetchTimeoutError).name === "TimeoutError";
180
+ }
181
+
182
+ const isBun = "bun" in process.versions;
183
+
184
+ type BunError = {code: string; path: string; errno: number; message: string};
185
+
186
+ function isBunError(e: unknown): e is BunError {
187
+ return isBun && typeof e === "object" && e !== null && "code" in e && "path" in e && "errno" in e && "message" in e;
188
+ }