@@ -47,6 +47,11 @@ export class Instrument extends InstrumentBase {
47
47
48
48
globalScope . addEventListener ( 'error' , ( errorEvent ) => {
49
49
if ( ! this . abortHandler ) return
50
+
51
+ /**
52
+ * If the spa feature is loaded, errors may already have been captured in the `fn-err` listener above.
53
+ * This ensures those errors are not captured twice.
54
+ */
50
55
if ( this . #seenErrors. has ( errorEvent . error ) ) {
51
56
this . #seenErrors. delete ( errorEvent . error )
52
57
return
@@ -66,16 +71,31 @@ export class Instrument extends InstrumentBase {
66
71
this . abortHandler = undefined // weakly allow this abort op to run only once
67
72
}
68
73
74
+ /**
75
+ * Any value can be used with the `throw` keyword. This function ensures that the value is
76
+ * either a proper Error instance or attempts to convert it to an UncaughtError instance.
77
+ * @param {any } error The value thrown
78
+ * @returns {Error|UncaughtError } The converted error instance
79
+ */
69
80
#castError ( error ) {
70
81
if ( error instanceof Error ) {
71
82
return error
72
83
}
73
84
74
- if ( typeof error . message !== 'undefined' ) {
75
- return new UncaughtError ( error . message , error . filename , error . lineno , error . colno )
85
+ /**
86
+ * The thrown value may contain a message property. If it does, try to treat the thrown
87
+ * value as an Error-like object.
88
+ */
89
+ if ( typeof error ?. message !== 'undefined' ) {
90
+ return new UncaughtError (
91
+ error . message ,
92
+ error . filename || error . sourceURL ,
93
+ error . lineno || error . line ,
94
+ error . colno || error . col
95
+ )
76
96
}
77
97
78
- return new UncaughtError ( error )
98
+ return new UncaughtError ( typeof error === 'string' ? error : stringify ( error ) )
79
99
}
80
100
81
101
/**
@@ -85,6 +105,7 @@ export class Instrument extends InstrumentBase {
85
105
*/
86
106
#castPromiseRejectionEvent ( promiseRejectionEvent ) {
87
107
let prefix = 'Unhandled Promise Rejection: '
108
+
88
109
if ( promiseRejectionEvent ?. reason instanceof Error ) {
89
110
try {
90
111
promiseRejectionEvent . reason . message = prefix + promiseRejectionEvent . reason . message
@@ -93,12 +114,12 @@ export class Instrument extends InstrumentBase {
93
114
return promiseRejectionEvent . reason
94
115
}
95
116
}
96
- if ( typeof promiseRejectionEvent . reason === 'undefined' ) return new Error ( prefix )
97
- try {
98
- return new Error ( prefix + stringify ( promiseRejectionEvent . reason ) )
99
- } catch ( e ) {
100
- return new Error ( promiseRejectionEvent . reason )
101
- }
117
+
118
+ if ( typeof promiseRejectionEvent . reason === 'undefined' ) return new UncaughtError ( prefix )
119
+
120
+ const error = this . #castError ( promiseRejectionEvent . reason )
121
+ error . message = prefix + error . message
122
+ return error
102
123
}
103
124
104
125
/**
@@ -111,6 +132,10 @@ export class Instrument extends InstrumentBase {
111
132
return errorEvent . error
112
133
}
113
134
135
+ /**
136
+ * Older browsers do not contain the `error` property on the ErrorEvent instance.
137
+ * https://caniuse.com/mdn-api_errorevent_error
138
+ */
114
139
return new UncaughtError ( errorEvent . message , errorEvent . filename , errorEvent . lineno , errorEvent . colno )
115
140
}
116
141
}
0 commit comments