@sentry/replay 7.80.0 → 7.80.2-alpha.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.
package/cjs/index.js CHANGED
@@ -4412,7 +4412,7 @@ function getDomTarget(handlerData) {
4412
4412
  // Accessing event.target can throw (see getsentry/raven-js#838, #768)
4413
4413
  try {
4414
4414
  target = isClick ? getClickTargetNode(handlerData.event) : getTargetNode(handlerData.event);
4415
- message = utils.htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
4415
+ message = utils.getElementIdentifier(target, { maxStringLength: 200 }) || '<unknown>';
4416
4416
  } catch (e) {
4417
4417
  message = '<unknown>';
4418
4418
  }
@@ -4463,7 +4463,7 @@ function getKeyboardBreadcrumb(event) {
4463
4463
  return null;
4464
4464
  }
4465
4465
 
4466
- const message = utils.htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
4466
+ const message = utils.getElementIdentifier(target, { maxStringLength: 200 }) || '<unknown>';
4467
4467
  const baseBreadcrumb = getBaseDomBreadcrumb(target , message);
4468
4468
 
4469
4469
  return createBreadcrumb({
@@ -5540,6 +5540,11 @@ function isReplayEvent(event) {
5540
5540
  return event.type === 'replay_event';
5541
5541
  }
5542
5542
 
5543
+ /** If the event is a feedback event */
5544
+ function isFeedbackEvent(event) {
5545
+ return event.type === 'feedback';
5546
+ }
5547
+
5543
5548
  /**
5544
5549
  * Returns a listener to be added to `client.on('afterSendErrorEvent, listener)`.
5545
5550
  */
@@ -5644,6 +5649,37 @@ function isRrwebError(event, hint) {
5644
5649
  return false;
5645
5650
  }
5646
5651
 
5652
+ /**
5653
+ * Add a feedback breadcrumb event to replay.
5654
+ */
5655
+ function addFeedbackBreadcrumb(replay, event) {
5656
+ replay.triggerUserActivity();
5657
+ replay.addUpdate(() => {
5658
+ if (!event.timestamp) {
5659
+ // Ignore events that don't have timestamps (this shouldn't happen, more of a typing issue)
5660
+ // Return true here so that we don't flush
5661
+ return true;
5662
+ }
5663
+
5664
+ void replay.throttledAddEvent({
5665
+ type: EventType.Custom,
5666
+ timestamp: event.timestamp * 1000,
5667
+ data: {
5668
+ timestamp: event.timestamp,
5669
+ tag: 'breadcrumb',
5670
+ payload: {
5671
+ category: 'sentry.feedback',
5672
+ data: {
5673
+ feedbackId: event.event_id,
5674
+ },
5675
+ },
5676
+ },
5677
+ });
5678
+
5679
+ return false;
5680
+ });
5681
+ }
5682
+
5647
5683
  /**
5648
5684
  * Determine if event should be sampled (only applies in buffer mode).
5649
5685
  * When an event is captured by `hanldleGlobalEvent`, when in buffer mode
@@ -5691,8 +5727,8 @@ function handleGlobalEventListener(
5691
5727
  return event;
5692
5728
  }
5693
5729
 
5694
- // We only want to handle errors & transactions, nothing else
5695
- if (!isErrorEvent(event) && !isTransactionEvent(event)) {
5730
+ // We only want to handle errors, transactions, and feedbacks, nothing else
5731
+ if (!isErrorEvent(event) && !isTransactionEvent(event) && !isFeedbackEvent(event)) {
5696
5732
  return event;
5697
5733
  }
5698
5734
 
@@ -5702,6 +5738,12 @@ function handleGlobalEventListener(
5702
5738
  return event;
5703
5739
  }
5704
5740
 
5741
+ if (isFeedbackEvent(event)) {
5742
+ // Add a replay breadcrumb for this piece of feedback
5743
+ addFeedbackBreadcrumb(replay, event);
5744
+ return event;
5745
+ }
5746
+
5705
5747
  // Unless `captureExceptions` is enabled, we want to ignore errors coming from rrweb
5706
5748
  // As there can be a bunch of stuff going wrong in internals there, that we don't want to bubble up to users
5707
5749
  if (isRrwebError(event, hint) && !replay.getOptions()._experiments.captureExceptions) {
@@ -5978,16 +6020,20 @@ function parseContentLengthHeader(header) {
5978
6020
 
5979
6021
  /** Get the string representation of a body. */
5980
6022
  function getBodyString(body) {
5981
- if (typeof body === 'string') {
5982
- return body;
5983
- }
6023
+ try {
6024
+ if (typeof body === 'string') {
6025
+ return body;
6026
+ }
5984
6027
 
5985
- if (body instanceof URLSearchParams) {
5986
- return body.toString();
5987
- }
6028
+ if (body instanceof URLSearchParams) {
6029
+ return body.toString();
6030
+ }
5988
6031
 
5989
- if (body instanceof FormData) {
5990
- return _serializeFormData(body);
6032
+ if (body instanceof FormData) {
6033
+ return _serializeFormData(body);
6034
+ }
6035
+ } catch (e2) {
6036
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.warn('[Replay] Failed to serialize body', body);
5991
6037
  }
5992
6038
 
5993
6039
  return undefined;
@@ -6099,7 +6145,6 @@ function normalizeNetworkBody(body)
6099
6145
  }
6100
6146
 
6101
6147
  const exceedsSizeLimit = body.length > NETWORK_BODY_MAX_SIZE;
6102
-
6103
6148
  const isProbablyJson = _strIsProbablyJson(body);
6104
6149
 
6105
6150
  if (exceedsSizeLimit) {
@@ -6124,7 +6169,7 @@ function normalizeNetworkBody(body)
6124
6169
  return {
6125
6170
  body: jsonBody,
6126
6171
  };
6127
- } catch (e3) {
6172
+ } catch (e4) {
6128
6173
  // fall back to just send the body as string
6129
6174
  }
6130
6175
  }
@@ -6206,7 +6251,7 @@ function enrichFetchBreadcrumb(
6206
6251
  ) {
6207
6252
  const { input, response } = hint;
6208
6253
 
6209
- const body = _getFetchRequestArgBody(input);
6254
+ const body = input ? _getFetchRequestArgBody(input) : undefined;
6210
6255
  const reqSize = getBodySize(body, options.textEncoder);
6211
6256
 
6212
6257
  const resSize = response ? parseContentLengthHeader(response.headers.get('content-length')) : undefined;
@@ -6226,7 +6271,8 @@ async function _prepareFetchData(
6226
6271
 
6227
6272
  ,
6228
6273
  ) {
6229
- const { startTimestamp, endTimestamp } = hint;
6274
+ const now = Date.now();
6275
+ const { startTimestamp = now, endTimestamp = now } = hint;
6230
6276
 
6231
6277
  const {
6232
6278
  url,
@@ -6260,7 +6306,7 @@ function _getRequestInfo(
6260
6306
  input,
6261
6307
  requestBodySize,
6262
6308
  ) {
6263
- const headers = getRequestHeaders(input, networkRequestHeaders);
6309
+ const headers = input ? getRequestHeaders(input, networkRequestHeaders) : {};
6264
6310
 
6265
6311
  if (!networkCaptureBodies) {
6266
6312
  return buildNetworkRequestOrResponse(headers, requestBodySize, undefined);
@@ -6288,9 +6334,9 @@ async function _getResponseInfo(
6288
6334
  return buildSkippedNetworkRequestOrResponse(responseBodySize);
6289
6335
  }
6290
6336
 
6291
- const headers = getAllHeaders(response.headers, networkResponseHeaders);
6337
+ const headers = response ? getAllHeaders(response.headers, networkResponseHeaders) : {};
6292
6338
 
6293
- if (!networkCaptureBodies && responseBodySize !== undefined) {
6339
+ if (!response || (!networkCaptureBodies && responseBodySize !== undefined)) {
6294
6340
  return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
6295
6341
  }
6296
6342
 
@@ -6314,7 +6360,8 @@ async function _getResponseInfo(
6314
6360
  }
6315
6361
 
6316
6362
  return buildNetworkRequestOrResponse(headers, size, undefined);
6317
- } catch (e) {
6363
+ } catch (error) {
6364
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.warn('[Replay] Failed to serialize response body', error);
6318
6365
  // fallback
6319
6366
  return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
6320
6367
  }
@@ -6323,7 +6370,7 @@ async function _getResponseInfo(
6323
6370
  async function _parseFetchBody(response) {
6324
6371
  try {
6325
6372
  return await response.text();
6326
- } catch (e2) {
6373
+ } catch (e) {
6327
6374
  return undefined;
6328
6375
  }
6329
6376
  }
@@ -6419,6 +6466,10 @@ function enrichXhrBreadcrumb(
6419
6466
  ) {
6420
6467
  const { xhr, input } = hint;
6421
6468
 
6469
+ if (!xhr) {
6470
+ return;
6471
+ }
6472
+
6422
6473
  const reqSize = getBodySize(input, options.textEncoder);
6423
6474
  const resSize = xhr.getResponseHeader('content-length')
6424
6475
  ? parseContentLengthHeader(xhr.getResponseHeader('content-length'))
@@ -6437,7 +6488,8 @@ function _prepareXhrData(
6437
6488
  hint,
6438
6489
  options,
6439
6490
  ) {
6440
- const { startTimestamp, endTimestamp, input, xhr } = hint;
6491
+ const now = Date.now();
6492
+ const { startTimestamp = now, endTimestamp = now, input, xhr } = hint;
6441
6493
 
6442
6494
  const {
6443
6495
  url,
@@ -6451,7 +6503,7 @@ function _prepareXhrData(
6451
6503
  return null;
6452
6504
  }
6453
6505
 
6454
- if (!urlMatches(url, options.networkDetailAllowUrls) || urlMatches(url, options.networkDetailDenyUrls)) {
6506
+ if (!xhr || !urlMatches(url, options.networkDetailAllowUrls) || urlMatches(url, options.networkDetailDenyUrls)) {
6455
6507
  const request = buildSkippedNetworkRequestOrResponse(requestBodySize);
6456
6508
  const response = buildSkippedNetworkRequestOrResponse(responseBodySize);
6457
6509
  return {
@@ -6471,16 +6523,11 @@ function _prepareXhrData(
6471
6523
  : {};
6472
6524
  const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders);
6473
6525
 
6474
- const request = buildNetworkRequestOrResponse(
6475
- networkRequestHeaders,
6476
- requestBodySize,
6477
- options.networkCaptureBodies ? getBodyString(input) : undefined,
6478
- );
6479
- const response = buildNetworkRequestOrResponse(
6480
- networkResponseHeaders,
6481
- responseBodySize,
6482
- options.networkCaptureBodies ? hint.xhr.responseText : undefined,
6483
- );
6526
+ const requestBody = options.networkCaptureBodies ? getBodyString(input) : undefined;
6527
+ const responseBody = options.networkCaptureBodies ? _getXhrResponseBody(xhr) : undefined;
6528
+
6529
+ const request = buildNetworkRequestOrResponse(networkRequestHeaders, requestBodySize, requestBody);
6530
+ const response = buildNetworkRequestOrResponse(networkResponseHeaders, responseBodySize, responseBody);
6484
6531
 
6485
6532
  return {
6486
6533
  startTimestamp,
@@ -6507,6 +6554,20 @@ function getResponseHeaders(xhr) {
6507
6554
  }, {});
6508
6555
  }
6509
6556
 
6557
+ function _getXhrResponseBody(xhr) {
6558
+ try {
6559
+ return xhr.responseText;
6560
+ } catch (e) {} // eslint-disable-line no-empty
6561
+
6562
+ // Try to manually parse the response body, if responseText fails
6563
+ try {
6564
+ const response = xhr.response;
6565
+ return getBodyString(response);
6566
+ } catch (e2) {} // eslint-disable-line no-empty
6567
+
6568
+ return undefined;
6569
+ }
6570
+
6510
6571
  /**
6511
6572
  * This method does two things:
6512
6573
  * - It enriches the regular XHR/fetch breadcrumbs with request/response size data