@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.d.cts CHANGED
@@ -282,9 +282,16 @@ export declare class Replayer {
282
282
  private lastSelectionData;
283
283
  private constructedStyleMutations;
284
284
  private adoptedStyleSheets;
285
+ private emitterHandlers;
286
+ private serviceSubscription?;
287
+ private speedServiceSubscription?;
288
+ private timeouts;
289
+ private styleSheetLoadListeners;
285
290
  constructor(events: Array<eventWithTime | string>, config?: Partial<playerConfig>);
286
291
  on(event: string, handler: Handler): this;
287
292
  off(event: string, handler: Handler): this;
293
+ private addEmitterHandler;
294
+ private addTimeout;
288
295
  setConfig(config: Partial<playerConfig>): void;
289
296
  getMetaData(): playerMetaData;
290
297
  getCurrentTime(): number;
package/dist/rrweb.d.ts CHANGED
@@ -282,9 +282,16 @@ export declare class Replayer {
282
282
  private lastSelectionData;
283
283
  private constructedStyleMutations;
284
284
  private adoptedStyleSheets;
285
+ private emitterHandlers;
286
+ private serviceSubscription?;
287
+ private speedServiceSubscription?;
288
+ private timeouts;
289
+ private styleSheetLoadListeners;
285
290
  constructor(events: Array<eventWithTime | string>, config?: Partial<playerConfig>);
286
291
  on(event: string, handler: Handler): this;
287
292
  off(event: string, handler: Handler): this;
293
+ private addEmitterHandler;
294
+ private addTimeout;
288
295
  setConfig(config: Partial<playerConfig>): void;
289
296
  getMetaData(): playerMetaData;
290
297
  getCurrentTime(): number;
package/dist/rrweb.js CHANGED
@@ -13227,6 +13227,7 @@ function initObservers(o2, hooks = {}) {
13227
13227
  selectionObserver();
13228
13228
  customElementObserver();
13229
13229
  pluginHandlers.forEach((h) => h());
13230
+ mutationBuffers.length = 0;
13230
13231
  });
13231
13232
  }
13232
13233
  function hasNestedCSSRule(prop) {
@@ -13313,6 +13314,9 @@ class IframeManager {
13313
13314
  __publicField(this, "loadListener");
13314
13315
  __publicField(this, "stylesheetManager");
13315
13316
  __publicField(this, "recordCrossOriginIframes");
13317
+ __publicField(this, "messageHandler");
13318
+ // Map window to handler for cleanup - windows are browser-owned and won't prevent GC
13319
+ __publicField(this, "nestedIframeListeners", /* @__PURE__ */ new Map());
13316
13320
  this.mutationCb = options.mutationCb;
13317
13321
  this.wrappedEmit = options.wrappedEmit;
13318
13322
  this.stylesheetManager = options.stylesheetManager;
@@ -13323,8 +13327,9 @@ class IframeManager {
13323
13327
  )
13324
13328
  );
13325
13329
  this.mirror = options.mirror;
13330
+ this.messageHandler = this.handleMessage.bind(this);
13326
13331
  if (this.recordCrossOriginIframes) {
13327
- window.addEventListener("message", this.handleMessage.bind(this));
13332
+ window.addEventListener("message", this.messageHandler);
13328
13333
  }
13329
13334
  }
13330
13335
  addIframe(iframeEl) {
@@ -13336,7 +13341,7 @@ class IframeManager {
13336
13341
  this.loadListener = cb;
13337
13342
  }
13338
13343
  attachIframe(iframeEl, childSn) {
13339
- var _a2, _b;
13344
+ var _a2;
13340
13345
  this.mutationCb({
13341
13346
  adds: [
13342
13347
  {
@@ -13350,12 +13355,13 @@ class IframeManager {
13350
13355
  attributes: [],
13351
13356
  isAttachIframe: true
13352
13357
  });
13353
- if (this.recordCrossOriginIframes)
13354
- (_a2 = iframeEl.contentWindow) == null ? void 0 : _a2.addEventListener(
13355
- "message",
13356
- this.handleMessage.bind(this)
13357
- );
13358
- (_b = this.loadListener) == null ? void 0 : _b.call(this, iframeEl);
13358
+ const win = iframeEl.contentWindow;
13359
+ if (this.recordCrossOriginIframes && win && !this.nestedIframeListeners.has(win)) {
13360
+ const nestedHandler = this.handleMessage.bind(this);
13361
+ this.nestedIframeListeners.set(win, nestedHandler);
13362
+ win.addEventListener("message", nestedHandler);
13363
+ }
13364
+ (_a2 = this.loadListener) == null ? void 0 : _a2.call(this, iframeEl);
13359
13365
  if (iframeEl.contentDocument && iframeEl.contentDocument.adoptedStyleSheets && iframeEl.contentDocument.adoptedStyleSheets.length > 0)
13360
13366
  this.stylesheetManager.adoptStyleSheets(
13361
13367
  iframeEl.contentDocument.adoptedStyleSheets,
@@ -13533,6 +13539,15 @@ class IframeManager {
13533
13539
  });
13534
13540
  }
13535
13541
  }
13542
+ destroy() {
13543
+ if (this.recordCrossOriginIframes) {
13544
+ window.removeEventListener("message", this.messageHandler);
13545
+ }
13546
+ this.nestedIframeListeners.forEach((handler, contentWindow) => {
13547
+ contentWindow.removeEventListener("message", handler);
13548
+ });
13549
+ this.nestedIframeListeners.clear();
13550
+ }
13536
13551
  }
13537
13552
  class ShadowDomManager {
13538
13553
  constructor(options) {
@@ -14768,6 +14783,7 @@ function record(options = {}) {
14768
14783
  return () => {
14769
14784
  handlers.forEach((h) => h());
14770
14785
  processedNodeManager.destroy();
14786
+ iframeManager.destroy();
14771
14787
  recording = false;
14772
14788
  unregisterErrorHandler();
14773
14789
  };
@@ -15990,6 +16006,12 @@ class Replayer {
15990
16006
  __publicField(this, "constructedStyleMutations", []);
15991
16007
  // Similar to the reason for constructedStyleMutations.
15992
16008
  __publicField(this, "adoptedStyleSheets", []);
16009
+ // Track resources for cleanup
16010
+ __publicField(this, "emitterHandlers", []);
16011
+ __publicField(this, "serviceSubscription");
16012
+ __publicField(this, "speedServiceSubscription");
16013
+ __publicField(this, "timeouts", /* @__PURE__ */ new Set());
16014
+ __publicField(this, "styleSheetLoadListeners", /* @__PURE__ */ new Map());
15993
16015
  __publicField(this, "handleResize", (dimension) => {
15994
16016
  this.iframe.style.display = "inherit";
15995
16017
  for (const el of [this.mouseTail, this.iframe]) {
@@ -16149,12 +16171,12 @@ class Replayer {
16149
16171
  this.handleResize = this.handleResize.bind(this);
16150
16172
  this.getCastFn = this.getCastFn.bind(this);
16151
16173
  this.applyEventsSynchronously = this.applyEventsSynchronously.bind(this);
16152
- this.emitter.on(ReplayerEvents.Resize, this.handleResize);
16174
+ this.addEmitterHandler(ReplayerEvents.Resize, this.handleResize);
16153
16175
  this.setupDom();
16154
16176
  for (const plugin of this.config.plugins || []) {
16155
16177
  if (plugin.getMirror) plugin.getMirror({ nodeMirror: this.mirror });
16156
16178
  }
16157
- this.emitter.on(ReplayerEvents.Flush, () => {
16179
+ const flushHandler = () => {
16158
16180
  if (this.usingVirtualDom) {
16159
16181
  const replayerHandler = {
16160
16182
  mirror: this.mirror,
@@ -16250,13 +16272,15 @@ class Replayer {
16250
16272
  this.applySelection(this.lastSelectionData);
16251
16273
  this.lastSelectionData = null;
16252
16274
  }
16253
- });
16254
- this.emitter.on(ReplayerEvents.PlayBack, () => {
16275
+ };
16276
+ this.addEmitterHandler(ReplayerEvents.Flush, flushHandler);
16277
+ const playBackHandler = () => {
16255
16278
  this.firstFullSnapshot = null;
16256
16279
  this.mirror.reset();
16257
16280
  this.styleMirror.reset();
16258
16281
  this.mediaManager.reset();
16259
- });
16282
+ };
16283
+ this.addEmitterHandler(ReplayerEvents.PlayBack, playBackHandler);
16260
16284
  const timer = new Timer([], {
16261
16285
  speed: this.config.speed
16262
16286
  });
@@ -16280,7 +16304,7 @@ class Replayer {
16280
16304
  }
16281
16305
  );
16282
16306
  this.service.start();
16283
- this.service.subscribe((state) => {
16307
+ this.serviceSubscription = this.service.subscribe((state) => {
16284
16308
  this.emitter.emit(ReplayerEvents.StateChange, {
16285
16309
  player: state
16286
16310
  });
@@ -16290,7 +16314,7 @@ class Replayer {
16290
16314
  timer
16291
16315
  });
16292
16316
  this.speedService.start();
16293
- this.speedService.subscribe((state) => {
16317
+ this.speedServiceSubscription = this.speedService.subscribe((state) => {
16294
16318
  this.emitter.emit(ReplayerEvents.StateChange, {
16295
16319
  speed: state
16296
16320
  });
@@ -16310,7 +16334,7 @@ class Replayer {
16310
16334
  );
16311
16335
  if (firstMeta) {
16312
16336
  const { width, height } = firstMeta.data;
16313
- setTimeout(() => {
16337
+ this.addTimeout(() => {
16314
16338
  this.emitter.emit(ReplayerEvents.Resize, {
16315
16339
  width,
16316
16340
  height
@@ -16318,7 +16342,7 @@ class Replayer {
16318
16342
  }, 0);
16319
16343
  }
16320
16344
  if (firstFullsnapshot) {
16321
- setTimeout(() => {
16345
+ this.addTimeout(() => {
16322
16346
  var _a2;
16323
16347
  if (this.firstFullSnapshot) {
16324
16348
  return;
@@ -16347,6 +16371,24 @@ class Replayer {
16347
16371
  this.emitter.off(event, handler);
16348
16372
  return this;
16349
16373
  }
16374
+ /**
16375
+ * Track emitter handlers for cleanup
16376
+ */
16377
+ addEmitterHandler(event, handler) {
16378
+ this.emitter.on(event, handler);
16379
+ this.emitterHandlers.push({ event, handler });
16380
+ }
16381
+ /**
16382
+ * Track timeouts for cleanup
16383
+ */
16384
+ addTimeout(callback, delay) {
16385
+ const timeout = setTimeout(() => {
16386
+ this.timeouts.delete(timeout);
16387
+ callback();
16388
+ }, delay);
16389
+ this.timeouts.add(timeout);
16390
+ return timeout;
16391
+ }
16350
16392
  setConfig(config) {
16351
16393
  Object.keys(config).forEach((key) => {
16352
16394
  config[key];
@@ -16449,10 +16491,31 @@ class Replayer {
16449
16491
  * Memory occupation can be released by removing all references to this replayer.
16450
16492
  */
16451
16493
  destroy() {
16494
+ var _a2, _b;
16495
+ if (!this.wrapper || !this.wrapper.parentNode) {
16496
+ return;
16497
+ }
16452
16498
  this.pause();
16499
+ this.emitterHandlers.forEach(({ event, handler }) => {
16500
+ this.emitter.off(event, handler);
16501
+ });
16502
+ this.emitterHandlers = [];
16503
+ (_a2 = this.serviceSubscription) == null ? void 0 : _a2.unsubscribe();
16504
+ (_b = this.speedServiceSubscription) == null ? void 0 : _b.unsubscribe();
16505
+ this.serviceSubscription = void 0;
16506
+ this.speedServiceSubscription = void 0;
16507
+ this.timeouts.forEach((timeout) => clearTimeout(timeout));
16508
+ this.timeouts.clear();
16509
+ this.styleSheetLoadListeners.forEach((handler, element) => {
16510
+ element.removeEventListener("load", handler);
16511
+ });
16512
+ this.styleSheetLoadListeners.clear();
16513
+ this.imageMap.clear();
16514
+ this.canvasEventMap.clear();
16453
16515
  this.mirror.reset();
16454
16516
  this.styleMirror.reset();
16455
16517
  this.mediaManager.reset();
16518
+ this.resetCache();
16456
16519
  this.config.root.removeChild(this.wrapper);
16457
16520
  this.emitter.emit(ReplayerEvents.Destroy);
16458
16521
  }