@posthog/rrweb 0.0.25 → 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
@@ -13229,6 +13229,7 @@ function initObservers(o2, hooks = {}) {
13229
13229
  selectionObserver();
13230
13230
  customElementObserver();
13231
13231
  pluginHandlers.forEach((h) => h());
13232
+ mutationBuffers.length = 0;
13232
13233
  });
13233
13234
  }
13234
13235
  function hasNestedCSSRule(prop) {
@@ -13315,6 +13316,9 @@ class IframeManager {
13315
13316
  __publicField(this, "loadListener");
13316
13317
  __publicField(this, "stylesheetManager");
13317
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());
13318
13322
  this.mutationCb = options.mutationCb;
13319
13323
  this.wrappedEmit = options.wrappedEmit;
13320
13324
  this.stylesheetManager = options.stylesheetManager;
@@ -13325,8 +13329,9 @@ class IframeManager {
13325
13329
  )
13326
13330
  );
13327
13331
  this.mirror = options.mirror;
13332
+ this.messageHandler = this.handleMessage.bind(this);
13328
13333
  if (this.recordCrossOriginIframes) {
13329
- window.addEventListener("message", this.handleMessage.bind(this));
13334
+ window.addEventListener("message", this.messageHandler);
13330
13335
  }
13331
13336
  }
13332
13337
  addIframe(iframeEl) {
@@ -13338,7 +13343,7 @@ class IframeManager {
13338
13343
  this.loadListener = cb;
13339
13344
  }
13340
13345
  attachIframe(iframeEl, childSn) {
13341
- var _a2, _b;
13346
+ var _a2;
13342
13347
  this.mutationCb({
13343
13348
  adds: [
13344
13349
  {
@@ -13352,12 +13357,13 @@ class IframeManager {
13352
13357
  attributes: [],
13353
13358
  isAttachIframe: true
13354
13359
  });
13355
- if (this.recordCrossOriginIframes)
13356
- (_a2 = iframeEl.contentWindow) == null ? void 0 : _a2.addEventListener(
13357
- "message",
13358
- this.handleMessage.bind(this)
13359
- );
13360
- (_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);
13361
13367
  if (iframeEl.contentDocument && iframeEl.contentDocument.adoptedStyleSheets && iframeEl.contentDocument.adoptedStyleSheets.length > 0)
13362
13368
  this.stylesheetManager.adoptStyleSheets(
13363
13369
  iframeEl.contentDocument.adoptedStyleSheets,
@@ -13535,6 +13541,15 @@ class IframeManager {
13535
13541
  });
13536
13542
  }
13537
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
+ }
13538
13553
  }
13539
13554
  class ShadowDomManager {
13540
13555
  constructor(options) {
@@ -14770,6 +14785,7 @@ function record(options = {}) {
14770
14785
  return () => {
14771
14786
  handlers.forEach((h) => h());
14772
14787
  processedNodeManager.destroy();
14788
+ iframeManager.destroy();
14773
14789
  recording = false;
14774
14790
  unregisterErrorHandler();
14775
14791
  };
@@ -15992,6 +16008,12 @@ class Replayer {
15992
16008
  __publicField(this, "constructedStyleMutations", []);
15993
16009
  // Similar to the reason for constructedStyleMutations.
15994
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());
15995
16017
  __publicField(this, "handleResize", (dimension) => {
15996
16018
  this.iframe.style.display = "inherit";
15997
16019
  for (const el of [this.mouseTail, this.iframe]) {
@@ -16151,12 +16173,12 @@ class Replayer {
16151
16173
  this.handleResize = this.handleResize.bind(this);
16152
16174
  this.getCastFn = this.getCastFn.bind(this);
16153
16175
  this.applyEventsSynchronously = this.applyEventsSynchronously.bind(this);
16154
- this.emitter.on(ReplayerEvents.Resize, this.handleResize);
16176
+ this.addEmitterHandler(ReplayerEvents.Resize, this.handleResize);
16155
16177
  this.setupDom();
16156
16178
  for (const plugin of this.config.plugins || []) {
16157
16179
  if (plugin.getMirror) plugin.getMirror({ nodeMirror: this.mirror });
16158
16180
  }
16159
- this.emitter.on(ReplayerEvents.Flush, () => {
16181
+ const flushHandler = () => {
16160
16182
  if (this.usingVirtualDom) {
16161
16183
  const replayerHandler = {
16162
16184
  mirror: this.mirror,
@@ -16252,13 +16274,15 @@ class Replayer {
16252
16274
  this.applySelection(this.lastSelectionData);
16253
16275
  this.lastSelectionData = null;
16254
16276
  }
16255
- });
16256
- this.emitter.on(ReplayerEvents.PlayBack, () => {
16277
+ };
16278
+ this.addEmitterHandler(ReplayerEvents.Flush, flushHandler);
16279
+ const playBackHandler = () => {
16257
16280
  this.firstFullSnapshot = null;
16258
16281
  this.mirror.reset();
16259
16282
  this.styleMirror.reset();
16260
16283
  this.mediaManager.reset();
16261
- });
16284
+ };
16285
+ this.addEmitterHandler(ReplayerEvents.PlayBack, playBackHandler);
16262
16286
  const timer = new Timer([], {
16263
16287
  speed: this.config.speed
16264
16288
  });
@@ -16282,7 +16306,7 @@ class Replayer {
16282
16306
  }
16283
16307
  );
16284
16308
  this.service.start();
16285
- this.service.subscribe((state) => {
16309
+ this.serviceSubscription = this.service.subscribe((state) => {
16286
16310
  this.emitter.emit(ReplayerEvents.StateChange, {
16287
16311
  player: state
16288
16312
  });
@@ -16292,7 +16316,7 @@ class Replayer {
16292
16316
  timer
16293
16317
  });
16294
16318
  this.speedService.start();
16295
- this.speedService.subscribe((state) => {
16319
+ this.speedServiceSubscription = this.speedService.subscribe((state) => {
16296
16320
  this.emitter.emit(ReplayerEvents.StateChange, {
16297
16321
  speed: state
16298
16322
  });
@@ -16312,7 +16336,7 @@ class Replayer {
16312
16336
  );
16313
16337
  if (firstMeta) {
16314
16338
  const { width, height } = firstMeta.data;
16315
- setTimeout(() => {
16339
+ this.addTimeout(() => {
16316
16340
  this.emitter.emit(ReplayerEvents.Resize, {
16317
16341
  width,
16318
16342
  height
@@ -16320,7 +16344,7 @@ class Replayer {
16320
16344
  }, 0);
16321
16345
  }
16322
16346
  if (firstFullsnapshot) {
16323
- setTimeout(() => {
16347
+ this.addTimeout(() => {
16324
16348
  var _a2;
16325
16349
  if (this.firstFullSnapshot) {
16326
16350
  return;
@@ -16349,6 +16373,24 @@ class Replayer {
16349
16373
  this.emitter.off(event, handler);
16350
16374
  return this;
16351
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
+ }
16352
16394
  setConfig(config) {
16353
16395
  Object.keys(config).forEach((key) => {
16354
16396
  config[key];
@@ -16451,10 +16493,31 @@ class Replayer {
16451
16493
  * Memory occupation can be released by removing all references to this replayer.
16452
16494
  */
16453
16495
  destroy() {
16496
+ var _a2, _b;
16497
+ if (!this.wrapper || !this.wrapper.parentNode) {
16498
+ return;
16499
+ }
16454
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();
16455
16517
  this.mirror.reset();
16456
16518
  this.styleMirror.reset();
16457
16519
  this.mediaManager.reset();
16520
+ this.resetCache();
16458
16521
  this.config.root.removeChild(this.wrapper);
16459
16522
  this.emitter.emit(ReplayerEvents.Destroy);
16460
16523
  }