diff --git a/packages/plugins/rrweb-plugin-console-record/package.json b/packages/plugins/rrweb-plugin-console-record/package.json index c59352c0..07897f39 100644 --- a/packages/plugins/rrweb-plugin-console-record/package.json +++ b/packages/plugins/rrweb-plugin-console-record/package.json @@ -53,6 +53,7 @@ "puppeteer": "^20.9.0" }, "peerDependencies": { - "rrweb": "^2.0.0-alpha.18" + "rrweb": "^2.0.0-alpha.18", + "@rrweb/utils": "^2.0.0-alpha.18" } } diff --git a/packages/plugins/rrweb-plugin-console-record/src/index.ts b/packages/plugins/rrweb-plugin-console-record/src/index.ts index d6c84169..986d7115 100644 --- a/packages/plugins/rrweb-plugin-console-record/src/index.ts +++ b/packages/plugins/rrweb-plugin-console-record/src/index.ts @@ -1,5 +1,5 @@ import type { listenerHandler, RecordPlugin, IWindow } from '@rrweb/types'; -import { utils } from 'rrweb'; +import { patch } from '@rrweb/utils'; import { ErrorStackParser, StackFrame } from './error-stack-parser'; import { stringify } from './stringify'; @@ -183,7 +183,7 @@ function initLogObserver( }; } // replace the logger.{level}. return a restore function - return utils.patch( + return patch( _logger, level, (original: (...args: Array) => void) => { diff --git a/packages/record/package.json b/packages/record/package.json index 0e58cd5a..6b1d244d 100644 --- a/packages/record/package.json +++ b/packages/record/package.json @@ -56,7 +56,8 @@ }, "dependencies": { "@rrweb/types": "^2.0.0-alpha.18", - "rrweb": "^2.0.0-alpha.18" + "rrweb": "^2.0.0-alpha.18", + "@rrweb/utils": "^2.0.0-alpha.18" }, "browserslist": [ "supports es6-class" diff --git a/packages/record/tsconfig.json b/packages/record/tsconfig.json index eb18687a..526faf22 100644 --- a/packages/record/tsconfig.json +++ b/packages/record/tsconfig.json @@ -11,6 +11,9 @@ }, { "path": "../rrweb" + }, + { + "path": "../utils" } ] } diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 7e3aab3f..8326d796 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -15,10 +15,10 @@ import { getWindowWidth, isBlocked, legacy_isTouchEvent, - patch, StyleSheetMirror, nowTimestamp, } from '../utils'; +import { patch } from '@rrweb/utils'; import type { observerParam, MutationBufferParam } from '../types'; import { IncrementalSource, diff --git a/packages/rrweb/src/record/observers/canvas/2d.ts b/packages/rrweb/src/record/observers/canvas/2d.ts index d6090a67..ce1332a8 100644 --- a/packages/rrweb/src/record/observers/canvas/2d.ts +++ b/packages/rrweb/src/record/observers/canvas/2d.ts @@ -5,7 +5,8 @@ import { type IWindow, type listenerHandler, } from '@rrweb/types'; -import { hookSetter, isBlocked, patch } from '../../../utils'; +import { hookSetter, isBlocked } from '../../../utils'; +import { patch } from '@rrweb/utils'; import { serializeArgs } from './serialize-args'; export default function initCanvas2DMutationObserver( diff --git a/packages/rrweb/src/record/observers/canvas/canvas.ts b/packages/rrweb/src/record/observers/canvas/canvas.ts index 4f6b30fc..aa9be94d 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas.ts @@ -1,6 +1,7 @@ import type { ICanvas } from 'rrweb-snapshot'; import type { blockClass, IWindow, listenerHandler } from '@rrweb/types'; -import { isBlocked, patch } from '../../../utils'; +import { isBlocked } from '../../../utils'; +import { patch } from '@rrweb/utils'; function getNormalizedContextName(contextType: string) { return contextType === 'experimental-webgl' ? 'webgl' : contextType; diff --git a/packages/rrweb/src/record/observers/canvas/webgl.ts b/packages/rrweb/src/record/observers/canvas/webgl.ts index 59218afb..3c51323b 100644 --- a/packages/rrweb/src/record/observers/canvas/webgl.ts +++ b/packages/rrweb/src/record/observers/canvas/webgl.ts @@ -6,7 +6,8 @@ import { type IWindow, type listenerHandler, } from '@rrweb/types'; -import { hookSetter, isBlocked, patch } from '../../../utils'; +import { hookSetter, isBlocked } from '../../../utils'; +import { patch } from '@rrweb/utils'; import { saveWebGLVar, serializeArgs } from './serialize-args'; function patchGLPrototype( diff --git a/packages/rrweb/src/record/shadow-dom-manager.ts b/packages/rrweb/src/record/shadow-dom-manager.ts index ab257e40..35affb72 100644 --- a/packages/rrweb/src/record/shadow-dom-manager.ts +++ b/packages/rrweb/src/record/shadow-dom-manager.ts @@ -9,10 +9,10 @@ import { initScrollObserver, initAdoptedStyleSheetObserver, } from './observer'; -import { patch, inDom } from '../utils'; +import { inDom } from '../utils'; import type { Mirror } from 'rrweb-snapshot'; import { isNativeShadowDom } from 'rrweb-snapshot'; -import dom from '@rrweb/utils'; +import dom, { patch } from '@rrweb/utils'; type BypassOptions = Omit< MutationBufferParam, diff --git a/packages/rrweb/src/utils.ts b/packages/rrweb/src/utils.ts index ecf72d05..13b15ec6 100644 --- a/packages/rrweb/src/utils.ts +++ b/packages/rrweb/src/utils.ts @@ -127,49 +127,6 @@ export function hookSetter( return () => hookSetter(target, key, original || {}, true); } -// copy from https://github.com/getsentry/sentry-javascript/blob/b2109071975af8bf0316d3b5b38f519bdaf5dc15/packages/utils/src/object.ts -export function patch( - source: { [key: string]: any }, - name: string, - replacement: (...args: unknown[]) => unknown, -): () => void { - try { - if (!(name in source)) { - return () => { - // - }; - } - - const original = source[name] as () => unknown; - const wrapped = replacement(original); - - // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work - // otherwise it'll throw "TypeError: Object.defineProperties called on non-object" - if (typeof wrapped === 'function') { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - wrapped.prototype = wrapped.prototype || {}; - Object.defineProperties(wrapped, { - __rrweb_original__: { - enumerable: false, - value: original, - }, - }); - } - - source[name] = wrapped; - - return () => { - source[name] = original; - }; - } catch { - return () => { - // - }; - // This can throw if multiple fill happens on a global object like XMLHttpRequest - // Fixes https://github.com/getsentry/sentry-javascript/issues/2043 - } -} - // guard against old third party libraries which redefine Date.now let nowTimestamp = Date.now; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 1cd267c0..94a8dc83 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -222,6 +222,49 @@ export function mutationObserverCtor(): (typeof MutationObserver)['prototype'][' return getUntaintedPrototype('MutationObserver').constructor; } +// copy from https://github.com/getsentry/sentry-javascript/blob/b2109071975af8bf0316d3b5b38f519bdaf5dc15/packages/utils/src/object.ts +export function patch( + source: { [key: string]: any }, + name: string, + replacement: (...args: unknown[]) => unknown, +): () => void { + try { + if (!(name in source)) { + return () => { + // + }; + } + + const original = source[name] as () => unknown; + const wrapped = replacement(original); + + // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work + // otherwise it'll throw "TypeError: Object.defineProperties called on non-object" + if (typeof wrapped === 'function') { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + wrapped.prototype = wrapped.prototype || {}; + Object.defineProperties(wrapped, { + __rrweb_original__: { + enumerable: false, + value: original, + }, + }); + } + + source[name] = wrapped; + + return () => { + source[name] = original; + }; + } catch { + return () => { + // + }; + // This can throw if multiple fill happens on a global object like XMLHttpRequest + // Fixes https://github.com/getsentry/sentry-javascript/issues/2043 + } +} + export default { childNodes, parentNode, @@ -235,4 +278,5 @@ export default { querySelector, querySelectorAll, mutationObserver: mutationObserverCtor, + patch, };