@posthog/rrweb-snapshot 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.
@@ -201,6 +201,91 @@ function isShadowRoot(n) {
201
201
  function isNativeShadowDom(shadowRoot2) {
202
202
  return Object.prototype.toString.call(shadowRoot2) === "[object ShadowRoot]";
203
203
  }
204
+ function fixBrowserCompatibilityIssuesInCSS(cssText) {
205
+ if (cssText.includes(" background-clip: text;") && !cssText.includes(" -webkit-background-clip: text;")) {
206
+ cssText = cssText.replace(
207
+ /\sbackground-clip:\s*text;/g,
208
+ " -webkit-background-clip: text; background-clip: text;"
209
+ );
210
+ }
211
+ return cssText;
212
+ }
213
+ function escapeImportStatement(rule2) {
214
+ const { cssText } = rule2;
215
+ if (cssText.split('"').length < 3) return cssText;
216
+ const statement = ["@import", `url(${JSON.stringify(rule2.href)})`];
217
+ if (rule2.layerName === "") {
218
+ statement.push(`layer`);
219
+ } else if (rule2.layerName) {
220
+ statement.push(`layer(${rule2.layerName})`);
221
+ }
222
+ if (rule2.supportsText) {
223
+ statement.push(`supports(${rule2.supportsText})`);
224
+ }
225
+ if (rule2.media.length) {
226
+ statement.push(rule2.media.mediaText);
227
+ }
228
+ return statement.join(" ") + ";";
229
+ }
230
+ function stringifyStylesheet(s) {
231
+ try {
232
+ const rules = s.rules || s.cssRules;
233
+ if (!rules) {
234
+ return null;
235
+ }
236
+ let sheetHref = s.href;
237
+ if (!sheetHref && s.ownerNode) {
238
+ sheetHref = s.ownerNode.baseURI;
239
+ }
240
+ const stringifiedRules = Array.from(
241
+ rules,
242
+ (rule2) => stringifyRule(rule2, sheetHref)
243
+ ).join("");
244
+ return fixBrowserCompatibilityIssuesInCSS(stringifiedRules);
245
+ } catch (error) {
246
+ return null;
247
+ }
248
+ }
249
+ function stringifyRule(rule2, sheetHref) {
250
+ var _a;
251
+ if (isCSSImportRule(rule2)) {
252
+ let importStringified;
253
+ try {
254
+ importStringified = // for same-origin stylesheets,
255
+ // we can access the imported stylesheet rules directly
256
+ stringifyStylesheet(rule2.styleSheet) || // work around browser issues with the raw string `@import url(...)` statement
257
+ escapeImportStatement(rule2);
258
+ } catch (error) {
259
+ importStringified = rule2.cssText;
260
+ }
261
+ try {
262
+ if (importStringified && ((_a = rule2.styleSheet) == null ? void 0 : _a.href)) {
263
+ return absolutifyURLs(importStringified, rule2.styleSheet.href);
264
+ }
265
+ } catch {
266
+ }
267
+ return importStringified;
268
+ } else {
269
+ let ruleStringified = rule2.cssText;
270
+ if (isCSSStyleRule(rule2) && rule2.selectorText.includes(":")) {
271
+ ruleStringified = fixSafariColons(ruleStringified);
272
+ }
273
+ if (sheetHref) {
274
+ return absolutifyURLs(ruleStringified, sheetHref);
275
+ }
276
+ return ruleStringified;
277
+ }
278
+ }
279
+ function fixSafariColons(cssStringified) {
280
+ const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
281
+ return cssStringified.replace(regex, "$1\\$2");
282
+ }
283
+ function isCSSImportRule(rule2) {
284
+ return "styleSheet" in rule2;
285
+ }
286
+ function isCSSStyleRule(rule2) {
287
+ return "selectorText" in rule2;
288
+ }
204
289
  class Mirror {
205
290
  constructor() {
206
291
  __publicField(this, "idNodeMap", /* @__PURE__ */ new Map());
@@ -335,91 +420,6 @@ function extractFileExtension(path, baseURL) {
335
420
  const match = url.pathname.match(regex);
336
421
  return (match == null ? void 0 : match[1]) ?? null;
337
422
  }
338
- function fixBrowserCompatibilityIssuesInCSS(cssText) {
339
- if (cssText.includes(" background-clip: text;") && !cssText.includes(" -webkit-background-clip: text;")) {
340
- cssText = cssText.replace(
341
- /\sbackground-clip:\s*text;/g,
342
- " -webkit-background-clip: text; background-clip: text;"
343
- );
344
- }
345
- return cssText;
346
- }
347
- function escapeImportStatement(rule2) {
348
- const { cssText } = rule2;
349
- if (cssText.split('"').length < 3) return cssText;
350
- const statement = ["@import", `url(${JSON.stringify(rule2.href)})`];
351
- if (rule2.layerName === "") {
352
- statement.push(`layer`);
353
- } else if (rule2.layerName) {
354
- statement.push(`layer(${rule2.layerName})`);
355
- }
356
- if (rule2.supportsText) {
357
- statement.push(`supports(${rule2.supportsText})`);
358
- }
359
- if (rule2.media.length) {
360
- statement.push(rule2.media.mediaText);
361
- }
362
- return statement.join(" ") + ";";
363
- }
364
- function stringifyStylesheet(s) {
365
- try {
366
- const rules = s.rules || s.cssRules;
367
- if (!rules) {
368
- return null;
369
- }
370
- let sheetHref = s.href;
371
- if (!sheetHref && s.ownerNode) {
372
- sheetHref = s.ownerNode.baseURI;
373
- }
374
- const stringifiedRules = Array.from(
375
- rules,
376
- (rule2) => stringifyRule(rule2, sheetHref)
377
- ).join("");
378
- return fixBrowserCompatibilityIssuesInCSS(stringifiedRules);
379
- } catch (error) {
380
- return null;
381
- }
382
- }
383
- function stringifyRule(rule2, sheetHref) {
384
- var _a;
385
- if (isCSSImportRule(rule2)) {
386
- let importStringified;
387
- try {
388
- importStringified = // for same-origin stylesheets,
389
- // we can access the imported stylesheet rules directly
390
- stringifyStylesheet(rule2.styleSheet) || // work around browser issues with the raw string `@import url(...)` statement
391
- escapeImportStatement(rule2);
392
- } catch (error) {
393
- importStringified = rule2.cssText;
394
- }
395
- try {
396
- if (importStringified && ((_a = rule2.styleSheet) == null ? void 0 : _a.href)) {
397
- return absolutifyURLs(importStringified, rule2.styleSheet.href);
398
- }
399
- } catch {
400
- }
401
- return importStringified;
402
- } else {
403
- let ruleStringified = rule2.cssText;
404
- if (isCSSStyleRule(rule2) && rule2.selectorText.includes(":")) {
405
- ruleStringified = fixSafariColons(ruleStringified);
406
- }
407
- if (sheetHref) {
408
- return absolutifyURLs(ruleStringified, sheetHref);
409
- }
410
- return ruleStringified;
411
- }
412
- }
413
- function fixSafariColons(cssStringified) {
414
- const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
415
- return cssStringified.replace(regex, "$1\\$2");
416
- }
417
- function isCSSImportRule(rule2) {
418
- return "styleSheet" in rule2;
419
- }
420
- function isCSSStyleRule(rule2) {
421
- return "selectorText" in rule2;
422
- }
423
423
  function extractOrigin(url) {
424
424
  let origin = "";
425
425
  if (url.indexOf("//") > -1) {
@@ -468,6 +468,36 @@ function absolutifyURLs(cssText, href) {
468
468
  }
469
469
  );
470
470
  }
471
+ const STRIPED_PLACEHOLDER_SVG = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzPgogICAgPHBhdHRlcm4gaWQ9InN0cmlwZXMiIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+CiAgICAgIDxyZWN0IHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iYmxhY2siLz4KICAgICAgPHBhdGggZD0iTTggMEgxNkwwIDE2VjhMOCAwWiIgZmlsbD0iIzJEMkQyRCIvPgogICAgICA8cGF0aCBkPSJNMTYgOFYxNkg4TDE2IDhaIiBmaWxsPSIjMkQyRDJEIi8+CiAgICA8L3BhdHRlcm4+CiAgPC9kZWZzPgogIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjc3RyaXBlcykiLz4KPC9zdmc+Cg==";
472
+ const MAX_IMAGE_DIMENSION_FOR_RECOMPRESSION = 4096;
473
+ function recompressBase64Image(img, dataURL, type, quality) {
474
+ if (!img.complete || img.naturalWidth === 0) {
475
+ return dataURL;
476
+ }
477
+ if (img.naturalWidth > MAX_IMAGE_DIMENSION_FOR_RECOMPRESSION || img.naturalHeight > MAX_IMAGE_DIMENSION_FOR_RECOMPRESSION) {
478
+ return dataURL;
479
+ }
480
+ try {
481
+ const canvas = document.createElement("canvas");
482
+ canvas.width = img.naturalWidth;
483
+ canvas.height = img.naturalHeight;
484
+ const ctx = canvas.getContext("2d");
485
+ if (!ctx) {
486
+ return dataURL;
487
+ }
488
+ ctx.drawImage(img, 0, 0);
489
+ const recompressed = canvas.toDataURL(type || "image/webp", quality ?? 0.4);
490
+ return recompressed;
491
+ } catch (err) {
492
+ return dataURL;
493
+ }
494
+ }
495
+ function checkDataURLSize(dataURL, maxLength) {
496
+ if (!maxLength || dataURL.length <= maxLength) {
497
+ return dataURL;
498
+ }
499
+ return STRIPED_PLACEHOLDER_SVG;
500
+ }
471
501
  let _id = 1;
472
502
  const tagNameRegex = new RegExp("[^a-z0-9-_:]");
473
503
  const IGNORED_NODE = -2;
@@ -566,12 +596,32 @@ function getHref(doc, customHref) {
566
596
  a.setAttribute("href", customHref);
567
597
  return a.href;
568
598
  }
569
- function transformAttribute(doc, tagName, name, value) {
599
+ function transformAttribute(doc, tagName, name, value, element, dataURLOptions) {
570
600
  if (!value) {
571
601
  return value;
572
602
  }
573
603
  if (name === "src" || name === "href" && !(tagName === "use" && value[0] === "#")) {
574
- return absoluteToDoc(doc, value);
604
+ const transformedValue = absoluteToDoc(doc, value);
605
+ if (tagName === "img" && transformedValue.startsWith("data:") && element) {
606
+ const img = element;
607
+ let processedDataURL = transformedValue;
608
+ if ((dataURLOptions == null ? void 0 : dataURLOptions.type) || (dataURLOptions == null ? void 0 : dataURLOptions.quality) !== void 0) {
609
+ processedDataURL = recompressBase64Image(
610
+ img,
611
+ transformedValue,
612
+ dataURLOptions.type,
613
+ dataURLOptions.quality
614
+ );
615
+ }
616
+ if (dataURLOptions == null ? void 0 : dataURLOptions.maxBase64ImageLength) {
617
+ processedDataURL = checkDataURLSize(
618
+ processedDataURL,
619
+ dataURLOptions.maxBase64ImageLength
620
+ );
621
+ }
622
+ return processedDataURL;
623
+ }
624
+ return transformedValue;
575
625
  } else if (name === "xlink:href" && value[0] !== "#") {
576
626
  return absoluteToDoc(doc, value);
577
627
  } else if (name === "background" && (tagName === "table" || tagName === "td" || tagName === "th")) {
@@ -862,7 +912,9 @@ function serializeElementNode(n, options) {
862
912
  doc,
863
913
  tagName,
864
914
  toLowerCase(attr.name),
865
- attr.value
915
+ attr.value,
916
+ n,
917
+ dataURLOptions
866
918
  );
867
919
  }
868
920
  }
@@ -1391,15 +1443,6 @@ function visitSnapshot(node2, onVisit) {
1391
1443
  function cleanupSnapshot() {
1392
1444
  _id = 1;
1393
1445
  }
1394
- var NodeType = /* @__PURE__ */ ((NodeType2) => {
1395
- NodeType2[NodeType2["Document"] = 0] = "Document";
1396
- NodeType2[NodeType2["DocumentType"] = 1] = "DocumentType";
1397
- NodeType2[NodeType2["Element"] = 2] = "Element";
1398
- NodeType2[NodeType2["Text"] = 3] = "Text";
1399
- NodeType2[NodeType2["CDATA"] = 4] = "CDATA";
1400
- NodeType2[NodeType2["Comment"] = 5] = "Comment";
1401
- return NodeType2;
1402
- })(NodeType || {});
1403
1446
  const MEDIA_SELECTOR = /(max|min)-device-(width|height)/;
1404
1447
  const MEDIA_SELECTOR_GLOBAL = new RegExp(MEDIA_SELECTOR.source, "g");
1405
1448
  const mediaSelectorPlugin = {
@@ -5321,6 +5364,15 @@ function requireSafeParse() {
5321
5364
  }
5322
5365
  var safeParseExports = requireSafeParse();
5323
5366
  const safeParser = /* @__PURE__ */ getDefaultExportFromCjs(safeParseExports);
5367
+ var NodeType = /* @__PURE__ */ ((NodeType2) => {
5368
+ NodeType2[NodeType2["Document"] = 0] = "Document";
5369
+ NodeType2[NodeType2["DocumentType"] = 1] = "DocumentType";
5370
+ NodeType2[NodeType2["Element"] = 2] = "Element";
5371
+ NodeType2[NodeType2["Text"] = 3] = "Text";
5372
+ NodeType2[NodeType2["CDATA"] = 4] = "CDATA";
5373
+ NodeType2[NodeType2["Comment"] = 5] = "Comment";
5374
+ return NodeType2;
5375
+ })(NodeType || {});
5324
5376
  var postcssExports = requirePostcss();
5325
5377
  const postcss = /* @__PURE__ */ getDefaultExportFromCjs(postcssExports);
5326
5378
  postcss.stringify;
@@ -5347,22 +5399,6 @@ postcss.Input;
5347
5399
  postcss.Rule;
5348
5400
  postcss.Root;
5349
5401
  postcss.Node;
5350
- function adaptCssForReplay(cssText, cache) {
5351
- const cachedStyle = cache == null ? void 0 : cache.stylesWithHoverClass.get(cssText);
5352
- if (cachedStyle) return cachedStyle;
5353
- let result2 = cssText;
5354
- try {
5355
- const ast = postcss([
5356
- mediaSelectorPlugin,
5357
- pseudoClassPlugin
5358
- ]).process(cssText, { parser: safeParser });
5359
- result2 = ast.css;
5360
- } catch (error) {
5361
- console.warn("Failed to adapt css for replay", error);
5362
- }
5363
- cache == null ? void 0 : cache.stylesWithHoverClass.set(cssText, result2);
5364
- return result2;
5365
- }
5366
5402
  const tagMap = {
5367
5403
  script: "noscript",
5368
5404
  // camel case svg element tag names
@@ -5410,6 +5446,22 @@ function getTagName(n) {
5410
5446
  }
5411
5447
  return tagName;
5412
5448
  }
5449
+ function adaptCssForReplay(cssText, cache) {
5450
+ const cachedStyle = cache == null ? void 0 : cache.stylesWithHoverClass.get(cssText);
5451
+ if (cachedStyle) return cachedStyle;
5452
+ let result2 = cssText;
5453
+ try {
5454
+ const ast = postcss([
5455
+ mediaSelectorPlugin,
5456
+ pseudoClassPlugin
5457
+ ]).process(cssText, { parser: safeParser });
5458
+ result2 = ast.css;
5459
+ } catch (error) {
5460
+ console.warn("Failed to adapt css for replay", error);
5461
+ }
5462
+ cache == null ? void 0 : cache.stylesWithHoverClass.set(cssText, result2);
5463
+ return result2;
5464
+ }
5413
5465
  function createCache() {
5414
5466
  const stylesWithHoverClass = /* @__PURE__ */ new Map();
5415
5467
  return {
@@ -5734,6 +5786,7 @@ export {
5734
5786
  absolutifyURLs,
5735
5787
  adaptCssForReplay,
5736
5788
  buildNodeWithSN,
5789
+ checkDataURLSize,
5737
5790
  classMatchesRegex,
5738
5791
  cleanupSnapshot,
5739
5792
  createCache,
@@ -5754,6 +5807,7 @@ export {
5754
5807
  maskInputValue,
5755
5808
  needMaskingText,
5756
5809
  rebuild,
5810
+ recompressBase64Image,
5757
5811
  serializeNodeWithId,
5758
5812
  snapshot,
5759
5813
  stringifyRule,