11import { ITranslatableMessage } from '@sofie-automation/blueprints-integration'
22import { stringifyError } from '@sofie-automation/shared-lib/dist/lib/stringifyError'
3- import { interpollateTranslation , translateMessage } from './TranslatableMessage.js'
3+ import { interpollateTranslation , isTranslatableMessage , translateMessage } from './TranslatableMessage.js'
44
55// Mock 't' function for i18next to find the keys
66function t ( key : string ) : string {
@@ -137,6 +137,12 @@ export interface UserErrorObj {
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+
140146export class UserError extends Error implements UserErrorObj {
141147 public readonly errorCode : number
142148
@@ -165,9 +171,9 @@ export class UserError extends Error implements UserErrorObj {
165171 /** Create a UserError from an unknown possibly error input */
166172 static fromUnknown ( err : unknown , errorCode ?: number ) : UserError {
167173 if ( err instanceof UserError ) return err
168- if ( this . isUserError ( err ) )
169- return new UserError ( new Error ( err . rawError . toString ( ) ) , err . key , err . userMessage , err . errorCode )
170-
174+ if ( this . isUserError ( err ) ) {
175+ return new UserError ( err . rawError , err . key , err . userMessage , err . errorCode )
176+ }
171177 const err2 = err instanceof Error ? err : new Error ( stringifyError ( err ) )
172178 return new UserError (
173179 err2 ,
@@ -184,9 +190,11 @@ export class UserError extends Error implements UserErrorObj {
184190
185191 static tryFromJSON ( str : string ) : UserError | undefined {
186192 try {
187- const p = JSON . parse ( str )
188- if ( UserError . isUserError ( p ) ) {
189- return new UserError ( new Error ( p . rawError . toString ( ) ) , p . key , p . userMessage , p . errorCode )
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
190198 } else {
191199 return undefined
192200 }
@@ -196,12 +204,22 @@ export class UserError extends Error implements UserErrorObj {
196204 }
197205
198206 static toJSON ( e : UserErrorObj ) : string {
199- return JSON . stringify ( {
200- rawError : stringifyError ( e . rawError ) ,
207+ const o : StringifiedUserErrorObject = {
208+ rawError : {
209+ name : e . rawError . name ,
210+ message : e . rawError . message ,
211+ stack : e . rawError . stack ,
212+ } ,
201213 userMessage : e . userMessage ,
202214 key : e . key ,
203215 errorCode : e . errorCode ,
204- } )
216+ }
217+ return JSON . stringify ( o )
218+ }
219+ static fromJSON ( str : string ) : StringifiedUserErrorObject | undefined {
220+ const o = JSON . parse ( str )
221+ if ( isStringifiedUserErrorObject ( o ) ) return o
222+ return undefined
205223 }
206224
207225 static isUserError ( e : unknown ) : e is UserErrorObj {
@@ -212,3 +230,22 @@ export class UserError extends Error implements UserErrorObj {
212230 return `${ translateMessage ( this . userMessage , interpollateTranslation ) } \n${ stringifyError ( this . rawError ) } `
213231 }
214232}
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