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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  var Config = {
4
4
  DEBUG: false,
5
- LIB_VERSION: '2.68.0'
5
+ LIB_VERSION: '2.69.0'
6
6
  };
7
7
 
8
8
  // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
@@ -3629,6 +3629,10 @@ LocalStorageWrapper.prototype.init = function () {
3629
3629
  return PromisePolyfill.resolve();
3630
3630
  };
3631
3631
 
3632
+ LocalStorageWrapper.prototype.isInitialized = function () {
3633
+ return true;
3634
+ };
3635
+
3632
3636
  LocalStorageWrapper.prototype.setItem = function (key, value) {
3633
3637
  return new PromisePolyfill(_.bind(function (resolve, reject) {
3634
3638
  try {
@@ -3709,7 +3713,7 @@ var RequestQueue = function (storageKey, options) {
3709
3713
  };
3710
3714
 
3711
3715
  RequestQueue.prototype.ensureInit = function () {
3712
- if (this.initialized) {
3716
+ if (this.initialized || !this.usePersistence) {
3713
3717
  return PromisePolyfill.resolve();
3714
3718
  }
3715
3719
 
@@ -5893,6 +5897,10 @@ IDBStorageWrapper.prototype.init = function () {
5893
5897
  });
5894
5898
  };
5895
5899
 
5900
+ IDBStorageWrapper.prototype.isInitialized = function () {
5901
+ return !!this.dbPromise;
5902
+ };
5903
+
5896
5904
  /**
5897
5905
  * @param {IDBTransactionMode} mode
5898
5906
  * @param {function(IDBObjectStore): void} storeCb
@@ -6326,7 +6334,9 @@ MixpanelLib.prototype._init = function(token, config, name) {
6326
6334
  * This is primarily used for session recording, where data must be isolated to the current tab.
6327
6335
  */
6328
6336
  MixpanelLib.prototype._init_tab_id = function() {
6329
- if (_.sessionStorage.is_supported()) {
6337
+ if (this.get_config('disable_persistence')) {
6338
+ console.log('Tab ID initialization skipped due to disable_persistence config');
6339
+ } else if (_.sessionStorage.is_supported()) {
6330
6340
  try {
6331
6341
  var key_suffix = this.get_config('name') + '_' + this.get_config('token');
6332
6342
  var tab_id_key = 'mp_tab_id_' + key_suffix;
@@ -6360,6 +6370,11 @@ MixpanelLib.prototype.get_tab_id = function () {
6360
6370
  };
6361
6371
 
6362
6372
  MixpanelLib.prototype._should_load_recorder = function () {
6373
+ if (this.get_config('disable_persistence')) {
6374
+ console.log('Load recorder check skipped due to disable_persistence config');
6375
+ return Promise.resolve(false);
6376
+ }
6377
+
6363
6378
  var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
6364
6379
  var tab_id = this.get_tab_id();
6365
6380
  return recording_registry_idb.init()
@@ -486,6 +486,30 @@
486
486
  function mutationObserverCtor$1() {
487
487
  return getUntaintedPrototype$1("MutationObserver").constructor;
488
488
  }
489
+ function patch$1(source, name, replacement) {
490
+ try {
491
+ if (!(name in source)) {
492
+ return function() {};
493
+ }
494
+ var original = source[name];
495
+ var wrapped = replacement(original);
496
+ if (typeof wrapped === "function") {
497
+ wrapped.prototype = wrapped.prototype || {};
498
+ Object.defineProperties(wrapped, {
499
+ __rrweb_original__: {
500
+ enumerable: false,
501
+ value: original
502
+ }
503
+ });
504
+ }
505
+ source[name] = wrapped;
506
+ return function() {
507
+ source[name] = original;
508
+ };
509
+ } catch (e) {
510
+ return function() {};
511
+ }
512
+ }
489
513
  var index$1 = {
490
514
  childNodes: childNodes$1,
491
515
  parentNode: parentNode$1,
@@ -498,7 +522,8 @@
498
522
  shadowRoot: shadowRoot$1,
499
523
  querySelector: querySelector$1,
500
524
  querySelectorAll: querySelectorAll$1,
501
- mutationObserver: mutationObserverCtor$1
525
+ mutationObserver: mutationObserverCtor$1,
526
+ patch: patch$1
502
527
  };
503
528
  function isElement(n2) {
504
529
  return n2.nodeType === n2.ELEMENT_NODE;
@@ -749,26 +774,82 @@
749
774
  return "url(" + maybeQuote + stack.join("/") + maybeQuote + ")";
750
775
  });
751
776
  }
752
- function normalizeCssString(cssText) {
753
- return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
777
+ function normalizeCssString(cssText, _testNoPxNorm) {
778
+ if (_testNoPxNorm === void 0) _testNoPxNorm = false;
779
+ if (_testNoPxNorm) {
780
+ return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
781
+ } else {
782
+ return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "").replace(/0px/g, "0");
783
+ }
754
784
  }
755
- function splitCssText(cssText, style) {
785
+ function splitCssText(cssText, style, _testNoPxNorm) {
786
+ if (_testNoPxNorm === void 0) _testNoPxNorm = false;
756
787
  var childNodes2 = Array.from(style.childNodes);
757
788
  var splits = [];
789
+ var iterCount = 0;
758
790
  if (childNodes2.length > 1 && cssText && typeof cssText === "string") {
759
- var cssTextNorm = normalizeCssString(cssText);
791
+ var cssTextNorm = normalizeCssString(cssText, _testNoPxNorm);
792
+ var normFactor = cssTextNorm.length / cssText.length;
760
793
  for(var i2 = 1; i2 < childNodes2.length; i2++){
761
794
  if (childNodes2[i2].textContent && typeof childNodes2[i2].textContent === "string") {
762
- var textContentNorm = normalizeCssString(childNodes2[i2].textContent);
763
- for(var j = 3; j < textContentNorm.length; j++){
764
- var bit = textContentNorm.substring(0, j);
765
- if (cssTextNorm.split(bit).length === 2) {
766
- var splitNorm = cssTextNorm.indexOf(bit);
767
- for(var k = splitNorm; k < cssText.length; k++){
768
- if (normalizeCssString(cssText.substring(0, k)).length === splitNorm) {
795
+ var textContentNorm = normalizeCssString(childNodes2[i2].textContent, _testNoPxNorm);
796
+ var jLimit = 100;
797
+ var j = 3;
798
+ for(; j < textContentNorm.length; j++){
799
+ if (// keep consuming css identifiers (to get a decent chunk more quickly)
800
+ textContentNorm[j].match(/[a-zA-Z0-9]/) || // substring needs to be unique to this section
801
+ textContentNorm.indexOf(textContentNorm.substring(0, j), 1) !== -1) {
802
+ continue;
803
+ }
804
+ break;
805
+ }
806
+ for(; j < textContentNorm.length; j++){
807
+ var startSubstring = textContentNorm.substring(0, j);
808
+ var cssNormSplits = cssTextNorm.split(startSubstring);
809
+ var splitNorm = -1;
810
+ if (cssNormSplits.length === 2) {
811
+ splitNorm = cssNormSplits[0].length;
812
+ } else if (cssNormSplits.length > 2 && cssNormSplits[0] === "" && childNodes2[i2 - 1].textContent !== "") {
813
+ splitNorm = cssTextNorm.indexOf(startSubstring, 1);
814
+ } else if (cssNormSplits.length === 1) {
815
+ startSubstring = startSubstring.substring(0, startSubstring.length - 1);
816
+ cssNormSplits = cssTextNorm.split(startSubstring);
817
+ if (cssNormSplits.length <= 1) {
818
+ splits.push(cssText);
819
+ return splits;
820
+ }
821
+ j = jLimit + 1;
822
+ } else if (j === textContentNorm.length - 1) {
823
+ splitNorm = cssTextNorm.indexOf(startSubstring);
824
+ }
825
+ if (cssNormSplits.length >= 2 && j > jLimit) {
826
+ var prevTextContent = childNodes2[i2 - 1].textContent;
827
+ if (prevTextContent && typeof prevTextContent === "string") {
828
+ var prevMinLength = normalizeCssString(prevTextContent).length;
829
+ splitNorm = cssTextNorm.indexOf(startSubstring, prevMinLength);
830
+ }
831
+ if (splitNorm === -1) {
832
+ splitNorm = cssNormSplits[0].length;
833
+ }
834
+ }
835
+ if (splitNorm !== -1) {
836
+ var k = Math.floor(splitNorm / normFactor);
837
+ for(; k > 0 && k < cssText.length;){
838
+ iterCount += 1;
839
+ if (iterCount > 50 * childNodes2.length) {
840
+ splits.push(cssText);
841
+ return splits;
842
+ }
843
+ var normPart = normalizeCssString(cssText.substring(0, k), _testNoPxNorm);
844
+ if (normPart.length === splitNorm) {
769
845
  splits.push(cssText.substring(0, k));
770
846
  cssText = cssText.substring(k);
847
+ cssTextNorm = cssTextNorm.substring(splitNorm);
771
848
  break;
849
+ } else if (normPart.length < splitNorm) {
850
+ k += Math.max(1, Math.floor((splitNorm - normPart.length) / normFactor));
851
+ } else {
852
+ k -= Math.max(1, Math.floor((normPart.length - splitNorm) * normFactor));
772
853
  }
773
854
  }
774
855
  break;
@@ -1285,7 +1366,7 @@
1285
1366
  } else if (sn.type === NodeType$3.Element) {
1286
1367
  if (slimDOMOptions.script && // script tag
1287
1368
  (sn.tagName === "script" || // (module)preload link
1288
- sn.tagName === "link" && (sn.attributes.rel === "preload" || sn.attributes.rel === "modulepreload") && sn.attributes.as === "script" || // prefetch link
1369
+ sn.tagName === "link" && (sn.attributes.rel === "preload" && sn.attributes.as === "script" || sn.attributes.rel === "modulepreload") || // prefetch link
1289
1370
  sn.tagName === "link" && sn.attributes.rel === "prefetch" && typeof sn.attributes.href === "string" && extractFileExtension(sn.attributes.href) === "js")) {
1290
1371
  return true;
1291
1372
  } 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"))) {
@@ -10036,6 +10117,30 @@
10036
10117
  function mutationObserverCtor() {
10037
10118
  return getUntaintedPrototype("MutationObserver").constructor;
10038
10119
  }
10120
+ function patch(source, name, replacement) {
10121
+ try {
10122
+ if (!(name in source)) {
10123
+ return function() {};
10124
+ }
10125
+ var original = source[name];
10126
+ var wrapped = replacement(original);
10127
+ if (typeof wrapped === "function") {
10128
+ wrapped.prototype = wrapped.prototype || {};
10129
+ Object.defineProperties(wrapped, {
10130
+ __rrweb_original__: {
10131
+ enumerable: false,
10132
+ value: original
10133
+ }
10134
+ });
10135
+ }
10136
+ source[name] = wrapped;
10137
+ return function() {
10138
+ source[name] = original;
10139
+ };
10140
+ } catch (e) {
10141
+ return function() {};
10142
+ }
10143
+ }
10039
10144
  var index = {
10040
10145
  childNodes: childNodes,
10041
10146
  parentNode: parentNode,
@@ -10048,7 +10153,8 @@
10048
10153
  shadowRoot: shadowRoot,
10049
10154
  querySelector: querySelector,
10050
10155
  querySelectorAll: querySelectorAll,
10051
- mutationObserver: mutationObserverCtor
10156
+ mutationObserver: mutationObserverCtor,
10157
+ patch: patch
10052
10158
  };
10053
10159
  function on(type, fn, target) {
10054
10160
  if (target === void 0) target = document;
@@ -10141,30 +10247,6 @@
10141
10247
  return hookSetter(target, key, original || {}, true);
10142
10248
  };
10143
10249
  }
10144
- function patch(source, name, replacement) {
10145
- try {
10146
- if (!(name in source)) {
10147
- return function() {};
10148
- }
10149
- var original = source[name];
10150
- var wrapped = replacement(original);
10151
- if (typeof wrapped === "function") {
10152
- wrapped.prototype = wrapped.prototype || {};
10153
- Object.defineProperties(wrapped, {
10154
- __rrweb_original__: {
10155
- enumerable: false,
10156
- value: original
10157
- }
10158
- });
10159
- }
10160
- source[name] = wrapped;
10161
- return function() {
10162
- source[name] = original;
10163
- };
10164
- } catch (e) {
10165
- return function() {};
10166
- }
10167
- }
10168
10250
  var nowTimestamp = Date.now;
10169
10251
  if (!/* @__PURE__ */ /[1-9][0-9]{12}/.test(Date.now().toString())) {
10170
10252
  nowTimestamp = function() {
@@ -10755,9 +10837,17 @@
10755
10837
  _this.attributes.push(item);
10756
10838
  _this.attributeMap.set(textarea, item);
10757
10839
  }
10758
- item.attributes.value = Array.from(index.childNodes(textarea), function(cn) {
10840
+ var value = Array.from(index.childNodes(textarea), function(cn) {
10759
10841
  return index.textContent(cn) || "";
10760
10842
  }).join("");
10843
+ item.attributes.value = maskInputValue({
10844
+ element: textarea,
10845
+ maskInputOptions: _this.maskInputOptions,
10846
+ tagName: textarea.tagName,
10847
+ type: getInputType(textarea),
10848
+ value: value,
10849
+ maskInputFn: _this.maskInputFn
10850
+ });
10761
10851
  });
10762
10852
  __publicField(this, "processMutation", function(m) {
10763
10853
  if (isIgnored(m.target, _this.mirror, _this.slimDOMOptions)) {
@@ -13538,8 +13628,15 @@
13538
13628
  }, window));
13539
13629
  }
13540
13630
  return function() {
13541
- handlers.forEach(function(h) {
13542
- return h();
13631
+ handlers.forEach(function(handler) {
13632
+ try {
13633
+ handler();
13634
+ } catch (error) {
13635
+ var msg = String(error).toLowerCase();
13636
+ if (!msg.includes("cross-origin")) {
13637
+ console.warn(error);
13638
+ }
13639
+ }
13543
13640
  });
13544
13641
  processedNodeManager.destroy();
13545
13642
  recording = false;
@@ -13945,7 +14042,7 @@
13945
14042
 
13946
14043
  var Config = {
13947
14044
  DEBUG: false,
13948
- LIB_VERSION: '2.68.0'
14045
+ LIB_VERSION: '2.69.0'
13949
14046
  };
13950
14047
 
13951
14048
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -15745,6 +15842,10 @@
15745
15842
  });
15746
15843
  };
15747
15844
 
15845
+ IDBStorageWrapper.prototype.isInitialized = function () {
15846
+ return !!this.dbPromise;
15847
+ };
15848
+
15748
15849
  /**
15749
15850
  * @param {IDBTransactionMode} mode
15750
15851
  * @param {function(IDBObjectStore): void} storeCb
@@ -16269,6 +16370,10 @@
16269
16370
  return PromisePolyfill.resolve();
16270
16371
  };
16271
16372
 
16373
+ LocalStorageWrapper.prototype.isInitialized = function () {
16374
+ return true;
16375
+ };
16376
+
16272
16377
  LocalStorageWrapper.prototype.setItem = function (key, value) {
16273
16378
  return new PromisePolyfill(_.bind(function (resolve, reject) {
16274
16379
  try {
@@ -16349,7 +16454,7 @@
16349
16454
  };
16350
16455
 
16351
16456
  RequestQueue.prototype.ensureInit = function () {
16352
- if (this.initialized) {
16457
+ if (this.initialized || !this.usePersistence) {
16353
16458
  return PromisePolyfill.resolve();
16354
16459
  }
16355
16460
 
@@ -17101,10 +17206,9 @@
17101
17206
 
17102
17207
  // disable persistence if localStorage is not supported
17103
17208
  // request-queue will automatically disable persistence if indexedDB fails to initialize
17104
- var usePersistence = localStorageSupported(options.sharedLockStorage, true);
17209
+ var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
17105
17210
 
17106
17211
  // each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
17107
- // this will be important when persistence is introduced
17108
17212
  this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
17109
17213
  this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
17110
17214
  this.batcher = new RequestBatcher(this.batcherKey, {
@@ -17485,12 +17589,17 @@
17485
17589
  * Makes sure that only one tab can be recording at a time.
17486
17590
  */
17487
17591
  var RecordingRegistry = function (options) {
17592
+ /** @type {IDBStorageWrapper} */
17488
17593
  this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
17489
17594
  this.errorReporter = options.errorReporter;
17490
17595
  this.mixpanelInstance = options.mixpanelInstance;
17491
17596
  this.sharedLockStorage = options.sharedLockStorage;
17492
17597
  };
17493
17598
 
17599
+ RecordingRegistry.prototype.isPersistenceEnabled = function() {
17600
+ return !this.mixpanelInstance.get_config('disable_persistence');
17601
+ };
17602
+
17494
17603
  RecordingRegistry.prototype.handleError = function (err) {
17495
17604
  this.errorReporter('IndexedDB error: ', err);
17496
17605
  };
@@ -17499,6 +17608,10 @@
17499
17608
  * @param {import('./session-recording').SerializedRecording} serializedRecording
17500
17609
  */
17501
17610
  RecordingRegistry.prototype.setActiveRecording = function (serializedRecording) {
17611
+ if (!this.isPersistenceEnabled()) {
17612
+ return PromisePolyfill.resolve();
17613
+ }
17614
+
17502
17615
  var tabId = serializedRecording['tabId'];
17503
17616
  if (!tabId) {
17504
17617
  console.warn('No tab ID is set, cannot persist recording metadata.');
@@ -17516,6 +17629,10 @@
17516
17629
  * @returns {Promise<import('./session-recording').SerializedRecording>}
17517
17630
  */
17518
17631
  RecordingRegistry.prototype.getActiveRecording = function () {
17632
+ if (!this.isPersistenceEnabled()) {
17633
+ return PromisePolyfill.resolve(null);
17634
+ }
17635
+
17519
17636
  return this.idb.init()
17520
17637
  .then(function () {
17521
17638
  return this.idb.getItem(this.mixpanelInstance.get_tab_id());
@@ -17527,8 +17644,16 @@
17527
17644
  };
17528
17645
 
17529
17646
  RecordingRegistry.prototype.clearActiveRecording = function () {
17530
- // mark recording as expired instead of deleting it in case the page unloads mid-flush and doesn't make it to ingestion.
17531
- // this will ensure the next pageload will flush the remaining events, but not try to continue the recording.
17647
+ if (this.isPersistenceEnabled()) {
17648
+ // mark recording as expired instead of deleting it in case the page unloads mid-flush and doesn't make it to ingestion.
17649
+ // this will ensure the next pageload will flush the remaining events, but not try to continue the recording.
17650
+ return this.markActiveRecordingExpired();
17651
+ } else {
17652
+ return this.deleteActiveRecording();
17653
+ }
17654
+ };
17655
+
17656
+ RecordingRegistry.prototype.markActiveRecordingExpired = function () {
17532
17657
  return this.getActiveRecording()
17533
17658
  .then(function (serializedRecording) {
17534
17659
  if (serializedRecording) {
@@ -17539,11 +17664,25 @@
17539
17664
  .catch(this.handleError.bind(this));
17540
17665
  };
17541
17666
 
17667
+ RecordingRegistry.prototype.deleteActiveRecording = function () {
17668
+ // avoid initializing IDB if this registry instance hasn't already written a recording
17669
+ if (this.idb.isInitialized()) {
17670
+ return this.idb.removeItem(this.mixpanelInstance.get_tab_id())
17671
+ .catch(this.handleError.bind(this));
17672
+ } else {
17673
+ return PromisePolyfill.resolve();
17674
+ }
17675
+ };
17676
+
17542
17677
  /**
17543
17678
  * Flush any inactive recordings from the registry to minimize data loss.
17544
17679
  * The main idea here is that we can flush remaining rrweb events on the next page load if a tab is closed mid-batch.
17545
17680
  */
17546
17681
  RecordingRegistry.prototype.flushInactiveRecordings = function () {
17682
+ if (!this.isPersistenceEnabled()) {
17683
+ return PromisePolyfill.resolve([]);
17684
+ }
17685
+
17547
17686
  return this.idb.init()
17548
17687
  .then(function() {
17549
17688
  return this.idb.getAll();
@@ -20591,7 +20730,9 @@
20591
20730
  * This is primarily used for session recording, where data must be isolated to the current tab.
20592
20731
  */
20593
20732
  MixpanelLib.prototype._init_tab_id = function() {
20594
- if (_.sessionStorage.is_supported()) {
20733
+ if (this.get_config('disable_persistence')) {
20734
+ console$1.log('Tab ID initialization skipped due to disable_persistence config');
20735
+ } else if (_.sessionStorage.is_supported()) {
20595
20736
  try {
20596
20737
  var key_suffix = this.get_config('name') + '_' + this.get_config('token');
20597
20738
  var tab_id_key = 'mp_tab_id_' + key_suffix;
@@ -20625,6 +20766,11 @@
20625
20766
  };
20626
20767
 
20627
20768
  MixpanelLib.prototype._should_load_recorder = function () {
20769
+ if (this.get_config('disable_persistence')) {
20770
+ console$1.log('Load recorder check skipped due to disable_persistence config');
20771
+ return Promise.resolve(false);
20772
+ }
20773
+
20628
20774
  var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
20629
20775
  var tab_id = this.get_tab_id();
20630
20776
  return recording_registry_idb.init()