mixpanel-browser 2.78.0 → 2.79.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 +6 -11
- package/.eslintrc.json +12 -0
- package/.github/workflows/openfeature-provider-tests.yml +31 -0
- package/CHANGELOG.md +8 -1
- package/build.sh +2 -2
- package/dist/async-modules/{mixpanel-recorder-BjSlYaNJ.min.js → mixpanel-recorder-D5HJyV2E.min.js} +2 -2
- package/dist/async-modules/mixpanel-recorder-D5HJyV2E.min.js.map +1 -0
- package/dist/async-modules/{mixpanel-recorder-zMBXIyeG.js → mixpanel-recorder-P6SEnnPV.js} +57 -33
- package/dist/async-modules/mixpanel-targeting-1L9FyetZ.min.js +2 -0
- package/dist/async-modules/mixpanel-targeting-1L9FyetZ.min.js.map +1 -0
- package/dist/async-modules/{mixpanel-targeting-UHf4eBfC.js → mixpanel-targeting-BBMVbgJF.js} +24 -13
- package/dist/mixpanel-core.cjs.d.ts +45 -1
- package/dist/mixpanel-core.cjs.js +565 -197
- package/dist/mixpanel-recorder.js +57 -33
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-targeting.js +24 -13
- 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 +45 -1
- package/dist/mixpanel-with-async-modules.cjs.js +567 -199
- package/dist/mixpanel-with-async-recorder.cjs.d.ts +45 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +567 -199
- package/dist/mixpanel-with-recorder.d.ts +45 -1
- package/dist/mixpanel-with-recorder.js +490 -122
- package/dist/mixpanel-with-recorder.min.d.ts +45 -1
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.d.ts +45 -1
- package/dist/mixpanel.amd.js +490 -122
- package/dist/mixpanel.cjs.d.ts +45 -1
- package/dist/mixpanel.cjs.js +490 -122
- package/dist/mixpanel.globals.js +567 -199
- package/dist/mixpanel.min.js +199 -189
- package/dist/mixpanel.module.d.ts +45 -1
- package/dist/mixpanel.module.js +490 -122
- package/dist/mixpanel.umd.d.ts +45 -1
- package/dist/mixpanel.umd.js +490 -122
- package/package.json +1 -1
- package/packages/openfeature-web-provider/README.md +357 -0
- package/packages/openfeature-web-provider/package-lock.json +1636 -0
- package/packages/openfeature-web-provider/package.json +51 -0
- package/packages/openfeature-web-provider/rollup.config.browser.mjs +26 -0
- package/packages/openfeature-web-provider/src/MixpanelProvider.ts +302 -0
- package/packages/openfeature-web-provider/src/index.ts +1 -0
- package/packages/openfeature-web-provider/src/types.ts +72 -0
- package/packages/openfeature-web-provider/test/MixpanelProvider.spec.ts +484 -0
- package/packages/openfeature-web-provider/tsconfig.json +15 -0
- package/src/autocapture/index.js +7 -2
- package/src/config.js +1 -1
- package/src/flags/flags-persistence.js +176 -0
- package/src/flags/index.js +174 -23
- package/src/index.d.ts +45 -1
- package/src/mixpanel-core.js +24 -7
- package/src/recorder/idb-config.js +16 -0
- package/src/recorder/recording-registry.js +7 -2
- package/src/recorder/session-recording.js +9 -4
- package/src/recorder-manager.js +7 -2
- package/src/request-queue.js +1 -2
- package/src/shared-lock.js +2 -3
- package/src/storage/indexed-db.js +16 -15
- package/src/storage/local-storage.js +5 -3
- package/src/utils.js +25 -12
- package/tsconfig.base.json +9 -0
- package/dist/async-modules/mixpanel-recorder-BjSlYaNJ.min.js.map +0 -1
- package/dist/async-modules/mixpanel-targeting-BSHal4N9.min.js +0 -2
- package/dist/async-modules/mixpanel-targeting-BSHal4N9.min.js.map +0 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
5
|
+
LIB_VERSION: '2.79.0'
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// Window global names for async modules
|
|
@@ -10,8 +10,8 @@ var TARGETING_GLOBAL_NAME = '__mp_targeting';
|
|
|
10
10
|
var RECORDER_GLOBAL_NAME = '__mp_recorder';
|
|
11
11
|
|
|
12
12
|
// Constants that are injected at build-time for the names of async modules.
|
|
13
|
-
var RECORDER_FILENAME = 'mixpanel-recorder-
|
|
14
|
-
var TARGETING_FILENAME = 'mixpanel-targeting-
|
|
13
|
+
var RECORDER_FILENAME = 'mixpanel-recorder-P6SEnnPV.js';
|
|
14
|
+
var TARGETING_FILENAME = 'mixpanel-targeting-BBMVbgJF.js';
|
|
15
15
|
|
|
16
16
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
17
17
|
var win;
|
|
@@ -501,6 +501,7 @@ var log_func_with_prefix = function(func, prefix) {
|
|
|
501
501
|
var console_with_prefix = function(prefix) {
|
|
502
502
|
return {
|
|
503
503
|
log: log_func_with_prefix(console.log, prefix),
|
|
504
|
+
warn: log_func_with_prefix(console.warn, prefix),
|
|
504
505
|
error: log_func_with_prefix(console.error, prefix),
|
|
505
506
|
critical: log_func_with_prefix(console.critical, prefix)
|
|
506
507
|
};
|
|
@@ -1447,7 +1448,8 @@ var localStorageSupported = function(storage, forceCheck) {
|
|
|
1447
1448
|
if (_localStorageSupported !== null && !forceCheck) {
|
|
1448
1449
|
return _localStorageSupported;
|
|
1449
1450
|
}
|
|
1450
|
-
|
|
1451
|
+
|
|
1452
|
+
return _localStorageSupported = _testStorageSupported(storage);
|
|
1451
1453
|
};
|
|
1452
1454
|
|
|
1453
1455
|
var _sessionStorageSupported = null;
|
|
@@ -1455,7 +1457,8 @@ var sessionStorageSupported = function(storage, forceCheck) {
|
|
|
1455
1457
|
if (_sessionStorageSupported !== null && !forceCheck) {
|
|
1456
1458
|
return _sessionStorageSupported;
|
|
1457
1459
|
}
|
|
1458
|
-
|
|
1460
|
+
|
|
1461
|
+
return _sessionStorageSupported = _testStorageSupported(storage);
|
|
1459
1462
|
};
|
|
1460
1463
|
|
|
1461
1464
|
function _storageWrapper(storage, name, is_supported_fn) {
|
|
@@ -1505,17 +1508,26 @@ function _storageWrapper(storage, name, is_supported_fn) {
|
|
|
1505
1508
|
};
|
|
1506
1509
|
}
|
|
1507
1510
|
|
|
1508
|
-
// Safari
|
|
1509
|
-
//
|
|
1510
|
-
var
|
|
1511
|
-
try {
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
}
|
|
1511
|
+
// Safari and other browsers may error out accessing localStorage/sessionStorage
|
|
1512
|
+
// when cookies are disabled, so wrap access in a try-catch.
|
|
1513
|
+
var getLocalStorage = function() {
|
|
1514
|
+
try {
|
|
1515
|
+
return win.localStorage; // eslint-disable-line no-restricted-properties
|
|
1516
|
+
} catch (_err) {
|
|
1517
|
+
return null;
|
|
1518
|
+
}
|
|
1519
|
+
};
|
|
1516
1520
|
|
|
1517
|
-
|
|
1518
|
-
|
|
1521
|
+
var getSessionStorage = function() {
|
|
1522
|
+
try {
|
|
1523
|
+
return win.sessionStorage; // eslint-disable-line no-restricted-properties
|
|
1524
|
+
} catch (_err) {
|
|
1525
|
+
return null;
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1528
|
+
|
|
1529
|
+
_.localStorage = _storageWrapper(getLocalStorage(), 'localStorage', localStorageSupported);
|
|
1530
|
+
_.sessionStorage = _storageWrapper(getSessionStorage(), 'sessionStorage', sessionStorageSupported);
|
|
1519
1531
|
|
|
1520
1532
|
_.register_event = (function() {
|
|
1521
1533
|
// written by Dean Edwards, 2005
|
|
@@ -2267,7 +2279,7 @@ var EVENT_HANDLER_ATTRIBUTES = [
|
|
|
2267
2279
|
|
|
2268
2280
|
var MAX_DEPTH = 5;
|
|
2269
2281
|
|
|
2270
|
-
var logger$
|
|
2282
|
+
var logger$6 = console_with_prefix('autocapture');
|
|
2271
2283
|
|
|
2272
2284
|
|
|
2273
2285
|
function getClasses(el) {
|
|
@@ -2531,7 +2543,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
|
2531
2543
|
return false;
|
|
2532
2544
|
}
|
|
2533
2545
|
} catch (err) {
|
|
2534
|
-
logger$
|
|
2546
|
+
logger$6.critical('Error while checking element in allowElementCallback', err);
|
|
2535
2547
|
return false;
|
|
2536
2548
|
}
|
|
2537
2549
|
}
|
|
@@ -2548,7 +2560,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
|
2548
2560
|
return true;
|
|
2549
2561
|
}
|
|
2550
2562
|
} catch (err) {
|
|
2551
|
-
logger$
|
|
2563
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
2552
2564
|
}
|
|
2553
2565
|
}
|
|
2554
2566
|
return false;
|
|
@@ -2563,7 +2575,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
|
2563
2575
|
return true;
|
|
2564
2576
|
}
|
|
2565
2577
|
} catch (err) {
|
|
2566
|
-
logger$
|
|
2578
|
+
logger$6.critical('Error while checking element in blockElementCallback', err);
|
|
2567
2579
|
return true;
|
|
2568
2580
|
}
|
|
2569
2581
|
}
|
|
@@ -2577,7 +2589,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
|
2577
2589
|
return true;
|
|
2578
2590
|
}
|
|
2579
2591
|
} catch (err) {
|
|
2580
|
-
logger$
|
|
2592
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
2581
2593
|
}
|
|
2582
2594
|
}
|
|
2583
2595
|
}
|
|
@@ -3041,7 +3053,7 @@ ShadowDOMObserver.prototype.observeShadowRoot = function(shadowRoot) {
|
|
|
3041
3053
|
observer.observe(shadowRoot, this.observerConfig);
|
|
3042
3054
|
this.shadowObservers.push(observer);
|
|
3043
3055
|
} catch (e) {
|
|
3044
|
-
logger$
|
|
3056
|
+
logger$6.critical('Error while observing shadow root', e);
|
|
3045
3057
|
}
|
|
3046
3058
|
};
|
|
3047
3059
|
|
|
@@ -3052,7 +3064,7 @@ ShadowDOMObserver.prototype.start = function() {
|
|
|
3052
3064
|
}
|
|
3053
3065
|
|
|
3054
3066
|
if (!weakSetSupported()) {
|
|
3055
|
-
logger$
|
|
3067
|
+
logger$6.critical('Shadow DOM observation unavailable: WeakSet not supported');
|
|
3056
3068
|
return;
|
|
3057
3069
|
}
|
|
3058
3070
|
|
|
@@ -3068,7 +3080,7 @@ ShadowDOMObserver.prototype.stop = function() {
|
|
|
3068
3080
|
try {
|
|
3069
3081
|
this.shadowObservers[i].disconnect();
|
|
3070
3082
|
} catch (e) {
|
|
3071
|
-
logger$
|
|
3083
|
+
logger$6.critical('Error while disconnecting shadow DOM observer', e);
|
|
3072
3084
|
}
|
|
3073
3085
|
}
|
|
3074
3086
|
this.shadowObservers = [];
|
|
@@ -3256,7 +3268,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
3256
3268
|
|
|
3257
3269
|
this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
|
|
3258
3270
|
} catch (e) {
|
|
3259
|
-
logger$
|
|
3271
|
+
logger$6.critical('Error while setting up mutation observer', e);
|
|
3260
3272
|
}
|
|
3261
3273
|
}
|
|
3262
3274
|
|
|
@@ -3271,7 +3283,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
3271
3283
|
);
|
|
3272
3284
|
this.shadowDOMObserver.start();
|
|
3273
3285
|
} catch (e) {
|
|
3274
|
-
logger$
|
|
3286
|
+
logger$6.critical('Error while setting up shadow DOM observer', e);
|
|
3275
3287
|
this.shadowDOMObserver = null;
|
|
3276
3288
|
}
|
|
3277
3289
|
}
|
|
@@ -3298,7 +3310,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
3298
3310
|
try {
|
|
3299
3311
|
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
3300
3312
|
} catch (e) {
|
|
3301
|
-
logger$
|
|
3313
|
+
logger$6.critical('Error while removing event listener', e);
|
|
3302
3314
|
}
|
|
3303
3315
|
}
|
|
3304
3316
|
this.eventListeners = [];
|
|
@@ -3307,7 +3319,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
3307
3319
|
try {
|
|
3308
3320
|
this.mutationObserver.disconnect();
|
|
3309
3321
|
} catch (e) {
|
|
3310
|
-
logger$
|
|
3322
|
+
logger$6.critical('Error while disconnecting mutation observer', e);
|
|
3311
3323
|
}
|
|
3312
3324
|
this.mutationObserver = null;
|
|
3313
3325
|
}
|
|
@@ -3316,7 +3328,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
3316
3328
|
try {
|
|
3317
3329
|
this.shadowDOMObserver.stop();
|
|
3318
3330
|
} catch (e) {
|
|
3319
|
-
logger$
|
|
3331
|
+
logger$6.critical('Error while stopping shadow DOM observer', e);
|
|
3320
3332
|
}
|
|
3321
3333
|
this.shadowDOMObserver = null;
|
|
3322
3334
|
}
|
|
@@ -3394,7 +3406,7 @@ var Autocapture = function(mp) {
|
|
|
3394
3406
|
|
|
3395
3407
|
Autocapture.prototype.init = function() {
|
|
3396
3408
|
if (!minDOMApisSupported()) {
|
|
3397
|
-
logger$
|
|
3409
|
+
logger$6.critical('Autocapture unavailable: missing required DOM APIs');
|
|
3398
3410
|
return;
|
|
3399
3411
|
}
|
|
3400
3412
|
this.initPageListeners();
|
|
@@ -3434,7 +3446,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
3434
3446
|
try {
|
|
3435
3447
|
return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
|
|
3436
3448
|
} catch (err) {
|
|
3437
|
-
logger$
|
|
3449
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
3438
3450
|
return true;
|
|
3439
3451
|
}
|
|
3440
3452
|
}
|
|
@@ -3447,7 +3459,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
3447
3459
|
try {
|
|
3448
3460
|
return urlMatchesRegexList(currentUrl, blockUrlRegexes);
|
|
3449
3461
|
} catch (err) {
|
|
3450
|
-
logger$
|
|
3462
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
3451
3463
|
return true;
|
|
3452
3464
|
}
|
|
3453
3465
|
};
|
|
@@ -3585,7 +3597,7 @@ Autocapture.prototype._initScrollDepthTracking = function() {
|
|
|
3585
3597
|
return;
|
|
3586
3598
|
}
|
|
3587
3599
|
|
|
3588
|
-
logger$
|
|
3600
|
+
logger$6.log('Initializing scroll depth tracking');
|
|
3589
3601
|
|
|
3590
3602
|
this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
|
|
3591
3603
|
|
|
@@ -3611,7 +3623,7 @@ Autocapture.prototype.initClickTracking = function() {
|
|
|
3611
3623
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
|
|
3612
3624
|
return;
|
|
3613
3625
|
}
|
|
3614
|
-
logger$
|
|
3626
|
+
logger$6.log('Initializing click tracking');
|
|
3615
3627
|
|
|
3616
3628
|
this.listenerClick = function(ev) {
|
|
3617
3629
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
|
|
@@ -3630,7 +3642,7 @@ Autocapture.prototype.initDeadClickTracking = function() {
|
|
|
3630
3642
|
return;
|
|
3631
3643
|
}
|
|
3632
3644
|
|
|
3633
|
-
logger$
|
|
3645
|
+
logger$6.log('Initializing dead click tracking');
|
|
3634
3646
|
if (!this._deadClickTracker) {
|
|
3635
3647
|
this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
|
|
3636
3648
|
this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
|
|
@@ -3664,7 +3676,7 @@ Autocapture.prototype.initInputTracking = function() {
|
|
|
3664
3676
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
3665
3677
|
return;
|
|
3666
3678
|
}
|
|
3667
|
-
logger$
|
|
3679
|
+
logger$6.log('Initializing input tracking');
|
|
3668
3680
|
|
|
3669
3681
|
this.listenerChange = function(ev) {
|
|
3670
3682
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
@@ -3678,14 +3690,15 @@ Autocapture.prototype.initInputTracking = function() {
|
|
|
3678
3690
|
Autocapture.prototype.initPageviewTracking = function() {
|
|
3679
3691
|
win.removeEventListener(EV_MP_LOCATION_CHANGE, this.listenerLocationchange);
|
|
3680
3692
|
|
|
3681
|
-
if (!this.pageviewTrackingConfig()) {
|
|
3693
|
+
if (!this.pageviewTrackingConfig() && !this.mp.get_config('record_heatmap_data')) {
|
|
3682
3694
|
return;
|
|
3683
3695
|
}
|
|
3684
|
-
logger$
|
|
3696
|
+
logger$6.log('Initializing pageview tracking');
|
|
3685
3697
|
|
|
3686
3698
|
var previousTrackedUrl = '';
|
|
3687
3699
|
var tracked = false;
|
|
3688
|
-
if
|
|
3700
|
+
// Track initial pageview if pageview tracking enabled OR heatmap recording is active
|
|
3701
|
+
if ((this.pageviewTrackingConfig() || this.mp.is_recording_heatmap_data()) && !this.currentUrlBlocked()) {
|
|
3689
3702
|
tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
3690
3703
|
}
|
|
3691
3704
|
if (tracked) {
|
|
@@ -3701,6 +3714,10 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
3701
3714
|
var shouldTrack = false;
|
|
3702
3715
|
var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
3703
3716
|
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
3717
|
+
if (!trackPageviewOption && this.mp.is_recording_heatmap_data()) {
|
|
3718
|
+
trackPageviewOption = PAGEVIEW_OPTION_FULL_URL;
|
|
3719
|
+
}
|
|
3720
|
+
|
|
3704
3721
|
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
3705
3722
|
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
3706
3723
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
@@ -3716,7 +3733,7 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
3716
3733
|
}
|
|
3717
3734
|
if (didPathChange) {
|
|
3718
3735
|
this.lastScrollCheckpoint = 0;
|
|
3719
|
-
logger$
|
|
3736
|
+
logger$6.log('Path change: re-initializing scroll depth checkpoints');
|
|
3720
3737
|
}
|
|
3721
3738
|
}
|
|
3722
3739
|
}.bind(this));
|
|
@@ -3731,7 +3748,7 @@ Autocapture.prototype.initRageClickTracking = function() {
|
|
|
3731
3748
|
return;
|
|
3732
3749
|
}
|
|
3733
3750
|
|
|
3734
|
-
logger$
|
|
3751
|
+
logger$6.log('Initializing rage click tracking');
|
|
3735
3752
|
if (!this._rageClickTracker) {
|
|
3736
3753
|
this._rageClickTracker = new RageClickTracker();
|
|
3737
3754
|
}
|
|
@@ -3761,7 +3778,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
3761
3778
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
3762
3779
|
return;
|
|
3763
3780
|
}
|
|
3764
|
-
logger$
|
|
3781
|
+
logger$6.log('Initializing scroll tracking');
|
|
3765
3782
|
this.lastScrollCheckpoint = 0;
|
|
3766
3783
|
|
|
3767
3784
|
var scrollTrackFunction = function() {
|
|
@@ -3798,7 +3815,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
3798
3815
|
}
|
|
3799
3816
|
}
|
|
3800
3817
|
} catch (err) {
|
|
3801
|
-
logger$
|
|
3818
|
+
logger$6.critical('Error while calculating scroll percentage', err);
|
|
3802
3819
|
}
|
|
3803
3820
|
if (shouldTrack) {
|
|
3804
3821
|
this.mp.track(MP_EV_SCROLL, props);
|
|
@@ -3816,7 +3833,7 @@ Autocapture.prototype.initSubmitTracking = function() {
|
|
|
3816
3833
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
3817
3834
|
return;
|
|
3818
3835
|
}
|
|
3819
|
-
logger$
|
|
3836
|
+
logger$6.log('Initializing submit tracking');
|
|
3820
3837
|
|
|
3821
3838
|
this.listenerSubmit = function(ev) {
|
|
3822
3839
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
@@ -3838,7 +3855,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
|
|
|
3838
3855
|
return;
|
|
3839
3856
|
}
|
|
3840
3857
|
|
|
3841
|
-
logger$
|
|
3858
|
+
logger$6.log('Initializing page visibility tracking.');
|
|
3842
3859
|
this._initScrollDepthTracking();
|
|
3843
3860
|
var previousTrackedUrl = _.info.currentUrl();
|
|
3844
3861
|
|
|
@@ -3923,10 +3940,309 @@ var getTargetingPromise = function(loadExtraBundle, targetingSrc) {
|
|
|
3923
3940
|
return win[TARGETING_GLOBAL_NAME];
|
|
3924
3941
|
};
|
|
3925
3942
|
|
|
3943
|
+
/**
|
|
3944
|
+
* @type {import('./wrapper').StorageWrapper}
|
|
3945
|
+
*/
|
|
3946
|
+
var IDBStorageWrapper = function (dbName, storeName, versionData) {
|
|
3947
|
+
this.dbName = dbName;
|
|
3948
|
+
this.storeName = storeName;
|
|
3949
|
+
this.version = versionData.version;
|
|
3950
|
+
this.storeNamesInDb = versionData.storeNames;
|
|
3951
|
+
/**
|
|
3952
|
+
* @type {Promise<IDBDatabase>|null}
|
|
3953
|
+
*/
|
|
3954
|
+
this.dbPromise = null;
|
|
3955
|
+
};
|
|
3956
|
+
|
|
3957
|
+
IDBStorageWrapper.prototype._openDb = function () {
|
|
3958
|
+
var dbName = this.dbName;
|
|
3959
|
+
var version = this.version;
|
|
3960
|
+
var storeNamesInDb = this.storeNamesInDb;
|
|
3961
|
+
return new PromisePolyfill(function (resolve, reject) {
|
|
3962
|
+
var openRequest = win.indexedDB.open(dbName, version);
|
|
3963
|
+
openRequest['onerror'] = function () {
|
|
3964
|
+
reject(openRequest.error);
|
|
3965
|
+
};
|
|
3966
|
+
|
|
3967
|
+
openRequest['onsuccess'] = function () {
|
|
3968
|
+
resolve(openRequest.result);
|
|
3969
|
+
};
|
|
3970
|
+
|
|
3971
|
+
openRequest['onupgradeneeded'] = function (ev) {
|
|
3972
|
+
var db = ev.target.result;
|
|
3973
|
+
|
|
3974
|
+
storeNamesInDb.forEach(function (storeName) {
|
|
3975
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
3976
|
+
db.createObjectStore(storeName);
|
|
3977
|
+
}
|
|
3978
|
+
});
|
|
3979
|
+
};
|
|
3980
|
+
});
|
|
3981
|
+
};
|
|
3982
|
+
|
|
3983
|
+
IDBStorageWrapper.prototype.init = function () {
|
|
3984
|
+
if (!win.indexedDB) {
|
|
3985
|
+
return PromisePolyfill.reject('indexedDB is not supported in this browser');
|
|
3986
|
+
}
|
|
3987
|
+
|
|
3988
|
+
if (!this.dbPromise) {
|
|
3989
|
+
this.dbPromise = this._openDb();
|
|
3990
|
+
}
|
|
3991
|
+
|
|
3992
|
+
return this.dbPromise
|
|
3993
|
+
.then(function (dbOrError) {
|
|
3994
|
+
if (dbOrError instanceof win['IDBDatabase']) {
|
|
3995
|
+
return PromisePolyfill.resolve();
|
|
3996
|
+
} else {
|
|
3997
|
+
return PromisePolyfill.reject(dbOrError);
|
|
3998
|
+
}
|
|
3999
|
+
});
|
|
4000
|
+
};
|
|
4001
|
+
|
|
4002
|
+
IDBStorageWrapper.prototype.isInitialized = function () {
|
|
4003
|
+
return !!this.dbPromise;
|
|
4004
|
+
};
|
|
4005
|
+
|
|
4006
|
+
/**
|
|
4007
|
+
* @param {IDBTransactionMode} mode
|
|
4008
|
+
* @param {function(IDBObjectStore): void} storeCb
|
|
4009
|
+
*/
|
|
4010
|
+
IDBStorageWrapper.prototype.makeTransaction = function (mode, storeCb) {
|
|
4011
|
+
var storeName = this.storeName;
|
|
4012
|
+
var doTransaction = function (db) {
|
|
4013
|
+
return new PromisePolyfill(function (resolve, reject) {
|
|
4014
|
+
var transaction = db.transaction(storeName, mode);
|
|
4015
|
+
transaction.oncomplete = function () {
|
|
4016
|
+
resolve(transaction);
|
|
4017
|
+
};
|
|
4018
|
+
transaction.onabort = transaction.onerror = function () {
|
|
4019
|
+
reject(transaction.error);
|
|
4020
|
+
};
|
|
4021
|
+
|
|
4022
|
+
storeCb(transaction.objectStore(storeName));
|
|
4023
|
+
});
|
|
4024
|
+
};
|
|
4025
|
+
|
|
4026
|
+
return this.dbPromise
|
|
4027
|
+
.then(doTransaction)
|
|
4028
|
+
.catch(function (err) {
|
|
4029
|
+
if (err && err['name'] === 'InvalidStateError') {
|
|
4030
|
+
// try reopening the DB if the connection is closed
|
|
4031
|
+
this.dbPromise = this._openDb();
|
|
4032
|
+
return this.dbPromise.then(doTransaction);
|
|
4033
|
+
} else {
|
|
4034
|
+
return PromisePolyfill.reject(err);
|
|
4035
|
+
}
|
|
4036
|
+
}.bind(this));
|
|
4037
|
+
};
|
|
4038
|
+
|
|
4039
|
+
IDBStorageWrapper.prototype.setItem = function (key, value) {
|
|
4040
|
+
return this.makeTransaction('readwrite', function (objectStore) {
|
|
4041
|
+
objectStore.put(value, key);
|
|
4042
|
+
});
|
|
4043
|
+
};
|
|
4044
|
+
|
|
4045
|
+
IDBStorageWrapper.prototype.getItem = function (key) {
|
|
4046
|
+
var req;
|
|
4047
|
+
return this.makeTransaction('readonly', function (objectStore) {
|
|
4048
|
+
req = objectStore.get(key);
|
|
4049
|
+
}).then(function () {
|
|
4050
|
+
return req.result;
|
|
4051
|
+
});
|
|
4052
|
+
};
|
|
4053
|
+
|
|
4054
|
+
IDBStorageWrapper.prototype.removeItem = function (key) {
|
|
4055
|
+
return this.makeTransaction('readwrite', function (objectStore) {
|
|
4056
|
+
objectStore.delete(key);
|
|
4057
|
+
});
|
|
4058
|
+
};
|
|
4059
|
+
|
|
4060
|
+
IDBStorageWrapper.prototype.getAll = function () {
|
|
4061
|
+
var req;
|
|
4062
|
+
return this.makeTransaction('readonly', function (objectStore) {
|
|
4063
|
+
req = objectStore.getAll();
|
|
4064
|
+
}).then(function () {
|
|
4065
|
+
return req.result;
|
|
4066
|
+
});
|
|
4067
|
+
};
|
|
4068
|
+
|
|
4069
|
+
var logger$5 = console_with_prefix('flags');
|
|
4070
|
+
|
|
4071
|
+
var MIXPANEL_FLAGS_DB_NAME = 'mixpanelFlagsDb';
|
|
4072
|
+
var FLAGS_STORE_NAME = 'mixpanelFlags';
|
|
4073
|
+
|
|
4074
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
4075
|
+
var FLAGS_VERSION_DATA = { version: 1, storeNames: [FLAGS_STORE_NAME] };
|
|
4076
|
+
|
|
4077
|
+
var PERSISTED_VARIANTS_KEY_PREFIX = 'persisted_variants_for_';
|
|
4078
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
4079
|
+
|
|
4080
|
+
var VariantLookupPolicy = Object.freeze({
|
|
4081
|
+
NETWORK_ONLY: 'networkOnly',
|
|
4082
|
+
NETWORK_FIRST: 'networkFirst',
|
|
4083
|
+
PERSISTENCE_UNTIL_NETWORK_SUCCESS: 'persistenceUntilNetworkSuccess'
|
|
4084
|
+
});
|
|
4085
|
+
|
|
4086
|
+
var VALID_POLICIES = [
|
|
4087
|
+
VariantLookupPolicy.NETWORK_ONLY,
|
|
4088
|
+
VariantLookupPolicy.NETWORK_FIRST,
|
|
4089
|
+
VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS
|
|
4090
|
+
];
|
|
4091
|
+
|
|
4092
|
+
/**
|
|
4093
|
+
* Module for handling the storage and retrieval of persisted feature flag variants.
|
|
4094
|
+
*/
|
|
4095
|
+
var FeatureFlagPersistence = function(persistenceConfig, token, isGloballyDisabled) {
|
|
4096
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_FLAGS_DB_NAME, FLAGS_STORE_NAME, FLAGS_VERSION_DATA);
|
|
4097
|
+
this.persistenceConfig = persistenceConfig;
|
|
4098
|
+
this.persistedVariantsKey = PERSISTED_VARIANTS_KEY_PREFIX + token;
|
|
4099
|
+
this.isGloballyDisabled = isGloballyDisabled || function() { return false; };
|
|
4100
|
+
};
|
|
4101
|
+
|
|
4102
|
+
FeatureFlagPersistence.prototype.getPolicy = function() {
|
|
4103
|
+
if (this.isGloballyDisabled() || !this._isConfigValid()) {
|
|
4104
|
+
return VariantLookupPolicy.NETWORK_ONLY;
|
|
4105
|
+
}
|
|
4106
|
+
return this.persistenceConfig['variantLookupPolicy'];
|
|
4107
|
+
};
|
|
4108
|
+
|
|
4109
|
+
FeatureFlagPersistence.prototype.getTtlMs = function() {
|
|
4110
|
+
if (!this._isConfigValid()) {
|
|
4111
|
+
return DEFAULT_TTL_MS;
|
|
4112
|
+
}
|
|
4113
|
+
var configuredTtl = this.persistenceConfig['persistenceTtlMs'];
|
|
4114
|
+
return (configuredTtl === undefined || configuredTtl === null) ? DEFAULT_TTL_MS : configuredTtl;
|
|
4115
|
+
};
|
|
4116
|
+
|
|
4117
|
+
FeatureFlagPersistence.prototype._isConfigValid = function() {
|
|
4118
|
+
var config = this.persistenceConfig;
|
|
4119
|
+
if (!config) {
|
|
4120
|
+
return false;
|
|
4121
|
+
}
|
|
4122
|
+
|
|
4123
|
+
if (VALID_POLICIES.indexOf(config['variantLookupPolicy']) === -1) {
|
|
4124
|
+
logger$5.error('Invalid variantLookupPolicy:', config['variantLookupPolicy']);
|
|
4125
|
+
return false;
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
if (config['persistenceTtlMs'] !== undefined &&
|
|
4129
|
+
config['persistenceTtlMs'] !== null &&
|
|
4130
|
+
config['persistenceTtlMs'] <= 0) {
|
|
4131
|
+
logger$5.error('If provided, persistenceTtlMs must be a positive number. Provided value:', config['persistenceTtlMs']);
|
|
4132
|
+
return false;
|
|
4133
|
+
}
|
|
4134
|
+
|
|
4135
|
+
return true;
|
|
4136
|
+
};
|
|
4137
|
+
|
|
4138
|
+
FeatureFlagPersistence.prototype.loadFlagsFromStorage = function(context) {
|
|
4139
|
+
var clearAndReturnNull = _.bind(function() {
|
|
4140
|
+
return this.clear().then(function() { return null; }).catch(function() { return null; });
|
|
4141
|
+
}, this);
|
|
4142
|
+
|
|
4143
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
4144
|
+
return clearAndReturnNull();
|
|
4145
|
+
}
|
|
4146
|
+
|
|
4147
|
+
var ttlMs = this.getTtlMs();
|
|
4148
|
+
|
|
4149
|
+
return this.idb.init().then(_.bind(function() {
|
|
4150
|
+
return this.idb.getItem(this.persistedVariantsKey);
|
|
4151
|
+
}, this)).then(_.bind(function(data) {
|
|
4152
|
+
if (!data) {
|
|
4153
|
+
logger$5.log('No persisted variants found in IndexedDB');
|
|
4154
|
+
return null;
|
|
4155
|
+
}
|
|
4156
|
+
|
|
4157
|
+
if (ttlMs && Date.now() - data['persistedAt'] >= ttlMs) {
|
|
4158
|
+
logger$5.log('Persisted variants are expiring');
|
|
4159
|
+
return null;
|
|
4160
|
+
}
|
|
4161
|
+
|
|
4162
|
+
if (!context || data['distinctId'] !== context['distinct_id']) {
|
|
4163
|
+
logger$5.log('Persisted variants found, but for a different distinct_id so clearing.');
|
|
4164
|
+
return clearAndReturnNull();
|
|
4165
|
+
}
|
|
4166
|
+
|
|
4167
|
+
var persistedFlags = new Map();
|
|
4168
|
+
_.each(data['flagVariants'], function(variantData, key) {
|
|
4169
|
+
persistedFlags.set(key, {
|
|
4170
|
+
'key': variantData['variant_key'],
|
|
4171
|
+
'value': variantData['variant_value'],
|
|
4172
|
+
'experiment_id': variantData['experiment_id'],
|
|
4173
|
+
'is_experiment_active': variantData['is_experiment_active'],
|
|
4174
|
+
'is_qa_tester': variantData['is_qa_tester'],
|
|
4175
|
+
'variant_source': 'persistence',
|
|
4176
|
+
'persisted_at_in_ms': data['persistedAt'],
|
|
4177
|
+
'ttl_in_ms': ttlMs
|
|
4178
|
+
});
|
|
4179
|
+
});
|
|
4180
|
+
|
|
4181
|
+
logger$5.log('Loaded', persistedFlags.size, 'variants from IndexedDB for distinct_id', data['distinctId']);
|
|
4182
|
+
|
|
4183
|
+
return {
|
|
4184
|
+
flags: persistedFlags,
|
|
4185
|
+
pendingFirstTimeEvents: data['pendingFirstTimeEvents'] || {},
|
|
4186
|
+
persistedAtMs: data['persistedAt'],
|
|
4187
|
+
ttlMs: ttlMs
|
|
4188
|
+
};
|
|
4189
|
+
}, this)).catch(_.bind(function(error) {
|
|
4190
|
+
logger$5.error('Failed to load persisted variants from IndexedDB, so clearing', error);
|
|
4191
|
+
return clearAndReturnNull();
|
|
4192
|
+
}, this));
|
|
4193
|
+
};
|
|
4194
|
+
|
|
4195
|
+
FeatureFlagPersistence.prototype.save = function(context, flagsMap, pendingFirstTimeEvents) {
|
|
4196
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
4197
|
+
return Promise.resolve();
|
|
4198
|
+
}
|
|
4199
|
+
|
|
4200
|
+
var flagVariants = {};
|
|
4201
|
+
flagsMap.forEach(function(variant, key) {
|
|
4202
|
+
flagVariants[key] = {
|
|
4203
|
+
'variant_key': variant['key'],
|
|
4204
|
+
'variant_value': variant['value'],
|
|
4205
|
+
'experiment_id': variant['experiment_id'],
|
|
4206
|
+
'is_experiment_active': variant['is_experiment_active'],
|
|
4207
|
+
'is_qa_tester': variant['is_qa_tester']
|
|
4208
|
+
};
|
|
4209
|
+
});
|
|
4210
|
+
|
|
4211
|
+
var data = {
|
|
4212
|
+
'persistedAt': Date.now(),
|
|
4213
|
+
'distinctId': context && context['distinct_id'],
|
|
4214
|
+
'context': context,
|
|
4215
|
+
'flagVariants': flagVariants,
|
|
4216
|
+
'pendingFirstTimeEvents': pendingFirstTimeEvents || {}
|
|
4217
|
+
};
|
|
4218
|
+
|
|
4219
|
+
return this.idb.init().then(_.bind(function() {
|
|
4220
|
+
return this.idb.setItem(this.persistedVariantsKey, data);
|
|
4221
|
+
}, this)).then(function() {
|
|
4222
|
+
logger$5.log('Saved', flagsMap.size, 'variants to IndexedDB for distinct_id', data['distinctId']);
|
|
4223
|
+
}).catch(function(error) {
|
|
4224
|
+
logger$5.error('Failed to persist variants to IndexedDB:', error);
|
|
4225
|
+
});
|
|
4226
|
+
};
|
|
4227
|
+
|
|
4228
|
+
FeatureFlagPersistence.prototype.clear = function() {
|
|
4229
|
+
if (this.isGloballyDisabled()) {
|
|
4230
|
+
return Promise.resolve();
|
|
4231
|
+
}
|
|
4232
|
+
return this.idb.init().then(_.bind(function() {
|
|
4233
|
+
return this.idb.removeItem(this.persistedVariantsKey);
|
|
4234
|
+
}, this)).then(function() {
|
|
4235
|
+
logger$5.log('Cleared persisted variants from IndexedDB');
|
|
4236
|
+
}).catch(function(error) {
|
|
4237
|
+
logger$5.error('Failed to clear persisted variants from IndexedDB:', error);
|
|
4238
|
+
});
|
|
4239
|
+
};
|
|
4240
|
+
|
|
3926
4241
|
var logger$4 = console_with_prefix('flags');
|
|
3927
4242
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
3928
4243
|
|
|
3929
4244
|
var CONFIG_CONTEXT = 'context';
|
|
4245
|
+
var CONFIG_PERSISTENCE = 'persistence';
|
|
3930
4246
|
var CONFIG_DEFAULTS = {};
|
|
3931
4247
|
CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
3932
4248
|
|
|
@@ -3949,6 +4265,13 @@ var getFlagKeyFromPendingEventKey = function(eventKey) {
|
|
|
3949
4265
|
return eventKey.split(':')[0];
|
|
3950
4266
|
};
|
|
3951
4267
|
|
|
4268
|
+
var withFallbackSource = function(fallback) {
|
|
4269
|
+
if (_.isObject(fallback)) {
|
|
4270
|
+
return _.extend({}, fallback, {'variant_source': 'fallback'});
|
|
4271
|
+
}
|
|
4272
|
+
return {'value': fallback, 'variant_source': 'fallback'};
|
|
4273
|
+
};
|
|
4274
|
+
|
|
3952
4275
|
/**
|
|
3953
4276
|
* FeatureFlagManager: support for Mixpanel's feature flagging product
|
|
3954
4277
|
* @constructor
|
|
@@ -3971,13 +4294,63 @@ FeatureFlagManager.prototype.init = function() {
|
|
|
3971
4294
|
}
|
|
3972
4295
|
|
|
3973
4296
|
this.flags = null;
|
|
3974
|
-
this.fetchFlags().catch(function() {
|
|
3975
|
-
logger$4.error('Error fetching flags during init');
|
|
3976
|
-
});
|
|
3977
|
-
|
|
3978
4297
|
this.trackedFeatures = new Set();
|
|
3979
4298
|
this.pendingFirstTimeEvents = {};
|
|
3980
4299
|
this.activatedFirstTimeEvents = {};
|
|
4300
|
+
this._loadedPersistedAtMs = null;
|
|
4301
|
+
this._loadedTtlMs = null;
|
|
4302
|
+
|
|
4303
|
+
this.persistence = new FeatureFlagPersistence(
|
|
4304
|
+
this.getConfig(CONFIG_PERSISTENCE),
|
|
4305
|
+
this.getMpConfig('token'),
|
|
4306
|
+
_.bind(function() { return this.getMpConfig('disable_persistence'); }, this)
|
|
4307
|
+
);
|
|
4308
|
+
|
|
4309
|
+
this.persistenceLoadedPromise = this.persistence.loadFlagsFromStorage(this._buildContext())
|
|
4310
|
+
.then(_.bind(function(loaded) {
|
|
4311
|
+
if (loaded) {
|
|
4312
|
+
this.flags = loaded.flags;
|
|
4313
|
+
this.pendingFirstTimeEvents = loaded.pendingFirstTimeEvents;
|
|
4314
|
+
this._loadedPersistedAtMs = loaded.persistedAtMs;
|
|
4315
|
+
this._loadedTtlMs = loaded.ttlMs;
|
|
4316
|
+
}
|
|
4317
|
+
}, this));
|
|
4318
|
+
|
|
4319
|
+
return this.persistenceLoadedPromise
|
|
4320
|
+
.then(_.bind(function() {
|
|
4321
|
+
return this.fetchFlags();
|
|
4322
|
+
}, this))
|
|
4323
|
+
.catch(function() {
|
|
4324
|
+
logger$4.error('Error initializing feature flags');
|
|
4325
|
+
});
|
|
4326
|
+
};
|
|
4327
|
+
|
|
4328
|
+
FeatureFlagManager.prototype._buildContext = function() {
|
|
4329
|
+
return _.extend(
|
|
4330
|
+
{'distinct_id': this.getMpProperty('distinct_id'), 'device_id': this.getMpProperty('$device_id')},
|
|
4331
|
+
this.getConfig(CONFIG_CONTEXT)
|
|
4332
|
+
);
|
|
4333
|
+
};
|
|
4334
|
+
|
|
4335
|
+
FeatureFlagManager.prototype.reset = function() {
|
|
4336
|
+
if (!this.persistence) {
|
|
4337
|
+
return Promise.resolve();
|
|
4338
|
+
}
|
|
4339
|
+
|
|
4340
|
+
this.flags = null;
|
|
4341
|
+
this.pendingFirstTimeEvents = {};
|
|
4342
|
+
this.activatedFirstTimeEvents = {};
|
|
4343
|
+
this.trackedFeatures = new Set();
|
|
4344
|
+
this.fetchPromise = null;
|
|
4345
|
+
this._fetchInProgressStartTime = null;
|
|
4346
|
+
this._loadedPersistedAtMs = null;
|
|
4347
|
+
this._loadedTtlMs = null;
|
|
4348
|
+
|
|
4349
|
+
return this.persistence.clear().then(_.bind(function() {
|
|
4350
|
+
return this.fetchFlags();
|
|
4351
|
+
}, this)).catch(function() {
|
|
4352
|
+
logger$4.error('Error during flags reset');
|
|
4353
|
+
});
|
|
3981
4354
|
};
|
|
3982
4355
|
|
|
3983
4356
|
FeatureFlagManager.prototype.getFullConfig = function() {
|
|
@@ -4034,12 +4407,11 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
4034
4407
|
return Promise.resolve();
|
|
4035
4408
|
}
|
|
4036
4409
|
|
|
4037
|
-
var
|
|
4038
|
-
var
|
|
4410
|
+
var context = this._buildContext();
|
|
4411
|
+
var distinctId = context['distinct_id'];
|
|
4039
4412
|
var traceparent = generateTraceparent();
|
|
4040
4413
|
logger$4.log('Fetching flags for distinct ID: ' + distinctId);
|
|
4041
4414
|
|
|
4042
|
-
var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
|
|
4043
4415
|
var searchParams = new URLSearchParams();
|
|
4044
4416
|
searchParams.set('context', JSON.stringify(context));
|
|
4045
4417
|
searchParams.set('token', this.getMpConfig('token'));
|
|
@@ -4089,7 +4461,8 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
4089
4461
|
'value': data['variant_value'],
|
|
4090
4462
|
'experiment_id': data['experiment_id'],
|
|
4091
4463
|
'is_experiment_active': data['is_experiment_active'],
|
|
4092
|
-
'is_qa_tester': data['is_qa_tester']
|
|
4464
|
+
'is_qa_tester': data['is_qa_tester'],
|
|
4465
|
+
'variant_source': 'network'
|
|
4093
4466
|
});
|
|
4094
4467
|
}
|
|
4095
4468
|
}, this);
|
|
@@ -4131,10 +4504,15 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
4131
4504
|
}
|
|
4132
4505
|
|
|
4133
4506
|
this.flags = flags;
|
|
4507
|
+
this.trackedFeatures = new Set();
|
|
4134
4508
|
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
4509
|
+
this._loadedPersistedAtMs = null;
|
|
4510
|
+
this._loadedTtlMs = null;
|
|
4135
4511
|
this._traceparent = traceparent;
|
|
4136
4512
|
|
|
4137
4513
|
this._loadTargetingIfNeeded();
|
|
4514
|
+
|
|
4515
|
+
this.persistence.save(context, this.flags, this.pendingFirstTimeEvents);
|
|
4138
4516
|
}.bind(this)).catch(function(error) {
|
|
4139
4517
|
if (this._fetchInProgressStartTime) {
|
|
4140
4518
|
this.markFetchComplete();
|
|
@@ -4294,6 +4672,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
4294
4672
|
};
|
|
4295
4673
|
|
|
4296
4674
|
this.flags.set(flagKey, newVariant);
|
|
4675
|
+
this.trackedFeatures.delete(flagKey);
|
|
4297
4676
|
this.activatedFirstTimeEvents[eventKey] = true;
|
|
4298
4677
|
|
|
4299
4678
|
this.recordFirstTimeEvent(
|
|
@@ -4343,35 +4722,106 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
|
|
|
4343
4722
|
};
|
|
4344
4723
|
|
|
4345
4724
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
4346
|
-
if (!this.
|
|
4725
|
+
if (!this.persistenceLoadedPromise) {
|
|
4347
4726
|
return new Promise(function(resolve) {
|
|
4348
4727
|
logger$4.critical('Feature Flags not initialized');
|
|
4349
|
-
resolve(fallback);
|
|
4728
|
+
resolve(withFallbackSource(fallback));
|
|
4350
4729
|
});
|
|
4351
4730
|
}
|
|
4352
4731
|
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4732
|
+
var policy = this.persistence.getPolicy();
|
|
4733
|
+
|
|
4734
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
4735
|
+
// Serve from persistence until the network completes a successful fetch. If a non-expired cached value is available, return it without waiting on the in-flight fetch.
|
|
4736
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
4737
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
4738
|
+
return this.getVariantSync(featureName, fallback);
|
|
4739
|
+
}
|
|
4740
|
+
if (!this.fetchPromise) {
|
|
4741
|
+
return withFallbackSource(fallback);
|
|
4742
|
+
}
|
|
4743
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
4744
|
+
return this.getVariantSync(featureName, fallback);
|
|
4745
|
+
}, this)).catch(function(error) {
|
|
4746
|
+
logger$4.error(error);
|
|
4747
|
+
return withFallbackSource(fallback);
|
|
4748
|
+
});
|
|
4749
|
+
}
|
|
4750
|
+
|
|
4751
|
+
var serve = _.bind(function() { return this.getVariantSync(featureName, fallback); }, this);
|
|
4752
|
+
if (!this.fetchPromise) {
|
|
4753
|
+
return withFallbackSource(fallback);
|
|
4754
|
+
}
|
|
4755
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
4756
|
+
}, this));
|
|
4757
|
+
};
|
|
4758
|
+
|
|
4759
|
+
FeatureFlagManager.prototype._loadedPersistenceIsStale = function() {
|
|
4760
|
+
if (!this._loadedPersistedAtMs || !this._loadedTtlMs) {
|
|
4761
|
+
return false;
|
|
4762
|
+
}
|
|
4763
|
+
return Date.now() - this._loadedPersistedAtMs >= this._loadedTtlMs;
|
|
4359
4764
|
};
|
|
4360
4765
|
|
|
4361
4766
|
FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
|
|
4767
|
+
if (this._loadedPersistenceIsStale()) {
|
|
4768
|
+
logger$4.log('Loaded persisted variants are past TTL so returning fallback for "' + featureName + '"');
|
|
4769
|
+
return withFallbackSource(fallback);
|
|
4770
|
+
}
|
|
4362
4771
|
if (!this.areFlagsReady()) {
|
|
4363
4772
|
logger$4.log('Flags not loaded yet');
|
|
4364
|
-
return fallback;
|
|
4773
|
+
return withFallbackSource(fallback);
|
|
4365
4774
|
}
|
|
4366
4775
|
var feature = this.flags.get(featureName);
|
|
4367
4776
|
if (!feature) {
|
|
4368
4777
|
logger$4.log('No flag found: "' + featureName + '"');
|
|
4369
|
-
return fallback;
|
|
4778
|
+
return withFallbackSource(fallback);
|
|
4370
4779
|
}
|
|
4371
4780
|
this.trackFeatureCheck(featureName, feature);
|
|
4372
4781
|
return feature;
|
|
4373
4782
|
};
|
|
4374
4783
|
|
|
4784
|
+
FeatureFlagManager.prototype.getAllVariants = function() {
|
|
4785
|
+
if (!this.persistenceLoadedPromise) {
|
|
4786
|
+
logger$4.critical('Feature Flags not initialized');
|
|
4787
|
+
return Promise.resolve(new Map());
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4790
|
+
var policy = this.persistence.getPolicy();
|
|
4791
|
+
|
|
4792
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
4793
|
+
// Serve from persistence until the network completes a successful fetch. If a non-expired cached value is available, return it without waiting on the in-flight fetch.
|
|
4794
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
4795
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
4796
|
+
return this.getAllVariantsSync();
|
|
4797
|
+
}
|
|
4798
|
+
if (!this.fetchPromise) {
|
|
4799
|
+
return new Map();
|
|
4800
|
+
}
|
|
4801
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
4802
|
+
return this.getAllVariantsSync();
|
|
4803
|
+
}, this)).catch(function(error) {
|
|
4804
|
+
logger$4.error(error);
|
|
4805
|
+
return new Map();
|
|
4806
|
+
});
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
var serve = _.bind(this.getAllVariantsSync, this);
|
|
4810
|
+
if (!this.fetchPromise) {
|
|
4811
|
+
return new Map();
|
|
4812
|
+
}
|
|
4813
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
4814
|
+
}, this));
|
|
4815
|
+
};
|
|
4816
|
+
|
|
4817
|
+
FeatureFlagManager.prototype.getAllVariantsSync = function() {
|
|
4818
|
+
if (this._loadedPersistenceIsStale()) {
|
|
4819
|
+
logger$4.log('Loaded persisted variants are past TTL so returning empty Map');
|
|
4820
|
+
return new Map();
|
|
4821
|
+
}
|
|
4822
|
+
return this.flags || new Map();
|
|
4823
|
+
};
|
|
4824
|
+
|
|
4375
4825
|
FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackValue) {
|
|
4376
4826
|
return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
|
|
4377
4827
|
return feature['value'];
|
|
@@ -4410,6 +4860,10 @@ FeatureFlagManager.prototype.isEnabledSync = function(featureName, fallbackValue
|
|
|
4410
4860
|
return val;
|
|
4411
4861
|
};
|
|
4412
4862
|
|
|
4863
|
+
function isPresent(v) {
|
|
4864
|
+
return v !== undefined && v !== null;
|
|
4865
|
+
}
|
|
4866
|
+
|
|
4413
4867
|
FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature) {
|
|
4414
4868
|
if (this.trackedFeatures.has(featureName)) {
|
|
4415
4869
|
return;
|
|
@@ -4420,21 +4874,30 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
4420
4874
|
'Experiment name': featureName,
|
|
4421
4875
|
'Variant name': feature['key'],
|
|
4422
4876
|
'$experiment_type': 'feature_flag',
|
|
4423
|
-
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
4424
|
-
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
4877
|
+
'Variant fetch start time': isPresent(this._fetchStartTime) ? new Date(this._fetchStartTime).toISOString() : null,
|
|
4878
|
+
'Variant fetch complete time': isPresent(this._fetchCompleteTime) ? new Date(this._fetchCompleteTime).toISOString() : null,
|
|
4425
4879
|
'Variant fetch latency (ms)': this._fetchLatency,
|
|
4426
4880
|
'Variant fetch traceparent': this._traceparent,
|
|
4427
4881
|
};
|
|
4428
4882
|
|
|
4429
|
-
if (feature['experiment_id']
|
|
4883
|
+
if (isPresent(feature['experiment_id'])) {
|
|
4430
4884
|
trackingProperties['$experiment_id'] = feature['experiment_id'];
|
|
4431
4885
|
}
|
|
4432
|
-
if (feature['is_experiment_active']
|
|
4886
|
+
if (isPresent(feature['is_experiment_active'])) {
|
|
4433
4887
|
trackingProperties['$is_experiment_active'] = feature['is_experiment_active'];
|
|
4434
4888
|
}
|
|
4435
|
-
if (feature['is_qa_tester']
|
|
4889
|
+
if (isPresent(feature['is_qa_tester'])) {
|
|
4436
4890
|
trackingProperties['$is_qa_tester'] = feature['is_qa_tester'];
|
|
4437
4891
|
}
|
|
4892
|
+
if (isPresent(feature['variant_source'])) {
|
|
4893
|
+
trackingProperties['$variant_source'] = feature['variant_source'];
|
|
4894
|
+
}
|
|
4895
|
+
if (isPresent(feature['persisted_at_in_ms'])) {
|
|
4896
|
+
trackingProperties['$persisted_at_in_ms'] = feature['persisted_at_in_ms'];
|
|
4897
|
+
}
|
|
4898
|
+
if (isPresent(feature['ttl_in_ms'])) {
|
|
4899
|
+
trackingProperties['$ttl_in_ms'] = feature['ttl_in_ms'];
|
|
4900
|
+
}
|
|
4438
4901
|
|
|
4439
4902
|
this.track('$experiment_started', trackingProperties);
|
|
4440
4903
|
};
|
|
@@ -4458,6 +4921,8 @@ safewrapClass(FeatureFlagManager);
|
|
|
4458
4921
|
FeatureFlagManager.prototype['are_flags_ready'] = FeatureFlagManager.prototype.areFlagsReady;
|
|
4459
4922
|
FeatureFlagManager.prototype['get_variant'] = FeatureFlagManager.prototype.getVariant;
|
|
4460
4923
|
FeatureFlagManager.prototype['get_variant_sync'] = FeatureFlagManager.prototype.getVariantSync;
|
|
4924
|
+
FeatureFlagManager.prototype['get_all_variants'] = FeatureFlagManager.prototype.getAllVariants;
|
|
4925
|
+
FeatureFlagManager.prototype['get_all_variants_sync'] = FeatureFlagManager.prototype.getAllVariantsSync;
|
|
4461
4926
|
FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype.getVariantValue;
|
|
4462
4927
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
4463
4928
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
@@ -4472,131 +4937,14 @@ FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.
|
|
|
4472
4937
|
// Exports intended only for testing
|
|
4473
4938
|
FeatureFlagManager.prototype['getTargeting'] = FeatureFlagManager.prototype.getTargeting;
|
|
4474
4939
|
|
|
4475
|
-
var
|
|
4476
|
-
|
|
4940
|
+
var MIXPANEL_BROWSER_DB_NAME = 'mixpanelBrowserDb';
|
|
4477
4941
|
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
4478
4942
|
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
4479
4943
|
|
|
4480
|
-
//
|
|
4481
|
-
var
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
/**
|
|
4485
|
-
* @type {import('./wrapper').StorageWrapper}
|
|
4486
|
-
*/
|
|
4487
|
-
var IDBStorageWrapper = function (storeName) {
|
|
4488
|
-
/**
|
|
4489
|
-
* @type {Promise<IDBDatabase>|null}
|
|
4490
|
-
*/
|
|
4491
|
-
this.dbPromise = null;
|
|
4492
|
-
this.storeName = storeName;
|
|
4493
|
-
};
|
|
4494
|
-
|
|
4495
|
-
IDBStorageWrapper.prototype._openDb = function () {
|
|
4496
|
-
return new PromisePolyfill(function (resolve, reject) {
|
|
4497
|
-
var openRequest = win.indexedDB.open(MIXPANEL_DB_NAME, DB_VERSION);
|
|
4498
|
-
openRequest['onerror'] = function () {
|
|
4499
|
-
reject(openRequest.error);
|
|
4500
|
-
};
|
|
4501
|
-
|
|
4502
|
-
openRequest['onsuccess'] = function () {
|
|
4503
|
-
resolve(openRequest.result);
|
|
4504
|
-
};
|
|
4505
|
-
|
|
4506
|
-
openRequest['onupgradeneeded'] = function (ev) {
|
|
4507
|
-
var db = ev.target.result;
|
|
4508
|
-
|
|
4509
|
-
OBJECT_STORES.forEach(function (storeName) {
|
|
4510
|
-
db.createObjectStore(storeName);
|
|
4511
|
-
});
|
|
4512
|
-
};
|
|
4513
|
-
});
|
|
4514
|
-
};
|
|
4515
|
-
|
|
4516
|
-
IDBStorageWrapper.prototype.init = function () {
|
|
4517
|
-
if (!win.indexedDB) {
|
|
4518
|
-
return PromisePolyfill.reject('indexedDB is not supported in this browser');
|
|
4519
|
-
}
|
|
4520
|
-
|
|
4521
|
-
if (!this.dbPromise) {
|
|
4522
|
-
this.dbPromise = this._openDb();
|
|
4523
|
-
}
|
|
4524
|
-
|
|
4525
|
-
return this.dbPromise
|
|
4526
|
-
.then(function (dbOrError) {
|
|
4527
|
-
if (dbOrError instanceof win['IDBDatabase']) {
|
|
4528
|
-
return PromisePolyfill.resolve();
|
|
4529
|
-
} else {
|
|
4530
|
-
return PromisePolyfill.reject(dbOrError);
|
|
4531
|
-
}
|
|
4532
|
-
});
|
|
4533
|
-
};
|
|
4534
|
-
|
|
4535
|
-
IDBStorageWrapper.prototype.isInitialized = function () {
|
|
4536
|
-
return !!this.dbPromise;
|
|
4537
|
-
};
|
|
4538
|
-
|
|
4539
|
-
/**
|
|
4540
|
-
* @param {IDBTransactionMode} mode
|
|
4541
|
-
* @param {function(IDBObjectStore): void} storeCb
|
|
4542
|
-
*/
|
|
4543
|
-
IDBStorageWrapper.prototype.makeTransaction = function (mode, storeCb) {
|
|
4544
|
-
var storeName = this.storeName;
|
|
4545
|
-
var doTransaction = function (db) {
|
|
4546
|
-
return new PromisePolyfill(function (resolve, reject) {
|
|
4547
|
-
var transaction = db.transaction(storeName, mode);
|
|
4548
|
-
transaction.oncomplete = function () {
|
|
4549
|
-
resolve(transaction);
|
|
4550
|
-
};
|
|
4551
|
-
transaction.onabort = transaction.onerror = function () {
|
|
4552
|
-
reject(transaction.error);
|
|
4553
|
-
};
|
|
4554
|
-
|
|
4555
|
-
storeCb(transaction.objectStore(storeName));
|
|
4556
|
-
});
|
|
4557
|
-
};
|
|
4558
|
-
|
|
4559
|
-
return this.dbPromise
|
|
4560
|
-
.then(doTransaction)
|
|
4561
|
-
.catch(function (err) {
|
|
4562
|
-
if (err && err['name'] === 'InvalidStateError') {
|
|
4563
|
-
// try reopening the DB if the connection is closed
|
|
4564
|
-
this.dbPromise = this._openDb();
|
|
4565
|
-
return this.dbPromise.then(doTransaction);
|
|
4566
|
-
} else {
|
|
4567
|
-
return PromisePolyfill.reject(err);
|
|
4568
|
-
}
|
|
4569
|
-
}.bind(this));
|
|
4570
|
-
};
|
|
4571
|
-
|
|
4572
|
-
IDBStorageWrapper.prototype.setItem = function (key, value) {
|
|
4573
|
-
return this.makeTransaction('readwrite', function (objectStore) {
|
|
4574
|
-
objectStore.put(value, key);
|
|
4575
|
-
});
|
|
4576
|
-
};
|
|
4577
|
-
|
|
4578
|
-
IDBStorageWrapper.prototype.getItem = function (key) {
|
|
4579
|
-
var req;
|
|
4580
|
-
return this.makeTransaction('readonly', function (objectStore) {
|
|
4581
|
-
req = objectStore.get(key);
|
|
4582
|
-
}).then(function () {
|
|
4583
|
-
return req.result;
|
|
4584
|
-
});
|
|
4585
|
-
};
|
|
4586
|
-
|
|
4587
|
-
IDBStorageWrapper.prototype.removeItem = function (key) {
|
|
4588
|
-
return this.makeTransaction('readwrite', function (objectStore) {
|
|
4589
|
-
objectStore.delete(key);
|
|
4590
|
-
});
|
|
4591
|
-
};
|
|
4592
|
-
|
|
4593
|
-
IDBStorageWrapper.prototype.getAll = function () {
|
|
4594
|
-
var req;
|
|
4595
|
-
return this.makeTransaction('readonly', function (objectStore) {
|
|
4596
|
-
req = objectStore.getAll();
|
|
4597
|
-
}).then(function () {
|
|
4598
|
-
return req.result;
|
|
4599
|
-
});
|
|
4944
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
4945
|
+
var RECORDER_VERSION_DATA = {
|
|
4946
|
+
version: 1,
|
|
4947
|
+
storeNames: [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME]
|
|
4600
4948
|
};
|
|
4601
4949
|
|
|
4602
4950
|
/**
|
|
@@ -4669,7 +5017,7 @@ RecorderManager.prototype.shouldLoadRecorder = function() {
|
|
|
4669
5017
|
return PromisePolyfill.resolve(false);
|
|
4670
5018
|
}
|
|
4671
5019
|
|
|
4672
|
-
var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
5020
|
+
var recording_registry_idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
4673
5021
|
var tab_id = this.getTabId();
|
|
4674
5022
|
return recording_registry_idb.init()
|
|
4675
5023
|
.then(function () {
|
|
@@ -5125,7 +5473,7 @@ var SharedLock = function(key, options) {
|
|
|
5125
5473
|
options = options || {};
|
|
5126
5474
|
|
|
5127
5475
|
this.storageKey = key;
|
|
5128
|
-
this.storage = options.storage ||
|
|
5476
|
+
this.storage = options.storage || getLocalStorage();
|
|
5129
5477
|
this.pollIntervalMS = options.pollIntervalMS || 100;
|
|
5130
5478
|
this.timeoutMS = options.timeoutMS || 2000;
|
|
5131
5479
|
|
|
@@ -5253,10 +5601,13 @@ SharedLock.prototype.withLock = function(lockedCB, pid) {
|
|
|
5253
5601
|
* @type {import('./wrapper').StorageWrapper}
|
|
5254
5602
|
*/
|
|
5255
5603
|
var LocalStorageWrapper = function (storageOverride) {
|
|
5256
|
-
this.storage = storageOverride ||
|
|
5604
|
+
this.storage = storageOverride || getLocalStorage();
|
|
5257
5605
|
};
|
|
5258
5606
|
|
|
5259
5607
|
LocalStorageWrapper.prototype.init = function () {
|
|
5608
|
+
if (!this.storage) {
|
|
5609
|
+
return PromisePolyfill.reject(new Error('localStorage is not available'));
|
|
5610
|
+
}
|
|
5260
5611
|
return PromisePolyfill.resolve();
|
|
5261
5612
|
};
|
|
5262
5613
|
|
|
@@ -5323,7 +5674,7 @@ var RequestQueue = function (storageKey, options) {
|
|
|
5323
5674
|
if (this.usePersistence) {
|
|
5324
5675
|
this.queueStorage = options.queueStorage || new LocalStorageWrapper();
|
|
5325
5676
|
this.lock = new SharedLock(storageKey, {
|
|
5326
|
-
storage: options.sharedLockStorage
|
|
5677
|
+
storage: options.sharedLockStorage,
|
|
5327
5678
|
timeoutMS: options.sharedLockTimeoutMS,
|
|
5328
5679
|
});
|
|
5329
5680
|
}
|
|
@@ -7788,6 +8139,7 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
7788
8139
|
'disable_all_events': false,
|
|
7789
8140
|
'identify_called': false
|
|
7790
8141
|
};
|
|
8142
|
+
this._remote_settings_strict_disabled = false;
|
|
7791
8143
|
|
|
7792
8144
|
// set up request queueing/batching
|
|
7793
8145
|
this.request_batchers = {};
|
|
@@ -7862,9 +8214,6 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
7862
8214
|
this.flags.init();
|
|
7863
8215
|
this['flags'] = this.flags;
|
|
7864
8216
|
|
|
7865
|
-
this.autocapture = new Autocapture(this);
|
|
7866
|
-
this.autocapture.init();
|
|
7867
|
-
|
|
7868
8217
|
this._init_tab_id();
|
|
7869
8218
|
|
|
7870
8219
|
// Based on remote_settings_mode, fetch remote settings and then start session recording if applicable
|
|
@@ -7876,6 +8225,9 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
7876
8225
|
} else {
|
|
7877
8226
|
this.__session_recording_init_promise = this._check_and_start_session_recording();
|
|
7878
8227
|
}
|
|
8228
|
+
|
|
8229
|
+
this.autocapture = new Autocapture(this);
|
|
8230
|
+
this.autocapture.init();
|
|
7879
8231
|
};
|
|
7880
8232
|
|
|
7881
8233
|
/**
|
|
@@ -7922,9 +8274,19 @@ MixpanelLib.prototype._check_and_start_session_recording = addOptOutCheckMixpane
|
|
|
7922
8274
|
return this.recorderManager.checkAndStartSessionRecording(force_start);
|
|
7923
8275
|
});
|
|
7924
8276
|
|
|
7925
|
-
MixpanelLib.prototype._start_recording_on_event = function(event_name, properties) {
|
|
7926
|
-
|
|
7927
|
-
|
|
8277
|
+
MixpanelLib.prototype._start_recording_on_event = safewrap(function(event_name, properties) {
|
|
8278
|
+
// Wait for recording init to complete before evaluating event triggers.
|
|
8279
|
+
// This ensures recording_event_triggers config is fully loaded when remote settings are used.
|
|
8280
|
+
if (this.__session_recording_init_promise) {
|
|
8281
|
+
this.__session_recording_init_promise.then(_.bind(function() {
|
|
8282
|
+
// In strict mode, skip recording if remote settings failed
|
|
8283
|
+
if (this._remote_settings_strict_disabled) {
|
|
8284
|
+
return;
|
|
8285
|
+
}
|
|
8286
|
+
return this.recorderManager.startRecordingOnEvent(event_name, properties);
|
|
8287
|
+
}, this));
|
|
8288
|
+
}
|
|
8289
|
+
});
|
|
7928
8290
|
|
|
7929
8291
|
MixpanelLib.prototype.start_session_recording = function () {
|
|
7930
8292
|
return this._check_and_start_session_recording(true);
|
|
@@ -8223,6 +8585,7 @@ MixpanelLib.prototype._fetch_remote_settings = function(mode) {
|
|
|
8223
8585
|
var disableRecordingIfStrict = function() {
|
|
8224
8586
|
if (mode === 'strict') {
|
|
8225
8587
|
self.set_config({'record_sessions_percent': 0});
|
|
8588
|
+
self._remote_settings_strict_disabled = true;
|
|
8226
8589
|
}
|
|
8227
8590
|
};
|
|
8228
8591
|
|
|
@@ -8848,6 +9211,10 @@ MixpanelLib.prototype.track_pageview = addOptOutCheckMixpanelLib(function(proper
|
|
|
8848
9211
|
properties
|
|
8849
9212
|
);
|
|
8850
9213
|
|
|
9214
|
+
if (this.is_recording_heatmap_data()) {
|
|
9215
|
+
event_properties['$captured_for_heatmap'] = true;
|
|
9216
|
+
}
|
|
9217
|
+
|
|
8851
9218
|
return this.track(event_name, event_properties);
|
|
8852
9219
|
});
|
|
8853
9220
|
|
|
@@ -9191,6 +9558,7 @@ MixpanelLib.prototype.reset = function() {
|
|
|
9191
9558
|
'$device_id': uuid
|
|
9192
9559
|
}, '');
|
|
9193
9560
|
this._check_and_start_session_recording();
|
|
9561
|
+
this.flags.reset();
|
|
9194
9562
|
};
|
|
9195
9563
|
|
|
9196
9564
|
/**
|