From 00413dfca76e8536caa525f415246949f5aab3f1 Mon Sep 17 00:00:00 2001 From: Vladimir Milenko Date: Wed, 27 Sep 2023 13:16:54 +0200 Subject: [PATCH 1/2] [rrweb] Fix hookSetter maximum call stack exceeded --- packages/rrweb/src/utils.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/rrweb/src/utils.ts b/packages/rrweb/src/utils.ts index 604c8810e2..68120b231b 100644 --- a/packages/rrweb/src/utils.ts +++ b/packages/rrweb/src/utils.ts @@ -104,7 +104,14 @@ export function hookSetter( isRevoked?: boolean, win = window, ): hookResetter { + const isAlreadyHooked = Object.prototype.hasOwnProperty.call(target, '__hooked__' + String(key)); + + // If already hooked, avoid re-hooking. + // eslint-disable-next-line @typescript-eslint/no-empty-function + if (isAlreadyHooked && !isRevoked) return () => {}; + const original = win.Object.getOwnPropertyDescriptor(target, key); + win.Object.defineProperty( target, key, @@ -112,7 +119,6 @@ export function hookSetter( ? d : { set(value) { - // put hooked setter into event loop to avoid of set latency setTimeout(() => { d.set!.call(this, value); }, 0); @@ -122,7 +128,21 @@ export function hookSetter( }, }, ); - return () => hookSetter(target, key, original || {}, true); + + if (!isRevoked) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + (target as any)['__hooked__' + String(key)] = true; + } else { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + delete (target as any)['__hooked__' + String(key)]; + } + + return () => { + if (isRevoked) return; // Ensure that you can't reset multiple times + win.Object.defineProperty(target, key, original || {}); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + delete (target as any)['__hooked__' + String(key)]; + }; } // copy from https://github.com/getsentry/sentry-javascript/blob/b2109071975af8bf0316d3b5b38f519bdaf5dc15/packages/utils/src/object.ts From 1514e8df7374ae072db87b952ca3d2eb57d54488 Mon Sep 17 00:00:00 2001 From: VladimirMilenko Date: Wed, 27 Sep 2023 11:18:26 +0000 Subject: [PATCH 2/2] Apply formatting changes --- packages/rrweb/src/utils.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/rrweb/src/utils.ts b/packages/rrweb/src/utils.ts index 68120b231b..cc14586132 100644 --- a/packages/rrweb/src/utils.ts +++ b/packages/rrweb/src/utils.ts @@ -104,7 +104,10 @@ export function hookSetter( isRevoked?: boolean, win = window, ): hookResetter { - const isAlreadyHooked = Object.prototype.hasOwnProperty.call(target, '__hooked__' + String(key)); + const isAlreadyHooked = Object.prototype.hasOwnProperty.call( + target, + '__hooked__' + String(key), + ); // If already hooked, avoid re-hooking. // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -138,7 +141,7 @@ export function hookSetter( } return () => { - if (isRevoked) return; // Ensure that you can't reset multiple times + if (isRevoked) return; // Ensure that you can't reset multiple times win.Object.defineProperty(target, key, original || {}); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access delete (target as any)['__hooked__' + String(key)];