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
package/dist/mixpanel.module.js
CHANGED
|
@@ -25,7 +25,7 @@ if (typeof(window) === 'undefined') {
|
|
|
25
25
|
|
|
26
26
|
var Config = {
|
|
27
27
|
DEBUG: false,
|
|
28
|
-
LIB_VERSION: '2.
|
|
28
|
+
LIB_VERSION: '2.79.0'
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
// Window global names for async modules
|
|
@@ -19123,6 +19123,7 @@ var log_func_with_prefix = function(func, prefix) {
|
|
|
19123
19123
|
var console_with_prefix = function(prefix) {
|
|
19124
19124
|
return {
|
|
19125
19125
|
log: log_func_with_prefix(console$1.log, prefix),
|
|
19126
|
+
warn: log_func_with_prefix(console$1.warn, prefix),
|
|
19126
19127
|
error: log_func_with_prefix(console$1.error, prefix),
|
|
19127
19128
|
critical: log_func_with_prefix(console$1.critical, prefix)
|
|
19128
19129
|
};
|
|
@@ -20069,7 +20070,8 @@ var localStorageSupported = function(storage, forceCheck) {
|
|
|
20069
20070
|
if (_localStorageSupported !== null && !forceCheck) {
|
|
20070
20071
|
return _localStorageSupported;
|
|
20071
20072
|
}
|
|
20072
|
-
|
|
20073
|
+
|
|
20074
|
+
return _localStorageSupported = _testStorageSupported(storage);
|
|
20073
20075
|
};
|
|
20074
20076
|
|
|
20075
20077
|
var _sessionStorageSupported = null;
|
|
@@ -20077,7 +20079,8 @@ var sessionStorageSupported = function(storage, forceCheck) {
|
|
|
20077
20079
|
if (_sessionStorageSupported !== null && !forceCheck) {
|
|
20078
20080
|
return _sessionStorageSupported;
|
|
20079
20081
|
}
|
|
20080
|
-
|
|
20082
|
+
|
|
20083
|
+
return _sessionStorageSupported = _testStorageSupported(storage);
|
|
20081
20084
|
};
|
|
20082
20085
|
|
|
20083
20086
|
function _storageWrapper(storage, name, is_supported_fn) {
|
|
@@ -20127,17 +20130,26 @@ function _storageWrapper(storage, name, is_supported_fn) {
|
|
|
20127
20130
|
};
|
|
20128
20131
|
}
|
|
20129
20132
|
|
|
20130
|
-
// Safari
|
|
20131
|
-
//
|
|
20132
|
-
var
|
|
20133
|
-
try {
|
|
20134
|
-
|
|
20135
|
-
|
|
20136
|
-
|
|
20137
|
-
}
|
|
20133
|
+
// Safari and other browsers may error out accessing localStorage/sessionStorage
|
|
20134
|
+
// when cookies are disabled, so wrap access in a try-catch.
|
|
20135
|
+
var getLocalStorage = function() {
|
|
20136
|
+
try {
|
|
20137
|
+
return win.localStorage; // eslint-disable-line no-restricted-properties
|
|
20138
|
+
} catch (_err) {
|
|
20139
|
+
return null;
|
|
20140
|
+
}
|
|
20141
|
+
};
|
|
20142
|
+
|
|
20143
|
+
var getSessionStorage = function() {
|
|
20144
|
+
try {
|
|
20145
|
+
return win.sessionStorage; // eslint-disable-line no-restricted-properties
|
|
20146
|
+
} catch (_err) {
|
|
20147
|
+
return null;
|
|
20148
|
+
}
|
|
20149
|
+
};
|
|
20138
20150
|
|
|
20139
|
-
_.localStorage = _storageWrapper(
|
|
20140
|
-
_.sessionStorage = _storageWrapper(
|
|
20151
|
+
_.localStorage = _storageWrapper(getLocalStorage(), 'localStorage', localStorageSupported);
|
|
20152
|
+
_.sessionStorage = _storageWrapper(getSessionStorage(), 'sessionStorage', sessionStorageSupported);
|
|
20141
20153
|
|
|
20142
20154
|
_.register_event = (function() {
|
|
20143
20155
|
// written by Dean Edwards, 2005
|
|
@@ -20806,29 +20818,26 @@ _['JSONEncode'] = _.JSONEncode;
|
|
|
20806
20818
|
_['toArray'] = _.toArray;
|
|
20807
20819
|
_['NPO'] = NpoPromise;
|
|
20808
20820
|
|
|
20809
|
-
var MIXPANEL_DB_NAME = 'mixpanelBrowserDb';
|
|
20810
|
-
|
|
20811
|
-
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
20812
|
-
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
20813
|
-
|
|
20814
|
-
// note: increment the version number when adding new object stores
|
|
20815
|
-
var DB_VERSION = 1;
|
|
20816
|
-
var OBJECT_STORES = [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME];
|
|
20817
|
-
|
|
20818
20821
|
/**
|
|
20819
20822
|
* @type {import('./wrapper').StorageWrapper}
|
|
20820
20823
|
*/
|
|
20821
|
-
var IDBStorageWrapper = function (storeName) {
|
|
20824
|
+
var IDBStorageWrapper = function (dbName, storeName, versionData) {
|
|
20825
|
+
this.dbName = dbName;
|
|
20826
|
+
this.storeName = storeName;
|
|
20827
|
+
this.version = versionData.version;
|
|
20828
|
+
this.storeNamesInDb = versionData.storeNames;
|
|
20822
20829
|
/**
|
|
20823
20830
|
* @type {Promise<IDBDatabase>|null}
|
|
20824
20831
|
*/
|
|
20825
20832
|
this.dbPromise = null;
|
|
20826
|
-
this.storeName = storeName;
|
|
20827
20833
|
};
|
|
20828
20834
|
|
|
20829
20835
|
IDBStorageWrapper.prototype._openDb = function () {
|
|
20836
|
+
var dbName = this.dbName;
|
|
20837
|
+
var version = this.version;
|
|
20838
|
+
var storeNamesInDb = this.storeNamesInDb;
|
|
20830
20839
|
return new PromisePolyfill(function (resolve, reject) {
|
|
20831
|
-
var openRequest = win.indexedDB.open(
|
|
20840
|
+
var openRequest = win.indexedDB.open(dbName, version);
|
|
20832
20841
|
openRequest['onerror'] = function () {
|
|
20833
20842
|
reject(openRequest.error);
|
|
20834
20843
|
};
|
|
@@ -20840,8 +20849,10 @@ IDBStorageWrapper.prototype._openDb = function () {
|
|
|
20840
20849
|
openRequest['onupgradeneeded'] = function (ev) {
|
|
20841
20850
|
var db = ev.target.result;
|
|
20842
20851
|
|
|
20843
|
-
|
|
20844
|
-
db.
|
|
20852
|
+
storeNamesInDb.forEach(function (storeName) {
|
|
20853
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
20854
|
+
db.createObjectStore(storeName);
|
|
20855
|
+
}
|
|
20845
20856
|
});
|
|
20846
20857
|
};
|
|
20847
20858
|
});
|
|
@@ -20933,6 +20944,16 @@ IDBStorageWrapper.prototype.getAll = function () {
|
|
|
20933
20944
|
});
|
|
20934
20945
|
};
|
|
20935
20946
|
|
|
20947
|
+
var MIXPANEL_BROWSER_DB_NAME = 'mixpanelBrowserDb';
|
|
20948
|
+
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
20949
|
+
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
20950
|
+
|
|
20951
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
20952
|
+
var RECORDER_VERSION_DATA = {
|
|
20953
|
+
version: 1,
|
|
20954
|
+
storeNames: [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME]
|
|
20955
|
+
};
|
|
20956
|
+
|
|
20936
20957
|
/**
|
|
20937
20958
|
* GDPR utils
|
|
20938
20959
|
*
|
|
@@ -21233,7 +21254,7 @@ function _addOptOutCheck(method, getConfigValue) {
|
|
|
21233
21254
|
};
|
|
21234
21255
|
}
|
|
21235
21256
|
|
|
21236
|
-
var logger$
|
|
21257
|
+
var logger$9 = console_with_prefix('lock');
|
|
21237
21258
|
|
|
21238
21259
|
/**
|
|
21239
21260
|
* SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
|
|
@@ -21259,7 +21280,7 @@ var SharedLock = function(key, options) {
|
|
|
21259
21280
|
options = options || {};
|
|
21260
21281
|
|
|
21261
21282
|
this.storageKey = key;
|
|
21262
|
-
this.storage = options.storage ||
|
|
21283
|
+
this.storage = options.storage || getLocalStorage();
|
|
21263
21284
|
this.pollIntervalMS = options.pollIntervalMS || 100;
|
|
21264
21285
|
this.timeoutMS = options.timeoutMS || 2000;
|
|
21265
21286
|
|
|
@@ -21285,7 +21306,7 @@ SharedLock.prototype.withLock = function(lockedCB, pid) {
|
|
|
21285
21306
|
|
|
21286
21307
|
var delay = function(cb) {
|
|
21287
21308
|
if (new Date().getTime() - startTime > timeoutMS) {
|
|
21288
|
-
logger$
|
|
21309
|
+
logger$9.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
|
|
21289
21310
|
storage.removeItem(keyZ);
|
|
21290
21311
|
storage.removeItem(keyY);
|
|
21291
21312
|
loop();
|
|
@@ -21387,10 +21408,13 @@ SharedLock.prototype.withLock = function(lockedCB, pid) {
|
|
|
21387
21408
|
* @type {import('./wrapper').StorageWrapper}
|
|
21388
21409
|
*/
|
|
21389
21410
|
var LocalStorageWrapper = function (storageOverride) {
|
|
21390
|
-
this.storage = storageOverride ||
|
|
21411
|
+
this.storage = storageOverride || getLocalStorage();
|
|
21391
21412
|
};
|
|
21392
21413
|
|
|
21393
21414
|
LocalStorageWrapper.prototype.init = function () {
|
|
21415
|
+
if (!this.storage) {
|
|
21416
|
+
return PromisePolyfill.reject(new Error('localStorage is not available'));
|
|
21417
|
+
}
|
|
21394
21418
|
return PromisePolyfill.resolve();
|
|
21395
21419
|
};
|
|
21396
21420
|
|
|
@@ -21432,7 +21456,7 @@ LocalStorageWrapper.prototype.removeItem = function (key) {
|
|
|
21432
21456
|
}, this));
|
|
21433
21457
|
};
|
|
21434
21458
|
|
|
21435
|
-
var logger$
|
|
21459
|
+
var logger$8 = console_with_prefix('batch');
|
|
21436
21460
|
|
|
21437
21461
|
/**
|
|
21438
21462
|
* RequestQueue: queue for batching API requests with localStorage backup for retries.
|
|
@@ -21457,11 +21481,11 @@ var RequestQueue = function (storageKey, options) {
|
|
|
21457
21481
|
if (this.usePersistence) {
|
|
21458
21482
|
this.queueStorage = options.queueStorage || new LocalStorageWrapper();
|
|
21459
21483
|
this.lock = new SharedLock(storageKey, {
|
|
21460
|
-
storage: options.sharedLockStorage
|
|
21484
|
+
storage: options.sharedLockStorage,
|
|
21461
21485
|
timeoutMS: options.sharedLockTimeoutMS,
|
|
21462
21486
|
});
|
|
21463
21487
|
}
|
|
21464
|
-
this.reportError = options.errorReporter || _.bind(logger$
|
|
21488
|
+
this.reportError = options.errorReporter || _.bind(logger$8.error, logger$8);
|
|
21465
21489
|
|
|
21466
21490
|
this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
|
|
21467
21491
|
|
|
@@ -21794,7 +21818,7 @@ RequestQueue.prototype.clear = function () {
|
|
|
21794
21818
|
// maximum interval between request retries after exponential backoff
|
|
21795
21819
|
var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
|
|
21796
21820
|
|
|
21797
|
-
var logger$
|
|
21821
|
+
var logger$7 = console_with_prefix('batch');
|
|
21798
21822
|
|
|
21799
21823
|
/**
|
|
21800
21824
|
* RequestBatcher: manages the queueing, flushing, retry etc of requests of one
|
|
@@ -21922,7 +21946,7 @@ RequestBatcher.prototype.sendRequestPromise = function(data, options) {
|
|
|
21922
21946
|
*/
|
|
21923
21947
|
RequestBatcher.prototype.flush = function(options) {
|
|
21924
21948
|
if (this.requestInProgress) {
|
|
21925
|
-
logger$
|
|
21949
|
+
logger$7.log('Flush: Request already in progress');
|
|
21926
21950
|
return PromisePolyfill.resolve();
|
|
21927
21951
|
}
|
|
21928
21952
|
|
|
@@ -22099,7 +22123,7 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
22099
22123
|
if (options.unloading) {
|
|
22100
22124
|
requestOptions.transport = 'sendBeacon';
|
|
22101
22125
|
}
|
|
22102
|
-
logger$
|
|
22126
|
+
logger$7.log('MIXPANEL REQUEST:', dataForRequest);
|
|
22103
22127
|
return this.sendRequestPromise(dataForRequest, requestOptions).then(batchSendCallback);
|
|
22104
22128
|
}, this))
|
|
22105
22129
|
.catch(_.bind(function(err) {
|
|
@@ -22112,7 +22136,7 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
22112
22136
|
* Log error to global logger and optional user-defined logger.
|
|
22113
22137
|
*/
|
|
22114
22138
|
RequestBatcher.prototype.reportError = function(msg, err) {
|
|
22115
|
-
logger$
|
|
22139
|
+
logger$7.error.apply(logger$7.error, arguments);
|
|
22116
22140
|
if (this.errorReporter) {
|
|
22117
22141
|
try {
|
|
22118
22142
|
if (!(err instanceof Error)) {
|
|
@@ -22120,7 +22144,7 @@ RequestBatcher.prototype.reportError = function(msg, err) {
|
|
|
22120
22144
|
}
|
|
22121
22145
|
this.errorReporter(msg, err);
|
|
22122
22146
|
} catch(err) {
|
|
22123
|
-
logger$
|
|
22147
|
+
logger$7.error(err);
|
|
22124
22148
|
}
|
|
22125
22149
|
}
|
|
22126
22150
|
};
|
|
@@ -22265,7 +22289,7 @@ var EVENT_HANDLER_ATTRIBUTES = [
|
|
|
22265
22289
|
|
|
22266
22290
|
var MAX_DEPTH = 5;
|
|
22267
22291
|
|
|
22268
|
-
var logger$
|
|
22292
|
+
var logger$6 = console_with_prefix('autocapture');
|
|
22269
22293
|
|
|
22270
22294
|
|
|
22271
22295
|
function getClasses(el) {
|
|
@@ -22529,7 +22553,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
|
22529
22553
|
return false;
|
|
22530
22554
|
}
|
|
22531
22555
|
} catch (err) {
|
|
22532
|
-
logger$
|
|
22556
|
+
logger$6.critical('Error while checking element in allowElementCallback', err);
|
|
22533
22557
|
return false;
|
|
22534
22558
|
}
|
|
22535
22559
|
}
|
|
@@ -22546,7 +22570,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
|
22546
22570
|
return true;
|
|
22547
22571
|
}
|
|
22548
22572
|
} catch (err) {
|
|
22549
|
-
logger$
|
|
22573
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
22550
22574
|
}
|
|
22551
22575
|
}
|
|
22552
22576
|
return false;
|
|
@@ -22561,7 +22585,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
|
22561
22585
|
return true;
|
|
22562
22586
|
}
|
|
22563
22587
|
} catch (err) {
|
|
22564
|
-
logger$
|
|
22588
|
+
logger$6.critical('Error while checking element in blockElementCallback', err);
|
|
22565
22589
|
return true;
|
|
22566
22590
|
}
|
|
22567
22591
|
}
|
|
@@ -22575,7 +22599,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
|
22575
22599
|
return true;
|
|
22576
22600
|
}
|
|
22577
22601
|
} catch (err) {
|
|
22578
|
-
logger$
|
|
22602
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
22579
22603
|
}
|
|
22580
22604
|
}
|
|
22581
22605
|
}
|
|
@@ -23131,7 +23155,7 @@ function shouldMaskText(element, privacyConfig) {
|
|
|
23131
23155
|
*
|
|
23132
23156
|
*/
|
|
23133
23157
|
|
|
23134
|
-
var logger$
|
|
23158
|
+
var logger$5 = console_with_prefix('network-plugin');
|
|
23135
23159
|
|
|
23136
23160
|
/**
|
|
23137
23161
|
* Get the time origin for converting performance timestamps to absolute timestamps.
|
|
@@ -23283,7 +23307,7 @@ function truncateBody(str) {
|
|
|
23283
23307
|
return str;
|
|
23284
23308
|
}
|
|
23285
23309
|
if (str.length > MAX_BODY_SIZE) {
|
|
23286
|
-
logger$
|
|
23310
|
+
logger$5.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
|
|
23287
23311
|
return str.substring(0, MAX_BODY_SIZE) + '... [truncated]';
|
|
23288
23312
|
}
|
|
23289
23313
|
return str;
|
|
@@ -23297,7 +23321,7 @@ function truncateBody(str) {
|
|
|
23297
23321
|
*/
|
|
23298
23322
|
function initPerformanceObserver(cb, win, options) {
|
|
23299
23323
|
if (!win.PerformanceObserver) {
|
|
23300
|
-
logger$
|
|
23324
|
+
logger$5.error('PerformanceObserver not supported');
|
|
23301
23325
|
return function() {
|
|
23302
23326
|
//
|
|
23303
23327
|
};
|
|
@@ -23450,7 +23474,7 @@ function getRequestPerformanceEntry(win, initiatorType, url, after, before, atte
|
|
|
23450
23474
|
attempt = 0;
|
|
23451
23475
|
}
|
|
23452
23476
|
if (attempt > 10) {
|
|
23453
|
-
logger$
|
|
23477
|
+
logger$5.error('Cannot find performance entry');
|
|
23454
23478
|
return Promise.resolve(null);
|
|
23455
23479
|
}
|
|
23456
23480
|
var urlPerformanceEntries = /** @type {PerformanceResourceTiming[]} */ (
|
|
@@ -23571,7 +23595,7 @@ function initXhrObserver(cb, win, options) {
|
|
|
23571
23595
|
)
|
|
23572
23596
|
.then(function(entry) {
|
|
23573
23597
|
if (!entry) {
|
|
23574
|
-
logger$
|
|
23598
|
+
logger$5.error('Failed to get performance entry for XHR request to ' + req.url);
|
|
23575
23599
|
return;
|
|
23576
23600
|
}
|
|
23577
23601
|
/** @type {NetworkRequest} */
|
|
@@ -23591,7 +23615,7 @@ function initXhrObserver(cb, win, options) {
|
|
|
23591
23615
|
cb({ requests: [request] });
|
|
23592
23616
|
})
|
|
23593
23617
|
.catch(function(e) {
|
|
23594
|
-
logger$
|
|
23618
|
+
logger$5.error('Error recording XHR request to ' + req.url + ': ' + String(e));
|
|
23595
23619
|
});
|
|
23596
23620
|
});
|
|
23597
23621
|
|
|
@@ -23683,7 +23707,7 @@ function initFetchObserver(cb, win, options) {
|
|
|
23683
23707
|
})
|
|
23684
23708
|
.then(function(entry) {
|
|
23685
23709
|
if (!entry) {
|
|
23686
|
-
logger$
|
|
23710
|
+
logger$5.error('Failed to get performance entry for fetch request to ' + req.url);
|
|
23687
23711
|
return;
|
|
23688
23712
|
}
|
|
23689
23713
|
/** @type {NetworkRequest} */
|
|
@@ -23703,7 +23727,7 @@ function initFetchObserver(cb, win, options) {
|
|
|
23703
23727
|
cb({ requests: [request] });
|
|
23704
23728
|
})
|
|
23705
23729
|
.catch(function (e) {
|
|
23706
|
-
logger$
|
|
23730
|
+
logger$5.error('Error recording fetch request to ' + req.url + ': ' + String(e));
|
|
23707
23731
|
});
|
|
23708
23732
|
|
|
23709
23733
|
return originalFetchPromise;
|
|
@@ -23776,7 +23800,7 @@ var getRecordNetworkPlugin = function(options) {
|
|
|
23776
23800
|
*/
|
|
23777
23801
|
|
|
23778
23802
|
|
|
23779
|
-
var logger$
|
|
23803
|
+
var logger$4 = console_with_prefix('recorder');
|
|
23780
23804
|
var CompressionStream = win['CompressionStream'];
|
|
23781
23805
|
|
|
23782
23806
|
var RECORDER_BATCHER_LIB_CONFIG = {
|
|
@@ -23873,11 +23897,11 @@ var SessionRecording = function(options) {
|
|
|
23873
23897
|
|
|
23874
23898
|
// disable persistence if localStorage is not supported
|
|
23875
23899
|
// request-queue will automatically disable persistence if indexedDB fails to initialize
|
|
23876
|
-
var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
|
|
23900
|
+
var usePersistence = localStorageSupported(options.sharedLockStorage || getLocalStorage(), true) && !this.getConfig('disable_persistence');
|
|
23877
23901
|
|
|
23878
23902
|
// each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
|
|
23879
23903
|
this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
|
|
23880
|
-
this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
|
|
23904
|
+
this.queueStorage = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_EVENTS_STORE_NAME, RECORDER_VERSION_DATA);
|
|
23881
23905
|
this.batcher = new RequestBatcher(this.batcherKey, {
|
|
23882
23906
|
errorReporter: this.reportError.bind(this),
|
|
23883
23907
|
flushOnlyOnInterval: true,
|
|
@@ -23956,14 +23980,14 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
23956
23980
|
}
|
|
23957
23981
|
|
|
23958
23982
|
if (this._stopRecording !== null) {
|
|
23959
|
-
logger$
|
|
23983
|
+
logger$4.log('Recording already in progress, skipping startRecording.');
|
|
23960
23984
|
return;
|
|
23961
23985
|
}
|
|
23962
23986
|
|
|
23963
23987
|
this.recordMaxMs = this.getConfig('record_max_ms');
|
|
23964
23988
|
if (this.recordMaxMs > MAX_RECORDING_MS) {
|
|
23965
23989
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23966
|
-
logger$
|
|
23990
|
+
logger$4.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
23967
23991
|
}
|
|
23968
23992
|
|
|
23969
23993
|
if (!this.maxExpires) {
|
|
@@ -24027,7 +24051,7 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
24027
24051
|
);
|
|
24028
24052
|
}
|
|
24029
24053
|
|
|
24030
|
-
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$
|
|
24054
|
+
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$4);
|
|
24031
24055
|
|
|
24032
24056
|
try {
|
|
24033
24057
|
this._stopRecording = this._rrwebRecord({
|
|
@@ -24289,14 +24313,14 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
24289
24313
|
|
|
24290
24314
|
|
|
24291
24315
|
SessionRecording.prototype.reportError = function(msg, err) {
|
|
24292
|
-
logger$
|
|
24316
|
+
logger$4.error.apply(logger$4.error, arguments);
|
|
24293
24317
|
try {
|
|
24294
24318
|
if (!err && !(msg instanceof Error)) {
|
|
24295
24319
|
msg = new Error(msg);
|
|
24296
24320
|
}
|
|
24297
24321
|
this.getConfig('error_reporter')(msg, err);
|
|
24298
24322
|
} catch(err) {
|
|
24299
|
-
logger$
|
|
24323
|
+
logger$4.error(err);
|
|
24300
24324
|
}
|
|
24301
24325
|
};
|
|
24302
24326
|
|
|
@@ -24325,7 +24349,7 @@ SessionRecording.prototype._getRecordMinMs = function() {
|
|
|
24325
24349
|
var configValue = this.getConfig('record_min_ms');
|
|
24326
24350
|
|
|
24327
24351
|
if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
24328
|
-
logger$
|
|
24352
|
+
logger$4.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
24329
24353
|
return MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
24330
24354
|
}
|
|
24331
24355
|
|
|
@@ -24367,7 +24391,7 @@ SessionRecording.prototype._getMaskFn = function(shouldMaskFn, privacyConfig) {
|
|
|
24367
24391
|
*/
|
|
24368
24392
|
var RecordingRegistry = function (options) {
|
|
24369
24393
|
/** @type {IDBStorageWrapper} */
|
|
24370
|
-
this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
24394
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
24371
24395
|
this.errorReporter = options.errorReporter;
|
|
24372
24396
|
this.mixpanelInstance = options.mixpanelInstance;
|
|
24373
24397
|
this.sharedLockStorage = options.sharedLockStorage;
|
|
@@ -24488,7 +24512,7 @@ RecordingRegistry.prototype.flushInactiveRecordings = function () {
|
|
|
24488
24512
|
.catch(this.handleError.bind(this));
|
|
24489
24513
|
};
|
|
24490
24514
|
|
|
24491
|
-
var logger$
|
|
24515
|
+
var logger$3 = console_with_prefix('recorder');
|
|
24492
24516
|
|
|
24493
24517
|
/**
|
|
24494
24518
|
* Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
|
|
@@ -24504,7 +24528,7 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
|
|
|
24504
24528
|
*/
|
|
24505
24529
|
this.recordingRegistry = new RecordingRegistry({
|
|
24506
24530
|
mixpanelInstance: this.mixpanelInstance,
|
|
24507
|
-
errorReporter: logger$
|
|
24531
|
+
errorReporter: logger$3.error,
|
|
24508
24532
|
sharedLockStorage: sharedLockStorage
|
|
24509
24533
|
});
|
|
24510
24534
|
this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
|
|
@@ -24516,17 +24540,17 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
|
|
|
24516
24540
|
MixpanelRecorder.prototype.startRecording = function(options) {
|
|
24517
24541
|
options = options || {};
|
|
24518
24542
|
if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
|
|
24519
|
-
logger$
|
|
24543
|
+
logger$3.log('Recording already in progress, skipping startRecording.');
|
|
24520
24544
|
return;
|
|
24521
24545
|
}
|
|
24522
24546
|
|
|
24523
24547
|
var onIdleTimeout = function () {
|
|
24524
|
-
logger$
|
|
24548
|
+
logger$3.log('Idle timeout reached, restarting recording.');
|
|
24525
24549
|
this.resetRecording();
|
|
24526
24550
|
}.bind(this);
|
|
24527
24551
|
|
|
24528
24552
|
var onMaxLengthReached = function () {
|
|
24529
|
-
logger$
|
|
24553
|
+
logger$3.log('Max recording length reached, stopping recording.');
|
|
24530
24554
|
this.resetRecording();
|
|
24531
24555
|
}.bind(this);
|
|
24532
24556
|
|
|
@@ -24596,7 +24620,7 @@ MixpanelRecorder.prototype.resumeRecording = function (startNewIfInactive) {
|
|
|
24596
24620
|
} else if (startNewIfInactive) {
|
|
24597
24621
|
return this.startRecording({shouldStopBatcher: false});
|
|
24598
24622
|
} else {
|
|
24599
|
-
logger$
|
|
24623
|
+
logger$3.log('No resumable recording found.');
|
|
24600
24624
|
return null;
|
|
24601
24625
|
}
|
|
24602
24626
|
}.bind(this));
|
|
@@ -25261,7 +25285,7 @@ ShadowDOMObserver.prototype.observeShadowRoot = function(shadowRoot) {
|
|
|
25261
25285
|
observer.observe(shadowRoot, this.observerConfig);
|
|
25262
25286
|
this.shadowObservers.push(observer);
|
|
25263
25287
|
} catch (e) {
|
|
25264
|
-
logger$
|
|
25288
|
+
logger$6.critical('Error while observing shadow root', e);
|
|
25265
25289
|
}
|
|
25266
25290
|
};
|
|
25267
25291
|
|
|
@@ -25272,7 +25296,7 @@ ShadowDOMObserver.prototype.start = function() {
|
|
|
25272
25296
|
}
|
|
25273
25297
|
|
|
25274
25298
|
if (!weakSetSupported()) {
|
|
25275
|
-
logger$
|
|
25299
|
+
logger$6.critical('Shadow DOM observation unavailable: WeakSet not supported');
|
|
25276
25300
|
return;
|
|
25277
25301
|
}
|
|
25278
25302
|
|
|
@@ -25288,7 +25312,7 @@ ShadowDOMObserver.prototype.stop = function() {
|
|
|
25288
25312
|
try {
|
|
25289
25313
|
this.shadowObservers[i].disconnect();
|
|
25290
25314
|
} catch (e) {
|
|
25291
|
-
logger$
|
|
25315
|
+
logger$6.critical('Error while disconnecting shadow DOM observer', e);
|
|
25292
25316
|
}
|
|
25293
25317
|
}
|
|
25294
25318
|
this.shadowObservers = [];
|
|
@@ -25476,7 +25500,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
25476
25500
|
|
|
25477
25501
|
this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
|
|
25478
25502
|
} catch (e) {
|
|
25479
|
-
logger$
|
|
25503
|
+
logger$6.critical('Error while setting up mutation observer', e);
|
|
25480
25504
|
}
|
|
25481
25505
|
}
|
|
25482
25506
|
|
|
@@ -25491,7 +25515,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
25491
25515
|
);
|
|
25492
25516
|
this.shadowDOMObserver.start();
|
|
25493
25517
|
} catch (e) {
|
|
25494
|
-
logger$
|
|
25518
|
+
logger$6.critical('Error while setting up shadow DOM observer', e);
|
|
25495
25519
|
this.shadowDOMObserver = null;
|
|
25496
25520
|
}
|
|
25497
25521
|
}
|
|
@@ -25518,7 +25542,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25518
25542
|
try {
|
|
25519
25543
|
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
25520
25544
|
} catch (e) {
|
|
25521
|
-
logger$
|
|
25545
|
+
logger$6.critical('Error while removing event listener', e);
|
|
25522
25546
|
}
|
|
25523
25547
|
}
|
|
25524
25548
|
this.eventListeners = [];
|
|
@@ -25527,7 +25551,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25527
25551
|
try {
|
|
25528
25552
|
this.mutationObserver.disconnect();
|
|
25529
25553
|
} catch (e) {
|
|
25530
|
-
logger$
|
|
25554
|
+
logger$6.critical('Error while disconnecting mutation observer', e);
|
|
25531
25555
|
}
|
|
25532
25556
|
this.mutationObserver = null;
|
|
25533
25557
|
}
|
|
@@ -25536,7 +25560,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25536
25560
|
try {
|
|
25537
25561
|
this.shadowDOMObserver.stop();
|
|
25538
25562
|
} catch (e) {
|
|
25539
|
-
logger$
|
|
25563
|
+
logger$6.critical('Error while stopping shadow DOM observer', e);
|
|
25540
25564
|
}
|
|
25541
25565
|
this.shadowDOMObserver = null;
|
|
25542
25566
|
}
|
|
@@ -25614,7 +25638,7 @@ var Autocapture = function(mp) {
|
|
|
25614
25638
|
|
|
25615
25639
|
Autocapture.prototype.init = function() {
|
|
25616
25640
|
if (!minDOMApisSupported()) {
|
|
25617
|
-
logger$
|
|
25641
|
+
logger$6.critical('Autocapture unavailable: missing required DOM APIs');
|
|
25618
25642
|
return;
|
|
25619
25643
|
}
|
|
25620
25644
|
this.initPageListeners();
|
|
@@ -25654,7 +25678,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
25654
25678
|
try {
|
|
25655
25679
|
return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
|
|
25656
25680
|
} catch (err) {
|
|
25657
|
-
logger$
|
|
25681
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25658
25682
|
return true;
|
|
25659
25683
|
}
|
|
25660
25684
|
}
|
|
@@ -25667,7 +25691,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
25667
25691
|
try {
|
|
25668
25692
|
return urlMatchesRegexList(currentUrl, blockUrlRegexes);
|
|
25669
25693
|
} catch (err) {
|
|
25670
|
-
logger$
|
|
25694
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25671
25695
|
return true;
|
|
25672
25696
|
}
|
|
25673
25697
|
};
|
|
@@ -25805,7 +25829,7 @@ Autocapture.prototype._initScrollDepthTracking = function() {
|
|
|
25805
25829
|
return;
|
|
25806
25830
|
}
|
|
25807
25831
|
|
|
25808
|
-
logger$
|
|
25832
|
+
logger$6.log('Initializing scroll depth tracking');
|
|
25809
25833
|
|
|
25810
25834
|
this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
|
|
25811
25835
|
|
|
@@ -25831,7 +25855,7 @@ Autocapture.prototype.initClickTracking = function() {
|
|
|
25831
25855
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
|
|
25832
25856
|
return;
|
|
25833
25857
|
}
|
|
25834
|
-
logger$
|
|
25858
|
+
logger$6.log('Initializing click tracking');
|
|
25835
25859
|
|
|
25836
25860
|
this.listenerClick = function(ev) {
|
|
25837
25861
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
|
|
@@ -25850,7 +25874,7 @@ Autocapture.prototype.initDeadClickTracking = function() {
|
|
|
25850
25874
|
return;
|
|
25851
25875
|
}
|
|
25852
25876
|
|
|
25853
|
-
logger$
|
|
25877
|
+
logger$6.log('Initializing dead click tracking');
|
|
25854
25878
|
if (!this._deadClickTracker) {
|
|
25855
25879
|
this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
|
|
25856
25880
|
this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
|
|
@@ -25884,7 +25908,7 @@ Autocapture.prototype.initInputTracking = function() {
|
|
|
25884
25908
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
25885
25909
|
return;
|
|
25886
25910
|
}
|
|
25887
|
-
logger$
|
|
25911
|
+
logger$6.log('Initializing input tracking');
|
|
25888
25912
|
|
|
25889
25913
|
this.listenerChange = function(ev) {
|
|
25890
25914
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
@@ -25898,14 +25922,15 @@ Autocapture.prototype.initInputTracking = function() {
|
|
|
25898
25922
|
Autocapture.prototype.initPageviewTracking = function() {
|
|
25899
25923
|
win.removeEventListener(EV_MP_LOCATION_CHANGE, this.listenerLocationchange);
|
|
25900
25924
|
|
|
25901
|
-
if (!this.pageviewTrackingConfig()) {
|
|
25925
|
+
if (!this.pageviewTrackingConfig() && !this.mp.get_config('record_heatmap_data')) {
|
|
25902
25926
|
return;
|
|
25903
25927
|
}
|
|
25904
|
-
logger$
|
|
25928
|
+
logger$6.log('Initializing pageview tracking');
|
|
25905
25929
|
|
|
25906
25930
|
var previousTrackedUrl = '';
|
|
25907
25931
|
var tracked = false;
|
|
25908
|
-
if
|
|
25932
|
+
// Track initial pageview if pageview tracking enabled OR heatmap recording is active
|
|
25933
|
+
if ((this.pageviewTrackingConfig() || this.mp.is_recording_heatmap_data()) && !this.currentUrlBlocked()) {
|
|
25909
25934
|
tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
25910
25935
|
}
|
|
25911
25936
|
if (tracked) {
|
|
@@ -25921,6 +25946,10 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
25921
25946
|
var shouldTrack = false;
|
|
25922
25947
|
var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
25923
25948
|
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
25949
|
+
if (!trackPageviewOption && this.mp.is_recording_heatmap_data()) {
|
|
25950
|
+
trackPageviewOption = PAGEVIEW_OPTION_FULL_URL;
|
|
25951
|
+
}
|
|
25952
|
+
|
|
25924
25953
|
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
25925
25954
|
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
25926
25955
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
@@ -25936,7 +25965,7 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
25936
25965
|
}
|
|
25937
25966
|
if (didPathChange) {
|
|
25938
25967
|
this.lastScrollCheckpoint = 0;
|
|
25939
|
-
logger$
|
|
25968
|
+
logger$6.log('Path change: re-initializing scroll depth checkpoints');
|
|
25940
25969
|
}
|
|
25941
25970
|
}
|
|
25942
25971
|
}.bind(this));
|
|
@@ -25951,7 +25980,7 @@ Autocapture.prototype.initRageClickTracking = function() {
|
|
|
25951
25980
|
return;
|
|
25952
25981
|
}
|
|
25953
25982
|
|
|
25954
|
-
logger$
|
|
25983
|
+
logger$6.log('Initializing rage click tracking');
|
|
25955
25984
|
if (!this._rageClickTracker) {
|
|
25956
25985
|
this._rageClickTracker = new RageClickTracker();
|
|
25957
25986
|
}
|
|
@@ -25981,7 +26010,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
25981
26010
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
25982
26011
|
return;
|
|
25983
26012
|
}
|
|
25984
|
-
logger$
|
|
26013
|
+
logger$6.log('Initializing scroll tracking');
|
|
25985
26014
|
this.lastScrollCheckpoint = 0;
|
|
25986
26015
|
|
|
25987
26016
|
var scrollTrackFunction = function() {
|
|
@@ -26018,7 +26047,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
26018
26047
|
}
|
|
26019
26048
|
}
|
|
26020
26049
|
} catch (err) {
|
|
26021
|
-
logger$
|
|
26050
|
+
logger$6.critical('Error while calculating scroll percentage', err);
|
|
26022
26051
|
}
|
|
26023
26052
|
if (shouldTrack) {
|
|
26024
26053
|
this.mp.track(MP_EV_SCROLL, props);
|
|
@@ -26036,7 +26065,7 @@ Autocapture.prototype.initSubmitTracking = function() {
|
|
|
26036
26065
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
26037
26066
|
return;
|
|
26038
26067
|
}
|
|
26039
|
-
logger$
|
|
26068
|
+
logger$6.log('Initializing submit tracking');
|
|
26040
26069
|
|
|
26041
26070
|
this.listenerSubmit = function(ev) {
|
|
26042
26071
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
@@ -26058,7 +26087,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
|
|
|
26058
26087
|
return;
|
|
26059
26088
|
}
|
|
26060
26089
|
|
|
26061
|
-
logger$
|
|
26090
|
+
logger$6.log('Initializing page visibility tracking.');
|
|
26062
26091
|
this._initScrollDepthTracking();
|
|
26063
26092
|
var previousTrackedUrl = _.info.currentUrl();
|
|
26064
26093
|
|
|
@@ -26143,10 +26172,183 @@ var getTargetingPromise = function(loadExtraBundle, targetingSrc) {
|
|
|
26143
26172
|
return win[TARGETING_GLOBAL_NAME];
|
|
26144
26173
|
};
|
|
26145
26174
|
|
|
26175
|
+
var logger$2 = console_with_prefix('flags');
|
|
26176
|
+
|
|
26177
|
+
var MIXPANEL_FLAGS_DB_NAME = 'mixpanelFlagsDb';
|
|
26178
|
+
var FLAGS_STORE_NAME = 'mixpanelFlags';
|
|
26179
|
+
|
|
26180
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
26181
|
+
var FLAGS_VERSION_DATA = { version: 1, storeNames: [FLAGS_STORE_NAME] };
|
|
26182
|
+
|
|
26183
|
+
var PERSISTED_VARIANTS_KEY_PREFIX = 'persisted_variants_for_';
|
|
26184
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
26185
|
+
|
|
26186
|
+
var VariantLookupPolicy = Object.freeze({
|
|
26187
|
+
NETWORK_ONLY: 'networkOnly',
|
|
26188
|
+
NETWORK_FIRST: 'networkFirst',
|
|
26189
|
+
PERSISTENCE_UNTIL_NETWORK_SUCCESS: 'persistenceUntilNetworkSuccess'
|
|
26190
|
+
});
|
|
26191
|
+
|
|
26192
|
+
var VALID_POLICIES = [
|
|
26193
|
+
VariantLookupPolicy.NETWORK_ONLY,
|
|
26194
|
+
VariantLookupPolicy.NETWORK_FIRST,
|
|
26195
|
+
VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS
|
|
26196
|
+
];
|
|
26197
|
+
|
|
26198
|
+
/**
|
|
26199
|
+
* Module for handling the storage and retrieval of persisted feature flag variants.
|
|
26200
|
+
*/
|
|
26201
|
+
var FeatureFlagPersistence = function(persistenceConfig, token, isGloballyDisabled) {
|
|
26202
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_FLAGS_DB_NAME, FLAGS_STORE_NAME, FLAGS_VERSION_DATA);
|
|
26203
|
+
this.persistenceConfig = persistenceConfig;
|
|
26204
|
+
this.persistedVariantsKey = PERSISTED_VARIANTS_KEY_PREFIX + token;
|
|
26205
|
+
this.isGloballyDisabled = isGloballyDisabled || function() { return false; };
|
|
26206
|
+
};
|
|
26207
|
+
|
|
26208
|
+
FeatureFlagPersistence.prototype.getPolicy = function() {
|
|
26209
|
+
if (this.isGloballyDisabled() || !this._isConfigValid()) {
|
|
26210
|
+
return VariantLookupPolicy.NETWORK_ONLY;
|
|
26211
|
+
}
|
|
26212
|
+
return this.persistenceConfig['variantLookupPolicy'];
|
|
26213
|
+
};
|
|
26214
|
+
|
|
26215
|
+
FeatureFlagPersistence.prototype.getTtlMs = function() {
|
|
26216
|
+
if (!this._isConfigValid()) {
|
|
26217
|
+
return DEFAULT_TTL_MS;
|
|
26218
|
+
}
|
|
26219
|
+
var configuredTtl = this.persistenceConfig['persistenceTtlMs'];
|
|
26220
|
+
return (configuredTtl === undefined || configuredTtl === null) ? DEFAULT_TTL_MS : configuredTtl;
|
|
26221
|
+
};
|
|
26222
|
+
|
|
26223
|
+
FeatureFlagPersistence.prototype._isConfigValid = function() {
|
|
26224
|
+
var config = this.persistenceConfig;
|
|
26225
|
+
if (!config) {
|
|
26226
|
+
return false;
|
|
26227
|
+
}
|
|
26228
|
+
|
|
26229
|
+
if (VALID_POLICIES.indexOf(config['variantLookupPolicy']) === -1) {
|
|
26230
|
+
logger$2.error('Invalid variantLookupPolicy:', config['variantLookupPolicy']);
|
|
26231
|
+
return false;
|
|
26232
|
+
}
|
|
26233
|
+
|
|
26234
|
+
if (config['persistenceTtlMs'] !== undefined &&
|
|
26235
|
+
config['persistenceTtlMs'] !== null &&
|
|
26236
|
+
config['persistenceTtlMs'] <= 0) {
|
|
26237
|
+
logger$2.error('If provided, persistenceTtlMs must be a positive number. Provided value:', config['persistenceTtlMs']);
|
|
26238
|
+
return false;
|
|
26239
|
+
}
|
|
26240
|
+
|
|
26241
|
+
return true;
|
|
26242
|
+
};
|
|
26243
|
+
|
|
26244
|
+
FeatureFlagPersistence.prototype.loadFlagsFromStorage = function(context) {
|
|
26245
|
+
var clearAndReturnNull = _.bind(function() {
|
|
26246
|
+
return this.clear().then(function() { return null; }).catch(function() { return null; });
|
|
26247
|
+
}, this);
|
|
26248
|
+
|
|
26249
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26250
|
+
return clearAndReturnNull();
|
|
26251
|
+
}
|
|
26252
|
+
|
|
26253
|
+
var ttlMs = this.getTtlMs();
|
|
26254
|
+
|
|
26255
|
+
return this.idb.init().then(_.bind(function() {
|
|
26256
|
+
return this.idb.getItem(this.persistedVariantsKey);
|
|
26257
|
+
}, this)).then(_.bind(function(data) {
|
|
26258
|
+
if (!data) {
|
|
26259
|
+
logger$2.log('No persisted variants found in IndexedDB');
|
|
26260
|
+
return null;
|
|
26261
|
+
}
|
|
26262
|
+
|
|
26263
|
+
if (ttlMs && Date.now() - data['persistedAt'] >= ttlMs) {
|
|
26264
|
+
logger$2.log('Persisted variants are expiring');
|
|
26265
|
+
return null;
|
|
26266
|
+
}
|
|
26267
|
+
|
|
26268
|
+
if (!context || data['distinctId'] !== context['distinct_id']) {
|
|
26269
|
+
logger$2.log('Persisted variants found, but for a different distinct_id so clearing.');
|
|
26270
|
+
return clearAndReturnNull();
|
|
26271
|
+
}
|
|
26272
|
+
|
|
26273
|
+
var persistedFlags = new Map();
|
|
26274
|
+
_.each(data['flagVariants'], function(variantData, key) {
|
|
26275
|
+
persistedFlags.set(key, {
|
|
26276
|
+
'key': variantData['variant_key'],
|
|
26277
|
+
'value': variantData['variant_value'],
|
|
26278
|
+
'experiment_id': variantData['experiment_id'],
|
|
26279
|
+
'is_experiment_active': variantData['is_experiment_active'],
|
|
26280
|
+
'is_qa_tester': variantData['is_qa_tester'],
|
|
26281
|
+
'variant_source': 'persistence',
|
|
26282
|
+
'persisted_at_in_ms': data['persistedAt'],
|
|
26283
|
+
'ttl_in_ms': ttlMs
|
|
26284
|
+
});
|
|
26285
|
+
});
|
|
26286
|
+
|
|
26287
|
+
logger$2.log('Loaded', persistedFlags.size, 'variants from IndexedDB for distinct_id', data['distinctId']);
|
|
26288
|
+
|
|
26289
|
+
return {
|
|
26290
|
+
flags: persistedFlags,
|
|
26291
|
+
pendingFirstTimeEvents: data['pendingFirstTimeEvents'] || {},
|
|
26292
|
+
persistedAtMs: data['persistedAt'],
|
|
26293
|
+
ttlMs: ttlMs
|
|
26294
|
+
};
|
|
26295
|
+
}, this)).catch(_.bind(function(error) {
|
|
26296
|
+
logger$2.error('Failed to load persisted variants from IndexedDB, so clearing', error);
|
|
26297
|
+
return clearAndReturnNull();
|
|
26298
|
+
}, this));
|
|
26299
|
+
};
|
|
26300
|
+
|
|
26301
|
+
FeatureFlagPersistence.prototype.save = function(context, flagsMap, pendingFirstTimeEvents) {
|
|
26302
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26303
|
+
return Promise.resolve();
|
|
26304
|
+
}
|
|
26305
|
+
|
|
26306
|
+
var flagVariants = {};
|
|
26307
|
+
flagsMap.forEach(function(variant, key) {
|
|
26308
|
+
flagVariants[key] = {
|
|
26309
|
+
'variant_key': variant['key'],
|
|
26310
|
+
'variant_value': variant['value'],
|
|
26311
|
+
'experiment_id': variant['experiment_id'],
|
|
26312
|
+
'is_experiment_active': variant['is_experiment_active'],
|
|
26313
|
+
'is_qa_tester': variant['is_qa_tester']
|
|
26314
|
+
};
|
|
26315
|
+
});
|
|
26316
|
+
|
|
26317
|
+
var data = {
|
|
26318
|
+
'persistedAt': Date.now(),
|
|
26319
|
+
'distinctId': context && context['distinct_id'],
|
|
26320
|
+
'context': context,
|
|
26321
|
+
'flagVariants': flagVariants,
|
|
26322
|
+
'pendingFirstTimeEvents': pendingFirstTimeEvents || {}
|
|
26323
|
+
};
|
|
26324
|
+
|
|
26325
|
+
return this.idb.init().then(_.bind(function() {
|
|
26326
|
+
return this.idb.setItem(this.persistedVariantsKey, data);
|
|
26327
|
+
}, this)).then(function() {
|
|
26328
|
+
logger$2.log('Saved', flagsMap.size, 'variants to IndexedDB for distinct_id', data['distinctId']);
|
|
26329
|
+
}).catch(function(error) {
|
|
26330
|
+
logger$2.error('Failed to persist variants to IndexedDB:', error);
|
|
26331
|
+
});
|
|
26332
|
+
};
|
|
26333
|
+
|
|
26334
|
+
FeatureFlagPersistence.prototype.clear = function() {
|
|
26335
|
+
if (this.isGloballyDisabled()) {
|
|
26336
|
+
return Promise.resolve();
|
|
26337
|
+
}
|
|
26338
|
+
return this.idb.init().then(_.bind(function() {
|
|
26339
|
+
return this.idb.removeItem(this.persistedVariantsKey);
|
|
26340
|
+
}, this)).then(function() {
|
|
26341
|
+
logger$2.log('Cleared persisted variants from IndexedDB');
|
|
26342
|
+
}).catch(function(error) {
|
|
26343
|
+
logger$2.error('Failed to clear persisted variants from IndexedDB:', error);
|
|
26344
|
+
});
|
|
26345
|
+
};
|
|
26346
|
+
|
|
26146
26347
|
var logger$1 = console_with_prefix('flags');
|
|
26147
26348
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
26148
26349
|
|
|
26149
26350
|
var CONFIG_CONTEXT = 'context';
|
|
26351
|
+
var CONFIG_PERSISTENCE = 'persistence';
|
|
26150
26352
|
var CONFIG_DEFAULTS = {};
|
|
26151
26353
|
CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
26152
26354
|
|
|
@@ -26169,6 +26371,13 @@ var getFlagKeyFromPendingEventKey = function(eventKey) {
|
|
|
26169
26371
|
return eventKey.split(':')[0];
|
|
26170
26372
|
};
|
|
26171
26373
|
|
|
26374
|
+
var withFallbackSource = function(fallback) {
|
|
26375
|
+
if (_.isObject(fallback)) {
|
|
26376
|
+
return _.extend({}, fallback, {'variant_source': 'fallback'});
|
|
26377
|
+
}
|
|
26378
|
+
return {'value': fallback, 'variant_source': 'fallback'};
|
|
26379
|
+
};
|
|
26380
|
+
|
|
26172
26381
|
/**
|
|
26173
26382
|
* FeatureFlagManager: support for Mixpanel's feature flagging product
|
|
26174
26383
|
* @constructor
|
|
@@ -26191,13 +26400,63 @@ FeatureFlagManager.prototype.init = function() {
|
|
|
26191
26400
|
}
|
|
26192
26401
|
|
|
26193
26402
|
this.flags = null;
|
|
26194
|
-
this.fetchFlags().catch(function() {
|
|
26195
|
-
logger$1.error('Error fetching flags during init');
|
|
26196
|
-
});
|
|
26197
|
-
|
|
26198
26403
|
this.trackedFeatures = new Set();
|
|
26199
26404
|
this.pendingFirstTimeEvents = {};
|
|
26200
26405
|
this.activatedFirstTimeEvents = {};
|
|
26406
|
+
this._loadedPersistedAtMs = null;
|
|
26407
|
+
this._loadedTtlMs = null;
|
|
26408
|
+
|
|
26409
|
+
this.persistence = new FeatureFlagPersistence(
|
|
26410
|
+
this.getConfig(CONFIG_PERSISTENCE),
|
|
26411
|
+
this.getMpConfig('token'),
|
|
26412
|
+
_.bind(function() { return this.getMpConfig('disable_persistence'); }, this)
|
|
26413
|
+
);
|
|
26414
|
+
|
|
26415
|
+
this.persistenceLoadedPromise = this.persistence.loadFlagsFromStorage(this._buildContext())
|
|
26416
|
+
.then(_.bind(function(loaded) {
|
|
26417
|
+
if (loaded) {
|
|
26418
|
+
this.flags = loaded.flags;
|
|
26419
|
+
this.pendingFirstTimeEvents = loaded.pendingFirstTimeEvents;
|
|
26420
|
+
this._loadedPersistedAtMs = loaded.persistedAtMs;
|
|
26421
|
+
this._loadedTtlMs = loaded.ttlMs;
|
|
26422
|
+
}
|
|
26423
|
+
}, this));
|
|
26424
|
+
|
|
26425
|
+
return this.persistenceLoadedPromise
|
|
26426
|
+
.then(_.bind(function() {
|
|
26427
|
+
return this.fetchFlags();
|
|
26428
|
+
}, this))
|
|
26429
|
+
.catch(function() {
|
|
26430
|
+
logger$1.error('Error initializing feature flags');
|
|
26431
|
+
});
|
|
26432
|
+
};
|
|
26433
|
+
|
|
26434
|
+
FeatureFlagManager.prototype._buildContext = function() {
|
|
26435
|
+
return _.extend(
|
|
26436
|
+
{'distinct_id': this.getMpProperty('distinct_id'), 'device_id': this.getMpProperty('$device_id')},
|
|
26437
|
+
this.getConfig(CONFIG_CONTEXT)
|
|
26438
|
+
);
|
|
26439
|
+
};
|
|
26440
|
+
|
|
26441
|
+
FeatureFlagManager.prototype.reset = function() {
|
|
26442
|
+
if (!this.persistence) {
|
|
26443
|
+
return Promise.resolve();
|
|
26444
|
+
}
|
|
26445
|
+
|
|
26446
|
+
this.flags = null;
|
|
26447
|
+
this.pendingFirstTimeEvents = {};
|
|
26448
|
+
this.activatedFirstTimeEvents = {};
|
|
26449
|
+
this.trackedFeatures = new Set();
|
|
26450
|
+
this.fetchPromise = null;
|
|
26451
|
+
this._fetchInProgressStartTime = null;
|
|
26452
|
+
this._loadedPersistedAtMs = null;
|
|
26453
|
+
this._loadedTtlMs = null;
|
|
26454
|
+
|
|
26455
|
+
return this.persistence.clear().then(_.bind(function() {
|
|
26456
|
+
return this.fetchFlags();
|
|
26457
|
+
}, this)).catch(function() {
|
|
26458
|
+
logger$1.error('Error during flags reset');
|
|
26459
|
+
});
|
|
26201
26460
|
};
|
|
26202
26461
|
|
|
26203
26462
|
FeatureFlagManager.prototype.getFullConfig = function() {
|
|
@@ -26254,12 +26513,11 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26254
26513
|
return Promise.resolve();
|
|
26255
26514
|
}
|
|
26256
26515
|
|
|
26257
|
-
var
|
|
26258
|
-
var
|
|
26516
|
+
var context = this._buildContext();
|
|
26517
|
+
var distinctId = context['distinct_id'];
|
|
26259
26518
|
var traceparent = generateTraceparent();
|
|
26260
26519
|
logger$1.log('Fetching flags for distinct ID: ' + distinctId);
|
|
26261
26520
|
|
|
26262
|
-
var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
|
|
26263
26521
|
var searchParams = new URLSearchParams();
|
|
26264
26522
|
searchParams.set('context', JSON.stringify(context));
|
|
26265
26523
|
searchParams.set('token', this.getMpConfig('token'));
|
|
@@ -26309,7 +26567,8 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26309
26567
|
'value': data['variant_value'],
|
|
26310
26568
|
'experiment_id': data['experiment_id'],
|
|
26311
26569
|
'is_experiment_active': data['is_experiment_active'],
|
|
26312
|
-
'is_qa_tester': data['is_qa_tester']
|
|
26570
|
+
'is_qa_tester': data['is_qa_tester'],
|
|
26571
|
+
'variant_source': 'network'
|
|
26313
26572
|
});
|
|
26314
26573
|
}
|
|
26315
26574
|
}, this);
|
|
@@ -26351,10 +26610,15 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26351
26610
|
}
|
|
26352
26611
|
|
|
26353
26612
|
this.flags = flags;
|
|
26613
|
+
this.trackedFeatures = new Set();
|
|
26354
26614
|
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
26615
|
+
this._loadedPersistedAtMs = null;
|
|
26616
|
+
this._loadedTtlMs = null;
|
|
26355
26617
|
this._traceparent = traceparent;
|
|
26356
26618
|
|
|
26357
26619
|
this._loadTargetingIfNeeded();
|
|
26620
|
+
|
|
26621
|
+
this.persistence.save(context, this.flags, this.pendingFirstTimeEvents);
|
|
26358
26622
|
}.bind(this)).catch(function(error) {
|
|
26359
26623
|
if (this._fetchInProgressStartTime) {
|
|
26360
26624
|
this.markFetchComplete();
|
|
@@ -26514,6 +26778,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
26514
26778
|
};
|
|
26515
26779
|
|
|
26516
26780
|
this.flags.set(flagKey, newVariant);
|
|
26781
|
+
this.trackedFeatures.delete(flagKey);
|
|
26517
26782
|
this.activatedFirstTimeEvents[eventKey] = true;
|
|
26518
26783
|
|
|
26519
26784
|
this.recordFirstTimeEvent(
|
|
@@ -26563,35 +26828,106 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
|
|
|
26563
26828
|
};
|
|
26564
26829
|
|
|
26565
26830
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
26566
|
-
if (!this.
|
|
26831
|
+
if (!this.persistenceLoadedPromise) {
|
|
26567
26832
|
return new Promise(function(resolve) {
|
|
26568
26833
|
logger$1.critical('Feature Flags not initialized');
|
|
26569
|
-
resolve(fallback);
|
|
26834
|
+
resolve(withFallbackSource(fallback));
|
|
26570
26835
|
});
|
|
26571
26836
|
}
|
|
26572
26837
|
|
|
26573
|
-
|
|
26574
|
-
|
|
26575
|
-
|
|
26576
|
-
|
|
26577
|
-
|
|
26578
|
-
|
|
26838
|
+
var policy = this.persistence.getPolicy();
|
|
26839
|
+
|
|
26840
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26841
|
+
// 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.
|
|
26842
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26843
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26844
|
+
return this.getVariantSync(featureName, fallback);
|
|
26845
|
+
}
|
|
26846
|
+
if (!this.fetchPromise) {
|
|
26847
|
+
return withFallbackSource(fallback);
|
|
26848
|
+
}
|
|
26849
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26850
|
+
return this.getVariantSync(featureName, fallback);
|
|
26851
|
+
}, this)).catch(function(error) {
|
|
26852
|
+
logger$1.error(error);
|
|
26853
|
+
return withFallbackSource(fallback);
|
|
26854
|
+
});
|
|
26855
|
+
}
|
|
26856
|
+
|
|
26857
|
+
var serve = _.bind(function() { return this.getVariantSync(featureName, fallback); }, this);
|
|
26858
|
+
if (!this.fetchPromise) {
|
|
26859
|
+
return withFallbackSource(fallback);
|
|
26860
|
+
}
|
|
26861
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26862
|
+
}, this));
|
|
26863
|
+
};
|
|
26864
|
+
|
|
26865
|
+
FeatureFlagManager.prototype._loadedPersistenceIsStale = function() {
|
|
26866
|
+
if (!this._loadedPersistedAtMs || !this._loadedTtlMs) {
|
|
26867
|
+
return false;
|
|
26868
|
+
}
|
|
26869
|
+
return Date.now() - this._loadedPersistedAtMs >= this._loadedTtlMs;
|
|
26579
26870
|
};
|
|
26580
26871
|
|
|
26581
26872
|
FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
|
|
26873
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26874
|
+
logger$1.log('Loaded persisted variants are past TTL so returning fallback for "' + featureName + '"');
|
|
26875
|
+
return withFallbackSource(fallback);
|
|
26876
|
+
}
|
|
26582
26877
|
if (!this.areFlagsReady()) {
|
|
26583
26878
|
logger$1.log('Flags not loaded yet');
|
|
26584
|
-
return fallback;
|
|
26879
|
+
return withFallbackSource(fallback);
|
|
26585
26880
|
}
|
|
26586
26881
|
var feature = this.flags.get(featureName);
|
|
26587
26882
|
if (!feature) {
|
|
26588
26883
|
logger$1.log('No flag found: "' + featureName + '"');
|
|
26589
|
-
return fallback;
|
|
26884
|
+
return withFallbackSource(fallback);
|
|
26590
26885
|
}
|
|
26591
26886
|
this.trackFeatureCheck(featureName, feature);
|
|
26592
26887
|
return feature;
|
|
26593
26888
|
};
|
|
26594
26889
|
|
|
26890
|
+
FeatureFlagManager.prototype.getAllVariants = function() {
|
|
26891
|
+
if (!this.persistenceLoadedPromise) {
|
|
26892
|
+
logger$1.critical('Feature Flags not initialized');
|
|
26893
|
+
return Promise.resolve(new Map());
|
|
26894
|
+
}
|
|
26895
|
+
|
|
26896
|
+
var policy = this.persistence.getPolicy();
|
|
26897
|
+
|
|
26898
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26899
|
+
// 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.
|
|
26900
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26901
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26902
|
+
return this.getAllVariantsSync();
|
|
26903
|
+
}
|
|
26904
|
+
if (!this.fetchPromise) {
|
|
26905
|
+
return new Map();
|
|
26906
|
+
}
|
|
26907
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26908
|
+
return this.getAllVariantsSync();
|
|
26909
|
+
}, this)).catch(function(error) {
|
|
26910
|
+
logger$1.error(error);
|
|
26911
|
+
return new Map();
|
|
26912
|
+
});
|
|
26913
|
+
}
|
|
26914
|
+
|
|
26915
|
+
var serve = _.bind(this.getAllVariantsSync, this);
|
|
26916
|
+
if (!this.fetchPromise) {
|
|
26917
|
+
return new Map();
|
|
26918
|
+
}
|
|
26919
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26920
|
+
}, this));
|
|
26921
|
+
};
|
|
26922
|
+
|
|
26923
|
+
FeatureFlagManager.prototype.getAllVariantsSync = function() {
|
|
26924
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26925
|
+
logger$1.log('Loaded persisted variants are past TTL so returning empty Map');
|
|
26926
|
+
return new Map();
|
|
26927
|
+
}
|
|
26928
|
+
return this.flags || new Map();
|
|
26929
|
+
};
|
|
26930
|
+
|
|
26595
26931
|
FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackValue) {
|
|
26596
26932
|
return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
|
|
26597
26933
|
return feature['value'];
|
|
@@ -26630,6 +26966,10 @@ FeatureFlagManager.prototype.isEnabledSync = function(featureName, fallbackValue
|
|
|
26630
26966
|
return val;
|
|
26631
26967
|
};
|
|
26632
26968
|
|
|
26969
|
+
function isPresent(v) {
|
|
26970
|
+
return v !== undefined && v !== null;
|
|
26971
|
+
}
|
|
26972
|
+
|
|
26633
26973
|
FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature) {
|
|
26634
26974
|
if (this.trackedFeatures.has(featureName)) {
|
|
26635
26975
|
return;
|
|
@@ -26640,21 +26980,30 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
26640
26980
|
'Experiment name': featureName,
|
|
26641
26981
|
'Variant name': feature['key'],
|
|
26642
26982
|
'$experiment_type': 'feature_flag',
|
|
26643
|
-
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
26644
|
-
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
26983
|
+
'Variant fetch start time': isPresent(this._fetchStartTime) ? new Date(this._fetchStartTime).toISOString() : null,
|
|
26984
|
+
'Variant fetch complete time': isPresent(this._fetchCompleteTime) ? new Date(this._fetchCompleteTime).toISOString() : null,
|
|
26645
26985
|
'Variant fetch latency (ms)': this._fetchLatency,
|
|
26646
26986
|
'Variant fetch traceparent': this._traceparent,
|
|
26647
26987
|
};
|
|
26648
26988
|
|
|
26649
|
-
if (feature['experiment_id']
|
|
26989
|
+
if (isPresent(feature['experiment_id'])) {
|
|
26650
26990
|
trackingProperties['$experiment_id'] = feature['experiment_id'];
|
|
26651
26991
|
}
|
|
26652
|
-
if (feature['is_experiment_active']
|
|
26992
|
+
if (isPresent(feature['is_experiment_active'])) {
|
|
26653
26993
|
trackingProperties['$is_experiment_active'] = feature['is_experiment_active'];
|
|
26654
26994
|
}
|
|
26655
|
-
if (feature['is_qa_tester']
|
|
26995
|
+
if (isPresent(feature['is_qa_tester'])) {
|
|
26656
26996
|
trackingProperties['$is_qa_tester'] = feature['is_qa_tester'];
|
|
26657
26997
|
}
|
|
26998
|
+
if (isPresent(feature['variant_source'])) {
|
|
26999
|
+
trackingProperties['$variant_source'] = feature['variant_source'];
|
|
27000
|
+
}
|
|
27001
|
+
if (isPresent(feature['persisted_at_in_ms'])) {
|
|
27002
|
+
trackingProperties['$persisted_at_in_ms'] = feature['persisted_at_in_ms'];
|
|
27003
|
+
}
|
|
27004
|
+
if (isPresent(feature['ttl_in_ms'])) {
|
|
27005
|
+
trackingProperties['$ttl_in_ms'] = feature['ttl_in_ms'];
|
|
27006
|
+
}
|
|
26658
27007
|
|
|
26659
27008
|
this.track('$experiment_started', trackingProperties);
|
|
26660
27009
|
};
|
|
@@ -26678,6 +27027,8 @@ safewrapClass(FeatureFlagManager);
|
|
|
26678
27027
|
FeatureFlagManager.prototype['are_flags_ready'] = FeatureFlagManager.prototype.areFlagsReady;
|
|
26679
27028
|
FeatureFlagManager.prototype['get_variant'] = FeatureFlagManager.prototype.getVariant;
|
|
26680
27029
|
FeatureFlagManager.prototype['get_variant_sync'] = FeatureFlagManager.prototype.getVariantSync;
|
|
27030
|
+
FeatureFlagManager.prototype['get_all_variants'] = FeatureFlagManager.prototype.getAllVariants;
|
|
27031
|
+
FeatureFlagManager.prototype['get_all_variants_sync'] = FeatureFlagManager.prototype.getAllVariantsSync;
|
|
26681
27032
|
FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype.getVariantValue;
|
|
26682
27033
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
26683
27034
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
@@ -26730,7 +27081,7 @@ RecorderManager.prototype.shouldLoadRecorder = function() {
|
|
|
26730
27081
|
return PromisePolyfill.resolve(false);
|
|
26731
27082
|
}
|
|
26732
27083
|
|
|
26733
|
-
var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
27084
|
+
var recording_registry_idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
26734
27085
|
var tab_id = this.getTabId();
|
|
26735
27086
|
return recording_registry_idb.init()
|
|
26736
27087
|
.then(function () {
|
|
@@ -28657,6 +29008,7 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28657
29008
|
'disable_all_events': false,
|
|
28658
29009
|
'identify_called': false
|
|
28659
29010
|
};
|
|
29011
|
+
this._remote_settings_strict_disabled = false;
|
|
28660
29012
|
|
|
28661
29013
|
// set up request queueing/batching
|
|
28662
29014
|
this.request_batchers = {};
|
|
@@ -28731,9 +29083,6 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28731
29083
|
this.flags.init();
|
|
28732
29084
|
this['flags'] = this.flags;
|
|
28733
29085
|
|
|
28734
|
-
this.autocapture = new Autocapture(this);
|
|
28735
|
-
this.autocapture.init();
|
|
28736
|
-
|
|
28737
29086
|
this._init_tab_id();
|
|
28738
29087
|
|
|
28739
29088
|
// Based on remote_settings_mode, fetch remote settings and then start session recording if applicable
|
|
@@ -28745,6 +29094,9 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28745
29094
|
} else {
|
|
28746
29095
|
this.__session_recording_init_promise = this._check_and_start_session_recording();
|
|
28747
29096
|
}
|
|
29097
|
+
|
|
29098
|
+
this.autocapture = new Autocapture(this);
|
|
29099
|
+
this.autocapture.init();
|
|
28748
29100
|
};
|
|
28749
29101
|
|
|
28750
29102
|
/**
|
|
@@ -28791,9 +29143,19 @@ MixpanelLib.prototype._check_and_start_session_recording = addOptOutCheckMixpane
|
|
|
28791
29143
|
return this.recorderManager.checkAndStartSessionRecording(force_start);
|
|
28792
29144
|
});
|
|
28793
29145
|
|
|
28794
|
-
MixpanelLib.prototype._start_recording_on_event = function(event_name, properties) {
|
|
28795
|
-
|
|
28796
|
-
|
|
29146
|
+
MixpanelLib.prototype._start_recording_on_event = safewrap(function(event_name, properties) {
|
|
29147
|
+
// Wait for recording init to complete before evaluating event triggers.
|
|
29148
|
+
// This ensures recording_event_triggers config is fully loaded when remote settings are used.
|
|
29149
|
+
if (this.__session_recording_init_promise) {
|
|
29150
|
+
this.__session_recording_init_promise.then(_.bind(function() {
|
|
29151
|
+
// In strict mode, skip recording if remote settings failed
|
|
29152
|
+
if (this._remote_settings_strict_disabled) {
|
|
29153
|
+
return;
|
|
29154
|
+
}
|
|
29155
|
+
return this.recorderManager.startRecordingOnEvent(event_name, properties);
|
|
29156
|
+
}, this));
|
|
29157
|
+
}
|
|
29158
|
+
});
|
|
28797
29159
|
|
|
28798
29160
|
MixpanelLib.prototype.start_session_recording = function () {
|
|
28799
29161
|
return this._check_and_start_session_recording(true);
|
|
@@ -29092,6 +29454,7 @@ MixpanelLib.prototype._fetch_remote_settings = function(mode) {
|
|
|
29092
29454
|
var disableRecordingIfStrict = function() {
|
|
29093
29455
|
if (mode === 'strict') {
|
|
29094
29456
|
self.set_config({'record_sessions_percent': 0});
|
|
29457
|
+
self._remote_settings_strict_disabled = true;
|
|
29095
29458
|
}
|
|
29096
29459
|
};
|
|
29097
29460
|
|
|
@@ -29717,6 +30080,10 @@ MixpanelLib.prototype.track_pageview = addOptOutCheckMixpanelLib(function(proper
|
|
|
29717
30080
|
properties
|
|
29718
30081
|
);
|
|
29719
30082
|
|
|
30083
|
+
if (this.is_recording_heatmap_data()) {
|
|
30084
|
+
event_properties['$captured_for_heatmap'] = true;
|
|
30085
|
+
}
|
|
30086
|
+
|
|
29720
30087
|
return this.track(event_name, event_properties);
|
|
29721
30088
|
});
|
|
29722
30089
|
|
|
@@ -30060,6 +30427,7 @@ MixpanelLib.prototype.reset = function() {
|
|
|
30060
30427
|
'$device_id': uuid
|
|
30061
30428
|
}, '');
|
|
30062
30429
|
this._check_and_start_session_recording();
|
|
30430
|
+
this.flags.reset();
|
|
30063
30431
|
};
|
|
30064
30432
|
|
|
30065
30433
|
/**
|