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