@sentry/replay 7.81.1 → 7.82.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 (31) hide show
  1. package/cjs/index.js +133 -36
  2. package/cjs/index.js.map +1 -1
  3. package/esm/index.js +135 -38
  4. package/esm/index.js.map +1 -1
  5. package/package.json +6 -6
  6. package/types/coreHandlers/handleDom.d.ts +3 -4
  7. package/types/coreHandlers/handleDom.d.ts.map +1 -1
  8. package/types/coreHandlers/handleFetch.d.ts +1 -1
  9. package/types/coreHandlers/handleHistory.d.ts +3 -7
  10. package/types/coreHandlers/handleHistory.d.ts.map +1 -1
  11. package/types/coreHandlers/handleXhr.d.ts +1 -1
  12. package/types/coreHandlers/util/domUtils.d.ts +2 -7
  13. package/types/coreHandlers/util/domUtils.d.ts.map +1 -1
  14. package/types/coreHandlers/util/fetchUtils.d.ts +5 -1
  15. package/types/coreHandlers/util/fetchUtils.d.ts.map +1 -1
  16. package/types/coreHandlers/util/networkUtils.d.ts +4 -4
  17. package/types/coreHandlers/util/networkUtils.d.ts.map +1 -1
  18. package/types/coreHandlers/util/xhrUtils.d.ts.map +1 -1
  19. package/types/types/performance.d.ts +1 -1
  20. package/types/types/performance.d.ts.map +1 -1
  21. package/types/types/request.d.ts +1 -1
  22. package/types/types/request.d.ts.map +1 -1
  23. package/types-ts3.8/coreHandlers/handleDom.d.ts +3 -4
  24. package/types-ts3.8/coreHandlers/handleFetch.d.ts +1 -1
  25. package/types-ts3.8/coreHandlers/handleHistory.d.ts +3 -7
  26. package/types-ts3.8/coreHandlers/handleXhr.d.ts +1 -1
  27. package/types-ts3.8/coreHandlers/util/domUtils.d.ts +2 -7
  28. package/types-ts3.8/coreHandlers/util/fetchUtils.d.ts +5 -1
  29. package/types-ts3.8/coreHandlers/util/networkUtils.d.ts +7 -4
  30. package/types-ts3.8/types/performance.d.ts +1 -1
  31. package/types-ts3.8/types/request.d.ts +1 -1
package/cjs/index.js CHANGED
@@ -4341,12 +4341,13 @@ const handleDomListener = (
4341
4341
  }
4342
4342
 
4343
4343
  const isClick = handlerData.name === 'click';
4344
- const event = isClick && (handlerData.event );
4344
+ const event = isClick ? (handlerData.event ) : undefined;
4345
4345
  // Ignore clicks if ctrl/alt/meta/shift keys are held down as they alter behavior of clicks (e.g. open in new tab)
4346
4346
  if (
4347
4347
  isClick &&
4348
4348
  replay.clickDetector &&
4349
4349
  event &&
4350
+ event.target &&
4350
4351
  !event.altKey &&
4351
4352
  !event.metaKey &&
4352
4353
  !event.ctrlKey &&
@@ -5472,7 +5473,7 @@ async function _addEvent(
5472
5473
  (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error(error);
5473
5474
  await replay.stop({ reason });
5474
5475
 
5475
- const client = core.getCurrentHub().getClient();
5476
+ const client = core.getClient();
5476
5477
 
5477
5478
  if (client) {
5478
5479
  client.recordDroppedEvent('internal_sdk_error', 'replay');
@@ -5618,7 +5619,7 @@ function handleErrorEvent(replay, event) {
5618
5619
  }
5619
5620
 
5620
5621
  function isBaseTransportSend() {
5621
- const client = core.getCurrentHub().getClient();
5622
+ const client = core.getClient();
5622
5623
  if (!client) {
5623
5624
  return false;
5624
5625
  }
@@ -5824,7 +5825,7 @@ function handleHistory(handlerData) {
5824
5825
  }
5825
5826
 
5826
5827
  /**
5827
- * Returns a listener to be added to `addInstrumentationHandler('history', listener)`.
5828
+ * Returns a listener to be added to `addHistoryInstrumentationHandler(listener)`.
5828
5829
  */
5829
5830
  function handleHistorySpanListener(replay) {
5830
5831
  return (handlerData) => {
@@ -5913,7 +5914,7 @@ function handleFetch(handlerData) {
5913
5914
  }
5914
5915
 
5915
5916
  /**
5916
- * Returns a listener to be added to `addInstrumentationHandler('fetch', listener)`.
5917
+ * Returns a listener to be added to `addFetchInstrumentationHandler(listener)`.
5917
5918
  */
5918
5919
  function handleFetchSpanListener(replay) {
5919
5920
  return (handlerData) => {
@@ -5957,7 +5958,7 @@ function handleXhr(handlerData) {
5957
5958
  }
5958
5959
 
5959
5960
  /**
5960
- * Returns a listener to be added to `addInstrumentationHandler('xhr', listener)`.
5961
+ * Returns a listener to be added to `addXhrInstrumentationHandler(listener)`.
5961
5962
  */
5962
5963
  function handleXhrSpanListener(replay) {
5963
5964
  return (handlerData) => {
@@ -6024,23 +6025,47 @@ function parseContentLengthHeader(header) {
6024
6025
  function getBodyString(body) {
6025
6026
  try {
6026
6027
  if (typeof body === 'string') {
6027
- return body;
6028
+ return [body];
6028
6029
  }
6029
6030
 
6030
6031
  if (body instanceof URLSearchParams) {
6031
- return body.toString();
6032
+ return [body.toString()];
6032
6033
  }
6033
6034
 
6034
6035
  if (body instanceof FormData) {
6035
- return _serializeFormData(body);
6036
+ return [_serializeFormData(body)];
6036
6037
  }
6037
6038
  } catch (e2) {
6038
6039
  (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.warn('[Replay] Failed to serialize body', body);
6040
+ return [undefined, 'BODY_PARSE_ERROR'];
6039
6041
  }
6040
6042
 
6041
6043
  (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.info('[Replay] Skipping network body because of body type', body);
6042
6044
 
6043
- return undefined;
6045
+ return [undefined];
6046
+ }
6047
+
6048
+ /** Merge a warning into an existing network request/response. */
6049
+ function mergeWarning(
6050
+ info,
6051
+ warning,
6052
+ ) {
6053
+ if (!info) {
6054
+ return {
6055
+ headers: {},
6056
+ size: undefined,
6057
+ _meta: {
6058
+ warnings: [warning],
6059
+ },
6060
+ };
6061
+ }
6062
+
6063
+ const newMeta = { ...info._meta };
6064
+ const existingWarnings = newMeta.warnings || [];
6065
+ newMeta.warnings = [...existingWarnings, warning];
6066
+
6067
+ info._meta = newMeta;
6068
+ return info;
6044
6069
  }
6045
6070
 
6046
6071
  /** Convert ReplayNetworkRequestData to a PerformanceEntry. */
@@ -6173,7 +6198,7 @@ function normalizeNetworkBody(body)
6173
6198
  return {
6174
6199
  body: jsonBody,
6175
6200
  };
6176
- } catch (e4) {
6201
+ } catch (e3) {
6177
6202
  // fall back to just send the body as string
6178
6203
  }
6179
6204
  }
@@ -6318,10 +6343,17 @@ function _getRequestInfo(
6318
6343
 
6319
6344
  // We only want to transmit string or string-like bodies
6320
6345
  const requestBody = _getFetchRequestArgBody(input);
6321
- const bodyStr = getBodyString(requestBody);
6322
- return buildNetworkRequestOrResponse(headers, requestBodySize, bodyStr);
6346
+ const [bodyStr, warning] = getBodyString(requestBody);
6347
+ const data = buildNetworkRequestOrResponse(headers, requestBodySize, bodyStr);
6348
+
6349
+ if (warning) {
6350
+ return mergeWarning(data, warning);
6351
+ }
6352
+
6353
+ return data;
6323
6354
  }
6324
6355
 
6356
+ /** Exported only for tests. */
6325
6357
  async function _getResponseInfo(
6326
6358
  captureDetails,
6327
6359
  {
@@ -6344,12 +6376,35 @@ async function _getResponseInfo(
6344
6376
  return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
6345
6377
  }
6346
6378
 
6347
- // Only clone the response if we need to
6348
- try {
6349
- // We have to clone this, as the body can only be read once
6350
- const res = response.clone();
6351
- const bodyText = await _parseFetchBody(res);
6379
+ const [bodyText, warning] = await _parseFetchResponseBody(response);
6380
+ const result = getResponseData(bodyText, {
6381
+ networkCaptureBodies,
6382
+ textEncoder,
6383
+ responseBodySize,
6384
+ captureDetails,
6385
+ headers,
6386
+ });
6387
+
6388
+ if (warning) {
6389
+ return mergeWarning(result, warning);
6390
+ }
6391
+
6392
+ return result;
6393
+ }
6394
+
6395
+ function getResponseData(
6396
+ bodyText,
6397
+ {
6398
+ networkCaptureBodies,
6399
+ textEncoder,
6400
+ responseBodySize,
6401
+ captureDetails,
6402
+ headers,
6403
+ }
6352
6404
 
6405
+ ,
6406
+ ) {
6407
+ try {
6353
6408
  const size =
6354
6409
  bodyText && bodyText.length && responseBodySize === undefined
6355
6410
  ? getBodySize(bodyText, textEncoder)
@@ -6371,11 +6426,19 @@ async function _getResponseInfo(
6371
6426
  }
6372
6427
  }
6373
6428
 
6374
- async function _parseFetchBody(response) {
6429
+ async function _parseFetchResponseBody(response) {
6430
+ const res = _tryCloneResponse(response);
6431
+
6432
+ if (!res) {
6433
+ return [undefined, 'BODY_PARSE_ERROR'];
6434
+ }
6435
+
6375
6436
  try {
6376
- return await response.text();
6377
- } catch (e) {
6378
- return undefined;
6437
+ const text = await _tryGetResponseText(res);
6438
+ return [text];
6439
+ } catch (error) {
6440
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.warn('[Replay] Failed to get text body from response', error);
6441
+ return [undefined, 'BODY_PARSE_ERROR'];
6379
6442
  }
6380
6443
  }
6381
6444
 
@@ -6438,6 +6501,40 @@ function getHeadersFromOptions(
6438
6501
  return getAllowedHeaders(headers, allowedHeaders);
6439
6502
  }
6440
6503
 
6504
+ function _tryCloneResponse(response) {
6505
+ try {
6506
+ // We have to clone this, as the body can only be read once
6507
+ return response.clone();
6508
+ } catch (error) {
6509
+ // this can throw if the response was already consumed before
6510
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.warn('[Replay] Failed to clone response body', error);
6511
+ }
6512
+ }
6513
+
6514
+ /**
6515
+ * Get the response body of a fetch request, or timeout after 500ms.
6516
+ * Fetch can return a streaming body, that may not resolve (or not for a long time).
6517
+ * If that happens, we rather abort after a short time than keep waiting for this.
6518
+ */
6519
+ function _tryGetResponseText(response) {
6520
+ return new Promise((resolve, reject) => {
6521
+ const timeout = setTimeout(() => reject(new Error('Timeout while trying to read response body')), 500);
6522
+
6523
+ _getResponseText(response)
6524
+ .then(
6525
+ txt => resolve(txt),
6526
+ reason => reject(reason),
6527
+ )
6528
+ .finally(() => clearTimeout(timeout));
6529
+ });
6530
+ }
6531
+
6532
+ async function _getResponseText(response) {
6533
+ // Force this to be a promise, just to be safe
6534
+ // eslint-disable-next-line no-return-await
6535
+ return await response.text();
6536
+ }
6537
+
6441
6538
  /**
6442
6539
  * Capture an XHR breadcrumb to a replay.
6443
6540
  * This adds additional data (where approriate).
@@ -6527,8 +6624,8 @@ function _prepareXhrData(
6527
6624
  : {};
6528
6625
  const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders);
6529
6626
 
6530
- const requestBody = options.networkCaptureBodies ? getBodyString(input) : undefined;
6531
- const responseBody = options.networkCaptureBodies ? _getXhrResponseBody(xhr) : undefined;
6627
+ const [requestBody, requestWarning] = options.networkCaptureBodies ? getBodyString(input) : [undefined];
6628
+ const [responseBody, responseWarning] = options.networkCaptureBodies ? _getXhrResponseBody(xhr) : [undefined];
6532
6629
 
6533
6630
  const request = buildNetworkRequestOrResponse(networkRequestHeaders, requestBodySize, requestBody);
6534
6631
  const response = buildNetworkRequestOrResponse(networkResponseHeaders, responseBodySize, responseBody);
@@ -6539,8 +6636,8 @@ function _prepareXhrData(
6539
6636
  url,
6540
6637
  method,
6541
6638
  statusCode,
6542
- request,
6543
- response,
6639
+ request: requestWarning ? mergeWarning(request, requestWarning) : request,
6640
+ response: responseWarning ? mergeWarning(response, responseWarning) : response,
6544
6641
  };
6545
6642
  }
6546
6643
 
@@ -6563,7 +6660,7 @@ function _getXhrResponseBody(xhr) {
6563
6660
  const errors = [];
6564
6661
 
6565
6662
  try {
6566
- return xhr.responseText;
6663
+ return [xhr.responseText];
6567
6664
  } catch (e) {
6568
6665
  errors.push(e);
6569
6666
  }
@@ -6578,7 +6675,7 @@ function _getXhrResponseBody(xhr) {
6578
6675
 
6579
6676
  (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.warn('[Replay] Failed to get xhr response body', ...errors);
6580
6677
 
6581
- return undefined;
6678
+ return [undefined];
6582
6679
  }
6583
6680
 
6584
6681
  /**
@@ -6588,7 +6685,7 @@ function _getXhrResponseBody(xhr) {
6588
6685
  * (enriching it with further data that is _not_ added to the regular breadcrumbs)
6589
6686
  */
6590
6687
  function handleNetworkBreadcrumbs(replay) {
6591
- const client = core.getCurrentHub().getClient();
6688
+ const client = core.getClient();
6592
6689
 
6593
6690
  try {
6594
6691
  const textEncoder = new TextEncoder();
@@ -6615,8 +6712,8 @@ function handleNetworkBreadcrumbs(replay) {
6615
6712
  client.on('beforeAddBreadcrumb', (breadcrumb, hint) => beforeAddNetworkBreadcrumb(options, breadcrumb, hint));
6616
6713
  } else {
6617
6714
  // Fallback behavior
6618
- utils.addInstrumentationHandler('fetch', handleFetchSpanListener(replay));
6619
- utils.addInstrumentationHandler('xhr', handleXhrSpanListener(replay));
6715
+ utils.addFetchInstrumentationHandler(handleFetchSpanListener(replay));
6716
+ utils.addXhrInstrumentationHandler(handleXhrSpanListener(replay));
6620
6717
  }
6621
6718
  } catch (e2) {
6622
6719
  // Do nothing
@@ -6786,11 +6883,11 @@ function normalizeConsoleBreadcrumb(
6786
6883
  function addGlobalListeners(replay) {
6787
6884
  // Listeners from core SDK //
6788
6885
  const scope = core.getCurrentHub().getScope();
6789
- const client = core.getCurrentHub().getClient();
6886
+ const client = core.getClient();
6790
6887
 
6791
6888
  scope.addScopeListener(handleScopeListener(replay));
6792
- utils.addInstrumentationHandler('dom', handleDomListener(replay));
6793
- utils.addInstrumentationHandler('history', handleHistorySpanListener(replay));
6889
+ utils.addClickKeypressInstrumentationHandler(handleDomListener(replay));
6890
+ utils.addHistoryInstrumentationHandler(handleHistorySpanListener(replay));
6794
6891
  handleNetworkBreadcrumbs(replay);
6795
6892
 
6796
6893
  // Tag all (non replay) events that get sent to Sentry with the current
@@ -8488,7 +8585,7 @@ class ReplayContainer {
8488
8585
  // In this case, we want to completely stop the replay - otherwise, we may get inconsistent segments
8489
8586
  void this.stop({ reason: 'sendReplay' });
8490
8587
 
8491
- const client = core.getCurrentHub().getClient();
8588
+ const client = core.getClient();
8492
8589
 
8493
8590
  if (client) {
8494
8591
  client.recordDroppedEvent('send_error', 'replay');
@@ -9053,7 +9150,7 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
9053
9150
 
9054
9151
  /** Parse Replay-related options from SDK options */
9055
9152
  function loadReplayOptionsFromClient(initialOptions) {
9056
- const client = core.getCurrentHub().getClient();
9153
+ const client = core.getClient();
9057
9154
  const opt = client && (client.getOptions() );
9058
9155
 
9059
9156
  const finalOptions = { sessionSampleRate: 0, errorSampleRate: 0, ...utils.dropUndefinedKeys(initialOptions) };