@posthog/rrweb-record 0.0.45 → 0.0.47

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.
@@ -10545,7 +10545,7 @@ function initMutationObserver(options, rootEl) {
10545
10545
  childList: true,
10546
10546
  subtree: true
10547
10547
  });
10548
- return observer;
10548
+ return { observer, buffer: mutationBuffer };
10549
10549
  }
10550
10550
  function initMoveObserver({
10551
10551
  mousemoveCb,
@@ -11466,8 +11466,11 @@ function initObservers(o2, hooks = {}) {
11466
11466
  }
11467
11467
  mergeHooks(o2, hooks);
11468
11468
  let mutationObserver;
11469
+ let mutationBuffer;
11469
11470
  if (o2.recordDOM) {
11470
- mutationObserver = initMutationObserver(o2, o2.doc);
11471
+ const result2 = initMutationObserver(o2, o2.doc);
11472
+ mutationObserver = result2.observer;
11473
+ mutationBuffer = result2.buffer;
11471
11474
  }
11472
11475
  const mousemoveHandler = initMoveObserver(o2);
11473
11476
  const mouseInteractionHandler = initMouseInteractionObserver(o2);
@@ -11504,8 +11507,14 @@ function initObservers(o2, hooks = {}) {
11504
11507
  );
11505
11508
  }
11506
11509
  return callbackWrapper(() => {
11507
- mutationBuffers.forEach((b) => b.destroy());
11508
- mutationBuffers.forEach((b) => b.reset());
11510
+ if (mutationBuffer) {
11511
+ mutationBuffer.destroy();
11512
+ mutationBuffer.reset();
11513
+ const index2 = mutationBuffers.indexOf(mutationBuffer);
11514
+ if (index2 !== -1) {
11515
+ mutationBuffers.splice(index2, 1);
11516
+ }
11517
+ }
11509
11518
  mutationObserver == null ? void 0 : mutationObserver.disconnect();
11510
11519
  mousemoveHandler();
11511
11520
  mouseInteractionHandler();
@@ -11520,7 +11529,6 @@ function initObservers(o2, hooks = {}) {
11520
11529
  selectionObserver();
11521
11530
  customElementObserver();
11522
11531
  pluginHandlers.forEach((h) => h());
11523
- mutationBuffers.length = 0;
11524
11532
  });
11525
11533
  }
11526
11534
  function hasNestedCSSRule(prop) {
@@ -11920,7 +11928,7 @@ class ShadowDomManager {
11920
11928
  if (!isNativeShadowDom(shadowRoot2)) return;
11921
11929
  if (this.shadowDoms.has(shadowRoot2)) return;
11922
11930
  this.shadowDoms.add(shadowRoot2);
11923
- const observer = initMutationObserver(
11931
+ const { observer, buffer } = initMutationObserver(
11924
11932
  {
11925
11933
  ...this.bypassOptions,
11926
11934
  doc,
@@ -11930,7 +11938,15 @@ class ShadowDomManager {
11930
11938
  },
11931
11939
  shadowRoot2
11932
11940
  );
11933
- this.restoreHandlers.push(() => observer.disconnect());
11941
+ this.restoreHandlers.push(() => {
11942
+ observer.disconnect();
11943
+ buffer.destroy();
11944
+ buffer.reset();
11945
+ const index2 = mutationBuffers.indexOf(buffer);
11946
+ if (index2 !== -1) {
11947
+ mutationBuffers.splice(index2, 1);
11948
+ }
11949
+ });
11934
11950
  this.restoreHandlers.push(
11935
11951
  initScrollObserver({
11936
11952
  ...this.bypassOptions,
@@ -12320,7 +12336,7 @@ function initCanvasWebGLMutationObserver(cb, win, blockClass, blockSelector, dat
12320
12336
  handlers.forEach((h) => h());
12321
12337
  };
12322
12338
  }
12323
- const jsContent = '(function() {\n "use strict";\n var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\n var lookup = typeof Uint8Array === "undefined" ? [] : new Uint8Array(256);\n for (var i = 0; i < chars.length; i++) {\n lookup[chars.charCodeAt(i)] = i;\n }\n var encode = function(arraybuffer) {\n var bytes = new Uint8Array(arraybuffer), i2, len = bytes.length, base64 = "";\n for (i2 = 0; i2 < len; i2 += 3) {\n base64 += chars[bytes[i2] >> 2];\n base64 += chars[(bytes[i2] & 3) << 4 | bytes[i2 + 1] >> 4];\n base64 += chars[(bytes[i2 + 1] & 15) << 2 | bytes[i2 + 2] >> 6];\n base64 += chars[bytes[i2 + 2] & 63];\n }\n if (len % 3 === 2) {\n base64 = base64.substring(0, base64.length - 1) + "=";\n } else if (len % 3 === 1) {\n base64 = base64.substring(0, base64.length - 2) + "==";\n }\n return base64;\n };\n const lastBlobMap = /* @__PURE__ */ new Map();\n const transparentBlobMap = /* @__PURE__ */ new Map();\n async function getTransparentBlobFor(width, height, dataURLOptions) {\n const id = `${width}-${height}`;\n if ("OffscreenCanvas" in globalThis) {\n if (transparentBlobMap.has(id)) return transparentBlobMap.get(id);\n const offscreen = new OffscreenCanvas(width, height);\n offscreen.getContext("2d");\n const blob = await offscreen.convertToBlob(dataURLOptions);\n const arrayBuffer = await blob.arrayBuffer();\n const base64 = encode(arrayBuffer);\n transparentBlobMap.set(id, base64);\n return base64;\n } else {\n return "";\n }\n }\n const worker = self;\n let reusableCanvas = null;\n let reusableCtx = null;\n worker.onmessage = async function(e) {\n if ("OffscreenCanvas" in globalThis) {\n const { id, bitmap, width, height, dataURLOptions } = e.data;\n const transparentBase64 = getTransparentBlobFor(\n width,\n height,\n dataURLOptions\n );\n if (!reusableCanvas || reusableCanvas.width !== width || reusableCanvas.height !== height) {\n reusableCanvas = new OffscreenCanvas(width, height);\n reusableCtx = reusableCanvas.getContext("2d");\n }\n reusableCtx.clearRect(0, 0, width, height);\n reusableCtx.drawImage(bitmap, 0, 0);\n bitmap.close();\n const blob = await reusableCanvas.convertToBlob(dataURLOptions);\n const type = blob.type;\n const arrayBuffer = await blob.arrayBuffer();\n const base64 = encode(arrayBuffer);\n if (!lastBlobMap.has(id) && await transparentBase64 === base64) {\n lastBlobMap.set(id, base64);\n return worker.postMessage({ id });\n }\n if (lastBlobMap.get(id) === base64) return worker.postMessage({ id });\n worker.postMessage({\n id,\n type,\n base64,\n width,\n height\n });\n lastBlobMap.set(id, base64);\n } else {\n e.data.bitmap.close();\n return worker.postMessage({ id: e.data.id });\n }\n };\n})();\n//# sourceMappingURL=image-bitmap-data-url-worker-ChEIhO0o.js.map\n';
12339
+ const jsContent = '(function() {\n "use strict";\n var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\n var lookup = typeof Uint8Array === "undefined" ? [] : new Uint8Array(256);\n for (var i = 0; i < chars.length; i++) {\n lookup[chars.charCodeAt(i)] = i;\n }\n var encode = function(arraybuffer) {\n var bytes = new Uint8Array(arraybuffer), i2, len = bytes.length, base64 = "";\n for (i2 = 0; i2 < len; i2 += 3) {\n base64 += chars[bytes[i2] >> 2];\n base64 += chars[(bytes[i2] & 3) << 4 | bytes[i2 + 1] >> 4];\n base64 += chars[(bytes[i2 + 1] & 15) << 2 | bytes[i2 + 2] >> 6];\n base64 += chars[bytes[i2 + 2] & 63];\n }\n if (len % 3 === 2) {\n base64 = base64.substring(0, base64.length - 1) + "=";\n } else if (len % 3 === 1) {\n base64 = base64.substring(0, base64.length - 2) + "==";\n }\n return base64;\n };\n const lastFingerprintMap = /* @__PURE__ */ new Map();\n const transparentBlobMap = /* @__PURE__ */ new Map();\n function fnv1aHash(buffer) {\n const view = new Uint8Array(buffer);\n let hash = 2166136261;\n for (let i2 = 0; i2 < view.length; i2++) {\n hash ^= view[i2];\n hash = hash * 16777619 | 0;\n }\n return (hash >>> 0).toString(16);\n }\n async function getTransparentBlobFor(width, height, dataURLOptions) {\n const id = `${width}-${height}`;\n if ("OffscreenCanvas" in globalThis) {\n if (transparentBlobMap.has(id)) return transparentBlobMap.get(id);\n const offscreen = new OffscreenCanvas(width, height);\n offscreen.getContext("2d");\n const blob = await offscreen.convertToBlob(dataURLOptions);\n const arrayBuffer = await blob.arrayBuffer();\n const base64 = encode(arrayBuffer);\n transparentBlobMap.set(id, base64);\n return base64;\n } else {\n return "";\n }\n }\n const worker = self;\n let reusableCanvas = null;\n let reusableCtx = null;\n worker.onmessage = async function(e) {\n if ("OffscreenCanvas" in globalThis) {\n const { id, bitmap, width, height, dataURLOptions } = e.data;\n const transparentBase64 = getTransparentBlobFor(\n width,\n height,\n dataURLOptions\n );\n if (!reusableCanvas || reusableCanvas.width !== width || reusableCanvas.height !== height) {\n reusableCanvas = new OffscreenCanvas(width, height);\n reusableCtx = reusableCanvas.getContext("2d");\n }\n reusableCtx.clearRect(0, 0, width, height);\n reusableCtx.drawImage(bitmap, 0, 0);\n bitmap.close();\n const blob = await reusableCanvas.convertToBlob(dataURLOptions);\n const type = blob.type;\n const arrayBuffer = await blob.arrayBuffer();\n const fingerprint = fnv1aHash(arrayBuffer);\n if (!lastFingerprintMap.has(id)) {\n const base642 = encode(arrayBuffer);\n if (await transparentBase64 === base642) {\n lastFingerprintMap.set(id, fingerprint);\n return worker.postMessage({ id });\n }\n lastFingerprintMap.set(id, fingerprint);\n worker.postMessage({ id, type, base64: base642, width, height });\n return;\n }\n if (lastFingerprintMap.get(id) === fingerprint)\n return worker.postMessage({ id });\n const base64 = encode(arrayBuffer);\n worker.postMessage({ id, type, base64, width, height });\n lastFingerprintMap.set(id, fingerprint);\n } else {\n e.data.bitmap.close();\n return worker.postMessage({ id: e.data.id });\n }\n };\n})();\n//# sourceMappingURL=image-bitmap-data-url-worker-B8-18rdG.js.map\n';
12324
12340
  const blob = typeof self !== "undefined" && self.Blob && new Blob([jsContent], { type: "text/javascript;charset=utf-8" });
12325
12341
  function WorkerWrapper(options) {
12326
12342
  let objURL;
@@ -12787,6 +12803,26 @@ function record(options = {}) {
12787
12803
  polyfill$1();
12788
12804
  let lastFullSnapshotEvent;
12789
12805
  let incrementalSnapshotCount = 0;
12806
+ const iframeObserverCleanups = /* @__PURE__ */ new Map();
12807
+ function cleanupDetachedIframeObservers() {
12808
+ for (const [iframeId, cleanup] of iframeObserverCleanups) {
12809
+ const iframe = mirror.getNode(iframeId);
12810
+ if (!iframe) {
12811
+ cleanup();
12812
+ iframeObserverCleanups.delete(iframeId);
12813
+ continue;
12814
+ }
12815
+ try {
12816
+ if (!iframe.contentDocument || !iframe.contentDocument.defaultView) {
12817
+ cleanup();
12818
+ iframeObserverCleanups.delete(iframeId);
12819
+ }
12820
+ } catch {
12821
+ cleanup();
12822
+ iframeObserverCleanups.delete(iframeId);
12823
+ }
12824
+ }
12825
+ }
12790
12826
  const eventProcessor = (e2) => {
12791
12827
  for (const plugin of plugins || []) {
12792
12828
  if (plugin.eventProcessor) {
@@ -12837,9 +12873,15 @@ function record(options = {}) {
12837
12873
  const addedIds = m.adds.length > 0 ? new Set(m.adds.map((add) => add.node.id)) : null;
12838
12874
  m.removes.forEach(({ id }) => {
12839
12875
  if (!addedIds || !addedIds.has(id)) {
12876
+ const cleanup = iframeObserverCleanups.get(id);
12877
+ if (cleanup) {
12878
+ cleanup();
12879
+ iframeObserverCleanups.delete(id);
12880
+ }
12840
12881
  iframeManager.removeIframeById(id);
12841
12882
  }
12842
12883
  });
12884
+ cleanupDetachedIframeObservers();
12843
12885
  }
12844
12886
  wrappedEmit({
12845
12887
  type: EventType.IncrementalSnapshot,
@@ -13127,7 +13169,12 @@ function record(options = {}) {
13127
13169
  };
13128
13170
  const loadListener = (iframeEl) => {
13129
13171
  try {
13130
- handlers.push(observe(iframeEl.contentDocument));
13172
+ const iframeId = mirror.getId(iframeEl);
13173
+ const cleanup = observe(iframeEl.contentDocument);
13174
+ handlers.push(cleanup);
13175
+ if (iframeId !== -1) {
13176
+ iframeObserverCleanups.set(iframeId, cleanup);
13177
+ }
13131
13178
  } catch (error) {
13132
13179
  console.warn(error);
13133
13180
  }
@@ -13169,6 +13216,7 @@ function record(options = {}) {
13169
13216
  processedNodeManager.destroy();
13170
13217
  iframeManager.removeLoadListener();
13171
13218
  iframeManager.destroy();
13219
+ iframeObserverCleanups.clear();
13172
13220
  mirror.reset();
13173
13221
  recording = false;
13174
13222
  unregisterErrorHandler();