@posthog/rrweb 0.0.28 → 0.0.30

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
@@ -207,6 +207,91 @@ function isShadowRoot(n2) {
207
207
  function isNativeShadowDom(shadowRoot2) {
208
208
  return Object.prototype.toString.call(shadowRoot2) === "[object ShadowRoot]";
209
209
  }
210
+ function fixBrowserCompatibilityIssuesInCSS(cssText) {
211
+ if (cssText.includes(" background-clip: text;") && !cssText.includes(" -webkit-background-clip: text;")) {
212
+ cssText = cssText.replace(
213
+ /\sbackground-clip:\s*text;/g,
214
+ " -webkit-background-clip: text; background-clip: text;"
215
+ );
216
+ }
217
+ return cssText;
218
+ }
219
+ function escapeImportStatement(rule2) {
220
+ const { cssText } = rule2;
221
+ if (cssText.split('"').length < 3) return cssText;
222
+ const statement = ["@import", `url(${JSON.stringify(rule2.href)})`];
223
+ if (rule2.layerName === "") {
224
+ statement.push(`layer`);
225
+ } else if (rule2.layerName) {
226
+ statement.push(`layer(${rule2.layerName})`);
227
+ }
228
+ if (rule2.supportsText) {
229
+ statement.push(`supports(${rule2.supportsText})`);
230
+ }
231
+ if (rule2.media.length) {
232
+ statement.push(rule2.media.mediaText);
233
+ }
234
+ return statement.join(" ") + ";";
235
+ }
236
+ function stringifyStylesheet(s2) {
237
+ try {
238
+ const rules2 = s2.rules || s2.cssRules;
239
+ if (!rules2) {
240
+ return null;
241
+ }
242
+ let sheetHref = s2.href;
243
+ if (!sheetHref && s2.ownerNode) {
244
+ sheetHref = s2.ownerNode.baseURI;
245
+ }
246
+ const stringifiedRules = Array.from(
247
+ rules2,
248
+ (rule2) => stringifyRule(rule2, sheetHref)
249
+ ).join("");
250
+ return fixBrowserCompatibilityIssuesInCSS(stringifiedRules);
251
+ } catch (error) {
252
+ return null;
253
+ }
254
+ }
255
+ function stringifyRule(rule2, sheetHref) {
256
+ var _a2;
257
+ if (isCSSImportRule(rule2)) {
258
+ let importStringified;
259
+ try {
260
+ importStringified = // for same-origin stylesheets,
261
+ // we can access the imported stylesheet rules directly
262
+ stringifyStylesheet(rule2.styleSheet) || // work around browser issues with the raw string `@import url(...)` statement
263
+ escapeImportStatement(rule2);
264
+ } catch (error) {
265
+ importStringified = rule2.cssText;
266
+ }
267
+ try {
268
+ if (importStringified && ((_a2 = rule2.styleSheet) == null ? void 0 : _a2.href)) {
269
+ return absolutifyURLs(importStringified, rule2.styleSheet.href);
270
+ }
271
+ } catch {
272
+ }
273
+ return importStringified;
274
+ } else {
275
+ let ruleStringified = rule2.cssText;
276
+ if (isCSSStyleRule(rule2) && rule2.selectorText.includes(":")) {
277
+ ruleStringified = fixSafariColons(ruleStringified);
278
+ }
279
+ if (sheetHref) {
280
+ return absolutifyURLs(ruleStringified, sheetHref);
281
+ }
282
+ return ruleStringified;
283
+ }
284
+ }
285
+ function fixSafariColons(cssStringified) {
286
+ const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
287
+ return cssStringified.replace(regex, "$1\\$2");
288
+ }
289
+ function isCSSImportRule(rule2) {
290
+ return "styleSheet" in rule2;
291
+ }
292
+ function isCSSStyleRule(rule2) {
293
+ return "selectorText" in rule2;
294
+ }
210
295
  class Mirror {
211
296
  constructor() {
212
297
  __publicField$1(this, "idNodeMap", /* @__PURE__ */ new Map());
@@ -341,91 +426,6 @@ function extractFileExtension(path, baseURL) {
341
426
  const match = url.pathname.match(regex);
342
427
  return (match == null ? void 0 : match[1]) ?? null;
343
428
  }
344
- function fixBrowserCompatibilityIssuesInCSS(cssText) {
345
- if (cssText.includes(" background-clip: text;") && !cssText.includes(" -webkit-background-clip: text;")) {
346
- cssText = cssText.replace(
347
- /\sbackground-clip:\s*text;/g,
348
- " -webkit-background-clip: text; background-clip: text;"
349
- );
350
- }
351
- return cssText;
352
- }
353
- function escapeImportStatement(rule2) {
354
- const { cssText } = rule2;
355
- if (cssText.split('"').length < 3) return cssText;
356
- const statement = ["@import", `url(${JSON.stringify(rule2.href)})`];
357
- if (rule2.layerName === "") {
358
- statement.push(`layer`);
359
- } else if (rule2.layerName) {
360
- statement.push(`layer(${rule2.layerName})`);
361
- }
362
- if (rule2.supportsText) {
363
- statement.push(`supports(${rule2.supportsText})`);
364
- }
365
- if (rule2.media.length) {
366
- statement.push(rule2.media.mediaText);
367
- }
368
- return statement.join(" ") + ";";
369
- }
370
- function stringifyStylesheet(s2) {
371
- try {
372
- const rules2 = s2.rules || s2.cssRules;
373
- if (!rules2) {
374
- return null;
375
- }
376
- let sheetHref = s2.href;
377
- if (!sheetHref && s2.ownerNode) {
378
- sheetHref = s2.ownerNode.baseURI;
379
- }
380
- const stringifiedRules = Array.from(
381
- rules2,
382
- (rule2) => stringifyRule(rule2, sheetHref)
383
- ).join("");
384
- return fixBrowserCompatibilityIssuesInCSS(stringifiedRules);
385
- } catch (error) {
386
- return null;
387
- }
388
- }
389
- function stringifyRule(rule2, sheetHref) {
390
- var _a2;
391
- if (isCSSImportRule(rule2)) {
392
- let importStringified;
393
- try {
394
- importStringified = // for same-origin stylesheets,
395
- // we can access the imported stylesheet rules directly
396
- stringifyStylesheet(rule2.styleSheet) || // work around browser issues with the raw string `@import url(...)` statement
397
- escapeImportStatement(rule2);
398
- } catch (error) {
399
- importStringified = rule2.cssText;
400
- }
401
- try {
402
- if (importStringified && ((_a2 = rule2.styleSheet) == null ? void 0 : _a2.href)) {
403
- return absolutifyURLs(importStringified, rule2.styleSheet.href);
404
- }
405
- } catch {
406
- }
407
- return importStringified;
408
- } else {
409
- let ruleStringified = rule2.cssText;
410
- if (isCSSStyleRule(rule2) && rule2.selectorText.includes(":")) {
411
- ruleStringified = fixSafariColons(ruleStringified);
412
- }
413
- if (sheetHref) {
414
- return absolutifyURLs(ruleStringified, sheetHref);
415
- }
416
- return ruleStringified;
417
- }
418
- }
419
- function fixSafariColons(cssStringified) {
420
- const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
421
- return cssStringified.replace(regex, "$1\\$2");
422
- }
423
- function isCSSImportRule(rule2) {
424
- return "styleSheet" in rule2;
425
- }
426
- function isCSSStyleRule(rule2) {
427
- return "selectorText" in rule2;
428
- }
429
429
  function extractOrigin(url) {
430
430
  let origin = "";
431
431
  if (url.indexOf("//") > -1) {
@@ -474,6 +474,36 @@ function absolutifyURLs(cssText, href) {
474
474
  }
475
475
  );
476
476
  }
477
+ const STRIPED_PLACEHOLDER_SVG = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzPgogICAgPHBhdHRlcm4gaWQ9InN0cmlwZXMiIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+CiAgICAgIDxyZWN0IHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iYmxhY2siLz4KICAgICAgPHBhdGggZD0iTTggMEgxNkwwIDE2VjhMOCAwWiIgZmlsbD0iIzJEMkQyRCIvPgogICAgICA8cGF0aCBkPSJNMTYgOFYxNkg4TDE2IDhaIiBmaWxsPSIjMkQyRDJEIi8+CiAgICA8L3BhdHRlcm4+CiAgPC9kZWZzPgogIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjc3RyaXBlcykiLz4KPC9zdmc+Cg==";
478
+ const MAX_IMAGE_DIMENSION_FOR_RECOMPRESSION = 4096;
479
+ function recompressBase64Image(img, dataURL, type, quality) {
480
+ if (!img.complete || img.naturalWidth === 0) {
481
+ return dataURL;
482
+ }
483
+ if (img.naturalWidth > MAX_IMAGE_DIMENSION_FOR_RECOMPRESSION || img.naturalHeight > MAX_IMAGE_DIMENSION_FOR_RECOMPRESSION) {
484
+ return dataURL;
485
+ }
486
+ try {
487
+ const canvas = document.createElement("canvas");
488
+ canvas.width = img.naturalWidth;
489
+ canvas.height = img.naturalHeight;
490
+ const ctx = canvas.getContext("2d");
491
+ if (!ctx) {
492
+ return dataURL;
493
+ }
494
+ ctx.drawImage(img, 0, 0);
495
+ const recompressed = canvas.toDataURL(type || "image/webp", quality ?? 0.4);
496
+ return recompressed;
497
+ } catch (err) {
498
+ return dataURL;
499
+ }
500
+ }
501
+ function checkDataURLSize(dataURL, maxLength) {
502
+ if (!maxLength || dataURL.length <= maxLength) {
503
+ return dataURL;
504
+ }
505
+ return STRIPED_PLACEHOLDER_SVG;
506
+ }
477
507
  let _id = 1;
478
508
  const tagNameRegex = new RegExp("[^a-z0-9-_:]");
479
509
  const IGNORED_NODE = -2;
@@ -572,12 +602,32 @@ function getHref(doc, customHref) {
572
602
  a2.setAttribute("href", customHref);
573
603
  return a2.href;
574
604
  }
575
- function transformAttribute(doc, tagName, name, value) {
605
+ function transformAttribute(doc, tagName, name, value, element, dataURLOptions) {
576
606
  if (!value) {
577
607
  return value;
578
608
  }
579
609
  if (name === "src" || name === "href" && !(tagName === "use" && value[0] === "#")) {
580
- return absoluteToDoc(doc, value);
610
+ const transformedValue = absoluteToDoc(doc, value);
611
+ if (tagName === "img" && transformedValue.startsWith("data:") && element) {
612
+ const img = element;
613
+ let processedDataURL = transformedValue;
614
+ if ((dataURLOptions == null ? void 0 : dataURLOptions.type) || (dataURLOptions == null ? void 0 : dataURLOptions.quality) !== void 0) {
615
+ processedDataURL = recompressBase64Image(
616
+ img,
617
+ transformedValue,
618
+ dataURLOptions.type,
619
+ dataURLOptions.quality
620
+ );
621
+ }
622
+ if (dataURLOptions == null ? void 0 : dataURLOptions.maxBase64ImageLength) {
623
+ processedDataURL = checkDataURLSize(
624
+ processedDataURL,
625
+ dataURLOptions.maxBase64ImageLength
626
+ );
627
+ }
628
+ return processedDataURL;
629
+ }
630
+ return transformedValue;
581
631
  } else if (name === "xlink:href" && value[0] !== "#") {
582
632
  return absoluteToDoc(doc, value);
583
633
  } else if (name === "background" && (tagName === "table" || tagName === "td" || tagName === "th")) {
@@ -868,7 +918,9 @@ function serializeElementNode(n2, options) {
868
918
  doc,
869
919
  tagName,
870
920
  toLowerCase(attr.name),
871
- attr.value
921
+ attr.value,
922
+ n2,
923
+ dataURLOptions
872
924
  );
873
925
  }
874
926
  }
@@ -5332,22 +5384,6 @@ postcss$1.Input;
5332
5384
  postcss$1.Rule;
5333
5385
  postcss$1.Root;
5334
5386
  postcss$1.Node;
5335
- function adaptCssForReplay(cssText, cache) {
5336
- const cachedStyle = cache == null ? void 0 : cache.stylesWithHoverClass.get(cssText);
5337
- if (cachedStyle) return cachedStyle;
5338
- let result2 = cssText;
5339
- try {
5340
- const ast = postcss$1([
5341
- mediaSelectorPlugin,
5342
- pseudoClassPlugin
5343
- ]).process(cssText, { parser: safeParser });
5344
- result2 = ast.css;
5345
- } catch (error) {
5346
- console.warn("Failed to adapt css for replay", error);
5347
- }
5348
- cache == null ? void 0 : cache.stylesWithHoverClass.set(cssText, result2);
5349
- return result2;
5350
- }
5351
5387
  const tagMap = {
5352
5388
  script: "noscript",
5353
5389
  // camel case svg element tag names
@@ -5395,6 +5431,22 @@ function getTagName(n2) {
5395
5431
  }
5396
5432
  return tagName;
5397
5433
  }
5434
+ function adaptCssForReplay(cssText, cache) {
5435
+ const cachedStyle = cache == null ? void 0 : cache.stylesWithHoverClass.get(cssText);
5436
+ if (cachedStyle) return cachedStyle;
5437
+ let result2 = cssText;
5438
+ try {
5439
+ const ast = postcss$1([
5440
+ mediaSelectorPlugin,
5441
+ pseudoClassPlugin
5442
+ ]).process(cssText, { parser: safeParser });
5443
+ result2 = ast.css;
5444
+ } catch (error) {
5445
+ console.warn("Failed to adapt css for replay", error);
5446
+ }
5447
+ cache == null ? void 0 : cache.stylesWithHoverClass.set(cssText, result2);
5448
+ return result2;
5449
+ }
5398
5450
  function createCache() {
5399
5451
  const stylesWithHoverClass = /* @__PURE__ */ new Map();
5400
5452
  return {
@@ -12006,7 +12058,9 @@ class MutationBuffer {
12006
12058
  this.doc,
12007
12059
  toLowerCase(target.tagName),
12008
12060
  toLowerCase(attributeName),
12009
- value
12061
+ value,
12062
+ target,
12063
+ this.dataURLOptions
12010
12064
  );
12011
12065
  if (attributeName === "style") {
12012
12066
  if (!this.unattachedDoc) {
@@ -12168,6 +12222,11 @@ class MutationBuffer {
12168
12222
  this.shadowDomManager.reset();
12169
12223
  this.canvasManager.reset();
12170
12224
  }
12225
+ destroy() {
12226
+ while (this.mapRemoves.length) {
12227
+ this.mirror.removeNodeFromMap(this.mapRemoves.shift());
12228
+ }
12229
+ }
12171
12230
  }
12172
12231
  function deepDelete(addsSet, n2) {
12173
12232
  addsSet.delete(n2);
@@ -13214,6 +13273,7 @@ function initObservers(o2, hooks = {}) {
13214
13273
  );
13215
13274
  }
13216
13275
  return callbackWrapper(() => {
13276
+ mutationBuffers.forEach((b) => b.destroy());
13217
13277
  mutationBuffers.forEach((b) => b.reset());
13218
13278
  mutationObserver == null ? void 0 : mutationObserver.disconnect();
13219
13279
  mousemoveHandler();
@@ -13552,6 +13612,8 @@ class IframeManager {
13552
13612
  contentWindow.removeEventListener("message", handler);
13553
13613
  });
13554
13614
  this.nestedIframeListeners.clear();
13615
+ this.crossOriginIframeMirror.reset();
13616
+ this.crossOriginIframeStyleMirror.reset();
13555
13617
  }
13556
13618
  }
13557
13619
  class ShadowDomManager {
@@ -14030,6 +14092,8 @@ class CanvasManager {
14030
14092
  __publicField(this, "resetObservers");
14031
14093
  __publicField(this, "frozen", false);
14032
14094
  __publicField(this, "locked", false);
14095
+ __publicField(this, "rafIdTimestamp", null);
14096
+ __publicField(this, "rafIdFlush", null);
14033
14097
  __publicField(this, "processMutation", (target, mutation) => {
14034
14098
  const newFrame = this.rafStamps.invokeId && this.rafStamps.latestId !== this.rafStamps.invokeId;
14035
14099
  if (newFrame || !this.rafStamps.invokeId)
@@ -14064,6 +14128,14 @@ class CanvasManager {
14064
14128
  reset() {
14065
14129
  this.pendingCanvasMutations.clear();
14066
14130
  this.resetObservers && this.resetObservers();
14131
+ if (this.rafIdTimestamp !== null) {
14132
+ cancelAnimationFrame(this.rafIdTimestamp);
14133
+ this.rafIdTimestamp = null;
14134
+ }
14135
+ if (this.rafIdFlush !== null) {
14136
+ cancelAnimationFrame(this.rafIdFlush);
14137
+ this.rafIdFlush = null;
14138
+ }
14067
14139
  }
14068
14140
  freeze() {
14069
14141
  this.frozen = true;
@@ -14214,14 +14286,16 @@ class CanvasManager {
14214
14286
  };
14215
14287
  }
14216
14288
  startPendingCanvasMutationFlusher() {
14217
- requestAnimationFrame(() => this.flushPendingCanvasMutations());
14289
+ this.rafIdFlush = requestAnimationFrame(
14290
+ () => this.flushPendingCanvasMutations()
14291
+ );
14218
14292
  }
14219
14293
  startRAFTimestamping() {
14220
14294
  const setLatestRAFTimestamp = (timestamp) => {
14221
14295
  this.rafStamps.latestId = timestamp;
14222
- requestAnimationFrame(setLatestRAFTimestamp);
14296
+ this.rafIdTimestamp = requestAnimationFrame(setLatestRAFTimestamp);
14223
14297
  };
14224
- requestAnimationFrame(setLatestRAFTimestamp);
14298
+ this.rafIdTimestamp = requestAnimationFrame(setLatestRAFTimestamp);
14225
14299
  }
14226
14300
  flushPendingCanvasMutations() {
14227
14301
  this.pendingCanvasMutations.forEach(
@@ -14230,7 +14304,9 @@ class CanvasManager {
14230
14304
  this.flushPendingCanvasMutationFor(canvas, id);
14231
14305
  }
14232
14306
  );
14233
- requestAnimationFrame(() => this.flushPendingCanvasMutations());
14307
+ this.rafIdFlush = requestAnimationFrame(
14308
+ () => this.flushPendingCanvasMutations()
14309
+ );
14234
14310
  }
14235
14311
  flushPendingCanvasMutationFor(canvas, id) {
14236
14312
  if (this.frozen || this.locked) {
@@ -14365,7 +14441,7 @@ function record(options = {}) {
14365
14441
  hooks,
14366
14442
  packFn,
14367
14443
  sampling = {},
14368
- dataURLOptions = {},
14444
+ dataURLOptions: _dataURLOptions = {},
14369
14445
  mousemoveWait,
14370
14446
  recordDOM = true,
14371
14447
  recordCanvas = false,
@@ -14380,6 +14456,12 @@ function record(options = {}) {
14380
14456
  errorHandler: errorHandler2
14381
14457
  } = options;
14382
14458
  registerErrorHandler(errorHandler2);
14459
+ const dataURLOptions = {
14460
+ type: "image/webp",
14461
+ quality: 0.4,
14462
+ maxBase64ImageLength: 1048576,
14463
+ ..._dataURLOptions
14464
+ };
14383
14465
  const inEmittingFrame = recordCrossOriginIframes ? window.parent === window : true;
14384
14466
  let passEmitsToParent = false;
14385
14467
  if (!inEmittingFrame) {
@@ -14809,6 +14891,7 @@ function record(options = {}) {
14809
14891
  processedNodeManager.destroy();
14810
14892
  iframeManager.removeLoadListener();
14811
14893
  iframeManager.destroy();
14894
+ mirror.reset();
14812
14895
  recording = false;
14813
14896
  unregisterErrorHandler();
14814
14897
  };