11import type { IntegrationFn , WrappedFunction } from '@sentry/core' ;
22import { defineIntegration , fill , getFunctionName , getOriginalFunction } from '@sentry/core' ;
33import { WINDOW , wrap } from '../helpers' ;
4+ import { __propKey } from 'tslib' ;
45
56const DEFAULT_EVENT_TARGET = [
67 'EventTarget' ,
@@ -46,6 +47,15 @@ interface BrowserApiErrorsOptions {
4647 requestAnimationFrame : boolean ;
4748 XMLHttpRequest : boolean ;
4849 eventTarget : boolean | string [ ] ;
50+
51+ /**
52+ * If you experience issues with this integration causing double-invocations of event listeners,
53+ * try setting this option to `true`. It will unregister the original callbacks from the event targets
54+ * before adding the instrumented callback.
55+ *
56+ * @default false
57+ */
58+ unregisterOriginalCallbacks : boolean ;
4959}
5060
5161const _browserApiErrorsIntegration = ( ( options : Partial < BrowserApiErrorsOptions > = { } ) => {
@@ -55,6 +65,7 @@ const _browserApiErrorsIntegration = ((options: Partial<BrowserApiErrorsOptions>
5565 requestAnimationFrame : true ,
5666 setInterval : true ,
5767 setTimeout : true ,
68+ unregisterOriginalCallbacks : false ,
5869 ...options ,
5970 } ;
6071
@@ -82,7 +93,7 @@ const _browserApiErrorsIntegration = ((options: Partial<BrowserApiErrorsOptions>
8293 const eventTargetOption = _options . eventTarget ;
8394 if ( eventTargetOption ) {
8495 const eventTarget = Array . isArray ( eventTargetOption ) ? eventTargetOption : DEFAULT_EVENT_TARGET ;
85- eventTarget . forEach ( _wrapEventTarget ) ;
96+ eventTarget . forEach ( target => _wrapEventTarget ( target , _options ) ) ;
8697 }
8798 } ,
8899 } ;
@@ -160,7 +171,7 @@ function _wrapXHR(originalSend: () => void): () => void {
160171 } ;
161172}
162173
163- function _wrapEventTarget ( target : string ) : void {
174+ function _wrapEventTarget ( target : string , integrationOptions : BrowserApiErrorsOptions ) : void {
164175 const globalObject = WINDOW as unknown as Record < string , { prototype ?: object } > ;
165176 const proto = globalObject [ target ] ?. prototype ;
166177
@@ -197,6 +208,10 @@ function _wrapEventTarget(target: string): void {
197208 // can sometimes get 'Permission denied to access property "handle Event'
198209 }
199210
211+ if ( integrationOptions . unregisterOriginalCallbacks ) {
212+ unregisterOriginalCallback ( this , eventName , fn ) ;
213+ }
214+
200215 return original . apply ( this , [
201216 eventName ,
202217 wrap ( fn , {
@@ -253,3 +268,14 @@ function _wrapEventTarget(target: string): void {
253268function isEventListenerObject ( obj : unknown ) : obj is EventListenerObject {
254269 return typeof ( obj as EventListenerObject ) . handleEvent === 'function' ;
255270}
271+
272+ function unregisterOriginalCallback ( target : unknown , eventName : string , fn : EventListenerOrEventListenerObject ) : void {
273+ if (
274+ target &&
275+ typeof target === 'object' &&
276+ 'removeEventListener' in target &&
277+ typeof target . removeEventListener === 'function'
278+ ) {
279+ target . removeEventListener ( eventName , fn ) ;
280+ }
281+ }
0 commit comments