mixpanel-browser 2.67.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.
- package/CHANGELOG.md +5 -0
- package/dist/mixpanel-core.cjs.js +132 -6
- package/dist/mixpanel-recorder.js +186 -47
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +132 -6
- package/dist/mixpanel-with-recorder.js +308 -51
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.js +308 -51
- package/dist/mixpanel.cjs.js +308 -51
- package/dist/mixpanel.globals.js +132 -6
- package/dist/mixpanel.min.js +148 -146
- package/dist/mixpanel.module.js +308 -51
- package/dist/mixpanel.umd.js +308 -51
- package/dist/rrweb-compiled.js +190 -59
- package/package.json +14 -2
- package/rollup.config.mjs +2 -2
- package/src/autocapture/index.js +59 -1
- package/src/autocapture/rageclick.js +38 -0
- package/src/config.js +1 -1
- package/src/flags/index.js +22 -1
- package/src/index.d.ts +19 -0
- package/src/mixpanel-core.js +10 -2
- package/src/recorder/recorder.js +1 -1
- package/src/recorder/recording-registry.js +37 -2
- package/src/recorder/session-recording.js +2 -3
- package/src/request-queue.js +1 -1
- package/src/storage/indexed-db.js +4 -0
- package/src/storage/local-storage.js +4 -0
- package/src/storage/wrapper.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
**2.68.0** (11 Aug 2025)
|
|
2
|
+
- Initial rage-click detection support
|
|
3
|
+
- Block `<audio>` tags by default in Session Recording
|
|
4
|
+
- Add `flags.update_context()` method for updating context variables and refetching variants
|
|
5
|
+
|
|
1
6
|
**2.67.0** (17 Jul 2025)
|
|
2
7
|
- Use `get_api_host()` consistently across the SDK
|
|
3
8
|
- Include `device_id` in default Feature Flag context
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
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
|
|
@@ -2654,6 +2654,38 @@ function shouldTrackValue(value) {
|
|
|
2654
2654
|
return true;
|
|
2655
2655
|
}
|
|
2656
2656
|
|
|
2657
|
+
/** @const */ var DEFAULT_RAGE_CLICK_THRESHOLD_PX = 30;
|
|
2658
|
+
/** @const */ var DEFAULT_RAGE_CLICK_TIMEOUT_MS = 1000;
|
|
2659
|
+
/** @const */ var DEFAULT_RAGE_CLICK_CLICK_COUNT = 4;
|
|
2660
|
+
|
|
2661
|
+
function RageClickTracker() {
|
|
2662
|
+
this.clicks = [];
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
RageClickTracker.prototype.isRageClick = function(x, y, options) {
|
|
2666
|
+
options = options || {};
|
|
2667
|
+
var thresholdPx = options['threshold_px'] || DEFAULT_RAGE_CLICK_THRESHOLD_PX;
|
|
2668
|
+
var timeoutMs = options['timeout_ms'] || DEFAULT_RAGE_CLICK_TIMEOUT_MS;
|
|
2669
|
+
var clickCount = options['click_count'] || DEFAULT_RAGE_CLICK_CLICK_COUNT;
|
|
2670
|
+
var timestamp = Date.now();
|
|
2671
|
+
|
|
2672
|
+
var lastClick = this.clicks[this.clicks.length - 1];
|
|
2673
|
+
if (
|
|
2674
|
+
lastClick &&
|
|
2675
|
+
timestamp - lastClick.timestamp < timeoutMs &&
|
|
2676
|
+
Math.sqrt(Math.pow(x - lastClick.x, 2) + Math.pow(y - lastClick.y, 2)) < thresholdPx
|
|
2677
|
+
) {
|
|
2678
|
+
this.clicks.push({ x: x, y: y, timestamp: timestamp });
|
|
2679
|
+
if (this.clicks.length >= clickCount) {
|
|
2680
|
+
this.clicks = [];
|
|
2681
|
+
return true;
|
|
2682
|
+
}
|
|
2683
|
+
} else {
|
|
2684
|
+
this.clicks = [{ x: x, y: y, timestamp: timestamp }];
|
|
2685
|
+
}
|
|
2686
|
+
return false;
|
|
2687
|
+
};
|
|
2688
|
+
|
|
2657
2689
|
var AUTOCAPTURE_CONFIG_KEY = 'autocapture';
|
|
2658
2690
|
var LEGACY_PAGEVIEW_CONFIG_KEY = 'track_pageview';
|
|
2659
2691
|
|
|
@@ -2675,6 +2707,7 @@ var CONFIG_SCROLL_CHECKPOINTS = 'scroll_depth_percent_checkpoints';
|
|
|
2675
2707
|
var CONFIG_TRACK_CLICK = 'click';
|
|
2676
2708
|
var CONFIG_TRACK_INPUT = 'input';
|
|
2677
2709
|
var CONFIG_TRACK_PAGEVIEW = 'pageview';
|
|
2710
|
+
var CONFIG_TRACK_RAGE_CLICK = 'rage_click';
|
|
2678
2711
|
var CONFIG_TRACK_SCROLL = 'scroll';
|
|
2679
2712
|
var CONFIG_TRACK_SUBMIT = 'submit';
|
|
2680
2713
|
|
|
@@ -2692,6 +2725,7 @@ CONFIG_DEFAULTS$1[CONFIG_SCROLL_CHECKPOINTS] = [25, 50, 75, 100];
|
|
|
2692
2725
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_CLICK] = true;
|
|
2693
2726
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_INPUT] = true;
|
|
2694
2727
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
|
|
2728
|
+
CONFIG_DEFAULTS$1[CONFIG_TRACK_RAGE_CLICK] = true;
|
|
2695
2729
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_SCROLL] = true;
|
|
2696
2730
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_SUBMIT] = true;
|
|
2697
2731
|
|
|
@@ -2701,6 +2735,7 @@ var DEFAULT_PROPS = {
|
|
|
2701
2735
|
|
|
2702
2736
|
var MP_EV_CLICK = '$mp_click';
|
|
2703
2737
|
var MP_EV_INPUT = '$mp_input_change';
|
|
2738
|
+
var MP_EV_RAGE_CLICK = '$mp_rage_click';
|
|
2704
2739
|
var MP_EV_SCROLL = '$mp_scroll';
|
|
2705
2740
|
var MP_EV_SUBMIT = '$mp_submit';
|
|
2706
2741
|
|
|
@@ -2723,6 +2758,7 @@ Autocapture.prototype.init = function() {
|
|
|
2723
2758
|
this.initInputTracking();
|
|
2724
2759
|
this.initScrollTracking();
|
|
2725
2760
|
this.initSubmitTracking();
|
|
2761
|
+
this.initRageClickTracking();
|
|
2726
2762
|
};
|
|
2727
2763
|
|
|
2728
2764
|
Autocapture.prototype.getFullConfig = function() {
|
|
@@ -2801,6 +2837,11 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
|
|
|
2801
2837
|
return;
|
|
2802
2838
|
}
|
|
2803
2839
|
|
|
2840
|
+
var isCapturedForHeatMap = this.mp.is_recording_heatmap_data() && (
|
|
2841
|
+
(mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK)) ||
|
|
2842
|
+
(mpEventName === MP_EV_RAGE_CLICK && !this._getRageClickConfig())
|
|
2843
|
+
);
|
|
2844
|
+
|
|
2804
2845
|
var props = getPropsForDOMEvent(ev, {
|
|
2805
2846
|
allowElementCallback: this.getConfig(CONFIG_ALLOW_ELEMENT_CALLBACK),
|
|
2806
2847
|
allowSelectors: this.getConfig(CONFIG_ALLOW_SELECTORS),
|
|
@@ -2809,7 +2850,7 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
|
|
|
2809
2850
|
blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
|
|
2810
2851
|
captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
|
|
2811
2852
|
captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT),
|
|
2812
|
-
capturedForHeatMap:
|
|
2853
|
+
capturedForHeatMap: isCapturedForHeatMap,
|
|
2813
2854
|
});
|
|
2814
2855
|
if (props) {
|
|
2815
2856
|
_.extend(props, DEFAULT_PROPS);
|
|
@@ -2817,6 +2858,24 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
|
|
|
2817
2858
|
}
|
|
2818
2859
|
};
|
|
2819
2860
|
|
|
2861
|
+
Autocapture.prototype._getRageClickConfig = function() {
|
|
2862
|
+
var config = this.getConfig(CONFIG_TRACK_RAGE_CLICK);
|
|
2863
|
+
|
|
2864
|
+
if (!config) {
|
|
2865
|
+
return null; // rage click tracking disabled
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
if (config === true) {
|
|
2869
|
+
return {}; // use defaults
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2872
|
+
if (typeof config === 'object') {
|
|
2873
|
+
return config; // use custom configuration
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
return {}; // fallback to defaults for any other truthy value
|
|
2877
|
+
};
|
|
2878
|
+
|
|
2820
2879
|
Autocapture.prototype.initClickTracking = function() {
|
|
2821
2880
|
win.removeEventListener(EV_CLICK, this.listenerClick);
|
|
2822
2881
|
|
|
@@ -2918,6 +2977,36 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
2918
2977
|
}.bind(this)));
|
|
2919
2978
|
};
|
|
2920
2979
|
|
|
2980
|
+
Autocapture.prototype.initRageClickTracking = function() {
|
|
2981
|
+
win.removeEventListener(EV_CLICK, this.listenerRageClick);
|
|
2982
|
+
|
|
2983
|
+
var rageClickConfig = this._getRageClickConfig();
|
|
2984
|
+
if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
|
|
2985
|
+
return;
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2988
|
+
logger$4.log('Initializing rage click tracking');
|
|
2989
|
+
if (!this._rageClickTracker) {
|
|
2990
|
+
this._rageClickTracker = new RageClickTracker();
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
this.listenerRageClick = function(ev) {
|
|
2994
|
+
var currentRageClickConfig = this._getRageClickConfig();
|
|
2995
|
+
if (!currentRageClickConfig && !this.mp.is_recording_heatmap_data()) {
|
|
2996
|
+
return;
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
if (this.currentUrlBlocked()) {
|
|
3000
|
+
return;
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
if (this._rageClickTracker.isRageClick(ev['pageX'], ev['pageY'], currentRageClickConfig)) {
|
|
3004
|
+
this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
|
|
3005
|
+
}
|
|
3006
|
+
}.bind(this);
|
|
3007
|
+
win.addEventListener(EV_CLICK, this.listenerRageClick);
|
|
3008
|
+
};
|
|
3009
|
+
|
|
2921
3010
|
Autocapture.prototype.initScrollTracking = function() {
|
|
2922
3011
|
win.removeEventListener(EV_SCROLLEND, this.listenerScroll);
|
|
2923
3012
|
|
|
@@ -3004,6 +3093,7 @@ CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
|
3004
3093
|
var FeatureFlagManager = function(initOptions) {
|
|
3005
3094
|
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
3006
3095
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
3096
|
+
this.setMpConfig = initOptions.setConfigFunc;
|
|
3007
3097
|
this.getMpProperty = initOptions.getPropertyFunc;
|
|
3008
3098
|
this.track = initOptions.trackingFunc;
|
|
3009
3099
|
};
|
|
@@ -3041,6 +3131,23 @@ FeatureFlagManager.prototype.isSystemEnabled = function() {
|
|
|
3041
3131
|
return !!this.getMpConfig(FLAGS_CONFIG_KEY);
|
|
3042
3132
|
};
|
|
3043
3133
|
|
|
3134
|
+
FeatureFlagManager.prototype.updateContext = function(newContext, options) {
|
|
3135
|
+
if (!this.isSystemEnabled()) {
|
|
3136
|
+
logger$3.critical('Feature Flags not enabled, cannot update context');
|
|
3137
|
+
return Promise.resolve();
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3140
|
+
var ffConfig = this.getMpConfig(FLAGS_CONFIG_KEY);
|
|
3141
|
+
if (!_.isObject(ffConfig)) {
|
|
3142
|
+
ffConfig = {};
|
|
3143
|
+
}
|
|
3144
|
+
var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
|
|
3145
|
+
ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
|
|
3146
|
+
|
|
3147
|
+
this.setMpConfig(FLAGS_CONFIG_KEY, ffConfig);
|
|
3148
|
+
return this.fetchFlags();
|
|
3149
|
+
};
|
|
3150
|
+
|
|
3044
3151
|
FeatureFlagManager.prototype.areFlagsReady = function() {
|
|
3045
3152
|
if (!this.isSystemEnabled()) {
|
|
3046
3153
|
logger$3.error('Feature Flags not enabled');
|
|
@@ -3050,7 +3157,7 @@ FeatureFlagManager.prototype.areFlagsReady = function() {
|
|
|
3050
3157
|
|
|
3051
3158
|
FeatureFlagManager.prototype.fetchFlags = function() {
|
|
3052
3159
|
if (!this.isSystemEnabled()) {
|
|
3053
|
-
return;
|
|
3160
|
+
return Promise.resolve();
|
|
3054
3161
|
}
|
|
3055
3162
|
|
|
3056
3163
|
var distinctId = this.getMpProperty('distinct_id');
|
|
@@ -3090,6 +3197,8 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
3090
3197
|
this.markFetchComplete();
|
|
3091
3198
|
logger$3.error(error);
|
|
3092
3199
|
}.bind(this));
|
|
3200
|
+
|
|
3201
|
+
return this.fetchPromise;
|
|
3093
3202
|
};
|
|
3094
3203
|
|
|
3095
3204
|
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
@@ -3202,6 +3311,7 @@ FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype
|
|
|
3202
3311
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
3203
3312
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
3204
3313
|
FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
|
|
3314
|
+
FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
|
|
3205
3315
|
|
|
3206
3316
|
// Deprecated method
|
|
3207
3317
|
FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
|
|
@@ -3519,6 +3629,10 @@ LocalStorageWrapper.prototype.init = function () {
|
|
|
3519
3629
|
return PromisePolyfill.resolve();
|
|
3520
3630
|
};
|
|
3521
3631
|
|
|
3632
|
+
LocalStorageWrapper.prototype.isInitialized = function () {
|
|
3633
|
+
return true;
|
|
3634
|
+
};
|
|
3635
|
+
|
|
3522
3636
|
LocalStorageWrapper.prototype.setItem = function (key, value) {
|
|
3523
3637
|
return new PromisePolyfill(_.bind(function (resolve, reject) {
|
|
3524
3638
|
try {
|
|
@@ -3599,7 +3713,7 @@ var RequestQueue = function (storageKey, options) {
|
|
|
3599
3713
|
};
|
|
3600
3714
|
|
|
3601
3715
|
RequestQueue.prototype.ensureInit = function () {
|
|
3602
|
-
if (this.initialized) {
|
|
3716
|
+
if (this.initialized || !this.usePersistence) {
|
|
3603
3717
|
return PromisePolyfill.resolve();
|
|
3604
3718
|
}
|
|
3605
3719
|
|
|
@@ -5783,6 +5897,10 @@ IDBStorageWrapper.prototype.init = function () {
|
|
|
5783
5897
|
});
|
|
5784
5898
|
};
|
|
5785
5899
|
|
|
5900
|
+
IDBStorageWrapper.prototype.isInitialized = function () {
|
|
5901
|
+
return !!this.dbPromise;
|
|
5902
|
+
};
|
|
5903
|
+
|
|
5786
5904
|
/**
|
|
5787
5905
|
* @param {IDBTransactionMode} mode
|
|
5788
5906
|
* @param {function(IDBObjectStore): void} storeCb
|
|
@@ -5973,7 +6091,7 @@ var DEFAULT_CONFIG = {
|
|
|
5973
6091
|
'batch_autostart': true,
|
|
5974
6092
|
'hooks': {},
|
|
5975
6093
|
'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
|
|
5976
|
-
'record_block_selector': 'img, video',
|
|
6094
|
+
'record_block_selector': 'img, video, audio',
|
|
5977
6095
|
'record_canvas': false,
|
|
5978
6096
|
'record_collect_fonts': false,
|
|
5979
6097
|
'record_heatmap_data': false,
|
|
@@ -6197,6 +6315,7 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
6197
6315
|
return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
|
|
6198
6316
|
}, this),
|
|
6199
6317
|
getConfigFunc: _.bind(this.get_config, this),
|
|
6318
|
+
setConfigFunc: _.bind(this.set_config, this),
|
|
6200
6319
|
getPropertyFunc: _.bind(this.get_property, this),
|
|
6201
6320
|
trackingFunc: _.bind(this.track, this)
|
|
6202
6321
|
});
|
|
@@ -6215,7 +6334,9 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
6215
6334
|
* This is primarily used for session recording, where data must be isolated to the current tab.
|
|
6216
6335
|
*/
|
|
6217
6336
|
MixpanelLib.prototype._init_tab_id = function() {
|
|
6218
|
-
if (
|
|
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()) {
|
|
6219
6340
|
try {
|
|
6220
6341
|
var key_suffix = this.get_config('name') + '_' + this.get_config('token');
|
|
6221
6342
|
var tab_id_key = 'mp_tab_id_' + key_suffix;
|
|
@@ -6249,6 +6370,11 @@ MixpanelLib.prototype.get_tab_id = function () {
|
|
|
6249
6370
|
};
|
|
6250
6371
|
|
|
6251
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
|
+
|
|
6252
6378
|
var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
6253
6379
|
var tab_id = this.get_tab_id();
|
|
6254
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
|
-
|
|
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
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
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"
|
|
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
|
-
|
|
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(
|
|
13542
|
-
|
|
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.
|
|
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
|
-
|
|
17346
|
-
|
|
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();
|