From fdc82260642dcfa4343a814eebbe4cbc065fd4f5 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 28 Nov 2024 19:10:36 +0000 Subject: [PATCH] fix: may as well just check for presence of zone --- patches/@rrweb__record@2.0.0-alpha.17.patch | 43 +++++++-------------- pnpm-lock.yaml | 6 +-- src/utils/prototype-utils.ts | 4 +- src/utils/type-utils.ts | 11 ++---- 4 files changed, 24 insertions(+), 40 deletions(-) diff --git a/patches/@rrweb__record@2.0.0-alpha.17.patch b/patches/@rrweb__record@2.0.0-alpha.17.patch index d10533326..16a5f839a 100644 --- a/patches/@rrweb__record@2.0.0-alpha.17.patch +++ b/patches/@rrweb__record@2.0.0-alpha.17.patch @@ -1,45 +1,32 @@ diff --git a/dist/record.js b/dist/record.js -index 46ec389fefb698243008b39db65470dbdf0a3857..6c62dab78676066344afb27976dd7d83a7e17c58 100644 +index 46ec389fefb698243008b39db65470dbdf0a3857..efc65d8c393de8d0ad35083cba315aef91a04c2c 100644 --- a/dist/record.js +++ b/dist/record.js -@@ -26,6 +26,27 @@ const testableMethods$1 = { +@@ -26,6 +26,14 @@ const testableMethods$1 = { Element: [], MutationObserver: ["constructor"] }; -+const isFunction = (x) => typeof x === 'function'; -+const isAngularZonePatchedFunction = (x) => { ++ ++const isAngularZonePresent = () => { + try { -+ if (!isFunction(x)) { -+ return false; -+ } -+ // if Angular has a zone, then whatever this is could be tainted -+ if (globalThis.Zone) { -+ return true -+ } -+ for (const key of Object.getOwnPropertyNames(x || {})) { -+ if (key.indexOf('__zone') !== -1) { -+ return true; -+ } -+ } -+ return false ++ return !!globalThis.Zone + } catch { -+ // we've seen some intermittent problems in Safari since introducing this check + return false + } +} const untaintedBasePrototype$1 = {}; function getUntaintedPrototype$1(key) { if (untaintedBasePrototype$1[key]) -@@ -54,7 +75,7 @@ function getUntaintedPrototype$1(key) { +@@ -54,7 +62,7 @@ function getUntaintedPrototype$1(key) { } ) ); - if (isUntaintedAccessors && isUntaintedMethods) { -+ if (isUntaintedAccessors && isUntaintedMethods && !isAngularZonePatchedFunction(defaultObj)) { ++ if (isUntaintedAccessors && isUntaintedMethods && !isAngularZonePresent()) { untaintedBasePrototype$1[key] = defaultObj.prototype; return defaultObj.prototype; } -@@ -65,10 +86,10 @@ function getUntaintedPrototype$1(key) { +@@ -65,10 +73,10 @@ function getUntaintedPrototype$1(key) { if (!win) return defaultObj.prototype; const untaintedObject = win[key].prototype; document.body.removeChild(iframeEl); @@ -52,7 +39,7 @@ index 46ec389fefb698243008b39db65470dbdf0a3857..6c62dab78676066344afb27976dd7d83 } } const untaintedAccessorCache$1 = {}; -@@ -246,6 +267,9 @@ function isCSSImportRule(rule2) { +@@ -246,6 +254,9 @@ function isCSSImportRule(rule2) { function isCSSStyleRule(rule2) { return "selectorText" in rule2; } @@ -62,7 +49,7 @@ index 46ec389fefb698243008b39db65470dbdf0a3857..6c62dab78676066344afb27976dd7d83 class Mirror { constructor() { __publicField$1(this, "idNodeMap", /* @__PURE__ */ new Map()); -@@ -809,9 +833,14 @@ function serializeElementNode(n2, options) { +@@ -809,9 +820,14 @@ function serializeElementNode(n2, options) { } } if (tagName === "link" && inlineStylesheet) { @@ -80,7 +67,7 @@ index 46ec389fefb698243008b39db65470dbdf0a3857..6c62dab78676066344afb27976dd7d83 let cssText = null; if (stylesheet) { cssText = stringifyStylesheet(stylesheet); -@@ -855,7 +884,15 @@ function serializeElementNode(n2, options) { +@@ -855,7 +871,15 @@ function serializeElementNode(n2, options) { } } if (tagName === "dialog" && n2.open) { @@ -97,7 +84,7 @@ index 46ec389fefb698243008b39db65470dbdf0a3857..6c62dab78676066344afb27976dd7d83 } if (tagName === "canvas" && recordCanvas) { if (n2.__context === "2d") { -@@ -1116,7300 +1153,227 @@ function serializeNodeWithId(n2, options) { +@@ -1116,7300 +1140,227 @@ function serializeNodeWithId(n2, options) { keepIframeSrcFn }; if (serializedNode.type === NodeType$2.Element && serializedNode.tagName === "textarea" && serializedNode.attributes.value !== void 0) ; @@ -7607,7 +7594,7 @@ index 46ec389fefb698243008b39db65470dbdf0a3857..6c62dab78676066344afb27976dd7d83 class BaseRRNode { // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any constructor(..._args) { -@@ -8507,7 +1471,7 @@ function getUntaintedPrototype(key) { +@@ -8507,7 +1458,7 @@ function getUntaintedPrototype(key) { } ) ); @@ -7616,7 +7603,7 @@ index 46ec389fefb698243008b39db65470dbdf0a3857..6c62dab78676066344afb27976dd7d83 untaintedBasePrototype[key] = defaultObj.prototype; return defaultObj.prototype; } -@@ -11382,11 +4346,19 @@ class CanvasManager { +@@ -11382,11 +4333,19 @@ class CanvasManager { let rafId; const getCanvas = () => { const matchedCanvas = []; @@ -7641,7 +7628,7 @@ index 46ec389fefb698243008b39db65470dbdf0a3857..6c62dab78676066344afb27976dd7d83 return matchedCanvas; }; const takeCanvasSnapshots = (timestamp) => { -@@ -11407,13 +4379,20 @@ class CanvasManager { +@@ -11407,13 +4366,20 @@ class CanvasManager { context.clear(context.COLOR_BUFFER_BIT); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c96d220fb..b0947b0e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: patchedDependencies: '@rrweb/record@2.0.0-alpha.17': - hash: nrscfm4vgic7ua6pjpvsibukl4 + hash: b2wlmgtfu75ftypjejqj7owubq path: patches/@rrweb__record@2.0.0-alpha.17.patch '@rrweb/rrweb-plugin-console-record@2.0.0-alpha.17': hash: ytsspyi7p3hvqcq64vqb7wb6bu @@ -74,7 +74,7 @@ devDependencies: version: 12.1.1(rollup@4.24.0)(tslib@2.5.0)(typescript@5.5.4) '@rrweb/record': specifier: 2.0.0-alpha.17 - version: 2.0.0-alpha.17(patch_hash=nrscfm4vgic7ua6pjpvsibukl4) + version: 2.0.0-alpha.17(patch_hash=b2wlmgtfu75ftypjejqj7owubq) '@rrweb/rrweb-plugin-console-record': specifier: 2.0.0-alpha.17 version: 2.0.0-alpha.17(patch_hash=ytsspyi7p3hvqcq64vqb7wb6bu)(rrweb@2.0.0-alpha.17) @@ -2870,7 +2870,7 @@ packages: dev: true optional: true - /@rrweb/record@2.0.0-alpha.17(patch_hash=nrscfm4vgic7ua6pjpvsibukl4): + /@rrweb/record@2.0.0-alpha.17(patch_hash=b2wlmgtfu75ftypjejqj7owubq): resolution: {integrity: sha512-Je+lzjeWMF8/I0IDoXFzkGPKT8j7AkaBup5YcwUHlkp18VhLVze416MvI6915teE27uUA2ScXMXzG0Yiu5VTIw==} dependencies: '@rrweb/types': 2.0.0-alpha.17 diff --git a/src/utils/prototype-utils.ts b/src/utils/prototype-utils.ts index 5a18b8b49..ccdfebcb4 100644 --- a/src/utils/prototype-utils.ts +++ b/src/utils/prototype-utils.ts @@ -5,7 +5,7 @@ */ import { AssignableWindow } from './globals' -import { isAngularZonePatchedFunction, isFunction, isNativeFunction } from './type-utils' +import { isAngularZonePresent, isFunction, isNativeFunction } from './type-utils' import { logger } from './logger' interface NativeImplementationsCache { @@ -25,7 +25,7 @@ export function getNativeImplementation any => { export const isNativeFunction = (x: unknown): x is (...args: any[]) => any => isFunction(x) && x.toString().indexOf('[native code]') !== -1 -// When angular patches functions they pass the above `isNativeFunction` check -export const isAngularZonePatchedFunction = (x: unknown): boolean => { - if (!isFunction(x)) { - return false - } - const prototypeKeys = Object.getOwnPropertyNames(x.prototype || {}) - return prototypeKeys.some((key) => key.indexOf('__zone')) +// When angular patches functions they pass the above `isNativeFunction` check (at least the MutationObserver) +export const isAngularZonePresent = (): boolean => { + return !!(window as any).Zone } // Underscore Addons