diff --git a/packages/rrweb/src/record/iframe-manager.ts b/packages/rrweb/src/record/iframe-manager.ts index 09ff366eb4..616c137856 100644 --- a/packages/rrweb/src/record/iframe-manager.ts +++ b/packages/rrweb/src/record/iframe-manager.ts @@ -12,7 +12,37 @@ import type { } from '@sentry-internal/rrweb-types'; import type { StylesheetManager } from './stylesheet-manager'; -export class IframeManager { +export interface IframeManagerInterface { + crossOriginIframeMirror: CrossOriginIframeMirror; + crossOriginIframeStyleMirror: CrossOriginIframeMirror; + crossOriginIframeRootIdMap: WeakMap; + + addIframe(iframeEl: HTMLIFrameElement): void; + addLoadListener(cb: (iframeEl: HTMLIFrameElement) => unknown): void; + attachIframe( + iframeEl: HTMLIFrameElement, + childSn: serializedNodeWithId, + ): void; +} + +export class IframeManagerNoop implements IframeManagerInterface { + public crossOriginIframeMirror = new CrossOriginIframeMirror(genId); + public crossOriginIframeStyleMirror: CrossOriginIframeMirror; + public crossOriginIframeRootIdMap: WeakMap = + new WeakMap(); + + public addIframe() { + // noop + } + public addLoadListener() { + // noop + } + public attachIframe() { + // noop + } +} + +export class IframeManager implements IframeManagerInterface { private iframes: WeakMap = new WeakMap(); private crossOriginIframeMap: WeakMap = new WeakMap(); diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index a6221abd90..b9ca102944 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -29,9 +29,21 @@ import { adoptedStyleSheetParam, } from '@sentry-internal/rrweb-types'; import type { CrossOriginIframeMessageEventContent } from '../types'; -import { IframeManager } from './iframe-manager'; -import { ShadowDomManager } from './shadow-dom-manager'; -import { CanvasManager } from './observers/canvas/canvas-manager'; +import { + IframeManager, + IframeManagerInterface, + IframeManagerNoop, +} from './iframe-manager'; +import { + ShadowDomManager, + ShadowDomManagerInterface, + ShadowDomManagerNoop, +} from './shadow-dom-manager'; +import { + CanvasManager, + CanvasManagerInterface, + CanvasManagerNoop, +} from './observers/canvas/canvas-manager'; import { StylesheetManager } from './stylesheet-manager'; import ProcessedNodeManager from './processed-node-manager'; import { @@ -47,10 +59,16 @@ function wrapEvent(e: event): eventWithTime { }; } +declare global { + const __RRWEB_EXCLUDE_CANVAS__: boolean; + const __RRWEB_EXCLUDE_SHADOW_DOM__: boolean; + const __RRWEB_EXCLUDE_IFRAME__: boolean; +} + let wrappedEmit!: (e: eventWithTime, isCheckout?: boolean) => void; let takeFullSnapshot!: (isCheckout?: boolean) => void; -let canvasManager!: CanvasManager; +let canvasManager: CanvasManagerInterface; let recording = false; const mirror = createMirror(); @@ -292,13 +310,16 @@ function record( adoptedStyleSheetCb: wrappedAdoptedStyleSheetEmit, }); - const iframeManager = new IframeManager({ - mirror, - mutationCb: wrappedMutationEmit, - stylesheetManager: stylesheetManager, - recordCrossOriginIframes, - wrappedEmit, - }); + const iframeManager: IframeManagerInterface = + typeof __RRWEB_EXCLUDE_IFRAME__ === 'boolean' && __RRWEB_EXCLUDE_IFRAME__ + ? new IframeManagerNoop() + : new IframeManager({ + mirror, + mutationCb: wrappedMutationEmit, + stylesheetManager: stylesheetManager, + recordCrossOriginIframes, + wrappedEmit, + }); /** * Exposes mirror to the plugins @@ -315,49 +336,56 @@ function record( const processedNodeManager = new ProcessedNodeManager(); - canvasManager = new CanvasManager({ - recordCanvas, - mutationCb: wrappedCanvasMutationEmit, - win: window, - blockClass, - blockSelector, - unblockSelector, - mirror, - sampling: sampling.canvas, - dataURLOptions, - }); + canvasManager = + typeof __RRWEB_EXCLUDE_CANVAS__ === 'boolean' && __RRWEB_EXCLUDE_CANVAS__ + ? new CanvasManagerNoop() + : new CanvasManager({ + recordCanvas, + mutationCb: wrappedCanvasMutationEmit, + win: window, + blockClass, + blockSelector, + unblockSelector, + mirror, + sampling: sampling.canvas, + dataURLOptions, + }); - const shadowDomManager = new ShadowDomManager({ - mutationCb: wrappedMutationEmit, - scrollCb: wrappedScrollEmit, - bypassOptions: { - onMutation, - blockClass, - blockSelector, - unblockSelector, - maskAllText, - maskTextClass, - unmaskTextClass, - maskTextSelector, - unmaskTextSelector, - inlineStylesheet, - maskInputOptions, - dataURLOptions, - maskAttributeFn, - maskTextFn, - maskInputFn, - recordCanvas, - inlineImages, - sampling, - slimDOMOptions, - iframeManager, - stylesheetManager, - canvasManager, - keepIframeSrcFn, - processedNodeManager, - }, - mirror, - }); + const shadowDomManager: ShadowDomManagerInterface = + typeof __RRWEB_EXCLUDE_SHADOW_DOM__ === 'boolean' && + __RRWEB_EXCLUDE_SHADOW_DOM__ + ? new ShadowDomManagerNoop() + : new ShadowDomManager({ + mutationCb: wrappedMutationEmit, + scrollCb: wrappedScrollEmit, + bypassOptions: { + onMutation, + blockClass, + blockSelector, + unblockSelector, + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, + inlineStylesheet, + maskInputOptions, + dataURLOptions, + maskAttributeFn, + maskTextFn, + maskInputFn, + recordCanvas, + inlineImages, + sampling, + slimDOMOptions, + iframeManager, + stylesheetManager, + canvasManager, + keepIframeSrcFn, + processedNodeManager, + }, + mirror, + }); takeFullSnapshot = (isCheckout = false) => { if (!recordDOM) { diff --git a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts index d98c1777e8..93dcd9e674 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts @@ -28,7 +28,33 @@ type pendingCanvasMutationsMap = Map< canvasMutationWithType[] >; -export class CanvasManager { +export interface CanvasManagerInterface { + reset(): void; + freeze(): void; + unfreeze(): void; + lock(): void; + unlock(): void; +} + +export class CanvasManagerNoop implements CanvasManagerInterface { + public reset() { + // noop + } + public freeze() { + // noop + } + public unfreeze() { + // noop + } + public lock() { + // noop + } + public unlock() { + // noop + } +} + +export class CanvasManager implements CanvasManagerInterface { private pendingCanvasMutations: pendingCanvasMutationsMap = new Map(); private rafStamps: RafStamps = { latestId: 0, invokeId: null }; private mirror: Mirror; diff --git a/packages/rrweb/src/record/shadow-dom-manager.ts b/packages/rrweb/src/record/shadow-dom-manager.ts index 9e15433da0..ed814f49c6 100644 --- a/packages/rrweb/src/record/shadow-dom-manager.ts +++ b/packages/rrweb/src/record/shadow-dom-manager.ts @@ -20,7 +20,29 @@ type BypassOptions = Omit< sampling: SamplingStrategy; }; -export class ShadowDomManager { +export interface ShadowDomManagerInterface { + init(): void; + addShadowRoot(shadowRoot: ShadowRoot, doc: Document): void; + observeAttachShadow(iframeElement: HTMLIFrameElement): void; + reset(): void; +} + +export class ShadowDomManagerNoop implements ShadowDomManagerInterface { + public init() { + // noop + } + public addShadowRoot() { + // noop + } + public observeAttachShadow() { + // noop + } + public reset() { + // noop + } +} + +export class ShadowDomManager implements ShadowDomManagerInterface { private shadowDoms = new WeakSet(); private mutationCb: mutationCallBack; private scrollCb: scrollCallback; diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index 31279be429..16da94fd4b 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -8,11 +8,20 @@ import type { MaskAttributeFn, } from '@sentry-internal/rrweb-snapshot'; import type { PackFn, UnpackFn } from './packer/base'; -import type { IframeManager } from './record/iframe-manager'; -import type { ShadowDomManager } from './record/shadow-dom-manager'; +import type { + IframeManager, + IframeManagerInterface, +} from './record/iframe-manager'; +import type { + ShadowDomManager, + ShadowDomManagerInterface, +} from './record/shadow-dom-manager'; import type { Replayer } from './replay'; import type { RRNode } from '@sentry-internal/rrdom'; -import type { CanvasManager } from './record/observers/canvas/canvas-manager'; +import type { + CanvasManager, + CanvasManagerInterface, +} from './record/observers/canvas/canvas-manager'; import type { StylesheetManager } from './record/stylesheet-manager'; import type { addedNodeMutation, @@ -124,10 +133,10 @@ export type observerParam = { dataURLOptions: DataURLOptions; doc: Document; mirror: Mirror; - iframeManager: IframeManager; + iframeManager: IframeManagerInterface; stylesheetManager: StylesheetManager; - shadowDomManager: ShadowDomManager; - canvasManager: CanvasManager; + shadowDomManager: ShadowDomManagerInterface; + canvasManager: CanvasManagerInterface; processedNodeManager: ProcessedNodeManager; ignoreCSSAttributes: Set; plugins: Array<{