@sentry/replay 7.69.0 → 7.70.0-beta.1

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/esm/index.js CHANGED
@@ -61,44 +61,159 @@ var NodeType$1;
61
61
  NodeType[NodeType["Comment"] = 5] = "Comment";
62
62
  })(NodeType$1 || (NodeType$1 = {}));
63
63
 
64
- function isElement(n) {
64
+ function isElement$1(n) {
65
65
  return n.nodeType === n.ELEMENT_NODE;
66
66
  }
67
67
  function isShadowRoot(n) {
68
68
  const host = n === null || n === void 0 ? void 0 : n.host;
69
- return Boolean(host && host.shadowRoot && host.shadowRoot === n);
69
+ return Boolean((host === null || host === void 0 ? void 0 : host.shadowRoot) === n);
70
70
  }
71
- function isInputTypeMasked({ maskInputOptions, tagName, type, }) {
72
- if (tagName.toLowerCase() === 'option') {
73
- tagName = 'select';
71
+ function isNativeShadowDom(shadowRoot) {
72
+ return Object.prototype.toString.call(shadowRoot) === '[object ShadowRoot]';
73
+ }
74
+ function fixBrowserCompatibilityIssuesInCSS(cssText) {
75
+ if (cssText.includes(' background-clip: text;') &&
76
+ !cssText.includes(' -webkit-background-clip: text;')) {
77
+ cssText = cssText.replace(' background-clip: text;', ' -webkit-background-clip: text; background-clip: text;');
74
78
  }
75
- const actualType = typeof type === 'string' ? type.toLowerCase() : undefined;
76
- return (maskInputOptions[tagName.toLowerCase()] ||
77
- (actualType && maskInputOptions[actualType]) ||
78
- actualType === 'password' ||
79
- (tagName === 'input' && !type && maskInputOptions['text']));
79
+ return cssText;
80
80
  }
81
- function hasInputMaskOptions({ tagName, type, maskInputOptions, maskInputSelector, }) {
82
- return (maskInputSelector || isInputTypeMasked({ maskInputOptions, tagName, type }));
81
+ function escapeImportStatement(rule) {
82
+ const { cssText } = rule;
83
+ if (cssText.split('"').length < 3)
84
+ return cssText;
85
+ const statement = ['@import', `url(${JSON.stringify(rule.href)})`];
86
+ if (rule.layerName === '') {
87
+ statement.push(`layer`);
88
+ }
89
+ else if (rule.layerName) {
90
+ statement.push(`layer(${rule.layerName})`);
91
+ }
92
+ if (rule.supportsText) {
93
+ statement.push(`supports(${rule.supportsText})`);
94
+ }
95
+ if (rule.media.length) {
96
+ statement.push(rule.media.mediaText);
97
+ }
98
+ return statement.join(' ') + ';';
83
99
  }
84
- function maskInputValue({ input, maskInputSelector, unmaskInputSelector, maskInputOptions, tagName, type, value, maskInputFn, }) {
85
- let text = value || '';
86
- if (unmaskInputSelector && input.matches(unmaskInputSelector)) {
87
- return text;
100
+ function stringifyStylesheet(s) {
101
+ try {
102
+ const rules = s.rules || s.cssRules;
103
+ return rules
104
+ ? fixBrowserCompatibilityIssuesInCSS(Array.from(rules, stringifyRule).join(''))
105
+ : null;
88
106
  }
89
- if (input.hasAttribute('data-rr-is-password')) {
90
- type = 'password';
107
+ catch (error) {
108
+ return null;
91
109
  }
92
- if (isInputTypeMasked({ maskInputOptions, tagName, type }) ||
93
- (maskInputSelector && input.matches(maskInputSelector))) {
94
- if (maskInputFn) {
95
- text = maskInputFn(text);
110
+ }
111
+ function stringifyRule(rule) {
112
+ let importStringified;
113
+ if (isCSSImportRule(rule)) {
114
+ try {
115
+ importStringified =
116
+ stringifyStylesheet(rule.styleSheet) ||
117
+ escapeImportStatement(rule);
96
118
  }
97
- else {
98
- text = '*'.repeat(text.length);
119
+ catch (error) {
120
+ }
121
+ }
122
+ else if (isCSSStyleRule(rule) && rule.selectorText.includes(':')) {
123
+ return fixSafariColons(rule.cssText);
124
+ }
125
+ return importStringified || rule.cssText;
126
+ }
127
+ function fixSafariColons(cssStringified) {
128
+ const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
129
+ return cssStringified.replace(regex, '$1\\$2');
130
+ }
131
+ function isCSSImportRule(rule) {
132
+ return 'styleSheet' in rule;
133
+ }
134
+ function isCSSStyleRule(rule) {
135
+ return 'selectorText' in rule;
136
+ }
137
+ class Mirror {
138
+ constructor() {
139
+ this.idNodeMap = new Map();
140
+ this.nodeMetaMap = new WeakMap();
141
+ }
142
+ getId(n) {
143
+ var _a;
144
+ if (!n)
145
+ return -1;
146
+ const id = (_a = this.getMeta(n)) === null || _a === void 0 ? void 0 : _a.id;
147
+ return id !== null && id !== void 0 ? id : -1;
148
+ }
149
+ getNode(id) {
150
+ return this.idNodeMap.get(id) || null;
151
+ }
152
+ getIds() {
153
+ return Array.from(this.idNodeMap.keys());
154
+ }
155
+ getMeta(n) {
156
+ return this.nodeMetaMap.get(n) || null;
157
+ }
158
+ removeNodeFromMap(n) {
159
+ const id = this.getId(n);
160
+ this.idNodeMap.delete(id);
161
+ if (n.childNodes) {
162
+ n.childNodes.forEach((childNode) => this.removeNodeFromMap(childNode));
163
+ }
164
+ }
165
+ has(id) {
166
+ return this.idNodeMap.has(id);
167
+ }
168
+ hasNode(node) {
169
+ return this.nodeMetaMap.has(node);
170
+ }
171
+ add(n, meta) {
172
+ const id = meta.id;
173
+ this.idNodeMap.set(id, n);
174
+ this.nodeMetaMap.set(n, meta);
175
+ }
176
+ replace(id, n) {
177
+ const oldNode = this.getNode(id);
178
+ if (oldNode) {
179
+ const meta = this.nodeMetaMap.get(oldNode);
180
+ if (meta)
181
+ this.nodeMetaMap.set(n, meta);
99
182
  }
183
+ this.idNodeMap.set(id, n);
184
+ }
185
+ reset() {
186
+ this.idNodeMap = new Map();
187
+ this.nodeMetaMap = new WeakMap();
188
+ }
189
+ }
190
+ function createMirror() {
191
+ return new Mirror();
192
+ }
193
+ function shouldMaskInput({ maskInputOptions, tagName, type, }) {
194
+ if (tagName === 'OPTION') {
195
+ tagName = 'SELECT';
196
+ }
197
+ return Boolean(maskInputOptions[tagName.toLowerCase()] ||
198
+ (type && maskInputOptions[type]) ||
199
+ type === 'password' ||
200
+ (tagName === 'INPUT' && !type && maskInputOptions['text']));
201
+ }
202
+ function maskInputValue({ isMasked, element, value, maskInputFn, }) {
203
+ let text = value || '';
204
+ if (!isMasked) {
205
+ return text;
206
+ }
207
+ if (maskInputFn) {
208
+ text = maskInputFn(text, element);
100
209
  }
101
- return text;
210
+ return '*'.repeat(text.length);
211
+ }
212
+ function toLowerCase(str) {
213
+ return str.toLowerCase();
214
+ }
215
+ function toUpperCase(str) {
216
+ return str.toUpperCase();
102
217
  }
103
218
  const ORIGINAL_ATTRIBUTE_NAME = '__rrweb_original__';
104
219
  function is2DCanvasBlank(canvas) {
@@ -124,11 +239,11 @@ function getInputType(element) {
124
239
  return element.hasAttribute('data-rr-is-password')
125
240
  ? 'password'
126
241
  : type
127
- ? type.toLowerCase()
242
+ ?
243
+ toLowerCase(type)
128
244
  : null;
129
245
  }
130
246
  function getInputValue(el, tagName, type) {
131
- typeof type === 'string' ? type.toLowerCase() : '';
132
247
  if (tagName === 'INPUT' && (type === 'radio' || type === 'checkbox')) {
133
248
  return el.getAttribute('value') || '';
134
249
  }
@@ -138,9 +253,6 @@ function getInputValue(el, tagName, type) {
138
253
  let _id = 1;
139
254
  const tagNameRegex = new RegExp('[^a-z0-9-_:]');
140
255
  const IGNORED_NODE = -2;
141
- function defaultMaskFn(str) {
142
- return str ? str.replace(/[\S]/g, '*') : '';
143
- }
144
256
  function genId() {
145
257
  return _id++;
146
258
  }
@@ -148,49 +260,12 @@ function getValidTagName(element) {
148
260
  if (element instanceof HTMLFormElement) {
149
261
  return 'form';
150
262
  }
151
- const processedTagName = element.tagName.toLowerCase().trim();
263
+ const processedTagName = toLowerCase(element.tagName);
152
264
  if (tagNameRegex.test(processedTagName)) {
153
265
  return 'div';
154
266
  }
155
267
  return processedTagName;
156
268
  }
157
- function getCssRulesString(s) {
158
- try {
159
- const rules = s.rules || s.cssRules;
160
- return rules ? Array.from(rules).map(getCssRuleString).join('') : null;
161
- }
162
- catch (error) {
163
- return null;
164
- }
165
- }
166
- function getCssRuleString(rule) {
167
- let cssStringified = rule.cssText;
168
- if (isCSSImportRule(rule)) {
169
- try {
170
- cssStringified = getCssRulesString(rule.styleSheet) || cssStringified;
171
- }
172
- catch (_a) {
173
- }
174
- }
175
- return validateStringifiedCssRule(cssStringified);
176
- }
177
- function validateStringifiedCssRule(cssStringified) {
178
- if (cssStringified.indexOf(':') > -1) {
179
- const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
180
- return cssStringified.replace(regex, '$1\\$2');
181
- }
182
- return cssStringified;
183
- }
184
- function isCSSImportRule(rule) {
185
- return 'styleSheet' in rule;
186
- }
187
- function stringifyStyleSheet(sheet) {
188
- return sheet.cssRules
189
- ? Array.from(sheet.cssRules)
190
- .map((rule) => rule.cssText ? validateStringifiedCssRule(rule.cssText) : '')
191
- .join('')
192
- : '';
193
- }
194
269
  function extractOrigin(url) {
195
270
  let origin = '';
196
271
  if (url.indexOf('//') > -1) {
@@ -205,7 +280,8 @@ function extractOrigin(url) {
205
280
  let canvasService;
206
281
  let canvasCtx;
207
282
  const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
208
- const RELATIVE_PATH = /^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/;
283
+ const URL_PROTOCOL_MATCH = /^(?:[a-z+]+:)?\/\//i;
284
+ const URL_WWW_MATCH = /^www\..*/i;
209
285
  const DATA_URI = /^(data:)([^,]*),(.*)/i;
210
286
  function absoluteToStylesheet(cssText, href) {
211
287
  return (cssText || '').replace(URL_IN_CSS_REF, (origin, quote1, path1, quote2, path2, path3) => {
@@ -214,7 +290,7 @@ function absoluteToStylesheet(cssText, href) {
214
290
  if (!filePath) {
215
291
  return origin;
216
292
  }
217
- if (!RELATIVE_PATH.test(filePath)) {
293
+ if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) {
218
294
  return `url(${maybeQuote}${filePath}${maybeQuote})`;
219
295
  }
220
296
  if (DATA_URI.test(filePath)) {
@@ -249,7 +325,7 @@ function getAbsoluteSrcsetString(doc, attributeValue) {
249
325
  let pos = 0;
250
326
  function collectCharacters(regEx) {
251
327
  let chars;
252
- let match = regEx.exec(attributeValue.substring(pos));
328
+ const match = regEx.exec(attributeValue.substring(pos));
253
329
  if (match) {
254
330
  chars = match[0];
255
331
  pos += chars.length;
@@ -257,7 +333,7 @@ function getAbsoluteSrcsetString(doc, attributeValue) {
257
333
  }
258
334
  return '';
259
335
  }
260
- let output = [];
336
+ const output = [];
261
337
  while (true) {
262
338
  collectCharacters(SRCSET_COMMAS_OR_SPACES);
263
339
  if (pos >= attributeValue.length) {
@@ -273,7 +349,7 @@ function getAbsoluteSrcsetString(doc, attributeValue) {
273
349
  url = absoluteToDoc(doc, url);
274
350
  let inParens = false;
275
351
  while (true) {
276
- let c = attributeValue.charAt(pos);
352
+ const c = attributeValue.charAt(pos);
277
353
  if (c === '') {
278
354
  output.push((url + descriptorsStr).trim());
279
355
  break;
@@ -316,13 +392,12 @@ function getHref() {
316
392
  a.href = '';
317
393
  return a.href;
318
394
  }
319
- function transformAttribute(doc, element, _tagName, _name, value, maskAllText, unmaskTextSelector, maskTextFn) {
395
+ function transformAttribute(doc, tagName, name, value, element, maskAttributeFn) {
320
396
  if (!value) {
321
397
  return value;
322
398
  }
323
- const name = _name.toLowerCase();
324
- const tagName = _tagName.toLowerCase();
325
- if (name === 'src' || name === 'href') {
399
+ if (name === 'src' ||
400
+ (name === 'href' && !(tagName === 'use' && value[0] === '#'))) {
326
401
  return absoluteToDoc(doc, value);
327
402
  }
328
403
  else if (name === 'xlink:href' && value[0] !== '#') {
@@ -341,79 +416,113 @@ function transformAttribute(doc, element, _tagName, _name, value, maskAllText, u
341
416
  else if (tagName === 'object' && name === 'data') {
342
417
  return absoluteToDoc(doc, value);
343
418
  }
344
- else if (maskAllText &&
345
- _shouldMaskAttribute(element, name, tagName, unmaskTextSelector)) {
346
- return maskTextFn ? maskTextFn(value) : defaultMaskFn(value);
419
+ if (typeof maskAttributeFn === 'function') {
420
+ return maskAttributeFn(name, value, element);
347
421
  }
348
422
  return value;
349
423
  }
350
- function _shouldMaskAttribute(element, attribute, tagName, unmaskTextSelector) {
351
- if (unmaskTextSelector && element.matches(unmaskTextSelector)) {
352
- return false;
353
- }
354
- return (['placeholder', 'title', 'aria-label'].indexOf(attribute) > -1 ||
355
- (tagName === 'input' &&
356
- attribute === 'value' &&
357
- element.hasAttribute('type') &&
358
- ['submit', 'button'].indexOf(element.getAttribute('type').toLowerCase()) > -1));
424
+ function ignoreAttribute(tagName, name, _value) {
425
+ return (tagName === 'video' || tagName === 'audio') && name === 'autoplay';
359
426
  }
360
427
  function _isBlockedElement(element, blockClass, blockSelector, unblockSelector) {
361
- if (unblockSelector && element.matches(unblockSelector)) {
362
- return false;
363
- }
364
- if (typeof blockClass === 'string') {
365
- if (element.classList.contains(blockClass)) {
366
- return true;
428
+ try {
429
+ if (unblockSelector && element.matches(unblockSelector)) {
430
+ return false;
367
431
  }
368
- }
369
- else {
370
- for (let eIndex = 0; eIndex < element.classList.length; eIndex++) {
371
- const className = element.classList[eIndex];
372
- if (blockClass.test(className)) {
432
+ if (typeof blockClass === 'string') {
433
+ if (element.classList.contains(blockClass)) {
373
434
  return true;
374
435
  }
375
436
  }
437
+ else {
438
+ for (let eIndex = element.classList.length; eIndex--;) {
439
+ const className = element.classList[eIndex];
440
+ if (blockClass.test(className)) {
441
+ return true;
442
+ }
443
+ }
444
+ }
445
+ if (blockSelector) {
446
+ return element.matches(blockSelector);
447
+ }
376
448
  }
377
- if (blockSelector) {
378
- return element.matches(blockSelector);
449
+ catch (e) {
379
450
  }
380
451
  return false;
381
452
  }
382
- function needMaskingText(node, maskTextClass, maskTextSelector, unmaskTextSelector, maskAllText) {
383
- if (!node) {
384
- return false;
385
- }
386
- if (node.nodeType !== node.ELEMENT_NODE) {
387
- return needMaskingText(node.parentNode, maskTextClass, maskTextSelector, unmaskTextSelector, maskAllText);
388
- }
389
- if (unmaskTextSelector) {
390
- if (node.matches(unmaskTextSelector) ||
391
- node.closest(unmaskTextSelector)) {
392
- return false;
393
- }
394
- }
395
- if (maskAllText) {
396
- return true;
397
- }
398
- if (typeof maskTextClass === 'string') {
399
- if (node.classList.contains(maskTextClass)) {
453
+ function elementClassMatchesRegex(el, regex) {
454
+ for (let eIndex = el.classList.length; eIndex--;) {
455
+ const className = el.classList[eIndex];
456
+ if (regex.test(className)) {
400
457
  return true;
401
458
  }
402
459
  }
403
- else {
404
- for (let eIndex = 0; eIndex < node.classList.length; eIndex++) {
405
- const className = node.classList[eIndex];
406
- if (maskTextClass.test(className)) {
460
+ return false;
461
+ }
462
+ function distanceToMatch(node, matchPredicate, limit = Infinity, distance = 0) {
463
+ if (!node)
464
+ return -1;
465
+ if (node.nodeType !== node.ELEMENT_NODE)
466
+ return -1;
467
+ if (distance > limit)
468
+ return -1;
469
+ if (matchPredicate(node))
470
+ return distance;
471
+ return distanceToMatch(node.parentNode, matchPredicate, limit, distance + 1);
472
+ }
473
+ function createMatchPredicate(className, selector) {
474
+ return (node) => {
475
+ const el = node;
476
+ if (el === null)
477
+ return false;
478
+ if (className) {
479
+ if (typeof className === 'string') {
480
+ if (el.matches(`.${className}`))
481
+ return true;
482
+ }
483
+ else if (elementClassMatchesRegex(el, className)) {
407
484
  return true;
408
485
  }
409
486
  }
410
- }
411
- if (maskTextSelector) {
412
- if (node.matches(maskTextSelector)) {
487
+ if (selector && el.matches(selector))
413
488
  return true;
489
+ return false;
490
+ };
491
+ }
492
+ function needMaskingText(node, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, maskAllText) {
493
+ try {
494
+ const el = node.nodeType === node.ELEMENT_NODE
495
+ ? node
496
+ : node.parentElement;
497
+ if (el === null)
498
+ return false;
499
+ let maskDistance = -1;
500
+ let unmaskDistance = -1;
501
+ if (maskAllText) {
502
+ unmaskDistance = distanceToMatch(el, createMatchPredicate(unmaskTextClass, unmaskTextSelector));
503
+ if (unmaskDistance < 0) {
504
+ return true;
505
+ }
506
+ maskDistance = distanceToMatch(el, createMatchPredicate(maskTextClass, maskTextSelector), unmaskDistance >= 0 ? unmaskDistance : Infinity);
414
507
  }
508
+ else {
509
+ maskDistance = distanceToMatch(el, createMatchPredicate(maskTextClass, maskTextSelector));
510
+ if (maskDistance < 0) {
511
+ return false;
512
+ }
513
+ unmaskDistance = distanceToMatch(el, createMatchPredicate(unmaskTextClass, unmaskTextSelector), maskDistance >= 0 ? maskDistance : Infinity);
514
+ }
515
+ return maskDistance >= 0
516
+ ? unmaskDistance >= 0
517
+ ? maskDistance <= unmaskDistance
518
+ : true
519
+ : unmaskDistance >= 0
520
+ ? false
521
+ : !!maskAllText;
522
+ }
523
+ catch (e) {
415
524
  }
416
- return needMaskingText(node.parentNode, maskTextClass, maskTextSelector, unmaskTextSelector, maskAllText);
525
+ return !!maskAllText;
417
526
  }
418
527
  function onceIframeLoaded(iframeEl, listener, iframeLoadTimeout) {
419
528
  const win = iframeEl.contentWindow;
@@ -447,18 +556,36 @@ function onceIframeLoaded(iframeEl, listener, iframeLoadTimeout) {
447
556
  iframeEl.src === blankUrl ||
448
557
  iframeEl.src === '') {
449
558
  setTimeout(listener, 0);
450
- return;
559
+ return iframeEl.addEventListener('load', listener);
451
560
  }
452
561
  iframeEl.addEventListener('load', listener);
453
562
  }
454
- function serializeNode(n, options) {
455
- var _a;
456
- const { doc, blockClass, blockSelector, unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, inlineStylesheet, maskInputSelector, unmaskInputSelector, maskAllText, maskInputOptions = {}, maskTextFn, maskInputFn, dataURLOptions = {}, inlineImages, recordCanvas, keepIframeSrcFn, } = options;
457
- let rootId;
458
- if (doc.__sn) {
459
- const docId = doc.__sn.id;
460
- rootId = docId === 1 ? undefined : docId;
563
+ function onceStylesheetLoaded(link, listener, styleSheetLoadTimeout) {
564
+ let fired = false;
565
+ let styleSheetLoaded;
566
+ try {
567
+ styleSheetLoaded = link.sheet;
568
+ }
569
+ catch (error) {
570
+ return;
461
571
  }
572
+ if (styleSheetLoaded)
573
+ return;
574
+ const timer = setTimeout(() => {
575
+ if (!fired) {
576
+ listener();
577
+ fired = true;
578
+ }
579
+ }, styleSheetLoadTimeout);
580
+ link.addEventListener('load', () => {
581
+ clearTimeout(timer);
582
+ fired = true;
583
+ listener();
584
+ });
585
+ }
586
+ function serializeNode(n, options) {
587
+ const { doc, mirror, blockClass, blockSelector, unblockSelector, maskAllText, maskAttributeFn, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, inlineStylesheet, maskInputOptions = {}, maskTextFn, maskInputFn, dataURLOptions = {}, inlineImages, recordCanvas, keepIframeSrcFn, newlyAddedElement = false, } = options;
588
+ const rootId = getRootId(doc, mirror);
462
589
  switch (n.nodeType) {
463
590
  case n.DOCUMENT_NODE:
464
591
  if (n.compatMode !== 'CSS1Compat') {
@@ -466,14 +593,12 @@ function serializeNode(n, options) {
466
593
  type: NodeType$1.Document,
467
594
  childNodes: [],
468
595
  compatMode: n.compatMode,
469
- rootId,
470
596
  };
471
597
  }
472
598
  else {
473
599
  return {
474
600
  type: NodeType$1.Document,
475
601
  childNodes: [],
476
- rootId,
477
602
  };
478
603
  }
479
604
  case n.DOCUMENT_TYPE_NODE:
@@ -485,202 +610,39 @@ function serializeNode(n, options) {
485
610
  rootId,
486
611
  };
487
612
  case n.ELEMENT_NODE:
488
- const needBlock = _isBlockedElement(n, blockClass, blockSelector, unblockSelector);
489
- const tagName = getValidTagName(n);
490
- let attributes = {};
491
- for (const { name, value } of Array.from(n.attributes)) {
492
- if (!skipAttribute(tagName, name)) {
493
- attributes[name] = transformAttribute(doc, n, tagName, name, value, maskAllText, unmaskTextSelector, maskTextFn);
494
- }
495
- }
496
- if (tagName === 'link' && inlineStylesheet) {
497
- const stylesheet = Array.from(doc.styleSheets).find((s) => {
498
- return s.href === n.href;
499
- });
500
- let cssText = null;
501
- if (stylesheet) {
502
- cssText = getCssRulesString(stylesheet);
503
- }
504
- if (cssText) {
505
- delete attributes.rel;
506
- delete attributes.href;
507
- attributes._cssText = absoluteToStylesheet(cssText, stylesheet.href);
508
- }
509
- }
510
- if (tagName === 'style' &&
511
- n.sheet &&
512
- !(n.innerText ||
513
- n.textContent ||
514
- '').trim().length) {
515
- const cssText = getCssRulesString(n.sheet);
516
- if (cssText) {
517
- attributes._cssText = absoluteToStylesheet(cssText, getHref());
518
- }
519
- }
520
- if (tagName === 'input' ||
521
- tagName === 'textarea' ||
522
- tagName === 'select' ||
523
- tagName === 'option') {
524
- const el = n;
525
- const type = getInputType(el);
526
- const value = getInputValue(el, tagName.toUpperCase(), type);
527
- const checked = n.checked;
528
- if (type !== 'submit' &&
529
- type !== 'button' &&
530
- value) {
531
- attributes.value = maskInputValue({
532
- input: el,
533
- type,
534
- tagName,
535
- value,
536
- maskInputSelector,
537
- unmaskInputSelector,
538
- maskInputOptions,
539
- maskInputFn,
540
- });
541
- }
542
- if (checked) {
543
- attributes.checked = checked;
544
- }
545
- }
546
- if (tagName === 'option') {
547
- if (n.selected && !maskInputOptions['select']) {
548
- attributes.selected = true;
549
- }
550
- else {
551
- delete attributes.selected;
552
- }
553
- }
554
- if (tagName === 'canvas' && recordCanvas) {
555
- if (n.__context === '2d') {
556
- if (!is2DCanvasBlank(n)) {
557
- attributes.rr_dataURL = n.toDataURL(dataURLOptions.type, dataURLOptions.quality);
558
- }
559
- }
560
- else if (!('__context' in n)) {
561
- const canvasDataURL = n.toDataURL(dataURLOptions.type, dataURLOptions.quality);
562
- const blankCanvas = document.createElement('canvas');
563
- blankCanvas.width = n.width;
564
- blankCanvas.height = n.height;
565
- const blankCanvasDataURL = blankCanvas.toDataURL(dataURLOptions.type, dataURLOptions.quality);
566
- if (canvasDataURL !== blankCanvasDataURL) {
567
- attributes.rr_dataURL = canvasDataURL;
568
- }
569
- }
570
- }
571
- if (tagName === 'img' && inlineImages) {
572
- if (!canvasService) {
573
- canvasService = doc.createElement('canvas');
574
- canvasCtx = canvasService.getContext('2d');
575
- }
576
- const image = n;
577
- const oldValue = image.crossOrigin;
578
- image.crossOrigin = 'anonymous';
579
- const recordInlineImage = () => {
580
- try {
581
- canvasService.width = image.naturalWidth;
582
- canvasService.height = image.naturalHeight;
583
- canvasCtx.drawImage(image, 0, 0);
584
- attributes.rr_dataURL = canvasService.toDataURL(dataURLOptions.type, dataURLOptions.quality);
585
- }
586
- catch (err) {
587
- console.warn(`Cannot inline img src=${image.currentSrc}! Error: ${err}`);
588
- }
589
- oldValue
590
- ? (attributes.crossOrigin = oldValue)
591
- : delete attributes.crossOrigin;
592
- };
593
- if (image.complete && image.naturalWidth !== 0)
594
- recordInlineImage();
595
- else
596
- image.onload = recordInlineImage;
597
- }
598
- if (tagName === 'audio' || tagName === 'video') {
599
- attributes.rr_mediaState = n.paused
600
- ? 'paused'
601
- : 'played';
602
- attributes.rr_mediaCurrentTime = n.currentTime;
603
- }
604
- if (n.scrollLeft) {
605
- attributes.rr_scrollLeft = n.scrollLeft;
606
- }
607
- if (n.scrollTop) {
608
- attributes.rr_scrollTop = n.scrollTop;
609
- }
610
- if (needBlock) {
611
- const { width, height } = n.getBoundingClientRect();
612
- attributes = {
613
- class: attributes.class,
614
- rr_width: `${width}px`,
615
- rr_height: `${height}px`,
616
- };
617
- }
618
- if (tagName === 'iframe' && !keepIframeSrcFn(attributes.src)) {
619
- if (!n.contentDocument) {
620
- attributes.rr_src = attributes.src;
621
- }
622
- delete attributes.src;
623
- }
624
- return {
625
- type: NodeType$1.Element,
626
- tagName,
627
- attributes,
628
- childNodes: [],
629
- isSVG: isSVGElement(n) || undefined,
630
- needBlock,
613
+ return serializeElementNode(n, {
614
+ doc,
615
+ blockClass,
616
+ blockSelector,
617
+ unblockSelector,
618
+ inlineStylesheet,
619
+ maskAttributeFn,
620
+ maskInputOptions,
621
+ maskInputFn,
622
+ dataURLOptions,
623
+ inlineImages,
624
+ recordCanvas,
625
+ keepIframeSrcFn,
626
+ newlyAddedElement,
631
627
  rootId,
632
- };
628
+ maskAllText,
629
+ maskTextClass,
630
+ unmaskTextClass,
631
+ maskTextSelector,
632
+ unmaskTextSelector,
633
+ });
633
634
  case n.TEXT_NODE:
634
- const parentTagName = n.parentNode && n.parentNode.tagName;
635
- let textContent = n.textContent;
636
- const isStyle = parentTagName === 'STYLE' ? true : undefined;
637
- const isScript = parentTagName === 'SCRIPT' ? true : undefined;
638
- if (isStyle && textContent) {
639
- try {
640
- if (n.nextSibling || n.previousSibling) {
641
- }
642
- else if ((_a = n.parentNode.sheet) === null || _a === void 0 ? void 0 : _a.cssRules) {
643
- textContent = stringifyStyleSheet(n.parentNode.sheet);
644
- }
645
- }
646
- catch (err) {
647
- console.warn(`Cannot get CSS styles from text's parentNode. Error: ${err}`, n);
648
- }
649
- textContent = absoluteToStylesheet(textContent, getHref());
650
- }
651
- if (isScript) {
652
- textContent = 'SCRIPT_PLACEHOLDER';
653
- }
654
- if (parentTagName === 'TEXTAREA' && textContent) {
655
- textContent = '';
656
- }
657
- else if (parentTagName === 'OPTION' && textContent) {
658
- const option = n.parentNode;
659
- textContent = maskInputValue({
660
- input: option,
661
- type: null,
662
- tagName: parentTagName,
663
- value: textContent,
664
- maskInputSelector,
665
- unmaskInputSelector,
666
- maskInputOptions,
667
- maskInputFn,
668
- });
669
- }
670
- else if (!isStyle &&
671
- !isScript &&
672
- needMaskingText(n, maskTextClass, maskTextSelector, unmaskTextSelector, maskAllText) &&
673
- textContent) {
674
- textContent = maskTextFn
675
- ? maskTextFn(textContent)
676
- : defaultMaskFn(textContent);
677
- }
678
- return {
679
- type: NodeType$1.Text,
680
- textContent: textContent || '',
681
- isStyle,
635
+ return serializeTextNode(n, {
636
+ maskAllText,
637
+ maskTextClass,
638
+ unmaskTextClass,
639
+ maskTextSelector,
640
+ unmaskTextSelector,
641
+ maskTextFn,
642
+ maskInputOptions,
643
+ maskInputFn,
682
644
  rootId,
683
- };
645
+ });
684
646
  case n.CDATA_SECTION_NODE:
685
647
  return {
686
648
  type: NodeType$1.CDATA,
@@ -697,6 +659,225 @@ function serializeNode(n, options) {
697
659
  return false;
698
660
  }
699
661
  }
662
+ function getRootId(doc, mirror) {
663
+ if (!mirror.hasNode(doc))
664
+ return undefined;
665
+ const docId = mirror.getId(doc);
666
+ return docId === 1 ? undefined : docId;
667
+ }
668
+ function serializeTextNode(n, options) {
669
+ var _a;
670
+ const { maskAllText, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, maskTextFn, maskInputOptions, maskInputFn, rootId, } = options;
671
+ const parentTagName = n.parentNode && n.parentNode.tagName;
672
+ let textContent = n.textContent;
673
+ const isStyle = parentTagName === 'STYLE' ? true : undefined;
674
+ const isScript = parentTagName === 'SCRIPT' ? true : undefined;
675
+ const isTextarea = parentTagName === 'TEXTAREA' ? true : undefined;
676
+ if (isStyle && textContent) {
677
+ try {
678
+ if (n.nextSibling || n.previousSibling) {
679
+ }
680
+ else if ((_a = n.parentNode.sheet) === null || _a === void 0 ? void 0 : _a.cssRules) {
681
+ textContent = stringifyStylesheet(n.parentNode.sheet);
682
+ }
683
+ }
684
+ catch (err) {
685
+ console.warn(`Cannot get CSS styles from text's parentNode. Error: ${err}`, n);
686
+ }
687
+ textContent = absoluteToStylesheet(textContent, getHref());
688
+ }
689
+ if (isScript) {
690
+ textContent = 'SCRIPT_PLACEHOLDER';
691
+ }
692
+ const forceMask = needMaskingText(n, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, maskAllText);
693
+ if (!isStyle && !isScript && !isTextarea && textContent && forceMask) {
694
+ textContent = maskTextFn
695
+ ? maskTextFn(textContent)
696
+ : textContent.replace(/[\S]/g, '*');
697
+ }
698
+ if (isTextarea && textContent && (maskInputOptions.textarea || forceMask)) {
699
+ textContent = maskInputFn
700
+ ? maskInputFn(textContent, n.parentNode)
701
+ : textContent.replace(/[\S]/g, '*');
702
+ }
703
+ if (parentTagName === 'OPTION' && textContent) {
704
+ const isInputMasked = shouldMaskInput({
705
+ type: null,
706
+ tagName: parentTagName,
707
+ maskInputOptions,
708
+ });
709
+ textContent = maskInputValue({
710
+ isMasked: needMaskingText(n, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, isInputMasked),
711
+ element: n,
712
+ value: textContent,
713
+ maskInputFn,
714
+ });
715
+ }
716
+ return {
717
+ type: NodeType$1.Text,
718
+ textContent: textContent || '',
719
+ isStyle,
720
+ rootId,
721
+ };
722
+ }
723
+ function serializeElementNode(n, options) {
724
+ const { doc, blockClass, blockSelector, unblockSelector, inlineStylesheet, maskInputOptions = {}, maskAttributeFn, maskInputFn, dataURLOptions = {}, inlineImages, recordCanvas, keepIframeSrcFn, newlyAddedElement = false, rootId, maskAllText, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, } = options;
725
+ const needBlock = _isBlockedElement(n, blockClass, blockSelector, unblockSelector);
726
+ const tagName = getValidTagName(n);
727
+ let attributes = {};
728
+ const len = n.attributes.length;
729
+ for (let i = 0; i < len; i++) {
730
+ const attr = n.attributes[i];
731
+ if (!ignoreAttribute(tagName, attr.name, attr.value)) {
732
+ attributes[attr.name] = transformAttribute(doc, tagName, toLowerCase(attr.name), attr.value, n, maskAttributeFn);
733
+ }
734
+ }
735
+ if (tagName === 'link' && inlineStylesheet) {
736
+ const stylesheet = Array.from(doc.styleSheets).find((s) => {
737
+ return s.href === n.href;
738
+ });
739
+ let cssText = null;
740
+ if (stylesheet) {
741
+ cssText = stringifyStylesheet(stylesheet);
742
+ }
743
+ if (cssText) {
744
+ delete attributes.rel;
745
+ delete attributes.href;
746
+ attributes._cssText = absoluteToStylesheet(cssText, stylesheet.href);
747
+ }
748
+ }
749
+ if (tagName === 'style' &&
750
+ n.sheet &&
751
+ !(n.innerText || n.textContent || '').trim().length) {
752
+ const cssText = stringifyStylesheet(n.sheet);
753
+ if (cssText) {
754
+ attributes._cssText = absoluteToStylesheet(cssText, getHref());
755
+ }
756
+ }
757
+ if (tagName === 'input' ||
758
+ tagName === 'textarea' ||
759
+ tagName === 'select' ||
760
+ tagName === 'option') {
761
+ const el = n;
762
+ const type = getInputType(el);
763
+ const value = getInputValue(el, toUpperCase(tagName), type);
764
+ const checked = el.checked;
765
+ if (type !== 'submit' && type !== 'button' && value) {
766
+ const forceMask = needMaskingText(el, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, shouldMaskInput({
767
+ type,
768
+ tagName: toUpperCase(tagName),
769
+ maskInputOptions,
770
+ }));
771
+ attributes.value = maskInputValue({
772
+ isMasked: forceMask,
773
+ element: el,
774
+ value,
775
+ maskInputFn,
776
+ });
777
+ }
778
+ if (checked) {
779
+ attributes.checked = checked;
780
+ }
781
+ }
782
+ if (tagName === 'option') {
783
+ if (n.selected && !maskInputOptions['select']) {
784
+ attributes.selected = true;
785
+ }
786
+ else {
787
+ delete attributes.selected;
788
+ }
789
+ }
790
+ if (tagName === 'canvas' && recordCanvas) {
791
+ if (n.__context === '2d') {
792
+ if (!is2DCanvasBlank(n)) {
793
+ attributes.rr_dataURL = n.toDataURL(dataURLOptions.type, dataURLOptions.quality);
794
+ }
795
+ }
796
+ else if (!('__context' in n)) {
797
+ const canvasDataURL = n.toDataURL(dataURLOptions.type, dataURLOptions.quality);
798
+ const blankCanvas = document.createElement('canvas');
799
+ blankCanvas.width = n.width;
800
+ blankCanvas.height = n.height;
801
+ const blankCanvasDataURL = blankCanvas.toDataURL(dataURLOptions.type, dataURLOptions.quality);
802
+ if (canvasDataURL !== blankCanvasDataURL) {
803
+ attributes.rr_dataURL = canvasDataURL;
804
+ }
805
+ }
806
+ }
807
+ if (tagName === 'img' && inlineImages) {
808
+ if (!canvasService) {
809
+ canvasService = doc.createElement('canvas');
810
+ canvasCtx = canvasService.getContext('2d');
811
+ }
812
+ const image = n;
813
+ const oldValue = image.crossOrigin;
814
+ image.crossOrigin = 'anonymous';
815
+ const recordInlineImage = () => {
816
+ image.removeEventListener('load', recordInlineImage);
817
+ try {
818
+ canvasService.width = image.naturalWidth;
819
+ canvasService.height = image.naturalHeight;
820
+ canvasCtx.drawImage(image, 0, 0);
821
+ attributes.rr_dataURL = canvasService.toDataURL(dataURLOptions.type, dataURLOptions.quality);
822
+ }
823
+ catch (err) {
824
+ console.warn(`Cannot inline img src=${image.currentSrc}! Error: ${err}`);
825
+ }
826
+ oldValue
827
+ ? (attributes.crossOrigin = oldValue)
828
+ : image.removeAttribute('crossorigin');
829
+ };
830
+ if (image.complete && image.naturalWidth !== 0)
831
+ recordInlineImage();
832
+ else
833
+ image.addEventListener('load', recordInlineImage);
834
+ }
835
+ if (tagName === 'audio' || tagName === 'video') {
836
+ attributes.rr_mediaState = n.paused
837
+ ? 'paused'
838
+ : 'played';
839
+ attributes.rr_mediaCurrentTime = n.currentTime;
840
+ }
841
+ if (!newlyAddedElement) {
842
+ if (n.scrollLeft) {
843
+ attributes.rr_scrollLeft = n.scrollLeft;
844
+ }
845
+ if (n.scrollTop) {
846
+ attributes.rr_scrollTop = n.scrollTop;
847
+ }
848
+ }
849
+ if (needBlock) {
850
+ const { width, height } = n.getBoundingClientRect();
851
+ attributes = {
852
+ class: attributes.class,
853
+ rr_width: `${width}px`,
854
+ rr_height: `${height}px`,
855
+ };
856
+ }
857
+ if (tagName === 'iframe' && !keepIframeSrcFn(attributes.src)) {
858
+ if (!n.contentDocument) {
859
+ attributes.rr_src = attributes.src;
860
+ }
861
+ delete attributes.src;
862
+ }
863
+ let isCustomElement;
864
+ try {
865
+ if (customElements.get(tagName))
866
+ isCustomElement = true;
867
+ }
868
+ catch (e) {
869
+ }
870
+ return {
871
+ type: NodeType$1.Element,
872
+ tagName,
873
+ attributes,
874
+ childNodes: [],
875
+ isSVG: isSVGElement(n) || undefined,
876
+ needBlock,
877
+ rootId,
878
+ isCustom: isCustomElement,
879
+ };
880
+ }
700
881
  function lowerIfExists(maybeAttr) {
701
882
  if (maybeAttr === undefined || maybeAttr === null) {
702
883
  return '';
@@ -778,35 +959,37 @@ function slimDOMExcluded(sn, slimDOMOptions) {
778
959
  return false;
779
960
  }
780
961
  function serializeNodeWithId(n, options) {
781
- const { doc, map, blockClass, blockSelector, unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, skipChild = false, inlineStylesheet = true, maskInputSelector, unmaskInputSelector, maskAllText, maskInputOptions = {}, maskTextFn, maskInputFn, slimDOMOptions, dataURLOptions = {}, inlineImages = false, recordCanvas = false, onSerialize, onIframeLoad, iframeLoadTimeout = 5000, keepIframeSrcFn = () => false, } = options;
962
+ const { doc, mirror, blockClass, blockSelector, unblockSelector, maskAllText, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, skipChild = false, inlineStylesheet = true, maskInputOptions = {}, maskAttributeFn, maskTextFn, maskInputFn, slimDOMOptions, dataURLOptions = {}, inlineImages = false, recordCanvas = false, onSerialize, onIframeLoad, iframeLoadTimeout = 5000, onStylesheetLoad, stylesheetLoadTimeout = 5000, keepIframeSrcFn = () => false, newlyAddedElement = false, } = options;
782
963
  let { preserveWhiteSpace = true } = options;
783
964
  const _serializedNode = serializeNode(n, {
784
965
  doc,
966
+ mirror,
785
967
  blockClass,
786
968
  blockSelector,
969
+ maskAllText,
787
970
  unblockSelector,
788
971
  maskTextClass,
972
+ unmaskTextClass,
789
973
  maskTextSelector,
790
974
  unmaskTextSelector,
791
975
  inlineStylesheet,
792
- maskInputSelector,
793
- unmaskInputSelector,
794
- maskAllText,
795
976
  maskInputOptions,
977
+ maskAttributeFn,
796
978
  maskTextFn,
797
979
  maskInputFn,
798
980
  dataURLOptions,
799
981
  inlineImages,
800
982
  recordCanvas,
801
983
  keepIframeSrcFn,
984
+ newlyAddedElement,
802
985
  });
803
986
  if (!_serializedNode) {
804
987
  console.warn(n, 'not serialized');
805
988
  return null;
806
989
  }
807
990
  let id;
808
- if ('__sn' in n) {
809
- id = n.__sn.id;
991
+ if (mirror.hasNode(n)) {
992
+ id = mirror.getId(n);
810
993
  }
811
994
  else if (slimDOMExcluded(_serializedNode, slimDOMOptions) ||
812
995
  (!preserveWhiteSpace &&
@@ -819,11 +1002,10 @@ function serializeNodeWithId(n, options) {
819
1002
  id = genId();
820
1003
  }
821
1004
  const serializedNode = Object.assign(_serializedNode, { id });
822
- n.__sn = serializedNode;
1005
+ mirror.add(n, serializedNode);
823
1006
  if (id === IGNORED_NODE) {
824
1007
  return null;
825
1008
  }
826
- map[id] = n;
827
1009
  if (onSerialize) {
828
1010
  onSerialize(n);
829
1011
  }
@@ -831,32 +1013,33 @@ function serializeNodeWithId(n, options) {
831
1013
  if (serializedNode.type === NodeType$1.Element) {
832
1014
  recordChild = recordChild && !serializedNode.needBlock;
833
1015
  delete serializedNode.needBlock;
834
- if (n.shadowRoot)
1016
+ const shadowRoot = n.shadowRoot;
1017
+ if (shadowRoot && isNativeShadowDom(shadowRoot))
835
1018
  serializedNode.isShadowHost = true;
836
1019
  }
837
1020
  if ((serializedNode.type === NodeType$1.Document ||
838
1021
  serializedNode.type === NodeType$1.Element) &&
839
1022
  recordChild) {
840
1023
  if (slimDOMOptions.headWhitespace &&
841
- _serializedNode.type === NodeType$1.Element &&
842
- _serializedNode.tagName === 'head') {
1024
+ serializedNode.type === NodeType$1.Element &&
1025
+ serializedNode.tagName === 'head') {
843
1026
  preserveWhiteSpace = false;
844
1027
  }
845
1028
  const bypassOptions = {
846
1029
  doc,
847
- map,
1030
+ mirror,
848
1031
  blockClass,
849
1032
  blockSelector,
1033
+ maskAllText,
850
1034
  unblockSelector,
851
1035
  maskTextClass,
1036
+ unmaskTextClass,
852
1037
  maskTextSelector,
853
1038
  unmaskTextSelector,
854
1039
  skipChild,
855
1040
  inlineStylesheet,
856
- maskInputSelector,
857
- unmaskInputSelector,
858
- maskAllText,
859
1041
  maskInputOptions,
1042
+ maskAttributeFn,
860
1043
  maskTextFn,
861
1044
  maskInputFn,
862
1045
  slimDOMOptions,
@@ -867,6 +1050,8 @@ function serializeNodeWithId(n, options) {
867
1050
  onSerialize,
868
1051
  onIframeLoad,
869
1052
  iframeLoadTimeout,
1053
+ onStylesheetLoad,
1054
+ stylesheetLoadTimeout,
870
1055
  keepIframeSrcFn,
871
1056
  };
872
1057
  for (const childN of Array.from(n.childNodes)) {
@@ -875,17 +1060,20 @@ function serializeNodeWithId(n, options) {
875
1060
  serializedNode.childNodes.push(serializedChildNode);
876
1061
  }
877
1062
  }
878
- if (isElement(n) && n.shadowRoot) {
1063
+ if (isElement$1(n) && n.shadowRoot) {
879
1064
  for (const childN of Array.from(n.shadowRoot.childNodes)) {
880
1065
  const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
881
1066
  if (serializedChildNode) {
882
- serializedChildNode.isShadow = true;
1067
+ isNativeShadowDom(n.shadowRoot) &&
1068
+ (serializedChildNode.isShadow = true);
883
1069
  serializedNode.childNodes.push(serializedChildNode);
884
1070
  }
885
1071
  }
886
1072
  }
887
1073
  }
888
- if (n.parentNode && isShadowRoot(n.parentNode)) {
1074
+ if (n.parentNode &&
1075
+ isShadowRoot(n.parentNode) &&
1076
+ isNativeShadowDom(n.parentNode)) {
889
1077
  serializedNode.isShadow = true;
890
1078
  }
891
1079
  if (serializedNode.type === NodeType$1.Element &&
@@ -895,19 +1083,19 @@ function serializeNodeWithId(n, options) {
895
1083
  if (iframeDoc && onIframeLoad) {
896
1084
  const serializedIframeNode = serializeNodeWithId(iframeDoc, {
897
1085
  doc: iframeDoc,
898
- map,
1086
+ mirror,
899
1087
  blockClass,
900
1088
  blockSelector,
901
1089
  unblockSelector,
1090
+ maskAllText,
902
1091
  maskTextClass,
1092
+ unmaskTextClass,
903
1093
  maskTextSelector,
904
1094
  unmaskTextSelector,
905
1095
  skipChild: false,
906
1096
  inlineStylesheet,
907
- maskInputSelector,
908
- unmaskInputSelector,
909
- maskAllText,
910
1097
  maskInputOptions,
1098
+ maskAttributeFn,
911
1099
  maskTextFn,
912
1100
  maskInputFn,
913
1101
  slimDOMOptions,
@@ -918,6 +1106,8 @@ function serializeNodeWithId(n, options) {
918
1106
  onSerialize,
919
1107
  onIframeLoad,
920
1108
  iframeLoadTimeout,
1109
+ onStylesheetLoad,
1110
+ stylesheetLoadTimeout,
921
1111
  keepIframeSrcFn,
922
1112
  });
923
1113
  if (serializedIframeNode) {
@@ -926,11 +1116,50 @@ function serializeNodeWithId(n, options) {
926
1116
  }
927
1117
  }, iframeLoadTimeout);
928
1118
  }
1119
+ if (serializedNode.type === NodeType$1.Element &&
1120
+ serializedNode.tagName === 'link' &&
1121
+ serializedNode.attributes.rel === 'stylesheet') {
1122
+ onceStylesheetLoaded(n, () => {
1123
+ if (onStylesheetLoad) {
1124
+ const serializedLinkNode = serializeNodeWithId(n, {
1125
+ doc,
1126
+ mirror,
1127
+ blockClass,
1128
+ blockSelector,
1129
+ unblockSelector,
1130
+ maskAllText,
1131
+ maskTextClass,
1132
+ unmaskTextClass,
1133
+ maskTextSelector,
1134
+ unmaskTextSelector,
1135
+ skipChild: false,
1136
+ inlineStylesheet,
1137
+ maskInputOptions,
1138
+ maskAttributeFn,
1139
+ maskTextFn,
1140
+ maskInputFn,
1141
+ slimDOMOptions,
1142
+ dataURLOptions,
1143
+ inlineImages,
1144
+ recordCanvas,
1145
+ preserveWhiteSpace,
1146
+ onSerialize,
1147
+ onIframeLoad,
1148
+ iframeLoadTimeout,
1149
+ onStylesheetLoad,
1150
+ stylesheetLoadTimeout,
1151
+ keepIframeSrcFn,
1152
+ });
1153
+ if (serializedLinkNode) {
1154
+ onStylesheetLoad(n, serializedLinkNode);
1155
+ }
1156
+ }
1157
+ }, stylesheetLoadTimeout);
1158
+ }
929
1159
  return serializedNode;
930
1160
  }
931
1161
  function snapshot(n, options) {
932
- const { blockClass = 'rr-block', blockSelector = null, unblockSelector = null, maskTextClass = 'rr-mask', maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, inlineImages = false, recordCanvas = false, maskInputSelector = null, unmaskInputSelector = null, maskAllText = false, maskAllInputs = false, maskTextFn, maskInputFn, slimDOM = false, dataURLOptions, preserveWhiteSpace, onSerialize, onIframeLoad, iframeLoadTimeout, keepIframeSrcFn = () => false, } = options || {};
933
- const idNodeMap = {};
1162
+ const { mirror = new Mirror(), blockClass = 'rr-block', blockSelector = null, unblockSelector = null, maskAllText = false, maskTextClass = 'rr-mask', unmaskTextClass = null, maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, inlineImages = false, recordCanvas = false, maskAllInputs = false, maskAttributeFn, maskTextFn, maskInputFn, slimDOM = false, dataURLOptions, preserveWhiteSpace, onSerialize, onIframeLoad, iframeLoadTimeout, onStylesheetLoad, stylesheetLoadTimeout, keepIframeSrcFn = () => false, } = options || {};
934
1163
  const maskInputOptions = maskAllInputs === true
935
1164
  ? {
936
1165
  color: true,
@@ -969,147 +1198,43 @@ function snapshot(n, options) {
969
1198
  : slimDOM === false
970
1199
  ? {}
971
1200
  : slimDOM;
972
- return [
973
- serializeNodeWithId(n, {
974
- doc: n,
975
- map: idNodeMap,
976
- blockClass,
977
- blockSelector,
978
- unblockSelector,
979
- maskTextClass,
980
- maskTextSelector,
981
- unmaskTextSelector,
982
- skipChild: false,
983
- inlineStylesheet,
984
- maskInputSelector,
985
- unmaskInputSelector,
986
- maskAllText,
987
- maskInputOptions,
988
- maskTextFn,
989
- maskInputFn,
990
- slimDOMOptions,
991
- dataURLOptions,
992
- inlineImages,
993
- recordCanvas,
994
- preserveWhiteSpace,
995
- onSerialize,
996
- onIframeLoad,
997
- iframeLoadTimeout,
998
- keepIframeSrcFn,
999
- }),
1000
- idNodeMap,
1001
- ];
1201
+ return serializeNodeWithId(n, {
1202
+ doc: n,
1203
+ mirror,
1204
+ blockClass,
1205
+ blockSelector,
1206
+ unblockSelector,
1207
+ maskAllText,
1208
+ maskTextClass,
1209
+ unmaskTextClass,
1210
+ maskTextSelector,
1211
+ unmaskTextSelector,
1212
+ skipChild: false,
1213
+ inlineStylesheet,
1214
+ maskInputOptions,
1215
+ maskAttributeFn,
1216
+ maskTextFn,
1217
+ maskInputFn,
1218
+ slimDOMOptions,
1219
+ dataURLOptions,
1220
+ inlineImages,
1221
+ recordCanvas,
1222
+ preserveWhiteSpace,
1223
+ onSerialize,
1224
+ onIframeLoad,
1225
+ iframeLoadTimeout,
1226
+ onStylesheetLoad,
1227
+ stylesheetLoadTimeout,
1228
+ keepIframeSrcFn,
1229
+ newlyAddedElement: false,
1230
+ });
1002
1231
  }
1003
- function skipAttribute(tagName, attributeName, value) {
1004
- return ((tagName === 'video' || tagName === 'audio') && attributeName === 'autoplay');
1005
- }
1006
-
1007
- var EventType;
1008
- (function (EventType) {
1009
- EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
1010
- EventType[EventType["Load"] = 1] = "Load";
1011
- EventType[EventType["FullSnapshot"] = 2] = "FullSnapshot";
1012
- EventType[EventType["IncrementalSnapshot"] = 3] = "IncrementalSnapshot";
1013
- EventType[EventType["Meta"] = 4] = "Meta";
1014
- EventType[EventType["Custom"] = 5] = "Custom";
1015
- EventType[EventType["Plugin"] = 6] = "Plugin";
1016
- })(EventType || (EventType = {}));
1017
- var IncrementalSource;
1018
- (function (IncrementalSource) {
1019
- IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
1020
- IncrementalSource[IncrementalSource["MouseMove"] = 1] = "MouseMove";
1021
- IncrementalSource[IncrementalSource["MouseInteraction"] = 2] = "MouseInteraction";
1022
- IncrementalSource[IncrementalSource["Scroll"] = 3] = "Scroll";
1023
- IncrementalSource[IncrementalSource["ViewportResize"] = 4] = "ViewportResize";
1024
- IncrementalSource[IncrementalSource["Input"] = 5] = "Input";
1025
- IncrementalSource[IncrementalSource["TouchMove"] = 6] = "TouchMove";
1026
- IncrementalSource[IncrementalSource["MediaInteraction"] = 7] = "MediaInteraction";
1027
- IncrementalSource[IncrementalSource["StyleSheetRule"] = 8] = "StyleSheetRule";
1028
- IncrementalSource[IncrementalSource["CanvasMutation"] = 9] = "CanvasMutation";
1029
- IncrementalSource[IncrementalSource["Font"] = 10] = "Font";
1030
- IncrementalSource[IncrementalSource["Log"] = 11] = "Log";
1031
- IncrementalSource[IncrementalSource["Drag"] = 12] = "Drag";
1032
- IncrementalSource[IncrementalSource["StyleDeclaration"] = 13] = "StyleDeclaration";
1033
- })(IncrementalSource || (IncrementalSource = {}));
1034
- var MouseInteractions;
1035
- (function (MouseInteractions) {
1036
- MouseInteractions[MouseInteractions["MouseUp"] = 0] = "MouseUp";
1037
- MouseInteractions[MouseInteractions["MouseDown"] = 1] = "MouseDown";
1038
- MouseInteractions[MouseInteractions["Click"] = 2] = "Click";
1039
- MouseInteractions[MouseInteractions["ContextMenu"] = 3] = "ContextMenu";
1040
- MouseInteractions[MouseInteractions["DblClick"] = 4] = "DblClick";
1041
- MouseInteractions[MouseInteractions["Focus"] = 5] = "Focus";
1042
- MouseInteractions[MouseInteractions["Blur"] = 6] = "Blur";
1043
- MouseInteractions[MouseInteractions["TouchStart"] = 7] = "TouchStart";
1044
- MouseInteractions[MouseInteractions["TouchMove_Departed"] = 8] = "TouchMove_Departed";
1045
- MouseInteractions[MouseInteractions["TouchEnd"] = 9] = "TouchEnd";
1046
- MouseInteractions[MouseInteractions["TouchCancel"] = 10] = "TouchCancel";
1047
- })(MouseInteractions || (MouseInteractions = {}));
1048
- var CanvasContext;
1049
- (function (CanvasContext) {
1050
- CanvasContext[CanvasContext["2D"] = 0] = "2D";
1051
- CanvasContext[CanvasContext["WebGL"] = 1] = "WebGL";
1052
- CanvasContext[CanvasContext["WebGL2"] = 2] = "WebGL2";
1053
- })(CanvasContext || (CanvasContext = {}));
1054
- var MediaInteractions;
1055
- (function (MediaInteractions) {
1056
- MediaInteractions[MediaInteractions["Play"] = 0] = "Play";
1057
- MediaInteractions[MediaInteractions["Pause"] = 1] = "Pause";
1058
- MediaInteractions[MediaInteractions["Seeked"] = 2] = "Seeked";
1059
- MediaInteractions[MediaInteractions["VolumeChange"] = 3] = "VolumeChange";
1060
- })(MediaInteractions || (MediaInteractions = {}));
1061
- var ReplayerEvents;
1062
- (function (ReplayerEvents) {
1063
- ReplayerEvents["Start"] = "start";
1064
- ReplayerEvents["Pause"] = "pause";
1065
- ReplayerEvents["Resume"] = "resume";
1066
- ReplayerEvents["Resize"] = "resize";
1067
- ReplayerEvents["Finish"] = "finish";
1068
- ReplayerEvents["FullsnapshotRebuilded"] = "fullsnapshot-rebuilded";
1069
- ReplayerEvents["LoadStylesheetStart"] = "load-stylesheet-start";
1070
- ReplayerEvents["LoadStylesheetEnd"] = "load-stylesheet-end";
1071
- ReplayerEvents["SkipStart"] = "skip-start";
1072
- ReplayerEvents["SkipEnd"] = "skip-end";
1073
- ReplayerEvents["MouseInteraction"] = "mouse-interaction";
1074
- ReplayerEvents["EventCast"] = "event-cast";
1075
- ReplayerEvents["CustomEvent"] = "custom-event";
1076
- ReplayerEvents["Flush"] = "flush";
1077
- ReplayerEvents["StateChange"] = "state-change";
1078
- ReplayerEvents["PlayBack"] = "play-back";
1079
- })(ReplayerEvents || (ReplayerEvents = {}));
1080
1232
 
1081
1233
  function on(type, fn, target = document) {
1082
1234
  const options = { capture: true, passive: true };
1083
1235
  target.addEventListener(type, fn, options);
1084
1236
  return () => target.removeEventListener(type, fn, options);
1085
1237
  }
1086
- function createMirror() {
1087
- return {
1088
- map: {},
1089
- getId(n) {
1090
- if (!n || !n.__sn) {
1091
- return -1;
1092
- }
1093
- return n.__sn.id;
1094
- },
1095
- getNode(id) {
1096
- return this.map[id] || null;
1097
- },
1098
- removeNodeFromMap(n) {
1099
- const id = n.__sn && n.__sn.id;
1100
- delete this.map[id];
1101
- if (n.childNodes) {
1102
- n.childNodes.forEach((child) => this.removeNodeFromMap(child));
1103
- }
1104
- },
1105
- has(id) {
1106
- return this.map.hasOwnProperty(id);
1107
- },
1108
- reset() {
1109
- this.map = {};
1110
- },
1111
- };
1112
- }
1113
1238
  const DEPARTED_MIRROR_ACCESS_WARNING = 'Please stop import mirror directly. Instead of that,' +
1114
1239
  '\r\n' +
1115
1240
  'now you can use replayer.getMirror() to access the mirror instance of a replayer,' +
@@ -1149,14 +1274,13 @@ if (typeof window !== 'undefined' && window.Proxy && window.Reflect) {
1149
1274
  function throttle$1(func, wait, options = {}) {
1150
1275
  let timeout = null;
1151
1276
  let previous = 0;
1152
- return function (arg) {
1153
- let now = Date.now();
1277
+ return function (...args) {
1278
+ const now = Date.now();
1154
1279
  if (!previous && options.leading === false) {
1155
1280
  previous = now;
1156
1281
  }
1157
- let remaining = wait - (now - previous);
1158
- let context = this;
1159
- let args = arguments;
1282
+ const remaining = wait - (now - previous);
1283
+ const context = this;
1160
1284
  if (remaining <= 0 || remaining > wait) {
1161
1285
  if (timeout) {
1162
1286
  clearTimeout(timeout);
@@ -1193,7 +1317,8 @@ function hookSetter(target, key, d, isRevoked, win = window) {
1193
1317
  function patch(source, name, replacement) {
1194
1318
  try {
1195
1319
  if (!(name in source)) {
1196
- return () => { };
1320
+ return () => {
1321
+ };
1197
1322
  }
1198
1323
  const original = source[name];
1199
1324
  const wrapped = replacement(original);
@@ -1212,9 +1337,36 @@ function patch(source, name, replacement) {
1212
1337
  };
1213
1338
  }
1214
1339
  catch (_a) {
1215
- return () => { };
1340
+ return () => {
1341
+ };
1216
1342
  }
1217
1343
  }
1344
+ let nowTimestamp = Date.now;
1345
+ if (!(/[1-9][0-9]{12}/.test(Date.now().toString()))) {
1346
+ nowTimestamp = () => new Date().getTime();
1347
+ }
1348
+ function getWindowScroll(win) {
1349
+ var _a, _b, _c, _d, _e, _f;
1350
+ const doc = win.document;
1351
+ return {
1352
+ left: doc.scrollingElement
1353
+ ? doc.scrollingElement.scrollLeft
1354
+ : win.pageXOffset !== undefined
1355
+ ? win.pageXOffset
1356
+ : (doc === null || doc === void 0 ? void 0 : doc.documentElement.scrollLeft) ||
1357
+ ((_b = (_a = doc === null || doc === void 0 ? void 0 : doc.body) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.scrollLeft) ||
1358
+ ((_c = doc === null || doc === void 0 ? void 0 : doc.body) === null || _c === void 0 ? void 0 : _c.scrollLeft) ||
1359
+ 0,
1360
+ top: doc.scrollingElement
1361
+ ? doc.scrollingElement.scrollTop
1362
+ : win.pageYOffset !== undefined
1363
+ ? win.pageYOffset
1364
+ : (doc === null || doc === void 0 ? void 0 : doc.documentElement.scrollTop) ||
1365
+ ((_e = (_d = doc === null || doc === void 0 ? void 0 : doc.body) === null || _d === void 0 ? void 0 : _d.parentElement) === null || _e === void 0 ? void 0 : _e.scrollTop) ||
1366
+ ((_f = doc === null || doc === void 0 ? void 0 : doc.body) === null || _f === void 0 ? void 0 : _f.scrollTop) ||
1367
+ 0,
1368
+ };
1369
+ }
1218
1370
  function getWindowHeight() {
1219
1371
  return (window.innerHeight ||
1220
1372
  (document.documentElement && document.documentElement.clientHeight) ||
@@ -1225,48 +1377,38 @@ function getWindowWidth() {
1225
1377
  (document.documentElement && document.documentElement.clientWidth) ||
1226
1378
  (document.body && document.body.clientWidth));
1227
1379
  }
1228
- function isBlocked(node, blockClass, blockSelector, unblockSelector) {
1380
+ function isBlocked(node, blockClass, blockSelector, unblockSelector, checkAncestors) {
1229
1381
  if (!node) {
1230
1382
  return false;
1231
1383
  }
1232
- if (node.nodeType === node.ELEMENT_NODE) {
1233
- let needBlock = false;
1234
- const needUnblock = unblockSelector && node.matches(unblockSelector);
1235
- if (typeof blockClass === 'string') {
1236
- if (node.closest !== undefined) {
1237
- needBlock =
1238
- !needUnblock &&
1239
- node.closest('.' + blockClass) !== null;
1240
- }
1241
- else {
1242
- needBlock =
1243
- !needUnblock && node.classList.contains(blockClass);
1244
- }
1245
- }
1246
- else {
1247
- !needUnblock &&
1248
- node.classList.forEach((className) => {
1249
- if (blockClass.test(className)) {
1250
- needBlock = true;
1251
- }
1252
- });
1253
- }
1254
- if (!needBlock && blockSelector) {
1255
- needBlock = node.matches(blockSelector);
1256
- }
1257
- return ((!needUnblock && needBlock) ||
1258
- isBlocked(node.parentNode, blockClass, blockSelector, unblockSelector));
1384
+ const el = node.nodeType === node.ELEMENT_NODE
1385
+ ? node
1386
+ : node.parentElement;
1387
+ if (!el)
1388
+ return false;
1389
+ const blockedPredicate = createMatchPredicate(blockClass, blockSelector);
1390
+ if (!checkAncestors) {
1391
+ const isUnblocked = unblockSelector && el.matches(unblockSelector);
1392
+ return blockedPredicate(el) && !isUnblocked;
1393
+ }
1394
+ const blockDistance = distanceToMatch(el, blockedPredicate);
1395
+ let unblockDistance = -1;
1396
+ if (blockDistance < 0) {
1397
+ return false;
1259
1398
  }
1260
- if (node.nodeType === node.TEXT_NODE) {
1261
- return isBlocked(node.parentNode, blockClass, blockSelector, unblockSelector);
1399
+ if (unblockSelector) {
1400
+ unblockDistance = distanceToMatch(el, createMatchPredicate(null, unblockSelector));
1262
1401
  }
1263
- return isBlocked(node.parentNode, blockClass, blockSelector, unblockSelector);
1264
- }
1265
- function isIgnored(n) {
1266
- if ('__sn' in n) {
1267
- return n.__sn.id === IGNORED_NODE;
1402
+ if (blockDistance > -1 && unblockDistance < 0) {
1403
+ return true;
1268
1404
  }
1269
- return false;
1405
+ return blockDistance < unblockDistance;
1406
+ }
1407
+ function isSerialized(n, mirror) {
1408
+ return mirror.getId(n) !== -1;
1409
+ }
1410
+ function isIgnored(n, mirror) {
1411
+ return mirror.getId(n) === IGNORED_NODE;
1270
1412
  }
1271
1413
  function isAncestorRemoved(target, mirror) {
1272
1414
  if (isShadowRoot(target)) {
@@ -1285,7 +1427,7 @@ function isAncestorRemoved(target, mirror) {
1285
1427
  }
1286
1428
  return isAncestorRemoved(target.parentNode, mirror);
1287
1429
  }
1288
- function isTouchEvent(event) {
1430
+ function legacy_isTouchEvent(event) {
1289
1431
  return Boolean(event.changedTouches);
1290
1432
  }
1291
1433
  function polyfill(win = window) {
@@ -1298,8 +1440,9 @@ function polyfill(win = window) {
1298
1440
  .forEach;
1299
1441
  }
1300
1442
  if (!Node.prototype.contains) {
1301
- Node.prototype.contains = function contains(node) {
1302
- if (!(0 in arguments)) {
1443
+ Node.prototype.contains = (...args) => {
1444
+ let node = args[0];
1445
+ if (!(0 in args)) {
1303
1446
  throw new TypeError('1 argument is required');
1304
1447
  }
1305
1448
  do {
@@ -1311,15 +1454,142 @@ function polyfill(win = window) {
1311
1454
  };
1312
1455
  }
1313
1456
  }
1314
- function isIframeINode(node) {
1315
- if ('__sn' in node) {
1316
- return (node.__sn.type === NodeType$1.Element && node.__sn.tagName === 'iframe');
1317
- }
1318
- return false;
1457
+ function isSerializedIframe(n, mirror) {
1458
+ return Boolean(n.nodeName === 'IFRAME' && mirror.getMeta(n));
1459
+ }
1460
+ function isSerializedStylesheet(n, mirror) {
1461
+ return Boolean(n.nodeName === 'LINK' &&
1462
+ n.nodeType === n.ELEMENT_NODE &&
1463
+ n.getAttribute &&
1464
+ n.getAttribute('rel') === 'stylesheet' &&
1465
+ mirror.getMeta(n));
1319
1466
  }
1320
1467
  function hasShadowRoot(n) {
1321
1468
  return Boolean(n === null || n === void 0 ? void 0 : n.shadowRoot);
1322
1469
  }
1470
+ class StyleSheetMirror {
1471
+ constructor() {
1472
+ this.id = 1;
1473
+ this.styleIDMap = new WeakMap();
1474
+ this.idStyleMap = new Map();
1475
+ }
1476
+ getId(stylesheet) {
1477
+ var _a;
1478
+ return (_a = this.styleIDMap.get(stylesheet)) !== null && _a !== void 0 ? _a : -1;
1479
+ }
1480
+ has(stylesheet) {
1481
+ return this.styleIDMap.has(stylesheet);
1482
+ }
1483
+ add(stylesheet, id) {
1484
+ if (this.has(stylesheet))
1485
+ return this.getId(stylesheet);
1486
+ let newId;
1487
+ if (id === undefined) {
1488
+ newId = this.id++;
1489
+ }
1490
+ else
1491
+ newId = id;
1492
+ this.styleIDMap.set(stylesheet, newId);
1493
+ this.idStyleMap.set(newId, stylesheet);
1494
+ return newId;
1495
+ }
1496
+ getStyle(id) {
1497
+ return this.idStyleMap.get(id) || null;
1498
+ }
1499
+ reset() {
1500
+ this.styleIDMap = new WeakMap();
1501
+ this.idStyleMap = new Map();
1502
+ this.id = 1;
1503
+ }
1504
+ generateId() {
1505
+ return this.id++;
1506
+ }
1507
+ }
1508
+ function getShadowHost(n) {
1509
+ var _a, _b;
1510
+ let shadowHost = null;
1511
+ if (((_b = (_a = n.getRootNode) === null || _a === void 0 ? void 0 : _a.call(n)) === null || _b === void 0 ? void 0 : _b.nodeType) === Node.DOCUMENT_FRAGMENT_NODE &&
1512
+ n.getRootNode().host)
1513
+ shadowHost = n.getRootNode().host;
1514
+ return shadowHost;
1515
+ }
1516
+ function getRootShadowHost(n) {
1517
+ let rootShadowHost = n;
1518
+ let shadowHost;
1519
+ while ((shadowHost = getShadowHost(rootShadowHost)))
1520
+ rootShadowHost = shadowHost;
1521
+ return rootShadowHost;
1522
+ }
1523
+ function shadowHostInDom(n) {
1524
+ const doc = n.ownerDocument;
1525
+ if (!doc)
1526
+ return false;
1527
+ const shadowHost = getRootShadowHost(n);
1528
+ return doc.contains(shadowHost);
1529
+ }
1530
+ function inDom(n) {
1531
+ const doc = n.ownerDocument;
1532
+ if (!doc)
1533
+ return false;
1534
+ return doc.contains(n) || shadowHostInDom(n);
1535
+ }
1536
+
1537
+ var EventType = /* @__PURE__ */ ((EventType2) => {
1538
+ EventType2[EventType2["DomContentLoaded"] = 0] = "DomContentLoaded";
1539
+ EventType2[EventType2["Load"] = 1] = "Load";
1540
+ EventType2[EventType2["FullSnapshot"] = 2] = "FullSnapshot";
1541
+ EventType2[EventType2["IncrementalSnapshot"] = 3] = "IncrementalSnapshot";
1542
+ EventType2[EventType2["Meta"] = 4] = "Meta";
1543
+ EventType2[EventType2["Custom"] = 5] = "Custom";
1544
+ EventType2[EventType2["Plugin"] = 6] = "Plugin";
1545
+ return EventType2;
1546
+ })(EventType || {});
1547
+ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {
1548
+ IncrementalSource2[IncrementalSource2["Mutation"] = 0] = "Mutation";
1549
+ IncrementalSource2[IncrementalSource2["MouseMove"] = 1] = "MouseMove";
1550
+ IncrementalSource2[IncrementalSource2["MouseInteraction"] = 2] = "MouseInteraction";
1551
+ IncrementalSource2[IncrementalSource2["Scroll"] = 3] = "Scroll";
1552
+ IncrementalSource2[IncrementalSource2["ViewportResize"] = 4] = "ViewportResize";
1553
+ IncrementalSource2[IncrementalSource2["Input"] = 5] = "Input";
1554
+ IncrementalSource2[IncrementalSource2["TouchMove"] = 6] = "TouchMove";
1555
+ IncrementalSource2[IncrementalSource2["MediaInteraction"] = 7] = "MediaInteraction";
1556
+ IncrementalSource2[IncrementalSource2["StyleSheetRule"] = 8] = "StyleSheetRule";
1557
+ IncrementalSource2[IncrementalSource2["CanvasMutation"] = 9] = "CanvasMutation";
1558
+ IncrementalSource2[IncrementalSource2["Font"] = 10] = "Font";
1559
+ IncrementalSource2[IncrementalSource2["Log"] = 11] = "Log";
1560
+ IncrementalSource2[IncrementalSource2["Drag"] = 12] = "Drag";
1561
+ IncrementalSource2[IncrementalSource2["StyleDeclaration"] = 13] = "StyleDeclaration";
1562
+ IncrementalSource2[IncrementalSource2["Selection"] = 14] = "Selection";
1563
+ IncrementalSource2[IncrementalSource2["AdoptedStyleSheet"] = 15] = "AdoptedStyleSheet";
1564
+ IncrementalSource2[IncrementalSource2["CustomElement"] = 16] = "CustomElement";
1565
+ return IncrementalSource2;
1566
+ })(IncrementalSource || {});
1567
+ var MouseInteractions = /* @__PURE__ */ ((MouseInteractions2) => {
1568
+ MouseInteractions2[MouseInteractions2["MouseUp"] = 0] = "MouseUp";
1569
+ MouseInteractions2[MouseInteractions2["MouseDown"] = 1] = "MouseDown";
1570
+ MouseInteractions2[MouseInteractions2["Click"] = 2] = "Click";
1571
+ MouseInteractions2[MouseInteractions2["ContextMenu"] = 3] = "ContextMenu";
1572
+ MouseInteractions2[MouseInteractions2["DblClick"] = 4] = "DblClick";
1573
+ MouseInteractions2[MouseInteractions2["Focus"] = 5] = "Focus";
1574
+ MouseInteractions2[MouseInteractions2["Blur"] = 6] = "Blur";
1575
+ MouseInteractions2[MouseInteractions2["TouchStart"] = 7] = "TouchStart";
1576
+ MouseInteractions2[MouseInteractions2["TouchMove_Departed"] = 8] = "TouchMove_Departed";
1577
+ MouseInteractions2[MouseInteractions2["TouchEnd"] = 9] = "TouchEnd";
1578
+ MouseInteractions2[MouseInteractions2["TouchCancel"] = 10] = "TouchCancel";
1579
+ return MouseInteractions2;
1580
+ })(MouseInteractions || {});
1581
+ var PointerTypes = /* @__PURE__ */ ((PointerTypes2) => {
1582
+ PointerTypes2[PointerTypes2["Mouse"] = 0] = "Mouse";
1583
+ PointerTypes2[PointerTypes2["Pen"] = 1] = "Pen";
1584
+ PointerTypes2[PointerTypes2["Touch"] = 2] = "Touch";
1585
+ return PointerTypes2;
1586
+ })(PointerTypes || {});
1587
+ var CanvasContext = /* @__PURE__ */ ((CanvasContext2) => {
1588
+ CanvasContext2[CanvasContext2["2D"] = 0] = "2D";
1589
+ CanvasContext2[CanvasContext2["WebGL"] = 1] = "WebGL";
1590
+ CanvasContext2[CanvasContext2["WebGL2"] = 2] = "WebGL2";
1591
+ return CanvasContext2;
1592
+ })(CanvasContext || {});
1323
1593
 
1324
1594
  function isNodeInLinkedList(n) {
1325
1595
  return '__ln' in n;
@@ -1328,6 +1598,7 @@ class DoubleLinkedList {
1328
1598
  constructor() {
1329
1599
  this.length = 0;
1330
1600
  this.head = null;
1601
+ this.tail = null;
1331
1602
  }
1332
1603
  get(position) {
1333
1604
  if (position >= this.length) {
@@ -1373,6 +1644,9 @@ class DoubleLinkedList {
1373
1644
  node.next = this.head;
1374
1645
  this.head = node;
1375
1646
  }
1647
+ if (node.next === null) {
1648
+ this.tail = node;
1649
+ }
1376
1650
  this.length++;
1377
1651
  }
1378
1652
  removeNode(n) {
@@ -1385,12 +1659,18 @@ class DoubleLinkedList {
1385
1659
  if (this.head) {
1386
1660
  this.head.previous = null;
1387
1661
  }
1662
+ else {
1663
+ this.tail = null;
1664
+ }
1388
1665
  }
1389
1666
  else {
1390
1667
  current.previous.next = current.next;
1391
1668
  if (current.next) {
1392
1669
  current.next.previous = current.previous;
1393
1670
  }
1671
+ else {
1672
+ this.tail = current.previous;
1673
+ }
1394
1674
  }
1395
1675
  if (n.__ln) {
1396
1676
  delete n.__ln;
@@ -1399,9 +1679,6 @@ class DoubleLinkedList {
1399
1679
  }
1400
1680
  }
1401
1681
  const moveKey = (id, parentId) => `${id}@${parentId}`;
1402
- function isINode(n) {
1403
- return '__sn' in n;
1404
- }
1405
1682
  class MutationBuffer {
1406
1683
  constructor() {
1407
1684
  this.frozen = false;
@@ -1423,6 +1700,7 @@ class MutationBuffer {
1423
1700
  return;
1424
1701
  }
1425
1702
  const adds = [];
1703
+ const addedIds = new Set();
1426
1704
  const addList = new DoubleLinkedList();
1427
1705
  const getNextId = (n) => {
1428
1706
  let ns = n;
@@ -1434,59 +1712,56 @@ class MutationBuffer {
1434
1712
  return nextId;
1435
1713
  };
1436
1714
  const pushAdd = (n) => {
1437
- var _a, _b, _c, _d, _e;
1438
- const shadowHost = n.getRootNode
1439
- ? (_a = n.getRootNode()) === null || _a === void 0 ? void 0 : _a.host
1440
- : null;
1441
- let rootShadowHost = shadowHost;
1442
- while ((_c = (_b = rootShadowHost === null || rootShadowHost === void 0 ? void 0 : rootShadowHost.getRootNode) === null || _b === void 0 ? void 0 : _b.call(rootShadowHost)) === null || _c === void 0 ? void 0 : _c.host)
1443
- rootShadowHost =
1444
- ((_e = (_d = rootShadowHost === null || rootShadowHost === void 0 ? void 0 : rootShadowHost.getRootNode) === null || _d === void 0 ? void 0 : _d.call(rootShadowHost)) === null || _e === void 0 ? void 0 : _e.host) ||
1445
- null;
1446
- const notInDoc = !this.doc.contains(n) &&
1447
- (!rootShadowHost || !this.doc.contains(rootShadowHost));
1448
- if (!n.parentNode || notInDoc) {
1715
+ if (!n.parentNode || !inDom(n)) {
1449
1716
  return;
1450
1717
  }
1451
1718
  const parentId = isShadowRoot(n.parentNode)
1452
- ? this.mirror.getId(shadowHost)
1719
+ ? this.mirror.getId(getShadowHost(n))
1453
1720
  : this.mirror.getId(n.parentNode);
1454
1721
  const nextId = getNextId(n);
1455
1722
  if (parentId === -1 || nextId === -1) {
1456
1723
  return addList.addNode(n);
1457
1724
  }
1458
- let sn = serializeNodeWithId(n, {
1725
+ const sn = serializeNodeWithId(n, {
1459
1726
  doc: this.doc,
1460
- map: this.mirror.map,
1727
+ mirror: this.mirror,
1461
1728
  blockClass: this.blockClass,
1462
1729
  blockSelector: this.blockSelector,
1730
+ maskAllText: this.maskAllText,
1463
1731
  unblockSelector: this.unblockSelector,
1464
1732
  maskTextClass: this.maskTextClass,
1733
+ unmaskTextClass: this.unmaskTextClass,
1465
1734
  maskTextSelector: this.maskTextSelector,
1466
1735
  unmaskTextSelector: this.unmaskTextSelector,
1467
- maskInputSelector: this.maskInputSelector,
1468
- unmaskInputSelector: this.unmaskInputSelector,
1469
1736
  skipChild: true,
1737
+ newlyAddedElement: true,
1470
1738
  inlineStylesheet: this.inlineStylesheet,
1471
- maskAllText: this.maskAllText,
1472
1739
  maskInputOptions: this.maskInputOptions,
1740
+ maskAttributeFn: this.maskAttributeFn,
1473
1741
  maskTextFn: this.maskTextFn,
1474
1742
  maskInputFn: this.maskInputFn,
1475
1743
  slimDOMOptions: this.slimDOMOptions,
1744
+ dataURLOptions: this.dataURLOptions,
1476
1745
  recordCanvas: this.recordCanvas,
1477
1746
  inlineImages: this.inlineImages,
1478
1747
  onSerialize: (currentN) => {
1479
- if (isIframeINode(currentN)) {
1748
+ if (isSerializedIframe(currentN, this.mirror)) {
1480
1749
  this.iframeManager.addIframe(currentN);
1481
1750
  }
1751
+ if (isSerializedStylesheet(currentN, this.mirror)) {
1752
+ this.stylesheetManager.trackLinkElement(currentN);
1753
+ }
1482
1754
  if (hasShadowRoot(n)) {
1483
- this.shadowDomManager.addShadowRoot(n.shadowRoot, document);
1755
+ this.shadowDomManager.addShadowRoot(n.shadowRoot, this.doc);
1484
1756
  }
1485
1757
  },
1486
1758
  onIframeLoad: (iframe, childSn) => {
1487
1759
  this.iframeManager.attachIframe(iframe, childSn);
1488
1760
  this.shadowDomManager.observeAttachShadow(iframe);
1489
1761
  },
1762
+ onStylesheetLoad: (link, childSn) => {
1763
+ this.stylesheetManager.attachLinkElement(link, childSn);
1764
+ },
1490
1765
  });
1491
1766
  if (sn) {
1492
1767
  adds.push({
@@ -1494,6 +1769,7 @@ class MutationBuffer {
1494
1769
  nextId,
1495
1770
  node: sn,
1496
1771
  });
1772
+ addedIds.add(sn.id);
1497
1773
  }
1498
1774
  };
1499
1775
  while (this.mapRemoves.length) {
@@ -1529,15 +1805,33 @@ class MutationBuffer {
1529
1805
  }
1530
1806
  }
1531
1807
  if (!node) {
1532
- for (let index = addList.length - 1; index >= 0; index--) {
1533
- const _node = addList.get(index);
1808
+ let tailNode = addList.tail;
1809
+ while (tailNode) {
1810
+ const _node = tailNode;
1811
+ tailNode = tailNode.previous;
1534
1812
  if (_node) {
1535
1813
  const parentId = this.mirror.getId(_node.value.parentNode);
1536
1814
  const nextId = getNextId(_node.value);
1537
- if (parentId !== -1 && nextId !== -1) {
1815
+ if (nextId === -1)
1816
+ continue;
1817
+ else if (parentId !== -1) {
1538
1818
  node = _node;
1539
1819
  break;
1540
1820
  }
1821
+ else {
1822
+ const unhandledNode = _node.value;
1823
+ if (unhandledNode.parentNode &&
1824
+ unhandledNode.parentNode.nodeType ===
1825
+ Node.DOCUMENT_FRAGMENT_NODE) {
1826
+ const shadowHost = unhandledNode.parentNode
1827
+ .host;
1828
+ const parentId = this.mirror.getId(shadowHost);
1829
+ if (parentId !== -1) {
1830
+ node = _node;
1831
+ break;
1832
+ }
1833
+ }
1834
+ }
1541
1835
  }
1542
1836
  }
1543
1837
  }
@@ -1557,12 +1851,27 @@ class MutationBuffer {
1557
1851
  id: this.mirror.getId(text.node),
1558
1852
  value: text.value,
1559
1853
  }))
1854
+ .filter((text) => !addedIds.has(text.id))
1560
1855
  .filter((text) => this.mirror.has(text.id)),
1561
1856
  attributes: this.attributes
1562
- .map((attribute) => ({
1563
- id: this.mirror.getId(attribute.node),
1564
- attributes: attribute.attributes,
1565
- }))
1857
+ .map((attribute) => {
1858
+ const { attributes } = attribute;
1859
+ if (typeof attributes.style === 'string') {
1860
+ const diffAsStr = JSON.stringify(attribute.styleDiff);
1861
+ const unchangedAsStr = JSON.stringify(attribute._unchangedStyles);
1862
+ if (diffAsStr.length < attributes.style.length) {
1863
+ if ((diffAsStr + unchangedAsStr).split('var(').length ===
1864
+ attributes.style.split('var(').length) {
1865
+ attributes.style = attribute.styleDiff;
1866
+ }
1867
+ }
1868
+ }
1869
+ return {
1870
+ id: this.mirror.getId(attribute.node),
1871
+ attributes: attributes,
1872
+ };
1873
+ })
1874
+ .filter((attribute) => !addedIds.has(attribute.id))
1566
1875
  .filter((attribute) => this.mirror.has(attribute.id)),
1567
1876
  removes: this.removes,
1568
1877
  adds,
@@ -1583,15 +1892,23 @@ class MutationBuffer {
1583
1892
  this.mutationCb(payload);
1584
1893
  };
1585
1894
  this.processMutation = (m) => {
1586
- if (isIgnored(m.target)) {
1895
+ if (isIgnored(m.target, this.mirror)) {
1587
1896
  return;
1588
1897
  }
1898
+ let unattachedDoc;
1899
+ try {
1900
+ unattachedDoc = document.implementation.createHTMLDocument();
1901
+ }
1902
+ catch (e) {
1903
+ unattachedDoc = this.doc;
1904
+ }
1589
1905
  switch (m.type) {
1590
1906
  case 'characterData': {
1591
1907
  const value = m.target.textContent;
1592
- if (!isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector) && value !== m.oldValue) {
1908
+ if (!isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector, false) &&
1909
+ value !== m.oldValue) {
1593
1910
  this.texts.push({
1594
- value: needMaskingText(m.target, this.maskTextClass, this.maskTextSelector, this.unmaskTextSelector, this.maskAllText) && value
1911
+ value: needMaskingText(m.target, this.maskTextClass, this.maskTextSelector, this.unmaskTextClass, this.unmaskTextSelector, this.maskAllText) && value
1595
1912
  ? this.maskTextFn
1596
1913
  ? this.maskTextFn(value)
1597
1914
  : value.replace(/[\S]/g, '*')
@@ -1603,83 +1920,99 @@ class MutationBuffer {
1603
1920
  }
1604
1921
  case 'attributes': {
1605
1922
  const target = m.target;
1606
- let value = target.getAttribute(m.attributeName);
1607
- if (m.attributeName === 'value') {
1608
- value = maskInputValue({
1609
- input: target,
1610
- maskInputSelector: this.maskInputSelector,
1611
- unmaskInputSelector: this.unmaskInputSelector,
1923
+ let attributeName = m.attributeName;
1924
+ let value = m.target.getAttribute(attributeName);
1925
+ if (attributeName === 'value') {
1926
+ const type = getInputType(target);
1927
+ const tagName = target.tagName;
1928
+ value = getInputValue(target, tagName, type);
1929
+ const isInputMasked = shouldMaskInput({
1612
1930
  maskInputOptions: this.maskInputOptions,
1613
- tagName: target.tagName,
1614
- type: target.getAttribute('type'),
1931
+ tagName,
1932
+ type,
1933
+ });
1934
+ const forceMask = needMaskingText(m.target, this.maskTextClass, this.maskTextSelector, this.unmaskTextClass, this.unmaskTextSelector, isInputMasked);
1935
+ value = maskInputValue({
1936
+ isMasked: forceMask,
1937
+ element: target,
1615
1938
  value,
1616
1939
  maskInputFn: this.maskInputFn,
1617
1940
  });
1618
1941
  }
1619
- if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector) || value === m.oldValue) {
1942
+ if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector, false) ||
1943
+ value === m.oldValue) {
1620
1944
  return;
1621
1945
  }
1622
1946
  let item = this.attributes.find((a) => a.node === m.target);
1947
+ if (target.tagName === 'IFRAME' &&
1948
+ attributeName === 'src' &&
1949
+ !this.keepIframeSrcFn(value)) {
1950
+ if (!target.contentDocument) {
1951
+ attributeName = 'rr_src';
1952
+ }
1953
+ else {
1954
+ return;
1955
+ }
1956
+ }
1623
1957
  if (!item) {
1624
1958
  item = {
1625
1959
  node: m.target,
1626
1960
  attributes: {},
1961
+ styleDiff: {},
1962
+ _unchangedStyles: {},
1627
1963
  };
1628
1964
  this.attributes.push(item);
1629
1965
  }
1630
- if (m.attributeName === 'type' &&
1966
+ if (attributeName === 'type' &&
1631
1967
  target.tagName === 'INPUT' &&
1632
1968
  (m.oldValue || '').toLowerCase() === 'password') {
1633
1969
  target.setAttribute('data-rr-is-password', 'true');
1634
1970
  }
1635
- if (m.attributeName === 'style') {
1636
- const old = this.doc.createElement('span');
1637
- if (m.oldValue) {
1638
- old.setAttribute('style', m.oldValue);
1639
- }
1640
- if (item.attributes.style === undefined ||
1641
- item.attributes.style === null) {
1642
- item.attributes.style = {};
1643
- }
1644
- try {
1645
- const styleObj = item.attributes.style;
1971
+ if (!ignoreAttribute(target.tagName, attributeName)) {
1972
+ item.attributes[attributeName] = transformAttribute(this.doc, toLowerCase(target.tagName), toLowerCase(attributeName), value, target, this.maskAttributeFn);
1973
+ if (attributeName === 'style') {
1974
+ const old = unattachedDoc.createElement('span');
1975
+ if (m.oldValue) {
1976
+ old.setAttribute('style', m.oldValue);
1977
+ }
1646
1978
  for (const pname of Array.from(target.style)) {
1647
1979
  const newValue = target.style.getPropertyValue(pname);
1648
1980
  const newPriority = target.style.getPropertyPriority(pname);
1649
1981
  if (newValue !== old.style.getPropertyValue(pname) ||
1650
1982
  newPriority !== old.style.getPropertyPriority(pname)) {
1651
1983
  if (newPriority === '') {
1652
- styleObj[pname] = newValue;
1984
+ item.styleDiff[pname] = newValue;
1653
1985
  }
1654
1986
  else {
1655
- styleObj[pname] = [newValue, newPriority];
1987
+ item.styleDiff[pname] = [newValue, newPriority];
1656
1988
  }
1657
1989
  }
1990
+ else {
1991
+ item._unchangedStyles[pname] = [newValue, newPriority];
1992
+ }
1658
1993
  }
1659
1994
  for (const pname of Array.from(old.style)) {
1660
1995
  if (target.style.getPropertyValue(pname) === '') {
1661
- styleObj[pname] = false;
1996
+ item.styleDiff[pname] = false;
1662
1997
  }
1663
1998
  }
1664
1999
  }
1665
- catch (error) {
1666
- console.warn('[rrweb] Error when parsing update to style attribute:', error);
1667
- }
1668
- }
1669
- else {
1670
- const element = m.target;
1671
- item.attributes[m.attributeName] = transformAttribute(this.doc, element, element.tagName, m.attributeName, value, this.maskAllText, this.unmaskTextSelector, this.maskTextFn);
1672
2000
  }
1673
2001
  break;
1674
2002
  }
1675
2003
  case 'childList': {
2004
+ if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector, true)) {
2005
+ return;
2006
+ }
1676
2007
  m.addedNodes.forEach((n) => this.genAdds(n, m.target));
1677
2008
  m.removedNodes.forEach((n) => {
1678
2009
  const nodeId = this.mirror.getId(n);
1679
2010
  const parentId = isShadowRoot(m.target)
1680
2011
  ? this.mirror.getId(m.target.host)
1681
2012
  : this.mirror.getId(m.target);
1682
- if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector) || isIgnored(n)) {
2013
+ if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector, false) ||
2014
+ isIgnored(n, this.mirror) ||
2015
+ !isSerialized(n, this.mirror)) {
1683
2016
  return;
1684
2017
  }
1685
2018
  if (this.addedSet.has(n)) {
@@ -1696,7 +2029,9 @@ class MutationBuffer {
1696
2029
  this.removes.push({
1697
2030
  parentId,
1698
2031
  id: nodeId,
1699
- isShadow: isShadowRoot(m.target) ? true : undefined,
2032
+ isShadow: isShadowRoot(m.target) && isNativeShadowDom(m.target)
2033
+ ? true
2034
+ : undefined,
1700
2035
  });
1701
2036
  }
1702
2037
  this.mapRemoves.push(n);
@@ -1706,28 +2041,36 @@ class MutationBuffer {
1706
2041
  }
1707
2042
  };
1708
2043
  this.genAdds = (n, target) => {
1709
- if (target && isBlocked(target, this.blockClass, this.blockSelector, this.unblockSelector)) {
2044
+ if (this.processedNodeManager.inOtherBuffer(n, this))
1710
2045
  return;
1711
- }
1712
- if (isINode(n)) {
1713
- if (isIgnored(n)) {
2046
+ if (this.addedSet.has(n) || this.movedSet.has(n))
2047
+ return;
2048
+ if (this.mirror.hasNode(n)) {
2049
+ if (isIgnored(n, this.mirror)) {
1714
2050
  return;
1715
2051
  }
1716
2052
  this.movedSet.add(n);
1717
2053
  let targetId = null;
1718
- if (target && isINode(target)) {
1719
- targetId = target.__sn.id;
2054
+ if (target && this.mirror.hasNode(target)) {
2055
+ targetId = this.mirror.getId(target);
1720
2056
  }
1721
- if (targetId) {
1722
- this.movedMap[moveKey(n.__sn.id, targetId)] = true;
2057
+ if (targetId && targetId !== -1) {
2058
+ this.movedMap[moveKey(this.mirror.getId(n), targetId)] = true;
1723
2059
  }
1724
2060
  }
1725
2061
  else {
1726
2062
  this.addedSet.add(n);
1727
2063
  this.droppedSet.delete(n);
1728
2064
  }
1729
- if (!isBlocked(n, this.blockClass, this.blockSelector, this.unblockSelector))
2065
+ if (!isBlocked(n, this.blockClass, this.blockSelector, this.unblockSelector, false)) {
1730
2066
  n.childNodes.forEach((childN) => this.genAdds(childN));
2067
+ if (hasShadowRoot(n)) {
2068
+ n.shadowRoot.childNodes.forEach((childN) => {
2069
+ this.processedNodeManager.add(childN, this);
2070
+ this.genAdds(childN, n);
2071
+ });
2072
+ }
2073
+ }
1731
2074
  };
1732
2075
  }
1733
2076
  init(options) {
@@ -1736,24 +2079,28 @@ class MutationBuffer {
1736
2079
  'blockClass',
1737
2080
  'blockSelector',
1738
2081
  'unblockSelector',
2082
+ 'maskAllText',
1739
2083
  'maskTextClass',
2084
+ 'unmaskTextClass',
1740
2085
  'maskTextSelector',
1741
2086
  'unmaskTextSelector',
1742
- 'maskInputSelector',
1743
- 'unmaskInputSelector',
1744
2087
  'inlineStylesheet',
1745
- 'maskAllText',
1746
2088
  'maskInputOptions',
2089
+ 'maskAttributeFn',
1747
2090
  'maskTextFn',
1748
2091
  'maskInputFn',
2092
+ 'keepIframeSrcFn',
1749
2093
  'recordCanvas',
1750
2094
  'inlineImages',
1751
2095
  'slimDOMOptions',
2096
+ 'dataURLOptions',
1752
2097
  'doc',
1753
2098
  'mirror',
1754
2099
  'iframeManager',
2100
+ 'stylesheetManager',
1755
2101
  'shadowDomManager',
1756
2102
  'canvasManager',
2103
+ 'processedNodeManager',
1757
2104
  ].forEach((key) => {
1758
2105
  this[key] = options[key];
1759
2106
  });
@@ -1789,6 +2136,11 @@ function deepDelete(addsSet, n) {
1789
2136
  n.childNodes.forEach((childN) => deepDelete(addsSet, childN));
1790
2137
  }
1791
2138
  function isParentRemoved(removes, n, mirror) {
2139
+ if (removes.length === 0)
2140
+ return false;
2141
+ return _isParentRemoved(removes, n, mirror);
2142
+ }
2143
+ function _isParentRemoved(removes, n, mirror) {
1792
2144
  const { parentNode } = n;
1793
2145
  if (!parentNode) {
1794
2146
  return false;
@@ -1797,9 +2149,14 @@ function isParentRemoved(removes, n, mirror) {
1797
2149
  if (removes.some((r) => r.id === parentId)) {
1798
2150
  return true;
1799
2151
  }
1800
- return isParentRemoved(removes, parentNode, mirror);
2152
+ return _isParentRemoved(removes, parentNode, mirror);
1801
2153
  }
1802
2154
  function isAncestorInSet(set, n) {
2155
+ if (set.size === 0)
2156
+ return false;
2157
+ return _isAncestorInSet(set, n);
2158
+ }
2159
+ function _isAncestorInSet(set, n) {
1803
2160
  const { parentNode } = n;
1804
2161
  if (!parentNode) {
1805
2162
  return false;
@@ -1807,23 +2164,32 @@ function isAncestorInSet(set, n) {
1807
2164
  if (set.has(parentNode)) {
1808
2165
  return true;
1809
2166
  }
1810
- return isAncestorInSet(set, parentNode);
2167
+ return _isAncestorInSet(set, parentNode);
1811
2168
  }
1812
2169
 
2170
+ let errorHandler;
2171
+ function registerErrorHandler(handler) {
2172
+ errorHandler = handler;
2173
+ }
2174
+ function unregisterErrorHandler() {
2175
+ errorHandler = undefined;
2176
+ }
1813
2177
  const callbackWrapper = (cb) => {
1814
- const rrwebWrapped = (...rest) => {
2178
+ if (!errorHandler) {
2179
+ return cb;
2180
+ }
2181
+ const rrwebWrapped = ((...rest) => {
1815
2182
  try {
1816
2183
  return cb(...rest);
1817
2184
  }
1818
2185
  catch (error) {
1819
- try {
1820
- error.__rrweb__ = true;
1821
- }
1822
- catch (_a) {
2186
+ if (errorHandler && errorHandler(error) === true) {
2187
+ return () => {
2188
+ };
1823
2189
  }
1824
2190
  throw error;
1825
2191
  }
1826
- };
2192
+ });
1827
2193
  return rrwebWrapped;
1828
2194
  };
1829
2195
 
@@ -1840,7 +2206,8 @@ function getEventTarget(event) {
1840
2206
  return event.path[0];
1841
2207
  }
1842
2208
  }
1843
- catch (_a) { }
2209
+ catch (_a) {
2210
+ }
1844
2211
  return event && event.target;
1845
2212
  }
1846
2213
  function initMutationObserver(options, rootEl) {
@@ -1859,7 +2226,7 @@ function initMutationObserver(options, rootEl) {
1859
2226
  if (options.onMutation && options.onMutation(mutations) === false) {
1860
2227
  return;
1861
2228
  }
1862
- mutationBuffer.processMutations(mutations);
2229
+ mutationBuffer.processMutations.bind(mutationBuffer)(mutations);
1863
2230
  }));
1864
2231
  observer.observe(rootEl, {
1865
2232
  attributes: true,
@@ -1873,7 +2240,8 @@ function initMutationObserver(options, rootEl) {
1873
2240
  }
1874
2241
  function initMoveObserver({ mousemoveCb, sampling, doc, mirror, }) {
1875
2242
  if (sampling.mousemove === false) {
1876
- return () => { };
2243
+ return () => {
2244
+ };
1877
2245
  }
1878
2246
  const threshold = typeof sampling.mousemove === 'number' ? sampling.mousemove : 50;
1879
2247
  const callbackThreshold = typeof sampling.mousemoveCallback === 'number'
@@ -1881,41 +2249,41 @@ function initMoveObserver({ mousemoveCb, sampling, doc, mirror, }) {
1881
2249
  : 500;
1882
2250
  let positions = [];
1883
2251
  let timeBaseline;
1884
- const wrappedCb = throttle$1((source) => {
2252
+ const wrappedCb = throttle$1(callbackWrapper((source) => {
1885
2253
  const totalOffset = Date.now() - timeBaseline;
1886
- callbackWrapper(mousemoveCb)(positions.map((p) => {
2254
+ mousemoveCb(positions.map((p) => {
1887
2255
  p.timeOffset -= totalOffset;
1888
2256
  return p;
1889
2257
  }), source);
1890
2258
  positions = [];
1891
2259
  timeBaseline = null;
1892
- }, callbackThreshold);
1893
- const updatePosition = throttle$1((evt) => {
2260
+ }), callbackThreshold);
2261
+ const updatePosition = callbackWrapper(throttle$1(callbackWrapper((evt) => {
1894
2262
  const target = getEventTarget(evt);
1895
- const { clientX, clientY } = isTouchEvent(evt)
2263
+ const { clientX, clientY } = legacy_isTouchEvent(evt)
1896
2264
  ? evt.changedTouches[0]
1897
2265
  : evt;
1898
2266
  if (!timeBaseline) {
1899
- timeBaseline = Date.now();
2267
+ timeBaseline = nowTimestamp();
1900
2268
  }
1901
2269
  positions.push({
1902
2270
  x: clientX,
1903
2271
  y: clientY,
1904
2272
  id: mirror.getId(target),
1905
- timeOffset: Date.now() - timeBaseline,
2273
+ timeOffset: nowTimestamp() - timeBaseline,
1906
2274
  });
1907
2275
  wrappedCb(typeof DragEvent !== 'undefined' && evt instanceof DragEvent
1908
2276
  ? IncrementalSource.Drag
1909
2277
  : evt instanceof MouseEvent
1910
2278
  ? IncrementalSource.MouseMove
1911
2279
  : IncrementalSource.TouchMove);
1912
- }, threshold, {
2280
+ }), threshold, {
1913
2281
  trailing: false,
1914
- });
2282
+ }));
1915
2283
  const handlers = [
1916
- on('mousemove', callbackWrapper(updatePosition), doc),
1917
- on('touchmove', callbackWrapper(updatePosition), doc),
1918
- on('drag', callbackWrapper(updatePosition), doc),
2284
+ on('mousemove', updatePosition, doc),
2285
+ on('touchmove', updatePosition, doc),
2286
+ on('drag', updatePosition, doc),
1919
2287
  ];
1920
2288
  return callbackWrapper(() => {
1921
2289
  handlers.forEach((h) => h());
@@ -1923,31 +2291,68 @@ function initMoveObserver({ mousemoveCb, sampling, doc, mirror, }) {
1923
2291
  }
1924
2292
  function initMouseInteractionObserver({ mouseInteractionCb, doc, mirror, blockClass, blockSelector, unblockSelector, sampling, }) {
1925
2293
  if (sampling.mouseInteraction === false) {
1926
- return () => { };
2294
+ return () => {
2295
+ };
1927
2296
  }
1928
2297
  const disableMap = sampling.mouseInteraction === true ||
1929
2298
  sampling.mouseInteraction === undefined
1930
2299
  ? {}
1931
2300
  : sampling.mouseInteraction;
1932
2301
  const handlers = [];
2302
+ let currentPointerType = null;
1933
2303
  const getHandler = (eventKey) => {
1934
2304
  return (event) => {
1935
2305
  const target = getEventTarget(event);
1936
- if (isBlocked(target, blockClass, blockSelector, unblockSelector)) {
2306
+ if (isBlocked(target, blockClass, blockSelector, unblockSelector, true)) {
1937
2307
  return;
1938
2308
  }
1939
- const e = isTouchEvent(event) ? event.changedTouches[0] : event;
2309
+ let pointerType = null;
2310
+ let thisEventKey = eventKey;
2311
+ if ('pointerType' in event) {
2312
+ switch (event.pointerType) {
2313
+ case 'mouse':
2314
+ pointerType = PointerTypes.Mouse;
2315
+ break;
2316
+ case 'touch':
2317
+ pointerType = PointerTypes.Touch;
2318
+ break;
2319
+ case 'pen':
2320
+ pointerType = PointerTypes.Pen;
2321
+ break;
2322
+ }
2323
+ if (pointerType === PointerTypes.Touch) {
2324
+ if (MouseInteractions[eventKey] === MouseInteractions.MouseDown) {
2325
+ thisEventKey = 'TouchStart';
2326
+ }
2327
+ else if (MouseInteractions[eventKey] === MouseInteractions.MouseUp) {
2328
+ thisEventKey = 'TouchEnd';
2329
+ }
2330
+ }
2331
+ else if (pointerType === PointerTypes.Pen) ;
2332
+ }
2333
+ else if (legacy_isTouchEvent(event)) {
2334
+ pointerType = PointerTypes.Touch;
2335
+ }
2336
+ if (pointerType !== null) {
2337
+ currentPointerType = pointerType;
2338
+ if ((thisEventKey.startsWith('Touch') &&
2339
+ pointerType === PointerTypes.Touch) ||
2340
+ (thisEventKey.startsWith('Mouse') &&
2341
+ pointerType === PointerTypes.Mouse)) {
2342
+ pointerType = null;
2343
+ }
2344
+ }
2345
+ else if (MouseInteractions[eventKey] === MouseInteractions.Click) {
2346
+ pointerType = currentPointerType;
2347
+ currentPointerType = null;
2348
+ }
2349
+ const e = legacy_isTouchEvent(event) ? event.changedTouches[0] : event;
1940
2350
  if (!e) {
1941
2351
  return;
1942
2352
  }
1943
2353
  const id = mirror.getId(target);
1944
- const { clientX, clientY } = e;
1945
- callbackWrapper(mouseInteractionCb)({
1946
- type: MouseInteractions[eventKey],
1947
- id,
1948
- x: clientX,
1949
- y: clientY,
1950
- });
2354
+ const { clientX, clientY } = e;
2355
+ callbackWrapper(mouseInteractionCb)(Object.assign({ type: MouseInteractions[thisEventKey], id, x: clientX, y: clientY }, (pointerType !== null && { pointerType })));
1951
2356
  };
1952
2357
  };
1953
2358
  Object.keys(MouseInteractions)
@@ -1955,8 +2360,19 @@ function initMouseInteractionObserver({ mouseInteractionCb, doc, mirror, blockCl
1955
2360
  !key.endsWith('_Departed') &&
1956
2361
  disableMap[key] !== false)
1957
2362
  .forEach((eventKey) => {
1958
- const eventName = eventKey.toLowerCase();
1959
- const handler = callbackWrapper(getHandler(eventKey));
2363
+ let eventName = toLowerCase(eventKey);
2364
+ const handler = getHandler(eventKey);
2365
+ if (window.PointerEvent) {
2366
+ switch (MouseInteractions[eventKey]) {
2367
+ case MouseInteractions.MouseDown:
2368
+ case MouseInteractions.MouseUp:
2369
+ eventName = eventName.replace('mouse', 'pointer');
2370
+ break;
2371
+ case MouseInteractions.TouchStart:
2372
+ case MouseInteractions.TouchEnd:
2373
+ return;
2374
+ }
2375
+ }
1960
2376
  handlers.push(on(eventName, handler, doc));
1961
2377
  });
1962
2378
  return callbackWrapper(() => {
@@ -1964,47 +2380,47 @@ function initMouseInteractionObserver({ mouseInteractionCb, doc, mirror, blockCl
1964
2380
  });
1965
2381
  }
1966
2382
  function initScrollObserver({ scrollCb, doc, mirror, blockClass, blockSelector, unblockSelector, sampling, }) {
1967
- const updatePosition = throttle$1((evt) => {
2383
+ const updatePosition = callbackWrapper(throttle$1(callbackWrapper((evt) => {
1968
2384
  const target = getEventTarget(evt);
1969
2385
  if (!target ||
1970
- isBlocked(target, blockClass, blockSelector, unblockSelector)) {
2386
+ isBlocked(target, blockClass, blockSelector, unblockSelector, true)) {
1971
2387
  return;
1972
2388
  }
1973
2389
  const id = mirror.getId(target);
1974
- if (target === doc) {
1975
- const scrollEl = (doc.scrollingElement || doc.documentElement);
1976
- callbackWrapper(scrollCb)({
2390
+ if (target === doc && doc.defaultView) {
2391
+ const scrollLeftTop = getWindowScroll(doc.defaultView);
2392
+ scrollCb({
1977
2393
  id,
1978
- x: scrollEl.scrollLeft,
1979
- y: scrollEl.scrollTop,
2394
+ x: scrollLeftTop.left,
2395
+ y: scrollLeftTop.top,
1980
2396
  });
1981
2397
  }
1982
2398
  else {
1983
- callbackWrapper(scrollCb)({
2399
+ scrollCb({
1984
2400
  id,
1985
2401
  x: target.scrollLeft,
1986
2402
  y: target.scrollTop,
1987
2403
  });
1988
2404
  }
1989
- }, sampling.scroll || 100);
1990
- return on('scroll', callbackWrapper(updatePosition), doc);
2405
+ }), sampling.scroll || 100));
2406
+ return on('scroll', updatePosition, doc);
1991
2407
  }
1992
- function initViewportResizeObserver({ viewportResizeCb, }) {
2408
+ function initViewportResizeObserver({ viewportResizeCb }, { win }) {
1993
2409
  let lastH = -1;
1994
2410
  let lastW = -1;
1995
- const updateDimension = throttle$1(() => {
2411
+ const updateDimension = callbackWrapper(throttle$1(callbackWrapper(() => {
1996
2412
  const height = getWindowHeight();
1997
2413
  const width = getWindowWidth();
1998
2414
  if (lastH !== height || lastW !== width) {
1999
- callbackWrapper(viewportResizeCb)({
2415
+ viewportResizeCb({
2000
2416
  width: Number(width),
2001
2417
  height: Number(height),
2002
2418
  });
2003
2419
  lastH = height;
2004
2420
  lastW = width;
2005
2421
  }
2006
- }, 200);
2007
- return on('resize', callbackWrapper(updateDimension), window);
2422
+ }), 200));
2423
+ return on('resize', updateDimension, win);
2008
2424
  }
2009
2425
  function wrapEventWithUserTriggeredFlag(v, enable) {
2010
2426
  const value = Object.assign({}, v);
@@ -2014,47 +2430,42 @@ function wrapEventWithUserTriggeredFlag(v, enable) {
2014
2430
  }
2015
2431
  const INPUT_TAGS = ['INPUT', 'TEXTAREA', 'SELECT'];
2016
2432
  const lastInputValueMap = new WeakMap();
2017
- function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, unblockSelector, ignoreClass, ignoreSelector, maskInputSelector, unmaskInputSelector, maskInputOptions, maskInputFn, sampling, userTriggeredOnInput, }) {
2433
+ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, unblockSelector, ignoreClass, ignoreSelector, maskInputOptions, maskInputFn, sampling, userTriggeredOnInput, maskTextClass, unmaskTextClass, maskTextSelector, unmaskTextSelector, }) {
2018
2434
  function eventHandler(event) {
2019
2435
  let target = getEventTarget(event);
2020
- const tagName = target && target.tagName;
2021
2436
  const userTriggered = event.isTrusted;
2437
+ const tagName = target && toUpperCase(target.tagName);
2022
2438
  if (tagName === 'OPTION')
2023
2439
  target = target.parentElement;
2024
2440
  if (!target ||
2025
2441
  !tagName ||
2026
2442
  INPUT_TAGS.indexOf(tagName) < 0 ||
2027
- isBlocked(target, blockClass, blockSelector, unblockSelector)) {
2443
+ isBlocked(target, blockClass, blockSelector, unblockSelector, true)) {
2028
2444
  return;
2029
2445
  }
2030
2446
  const el = target;
2031
- const type = getInputType(el);
2032
2447
  if (el.classList.contains(ignoreClass) ||
2033
2448
  (ignoreSelector && el.matches(ignoreSelector))) {
2034
2449
  return;
2035
2450
  }
2451
+ const type = getInputType(target);
2036
2452
  let text = getInputValue(el, tagName, type);
2037
2453
  let isChecked = false;
2038
- if (type === 'radio' || type === 'checkbox') {
2039
- isChecked = target.checked;
2040
- }
2041
- if (hasInputMaskOptions({
2454
+ const isInputMasked = shouldMaskInput({
2042
2455
  maskInputOptions,
2043
- maskInputSelector,
2044
2456
  tagName,
2045
2457
  type,
2046
- })) {
2047
- text = maskInputValue({
2048
- input: el,
2049
- maskInputOptions,
2050
- maskInputSelector,
2051
- unmaskInputSelector,
2052
- tagName,
2053
- type,
2054
- value: text,
2055
- maskInputFn,
2056
- });
2458
+ });
2459
+ const forceMask = needMaskingText(target, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, isInputMasked);
2460
+ if (type === 'radio' || type === 'checkbox') {
2461
+ isChecked = target.checked;
2057
2462
  }
2463
+ text = maskInputValue({
2464
+ isMasked: forceMask,
2465
+ element: target,
2466
+ value: text,
2467
+ maskInputFn,
2468
+ });
2058
2469
  cbWithDedup(target, callbackWrapper(wrapEventWithUserTriggeredFlag)({ text, isChecked, userTriggered }, userTriggeredOnInput));
2059
2470
  const name = target.name;
2060
2471
  if (type === 'radio' && name && isChecked) {
@@ -2063,12 +2474,8 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
2063
2474
  .forEach((el) => {
2064
2475
  if (el !== target) {
2065
2476
  const text = maskInputValue({
2066
- input: el,
2067
- maskInputOptions,
2068
- maskInputSelector,
2069
- unmaskInputSelector,
2070
- tagName,
2071
- type,
2477
+ isMasked: forceMask,
2478
+ element: el,
2072
2479
  value: getInputValue(el, tagName, type),
2073
2480
  maskInputFn,
2074
2481
  });
@@ -2088,26 +2495,35 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
2088
2495
  lastInputValue.isChecked !== v.isChecked) {
2089
2496
  lastInputValueMap.set(target, v);
2090
2497
  const id = mirror.getId(target);
2091
- inputCb(Object.assign(Object.assign({}, v), { id }));
2498
+ callbackWrapper(inputCb)(Object.assign(Object.assign({}, v), { id }));
2092
2499
  }
2093
2500
  }
2094
2501
  const events = sampling.input === 'last' ? ['change'] : ['input', 'change'];
2095
2502
  const handlers = events.map((eventName) => on(eventName, callbackWrapper(eventHandler), doc));
2096
- const propertyDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
2503
+ const currentWindow = doc.defaultView;
2504
+ if (!currentWindow) {
2505
+ return () => {
2506
+ handlers.forEach((h) => h());
2507
+ };
2508
+ }
2509
+ const propertyDescriptor = currentWindow.Object.getOwnPropertyDescriptor(currentWindow.HTMLInputElement.prototype, 'value');
2097
2510
  const hookProperties = [
2098
- [HTMLInputElement.prototype, 'value'],
2099
- [HTMLInputElement.prototype, 'checked'],
2100
- [HTMLSelectElement.prototype, 'value'],
2101
- [HTMLTextAreaElement.prototype, 'value'],
2102
- [HTMLSelectElement.prototype, 'selectedIndex'],
2103
- [HTMLOptionElement.prototype, 'selected'],
2511
+ [currentWindow.HTMLInputElement.prototype, 'value'],
2512
+ [currentWindow.HTMLInputElement.prototype, 'checked'],
2513
+ [currentWindow.HTMLSelectElement.prototype, 'value'],
2514
+ [currentWindow.HTMLTextAreaElement.prototype, 'value'],
2515
+ [currentWindow.HTMLSelectElement.prototype, 'selectedIndex'],
2516
+ [currentWindow.HTMLOptionElement.prototype, 'selected'],
2104
2517
  ];
2105
2518
  if (propertyDescriptor && propertyDescriptor.set) {
2106
2519
  handlers.push(...hookProperties.map((p) => hookSetter(p[0], p[1], {
2107
2520
  set() {
2108
- callbackWrapper(eventHandler)({ target: this });
2521
+ callbackWrapper(eventHandler)({
2522
+ target: this,
2523
+ isTrusted: false,
2524
+ });
2109
2525
  },
2110
- })));
2526
+ }, false, currentWindow)));
2111
2527
  }
2112
2528
  return callbackWrapper(() => {
2113
2529
  handlers.forEach((h) => h());
@@ -2128,7 +2544,7 @@ function getNestedCSSRulePositions(rule) {
2128
2544
  const index = rules.indexOf(childRule);
2129
2545
  pos.unshift(index);
2130
2546
  }
2131
- else {
2547
+ else if (childRule.parentStyleSheet) {
2132
2548
  const rules = Array.from(childRule.parentStyleSheet.cssRules);
2133
2549
  const index = rules.indexOf(childRule);
2134
2550
  pos.unshift(index);
@@ -2137,18 +2553,33 @@ function getNestedCSSRulePositions(rule) {
2137
2553
  }
2138
2554
  return recurse(rule, positions);
2139
2555
  }
2140
- function initStyleSheetObserver({ styleSheetRuleCb, mirror }, { win }) {
2556
+ function getIdAndStyleId(sheet, mirror, styleMirror) {
2557
+ let id, styleId;
2558
+ if (!sheet)
2559
+ return {};
2560
+ if (sheet.ownerNode)
2561
+ id = mirror.getId(sheet.ownerNode);
2562
+ else
2563
+ styleId = styleMirror.getId(sheet);
2564
+ return {
2565
+ styleId,
2566
+ id,
2567
+ };
2568
+ }
2569
+ function initStyleSheetObserver({ styleSheetRuleCb, mirror, stylesheetManager }, { win }) {
2141
2570
  if (!win.CSSStyleSheet || !win.CSSStyleSheet.prototype) {
2142
- return () => { };
2571
+ return () => {
2572
+ };
2143
2573
  }
2144
2574
  const insertRule = win.CSSStyleSheet.prototype.insertRule;
2145
2575
  win.CSSStyleSheet.prototype.insertRule = new Proxy(insertRule, {
2146
2576
  apply: callbackWrapper((target, thisArg, argumentsList) => {
2147
2577
  const [rule, index] = argumentsList;
2148
- const id = mirror.getId(thisArg.ownerNode);
2149
- if (id !== -1) {
2578
+ const { id, styleId } = getIdAndStyleId(thisArg, mirror, stylesheetManager.styleMirror);
2579
+ if ((id && id !== -1) || (styleId && styleId !== -1)) {
2150
2580
  styleSheetRuleCb({
2151
2581
  id,
2582
+ styleId,
2152
2583
  adds: [{ rule, index }],
2153
2584
  });
2154
2585
  }
@@ -2159,16 +2590,53 @@ function initStyleSheetObserver({ styleSheetRuleCb, mirror }, { win }) {
2159
2590
  win.CSSStyleSheet.prototype.deleteRule = new Proxy(deleteRule, {
2160
2591
  apply: callbackWrapper((target, thisArg, argumentsList) => {
2161
2592
  const [index] = argumentsList;
2162
- const id = mirror.getId(thisArg.ownerNode);
2163
- if (id !== -1) {
2593
+ const { id, styleId } = getIdAndStyleId(thisArg, mirror, stylesheetManager.styleMirror);
2594
+ if ((id && id !== -1) || (styleId && styleId !== -1)) {
2164
2595
  styleSheetRuleCb({
2165
2596
  id,
2597
+ styleId,
2166
2598
  removes: [{ index }],
2167
2599
  });
2168
2600
  }
2169
2601
  return target.apply(thisArg, argumentsList);
2170
2602
  }),
2171
2603
  });
2604
+ let replace;
2605
+ if (win.CSSStyleSheet.prototype.replace) {
2606
+ replace = win.CSSStyleSheet.prototype.replace;
2607
+ win.CSSStyleSheet.prototype.replace = new Proxy(replace, {
2608
+ apply: callbackWrapper((target, thisArg, argumentsList) => {
2609
+ const [text] = argumentsList;
2610
+ const { id, styleId } = getIdAndStyleId(thisArg, mirror, stylesheetManager.styleMirror);
2611
+ if ((id && id !== -1) || (styleId && styleId !== -1)) {
2612
+ styleSheetRuleCb({
2613
+ id,
2614
+ styleId,
2615
+ replace: text,
2616
+ });
2617
+ }
2618
+ return target.apply(thisArg, argumentsList);
2619
+ }),
2620
+ });
2621
+ }
2622
+ let replaceSync;
2623
+ if (win.CSSStyleSheet.prototype.replaceSync) {
2624
+ replaceSync = win.CSSStyleSheet.prototype.replaceSync;
2625
+ win.CSSStyleSheet.prototype.replaceSync = new Proxy(replaceSync, {
2626
+ apply: callbackWrapper((target, thisArg, argumentsList) => {
2627
+ const [text] = argumentsList;
2628
+ const { id, styleId } = getIdAndStyleId(thisArg, mirror, stylesheetManager.styleMirror);
2629
+ if ((id && id !== -1) || (styleId && styleId !== -1)) {
2630
+ styleSheetRuleCb({
2631
+ id,
2632
+ styleId,
2633
+ replaceSync: text,
2634
+ });
2635
+ }
2636
+ return target.apply(thisArg, argumentsList);
2637
+ }),
2638
+ });
2639
+ }
2172
2640
  const supportedNestedCSSRuleTypes = {};
2173
2641
  if (canMonkeyPatchNestedCSSRule('CSSGroupingRule')) {
2174
2642
  supportedNestedCSSRuleTypes.CSSGroupingRule = win.CSSGroupingRule;
@@ -2193,10 +2661,11 @@ function initStyleSheetObserver({ styleSheetRuleCb, mirror }, { win }) {
2193
2661
  type.prototype.insertRule = new Proxy(unmodifiedFunctions[typeKey].insertRule, {
2194
2662
  apply: callbackWrapper((target, thisArg, argumentsList) => {
2195
2663
  const [rule, index] = argumentsList;
2196
- const id = mirror.getId(thisArg.parentStyleSheet.ownerNode);
2197
- if (id !== -1) {
2664
+ const { id, styleId } = getIdAndStyleId(thisArg.parentStyleSheet, mirror, stylesheetManager.styleMirror);
2665
+ if ((id && id !== -1) || (styleId && styleId !== -1)) {
2198
2666
  styleSheetRuleCb({
2199
2667
  id,
2668
+ styleId,
2200
2669
  adds: [
2201
2670
  {
2202
2671
  rule,
@@ -2214,10 +2683,11 @@ function initStyleSheetObserver({ styleSheetRuleCb, mirror }, { win }) {
2214
2683
  type.prototype.deleteRule = new Proxy(unmodifiedFunctions[typeKey].deleteRule, {
2215
2684
  apply: callbackWrapper((target, thisArg, argumentsList) => {
2216
2685
  const [index] = argumentsList;
2217
- const id = mirror.getId(thisArg.parentStyleSheet.ownerNode);
2218
- if (id !== -1) {
2686
+ const { id, styleId } = getIdAndStyleId(thisArg.parentStyleSheet, mirror, stylesheetManager.styleMirror);
2687
+ if ((id && id !== -1) || (styleId && styleId !== -1)) {
2219
2688
  styleSheetRuleCb({
2220
2689
  id,
2690
+ styleId,
2221
2691
  removes: [
2222
2692
  { index: [...getNestedCSSRulePositions(thisArg), index] },
2223
2693
  ],
@@ -2230,22 +2700,74 @@ function initStyleSheetObserver({ styleSheetRuleCb, mirror }, { win }) {
2230
2700
  return callbackWrapper(() => {
2231
2701
  win.CSSStyleSheet.prototype.insertRule = insertRule;
2232
2702
  win.CSSStyleSheet.prototype.deleteRule = deleteRule;
2703
+ replace && (win.CSSStyleSheet.prototype.replace = replace);
2704
+ replaceSync && (win.CSSStyleSheet.prototype.replaceSync = replaceSync);
2233
2705
  Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => {
2234
2706
  type.prototype.insertRule = unmodifiedFunctions[typeKey].insertRule;
2235
2707
  type.prototype.deleteRule = unmodifiedFunctions[typeKey].deleteRule;
2236
2708
  });
2237
2709
  });
2238
2710
  }
2239
- function initStyleDeclarationObserver({ styleDeclarationCb, mirror }, { win }) {
2711
+ function initAdoptedStyleSheetObserver({ mirror, stylesheetManager, }, host) {
2712
+ var _a, _b, _c;
2713
+ let hostId = null;
2714
+ if (host.nodeName === '#document')
2715
+ hostId = mirror.getId(host);
2716
+ else
2717
+ hostId = mirror.getId(host.host);
2718
+ const patchTarget = host.nodeName === '#document'
2719
+ ? (_a = host.defaultView) === null || _a === void 0 ? void 0 : _a.Document
2720
+ : (_c = (_b = host.ownerDocument) === null || _b === void 0 ? void 0 : _b.defaultView) === null || _c === void 0 ? void 0 : _c.ShadowRoot;
2721
+ const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(patchTarget === null || patchTarget === void 0 ? void 0 : patchTarget.prototype, 'adoptedStyleSheets');
2722
+ if (hostId === null ||
2723
+ hostId === -1 ||
2724
+ !patchTarget ||
2725
+ !originalPropertyDescriptor)
2726
+ return () => {
2727
+ };
2728
+ Object.defineProperty(host, 'adoptedStyleSheets', {
2729
+ configurable: originalPropertyDescriptor.configurable,
2730
+ enumerable: originalPropertyDescriptor.enumerable,
2731
+ get() {
2732
+ var _a;
2733
+ return (_a = originalPropertyDescriptor.get) === null || _a === void 0 ? void 0 : _a.call(this);
2734
+ },
2735
+ set(sheets) {
2736
+ var _a;
2737
+ const result = (_a = originalPropertyDescriptor.set) === null || _a === void 0 ? void 0 : _a.call(this, sheets);
2738
+ if (hostId !== null && hostId !== -1) {
2739
+ try {
2740
+ stylesheetManager.adoptStyleSheets(sheets, hostId);
2741
+ }
2742
+ catch (e) {
2743
+ }
2744
+ }
2745
+ return result;
2746
+ },
2747
+ });
2748
+ return callbackWrapper(() => {
2749
+ Object.defineProperty(host, 'adoptedStyleSheets', {
2750
+ configurable: originalPropertyDescriptor.configurable,
2751
+ enumerable: originalPropertyDescriptor.enumerable,
2752
+ get: originalPropertyDescriptor.get,
2753
+ set: originalPropertyDescriptor.set,
2754
+ });
2755
+ });
2756
+ }
2757
+ function initStyleDeclarationObserver({ styleDeclarationCb, mirror, ignoreCSSAttributes, stylesheetManager, }, { win }) {
2240
2758
  const setProperty = win.CSSStyleDeclaration.prototype.setProperty;
2241
2759
  win.CSSStyleDeclaration.prototype.setProperty = new Proxy(setProperty, {
2242
2760
  apply: callbackWrapper((target, thisArg, argumentsList) => {
2243
- var _a, _b;
2761
+ var _a;
2244
2762
  const [property, value, priority] = argumentsList;
2245
- const id = mirror.getId((_b = (_a = thisArg.parentRule) === null || _a === void 0 ? void 0 : _a.parentStyleSheet) === null || _b === void 0 ? void 0 : _b.ownerNode);
2246
- if (id !== -1) {
2763
+ if (ignoreCSSAttributes.has(property)) {
2764
+ return setProperty.apply(thisArg, [property, value, priority]);
2765
+ }
2766
+ const { id, styleId } = getIdAndStyleId((_a = thisArg.parentRule) === null || _a === void 0 ? void 0 : _a.parentStyleSheet, mirror, stylesheetManager.styleMirror);
2767
+ if ((id && id !== -1) || (styleId && styleId !== -1)) {
2247
2768
  styleDeclarationCb({
2248
2769
  id,
2770
+ styleId,
2249
2771
  set: {
2250
2772
  property,
2251
2773
  value,
@@ -2260,12 +2782,16 @@ function initStyleDeclarationObserver({ styleDeclarationCb, mirror }, { win }) {
2260
2782
  const removeProperty = win.CSSStyleDeclaration.prototype.removeProperty;
2261
2783
  win.CSSStyleDeclaration.prototype.removeProperty = new Proxy(removeProperty, {
2262
2784
  apply: callbackWrapper((target, thisArg, argumentsList) => {
2263
- var _a, _b;
2785
+ var _a;
2264
2786
  const [property] = argumentsList;
2265
- const id = mirror.getId((_b = (_a = thisArg.parentRule) === null || _a === void 0 ? void 0 : _a.parentStyleSheet) === null || _b === void 0 ? void 0 : _b.ownerNode);
2266
- if (id !== -1) {
2787
+ if (ignoreCSSAttributes.has(property)) {
2788
+ return removeProperty.apply(thisArg, [property]);
2789
+ }
2790
+ const { id, styleId } = getIdAndStyleId((_a = thisArg.parentRule) === null || _a === void 0 ? void 0 : _a.parentStyleSheet, mirror, stylesheetManager.styleMirror);
2791
+ if ((id && id !== -1) || (styleId && styleId !== -1)) {
2267
2792
  styleDeclarationCb({
2268
2793
  id,
2794
+ styleId,
2269
2795
  remove: {
2270
2796
  property,
2271
2797
  },
@@ -2280,27 +2806,29 @@ function initStyleDeclarationObserver({ styleDeclarationCb, mirror }, { win }) {
2280
2806
  win.CSSStyleDeclaration.prototype.removeProperty = removeProperty;
2281
2807
  });
2282
2808
  }
2283
- function initMediaInteractionObserver({ mediaInteractionCb, blockClass, blockSelector, unblockSelector, mirror, sampling, }) {
2284
- const handler = (type) => throttle$1(callbackWrapper((event) => {
2809
+ function initMediaInteractionObserver({ mediaInteractionCb, blockClass, blockSelector, unblockSelector, mirror, sampling, doc, }) {
2810
+ const handler = callbackWrapper((type) => throttle$1(callbackWrapper((event) => {
2285
2811
  const target = getEventTarget(event);
2286
2812
  if (!target ||
2287
- isBlocked(target, blockClass, blockSelector, unblockSelector)) {
2813
+ isBlocked(target, blockClass, blockSelector, unblockSelector, true)) {
2288
2814
  return;
2289
2815
  }
2290
- const { currentTime, volume, muted } = target;
2816
+ const { currentTime, volume, muted, playbackRate } = target;
2291
2817
  mediaInteractionCb({
2292
2818
  type,
2293
2819
  id: mirror.getId(target),
2294
2820
  currentTime,
2295
2821
  volume,
2296
2822
  muted,
2823
+ playbackRate,
2297
2824
  });
2298
- }), sampling.media || 500);
2825
+ }), sampling.media || 500));
2299
2826
  const handlers = [
2300
- on('play', handler(0)),
2301
- on('pause', handler(1)),
2302
- on('seeked', handler(2)),
2303
- on('volumechange', handler(3)),
2827
+ on('play', handler(0), doc),
2828
+ on('pause', handler(1), doc),
2829
+ on('seeked', handler(2), doc),
2830
+ on('volumechange', handler(3), doc),
2831
+ on('ratechange', handler(4), doc),
2304
2832
  ];
2305
2833
  return callbackWrapper(() => {
2306
2834
  handlers.forEach((h) => h());
@@ -2309,7 +2837,8 @@ function initMediaInteractionObserver({ mediaInteractionCb, blockClass, blockSel
2309
2837
  function initFontObserver({ fontCb, doc }) {
2310
2838
  const win = doc.defaultView;
2311
2839
  if (!win) {
2312
- return () => { };
2840
+ return () => {
2841
+ };
2313
2842
  }
2314
2843
  const handlers = [];
2315
2844
  const fontMap = new WeakMap();
@@ -2322,20 +2851,19 @@ function initFontObserver({ fontCb, doc }) {
2322
2851
  descriptors,
2323
2852
  fontSource: typeof source === 'string'
2324
2853
  ? source
2325
- :
2326
- JSON.stringify(Array.from(new Uint8Array(source))),
2854
+ : JSON.stringify(Array.from(new Uint8Array(source))),
2327
2855
  });
2328
2856
  return fontFace;
2329
2857
  };
2330
2858
  const restoreHandler = patch(doc.fonts, 'add', function (original) {
2331
2859
  return function (fontFace) {
2332
- setTimeout(() => {
2860
+ setTimeout(callbackWrapper(() => {
2333
2861
  const p = fontMap.get(fontFace);
2334
2862
  if (p) {
2335
2863
  fontCb(p);
2336
2864
  fontMap.delete(fontFace);
2337
2865
  }
2338
- }, 0);
2866
+ }), 0);
2339
2867
  return original.apply(this, [fontFace]);
2340
2868
  };
2341
2869
  });
@@ -2347,8 +2875,59 @@ function initFontObserver({ fontCb, doc }) {
2347
2875
  handlers.forEach((h) => h());
2348
2876
  });
2349
2877
  }
2878
+ function initSelectionObserver(param) {
2879
+ const { doc, mirror, blockClass, blockSelector, unblockSelector, selectionCb, } = param;
2880
+ let collapsed = true;
2881
+ const updateSelection = callbackWrapper(() => {
2882
+ const selection = doc.getSelection();
2883
+ if (!selection || (collapsed && (selection === null || selection === void 0 ? void 0 : selection.isCollapsed)))
2884
+ return;
2885
+ collapsed = selection.isCollapsed || false;
2886
+ const ranges = [];
2887
+ const count = selection.rangeCount || 0;
2888
+ for (let i = 0; i < count; i++) {
2889
+ const range = selection.getRangeAt(i);
2890
+ const { startContainer, startOffset, endContainer, endOffset } = range;
2891
+ const blocked = isBlocked(startContainer, blockClass, blockSelector, unblockSelector, true) ||
2892
+ isBlocked(endContainer, blockClass, blockSelector, unblockSelector, true);
2893
+ if (blocked)
2894
+ continue;
2895
+ ranges.push({
2896
+ start: mirror.getId(startContainer),
2897
+ startOffset,
2898
+ end: mirror.getId(endContainer),
2899
+ endOffset,
2900
+ });
2901
+ }
2902
+ selectionCb({ ranges });
2903
+ });
2904
+ updateSelection();
2905
+ return on('selectionchange', updateSelection);
2906
+ }
2907
+ function initCustomElementObserver({ doc, customElementCb, }) {
2908
+ const win = doc.defaultView;
2909
+ if (!win || !win.customElements) {
2910
+ return () => {
2911
+ };
2912
+ }
2913
+ const restoreHandler = patch(win.customElements, 'define', function (original) {
2914
+ return function (name, constructor, options) {
2915
+ try {
2916
+ customElementCb({
2917
+ define: {
2918
+ name,
2919
+ },
2920
+ });
2921
+ }
2922
+ catch (e) {
2923
+ }
2924
+ return original.apply(this, [name, constructor, options]);
2925
+ };
2926
+ });
2927
+ return restoreHandler;
2928
+ }
2350
2929
  function mergeHooks(o, hooks) {
2351
- const { mutationCb, mousemoveCb, mouseInteractionCb, scrollCb, viewportResizeCb, inputCb, mediaInteractionCb, styleSheetRuleCb, styleDeclarationCb, canvasMutationCb, fontCb, } = o;
2930
+ const { mutationCb, mousemoveCb, mouseInteractionCb, scrollCb, viewportResizeCb, inputCb, mediaInteractionCb, styleSheetRuleCb, styleDeclarationCb, canvasMutationCb, fontCb, selectionCb, customElementCb, } = o;
2352
2931
  o.mutationCb = (...p) => {
2353
2932
  if (hooks.mutation) {
2354
2933
  hooks.mutation(...p);
@@ -2415,25 +2994,46 @@ function mergeHooks(o, hooks) {
2415
2994
  }
2416
2995
  fontCb(...p);
2417
2996
  };
2997
+ o.selectionCb = (...p) => {
2998
+ if (hooks.selection) {
2999
+ hooks.selection(...p);
3000
+ }
3001
+ selectionCb(...p);
3002
+ };
3003
+ o.customElementCb = (...c) => {
3004
+ if (hooks.customElement) {
3005
+ hooks.customElement(...c);
3006
+ }
3007
+ customElementCb(...c);
3008
+ };
2418
3009
  }
2419
3010
  function initObservers(o, hooks = {}) {
2420
3011
  const currentWindow = o.doc.defaultView;
2421
3012
  if (!currentWindow) {
2422
- return () => { };
3013
+ return () => {
3014
+ };
2423
3015
  }
2424
3016
  mergeHooks(o, hooks);
2425
3017
  const mutationObserver = initMutationObserver(o, o.doc);
2426
3018
  const mousemoveHandler = initMoveObserver(o);
2427
3019
  const mouseInteractionHandler = initMouseInteractionObserver(o);
2428
3020
  const scrollHandler = initScrollObserver(o);
2429
- const viewportResizeHandler = initViewportResizeObserver(o);
3021
+ const viewportResizeHandler = initViewportResizeObserver(o, {
3022
+ win: currentWindow,
3023
+ });
2430
3024
  const inputHandler = initInputObserver(o);
2431
3025
  const mediaInteractionHandler = initMediaInteractionObserver(o);
2432
3026
  const styleSheetObserver = initStyleSheetObserver(o, { win: currentWindow });
3027
+ const adoptedStyleSheetObserver = initAdoptedStyleSheetObserver(o, o.doc);
2433
3028
  const styleDeclarationObserver = initStyleDeclarationObserver(o, {
2434
3029
  win: currentWindow,
2435
3030
  });
2436
- const fontObserver = o.collectFonts ? initFontObserver(o) : () => { };
3031
+ const fontObserver = o.collectFonts
3032
+ ? initFontObserver(o)
3033
+ : () => {
3034
+ };
3035
+ const selectionObserver = initSelectionObserver(o);
3036
+ const customElementObserver = initCustomElementObserver(o);
2437
3037
  const pluginHandlers = [];
2438
3038
  for (const plugin of o.plugins) {
2439
3039
  pluginHandlers.push(plugin.observer(plugin.callback, currentWindow, plugin.options));
@@ -2447,13 +3047,12 @@ function initObservers(o, hooks = {}) {
2447
3047
  viewportResizeHandler();
2448
3048
  inputHandler();
2449
3049
  mediaInteractionHandler();
2450
- try {
2451
- styleSheetObserver();
2452
- styleDeclarationObserver();
2453
- }
2454
- catch (e) {
2455
- }
3050
+ styleSheetObserver();
3051
+ adoptedStyleSheetObserver();
3052
+ styleDeclarationObserver();
2456
3053
  fontObserver();
3054
+ selectionObserver();
3055
+ customElementObserver();
2457
3056
  pluginHandlers.forEach((h) => h());
2458
3057
  });
2459
3058
  }
@@ -2467,13 +3066,88 @@ function canMonkeyPatchNestedCSSRule(prop) {
2467
3066
  'deleteRule' in window[prop].prototype);
2468
3067
  }
2469
3068
 
3069
+ class CrossOriginIframeMirror {
3070
+ constructor(generateIdFn) {
3071
+ this.generateIdFn = generateIdFn;
3072
+ this.iframeIdToRemoteIdMap = new WeakMap();
3073
+ this.iframeRemoteIdToIdMap = new WeakMap();
3074
+ }
3075
+ getId(iframe, remoteId, idToRemoteMap, remoteToIdMap) {
3076
+ const idToRemoteIdMap = idToRemoteMap || this.getIdToRemoteIdMap(iframe);
3077
+ const remoteIdToIdMap = remoteToIdMap || this.getRemoteIdToIdMap(iframe);
3078
+ let id = idToRemoteIdMap.get(remoteId);
3079
+ if (!id) {
3080
+ id = this.generateIdFn();
3081
+ idToRemoteIdMap.set(remoteId, id);
3082
+ remoteIdToIdMap.set(id, remoteId);
3083
+ }
3084
+ return id;
3085
+ }
3086
+ getIds(iframe, remoteId) {
3087
+ const idToRemoteIdMap = this.getIdToRemoteIdMap(iframe);
3088
+ const remoteIdToIdMap = this.getRemoteIdToIdMap(iframe);
3089
+ return remoteId.map((id) => this.getId(iframe, id, idToRemoteIdMap, remoteIdToIdMap));
3090
+ }
3091
+ getRemoteId(iframe, id, map) {
3092
+ const remoteIdToIdMap = map || this.getRemoteIdToIdMap(iframe);
3093
+ if (typeof id !== 'number')
3094
+ return id;
3095
+ const remoteId = remoteIdToIdMap.get(id);
3096
+ if (!remoteId)
3097
+ return -1;
3098
+ return remoteId;
3099
+ }
3100
+ getRemoteIds(iframe, ids) {
3101
+ const remoteIdToIdMap = this.getRemoteIdToIdMap(iframe);
3102
+ return ids.map((id) => this.getRemoteId(iframe, id, remoteIdToIdMap));
3103
+ }
3104
+ reset(iframe) {
3105
+ if (!iframe) {
3106
+ this.iframeIdToRemoteIdMap = new WeakMap();
3107
+ this.iframeRemoteIdToIdMap = new WeakMap();
3108
+ return;
3109
+ }
3110
+ this.iframeIdToRemoteIdMap.delete(iframe);
3111
+ this.iframeRemoteIdToIdMap.delete(iframe);
3112
+ }
3113
+ getIdToRemoteIdMap(iframe) {
3114
+ let idToRemoteIdMap = this.iframeIdToRemoteIdMap.get(iframe);
3115
+ if (!idToRemoteIdMap) {
3116
+ idToRemoteIdMap = new Map();
3117
+ this.iframeIdToRemoteIdMap.set(iframe, idToRemoteIdMap);
3118
+ }
3119
+ return idToRemoteIdMap;
3120
+ }
3121
+ getRemoteIdToIdMap(iframe) {
3122
+ let remoteIdToIdMap = this.iframeRemoteIdToIdMap.get(iframe);
3123
+ if (!remoteIdToIdMap) {
3124
+ remoteIdToIdMap = new Map();
3125
+ this.iframeRemoteIdToIdMap.set(iframe, remoteIdToIdMap);
3126
+ }
3127
+ return remoteIdToIdMap;
3128
+ }
3129
+ }
3130
+
2470
3131
  class IframeManager {
2471
3132
  constructor(options) {
2472
3133
  this.iframes = new WeakMap();
3134
+ this.crossOriginIframeMap = new WeakMap();
3135
+ this.crossOriginIframeMirror = new CrossOriginIframeMirror(genId);
3136
+ this.crossOriginIframeRootIdMap = new WeakMap();
2473
3137
  this.mutationCb = options.mutationCb;
3138
+ this.wrappedEmit = options.wrappedEmit;
3139
+ this.stylesheetManager = options.stylesheetManager;
3140
+ this.recordCrossOriginIframes = options.recordCrossOriginIframes;
3141
+ this.crossOriginIframeStyleMirror = new CrossOriginIframeMirror(this.stylesheetManager.styleMirror.generateId.bind(this.stylesheetManager.styleMirror));
3142
+ this.mirror = options.mirror;
3143
+ if (this.recordCrossOriginIframes) {
3144
+ window.addEventListener('message', this.handleMessage.bind(this));
3145
+ }
2474
3146
  }
2475
3147
  addIframe(iframeEl) {
2476
3148
  this.iframes.set(iframeEl, true);
3149
+ if (iframeEl.contentWindow)
3150
+ this.crossOriginIframeMap.set(iframeEl.contentWindow, iframeEl);
2477
3151
  }
2478
3152
  addLoadListener(cb) {
2479
3153
  this.loadListener = cb;
@@ -2483,7 +3157,7 @@ class IframeManager {
2483
3157
  this.mutationCb({
2484
3158
  adds: [
2485
3159
  {
2486
- parentId: iframeEl.__sn.id,
3160
+ parentId: this.mirror.getId(iframeEl),
2487
3161
  nextId: null,
2488
3162
  node: childSn,
2489
3163
  },
@@ -2494,154 +3168,278 @@ class IframeManager {
2494
3168
  isAttachIframe: true,
2495
3169
  });
2496
3170
  (_a = this.loadListener) === null || _a === void 0 ? void 0 : _a.call(this, iframeEl);
3171
+ if (iframeEl.contentDocument &&
3172
+ iframeEl.contentDocument.adoptedStyleSheets &&
3173
+ iframeEl.contentDocument.adoptedStyleSheets.length > 0)
3174
+ this.stylesheetManager.adoptStyleSheets(iframeEl.contentDocument.adoptedStyleSheets, this.mirror.getId(iframeEl.contentDocument));
3175
+ }
3176
+ handleMessage(message) {
3177
+ const crossOriginMessageEvent = message;
3178
+ if (crossOriginMessageEvent.data.type !== 'rrweb' ||
3179
+ crossOriginMessageEvent.origin !== crossOriginMessageEvent.data.origin)
3180
+ return;
3181
+ const iframeSourceWindow = message.source;
3182
+ if (!iframeSourceWindow)
3183
+ return;
3184
+ const iframeEl = this.crossOriginIframeMap.get(message.source);
3185
+ if (!iframeEl)
3186
+ return;
3187
+ const transformedEvent = this.transformCrossOriginEvent(iframeEl, crossOriginMessageEvent.data.event);
3188
+ if (transformedEvent)
3189
+ this.wrappedEmit(transformedEvent, crossOriginMessageEvent.data.isCheckout);
2497
3190
  }
2498
- }
2499
-
2500
- class ShadowDomManager {
2501
- constructor(options) {
2502
- this.restorePatches = [];
2503
- this.mutationCb = options.mutationCb;
2504
- this.scrollCb = options.scrollCb;
2505
- this.bypassOptions = options.bypassOptions;
2506
- this.mirror = options.mirror;
2507
- const manager = this;
2508
- this.restorePatches.push(patch(HTMLElement.prototype, 'attachShadow', function (original) {
2509
- return function () {
2510
- const shadowRoot = original.apply(this, arguments);
2511
- if (this.shadowRoot)
2512
- manager.addShadowRoot(this.shadowRoot, this.ownerDocument);
2513
- return shadowRoot;
2514
- };
2515
- }));
2516
- }
2517
- addShadowRoot(shadowRoot, doc) {
2518
- initMutationObserver(Object.assign(Object.assign({}, this.bypassOptions), { doc, mutationCb: this.mutationCb, mirror: this.mirror, shadowDomManager: this }), shadowRoot);
2519
- initScrollObserver(Object.assign(Object.assign({}, this.bypassOptions), { scrollCb: this.scrollCb, doc: shadowRoot, mirror: this.mirror }));
2520
- }
2521
- observeAttachShadow(iframeElement) {
2522
- if (iframeElement.contentWindow) {
2523
- const manager = this;
2524
- this.restorePatches.push(patch(iframeElement.contentWindow.HTMLElement.prototype, 'attachShadow', function (original) {
2525
- return function () {
2526
- const shadowRoot = original.apply(this, arguments);
2527
- if (this.shadowRoot)
2528
- manager.addShadowRoot(this.shadowRoot, iframeElement.contentDocument);
2529
- return shadowRoot;
3191
+ transformCrossOriginEvent(iframeEl, e) {
3192
+ var _a;
3193
+ switch (e.type) {
3194
+ case EventType.FullSnapshot: {
3195
+ this.crossOriginIframeMirror.reset(iframeEl);
3196
+ this.crossOriginIframeStyleMirror.reset(iframeEl);
3197
+ this.replaceIdOnNode(e.data.node, iframeEl);
3198
+ const rootId = e.data.node.id;
3199
+ this.crossOriginIframeRootIdMap.set(iframeEl, rootId);
3200
+ this.patchRootIdOnNode(e.data.node, rootId);
3201
+ return {
3202
+ timestamp: e.timestamp,
3203
+ type: EventType.IncrementalSnapshot,
3204
+ data: {
3205
+ source: IncrementalSource.Mutation,
3206
+ adds: [
3207
+ {
3208
+ parentId: this.mirror.getId(iframeEl),
3209
+ nextId: null,
3210
+ node: e.data.node,
3211
+ },
3212
+ ],
3213
+ removes: [],
3214
+ texts: [],
3215
+ attributes: [],
3216
+ isAttachIframe: true,
3217
+ },
2530
3218
  };
2531
- }));
3219
+ }
3220
+ case EventType.Meta:
3221
+ case EventType.Load:
3222
+ case EventType.DomContentLoaded: {
3223
+ return false;
3224
+ }
3225
+ case EventType.Plugin: {
3226
+ return e;
3227
+ }
3228
+ case EventType.Custom: {
3229
+ this.replaceIds(e.data.payload, iframeEl, ['id', 'parentId', 'previousId', 'nextId']);
3230
+ return e;
3231
+ }
3232
+ case EventType.IncrementalSnapshot: {
3233
+ switch (e.data.source) {
3234
+ case IncrementalSource.Mutation: {
3235
+ e.data.adds.forEach((n) => {
3236
+ this.replaceIds(n, iframeEl, [
3237
+ 'parentId',
3238
+ 'nextId',
3239
+ 'previousId',
3240
+ ]);
3241
+ this.replaceIdOnNode(n.node, iframeEl);
3242
+ const rootId = this.crossOriginIframeRootIdMap.get(iframeEl);
3243
+ rootId && this.patchRootIdOnNode(n.node, rootId);
3244
+ });
3245
+ e.data.removes.forEach((n) => {
3246
+ this.replaceIds(n, iframeEl, ['parentId', 'id']);
3247
+ });
3248
+ e.data.attributes.forEach((n) => {
3249
+ this.replaceIds(n, iframeEl, ['id']);
3250
+ });
3251
+ e.data.texts.forEach((n) => {
3252
+ this.replaceIds(n, iframeEl, ['id']);
3253
+ });
3254
+ return e;
3255
+ }
3256
+ case IncrementalSource.Drag:
3257
+ case IncrementalSource.TouchMove:
3258
+ case IncrementalSource.MouseMove: {
3259
+ e.data.positions.forEach((p) => {
3260
+ this.replaceIds(p, iframeEl, ['id']);
3261
+ });
3262
+ return e;
3263
+ }
3264
+ case IncrementalSource.ViewportResize: {
3265
+ return false;
3266
+ }
3267
+ case IncrementalSource.MediaInteraction:
3268
+ case IncrementalSource.MouseInteraction:
3269
+ case IncrementalSource.Scroll:
3270
+ case IncrementalSource.CanvasMutation:
3271
+ case IncrementalSource.Input: {
3272
+ this.replaceIds(e.data, iframeEl, ['id']);
3273
+ return e;
3274
+ }
3275
+ case IncrementalSource.StyleSheetRule:
3276
+ case IncrementalSource.StyleDeclaration: {
3277
+ this.replaceIds(e.data, iframeEl, ['id']);
3278
+ this.replaceStyleIds(e.data, iframeEl, ['styleId']);
3279
+ return e;
3280
+ }
3281
+ case IncrementalSource.Font: {
3282
+ return e;
3283
+ }
3284
+ case IncrementalSource.Selection: {
3285
+ e.data.ranges.forEach((range) => {
3286
+ this.replaceIds(range, iframeEl, ['start', 'end']);
3287
+ });
3288
+ return e;
3289
+ }
3290
+ case IncrementalSource.AdoptedStyleSheet: {
3291
+ this.replaceIds(e.data, iframeEl, ['id']);
3292
+ this.replaceStyleIds(e.data, iframeEl, ['styleIds']);
3293
+ (_a = e.data.styles) === null || _a === void 0 ? void 0 : _a.forEach((style) => {
3294
+ this.replaceStyleIds(style, iframeEl, ['styleId']);
3295
+ });
3296
+ return e;
3297
+ }
3298
+ }
3299
+ }
2532
3300
  }
3301
+ return false;
2533
3302
  }
2534
- reset() {
2535
- this.restorePatches.forEach((restorePatch) => restorePatch());
2536
- }
2537
- }
2538
-
2539
- /******************************************************************************
2540
- Copyright (c) Microsoft Corporation.
2541
-
2542
- Permission to use, copy, modify, and/or distribute this software for any
2543
- purpose with or without fee is hereby granted.
2544
-
2545
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
2546
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
2547
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
2548
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
2549
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
2550
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2551
- PERFORMANCE OF THIS SOFTWARE.
2552
- ***************************************************************************** */
2553
-
2554
- function __rest(s, e) {
2555
- var t = {};
2556
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
2557
- t[p] = s[p];
2558
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
2559
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
2560
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
2561
- t[p[i]] = s[p[i]];
2562
- }
2563
- return t;
2564
- }
2565
-
2566
- function initCanvas2DMutationObserver(cb, win, blockClass, unblockSelector, blockSelector, mirror) {
2567
- const handlers = [];
2568
- const props2D = Object.getOwnPropertyNames(win.CanvasRenderingContext2D.prototype);
2569
- for (const prop of props2D) {
2570
- try {
2571
- if (typeof win.CanvasRenderingContext2D.prototype[prop] !== 'function') {
3303
+ replace(iframeMirror, obj, iframeEl, keys) {
3304
+ for (const key of keys) {
3305
+ if (!Array.isArray(obj[key]) && typeof obj[key] !== 'number')
2572
3306
  continue;
3307
+ if (Array.isArray(obj[key])) {
3308
+ obj[key] = iframeMirror.getIds(iframeEl, obj[key]);
2573
3309
  }
2574
- const restoreHandler = patch(win.CanvasRenderingContext2D.prototype, prop, function (original) {
2575
- return function (...args) {
2576
- if (!isBlocked(this.canvas, blockClass, blockSelector, unblockSelector)) {
2577
- setTimeout(() => {
2578
- const recordArgs = [...args];
2579
- if (prop === 'drawImage') {
2580
- if (recordArgs[0] &&
2581
- recordArgs[0] instanceof HTMLCanvasElement) {
2582
- const canvas = recordArgs[0];
2583
- const ctx = canvas.getContext('2d');
2584
- let imgd = ctx === null || ctx === void 0 ? void 0 : ctx.getImageData(0, 0, canvas.width, canvas.height);
2585
- let pix = imgd === null || imgd === void 0 ? void 0 : imgd.data;
2586
- recordArgs[0] = JSON.stringify(pix);
2587
- }
2588
- }
2589
- cb(this.canvas, {
2590
- type: CanvasContext['2D'],
2591
- property: prop,
2592
- args: recordArgs,
2593
- });
2594
- }, 0);
2595
- }
2596
- return original.apply(this, args);
2597
- };
3310
+ else {
3311
+ obj[key] = iframeMirror.getId(iframeEl, obj[key]);
3312
+ }
3313
+ }
3314
+ return obj;
3315
+ }
3316
+ replaceIds(obj, iframeEl, keys) {
3317
+ return this.replace(this.crossOriginIframeMirror, obj, iframeEl, keys);
3318
+ }
3319
+ replaceStyleIds(obj, iframeEl, keys) {
3320
+ return this.replace(this.crossOriginIframeStyleMirror, obj, iframeEl, keys);
3321
+ }
3322
+ replaceIdOnNode(node, iframeEl) {
3323
+ this.replaceIds(node, iframeEl, ['id', 'rootId']);
3324
+ if ('childNodes' in node) {
3325
+ node.childNodes.forEach((child) => {
3326
+ this.replaceIdOnNode(child, iframeEl);
2598
3327
  });
2599
- handlers.push(restoreHandler);
2600
3328
  }
2601
- catch (_a) {
2602
- const hookHandler = hookSetter(win.CanvasRenderingContext2D.prototype, prop, {
2603
- set(v) {
2604
- cb(this.canvas, {
2605
- type: CanvasContext['2D'],
2606
- property: prop,
2607
- args: [v],
2608
- setter: true,
2609
- });
2610
- },
3329
+ }
3330
+ patchRootIdOnNode(node, rootId) {
3331
+ if (node.type !== NodeType$1.Document && !node.rootId)
3332
+ node.rootId = rootId;
3333
+ if ('childNodes' in node) {
3334
+ node.childNodes.forEach((child) => {
3335
+ this.patchRootIdOnNode(child, rootId);
2611
3336
  });
2612
- handlers.push(hookHandler);
2613
3337
  }
2614
3338
  }
2615
- return () => {
2616
- handlers.forEach((h) => h());
2617
- };
2618
3339
  }
2619
3340
 
2620
- function initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector) {
2621
- const handlers = [];
2622
- try {
2623
- const restoreHandler = patch(win.HTMLCanvasElement.prototype, 'getContext', function (original) {
2624
- return function (contextType, ...args) {
2625
- if (!isBlocked(this, blockClass, blockSelector, unblockSelector)) {
2626
- if (!('__context' in this))
2627
- this.__context = contextType;
2628
- }
2629
- return original.apply(this, [contextType, ...args]);
3341
+ class ShadowDomManager {
3342
+ constructor(options) {
3343
+ this.shadowDoms = new WeakSet();
3344
+ this.restoreHandlers = [];
3345
+ this.mutationCb = options.mutationCb;
3346
+ this.scrollCb = options.scrollCb;
3347
+ this.bypassOptions = options.bypassOptions;
3348
+ this.mirror = options.mirror;
3349
+ this.init();
3350
+ }
3351
+ init() {
3352
+ this.reset();
3353
+ this.patchAttachShadow(Element, document);
3354
+ }
3355
+ addShadowRoot(shadowRoot, doc) {
3356
+ if (!isNativeShadowDom(shadowRoot))
3357
+ return;
3358
+ if (this.shadowDoms.has(shadowRoot))
3359
+ return;
3360
+ this.shadowDoms.add(shadowRoot);
3361
+ const observer = initMutationObserver(Object.assign(Object.assign({}, this.bypassOptions), { doc, mutationCb: this.mutationCb, mirror: this.mirror, shadowDomManager: this }), shadowRoot);
3362
+ this.restoreHandlers.push(() => observer.disconnect());
3363
+ this.restoreHandlers.push(initScrollObserver(Object.assign(Object.assign({}, this.bypassOptions), { scrollCb: this.scrollCb, doc: shadowRoot, mirror: this.mirror })));
3364
+ setTimeout(() => {
3365
+ if (shadowRoot.adoptedStyleSheets &&
3366
+ shadowRoot.adoptedStyleSheets.length > 0)
3367
+ this.bypassOptions.stylesheetManager.adoptStyleSheets(shadowRoot.adoptedStyleSheets, this.mirror.getId(shadowRoot.host));
3368
+ this.restoreHandlers.push(initAdoptedStyleSheetObserver({
3369
+ mirror: this.mirror,
3370
+ stylesheetManager: this.bypassOptions.stylesheetManager,
3371
+ }, shadowRoot));
3372
+ }, 0);
3373
+ }
3374
+ observeAttachShadow(iframeElement) {
3375
+ if (!iframeElement.contentWindow || !iframeElement.contentDocument)
3376
+ return;
3377
+ this.patchAttachShadow(iframeElement.contentWindow.Element, iframeElement.contentDocument);
3378
+ }
3379
+ patchAttachShadow(element, doc) {
3380
+ const manager = this;
3381
+ this.restoreHandlers.push(patch(element.prototype, 'attachShadow', function (original) {
3382
+ return function (option) {
3383
+ const shadowRoot = original.call(this, option);
3384
+ if (this.shadowRoot && inDom(this))
3385
+ manager.addShadowRoot(this.shadowRoot, doc);
3386
+ return shadowRoot;
2630
3387
  };
2631
- });
2632
- handlers.push(restoreHandler);
3388
+ }));
2633
3389
  }
2634
- catch (_a) {
2635
- console.error('failed to patch HTMLCanvasElement.prototype.getContext');
3390
+ reset() {
3391
+ this.restoreHandlers.forEach((handler) => {
3392
+ try {
3393
+ handler();
3394
+ }
3395
+ catch (e) {
3396
+ }
3397
+ });
3398
+ this.restoreHandlers = [];
3399
+ this.shadowDoms = new WeakSet();
2636
3400
  }
2637
- return () => {
2638
- handlers.forEach((h) => h());
2639
- };
3401
+ }
3402
+
3403
+ /*! *****************************************************************************
3404
+ Copyright (c) Microsoft Corporation.
3405
+
3406
+ Permission to use, copy, modify, and/or distribute this software for any
3407
+ purpose with or without fee is hereby granted.
3408
+
3409
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
3410
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
3411
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
3412
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
3413
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
3414
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
3415
+ PERFORMANCE OF THIS SOFTWARE.
3416
+ ***************************************************************************** */
3417
+
3418
+ function __rest(s, e) {
3419
+ var t = {};
3420
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
3421
+ t[p] = s[p];
3422
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
3423
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
3424
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
3425
+ t[p[i]] = s[p[i]];
3426
+ }
3427
+ return t;
3428
+ }
3429
+
3430
+ function __awaiter(thisArg, _arguments, P, generator) {
3431
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3432
+ return new (P || (P = Promise))(function (resolve, reject) {
3433
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
3434
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
3435
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
3436
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
3437
+ });
2640
3438
  }
2641
3439
 
2642
3440
  /*
2643
- * base64-arraybuffer 1.0.2 <https://github.com/niklasvh/base64-arraybuffer>
2644
- * Copyright (c) 2022 Niklas von Hertzen <https://hertzen.com>
3441
+ * base64-arraybuffer 1.0.1 <https://github.com/niklasvh/base64-arraybuffer>
3442
+ * Copyright (c) 2021 Niklas von Hertzen <https://hertzen.com>
2645
3443
  * Released under MIT License
2646
3444
  */
2647
3445
  var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
@@ -2667,12 +3465,12 @@ var encode = function (arraybuffer) {
2667
3465
  return base64;
2668
3466
  };
2669
3467
 
2670
- const webGLVarMap = new Map();
3468
+ const canvasVarMap = new Map();
2671
3469
  function variableListFor(ctx, ctor) {
2672
- let contextMap = webGLVarMap.get(ctx);
3470
+ let contextMap = canvasVarMap.get(ctx);
2673
3471
  if (!contextMap) {
2674
3472
  contextMap = new Map();
2675
- webGLVarMap.set(ctx, contextMap);
3473
+ canvasVarMap.set(ctx, contextMap);
2676
3474
  }
2677
3475
  if (!contextMap.has(ctor)) {
2678
3476
  contextMap.set(ctor, []);
@@ -2741,6 +3539,14 @@ function serializeArg(value, win, ctx) {
2741
3539
  src,
2742
3540
  };
2743
3541
  }
3542
+ else if (value instanceof HTMLCanvasElement) {
3543
+ const name = 'HTMLImageElement';
3544
+ const src = value.toDataURL();
3545
+ return {
3546
+ rr_type: name,
3547
+ src,
3548
+ };
3549
+ }
2744
3550
  else if (value instanceof ImageData) {
2745
3551
  const name = value.constructor.name;
2746
3552
  return {
@@ -2779,10 +3585,102 @@ const isInstanceOfWebGLObject = (value, win) => {
2779
3585
  return Boolean(supportedWebGLConstructorNames.find((name) => value instanceof win[name]));
2780
3586
  };
2781
3587
 
2782
- function patchGLPrototype(prototype, type, cb, blockClass, unblockSelector, blockSelector, mirror, win) {
3588
+ function initCanvas2DMutationObserver(cb, win, blockClass, blockSelector, unblockSelector) {
3589
+ const handlers = [];
3590
+ const props2D = Object.getOwnPropertyNames(win.CanvasRenderingContext2D.prototype);
3591
+ for (const prop of props2D) {
3592
+ try {
3593
+ if (typeof win.CanvasRenderingContext2D.prototype[prop] !== 'function') {
3594
+ continue;
3595
+ }
3596
+ const restoreHandler = patch(win.CanvasRenderingContext2D.prototype, prop, function (original) {
3597
+ return function (...args) {
3598
+ if (!isBlocked(this.canvas, blockClass, blockSelector, unblockSelector, true)) {
3599
+ setTimeout(() => {
3600
+ const recordArgs = serializeArgs([...args], win, this);
3601
+ cb(this.canvas, {
3602
+ type: CanvasContext['2D'],
3603
+ property: prop,
3604
+ args: recordArgs,
3605
+ });
3606
+ }, 0);
3607
+ }
3608
+ return original.apply(this, args);
3609
+ };
3610
+ });
3611
+ handlers.push(restoreHandler);
3612
+ }
3613
+ catch (_a) {
3614
+ const hookHandler = hookSetter(win.CanvasRenderingContext2D.prototype, prop, {
3615
+ set(v) {
3616
+ cb(this.canvas, {
3617
+ type: CanvasContext['2D'],
3618
+ property: prop,
3619
+ args: [v],
3620
+ setter: true,
3621
+ });
3622
+ },
3623
+ });
3624
+ handlers.push(hookHandler);
3625
+ }
3626
+ }
3627
+ return () => {
3628
+ handlers.forEach((h) => h());
3629
+ };
3630
+ }
3631
+
3632
+ function getNormalizedContextName(contextType) {
3633
+ return contextType === 'experimental-webgl' ? 'webgl' : contextType;
3634
+ }
3635
+ function initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector, setPreserveDrawingBufferToTrue) {
3636
+ const handlers = [];
3637
+ try {
3638
+ const restoreHandler = patch(win.HTMLCanvasElement.prototype, 'getContext', function (original) {
3639
+ return function (contextType, ...args) {
3640
+ if (!isBlocked(this, blockClass, blockSelector, unblockSelector, true)) {
3641
+ const ctxName = getNormalizedContextName(contextType);
3642
+ if (!('__context' in this))
3643
+ this.__context = ctxName;
3644
+ if (setPreserveDrawingBufferToTrue &&
3645
+ ['webgl', 'webgl2'].includes(ctxName)) {
3646
+ if (args[0] && typeof args[0] === 'object') {
3647
+ const contextAttributes = args[0];
3648
+ if (!contextAttributes.preserveDrawingBuffer) {
3649
+ contextAttributes.preserveDrawingBuffer = true;
3650
+ }
3651
+ }
3652
+ else {
3653
+ args.splice(0, 1, {
3654
+ preserveDrawingBuffer: true,
3655
+ });
3656
+ }
3657
+ }
3658
+ }
3659
+ return original.apply(this, [contextType, ...args]);
3660
+ };
3661
+ });
3662
+ handlers.push(restoreHandler);
3663
+ }
3664
+ catch (_a) {
3665
+ console.error('failed to patch HTMLCanvasElement.prototype.getContext');
3666
+ }
3667
+ return () => {
3668
+ handlers.forEach((h) => h());
3669
+ };
3670
+ }
3671
+
3672
+ function patchGLPrototype(prototype, type, cb, blockClass, blockSelector, unblockSelector, mirror, win) {
2783
3673
  const handlers = [];
2784
3674
  const props = Object.getOwnPropertyNames(prototype);
2785
3675
  for (const prop of props) {
3676
+ if ([
3677
+ 'isContextLost',
3678
+ 'canvas',
3679
+ 'drawingBufferWidth',
3680
+ 'drawingBufferHeight',
3681
+ ].includes(prop)) {
3682
+ continue;
3683
+ }
2786
3684
  try {
2787
3685
  if (typeof prototype[prop] !== 'function') {
2788
3686
  continue;
@@ -2790,10 +3688,10 @@ function patchGLPrototype(prototype, type, cb, blockClass, unblockSelector, bloc
2790
3688
  const restoreHandler = patch(prototype, prop, function (original) {
2791
3689
  return function (...args) {
2792
3690
  const result = original.apply(this, args);
2793
- saveWebGLVar(result, win, prototype);
2794
- if (!isBlocked(this.canvas, blockClass, blockSelector, unblockSelector)) {
2795
- const id = mirror.getId(this.canvas);
2796
- const recordArgs = serializeArgs([...args], win, prototype);
3691
+ saveWebGLVar(result, win, this);
3692
+ if ('tagName' in this.canvas &&
3693
+ !isBlocked(this.canvas, blockClass, blockSelector, unblockSelector, true)) {
3694
+ const recordArgs = serializeArgs([...args], win, this);
2797
3695
  const mutation = {
2798
3696
  type,
2799
3697
  property: prop,
@@ -2833,6 +3731,38 @@ function initCanvasWebGLMutationObserver(cb, win, blockClass, blockSelector, unb
2833
3731
  };
2834
3732
  }
2835
3733
 
3734
+ function decodeBase64(base64, enableUnicode) {
3735
+ var binaryString = atob(base64);
3736
+ if (enableUnicode) {
3737
+ var binaryView = new Uint8Array(binaryString.length);
3738
+ for (var i = 0, n = binaryString.length; i < n; ++i) {
3739
+ binaryView[i] = binaryString.charCodeAt(i);
3740
+ }
3741
+ return String.fromCharCode.apply(null, new Uint16Array(binaryView.buffer));
3742
+ }
3743
+ return binaryString;
3744
+ }
3745
+
3746
+ function createURL(base64, sourcemapArg, enableUnicodeArg) {
3747
+ var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
3748
+ var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
3749
+ var source = decodeBase64(base64, enableUnicode);
3750
+ var start = source.indexOf('\n', 10) + 1;
3751
+ var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
3752
+ var blob = new Blob([body], { type: 'application/javascript' });
3753
+ return URL.createObjectURL(blob);
3754
+ }
3755
+
3756
+ function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
3757
+ var url;
3758
+ return function WorkerFactory(options) {
3759
+ url = url || createURL(base64, sourcemapArg, enableUnicodeArg);
3760
+ return new Worker(url, options);
3761
+ };
3762
+ }
3763
+
3764
+ var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24gKCkgewogICAgJ3VzZSBzdHJpY3QnOwoKICAgIC8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KICAgIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLg0KDQogICAgUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kL29yIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBmb3IgYW55DQogICAgcHVycG9zZSB3aXRoIG9yIHdpdGhvdXQgZmVlIGlzIGhlcmVieSBncmFudGVkLg0KDQogICAgVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIgQU5EIFRIRSBBVVRIT1IgRElTQ0xBSU1TIEFMTCBXQVJSQU5USUVTIFdJVEgNCiAgICBSRUdBUkQgVE8gVEhJUyBTT0ZUV0FSRSBJTkNMVURJTkcgQUxMIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkNCiAgICBBTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsDQogICAgSU5ESVJFQ1QsIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPUiBBTlkgREFNQUdFUyBXSEFUU09FVkVSIFJFU1VMVElORyBGUk9NDQogICAgTE9TUyBPRiBVU0UsIERBVEEgT1IgUFJPRklUUywgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIE5FR0xJR0VOQ0UgT1INCiAgICBPVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SDQogICAgUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS4NCiAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAqLw0KDQogICAgZnVuY3Rpb24gX19hd2FpdGVyKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikgew0KICAgICAgICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkgeyByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHZhbHVlKTsgfSk7IH0NCiAgICAgICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7DQogICAgICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9DQogICAgICAgICAgICBmdW5jdGlvbiByZWplY3RlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvclsidGhyb3ciXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9DQogICAgICAgICAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkgeyByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTsgfQ0KICAgICAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpOw0KICAgICAgICB9KTsNCiAgICB9CgogICAgLyoKICAgICAqIGJhc2U2NC1hcnJheWJ1ZmZlciAxLjAuMSA8aHR0cHM6Ly9naXRodWIuY29tL25pa2xhc3ZoL2Jhc2U2NC1hcnJheWJ1ZmZlcj4KICAgICAqIENvcHlyaWdodCAoYykgMjAyMSBOaWtsYXMgdm9uIEhlcnR6ZW4gPGh0dHBzOi8vaGVydHplbi5jb20+CiAgICAgKiBSZWxlYXNlZCB1bmRlciBNSVQgTGljZW5zZQogICAgICovCiAgICB2YXIgY2hhcnMgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLyc7CiAgICAvLyBVc2UgYSBsb29rdXAgdGFibGUgdG8gZmluZCB0aGUgaW5kZXguCiAgICB2YXIgbG9va3VwID0gdHlwZW9mIFVpbnQ4QXJyYXkgPT09ICd1bmRlZmluZWQnID8gW10gOiBuZXcgVWludDhBcnJheSgyNTYpOwogICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjaGFycy5sZW5ndGg7IGkrKykgewogICAgICAgIGxvb2t1cFtjaGFycy5jaGFyQ29kZUF0KGkpXSA9IGk7CiAgICB9CiAgICB2YXIgZW5jb2RlID0gZnVuY3Rpb24gKGFycmF5YnVmZmVyKSB7CiAgICAgICAgdmFyIGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoYXJyYXlidWZmZXIpLCBpLCBsZW4gPSBieXRlcy5sZW5ndGgsIGJhc2U2NCA9ICcnOwogICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkgKz0gMykgewogICAgICAgICAgICBiYXNlNjQgKz0gY2hhcnNbYnl0ZXNbaV0gPj4gMl07CiAgICAgICAgICAgIGJhc2U2NCArPSBjaGFyc1soKGJ5dGVzW2ldICYgMykgPDwgNCkgfCAoYnl0ZXNbaSArIDFdID4+IDQpXTsKICAgICAgICAgICAgYmFzZTY0ICs9IGNoYXJzWygoYnl0ZXNbaSArIDFdICYgMTUpIDw8IDIpIHwgKGJ5dGVzW2kgKyAyXSA+PiA2KV07CiAgICAgICAgICAgIGJhc2U2NCArPSBjaGFyc1tieXRlc1tpICsgMl0gJiA2M107CiAgICAgICAgfQogICAgICAgIGlmIChsZW4gJSAzID09PSAyKSB7CiAgICAgICAgICAgIGJhc2U2NCA9IGJhc2U2NC5zdWJzdHJpbmcoMCwgYmFzZTY0Lmxlbmd0aCAtIDEpICsgJz0nOwogICAgICAgIH0KICAgICAgICBlbHNlIGlmIChsZW4gJSAzID09PSAxKSB7CiAgICAgICAgICAgIGJhc2U2NCA9IGJhc2U2NC5zdWJzdHJpbmcoMCwgYmFzZTY0Lmxlbmd0aCAtIDIpICsgJz09JzsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGJhc2U2NDsKICAgIH07CgogICAgY29uc3QgbGFzdEJsb2JNYXAgPSBuZXcgTWFwKCk7DQogICAgY29uc3QgdHJhbnNwYXJlbnRCbG9iTWFwID0gbmV3IE1hcCgpOw0KICAgIGZ1bmN0aW9uIGdldFRyYW5zcGFyZW50QmxvYkZvcih3aWR0aCwgaGVpZ2h0LCBkYXRhVVJMT3B0aW9ucykgew0KICAgICAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkgew0KICAgICAgICAgICAgY29uc3QgaWQgPSBgJHt3aWR0aH0tJHtoZWlnaHR9YDsNCiAgICAgICAgICAgIGlmICgnT2Zmc2NyZWVuQ2FudmFzJyBpbiBnbG9iYWxUaGlzKSB7DQogICAgICAgICAgICAgICAgaWYgKHRyYW5zcGFyZW50QmxvYk1hcC5oYXMoaWQpKQ0KICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJhbnNwYXJlbnRCbG9iTWFwLmdldChpZCk7DQogICAgICAgICAgICAgICAgY29uc3Qgb2Zmc2NyZWVuID0gbmV3IE9mZnNjcmVlbkNhbnZhcyh3aWR0aCwgaGVpZ2h0KTsNCiAgICAgICAgICAgICAgICBvZmZzY3JlZW4uZ2V0Q29udGV4dCgnMmQnKTsNCiAgICAgICAgICAgICAgICBjb25zdCBibG9iID0geWllbGQgb2Zmc2NyZWVuLmNvbnZlcnRUb0Jsb2IoZGF0YVVSTE9wdGlvbnMpOw0KICAgICAgICAgICAgICAgIGNvbnN0IGFycmF5QnVmZmVyID0geWllbGQgYmxvYi5hcnJheUJ1ZmZlcigpOw0KICAgICAgICAgICAgICAgIGNvbnN0IGJhc2U2NCA9IGVuY29kZShhcnJheUJ1ZmZlcik7DQogICAgICAgICAgICAgICAgdHJhbnNwYXJlbnRCbG9iTWFwLnNldChpZCwgYmFzZTY0KTsNCiAgICAgICAgICAgICAgICByZXR1cm4gYmFzZTY0Ow0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgZWxzZSB7DQogICAgICAgICAgICAgICAgcmV0dXJuICcnOw0KICAgICAgICAgICAgfQ0KICAgICAgICB9KTsNCiAgICB9DQogICAgY29uc3Qgd29ya2VyID0gc2VsZjsNCiAgICB3b3JrZXIub25tZXNzYWdlID0gZnVuY3Rpb24gKGUpIHsNCiAgICAgICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHsNCiAgICAgICAgICAgIGlmICgnT2Zmc2NyZWVuQ2FudmFzJyBpbiBnbG9iYWxUaGlzKSB7DQogICAgICAgICAgICAgICAgY29uc3QgeyBpZCwgYml0bWFwLCB3aWR0aCwgaGVpZ2h0LCBkYXRhVVJMT3B0aW9ucyB9ID0gZS5kYXRhOw0KICAgICAgICAgICAgICAgIGNvbnN0IHRyYW5zcGFyZW50QmFzZTY0ID0gZ2V0VHJhbnNwYXJlbnRCbG9iRm9yKHdpZHRoLCBoZWlnaHQsIGRhdGFVUkxPcHRpb25zKTsNCiAgICAgICAgICAgICAgICBjb25zdCBvZmZzY3JlZW4gPSBuZXcgT2Zmc2NyZWVuQ2FudmFzKHdpZHRoLCBoZWlnaHQpOw0KICAgICAgICAgICAgICAgIGNvbnN0IGN0eCA9IG9mZnNjcmVlbi5nZXRDb250ZXh0KCcyZCcpOw0KICAgICAgICAgICAgICAgIGN0eC5kcmF3SW1hZ2UoYml0bWFwLCAwLCAwKTsNCiAgICAgICAgICAgICAgICBiaXRtYXAuY2xvc2UoKTsNCiAgICAgICAgICAgICAgICBjb25zdCBibG9iID0geWllbGQgb2Zmc2NyZWVuLmNvbnZlcnRUb0Jsb2IoZGF0YVVSTE9wdGlvbnMpOw0KICAgICAgICAgICAgICAgIGNvbnN0IHR5cGUgPSBibG9iLnR5cGU7DQogICAgICAgICAgICAgICAgY29uc3QgYXJyYXlCdWZmZXIgPSB5aWVsZCBibG9iLmFycmF5QnVmZmVyKCk7DQogICAgICAgICAgICAgICAgY29uc3QgYmFzZTY0ID0gZW5jb2RlKGFycmF5QnVmZmVyKTsNCiAgICAgICAgICAgICAgICBpZiAoIWxhc3RCbG9iTWFwLmhhcyhpZCkgJiYgKHlpZWxkIHRyYW5zcGFyZW50QmFzZTY0KSA9PT0gYmFzZTY0KSB7DQogICAgICAgICAgICAgICAgICAgIGxhc3RCbG9iTWFwLnNldChpZCwgYmFzZTY0KTsNCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHdvcmtlci5wb3N0TWVzc2FnZSh7IGlkIH0pOw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBpZiAobGFzdEJsb2JNYXAuZ2V0KGlkKSA9PT0gYmFzZTY0KQ0KICAgICAgICAgICAgICAgICAgICByZXR1cm4gd29ya2VyLnBvc3RNZXNzYWdlKHsgaWQgfSk7DQogICAgICAgICAgICAgICAgd29ya2VyLnBvc3RNZXNzYWdlKHsNCiAgICAgICAgICAgICAgICAgICAgaWQsDQogICAgICAgICAgICAgICAgICAgIHR5cGUsDQogICAgICAgICAgICAgICAgICAgIGJhc2U2NCwNCiAgICAgICAgICAgICAgICAgICAgd2lkdGgsDQogICAgICAgICAgICAgICAgICAgIGhlaWdodCwNCiAgICAgICAgICAgICAgICB9KTsNCiAgICAgICAgICAgICAgICBsYXN0QmxvYk1hcC5zZXQoaWQsIGJhc2U2NCk7DQogICAgICAgICAgICB9DQogICAgICAgICAgICBlbHNlIHsNCiAgICAgICAgICAgICAgICByZXR1cm4gd29ya2VyLnBvc3RNZXNzYWdlKHsgaWQ6IGUuZGF0YS5pZCB9KTsNCiAgICAgICAgICAgIH0NCiAgICAgICAgfSk7DQogICAgfTsKCn0pKCk7Cgo=', null, false);
3765
+
2836
3766
  class CanvasManager {
2837
3767
  reset() {
2838
3768
  this.pendingCanvasMutations.clear();
@@ -2855,7 +3785,7 @@ class CanvasManager {
2855
3785
  this.rafStamps = { latestId: 0, invokeId: null };
2856
3786
  this.frozen = false;
2857
3787
  this.locked = false;
2858
- this.processMutation = function (target, mutation) {
3788
+ this.processMutation = (target, mutation) => {
2859
3789
  const newFrame = this.rafStamps.invokeId &&
2860
3790
  this.rafStamps.latestId !== this.rafStamps.invokeId;
2861
3791
  if (newFrame || !this.rafStamps.invokeId)
@@ -2865,16 +3795,108 @@ class CanvasManager {
2865
3795
  }
2866
3796
  this.pendingCanvasMutations.get(target).push(mutation);
2867
3797
  };
3798
+ const { sampling = 'all', win, blockClass, blockSelector, unblockSelector, recordCanvas, dataURLOptions, } = options;
2868
3799
  this.mutationCb = options.mutationCb;
2869
3800
  this.mirror = options.mirror;
2870
- if (options.recordCanvas === true)
2871
- this.initCanvasMutationObserver(options.win, options.blockClass, options.blockSelector, options.unblockSelector);
3801
+ if (recordCanvas && sampling === 'all')
3802
+ this.initCanvasMutationObserver(win, blockClass, blockSelector, unblockSelector);
3803
+ if (recordCanvas && typeof sampling === 'number')
3804
+ this.initCanvasFPSObserver(sampling, win, blockClass, blockSelector, unblockSelector, {
3805
+ dataURLOptions,
3806
+ });
3807
+ }
3808
+ initCanvasFPSObserver(fps, win, blockClass, blockSelector, unblockSelector, options) {
3809
+ const canvasContextReset = initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector, true);
3810
+ const snapshotInProgressMap = new Map();
3811
+ const worker = new WorkerFactory();
3812
+ worker.onmessage = (e) => {
3813
+ const { id } = e.data;
3814
+ snapshotInProgressMap.set(id, false);
3815
+ if (!('base64' in e.data))
3816
+ return;
3817
+ const { base64, type, width, height } = e.data;
3818
+ this.mutationCb({
3819
+ id,
3820
+ type: CanvasContext['2D'],
3821
+ commands: [
3822
+ {
3823
+ property: 'clearRect',
3824
+ args: [0, 0, width, height],
3825
+ },
3826
+ {
3827
+ property: 'drawImage',
3828
+ args: [
3829
+ {
3830
+ rr_type: 'ImageBitmap',
3831
+ args: [
3832
+ {
3833
+ rr_type: 'Blob',
3834
+ data: [{ rr_type: 'ArrayBuffer', base64 }],
3835
+ type,
3836
+ },
3837
+ ],
3838
+ },
3839
+ 0,
3840
+ 0,
3841
+ ],
3842
+ },
3843
+ ],
3844
+ });
3845
+ };
3846
+ const timeBetweenSnapshots = 1000 / fps;
3847
+ let lastSnapshotTime = 0;
3848
+ let rafId;
3849
+ const getCanvas = () => {
3850
+ const matchedCanvas = [];
3851
+ win.document.querySelectorAll('canvas').forEach((canvas) => {
3852
+ if (!isBlocked(canvas, blockClass, blockSelector, unblockSelector, true)) {
3853
+ matchedCanvas.push(canvas);
3854
+ }
3855
+ });
3856
+ return matchedCanvas;
3857
+ };
3858
+ const takeCanvasSnapshots = (timestamp) => {
3859
+ if (lastSnapshotTime &&
3860
+ timestamp - lastSnapshotTime < timeBetweenSnapshots) {
3861
+ rafId = requestAnimationFrame(takeCanvasSnapshots);
3862
+ return;
3863
+ }
3864
+ lastSnapshotTime = timestamp;
3865
+ getCanvas()
3866
+ .forEach((canvas) => __awaiter(this, void 0, void 0, function* () {
3867
+ var _a;
3868
+ const id = this.mirror.getId(canvas);
3869
+ if (snapshotInProgressMap.get(id))
3870
+ return;
3871
+ snapshotInProgressMap.set(id, true);
3872
+ if (['webgl', 'webgl2'].includes(canvas.__context)) {
3873
+ const context = canvas.getContext(canvas.__context);
3874
+ if (((_a = context === null || context === void 0 ? void 0 : context.getContextAttributes()) === null || _a === void 0 ? void 0 : _a.preserveDrawingBuffer) === false) {
3875
+ context.clear(context.COLOR_BUFFER_BIT);
3876
+ }
3877
+ }
3878
+ const bitmap = yield createImageBitmap(canvas);
3879
+ worker.postMessage({
3880
+ id,
3881
+ bitmap,
3882
+ width: canvas.width,
3883
+ height: canvas.height,
3884
+ dataURLOptions: options.dataURLOptions,
3885
+ }, [bitmap]);
3886
+ }));
3887
+ rafId = requestAnimationFrame(takeCanvasSnapshots);
3888
+ };
3889
+ rafId = requestAnimationFrame(takeCanvasSnapshots);
3890
+ this.resetObservers = () => {
3891
+ canvasContextReset();
3892
+ cancelAnimationFrame(rafId);
3893
+ };
2872
3894
  }
2873
- initCanvasMutationObserver(win, blockClass, unblockSelector, blockSelector) {
3895
+ initCanvasMutationObserver(win, blockClass, blockSelector, unblockSelector) {
2874
3896
  this.startRAFTimestamping();
2875
3897
  this.startPendingCanvasMutationFlusher();
2876
- const canvasContextReset = initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector);
2877
- const canvas2DReset = initCanvas2DMutationObserver(this.processMutation.bind(this), win, blockClass, blockSelector, unblockSelector, this.mirror);
3898
+ const canvasContextReset = initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector, false);
3899
+ const canvas2DReset = initCanvas2DMutationObserver(this.processMutation.bind(this), win, blockClass, blockSelector, unblockSelector);
2878
3900
  const canvasWebGL1and2Reset = initCanvasWebGLMutationObserver(this.processMutation.bind(this), win, blockClass, blockSelector, unblockSelector, this.mirror);
2879
3901
  this.resetObservers = () => {
2880
3902
  canvasContextReset();
@@ -2916,20 +3938,133 @@ class CanvasManager {
2916
3938
  }
2917
3939
  }
2918
3940
 
3941
+ class StylesheetManager {
3942
+ constructor(options) {
3943
+ this.trackedLinkElements = new WeakSet();
3944
+ this.styleMirror = new StyleSheetMirror();
3945
+ this.mutationCb = options.mutationCb;
3946
+ this.adoptedStyleSheetCb = options.adoptedStyleSheetCb;
3947
+ }
3948
+ attachLinkElement(linkEl, childSn) {
3949
+ if ('_cssText' in childSn.attributes)
3950
+ this.mutationCb({
3951
+ adds: [],
3952
+ removes: [],
3953
+ texts: [],
3954
+ attributes: [
3955
+ {
3956
+ id: childSn.id,
3957
+ attributes: childSn
3958
+ .attributes,
3959
+ },
3960
+ ],
3961
+ });
3962
+ this.trackLinkElement(linkEl);
3963
+ }
3964
+ trackLinkElement(linkEl) {
3965
+ if (this.trackedLinkElements.has(linkEl))
3966
+ return;
3967
+ this.trackedLinkElements.add(linkEl);
3968
+ this.trackStylesheetInLinkElement(linkEl);
3969
+ }
3970
+ adoptStyleSheets(sheets, hostId) {
3971
+ if (sheets.length === 0)
3972
+ return;
3973
+ const adoptedStyleSheetData = {
3974
+ id: hostId,
3975
+ styleIds: [],
3976
+ };
3977
+ const styles = [];
3978
+ for (const sheet of sheets) {
3979
+ let styleId;
3980
+ if (!this.styleMirror.has(sheet)) {
3981
+ styleId = this.styleMirror.add(sheet);
3982
+ styles.push({
3983
+ styleId,
3984
+ rules: Array.from(sheet.rules || CSSRule, (r, index) => ({
3985
+ rule: stringifyRule(r),
3986
+ index,
3987
+ })),
3988
+ });
3989
+ }
3990
+ else
3991
+ styleId = this.styleMirror.getId(sheet);
3992
+ adoptedStyleSheetData.styleIds.push(styleId);
3993
+ }
3994
+ if (styles.length > 0)
3995
+ adoptedStyleSheetData.styles = styles;
3996
+ this.adoptedStyleSheetCb(adoptedStyleSheetData);
3997
+ }
3998
+ reset() {
3999
+ this.styleMirror.reset();
4000
+ this.trackedLinkElements = new WeakSet();
4001
+ }
4002
+ trackStylesheetInLinkElement(linkEl) {
4003
+ }
4004
+ }
4005
+
4006
+ class ProcessedNodeManager {
4007
+ constructor() {
4008
+ this.nodeMap = new WeakMap();
4009
+ this.loop = true;
4010
+ this.periodicallyClear();
4011
+ }
4012
+ periodicallyClear() {
4013
+ requestAnimationFrame(() => {
4014
+ this.clear();
4015
+ if (this.loop)
4016
+ this.periodicallyClear();
4017
+ });
4018
+ }
4019
+ inOtherBuffer(node, thisBuffer) {
4020
+ const buffers = this.nodeMap.get(node);
4021
+ return (buffers && Array.from(buffers).some((buffer) => buffer !== thisBuffer));
4022
+ }
4023
+ add(node, buffer) {
4024
+ this.nodeMap.set(node, (this.nodeMap.get(node) || new Set()).add(buffer));
4025
+ }
4026
+ clear() {
4027
+ this.nodeMap = new WeakMap();
4028
+ }
4029
+ destroy() {
4030
+ this.loop = false;
4031
+ }
4032
+ }
4033
+
2919
4034
  function wrapEvent(e) {
2920
- return Object.assign(Object.assign({}, e), { timestamp: Date.now() });
4035
+ return Object.assign(Object.assign({}, e), { timestamp: nowTimestamp() });
2921
4036
  }
2922
4037
  let wrappedEmit;
2923
4038
  let takeFullSnapshot;
4039
+ let canvasManager;
4040
+ let recording = false;
2924
4041
  const mirror = createMirror();
2925
4042
  function record(options = {}) {
2926
- const { emit, checkoutEveryNms, checkoutEveryNth, blockClass = 'rr-block', blockSelector = null, unblockSelector = null, ignoreClass = 'rr-ignore', ignoreSelector = null, maskTextClass = 'rr-mask', maskTextSelector = null, maskInputSelector = null, unmaskTextSelector = null, unmaskInputSelector = null, inlineStylesheet = true, maskAllText = false, maskAllInputs, maskInputOptions: _maskInputOptions, slimDOMOptions: _slimDOMOptions, maskInputFn, maskTextFn, hooks, packFn, sampling = {}, mousemoveWait, recordCanvas = false, userTriggeredOnInput = false, collectFonts = false, inlineImages = false, plugins, keepIframeSrcFn = () => false, onMutation, } = options;
2927
- if (!emit) {
4043
+ const { emit, checkoutEveryNms, checkoutEveryNth, blockClass = 'rr-block', blockSelector = null, unblockSelector = null, ignoreClass = 'rr-ignore', ignoreSelector = null, maskAllText = false, maskTextClass = 'rr-mask', unmaskTextClass = null, maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, maskAllInputs, maskInputOptions: _maskInputOptions, slimDOMOptions: _slimDOMOptions, maskAttributeFn, maskInputFn, maskTextFn, hooks, packFn, sampling = {}, dataURLOptions = {}, mousemoveWait, recordCanvas = false, recordCrossOriginIframes = false, recordAfter = options.recordAfter === 'DOMContentLoaded'
4044
+ ? options.recordAfter
4045
+ : 'load', userTriggeredOnInput = false, collectFonts = false, inlineImages = false, plugins, keepIframeSrcFn = () => false, ignoreCSSAttributes = new Set([]), errorHandler, onMutation, } = options;
4046
+ registerErrorHandler(errorHandler);
4047
+ const inEmittingFrame = recordCrossOriginIframes
4048
+ ? window.parent === window
4049
+ : true;
4050
+ let passEmitsToParent = false;
4051
+ if (!inEmittingFrame) {
4052
+ try {
4053
+ if (window.parent.document) {
4054
+ passEmitsToParent = false;
4055
+ }
4056
+ }
4057
+ catch (e) {
4058
+ passEmitsToParent = true;
4059
+ }
4060
+ }
4061
+ if (inEmittingFrame && !emit) {
2928
4062
  throw new Error('emit function is required');
2929
4063
  }
2930
4064
  if (mousemoveWait !== undefined && sampling.mousemove === undefined) {
2931
4065
  sampling.mousemove = mousemoveWait;
2932
4066
  }
4067
+ mirror.reset();
2933
4068
  const maskInputOptions = maskAllInputs === true
2934
4069
  ? {
2935
4070
  color: true,
@@ -2978,7 +4113,8 @@ function record(options = {}) {
2978
4113
  e = plugin.eventProcessor(e);
2979
4114
  }
2980
4115
  }
2981
- if (packFn) {
4116
+ if (packFn &&
4117
+ !passEmitsToParent) {
2982
4118
  e = packFn(e);
2983
4119
  }
2984
4120
  return e;
@@ -2991,7 +4127,18 @@ function record(options = {}) {
2991
4127
  e.data.source === IncrementalSource.Mutation)) {
2992
4128
  mutationBuffers.forEach((buf) => buf.unfreeze());
2993
4129
  }
2994
- emit(eventProcessor(e), isCheckout);
4130
+ if (inEmittingFrame) {
4131
+ emit === null || emit === void 0 ? void 0 : emit(eventProcessor(e), isCheckout);
4132
+ }
4133
+ else if (passEmitsToParent) {
4134
+ const message = {
4135
+ type: 'rrweb',
4136
+ event: eventProcessor(e),
4137
+ origin: window.location.origin,
4138
+ isCheckout,
4139
+ };
4140
+ window.parent.postMessage(message, '*');
4141
+ }
2995
4142
  if (e.type === EventType.FullSnapshot) {
2996
4143
  lastFullSnapshotEvent = e;
2997
4144
  incrementalSnapshotCount = 0;
@@ -3024,10 +4171,31 @@ function record(options = {}) {
3024
4171
  type: EventType.IncrementalSnapshot,
3025
4172
  data: Object.assign({ source: IncrementalSource.CanvasMutation }, p),
3026
4173
  }));
4174
+ const wrappedAdoptedStyleSheetEmit = (a) => wrappedEmit(wrapEvent({
4175
+ type: EventType.IncrementalSnapshot,
4176
+ data: Object.assign({ source: IncrementalSource.AdoptedStyleSheet }, a),
4177
+ }));
4178
+ const stylesheetManager = new StylesheetManager({
4179
+ mutationCb: wrappedMutationEmit,
4180
+ adoptedStyleSheetCb: wrappedAdoptedStyleSheetEmit,
4181
+ });
3027
4182
  const iframeManager = new IframeManager({
4183
+ mirror,
3028
4184
  mutationCb: wrappedMutationEmit,
4185
+ stylesheetManager: stylesheetManager,
4186
+ recordCrossOriginIframes,
4187
+ wrappedEmit,
3029
4188
  });
3030
- const canvasManager = new CanvasManager({
4189
+ for (const plugin of plugins || []) {
4190
+ if (plugin.getMirror)
4191
+ plugin.getMirror({
4192
+ nodeMirror: mirror,
4193
+ crossOriginIframeMirror: iframeManager.crossOriginIframeMirror,
4194
+ crossOriginIframeStyleMirror: iframeManager.crossOriginIframeStyleMirror,
4195
+ });
4196
+ }
4197
+ const processedNodeManager = new ProcessedNodeManager();
4198
+ canvasManager = new CanvasManager({
3031
4199
  recordCanvas,
3032
4200
  mutationCb: wrappedCanvasMutationEmit,
3033
4201
  win: window,
@@ -3035,6 +4203,8 @@ function record(options = {}) {
3035
4203
  blockSelector,
3036
4204
  unblockSelector,
3037
4205
  mirror,
4206
+ sampling: sampling.canvas,
4207
+ dataURLOptions,
3038
4208
  });
3039
4209
  const shadowDomManager = new ShadowDomManager({
3040
4210
  mutationCb: wrappedMutationEmit,
@@ -3044,14 +4214,15 @@ function record(options = {}) {
3044
4214
  blockClass,
3045
4215
  blockSelector,
3046
4216
  unblockSelector,
4217
+ maskAllText,
3047
4218
  maskTextClass,
4219
+ unmaskTextClass,
3048
4220
  maskTextSelector,
3049
4221
  unmaskTextSelector,
3050
- maskInputSelector,
3051
- unmaskInputSelector,
3052
4222
  inlineStylesheet,
3053
- maskAllText,
3054
4223
  maskInputOptions,
4224
+ dataURLOptions,
4225
+ maskAttributeFn,
3055
4226
  maskTextFn,
3056
4227
  maskInputFn,
3057
4228
  recordCanvas,
@@ -3059,12 +4230,14 @@ function record(options = {}) {
3059
4230
  sampling,
3060
4231
  slimDOMOptions,
3061
4232
  iframeManager,
4233
+ stylesheetManager,
3062
4234
  canvasManager,
4235
+ keepIframeSrcFn,
4236
+ processedNodeManager,
3063
4237
  },
3064
4238
  mirror,
3065
4239
  });
3066
4240
  takeFullSnapshot = (isCheckout = false) => {
3067
- var _a, _b, _c, _d;
3068
4241
  wrappedEmit(wrapEvent({
3069
4242
  type: EventType.Meta,
3070
4243
  data: {
@@ -3073,27 +4246,35 @@ function record(options = {}) {
3073
4246
  height: getWindowHeight(),
3074
4247
  },
3075
4248
  }), isCheckout);
4249
+ stylesheetManager.reset();
4250
+ shadowDomManager.init();
3076
4251
  mutationBuffers.forEach((buf) => buf.lock());
3077
- const [node, idNodeMap] = snapshot(document, {
4252
+ const node = snapshot(document, {
4253
+ mirror,
3078
4254
  blockClass,
3079
4255
  blockSelector,
3080
4256
  unblockSelector,
4257
+ maskAllText,
3081
4258
  maskTextClass,
4259
+ unmaskTextClass,
3082
4260
  maskTextSelector,
3083
4261
  unmaskTextSelector,
3084
- maskInputSelector,
3085
- unmaskInputSelector,
3086
4262
  inlineStylesheet,
3087
- maskAllText,
3088
4263
  maskAllInputs: maskInputOptions,
4264
+ maskAttributeFn,
4265
+ maskInputFn,
3089
4266
  maskTextFn,
3090
4267
  slimDOM: slimDOMOptions,
4268
+ dataURLOptions,
3091
4269
  recordCanvas,
3092
4270
  inlineImages,
3093
4271
  onSerialize: (n) => {
3094
- if (isIframeINode(n)) {
4272
+ if (isSerializedIframe(n, mirror)) {
3095
4273
  iframeManager.addIframe(n);
3096
4274
  }
4275
+ if (isSerializedStylesheet(n, mirror)) {
4276
+ stylesheetManager.trackLinkElement(n);
4277
+ }
3097
4278
  if (hasShadowRoot(n)) {
3098
4279
  shadowDomManager.addShadowRoot(n.shadowRoot, document);
3099
4280
  }
@@ -3102,42 +4283,27 @@ function record(options = {}) {
3102
4283
  iframeManager.attachIframe(iframe, childSn);
3103
4284
  shadowDomManager.observeAttachShadow(iframe);
3104
4285
  },
4286
+ onStylesheetLoad: (linkEl, childSn) => {
4287
+ stylesheetManager.attachLinkElement(linkEl, childSn);
4288
+ },
3105
4289
  keepIframeSrcFn,
3106
4290
  });
3107
4291
  if (!node) {
3108
4292
  return console.warn('Failed to snapshot the document');
3109
4293
  }
3110
- mirror.map = idNodeMap;
3111
4294
  wrappedEmit(wrapEvent({
3112
4295
  type: EventType.FullSnapshot,
3113
4296
  data: {
3114
4297
  node,
3115
- initialOffset: {
3116
- left: window.pageXOffset !== undefined
3117
- ? window.pageXOffset
3118
- : (document === null || document === void 0 ? void 0 : document.documentElement.scrollLeft) ||
3119
- ((_b = (_a = document === null || document === void 0 ? void 0 : document.body) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.scrollLeft) ||
3120
- (document === null || document === void 0 ? void 0 : document.body.scrollLeft) ||
3121
- 0,
3122
- top: window.pageYOffset !== undefined
3123
- ? window.pageYOffset
3124
- : (document === null || document === void 0 ? void 0 : document.documentElement.scrollTop) ||
3125
- ((_d = (_c = document === null || document === void 0 ? void 0 : document.body) === null || _c === void 0 ? void 0 : _c.parentElement) === null || _d === void 0 ? void 0 : _d.scrollTop) ||
3126
- (document === null || document === void 0 ? void 0 : document.body.scrollTop) ||
3127
- 0,
3128
- },
4298
+ initialOffset: getWindowScroll(window),
3129
4299
  },
3130
- }));
4300
+ }), isCheckout);
3131
4301
  mutationBuffers.forEach((buf) => buf.unlock());
4302
+ if (document.adoptedStyleSheets && document.adoptedStyleSheets.length > 0)
4303
+ stylesheetManager.adoptStyleSheets(document.adoptedStyleSheets, mirror.getId(document));
3132
4304
  };
3133
4305
  try {
3134
4306
  const handlers = [];
3135
- handlers.push(on('DOMContentLoaded', () => {
3136
- wrappedEmit(wrapEvent({
3137
- type: EventType.DomContentLoaded,
3138
- data: {},
3139
- }));
3140
- }));
3141
4307
  const observe = (doc) => {
3142
4308
  var _a;
3143
4309
  return callbackWrapper(initObservers)({
@@ -3180,14 +4346,26 @@ function record(options = {}) {
3180
4346
  type: EventType.IncrementalSnapshot,
3181
4347
  data: Object.assign({ source: IncrementalSource.Font }, p),
3182
4348
  })),
4349
+ selectionCb: (p) => {
4350
+ wrappedEmit(wrapEvent({
4351
+ type: EventType.IncrementalSnapshot,
4352
+ data: Object.assign({ source: IncrementalSource.Selection }, p),
4353
+ }));
4354
+ },
4355
+ customElementCb: (c) => {
4356
+ wrappedEmit(wrapEvent({
4357
+ type: EventType.IncrementalSnapshot,
4358
+ data: Object.assign({ source: IncrementalSource.CustomElement }, c),
4359
+ }));
4360
+ },
3183
4361
  blockClass,
3184
4362
  ignoreClass,
3185
4363
  ignoreSelector,
4364
+ maskAllText,
3186
4365
  maskTextClass,
4366
+ unmaskTextClass,
3187
4367
  maskTextSelector,
3188
4368
  unmaskTextSelector,
3189
- maskInputSelector,
3190
- unmaskInputSelector,
3191
4369
  maskInputOptions,
3192
4370
  inlineStylesheet,
3193
4371
  sampling,
@@ -3196,16 +4374,21 @@ function record(options = {}) {
3196
4374
  userTriggeredOnInput,
3197
4375
  collectFonts,
3198
4376
  doc,
3199
- maskAllText,
4377
+ maskAttributeFn,
3200
4378
  maskInputFn,
3201
4379
  maskTextFn,
4380
+ keepIframeSrcFn,
3202
4381
  blockSelector,
3203
4382
  unblockSelector,
3204
4383
  slimDOMOptions,
4384
+ dataURLOptions,
3205
4385
  mirror,
3206
4386
  iframeManager,
4387
+ stylesheetManager,
3207
4388
  shadowDomManager,
4389
+ processedNodeManager,
3208
4390
  canvasManager,
4391
+ ignoreCSSAttributes,
3209
4392
  plugins: ((_a = plugins === null || plugins === void 0 ? void 0 : plugins.filter((p) => p.observer)) === null || _a === void 0 ? void 0 : _a.map((p) => ({
3210
4393
  observer: p.observer,
3211
4394
  options: p.options,
@@ -3230,22 +4413,35 @@ function record(options = {}) {
3230
4413
  const init = () => {
3231
4414
  takeFullSnapshot();
3232
4415
  handlers.push(observe(document));
4416
+ recording = true;
3233
4417
  };
3234
4418
  if (document.readyState === 'interactive' ||
3235
4419
  document.readyState === 'complete') {
3236
4420
  init();
3237
4421
  }
3238
4422
  else {
4423
+ handlers.push(on('DOMContentLoaded', () => {
4424
+ wrappedEmit(wrapEvent({
4425
+ type: EventType.DomContentLoaded,
4426
+ data: {},
4427
+ }));
4428
+ if (recordAfter === 'DOMContentLoaded')
4429
+ init();
4430
+ }));
3239
4431
  handlers.push(on('load', () => {
3240
4432
  wrappedEmit(wrapEvent({
3241
4433
  type: EventType.Load,
3242
4434
  data: {},
3243
4435
  }));
3244
- init();
4436
+ if (recordAfter === 'load')
4437
+ init();
3245
4438
  }, window));
3246
4439
  }
3247
4440
  return () => {
3248
4441
  handlers.forEach((h) => h());
4442
+ processedNodeManager.destroy();
4443
+ recording = false;
4444
+ unregisterErrorHandler();
3249
4445
  };
3250
4446
  }
3251
4447
  catch (error) {
@@ -3253,7 +4449,7 @@ function record(options = {}) {
3253
4449
  }
3254
4450
  }
3255
4451
  record.addCustomEvent = (tag, payload) => {
3256
- if (!wrappedEmit) {
4452
+ if (!recording) {
3257
4453
  throw new Error('please add custom event after start recording');
3258
4454
  }
3259
4455
  wrappedEmit(wrapEvent({
@@ -3268,7 +4464,7 @@ record.freezePage = () => {
3268
4464
  mutationBuffers.forEach((buf) => buf.freeze());
3269
4465
  };
3270
4466
  record.takeFullSnapshot = (isCheckout) => {
3271
- if (!takeFullSnapshot) {
4467
+ if (!recording) {
3272
4468
  throw new Error('please take full snapshot after start recording');
3273
4469
  }
3274
4470
  takeFullSnapshot(isCheckout);
@@ -3764,27 +4960,25 @@ const handleDomListener = (
3764
4960
 
3765
4961
  /** Get the base DOM breadcrumb. */
3766
4962
  function getBaseDomBreadcrumb(target, message) {
3767
- // `__sn` property is the serialized node created by rrweb
3768
- const serializedNode = target && isRrwebNode(target) && target.__sn.type === NodeType.Element ? target.__sn : null;
4963
+ const nodeId = record.mirror.getId(target);
4964
+ const node = nodeId && record.mirror.getNode(nodeId);
4965
+ const meta = node && record.mirror.getMeta(node);
4966
+ const element = meta && isElement(meta) ? meta : null;
3769
4967
 
3770
4968
  return {
3771
4969
  message,
3772
- data: serializedNode
4970
+ data: element
3773
4971
  ? {
3774
- nodeId: serializedNode.id,
4972
+ nodeId,
3775
4973
  node: {
3776
- id: serializedNode.id,
3777
- tagName: serializedNode.tagName,
3778
- textContent: target
3779
- ? Array.from(target.childNodes)
3780
- .map(
3781
- (node) => '__sn' in node && node.__sn.type === NodeType.Text && node.__sn.textContent,
3782
- )
3783
- .filter(Boolean) // filter out empty values
3784
- .map(text => (text ).trim())
3785
- .join('')
3786
- : '',
3787
- attributes: getAttributesToRecord(serializedNode.attributes),
4974
+ id: nodeId,
4975
+ tagName: element.tagName,
4976
+ textContent: Array.from(element.childNodes)
4977
+ .map((node) => node.type === NodeType.Text && node.textContent)
4978
+ .filter(Boolean) // filter out empty values
4979
+ .map(text => (text ).trim())
4980
+ .join(''),
4981
+ attributes: getAttributesToRecord(element.attributes),
3788
4982
  },
3789
4983
  }
3790
4984
  : {},
@@ -3821,8 +5015,8 @@ function getDomTarget(handlerData) {
3821
5015
  return { target, message };
3822
5016
  }
3823
5017
 
3824
- function isRrwebNode(node) {
3825
- return '__sn' in node;
5018
+ function isElement(node) {
5019
+ return node.type === NodeType.Element;
3826
5020
  }
3827
5021
 
3828
5022
  /** Handle keyboard events & create breadcrumbs. */
@@ -6647,9 +7841,7 @@ function createLargestContentfulPaint(
6647
7841
  data: {
6648
7842
  value, // LCP "duration" in ms
6649
7843
  size,
6650
- // Not sure why this errors, Node should be correct (Argument of type 'Node' is not assignable to parameter of type 'INode')
6651
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6652
- nodeId: record.mirror.getId(entry.element ),
7844
+ nodeId: record.mirror.getId(entry.element),
6653
7845
  },
6654
7846
  };
6655
7847
  }
@@ -7505,7 +8697,9 @@ class ReplayContainer {
7505
8697
 
7506
8698
  try {
7507
8699
  logInfo(
7508
- `[Replay] Stopping Replay${reason ? ` triggered by ${reason}` : ''}`,
8700
+ `[Replay] Stopping Replay${reason ? ` triggered by ${reason}` : ''} ${new Date().toISOString()} ${
8701
+ this._isEnabled
8702
+ }`,
7509
8703
  this._options._experiments.traceInternals,
7510
8704
  );
7511
8705
 
@@ -8438,8 +9632,6 @@ function getPrivacyOptions({
8438
9632
  // We are making the decision to make text and input selectors the same
8439
9633
  maskTextSelector: maskSelector,
8440
9634
  unmaskTextSelector: unmaskSelector,
8441
- maskInputSelector: maskSelector,
8442
- unmaskInputSelector: unmaskSelector,
8443
9635
 
8444
9636
  blockSelector: getOption(
8445
9637
  block,
@@ -8475,6 +9667,39 @@ function isElectronNodeRenderer() {
8475
9667
  return typeof process !== 'undefined' && (process ).type === 'renderer';
8476
9668
  }
8477
9669
 
9670
+ /**
9671
+ * Masks an attribute if necessary, otherwise return attribute value as-is.
9672
+ */
9673
+ function maskAttribute({
9674
+ el,
9675
+ key,
9676
+ maskAttributes,
9677
+ maskAllText,
9678
+ privacyOptions,
9679
+ value,
9680
+ }) {
9681
+ // We only mask attributes if `maskAllText` is true
9682
+ if (!maskAllText) {
9683
+ return value;
9684
+ }
9685
+
9686
+ // unmaskTextSelector takes precendence
9687
+ if (privacyOptions.unmaskTextSelector && el.matches(privacyOptions.unmaskTextSelector)) {
9688
+ return value;
9689
+ }
9690
+
9691
+ if (
9692
+ maskAttributes.includes(key) ||
9693
+ // Need to mask `value` attribute for `<input>` if it's a button-like
9694
+ // type
9695
+ (key === 'value' && el.tagName === 'INPUT' && ['submit', 'button'].includes(el.getAttribute('type') || ''))
9696
+ ) {
9697
+ return value.replace(/[\S]/g, '*');
9698
+ }
9699
+
9700
+ return value;
9701
+ }
9702
+
8478
9703
  const MEDIA_SELECTORS =
8479
9704
  'img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]';
8480
9705
 
@@ -8534,6 +9759,7 @@ class Replay {
8534
9759
  networkResponseHeaders = [],
8535
9760
 
8536
9761
  mask = [],
9762
+ maskAttributes = ['title', 'placeholder'],
8537
9763
  unmask = [],
8538
9764
  block = [],
8539
9765
  unblock = [],
@@ -8557,25 +9783,36 @@ class Replay {
8557
9783
  } = {}) {
8558
9784
  this.name = Replay.id;
8559
9785
 
9786
+ const privacyOptions = getPrivacyOptions({
9787
+ mask,
9788
+ unmask,
9789
+ block,
9790
+ unblock,
9791
+ ignore,
9792
+ blockClass,
9793
+ blockSelector,
9794
+ maskTextClass,
9795
+ maskTextSelector,
9796
+ ignoreClass,
9797
+ });
9798
+
8560
9799
  this._recordingOptions = {
8561
9800
  maskAllInputs,
8562
9801
  maskAllText,
8563
9802
  maskInputOptions: { ...(maskInputOptions || {}), password: true },
8564
9803
  maskTextFn: maskFn,
8565
9804
  maskInputFn: maskFn,
9805
+ maskAttributeFn: (key, value, el) =>
9806
+ maskAttribute({
9807
+ maskAttributes,
9808
+ maskAllText,
9809
+ privacyOptions,
9810
+ key,
9811
+ value,
9812
+ el,
9813
+ }),
8566
9814
 
8567
- ...getPrivacyOptions({
8568
- mask,
8569
- unmask,
8570
- block,
8571
- unblock,
8572
- ignore,
8573
- blockClass,
8574
- blockSelector,
8575
- maskTextClass,
8576
- maskTextSelector,
8577
- ignoreClass,
8578
- }),
9815
+ ...privacyOptions,
8579
9816
 
8580
9817
  // Our defaults
8581
9818
  slimDOMOptions: 'all',
@@ -8585,6 +9822,16 @@ class Replay {
8585
9822
  // collect fonts, but be aware that `sentry.io` needs to be an allowed
8586
9823
  // origin for playback
8587
9824
  collectFonts: true,
9825
+ errorHandler: (err) => {
9826
+ try {
9827
+ // @ts-expect-error Set this so that replay SDK can ignore errors originating from rrweb
9828
+ err.__rrweb__ = true;
9829
+ } catch (e) {
9830
+ // avoid any potential hazards here
9831
+ }
9832
+ // return true to suppress throwing the error inside of rrweb
9833
+ return true;
9834
+ },
8588
9835
  };
8589
9836
 
8590
9837
  this._initialOptions = {