mixpanel-browser 2.76.0 → 2.78.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/.claude/settings.local.json +3 -1
- package/.github/dependabot.yml +8 -0
- package/.github/workflows/integration-tests.yml +2 -2
- package/.github/workflows/unit-tests.yml +2 -2
- package/CHANGELOG.md +8 -0
- package/dist/async-modules/mixpanel-recorder-BjSlYaNJ.min.js +2 -0
- package/dist/async-modules/mixpanel-recorder-BjSlYaNJ.min.js.map +1 -0
- package/dist/async-modules/{mixpanel-recorder-bIS4LMGd.js → mixpanel-recorder-zMBXIyeG.js} +84 -10
- package/dist/async-modules/{mixpanel-targeting-VOeN7RWY.min.js → mixpanel-targeting-BSHal4N9.min.js} +2 -2
- package/dist/async-modules/{mixpanel-targeting-VOeN7RWY.min.js.map → mixpanel-targeting-BSHal4N9.min.js.map} +1 -1
- package/dist/async-modules/{mixpanel-targeting-BcAPS-Mz.js → mixpanel-targeting-UHf4eBfC.js} +1 -1
- package/dist/mixpanel-core.cjs.d.ts +3 -1
- package/dist/mixpanel-core.cjs.js +292 -130
- package/dist/mixpanel-recorder.js +84 -10
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-targeting.js +1 -1
- package/dist/mixpanel-targeting.min.js +1 -1
- package/dist/mixpanel-targeting.min.js.map +1 -1
- package/dist/mixpanel-with-async-modules.cjs.d.ts +3 -1
- package/dist/mixpanel-with-async-modules.cjs.js +294 -132
- package/dist/mixpanel-with-async-recorder.cjs.d.ts +3 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +294 -132
- package/dist/mixpanel-with-recorder.d.ts +3 -1
- package/dist/mixpanel-with-recorder.js +381 -168
- package/dist/mixpanel-with-recorder.min.d.ts +3 -1
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.d.ts +3 -1
- package/dist/mixpanel.amd.js +381 -168
- package/dist/mixpanel.cjs.d.ts +3 -1
- package/dist/mixpanel.cjs.js +381 -168
- package/dist/mixpanel.globals.js +294 -132
- package/dist/mixpanel.min.js +191 -186
- package/dist/mixpanel.module.d.ts +3 -1
- package/dist/mixpanel.module.js +381 -168
- package/dist/mixpanel.umd.d.ts +3 -1
- package/dist/mixpanel.umd.js +381 -168
- package/dist/rrweb-bundled.js +61 -9
- package/dist/rrweb-compiled.js +56 -9
- package/package.json +6 -5
- package/src/config.js +1 -1
- package/src/flags/CLAUDE.md +24 -0
- package/src/flags/index.js +109 -80
- package/src/index.d.ts +3 -1
- package/src/mixpanel-core.js +4 -2
- package/src/recorder/session-recording.js +5 -1
- package/src/recorder/utils.js +27 -1
- package/src/recorder-manager.js +110 -2
- package/testServer.js +16 -1
- package/dist/async-modules/mixpanel-recorder-hFoTniVR.min.js +0 -2
- package/dist/async-modules/mixpanel-recorder-hFoTniVR.min.js.map +0 -1
- /package/src/loaders/{loader-module-with-async-recorder.d.ts → loader-module-with-async-modules.d.ts} +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
5
|
+
LIB_VERSION: '2.78.0'
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// Window global names for async modules
|
|
@@ -2267,7 +2267,7 @@ var EVENT_HANDLER_ATTRIBUTES = [
|
|
|
2267
2267
|
|
|
2268
2268
|
var MAX_DEPTH = 5;
|
|
2269
2269
|
|
|
2270
|
-
var logger$
|
|
2270
|
+
var logger$5 = console_with_prefix('autocapture');
|
|
2271
2271
|
|
|
2272
2272
|
|
|
2273
2273
|
function getClasses(el) {
|
|
@@ -2531,7 +2531,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
|
2531
2531
|
return false;
|
|
2532
2532
|
}
|
|
2533
2533
|
} catch (err) {
|
|
2534
|
-
logger$
|
|
2534
|
+
logger$5.critical('Error while checking element in allowElementCallback', err);
|
|
2535
2535
|
return false;
|
|
2536
2536
|
}
|
|
2537
2537
|
}
|
|
@@ -2548,7 +2548,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
|
2548
2548
|
return true;
|
|
2549
2549
|
}
|
|
2550
2550
|
} catch (err) {
|
|
2551
|
-
logger$
|
|
2551
|
+
logger$5.critical('Error while checking selector: ' + sel, err);
|
|
2552
2552
|
}
|
|
2553
2553
|
}
|
|
2554
2554
|
return false;
|
|
@@ -2563,7 +2563,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
|
2563
2563
|
return true;
|
|
2564
2564
|
}
|
|
2565
2565
|
} catch (err) {
|
|
2566
|
-
logger$
|
|
2566
|
+
logger$5.critical('Error while checking element in blockElementCallback', err);
|
|
2567
2567
|
return true;
|
|
2568
2568
|
}
|
|
2569
2569
|
}
|
|
@@ -2577,7 +2577,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
|
2577
2577
|
return true;
|
|
2578
2578
|
}
|
|
2579
2579
|
} catch (err) {
|
|
2580
|
-
logger$
|
|
2580
|
+
logger$5.critical('Error while checking selector: ' + sel, err);
|
|
2581
2581
|
}
|
|
2582
2582
|
}
|
|
2583
2583
|
}
|
|
@@ -3041,7 +3041,7 @@ ShadowDOMObserver.prototype.observeShadowRoot = function(shadowRoot) {
|
|
|
3041
3041
|
observer.observe(shadowRoot, this.observerConfig);
|
|
3042
3042
|
this.shadowObservers.push(observer);
|
|
3043
3043
|
} catch (e) {
|
|
3044
|
-
logger$
|
|
3044
|
+
logger$5.critical('Error while observing shadow root', e);
|
|
3045
3045
|
}
|
|
3046
3046
|
};
|
|
3047
3047
|
|
|
@@ -3052,7 +3052,7 @@ ShadowDOMObserver.prototype.start = function() {
|
|
|
3052
3052
|
}
|
|
3053
3053
|
|
|
3054
3054
|
if (!weakSetSupported()) {
|
|
3055
|
-
logger$
|
|
3055
|
+
logger$5.critical('Shadow DOM observation unavailable: WeakSet not supported');
|
|
3056
3056
|
return;
|
|
3057
3057
|
}
|
|
3058
3058
|
|
|
@@ -3068,7 +3068,7 @@ ShadowDOMObserver.prototype.stop = function() {
|
|
|
3068
3068
|
try {
|
|
3069
3069
|
this.shadowObservers[i].disconnect();
|
|
3070
3070
|
} catch (e) {
|
|
3071
|
-
logger$
|
|
3071
|
+
logger$5.critical('Error while disconnecting shadow DOM observer', e);
|
|
3072
3072
|
}
|
|
3073
3073
|
}
|
|
3074
3074
|
this.shadowObservers = [];
|
|
@@ -3256,7 +3256,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
3256
3256
|
|
|
3257
3257
|
this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
|
|
3258
3258
|
} catch (e) {
|
|
3259
|
-
logger$
|
|
3259
|
+
logger$5.critical('Error while setting up mutation observer', e);
|
|
3260
3260
|
}
|
|
3261
3261
|
}
|
|
3262
3262
|
|
|
@@ -3271,7 +3271,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
3271
3271
|
);
|
|
3272
3272
|
this.shadowDOMObserver.start();
|
|
3273
3273
|
} catch (e) {
|
|
3274
|
-
logger$
|
|
3274
|
+
logger$5.critical('Error while setting up shadow DOM observer', e);
|
|
3275
3275
|
this.shadowDOMObserver = null;
|
|
3276
3276
|
}
|
|
3277
3277
|
}
|
|
@@ -3298,7 +3298,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
3298
3298
|
try {
|
|
3299
3299
|
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
3300
3300
|
} catch (e) {
|
|
3301
|
-
logger$
|
|
3301
|
+
logger$5.critical('Error while removing event listener', e);
|
|
3302
3302
|
}
|
|
3303
3303
|
}
|
|
3304
3304
|
this.eventListeners = [];
|
|
@@ -3307,7 +3307,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
3307
3307
|
try {
|
|
3308
3308
|
this.mutationObserver.disconnect();
|
|
3309
3309
|
} catch (e) {
|
|
3310
|
-
logger$
|
|
3310
|
+
logger$5.critical('Error while disconnecting mutation observer', e);
|
|
3311
3311
|
}
|
|
3312
3312
|
this.mutationObserver = null;
|
|
3313
3313
|
}
|
|
@@ -3316,7 +3316,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
3316
3316
|
try {
|
|
3317
3317
|
this.shadowDOMObserver.stop();
|
|
3318
3318
|
} catch (e) {
|
|
3319
|
-
logger$
|
|
3319
|
+
logger$5.critical('Error while stopping shadow DOM observer', e);
|
|
3320
3320
|
}
|
|
3321
3321
|
this.shadowDOMObserver = null;
|
|
3322
3322
|
}
|
|
@@ -3394,7 +3394,7 @@ var Autocapture = function(mp) {
|
|
|
3394
3394
|
|
|
3395
3395
|
Autocapture.prototype.init = function() {
|
|
3396
3396
|
if (!minDOMApisSupported()) {
|
|
3397
|
-
logger$
|
|
3397
|
+
logger$5.critical('Autocapture unavailable: missing required DOM APIs');
|
|
3398
3398
|
return;
|
|
3399
3399
|
}
|
|
3400
3400
|
this.initPageListeners();
|
|
@@ -3434,7 +3434,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
3434
3434
|
try {
|
|
3435
3435
|
return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
|
|
3436
3436
|
} catch (err) {
|
|
3437
|
-
logger$
|
|
3437
|
+
logger$5.critical('Error while checking block URL regexes: ', err);
|
|
3438
3438
|
return true;
|
|
3439
3439
|
}
|
|
3440
3440
|
}
|
|
@@ -3447,7 +3447,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
3447
3447
|
try {
|
|
3448
3448
|
return urlMatchesRegexList(currentUrl, blockUrlRegexes);
|
|
3449
3449
|
} catch (err) {
|
|
3450
|
-
logger$
|
|
3450
|
+
logger$5.critical('Error while checking block URL regexes: ', err);
|
|
3451
3451
|
return true;
|
|
3452
3452
|
}
|
|
3453
3453
|
};
|
|
@@ -3585,7 +3585,7 @@ Autocapture.prototype._initScrollDepthTracking = function() {
|
|
|
3585
3585
|
return;
|
|
3586
3586
|
}
|
|
3587
3587
|
|
|
3588
|
-
logger$
|
|
3588
|
+
logger$5.log('Initializing scroll depth tracking');
|
|
3589
3589
|
|
|
3590
3590
|
this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
|
|
3591
3591
|
|
|
@@ -3611,7 +3611,7 @@ Autocapture.prototype.initClickTracking = function() {
|
|
|
3611
3611
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
|
|
3612
3612
|
return;
|
|
3613
3613
|
}
|
|
3614
|
-
logger$
|
|
3614
|
+
logger$5.log('Initializing click tracking');
|
|
3615
3615
|
|
|
3616
3616
|
this.listenerClick = function(ev) {
|
|
3617
3617
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
|
|
@@ -3630,7 +3630,7 @@ Autocapture.prototype.initDeadClickTracking = function() {
|
|
|
3630
3630
|
return;
|
|
3631
3631
|
}
|
|
3632
3632
|
|
|
3633
|
-
logger$
|
|
3633
|
+
logger$5.log('Initializing dead click tracking');
|
|
3634
3634
|
if (!this._deadClickTracker) {
|
|
3635
3635
|
this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
|
|
3636
3636
|
this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
|
|
@@ -3664,7 +3664,7 @@ Autocapture.prototype.initInputTracking = function() {
|
|
|
3664
3664
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
3665
3665
|
return;
|
|
3666
3666
|
}
|
|
3667
|
-
logger$
|
|
3667
|
+
logger$5.log('Initializing input tracking');
|
|
3668
3668
|
|
|
3669
3669
|
this.listenerChange = function(ev) {
|
|
3670
3670
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
@@ -3681,7 +3681,7 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
3681
3681
|
if (!this.pageviewTrackingConfig()) {
|
|
3682
3682
|
return;
|
|
3683
3683
|
}
|
|
3684
|
-
logger$
|
|
3684
|
+
logger$5.log('Initializing pageview tracking');
|
|
3685
3685
|
|
|
3686
3686
|
var previousTrackedUrl = '';
|
|
3687
3687
|
var tracked = false;
|
|
@@ -3716,7 +3716,7 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
3716
3716
|
}
|
|
3717
3717
|
if (didPathChange) {
|
|
3718
3718
|
this.lastScrollCheckpoint = 0;
|
|
3719
|
-
logger$
|
|
3719
|
+
logger$5.log('Path change: re-initializing scroll depth checkpoints');
|
|
3720
3720
|
}
|
|
3721
3721
|
}
|
|
3722
3722
|
}.bind(this));
|
|
@@ -3731,7 +3731,7 @@ Autocapture.prototype.initRageClickTracking = function() {
|
|
|
3731
3731
|
return;
|
|
3732
3732
|
}
|
|
3733
3733
|
|
|
3734
|
-
logger$
|
|
3734
|
+
logger$5.log('Initializing rage click tracking');
|
|
3735
3735
|
if (!this._rageClickTracker) {
|
|
3736
3736
|
this._rageClickTracker = new RageClickTracker();
|
|
3737
3737
|
}
|
|
@@ -3761,7 +3761,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
3761
3761
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
3762
3762
|
return;
|
|
3763
3763
|
}
|
|
3764
|
-
logger$
|
|
3764
|
+
logger$5.log('Initializing scroll tracking');
|
|
3765
3765
|
this.lastScrollCheckpoint = 0;
|
|
3766
3766
|
|
|
3767
3767
|
var scrollTrackFunction = function() {
|
|
@@ -3798,7 +3798,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
3798
3798
|
}
|
|
3799
3799
|
}
|
|
3800
3800
|
} catch (err) {
|
|
3801
|
-
logger$
|
|
3801
|
+
logger$5.critical('Error while calculating scroll percentage', err);
|
|
3802
3802
|
}
|
|
3803
3803
|
if (shouldTrack) {
|
|
3804
3804
|
this.mp.track(MP_EV_SCROLL, props);
|
|
@@ -3816,7 +3816,7 @@ Autocapture.prototype.initSubmitTracking = function() {
|
|
|
3816
3816
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
3817
3817
|
return;
|
|
3818
3818
|
}
|
|
3819
|
-
logger$
|
|
3819
|
+
logger$5.log('Initializing submit tracking');
|
|
3820
3820
|
|
|
3821
3821
|
this.listenerSubmit = function(ev) {
|
|
3822
3822
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
@@ -3838,7 +3838,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
|
|
|
3838
3838
|
return;
|
|
3839
3839
|
}
|
|
3840
3840
|
|
|
3841
|
-
logger$
|
|
3841
|
+
logger$5.log('Initializing page visibility tracking.');
|
|
3842
3842
|
this._initScrollDepthTracking();
|
|
3843
3843
|
var previousTrackedUrl = _.info.currentUrl();
|
|
3844
3844
|
|
|
@@ -3923,7 +3923,7 @@ var getTargetingPromise = function(loadExtraBundle, targetingSrc) {
|
|
|
3923
3923
|
return win[TARGETING_GLOBAL_NAME];
|
|
3924
3924
|
};
|
|
3925
3925
|
|
|
3926
|
-
var logger$
|
|
3926
|
+
var logger$4 = console_with_prefix('flags');
|
|
3927
3927
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
3928
3928
|
|
|
3929
3929
|
var CONFIG_CONTEXT = 'context';
|
|
@@ -3966,12 +3966,14 @@ var FeatureFlagManager = function(initOptions) {
|
|
|
3966
3966
|
|
|
3967
3967
|
FeatureFlagManager.prototype.init = function() {
|
|
3968
3968
|
if (!this.minApisSupported()) {
|
|
3969
|
-
logger$
|
|
3969
|
+
logger$4.critical('Feature Flags unavailable: missing minimum required APIs');
|
|
3970
3970
|
return;
|
|
3971
3971
|
}
|
|
3972
3972
|
|
|
3973
3973
|
this.flags = null;
|
|
3974
|
-
this.fetchFlags()
|
|
3974
|
+
this.fetchFlags().catch(function() {
|
|
3975
|
+
logger$4.error('Error fetching flags during init');
|
|
3976
|
+
});
|
|
3975
3977
|
|
|
3976
3978
|
this.trackedFeatures = new Set();
|
|
3977
3979
|
this.pendingFirstTimeEvents = {};
|
|
@@ -4001,7 +4003,7 @@ FeatureFlagManager.prototype.isSystemEnabled = function() {
|
|
|
4001
4003
|
|
|
4002
4004
|
FeatureFlagManager.prototype.updateContext = function(newContext, options) {
|
|
4003
4005
|
if (!this.isSystemEnabled()) {
|
|
4004
|
-
logger$
|
|
4006
|
+
logger$4.critical('Feature Flags not enabled, cannot update context');
|
|
4005
4007
|
return Promise.resolve();
|
|
4006
4008
|
}
|
|
4007
4009
|
|
|
@@ -4012,13 +4014,17 @@ FeatureFlagManager.prototype.updateContext = function(newContext, options) {
|
|
|
4012
4014
|
var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
|
|
4013
4015
|
ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
|
|
4014
4016
|
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
+
var configUpdate = {};
|
|
4018
|
+
configUpdate[FLAGS_CONFIG_KEY] = ffConfig;
|
|
4019
|
+
this.setMpConfig(configUpdate);
|
|
4020
|
+
return this.fetchFlags().catch(function() {
|
|
4021
|
+
logger$4.error('Error fetching flags during updateContext');
|
|
4022
|
+
});
|
|
4017
4023
|
};
|
|
4018
4024
|
|
|
4019
4025
|
FeatureFlagManager.prototype.areFlagsReady = function() {
|
|
4020
4026
|
if (!this.isSystemEnabled()) {
|
|
4021
|
-
logger$
|
|
4027
|
+
logger$4.error('Feature Flags not enabled');
|
|
4022
4028
|
}
|
|
4023
4029
|
return !!this.flags;
|
|
4024
4030
|
};
|
|
@@ -4031,7 +4037,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
4031
4037
|
var distinctId = this.getMpProperty('distinct_id');
|
|
4032
4038
|
var deviceId = this.getMpProperty('$device_id');
|
|
4033
4039
|
var traceparent = generateTraceparent();
|
|
4034
|
-
logger$
|
|
4040
|
+
logger$4.log('Fetching flags for distinct ID: ' + distinctId);
|
|
4035
4041
|
|
|
4036
4042
|
var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
|
|
4037
4043
|
var searchParams = new URLSearchParams();
|
|
@@ -4050,99 +4056,113 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
4050
4056
|
}
|
|
4051
4057
|
}).then(function(response) {
|
|
4052
4058
|
this.markFetchComplete();
|
|
4053
|
-
return response.json()
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
}
|
|
4059
|
+
return response.json();
|
|
4060
|
+
}.bind(this)).then(function(responseBody) {
|
|
4061
|
+
var responseFlags = responseBody['flags'];
|
|
4062
|
+
if (!responseFlags) {
|
|
4063
|
+
throw new Error('No flags in API response');
|
|
4064
|
+
}
|
|
4065
|
+
var flags = new Map();
|
|
4066
|
+
var pendingFirstTimeEvents = {};
|
|
4067
|
+
|
|
4068
|
+
// Process flags from response
|
|
4069
|
+
_.each(responseFlags, function(data, key) {
|
|
4070
|
+
// Check if this flag has any activated first-time events this session
|
|
4071
|
+
var hasActivatedEvent = false;
|
|
4072
|
+
var prefix = key + ':';
|
|
4073
|
+
_.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
|
|
4074
|
+
if (eventKey.startsWith(prefix)) {
|
|
4075
|
+
hasActivatedEvent = true;
|
|
4076
|
+
}
|
|
4077
|
+
});
|
|
4071
4078
|
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
}
|
|
4078
|
-
} else {
|
|
4079
|
-
// Use server's current variant
|
|
4080
|
-
flags.set(key, {
|
|
4081
|
-
'key': data['variant_key'],
|
|
4082
|
-
'value': data['variant_value'],
|
|
4083
|
-
'experiment_id': data['experiment_id'],
|
|
4084
|
-
'is_experiment_active': data['is_experiment_active'],
|
|
4085
|
-
'is_qa_tester': data['is_qa_tester']
|
|
4086
|
-
});
|
|
4079
|
+
if (hasActivatedEvent) {
|
|
4080
|
+
// Preserve the activated variant, don't overwrite with server's current variant
|
|
4081
|
+
var currentFlag = this.flags && this.flags.get(key);
|
|
4082
|
+
if (currentFlag) {
|
|
4083
|
+
flags.set(key, currentFlag);
|
|
4087
4084
|
}
|
|
4088
|
-
}
|
|
4085
|
+
} else {
|
|
4086
|
+
// Use server's current variant
|
|
4087
|
+
flags.set(key, {
|
|
4088
|
+
'key': data['variant_key'],
|
|
4089
|
+
'value': data['variant_value'],
|
|
4090
|
+
'experiment_id': data['experiment_id'],
|
|
4091
|
+
'is_experiment_active': data['is_experiment_active'],
|
|
4092
|
+
'is_qa_tester': data['is_qa_tester']
|
|
4093
|
+
});
|
|
4094
|
+
}
|
|
4095
|
+
}, this);
|
|
4089
4096
|
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4097
|
+
// Process top-level pending_first_time_events array
|
|
4098
|
+
var topLevelDefinitions = responseBody['pending_first_time_events'];
|
|
4099
|
+
if (topLevelDefinitions && topLevelDefinitions.length > 0) {
|
|
4100
|
+
_.each(topLevelDefinitions, function(def) {
|
|
4101
|
+
var flagKey = def['flag_key'];
|
|
4102
|
+
var eventKey = getPendingEventKey(flagKey, def['first_time_event_hash']);
|
|
4096
4103
|
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4104
|
+
// Skip if this specific event has already been activated this session
|
|
4105
|
+
if (this.activatedFirstTimeEvents[eventKey]) {
|
|
4106
|
+
return;
|
|
4107
|
+
}
|
|
4101
4108
|
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4109
|
+
// Store pending event definition using composite key
|
|
4110
|
+
pendingFirstTimeEvents[eventKey] = {
|
|
4111
|
+
'flag_key': flagKey,
|
|
4112
|
+
'flag_id': def['flag_id'],
|
|
4113
|
+
'project_id': def['project_id'],
|
|
4114
|
+
'first_time_event_hash': def['first_time_event_hash'],
|
|
4115
|
+
'event_name': def['event_name'],
|
|
4116
|
+
'property_filters': def['property_filters'],
|
|
4117
|
+
'pending_variant': def['pending_variant']
|
|
4118
|
+
};
|
|
4119
|
+
}, this);
|
|
4120
|
+
}
|
|
4114
4121
|
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4122
|
+
// Preserve any activated orphaned flags (flags that were activated but are no longer in response)
|
|
4123
|
+
if (this.activatedFirstTimeEvents) {
|
|
4124
|
+
_.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
|
|
4125
|
+
var flagKey = getFlagKeyFromPendingEventKey(eventKey);
|
|
4126
|
+
if (activated && !flags.has(flagKey) && this.flags && this.flags.has(flagKey)) {
|
|
4127
|
+
// Keep the activated flag even though it's not in the new response
|
|
4128
|
+
flags.set(flagKey, this.flags.get(flagKey));
|
|
4129
|
+
}
|
|
4130
|
+
}, this);
|
|
4131
|
+
}
|
|
4125
4132
|
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4133
|
+
this.flags = flags;
|
|
4134
|
+
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
4135
|
+
this._traceparent = traceparent;
|
|
4129
4136
|
|
|
4130
|
-
|
|
4131
|
-
}.bind(this)).catch(function(error) {
|
|
4132
|
-
this.markFetchComplete();
|
|
4133
|
-
logger$3.error(error);
|
|
4134
|
-
}.bind(this));
|
|
4137
|
+
this._loadTargetingIfNeeded();
|
|
4135
4138
|
}.bind(this)).catch(function(error) {
|
|
4136
|
-
this.
|
|
4137
|
-
|
|
4139
|
+
if (this._fetchInProgressStartTime) {
|
|
4140
|
+
this.markFetchComplete();
|
|
4141
|
+
}
|
|
4142
|
+
logger$4.error(error);
|
|
4143
|
+
throw error;
|
|
4138
4144
|
}.bind(this));
|
|
4139
4145
|
|
|
4140
4146
|
return this.fetchPromise;
|
|
4141
4147
|
};
|
|
4142
4148
|
|
|
4149
|
+
FeatureFlagManager.prototype.loadFlags = function() {
|
|
4150
|
+
if (!this.isSystemEnabled()) {
|
|
4151
|
+
return Promise.resolve();
|
|
4152
|
+
}
|
|
4153
|
+
if (!this.trackedFeatures) {
|
|
4154
|
+
logger$4.error('loadFlags called before init');
|
|
4155
|
+
return Promise.resolve();
|
|
4156
|
+
}
|
|
4157
|
+
if (this._fetchInProgressStartTime) {
|
|
4158
|
+
return this.fetchPromise;
|
|
4159
|
+
}
|
|
4160
|
+
return this.fetchFlags();
|
|
4161
|
+
};
|
|
4162
|
+
|
|
4143
4163
|
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
4144
4164
|
if (!this._fetchInProgressStartTime) {
|
|
4145
|
-
logger$
|
|
4165
|
+
logger$4.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
4146
4166
|
return;
|
|
4147
4167
|
}
|
|
4148
4168
|
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
@@ -4164,7 +4184,7 @@ FeatureFlagManager.prototype._loadTargetingIfNeeded = function() {
|
|
|
4164
4184
|
|
|
4165
4185
|
if (hasPropertyFilters) {
|
|
4166
4186
|
this.getTargeting().then(function() {
|
|
4167
|
-
logger$
|
|
4187
|
+
logger$4.log('targeting loaded for property filter evaluation');
|
|
4168
4188
|
});
|
|
4169
4189
|
}
|
|
4170
4190
|
};
|
|
@@ -4179,7 +4199,7 @@ FeatureFlagManager.prototype.getTargeting = function() {
|
|
|
4179
4199
|
this.loadExtraBundle.bind(this),
|
|
4180
4200
|
this.targetingSrc
|
|
4181
4201
|
).catch(function(error) {
|
|
4182
|
-
logger$
|
|
4202
|
+
logger$4.error('Failed to load targeting: ' + error);
|
|
4183
4203
|
}.bind(this));
|
|
4184
4204
|
};
|
|
4185
4205
|
|
|
@@ -4233,7 +4253,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
4233
4253
|
|
|
4234
4254
|
// If no targeting library and event has property filters, skip it
|
|
4235
4255
|
if (!targeting && pendingEvent['property_filters'] && !_.isEmptyObject(pendingEvent['property_filters'])) {
|
|
4236
|
-
logger$
|
|
4256
|
+
logger$4.warn('Skipping event check for "' + flagKey + '" - property filters require targeting library');
|
|
4237
4257
|
return;
|
|
4238
4258
|
}
|
|
4239
4259
|
|
|
@@ -4256,7 +4276,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
4256
4276
|
}
|
|
4257
4277
|
|
|
4258
4278
|
if (matchResult.error) {
|
|
4259
|
-
logger$
|
|
4279
|
+
logger$4.error('Error checking first-time event for flag "' + flagKey + '": ' + matchResult.error);
|
|
4260
4280
|
return;
|
|
4261
4281
|
}
|
|
4262
4282
|
|
|
@@ -4264,7 +4284,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
4264
4284
|
return;
|
|
4265
4285
|
}
|
|
4266
4286
|
|
|
4267
|
-
logger$
|
|
4287
|
+
logger$4.log('First-time event matched for flag "' + flagKey + '": ' + eventName);
|
|
4268
4288
|
|
|
4269
4289
|
var newVariant = {
|
|
4270
4290
|
'key': pendingEvent['pending_variant']['variant_key'],
|
|
@@ -4305,7 +4325,7 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
|
|
|
4305
4325
|
'first_time_event_hash': firstTimeEventHash
|
|
4306
4326
|
};
|
|
4307
4327
|
|
|
4308
|
-
logger$
|
|
4328
|
+
logger$4.log('Recording first-time event for flag: ' + flagId);
|
|
4309
4329
|
|
|
4310
4330
|
// Fire-and-forget POST request
|
|
4311
4331
|
this.fetch.call(win, url, {
|
|
@@ -4318,14 +4338,14 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
|
|
|
4318
4338
|
'body': JSON.stringify(payload)
|
|
4319
4339
|
}).catch(function(error) {
|
|
4320
4340
|
// Silent failure - cohort sync will catch up
|
|
4321
|
-
logger$
|
|
4341
|
+
logger$4.error('Failed to record first-time event for flag ' + flagId + ': ' + error);
|
|
4322
4342
|
});
|
|
4323
4343
|
};
|
|
4324
4344
|
|
|
4325
4345
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
4326
4346
|
if (!this.fetchPromise) {
|
|
4327
4347
|
return new Promise(function(resolve) {
|
|
4328
|
-
logger$
|
|
4348
|
+
logger$4.critical('Feature Flags not initialized');
|
|
4329
4349
|
resolve(fallback);
|
|
4330
4350
|
});
|
|
4331
4351
|
}
|
|
@@ -4333,19 +4353,19 @@ FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
|
4333
4353
|
return this.fetchPromise.then(function() {
|
|
4334
4354
|
return this.getVariantSync(featureName, fallback);
|
|
4335
4355
|
}.bind(this)).catch(function(error) {
|
|
4336
|
-
logger$
|
|
4356
|
+
logger$4.error(error);
|
|
4337
4357
|
return fallback;
|
|
4338
4358
|
});
|
|
4339
4359
|
};
|
|
4340
4360
|
|
|
4341
4361
|
FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
|
|
4342
4362
|
if (!this.areFlagsReady()) {
|
|
4343
|
-
logger$
|
|
4363
|
+
logger$4.log('Flags not loaded yet');
|
|
4344
4364
|
return fallback;
|
|
4345
4365
|
}
|
|
4346
4366
|
var feature = this.flags.get(featureName);
|
|
4347
4367
|
if (!feature) {
|
|
4348
|
-
logger$
|
|
4368
|
+
logger$4.log('No flag found: "' + featureName + '"');
|
|
4349
4369
|
return fallback;
|
|
4350
4370
|
}
|
|
4351
4371
|
this.trackFeatureCheck(featureName, feature);
|
|
@@ -4356,14 +4376,14 @@ FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackVal
|
|
|
4356
4376
|
return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
|
|
4357
4377
|
return feature['value'];
|
|
4358
4378
|
}).catch(function(error) {
|
|
4359
|
-
logger$
|
|
4379
|
+
logger$4.error(error);
|
|
4360
4380
|
return fallbackValue;
|
|
4361
4381
|
});
|
|
4362
4382
|
};
|
|
4363
4383
|
|
|
4364
4384
|
// TODO remove deprecated method
|
|
4365
4385
|
FeatureFlagManager.prototype.getFeatureData = function(featureName, fallbackValue) {
|
|
4366
|
-
logger$
|
|
4386
|
+
logger$4.critical('mixpanel.flags.get_feature_data() is deprecated and will be removed in a future release. Use mixpanel.flags.get_variant_value() instead.');
|
|
4367
4387
|
return this.getVariantValue(featureName, fallbackValue);
|
|
4368
4388
|
};
|
|
4369
4389
|
|
|
@@ -4375,7 +4395,7 @@ FeatureFlagManager.prototype.isEnabled = function(featureName, fallbackValue) {
|
|
|
4375
4395
|
return this.getVariantValue(featureName).then(function() {
|
|
4376
4396
|
return this.isEnabledSync(featureName, fallbackValue);
|
|
4377
4397
|
}.bind(this)).catch(function(error) {
|
|
4378
|
-
logger$
|
|
4398
|
+
logger$4.error(error);
|
|
4379
4399
|
return fallbackValue;
|
|
4380
4400
|
});
|
|
4381
4401
|
};
|
|
@@ -4384,7 +4404,7 @@ FeatureFlagManager.prototype.isEnabledSync = function(featureName, fallbackValue
|
|
|
4384
4404
|
fallbackValue = fallbackValue || false;
|
|
4385
4405
|
var val = this.getVariantValueSync(featureName, fallbackValue);
|
|
4386
4406
|
if (val !== true && val !== false) {
|
|
4387
|
-
logger$
|
|
4407
|
+
logger$4.error('Feature flag "' + featureName + '" value: ' + val + ' is not a boolean; returning fallback value: ' + fallbackValue);
|
|
4388
4408
|
val = fallbackValue;
|
|
4389
4409
|
}
|
|
4390
4410
|
return val;
|
|
@@ -4419,6 +4439,13 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
4419
4439
|
this.track('$experiment_started', trackingProperties);
|
|
4420
4440
|
};
|
|
4421
4441
|
|
|
4442
|
+
FeatureFlagManager.prototype.whenReady = function() {
|
|
4443
|
+
if (this.fetchPromise) {
|
|
4444
|
+
return this.fetchPromise;
|
|
4445
|
+
}
|
|
4446
|
+
return Promise.resolve();
|
|
4447
|
+
};
|
|
4448
|
+
|
|
4422
4449
|
FeatureFlagManager.prototype.minApisSupported = function() {
|
|
4423
4450
|
return !!this.fetch &&
|
|
4424
4451
|
typeof Promise !== 'undefined' &&
|
|
@@ -4435,7 +4462,9 @@ FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype
|
|
|
4435
4462
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
4436
4463
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
4437
4464
|
FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
|
|
4465
|
+
FeatureFlagManager.prototype['load_flags'] = FeatureFlagManager.prototype.loadFlags;
|
|
4438
4466
|
FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
|
|
4467
|
+
FeatureFlagManager.prototype['when_ready'] = FeatureFlagManager.prototype.whenReady;
|
|
4439
4468
|
|
|
4440
4469
|
// Deprecated method
|
|
4441
4470
|
FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
|
|
@@ -4579,9 +4608,38 @@ var isRecordingExpired = function(serializedRecording) {
|
|
|
4579
4608
|
return !serializedRecording || now > serializedRecording['maxExpires'] || now > serializedRecording['idleExpires'];
|
|
4580
4609
|
};
|
|
4581
4610
|
|
|
4611
|
+
var validateAllowedOrigins = function(origins, logger) {
|
|
4612
|
+
if (!_.isArray(origins)) {
|
|
4613
|
+
if (origins) {
|
|
4614
|
+
logger.critical('record_allowed_iframe_origins must be an array of origin strings, cross-origin recording will be disabled.');
|
|
4615
|
+
}
|
|
4616
|
+
return [];
|
|
4617
|
+
}
|
|
4618
|
+
var valid = [];
|
|
4619
|
+
for (var i = 0; i < origins.length; i++) {
|
|
4620
|
+
try {
|
|
4621
|
+
var origin = new URL(origins[i]).origin;
|
|
4622
|
+
if (origin === 'null') {
|
|
4623
|
+
logger.critical(origins[i] + ' has an opaque origin. Skipping this entry.');
|
|
4624
|
+
continue;
|
|
4625
|
+
}
|
|
4626
|
+
valid.push(origin);
|
|
4627
|
+
} catch (e) {
|
|
4628
|
+
logger.critical(origins[i] + ' is not a valid origin URL. Skipping this entry.');
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
return valid;
|
|
4632
|
+
};
|
|
4633
|
+
|
|
4582
4634
|
/* eslint camelcase: "off" */
|
|
4583
4635
|
|
|
4584
4636
|
|
|
4637
|
+
var logger$3 = console_with_prefix('recorder');
|
|
4638
|
+
|
|
4639
|
+
var IFRAME_HANDSHAKE_REQUEST = 'mp_iframe_handshake_request';
|
|
4640
|
+
var IFRAME_HANDSHAKE_RESPONSE = 'mp_iframe_handshake_response';
|
|
4641
|
+
|
|
4642
|
+
|
|
4585
4643
|
/**
|
|
4586
4644
|
* RecorderManager: manages session recording initialization, lifecycle and state
|
|
4587
4645
|
* @constructor
|
|
@@ -4601,6 +4659,8 @@ var RecorderManager = function(initOptions) {
|
|
|
4601
4659
|
this.libBasePath = initOptions.libBasePath;
|
|
4602
4660
|
|
|
4603
4661
|
this._recorder = null;
|
|
4662
|
+
this._parentReplayId = null;
|
|
4663
|
+
this._parentFrameRetryInterval = null;
|
|
4604
4664
|
};
|
|
4605
4665
|
|
|
4606
4666
|
RecorderManager.prototype.shouldLoadRecorder = function() {
|
|
@@ -4654,6 +4714,22 @@ RecorderManager.prototype.checkAndStartSessionRecording = function(force_start,
|
|
|
4654
4714
|
}, this));
|
|
4655
4715
|
}, this);
|
|
4656
4716
|
|
|
4717
|
+
// Cross-origin iframe handling
|
|
4718
|
+
var allowedOrigins = validateAllowedOrigins(this.getMpConfig('record_allowed_iframe_origins'), logger$3);
|
|
4719
|
+
var isCrossOriginRecordingEnabled = allowedOrigins.length > 0;
|
|
4720
|
+
|
|
4721
|
+
if (isCrossOriginRecordingEnabled) {
|
|
4722
|
+
// listen for handshake requests from their own child iframes (including nested)
|
|
4723
|
+
this._setupParentFrameListener(allowedOrigins);
|
|
4724
|
+
|
|
4725
|
+
if (win.parent !== win) {
|
|
4726
|
+
// also wait for parent's replay ID
|
|
4727
|
+
this._setupChildFrameListener(allowedOrigins, loadRecorder);
|
|
4728
|
+
this._sendParentFrameRequestWithRetry(allowedOrigins);
|
|
4729
|
+
return PromisePolyfill.resolve();
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
|
|
4657
4733
|
/**
|
|
4658
4734
|
* If the user is sampled or start_session_recording is called, we always load the recorder since it's guaranteed a recording should start.
|
|
4659
4735
|
* Otherwise, if the recording registry has any records then it's likely there's a recording in progress or orphaned data that needs to be flushed.
|
|
@@ -4773,6 +4849,10 @@ RecorderManager.prototype.getSessionReplayUrl = function() {
|
|
|
4773
4849
|
};
|
|
4774
4850
|
|
|
4775
4851
|
RecorderManager.prototype.getSessionReplayId = function() {
|
|
4852
|
+
// Child iframe uses parent's replay ID
|
|
4853
|
+
if (this._parentReplayId) {
|
|
4854
|
+
return this._parentReplayId;
|
|
4855
|
+
}
|
|
4776
4856
|
var replay_id = null;
|
|
4777
4857
|
if (this._recorder) {
|
|
4778
4858
|
replay_id = this._recorder['replayId'];
|
|
@@ -4785,6 +4865,86 @@ RecorderManager.prototype.getRecorder = function() {
|
|
|
4785
4865
|
return this._recorder;
|
|
4786
4866
|
};
|
|
4787
4867
|
|
|
4868
|
+
RecorderManager.prototype._setupChildFrameListener = function(allowedOrigins, loadRecorder) {
|
|
4869
|
+
if (this._childFrameMessageHandler) {
|
|
4870
|
+
return;
|
|
4871
|
+
}
|
|
4872
|
+
var self = this;
|
|
4873
|
+
this._childFrameMessageHandler = function(event) {
|
|
4874
|
+
if (allowedOrigins.indexOf(event.origin) === -1) return;
|
|
4875
|
+
var data = event.data;
|
|
4876
|
+
if (data && data['type'] === IFRAME_HANDSHAKE_RESPONSE && data['token'] === self.getMpConfig('token') && data['replayId']) {
|
|
4877
|
+
self._parentReplayId = data['replayId'];
|
|
4878
|
+
if (data['distinctId']) {
|
|
4879
|
+
self.mixpanelInstance['identify'](data['distinctId']);
|
|
4880
|
+
}
|
|
4881
|
+
self._parentFrameRetryActive = false;
|
|
4882
|
+
win.removeEventListener('message', self._childFrameMessageHandler);
|
|
4883
|
+
self._childFrameMessageHandler = null;
|
|
4884
|
+
loadRecorder(true);
|
|
4885
|
+
}
|
|
4886
|
+
};
|
|
4887
|
+
win.addEventListener('message', this._childFrameMessageHandler);
|
|
4888
|
+
};
|
|
4889
|
+
|
|
4890
|
+
RecorderManager.prototype._sendParentFrameRequest = function(allowedOrigins) {
|
|
4891
|
+
var message = {};
|
|
4892
|
+
message['type'] = IFRAME_HANDSHAKE_REQUEST;
|
|
4893
|
+
message['token'] = this.getMpConfig('token');
|
|
4894
|
+
for (var i = 0; i < allowedOrigins.length; i++) {
|
|
4895
|
+
try {
|
|
4896
|
+
win.parent.postMessage(message, allowedOrigins[i]);
|
|
4897
|
+
} catch (e) {
|
|
4898
|
+
// origin mismatch - ignore
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
};
|
|
4902
|
+
|
|
4903
|
+
RecorderManager.prototype._sendParentFrameRequestWithRetry = function(allowedOrigins) {
|
|
4904
|
+
var self = this;
|
|
4905
|
+
var maxRetries = 10;
|
|
4906
|
+
var retryCount = 0;
|
|
4907
|
+
var delay = 50;
|
|
4908
|
+
this._parentFrameRetryActive = true;
|
|
4909
|
+
|
|
4910
|
+
this._sendParentFrameRequest(allowedOrigins);
|
|
4911
|
+
|
|
4912
|
+
function scheduleRetry() {
|
|
4913
|
+
setTimeout(function() {
|
|
4914
|
+
if (!self._parentFrameRetryActive || self._parentReplayId || ++retryCount >= maxRetries) {
|
|
4915
|
+
return;
|
|
4916
|
+
}
|
|
4917
|
+
self._sendParentFrameRequest(allowedOrigins);
|
|
4918
|
+
delay *= 2;
|
|
4919
|
+
scheduleRetry();
|
|
4920
|
+
}, delay);
|
|
4921
|
+
}
|
|
4922
|
+
scheduleRetry();
|
|
4923
|
+
};
|
|
4924
|
+
|
|
4925
|
+
RecorderManager.prototype._setupParentFrameListener = function(allowedOrigins) {
|
|
4926
|
+
if (this._parentFrameMessageHandler) {
|
|
4927
|
+
return;
|
|
4928
|
+
}
|
|
4929
|
+
var self = this;
|
|
4930
|
+
this._parentFrameMessageHandler = function(event) {
|
|
4931
|
+
if (allowedOrigins.indexOf(event.origin) === -1) return;
|
|
4932
|
+
var data = event.data;
|
|
4933
|
+
if (data && data['type'] === IFRAME_HANDSHAKE_REQUEST && data['token'] === self.getMpConfig('token')) {
|
|
4934
|
+
var replayId = self.getSessionReplayId();
|
|
4935
|
+
if (replayId) {
|
|
4936
|
+
var response = {};
|
|
4937
|
+
response['type'] = IFRAME_HANDSHAKE_RESPONSE;
|
|
4938
|
+
response['token'] = self.getMpConfig('token');
|
|
4939
|
+
response['replayId'] = replayId;
|
|
4940
|
+
response['distinctId'] = self.getDistinctId();
|
|
4941
|
+
event.source.postMessage(response, event.origin);
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4944
|
+
};
|
|
4945
|
+
win.addEventListener('message', this._parentFrameMessageHandler);
|
|
4946
|
+
};
|
|
4947
|
+
|
|
4788
4948
|
safewrapClass(RecorderManager);
|
|
4789
4949
|
|
|
4790
4950
|
/* eslint camelcase: "off" */
|
|
@@ -7351,7 +7511,6 @@ var INIT_SNIPPET = 1;
|
|
|
7351
7511
|
/** @const */ var SETTING_FALLBACK = 'fallback';
|
|
7352
7512
|
/** @const */ var SETTING_DISABLED = 'disabled';
|
|
7353
7513
|
|
|
7354
|
-
|
|
7355
7514
|
/*
|
|
7356
7515
|
* Dynamic... constants? Is that an oxymoron?
|
|
7357
7516
|
*/
|
|
@@ -7436,6 +7595,7 @@ var DEFAULT_CONFIG = {
|
|
|
7436
7595
|
'batch_request_timeout_ms': 90000,
|
|
7437
7596
|
'batch_autostart': true,
|
|
7438
7597
|
'hooks': {},
|
|
7598
|
+
'record_allowed_iframe_origins': [],
|
|
7439
7599
|
'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
|
|
7440
7600
|
'record_block_selector': 'img, video, audio',
|
|
7441
7601
|
'record_canvas': false,
|
|
@@ -9011,7 +9171,9 @@ MixpanelLib.prototype.identify = function(
|
|
|
9011
9171
|
|
|
9012
9172
|
// check feature flags again if distinct id has changed
|
|
9013
9173
|
if (new_distinct_id !== previous_distinct_id) {
|
|
9014
|
-
this.flags.fetchFlags()
|
|
9174
|
+
this.flags.fetchFlags().catch(function() {
|
|
9175
|
+
console.error('[flags] Error fetching flags during identify');
|
|
9176
|
+
});
|
|
9015
9177
|
}
|
|
9016
9178
|
};
|
|
9017
9179
|
|