@layerzerolabs/common-error-utils 0.2.8

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.
@@ -0,0 +1,18 @@
1
+
2
+ > @layerzerolabs/common-error-utils@0.0.0 build /home/runner/work/monorepo-internal/monorepo-internal/packages/common/common-error-utils
3
+ > tsup
4
+
5
+ CLI Building entry: src/index.ts
6
+ CLI Using tsconfig: tsconfig.json
7
+ CLI tsup v8.5.1
8
+ CLI Using tsup config: /home/runner/work/monorepo-internal/monorepo-internal/packages/common/common-error-utils/tsup.config.ts
9
+ CLI Target: ES2023
10
+ CLI Cleaning output folder
11
+ CJS Build start
12
+ ESM Build start
13
+ ESM dist/index.js 4.54 KB
14
+ ESM dist/index.js.map 9.77 KB
15
+ ESM ⚡️ Build success in 111ms
16
+ CJS dist/index.cjs 4.80 KB
17
+ CJS dist/index.cjs.map 9.77 KB
18
+ CJS ⚡️ Build success in 111ms
@@ -0,0 +1,8 @@
1
+
2
+ > @layerzerolabs/common-error-utils@0.0.0 lint /home/runner/work/monorepo-internal/monorepo-internal/packages/common/common-error-utils
3
+ > eslint . --max-warnings 0 || (eslint . --fix --max-warnings 0 && false)
4
+
5
+ (node:26639) [MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type of file:///home/runner/work/monorepo-internal/monorepo-internal/eslint.config.js?mtime=1766517510509 is not specified and it doesn't parse as CommonJS.
6
+ Reparsing as ES module because module syntax was detected. This incurs a performance overhead.
7
+ To eliminate this warning, add "type": "module" to /home/runner/work/monorepo-internal/monorepo-internal/package.json.
8
+ (Use `node --trace-warnings ...` to show where the warning was created)
@@ -0,0 +1,32 @@
1
+
2
+ > @layerzerolabs/common-error-utils@0.0.0 test /home/runner/work/monorepo-internal/monorepo-internal/packages/common/common-error-utils
3
+ > vitest --run --pass-with-no-tests --typecheck
4
+
5
+ Testing types with tsc and vue-tsc is an experimental feature.
6
+ Breaking changes might not follow SemVer, please pin Vitest's version when using it.
7
+
8
+  RUN  v3.2.4 /home/runner/work/monorepo-internal/monorepo-internal/packages/common/common-error-utils
9
+
10
+ stdout | tests/error.test.ts > SerializableError > wraps simple error
11
+ SomeError constructor called {
12
+ cause: Error: Some error 2
13
+ at /home/runner/work/monorepo-internal/monorepo-internal/packages/common/common-error-utils/tests/error.test.ts:33:21
14
+ at file:///home/runner/work/monorepo-internal/monorepo-internal/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:155:11
15
+ at file:///home/runner/work/monorepo-internal/monorepo-internal/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:752:26
16
+ at file:///home/runner/work/monorepo-internal/monorepo-internal/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:1897:20
17
+ at new Promise (<anonymous>)
18
+ at runWithTimeout (file:///home/runner/work/monorepo-internal/monorepo-internal/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:1863:10)
19
+ at runTest (file:///home/runner/work/monorepo-internal/monorepo-internal/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:1574:12)
20
+  at processTicksAndRejections (node:internal/process/task_queues:105:5)
21
+ at runSuite (file:///home/runner/work/monorepo-internal/monorepo-internal/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:1729:8)
22
+ at runSuite (file:///home/runner/work/monorepo-internal/monorepo-internal/node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js:1729:8)
23
+ }
24
+
25
+ ✓ tests/error.test.ts (3 tests) 8ms
26
+
27
+  Test Files  1 passed (1)
28
+  Tests  3 passed (3)
29
+ Type Errors  no errors
30
+  Start at  19:23:31
31
+  Duration  334ms (transform 44ms, setup 0ms, collect 40ms, tests 8ms, environment 0ms, prepare 73ms)
32
+
package/dist/index.cjs ADDED
@@ -0,0 +1,174 @@
1
+ 'use strict';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
+
6
+ // src/index.ts
7
+ var extractMessageFromJsonRpcError = /* @__PURE__ */ __name((err) => {
8
+ try {
9
+ if (typeof err.body === "object" && err.body.message) {
10
+ return err.body.message;
11
+ }
12
+ const parsedBody = JSON.parse(err.body);
13
+ return parsedBody?.error?.message;
14
+ } catch {
15
+ return "unknown";
16
+ }
17
+ }, "extractMessageFromJsonRpcError");
18
+ function convertErrorToObject(err) {
19
+ return JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err)));
20
+ }
21
+ __name(convertErrorToObject, "convertErrorToObject");
22
+ function normalizeError(err) {
23
+ const error = convertErrorToObject(err);
24
+ return {
25
+ // Normal Error properties
26
+ ...error.name ? {
27
+ name: error.name
28
+ } : {},
29
+ ...error.message ? {
30
+ message: error.message
31
+ } : {},
32
+ ...error.stack ? {
33
+ stack: error.stack
34
+ } : {},
35
+ // Rpc properties
36
+ ...error.reason ? {
37
+ reason: error.reason
38
+ } : {},
39
+ ...error.code ? {
40
+ code: error.code
41
+ } : {},
42
+ ...error.event ? {
43
+ event: error.event
44
+ } : {},
45
+ ...error.body ? {
46
+ body: extractMessageFromJsonRpcError(error)
47
+ } : {}
48
+ };
49
+ }
50
+ __name(normalizeError, "normalizeError");
51
+ var SerializableError = class extends Error {
52
+ static {
53
+ __name(this, "SerializableError");
54
+ }
55
+ details;
56
+ /*
57
+ * The instance of the error that was wrapped, if any.
58
+ * Creates a linked list of error objects.
59
+ * Only exists if the error hasn't been serialized and deserialized.
60
+ */
61
+ cause;
62
+ constructor(message, options) {
63
+ super(message, options);
64
+ this.cause = options?.cause;
65
+ this.name = this.constructor.name;
66
+ this.details = [
67
+ this.constructor.name,
68
+ "SerializableError"
69
+ ];
70
+ }
71
+ /*
72
+ * Checks if the error is an instance of the current class or a subclass. Returns the error if it is.
73
+ * We can't type the error as more than SerializableError because it could have been serialized and deserialized,
74
+ * which could make it lose extra fields.
75
+ */
76
+ static inStackOf(error) {
77
+ if (error?.details?.includes(this.name)) {
78
+ return error;
79
+ } else if (error?.cause?.details?.includes(this.name)) {
80
+ return error.cause;
81
+ }
82
+ return void 0;
83
+ }
84
+ // We could limit this to only wrap serializable errors, but that could limit the flexibility of the error system.
85
+ static wrap(error, ...args) {
86
+ const wrappedError = new this(...args, {
87
+ cause: error
88
+ });
89
+ wrappedError.details = error?.details ? [
90
+ wrappedError.name,
91
+ ...error.details
92
+ ] : [
93
+ wrappedError.name,
94
+ "SerializableError",
95
+ error?.name ?? "UnknownError"
96
+ ];
97
+ wrappedError.message = `${wrappedError.message} > ${error?.message ?? String(error)}`;
98
+ return wrappedError;
99
+ }
100
+ };
101
+ var NonRetryableError = class extends SerializableError {
102
+ static {
103
+ __name(this, "NonRetryableError");
104
+ }
105
+ constructor(message, options) {
106
+ super(message, options);
107
+ }
108
+ };
109
+ var NotFoundError = class extends SerializableError {
110
+ static {
111
+ __name(this, "NotFoundError");
112
+ }
113
+ constructor(message, options) {
114
+ super(message ? `Not found: ${message}` : "Not found", options);
115
+ }
116
+ };
117
+ var ProviderError = class _ProviderError extends SerializableError {
118
+ static {
119
+ __name(this, "ProviderError");
120
+ }
121
+ constructor(providerUri, options) {
122
+ super(`Provider error at host '${_ProviderError.parseHost(providerUri)}'`, options);
123
+ }
124
+ static parseHost(providerUri) {
125
+ try {
126
+ const url = new URL(providerUri);
127
+ return url.host;
128
+ } catch {
129
+ return "UNKNOWN_HOST";
130
+ }
131
+ }
132
+ };
133
+ var NonEmittableError = class extends SerializableError {
134
+ static {
135
+ __name(this, "NonEmittableError");
136
+ }
137
+ constructor(message, options) {
138
+ super(message, options);
139
+ this.name = "NonEmittableError";
140
+ }
141
+ };
142
+ var QuorumNotAchievedYet = class extends SerializableError {
143
+ static {
144
+ __name(this, "QuorumNotAchievedYet");
145
+ }
146
+ constructor(options) {
147
+ super("The quorum was not achieved yet", options);
148
+ }
149
+ };
150
+ var MultiError = class extends Error {
151
+ static {
152
+ __name(this, "MultiError");
153
+ }
154
+ errs;
155
+ constructor(errs) {
156
+ super(errs.map((err) => err.message).join(", ")), this.errs = errs;
157
+ }
158
+ };
159
+ var throwError = /* @__PURE__ */ __name((message, error) => {
160
+ throw error?.(message) ?? new Error(message);
161
+ }, "throwError");
162
+
163
+ exports.MultiError = MultiError;
164
+ exports.NonEmittableError = NonEmittableError;
165
+ exports.NonRetryableError = NonRetryableError;
166
+ exports.NotFoundError = NotFoundError;
167
+ exports.ProviderError = ProviderError;
168
+ exports.QuorumNotAchievedYet = QuorumNotAchievedYet;
169
+ exports.SerializableError = SerializableError;
170
+ exports.convertErrorToObject = convertErrorToObject;
171
+ exports.normalizeError = normalizeError;
172
+ exports.throwError = throwError;
173
+ //# sourceMappingURL=index.cjs.map
174
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["extractMessageFromJsonRpcError","err","body","message","parsedBody","JSON","parse","error","convertErrorToObject","stringify","Object","getOwnPropertyNames","normalizeError","name","stack","reason","code","event","SerializableError","Error","details","cause","options","inStackOf","includes","undefined","wrap","args","wrappedError","String","NonRetryableError","NotFoundError","ProviderError","providerUri","parseHost","url","URL","host","NonEmittableError","QuorumNotAchievedYet","MultiError","errs","map","join","throwError"],"mappings":"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","file":"index.cjs","sourcesContent":["const extractMessageFromJsonRpcError = (err: any): string => {\n try {\n if (typeof err.body === 'object' && err.body.message) {\n return err.body.message;\n }\n const parsedBody = JSON.parse(err.body);\n return parsedBody?.error?.message;\n } catch {\n return 'unknown';\n }\n};\n\nexport function convertErrorToObject(err: any): any {\n return JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err)));\n}\n\nexport function normalizeError(err: any) {\n const error = convertErrorToObject(err);\n return {\n // Normal Error properties\n ...(error.name ? { name: error.name } : {}),\n ...(error.message ? { message: error.message } : {}),\n ...(error.stack ? { stack: error.stack } : {}),\n // Rpc properties\n ...(error.reason ? { reason: error.reason } : {}),\n ...(error.code ? { code: error.code } : {}),\n ...(error.event ? { event: error.event } : {}),\n ...(error.body ? { body: extractMessageFromJsonRpcError(error) } : {}),\n };\n}\n\n// Removes the last argument if it is an ErrorOptions\ntype RemoveErrorOptions<T extends any[]> = T extends [...infer U, ErrorOptions?] ? U : never;\n\n/**\n * Base class for all serializable errors.\n * This class is designed to be extended by other error classes.\n * It provides a way to wrap errors and a way to check if an error is in the stack of a specific error class.\n * All errors that extend this class *must* have error options as the last argument in their constructor.\n */\nexport abstract class SerializableError extends Error {\n details: string[];\n /*\n * The instance of the error that was wrapped, if any.\n * Creates a linked list of error objects.\n * Only exists if the error hasn't been serialized and deserialized.\n */\n cause: unknown;\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n // for some reason, we need to set the cause directly on the instance, even after calling super\n this.cause = options?.cause;\n this.name = this.constructor.name;\n this.details = [this.constructor.name, 'SerializableError'];\n }\n\n /*\n * Checks if the error is an instance of the current class or a subclass. Returns the error if it is.\n * We can't type the error as more than SerializableError because it could have been serialized and deserialized,\n * which could make it lose extra fields.\n */\n static inStackOf<T extends abstract new (...args: any) => any>(\n this: T,\n error: any,\n ): SerializableError | undefined {\n if (error?.details?.includes(this.name)) {\n return error as SerializableError;\n } else if (error?.cause?.details?.includes(this.name)) {\n return error.cause as SerializableError;\n }\n return undefined;\n }\n\n // We could limit this to only wrap serializable errors, but that could limit the flexibility of the error system.\n static wrap<T extends new (...args: any) => SerializableError>(\n this: T,\n error: any,\n // Remove the optional error arguments\n ...args: RemoveErrorOptions<ConstructorParameters<T>>\n ): InstanceType<T> {\n const wrappedError = new this(...args, { cause: error });\n\n wrappedError.details = error?.details\n ? [wrappedError.name, ...error.details]\n : [wrappedError.name, 'SerializableError', error?.name ?? 'UnknownError'];\n\n wrappedError.message = `${wrappedError.message} > ${error?.message ?? String(error)}`;\n\n return wrappedError as InstanceType<T>;\n }\n}\n\nexport class NonRetryableError extends SerializableError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\nexport class NotFoundError extends SerializableError {\n constructor(message?: string, options?: ErrorOptions) {\n super(message ? `Not found: ${message}` : 'Not found', options);\n }\n}\n\n// TODO: extend this for chain specific providers\nexport class ProviderError extends SerializableError {\n constructor(providerUri: string, options?: ErrorOptions) {\n super(`Provider error at host '${ProviderError.parseHost(providerUri)}'`, options);\n }\n\n private static parseHost(providerUri: string): string {\n try {\n const url = new URL(providerUri);\n return url.host;\n } catch {\n return 'UNKNOWN_HOST';\n }\n }\n}\n\nexport class NonEmittableError extends SerializableError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'NonEmittableError';\n }\n}\n\nexport class QuorumNotAchievedYet extends SerializableError {\n constructor(options?: ErrorOptions) {\n super('The quorum was not achieved yet', options);\n }\n}\n\nexport class MultiError extends Error {\n constructor(public readonly errs: any[]) {\n super(errs.map((err) => err.message).join(', '));\n }\n}\n\nexport const throwError = <Err extends Error>(\n message: string,\n error?: (message: string) => Err,\n): never => {\n throw error?.(message) ?? new Error(message);\n};\n"]}
@@ -0,0 +1,47 @@
1
+ export declare function convertErrorToObject(err: any): any;
2
+ export declare function normalizeError(err: any): {
3
+ body?: string | undefined;
4
+ event?: any;
5
+ code?: any;
6
+ reason?: any;
7
+ stack?: any;
8
+ message?: any;
9
+ name?: any;
10
+ };
11
+ type RemoveErrorOptions<T extends any[]> = T extends [...infer U, ErrorOptions?] ? U : never;
12
+ /**
13
+ * Base class for all serializable errors.
14
+ * This class is designed to be extended by other error classes.
15
+ * It provides a way to wrap errors and a way to check if an error is in the stack of a specific error class.
16
+ * All errors that extend this class *must* have error options as the last argument in their constructor.
17
+ */
18
+ export declare abstract class SerializableError extends Error {
19
+ details: string[];
20
+ cause: unknown;
21
+ constructor(message: string, options?: ErrorOptions);
22
+ static inStackOf<T extends abstract new (...args: any) => any>(this: T, error: any): SerializableError | undefined;
23
+ static wrap<T extends new (...args: any) => SerializableError>(this: T, error: any, ...args: RemoveErrorOptions<ConstructorParameters<T>>): InstanceType<T>;
24
+ }
25
+ export declare class NonRetryableError extends SerializableError {
26
+ constructor(message: string, options?: ErrorOptions);
27
+ }
28
+ export declare class NotFoundError extends SerializableError {
29
+ constructor(message?: string, options?: ErrorOptions);
30
+ }
31
+ export declare class ProviderError extends SerializableError {
32
+ constructor(providerUri: string, options?: ErrorOptions);
33
+ private static parseHost;
34
+ }
35
+ export declare class NonEmittableError extends SerializableError {
36
+ constructor(message: string, options?: ErrorOptions);
37
+ }
38
+ export declare class QuorumNotAchievedYet extends SerializableError {
39
+ constructor(options?: ErrorOptions);
40
+ }
41
+ export declare class MultiError extends Error {
42
+ readonly errs: any[];
43
+ constructor(errs: any[]);
44
+ }
45
+ export declare const throwError: <Err extends Error>(message: string, error?: (message: string) => Err) => never;
46
+ export {};
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAElD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG;;;;;;;;EAatC;AAGD,KAAK,kBAAkB,CAAC,CAAC,SAAS,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE7F;;;;;GAKG;AACH,8BAAsB,iBAAkB,SAAQ,KAAK;IACjD,OAAO,EAAE,MAAM,EAAE,CAAC;IAMlB,KAAK,EAAE,OAAO,CAAC;gBACH,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;IAanD,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,EACzD,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,GAAG,GACX,iBAAiB,GAAG,SAAS;IAUhC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,KAAK,iBAAiB,EACzD,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,GAAG,EAEV,GAAG,IAAI,EAAE,kBAAkB,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,GACtD,YAAY,CAAC,CAAC,CAAC;CAWrB;AAED,qBAAa,iBAAkB,SAAQ,iBAAiB;gBACxC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAGtD;AAED,qBAAa,aAAc,SAAQ,iBAAiB;gBACpC,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAGvD;AAGD,qBAAa,aAAc,SAAQ,iBAAiB;gBACpC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;IAIvD,OAAO,CAAC,MAAM,CAAC,SAAS;CAQ3B;AAED,qBAAa,iBAAkB,SAAQ,iBAAiB;gBACxC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAItD;AAED,qBAAa,oBAAqB,SAAQ,iBAAiB;gBAC3C,OAAO,CAAC,EAAE,YAAY;CAGrC;AAED,qBAAa,UAAW,SAAQ,KAAK;aACL,IAAI,EAAE,GAAG,EAAE;gBAAX,IAAI,EAAE,GAAG,EAAE;CAG1C;AAED,eAAO,MAAM,UAAU,GAAI,GAAG,SAAS,KAAK,EACxC,SAAS,MAAM,EACf,QAAQ,CAAC,OAAO,EAAE,MAAM,KAAK,GAAG,KACjC,KAEF,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,163 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/index.ts
5
+ var extractMessageFromJsonRpcError = /* @__PURE__ */ __name((err) => {
6
+ try {
7
+ if (typeof err.body === "object" && err.body.message) {
8
+ return err.body.message;
9
+ }
10
+ const parsedBody = JSON.parse(err.body);
11
+ return parsedBody?.error?.message;
12
+ } catch {
13
+ return "unknown";
14
+ }
15
+ }, "extractMessageFromJsonRpcError");
16
+ function convertErrorToObject(err) {
17
+ return JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err)));
18
+ }
19
+ __name(convertErrorToObject, "convertErrorToObject");
20
+ function normalizeError(err) {
21
+ const error = convertErrorToObject(err);
22
+ return {
23
+ // Normal Error properties
24
+ ...error.name ? {
25
+ name: error.name
26
+ } : {},
27
+ ...error.message ? {
28
+ message: error.message
29
+ } : {},
30
+ ...error.stack ? {
31
+ stack: error.stack
32
+ } : {},
33
+ // Rpc properties
34
+ ...error.reason ? {
35
+ reason: error.reason
36
+ } : {},
37
+ ...error.code ? {
38
+ code: error.code
39
+ } : {},
40
+ ...error.event ? {
41
+ event: error.event
42
+ } : {},
43
+ ...error.body ? {
44
+ body: extractMessageFromJsonRpcError(error)
45
+ } : {}
46
+ };
47
+ }
48
+ __name(normalizeError, "normalizeError");
49
+ var SerializableError = class extends Error {
50
+ static {
51
+ __name(this, "SerializableError");
52
+ }
53
+ details;
54
+ /*
55
+ * The instance of the error that was wrapped, if any.
56
+ * Creates a linked list of error objects.
57
+ * Only exists if the error hasn't been serialized and deserialized.
58
+ */
59
+ cause;
60
+ constructor(message, options) {
61
+ super(message, options);
62
+ this.cause = options?.cause;
63
+ this.name = this.constructor.name;
64
+ this.details = [
65
+ this.constructor.name,
66
+ "SerializableError"
67
+ ];
68
+ }
69
+ /*
70
+ * Checks if the error is an instance of the current class or a subclass. Returns the error if it is.
71
+ * We can't type the error as more than SerializableError because it could have been serialized and deserialized,
72
+ * which could make it lose extra fields.
73
+ */
74
+ static inStackOf(error) {
75
+ if (error?.details?.includes(this.name)) {
76
+ return error;
77
+ } else if (error?.cause?.details?.includes(this.name)) {
78
+ return error.cause;
79
+ }
80
+ return void 0;
81
+ }
82
+ // We could limit this to only wrap serializable errors, but that could limit the flexibility of the error system.
83
+ static wrap(error, ...args) {
84
+ const wrappedError = new this(...args, {
85
+ cause: error
86
+ });
87
+ wrappedError.details = error?.details ? [
88
+ wrappedError.name,
89
+ ...error.details
90
+ ] : [
91
+ wrappedError.name,
92
+ "SerializableError",
93
+ error?.name ?? "UnknownError"
94
+ ];
95
+ wrappedError.message = `${wrappedError.message} > ${error?.message ?? String(error)}`;
96
+ return wrappedError;
97
+ }
98
+ };
99
+ var NonRetryableError = class extends SerializableError {
100
+ static {
101
+ __name(this, "NonRetryableError");
102
+ }
103
+ constructor(message, options) {
104
+ super(message, options);
105
+ }
106
+ };
107
+ var NotFoundError = class extends SerializableError {
108
+ static {
109
+ __name(this, "NotFoundError");
110
+ }
111
+ constructor(message, options) {
112
+ super(message ? `Not found: ${message}` : "Not found", options);
113
+ }
114
+ };
115
+ var ProviderError = class _ProviderError extends SerializableError {
116
+ static {
117
+ __name(this, "ProviderError");
118
+ }
119
+ constructor(providerUri, options) {
120
+ super(`Provider error at host '${_ProviderError.parseHost(providerUri)}'`, options);
121
+ }
122
+ static parseHost(providerUri) {
123
+ try {
124
+ const url = new URL(providerUri);
125
+ return url.host;
126
+ } catch {
127
+ return "UNKNOWN_HOST";
128
+ }
129
+ }
130
+ };
131
+ var NonEmittableError = class extends SerializableError {
132
+ static {
133
+ __name(this, "NonEmittableError");
134
+ }
135
+ constructor(message, options) {
136
+ super(message, options);
137
+ this.name = "NonEmittableError";
138
+ }
139
+ };
140
+ var QuorumNotAchievedYet = class extends SerializableError {
141
+ static {
142
+ __name(this, "QuorumNotAchievedYet");
143
+ }
144
+ constructor(options) {
145
+ super("The quorum was not achieved yet", options);
146
+ }
147
+ };
148
+ var MultiError = class extends Error {
149
+ static {
150
+ __name(this, "MultiError");
151
+ }
152
+ errs;
153
+ constructor(errs) {
154
+ super(errs.map((err) => err.message).join(", ")), this.errs = errs;
155
+ }
156
+ };
157
+ var throwError = /* @__PURE__ */ __name((message, error) => {
158
+ throw error?.(message) ?? new Error(message);
159
+ }, "throwError");
160
+
161
+ export { MultiError, NonEmittableError, NonRetryableError, NotFoundError, ProviderError, QuorumNotAchievedYet, SerializableError, convertErrorToObject, normalizeError, throwError };
162
+ //# sourceMappingURL=index.js.map
163
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["extractMessageFromJsonRpcError","err","body","message","parsedBody","JSON","parse","error","convertErrorToObject","stringify","Object","getOwnPropertyNames","normalizeError","name","stack","reason","code","event","SerializableError","Error","details","cause","options","inStackOf","includes","undefined","wrap","args","wrappedError","String","NonRetryableError","NotFoundError","ProviderError","providerUri","parseHost","url","URL","host","NonEmittableError","QuorumNotAchievedYet","MultiError","errs","map","join","throwError"],"mappings":"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","file":"index.js","sourcesContent":["const extractMessageFromJsonRpcError = (err: any): string => {\n try {\n if (typeof err.body === 'object' && err.body.message) {\n return err.body.message;\n }\n const parsedBody = JSON.parse(err.body);\n return parsedBody?.error?.message;\n } catch {\n return 'unknown';\n }\n};\n\nexport function convertErrorToObject(err: any): any {\n return JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err)));\n}\n\nexport function normalizeError(err: any) {\n const error = convertErrorToObject(err);\n return {\n // Normal Error properties\n ...(error.name ? { name: error.name } : {}),\n ...(error.message ? { message: error.message } : {}),\n ...(error.stack ? { stack: error.stack } : {}),\n // Rpc properties\n ...(error.reason ? { reason: error.reason } : {}),\n ...(error.code ? { code: error.code } : {}),\n ...(error.event ? { event: error.event } : {}),\n ...(error.body ? { body: extractMessageFromJsonRpcError(error) } : {}),\n };\n}\n\n// Removes the last argument if it is an ErrorOptions\ntype RemoveErrorOptions<T extends any[]> = T extends [...infer U, ErrorOptions?] ? U : never;\n\n/**\n * Base class for all serializable errors.\n * This class is designed to be extended by other error classes.\n * It provides a way to wrap errors and a way to check if an error is in the stack of a specific error class.\n * All errors that extend this class *must* have error options as the last argument in their constructor.\n */\nexport abstract class SerializableError extends Error {\n details: string[];\n /*\n * The instance of the error that was wrapped, if any.\n * Creates a linked list of error objects.\n * Only exists if the error hasn't been serialized and deserialized.\n */\n cause: unknown;\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n // for some reason, we need to set the cause directly on the instance, even after calling super\n this.cause = options?.cause;\n this.name = this.constructor.name;\n this.details = [this.constructor.name, 'SerializableError'];\n }\n\n /*\n * Checks if the error is an instance of the current class or a subclass. Returns the error if it is.\n * We can't type the error as more than SerializableError because it could have been serialized and deserialized,\n * which could make it lose extra fields.\n */\n static inStackOf<T extends abstract new (...args: any) => any>(\n this: T,\n error: any,\n ): SerializableError | undefined {\n if (error?.details?.includes(this.name)) {\n return error as SerializableError;\n } else if (error?.cause?.details?.includes(this.name)) {\n return error.cause as SerializableError;\n }\n return undefined;\n }\n\n // We could limit this to only wrap serializable errors, but that could limit the flexibility of the error system.\n static wrap<T extends new (...args: any) => SerializableError>(\n this: T,\n error: any,\n // Remove the optional error arguments\n ...args: RemoveErrorOptions<ConstructorParameters<T>>\n ): InstanceType<T> {\n const wrappedError = new this(...args, { cause: error });\n\n wrappedError.details = error?.details\n ? [wrappedError.name, ...error.details]\n : [wrappedError.name, 'SerializableError', error?.name ?? 'UnknownError'];\n\n wrappedError.message = `${wrappedError.message} > ${error?.message ?? String(error)}`;\n\n return wrappedError as InstanceType<T>;\n }\n}\n\nexport class NonRetryableError extends SerializableError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\nexport class NotFoundError extends SerializableError {\n constructor(message?: string, options?: ErrorOptions) {\n super(message ? `Not found: ${message}` : 'Not found', options);\n }\n}\n\n// TODO: extend this for chain specific providers\nexport class ProviderError extends SerializableError {\n constructor(providerUri: string, options?: ErrorOptions) {\n super(`Provider error at host '${ProviderError.parseHost(providerUri)}'`, options);\n }\n\n private static parseHost(providerUri: string): string {\n try {\n const url = new URL(providerUri);\n return url.host;\n } catch {\n return 'UNKNOWN_HOST';\n }\n }\n}\n\nexport class NonEmittableError extends SerializableError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'NonEmittableError';\n }\n}\n\nexport class QuorumNotAchievedYet extends SerializableError {\n constructor(options?: ErrorOptions) {\n super('The quorum was not achieved yet', options);\n }\n}\n\nexport class MultiError extends Error {\n constructor(public readonly errs: any[]) {\n super(errs.map((err) => err.message).join(', '));\n }\n}\n\nexport const throwError = <Err extends Error>(\n message: string,\n error?: (message: string) => Err,\n): never => {\n throw error?.(message) ?? new Error(message);\n};\n"]}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@layerzerolabs/common-error-utils",
3
+ "version": "0.2.8",
4
+ "private": false,
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ "types": "./dist/index.d.ts",
9
+ "require": "./dist/index.cjs",
10
+ "import": "./dist/index.js",
11
+ "default": "./dist/index.cjs"
12
+ },
13
+ "main": "./dist/index.cjs",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "devDependencies": {
17
+ "tsup": "^8.4.0",
18
+ "vitest": "^3.2.3",
19
+ "@layerzerolabs/tsup-configuration": "0.2.8",
20
+ "@layerzerolabs/typescript-configuration": "0.2.8"
21
+ },
22
+ "publishConfig": {
23
+ "access": "restricted",
24
+ "registry": "https://registry.npmjs.org/"
25
+ },
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "lint": "eslint . --max-warnings 0 || (eslint . --fix --max-warnings 0 && false)",
29
+ "test": "vitest --run --pass-with-no-tests --typecheck"
30
+ }
31
+ }
package/src/index.ts ADDED
@@ -0,0 +1,145 @@
1
+ const extractMessageFromJsonRpcError = (err: any): string => {
2
+ try {
3
+ if (typeof err.body === 'object' && err.body.message) {
4
+ return err.body.message;
5
+ }
6
+ const parsedBody = JSON.parse(err.body);
7
+ return parsedBody?.error?.message;
8
+ } catch {
9
+ return 'unknown';
10
+ }
11
+ };
12
+
13
+ export function convertErrorToObject(err: any): any {
14
+ return JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err)));
15
+ }
16
+
17
+ export function normalizeError(err: any) {
18
+ const error = convertErrorToObject(err);
19
+ return {
20
+ // Normal Error properties
21
+ ...(error.name ? { name: error.name } : {}),
22
+ ...(error.message ? { message: error.message } : {}),
23
+ ...(error.stack ? { stack: error.stack } : {}),
24
+ // Rpc properties
25
+ ...(error.reason ? { reason: error.reason } : {}),
26
+ ...(error.code ? { code: error.code } : {}),
27
+ ...(error.event ? { event: error.event } : {}),
28
+ ...(error.body ? { body: extractMessageFromJsonRpcError(error) } : {}),
29
+ };
30
+ }
31
+
32
+ // Removes the last argument if it is an ErrorOptions
33
+ type RemoveErrorOptions<T extends any[]> = T extends [...infer U, ErrorOptions?] ? U : never;
34
+
35
+ /**
36
+ * Base class for all serializable errors.
37
+ * This class is designed to be extended by other error classes.
38
+ * It provides a way to wrap errors and a way to check if an error is in the stack of a specific error class.
39
+ * All errors that extend this class *must* have error options as the last argument in their constructor.
40
+ */
41
+ export abstract class SerializableError extends Error {
42
+ details: string[];
43
+ /*
44
+ * The instance of the error that was wrapped, if any.
45
+ * Creates a linked list of error objects.
46
+ * Only exists if the error hasn't been serialized and deserialized.
47
+ */
48
+ cause: unknown;
49
+ constructor(message: string, options?: ErrorOptions) {
50
+ super(message, options);
51
+ // for some reason, we need to set the cause directly on the instance, even after calling super
52
+ this.cause = options?.cause;
53
+ this.name = this.constructor.name;
54
+ this.details = [this.constructor.name, 'SerializableError'];
55
+ }
56
+
57
+ /*
58
+ * Checks if the error is an instance of the current class or a subclass. Returns the error if it is.
59
+ * We can't type the error as more than SerializableError because it could have been serialized and deserialized,
60
+ * which could make it lose extra fields.
61
+ */
62
+ static inStackOf<T extends abstract new (...args: any) => any>(
63
+ this: T,
64
+ error: any,
65
+ ): SerializableError | undefined {
66
+ if (error?.details?.includes(this.name)) {
67
+ return error as SerializableError;
68
+ } else if (error?.cause?.details?.includes(this.name)) {
69
+ return error.cause as SerializableError;
70
+ }
71
+ return undefined;
72
+ }
73
+
74
+ // We could limit this to only wrap serializable errors, but that could limit the flexibility of the error system.
75
+ static wrap<T extends new (...args: any) => SerializableError>(
76
+ this: T,
77
+ error: any,
78
+ // Remove the optional error arguments
79
+ ...args: RemoveErrorOptions<ConstructorParameters<T>>
80
+ ): InstanceType<T> {
81
+ const wrappedError = new this(...args, { cause: error });
82
+
83
+ wrappedError.details = error?.details
84
+ ? [wrappedError.name, ...error.details]
85
+ : [wrappedError.name, 'SerializableError', error?.name ?? 'UnknownError'];
86
+
87
+ wrappedError.message = `${wrappedError.message} > ${error?.message ?? String(error)}`;
88
+
89
+ return wrappedError as InstanceType<T>;
90
+ }
91
+ }
92
+
93
+ export class NonRetryableError extends SerializableError {
94
+ constructor(message: string, options?: ErrorOptions) {
95
+ super(message, options);
96
+ }
97
+ }
98
+
99
+ export class NotFoundError extends SerializableError {
100
+ constructor(message?: string, options?: ErrorOptions) {
101
+ super(message ? `Not found: ${message}` : 'Not found', options);
102
+ }
103
+ }
104
+
105
+ // TODO: extend this for chain specific providers
106
+ export class ProviderError extends SerializableError {
107
+ constructor(providerUri: string, options?: ErrorOptions) {
108
+ super(`Provider error at host '${ProviderError.parseHost(providerUri)}'`, options);
109
+ }
110
+
111
+ private static parseHost(providerUri: string): string {
112
+ try {
113
+ const url = new URL(providerUri);
114
+ return url.host;
115
+ } catch {
116
+ return 'UNKNOWN_HOST';
117
+ }
118
+ }
119
+ }
120
+
121
+ export class NonEmittableError extends SerializableError {
122
+ constructor(message: string, options?: ErrorOptions) {
123
+ super(message, options);
124
+ this.name = 'NonEmittableError';
125
+ }
126
+ }
127
+
128
+ export class QuorumNotAchievedYet extends SerializableError {
129
+ constructor(options?: ErrorOptions) {
130
+ super('The quorum was not achieved yet', options);
131
+ }
132
+ }
133
+
134
+ export class MultiError extends Error {
135
+ constructor(public readonly errs: any[]) {
136
+ super(errs.map((err) => err.message).join(', '));
137
+ }
138
+ }
139
+
140
+ export const throwError = <Err extends Error>(
141
+ message: string,
142
+ error?: (message: string) => Err,
143
+ ): never => {
144
+ throw error?.(message) ?? new Error(message);
145
+ };
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { NotFoundError, SerializableError } from './../src/';
4
+
5
+ describe('SerializableError', () => {
6
+ it('should check if error is in stack', () => {
7
+ const err = new NotFoundError('User');
8
+ expect(err.name).toBe('NotFoundError');
9
+ expect(err.message).toBe('Not found: User');
10
+ expect(err.cause).toBeUndefined();
11
+ expect(err.details).toEqual(['NotFoundError', 'SerializableError']);
12
+ expect(NotFoundError.inStackOf(err)).toBe(err);
13
+ });
14
+
15
+ it('should wrap an error', () => {
16
+ const originalError = new Error('No rows returned');
17
+ const wrappedError = NotFoundError.wrap(originalError, 'User');
18
+
19
+ expect(wrappedError.name).toBe('NotFoundError');
20
+ expect(wrappedError.message).toBe('Not found: User > No rows returned');
21
+ expect(wrappedError.cause).toBe(originalError);
22
+ expect(wrappedError.details).toEqual(['NotFoundError', 'SerializableError', 'Error']);
23
+ });
24
+
25
+ it('wraps simple error', () => {
26
+ class SomeError extends SerializableError {
27
+ constructor(opts: ErrorOptions) {
28
+ console.log('SomeError constructor called', opts);
29
+ super('Some error', opts);
30
+ }
31
+ }
32
+
33
+ const err = new Error('Some error 2');
34
+ const wrapped = SomeError.wrap(err);
35
+ expect(wrapped.name).toBe('SomeError');
36
+ expect(wrapped.message).toBe('Some error > Some error 2');
37
+ expect(wrapped.cause).toBe(err);
38
+ expect(wrapped.details).toEqual(['SomeError', 'SerializableError', 'Error']);
39
+ });
40
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "@layerzerolabs/typescript-configuration/tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src",
5
+ "outDir": "./dist",
6
+ "strictPropertyInitialization": false,
7
+ "noUnusedLocals": false,
8
+ "noUnusedParameters": false,
9
+ "jsx": "react-jsx"
10
+ },
11
+ "exclude": [
12
+ "node_modules",
13
+ "**/__mocks__/*",
14
+ "**/__tests__/*",
15
+ "**/*.spec.ts",
16
+ "**/*.test.ts",
17
+ "dist"
18
+ ],
19
+ "include": ["src/**/*"]
20
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ import { createPackageTsupConfig } from '@layerzerolabs/tsup-configuration';
4
+
5
+ export default defineConfig(({ watch }) => ({
6
+ ...createPackageTsupConfig(),
7
+ clean: !watch,
8
+ }));