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.
@@ -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;
@@ -13944,7 +14041,7 @@
13944
14041
  }
13945
14042
 
13946
14043
  var Config = {
13947
- LIB_VERSION: '2.68.0'
14044
+ LIB_VERSION: '2.69.0'
13948
14045
  };
13949
14046
 
13950
14047
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -15692,6 +15789,10 @@
15692
15789
  });
15693
15790
  };
15694
15791
 
15792
+ IDBStorageWrapper.prototype.isInitialized = function () {
15793
+ return !!this.dbPromise;
15794
+ };
15795
+
15695
15796
  /**
15696
15797
  * @param {IDBTransactionMode} mode
15697
15798
  * @param {function(IDBObjectStore): void} storeCb
@@ -16084,6 +16185,10 @@
16084
16185
  return PromisePolyfill.resolve();
16085
16186
  };
16086
16187
 
16188
+ LocalStorageWrapper.prototype.isInitialized = function () {
16189
+ return true;
16190
+ };
16191
+
16087
16192
  LocalStorageWrapper.prototype.setItem = function (key, value) {
16088
16193
  return new PromisePolyfill(_.bind(function (resolve, reject) {
16089
16194
  try {
@@ -16164,7 +16269,7 @@
16164
16269
  };
16165
16270
 
16166
16271
  RequestQueue.prototype.ensureInit = function () {
16167
- if (this.initialized) {
16272
+ if (this.initialized || !this.usePersistence) {
16168
16273
  return PromisePolyfill.resolve();
16169
16274
  }
16170
16275
 
@@ -16916,10 +17021,9 @@
16916
17021
 
16917
17022
  // disable persistence if localStorage is not supported
16918
17023
  // request-queue will automatically disable persistence if indexedDB fails to initialize
16919
- var usePersistence = localStorageSupported(options.sharedLockStorage, true);
17024
+ var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
16920
17025
 
16921
17026
  // each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
16922
- // this will be important when persistence is introduced
16923
17027
  this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
16924
17028
  this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
16925
17029
  this.batcher = new RequestBatcher(this.batcherKey, {
@@ -17300,12 +17404,17 @@
17300
17404
  * Makes sure that only one tab can be recording at a time.
17301
17405
  */
17302
17406
  var RecordingRegistry = function (options) {
17407
+ /** @type {IDBStorageWrapper} */
17303
17408
  this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
17304
17409
  this.errorReporter = options.errorReporter;
17305
17410
  this.mixpanelInstance = options.mixpanelInstance;
17306
17411
  this.sharedLockStorage = options.sharedLockStorage;
17307
17412
  };
17308
17413
 
17414
+ RecordingRegistry.prototype.isPersistenceEnabled = function() {
17415
+ return !this.mixpanelInstance.get_config('disable_persistence');
17416
+ };
17417
+
17309
17418
  RecordingRegistry.prototype.handleError = function (err) {
17310
17419
  this.errorReporter('IndexedDB error: ', err);
17311
17420
  };
@@ -17314,6 +17423,10 @@
17314
17423
  * @param {import('./session-recording').SerializedRecording} serializedRecording
17315
17424
  */
17316
17425
  RecordingRegistry.prototype.setActiveRecording = function (serializedRecording) {
17426
+ if (!this.isPersistenceEnabled()) {
17427
+ return PromisePolyfill.resolve();
17428
+ }
17429
+
17317
17430
  var tabId = serializedRecording['tabId'];
17318
17431
  if (!tabId) {
17319
17432
  console.warn('No tab ID is set, cannot persist recording metadata.');
@@ -17331,6 +17444,10 @@
17331
17444
  * @returns {Promise<import('./session-recording').SerializedRecording>}
17332
17445
  */
17333
17446
  RecordingRegistry.prototype.getActiveRecording = function () {
17447
+ if (!this.isPersistenceEnabled()) {
17448
+ return PromisePolyfill.resolve(null);
17449
+ }
17450
+
17334
17451
  return this.idb.init()
17335
17452
  .then(function () {
17336
17453
  return this.idb.getItem(this.mixpanelInstance.get_tab_id());
@@ -17342,8 +17459,16 @@
17342
17459
  };
17343
17460
 
17344
17461
  RecordingRegistry.prototype.clearActiveRecording = function () {
17345
- // mark recording as expired instead of deleting it in case the page unloads mid-flush and doesn't make it to ingestion.
17346
- // this will ensure the next pageload will flush the remaining events, but not try to continue the recording.
17462
+ if (this.isPersistenceEnabled()) {
17463
+ // mark recording as expired instead of deleting it in case the page unloads mid-flush and doesn't make it to ingestion.
17464
+ // this will ensure the next pageload will flush the remaining events, but not try to continue the recording.
17465
+ return this.markActiveRecordingExpired();
17466
+ } else {
17467
+ return this.deleteActiveRecording();
17468
+ }
17469
+ };
17470
+
17471
+ RecordingRegistry.prototype.markActiveRecordingExpired = function () {
17347
17472
  return this.getActiveRecording()
17348
17473
  .then(function (serializedRecording) {
17349
17474
  if (serializedRecording) {
@@ -17354,11 +17479,25 @@
17354
17479
  .catch(this.handleError.bind(this));
17355
17480
  };
17356
17481
 
17482
+ RecordingRegistry.prototype.deleteActiveRecording = function () {
17483
+ // avoid initializing IDB if this registry instance hasn't already written a recording
17484
+ if (this.idb.isInitialized()) {
17485
+ return this.idb.removeItem(this.mixpanelInstance.get_tab_id())
17486
+ .catch(this.handleError.bind(this));
17487
+ } else {
17488
+ return PromisePolyfill.resolve();
17489
+ }
17490
+ };
17491
+
17357
17492
  /**
17358
17493
  * Flush any inactive recordings from the registry to minimize data loss.
17359
17494
  * The main idea here is that we can flush remaining rrweb events on the next page load if a tab is closed mid-batch.
17360
17495
  */
17361
17496
  RecordingRegistry.prototype.flushInactiveRecordings = function () {
17497
+ if (!this.isPersistenceEnabled()) {
17498
+ return PromisePolyfill.resolve([]);
17499
+ }
17500
+
17362
17501
  return this.idb.init()
17363
17502
  .then(function() {
17364
17503
  return this.idb.getAll();