@exodus/errors 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [2.0.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/errors@1.3.0...@exodus/errors@2.0.0) (2025-02-26)
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ - **errors:** SafeError returns stack trace in the text format (#11581)
11
+
12
+ ### Features
13
+
14
+ - feat(errors)!: SafeError returns stack trace in the text format (#11581)
15
+
16
+ ## [1.3.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/errors@1.2.0...@exodus/errors@1.3.0) (2025-02-17)
17
+
18
+ ### Features
19
+
20
+ - feat: whitelist TimeoutError (#11443)
21
+
6
22
  ## [1.2.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/errors@1.1.1...@exodus/errors@1.2.0) (2025-02-12)
7
23
 
8
24
  ### Features
@@ -1,17 +1,17 @@
1
1
  import type { Frame } from './types.js';
2
2
  type ReadonlySetValues<S> = S extends ReadonlySet<infer T> ? T : never;
3
- declare const SAFE_NAMES_SET: ReadonlySet<"Error" | "AssertionError" | "TypeError" | "RangeError" | "UnknownError" | "SafeErrorFailedToParse">;
3
+ declare const SAFE_NAMES_SET: ReadonlySet<"Error" | "AssertionError" | "TypeError" | "RangeError" | "UnknownError" | "SafeErrorFailedToParse" | "TimeoutError">;
4
4
  declare const SAFE_HINTS_SET: ReadonlySet<"broadcastTx" | "otherErr:broadcastTx" | "retry:broadcastTx" | "getNftArguments" | "ethCall" | "ethCall:executionReverted" | "failed to parse error">;
5
- type SafeName = ReadonlySetValues<typeof SAFE_NAMES_SET>;
6
- type SafeHint = ReadonlySetValues<typeof SAFE_HINTS_SET>;
7
- type SafeCode = string & {
5
+ export type SafeName = ReadonlySetValues<typeof SAFE_NAMES_SET>;
6
+ export type SafeHint = ReadonlySetValues<typeof SAFE_HINTS_SET>;
7
+ export type SafeCode = string & {
8
8
  __branded_type: 'SafeCodeOutcome';
9
9
  };
10
10
  type UnknownError = Error & {
11
11
  hint?: unknown;
12
12
  code?: unknown;
13
13
  };
14
- declare const FACTORY_SYMBOL: unique symbol;
14
+ export declare const FACTORY_SYMBOL: unique symbol;
15
15
  export declare class SafeError {
16
16
  #private;
17
17
  static readonly hints: {
@@ -33,7 +33,7 @@ export declare class SafeError {
33
33
  };
34
34
  };
35
35
  static from<T extends UnknownError>(err: T): SafeError;
36
- get name(): "Error" | "AssertionError" | "TypeError" | "RangeError" | "UnknownError" | "SafeErrorFailedToParse";
36
+ get name(): "Error" | "AssertionError" | "TypeError" | "RangeError" | "UnknownError" | "SafeErrorFailedToParse" | "TimeoutError";
37
37
  get code(): SafeCode | undefined;
38
38
  get hint(): "broadcastTx" | "otherErr:broadcastTx" | "retry:broadcastTx" | "getNftArguments" | "ethCall" | "ethCall:executionReverted" | "failed to parse error" | undefined;
39
39
  get stackFrames(): {
@@ -47,24 +47,10 @@ export declare class SafeError {
47
47
  in_app?: boolean | null;
48
48
  __proto__: null;
49
49
  }[] | undefined;
50
+ get stack(): string | undefined;
50
51
  get timestamp(): number;
51
52
  toJSON(): {
52
- __proto__: null;
53
- name: "Error" | "AssertionError" | "TypeError" | "RangeError" | "UnknownError" | "SafeErrorFailedToParse";
54
- code: SafeCode | undefined;
55
- hint: "broadcastTx" | "otherErr:broadcastTx" | "retry:broadcastTx" | "getNftArguments" | "ethCall" | "ethCall:executionReverted" | "failed to parse error" | undefined;
56
- stackFrames: {
57
- function?: string | null;
58
- method?: string | null;
59
- file?: string | null;
60
- line?: number | null;
61
- column?: number | null;
62
- async?: boolean | null;
63
- toplevel?: boolean | null;
64
- in_app?: boolean | null;
65
- __proto__: null;
66
- }[] | undefined;
67
- timestamp: number;
53
+ [k: string]: any;
68
54
  };
69
55
  constructor({ name, code, hint, stack, initSymbol, }: {
70
56
  name: SafeName;
package/lib/safe-error.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import assert from 'minimalistic-assert';
2
- import parseStackTraceNatively from './stack.js';
2
+ import parseStackTraceNatively, { stackFramesToString } from './stack.js';
3
+ import { omitUndefined } from './utils.js';
3
4
  function makeReadonlySet(values) {
4
5
  return new Set(values);
5
6
  }
@@ -11,6 +12,7 @@ const SAFE_NAMES_SET = makeReadonlySet([
11
12
  'RangeError',
12
13
  'UnknownError',
13
14
  'SafeErrorFailedToParse',
15
+ 'TimeoutError',
14
16
  ]);
15
17
  const safeHints = {
16
18
  __proto__: null,
@@ -57,7 +59,7 @@ function isExodusErrorCode(code) {
57
59
  function isSafeCode(value) {
58
60
  return SAFE_CODES_SET.has(value) || isExodusErrorCode(value);
59
61
  }
60
- const FACTORY_SYMBOL = Symbol('SafeError');
62
+ export const FACTORY_SYMBOL = Symbol('SafeError');
61
63
  export class SafeError {
62
64
  static hints = safeHints;
63
65
  static from(err) {
@@ -112,18 +114,24 @@ export class SafeError {
112
114
  get stackFrames() {
113
115
  return this.#stackFrames?.map((frame) => ({ __proto__: null, ...frame }));
114
116
  }
117
+ get stack() {
118
+ const stackTrace = stackFramesToString(this.stackFrames);
119
+ return stackTrace
120
+ ? `${this.name}: ${this.code || this.hint || 'unknownHint'}\n${stackTrace}`
121
+ : undefined;
122
+ }
115
123
  get timestamp() {
116
124
  return this.#timestamp;
117
125
  }
118
126
  toJSON() {
119
- return {
127
+ return omitUndefined({
120
128
  __proto__: null,
121
129
  name: this.name,
122
130
  code: this.code,
123
131
  hint: this.hint,
124
- stackFrames: this.stackFrames,
132
+ stack: this.stack,
125
133
  timestamp: this.timestamp,
126
- };
134
+ });
127
135
  }
128
136
  constructor({ name, code, hint, stack, initSymbol, }) {
129
137
  assert(initSymbol === FACTORY_SYMBOL, 'SafeError: use SafeError.from()');
package/lib/stack.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import type { Frame } from './types.js';
2
+ export declare function stackFramesToString(frames?: Frame[]): string | undefined;
2
3
  export default function parseStackTraceNatively(err: Error): Frame[] | undefined;
package/lib/stack.js CHANGED
@@ -1,3 +1,14 @@
1
+ export function stackFramesToString(frames) {
2
+ if (frames === undefined) {
3
+ return;
4
+ }
5
+ return frames
6
+ .map((frame) => {
7
+ const { function: fn, method, file, line, column } = frame;
8
+ return ` at ${fn || 'unknownFn'}${method ? `.${method}` : ''}${file ? `(${file}${line === null ? '' : `:${line}:${column}`})` : ''}`;
9
+ })
10
+ .join('\n');
11
+ }
1
12
  export default function parseStackTraceNatively(err) {
2
13
  const { prepareStackTrace } = Error;
3
14
  let stack;
package/lib/utils.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare const omitUndefined: (object: Record<string, any>) => {
2
+ [k: string]: any;
3
+ };
package/lib/utils.js ADDED
@@ -0,0 +1 @@
1
+ export const omitUndefined = (object) => Object.fromEntries(Object.entries(object).filter(([, value]) => value !== undefined));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exodus/errors",
3
3
  "type": "module",
4
- "version": "1.2.0",
4
+ "version": "2.0.0",
5
5
  "description": "Utilities for error handling in client code, such as sanitization",
6
6
  "author": "Exodus Movement, Inc.",
7
7
  "repository": {
@@ -44,5 +44,5 @@
44
44
  "publishConfig": {
45
45
  "access": "public"
46
46
  },
47
- "gitHead": "3f98f500b3b5289ff3e38a8c8385c164b4ee8a5e"
47
+ "gitHead": "b5f5320ef9490bae4794356a815b2f8a376bbf03"
48
48
  }