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