@sentry/replay 7.85.0 → 7.87.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
@@ -2945,6 +2945,10 @@ function initObservers(o, _hooks = {}) {
2945
2945
  };
2946
2946
  const selectionObserver = initSelectionObserver(o);
2947
2947
  const customElementObserver = initCustomElementObserver(o);
2948
+ const pluginHandlers = [];
2949
+ for (const plugin of o.plugins) {
2950
+ pluginHandlers.push(plugin.observer(plugin.callback, currentWindow, plugin.options));
2951
+ }
2948
2952
  return callbackWrapper(() => {
2949
2953
  mutationBuffers.forEach((b) => b.reset());
2950
2954
  mutationObserver.disconnect();
@@ -2960,6 +2964,7 @@ function initObservers(o, _hooks = {}) {
2960
2964
  fontObserver();
2961
2965
  selectionObserver();
2962
2966
  customElementObserver();
2967
+ pluginHandlers.forEach((h) => h());
2963
2968
  });
2964
2969
  }
2965
2970
  function hasNestedCSSRule(prop) {
@@ -3444,7 +3449,7 @@ const mirror = createMirror();
3444
3449
  function record(options = {}) {
3445
3450
  const { emit, checkoutEveryNms, checkoutEveryNth, blockClass = 'rr-block', blockSelector = null, unblockSelector = null, ignoreClass = 'rr-ignore', ignoreSelector = null, maskAllText = false, maskTextClass = 'rr-mask', unmaskTextClass = null, maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, maskAllInputs, maskInputOptions: _maskInputOptions, slimDOMOptions: _slimDOMOptions, maskAttributeFn, maskInputFn, maskTextFn, packFn, sampling = {}, dataURLOptions = {}, mousemoveWait, recordCanvas = false, recordCrossOriginIframes = false, recordAfter = options.recordAfter === 'DOMContentLoaded'
3446
3451
  ? options.recordAfter
3447
- : 'load', userTriggeredOnInput = false, collectFonts = false, inlineImages = false, keepIframeSrcFn = () => false, ignoreCSSAttributes = new Set([]), errorHandler, onMutation, getCanvasManager, } = options;
3452
+ : 'load', userTriggeredOnInput = false, collectFonts = false, inlineImages = false, plugins, keepIframeSrcFn = () => false, ignoreCSSAttributes = new Set([]), errorHandler, onMutation, getCanvasManager, } = options;
3448
3453
  registerErrorHandler(errorHandler);
3449
3454
  const inEmittingFrame = recordCrossOriginIframes
3450
3455
  ? window.parent === window
@@ -3510,6 +3515,11 @@ function record(options = {}) {
3510
3515
  let lastFullSnapshotEvent;
3511
3516
  let incrementalSnapshotCount = 0;
3512
3517
  const eventProcessor = (e) => {
3518
+ for (const plugin of plugins || []) {
3519
+ if (plugin.eventProcessor) {
3520
+ e = plugin.eventProcessor(e);
3521
+ }
3522
+ }
3513
3523
  if (packFn &&
3514
3524
  !passEmitsToParent) {
3515
3525
  e = packFn(e);
@@ -3585,6 +3595,14 @@ function record(options = {}) {
3585
3595
  recordCrossOriginIframes,
3586
3596
  wrappedEmit,
3587
3597
  });
3598
+ for (const plugin of plugins || []) {
3599
+ if (plugin.getMirror)
3600
+ plugin.getMirror({
3601
+ nodeMirror: mirror,
3602
+ crossOriginIframeMirror: iframeManager.crossOriginIframeMirror,
3603
+ crossOriginIframeStyleMirror: iframeManager.crossOriginIframeStyleMirror,
3604
+ });
3605
+ }
3588
3606
  const processedNodeManager = new ProcessedNodeManager();
3589
3607
  const canvasManager = getCanvasManager
3590
3608
  ? getCanvasManager({
@@ -3690,7 +3708,7 @@ function record(options = {}) {
3690
3708
  node,
3691
3709
  initialOffset: getWindowScroll(window),
3692
3710
  },
3693
- }), isCheckout);
3711
+ }));
3694
3712
  mutationBuffers.forEach((buf) => buf.unlock());
3695
3713
  if (document.adoptedStyleSheets && document.adoptedStyleSheets.length > 0)
3696
3714
  stylesheetManager.adoptStyleSheets(document.adoptedStyleSheets, mirror.getId(document));
@@ -3699,6 +3717,7 @@ function record(options = {}) {
3699
3717
  try {
3700
3718
  const handlers = [];
3701
3719
  const observe = (doc) => {
3720
+ var _a;
3702
3721
  return callbackWrapper(initObservers)({
3703
3722
  onMutation,
3704
3723
  mutationCb: wrappedMutationEmit,
@@ -3782,7 +3801,17 @@ function record(options = {}) {
3782
3801
  processedNodeManager,
3783
3802
  canvasManager,
3784
3803
  ignoreCSSAttributes,
3785
- plugins: [],
3804
+ plugins: ((_a = plugins === null || plugins === void 0 ? void 0 : plugins.filter((p) => p.observer)) === null || _a === void 0 ? void 0 : _a.map((p) => ({
3805
+ observer: p.observer,
3806
+ options: p.options,
3807
+ callback: (payload) => wrappedEmit(wrapEvent({
3808
+ type: EventType.Plugin,
3809
+ data: {
3810
+ plugin: p.name,
3811
+ payload,
3812
+ },
3813
+ })),
3814
+ }))) || [],
3786
3815
  }, {});
3787
3816
  };
3788
3817
  iframeManager.addLoadListener((iframeEl) => {
@@ -5641,6 +5670,40 @@ function isBaseTransportSend() {
5641
5670
  );
5642
5671
  }
5643
5672
 
5673
+ /**
5674
+ * Returns a listener to be added to `client.on('afterSendErrorEvent, listener)`.
5675
+ */
5676
+ function handleBeforeSendEvent(replay) {
5677
+ return (event) => {
5678
+ if (!replay.isEnabled() || !isErrorEvent(event)) {
5679
+ return;
5680
+ }
5681
+
5682
+ handleHydrationError(replay, event);
5683
+ };
5684
+ }
5685
+
5686
+ function handleHydrationError(replay, event) {
5687
+ const exceptionValue = event.exception && event.exception.values && event.exception.values[0].value;
5688
+ if (typeof exceptionValue !== 'string') {
5689
+ return;
5690
+ }
5691
+
5692
+ if (
5693
+ // Only matches errors in production builds of react-dom
5694
+ // Example https://reactjs.org/docs/error-decoder.html?invariant=423
5695
+ exceptionValue.match(/reactjs\.org\/docs\/error-decoder\.html\?invariant=(418|419|422|423|425)/) ||
5696
+ // Development builds of react-dom
5697
+ // Example Text: content did not match. Server: "A" Client: "B"
5698
+ exceptionValue.match(/(hydration|content does not match|did not match)/i)
5699
+ ) {
5700
+ const breadcrumb = createBreadcrumb({
5701
+ category: 'replay.hydrate-error',
5702
+ });
5703
+ addBreadcrumbEvent(replay, breadcrumb);
5704
+ }
5705
+ }
5706
+
5644
5707
  /**
5645
5708
  * Returns true if we think the given event is an error originating inside of rrweb.
5646
5709
  */
@@ -6965,6 +7028,7 @@ function addGlobalListeners(replay) {
6965
7028
 
6966
7029
  // If a custom client has no hooks yet, we continue to use the "old" implementation
6967
7030
  if (hasHooks(client)) {
7031
+ client.on('beforeSendEvent', handleBeforeSendEvent(replay));
6968
7032
  client.on('afterSendEvent', handleAfterSendEvent(replay));
6969
7033
  client.on('createDsc', (dsc) => {
6970
7034
  const replayId = replay.getSessionId();
@@ -7872,6 +7936,7 @@ class ReplayContainer {
7872
7936
  */
7873
7937
  startRecording() {
7874
7938
  try {
7939
+ const canvas = this._options._experiments.canvas;
7875
7940
  this._stopRecording = record({
7876
7941
  ...this._recordingOptions,
7877
7942
  // When running in error sampling mode, we need to overwrite `checkoutEveryNms`
@@ -7880,6 +7945,12 @@ class ReplayContainer {
7880
7945
  ...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }),
7881
7946
  emit: getHandleRecordingEmit(this),
7882
7947
  onMutation: this._onMutationHandler,
7948
+ ...(canvas && {
7949
+ recordCanvas: true,
7950
+ sampling: { canvas: canvas.fps || 4 },
7951
+ dataURLOptions: { quality: canvas.quality || 0.6 },
7952
+ getCanvasManager: canvas.manager,
7953
+ }),
7883
7954
  });
7884
7955
  } catch (err) {
7885
7956
  this._handleException(err);