mixpanel-browser 2.78.0 → 2.80.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/.eslintrc.json +12 -0
- package/.github/workflows/integration-tests.yml +1 -0
- package/.github/workflows/openfeature-provider-tests.yml +31 -0
- package/CHANGELOG.md +14 -1
- package/build.sh +2 -2
- package/dist/async-modules/{mixpanel-recorder-BjSlYaNJ.min.js → mixpanel-recorder-B61POiHc.min.js} +2 -2
- package/dist/async-modules/mixpanel-recorder-B61POiHc.min.js.map +1 -0
- package/dist/async-modules/{mixpanel-recorder-zMBXIyeG.js → mixpanel-recorder-C3AW7mPl.js} +63 -35
- package/dist/async-modules/{mixpanel-targeting-UHf4eBfC.js → mixpanel-targeting-CBwOQJZw.js} +24 -13
- package/dist/async-modules/mixpanel-targeting-kdl-eE-1.min.js +2 -0
- package/dist/async-modules/mixpanel-targeting-kdl-eE-1.min.js.map +1 -0
- package/dist/mixpanel-core.cjs.d.ts +45 -1
- package/dist/mixpanel-core.cjs.js +577 -209
- package/dist/mixpanel-recorder.js +63 -35
- 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 +579 -211
- package/dist/mixpanel-with-async-recorder.cjs.d.ts +45 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +579 -211
- package/dist/mixpanel-with-recorder.d.ts +45 -1
- package/dist/mixpanel-with-recorder.js +508 -136
- 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 +508 -136
- package/dist/mixpanel.cjs.d.ts +45 -1
- package/dist/mixpanel.cjs.js +508 -136
- package/dist/mixpanel.globals.js +579 -211
- package/dist/mixpanel.min.js +200 -190
- package/dist/mixpanel.module.d.ts +45 -1
- package/dist/mixpanel.module.js +508 -136
- package/dist/mixpanel.umd.d.ts +45 -1
- package/dist/mixpanel.umd.js +508 -136
- 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 +17 -12
- package/src/config.js +1 -1
- package/src/flags/flags-persistence.js +176 -0
- package/src/flags/index.js +176 -25
- 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 +15 -6
- 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/.claude/settings.local.json +0 -16
- 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
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
var Config = {
|
|
30
30
|
DEBUG: false,
|
|
31
|
-
LIB_VERSION: '2.
|
|
31
|
+
LIB_VERSION: '2.80.0'
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
// Window global names for async modules
|
|
@@ -19126,6 +19126,7 @@
|
|
|
19126
19126
|
var console_with_prefix = function(prefix) {
|
|
19127
19127
|
return {
|
|
19128
19128
|
log: log_func_with_prefix(console$1.log, prefix),
|
|
19129
|
+
warn: log_func_with_prefix(console$1.warn, prefix),
|
|
19129
19130
|
error: log_func_with_prefix(console$1.error, prefix),
|
|
19130
19131
|
critical: log_func_with_prefix(console$1.critical, prefix)
|
|
19131
19132
|
};
|
|
@@ -20072,7 +20073,8 @@
|
|
|
20072
20073
|
if (_localStorageSupported !== null && !forceCheck) {
|
|
20073
20074
|
return _localStorageSupported;
|
|
20074
20075
|
}
|
|
20075
|
-
|
|
20076
|
+
|
|
20077
|
+
return _localStorageSupported = _testStorageSupported(storage);
|
|
20076
20078
|
};
|
|
20077
20079
|
|
|
20078
20080
|
var _sessionStorageSupported = null;
|
|
@@ -20080,7 +20082,8 @@
|
|
|
20080
20082
|
if (_sessionStorageSupported !== null && !forceCheck) {
|
|
20081
20083
|
return _sessionStorageSupported;
|
|
20082
20084
|
}
|
|
20083
|
-
|
|
20085
|
+
|
|
20086
|
+
return _sessionStorageSupported = _testStorageSupported(storage);
|
|
20084
20087
|
};
|
|
20085
20088
|
|
|
20086
20089
|
function _storageWrapper(storage, name, is_supported_fn) {
|
|
@@ -20130,17 +20133,26 @@
|
|
|
20130
20133
|
};
|
|
20131
20134
|
}
|
|
20132
20135
|
|
|
20133
|
-
// Safari
|
|
20134
|
-
//
|
|
20135
|
-
var
|
|
20136
|
-
|
|
20137
|
-
|
|
20138
|
-
|
|
20139
|
-
|
|
20140
|
-
|
|
20136
|
+
// Safari and other browsers may error out accessing localStorage/sessionStorage
|
|
20137
|
+
// when cookies are disabled, so wrap access in a try-catch.
|
|
20138
|
+
var getLocalStorage = function() {
|
|
20139
|
+
try {
|
|
20140
|
+
return win.localStorage; // eslint-disable-line no-restricted-properties
|
|
20141
|
+
} catch (_err) {
|
|
20142
|
+
return null;
|
|
20143
|
+
}
|
|
20144
|
+
};
|
|
20145
|
+
|
|
20146
|
+
var getSessionStorage = function() {
|
|
20147
|
+
try {
|
|
20148
|
+
return win.sessionStorage; // eslint-disable-line no-restricted-properties
|
|
20149
|
+
} catch (_err) {
|
|
20150
|
+
return null;
|
|
20151
|
+
}
|
|
20152
|
+
};
|
|
20141
20153
|
|
|
20142
|
-
_.localStorage = _storageWrapper(
|
|
20143
|
-
_.sessionStorage = _storageWrapper(
|
|
20154
|
+
_.localStorage = _storageWrapper(getLocalStorage(), 'localStorage', localStorageSupported);
|
|
20155
|
+
_.sessionStorage = _storageWrapper(getSessionStorage(), 'sessionStorage', sessionStorageSupported);
|
|
20144
20156
|
|
|
20145
20157
|
_.register_event = (function() {
|
|
20146
20158
|
// written by Dean Edwards, 2005
|
|
@@ -20809,29 +20821,26 @@
|
|
|
20809
20821
|
_['toArray'] = _.toArray;
|
|
20810
20822
|
_['NPO'] = NpoPromise;
|
|
20811
20823
|
|
|
20812
|
-
var MIXPANEL_DB_NAME = 'mixpanelBrowserDb';
|
|
20813
|
-
|
|
20814
|
-
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
20815
|
-
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
20816
|
-
|
|
20817
|
-
// note: increment the version number when adding new object stores
|
|
20818
|
-
var DB_VERSION = 1;
|
|
20819
|
-
var OBJECT_STORES = [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME];
|
|
20820
|
-
|
|
20821
20824
|
/**
|
|
20822
20825
|
* @type {import('./wrapper').StorageWrapper}
|
|
20823
20826
|
*/
|
|
20824
|
-
var IDBStorageWrapper = function (storeName) {
|
|
20827
|
+
var IDBStorageWrapper = function (dbName, storeName, versionData) {
|
|
20828
|
+
this.dbName = dbName;
|
|
20829
|
+
this.storeName = storeName;
|
|
20830
|
+
this.version = versionData.version;
|
|
20831
|
+
this.storeNamesInDb = versionData.storeNames;
|
|
20825
20832
|
/**
|
|
20826
20833
|
* @type {Promise<IDBDatabase>|null}
|
|
20827
20834
|
*/
|
|
20828
20835
|
this.dbPromise = null;
|
|
20829
|
-
this.storeName = storeName;
|
|
20830
20836
|
};
|
|
20831
20837
|
|
|
20832
20838
|
IDBStorageWrapper.prototype._openDb = function () {
|
|
20839
|
+
var dbName = this.dbName;
|
|
20840
|
+
var version = this.version;
|
|
20841
|
+
var storeNamesInDb = this.storeNamesInDb;
|
|
20833
20842
|
return new PromisePolyfill(function (resolve, reject) {
|
|
20834
|
-
var openRequest = win.indexedDB.open(
|
|
20843
|
+
var openRequest = win.indexedDB.open(dbName, version);
|
|
20835
20844
|
openRequest['onerror'] = function () {
|
|
20836
20845
|
reject(openRequest.error);
|
|
20837
20846
|
};
|
|
@@ -20843,8 +20852,10 @@
|
|
|
20843
20852
|
openRequest['onupgradeneeded'] = function (ev) {
|
|
20844
20853
|
var db = ev.target.result;
|
|
20845
20854
|
|
|
20846
|
-
|
|
20847
|
-
db.
|
|
20855
|
+
storeNamesInDb.forEach(function (storeName) {
|
|
20856
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
20857
|
+
db.createObjectStore(storeName);
|
|
20858
|
+
}
|
|
20848
20859
|
});
|
|
20849
20860
|
};
|
|
20850
20861
|
});
|
|
@@ -20936,6 +20947,16 @@
|
|
|
20936
20947
|
});
|
|
20937
20948
|
};
|
|
20938
20949
|
|
|
20950
|
+
var MIXPANEL_BROWSER_DB_NAME = 'mixpanelBrowserDb';
|
|
20951
|
+
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
20952
|
+
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
20953
|
+
|
|
20954
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
20955
|
+
var RECORDER_VERSION_DATA = {
|
|
20956
|
+
version: 1,
|
|
20957
|
+
storeNames: [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME]
|
|
20958
|
+
};
|
|
20959
|
+
|
|
20939
20960
|
/**
|
|
20940
20961
|
* GDPR utils
|
|
20941
20962
|
*
|
|
@@ -21236,7 +21257,7 @@
|
|
|
21236
21257
|
};
|
|
21237
21258
|
}
|
|
21238
21259
|
|
|
21239
|
-
var logger$
|
|
21260
|
+
var logger$9 = console_with_prefix('lock');
|
|
21240
21261
|
|
|
21241
21262
|
/**
|
|
21242
21263
|
* SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
|
|
@@ -21262,7 +21283,7 @@
|
|
|
21262
21283
|
options = options || {};
|
|
21263
21284
|
|
|
21264
21285
|
this.storageKey = key;
|
|
21265
|
-
this.storage = options.storage ||
|
|
21286
|
+
this.storage = options.storage || getLocalStorage();
|
|
21266
21287
|
this.pollIntervalMS = options.pollIntervalMS || 100;
|
|
21267
21288
|
this.timeoutMS = options.timeoutMS || 2000;
|
|
21268
21289
|
|
|
@@ -21288,7 +21309,7 @@
|
|
|
21288
21309
|
|
|
21289
21310
|
var delay = function(cb) {
|
|
21290
21311
|
if (new Date().getTime() - startTime > timeoutMS) {
|
|
21291
|
-
logger$
|
|
21312
|
+
logger$9.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
|
|
21292
21313
|
storage.removeItem(keyZ);
|
|
21293
21314
|
storage.removeItem(keyY);
|
|
21294
21315
|
loop();
|
|
@@ -21390,10 +21411,13 @@
|
|
|
21390
21411
|
* @type {import('./wrapper').StorageWrapper}
|
|
21391
21412
|
*/
|
|
21392
21413
|
var LocalStorageWrapper = function (storageOverride) {
|
|
21393
|
-
this.storage = storageOverride ||
|
|
21414
|
+
this.storage = storageOverride || getLocalStorage();
|
|
21394
21415
|
};
|
|
21395
21416
|
|
|
21396
21417
|
LocalStorageWrapper.prototype.init = function () {
|
|
21418
|
+
if (!this.storage) {
|
|
21419
|
+
return PromisePolyfill.reject(new Error('localStorage is not available'));
|
|
21420
|
+
}
|
|
21397
21421
|
return PromisePolyfill.resolve();
|
|
21398
21422
|
};
|
|
21399
21423
|
|
|
@@ -21435,7 +21459,7 @@
|
|
|
21435
21459
|
}, this));
|
|
21436
21460
|
};
|
|
21437
21461
|
|
|
21438
|
-
var logger$
|
|
21462
|
+
var logger$8 = console_with_prefix('batch');
|
|
21439
21463
|
|
|
21440
21464
|
/**
|
|
21441
21465
|
* RequestQueue: queue for batching API requests with localStorage backup for retries.
|
|
@@ -21460,11 +21484,11 @@
|
|
|
21460
21484
|
if (this.usePersistence) {
|
|
21461
21485
|
this.queueStorage = options.queueStorage || new LocalStorageWrapper();
|
|
21462
21486
|
this.lock = new SharedLock(storageKey, {
|
|
21463
|
-
storage: options.sharedLockStorage
|
|
21487
|
+
storage: options.sharedLockStorage,
|
|
21464
21488
|
timeoutMS: options.sharedLockTimeoutMS,
|
|
21465
21489
|
});
|
|
21466
21490
|
}
|
|
21467
|
-
this.reportError = options.errorReporter || _.bind(logger$
|
|
21491
|
+
this.reportError = options.errorReporter || _.bind(logger$8.error, logger$8);
|
|
21468
21492
|
|
|
21469
21493
|
this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
|
|
21470
21494
|
|
|
@@ -21797,7 +21821,7 @@
|
|
|
21797
21821
|
// maximum interval between request retries after exponential backoff
|
|
21798
21822
|
var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
|
|
21799
21823
|
|
|
21800
|
-
var logger$
|
|
21824
|
+
var logger$7 = console_with_prefix('batch');
|
|
21801
21825
|
|
|
21802
21826
|
/**
|
|
21803
21827
|
* RequestBatcher: manages the queueing, flushing, retry etc of requests of one
|
|
@@ -21925,7 +21949,7 @@
|
|
|
21925
21949
|
*/
|
|
21926
21950
|
RequestBatcher.prototype.flush = function(options) {
|
|
21927
21951
|
if (this.requestInProgress) {
|
|
21928
|
-
logger$
|
|
21952
|
+
logger$7.log('Flush: Request already in progress');
|
|
21929
21953
|
return PromisePolyfill.resolve();
|
|
21930
21954
|
}
|
|
21931
21955
|
|
|
@@ -22102,7 +22126,7 @@
|
|
|
22102
22126
|
if (options.unloading) {
|
|
22103
22127
|
requestOptions.transport = 'sendBeacon';
|
|
22104
22128
|
}
|
|
22105
|
-
logger$
|
|
22129
|
+
logger$7.log('MIXPANEL REQUEST:', dataForRequest);
|
|
22106
22130
|
return this.sendRequestPromise(dataForRequest, requestOptions).then(batchSendCallback);
|
|
22107
22131
|
}, this))
|
|
22108
22132
|
.catch(_.bind(function(err) {
|
|
@@ -22115,7 +22139,7 @@
|
|
|
22115
22139
|
* Log error to global logger and optional user-defined logger.
|
|
22116
22140
|
*/
|
|
22117
22141
|
RequestBatcher.prototype.reportError = function(msg, err) {
|
|
22118
|
-
logger$
|
|
22142
|
+
logger$7.error.apply(logger$7.error, arguments);
|
|
22119
22143
|
if (this.errorReporter) {
|
|
22120
22144
|
try {
|
|
22121
22145
|
if (!(err instanceof Error)) {
|
|
@@ -22123,7 +22147,7 @@
|
|
|
22123
22147
|
}
|
|
22124
22148
|
this.errorReporter(msg, err);
|
|
22125
22149
|
} catch(err) {
|
|
22126
|
-
logger$
|
|
22150
|
+
logger$7.error(err);
|
|
22127
22151
|
}
|
|
22128
22152
|
}
|
|
22129
22153
|
};
|
|
@@ -22268,7 +22292,7 @@
|
|
|
22268
22292
|
|
|
22269
22293
|
var MAX_DEPTH = 5;
|
|
22270
22294
|
|
|
22271
|
-
var logger$
|
|
22295
|
+
var logger$6 = console_with_prefix('autocapture');
|
|
22272
22296
|
|
|
22273
22297
|
|
|
22274
22298
|
function getClasses(el) {
|
|
@@ -22532,7 +22556,7 @@
|
|
|
22532
22556
|
return false;
|
|
22533
22557
|
}
|
|
22534
22558
|
} catch (err) {
|
|
22535
|
-
logger$
|
|
22559
|
+
logger$6.critical('Error while checking element in allowElementCallback', err);
|
|
22536
22560
|
return false;
|
|
22537
22561
|
}
|
|
22538
22562
|
}
|
|
@@ -22549,7 +22573,7 @@
|
|
|
22549
22573
|
return true;
|
|
22550
22574
|
}
|
|
22551
22575
|
} catch (err) {
|
|
22552
|
-
logger$
|
|
22576
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
22553
22577
|
}
|
|
22554
22578
|
}
|
|
22555
22579
|
return false;
|
|
@@ -22564,7 +22588,7 @@
|
|
|
22564
22588
|
return true;
|
|
22565
22589
|
}
|
|
22566
22590
|
} catch (err) {
|
|
22567
|
-
logger$
|
|
22591
|
+
logger$6.critical('Error while checking element in blockElementCallback', err);
|
|
22568
22592
|
return true;
|
|
22569
22593
|
}
|
|
22570
22594
|
}
|
|
@@ -22578,7 +22602,7 @@
|
|
|
22578
22602
|
return true;
|
|
22579
22603
|
}
|
|
22580
22604
|
} catch (err) {
|
|
22581
|
-
logger$
|
|
22605
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
22582
22606
|
}
|
|
22583
22607
|
}
|
|
22584
22608
|
}
|
|
@@ -23134,7 +23158,7 @@
|
|
|
23134
23158
|
*
|
|
23135
23159
|
*/
|
|
23136
23160
|
|
|
23137
|
-
var logger$
|
|
23161
|
+
var logger$5 = console_with_prefix('network-plugin');
|
|
23138
23162
|
|
|
23139
23163
|
/**
|
|
23140
23164
|
* Get the time origin for converting performance timestamps to absolute timestamps.
|
|
@@ -23286,7 +23310,7 @@
|
|
|
23286
23310
|
return str;
|
|
23287
23311
|
}
|
|
23288
23312
|
if (str.length > MAX_BODY_SIZE) {
|
|
23289
|
-
logger$
|
|
23313
|
+
logger$5.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
|
|
23290
23314
|
return str.substring(0, MAX_BODY_SIZE) + '... [truncated]';
|
|
23291
23315
|
}
|
|
23292
23316
|
return str;
|
|
@@ -23300,7 +23324,7 @@
|
|
|
23300
23324
|
*/
|
|
23301
23325
|
function initPerformanceObserver(cb, win, options) {
|
|
23302
23326
|
if (!win.PerformanceObserver) {
|
|
23303
|
-
logger$
|
|
23327
|
+
logger$5.error('PerformanceObserver not supported');
|
|
23304
23328
|
return function() {
|
|
23305
23329
|
//
|
|
23306
23330
|
};
|
|
@@ -23453,7 +23477,7 @@
|
|
|
23453
23477
|
attempt = 0;
|
|
23454
23478
|
}
|
|
23455
23479
|
if (attempt > 10) {
|
|
23456
|
-
logger$
|
|
23480
|
+
logger$5.error('Cannot find performance entry');
|
|
23457
23481
|
return Promise.resolve(null);
|
|
23458
23482
|
}
|
|
23459
23483
|
var urlPerformanceEntries = /** @type {PerformanceResourceTiming[]} */ (
|
|
@@ -23574,7 +23598,7 @@
|
|
|
23574
23598
|
)
|
|
23575
23599
|
.then(function(entry) {
|
|
23576
23600
|
if (!entry) {
|
|
23577
|
-
logger$
|
|
23601
|
+
logger$5.error('Failed to get performance entry for XHR request to ' + req.url);
|
|
23578
23602
|
return;
|
|
23579
23603
|
}
|
|
23580
23604
|
/** @type {NetworkRequest} */
|
|
@@ -23594,7 +23618,7 @@
|
|
|
23594
23618
|
cb({ requests: [request] });
|
|
23595
23619
|
})
|
|
23596
23620
|
.catch(function(e) {
|
|
23597
|
-
logger$
|
|
23621
|
+
logger$5.error('Error recording XHR request to ' + req.url + ': ' + String(e));
|
|
23598
23622
|
});
|
|
23599
23623
|
});
|
|
23600
23624
|
|
|
@@ -23686,7 +23710,7 @@
|
|
|
23686
23710
|
})
|
|
23687
23711
|
.then(function(entry) {
|
|
23688
23712
|
if (!entry) {
|
|
23689
|
-
logger$
|
|
23713
|
+
logger$5.error('Failed to get performance entry for fetch request to ' + req.url);
|
|
23690
23714
|
return;
|
|
23691
23715
|
}
|
|
23692
23716
|
/** @type {NetworkRequest} */
|
|
@@ -23706,7 +23730,7 @@
|
|
|
23706
23730
|
cb({ requests: [request] });
|
|
23707
23731
|
})
|
|
23708
23732
|
.catch(function (e) {
|
|
23709
|
-
logger$
|
|
23733
|
+
logger$5.error('Error recording fetch request to ' + req.url + ': ' + String(e));
|
|
23710
23734
|
});
|
|
23711
23735
|
|
|
23712
23736
|
return originalFetchPromise;
|
|
@@ -23779,7 +23803,7 @@
|
|
|
23779
23803
|
*/
|
|
23780
23804
|
|
|
23781
23805
|
|
|
23782
|
-
var logger$
|
|
23806
|
+
var logger$4 = console_with_prefix('recorder');
|
|
23783
23807
|
var CompressionStream = win['CompressionStream'];
|
|
23784
23808
|
|
|
23785
23809
|
var RECORDER_BATCHER_LIB_CONFIG = {
|
|
@@ -23873,14 +23897,15 @@
|
|
|
23873
23897
|
|
|
23874
23898
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23875
23899
|
this.recordMinMs = 0;
|
|
23900
|
+
this._recordMinMsCheckStart = null;
|
|
23876
23901
|
|
|
23877
23902
|
// disable persistence if localStorage is not supported
|
|
23878
23903
|
// request-queue will automatically disable persistence if indexedDB fails to initialize
|
|
23879
|
-
var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
|
|
23904
|
+
var usePersistence = localStorageSupported(options.sharedLockStorage || getLocalStorage(), true) && !this.getConfig('disable_persistence');
|
|
23880
23905
|
|
|
23881
23906
|
// each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
|
|
23882
23907
|
this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
|
|
23883
|
-
this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
|
|
23908
|
+
this.queueStorage = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_EVENTS_STORE_NAME, RECORDER_VERSION_DATA);
|
|
23884
23909
|
this.batcher = new RequestBatcher(this.batcherKey, {
|
|
23885
23910
|
errorReporter: this.reportError.bind(this),
|
|
23886
23911
|
flushOnlyOnInterval: true,
|
|
@@ -23959,14 +23984,14 @@
|
|
|
23959
23984
|
}
|
|
23960
23985
|
|
|
23961
23986
|
if (this._stopRecording !== null) {
|
|
23962
|
-
logger$
|
|
23987
|
+
logger$4.log('Recording already in progress, skipping startRecording.');
|
|
23963
23988
|
return;
|
|
23964
23989
|
}
|
|
23965
23990
|
|
|
23966
23991
|
this.recordMaxMs = this.getConfig('record_max_ms');
|
|
23967
23992
|
if (this.recordMaxMs > MAX_RECORDING_MS) {
|
|
23968
23993
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23969
|
-
logger$
|
|
23994
|
+
logger$4.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
23970
23995
|
}
|
|
23971
23996
|
|
|
23972
23997
|
if (!this.maxExpires) {
|
|
@@ -23988,6 +24013,7 @@
|
|
|
23988
24013
|
// this also applies if the minimum recording length has not been hit yet
|
|
23989
24014
|
// so that we don't send data until we know the recording will be long enough
|
|
23990
24015
|
this.batcher.stop();
|
|
24016
|
+
this._recordMinMsCheckStart = null;
|
|
23991
24017
|
} else {
|
|
23992
24018
|
this.batcher.start();
|
|
23993
24019
|
}
|
|
@@ -24030,7 +24056,7 @@
|
|
|
24030
24056
|
);
|
|
24031
24057
|
}
|
|
24032
24058
|
|
|
24033
|
-
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$
|
|
24059
|
+
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$4);
|
|
24034
24060
|
|
|
24035
24061
|
try {
|
|
24036
24062
|
this._stopRecording = this._rrwebRecord({
|
|
@@ -24039,9 +24065,11 @@
|
|
|
24039
24065
|
this._onIdleTimeout();
|
|
24040
24066
|
return;
|
|
24041
24067
|
}
|
|
24068
|
+
if (this._recordMinMsCheckStart === null) {
|
|
24069
|
+
this._recordMinMsCheckStart = ev.timestamp;
|
|
24070
|
+
}
|
|
24042
24071
|
if (isUserEvent(ev)) {
|
|
24043
|
-
if (this.batcher.stopped &&
|
|
24044
|
-
// start flushing again after user activity
|
|
24072
|
+
if (this.batcher.stopped && ev.timestamp - this._recordMinMsCheckStart >= this.recordMinMs) {
|
|
24045
24073
|
this.batcher.start();
|
|
24046
24074
|
}
|
|
24047
24075
|
resetIdleTimeout();
|
|
@@ -24292,14 +24320,14 @@
|
|
|
24292
24320
|
|
|
24293
24321
|
|
|
24294
24322
|
SessionRecording.prototype.reportError = function(msg, err) {
|
|
24295
|
-
logger$
|
|
24323
|
+
logger$4.error.apply(logger$4.error, arguments);
|
|
24296
24324
|
try {
|
|
24297
24325
|
if (!err && !(msg instanceof Error)) {
|
|
24298
24326
|
msg = new Error(msg);
|
|
24299
24327
|
}
|
|
24300
24328
|
this.getConfig('error_reporter')(msg, err);
|
|
24301
24329
|
} catch(err) {
|
|
24302
|
-
logger$
|
|
24330
|
+
logger$4.error(err);
|
|
24303
24331
|
}
|
|
24304
24332
|
};
|
|
24305
24333
|
|
|
@@ -24328,7 +24356,7 @@
|
|
|
24328
24356
|
var configValue = this.getConfig('record_min_ms');
|
|
24329
24357
|
|
|
24330
24358
|
if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
24331
|
-
logger$
|
|
24359
|
+
logger$4.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
24332
24360
|
return MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
24333
24361
|
}
|
|
24334
24362
|
|
|
@@ -24370,7 +24398,7 @@
|
|
|
24370
24398
|
*/
|
|
24371
24399
|
var RecordingRegistry = function (options) {
|
|
24372
24400
|
/** @type {IDBStorageWrapper} */
|
|
24373
|
-
this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
24401
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
24374
24402
|
this.errorReporter = options.errorReporter;
|
|
24375
24403
|
this.mixpanelInstance = options.mixpanelInstance;
|
|
24376
24404
|
this.sharedLockStorage = options.sharedLockStorage;
|
|
@@ -24491,7 +24519,7 @@
|
|
|
24491
24519
|
.catch(this.handleError.bind(this));
|
|
24492
24520
|
};
|
|
24493
24521
|
|
|
24494
|
-
var logger$
|
|
24522
|
+
var logger$3 = console_with_prefix('recorder');
|
|
24495
24523
|
|
|
24496
24524
|
/**
|
|
24497
24525
|
* Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
|
|
@@ -24507,7 +24535,7 @@
|
|
|
24507
24535
|
*/
|
|
24508
24536
|
this.recordingRegistry = new RecordingRegistry({
|
|
24509
24537
|
mixpanelInstance: this.mixpanelInstance,
|
|
24510
|
-
errorReporter: logger$
|
|
24538
|
+
errorReporter: logger$3.error,
|
|
24511
24539
|
sharedLockStorage: sharedLockStorage
|
|
24512
24540
|
});
|
|
24513
24541
|
this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
|
|
@@ -24519,17 +24547,17 @@
|
|
|
24519
24547
|
MixpanelRecorder.prototype.startRecording = function(options) {
|
|
24520
24548
|
options = options || {};
|
|
24521
24549
|
if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
|
|
24522
|
-
logger$
|
|
24550
|
+
logger$3.log('Recording already in progress, skipping startRecording.');
|
|
24523
24551
|
return;
|
|
24524
24552
|
}
|
|
24525
24553
|
|
|
24526
24554
|
var onIdleTimeout = function () {
|
|
24527
|
-
logger$
|
|
24555
|
+
logger$3.log('Idle timeout reached, restarting recording.');
|
|
24528
24556
|
this.resetRecording();
|
|
24529
24557
|
}.bind(this);
|
|
24530
24558
|
|
|
24531
24559
|
var onMaxLengthReached = function () {
|
|
24532
|
-
logger$
|
|
24560
|
+
logger$3.log('Max recording length reached, stopping recording.');
|
|
24533
24561
|
this.resetRecording();
|
|
24534
24562
|
}.bind(this);
|
|
24535
24563
|
|
|
@@ -24599,7 +24627,7 @@
|
|
|
24599
24627
|
} else if (startNewIfInactive) {
|
|
24600
24628
|
return this.startRecording({shouldStopBatcher: false});
|
|
24601
24629
|
} else {
|
|
24602
|
-
logger$
|
|
24630
|
+
logger$3.log('No resumable recording found.');
|
|
24603
24631
|
return null;
|
|
24604
24632
|
}
|
|
24605
24633
|
}.bind(this));
|
|
@@ -24733,7 +24761,7 @@
|
|
|
24733
24761
|
observer.observe(shadowRoot, this.observerConfig);
|
|
24734
24762
|
this.shadowObservers.push(observer);
|
|
24735
24763
|
} catch (e) {
|
|
24736
|
-
logger$
|
|
24764
|
+
logger$6.critical('Error while observing shadow root', e);
|
|
24737
24765
|
}
|
|
24738
24766
|
};
|
|
24739
24767
|
|
|
@@ -24744,7 +24772,7 @@
|
|
|
24744
24772
|
}
|
|
24745
24773
|
|
|
24746
24774
|
if (!weakSetSupported()) {
|
|
24747
|
-
logger$
|
|
24775
|
+
logger$6.critical('Shadow DOM observation unavailable: WeakSet not supported');
|
|
24748
24776
|
return;
|
|
24749
24777
|
}
|
|
24750
24778
|
|
|
@@ -24760,7 +24788,7 @@
|
|
|
24760
24788
|
try {
|
|
24761
24789
|
this.shadowObservers[i].disconnect();
|
|
24762
24790
|
} catch (e) {
|
|
24763
|
-
logger$
|
|
24791
|
+
logger$6.critical('Error while disconnecting shadow DOM observer', e);
|
|
24764
24792
|
}
|
|
24765
24793
|
}
|
|
24766
24794
|
this.shadowObservers = [];
|
|
@@ -24948,7 +24976,7 @@
|
|
|
24948
24976
|
|
|
24949
24977
|
this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
|
|
24950
24978
|
} catch (e) {
|
|
24951
|
-
logger$
|
|
24979
|
+
logger$6.critical('Error while setting up mutation observer', e);
|
|
24952
24980
|
}
|
|
24953
24981
|
}
|
|
24954
24982
|
|
|
@@ -24963,7 +24991,7 @@
|
|
|
24963
24991
|
);
|
|
24964
24992
|
this.shadowDOMObserver.start();
|
|
24965
24993
|
} catch (e) {
|
|
24966
|
-
logger$
|
|
24994
|
+
logger$6.critical('Error while setting up shadow DOM observer', e);
|
|
24967
24995
|
this.shadowDOMObserver = null;
|
|
24968
24996
|
}
|
|
24969
24997
|
}
|
|
@@ -24990,7 +25018,7 @@
|
|
|
24990
25018
|
try {
|
|
24991
25019
|
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
24992
25020
|
} catch (e) {
|
|
24993
|
-
logger$
|
|
25021
|
+
logger$6.critical('Error while removing event listener', e);
|
|
24994
25022
|
}
|
|
24995
25023
|
}
|
|
24996
25024
|
this.eventListeners = [];
|
|
@@ -24999,7 +25027,7 @@
|
|
|
24999
25027
|
try {
|
|
25000
25028
|
this.mutationObserver.disconnect();
|
|
25001
25029
|
} catch (e) {
|
|
25002
|
-
logger$
|
|
25030
|
+
logger$6.critical('Error while disconnecting mutation observer', e);
|
|
25003
25031
|
}
|
|
25004
25032
|
this.mutationObserver = null;
|
|
25005
25033
|
}
|
|
@@ -25008,7 +25036,7 @@
|
|
|
25008
25036
|
try {
|
|
25009
25037
|
this.shadowDOMObserver.stop();
|
|
25010
25038
|
} catch (e) {
|
|
25011
|
-
logger$
|
|
25039
|
+
logger$6.critical('Error while stopping shadow DOM observer', e);
|
|
25012
25040
|
}
|
|
25013
25041
|
this.shadowDOMObserver = null;
|
|
25014
25042
|
}
|
|
@@ -25086,7 +25114,7 @@
|
|
|
25086
25114
|
|
|
25087
25115
|
Autocapture.prototype.init = function() {
|
|
25088
25116
|
if (!minDOMApisSupported()) {
|
|
25089
|
-
logger$
|
|
25117
|
+
logger$6.critical('Autocapture unavailable: missing required DOM APIs');
|
|
25090
25118
|
return;
|
|
25091
25119
|
}
|
|
25092
25120
|
this.initPageListeners();
|
|
@@ -25126,7 +25154,7 @@
|
|
|
25126
25154
|
try {
|
|
25127
25155
|
return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
|
|
25128
25156
|
} catch (err) {
|
|
25129
|
-
logger$
|
|
25157
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25130
25158
|
return true;
|
|
25131
25159
|
}
|
|
25132
25160
|
}
|
|
@@ -25139,7 +25167,7 @@
|
|
|
25139
25167
|
try {
|
|
25140
25168
|
return urlMatchesRegexList(currentUrl, blockUrlRegexes);
|
|
25141
25169
|
} catch (err) {
|
|
25142
|
-
logger$
|
|
25170
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25143
25171
|
return true;
|
|
25144
25172
|
}
|
|
25145
25173
|
};
|
|
@@ -25277,7 +25305,7 @@
|
|
|
25277
25305
|
return;
|
|
25278
25306
|
}
|
|
25279
25307
|
|
|
25280
|
-
logger$
|
|
25308
|
+
logger$6.log('Initializing scroll depth tracking');
|
|
25281
25309
|
|
|
25282
25310
|
this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
|
|
25283
25311
|
|
|
@@ -25298,12 +25326,12 @@
|
|
|
25298
25326
|
};
|
|
25299
25327
|
|
|
25300
25328
|
Autocapture.prototype.initClickTracking = function() {
|
|
25301
|
-
win.removeEventListener(EV_CLICK, this.listenerClick);
|
|
25329
|
+
win.removeEventListener(EV_CLICK, this.listenerClick, true);
|
|
25302
25330
|
|
|
25303
25331
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
|
|
25304
25332
|
return;
|
|
25305
25333
|
}
|
|
25306
|
-
logger$
|
|
25334
|
+
logger$6.log('Initializing click tracking');
|
|
25307
25335
|
|
|
25308
25336
|
this.listenerClick = function(ev) {
|
|
25309
25337
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
|
|
@@ -25311,7 +25339,7 @@
|
|
|
25311
25339
|
}
|
|
25312
25340
|
this.trackDomEvent(ev, MP_EV_CLICK);
|
|
25313
25341
|
}.bind(this);
|
|
25314
|
-
win.addEventListener(EV_CLICK, this.listenerClick);
|
|
25342
|
+
win.addEventListener(EV_CLICK, this.listenerClick, true);
|
|
25315
25343
|
};
|
|
25316
25344
|
|
|
25317
25345
|
Autocapture.prototype.initDeadClickTracking = function() {
|
|
@@ -25322,7 +25350,7 @@
|
|
|
25322
25350
|
return;
|
|
25323
25351
|
}
|
|
25324
25352
|
|
|
25325
|
-
logger$
|
|
25353
|
+
logger$6.log('Initializing dead click tracking');
|
|
25326
25354
|
if (!this._deadClickTracker) {
|
|
25327
25355
|
this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
|
|
25328
25356
|
this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
|
|
@@ -25346,17 +25374,17 @@
|
|
|
25346
25374
|
}
|
|
25347
25375
|
this._deadClickTracker.trackClick(ev, normalizedConfig);
|
|
25348
25376
|
}.bind(this);
|
|
25349
|
-
win.addEventListener(EV_CLICK, this.listenerDeadClick);
|
|
25377
|
+
win.addEventListener(EV_CLICK, this.listenerDeadClick, true);
|
|
25350
25378
|
}
|
|
25351
25379
|
};
|
|
25352
25380
|
|
|
25353
25381
|
Autocapture.prototype.initInputTracking = function() {
|
|
25354
|
-
win.removeEventListener(EV_CHANGE, this.listenerChange);
|
|
25382
|
+
win.removeEventListener(EV_CHANGE, this.listenerChange, true);
|
|
25355
25383
|
|
|
25356
25384
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
25357
25385
|
return;
|
|
25358
25386
|
}
|
|
25359
|
-
logger$
|
|
25387
|
+
logger$6.log('Initializing input tracking');
|
|
25360
25388
|
|
|
25361
25389
|
this.listenerChange = function(ev) {
|
|
25362
25390
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
@@ -25364,20 +25392,21 @@
|
|
|
25364
25392
|
}
|
|
25365
25393
|
this.trackDomEvent(ev, MP_EV_INPUT);
|
|
25366
25394
|
}.bind(this);
|
|
25367
|
-
win.addEventListener(EV_CHANGE, this.listenerChange);
|
|
25395
|
+
win.addEventListener(EV_CHANGE, this.listenerChange, true);
|
|
25368
25396
|
};
|
|
25369
25397
|
|
|
25370
25398
|
Autocapture.prototype.initPageviewTracking = function() {
|
|
25371
25399
|
win.removeEventListener(EV_MP_LOCATION_CHANGE, this.listenerLocationchange);
|
|
25372
25400
|
|
|
25373
|
-
if (!this.pageviewTrackingConfig()) {
|
|
25401
|
+
if (!this.pageviewTrackingConfig() && !this.mp.get_config('record_heatmap_data')) {
|
|
25374
25402
|
return;
|
|
25375
25403
|
}
|
|
25376
|
-
logger$
|
|
25404
|
+
logger$6.log('Initializing pageview tracking');
|
|
25377
25405
|
|
|
25378
25406
|
var previousTrackedUrl = '';
|
|
25379
25407
|
var tracked = false;
|
|
25380
|
-
if
|
|
25408
|
+
// Track initial pageview if pageview tracking enabled OR heatmap recording is active
|
|
25409
|
+
if ((this.pageviewTrackingConfig() || this.mp.is_recording_heatmap_data()) && !this.currentUrlBlocked()) {
|
|
25381
25410
|
tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
25382
25411
|
}
|
|
25383
25412
|
if (tracked) {
|
|
@@ -25393,6 +25422,10 @@
|
|
|
25393
25422
|
var shouldTrack = false;
|
|
25394
25423
|
var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
25395
25424
|
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
25425
|
+
if (!trackPageviewOption && this.mp.is_recording_heatmap_data()) {
|
|
25426
|
+
trackPageviewOption = PAGEVIEW_OPTION_FULL_URL;
|
|
25427
|
+
}
|
|
25428
|
+
|
|
25396
25429
|
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
25397
25430
|
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
25398
25431
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
@@ -25408,7 +25441,7 @@
|
|
|
25408
25441
|
}
|
|
25409
25442
|
if (didPathChange) {
|
|
25410
25443
|
this.lastScrollCheckpoint = 0;
|
|
25411
|
-
logger$
|
|
25444
|
+
logger$6.log('Path change: re-initializing scroll depth checkpoints');
|
|
25412
25445
|
}
|
|
25413
25446
|
}
|
|
25414
25447
|
}.bind(this));
|
|
@@ -25416,14 +25449,14 @@
|
|
|
25416
25449
|
};
|
|
25417
25450
|
|
|
25418
25451
|
Autocapture.prototype.initRageClickTracking = function() {
|
|
25419
|
-
win.removeEventListener(EV_CLICK, this.listenerRageClick);
|
|
25452
|
+
win.removeEventListener(EV_CLICK, this.listenerRageClick, true);
|
|
25420
25453
|
|
|
25421
25454
|
var rageClickConfig = this._getClickTrackingConfig(CONFIG_TRACK_RAGE_CLICK);
|
|
25422
25455
|
if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
|
|
25423
25456
|
return;
|
|
25424
25457
|
}
|
|
25425
25458
|
|
|
25426
|
-
logger$
|
|
25459
|
+
logger$6.log('Initializing rage click tracking');
|
|
25427
25460
|
if (!this._rageClickTracker) {
|
|
25428
25461
|
this._rageClickTracker = new RageClickTracker();
|
|
25429
25462
|
}
|
|
@@ -25442,7 +25475,7 @@
|
|
|
25442
25475
|
this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
|
|
25443
25476
|
}
|
|
25444
25477
|
}.bind(this);
|
|
25445
|
-
win.addEventListener(EV_CLICK, this.listenerRageClick);
|
|
25478
|
+
win.addEventListener(EV_CLICK, this.listenerRageClick, true);
|
|
25446
25479
|
};
|
|
25447
25480
|
|
|
25448
25481
|
Autocapture.prototype.initScrollTracking = function() {
|
|
@@ -25453,7 +25486,7 @@
|
|
|
25453
25486
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
25454
25487
|
return;
|
|
25455
25488
|
}
|
|
25456
|
-
logger$
|
|
25489
|
+
logger$6.log('Initializing scroll tracking');
|
|
25457
25490
|
this.lastScrollCheckpoint = 0;
|
|
25458
25491
|
|
|
25459
25492
|
var scrollTrackFunction = function() {
|
|
@@ -25490,7 +25523,7 @@
|
|
|
25490
25523
|
}
|
|
25491
25524
|
}
|
|
25492
25525
|
} catch (err) {
|
|
25493
|
-
logger$
|
|
25526
|
+
logger$6.critical('Error while calculating scroll percentage', err);
|
|
25494
25527
|
}
|
|
25495
25528
|
if (shouldTrack) {
|
|
25496
25529
|
this.mp.track(MP_EV_SCROLL, props);
|
|
@@ -25503,12 +25536,12 @@
|
|
|
25503
25536
|
};
|
|
25504
25537
|
|
|
25505
25538
|
Autocapture.prototype.initSubmitTracking = function() {
|
|
25506
|
-
win.removeEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
25539
|
+
win.removeEventListener(EV_SUBMIT, this.listenerSubmit, true);
|
|
25507
25540
|
|
|
25508
25541
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
25509
25542
|
return;
|
|
25510
25543
|
}
|
|
25511
|
-
logger$
|
|
25544
|
+
logger$6.log('Initializing submit tracking');
|
|
25512
25545
|
|
|
25513
25546
|
this.listenerSubmit = function(ev) {
|
|
25514
25547
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
@@ -25516,7 +25549,7 @@
|
|
|
25516
25549
|
}
|
|
25517
25550
|
this.trackDomEvent(ev, MP_EV_SUBMIT);
|
|
25518
25551
|
}.bind(this);
|
|
25519
|
-
win.addEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
25552
|
+
win.addEventListener(EV_SUBMIT, this.listenerSubmit, true);
|
|
25520
25553
|
};
|
|
25521
25554
|
|
|
25522
25555
|
Autocapture.prototype.initPageLeaveTracking = function() {
|
|
@@ -25530,7 +25563,7 @@
|
|
|
25530
25563
|
return;
|
|
25531
25564
|
}
|
|
25532
25565
|
|
|
25533
|
-
logger$
|
|
25566
|
+
logger$6.log('Initializing page visibility tracking.');
|
|
25534
25567
|
this._initScrollDepthTracking();
|
|
25535
25568
|
var previousTrackedUrl = _.info.currentUrl();
|
|
25536
25569
|
|
|
@@ -25572,7 +25605,7 @@
|
|
|
25572
25605
|
|
|
25573
25606
|
Autocapture.prototype.stopDeadClickTracking = function() {
|
|
25574
25607
|
if (this.listenerDeadClick) {
|
|
25575
|
-
win.removeEventListener(EV_CLICK, this.listenerDeadClick);
|
|
25608
|
+
win.removeEventListener(EV_CLICK, this.listenerDeadClick, true);
|
|
25576
25609
|
this.listenerDeadClick = null;
|
|
25577
25610
|
}
|
|
25578
25611
|
|
|
@@ -25615,10 +25648,183 @@
|
|
|
25615
25648
|
return win[TARGETING_GLOBAL_NAME];
|
|
25616
25649
|
};
|
|
25617
25650
|
|
|
25651
|
+
var logger$2 = console_with_prefix('flags');
|
|
25652
|
+
|
|
25653
|
+
var MIXPANEL_FLAGS_DB_NAME = 'mixpanelFlagsDb';
|
|
25654
|
+
var FLAGS_STORE_NAME = 'mixpanelFlags';
|
|
25655
|
+
|
|
25656
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
25657
|
+
var FLAGS_VERSION_DATA = { version: 1, storeNames: [FLAGS_STORE_NAME] };
|
|
25658
|
+
|
|
25659
|
+
var PERSISTED_VARIANTS_KEY_PREFIX = 'persisted_variants_for_';
|
|
25660
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
25661
|
+
|
|
25662
|
+
var VariantLookupPolicy = Object.freeze({
|
|
25663
|
+
NETWORK_ONLY: 'networkOnly',
|
|
25664
|
+
NETWORK_FIRST: 'networkFirst',
|
|
25665
|
+
PERSISTENCE_UNTIL_NETWORK_SUCCESS: 'persistenceUntilNetworkSuccess'
|
|
25666
|
+
});
|
|
25667
|
+
|
|
25668
|
+
var VALID_POLICIES = [
|
|
25669
|
+
VariantLookupPolicy.NETWORK_ONLY,
|
|
25670
|
+
VariantLookupPolicy.NETWORK_FIRST,
|
|
25671
|
+
VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS
|
|
25672
|
+
];
|
|
25673
|
+
|
|
25674
|
+
/**
|
|
25675
|
+
* Module for handling the storage and retrieval of persisted feature flag variants.
|
|
25676
|
+
*/
|
|
25677
|
+
var FeatureFlagPersistence = function(persistenceConfig, token, isGloballyDisabled) {
|
|
25678
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_FLAGS_DB_NAME, FLAGS_STORE_NAME, FLAGS_VERSION_DATA);
|
|
25679
|
+
this.persistenceConfig = persistenceConfig;
|
|
25680
|
+
this.persistedVariantsKey = PERSISTED_VARIANTS_KEY_PREFIX + token;
|
|
25681
|
+
this.isGloballyDisabled = isGloballyDisabled || function() { return false; };
|
|
25682
|
+
};
|
|
25683
|
+
|
|
25684
|
+
FeatureFlagPersistence.prototype.getPolicy = function() {
|
|
25685
|
+
if (this.isGloballyDisabled() || !this._isConfigValid()) {
|
|
25686
|
+
return VariantLookupPolicy.NETWORK_ONLY;
|
|
25687
|
+
}
|
|
25688
|
+
return this.persistenceConfig['variantLookupPolicy'];
|
|
25689
|
+
};
|
|
25690
|
+
|
|
25691
|
+
FeatureFlagPersistence.prototype.getTtlMs = function() {
|
|
25692
|
+
if (!this._isConfigValid()) {
|
|
25693
|
+
return DEFAULT_TTL_MS;
|
|
25694
|
+
}
|
|
25695
|
+
var configuredTtl = this.persistenceConfig['persistenceTtlMs'];
|
|
25696
|
+
return (configuredTtl === undefined || configuredTtl === null) ? DEFAULT_TTL_MS : configuredTtl;
|
|
25697
|
+
};
|
|
25698
|
+
|
|
25699
|
+
FeatureFlagPersistence.prototype._isConfigValid = function() {
|
|
25700
|
+
var config = this.persistenceConfig;
|
|
25701
|
+
if (!config) {
|
|
25702
|
+
return false;
|
|
25703
|
+
}
|
|
25704
|
+
|
|
25705
|
+
if (VALID_POLICIES.indexOf(config['variantLookupPolicy']) === -1) {
|
|
25706
|
+
logger$2.error('Invalid variantLookupPolicy:', config['variantLookupPolicy']);
|
|
25707
|
+
return false;
|
|
25708
|
+
}
|
|
25709
|
+
|
|
25710
|
+
if (config['persistenceTtlMs'] !== undefined &&
|
|
25711
|
+
config['persistenceTtlMs'] !== null &&
|
|
25712
|
+
config['persistenceTtlMs'] <= 0) {
|
|
25713
|
+
logger$2.error('If provided, persistenceTtlMs must be a positive number. Provided value:', config['persistenceTtlMs']);
|
|
25714
|
+
return false;
|
|
25715
|
+
}
|
|
25716
|
+
|
|
25717
|
+
return true;
|
|
25718
|
+
};
|
|
25719
|
+
|
|
25720
|
+
FeatureFlagPersistence.prototype.loadFlagsFromStorage = function(context) {
|
|
25721
|
+
var clearAndReturnNull = _.bind(function() {
|
|
25722
|
+
return this.clear().then(function() { return null; }).catch(function() { return null; });
|
|
25723
|
+
}, this);
|
|
25724
|
+
|
|
25725
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
25726
|
+
return clearAndReturnNull();
|
|
25727
|
+
}
|
|
25728
|
+
|
|
25729
|
+
var ttlMs = this.getTtlMs();
|
|
25730
|
+
|
|
25731
|
+
return this.idb.init().then(_.bind(function() {
|
|
25732
|
+
return this.idb.getItem(this.persistedVariantsKey);
|
|
25733
|
+
}, this)).then(_.bind(function(data) {
|
|
25734
|
+
if (!data) {
|
|
25735
|
+
logger$2.log('No persisted variants found in IndexedDB');
|
|
25736
|
+
return null;
|
|
25737
|
+
}
|
|
25738
|
+
|
|
25739
|
+
if (ttlMs && Date.now() - data['persistedAt'] >= ttlMs) {
|
|
25740
|
+
logger$2.log('Persisted variants are expiring');
|
|
25741
|
+
return null;
|
|
25742
|
+
}
|
|
25743
|
+
|
|
25744
|
+
if (!context || data['distinctId'] !== context['distinct_id']) {
|
|
25745
|
+
logger$2.log('Persisted variants found, but for a different distinct_id so clearing.');
|
|
25746
|
+
return clearAndReturnNull();
|
|
25747
|
+
}
|
|
25748
|
+
|
|
25749
|
+
var persistedFlags = new Map();
|
|
25750
|
+
_.each(data['flagVariants'], function(variantData, key) {
|
|
25751
|
+
persistedFlags.set(key, {
|
|
25752
|
+
'key': variantData['variant_key'],
|
|
25753
|
+
'value': variantData['variant_value'],
|
|
25754
|
+
'experiment_id': variantData['experiment_id'],
|
|
25755
|
+
'is_experiment_active': variantData['is_experiment_active'],
|
|
25756
|
+
'is_qa_tester': variantData['is_qa_tester'],
|
|
25757
|
+
'variant_source': 'persistence',
|
|
25758
|
+
'persisted_at_in_ms': data['persistedAt'],
|
|
25759
|
+
'ttl_in_ms': ttlMs
|
|
25760
|
+
});
|
|
25761
|
+
});
|
|
25762
|
+
|
|
25763
|
+
logger$2.log('Loaded', persistedFlags.size, 'variants from IndexedDB for distinct_id', data['distinctId']);
|
|
25764
|
+
|
|
25765
|
+
return {
|
|
25766
|
+
flags: persistedFlags,
|
|
25767
|
+
pendingFirstTimeEvents: data['pendingFirstTimeEvents'] || {},
|
|
25768
|
+
persistedAtMs: data['persistedAt'],
|
|
25769
|
+
ttlMs: ttlMs
|
|
25770
|
+
};
|
|
25771
|
+
}, this)).catch(_.bind(function(error) {
|
|
25772
|
+
logger$2.error('Failed to load persisted variants from IndexedDB, so clearing', error);
|
|
25773
|
+
return clearAndReturnNull();
|
|
25774
|
+
}, this));
|
|
25775
|
+
};
|
|
25776
|
+
|
|
25777
|
+
FeatureFlagPersistence.prototype.save = function(context, flagsMap, pendingFirstTimeEvents) {
|
|
25778
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
25779
|
+
return Promise.resolve();
|
|
25780
|
+
}
|
|
25781
|
+
|
|
25782
|
+
var flagVariants = {};
|
|
25783
|
+
flagsMap.forEach(function(variant, key) {
|
|
25784
|
+
flagVariants[key] = {
|
|
25785
|
+
'variant_key': variant['key'],
|
|
25786
|
+
'variant_value': variant['value'],
|
|
25787
|
+
'experiment_id': variant['experiment_id'],
|
|
25788
|
+
'is_experiment_active': variant['is_experiment_active'],
|
|
25789
|
+
'is_qa_tester': variant['is_qa_tester']
|
|
25790
|
+
};
|
|
25791
|
+
});
|
|
25792
|
+
|
|
25793
|
+
var data = {
|
|
25794
|
+
'persistedAt': Date.now(),
|
|
25795
|
+
'distinctId': context && context['distinct_id'],
|
|
25796
|
+
'context': context,
|
|
25797
|
+
'flagVariants': flagVariants,
|
|
25798
|
+
'pendingFirstTimeEvents': pendingFirstTimeEvents || {}
|
|
25799
|
+
};
|
|
25800
|
+
|
|
25801
|
+
return this.idb.init().then(_.bind(function() {
|
|
25802
|
+
return this.idb.setItem(this.persistedVariantsKey, data);
|
|
25803
|
+
}, this)).then(function() {
|
|
25804
|
+
logger$2.log('Saved', flagsMap.size, 'variants to IndexedDB for distinct_id', data['distinctId']);
|
|
25805
|
+
}).catch(function(error) {
|
|
25806
|
+
logger$2.error('Failed to persist variants to IndexedDB:', error);
|
|
25807
|
+
});
|
|
25808
|
+
};
|
|
25809
|
+
|
|
25810
|
+
FeatureFlagPersistence.prototype.clear = function() {
|
|
25811
|
+
if (this.isGloballyDisabled()) {
|
|
25812
|
+
return Promise.resolve();
|
|
25813
|
+
}
|
|
25814
|
+
return this.idb.init().then(_.bind(function() {
|
|
25815
|
+
return this.idb.removeItem(this.persistedVariantsKey);
|
|
25816
|
+
}, this)).then(function() {
|
|
25817
|
+
logger$2.log('Cleared persisted variants from IndexedDB');
|
|
25818
|
+
}).catch(function(error) {
|
|
25819
|
+
logger$2.error('Failed to clear persisted variants from IndexedDB:', error);
|
|
25820
|
+
});
|
|
25821
|
+
};
|
|
25822
|
+
|
|
25618
25823
|
var logger$1 = console_with_prefix('flags');
|
|
25619
25824
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
25620
25825
|
|
|
25621
25826
|
var CONFIG_CONTEXT = 'context';
|
|
25827
|
+
var CONFIG_PERSISTENCE = 'persistence';
|
|
25622
25828
|
var CONFIG_DEFAULTS = {};
|
|
25623
25829
|
CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
25624
25830
|
|
|
@@ -25641,6 +25847,13 @@
|
|
|
25641
25847
|
return eventKey.split(':')[0];
|
|
25642
25848
|
};
|
|
25643
25849
|
|
|
25850
|
+
var withFallbackSource = function(fallback) {
|
|
25851
|
+
if (_.isObject(fallback)) {
|
|
25852
|
+
return _.extend({}, fallback, {'variant_source': 'fallback'});
|
|
25853
|
+
}
|
|
25854
|
+
return {'value': fallback, 'variant_source': 'fallback'};
|
|
25855
|
+
};
|
|
25856
|
+
|
|
25644
25857
|
/**
|
|
25645
25858
|
* FeatureFlagManager: support for Mixpanel's feature flagging product
|
|
25646
25859
|
* @constructor
|
|
@@ -25663,13 +25876,63 @@
|
|
|
25663
25876
|
}
|
|
25664
25877
|
|
|
25665
25878
|
this.flags = null;
|
|
25666
|
-
this.fetchFlags().catch(function() {
|
|
25667
|
-
logger$1.error('Error fetching flags during init');
|
|
25668
|
-
});
|
|
25669
|
-
|
|
25670
25879
|
this.trackedFeatures = new Set();
|
|
25671
25880
|
this.pendingFirstTimeEvents = {};
|
|
25672
25881
|
this.activatedFirstTimeEvents = {};
|
|
25882
|
+
this._loadedPersistedAtMs = null;
|
|
25883
|
+
this._loadedTtlMs = null;
|
|
25884
|
+
|
|
25885
|
+
this.persistence = new FeatureFlagPersistence(
|
|
25886
|
+
this.getConfig(CONFIG_PERSISTENCE),
|
|
25887
|
+
this.getMpConfig('token'),
|
|
25888
|
+
_.bind(function() { return this.getMpConfig('disable_persistence'); }, this)
|
|
25889
|
+
);
|
|
25890
|
+
|
|
25891
|
+
this.persistenceLoadedPromise = this.persistence.loadFlagsFromStorage(this._buildContext())
|
|
25892
|
+
.then(_.bind(function(loaded) {
|
|
25893
|
+
if (loaded) {
|
|
25894
|
+
this.flags = loaded.flags;
|
|
25895
|
+
this.pendingFirstTimeEvents = loaded.pendingFirstTimeEvents;
|
|
25896
|
+
this._loadedPersistedAtMs = loaded.persistedAtMs;
|
|
25897
|
+
this._loadedTtlMs = loaded.ttlMs;
|
|
25898
|
+
}
|
|
25899
|
+
}, this));
|
|
25900
|
+
|
|
25901
|
+
return this.persistenceLoadedPromise
|
|
25902
|
+
.then(_.bind(function() {
|
|
25903
|
+
return this.fetchFlags();
|
|
25904
|
+
}, this))
|
|
25905
|
+
.catch(function() {
|
|
25906
|
+
logger$1.error('Error initializing feature flags');
|
|
25907
|
+
});
|
|
25908
|
+
};
|
|
25909
|
+
|
|
25910
|
+
FeatureFlagManager.prototype._buildContext = function() {
|
|
25911
|
+
return _.extend(
|
|
25912
|
+
{'distinct_id': this.getMpProperty('distinct_id'), 'device_id': this.getMpProperty('$device_id')},
|
|
25913
|
+
this.getConfig(CONFIG_CONTEXT)
|
|
25914
|
+
);
|
|
25915
|
+
};
|
|
25916
|
+
|
|
25917
|
+
FeatureFlagManager.prototype.reset = function() {
|
|
25918
|
+
if (!this.persistence) {
|
|
25919
|
+
return Promise.resolve();
|
|
25920
|
+
}
|
|
25921
|
+
|
|
25922
|
+
this.flags = null;
|
|
25923
|
+
this.pendingFirstTimeEvents = {};
|
|
25924
|
+
this.activatedFirstTimeEvents = {};
|
|
25925
|
+
this.trackedFeatures = new Set();
|
|
25926
|
+
this.fetchPromise = null;
|
|
25927
|
+
this._fetchInProgressStartTime = null;
|
|
25928
|
+
this._loadedPersistedAtMs = null;
|
|
25929
|
+
this._loadedTtlMs = null;
|
|
25930
|
+
|
|
25931
|
+
return this.persistence.clear().then(_.bind(function() {
|
|
25932
|
+
return this.fetchFlags();
|
|
25933
|
+
}, this)).catch(function() {
|
|
25934
|
+
logger$1.error('Error during flags reset');
|
|
25935
|
+
});
|
|
25673
25936
|
};
|
|
25674
25937
|
|
|
25675
25938
|
FeatureFlagManager.prototype.getFullConfig = function() {
|
|
@@ -25726,12 +25989,11 @@
|
|
|
25726
25989
|
return Promise.resolve();
|
|
25727
25990
|
}
|
|
25728
25991
|
|
|
25729
|
-
var
|
|
25730
|
-
var
|
|
25992
|
+
var context = this._buildContext();
|
|
25993
|
+
var distinctId = context['distinct_id'];
|
|
25731
25994
|
var traceparent = generateTraceparent();
|
|
25732
25995
|
logger$1.log('Fetching flags for distinct ID: ' + distinctId);
|
|
25733
25996
|
|
|
25734
|
-
var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
|
|
25735
25997
|
var searchParams = new URLSearchParams();
|
|
25736
25998
|
searchParams.set('context', JSON.stringify(context));
|
|
25737
25999
|
searchParams.set('token', this.getMpConfig('token'));
|
|
@@ -25781,7 +26043,8 @@
|
|
|
25781
26043
|
'value': data['variant_value'],
|
|
25782
26044
|
'experiment_id': data['experiment_id'],
|
|
25783
26045
|
'is_experiment_active': data['is_experiment_active'],
|
|
25784
|
-
'is_qa_tester': data['is_qa_tester']
|
|
26046
|
+
'is_qa_tester': data['is_qa_tester'],
|
|
26047
|
+
'variant_source': 'network'
|
|
25785
26048
|
});
|
|
25786
26049
|
}
|
|
25787
26050
|
}, this);
|
|
@@ -25823,10 +26086,15 @@
|
|
|
25823
26086
|
}
|
|
25824
26087
|
|
|
25825
26088
|
this.flags = flags;
|
|
26089
|
+
this.trackedFeatures = new Set();
|
|
25826
26090
|
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
26091
|
+
this._loadedPersistedAtMs = null;
|
|
26092
|
+
this._loadedTtlMs = null;
|
|
25827
26093
|
this._traceparent = traceparent;
|
|
25828
26094
|
|
|
25829
26095
|
this._loadTargetingIfNeeded();
|
|
26096
|
+
|
|
26097
|
+
this.persistence.save(context, this.flags, this.pendingFirstTimeEvents);
|
|
25830
26098
|
}.bind(this)).catch(function(error) {
|
|
25831
26099
|
if (this._fetchInProgressStartTime) {
|
|
25832
26100
|
this.markFetchComplete();
|
|
@@ -25986,6 +26254,7 @@
|
|
|
25986
26254
|
};
|
|
25987
26255
|
|
|
25988
26256
|
this.flags.set(flagKey, newVariant);
|
|
26257
|
+
this.trackedFeatures.delete(flagKey);
|
|
25989
26258
|
this.activatedFirstTimeEvents[eventKey] = true;
|
|
25990
26259
|
|
|
25991
26260
|
this.recordFirstTimeEvent(
|
|
@@ -25997,8 +26266,8 @@
|
|
|
25997
26266
|
};
|
|
25998
26267
|
|
|
25999
26268
|
FeatureFlagManager.prototype.getFirstTimeEventApiRoute = function(flagId) {
|
|
26000
|
-
|
|
26001
|
-
return
|
|
26269
|
+
var base = this.getFullApiRoute().replace(/\/$/, '');
|
|
26270
|
+
return base + '/' + flagId + '/first-time-events';
|
|
26002
26271
|
};
|
|
26003
26272
|
|
|
26004
26273
|
FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId, firstTimeEventHash) {
|
|
@@ -26035,35 +26304,106 @@
|
|
|
26035
26304
|
};
|
|
26036
26305
|
|
|
26037
26306
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
26038
|
-
if (!this.
|
|
26307
|
+
if (!this.persistenceLoadedPromise) {
|
|
26039
26308
|
return new Promise(function(resolve) {
|
|
26040
26309
|
logger$1.critical('Feature Flags not initialized');
|
|
26041
|
-
resolve(fallback);
|
|
26310
|
+
resolve(withFallbackSource(fallback));
|
|
26042
26311
|
});
|
|
26043
26312
|
}
|
|
26044
26313
|
|
|
26045
|
-
|
|
26046
|
-
|
|
26047
|
-
|
|
26048
|
-
|
|
26049
|
-
|
|
26050
|
-
|
|
26314
|
+
var policy = this.persistence.getPolicy();
|
|
26315
|
+
|
|
26316
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26317
|
+
// 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.
|
|
26318
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26319
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26320
|
+
return this.getVariantSync(featureName, fallback);
|
|
26321
|
+
}
|
|
26322
|
+
if (!this.fetchPromise) {
|
|
26323
|
+
return withFallbackSource(fallback);
|
|
26324
|
+
}
|
|
26325
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26326
|
+
return this.getVariantSync(featureName, fallback);
|
|
26327
|
+
}, this)).catch(function(error) {
|
|
26328
|
+
logger$1.error(error);
|
|
26329
|
+
return withFallbackSource(fallback);
|
|
26330
|
+
});
|
|
26331
|
+
}
|
|
26332
|
+
|
|
26333
|
+
var serve = _.bind(function() { return this.getVariantSync(featureName, fallback); }, this);
|
|
26334
|
+
if (!this.fetchPromise) {
|
|
26335
|
+
return withFallbackSource(fallback);
|
|
26336
|
+
}
|
|
26337
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26338
|
+
}, this));
|
|
26339
|
+
};
|
|
26340
|
+
|
|
26341
|
+
FeatureFlagManager.prototype._loadedPersistenceIsStale = function() {
|
|
26342
|
+
if (!this._loadedPersistedAtMs || !this._loadedTtlMs) {
|
|
26343
|
+
return false;
|
|
26344
|
+
}
|
|
26345
|
+
return Date.now() - this._loadedPersistedAtMs >= this._loadedTtlMs;
|
|
26051
26346
|
};
|
|
26052
26347
|
|
|
26053
26348
|
FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
|
|
26349
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26350
|
+
logger$1.log('Loaded persisted variants are past TTL so returning fallback for "' + featureName + '"');
|
|
26351
|
+
return withFallbackSource(fallback);
|
|
26352
|
+
}
|
|
26054
26353
|
if (!this.areFlagsReady()) {
|
|
26055
26354
|
logger$1.log('Flags not loaded yet');
|
|
26056
|
-
return fallback;
|
|
26355
|
+
return withFallbackSource(fallback);
|
|
26057
26356
|
}
|
|
26058
26357
|
var feature = this.flags.get(featureName);
|
|
26059
26358
|
if (!feature) {
|
|
26060
26359
|
logger$1.log('No flag found: "' + featureName + '"');
|
|
26061
|
-
return fallback;
|
|
26360
|
+
return withFallbackSource(fallback);
|
|
26062
26361
|
}
|
|
26063
26362
|
this.trackFeatureCheck(featureName, feature);
|
|
26064
26363
|
return feature;
|
|
26065
26364
|
};
|
|
26066
26365
|
|
|
26366
|
+
FeatureFlagManager.prototype.getAllVariants = function() {
|
|
26367
|
+
if (!this.persistenceLoadedPromise) {
|
|
26368
|
+
logger$1.critical('Feature Flags not initialized');
|
|
26369
|
+
return Promise.resolve(new Map());
|
|
26370
|
+
}
|
|
26371
|
+
|
|
26372
|
+
var policy = this.persistence.getPolicy();
|
|
26373
|
+
|
|
26374
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26375
|
+
// 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.
|
|
26376
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26377
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26378
|
+
return this.getAllVariantsSync();
|
|
26379
|
+
}
|
|
26380
|
+
if (!this.fetchPromise) {
|
|
26381
|
+
return new Map();
|
|
26382
|
+
}
|
|
26383
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26384
|
+
return this.getAllVariantsSync();
|
|
26385
|
+
}, this)).catch(function(error) {
|
|
26386
|
+
logger$1.error(error);
|
|
26387
|
+
return new Map();
|
|
26388
|
+
});
|
|
26389
|
+
}
|
|
26390
|
+
|
|
26391
|
+
var serve = _.bind(this.getAllVariantsSync, this);
|
|
26392
|
+
if (!this.fetchPromise) {
|
|
26393
|
+
return new Map();
|
|
26394
|
+
}
|
|
26395
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26396
|
+
}, this));
|
|
26397
|
+
};
|
|
26398
|
+
|
|
26399
|
+
FeatureFlagManager.prototype.getAllVariantsSync = function() {
|
|
26400
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26401
|
+
logger$1.log('Loaded persisted variants are past TTL so returning empty Map');
|
|
26402
|
+
return new Map();
|
|
26403
|
+
}
|
|
26404
|
+
return this.flags || new Map();
|
|
26405
|
+
};
|
|
26406
|
+
|
|
26067
26407
|
FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackValue) {
|
|
26068
26408
|
return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
|
|
26069
26409
|
return feature['value'];
|
|
@@ -26102,6 +26442,10 @@
|
|
|
26102
26442
|
return val;
|
|
26103
26443
|
};
|
|
26104
26444
|
|
|
26445
|
+
function isPresent(v) {
|
|
26446
|
+
return v !== undefined && v !== null;
|
|
26447
|
+
}
|
|
26448
|
+
|
|
26105
26449
|
FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature) {
|
|
26106
26450
|
if (this.trackedFeatures.has(featureName)) {
|
|
26107
26451
|
return;
|
|
@@ -26112,21 +26456,30 @@
|
|
|
26112
26456
|
'Experiment name': featureName,
|
|
26113
26457
|
'Variant name': feature['key'],
|
|
26114
26458
|
'$experiment_type': 'feature_flag',
|
|
26115
|
-
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
26116
|
-
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
26459
|
+
'Variant fetch start time': isPresent(this._fetchStartTime) ? new Date(this._fetchStartTime).toISOString() : null,
|
|
26460
|
+
'Variant fetch complete time': isPresent(this._fetchCompleteTime) ? new Date(this._fetchCompleteTime).toISOString() : null,
|
|
26117
26461
|
'Variant fetch latency (ms)': this._fetchLatency,
|
|
26118
26462
|
'Variant fetch traceparent': this._traceparent,
|
|
26119
26463
|
};
|
|
26120
26464
|
|
|
26121
|
-
if (feature['experiment_id']
|
|
26465
|
+
if (isPresent(feature['experiment_id'])) {
|
|
26122
26466
|
trackingProperties['$experiment_id'] = feature['experiment_id'];
|
|
26123
26467
|
}
|
|
26124
|
-
if (feature['is_experiment_active']
|
|
26468
|
+
if (isPresent(feature['is_experiment_active'])) {
|
|
26125
26469
|
trackingProperties['$is_experiment_active'] = feature['is_experiment_active'];
|
|
26126
26470
|
}
|
|
26127
|
-
if (feature['is_qa_tester']
|
|
26471
|
+
if (isPresent(feature['is_qa_tester'])) {
|
|
26128
26472
|
trackingProperties['$is_qa_tester'] = feature['is_qa_tester'];
|
|
26129
26473
|
}
|
|
26474
|
+
if (isPresent(feature['variant_source'])) {
|
|
26475
|
+
trackingProperties['$variant_source'] = feature['variant_source'];
|
|
26476
|
+
}
|
|
26477
|
+
if (isPresent(feature['persisted_at_in_ms'])) {
|
|
26478
|
+
trackingProperties['$persisted_at_in_ms'] = feature['persisted_at_in_ms'];
|
|
26479
|
+
}
|
|
26480
|
+
if (isPresent(feature['ttl_in_ms'])) {
|
|
26481
|
+
trackingProperties['$ttl_in_ms'] = feature['ttl_in_ms'];
|
|
26482
|
+
}
|
|
26130
26483
|
|
|
26131
26484
|
this.track('$experiment_started', trackingProperties);
|
|
26132
26485
|
};
|
|
@@ -26150,6 +26503,8 @@
|
|
|
26150
26503
|
FeatureFlagManager.prototype['are_flags_ready'] = FeatureFlagManager.prototype.areFlagsReady;
|
|
26151
26504
|
FeatureFlagManager.prototype['get_variant'] = FeatureFlagManager.prototype.getVariant;
|
|
26152
26505
|
FeatureFlagManager.prototype['get_variant_sync'] = FeatureFlagManager.prototype.getVariantSync;
|
|
26506
|
+
FeatureFlagManager.prototype['get_all_variants'] = FeatureFlagManager.prototype.getAllVariants;
|
|
26507
|
+
FeatureFlagManager.prototype['get_all_variants_sync'] = FeatureFlagManager.prototype.getAllVariantsSync;
|
|
26153
26508
|
FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype.getVariantValue;
|
|
26154
26509
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
26155
26510
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
@@ -26202,7 +26557,7 @@
|
|
|
26202
26557
|
return PromisePolyfill.resolve(false);
|
|
26203
26558
|
}
|
|
26204
26559
|
|
|
26205
|
-
var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
26560
|
+
var recording_registry_idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
26206
26561
|
var tab_id = this.getTabId();
|
|
26207
26562
|
return recording_registry_idb.init()
|
|
26208
26563
|
.then(function () {
|
|
@@ -28129,6 +28484,7 @@
|
|
|
28129
28484
|
'disable_all_events': false,
|
|
28130
28485
|
'identify_called': false
|
|
28131
28486
|
};
|
|
28487
|
+
this._remote_settings_strict_disabled = false;
|
|
28132
28488
|
|
|
28133
28489
|
// set up request queueing/batching
|
|
28134
28490
|
this.request_batchers = {};
|
|
@@ -28203,9 +28559,6 @@
|
|
|
28203
28559
|
this.flags.init();
|
|
28204
28560
|
this['flags'] = this.flags;
|
|
28205
28561
|
|
|
28206
|
-
this.autocapture = new Autocapture(this);
|
|
28207
|
-
this.autocapture.init();
|
|
28208
|
-
|
|
28209
28562
|
this._init_tab_id();
|
|
28210
28563
|
|
|
28211
28564
|
// Based on remote_settings_mode, fetch remote settings and then start session recording if applicable
|
|
@@ -28217,6 +28570,9 @@
|
|
|
28217
28570
|
} else {
|
|
28218
28571
|
this.__session_recording_init_promise = this._check_and_start_session_recording();
|
|
28219
28572
|
}
|
|
28573
|
+
|
|
28574
|
+
this.autocapture = new Autocapture(this);
|
|
28575
|
+
this.autocapture.init();
|
|
28220
28576
|
};
|
|
28221
28577
|
|
|
28222
28578
|
/**
|
|
@@ -28263,9 +28619,19 @@
|
|
|
28263
28619
|
return this.recorderManager.checkAndStartSessionRecording(force_start);
|
|
28264
28620
|
});
|
|
28265
28621
|
|
|
28266
|
-
MixpanelLib.prototype._start_recording_on_event = function(event_name, properties) {
|
|
28267
|
-
|
|
28268
|
-
|
|
28622
|
+
MixpanelLib.prototype._start_recording_on_event = safewrap(function(event_name, properties) {
|
|
28623
|
+
// Wait for recording init to complete before evaluating event triggers.
|
|
28624
|
+
// This ensures recording_event_triggers config is fully loaded when remote settings are used.
|
|
28625
|
+
if (this.__session_recording_init_promise) {
|
|
28626
|
+
this.__session_recording_init_promise.then(_.bind(function() {
|
|
28627
|
+
// In strict mode, skip recording if remote settings failed
|
|
28628
|
+
if (this._remote_settings_strict_disabled) {
|
|
28629
|
+
return;
|
|
28630
|
+
}
|
|
28631
|
+
return this.recorderManager.startRecordingOnEvent(event_name, properties);
|
|
28632
|
+
}, this));
|
|
28633
|
+
}
|
|
28634
|
+
});
|
|
28269
28635
|
|
|
28270
28636
|
MixpanelLib.prototype.start_session_recording = function () {
|
|
28271
28637
|
return this._check_and_start_session_recording(true);
|
|
@@ -28564,6 +28930,7 @@
|
|
|
28564
28930
|
var disableRecordingIfStrict = function() {
|
|
28565
28931
|
if (mode === 'strict') {
|
|
28566
28932
|
self.set_config({'record_sessions_percent': 0});
|
|
28933
|
+
self._remote_settings_strict_disabled = true;
|
|
28567
28934
|
}
|
|
28568
28935
|
};
|
|
28569
28936
|
|
|
@@ -29189,6 +29556,10 @@
|
|
|
29189
29556
|
properties
|
|
29190
29557
|
);
|
|
29191
29558
|
|
|
29559
|
+
if (this.is_recording_heatmap_data()) {
|
|
29560
|
+
event_properties['$captured_for_heatmap'] = true;
|
|
29561
|
+
}
|
|
29562
|
+
|
|
29192
29563
|
return this.track(event_name, event_properties);
|
|
29193
29564
|
});
|
|
29194
29565
|
|
|
@@ -29532,6 +29903,7 @@
|
|
|
29532
29903
|
'$device_id': uuid
|
|
29533
29904
|
}, '');
|
|
29534
29905
|
this._check_and_start_session_recording();
|
|
29906
|
+
this.flags.reset();
|
|
29535
29907
|
};
|
|
29536
29908
|
|
|
29537
29909
|
/**
|