@@ -126,29 +126,23 @@ const UserErrorMessagesTranslations: { [key in UserErrorMessage]: string } = {
126126 [ UserErrorMessage . RateLimitExceeded ] : t ( `Rate limit exceeded` ) ,
127127}
128128
129- export interface UserErrorObj {
129+ export interface SerializedUserError {
130130 readonly errorCode : number
131131
132132 /** The raw Error that was thrown */
133- readonly rawError : Error
133+ rawError : Pick < Error , 'name' | 'message' | 'stack' >
134134 /** The UserErrorMessage key (for matching certain error) */
135135 readonly key : UserErrorMessage
136136 /** The translatable string for the key */
137137 readonly userMessage : ITranslatableMessage
138138}
139139
140- export interface StringifiedUserErrorObject extends Omit < UserErrorObj , 'rawError' > {
141- rawError : Pick < Error , 'name' | 'message' | 'stack' >
142- }
143-
144- export type StringifiedErrorObject = Omit < Error , 'cause' >
145-
146- export class UserError extends Error implements UserErrorObj {
140+ export class UserError extends Error {
147141 public readonly errorCode : number
148142
149143 private constructor (
150144 /** The raw Error that was thrown */
151- public readonly rawError : Error ,
145+ rawError : SerializedUserError [ 'rawError' ] ,
152146 /** The UserErrorMessage key (for matching certain error) */
153147 public readonly key : UserErrorMessage ,
154148 /** The translatable string for the key */
@@ -157,21 +151,31 @@ export class UserError extends Error implements UserErrorObj {
157151 errorCode : number | undefined
158152 ) {
159153 super ( )
160- this . errorCode = errorCode ?? 500
161- }
162154
163- public toString ( ) : string {
164- return UserError . toJSON ( this )
155+ // Populate the error properties:
156+ this . message = rawError . message
157+ this . stack = rawError . stack
158+ this . name = 'UserError'
159+
160+ this . errorCode = errorCode ?? 500
165161 }
166162
167163 /** Create a UserError with a custom error for the log */
168164 static from ( err : Error , key : UserErrorMessage , args ?: { [ k : string ] : any } , errCode ?: number ) : UserError {
169165 return new UserError ( err , key , { key : UserErrorMessagesTranslations [ key ] , args } , errCode )
170166 }
167+ /** Create a UserError duplicating the same error for the log */
168+ static create ( key : UserErrorMessage , args ?: { [ k : string ] : any } , errorCode ?: number ) : UserError {
169+ return UserError . from ( new Error ( UserErrorMessagesTranslations [ key ] ) , key , args , errorCode )
170+ }
171+ static fromSerialized ( o : SerializedUserError ) : UserError {
172+ return new UserError ( o . rawError , o . key , o . userMessage , o . errorCode )
173+ }
171174 /** Create a UserError from an unknown possibly error input */
172175 static fromUnknown ( err : unknown , errorCode ?: number ) : UserError {
173176 if ( err instanceof UserError ) return err
174- if ( this . isUserError ( err ) ) {
177+
178+ if ( this . isStringifiedUserErrorObject ( err ) ) {
175179 return new UserError ( err . rawError , err . key , err . userMessage , err . errorCode )
176180 }
177181 const err2 = err instanceof Error ? err : new Error ( stringifyError ( err ) )
@@ -183,69 +187,61 @@ export class UserError extends Error implements UserErrorObj {
183187 )
184188 }
185189
186- /** Create a UserError duplicating the same error for the log */
187- static create ( key : UserErrorMessage , args ?: { [ k : string ] : any } , errorCode ?: number ) : UserError {
188- return UserError . from ( new Error ( UserErrorMessagesTranslations [ key ] ) , key , args , errorCode )
189- }
190-
191190 static tryFromJSON ( str : string ) : UserError | undefined {
191+ let p : SerializedUserError | undefined
192192 try {
193- const p = UserError . fromJSON ( str )
194- if ( p ) {
195- const newError = p . rawError as Error
196- const newUserError = new UserError ( newError , p . key , p . userMessage , p . errorCode )
197- return newUserError
198- } else {
199- return undefined
200- }
193+ p = UserError . fromJSON ( str )
194+ if ( ! p ) return undefined
201195 } catch ( _e : any ) {
196+ // Ignore JSON parsing error
197+ return undefined
198+ }
199+
200+ if ( this . isStringifiedUserErrorObject ( p ) ) {
201+ return new UserError ( p . rawError , p . key , p . userMessage , p . errorCode )
202+ } else {
202203 return undefined
203204 }
204205 }
205206
206- static toJSON ( e : UserErrorObj ) : string {
207- const o : StringifiedUserErrorObject = {
207+ static serialize ( e : UserError ) : SerializedUserError {
208+ const o : SerializedUserError = {
208209 rawError : {
209- name : e . rawError . name ,
210- message : e . rawError . message ,
211- stack : e . rawError . stack ,
210+ name : e . name ,
211+ message : e . message ,
212+ stack : e . stack ,
212213 } ,
213214 userMessage : e . userMessage ,
214215 key : e . key ,
215216 errorCode : e . errorCode ,
216217 }
217- return JSON . stringify ( o )
218+ return o
218219 }
219- static fromJSON ( str : string ) : StringifiedUserErrorObject | undefined {
220+ static toJSON ( e : UserError ) : string {
221+ return JSON . stringify ( this . serialize ( e ) )
222+ }
223+ static fromJSON ( str : string ) : SerializedUserError | undefined {
220224 const o = JSON . parse ( str )
221- if ( isStringifiedUserErrorObject ( o ) ) return o
225+ if ( this . isStringifiedUserErrorObject ( o ) ) return o
222226 return undefined
223227 }
224-
225- static isUserError ( e : unknown ) : e is UserErrorObj {
226- return ! ! e && typeof e === 'object' && 'rawError' in e && 'userMessage' in e && 'key' in e
228+ static isStringifiedUserErrorObject ( o : unknown ) : o is SerializedUserError {
229+ if ( ! o || typeof o !== 'object' ) return false
230+ const errorObject = o as SerializedUserError
231+
232+ return (
233+ 'rawError' in errorObject &&
234+ ! ! errorObject . rawError &&
235+ typeof errorObject . rawError === 'object' &&
236+ errorObject . rawError &&
237+ typeof errorObject . rawError . message === 'string' &&
238+ isTranslatableMessage ( errorObject . userMessage ) &&
239+ typeof errorObject . errorCode === 'number' &&
240+ typeof errorObject . key === 'number'
241+ )
227242 }
228243
229244 toErrorString ( ) : string {
230- return `${ translateMessage ( this . userMessage , interpollateTranslation ) } \n${ stringifyError ( this . rawError ) } `
245+ return `${ translateMessage ( this . userMessage , interpollateTranslation ) } \n${ stringifyError ( this ) } `
231246 }
232247}
233-
234- function isStringifiedUserErrorObject ( o : any ) : o is StringifiedUserErrorObject {
235- return (
236- o &&
237- typeof o === 'object' &&
238- 'rawError' in o &&
239- o . rawError &&
240- isStringifiedErrorObject ( o . rawError ) &&
241- isTranslatableMessage ( o . userMessage ) &&
242- typeof o . errorCode === 'number' &&
243- typeof o . key === 'number' &&
244- o . key >= 0 &&
245- o . key < Object . keys ( UserErrorMessage ) . length / 2
246- )
247- }
248-
249- function isStringifiedErrorObject ( o : any ) : o is StringifiedErrorObject {
250- return o && typeof o === 'object' && 'name' in o && 'message' in o && 'stack' in o
251- }
0 commit comments