mixpanel-browser 2.68.0 → 2.69.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.
@@ -489,6 +489,30 @@
489
489
  function mutationObserverCtor$1() {
490
490
  return getUntaintedPrototype$1("MutationObserver").constructor;
491
491
  }
492
+ function patch$1(source, name, replacement) {
493
+ try {
494
+ if (!(name in source)) {
495
+ return function() {};
496
+ }
497
+ var original = source[name];
498
+ var wrapped = replacement(original);
499
+ if (typeof wrapped === "function") {
500
+ wrapped.prototype = wrapped.prototype || {};
501
+ Object.defineProperties(wrapped, {
502
+ __rrweb_original__: {
503
+ enumerable: false,
504
+ value: original
505
+ }
506
+ });
507
+ }
508
+ source[name] = wrapped;
509
+ return function() {
510
+ source[name] = original;
511
+ };
512
+ } catch (e) {
513
+ return function() {};
514
+ }
515
+ }
492
516
  var index$1 = {
493
517
  childNodes: childNodes$1,
494
518
  parentNode: parentNode$1,
@@ -501,7 +525,8 @@
501
525
  shadowRoot: shadowRoot$1,
502
526
  querySelector: querySelector$1,
503
527
  querySelectorAll: querySelectorAll$1,
504
- mutationObserver: mutationObserverCtor$1
528
+ mutationObserver: mutationObserverCtor$1,
529
+ patch: patch$1
505
530
  };
506
531
  function isElement(n2) {
507
532
  return n2.nodeType === n2.ELEMENT_NODE;
@@ -752,26 +777,82 @@
752
777
  return "url(" + maybeQuote + stack.join("/") + maybeQuote + ")";
753
778
  });
754
779
  }
755
- function normalizeCssString(cssText) {
756
- return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
780
+ function normalizeCssString(cssText, _testNoPxNorm) {
781
+ if (_testNoPxNorm === void 0) _testNoPxNorm = false;
782
+ if (_testNoPxNorm) {
783
+ return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
784
+ } else {
785
+ return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "").replace(/0px/g, "0");
786
+ }
757
787
  }
758
- function splitCssText(cssText, style) {
788
+ function splitCssText(cssText, style, _testNoPxNorm) {
789
+ if (_testNoPxNorm === void 0) _testNoPxNorm = false;
759
790
  var childNodes2 = Array.from(style.childNodes);
760
791
  var splits = [];
792
+ var iterCount = 0;
761
793
  if (childNodes2.length > 1 && cssText && typeof cssText === "string") {
762
- var cssTextNorm = normalizeCssString(cssText);
794
+ var cssTextNorm = normalizeCssString(cssText, _testNoPxNorm);
795
+ var normFactor = cssTextNorm.length / cssText.length;
763
796
  for(var i2 = 1; i2 < childNodes2.length; i2++){
764
797
  if (childNodes2[i2].textContent && typeof childNodes2[i2].textContent === "string") {
765
- var textContentNorm = normalizeCssString(childNodes2[i2].textContent);
766
- for(var j = 3; j < textContentNorm.length; j++){
767
- var bit = textContentNorm.substring(0, j);
768
- if (cssTextNorm.split(bit).length === 2) {
769
- var splitNorm = cssTextNorm.indexOf(bit);
770
- for(var k = splitNorm; k < cssText.length; k++){
771
- if (normalizeCssString(cssText.substring(0, k)).length === splitNorm) {
798
+ var textContentNorm = normalizeCssString(childNodes2[i2].textContent, _testNoPxNorm);
799
+ var jLimit = 100;
800
+ var j = 3;
801
+ for(; j < textContentNorm.length; j++){
802
+ if (// keep consuming css identifiers (to get a decent chunk more quickly)
803
+ textContentNorm[j].match(/[a-zA-Z0-9]/) || // substring needs to be unique to this section
804
+ textContentNorm.indexOf(textContentNorm.substring(0, j), 1) !== -1) {
805
+ continue;
806
+ }
807
+ break;
808
+ }
809
+ for(; j < textContentNorm.length; j++){
810
+ var startSubstring = textContentNorm.substring(0, j);
811
+ var cssNormSplits = cssTextNorm.split(startSubstring);
812
+ var splitNorm = -1;
813
+ if (cssNormSplits.length === 2) {
814
+ splitNorm = cssNormSplits[0].length;
815
+ } else if (cssNormSplits.length > 2 && cssNormSplits[0] === "" && childNodes2[i2 - 1].textContent !== "") {
816
+ splitNorm = cssTextNorm.indexOf(startSubstring, 1);
817
+ } else if (cssNormSplits.length === 1) {
818
+ startSubstring = startSubstring.substring(0, startSubstring.length - 1);
819
+ cssNormSplits = cssTextNorm.split(startSubstring);
820
+ if (cssNormSplits.length <= 1) {
821
+ splits.push(cssText);
822
+ return splits;
823
+ }
824
+ j = jLimit + 1;
825
+ } else if (j === textContentNorm.length - 1) {
826
+ splitNorm = cssTextNorm.indexOf(startSubstring);
827
+ }
828
+ if (cssNormSplits.length >= 2 && j > jLimit) {
829
+ var prevTextContent = childNodes2[i2 - 1].textContent;
830
+ if (prevTextContent && typeof prevTextContent === "string") {
831
+ var prevMinLength = normalizeCssString(prevTextContent).length;
832
+ splitNorm = cssTextNorm.indexOf(startSubstring, prevMinLength);
833
+ }
834
+ if (splitNorm === -1) {
835
+ splitNorm = cssNormSplits[0].length;
836
+ }
837
+ }
838
+ if (splitNorm !== -1) {
839
+ var k = Math.floor(splitNorm / normFactor);
840
+ for(; k > 0 && k < cssText.length;){
841
+ iterCount += 1;
842
+ if (iterCount > 50 * childNodes2.length) {
843
+ splits.push(cssText);
844
+ return splits;
845
+ }
846
+ var normPart = normalizeCssString(cssText.substring(0, k), _testNoPxNorm);
847
+ if (normPart.length === splitNorm) {
772
848
  splits.push(cssText.substring(0, k));
773
849
  cssText = cssText.substring(k);
850
+ cssTextNorm = cssTextNorm.substring(splitNorm);
774
851
  break;
852
+ } else if (normPart.length < splitNorm) {
853
+ k += Math.max(1, Math.floor((splitNorm - normPart.length) / normFactor));
854
+ } else {
855
+ k -= Math.max(1, Math.floor((normPart.length - splitNorm) * normFactor));
775
856
  }
776
857
  }
777
858
  break;
@@ -1288,7 +1369,7 @@
1288
1369
  } else if (sn.type === NodeType$3.Element) {
1289
1370
  if (slimDOMOptions.script && // script tag
1290
1371
  (sn.tagName === "script" || // (module)preload link
1291
- sn.tagName === "link" && (sn.attributes.rel === "preload" || sn.attributes.rel === "modulepreload") && sn.attributes.as === "script" || // prefetch link
1372
+ sn.tagName === "link" && (sn.attributes.rel === "preload" && sn.attributes.as === "script" || sn.attributes.rel === "modulepreload") || // prefetch link
1292
1373
  sn.tagName === "link" && sn.attributes.rel === "prefetch" && typeof sn.attributes.href === "string" && extractFileExtension(sn.attributes.href) === "js")) {
1293
1374
  return true;
1294
1375
  } 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"))) {
@@ -10039,6 +10120,30 @@
10039
10120
  function mutationObserverCtor() {
10040
10121
  return getUntaintedPrototype("MutationObserver").constructor;
10041
10122
  }
10123
+ function patch(source, name, replacement) {
10124
+ try {
10125
+ if (!(name in source)) {
10126
+ return function() {};
10127
+ }
10128
+ var original = source[name];
10129
+ var wrapped = replacement(original);
10130
+ if (typeof wrapped === "function") {
10131
+ wrapped.prototype = wrapped.prototype || {};
10132
+ Object.defineProperties(wrapped, {
10133
+ __rrweb_original__: {
10134
+ enumerable: false,
10135
+ value: original
10136
+ }
10137
+ });
10138
+ }
10139
+ source[name] = wrapped;
10140
+ return function() {
10141
+ source[name] = original;
10142
+ };
10143
+ } catch (e) {
10144
+ return function() {};
10145
+ }
10146
+ }
10042
10147
  var index = {
10043
10148
  childNodes: childNodes,
10044
10149
  parentNode: parentNode,
@@ -10051,7 +10156,8 @@
10051
10156
  shadowRoot: shadowRoot,
10052
10157
  querySelector: querySelector,
10053
10158
  querySelectorAll: querySelectorAll,
10054
- mutationObserver: mutationObserverCtor
10159
+ mutationObserver: mutationObserverCtor,
10160
+ patch: patch
10055
10161
  };
10056
10162
  function on(type, fn, target) {
10057
10163
  if (target === void 0) target = document;
@@ -10144,30 +10250,6 @@
10144
10250
  return hookSetter(target, key, original || {}, true);
10145
10251
  };
10146
10252
  }
10147
- function patch(source, name, replacement) {
10148
- try {
10149
- if (!(name in source)) {
10150
- return function() {};
10151
- }
10152
- var original = source[name];
10153
- var wrapped = replacement(original);
10154
- if (typeof wrapped === "function") {
10155
- wrapped.prototype = wrapped.prototype || {};
10156
- Object.defineProperties(wrapped, {
10157
- __rrweb_original__: {
10158
- enumerable: false,
10159
- value: original
10160
- }
10161
- });
10162
- }
10163
- source[name] = wrapped;
10164
- return function() {
10165
- source[name] = original;
10166
- };
10167
- } catch (e) {
10168
- return function() {};
10169
- }
10170
- }
10171
10253
  var nowTimestamp = Date.now;
10172
10254
  if (!/* @__PURE__ */ /[1-9][0-9]{12}/.test(Date.now().toString())) {
10173
10255
  nowTimestamp = function() {
@@ -10758,9 +10840,17 @@
10758
10840
  _this.attributes.push(item);
10759
10841
  _this.attributeMap.set(textarea, item);
10760
10842
  }
10761
- item.attributes.value = Array.from(index.childNodes(textarea), function(cn) {
10843
+ var value = Array.from(index.childNodes(textarea), function(cn) {
10762
10844
  return index.textContent(cn) || "";
10763
10845
  }).join("");
10846
+ item.attributes.value = maskInputValue({
10847
+ element: textarea,
10848
+ maskInputOptions: _this.maskInputOptions,
10849
+ tagName: textarea.tagName,
10850
+ type: getInputType(textarea),
10851
+ value: value,
10852
+ maskInputFn: _this.maskInputFn
10853
+ });
10764
10854
  });
10765
10855
  __publicField(this, "processMutation", function(m) {
10766
10856
  if (isIgnored(m.target, _this.mirror, _this.slimDOMOptions)) {
@@ -13541,8 +13631,15 @@
13541
13631
  }, window));
13542
13632
  }
13543
13633
  return function() {
13544
- handlers.forEach(function(h) {
13545
- return h();
13634
+ handlers.forEach(function(handler) {
13635
+ try {
13636
+ handler();
13637
+ } catch (error) {
13638
+ var msg = String(error).toLowerCase();
13639
+ if (!msg.includes("cross-origin")) {
13640
+ console.warn(error);
13641
+ }
13642
+ }
13546
13643
  });
13547
13644
  processedNodeManager.destroy();
13548
13645
  recording = false;
@@ -13948,7 +14045,7 @@
13948
14045
 
13949
14046
  var Config = {
13950
14047
  DEBUG: false,
13951
- LIB_VERSION: '2.68.0'
14048
+ LIB_VERSION: '2.69.0'
13952
14049
  };
13953
14050
 
13954
14051
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -15748,6 +15845,10 @@
15748
15845
  });
15749
15846
  };
15750
15847
 
15848
+ IDBStorageWrapper.prototype.isInitialized = function () {
15849
+ return !!this.dbPromise;
15850
+ };
15851
+
15751
15852
  /**
15752
15853
  * @param {IDBTransactionMode} mode
15753
15854
  * @param {function(IDBObjectStore): void} storeCb
@@ -16272,6 +16373,10 @@
16272
16373
  return PromisePolyfill.resolve();
16273
16374
  };
16274
16375
 
16376
+ LocalStorageWrapper.prototype.isInitialized = function () {
16377
+ return true;
16378
+ };
16379
+
16275
16380
  LocalStorageWrapper.prototype.setItem = function (key, value) {
16276
16381
  return new PromisePolyfill(_.bind(function (resolve, reject) {
16277
16382
  try {
@@ -16352,7 +16457,7 @@
16352
16457
  };
16353
16458
 
16354
16459
  RequestQueue.prototype.ensureInit = function () {
16355
- if (this.initialized) {
16460
+ if (this.initialized || !this.usePersistence) {
16356
16461
  return PromisePolyfill.resolve();
16357
16462
  }
16358
16463
 
@@ -17104,10 +17209,9 @@
17104
17209
 
17105
17210
  // disable persistence if localStorage is not supported
17106
17211
  // request-queue will automatically disable persistence if indexedDB fails to initialize
17107
- var usePersistence = localStorageSupported(options.sharedLockStorage, true);
17212
+ var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
17108
17213
 
17109
17214
  // each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
17110
- // this will be important when persistence is introduced
17111
17215
  this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
17112
17216
  this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
17113
17217
  this.batcher = new RequestBatcher(this.batcherKey, {
@@ -17488,12 +17592,17 @@
17488
17592
  * Makes sure that only one tab can be recording at a time.
17489
17593
  */
17490
17594
  var RecordingRegistry = function (options) {
17595
+ /** @type {IDBStorageWrapper} */
17491
17596
  this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
17492
17597
  this.errorReporter = options.errorReporter;
17493
17598
  this.mixpanelInstance = options.mixpanelInstance;
17494
17599
  this.sharedLockStorage = options.sharedLockStorage;
17495
17600
  };
17496
17601
 
17602
+ RecordingRegistry.prototype.isPersistenceEnabled = function() {
17603
+ return !this.mixpanelInstance.get_config('disable_persistence');
17604
+ };
17605
+
17497
17606
  RecordingRegistry.prototype.handleError = function (err) {
17498
17607
  this.errorReporter('IndexedDB error: ', err);
17499
17608
  };
@@ -17502,6 +17611,10 @@
17502
17611
  * @param {import('./session-recording').SerializedRecording} serializedRecording
17503
17612
  */
17504
17613
  RecordingRegistry.prototype.setActiveRecording = function (serializedRecording) {
17614
+ if (!this.isPersistenceEnabled()) {
17615
+ return PromisePolyfill.resolve();
17616
+ }
17617
+
17505
17618
  var tabId = serializedRecording['tabId'];
17506
17619
  if (!tabId) {
17507
17620
  console.warn('No tab ID is set, cannot persist recording metadata.');
@@ -17519,6 +17632,10 @@
17519
17632
  * @returns {Promise<import('./session-recording').SerializedRecording>}
17520
17633
  */
17521
17634
  RecordingRegistry.prototype.getActiveRecording = function () {
17635
+ if (!this.isPersistenceEnabled()) {
17636
+ return PromisePolyfill.resolve(null);
17637
+ }
17638
+
17522
17639
  return this.idb.init()
17523
17640
  .then(function () {
17524
17641
  return this.idb.getItem(this.mixpanelInstance.get_tab_id());
@@ -17530,8 +17647,16 @@
17530
17647
  };
17531
17648
 
17532
17649
  RecordingRegistry.prototype.clearActiveRecording = function () {
17533
- // mark recording as expired instead of deleting it in case the page unloads mid-flush and doesn't make it to ingestion.
17534
- // this will ensure the next pageload will flush the remaining events, but not try to continue the recording.
17650
+ if (this.isPersistenceEnabled()) {
17651
+ // mark recording as expired instead of deleting it in case the page unloads mid-flush and doesn't make it to ingestion.
17652
+ // this will ensure the next pageload will flush the remaining events, but not try to continue the recording.
17653
+ return this.markActiveRecordingExpired();
17654
+ } else {
17655
+ return this.deleteActiveRecording();
17656
+ }
17657
+ };
17658
+
17659
+ RecordingRegistry.prototype.markActiveRecordingExpired = function () {
17535
17660
  return this.getActiveRecording()
17536
17661
  .then(function (serializedRecording) {
17537
17662
  if (serializedRecording) {
@@ -17542,11 +17667,25 @@
17542
17667
  .catch(this.handleError.bind(this));
17543
17668
  };
17544
17669
 
17670
+ RecordingRegistry.prototype.deleteActiveRecording = function () {
17671
+ // avoid initializing IDB if this registry instance hasn't already written a recording
17672
+ if (this.idb.isInitialized()) {
17673
+ return this.idb.removeItem(this.mixpanelInstance.get_tab_id())
17674
+ .catch(this.handleError.bind(this));
17675
+ } else {
17676
+ return PromisePolyfill.resolve();
17677
+ }
17678
+ };
17679
+
17545
17680
  /**
17546
17681
  * Flush any inactive recordings from the registry to minimize data loss.
17547
17682
  * The main idea here is that we can flush remaining rrweb events on the next page load if a tab is closed mid-batch.
17548
17683
  */
17549
17684
  RecordingRegistry.prototype.flushInactiveRecordings = function () {
17685
+ if (!this.isPersistenceEnabled()) {
17686
+ return PromisePolyfill.resolve([]);
17687
+ }
17688
+
17550
17689
  return this.idb.init()
17551
17690
  .then(function() {
17552
17691
  return this.idb.getAll();
@@ -20594,7 +20733,9 @@
20594
20733
  * This is primarily used for session recording, where data must be isolated to the current tab.
20595
20734
  */
20596
20735
  MixpanelLib.prototype._init_tab_id = function() {
20597
- if (_.sessionStorage.is_supported()) {
20736
+ if (this.get_config('disable_persistence')) {
20737
+ console$1.log('Tab ID initialization skipped due to disable_persistence config');
20738
+ } else if (_.sessionStorage.is_supported()) {
20598
20739
  try {
20599
20740
  var key_suffix = this.get_config('name') + '_' + this.get_config('token');
20600
20741
  var tab_id_key = 'mp_tab_id_' + key_suffix;
@@ -20628,6 +20769,11 @@
20628
20769
  };
20629
20770
 
20630
20771
  MixpanelLib.prototype._should_load_recorder = function () {
20772
+ if (this.get_config('disable_persistence')) {
20773
+ console$1.log('Load recorder check skipped due to disable_persistence config');
20774
+ return Promise.resolve(false);
20775
+ }
20776
+
20631
20777
  var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
20632
20778
  var tab_id = this.get_tab_id();
20633
20779
  return recording_registry_idb.init()