mixpanel-browser 2.68.0 → 2.69.0

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.
@@ -483,6 +483,30 @@ function querySelectorAll$1(n2, selectors) {
483
483
  function mutationObserverCtor$1() {
484
484
  return getUntaintedPrototype$1("MutationObserver").constructor;
485
485
  }
486
+ function patch$1(source, name, replacement) {
487
+ try {
488
+ if (!(name in source)) {
489
+ return function() {};
490
+ }
491
+ var original = source[name];
492
+ var wrapped = replacement(original);
493
+ if (typeof wrapped === "function") {
494
+ wrapped.prototype = wrapped.prototype || {};
495
+ Object.defineProperties(wrapped, {
496
+ __rrweb_original__: {
497
+ enumerable: false,
498
+ value: original
499
+ }
500
+ });
501
+ }
502
+ source[name] = wrapped;
503
+ return function() {
504
+ source[name] = original;
505
+ };
506
+ } catch (e) {
507
+ return function() {};
508
+ }
509
+ }
486
510
  var index$1 = {
487
511
  childNodes: childNodes$1,
488
512
  parentNode: parentNode$1,
@@ -495,7 +519,8 @@ var index$1 = {
495
519
  shadowRoot: shadowRoot$1,
496
520
  querySelector: querySelector$1,
497
521
  querySelectorAll: querySelectorAll$1,
498
- mutationObserver: mutationObserverCtor$1
522
+ mutationObserver: mutationObserverCtor$1,
523
+ patch: patch$1
499
524
  };
500
525
  function isElement(n2) {
501
526
  return n2.nodeType === n2.ELEMENT_NODE;
@@ -746,26 +771,82 @@ function absolutifyURLs(cssText, href) {
746
771
  return "url(" + maybeQuote + stack.join("/") + maybeQuote + ")";
747
772
  });
748
773
  }
749
- function normalizeCssString(cssText) {
750
- return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
774
+ function normalizeCssString(cssText, _testNoPxNorm) {
775
+ if (_testNoPxNorm === void 0) _testNoPxNorm = false;
776
+ if (_testNoPxNorm) {
777
+ return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
778
+ } else {
779
+ return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "").replace(/0px/g, "0");
780
+ }
751
781
  }
752
- function splitCssText(cssText, style) {
782
+ function splitCssText(cssText, style, _testNoPxNorm) {
783
+ if (_testNoPxNorm === void 0) _testNoPxNorm = false;
753
784
  var childNodes2 = Array.from(style.childNodes);
754
785
  var splits = [];
786
+ var iterCount = 0;
755
787
  if (childNodes2.length > 1 && cssText && typeof cssText === "string") {
756
- var cssTextNorm = normalizeCssString(cssText);
788
+ var cssTextNorm = normalizeCssString(cssText, _testNoPxNorm);
789
+ var normFactor = cssTextNorm.length / cssText.length;
757
790
  for(var i2 = 1; i2 < childNodes2.length; i2++){
758
791
  if (childNodes2[i2].textContent && typeof childNodes2[i2].textContent === "string") {
759
- var textContentNorm = normalizeCssString(childNodes2[i2].textContent);
760
- for(var j = 3; j < textContentNorm.length; j++){
761
- var bit = textContentNorm.substring(0, j);
762
- if (cssTextNorm.split(bit).length === 2) {
763
- var splitNorm = cssTextNorm.indexOf(bit);
764
- for(var k = splitNorm; k < cssText.length; k++){
765
- if (normalizeCssString(cssText.substring(0, k)).length === splitNorm) {
792
+ var textContentNorm = normalizeCssString(childNodes2[i2].textContent, _testNoPxNorm);
793
+ var jLimit = 100;
794
+ var j = 3;
795
+ for(; j < textContentNorm.length; j++){
796
+ if (// keep consuming css identifiers (to get a decent chunk more quickly)
797
+ textContentNorm[j].match(/[a-zA-Z0-9]/) || // substring needs to be unique to this section
798
+ textContentNorm.indexOf(textContentNorm.substring(0, j), 1) !== -1) {
799
+ continue;
800
+ }
801
+ break;
802
+ }
803
+ for(; j < textContentNorm.length; j++){
804
+ var startSubstring = textContentNorm.substring(0, j);
805
+ var cssNormSplits = cssTextNorm.split(startSubstring);
806
+ var splitNorm = -1;
807
+ if (cssNormSplits.length === 2) {
808
+ splitNorm = cssNormSplits[0].length;
809
+ } else if (cssNormSplits.length > 2 && cssNormSplits[0] === "" && childNodes2[i2 - 1].textContent !== "") {
810
+ splitNorm = cssTextNorm.indexOf(startSubstring, 1);
811
+ } else if (cssNormSplits.length === 1) {
812
+ startSubstring = startSubstring.substring(0, startSubstring.length - 1);
813
+ cssNormSplits = cssTextNorm.split(startSubstring);
814
+ if (cssNormSplits.length <= 1) {
815
+ splits.push(cssText);
816
+ return splits;
817
+ }
818
+ j = jLimit + 1;
819
+ } else if (j === textContentNorm.length - 1) {
820
+ splitNorm = cssTextNorm.indexOf(startSubstring);
821
+ }
822
+ if (cssNormSplits.length >= 2 && j > jLimit) {
823
+ var prevTextContent = childNodes2[i2 - 1].textContent;
824
+ if (prevTextContent && typeof prevTextContent === "string") {
825
+ var prevMinLength = normalizeCssString(prevTextContent).length;
826
+ splitNorm = cssTextNorm.indexOf(startSubstring, prevMinLength);
827
+ }
828
+ if (splitNorm === -1) {
829
+ splitNorm = cssNormSplits[0].length;
830
+ }
831
+ }
832
+ if (splitNorm !== -1) {
833
+ var k = Math.floor(splitNorm / normFactor);
834
+ for(; k > 0 && k < cssText.length;){
835
+ iterCount += 1;
836
+ if (iterCount > 50 * childNodes2.length) {
837
+ splits.push(cssText);
838
+ return splits;
839
+ }
840
+ var normPart = normalizeCssString(cssText.substring(0, k), _testNoPxNorm);
841
+ if (normPart.length === splitNorm) {
766
842
  splits.push(cssText.substring(0, k));
767
843
  cssText = cssText.substring(k);
844
+ cssTextNorm = cssTextNorm.substring(splitNorm);
768
845
  break;
846
+ } else if (normPart.length < splitNorm) {
847
+ k += Math.max(1, Math.floor((splitNorm - normPart.length) / normFactor));
848
+ } else {
849
+ k -= Math.max(1, Math.floor((normPart.length - splitNorm) * normFactor));
769
850
  }
770
851
  }
771
852
  break;
@@ -1282,7 +1363,7 @@ function slimDOMExcluded(sn, slimDOMOptions) {
1282
1363
  } else if (sn.type === NodeType$3.Element) {
1283
1364
  if (slimDOMOptions.script && // script tag
1284
1365
  (sn.tagName === "script" || // (module)preload link
1285
- sn.tagName === "link" && (sn.attributes.rel === "preload" || sn.attributes.rel === "modulepreload") && sn.attributes.as === "script" || // prefetch link
1366
+ sn.tagName === "link" && (sn.attributes.rel === "preload" && sn.attributes.as === "script" || sn.attributes.rel === "modulepreload") || // prefetch link
1286
1367
  sn.tagName === "link" && sn.attributes.rel === "prefetch" && typeof sn.attributes.href === "string" && extractFileExtension(sn.attributes.href) === "js")) {
1287
1368
  return true;
1288
1369
  } else if (slimDOMOptions.headFavicon && (sn.tagName === "link" && sn.attributes.rel === "shortcut icon" || sn.tagName === "meta" && (lowerIfExists(sn.attributes.name).match(/^msapplication-tile(image|color)$/) || lowerIfExists(sn.attributes.name) === "application-name" || lowerIfExists(sn.attributes.rel) === "icon" || lowerIfExists(sn.attributes.rel) === "apple-touch-icon" || lowerIfExists(sn.attributes.rel) === "shortcut icon"))) {
@@ -10033,6 +10114,30 @@ function querySelectorAll(n2, selectors) {
10033
10114
  function mutationObserverCtor() {
10034
10115
  return getUntaintedPrototype("MutationObserver").constructor;
10035
10116
  }
10117
+ function patch(source, name, replacement) {
10118
+ try {
10119
+ if (!(name in source)) {
10120
+ return function() {};
10121
+ }
10122
+ var original = source[name];
10123
+ var wrapped = replacement(original);
10124
+ if (typeof wrapped === "function") {
10125
+ wrapped.prototype = wrapped.prototype || {};
10126
+ Object.defineProperties(wrapped, {
10127
+ __rrweb_original__: {
10128
+ enumerable: false,
10129
+ value: original
10130
+ }
10131
+ });
10132
+ }
10133
+ source[name] = wrapped;
10134
+ return function() {
10135
+ source[name] = original;
10136
+ };
10137
+ } catch (e) {
10138
+ return function() {};
10139
+ }
10140
+ }
10036
10141
  var index = {
10037
10142
  childNodes: childNodes,
10038
10143
  parentNode: parentNode,
@@ -10045,7 +10150,8 @@ var index = {
10045
10150
  shadowRoot: shadowRoot,
10046
10151
  querySelector: querySelector,
10047
10152
  querySelectorAll: querySelectorAll,
10048
- mutationObserver: mutationObserverCtor
10153
+ mutationObserver: mutationObserverCtor,
10154
+ patch: patch
10049
10155
  };
10050
10156
  function on(type, fn, target) {
10051
10157
  if (target === void 0) target = document;
@@ -10138,30 +10244,6 @@ function hookSetter(target, key, d, isRevoked, win) {
10138
10244
  return hookSetter(target, key, original || {}, true);
10139
10245
  };
10140
10246
  }
10141
- function patch(source, name, replacement) {
10142
- try {
10143
- if (!(name in source)) {
10144
- return function() {};
10145
- }
10146
- var original = source[name];
10147
- var wrapped = replacement(original);
10148
- if (typeof wrapped === "function") {
10149
- wrapped.prototype = wrapped.prototype || {};
10150
- Object.defineProperties(wrapped, {
10151
- __rrweb_original__: {
10152
- enumerable: false,
10153
- value: original
10154
- }
10155
- });
10156
- }
10157
- source[name] = wrapped;
10158
- return function() {
10159
- source[name] = original;
10160
- };
10161
- } catch (e) {
10162
- return function() {};
10163
- }
10164
- }
10165
10247
  var nowTimestamp = Date.now;
10166
10248
  if (!/* @__PURE__ */ /[1-9][0-9]{12}/.test(Date.now().toString())) {
10167
10249
  nowTimestamp = function() {
@@ -10752,9 +10834,17 @@ var MutationBuffer = /*#__PURE__*/ function() {
10752
10834
  _this.attributes.push(item);
10753
10835
  _this.attributeMap.set(textarea, item);
10754
10836
  }
10755
- item.attributes.value = Array.from(index.childNodes(textarea), function(cn) {
10837
+ var value = Array.from(index.childNodes(textarea), function(cn) {
10756
10838
  return index.textContent(cn) || "";
10757
10839
  }).join("");
10840
+ item.attributes.value = maskInputValue({
10841
+ element: textarea,
10842
+ maskInputOptions: _this.maskInputOptions,
10843
+ tagName: textarea.tagName,
10844
+ type: getInputType(textarea),
10845
+ value: value,
10846
+ maskInputFn: _this.maskInputFn
10847
+ });
10758
10848
  });
10759
10849
  __publicField(this, "processMutation", function(m) {
10760
10850
  if (isIgnored(m.target, _this.mirror, _this.slimDOMOptions)) {
@@ -13535,8 +13625,15 @@ function record(options) {
13535
13625
  }, window));
13536
13626
  }
13537
13627
  return function() {
13538
- handlers.forEach(function(h) {
13539
- return h();
13628
+ handlers.forEach(function(handler) {
13629
+ try {
13630
+ handler();
13631
+ } catch (error) {
13632
+ var msg = String(error).toLowerCase();
13633
+ if (!msg.includes("cross-origin")) {
13634
+ console.warn(error);
13635
+ }
13636
+ }
13540
13637
  });
13541
13638
  processedNodeManager.destroy();
13542
13639
  recording = false;
@@ -13942,7 +14039,7 @@ if (typeof Promise !== 'undefined' && Promise.toString().indexOf('[native code]'
13942
14039
 
13943
14040
  var Config = {
13944
14041
  DEBUG: false,
13945
- LIB_VERSION: '2.68.0'
14042
+ LIB_VERSION: '2.69.0'
13946
14043
  };
13947
14044
 
13948
14045
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -15742,6 +15839,10 @@ IDBStorageWrapper.prototype.init = function () {
15742
15839
  });
15743
15840
  };
15744
15841
 
15842
+ IDBStorageWrapper.prototype.isInitialized = function () {
15843
+ return !!this.dbPromise;
15844
+ };
15845
+
15745
15846
  /**
15746
15847
  * @param {IDBTransactionMode} mode
15747
15848
  * @param {function(IDBObjectStore): void} storeCb
@@ -16266,6 +16367,10 @@ LocalStorageWrapper.prototype.init = function () {
16266
16367
  return PromisePolyfill.resolve();
16267
16368
  };
16268
16369
 
16370
+ LocalStorageWrapper.prototype.isInitialized = function () {
16371
+ return true;
16372
+ };
16373
+
16269
16374
  LocalStorageWrapper.prototype.setItem = function (key, value) {
16270
16375
  return new PromisePolyfill(_.bind(function (resolve, reject) {
16271
16376
  try {
@@ -16346,7 +16451,7 @@ var RequestQueue = function (storageKey, options) {
16346
16451
  };
16347
16452
 
16348
16453
  RequestQueue.prototype.ensureInit = function () {
16349
- if (this.initialized) {
16454
+ if (this.initialized || !this.usePersistence) {
16350
16455
  return PromisePolyfill.resolve();
16351
16456
  }
16352
16457
 
@@ -17098,10 +17203,9 @@ var SessionRecording = function(options) {
17098
17203
 
17099
17204
  // disable persistence if localStorage is not supported
17100
17205
  // request-queue will automatically disable persistence if indexedDB fails to initialize
17101
- var usePersistence = localStorageSupported(options.sharedLockStorage, true);
17206
+ var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
17102
17207
 
17103
17208
  // each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
17104
- // this will be important when persistence is introduced
17105
17209
  this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
17106
17210
  this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
17107
17211
  this.batcher = new RequestBatcher(this.batcherKey, {
@@ -17482,12 +17586,17 @@ SessionRecording.prototype.reportError = function(msg, err) {
17482
17586
  * Makes sure that only one tab can be recording at a time.
17483
17587
  */
17484
17588
  var RecordingRegistry = function (options) {
17589
+ /** @type {IDBStorageWrapper} */
17485
17590
  this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
17486
17591
  this.errorReporter = options.errorReporter;
17487
17592
  this.mixpanelInstance = options.mixpanelInstance;
17488
17593
  this.sharedLockStorage = options.sharedLockStorage;
17489
17594
  };
17490
17595
 
17596
+ RecordingRegistry.prototype.isPersistenceEnabled = function() {
17597
+ return !this.mixpanelInstance.get_config('disable_persistence');
17598
+ };
17599
+
17491
17600
  RecordingRegistry.prototype.handleError = function (err) {
17492
17601
  this.errorReporter('IndexedDB error: ', err);
17493
17602
  };
@@ -17496,6 +17605,10 @@ RecordingRegistry.prototype.handleError = function (err) {
17496
17605
  * @param {import('./session-recording').SerializedRecording} serializedRecording
17497
17606
  */
17498
17607
  RecordingRegistry.prototype.setActiveRecording = function (serializedRecording) {
17608
+ if (!this.isPersistenceEnabled()) {
17609
+ return PromisePolyfill.resolve();
17610
+ }
17611
+
17499
17612
  var tabId = serializedRecording['tabId'];
17500
17613
  if (!tabId) {
17501
17614
  console.warn('No tab ID is set, cannot persist recording metadata.');
@@ -17513,6 +17626,10 @@ RecordingRegistry.prototype.setActiveRecording = function (serializedRecording)
17513
17626
  * @returns {Promise<import('./session-recording').SerializedRecording>}
17514
17627
  */
17515
17628
  RecordingRegistry.prototype.getActiveRecording = function () {
17629
+ if (!this.isPersistenceEnabled()) {
17630
+ return PromisePolyfill.resolve(null);
17631
+ }
17632
+
17516
17633
  return this.idb.init()
17517
17634
  .then(function () {
17518
17635
  return this.idb.getItem(this.mixpanelInstance.get_tab_id());
@@ -17524,8 +17641,16 @@ RecordingRegistry.prototype.getActiveRecording = function () {
17524
17641
  };
17525
17642
 
17526
17643
  RecordingRegistry.prototype.clearActiveRecording = function () {
17527
- // mark recording as expired instead of deleting it in case the page unloads mid-flush and doesn't make it to ingestion.
17528
- // this will ensure the next pageload will flush the remaining events, but not try to continue the recording.
17644
+ if (this.isPersistenceEnabled()) {
17645
+ // mark recording as expired instead of deleting it in case the page unloads mid-flush and doesn't make it to ingestion.
17646
+ // this will ensure the next pageload will flush the remaining events, but not try to continue the recording.
17647
+ return this.markActiveRecordingExpired();
17648
+ } else {
17649
+ return this.deleteActiveRecording();
17650
+ }
17651
+ };
17652
+
17653
+ RecordingRegistry.prototype.markActiveRecordingExpired = function () {
17529
17654
  return this.getActiveRecording()
17530
17655
  .then(function (serializedRecording) {
17531
17656
  if (serializedRecording) {
@@ -17536,11 +17661,25 @@ RecordingRegistry.prototype.clearActiveRecording = function () {
17536
17661
  .catch(this.handleError.bind(this));
17537
17662
  };
17538
17663
 
17664
+ RecordingRegistry.prototype.deleteActiveRecording = function () {
17665
+ // avoid initializing IDB if this registry instance hasn't already written a recording
17666
+ if (this.idb.isInitialized()) {
17667
+ return this.idb.removeItem(this.mixpanelInstance.get_tab_id())
17668
+ .catch(this.handleError.bind(this));
17669
+ } else {
17670
+ return PromisePolyfill.resolve();
17671
+ }
17672
+ };
17673
+
17539
17674
  /**
17540
17675
  * Flush any inactive recordings from the registry to minimize data loss.
17541
17676
  * The main idea here is that we can flush remaining rrweb events on the next page load if a tab is closed mid-batch.
17542
17677
  */
17543
17678
  RecordingRegistry.prototype.flushInactiveRecordings = function () {
17679
+ if (!this.isPersistenceEnabled()) {
17680
+ return PromisePolyfill.resolve([]);
17681
+ }
17682
+
17544
17683
  return this.idb.init()
17545
17684
  .then(function() {
17546
17685
  return this.idb.getAll();
@@ -20588,7 +20727,9 @@ MixpanelLib.prototype._init = function(token, config, name) {
20588
20727
  * This is primarily used for session recording, where data must be isolated to the current tab.
20589
20728
  */
20590
20729
  MixpanelLib.prototype._init_tab_id = function() {
20591
- if (_.sessionStorage.is_supported()) {
20730
+ if (this.get_config('disable_persistence')) {
20731
+ console$1.log('Tab ID initialization skipped due to disable_persistence config');
20732
+ } else if (_.sessionStorage.is_supported()) {
20592
20733
  try {
20593
20734
  var key_suffix = this.get_config('name') + '_' + this.get_config('token');
20594
20735
  var tab_id_key = 'mp_tab_id_' + key_suffix;
@@ -20622,6 +20763,11 @@ MixpanelLib.prototype.get_tab_id = function () {
20622
20763
  };
20623
20764
 
20624
20765
  MixpanelLib.prototype._should_load_recorder = function () {
20766
+ if (this.get_config('disable_persistence')) {
20767
+ console$1.log('Load recorder check skipped due to disable_persistence config');
20768
+ return Promise.resolve(false);
20769
+ }
20770
+
20625
20771
  var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
20626
20772
  var tab_id = this.get_tab_id();
20627
20773
  return recording_registry_idb.init()