import { Integration , WrappedFunction } from "@sentry/types" ; import { fill , getGlobalObject } from "@sentry/utils" ; import { wrap } from "../helpers" ; /** Wrap timer functions and event targets to catch errors and provide better meta data */ export class TryCatch implements Integration { /** JSDoc */ private _ignoreOnError : number = 0 ; inheritDoc public name : string = TryCatch . id ; inheritDoc public static id : string = "TryCatch" ; /** JSDoc */ private _wrapTimeFunction ( original ) { return function ( this , ... args ) : number { const originalCallback = args [ 0 ] ; args [ 0 ] = wrap ( originalCallback , { mechanism : { data : { function : getFunctionName ( original ) } , handled : true , type : "instrument" } } ) ; return original . apply ( this , args ) ; } ; } /** JSDoc */ private _wrapRAF ( original ) { return function ( this , callback ) : ( ) => void { return original ( wrap ( callback , { mechanism : { data : { function : "requestAnimationFrame" , handler : getFunctionName ( original ) } , handled : true , type : "instrument" } } ) ) ; } ; } /** JSDoc */ private _wrapEventTarget ( target ) { const global = getGlobalObject ( ) as { [ key ] : any ; } ; const proto = global [ target ] && global [ target ] . prototype ; if ( ! proto || ! proto . hasOwnProperty || ! proto . hasOwnProperty ( "addEventListener" ) ) { return ; } fill ( proto , "addEventListener" , function ( original ) : ( eventName : string , fn : EventListenerObject , options ? : boolean | AddEventListenerOptions ) => void { return function ( this , eventName , fn , options ? ) : ( eventName : string , fn : EventListenerObject , capture ? : boolean , secure ? : boolean ) => void { try { if ( typeof fn . handleEvent === "function" ) { fn . handleEvent = wrap ( fn . handleEvent . bind ( fn ) , { mechanism : { data : { function : "handleEvent" , handler : getFunctionName ( fn ) , target } , handled : true , type : "instrument" } } ) ; } } catch ( err ) { } return original . call ( this , eventName , wrap ( ( fn as any ) as WrappedFunction , { mechanism : { data : { function : "addEventListener" , handler : getFunctionName ( fn ) , target } , handled : true , type : "instrument" } } ) , options ) ; } ; } ) ; fill ( proto , "removeEventListener" , function ( original ) : ( this : any , eventName : string , fn : EventListenerObject , options ? : boolean | EventListenerOptions ) => ( ) => void { return function ( this , eventName , fn , options ? ) : ( ) => void { let callback = ( fn as any ) as WrappedFunction ; try { callback = callback && ( callback . __sentry_wrapped__ || callback ) ; } catch ( e ) { } return original . call ( this , eventName , callback , options ) ; } ; } ) ; } /**
     * Wrap timer functions and event targets to catch errors
     * and provide better metadata.
     */ public setupOnce ( ) { this . _ignoreOnError = this . _ignoreOnError ; const global = getGlobalObject ( ) ; fill ( global , "setTimeout" , this . _wrapTimeFunction . bind ( this ) ) ; fill ( global , "setInterval" , this . _wrapTimeFunction . bind ( this ) ) ; fill ( global , "requestAnimationFrame" , this . _wrapRAF . bind ( this ) ) ; [ "EventTarget" , "Window" , "Node" , "ApplicationCache" , "AudioTrackList" , "ChannelMergerNode" , "CryptoOperation" , "EventSource" , "FileReader" , "HTMLUnknownElement" , "IDBDatabase" , "IDBRequest" , "IDBTransaction" , "KeyOperation" , "MediaController" , "MessagePort" , "ModalWindow" , "Notification" , "SVGElementInstance" , "Screen" , "TextTrack" , "TextTrackCue" , "TextTrackList" , "WebSocket" , "WebSocketWorker" , "Worker" , "XMLHttpRequest" , "XMLHttpRequestEventTarget" , "XMLHttpRequestUpload" ] . forEach ( this . _wrapEventTarget . bind ( this ) ) ; } } /**
 * Safely extract function name from itself
 */ function getFunctionName ( fn ) { try { return ( fn && fn . name ) || "<anonymous>" ; } catch ( e ) { return "<anonymous>" ; } }