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
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.80.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 = {
|
|
@@ -23870,14 +23894,15 @@ var SessionRecording = function(options) {
|
|
|
23870
23894
|
|
|
23871
23895
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23872
23896
|
this.recordMinMs = 0;
|
|
23897
|
+
this._recordMinMsCheckStart = null;
|
|
23873
23898
|
|
|
23874
23899
|
// disable persistence if localStorage is not supported
|
|
23875
23900
|
// request-queue will automatically disable persistence if indexedDB fails to initialize
|
|
23876
|
-
var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
|
|
23901
|
+
var usePersistence = localStorageSupported(options.sharedLockStorage || getLocalStorage(), true) && !this.getConfig('disable_persistence');
|
|
23877
23902
|
|
|
23878
23903
|
// each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
|
|
23879
23904
|
this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
|
|
23880
|
-
this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
|
|
23905
|
+
this.queueStorage = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_EVENTS_STORE_NAME, RECORDER_VERSION_DATA);
|
|
23881
23906
|
this.batcher = new RequestBatcher(this.batcherKey, {
|
|
23882
23907
|
errorReporter: this.reportError.bind(this),
|
|
23883
23908
|
flushOnlyOnInterval: true,
|
|
@@ -23956,14 +23981,14 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
23956
23981
|
}
|
|
23957
23982
|
|
|
23958
23983
|
if (this._stopRecording !== null) {
|
|
23959
|
-
logger$
|
|
23984
|
+
logger$4.log('Recording already in progress, skipping startRecording.');
|
|
23960
23985
|
return;
|
|
23961
23986
|
}
|
|
23962
23987
|
|
|
23963
23988
|
this.recordMaxMs = this.getConfig('record_max_ms');
|
|
23964
23989
|
if (this.recordMaxMs > MAX_RECORDING_MS) {
|
|
23965
23990
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23966
|
-
logger$
|
|
23991
|
+
logger$4.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
23967
23992
|
}
|
|
23968
23993
|
|
|
23969
23994
|
if (!this.maxExpires) {
|
|
@@ -23985,6 +24010,7 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
23985
24010
|
// this also applies if the minimum recording length has not been hit yet
|
|
23986
24011
|
// so that we don't send data until we know the recording will be long enough
|
|
23987
24012
|
this.batcher.stop();
|
|
24013
|
+
this._recordMinMsCheckStart = null;
|
|
23988
24014
|
} else {
|
|
23989
24015
|
this.batcher.start();
|
|
23990
24016
|
}
|
|
@@ -24027,7 +24053,7 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
24027
24053
|
);
|
|
24028
24054
|
}
|
|
24029
24055
|
|
|
24030
|
-
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$
|
|
24056
|
+
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$4);
|
|
24031
24057
|
|
|
24032
24058
|
try {
|
|
24033
24059
|
this._stopRecording = this._rrwebRecord({
|
|
@@ -24036,9 +24062,11 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
24036
24062
|
this._onIdleTimeout();
|
|
24037
24063
|
return;
|
|
24038
24064
|
}
|
|
24065
|
+
if (this._recordMinMsCheckStart === null) {
|
|
24066
|
+
this._recordMinMsCheckStart = ev.timestamp;
|
|
24067
|
+
}
|
|
24039
24068
|
if (isUserEvent(ev)) {
|
|
24040
|
-
if (this.batcher.stopped &&
|
|
24041
|
-
// start flushing again after user activity
|
|
24069
|
+
if (this.batcher.stopped && ev.timestamp - this._recordMinMsCheckStart >= this.recordMinMs) {
|
|
24042
24070
|
this.batcher.start();
|
|
24043
24071
|
}
|
|
24044
24072
|
resetIdleTimeout();
|
|
@@ -24289,14 +24317,14 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
24289
24317
|
|
|
24290
24318
|
|
|
24291
24319
|
SessionRecording.prototype.reportError = function(msg, err) {
|
|
24292
|
-
logger$
|
|
24320
|
+
logger$4.error.apply(logger$4.error, arguments);
|
|
24293
24321
|
try {
|
|
24294
24322
|
if (!err && !(msg instanceof Error)) {
|
|
24295
24323
|
msg = new Error(msg);
|
|
24296
24324
|
}
|
|
24297
24325
|
this.getConfig('error_reporter')(msg, err);
|
|
24298
24326
|
} catch(err) {
|
|
24299
|
-
logger$
|
|
24327
|
+
logger$4.error(err);
|
|
24300
24328
|
}
|
|
24301
24329
|
};
|
|
24302
24330
|
|
|
@@ -24325,7 +24353,7 @@ SessionRecording.prototype._getRecordMinMs = function() {
|
|
|
24325
24353
|
var configValue = this.getConfig('record_min_ms');
|
|
24326
24354
|
|
|
24327
24355
|
if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
24328
|
-
logger$
|
|
24356
|
+
logger$4.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
24329
24357
|
return MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
24330
24358
|
}
|
|
24331
24359
|
|
|
@@ -24367,7 +24395,7 @@ SessionRecording.prototype._getMaskFn = function(shouldMaskFn, privacyConfig) {
|
|
|
24367
24395
|
*/
|
|
24368
24396
|
var RecordingRegistry = function (options) {
|
|
24369
24397
|
/** @type {IDBStorageWrapper} */
|
|
24370
|
-
this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
24398
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
24371
24399
|
this.errorReporter = options.errorReporter;
|
|
24372
24400
|
this.mixpanelInstance = options.mixpanelInstance;
|
|
24373
24401
|
this.sharedLockStorage = options.sharedLockStorage;
|
|
@@ -24488,7 +24516,7 @@ RecordingRegistry.prototype.flushInactiveRecordings = function () {
|
|
|
24488
24516
|
.catch(this.handleError.bind(this));
|
|
24489
24517
|
};
|
|
24490
24518
|
|
|
24491
|
-
var logger$
|
|
24519
|
+
var logger$3 = console_with_prefix('recorder');
|
|
24492
24520
|
|
|
24493
24521
|
/**
|
|
24494
24522
|
* Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
|
|
@@ -24504,7 +24532,7 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
|
|
|
24504
24532
|
*/
|
|
24505
24533
|
this.recordingRegistry = new RecordingRegistry({
|
|
24506
24534
|
mixpanelInstance: this.mixpanelInstance,
|
|
24507
|
-
errorReporter: logger$
|
|
24535
|
+
errorReporter: logger$3.error,
|
|
24508
24536
|
sharedLockStorage: sharedLockStorage
|
|
24509
24537
|
});
|
|
24510
24538
|
this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
|
|
@@ -24516,17 +24544,17 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
|
|
|
24516
24544
|
MixpanelRecorder.prototype.startRecording = function(options) {
|
|
24517
24545
|
options = options || {};
|
|
24518
24546
|
if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
|
|
24519
|
-
logger$
|
|
24547
|
+
logger$3.log('Recording already in progress, skipping startRecording.');
|
|
24520
24548
|
return;
|
|
24521
24549
|
}
|
|
24522
24550
|
|
|
24523
24551
|
var onIdleTimeout = function () {
|
|
24524
|
-
logger$
|
|
24552
|
+
logger$3.log('Idle timeout reached, restarting recording.');
|
|
24525
24553
|
this.resetRecording();
|
|
24526
24554
|
}.bind(this);
|
|
24527
24555
|
|
|
24528
24556
|
var onMaxLengthReached = function () {
|
|
24529
|
-
logger$
|
|
24557
|
+
logger$3.log('Max recording length reached, stopping recording.');
|
|
24530
24558
|
this.resetRecording();
|
|
24531
24559
|
}.bind(this);
|
|
24532
24560
|
|
|
@@ -24596,7 +24624,7 @@ MixpanelRecorder.prototype.resumeRecording = function (startNewIfInactive) {
|
|
|
24596
24624
|
} else if (startNewIfInactive) {
|
|
24597
24625
|
return this.startRecording({shouldStopBatcher: false});
|
|
24598
24626
|
} else {
|
|
24599
|
-
logger$
|
|
24627
|
+
logger$3.log('No resumable recording found.');
|
|
24600
24628
|
return null;
|
|
24601
24629
|
}
|
|
24602
24630
|
}.bind(this));
|
|
@@ -25261,7 +25289,7 @@ ShadowDOMObserver.prototype.observeShadowRoot = function(shadowRoot) {
|
|
|
25261
25289
|
observer.observe(shadowRoot, this.observerConfig);
|
|
25262
25290
|
this.shadowObservers.push(observer);
|
|
25263
25291
|
} catch (e) {
|
|
25264
|
-
logger$
|
|
25292
|
+
logger$6.critical('Error while observing shadow root', e);
|
|
25265
25293
|
}
|
|
25266
25294
|
};
|
|
25267
25295
|
|
|
@@ -25272,7 +25300,7 @@ ShadowDOMObserver.prototype.start = function() {
|
|
|
25272
25300
|
}
|
|
25273
25301
|
|
|
25274
25302
|
if (!weakSetSupported()) {
|
|
25275
|
-
logger$
|
|
25303
|
+
logger$6.critical('Shadow DOM observation unavailable: WeakSet not supported');
|
|
25276
25304
|
return;
|
|
25277
25305
|
}
|
|
25278
25306
|
|
|
@@ -25288,7 +25316,7 @@ ShadowDOMObserver.prototype.stop = function() {
|
|
|
25288
25316
|
try {
|
|
25289
25317
|
this.shadowObservers[i].disconnect();
|
|
25290
25318
|
} catch (e) {
|
|
25291
|
-
logger$
|
|
25319
|
+
logger$6.critical('Error while disconnecting shadow DOM observer', e);
|
|
25292
25320
|
}
|
|
25293
25321
|
}
|
|
25294
25322
|
this.shadowObservers = [];
|
|
@@ -25476,7 +25504,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
25476
25504
|
|
|
25477
25505
|
this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
|
|
25478
25506
|
} catch (e) {
|
|
25479
|
-
logger$
|
|
25507
|
+
logger$6.critical('Error while setting up mutation observer', e);
|
|
25480
25508
|
}
|
|
25481
25509
|
}
|
|
25482
25510
|
|
|
@@ -25491,7 +25519,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
25491
25519
|
);
|
|
25492
25520
|
this.shadowDOMObserver.start();
|
|
25493
25521
|
} catch (e) {
|
|
25494
|
-
logger$
|
|
25522
|
+
logger$6.critical('Error while setting up shadow DOM observer', e);
|
|
25495
25523
|
this.shadowDOMObserver = null;
|
|
25496
25524
|
}
|
|
25497
25525
|
}
|
|
@@ -25518,7 +25546,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25518
25546
|
try {
|
|
25519
25547
|
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
25520
25548
|
} catch (e) {
|
|
25521
|
-
logger$
|
|
25549
|
+
logger$6.critical('Error while removing event listener', e);
|
|
25522
25550
|
}
|
|
25523
25551
|
}
|
|
25524
25552
|
this.eventListeners = [];
|
|
@@ -25527,7 +25555,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25527
25555
|
try {
|
|
25528
25556
|
this.mutationObserver.disconnect();
|
|
25529
25557
|
} catch (e) {
|
|
25530
|
-
logger$
|
|
25558
|
+
logger$6.critical('Error while disconnecting mutation observer', e);
|
|
25531
25559
|
}
|
|
25532
25560
|
this.mutationObserver = null;
|
|
25533
25561
|
}
|
|
@@ -25536,7 +25564,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25536
25564
|
try {
|
|
25537
25565
|
this.shadowDOMObserver.stop();
|
|
25538
25566
|
} catch (e) {
|
|
25539
|
-
logger$
|
|
25567
|
+
logger$6.critical('Error while stopping shadow DOM observer', e);
|
|
25540
25568
|
}
|
|
25541
25569
|
this.shadowDOMObserver = null;
|
|
25542
25570
|
}
|
|
@@ -25614,7 +25642,7 @@ var Autocapture = function(mp) {
|
|
|
25614
25642
|
|
|
25615
25643
|
Autocapture.prototype.init = function() {
|
|
25616
25644
|
if (!minDOMApisSupported()) {
|
|
25617
|
-
logger$
|
|
25645
|
+
logger$6.critical('Autocapture unavailable: missing required DOM APIs');
|
|
25618
25646
|
return;
|
|
25619
25647
|
}
|
|
25620
25648
|
this.initPageListeners();
|
|
@@ -25654,7 +25682,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
25654
25682
|
try {
|
|
25655
25683
|
return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
|
|
25656
25684
|
} catch (err) {
|
|
25657
|
-
logger$
|
|
25685
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25658
25686
|
return true;
|
|
25659
25687
|
}
|
|
25660
25688
|
}
|
|
@@ -25667,7 +25695,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
25667
25695
|
try {
|
|
25668
25696
|
return urlMatchesRegexList(currentUrl, blockUrlRegexes);
|
|
25669
25697
|
} catch (err) {
|
|
25670
|
-
logger$
|
|
25698
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25671
25699
|
return true;
|
|
25672
25700
|
}
|
|
25673
25701
|
};
|
|
@@ -25805,7 +25833,7 @@ Autocapture.prototype._initScrollDepthTracking = function() {
|
|
|
25805
25833
|
return;
|
|
25806
25834
|
}
|
|
25807
25835
|
|
|
25808
|
-
logger$
|
|
25836
|
+
logger$6.log('Initializing scroll depth tracking');
|
|
25809
25837
|
|
|
25810
25838
|
this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
|
|
25811
25839
|
|
|
@@ -25826,12 +25854,12 @@ Autocapture.prototype._initScrollDepthTracking = function() {
|
|
|
25826
25854
|
};
|
|
25827
25855
|
|
|
25828
25856
|
Autocapture.prototype.initClickTracking = function() {
|
|
25829
|
-
win.removeEventListener(EV_CLICK, this.listenerClick);
|
|
25857
|
+
win.removeEventListener(EV_CLICK, this.listenerClick, true);
|
|
25830
25858
|
|
|
25831
25859
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
|
|
25832
25860
|
return;
|
|
25833
25861
|
}
|
|
25834
|
-
logger$
|
|
25862
|
+
logger$6.log('Initializing click tracking');
|
|
25835
25863
|
|
|
25836
25864
|
this.listenerClick = function(ev) {
|
|
25837
25865
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
|
|
@@ -25839,7 +25867,7 @@ Autocapture.prototype.initClickTracking = function() {
|
|
|
25839
25867
|
}
|
|
25840
25868
|
this.trackDomEvent(ev, MP_EV_CLICK);
|
|
25841
25869
|
}.bind(this);
|
|
25842
|
-
win.addEventListener(EV_CLICK, this.listenerClick);
|
|
25870
|
+
win.addEventListener(EV_CLICK, this.listenerClick, true);
|
|
25843
25871
|
};
|
|
25844
25872
|
|
|
25845
25873
|
Autocapture.prototype.initDeadClickTracking = function() {
|
|
@@ -25850,7 +25878,7 @@ Autocapture.prototype.initDeadClickTracking = function() {
|
|
|
25850
25878
|
return;
|
|
25851
25879
|
}
|
|
25852
25880
|
|
|
25853
|
-
logger$
|
|
25881
|
+
logger$6.log('Initializing dead click tracking');
|
|
25854
25882
|
if (!this._deadClickTracker) {
|
|
25855
25883
|
this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
|
|
25856
25884
|
this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
|
|
@@ -25874,17 +25902,17 @@ Autocapture.prototype.initDeadClickTracking = function() {
|
|
|
25874
25902
|
}
|
|
25875
25903
|
this._deadClickTracker.trackClick(ev, normalizedConfig);
|
|
25876
25904
|
}.bind(this);
|
|
25877
|
-
win.addEventListener(EV_CLICK, this.listenerDeadClick);
|
|
25905
|
+
win.addEventListener(EV_CLICK, this.listenerDeadClick, true);
|
|
25878
25906
|
}
|
|
25879
25907
|
};
|
|
25880
25908
|
|
|
25881
25909
|
Autocapture.prototype.initInputTracking = function() {
|
|
25882
|
-
win.removeEventListener(EV_CHANGE, this.listenerChange);
|
|
25910
|
+
win.removeEventListener(EV_CHANGE, this.listenerChange, true);
|
|
25883
25911
|
|
|
25884
25912
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
25885
25913
|
return;
|
|
25886
25914
|
}
|
|
25887
|
-
logger$
|
|
25915
|
+
logger$6.log('Initializing input tracking');
|
|
25888
25916
|
|
|
25889
25917
|
this.listenerChange = function(ev) {
|
|
25890
25918
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
@@ -25892,20 +25920,21 @@ Autocapture.prototype.initInputTracking = function() {
|
|
|
25892
25920
|
}
|
|
25893
25921
|
this.trackDomEvent(ev, MP_EV_INPUT);
|
|
25894
25922
|
}.bind(this);
|
|
25895
|
-
win.addEventListener(EV_CHANGE, this.listenerChange);
|
|
25923
|
+
win.addEventListener(EV_CHANGE, this.listenerChange, true);
|
|
25896
25924
|
};
|
|
25897
25925
|
|
|
25898
25926
|
Autocapture.prototype.initPageviewTracking = function() {
|
|
25899
25927
|
win.removeEventListener(EV_MP_LOCATION_CHANGE, this.listenerLocationchange);
|
|
25900
25928
|
|
|
25901
|
-
if (!this.pageviewTrackingConfig()) {
|
|
25929
|
+
if (!this.pageviewTrackingConfig() && !this.mp.get_config('record_heatmap_data')) {
|
|
25902
25930
|
return;
|
|
25903
25931
|
}
|
|
25904
|
-
logger$
|
|
25932
|
+
logger$6.log('Initializing pageview tracking');
|
|
25905
25933
|
|
|
25906
25934
|
var previousTrackedUrl = '';
|
|
25907
25935
|
var tracked = false;
|
|
25908
|
-
if
|
|
25936
|
+
// Track initial pageview if pageview tracking enabled OR heatmap recording is active
|
|
25937
|
+
if ((this.pageviewTrackingConfig() || this.mp.is_recording_heatmap_data()) && !this.currentUrlBlocked()) {
|
|
25909
25938
|
tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
25910
25939
|
}
|
|
25911
25940
|
if (tracked) {
|
|
@@ -25921,6 +25950,10 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
25921
25950
|
var shouldTrack = false;
|
|
25922
25951
|
var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
25923
25952
|
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
25953
|
+
if (!trackPageviewOption && this.mp.is_recording_heatmap_data()) {
|
|
25954
|
+
trackPageviewOption = PAGEVIEW_OPTION_FULL_URL;
|
|
25955
|
+
}
|
|
25956
|
+
|
|
25924
25957
|
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
25925
25958
|
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
25926
25959
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
@@ -25936,7 +25969,7 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
25936
25969
|
}
|
|
25937
25970
|
if (didPathChange) {
|
|
25938
25971
|
this.lastScrollCheckpoint = 0;
|
|
25939
|
-
logger$
|
|
25972
|
+
logger$6.log('Path change: re-initializing scroll depth checkpoints');
|
|
25940
25973
|
}
|
|
25941
25974
|
}
|
|
25942
25975
|
}.bind(this));
|
|
@@ -25944,14 +25977,14 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
25944
25977
|
};
|
|
25945
25978
|
|
|
25946
25979
|
Autocapture.prototype.initRageClickTracking = function() {
|
|
25947
|
-
win.removeEventListener(EV_CLICK, this.listenerRageClick);
|
|
25980
|
+
win.removeEventListener(EV_CLICK, this.listenerRageClick, true);
|
|
25948
25981
|
|
|
25949
25982
|
var rageClickConfig = this._getClickTrackingConfig(CONFIG_TRACK_RAGE_CLICK);
|
|
25950
25983
|
if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
|
|
25951
25984
|
return;
|
|
25952
25985
|
}
|
|
25953
25986
|
|
|
25954
|
-
logger$
|
|
25987
|
+
logger$6.log('Initializing rage click tracking');
|
|
25955
25988
|
if (!this._rageClickTracker) {
|
|
25956
25989
|
this._rageClickTracker = new RageClickTracker();
|
|
25957
25990
|
}
|
|
@@ -25970,7 +26003,7 @@ Autocapture.prototype.initRageClickTracking = function() {
|
|
|
25970
26003
|
this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
|
|
25971
26004
|
}
|
|
25972
26005
|
}.bind(this);
|
|
25973
|
-
win.addEventListener(EV_CLICK, this.listenerRageClick);
|
|
26006
|
+
win.addEventListener(EV_CLICK, this.listenerRageClick, true);
|
|
25974
26007
|
};
|
|
25975
26008
|
|
|
25976
26009
|
Autocapture.prototype.initScrollTracking = function() {
|
|
@@ -25981,7 +26014,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
25981
26014
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
25982
26015
|
return;
|
|
25983
26016
|
}
|
|
25984
|
-
logger$
|
|
26017
|
+
logger$6.log('Initializing scroll tracking');
|
|
25985
26018
|
this.lastScrollCheckpoint = 0;
|
|
25986
26019
|
|
|
25987
26020
|
var scrollTrackFunction = function() {
|
|
@@ -26018,7 +26051,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
26018
26051
|
}
|
|
26019
26052
|
}
|
|
26020
26053
|
} catch (err) {
|
|
26021
|
-
logger$
|
|
26054
|
+
logger$6.critical('Error while calculating scroll percentage', err);
|
|
26022
26055
|
}
|
|
26023
26056
|
if (shouldTrack) {
|
|
26024
26057
|
this.mp.track(MP_EV_SCROLL, props);
|
|
@@ -26031,12 +26064,12 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
26031
26064
|
};
|
|
26032
26065
|
|
|
26033
26066
|
Autocapture.prototype.initSubmitTracking = function() {
|
|
26034
|
-
win.removeEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
26067
|
+
win.removeEventListener(EV_SUBMIT, this.listenerSubmit, true);
|
|
26035
26068
|
|
|
26036
26069
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
26037
26070
|
return;
|
|
26038
26071
|
}
|
|
26039
|
-
logger$
|
|
26072
|
+
logger$6.log('Initializing submit tracking');
|
|
26040
26073
|
|
|
26041
26074
|
this.listenerSubmit = function(ev) {
|
|
26042
26075
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
@@ -26044,7 +26077,7 @@ Autocapture.prototype.initSubmitTracking = function() {
|
|
|
26044
26077
|
}
|
|
26045
26078
|
this.trackDomEvent(ev, MP_EV_SUBMIT);
|
|
26046
26079
|
}.bind(this);
|
|
26047
|
-
win.addEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
26080
|
+
win.addEventListener(EV_SUBMIT, this.listenerSubmit, true);
|
|
26048
26081
|
};
|
|
26049
26082
|
|
|
26050
26083
|
Autocapture.prototype.initPageLeaveTracking = function() {
|
|
@@ -26058,7 +26091,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
|
|
|
26058
26091
|
return;
|
|
26059
26092
|
}
|
|
26060
26093
|
|
|
26061
|
-
logger$
|
|
26094
|
+
logger$6.log('Initializing page visibility tracking.');
|
|
26062
26095
|
this._initScrollDepthTracking();
|
|
26063
26096
|
var previousTrackedUrl = _.info.currentUrl();
|
|
26064
26097
|
|
|
@@ -26100,7 +26133,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
|
|
|
26100
26133
|
|
|
26101
26134
|
Autocapture.prototype.stopDeadClickTracking = function() {
|
|
26102
26135
|
if (this.listenerDeadClick) {
|
|
26103
|
-
win.removeEventListener(EV_CLICK, this.listenerDeadClick);
|
|
26136
|
+
win.removeEventListener(EV_CLICK, this.listenerDeadClick, true);
|
|
26104
26137
|
this.listenerDeadClick = null;
|
|
26105
26138
|
}
|
|
26106
26139
|
|
|
@@ -26143,10 +26176,183 @@ var getTargetingPromise = function(loadExtraBundle, targetingSrc) {
|
|
|
26143
26176
|
return win[TARGETING_GLOBAL_NAME];
|
|
26144
26177
|
};
|
|
26145
26178
|
|
|
26179
|
+
var logger$2 = console_with_prefix('flags');
|
|
26180
|
+
|
|
26181
|
+
var MIXPANEL_FLAGS_DB_NAME = 'mixpanelFlagsDb';
|
|
26182
|
+
var FLAGS_STORE_NAME = 'mixpanelFlags';
|
|
26183
|
+
|
|
26184
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
26185
|
+
var FLAGS_VERSION_DATA = { version: 1, storeNames: [FLAGS_STORE_NAME] };
|
|
26186
|
+
|
|
26187
|
+
var PERSISTED_VARIANTS_KEY_PREFIX = 'persisted_variants_for_';
|
|
26188
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
26189
|
+
|
|
26190
|
+
var VariantLookupPolicy = Object.freeze({
|
|
26191
|
+
NETWORK_ONLY: 'networkOnly',
|
|
26192
|
+
NETWORK_FIRST: 'networkFirst',
|
|
26193
|
+
PERSISTENCE_UNTIL_NETWORK_SUCCESS: 'persistenceUntilNetworkSuccess'
|
|
26194
|
+
});
|
|
26195
|
+
|
|
26196
|
+
var VALID_POLICIES = [
|
|
26197
|
+
VariantLookupPolicy.NETWORK_ONLY,
|
|
26198
|
+
VariantLookupPolicy.NETWORK_FIRST,
|
|
26199
|
+
VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS
|
|
26200
|
+
];
|
|
26201
|
+
|
|
26202
|
+
/**
|
|
26203
|
+
* Module for handling the storage and retrieval of persisted feature flag variants.
|
|
26204
|
+
*/
|
|
26205
|
+
var FeatureFlagPersistence = function(persistenceConfig, token, isGloballyDisabled) {
|
|
26206
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_FLAGS_DB_NAME, FLAGS_STORE_NAME, FLAGS_VERSION_DATA);
|
|
26207
|
+
this.persistenceConfig = persistenceConfig;
|
|
26208
|
+
this.persistedVariantsKey = PERSISTED_VARIANTS_KEY_PREFIX + token;
|
|
26209
|
+
this.isGloballyDisabled = isGloballyDisabled || function() { return false; };
|
|
26210
|
+
};
|
|
26211
|
+
|
|
26212
|
+
FeatureFlagPersistence.prototype.getPolicy = function() {
|
|
26213
|
+
if (this.isGloballyDisabled() || !this._isConfigValid()) {
|
|
26214
|
+
return VariantLookupPolicy.NETWORK_ONLY;
|
|
26215
|
+
}
|
|
26216
|
+
return this.persistenceConfig['variantLookupPolicy'];
|
|
26217
|
+
};
|
|
26218
|
+
|
|
26219
|
+
FeatureFlagPersistence.prototype.getTtlMs = function() {
|
|
26220
|
+
if (!this._isConfigValid()) {
|
|
26221
|
+
return DEFAULT_TTL_MS;
|
|
26222
|
+
}
|
|
26223
|
+
var configuredTtl = this.persistenceConfig['persistenceTtlMs'];
|
|
26224
|
+
return (configuredTtl === undefined || configuredTtl === null) ? DEFAULT_TTL_MS : configuredTtl;
|
|
26225
|
+
};
|
|
26226
|
+
|
|
26227
|
+
FeatureFlagPersistence.prototype._isConfigValid = function() {
|
|
26228
|
+
var config = this.persistenceConfig;
|
|
26229
|
+
if (!config) {
|
|
26230
|
+
return false;
|
|
26231
|
+
}
|
|
26232
|
+
|
|
26233
|
+
if (VALID_POLICIES.indexOf(config['variantLookupPolicy']) === -1) {
|
|
26234
|
+
logger$2.error('Invalid variantLookupPolicy:', config['variantLookupPolicy']);
|
|
26235
|
+
return false;
|
|
26236
|
+
}
|
|
26237
|
+
|
|
26238
|
+
if (config['persistenceTtlMs'] !== undefined &&
|
|
26239
|
+
config['persistenceTtlMs'] !== null &&
|
|
26240
|
+
config['persistenceTtlMs'] <= 0) {
|
|
26241
|
+
logger$2.error('If provided, persistenceTtlMs must be a positive number. Provided value:', config['persistenceTtlMs']);
|
|
26242
|
+
return false;
|
|
26243
|
+
}
|
|
26244
|
+
|
|
26245
|
+
return true;
|
|
26246
|
+
};
|
|
26247
|
+
|
|
26248
|
+
FeatureFlagPersistence.prototype.loadFlagsFromStorage = function(context) {
|
|
26249
|
+
var clearAndReturnNull = _.bind(function() {
|
|
26250
|
+
return this.clear().then(function() { return null; }).catch(function() { return null; });
|
|
26251
|
+
}, this);
|
|
26252
|
+
|
|
26253
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26254
|
+
return clearAndReturnNull();
|
|
26255
|
+
}
|
|
26256
|
+
|
|
26257
|
+
var ttlMs = this.getTtlMs();
|
|
26258
|
+
|
|
26259
|
+
return this.idb.init().then(_.bind(function() {
|
|
26260
|
+
return this.idb.getItem(this.persistedVariantsKey);
|
|
26261
|
+
}, this)).then(_.bind(function(data) {
|
|
26262
|
+
if (!data) {
|
|
26263
|
+
logger$2.log('No persisted variants found in IndexedDB');
|
|
26264
|
+
return null;
|
|
26265
|
+
}
|
|
26266
|
+
|
|
26267
|
+
if (ttlMs && Date.now() - data['persistedAt'] >= ttlMs) {
|
|
26268
|
+
logger$2.log('Persisted variants are expiring');
|
|
26269
|
+
return null;
|
|
26270
|
+
}
|
|
26271
|
+
|
|
26272
|
+
if (!context || data['distinctId'] !== context['distinct_id']) {
|
|
26273
|
+
logger$2.log('Persisted variants found, but for a different distinct_id so clearing.');
|
|
26274
|
+
return clearAndReturnNull();
|
|
26275
|
+
}
|
|
26276
|
+
|
|
26277
|
+
var persistedFlags = new Map();
|
|
26278
|
+
_.each(data['flagVariants'], function(variantData, key) {
|
|
26279
|
+
persistedFlags.set(key, {
|
|
26280
|
+
'key': variantData['variant_key'],
|
|
26281
|
+
'value': variantData['variant_value'],
|
|
26282
|
+
'experiment_id': variantData['experiment_id'],
|
|
26283
|
+
'is_experiment_active': variantData['is_experiment_active'],
|
|
26284
|
+
'is_qa_tester': variantData['is_qa_tester'],
|
|
26285
|
+
'variant_source': 'persistence',
|
|
26286
|
+
'persisted_at_in_ms': data['persistedAt'],
|
|
26287
|
+
'ttl_in_ms': ttlMs
|
|
26288
|
+
});
|
|
26289
|
+
});
|
|
26290
|
+
|
|
26291
|
+
logger$2.log('Loaded', persistedFlags.size, 'variants from IndexedDB for distinct_id', data['distinctId']);
|
|
26292
|
+
|
|
26293
|
+
return {
|
|
26294
|
+
flags: persistedFlags,
|
|
26295
|
+
pendingFirstTimeEvents: data['pendingFirstTimeEvents'] || {},
|
|
26296
|
+
persistedAtMs: data['persistedAt'],
|
|
26297
|
+
ttlMs: ttlMs
|
|
26298
|
+
};
|
|
26299
|
+
}, this)).catch(_.bind(function(error) {
|
|
26300
|
+
logger$2.error('Failed to load persisted variants from IndexedDB, so clearing', error);
|
|
26301
|
+
return clearAndReturnNull();
|
|
26302
|
+
}, this));
|
|
26303
|
+
};
|
|
26304
|
+
|
|
26305
|
+
FeatureFlagPersistence.prototype.save = function(context, flagsMap, pendingFirstTimeEvents) {
|
|
26306
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26307
|
+
return Promise.resolve();
|
|
26308
|
+
}
|
|
26309
|
+
|
|
26310
|
+
var flagVariants = {};
|
|
26311
|
+
flagsMap.forEach(function(variant, key) {
|
|
26312
|
+
flagVariants[key] = {
|
|
26313
|
+
'variant_key': variant['key'],
|
|
26314
|
+
'variant_value': variant['value'],
|
|
26315
|
+
'experiment_id': variant['experiment_id'],
|
|
26316
|
+
'is_experiment_active': variant['is_experiment_active'],
|
|
26317
|
+
'is_qa_tester': variant['is_qa_tester']
|
|
26318
|
+
};
|
|
26319
|
+
});
|
|
26320
|
+
|
|
26321
|
+
var data = {
|
|
26322
|
+
'persistedAt': Date.now(),
|
|
26323
|
+
'distinctId': context && context['distinct_id'],
|
|
26324
|
+
'context': context,
|
|
26325
|
+
'flagVariants': flagVariants,
|
|
26326
|
+
'pendingFirstTimeEvents': pendingFirstTimeEvents || {}
|
|
26327
|
+
};
|
|
26328
|
+
|
|
26329
|
+
return this.idb.init().then(_.bind(function() {
|
|
26330
|
+
return this.idb.setItem(this.persistedVariantsKey, data);
|
|
26331
|
+
}, this)).then(function() {
|
|
26332
|
+
logger$2.log('Saved', flagsMap.size, 'variants to IndexedDB for distinct_id', data['distinctId']);
|
|
26333
|
+
}).catch(function(error) {
|
|
26334
|
+
logger$2.error('Failed to persist variants to IndexedDB:', error);
|
|
26335
|
+
});
|
|
26336
|
+
};
|
|
26337
|
+
|
|
26338
|
+
FeatureFlagPersistence.prototype.clear = function() {
|
|
26339
|
+
if (this.isGloballyDisabled()) {
|
|
26340
|
+
return Promise.resolve();
|
|
26341
|
+
}
|
|
26342
|
+
return this.idb.init().then(_.bind(function() {
|
|
26343
|
+
return this.idb.removeItem(this.persistedVariantsKey);
|
|
26344
|
+
}, this)).then(function() {
|
|
26345
|
+
logger$2.log('Cleared persisted variants from IndexedDB');
|
|
26346
|
+
}).catch(function(error) {
|
|
26347
|
+
logger$2.error('Failed to clear persisted variants from IndexedDB:', error);
|
|
26348
|
+
});
|
|
26349
|
+
};
|
|
26350
|
+
|
|
26146
26351
|
var logger$1 = console_with_prefix('flags');
|
|
26147
26352
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
26148
26353
|
|
|
26149
26354
|
var CONFIG_CONTEXT = 'context';
|
|
26355
|
+
var CONFIG_PERSISTENCE = 'persistence';
|
|
26150
26356
|
var CONFIG_DEFAULTS = {};
|
|
26151
26357
|
CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
26152
26358
|
|
|
@@ -26169,6 +26375,13 @@ var getFlagKeyFromPendingEventKey = function(eventKey) {
|
|
|
26169
26375
|
return eventKey.split(':')[0];
|
|
26170
26376
|
};
|
|
26171
26377
|
|
|
26378
|
+
var withFallbackSource = function(fallback) {
|
|
26379
|
+
if (_.isObject(fallback)) {
|
|
26380
|
+
return _.extend({}, fallback, {'variant_source': 'fallback'});
|
|
26381
|
+
}
|
|
26382
|
+
return {'value': fallback, 'variant_source': 'fallback'};
|
|
26383
|
+
};
|
|
26384
|
+
|
|
26172
26385
|
/**
|
|
26173
26386
|
* FeatureFlagManager: support for Mixpanel's feature flagging product
|
|
26174
26387
|
* @constructor
|
|
@@ -26191,13 +26404,63 @@ FeatureFlagManager.prototype.init = function() {
|
|
|
26191
26404
|
}
|
|
26192
26405
|
|
|
26193
26406
|
this.flags = null;
|
|
26194
|
-
this.fetchFlags().catch(function() {
|
|
26195
|
-
logger$1.error('Error fetching flags during init');
|
|
26196
|
-
});
|
|
26197
|
-
|
|
26198
26407
|
this.trackedFeatures = new Set();
|
|
26199
26408
|
this.pendingFirstTimeEvents = {};
|
|
26200
26409
|
this.activatedFirstTimeEvents = {};
|
|
26410
|
+
this._loadedPersistedAtMs = null;
|
|
26411
|
+
this._loadedTtlMs = null;
|
|
26412
|
+
|
|
26413
|
+
this.persistence = new FeatureFlagPersistence(
|
|
26414
|
+
this.getConfig(CONFIG_PERSISTENCE),
|
|
26415
|
+
this.getMpConfig('token'),
|
|
26416
|
+
_.bind(function() { return this.getMpConfig('disable_persistence'); }, this)
|
|
26417
|
+
);
|
|
26418
|
+
|
|
26419
|
+
this.persistenceLoadedPromise = this.persistence.loadFlagsFromStorage(this._buildContext())
|
|
26420
|
+
.then(_.bind(function(loaded) {
|
|
26421
|
+
if (loaded) {
|
|
26422
|
+
this.flags = loaded.flags;
|
|
26423
|
+
this.pendingFirstTimeEvents = loaded.pendingFirstTimeEvents;
|
|
26424
|
+
this._loadedPersistedAtMs = loaded.persistedAtMs;
|
|
26425
|
+
this._loadedTtlMs = loaded.ttlMs;
|
|
26426
|
+
}
|
|
26427
|
+
}, this));
|
|
26428
|
+
|
|
26429
|
+
return this.persistenceLoadedPromise
|
|
26430
|
+
.then(_.bind(function() {
|
|
26431
|
+
return this.fetchFlags();
|
|
26432
|
+
}, this))
|
|
26433
|
+
.catch(function() {
|
|
26434
|
+
logger$1.error('Error initializing feature flags');
|
|
26435
|
+
});
|
|
26436
|
+
};
|
|
26437
|
+
|
|
26438
|
+
FeatureFlagManager.prototype._buildContext = function() {
|
|
26439
|
+
return _.extend(
|
|
26440
|
+
{'distinct_id': this.getMpProperty('distinct_id'), 'device_id': this.getMpProperty('$device_id')},
|
|
26441
|
+
this.getConfig(CONFIG_CONTEXT)
|
|
26442
|
+
);
|
|
26443
|
+
};
|
|
26444
|
+
|
|
26445
|
+
FeatureFlagManager.prototype.reset = function() {
|
|
26446
|
+
if (!this.persistence) {
|
|
26447
|
+
return Promise.resolve();
|
|
26448
|
+
}
|
|
26449
|
+
|
|
26450
|
+
this.flags = null;
|
|
26451
|
+
this.pendingFirstTimeEvents = {};
|
|
26452
|
+
this.activatedFirstTimeEvents = {};
|
|
26453
|
+
this.trackedFeatures = new Set();
|
|
26454
|
+
this.fetchPromise = null;
|
|
26455
|
+
this._fetchInProgressStartTime = null;
|
|
26456
|
+
this._loadedPersistedAtMs = null;
|
|
26457
|
+
this._loadedTtlMs = null;
|
|
26458
|
+
|
|
26459
|
+
return this.persistence.clear().then(_.bind(function() {
|
|
26460
|
+
return this.fetchFlags();
|
|
26461
|
+
}, this)).catch(function() {
|
|
26462
|
+
logger$1.error('Error during flags reset');
|
|
26463
|
+
});
|
|
26201
26464
|
};
|
|
26202
26465
|
|
|
26203
26466
|
FeatureFlagManager.prototype.getFullConfig = function() {
|
|
@@ -26254,12 +26517,11 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26254
26517
|
return Promise.resolve();
|
|
26255
26518
|
}
|
|
26256
26519
|
|
|
26257
|
-
var
|
|
26258
|
-
var
|
|
26520
|
+
var context = this._buildContext();
|
|
26521
|
+
var distinctId = context['distinct_id'];
|
|
26259
26522
|
var traceparent = generateTraceparent();
|
|
26260
26523
|
logger$1.log('Fetching flags for distinct ID: ' + distinctId);
|
|
26261
26524
|
|
|
26262
|
-
var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
|
|
26263
26525
|
var searchParams = new URLSearchParams();
|
|
26264
26526
|
searchParams.set('context', JSON.stringify(context));
|
|
26265
26527
|
searchParams.set('token', this.getMpConfig('token'));
|
|
@@ -26309,7 +26571,8 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26309
26571
|
'value': data['variant_value'],
|
|
26310
26572
|
'experiment_id': data['experiment_id'],
|
|
26311
26573
|
'is_experiment_active': data['is_experiment_active'],
|
|
26312
|
-
'is_qa_tester': data['is_qa_tester']
|
|
26574
|
+
'is_qa_tester': data['is_qa_tester'],
|
|
26575
|
+
'variant_source': 'network'
|
|
26313
26576
|
});
|
|
26314
26577
|
}
|
|
26315
26578
|
}, this);
|
|
@@ -26351,10 +26614,15 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26351
26614
|
}
|
|
26352
26615
|
|
|
26353
26616
|
this.flags = flags;
|
|
26617
|
+
this.trackedFeatures = new Set();
|
|
26354
26618
|
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
26619
|
+
this._loadedPersistedAtMs = null;
|
|
26620
|
+
this._loadedTtlMs = null;
|
|
26355
26621
|
this._traceparent = traceparent;
|
|
26356
26622
|
|
|
26357
26623
|
this._loadTargetingIfNeeded();
|
|
26624
|
+
|
|
26625
|
+
this.persistence.save(context, this.flags, this.pendingFirstTimeEvents);
|
|
26358
26626
|
}.bind(this)).catch(function(error) {
|
|
26359
26627
|
if (this._fetchInProgressStartTime) {
|
|
26360
26628
|
this.markFetchComplete();
|
|
@@ -26514,6 +26782,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
26514
26782
|
};
|
|
26515
26783
|
|
|
26516
26784
|
this.flags.set(flagKey, newVariant);
|
|
26785
|
+
this.trackedFeatures.delete(flagKey);
|
|
26517
26786
|
this.activatedFirstTimeEvents[eventKey] = true;
|
|
26518
26787
|
|
|
26519
26788
|
this.recordFirstTimeEvent(
|
|
@@ -26525,8 +26794,8 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
26525
26794
|
};
|
|
26526
26795
|
|
|
26527
26796
|
FeatureFlagManager.prototype.getFirstTimeEventApiRoute = function(flagId) {
|
|
26528
|
-
|
|
26529
|
-
return
|
|
26797
|
+
var base = this.getFullApiRoute().replace(/\/$/, '');
|
|
26798
|
+
return base + '/' + flagId + '/first-time-events';
|
|
26530
26799
|
};
|
|
26531
26800
|
|
|
26532
26801
|
FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId, firstTimeEventHash) {
|
|
@@ -26563,35 +26832,106 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
|
|
|
26563
26832
|
};
|
|
26564
26833
|
|
|
26565
26834
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
26566
|
-
if (!this.
|
|
26835
|
+
if (!this.persistenceLoadedPromise) {
|
|
26567
26836
|
return new Promise(function(resolve) {
|
|
26568
26837
|
logger$1.critical('Feature Flags not initialized');
|
|
26569
|
-
resolve(fallback);
|
|
26838
|
+
resolve(withFallbackSource(fallback));
|
|
26570
26839
|
});
|
|
26571
26840
|
}
|
|
26572
26841
|
|
|
26573
|
-
|
|
26574
|
-
|
|
26575
|
-
|
|
26576
|
-
|
|
26577
|
-
|
|
26578
|
-
|
|
26842
|
+
var policy = this.persistence.getPolicy();
|
|
26843
|
+
|
|
26844
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26845
|
+
// 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.
|
|
26846
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26847
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26848
|
+
return this.getVariantSync(featureName, fallback);
|
|
26849
|
+
}
|
|
26850
|
+
if (!this.fetchPromise) {
|
|
26851
|
+
return withFallbackSource(fallback);
|
|
26852
|
+
}
|
|
26853
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26854
|
+
return this.getVariantSync(featureName, fallback);
|
|
26855
|
+
}, this)).catch(function(error) {
|
|
26856
|
+
logger$1.error(error);
|
|
26857
|
+
return withFallbackSource(fallback);
|
|
26858
|
+
});
|
|
26859
|
+
}
|
|
26860
|
+
|
|
26861
|
+
var serve = _.bind(function() { return this.getVariantSync(featureName, fallback); }, this);
|
|
26862
|
+
if (!this.fetchPromise) {
|
|
26863
|
+
return withFallbackSource(fallback);
|
|
26864
|
+
}
|
|
26865
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26866
|
+
}, this));
|
|
26867
|
+
};
|
|
26868
|
+
|
|
26869
|
+
FeatureFlagManager.prototype._loadedPersistenceIsStale = function() {
|
|
26870
|
+
if (!this._loadedPersistedAtMs || !this._loadedTtlMs) {
|
|
26871
|
+
return false;
|
|
26872
|
+
}
|
|
26873
|
+
return Date.now() - this._loadedPersistedAtMs >= this._loadedTtlMs;
|
|
26579
26874
|
};
|
|
26580
26875
|
|
|
26581
26876
|
FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
|
|
26877
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26878
|
+
logger$1.log('Loaded persisted variants are past TTL so returning fallback for "' + featureName + '"');
|
|
26879
|
+
return withFallbackSource(fallback);
|
|
26880
|
+
}
|
|
26582
26881
|
if (!this.areFlagsReady()) {
|
|
26583
26882
|
logger$1.log('Flags not loaded yet');
|
|
26584
|
-
return fallback;
|
|
26883
|
+
return withFallbackSource(fallback);
|
|
26585
26884
|
}
|
|
26586
26885
|
var feature = this.flags.get(featureName);
|
|
26587
26886
|
if (!feature) {
|
|
26588
26887
|
logger$1.log('No flag found: "' + featureName + '"');
|
|
26589
|
-
return fallback;
|
|
26888
|
+
return withFallbackSource(fallback);
|
|
26590
26889
|
}
|
|
26591
26890
|
this.trackFeatureCheck(featureName, feature);
|
|
26592
26891
|
return feature;
|
|
26593
26892
|
};
|
|
26594
26893
|
|
|
26894
|
+
FeatureFlagManager.prototype.getAllVariants = function() {
|
|
26895
|
+
if (!this.persistenceLoadedPromise) {
|
|
26896
|
+
logger$1.critical('Feature Flags not initialized');
|
|
26897
|
+
return Promise.resolve(new Map());
|
|
26898
|
+
}
|
|
26899
|
+
|
|
26900
|
+
var policy = this.persistence.getPolicy();
|
|
26901
|
+
|
|
26902
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26903
|
+
// 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.
|
|
26904
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26905
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26906
|
+
return this.getAllVariantsSync();
|
|
26907
|
+
}
|
|
26908
|
+
if (!this.fetchPromise) {
|
|
26909
|
+
return new Map();
|
|
26910
|
+
}
|
|
26911
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26912
|
+
return this.getAllVariantsSync();
|
|
26913
|
+
}, this)).catch(function(error) {
|
|
26914
|
+
logger$1.error(error);
|
|
26915
|
+
return new Map();
|
|
26916
|
+
});
|
|
26917
|
+
}
|
|
26918
|
+
|
|
26919
|
+
var serve = _.bind(this.getAllVariantsSync, this);
|
|
26920
|
+
if (!this.fetchPromise) {
|
|
26921
|
+
return new Map();
|
|
26922
|
+
}
|
|
26923
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26924
|
+
}, this));
|
|
26925
|
+
};
|
|
26926
|
+
|
|
26927
|
+
FeatureFlagManager.prototype.getAllVariantsSync = function() {
|
|
26928
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26929
|
+
logger$1.log('Loaded persisted variants are past TTL so returning empty Map');
|
|
26930
|
+
return new Map();
|
|
26931
|
+
}
|
|
26932
|
+
return this.flags || new Map();
|
|
26933
|
+
};
|
|
26934
|
+
|
|
26595
26935
|
FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackValue) {
|
|
26596
26936
|
return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
|
|
26597
26937
|
return feature['value'];
|
|
@@ -26630,6 +26970,10 @@ FeatureFlagManager.prototype.isEnabledSync = function(featureName, fallbackValue
|
|
|
26630
26970
|
return val;
|
|
26631
26971
|
};
|
|
26632
26972
|
|
|
26973
|
+
function isPresent(v) {
|
|
26974
|
+
return v !== undefined && v !== null;
|
|
26975
|
+
}
|
|
26976
|
+
|
|
26633
26977
|
FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature) {
|
|
26634
26978
|
if (this.trackedFeatures.has(featureName)) {
|
|
26635
26979
|
return;
|
|
@@ -26640,21 +26984,30 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
26640
26984
|
'Experiment name': featureName,
|
|
26641
26985
|
'Variant name': feature['key'],
|
|
26642
26986
|
'$experiment_type': 'feature_flag',
|
|
26643
|
-
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
26644
|
-
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
26987
|
+
'Variant fetch start time': isPresent(this._fetchStartTime) ? new Date(this._fetchStartTime).toISOString() : null,
|
|
26988
|
+
'Variant fetch complete time': isPresent(this._fetchCompleteTime) ? new Date(this._fetchCompleteTime).toISOString() : null,
|
|
26645
26989
|
'Variant fetch latency (ms)': this._fetchLatency,
|
|
26646
26990
|
'Variant fetch traceparent': this._traceparent,
|
|
26647
26991
|
};
|
|
26648
26992
|
|
|
26649
|
-
if (feature['experiment_id']
|
|
26993
|
+
if (isPresent(feature['experiment_id'])) {
|
|
26650
26994
|
trackingProperties['$experiment_id'] = feature['experiment_id'];
|
|
26651
26995
|
}
|
|
26652
|
-
if (feature['is_experiment_active']
|
|
26996
|
+
if (isPresent(feature['is_experiment_active'])) {
|
|
26653
26997
|
trackingProperties['$is_experiment_active'] = feature['is_experiment_active'];
|
|
26654
26998
|
}
|
|
26655
|
-
if (feature['is_qa_tester']
|
|
26999
|
+
if (isPresent(feature['is_qa_tester'])) {
|
|
26656
27000
|
trackingProperties['$is_qa_tester'] = feature['is_qa_tester'];
|
|
26657
27001
|
}
|
|
27002
|
+
if (isPresent(feature['variant_source'])) {
|
|
27003
|
+
trackingProperties['$variant_source'] = feature['variant_source'];
|
|
27004
|
+
}
|
|
27005
|
+
if (isPresent(feature['persisted_at_in_ms'])) {
|
|
27006
|
+
trackingProperties['$persisted_at_in_ms'] = feature['persisted_at_in_ms'];
|
|
27007
|
+
}
|
|
27008
|
+
if (isPresent(feature['ttl_in_ms'])) {
|
|
27009
|
+
trackingProperties['$ttl_in_ms'] = feature['ttl_in_ms'];
|
|
27010
|
+
}
|
|
26658
27011
|
|
|
26659
27012
|
this.track('$experiment_started', trackingProperties);
|
|
26660
27013
|
};
|
|
@@ -26678,6 +27031,8 @@ safewrapClass(FeatureFlagManager);
|
|
|
26678
27031
|
FeatureFlagManager.prototype['are_flags_ready'] = FeatureFlagManager.prototype.areFlagsReady;
|
|
26679
27032
|
FeatureFlagManager.prototype['get_variant'] = FeatureFlagManager.prototype.getVariant;
|
|
26680
27033
|
FeatureFlagManager.prototype['get_variant_sync'] = FeatureFlagManager.prototype.getVariantSync;
|
|
27034
|
+
FeatureFlagManager.prototype['get_all_variants'] = FeatureFlagManager.prototype.getAllVariants;
|
|
27035
|
+
FeatureFlagManager.prototype['get_all_variants_sync'] = FeatureFlagManager.prototype.getAllVariantsSync;
|
|
26681
27036
|
FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype.getVariantValue;
|
|
26682
27037
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
26683
27038
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
@@ -26730,7 +27085,7 @@ RecorderManager.prototype.shouldLoadRecorder = function() {
|
|
|
26730
27085
|
return PromisePolyfill.resolve(false);
|
|
26731
27086
|
}
|
|
26732
27087
|
|
|
26733
|
-
var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
27088
|
+
var recording_registry_idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
26734
27089
|
var tab_id = this.getTabId();
|
|
26735
27090
|
return recording_registry_idb.init()
|
|
26736
27091
|
.then(function () {
|
|
@@ -28657,6 +29012,7 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28657
29012
|
'disable_all_events': false,
|
|
28658
29013
|
'identify_called': false
|
|
28659
29014
|
};
|
|
29015
|
+
this._remote_settings_strict_disabled = false;
|
|
28660
29016
|
|
|
28661
29017
|
// set up request queueing/batching
|
|
28662
29018
|
this.request_batchers = {};
|
|
@@ -28731,9 +29087,6 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28731
29087
|
this.flags.init();
|
|
28732
29088
|
this['flags'] = this.flags;
|
|
28733
29089
|
|
|
28734
|
-
this.autocapture = new Autocapture(this);
|
|
28735
|
-
this.autocapture.init();
|
|
28736
|
-
|
|
28737
29090
|
this._init_tab_id();
|
|
28738
29091
|
|
|
28739
29092
|
// Based on remote_settings_mode, fetch remote settings and then start session recording if applicable
|
|
@@ -28745,6 +29098,9 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28745
29098
|
} else {
|
|
28746
29099
|
this.__session_recording_init_promise = this._check_and_start_session_recording();
|
|
28747
29100
|
}
|
|
29101
|
+
|
|
29102
|
+
this.autocapture = new Autocapture(this);
|
|
29103
|
+
this.autocapture.init();
|
|
28748
29104
|
};
|
|
28749
29105
|
|
|
28750
29106
|
/**
|
|
@@ -28791,9 +29147,19 @@ MixpanelLib.prototype._check_and_start_session_recording = addOptOutCheckMixpane
|
|
|
28791
29147
|
return this.recorderManager.checkAndStartSessionRecording(force_start);
|
|
28792
29148
|
});
|
|
28793
29149
|
|
|
28794
|
-
MixpanelLib.prototype._start_recording_on_event = function(event_name, properties) {
|
|
28795
|
-
|
|
28796
|
-
|
|
29150
|
+
MixpanelLib.prototype._start_recording_on_event = safewrap(function(event_name, properties) {
|
|
29151
|
+
// Wait for recording init to complete before evaluating event triggers.
|
|
29152
|
+
// This ensures recording_event_triggers config is fully loaded when remote settings are used.
|
|
29153
|
+
if (this.__session_recording_init_promise) {
|
|
29154
|
+
this.__session_recording_init_promise.then(_.bind(function() {
|
|
29155
|
+
// In strict mode, skip recording if remote settings failed
|
|
29156
|
+
if (this._remote_settings_strict_disabled) {
|
|
29157
|
+
return;
|
|
29158
|
+
}
|
|
29159
|
+
return this.recorderManager.startRecordingOnEvent(event_name, properties);
|
|
29160
|
+
}, this));
|
|
29161
|
+
}
|
|
29162
|
+
});
|
|
28797
29163
|
|
|
28798
29164
|
MixpanelLib.prototype.start_session_recording = function () {
|
|
28799
29165
|
return this._check_and_start_session_recording(true);
|
|
@@ -29092,6 +29458,7 @@ MixpanelLib.prototype._fetch_remote_settings = function(mode) {
|
|
|
29092
29458
|
var disableRecordingIfStrict = function() {
|
|
29093
29459
|
if (mode === 'strict') {
|
|
29094
29460
|
self.set_config({'record_sessions_percent': 0});
|
|
29461
|
+
self._remote_settings_strict_disabled = true;
|
|
29095
29462
|
}
|
|
29096
29463
|
};
|
|
29097
29464
|
|
|
@@ -29717,6 +30084,10 @@ MixpanelLib.prototype.track_pageview = addOptOutCheckMixpanelLib(function(proper
|
|
|
29717
30084
|
properties
|
|
29718
30085
|
);
|
|
29719
30086
|
|
|
30087
|
+
if (this.is_recording_heatmap_data()) {
|
|
30088
|
+
event_properties['$captured_for_heatmap'] = true;
|
|
30089
|
+
}
|
|
30090
|
+
|
|
29720
30091
|
return this.track(event_name, event_properties);
|
|
29721
30092
|
});
|
|
29722
30093
|
|
|
@@ -30060,6 +30431,7 @@ MixpanelLib.prototype.reset = function() {
|
|
|
30060
30431
|
'$device_id': uuid
|
|
30061
30432
|
}, '');
|
|
30062
30433
|
this._check_and_start_session_recording();
|
|
30434
|
+
this.flags.reset();
|
|
30063
30435
|
};
|
|
30064
30436
|
|
|
30065
30437
|
/**
|