@appsurify-testmap/rrweb 2.1.0-alpha.3 → 2.1.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/rrweb.cjs CHANGED
@@ -892,32 +892,14 @@ function transformAttribute(doc, tagName, name, value) {
892
892
  }
893
893
  return value;
894
894
  }
895
- function isIgnoreAttribute(tagName, name, _value) {
895
+ function ignoreAttribute(tagName, name, _value) {
896
896
  return (tagName === "video" || tagName === "audio") && name === "autoplay";
897
897
  }
898
- function cleanAttributes(doc, element, ignoreAttribute) {
899
- const tagName = getValidTagName$1(element);
900
- const attributes = {};
901
- const len = element.attributes.length;
902
- for (let i2 = 0; i2 < len; i2++) {
903
- const attr = element.attributes[i2];
904
- const name = attr.name;
905
- const value = attr.value;
906
- const shouldIgnoreByName = typeof ignoreAttribute === "string" ? name === ignoreAttribute : ignoreAttribute.test(name);
907
- if (!shouldIgnoreByName && !isIgnoreAttribute(tagName, name)) {
908
- attributes[name] = transformAttribute(
909
- doc,
910
- tagName,
911
- toLowerCase(name),
912
- value
913
- );
914
- }
915
- }
916
- return attributes;
898
+ function isIncludeAttribute(name, include) {
899
+ return typeof include === "string" ? name.includes(include) : include.test(name);
917
900
  }
918
- function shouldIgnoreAttribute(ignore, name) {
919
- if (!ignore) return false;
920
- return typeof ignore === "string" ? name === ignore : ignore.test(name);
901
+ function isExcludeAttribute(name, exclude) {
902
+ return typeof exclude === "string" ? name.includes(exclude) : exclude.test(name);
921
903
  }
922
904
  function _isBlockedElement(element, blockClass, blockSelector) {
923
905
  try {
@@ -1048,7 +1030,8 @@ function serializeNode(n2, options) {
1048
1030
  mirror: mirror2,
1049
1031
  blockClass,
1050
1032
  blockSelector,
1051
- ignoreAttribute,
1033
+ excludeAttribute,
1034
+ includeAttribute,
1052
1035
  needsMask,
1053
1036
  inlineStylesheet,
1054
1037
  maskInputOptions = {},
@@ -1094,7 +1077,8 @@ function serializeNode(n2, options) {
1094
1077
  doc,
1095
1078
  blockClass,
1096
1079
  blockSelector,
1097
- ignoreAttribute,
1080
+ excludeAttribute,
1081
+ includeAttribute,
1098
1082
  inlineStylesheet,
1099
1083
  maskInputOptions,
1100
1084
  maskInputFn,
@@ -1172,7 +1156,8 @@ function serializeElementNode(n2, options) {
1172
1156
  doc,
1173
1157
  blockClass,
1174
1158
  blockSelector,
1175
- ignoreAttribute,
1159
+ excludeAttribute,
1160
+ includeAttribute,
1176
1161
  inlineStylesheet,
1177
1162
  maskInputOptions = {},
1178
1163
  maskInputFn,
@@ -1186,7 +1171,22 @@ function serializeElementNode(n2, options) {
1186
1171
  } = options;
1187
1172
  const needBlock = _isBlockedElement(n2, blockClass, blockSelector);
1188
1173
  const tagName = getValidTagName$1(n2);
1189
- let attributes = cleanAttributes(doc, n2, ignoreAttribute);
1174
+ let attributes = {};
1175
+ const len = n2.attributes.length;
1176
+ for (let i2 = 0; i2 < len; i2++) {
1177
+ const attr = n2.attributes[i2];
1178
+ if (isExcludeAttribute(attr.name, excludeAttribute) && !isIncludeAttribute(attr.name, includeAttribute)) {
1179
+ continue;
1180
+ }
1181
+ if (!ignoreAttribute(tagName, attr.name, attr.value)) {
1182
+ attributes[attr.name] = transformAttribute(
1183
+ doc,
1184
+ tagName,
1185
+ toLowerCase(attr.name),
1186
+ attr.value
1187
+ );
1188
+ }
1189
+ }
1190
1190
  if (tagName === "link" && inlineStylesheet) {
1191
1191
  const stylesheet = Array.from(doc.styleSheets).find((s2) => {
1192
1192
  return s2.href === n2.href;
@@ -1400,7 +1400,8 @@ function serializeNodeWithId(n2, options) {
1400
1400
  blockSelector,
1401
1401
  maskTextClass,
1402
1402
  maskTextSelector,
1403
- ignoreAttribute,
1403
+ excludeAttribute,
1404
+ includeAttribute,
1404
1405
  skipChild = false,
1405
1406
  inlineStylesheet = true,
1406
1407
  maskInputOptions = {},
@@ -1435,7 +1436,8 @@ function serializeNodeWithId(n2, options) {
1435
1436
  mirror: mirror2,
1436
1437
  blockClass,
1437
1438
  blockSelector,
1438
- ignoreAttribute,
1439
+ excludeAttribute,
1440
+ includeAttribute,
1439
1441
  needsMask,
1440
1442
  inlineStylesheet,
1441
1443
  maskInputOptions,
@@ -1488,7 +1490,8 @@ function serializeNodeWithId(n2, options) {
1488
1490
  needsMask,
1489
1491
  maskTextClass,
1490
1492
  maskTextSelector,
1491
- ignoreAttribute,
1493
+ excludeAttribute,
1494
+ includeAttribute,
1492
1495
  skipChild,
1493
1496
  inlineStylesheet,
1494
1497
  maskInputOptions,
@@ -1548,7 +1551,8 @@ function serializeNodeWithId(n2, options) {
1548
1551
  needsMask,
1549
1552
  maskTextClass,
1550
1553
  maskTextSelector,
1551
- ignoreAttribute,
1554
+ excludeAttribute,
1555
+ includeAttribute,
1552
1556
  skipChild: false,
1553
1557
  inlineStylesheet,
1554
1558
  maskInputOptions,
@@ -1590,7 +1594,8 @@ function serializeNodeWithId(n2, options) {
1590
1594
  needsMask,
1591
1595
  maskTextClass,
1592
1596
  maskTextSelector,
1593
- ignoreAttribute,
1597
+ excludeAttribute,
1598
+ includeAttribute,
1594
1599
  skipChild: false,
1595
1600
  inlineStylesheet,
1596
1601
  maskInputOptions,
@@ -1628,7 +1633,8 @@ function snapshot(n2, options) {
1628
1633
  blockSelector = null,
1629
1634
  maskTextClass = "rr-mask",
1630
1635
  maskTextSelector = null,
1631
- ignoreAttribute = "rr-ignore",
1636
+ excludeAttribute = /^$a/,
1637
+ includeAttribute = /.+/i,
1632
1638
  inlineStylesheet = true,
1633
1639
  inlineImages = false,
1634
1640
  recordCanvas = false,
@@ -1688,7 +1694,8 @@ function snapshot(n2, options) {
1688
1694
  blockSelector,
1689
1695
  maskTextClass,
1690
1696
  maskTextSelector,
1691
- ignoreAttribute,
1697
+ excludeAttribute,
1698
+ includeAttribute,
1692
1699
  skipChild: false,
1693
1700
  inlineStylesheet,
1694
1701
  maskInputOptions,
@@ -10924,7 +10931,7 @@ function hookSetter(target, key, d, isRevoked, win = window) {
10924
10931
  return () => hookSetter(target, key, original || {}, true);
10925
10932
  }
10926
10933
  function nowTimestamp() {
10927
- return performance.timeOrigin + performance.now();
10934
+ return Math.round(performance.timeOrigin + performance.now());
10928
10935
  }
10929
10936
  function getWindowScroll(win = window) {
10930
10937
  var _a2, _b, _c, _d;
@@ -11241,7 +11248,6 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {
11241
11248
  IncrementalSource2[IncrementalSource2["Selection"] = 14] = "Selection";
11242
11249
  IncrementalSource2[IncrementalSource2["AdoptedStyleSheet"] = 15] = "AdoptedStyleSheet";
11243
11250
  IncrementalSource2[IncrementalSource2["CustomElement"] = 16] = "CustomElement";
11244
- IncrementalSource2[IncrementalSource2["VisibilityChange"] = 17] = "VisibilityChange";
11245
11251
  return IncrementalSource2;
11246
11252
  })(IncrementalSource || {});
11247
11253
  var MouseInteractions = /* @__PURE__ */ ((MouseInteractions2) => {
@@ -11424,7 +11430,8 @@ class MutationBuffer {
11424
11430
  __publicField(this, "blockSelector");
11425
11431
  __publicField(this, "maskTextClass");
11426
11432
  __publicField(this, "maskTextSelector");
11427
- __publicField(this, "ignoreAttribute");
11433
+ __publicField(this, "excludeAttribute");
11434
+ __publicField(this, "includeAttribute");
11428
11435
  __publicField(this, "inlineStylesheet");
11429
11436
  __publicField(this, "maskInputOptions");
11430
11437
  __publicField(this, "maskTextFn");
@@ -11488,7 +11495,8 @@ class MutationBuffer {
11488
11495
  blockSelector: this.blockSelector,
11489
11496
  maskTextClass: this.maskTextClass,
11490
11497
  maskTextSelector: this.maskTextSelector,
11491
- ignoreAttribute: this.ignoreAttribute || "",
11498
+ excludeAttribute: this.excludeAttribute,
11499
+ includeAttribute: this.includeAttribute,
11492
11500
  skipChild: true,
11493
11501
  newlyAddedElement: true,
11494
11502
  inlineStylesheet: this.inlineStylesheet,
@@ -11608,21 +11616,6 @@ class MutationBuffer {
11608
11616
  };
11609
11617
  }).filter((text) => !addedIds.has(text.id)).filter((text) => this.mirror.has(text.id)),
11610
11618
  attributes: this.attributes.map((attribute) => {
11611
- const element = attribute.node;
11612
- const filtered = {};
11613
- for (const [name, value] of Object.entries(attribute.attributes)) {
11614
- const isIgnored2 = shouldIgnoreAttribute(this.ignoreAttribute, name);
11615
- const existedBefore = element.hasAttribute(name);
11616
- const keep = value !== null && !isIgnored2 || value === null && (!isIgnored2 || attribute.attributes[name] !== null || existedBefore);
11617
- if (keep) {
11618
- filtered[name] = value;
11619
- }
11620
- }
11621
- return {
11622
- ...attribute,
11623
- attributes: filtered
11624
- };
11625
- }).filter((attribute) => Object.keys(attribute.attributes).length > 0).map((attribute) => {
11626
11619
  const { attributes } = attribute;
11627
11620
  if (typeof attributes.style === "string") {
11628
11621
  const diffAsStr = JSON.stringify(attribute.styleDiff);
@@ -11704,8 +11697,13 @@ class MutationBuffer {
11704
11697
  case "attributes": {
11705
11698
  const target = m.target;
11706
11699
  let attributeName = m.attributeName;
11707
- let value = target.getAttribute(attributeName);
11708
- if (value === null && m.oldValue === null) {
11700
+ let value = m.target.getAttribute(attributeName);
11701
+ const propValue = target[attributeName];
11702
+ const isPhantomAttributeMutation = value === null && !target.hasAttribute(attributeName) && m.oldValue !== null && (propValue === "" || propValue === null || typeof propValue === "undefined");
11703
+ if (isPhantomAttributeMutation && !isIncludeAttribute(attributeName, this.includeAttribute)) {
11704
+ return;
11705
+ }
11706
+ if (isExcludeAttribute(attributeName, this.excludeAttribute)) {
11709
11707
  return;
11710
11708
  }
11711
11709
  if (attributeName === "value") {
@@ -11743,14 +11741,21 @@ class MutationBuffer {
11743
11741
  if (attributeName === "type" && target.tagName === "INPUT" && (m.oldValue || "").toLowerCase() === "password") {
11744
11742
  target.setAttribute("data-rr-is-password", "true");
11745
11743
  }
11746
- if (!isIgnoreAttribute(target.tagName, attributeName) && // eslint-disable-next-line @typescript-eslint/no-unsafe-call
11747
- !shouldIgnoreAttribute(this.ignoreAttribute, attributeName)) {
11744
+ if (!ignoreAttribute(target.tagName, attributeName)) {
11748
11745
  item.attributes[attributeName] = transformAttribute(
11749
11746
  this.doc,
11750
11747
  toLowerCase(target.tagName),
11751
11748
  toLowerCase(attributeName),
11752
11749
  value
11753
11750
  );
11751
+ if (value === item.attributes[attributeName] && !isIncludeAttribute(attributeName, this.includeAttribute)) {
11752
+ delete item.attributes[attributeName];
11753
+ if (Object.keys(item.attributes).length === 0) {
11754
+ this.attributes = this.attributes.filter((a2) => a2 !== item);
11755
+ this.attributeMap.delete(m.target);
11756
+ }
11757
+ return;
11758
+ }
11754
11759
  if (attributeName === "style") {
11755
11760
  if (!this.unattachedDoc) {
11756
11761
  try {
@@ -11866,7 +11871,8 @@ class MutationBuffer {
11866
11871
  "blockSelector",
11867
11872
  "maskTextClass",
11868
11873
  "maskTextSelector",
11869
- "ignoreAttribute",
11874
+ "excludeAttribute",
11875
+ "includeAttribute",
11870
11876
  "inlineStylesheet",
11871
11877
  "maskInputOptions",
11872
11878
  "maskTextFn",
@@ -12005,60 +12011,6 @@ function initMutationObserver(options, rootEl) {
12005
12011
  });
12006
12012
  return observer;
12007
12013
  }
12008
- function initVisibilityObserver({
12009
- visibilityChangeCb,
12010
- doc,
12011
- mirror: mirror2,
12012
- sampling
12013
- }) {
12014
- if (!visibilityChangeCb) {
12015
- return () => {
12016
- };
12017
- }
12018
- const observedElements = /* @__PURE__ */ new WeakMap();
12019
- const debounceThreshold = typeof sampling.visibility === "number" ? sampling.visibility : 50;
12020
- const throttledCb = throttle(
12021
- callbackWrapper((entry) => {
12022
- const target = entry.target;
12023
- const id = mirror2.getId(target);
12024
- const isVisible = entry.isIntersecting || entry.intersectionRatio > 0;
12025
- if (id !== -1) {
12026
- visibilityChangeCb({
12027
- id,
12028
- isVisible,
12029
- visibilityRatio: entry.intersectionRatio
12030
- });
12031
- }
12032
- }),
12033
- debounceThreshold,
12034
- { leading: sampling.visibility !== false, trailing: true }
12035
- );
12036
- const observer = new IntersectionObserver((entries) => {
12037
- entries.forEach((entry) => {
12038
- const target = entry.target;
12039
- if (observedElements.has(target)) {
12040
- throttledCb(entry);
12041
- } else {
12042
- observedElements.set(target, true);
12043
- }
12044
- });
12045
- }, { root: null, threshold: [0.1, 0.9] });
12046
- doc.querySelectorAll("*").forEach((el) => observer.observe(el));
12047
- const mutationObserver = new MutationObserver((mutations) => {
12048
- mutations.forEach((mutation) => {
12049
- mutation.addedNodes.forEach((node2) => {
12050
- if (node2 instanceof Element) {
12051
- observer.observe(node2);
12052
- }
12053
- });
12054
- });
12055
- });
12056
- mutationObserver.observe(doc, { childList: true, subtree: true });
12057
- return () => {
12058
- observer.disconnect();
12059
- mutationObserver.disconnect();
12060
- };
12061
- }
12062
12014
  function initMoveObserver({
12063
12015
  mousemoveCb,
12064
12016
  sampling,
@@ -12338,6 +12290,20 @@ function initInputObserver({
12338
12290
  }
12339
12291
  function cbWithDedup(target, v2) {
12340
12292
  const lastInputValue = lastInputValueMap.get(target);
12293
+ const el = target;
12294
+ const hasPlaceholder = el.hasAttribute("placeholder");
12295
+ const isEmpty = el.value === "";
12296
+ const isDefaultEmpty = typeof el.defaultValue === "string" ? el.defaultValue === "" : true;
12297
+ const isNonUser = !v2.userTriggered;
12298
+ const isRepeatEmpty = !lastInputValue || lastInputValue.text === "";
12299
+ const isLikelyPhantom = hasPlaceholder && isEmpty && isDefaultEmpty && isRepeatEmpty && isNonUser && !v2.isChecked && el.type !== "hidden" && INPUT_TAGS.includes(el.tagName);
12300
+ const isRenderDrivenTextInput = el.tagName === "INPUT" && el.type === "text" && !v2.userTriggered && v2.text === el.defaultValue && !lastInputValue && el.hasAttribute("placeholder");
12301
+ const isValueFromDefault = !v2.userTriggered && el.value === el.defaultValue && !lastInputValue && el.hasAttribute("placeholder") && !v2.isChecked && el.type !== "hidden" && INPUT_TAGS.includes(el.tagName);
12302
+ const isPhantomCheckbox = el.type === "checkbox" && !v2.userTriggered && !v2.isChecked && !lastInputValue;
12303
+ const isPhantomRadio = el.type === "radio" && !v2.userTriggered && !v2.isChecked && !lastInputValue;
12304
+ if (isLikelyPhantom || isRenderDrivenTextInput || isValueFromDefault || isPhantomCheckbox || isPhantomRadio) {
12305
+ return;
12306
+ }
12341
12307
  if (!lastInputValue || lastInputValue.text !== v2.text || lastInputValue.isChecked !== v2.isChecked) {
12342
12308
  lastInputValueMap.set(target, v2);
12343
12309
  const id = mirror2.getId(target);
@@ -12875,7 +12841,6 @@ function initCustomElementObserver({
12875
12841
  function mergeHooks(o2, hooks) {
12876
12842
  const {
12877
12843
  mutationCb,
12878
- visibilityChangeCb,
12879
12844
  mousemoveCb,
12880
12845
  mouseInteractionCb,
12881
12846
  scrollCb,
@@ -12895,12 +12860,6 @@ function mergeHooks(o2, hooks) {
12895
12860
  }
12896
12861
  mutationCb(...p);
12897
12862
  };
12898
- o2.visibilityChangeCb = (...p) => {
12899
- if (hooks.visibilityChange) {
12900
- hooks.visibilityChange(...p);
12901
- }
12902
- visibilityChangeCb(...p);
12903
- };
12904
12863
  o2.mousemoveCb = (...p) => {
12905
12864
  if (hooks.mousemove) {
12906
12865
  hooks.mousemove(...p);
@@ -12993,7 +12952,6 @@ function initObservers(o2, hooks = {}) {
12993
12952
  });
12994
12953
  const inputHandler = initInputObserver(o2);
12995
12954
  const mediaInteractionHandler = initMediaInteractionObserver(o2);
12996
- const visibleHandler = initVisibilityObserver(o2);
12997
12955
  let styleSheetObserver = () => {
12998
12956
  };
12999
12957
  let adoptedStyleSheetObserver = () => {
@@ -13023,7 +12981,6 @@ function initObservers(o2, hooks = {}) {
13023
12981
  return callbackWrapper(() => {
13024
12982
  mutationBuffers.forEach((b) => b.reset());
13025
12983
  mutationObserver == null ? void 0 : mutationObserver.disconnect();
13026
- visibleHandler();
13027
12984
  mousemoveHandler();
13028
12985
  mouseInteractionHandler();
13029
12986
  scrollHandler();
@@ -14094,6 +14051,7 @@ let wrappedEmit;
14094
14051
  let takeFullSnapshot$1;
14095
14052
  let canvasManager;
14096
14053
  let recording = false;
14054
+ const preRecordingCustomEvents = [];
14097
14055
  try {
14098
14056
  if (Array.from([1], (x2) => x2 * 2)[0] !== 2) {
14099
14057
  const cleanFrame = document.createElement("iframe");
@@ -14110,12 +14068,12 @@ function record(options = {}) {
14110
14068
  emit,
14111
14069
  checkoutEveryNms,
14112
14070
  checkoutEveryNth,
14113
- checkoutEveryEvc,
14114
14071
  blockClass = "rr-block",
14115
14072
  blockSelector = null,
14116
14073
  ignoreClass = "rr-ignore",
14117
14074
  ignoreSelector = null,
14118
- ignoreAttribute = "rr-ignore",
14075
+ excludeAttribute: _excludeAttribute,
14076
+ includeAttribute: _includeAttribute,
14119
14077
  maskTextClass = "rr-mask",
14120
14078
  maskTextSelector = null,
14121
14079
  inlineStylesheet = true,
@@ -14133,6 +14091,7 @@ function record(options = {}) {
14133
14091
  recordCanvas = false,
14134
14092
  recordCrossOriginIframes = false,
14135
14093
  recordAfter = options.recordAfter === "DOMContentLoaded" ? options.recordAfter : "load",
14094
+ flushCustomQueue = options.flushCustomQueue !== void 0 ? options.flushCustomQueue : "after",
14136
14095
  userTriggeredOnInput = false,
14137
14096
  collectFonts = false,
14138
14097
  inlineImages = false,
@@ -14164,6 +14123,8 @@ function record(options = {}) {
14164
14123
  sampling.mousemove = mousemoveWait;
14165
14124
  }
14166
14125
  mirror.reset();
14126
+ const excludeAttribute = _excludeAttribute === void 0 ? /^$a/ : _excludeAttribute;
14127
+ const includeAttribute = _includeAttribute === void 0 ? /.+/i : _includeAttribute;
14167
14128
  const maskInputOptions = maskAllInputs === true ? {
14168
14129
  color: true,
14169
14130
  date: true,
@@ -14240,8 +14201,7 @@ function record(options = {}) {
14240
14201
  incrementalSnapshotCount++;
14241
14202
  const exceedCount = checkoutEveryNth && incrementalSnapshotCount >= checkoutEveryNth;
14242
14203
  const exceedTime = checkoutEveryNms && e2.timestamp - lastFullSnapshotEvent.timestamp > checkoutEveryNms;
14243
- const isVisibilityChanged = checkoutEveryEvc && e2.type === EventType.IncrementalSnapshot && e2.data.source === IncrementalSource.VisibilityChange;
14244
- if (exceedCount || exceedTime || isVisibilityChanged) {
14204
+ if (exceedCount || exceedTime) {
14245
14205
  takeFullSnapshot$1(true);
14246
14206
  }
14247
14207
  }
@@ -14314,7 +14274,8 @@ function record(options = {}) {
14314
14274
  blockSelector,
14315
14275
  maskTextClass,
14316
14276
  maskTextSelector,
14317
- ignoreAttribute,
14277
+ excludeAttribute,
14278
+ includeAttribute,
14318
14279
  inlineStylesheet,
14319
14280
  maskInputOptions,
14320
14281
  dataURLOptions,
@@ -14356,7 +14317,8 @@ function record(options = {}) {
14356
14317
  blockSelector,
14357
14318
  maskTextClass,
14358
14319
  maskTextSelector,
14359
- ignoreAttribute,
14320
+ excludeAttribute,
14321
+ includeAttribute,
14360
14322
  inlineStylesheet,
14361
14323
  maskAllInputs: maskInputOptions,
14362
14324
  maskTextFn,
@@ -14412,15 +14374,6 @@ function record(options = {}) {
14412
14374
  return callbackWrapper(initObservers)(
14413
14375
  {
14414
14376
  mutationCb: wrappedMutationEmit,
14415
- visibilityChangeCb: (v2) => {
14416
- wrappedEmit({
14417
- type: EventType.IncrementalSnapshot,
14418
- data: {
14419
- source: IncrementalSource.VisibilityChange,
14420
- ...v2
14421
- }
14422
- });
14423
- },
14424
14377
  mousemoveCb: (positions, source) => wrappedEmit({
14425
14378
  type: EventType.IncrementalSnapshot,
14426
14379
  data: {
@@ -14502,7 +14455,8 @@ function record(options = {}) {
14502
14455
  ignoreSelector,
14503
14456
  maskTextClass,
14504
14457
  maskTextSelector,
14505
- ignoreAttribute,
14458
+ excludeAttribute,
14459
+ includeAttribute,
14506
14460
  maskInputOptions,
14507
14461
  inlineStylesheet,
14508
14462
  sampling,
@@ -14548,9 +14502,15 @@ function record(options = {}) {
14548
14502
  }
14549
14503
  });
14550
14504
  const init = () => {
14505
+ if (flushCustomQueue === "before") {
14506
+ flushPreRecordingEvents();
14507
+ }
14551
14508
  takeFullSnapshot$1();
14552
14509
  handlers.push(observe(document));
14553
14510
  recording = true;
14511
+ if (flushCustomQueue === "after") {
14512
+ flushPreRecordingEvents();
14513
+ }
14554
14514
  };
14555
14515
  if (document.readyState === "interactive" || document.readyState === "complete") {
14556
14516
  init();
@@ -14579,6 +14539,7 @@ function record(options = {}) {
14579
14539
  );
14580
14540
  }
14581
14541
  return () => {
14542
+ flushPreRecordingEvents();
14582
14543
  handlers.forEach((h) => h());
14583
14544
  processedNodeManager.destroy();
14584
14545
  recording = false;
@@ -14588,17 +14549,26 @@ function record(options = {}) {
14588
14549
  console.warn(error);
14589
14550
  }
14590
14551
  }
14591
- record.addCustomEvent = (tag, payload) => {
14592
- if (!recording) {
14593
- throw new Error("please add custom event after start recording");
14552
+ function flushPreRecordingEvents() {
14553
+ for (const e2 of preRecordingCustomEvents) {
14554
+ wrappedEmit(e2);
14594
14555
  }
14595
- wrappedEmit({
14556
+ preRecordingCustomEvents.length = 0;
14557
+ }
14558
+ record.addCustomEvent = (tag, payload) => {
14559
+ const customEvent = {
14596
14560
  type: EventType.Custom,
14597
14561
  data: {
14598
14562
  tag,
14599
14563
  payload
14600
14564
  }
14601
- });
14565
+ };
14566
+ if (!recording) {
14567
+ console.warn(`[rrweb] CustomEvent buffered before recording start: ${tag}`);
14568
+ preRecordingCustomEvents.push(customEvent);
14569
+ return;
14570
+ }
14571
+ wrappedEmit(customEvent);
14602
14572
  };
14603
14573
  record.freezePage = () => {
14604
14574
  mutationBuffers.forEach((buf) => buf.freeze());