@posthog/rrweb 0.0.24 → 0.0.26

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.
package/dist/rrweb.cjs CHANGED
@@ -240,8 +240,8 @@ function stringifyStylesheet(s2) {
240
240
  return null;
241
241
  }
242
242
  let sheetHref = s2.href;
243
- if (!sheetHref && s2.ownerNode && s2.ownerNode.ownerDocument) {
244
- sheetHref = s2.ownerNode.ownerDocument.baseURI;
243
+ if (!sheetHref && s2.ownerNode) {
244
+ sheetHref = s2.ownerNode.baseURI;
245
245
  }
246
246
  const stringifiedRules = Array.from(
247
247
  rules2,
@@ -5642,6 +5642,12 @@ function buildNodeWithSN(n2, options) {
5642
5642
  } else {
5643
5643
  node2.appendChild(childNode);
5644
5644
  }
5645
+ } else if (n2.type === NodeType$1$1.Document && childN.type === NodeType$1$1.DocumentType) {
5646
+ if (node2.firstChild && node2.firstChild.nodeType === 1) {
5647
+ node2.insertBefore(childNode, node2.firstChild);
5648
+ } else {
5649
+ node2.appendChild(childNode);
5650
+ }
5645
5651
  } else {
5646
5652
  node2.appendChild(childNode);
5647
5653
  }
@@ -13223,6 +13229,7 @@ function initObservers(o2, hooks = {}) {
13223
13229
  selectionObserver();
13224
13230
  customElementObserver();
13225
13231
  pluginHandlers.forEach((h) => h());
13232
+ mutationBuffers.length = 0;
13226
13233
  });
13227
13234
  }
13228
13235
  function hasNestedCSSRule(prop) {
@@ -13309,6 +13316,9 @@ class IframeManager {
13309
13316
  __publicField(this, "loadListener");
13310
13317
  __publicField(this, "stylesheetManager");
13311
13318
  __publicField(this, "recordCrossOriginIframes");
13319
+ __publicField(this, "messageHandler");
13320
+ // Map window to handler for cleanup - windows are browser-owned and won't prevent GC
13321
+ __publicField(this, "nestedIframeListeners", /* @__PURE__ */ new Map());
13312
13322
  this.mutationCb = options.mutationCb;
13313
13323
  this.wrappedEmit = options.wrappedEmit;
13314
13324
  this.stylesheetManager = options.stylesheetManager;
@@ -13319,8 +13329,9 @@ class IframeManager {
13319
13329
  )
13320
13330
  );
13321
13331
  this.mirror = options.mirror;
13332
+ this.messageHandler = this.handleMessage.bind(this);
13322
13333
  if (this.recordCrossOriginIframes) {
13323
- window.addEventListener("message", this.handleMessage.bind(this));
13334
+ window.addEventListener("message", this.messageHandler);
13324
13335
  }
13325
13336
  }
13326
13337
  addIframe(iframeEl) {
@@ -13332,7 +13343,7 @@ class IframeManager {
13332
13343
  this.loadListener = cb;
13333
13344
  }
13334
13345
  attachIframe(iframeEl, childSn) {
13335
- var _a2, _b;
13346
+ var _a2;
13336
13347
  this.mutationCb({
13337
13348
  adds: [
13338
13349
  {
@@ -13346,12 +13357,13 @@ class IframeManager {
13346
13357
  attributes: [],
13347
13358
  isAttachIframe: true
13348
13359
  });
13349
- if (this.recordCrossOriginIframes)
13350
- (_a2 = iframeEl.contentWindow) == null ? void 0 : _a2.addEventListener(
13351
- "message",
13352
- this.handleMessage.bind(this)
13353
- );
13354
- (_b = this.loadListener) == null ? void 0 : _b.call(this, iframeEl);
13360
+ const win = iframeEl.contentWindow;
13361
+ if (this.recordCrossOriginIframes && win && !this.nestedIframeListeners.has(win)) {
13362
+ const nestedHandler = this.handleMessage.bind(this);
13363
+ this.nestedIframeListeners.set(win, nestedHandler);
13364
+ win.addEventListener("message", nestedHandler);
13365
+ }
13366
+ (_a2 = this.loadListener) == null ? void 0 : _a2.call(this, iframeEl);
13355
13367
  if (iframeEl.contentDocument && iframeEl.contentDocument.adoptedStyleSheets && iframeEl.contentDocument.adoptedStyleSheets.length > 0)
13356
13368
  this.stylesheetManager.adoptStyleSheets(
13357
13369
  iframeEl.contentDocument.adoptedStyleSheets,
@@ -13529,6 +13541,15 @@ class IframeManager {
13529
13541
  });
13530
13542
  }
13531
13543
  }
13544
+ destroy() {
13545
+ if (this.recordCrossOriginIframes) {
13546
+ window.removeEventListener("message", this.messageHandler);
13547
+ }
13548
+ this.nestedIframeListeners.forEach((handler, contentWindow) => {
13549
+ contentWindow.removeEventListener("message", handler);
13550
+ });
13551
+ this.nestedIframeListeners.clear();
13552
+ }
13532
13553
  }
13533
13554
  class ShadowDomManager {
13534
13555
  constructor(options) {
@@ -14764,6 +14785,7 @@ function record(options = {}) {
14764
14785
  return () => {
14765
14786
  handlers.forEach((h) => h());
14766
14787
  processedNodeManager.destroy();
14788
+ iframeManager.destroy();
14767
14789
  recording = false;
14768
14790
  unregisterErrorHandler();
14769
14791
  };
@@ -15986,6 +16008,12 @@ class Replayer {
15986
16008
  __publicField(this, "constructedStyleMutations", []);
15987
16009
  // Similar to the reason for constructedStyleMutations.
15988
16010
  __publicField(this, "adoptedStyleSheets", []);
16011
+ // Track resources for cleanup
16012
+ __publicField(this, "emitterHandlers", []);
16013
+ __publicField(this, "serviceSubscription");
16014
+ __publicField(this, "speedServiceSubscription");
16015
+ __publicField(this, "timeouts", /* @__PURE__ */ new Set());
16016
+ __publicField(this, "styleSheetLoadListeners", /* @__PURE__ */ new Map());
15989
16017
  __publicField(this, "handleResize", (dimension) => {
15990
16018
  this.iframe.style.display = "inherit";
15991
16019
  for (const el of [this.mouseTail, this.iframe]) {
@@ -16145,12 +16173,12 @@ class Replayer {
16145
16173
  this.handleResize = this.handleResize.bind(this);
16146
16174
  this.getCastFn = this.getCastFn.bind(this);
16147
16175
  this.applyEventsSynchronously = this.applyEventsSynchronously.bind(this);
16148
- this.emitter.on(ReplayerEvents.Resize, this.handleResize);
16176
+ this.addEmitterHandler(ReplayerEvents.Resize, this.handleResize);
16149
16177
  this.setupDom();
16150
16178
  for (const plugin of this.config.plugins || []) {
16151
16179
  if (plugin.getMirror) plugin.getMirror({ nodeMirror: this.mirror });
16152
16180
  }
16153
- this.emitter.on(ReplayerEvents.Flush, () => {
16181
+ const flushHandler = () => {
16154
16182
  if (this.usingVirtualDom) {
16155
16183
  const replayerHandler = {
16156
16184
  mirror: this.mirror,
@@ -16246,13 +16274,15 @@ class Replayer {
16246
16274
  this.applySelection(this.lastSelectionData);
16247
16275
  this.lastSelectionData = null;
16248
16276
  }
16249
- });
16250
- this.emitter.on(ReplayerEvents.PlayBack, () => {
16277
+ };
16278
+ this.addEmitterHandler(ReplayerEvents.Flush, flushHandler);
16279
+ const playBackHandler = () => {
16251
16280
  this.firstFullSnapshot = null;
16252
16281
  this.mirror.reset();
16253
16282
  this.styleMirror.reset();
16254
16283
  this.mediaManager.reset();
16255
- });
16284
+ };
16285
+ this.addEmitterHandler(ReplayerEvents.PlayBack, playBackHandler);
16256
16286
  const timer = new Timer([], {
16257
16287
  speed: this.config.speed
16258
16288
  });
@@ -16276,7 +16306,7 @@ class Replayer {
16276
16306
  }
16277
16307
  );
16278
16308
  this.service.start();
16279
- this.service.subscribe((state) => {
16309
+ this.serviceSubscription = this.service.subscribe((state) => {
16280
16310
  this.emitter.emit(ReplayerEvents.StateChange, {
16281
16311
  player: state
16282
16312
  });
@@ -16286,7 +16316,7 @@ class Replayer {
16286
16316
  timer
16287
16317
  });
16288
16318
  this.speedService.start();
16289
- this.speedService.subscribe((state) => {
16319
+ this.speedServiceSubscription = this.speedService.subscribe((state) => {
16290
16320
  this.emitter.emit(ReplayerEvents.StateChange, {
16291
16321
  speed: state
16292
16322
  });
@@ -16306,7 +16336,7 @@ class Replayer {
16306
16336
  );
16307
16337
  if (firstMeta) {
16308
16338
  const { width, height } = firstMeta.data;
16309
- setTimeout(() => {
16339
+ this.addTimeout(() => {
16310
16340
  this.emitter.emit(ReplayerEvents.Resize, {
16311
16341
  width,
16312
16342
  height
@@ -16314,7 +16344,7 @@ class Replayer {
16314
16344
  }, 0);
16315
16345
  }
16316
16346
  if (firstFullsnapshot) {
16317
- setTimeout(() => {
16347
+ this.addTimeout(() => {
16318
16348
  var _a2;
16319
16349
  if (this.firstFullSnapshot) {
16320
16350
  return;
@@ -16343,6 +16373,24 @@ class Replayer {
16343
16373
  this.emitter.off(event, handler);
16344
16374
  return this;
16345
16375
  }
16376
+ /**
16377
+ * Track emitter handlers for cleanup
16378
+ */
16379
+ addEmitterHandler(event, handler) {
16380
+ this.emitter.on(event, handler);
16381
+ this.emitterHandlers.push({ event, handler });
16382
+ }
16383
+ /**
16384
+ * Track timeouts for cleanup
16385
+ */
16386
+ addTimeout(callback, delay) {
16387
+ const timeout = setTimeout(() => {
16388
+ this.timeouts.delete(timeout);
16389
+ callback();
16390
+ }, delay);
16391
+ this.timeouts.add(timeout);
16392
+ return timeout;
16393
+ }
16346
16394
  setConfig(config) {
16347
16395
  Object.keys(config).forEach((key) => {
16348
16396
  config[key];
@@ -16445,10 +16493,31 @@ class Replayer {
16445
16493
  * Memory occupation can be released by removing all references to this replayer.
16446
16494
  */
16447
16495
  destroy() {
16496
+ var _a2, _b;
16497
+ if (!this.wrapper || !this.wrapper.parentNode) {
16498
+ return;
16499
+ }
16448
16500
  this.pause();
16501
+ this.emitterHandlers.forEach(({ event, handler }) => {
16502
+ this.emitter.off(event, handler);
16503
+ });
16504
+ this.emitterHandlers = [];
16505
+ (_a2 = this.serviceSubscription) == null ? void 0 : _a2.unsubscribe();
16506
+ (_b = this.speedServiceSubscription) == null ? void 0 : _b.unsubscribe();
16507
+ this.serviceSubscription = void 0;
16508
+ this.speedServiceSubscription = void 0;
16509
+ this.timeouts.forEach((timeout) => clearTimeout(timeout));
16510
+ this.timeouts.clear();
16511
+ this.styleSheetLoadListeners.forEach((handler, element) => {
16512
+ element.removeEventListener("load", handler);
16513
+ });
16514
+ this.styleSheetLoadListeners.clear();
16515
+ this.imageMap.clear();
16516
+ this.canvasEventMap.clear();
16449
16517
  this.mirror.reset();
16450
16518
  this.styleMirror.reset();
16451
16519
  this.mediaManager.reset();
16520
+ this.resetCache();
16452
16521
  this.config.root.removeChild(this.wrapper);
16453
16522
  this.emitter.emit(ReplayerEvents.Destroy);
16454
16523
  }