1
+ import { DSN } from '@sentry/core' ;
1
2
import { getCurrentHub } from '@sentry/hub' ;
2
3
import { Integration , Severity } from '@sentry/types' ;
3
4
import { isFunction , isString } from '@sentry/utils/is' ;
4
5
import { getGlobalObject , parseUrl } from '@sentry/utils/misc' ;
5
6
import { fill } from '@sentry/utils/object' ;
6
7
import { safeJoin } from '@sentry/utils/string' ;
7
8
import { supportsFetch , supportsHistory } from '@sentry/utils/supports' ;
9
+ import { BrowserOptions } from '../backend' ;
8
10
import { breadcrumbEventHandler , keypressEventHandler , wrap } from './helpers' ;
9
11
10
12
const global = getGlobalObject ( ) as Window ;
@@ -36,7 +38,7 @@ export class Breadcrumbs implements Integration {
36
38
* @inheritDoc
37
39
*/
38
40
public constructor (
39
- private readonly options : {
41
+ private readonly config : {
40
42
console ?: boolean ;
41
43
dom ?: boolean ;
42
44
fetch ?: boolean ;
@@ -109,7 +111,7 @@ export class Breadcrumbs implements Integration {
109
111
}
110
112
111
113
/** JSDoc */
112
- private instrumentFetch ( ) : void {
114
+ private instrumentFetch ( options : { filterUrl ?: string } ) : void {
113
115
if ( ! supportsFetch ( ) ) {
114
116
return ;
115
117
}
@@ -131,6 +133,11 @@ export class Breadcrumbs implements Integration {
131
133
url = String ( fetchInput ) ;
132
134
}
133
135
136
+ // if Sentry key appears in URL, don't capture, as it's our own request
137
+ if ( options . filterUrl && url . includes ( options . filterUrl ) ) {
138
+ return originalFetch . apply ( global , args ) ;
139
+ }
140
+
134
141
if ( args [ 1 ] && args [ 1 ] . method ) {
135
142
method = args [ 1 ] . method ;
136
143
}
@@ -178,7 +185,12 @@ export class Breadcrumbs implements Integration {
178
185
const captureUrlChange = ( from : string | undefined , to : string | undefined ) : void => {
179
186
const parsedLoc = parseUrl ( global . location . href ) ;
180
187
const parsedTo = parseUrl ( to as string ) ;
181
- const parsedFrom = parseUrl ( from as string ) ;
188
+ let parsedFrom = parseUrl ( from as string ) ;
189
+
190
+ // Initial pushState doesn't provide `from` information
191
+ if ( ! parsedFrom . path ) {
192
+ parsedFrom = parsedLoc ;
193
+ }
182
194
183
195
// because onpopstate only tells you the "new" (to) value of location.href, and
184
196
// not the previous (from) value, we need to track the value of the current URL
@@ -211,30 +223,30 @@ export class Breadcrumbs implements Integration {
211
223
const currentHref = global . location . href ;
212
224
captureUrlChange ( lastHref , currentHref ) ;
213
225
if ( oldOnPopState ) {
214
- return oldOnPopState . apply ( global , args ) ;
226
+ return oldOnPopState . apply ( this , args ) ;
215
227
}
216
228
} ;
217
229
218
230
/** JSDoc */
219
231
function historyReplacementFunction ( originalHistoryFunction : ( ) => void ) : ( ) => void {
220
232
// note history.pushState.length is 0; intentionally not declaring
221
233
// params to preserve 0 arity
222
- return function ( ...args : any [ ] ) : void {
234
+ return function ( this : History , ...args : any [ ] ) : void {
223
235
const url = args . length > 2 ? args [ 2 ] : undefined ;
224
236
// url argument is optional
225
237
if ( url ) {
226
238
// coerce to string (this is what pushState does)
227
239
captureUrlChange ( lastHref , String ( url ) ) ;
228
240
}
229
- return originalHistoryFunction . apply ( global , ... args ) ;
241
+ return originalHistoryFunction . apply ( this , args ) ;
230
242
} ;
231
243
}
232
244
233
245
fill ( global . history , 'pushState' , historyReplacementFunction ) ;
234
246
fill ( global . history , 'replaceState' , historyReplacementFunction ) ;
235
247
}
236
248
/** JSDoc */
237
- private instrumentXHR ( ) : void {
249
+ private instrumentXHR ( options : { filterUrl ?: string } ) : void {
238
250
if ( ! ( 'XMLHttpRequest' in global ) ) {
239
251
return ;
240
252
}
@@ -250,6 +262,7 @@ export class Breadcrumbs implements Integration {
250
262
function : prop ,
251
263
handler : ( original && original . name ) || '<anonymous>' ,
252
264
} ,
265
+ handled : true ,
253
266
type : 'instrument' ,
254
267
} ,
255
268
} ) ,
@@ -263,7 +276,9 @@ export class Breadcrumbs implements Integration {
263
276
'open' ,
264
277
originalOpen =>
265
278
function ( this : SentryWrappedXMLHttpRequest , ...args : any [ ] ) : void {
266
- if ( isString ( args [ 1 ] ) ) {
279
+ const url = args [ 1 ] ;
280
+ // if Sentry key appears in URL, don't capture, as it's our own request
281
+ if ( isString ( url ) && ( options . filterUrl && ! url . includes ( options . filterUrl ) ) ) {
267
282
this . __sentry_xhr__ = {
268
283
method : args [ 0 ] ,
269
284
url : args [ 1 ] ,
@@ -312,6 +327,7 @@ export class Breadcrumbs implements Integration {
312
327
function : 'onreadystatechange' ,
313
328
handler : ( original && original . name ) || '<anonymous>' ,
314
329
} ,
330
+ handled : true ,
315
331
type : 'instrument' ,
316
332
} ,
317
333
} ,
@@ -323,7 +339,7 @@ export class Breadcrumbs implements Integration {
323
339
// are free to set our own and capture the breadcrumb
324
340
xhr . onreadystatechange = onreadystatechangeHandler ;
325
341
}
326
- return originalSend . apply ( XMLHttpRequest , args ) ;
342
+ return originalSend . apply ( this , args ) ;
327
343
} ,
328
344
) ;
329
345
}
@@ -337,20 +353,23 @@ export class Breadcrumbs implements Integration {
337
353
*
338
354
* Can be disabled or individually configured via the `autoBreadcrumbs` config option
339
355
*/
340
- public install ( ) : void {
341
- if ( this . options . console ) {
356
+ public install ( options : BrowserOptions = { } ) : void {
357
+ // TODO: Use API provider instead of raw `new DSN`
358
+ const filterUrl = options . dsn && new DSN ( options . dsn ) . user ;
359
+
360
+ if ( this . config . console ) {
342
361
this . instrumentConsole ( ) ;
343
362
}
344
- if ( this . options . dom ) {
363
+ if ( this . config . dom ) {
345
364
this . instrumentDOM ( ) ;
346
365
}
347
- if ( this . options . xhr ) {
348
- this . instrumentXHR ( ) ;
366
+ if ( this . config . xhr ) {
367
+ this . instrumentXHR ( { filterUrl } ) ;
349
368
}
350
- if ( this . options . fetch ) {
351
- this . instrumentFetch ( ) ;
369
+ if ( this . config . fetch ) {
370
+ this . instrumentFetch ( { filterUrl } ) ;
352
371
}
353
- if ( this . options . history ) {
372
+ if ( this . config . history ) {
354
373
this . instrumentHistory ( ) ;
355
374
}
356
375
}
0 commit comments