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