@sentry/browser 6.6.0 → 6.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/build/bundle.es6.js +280 -80
  2. package/build/bundle.es6.js.map +1 -1
  3. package/build/bundle.es6.min.js +2 -2
  4. package/build/bundle.es6.min.js.map +1 -1
  5. package/build/bundle.js +318 -113
  6. package/build/bundle.js.map +1 -1
  7. package/build/bundle.min.js +2 -2
  8. package/build/bundle.min.js.map +1 -1
  9. package/dist/backend.d.ts.map +1 -1
  10. package/dist/backend.js +1 -1
  11. package/dist/backend.js.map +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/integrations/breadcrumbs.d.ts +1 -1
  15. package/dist/integrations/breadcrumbs.d.ts.map +1 -1
  16. package/dist/integrations/breadcrumbs.js +6 -3
  17. package/dist/integrations/breadcrumbs.js.map +1 -1
  18. package/dist/integrations/dedupe.d.ts +35 -0
  19. package/dist/integrations/dedupe.d.ts.map +1 -0
  20. package/dist/integrations/dedupe.js +166 -0
  21. package/dist/integrations/dedupe.js.map +1 -0
  22. package/dist/integrations/globalhandlers.d.ts.map +1 -1
  23. package/dist/integrations/globalhandlers.js +6 -8
  24. package/dist/integrations/globalhandlers.js.map +1 -1
  25. package/dist/integrations/index.d.ts +1 -0
  26. package/dist/integrations/index.d.ts.map +1 -1
  27. package/dist/integrations/index.js +2 -0
  28. package/dist/integrations/index.js.map +1 -1
  29. package/dist/sdk.d.ts +2 -2
  30. package/dist/sdk.d.ts.map +1 -1
  31. package/dist/sdk.js +1 -0
  32. package/dist/sdk.js.map +1 -1
  33. package/dist/transports/base.d.ts.map +1 -1
  34. package/dist/transports/base.js +2 -2
  35. package/dist/transports/base.js.map +1 -1
  36. package/dist/transports/fetch.d.ts.map +1 -1
  37. package/dist/transports/fetch.js +20 -18
  38. package/dist/transports/fetch.js.map +1 -1
  39. package/dist/transports/xhr.d.ts.map +1 -1
  40. package/dist/transports/xhr.js +21 -19
  41. package/dist/transports/xhr.js.map +1 -1
  42. package/esm/backend.d.ts.map +1 -1
  43. package/esm/backend.js +1 -1
  44. package/esm/backend.js.map +1 -1
  45. package/esm/index.d.ts +1 -0
  46. package/esm/index.d.ts.map +1 -1
  47. package/esm/integrations/breadcrumbs.d.ts +1 -1
  48. package/esm/integrations/breadcrumbs.d.ts.map +1 -1
  49. package/esm/integrations/breadcrumbs.js +6 -3
  50. package/esm/integrations/breadcrumbs.js.map +1 -1
  51. package/esm/integrations/dedupe.d.ts +35 -0
  52. package/esm/integrations/dedupe.d.ts.map +1 -0
  53. package/esm/integrations/dedupe.js +165 -0
  54. package/esm/integrations/dedupe.js.map +1 -0
  55. package/esm/integrations/globalhandlers.d.ts.map +1 -1
  56. package/esm/integrations/globalhandlers.js +6 -8
  57. package/esm/integrations/globalhandlers.js.map +1 -1
  58. package/esm/integrations/index.d.ts +1 -0
  59. package/esm/integrations/index.d.ts.map +1 -1
  60. package/esm/integrations/index.js +1 -0
  61. package/esm/integrations/index.js.map +1 -1
  62. package/esm/sdk.d.ts +2 -2
  63. package/esm/sdk.d.ts.map +1 -1
  64. package/esm/sdk.js +2 -1
  65. package/esm/sdk.js.map +1 -1
  66. package/esm/transports/base.d.ts.map +1 -1
  67. package/esm/transports/base.js +2 -2
  68. package/esm/transports/base.js.map +1 -1
  69. package/esm/transports/fetch.d.ts.map +1 -1
  70. package/esm/transports/fetch.js +20 -18
  71. package/esm/transports/fetch.js.map +1 -1
  72. package/esm/transports/xhr.d.ts.map +1 -1
  73. package/esm/transports/xhr.js +21 -19
  74. package/esm/transports/xhr.js.map +1 -1
  75. package/package.json +5 -5
@@ -1,4 +1,4 @@
1
- /*! @sentry/browser 6.6.0 (9a13c8b) | https://github.com/getsentry/sentry-javascript */
1
+ /*! @sentry/browser 6.8.0 (e93d96f) | https://github.com/getsentry/sentry-javascript */
2
2
  var Sentry = (function (exports) {
3
3
  /** Console logging verbosity for the SDK. */
4
4
  var LogLevel;
@@ -286,7 +286,7 @@ var Sentry = (function (exports) {
286
286
  * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
287
287
  * @returns generated DOM path
288
288
  */
289
- function htmlTreeAsString(elem, keyAttr) {
289
+ function htmlTreeAsString(elem, keyAttrs) {
290
290
  // try/catch both:
291
291
  // - accessing event.target (see getsentry/raven-js#838, #768)
292
292
  // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
@@ -303,7 +303,7 @@ var Sentry = (function (exports) {
303
303
  let nextStr;
304
304
  // eslint-disable-next-line no-plusplus
305
305
  while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) {
306
- nextStr = _htmlElementAsString(currentElem, keyAttr);
306
+ nextStr = _htmlElementAsString(currentElem, keyAttrs);
307
307
  // bail out if
308
308
  // - nextStr is the 'html' element
309
309
  // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
@@ -326,7 +326,8 @@ var Sentry = (function (exports) {
326
326
  * e.g. [HTMLElement] => input#foo.btn[name=baz]
327
327
  * @returns generated DOM path
328
328
  */
329
- function _htmlElementAsString(el, keyAttr) {
329
+ function _htmlElementAsString(el, keyAttrs) {
330
+ var _a, _b;
330
331
  const elem = el;
331
332
  const out = [];
332
333
  let className;
@@ -338,9 +339,13 @@ var Sentry = (function (exports) {
338
339
  return '';
339
340
  }
340
341
  out.push(elem.tagName.toLowerCase());
341
- const keyAttrValue = keyAttr ? elem.getAttribute(keyAttr) : null;
342
- if (keyAttrValue) {
343
- out.push(`[${keyAttr}="${keyAttrValue}"]`);
342
+ // Pairs of attribute keys defined in `serializeAttribute` and their values on element.
343
+ const keyAttrPairs = ((_a = keyAttrs) === null || _a === void 0 ? void 0 : _a.length) ? keyAttrs.filter(keyAttr => elem.getAttribute(keyAttr)).map(keyAttr => [keyAttr, elem.getAttribute(keyAttr)])
344
+ : null;
345
+ if ((_b = keyAttrPairs) === null || _b === void 0 ? void 0 : _b.length) {
346
+ keyAttrPairs.forEach(keyAttrPair => {
347
+ out.push(`[${keyAttrPair[0]}="${keyAttrPair[1]}"]`);
348
+ });
344
349
  }
345
350
  else {
346
351
  if (elem.id) {
@@ -1987,13 +1992,15 @@ var Sentry = (function (exports) {
1987
1992
  /**
1988
1993
  * Add a promise to the queue.
1989
1994
  *
1990
- * @param task Can be any PromiseLike<T>
1995
+ * @param taskProducer A function producing any PromiseLike<T>; In previous versions this used to be `task: PromiseLike<T>`,
1996
+ * however, Promises were instantly created on the call-site, making them fall through the buffer limit.
1991
1997
  * @returns The original promise.
1992
1998
  */
1993
- add(task) {
1999
+ add(taskProducer) {
1994
2000
  if (!this.isReady()) {
1995
2001
  return SyncPromise.reject(new SentryError('Not adding Promise due to buffer limit reached.'));
1996
2002
  }
2003
+ const task = taskProducer();
1997
2004
  if (this._buffer.indexOf(task) === -1) {
1998
2005
  this._buffer.push(task);
1999
2006
  }
@@ -2175,6 +2182,11 @@ var Sentry = (function (exports) {
2175
2182
  return dateNow;
2176
2183
  })();
2177
2184
 
2185
+ /**
2186
+ * Absolute maximum number of breadcrumbs added to an event.
2187
+ * The `maxBreadcrumbs` option cannot be higher than this value.
2188
+ */
2189
+ const MAX_BREADCRUMBS = 100;
2178
2190
  /**
2179
2191
  * Holds additional event information. {@link Scope.applyToEvent} will be
2180
2192
  * called by the client before an event will be sent.
@@ -2463,11 +2475,13 @@ var Sentry = (function (exports) {
2463
2475
  * @inheritDoc
2464
2476
  */
2465
2477
  addBreadcrumb(breadcrumb, maxBreadcrumbs) {
2478
+ const maxCrumbs = typeof maxBreadcrumbs === 'number' ? Math.min(maxBreadcrumbs, MAX_BREADCRUMBS) : MAX_BREADCRUMBS;
2479
+ // No data has been changed, so don't notify scope listeners
2480
+ if (maxCrumbs <= 0) {
2481
+ return this;
2482
+ }
2466
2483
  const mergedBreadcrumb = Object.assign({ timestamp: dateTimestampInSeconds() }, breadcrumb);
2467
- this._breadcrumbs =
2468
- maxBreadcrumbs !== undefined && maxBreadcrumbs >= 0
2469
- ? [...this._breadcrumbs, mergedBreadcrumb].slice(-maxBreadcrumbs)
2470
- : [...this._breadcrumbs, mergedBreadcrumb];
2484
+ this._breadcrumbs = [...this._breadcrumbs, mergedBreadcrumb].slice(-maxCrumbs);
2471
2485
  this._notifyScopeListeners();
2472
2486
  return this;
2473
2487
  }
@@ -2624,10 +2638,10 @@ var Sentry = (function (exports) {
2624
2638
  // eslint-disable-next-line complexity
2625
2639
  update(context = {}) {
2626
2640
  if (context.user) {
2627
- if (context.user.ip_address) {
2641
+ if (!this.ipAddress && context.user.ip_address) {
2628
2642
  this.ipAddress = context.user.ip_address;
2629
2643
  }
2630
- if (!context.did) {
2644
+ if (!this.did && !context.did) {
2631
2645
  this.did = context.user.id || context.user.email || context.user.username;
2632
2646
  }
2633
2647
  }
@@ -2642,7 +2656,7 @@ var Sentry = (function (exports) {
2642
2656
  if (context.init !== undefined) {
2643
2657
  this.init = context.init;
2644
2658
  }
2645
- if (context.did) {
2659
+ if (!this.did && context.did) {
2646
2660
  this.did = `${context.did}`;
2647
2661
  }
2648
2662
  if (typeof context.started === 'number') {
@@ -2664,10 +2678,10 @@ var Sentry = (function (exports) {
2664
2678
  if (context.environment) {
2665
2679
  this.environment = context.environment;
2666
2680
  }
2667
- if (context.ipAddress) {
2681
+ if (!this.ipAddress && context.ipAddress) {
2668
2682
  this.ipAddress = context.ipAddress;
2669
2683
  }
2670
- if (context.userAgent) {
2684
+ if (!this.userAgent && context.userAgent) {
2671
2685
  this.userAgent = context.userAgent;
2672
2686
  }
2673
2687
  if (typeof context.errors === 'number') {
@@ -2726,11 +2740,6 @@ var Sentry = (function (exports) {
2726
2740
  * with {@link Options.maxBreadcrumbs}.
2727
2741
  */
2728
2742
  const DEFAULT_BREADCRUMBS = 100;
2729
- /**
2730
- * Absolute maximum number of breadcrumbs added to an event. The
2731
- * `maxBreadcrumbs` option cannot be higher than this value.
2732
- */
2733
- const MAX_BREADCRUMBS = 100;
2734
2743
  /**
2735
2744
  * @inheritDoc
2736
2745
  */
@@ -2901,7 +2910,7 @@ var Sentry = (function (exports) {
2901
2910
  : mergedBreadcrumb;
2902
2911
  if (finalBreadcrumb === null)
2903
2912
  return;
2904
- scope.addBreadcrumb(finalBreadcrumb, Math.min(maxBreadcrumbs, MAX_BREADCRUMBS));
2913
+ scope.addBreadcrumb(finalBreadcrumb, maxBreadcrumbs);
2905
2914
  }
2906
2915
  /**
2907
2916
  * @inheritDoc
@@ -3033,8 +3042,11 @@ var Sentry = (function (exports) {
3033
3042
  startSession(context) {
3034
3043
  const { scope, client } = this.getStackTop();
3035
3044
  const { release, environment } = (client && client.getOptions()) || {};
3036
- const session = new Session(Object.assign(Object.assign({ release,
3037
- environment }, (scope && { user: scope.getUser() })), context));
3045
+ // Will fetch userAgent if called from browser sdk
3046
+ const global = getGlobalObject();
3047
+ const { userAgent } = global.navigator || {};
3048
+ const session = new Session(Object.assign(Object.assign(Object.assign({ release,
3049
+ environment }, (scope && { user: scope.getUser() })), (userAgent && { userAgent })), context));
3038
3050
  if (scope) {
3039
3051
  // End existing session if there's one
3040
3052
  const currentSession = scope.getSession && scope.getSession();
@@ -3373,18 +3385,23 @@ var Sentry = (function (exports) {
3373
3385
  **/
3374
3386
  class API {
3375
3387
  /** Create a new instance of API */
3376
- constructor(dsn, metadata = {}) {
3388
+ constructor(dsn, metadata = {}, tunnel) {
3377
3389
  this.dsn = dsn;
3378
3390
  this._dsnObject = new Dsn(dsn);
3379
3391
  this.metadata = metadata;
3392
+ this._tunnel = tunnel;
3380
3393
  }
3381
3394
  /** Returns the Dsn object. */
3382
3395
  getDsn() {
3383
3396
  return this._dsnObject;
3384
3397
  }
3398
+ /** Does this transport force envelopes? */
3399
+ forceEnvelope() {
3400
+ return !!this._tunnel;
3401
+ }
3385
3402
  /** Returns the prefix to construct Sentry ingestion API endpoints. */
3386
3403
  getBaseApiEndpoint() {
3387
- const dsn = this._dsnObject;
3404
+ const dsn = this.getDsn();
3388
3405
  const protocol = dsn.protocol ? `${dsn.protocol}:` : '';
3389
3406
  const port = dsn.port ? `:${dsn.port}` : '';
3390
3407
  return `${protocol}//${dsn.host}${port}${dsn.path ? `/${dsn.path}` : ''}/api/`;
@@ -3407,11 +3424,14 @@ var Sentry = (function (exports) {
3407
3424
  * Sending auth as part of the query string and not as custom HTTP headers avoids CORS preflight requests.
3408
3425
  */
3409
3426
  getEnvelopeEndpointWithUrlEncodedAuth() {
3427
+ if (this.forceEnvelope()) {
3428
+ return this._tunnel;
3429
+ }
3410
3430
  return `${this._getEnvelopeEndpoint()}?${this._encodedAuth()}`;
3411
3431
  }
3412
3432
  /** Returns only the path component for the store endpoint. */
3413
3433
  getStoreEndpointPath() {
3414
- const dsn = this._dsnObject;
3434
+ const dsn = this.getDsn();
3415
3435
  return `${dsn.path ? `/${dsn.path}` : ''}/api/${dsn.projectId}/store/`;
3416
3436
  }
3417
3437
  /**
@@ -3420,7 +3440,7 @@ var Sentry = (function (exports) {
3420
3440
  */
3421
3441
  getRequestHeaders(clientName, clientVersion) {
3422
3442
  // CHANGE THIS to use metadata but keep clientName and clientVersion compatible
3423
- const dsn = this._dsnObject;
3443
+ const dsn = this.getDsn();
3424
3444
  const header = [`Sentry sentry_version=${SENTRY_API_VERSION}`];
3425
3445
  header.push(`sentry_client=${clientName}/${clientVersion}`);
3426
3446
  header.push(`sentry_key=${dsn.publicKey}`);
@@ -3434,7 +3454,7 @@ var Sentry = (function (exports) {
3434
3454
  }
3435
3455
  /** Returns the url to the report dialog endpoint. */
3436
3456
  getReportDialogEndpoint(dialogOptions = {}) {
3437
- const dsn = this._dsnObject;
3457
+ const dsn = this.getDsn();
3438
3458
  const endpoint = `${this.getBaseApiEndpoint()}embed/error-page/`;
3439
3459
  const encodedOptions = [];
3440
3460
  encodedOptions.push(`dsn=${dsn.toString()}`);
@@ -3468,13 +3488,16 @@ var Sentry = (function (exports) {
3468
3488
  }
3469
3489
  /** Returns the ingest API endpoint for target. */
3470
3490
  _getIngestEndpoint(target) {
3491
+ if (this._tunnel) {
3492
+ return this._tunnel;
3493
+ }
3471
3494
  const base = this.getBaseApiEndpoint();
3472
- const dsn = this._dsnObject;
3495
+ const dsn = this.getDsn();
3473
3496
  return `${base}${dsn.projectId}/${target}/`;
3474
3497
  }
3475
3498
  /** Returns a URL-encoded string with auth config suitable for a query string. */
3476
3499
  _encodedAuth() {
3477
- const dsn = this._dsnObject;
3500
+ const dsn = this.getDsn();
3478
3501
  const auth = {
3479
3502
  // We send only the minimum set of required information. See
3480
3503
  // https://github.com/getsentry/sentry-javascript/issues/2572.
@@ -3640,6 +3663,10 @@ var Sentry = (function (exports) {
3640
3663
  * @inheritDoc
3641
3664
  */
3642
3665
  captureSession(session) {
3666
+ if (!this._isEnabled()) {
3667
+ logger.warn('SDK not enabled, will not capture session.');
3668
+ return;
3669
+ }
3643
3670
  if (!(typeof session.release === 'string')) {
3644
3671
  logger.warn('Discarded session because of missing or non-string release');
3645
3672
  }
@@ -3705,7 +3732,6 @@ var Sentry = (function (exports) {
3705
3732
  _updateSessionFromEvent(session, event) {
3706
3733
  let crashed = false;
3707
3734
  let errored = false;
3708
- let userAgent;
3709
3735
  const exceptions = event.exception && event.exception.values;
3710
3736
  if (exceptions) {
3711
3737
  errored = true;
@@ -3717,19 +3743,15 @@ var Sentry = (function (exports) {
3717
3743
  }
3718
3744
  }
3719
3745
  }
3720
- const user = event.user;
3721
- if (!session.userAgent) {
3722
- const headers = event.request ? event.request.headers : {};
3723
- for (const key in headers) {
3724
- if (key.toLowerCase() === 'user-agent') {
3725
- userAgent = headers[key];
3726
- break;
3727
- }
3728
- }
3746
+ // A session is updated and that session update is sent in only one of the two following scenarios:
3747
+ // 1. Session with non terminal status and 0 errors + an error occurred -> Will set error count to 1 and send update
3748
+ // 2. Session with non terminal status and 1 error + a crash occurred -> Will set status crashed and send update
3749
+ const sessionNonTerminal = session.status === SessionStatus.Ok;
3750
+ const shouldUpdateAndSend = (sessionNonTerminal && session.errors === 0) || (sessionNonTerminal && crashed);
3751
+ if (shouldUpdateAndSend) {
3752
+ session.update(Object.assign(Object.assign({}, (crashed && { status: SessionStatus.Crashed })), { errors: session.errors || Number(errored || crashed) }));
3753
+ this.captureSession(session);
3729
3754
  }
3730
- session.update(Object.assign(Object.assign({}, (crashed && { status: SessionStatus.Crashed })), { user,
3731
- userAgent, errors: session.errors + Number(errored || crashed) }));
3732
- this.captureSession(session);
3733
3755
  }
3734
3756
  /** Deliver captured session to Sentry */
3735
3757
  _sendSession(session) {
@@ -3920,7 +3942,7 @@ var Sentry = (function (exports) {
3920
3942
  // eslint-disable-next-line @typescript-eslint/unbound-method
3921
3943
  const { beforeSend, sampleRate } = this.getOptions();
3922
3944
  if (!this._isEnabled()) {
3923
- return SyncPromise.reject(new SentryError('SDK not enabled, will not send event.'));
3945
+ return SyncPromise.reject(new SentryError('SDK not enabled, will not capture event.'));
3924
3946
  }
3925
3947
  const isTransaction = event.type === 'transaction';
3926
3948
  // 1.0 === 100% events are sent
@@ -3939,15 +3961,7 @@ var Sentry = (function (exports) {
3939
3961
  return prepared;
3940
3962
  }
3941
3963
  const beforeSendResult = beforeSend(prepared, hint);
3942
- if (typeof beforeSendResult === 'undefined') {
3943
- throw new SentryError('`beforeSend` method has to return `null` or a valid event.');
3944
- }
3945
- else if (isThenable(beforeSendResult)) {
3946
- return beforeSendResult.then(event => event, e => {
3947
- throw new SentryError(`beforeSend rejected with ${e}`);
3948
- });
3949
- }
3950
- return beforeSendResult;
3964
+ return this._ensureBeforeSendRv(beforeSendResult);
3951
3965
  })
3952
3966
  .then(processedEvent => {
3953
3967
  if (processedEvent === null) {
@@ -3986,6 +4000,26 @@ var Sentry = (function (exports) {
3986
4000
  return reason;
3987
4001
  });
3988
4002
  }
4003
+ /**
4004
+ * Verifies that return value of configured `beforeSend` is of expected type.
4005
+ */
4006
+ _ensureBeforeSendRv(rv) {
4007
+ const nullErr = '`beforeSend` method has to return `null` or a valid event.';
4008
+ if (isThenable(rv)) {
4009
+ return rv.then(event => {
4010
+ if (!(isPlainObject(event) || event === null)) {
4011
+ throw new SentryError(nullErr);
4012
+ }
4013
+ return event;
4014
+ }, e => {
4015
+ throw new SentryError(`beforeSend rejected with ${e}`);
4016
+ });
4017
+ }
4018
+ else if (!(isPlainObject(rv) || rv === null)) {
4019
+ throw new SentryError(nullErr);
4020
+ }
4021
+ return rv;
4022
+ }
3989
4023
  }
3990
4024
 
3991
4025
  /** Noop transport */
@@ -4118,7 +4152,7 @@ var Sentry = (function (exports) {
4118
4152
  /** Creates a SentryRequest from a Session. */
4119
4153
  function sessionToSentryRequest(session, api) {
4120
4154
  const sdkInfo = getSdkMetadataForEnvelopeHeader(api);
4121
- const envelopeHeaders = JSON.stringify(Object.assign({ sent_at: new Date().toISOString() }, (sdkInfo && { sdk: sdkInfo })));
4155
+ const envelopeHeaders = JSON.stringify(Object.assign(Object.assign({ sent_at: new Date().toISOString() }, (sdkInfo && { sdk: sdkInfo })), (api.forceEnvelope() && { dsn: api.getDsn().toString() })));
4122
4156
  // I know this is hacky but we don't want to add `session` to request type since it's never rate limited
4123
4157
  const type = 'aggregates' in session ? 'sessions' : 'session';
4124
4158
  const itemHeaders = JSON.stringify({
@@ -4134,7 +4168,7 @@ var Sentry = (function (exports) {
4134
4168
  function eventToSentryRequest(event, api) {
4135
4169
  const sdkInfo = getSdkMetadataForEnvelopeHeader(api);
4136
4170
  const eventType = event.type || 'event';
4137
- const useEnvelope = eventType === 'transaction';
4171
+ const useEnvelope = eventType === 'transaction' || api.forceEnvelope();
4138
4172
  const _a = event.debug_meta || {}, { transactionSampling } = _a, metadata = __rest(_a, ["transactionSampling"]);
4139
4173
  const { method: samplingMethod, rate: sampleRate } = transactionSampling || {};
4140
4174
  if (Object.keys(metadata).length === 0) {
@@ -4154,9 +4188,9 @@ var Sentry = (function (exports) {
4154
4188
  // deserialization. Instead, we only implement a minimal subset of the spec to
4155
4189
  // serialize events inline here.
4156
4190
  if (useEnvelope) {
4157
- const envelopeHeaders = JSON.stringify(Object.assign({ event_id: event.event_id, sent_at: new Date().toISOString() }, (sdkInfo && { sdk: sdkInfo })));
4191
+ const envelopeHeaders = JSON.stringify(Object.assign(Object.assign({ event_id: event.event_id, sent_at: new Date().toISOString() }, (sdkInfo && { sdk: sdkInfo })), (api.forceEnvelope() && { dsn: api.getDsn().toString() })));
4158
4192
  const itemHeaders = JSON.stringify({
4159
- type: event.type,
4193
+ type: eventType,
4160
4194
  // TODO: Right now, sampleRate may or may not be defined (it won't be in the cases of inheritance and
4161
4195
  // explicitly-set sampling decisions). Are we good with that?
4162
4196
  sample_rates: [{ id: samplingMethod, rate: sampleRate }],
@@ -4189,7 +4223,7 @@ var Sentry = (function (exports) {
4189
4223
  hub.bindClient(client);
4190
4224
  }
4191
4225
 
4192
- const SDK_VERSION = '6.6.0';
4226
+ const SDK_VERSION = '6.8.0';
4193
4227
 
4194
4228
  let originalFunctionToString;
4195
4229
  /** Patch toString calls to return proper name for wrapped functions */
@@ -4837,7 +4871,7 @@ var Sentry = (function (exports) {
4837
4871
  this._buffer = new PromiseBuffer(30);
4838
4872
  /** Locks transport after receiving rate limits in a response */
4839
4873
  this._rateLimits = {};
4840
- this._api = new API(options.dsn, options._metadata);
4874
+ this._api = new API(options.dsn, options._metadata, options.tunnel);
4841
4875
  // eslint-disable-next-line deprecation/deprecation
4842
4876
  this.url = this._api.getStoreEndpointWithUrlEncodedAuth();
4843
4877
  }
@@ -4864,7 +4898,7 @@ var Sentry = (function (exports) {
4864
4898
  */
4865
4899
  const limited = this._handleRateLimit(headers);
4866
4900
  if (limited)
4867
- logger.warn(`Too many requests, backing off until: ${this._disabledUntil(requestType)}`);
4901
+ logger.warn(`Too many ${requestType} requests, backing off until: ${this._disabledUntil(requestType)}`);
4868
4902
  if (status === exports.Status.Success) {
4869
4903
  resolve({ status });
4870
4904
  return;
@@ -5013,7 +5047,7 @@ var Sentry = (function (exports) {
5013
5047
  return Promise.reject({
5014
5048
  event: originalPayload,
5015
5049
  type: sentryRequest.type,
5016
- reason: `Transport locked till ${this._disabledUntil(sentryRequest.type)} due to too many requests.`,
5050
+ reason: `Transport for ${sentryRequest.type} requests locked till ${this._disabledUntil(sentryRequest.type)} due to too many requests.`,
5017
5051
  status: 429,
5018
5052
  });
5019
5053
  }
@@ -5032,7 +5066,7 @@ var Sentry = (function (exports) {
5032
5066
  if (this.options.headers !== undefined) {
5033
5067
  options.headers = this.options.headers;
5034
5068
  }
5035
- return this._buffer.add(new SyncPromise((resolve, reject) => {
5069
+ return this._buffer.add(() => new SyncPromise((resolve, reject) => {
5036
5070
  void this._fetch(sentryRequest.url, options)
5037
5071
  .then(response => {
5038
5072
  const headers = {
@@ -5075,11 +5109,11 @@ var Sentry = (function (exports) {
5075
5109
  return Promise.reject({
5076
5110
  event: originalPayload,
5077
5111
  type: sentryRequest.type,
5078
- reason: `Transport locked till ${this._disabledUntil(sentryRequest.type)} due to too many requests.`,
5112
+ reason: `Transport for ${sentryRequest.type} requests locked till ${this._disabledUntil(sentryRequest.type)} due to too many requests.`,
5079
5113
  status: 429,
5080
5114
  });
5081
5115
  }
5082
- return this._buffer.add(new SyncPromise((resolve, reject) => {
5116
+ return this._buffer.add(() => new SyncPromise((resolve, reject) => {
5083
5117
  const request = new XMLHttpRequest();
5084
5118
  request.onreadystatechange = () => {
5085
5119
  if (request.readyState === 4) {
@@ -5135,7 +5169,7 @@ var Sentry = (function (exports) {
5135
5169
  // We return the noop transport here in case there is no Dsn.
5136
5170
  return super._setupTransport();
5137
5171
  }
5138
- const transportOptions = Object.assign(Object.assign({}, this._options.transportOptions), { dsn: this._options.dsn, _metadata: this._options._metadata });
5172
+ const transportOptions = Object.assign(Object.assign({}, this._options.transportOptions), { dsn: this._options.dsn, tunnel: this._options.tunnel, _metadata: this._options._metadata });
5139
5173
  if (this._options.transport) {
5140
5174
  return new this._options.transport(transportOptions);
5141
5175
  }
@@ -5344,9 +5378,9 @@ var Sentry = (function (exports) {
5344
5378
  return;
5345
5379
  }
5346
5380
  const client = currentHub.getClient();
5347
- const event = isPrimitive(error)
5381
+ const event = error === undefined && isString(data.msg)
5348
5382
  ? this._eventFromIncompleteOnError(data.msg, data.url, data.line, data.column)
5349
- : this._enhanceEventWithInitialFrame(eventFromUnknownInput(error, undefined, {
5383
+ : this._enhanceEventWithInitialFrame(eventFromUnknownInput(error || data.msg, undefined, {
5350
5384
  attachStacktrace: client && client.getOptions().attachStacktrace,
5351
5385
  rejection: false,
5352
5386
  }), data.url, data.line, data.column);
@@ -5426,12 +5460,10 @@ var Sentry = (function (exports) {
5426
5460
  // If 'message' is ErrorEvent, get real message from inside
5427
5461
  let message = isErrorEvent(msg) ? msg.message : msg;
5428
5462
  let name;
5429
- if (isString(message)) {
5430
- const groups = message.match(ERROR_TYPES_RE);
5431
- if (groups) {
5432
- name = groups[1];
5433
- message = groups[2];
5434
- }
5463
+ const groups = message.match(ERROR_TYPES_RE);
5464
+ if (groups) {
5465
+ name = groups[1];
5466
+ message = groups[2];
5435
5467
  }
5436
5468
  const event = {
5437
5469
  exception: {
@@ -5826,12 +5858,15 @@ var Sentry = (function (exports) {
5826
5858
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5827
5859
  _domBreadcrumb(handlerData) {
5828
5860
  let target;
5829
- const keyAttr = typeof this._options.dom === 'object' ? this._options.dom.serializeAttribute : undefined;
5861
+ let keyAttrs = typeof this._options.dom === 'object' ? this._options.dom.serializeAttribute : undefined;
5862
+ if (typeof keyAttrs === 'string') {
5863
+ keyAttrs = [keyAttrs];
5864
+ }
5830
5865
  // Accessing event.target can throw (see getsentry/raven-js#838, #768)
5831
5866
  try {
5832
5867
  target = handlerData.event.target
5833
- ? htmlTreeAsString(handlerData.event.target, keyAttr)
5834
- : htmlTreeAsString(handlerData.event, keyAttr);
5868
+ ? htmlTreeAsString(handlerData.event.target, keyAttrs)
5869
+ : htmlTreeAsString(handlerData.event, keyAttrs);
5835
5870
  }
5836
5871
  catch (e) {
5837
5872
  target = '<unknown>';
@@ -6038,6 +6073,169 @@ var Sentry = (function (exports) {
6038
6073
  */
6039
6074
  UserAgent.id = 'UserAgent';
6040
6075
 
6076
+ /** Deduplication filter */
6077
+ class Dedupe {
6078
+ constructor() {
6079
+ /**
6080
+ * @inheritDoc
6081
+ */
6082
+ this.name = Dedupe.id;
6083
+ }
6084
+ /**
6085
+ * @inheritDoc
6086
+ */
6087
+ setupOnce(addGlobalEventProcessor, getCurrentHub) {
6088
+ addGlobalEventProcessor((currentEvent) => {
6089
+ const self = getCurrentHub().getIntegration(Dedupe);
6090
+ if (self) {
6091
+ // Juuust in case something goes wrong
6092
+ try {
6093
+ if (self._shouldDropEvent(currentEvent, self._previousEvent)) {
6094
+ return null;
6095
+ }
6096
+ }
6097
+ catch (_oO) {
6098
+ return (self._previousEvent = currentEvent);
6099
+ }
6100
+ return (self._previousEvent = currentEvent);
6101
+ }
6102
+ return currentEvent;
6103
+ });
6104
+ }
6105
+ /** JSDoc */
6106
+ _shouldDropEvent(currentEvent, previousEvent) {
6107
+ if (!previousEvent) {
6108
+ return false;
6109
+ }
6110
+ if (this._isSameMessageEvent(currentEvent, previousEvent)) {
6111
+ return true;
6112
+ }
6113
+ if (this._isSameExceptionEvent(currentEvent, previousEvent)) {
6114
+ return true;
6115
+ }
6116
+ return false;
6117
+ }
6118
+ /** JSDoc */
6119
+ _isSameMessageEvent(currentEvent, previousEvent) {
6120
+ const currentMessage = currentEvent.message;
6121
+ const previousMessage = previousEvent.message;
6122
+ // If neither event has a message property, they were both exceptions, so bail out
6123
+ if (!currentMessage && !previousMessage) {
6124
+ return false;
6125
+ }
6126
+ // If only one event has a stacktrace, but not the other one, they are not the same
6127
+ if ((currentMessage && !previousMessage) || (!currentMessage && previousMessage)) {
6128
+ return false;
6129
+ }
6130
+ if (currentMessage !== previousMessage) {
6131
+ return false;
6132
+ }
6133
+ if (!this._isSameFingerprint(currentEvent, previousEvent)) {
6134
+ return false;
6135
+ }
6136
+ if (!this._isSameStacktrace(currentEvent, previousEvent)) {
6137
+ return false;
6138
+ }
6139
+ return true;
6140
+ }
6141
+ /** JSDoc */
6142
+ _getFramesFromEvent(event) {
6143
+ const exception = event.exception;
6144
+ if (exception) {
6145
+ try {
6146
+ // @ts-ignore Object could be undefined
6147
+ return exception.values[0].stacktrace.frames;
6148
+ }
6149
+ catch (_oO) {
6150
+ return undefined;
6151
+ }
6152
+ }
6153
+ else if (event.stacktrace) {
6154
+ return event.stacktrace.frames;
6155
+ }
6156
+ return undefined;
6157
+ }
6158
+ /** JSDoc */
6159
+ _isSameStacktrace(currentEvent, previousEvent) {
6160
+ let currentFrames = this._getFramesFromEvent(currentEvent);
6161
+ let previousFrames = this._getFramesFromEvent(previousEvent);
6162
+ // If neither event has a stacktrace, they are assumed to be the same
6163
+ if (!currentFrames && !previousFrames) {
6164
+ return true;
6165
+ }
6166
+ // If only one event has a stacktrace, but not the other one, they are not the same
6167
+ if ((currentFrames && !previousFrames) || (!currentFrames && previousFrames)) {
6168
+ return false;
6169
+ }
6170
+ currentFrames = currentFrames;
6171
+ previousFrames = previousFrames;
6172
+ // If number of frames differ, they are not the same
6173
+ if (previousFrames.length !== currentFrames.length) {
6174
+ return false;
6175
+ }
6176
+ // Otherwise, compare the two
6177
+ for (let i = 0; i < previousFrames.length; i++) {
6178
+ const frameA = previousFrames[i];
6179
+ const frameB = currentFrames[i];
6180
+ if (frameA.filename !== frameB.filename ||
6181
+ frameA.lineno !== frameB.lineno ||
6182
+ frameA.colno !== frameB.colno ||
6183
+ frameA.function !== frameB.function) {
6184
+ return false;
6185
+ }
6186
+ }
6187
+ return true;
6188
+ }
6189
+ /** JSDoc */
6190
+ _getExceptionFromEvent(event) {
6191
+ return event.exception && event.exception.values && event.exception.values[0];
6192
+ }
6193
+ /** JSDoc */
6194
+ _isSameExceptionEvent(currentEvent, previousEvent) {
6195
+ const previousException = this._getExceptionFromEvent(previousEvent);
6196
+ const currentException = this._getExceptionFromEvent(currentEvent);
6197
+ if (!previousException || !currentException) {
6198
+ return false;
6199
+ }
6200
+ if (previousException.type !== currentException.type || previousException.value !== currentException.value) {
6201
+ return false;
6202
+ }
6203
+ if (!this._isSameFingerprint(currentEvent, previousEvent)) {
6204
+ return false;
6205
+ }
6206
+ if (!this._isSameStacktrace(currentEvent, previousEvent)) {
6207
+ return false;
6208
+ }
6209
+ return true;
6210
+ }
6211
+ /** JSDoc */
6212
+ _isSameFingerprint(currentEvent, previousEvent) {
6213
+ let currentFingerprint = currentEvent.fingerprint;
6214
+ let previousFingerprint = previousEvent.fingerprint;
6215
+ // If neither event has a fingerprint, they are assumed to be the same
6216
+ if (!currentFingerprint && !previousFingerprint) {
6217
+ return true;
6218
+ }
6219
+ // If only one event has a fingerprint, but not the other one, they are not the same
6220
+ if ((currentFingerprint && !previousFingerprint) || (!currentFingerprint && previousFingerprint)) {
6221
+ return false;
6222
+ }
6223
+ currentFingerprint = currentFingerprint;
6224
+ previousFingerprint = previousFingerprint;
6225
+ // Otherwise, compare the two
6226
+ try {
6227
+ return !!(currentFingerprint.join('') === previousFingerprint.join(''));
6228
+ }
6229
+ catch (_oO) {
6230
+ return false;
6231
+ }
6232
+ }
6233
+ }
6234
+ /**
6235
+ * @inheritDoc
6236
+ */
6237
+ Dedupe.id = 'Dedupe';
6238
+
6041
6239
 
6042
6240
 
6043
6241
  var BrowserIntegrations = /*#__PURE__*/Object.freeze({
@@ -6046,7 +6244,8 @@ var Sentry = (function (exports) {
6046
6244
  TryCatch: TryCatch,
6047
6245
  Breadcrumbs: Breadcrumbs,
6048
6246
  LinkedErrors: LinkedErrors,
6049
- UserAgent: UserAgent
6247
+ UserAgent: UserAgent,
6248
+ Dedupe: Dedupe
6050
6249
  });
6051
6250
 
6052
6251
  /**
@@ -6118,6 +6317,7 @@ var Sentry = (function (exports) {
6118
6317
  new Breadcrumbs(),
6119
6318
  new GlobalHandlers(),
6120
6319
  new LinkedErrors(),
6320
+ new Dedupe(),
6121
6321
  new UserAgent(),
6122
6322
  ];
6123
6323
  /**