@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.
@@ -939,32 +939,14 @@ function transformAttribute(doc, tagName, name, value) {
939
939
  }
940
940
  return value;
941
941
  }
942
- function isIgnoreAttribute(tagName, name, _value) {
942
+ function ignoreAttribute(tagName, name, _value) {
943
943
  return (tagName === "video" || tagName === "audio") && name === "autoplay";
944
944
  }
945
- function cleanAttributes(doc, element, ignoreAttribute) {
946
- const tagName = getValidTagName$1(element);
947
- const attributes = {};
948
- const len = element.attributes.length;
949
- for (let i2 = 0; i2 < len; i2++) {
950
- const attr = element.attributes[i2];
951
- const name = attr.name;
952
- const value = attr.value;
953
- const shouldIgnoreByName = typeof ignoreAttribute === "string" ? name === ignoreAttribute : ignoreAttribute.test(name);
954
- if (!shouldIgnoreByName && !isIgnoreAttribute(tagName, name)) {
955
- attributes[name] = transformAttribute(
956
- doc,
957
- tagName,
958
- toLowerCase(name),
959
- value
960
- );
961
- }
962
- }
963
- return attributes;
945
+ function isIncludeAttribute(name, include) {
946
+ return typeof include === "string" ? name.includes(include) : include.test(name);
964
947
  }
965
- function shouldIgnoreAttribute(ignore, name) {
966
- if (!ignore) return false;
967
- return typeof ignore === "string" ? name === ignore : ignore.test(name);
948
+ function isExcludeAttribute(name, exclude) {
949
+ return typeof exclude === "string" ? name.includes(exclude) : exclude.test(name);
968
950
  }
969
951
  function _isBlockedElement(element, blockClass, blockSelector) {
970
952
  try {
@@ -1095,7 +1077,8 @@ function serializeNode(n2, options) {
1095
1077
  mirror: mirror2,
1096
1078
  blockClass,
1097
1079
  blockSelector,
1098
- ignoreAttribute,
1080
+ excludeAttribute,
1081
+ includeAttribute,
1099
1082
  needsMask,
1100
1083
  inlineStylesheet,
1101
1084
  maskInputOptions = {},
@@ -1141,7 +1124,8 @@ function serializeNode(n2, options) {
1141
1124
  doc,
1142
1125
  blockClass,
1143
1126
  blockSelector,
1144
- ignoreAttribute,
1127
+ excludeAttribute,
1128
+ includeAttribute,
1145
1129
  inlineStylesheet,
1146
1130
  maskInputOptions,
1147
1131
  maskInputFn,
@@ -1219,7 +1203,8 @@ function serializeElementNode(n2, options) {
1219
1203
  doc,
1220
1204
  blockClass,
1221
1205
  blockSelector,
1222
- ignoreAttribute,
1206
+ excludeAttribute,
1207
+ includeAttribute,
1223
1208
  inlineStylesheet,
1224
1209
  maskInputOptions = {},
1225
1210
  maskInputFn,
@@ -1233,7 +1218,22 @@ function serializeElementNode(n2, options) {
1233
1218
  } = options;
1234
1219
  const needBlock = _isBlockedElement(n2, blockClass, blockSelector);
1235
1220
  const tagName = getValidTagName$1(n2);
1236
- let attributes = cleanAttributes(doc, n2, ignoreAttribute);
1221
+ let attributes = {};
1222
+ const len = n2.attributes.length;
1223
+ for (let i2 = 0; i2 < len; i2++) {
1224
+ const attr = n2.attributes[i2];
1225
+ if (isExcludeAttribute(attr.name, excludeAttribute) && !isIncludeAttribute(attr.name, includeAttribute)) {
1226
+ continue;
1227
+ }
1228
+ if (!ignoreAttribute(tagName, attr.name, attr.value)) {
1229
+ attributes[attr.name] = transformAttribute(
1230
+ doc,
1231
+ tagName,
1232
+ toLowerCase(attr.name),
1233
+ attr.value
1234
+ );
1235
+ }
1236
+ }
1237
1237
  if (tagName === "link" && inlineStylesheet) {
1238
1238
  const stylesheet = Array.from(doc.styleSheets).find((s2) => {
1239
1239
  return s2.href === n2.href;
@@ -1447,7 +1447,8 @@ function serializeNodeWithId(n2, options) {
1447
1447
  blockSelector,
1448
1448
  maskTextClass,
1449
1449
  maskTextSelector,
1450
- ignoreAttribute,
1450
+ excludeAttribute,
1451
+ includeAttribute,
1451
1452
  skipChild = false,
1452
1453
  inlineStylesheet = true,
1453
1454
  maskInputOptions = {},
@@ -1482,7 +1483,8 @@ function serializeNodeWithId(n2, options) {
1482
1483
  mirror: mirror2,
1483
1484
  blockClass,
1484
1485
  blockSelector,
1485
- ignoreAttribute,
1486
+ excludeAttribute,
1487
+ includeAttribute,
1486
1488
  needsMask,
1487
1489
  inlineStylesheet,
1488
1490
  maskInputOptions,
@@ -1535,7 +1537,8 @@ function serializeNodeWithId(n2, options) {
1535
1537
  needsMask,
1536
1538
  maskTextClass,
1537
1539
  maskTextSelector,
1538
- ignoreAttribute,
1540
+ excludeAttribute,
1541
+ includeAttribute,
1539
1542
  skipChild,
1540
1543
  inlineStylesheet,
1541
1544
  maskInputOptions,
@@ -1595,7 +1598,8 @@ function serializeNodeWithId(n2, options) {
1595
1598
  needsMask,
1596
1599
  maskTextClass,
1597
1600
  maskTextSelector,
1598
- ignoreAttribute,
1601
+ excludeAttribute,
1602
+ includeAttribute,
1599
1603
  skipChild: false,
1600
1604
  inlineStylesheet,
1601
1605
  maskInputOptions,
@@ -1637,7 +1641,8 @@ function serializeNodeWithId(n2, options) {
1637
1641
  needsMask,
1638
1642
  maskTextClass,
1639
1643
  maskTextSelector,
1640
- ignoreAttribute,
1644
+ excludeAttribute,
1645
+ includeAttribute,
1641
1646
  skipChild: false,
1642
1647
  inlineStylesheet,
1643
1648
  maskInputOptions,
@@ -1675,7 +1680,8 @@ function snapshot(n2, options) {
1675
1680
  blockSelector = null,
1676
1681
  maskTextClass = "rr-mask",
1677
1682
  maskTextSelector = null,
1678
- ignoreAttribute = "rr-ignore",
1683
+ excludeAttribute = /^$a/,
1684
+ includeAttribute = /.+/i,
1679
1685
  inlineStylesheet = true,
1680
1686
  inlineImages = false,
1681
1687
  recordCanvas = false,
@@ -1735,7 +1741,8 @@ function snapshot(n2, options) {
1735
1741
  blockSelector,
1736
1742
  maskTextClass,
1737
1743
  maskTextSelector,
1738
- ignoreAttribute,
1744
+ excludeAttribute,
1745
+ includeAttribute,
1739
1746
  skipChild: false,
1740
1747
  inlineStylesheet,
1741
1748
  maskInputOptions,
@@ -10979,7 +10986,7 @@ function hookSetter(target, key, d, isRevoked, win = window) {
10979
10986
  return () => hookSetter(target, key, original || {}, true);
10980
10987
  }
10981
10988
  function nowTimestamp() {
10982
- return performance.timeOrigin + performance.now();
10989
+ return Math.round(performance.timeOrigin + performance.now());
10983
10990
  }
10984
10991
  function getWindowScroll(win = window) {
10985
10992
  var _a2, _b, _c, _d;
@@ -11297,7 +11304,6 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {
11297
11304
  IncrementalSource2[IncrementalSource2["Selection"] = 14] = "Selection";
11298
11305
  IncrementalSource2[IncrementalSource2["AdoptedStyleSheet"] = 15] = "AdoptedStyleSheet";
11299
11306
  IncrementalSource2[IncrementalSource2["CustomElement"] = 16] = "CustomElement";
11300
- IncrementalSource2[IncrementalSource2["VisibilityChange"] = 17] = "VisibilityChange";
11301
11307
  return IncrementalSource2;
11302
11308
  })(IncrementalSource || {});
11303
11309
  var MouseInteractions = /* @__PURE__ */ ((MouseInteractions2) => {
@@ -11463,7 +11469,8 @@ class MutationBuffer {
11463
11469
  __publicField(this, "blockSelector");
11464
11470
  __publicField(this, "maskTextClass");
11465
11471
  __publicField(this, "maskTextSelector");
11466
- __publicField(this, "ignoreAttribute");
11472
+ __publicField(this, "excludeAttribute");
11473
+ __publicField(this, "includeAttribute");
11467
11474
  __publicField(this, "inlineStylesheet");
11468
11475
  __publicField(this, "maskInputOptions");
11469
11476
  __publicField(this, "maskTextFn");
@@ -11527,7 +11534,8 @@ class MutationBuffer {
11527
11534
  blockSelector: this.blockSelector,
11528
11535
  maskTextClass: this.maskTextClass,
11529
11536
  maskTextSelector: this.maskTextSelector,
11530
- ignoreAttribute: this.ignoreAttribute || "",
11537
+ excludeAttribute: this.excludeAttribute,
11538
+ includeAttribute: this.includeAttribute,
11531
11539
  skipChild: true,
11532
11540
  newlyAddedElement: true,
11533
11541
  inlineStylesheet: this.inlineStylesheet,
@@ -11647,20 +11655,6 @@ class MutationBuffer {
11647
11655
  };
11648
11656
  }).filter((text) => !addedIds.has(text.id)).filter((text) => this.mirror.has(text.id)),
11649
11657
  attributes: this.attributes.map((attribute) => {
11650
- const element = attribute.node;
11651
- const filtered = {};
11652
- for (const [name, value] of Object.entries(attribute.attributes)) {
11653
- const isIgnored2 = shouldIgnoreAttribute(this.ignoreAttribute, name);
11654
- const existedBefore = element.hasAttribute(name);
11655
- const keep = value !== null && !isIgnored2 || value === null && (!isIgnored2 || attribute.attributes[name] !== null || existedBefore);
11656
- if (keep) {
11657
- filtered[name] = value;
11658
- }
11659
- }
11660
- return __spreadProps(__spreadValues({}, attribute), {
11661
- attributes: filtered
11662
- });
11663
- }).filter((attribute) => Object.keys(attribute.attributes).length > 0).map((attribute) => {
11664
11658
  const { attributes } = attribute;
11665
11659
  if (typeof attributes.style === "string") {
11666
11660
  const diffAsStr = JSON.stringify(attribute.styleDiff);
@@ -11742,8 +11736,13 @@ class MutationBuffer {
11742
11736
  case "attributes": {
11743
11737
  const target = m.target;
11744
11738
  let attributeName = m.attributeName;
11745
- let value = target.getAttribute(attributeName);
11746
- if (value === null && m.oldValue === null) {
11739
+ let value = m.target.getAttribute(attributeName);
11740
+ const propValue = target[attributeName];
11741
+ const isPhantomAttributeMutation = value === null && !target.hasAttribute(attributeName) && m.oldValue !== null && (propValue === "" || propValue === null || typeof propValue === "undefined");
11742
+ if (isPhantomAttributeMutation && !isIncludeAttribute(attributeName, this.includeAttribute)) {
11743
+ return;
11744
+ }
11745
+ if (isExcludeAttribute(attributeName, this.excludeAttribute)) {
11747
11746
  return;
11748
11747
  }
11749
11748
  if (attributeName === "value") {
@@ -11781,14 +11780,21 @@ class MutationBuffer {
11781
11780
  if (attributeName === "type" && target.tagName === "INPUT" && (m.oldValue || "").toLowerCase() === "password") {
11782
11781
  target.setAttribute("data-rr-is-password", "true");
11783
11782
  }
11784
- if (!isIgnoreAttribute(target.tagName, attributeName) && // eslint-disable-next-line @typescript-eslint/no-unsafe-call
11785
- !shouldIgnoreAttribute(this.ignoreAttribute, attributeName)) {
11783
+ if (!ignoreAttribute(target.tagName, attributeName)) {
11786
11784
  item.attributes[attributeName] = transformAttribute(
11787
11785
  this.doc,
11788
11786
  toLowerCase(target.tagName),
11789
11787
  toLowerCase(attributeName),
11790
11788
  value
11791
11789
  );
11790
+ if (value === item.attributes[attributeName] && !isIncludeAttribute(attributeName, this.includeAttribute)) {
11791
+ delete item.attributes[attributeName];
11792
+ if (Object.keys(item.attributes).length === 0) {
11793
+ this.attributes = this.attributes.filter((a2) => a2 !== item);
11794
+ this.attributeMap.delete(m.target);
11795
+ }
11796
+ return;
11797
+ }
11792
11798
  if (attributeName === "style") {
11793
11799
  if (!this.unattachedDoc) {
11794
11800
  try {
@@ -11901,7 +11907,8 @@ class MutationBuffer {
11901
11907
  "blockSelector",
11902
11908
  "maskTextClass",
11903
11909
  "maskTextSelector",
11904
- "ignoreAttribute",
11910
+ "excludeAttribute",
11911
+ "includeAttribute",
11905
11912
  "inlineStylesheet",
11906
11913
  "maskInputOptions",
11907
11914
  "maskTextFn",
@@ -12040,60 +12047,6 @@ function initMutationObserver(options, rootEl) {
12040
12047
  });
12041
12048
  return observer;
12042
12049
  }
12043
- function initVisibilityObserver({
12044
- visibilityChangeCb,
12045
- doc,
12046
- mirror: mirror2,
12047
- sampling
12048
- }) {
12049
- if (!visibilityChangeCb) {
12050
- return () => {
12051
- };
12052
- }
12053
- const observedElements = /* @__PURE__ */ new WeakMap();
12054
- const debounceThreshold = typeof sampling.visibility === "number" ? sampling.visibility : 50;
12055
- const throttledCb = throttle(
12056
- callbackWrapper((entry) => {
12057
- const target = entry.target;
12058
- const id = mirror2.getId(target);
12059
- const isVisible = entry.isIntersecting || entry.intersectionRatio > 0;
12060
- if (id !== -1) {
12061
- visibilityChangeCb({
12062
- id,
12063
- isVisible,
12064
- visibilityRatio: entry.intersectionRatio
12065
- });
12066
- }
12067
- }),
12068
- debounceThreshold,
12069
- { leading: sampling.visibility !== false, trailing: true }
12070
- );
12071
- const observer = new IntersectionObserver((entries) => {
12072
- entries.forEach((entry) => {
12073
- const target = entry.target;
12074
- if (observedElements.has(target)) {
12075
- throttledCb(entry);
12076
- } else {
12077
- observedElements.set(target, true);
12078
- }
12079
- });
12080
- }, { root: null, threshold: [0.1, 0.9] });
12081
- doc.querySelectorAll("*").forEach((el) => observer.observe(el));
12082
- const mutationObserver = new MutationObserver((mutations) => {
12083
- mutations.forEach((mutation) => {
12084
- mutation.addedNodes.forEach((node2) => {
12085
- if (node2 instanceof Element) {
12086
- observer.observe(node2);
12087
- }
12088
- });
12089
- });
12090
- });
12091
- mutationObserver.observe(doc, { childList: true, subtree: true });
12092
- return () => {
12093
- observer.disconnect();
12094
- mutationObserver.disconnect();
12095
- };
12096
- }
12097
12050
  function initMoveObserver({
12098
12051
  mousemoveCb,
12099
12052
  sampling,
@@ -12372,6 +12325,20 @@ function initInputObserver({
12372
12325
  }
12373
12326
  function cbWithDedup(target, v2) {
12374
12327
  const lastInputValue = lastInputValueMap.get(target);
12328
+ const el = target;
12329
+ const hasPlaceholder = el.hasAttribute("placeholder");
12330
+ const isEmpty = el.value === "";
12331
+ const isDefaultEmpty = typeof el.defaultValue === "string" ? el.defaultValue === "" : true;
12332
+ const isNonUser = !v2.userTriggered;
12333
+ const isRepeatEmpty = !lastInputValue || lastInputValue.text === "";
12334
+ const isLikelyPhantom = hasPlaceholder && isEmpty && isDefaultEmpty && isRepeatEmpty && isNonUser && !v2.isChecked && el.type !== "hidden" && INPUT_TAGS.includes(el.tagName);
12335
+ const isRenderDrivenTextInput = el.tagName === "INPUT" && el.type === "text" && !v2.userTriggered && v2.text === el.defaultValue && !lastInputValue && el.hasAttribute("placeholder");
12336
+ const isValueFromDefault = !v2.userTriggered && el.value === el.defaultValue && !lastInputValue && el.hasAttribute("placeholder") && !v2.isChecked && el.type !== "hidden" && INPUT_TAGS.includes(el.tagName);
12337
+ const isPhantomCheckbox = el.type === "checkbox" && !v2.userTriggered && !v2.isChecked && !lastInputValue;
12338
+ const isPhantomRadio = el.type === "radio" && !v2.userTriggered && !v2.isChecked && !lastInputValue;
12339
+ if (isLikelyPhantom || isRenderDrivenTextInput || isValueFromDefault || isPhantomCheckbox || isPhantomRadio) {
12340
+ return;
12341
+ }
12375
12342
  if (!lastInputValue || lastInputValue.text !== v2.text || lastInputValue.isChecked !== v2.isChecked) {
12376
12343
  lastInputValueMap.set(target, v2);
12377
12344
  const id = mirror2.getId(target);
@@ -12908,7 +12875,6 @@ function initCustomElementObserver({
12908
12875
  function mergeHooks(o2, hooks) {
12909
12876
  const {
12910
12877
  mutationCb,
12911
- visibilityChangeCb,
12912
12878
  mousemoveCb,
12913
12879
  mouseInteractionCb,
12914
12880
  scrollCb,
@@ -12928,12 +12894,6 @@ function mergeHooks(o2, hooks) {
12928
12894
  }
12929
12895
  mutationCb(...p);
12930
12896
  };
12931
- o2.visibilityChangeCb = (...p) => {
12932
- if (hooks.visibilityChange) {
12933
- hooks.visibilityChange(...p);
12934
- }
12935
- visibilityChangeCb(...p);
12936
- };
12937
12897
  o2.mousemoveCb = (...p) => {
12938
12898
  if (hooks.mousemove) {
12939
12899
  hooks.mousemove(...p);
@@ -13026,7 +12986,6 @@ function initObservers(o2, hooks = {}) {
13026
12986
  });
13027
12987
  const inputHandler = initInputObserver(o2);
13028
12988
  const mediaInteractionHandler = initMediaInteractionObserver(o2);
13029
- const visibleHandler = initVisibilityObserver(o2);
13030
12989
  let styleSheetObserver = () => {
13031
12990
  };
13032
12991
  let adoptedStyleSheetObserver = () => {
@@ -13056,7 +13015,6 @@ function initObservers(o2, hooks = {}) {
13056
13015
  return callbackWrapper(() => {
13057
13016
  mutationBuffers.forEach((b) => b.reset());
13058
13017
  mutationObserver == null ? void 0 : mutationObserver.disconnect();
13059
- visibleHandler();
13060
13018
  mousemoveHandler();
13061
13019
  mouseInteractionHandler();
13062
13020
  scrollHandler();
@@ -14125,6 +14083,7 @@ let wrappedEmit;
14125
14083
  let takeFullSnapshot$1;
14126
14084
  let canvasManager;
14127
14085
  let recording = false;
14086
+ const preRecordingCustomEvents = [];
14128
14087
  try {
14129
14088
  if (Array.from([1], (x2) => x2 * 2)[0] !== 2) {
14130
14089
  const cleanFrame = document.createElement("iframe");
@@ -14141,12 +14100,12 @@ function record(options = {}) {
14141
14100
  emit,
14142
14101
  checkoutEveryNms,
14143
14102
  checkoutEveryNth,
14144
- checkoutEveryEvc,
14145
14103
  blockClass = "rr-block",
14146
14104
  blockSelector = null,
14147
14105
  ignoreClass = "rr-ignore",
14148
14106
  ignoreSelector = null,
14149
- ignoreAttribute = "rr-ignore",
14107
+ excludeAttribute: _excludeAttribute,
14108
+ includeAttribute: _includeAttribute,
14150
14109
  maskTextClass = "rr-mask",
14151
14110
  maskTextSelector = null,
14152
14111
  inlineStylesheet = true,
@@ -14164,6 +14123,7 @@ function record(options = {}) {
14164
14123
  recordCanvas = false,
14165
14124
  recordCrossOriginIframes = false,
14166
14125
  recordAfter = options.recordAfter === "DOMContentLoaded" ? options.recordAfter : "load",
14126
+ flushCustomQueue = options.flushCustomQueue !== void 0 ? options.flushCustomQueue : "after",
14167
14127
  userTriggeredOnInput = false,
14168
14128
  collectFonts = false,
14169
14129
  inlineImages = false,
@@ -14195,6 +14155,8 @@ function record(options = {}) {
14195
14155
  sampling.mousemove = mousemoveWait;
14196
14156
  }
14197
14157
  mirror.reset();
14158
+ const excludeAttribute = _excludeAttribute === void 0 ? /^$a/ : _excludeAttribute;
14159
+ const includeAttribute = _includeAttribute === void 0 ? /.+/i : _includeAttribute;
14198
14160
  const maskInputOptions = maskAllInputs === true ? {
14199
14161
  color: true,
14200
14162
  date: true,
@@ -14271,8 +14233,7 @@ function record(options = {}) {
14271
14233
  incrementalSnapshotCount++;
14272
14234
  const exceedCount = checkoutEveryNth && incrementalSnapshotCount >= checkoutEveryNth;
14273
14235
  const exceedTime = checkoutEveryNms && e2.timestamp - lastFullSnapshotEvent.timestamp > checkoutEveryNms;
14274
- const isVisibilityChanged = checkoutEveryEvc && e2.type === EventType.IncrementalSnapshot && e2.data.source === IncrementalSource.VisibilityChange;
14275
- if (exceedCount || exceedTime || isVisibilityChanged) {
14236
+ if (exceedCount || exceedTime) {
14276
14237
  takeFullSnapshot$1(true);
14277
14238
  }
14278
14239
  }
@@ -14341,7 +14302,8 @@ function record(options = {}) {
14341
14302
  blockSelector,
14342
14303
  maskTextClass,
14343
14304
  maskTextSelector,
14344
- ignoreAttribute,
14305
+ excludeAttribute,
14306
+ includeAttribute,
14345
14307
  inlineStylesheet,
14346
14308
  maskInputOptions,
14347
14309
  dataURLOptions,
@@ -14383,7 +14345,8 @@ function record(options = {}) {
14383
14345
  blockSelector,
14384
14346
  maskTextClass,
14385
14347
  maskTextSelector,
14386
- ignoreAttribute,
14348
+ excludeAttribute,
14349
+ includeAttribute,
14387
14350
  inlineStylesheet,
14388
14351
  maskAllInputs: maskInputOptions,
14389
14352
  maskTextFn,
@@ -14439,14 +14402,6 @@ function record(options = {}) {
14439
14402
  return callbackWrapper(initObservers)(
14440
14403
  {
14441
14404
  mutationCb: wrappedMutationEmit,
14442
- visibilityChangeCb: (v2) => {
14443
- wrappedEmit({
14444
- type: EventType.IncrementalSnapshot,
14445
- data: __spreadValues({
14446
- source: IncrementalSource.VisibilityChange
14447
- }, v2)
14448
- });
14449
- },
14450
14405
  mousemoveCb: (positions, source) => wrappedEmit({
14451
14406
  type: EventType.IncrementalSnapshot,
14452
14407
  data: {
@@ -14519,7 +14474,8 @@ function record(options = {}) {
14519
14474
  ignoreSelector,
14520
14475
  maskTextClass,
14521
14476
  maskTextSelector,
14522
- ignoreAttribute,
14477
+ excludeAttribute,
14478
+ includeAttribute,
14523
14479
  maskInputOptions,
14524
14480
  inlineStylesheet,
14525
14481
  sampling,
@@ -14565,9 +14521,15 @@ function record(options = {}) {
14565
14521
  }
14566
14522
  });
14567
14523
  const init = () => {
14524
+ if (flushCustomQueue === "before") {
14525
+ flushPreRecordingEvents();
14526
+ }
14568
14527
  takeFullSnapshot$1();
14569
14528
  handlers.push(observe(document));
14570
14529
  recording = true;
14530
+ if (flushCustomQueue === "after") {
14531
+ flushPreRecordingEvents();
14532
+ }
14571
14533
  };
14572
14534
  if (document.readyState === "interactive" || document.readyState === "complete") {
14573
14535
  init();
@@ -14596,6 +14558,7 @@ function record(options = {}) {
14596
14558
  );
14597
14559
  }
14598
14560
  return () => {
14561
+ flushPreRecordingEvents();
14599
14562
  handlers.forEach((h) => h());
14600
14563
  processedNodeManager.destroy();
14601
14564
  recording = false;
@@ -14605,17 +14568,26 @@ function record(options = {}) {
14605
14568
  console.warn(error);
14606
14569
  }
14607
14570
  }
14608
- record.addCustomEvent = (tag, payload) => {
14609
- if (!recording) {
14610
- throw new Error("please add custom event after start recording");
14571
+ function flushPreRecordingEvents() {
14572
+ for (const e2 of preRecordingCustomEvents) {
14573
+ wrappedEmit(e2);
14611
14574
  }
14612
- wrappedEmit({
14575
+ preRecordingCustomEvents.length = 0;
14576
+ }
14577
+ record.addCustomEvent = (tag, payload) => {
14578
+ const customEvent = {
14613
14579
  type: EventType.Custom,
14614
14580
  data: {
14615
14581
  tag,
14616
14582
  payload
14617
14583
  }
14618
- });
14584
+ };
14585
+ if (!recording) {
14586
+ console.warn(`[rrweb] CustomEvent buffered before recording start: ${tag}`);
14587
+ preRecordingCustomEvents.push(customEvent);
14588
+ return;
14589
+ }
14590
+ wrappedEmit(customEvent);
14619
14591
  };
14620
14592
  record.freezePage = () => {
14621
14593
  mutationBuffers.forEach((buf) => buf.freeze());