@sentry/replay 7.86.0 → 7.88.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) {
@@ -3439,12 +3444,13 @@ function wrapEvent(e) {
3439
3444
  eWithTime.timestamp = nowTimestamp();
3440
3445
  return eWithTime;
3441
3446
  }
3447
+ let _wrappedEmit;
3442
3448
  let _takeFullSnapshot;
3443
3449
  const mirror = createMirror();
3444
3450
  function record(options = {}) {
3445
3451
  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
3452
  ? options.recordAfter
3447
- : 'load', userTriggeredOnInput = false, collectFonts = false, inlineImages = false, keepIframeSrcFn = () => false, ignoreCSSAttributes = new Set([]), errorHandler, onMutation, getCanvasManager, } = options;
3453
+ : 'load', userTriggeredOnInput = false, collectFonts = false, inlineImages = false, plugins, keepIframeSrcFn = () => false, ignoreCSSAttributes = new Set([]), errorHandler, onMutation, getCanvasManager, } = options;
3448
3454
  registerErrorHandler(errorHandler);
3449
3455
  const inEmittingFrame = recordCrossOriginIframes
3450
3456
  ? window.parent === window
@@ -3510,6 +3516,11 @@ function record(options = {}) {
3510
3516
  let lastFullSnapshotEvent;
3511
3517
  let incrementalSnapshotCount = 0;
3512
3518
  const eventProcessor = (e) => {
3519
+ for (const plugin of plugins || []) {
3520
+ if (plugin.eventProcessor) {
3521
+ e = plugin.eventProcessor(e);
3522
+ }
3523
+ }
3513
3524
  if (packFn &&
3514
3525
  !passEmitsToParent) {
3515
3526
  e = packFn(e);
@@ -3554,6 +3565,7 @@ function record(options = {}) {
3554
3565
  }
3555
3566
  }
3556
3567
  };
3568
+ _wrappedEmit = wrappedEmit;
3557
3569
  const wrappedMutationEmit = (m) => {
3558
3570
  wrappedEmit(wrapEvent({
3559
3571
  type: EventType.IncrementalSnapshot,
@@ -3585,17 +3597,23 @@ function record(options = {}) {
3585
3597
  recordCrossOriginIframes,
3586
3598
  wrappedEmit,
3587
3599
  });
3600
+ for (const plugin of plugins || []) {
3601
+ if (plugin.getMirror)
3602
+ plugin.getMirror({
3603
+ nodeMirror: mirror,
3604
+ crossOriginIframeMirror: iframeManager.crossOriginIframeMirror,
3605
+ crossOriginIframeStyleMirror: iframeManager.crossOriginIframeStyleMirror,
3606
+ });
3607
+ }
3588
3608
  const processedNodeManager = new ProcessedNodeManager();
3589
- const canvasManager = getCanvasManager
3590
- ? getCanvasManager({
3591
- recordCanvas,
3592
- blockClass,
3593
- blockSelector,
3594
- unblockSelector,
3595
- sampling: sampling['canvas'],
3596
- dataURLOptions,
3597
- })
3598
- : new CanvasManagerNoop();
3609
+ const canvasManager = _getCanvasManager(getCanvasManager, {
3610
+ recordCanvas,
3611
+ blockClass,
3612
+ blockSelector,
3613
+ unblockSelector,
3614
+ sampling: sampling['canvas'],
3615
+ dataURLOptions,
3616
+ });
3599
3617
  const shadowDomManager = typeof __RRWEB_EXCLUDE_SHADOW_DOM__ === 'boolean' &&
3600
3618
  __RRWEB_EXCLUDE_SHADOW_DOM__
3601
3619
  ? new ShadowDomManagerNoop()
@@ -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) => {
@@ -3836,8 +3865,22 @@ function takeFullSnapshot(isCheckout) {
3836
3865
  }
3837
3866
  _takeFullSnapshot(isCheckout);
3838
3867
  }
3868
+ function wrappedEmit(e) {
3869
+ if (!_wrappedEmit) {
3870
+ return;
3871
+ }
3872
+ _wrappedEmit(e);
3873
+ }
3839
3874
  record.mirror = mirror;
3840
3875
  record.takeFullSnapshot = takeFullSnapshot;
3876
+ function _getCanvasManager(getCanvasManagerFn, options) {
3877
+ return getCanvasManagerFn
3878
+ ? getCanvasManagerFn(Object.assign(Object.assign({}, options), { mirror, win: window, mutationCb: (p) => wrappedEmit(wrapEvent({
3879
+ type: EventType.IncrementalSnapshot,
3880
+ data: Object.assign({ source: IncrementalSource.CanvasMutation }, p),
3881
+ })) }))
3882
+ : new CanvasManagerNoop();
3883
+ }
3841
3884
 
3842
3885
  const ReplayEventTypeIncrementalSnapshot = 3;
3843
3886
  const ReplayEventTypeCustom = 5;
@@ -5641,6 +5684,40 @@ function isBaseTransportSend() {
5641
5684
  );
5642
5685
  }
5643
5686
 
5687
+ /**
5688
+ * Returns a listener to be added to `client.on('afterSendErrorEvent, listener)`.
5689
+ */
5690
+ function handleBeforeSendEvent(replay) {
5691
+ return (event) => {
5692
+ if (!replay.isEnabled() || !isErrorEvent(event)) {
5693
+ return;
5694
+ }
5695
+
5696
+ handleHydrationError(replay, event);
5697
+ };
5698
+ }
5699
+
5700
+ function handleHydrationError(replay, event) {
5701
+ const exceptionValue = event.exception && event.exception.values && event.exception.values[0].value;
5702
+ if (typeof exceptionValue !== 'string') {
5703
+ return;
5704
+ }
5705
+
5706
+ if (
5707
+ // Only matches errors in production builds of react-dom
5708
+ // Example https://reactjs.org/docs/error-decoder.html?invariant=423
5709
+ exceptionValue.match(/reactjs\.org\/docs\/error-decoder\.html\?invariant=(418|419|422|423|425)/) ||
5710
+ // Development builds of react-dom
5711
+ // Example Text: content did not match. Server: "A" Client: "B"
5712
+ exceptionValue.match(/(hydration|content does not match|did not match)/i)
5713
+ ) {
5714
+ const breadcrumb = createBreadcrumb({
5715
+ category: 'replay.hydrate-error',
5716
+ });
5717
+ addBreadcrumbEvent(replay, breadcrumb);
5718
+ }
5719
+ }
5720
+
5644
5721
  /**
5645
5722
  * Returns true if we think the given event is an error originating inside of rrweb.
5646
5723
  */
@@ -6965,6 +7042,7 @@ function addGlobalListeners(replay) {
6965
7042
 
6966
7043
  // If a custom client has no hooks yet, we continue to use the "old" implementation
6967
7044
  if (hasHooks(client)) {
7045
+ client.on('beforeSendEvent', handleBeforeSendEvent(replay));
6968
7046
  client.on('afterSendEvent', handleAfterSendEvent(replay));
6969
7047
  client.on('createDsc', (dsc) => {
6970
7048
  const replayId = replay.getSessionId();
@@ -7872,6 +7950,7 @@ class ReplayContainer {
7872
7950
  */
7873
7951
  startRecording() {
7874
7952
  try {
7953
+ const canvas = this._options._experiments.canvas;
7875
7954
  this._stopRecording = record({
7876
7955
  ...this._recordingOptions,
7877
7956
  // When running in error sampling mode, we need to overwrite `checkoutEveryNms`
@@ -7880,6 +7959,12 @@ class ReplayContainer {
7880
7959
  ...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }),
7881
7960
  emit: getHandleRecordingEmit(this),
7882
7961
  onMutation: this._onMutationHandler,
7962
+ ...(canvas && {
7963
+ recordCanvas: true,
7964
+ sampling: { canvas: canvas.fps || 4 },
7965
+ dataURLOptions: { quality: canvas.quality || 0.6 },
7966
+ getCanvasManager: canvas.manager,
7967
+ }),
7883
7968
  });
7884
7969
  } catch (err) {
7885
7970
  this._handleException(err);