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.cjs.js
CHANGED
|
@@ -27,7 +27,7 @@ if (typeof(window) === 'undefined') {
|
|
|
27
27
|
|
|
28
28
|
var Config = {
|
|
29
29
|
DEBUG: false,
|
|
30
|
-
LIB_VERSION: '2.
|
|
30
|
+
LIB_VERSION: '2.80.0'
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
// Window global names for async modules
|
|
@@ -19125,6 +19125,7 @@ var log_func_with_prefix = function(func, prefix) {
|
|
|
19125
19125
|
var console_with_prefix = function(prefix) {
|
|
19126
19126
|
return {
|
|
19127
19127
|
log: log_func_with_prefix(console$1.log, prefix),
|
|
19128
|
+
warn: log_func_with_prefix(console$1.warn, prefix),
|
|
19128
19129
|
error: log_func_with_prefix(console$1.error, prefix),
|
|
19129
19130
|
critical: log_func_with_prefix(console$1.critical, prefix)
|
|
19130
19131
|
};
|
|
@@ -20071,7 +20072,8 @@ var localStorageSupported = function(storage, forceCheck) {
|
|
|
20071
20072
|
if (_localStorageSupported !== null && !forceCheck) {
|
|
20072
20073
|
return _localStorageSupported;
|
|
20073
20074
|
}
|
|
20074
|
-
|
|
20075
|
+
|
|
20076
|
+
return _localStorageSupported = _testStorageSupported(storage);
|
|
20075
20077
|
};
|
|
20076
20078
|
|
|
20077
20079
|
var _sessionStorageSupported = null;
|
|
@@ -20079,7 +20081,8 @@ var sessionStorageSupported = function(storage, forceCheck) {
|
|
|
20079
20081
|
if (_sessionStorageSupported !== null && !forceCheck) {
|
|
20080
20082
|
return _sessionStorageSupported;
|
|
20081
20083
|
}
|
|
20082
|
-
|
|
20084
|
+
|
|
20085
|
+
return _sessionStorageSupported = _testStorageSupported(storage);
|
|
20083
20086
|
};
|
|
20084
20087
|
|
|
20085
20088
|
function _storageWrapper(storage, name, is_supported_fn) {
|
|
@@ -20129,17 +20132,26 @@ function _storageWrapper(storage, name, is_supported_fn) {
|
|
|
20129
20132
|
};
|
|
20130
20133
|
}
|
|
20131
20134
|
|
|
20132
|
-
// Safari
|
|
20133
|
-
//
|
|
20134
|
-
var
|
|
20135
|
-
try {
|
|
20136
|
-
|
|
20137
|
-
|
|
20138
|
-
|
|
20139
|
-
}
|
|
20135
|
+
// Safari and other browsers may error out accessing localStorage/sessionStorage
|
|
20136
|
+
// when cookies are disabled, so wrap access in a try-catch.
|
|
20137
|
+
var getLocalStorage = function() {
|
|
20138
|
+
try {
|
|
20139
|
+
return win.localStorage; // eslint-disable-line no-restricted-properties
|
|
20140
|
+
} catch (_err) {
|
|
20141
|
+
return null;
|
|
20142
|
+
}
|
|
20143
|
+
};
|
|
20144
|
+
|
|
20145
|
+
var getSessionStorage = function() {
|
|
20146
|
+
try {
|
|
20147
|
+
return win.sessionStorage; // eslint-disable-line no-restricted-properties
|
|
20148
|
+
} catch (_err) {
|
|
20149
|
+
return null;
|
|
20150
|
+
}
|
|
20151
|
+
};
|
|
20140
20152
|
|
|
20141
|
-
_.localStorage = _storageWrapper(
|
|
20142
|
-
_.sessionStorage = _storageWrapper(
|
|
20153
|
+
_.localStorage = _storageWrapper(getLocalStorage(), 'localStorage', localStorageSupported);
|
|
20154
|
+
_.sessionStorage = _storageWrapper(getSessionStorage(), 'sessionStorage', sessionStorageSupported);
|
|
20143
20155
|
|
|
20144
20156
|
_.register_event = (function() {
|
|
20145
20157
|
// written by Dean Edwards, 2005
|
|
@@ -20808,29 +20820,26 @@ _['JSONEncode'] = _.JSONEncode;
|
|
|
20808
20820
|
_['toArray'] = _.toArray;
|
|
20809
20821
|
_['NPO'] = NpoPromise;
|
|
20810
20822
|
|
|
20811
|
-
var MIXPANEL_DB_NAME = 'mixpanelBrowserDb';
|
|
20812
|
-
|
|
20813
|
-
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
20814
|
-
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
20815
|
-
|
|
20816
|
-
// note: increment the version number when adding new object stores
|
|
20817
|
-
var DB_VERSION = 1;
|
|
20818
|
-
var OBJECT_STORES = [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME];
|
|
20819
|
-
|
|
20820
20823
|
/**
|
|
20821
20824
|
* @type {import('./wrapper').StorageWrapper}
|
|
20822
20825
|
*/
|
|
20823
|
-
var IDBStorageWrapper = function (storeName) {
|
|
20826
|
+
var IDBStorageWrapper = function (dbName, storeName, versionData) {
|
|
20827
|
+
this.dbName = dbName;
|
|
20828
|
+
this.storeName = storeName;
|
|
20829
|
+
this.version = versionData.version;
|
|
20830
|
+
this.storeNamesInDb = versionData.storeNames;
|
|
20824
20831
|
/**
|
|
20825
20832
|
* @type {Promise<IDBDatabase>|null}
|
|
20826
20833
|
*/
|
|
20827
20834
|
this.dbPromise = null;
|
|
20828
|
-
this.storeName = storeName;
|
|
20829
20835
|
};
|
|
20830
20836
|
|
|
20831
20837
|
IDBStorageWrapper.prototype._openDb = function () {
|
|
20838
|
+
var dbName = this.dbName;
|
|
20839
|
+
var version = this.version;
|
|
20840
|
+
var storeNamesInDb = this.storeNamesInDb;
|
|
20832
20841
|
return new PromisePolyfill(function (resolve, reject) {
|
|
20833
|
-
var openRequest = win.indexedDB.open(
|
|
20842
|
+
var openRequest = win.indexedDB.open(dbName, version);
|
|
20834
20843
|
openRequest['onerror'] = function () {
|
|
20835
20844
|
reject(openRequest.error);
|
|
20836
20845
|
};
|
|
@@ -20842,8 +20851,10 @@ IDBStorageWrapper.prototype._openDb = function () {
|
|
|
20842
20851
|
openRequest['onupgradeneeded'] = function (ev) {
|
|
20843
20852
|
var db = ev.target.result;
|
|
20844
20853
|
|
|
20845
|
-
|
|
20846
|
-
db.
|
|
20854
|
+
storeNamesInDb.forEach(function (storeName) {
|
|
20855
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
20856
|
+
db.createObjectStore(storeName);
|
|
20857
|
+
}
|
|
20847
20858
|
});
|
|
20848
20859
|
};
|
|
20849
20860
|
});
|
|
@@ -20935,6 +20946,16 @@ IDBStorageWrapper.prototype.getAll = function () {
|
|
|
20935
20946
|
});
|
|
20936
20947
|
};
|
|
20937
20948
|
|
|
20949
|
+
var MIXPANEL_BROWSER_DB_NAME = 'mixpanelBrowserDb';
|
|
20950
|
+
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
20951
|
+
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
20952
|
+
|
|
20953
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
20954
|
+
var RECORDER_VERSION_DATA = {
|
|
20955
|
+
version: 1,
|
|
20956
|
+
storeNames: [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME]
|
|
20957
|
+
};
|
|
20958
|
+
|
|
20938
20959
|
/**
|
|
20939
20960
|
* GDPR utils
|
|
20940
20961
|
*
|
|
@@ -21235,7 +21256,7 @@ function _addOptOutCheck(method, getConfigValue) {
|
|
|
21235
21256
|
};
|
|
21236
21257
|
}
|
|
21237
21258
|
|
|
21238
|
-
var logger$
|
|
21259
|
+
var logger$9 = console_with_prefix('lock');
|
|
21239
21260
|
|
|
21240
21261
|
/**
|
|
21241
21262
|
* SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
|
|
@@ -21261,7 +21282,7 @@ var SharedLock = function(key, options) {
|
|
|
21261
21282
|
options = options || {};
|
|
21262
21283
|
|
|
21263
21284
|
this.storageKey = key;
|
|
21264
|
-
this.storage = options.storage ||
|
|
21285
|
+
this.storage = options.storage || getLocalStorage();
|
|
21265
21286
|
this.pollIntervalMS = options.pollIntervalMS || 100;
|
|
21266
21287
|
this.timeoutMS = options.timeoutMS || 2000;
|
|
21267
21288
|
|
|
@@ -21287,7 +21308,7 @@ SharedLock.prototype.withLock = function(lockedCB, pid) {
|
|
|
21287
21308
|
|
|
21288
21309
|
var delay = function(cb) {
|
|
21289
21310
|
if (new Date().getTime() - startTime > timeoutMS) {
|
|
21290
|
-
logger$
|
|
21311
|
+
logger$9.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
|
|
21291
21312
|
storage.removeItem(keyZ);
|
|
21292
21313
|
storage.removeItem(keyY);
|
|
21293
21314
|
loop();
|
|
@@ -21389,10 +21410,13 @@ SharedLock.prototype.withLock = function(lockedCB, pid) {
|
|
|
21389
21410
|
* @type {import('./wrapper').StorageWrapper}
|
|
21390
21411
|
*/
|
|
21391
21412
|
var LocalStorageWrapper = function (storageOverride) {
|
|
21392
|
-
this.storage = storageOverride ||
|
|
21413
|
+
this.storage = storageOverride || getLocalStorage();
|
|
21393
21414
|
};
|
|
21394
21415
|
|
|
21395
21416
|
LocalStorageWrapper.prototype.init = function () {
|
|
21417
|
+
if (!this.storage) {
|
|
21418
|
+
return PromisePolyfill.reject(new Error('localStorage is not available'));
|
|
21419
|
+
}
|
|
21396
21420
|
return PromisePolyfill.resolve();
|
|
21397
21421
|
};
|
|
21398
21422
|
|
|
@@ -21434,7 +21458,7 @@ LocalStorageWrapper.prototype.removeItem = function (key) {
|
|
|
21434
21458
|
}, this));
|
|
21435
21459
|
};
|
|
21436
21460
|
|
|
21437
|
-
var logger$
|
|
21461
|
+
var logger$8 = console_with_prefix('batch');
|
|
21438
21462
|
|
|
21439
21463
|
/**
|
|
21440
21464
|
* RequestQueue: queue for batching API requests with localStorage backup for retries.
|
|
@@ -21459,11 +21483,11 @@ var RequestQueue = function (storageKey, options) {
|
|
|
21459
21483
|
if (this.usePersistence) {
|
|
21460
21484
|
this.queueStorage = options.queueStorage || new LocalStorageWrapper();
|
|
21461
21485
|
this.lock = new SharedLock(storageKey, {
|
|
21462
|
-
storage: options.sharedLockStorage
|
|
21486
|
+
storage: options.sharedLockStorage,
|
|
21463
21487
|
timeoutMS: options.sharedLockTimeoutMS,
|
|
21464
21488
|
});
|
|
21465
21489
|
}
|
|
21466
|
-
this.reportError = options.errorReporter || _.bind(logger$
|
|
21490
|
+
this.reportError = options.errorReporter || _.bind(logger$8.error, logger$8);
|
|
21467
21491
|
|
|
21468
21492
|
this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
|
|
21469
21493
|
|
|
@@ -21796,7 +21820,7 @@ RequestQueue.prototype.clear = function () {
|
|
|
21796
21820
|
// maximum interval between request retries after exponential backoff
|
|
21797
21821
|
var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
|
|
21798
21822
|
|
|
21799
|
-
var logger$
|
|
21823
|
+
var logger$7 = console_with_prefix('batch');
|
|
21800
21824
|
|
|
21801
21825
|
/**
|
|
21802
21826
|
* RequestBatcher: manages the queueing, flushing, retry etc of requests of one
|
|
@@ -21924,7 +21948,7 @@ RequestBatcher.prototype.sendRequestPromise = function(data, options) {
|
|
|
21924
21948
|
*/
|
|
21925
21949
|
RequestBatcher.prototype.flush = function(options) {
|
|
21926
21950
|
if (this.requestInProgress) {
|
|
21927
|
-
logger$
|
|
21951
|
+
logger$7.log('Flush: Request already in progress');
|
|
21928
21952
|
return PromisePolyfill.resolve();
|
|
21929
21953
|
}
|
|
21930
21954
|
|
|
@@ -22101,7 +22125,7 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
22101
22125
|
if (options.unloading) {
|
|
22102
22126
|
requestOptions.transport = 'sendBeacon';
|
|
22103
22127
|
}
|
|
22104
|
-
logger$
|
|
22128
|
+
logger$7.log('MIXPANEL REQUEST:', dataForRequest);
|
|
22105
22129
|
return this.sendRequestPromise(dataForRequest, requestOptions).then(batchSendCallback);
|
|
22106
22130
|
}, this))
|
|
22107
22131
|
.catch(_.bind(function(err) {
|
|
@@ -22114,7 +22138,7 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
22114
22138
|
* Log error to global logger and optional user-defined logger.
|
|
22115
22139
|
*/
|
|
22116
22140
|
RequestBatcher.prototype.reportError = function(msg, err) {
|
|
22117
|
-
logger$
|
|
22141
|
+
logger$7.error.apply(logger$7.error, arguments);
|
|
22118
22142
|
if (this.errorReporter) {
|
|
22119
22143
|
try {
|
|
22120
22144
|
if (!(err instanceof Error)) {
|
|
@@ -22122,7 +22146,7 @@ RequestBatcher.prototype.reportError = function(msg, err) {
|
|
|
22122
22146
|
}
|
|
22123
22147
|
this.errorReporter(msg, err);
|
|
22124
22148
|
} catch(err) {
|
|
22125
|
-
logger$
|
|
22149
|
+
logger$7.error(err);
|
|
22126
22150
|
}
|
|
22127
22151
|
}
|
|
22128
22152
|
};
|
|
@@ -22267,7 +22291,7 @@ var EVENT_HANDLER_ATTRIBUTES = [
|
|
|
22267
22291
|
|
|
22268
22292
|
var MAX_DEPTH = 5;
|
|
22269
22293
|
|
|
22270
|
-
var logger$
|
|
22294
|
+
var logger$6 = console_with_prefix('autocapture');
|
|
22271
22295
|
|
|
22272
22296
|
|
|
22273
22297
|
function getClasses(el) {
|
|
@@ -22531,7 +22555,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
|
22531
22555
|
return false;
|
|
22532
22556
|
}
|
|
22533
22557
|
} catch (err) {
|
|
22534
|
-
logger$
|
|
22558
|
+
logger$6.critical('Error while checking element in allowElementCallback', err);
|
|
22535
22559
|
return false;
|
|
22536
22560
|
}
|
|
22537
22561
|
}
|
|
@@ -22548,7 +22572,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
|
22548
22572
|
return true;
|
|
22549
22573
|
}
|
|
22550
22574
|
} catch (err) {
|
|
22551
|
-
logger$
|
|
22575
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
22552
22576
|
}
|
|
22553
22577
|
}
|
|
22554
22578
|
return false;
|
|
@@ -22563,7 +22587,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
|
22563
22587
|
return true;
|
|
22564
22588
|
}
|
|
22565
22589
|
} catch (err) {
|
|
22566
|
-
logger$
|
|
22590
|
+
logger$6.critical('Error while checking element in blockElementCallback', err);
|
|
22567
22591
|
return true;
|
|
22568
22592
|
}
|
|
22569
22593
|
}
|
|
@@ -22577,7 +22601,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
|
22577
22601
|
return true;
|
|
22578
22602
|
}
|
|
22579
22603
|
} catch (err) {
|
|
22580
|
-
logger$
|
|
22604
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
22581
22605
|
}
|
|
22582
22606
|
}
|
|
22583
22607
|
}
|
|
@@ -23133,7 +23157,7 @@ function shouldMaskText(element, privacyConfig) {
|
|
|
23133
23157
|
*
|
|
23134
23158
|
*/
|
|
23135
23159
|
|
|
23136
|
-
var logger$
|
|
23160
|
+
var logger$5 = console_with_prefix('network-plugin');
|
|
23137
23161
|
|
|
23138
23162
|
/**
|
|
23139
23163
|
* Get the time origin for converting performance timestamps to absolute timestamps.
|
|
@@ -23285,7 +23309,7 @@ function truncateBody(str) {
|
|
|
23285
23309
|
return str;
|
|
23286
23310
|
}
|
|
23287
23311
|
if (str.length > MAX_BODY_SIZE) {
|
|
23288
|
-
logger$
|
|
23312
|
+
logger$5.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
|
|
23289
23313
|
return str.substring(0, MAX_BODY_SIZE) + '... [truncated]';
|
|
23290
23314
|
}
|
|
23291
23315
|
return str;
|
|
@@ -23299,7 +23323,7 @@ function truncateBody(str) {
|
|
|
23299
23323
|
*/
|
|
23300
23324
|
function initPerformanceObserver(cb, win, options) {
|
|
23301
23325
|
if (!win.PerformanceObserver) {
|
|
23302
|
-
logger$
|
|
23326
|
+
logger$5.error('PerformanceObserver not supported');
|
|
23303
23327
|
return function() {
|
|
23304
23328
|
//
|
|
23305
23329
|
};
|
|
@@ -23452,7 +23476,7 @@ function getRequestPerformanceEntry(win, initiatorType, url, after, before, atte
|
|
|
23452
23476
|
attempt = 0;
|
|
23453
23477
|
}
|
|
23454
23478
|
if (attempt > 10) {
|
|
23455
|
-
logger$
|
|
23479
|
+
logger$5.error('Cannot find performance entry');
|
|
23456
23480
|
return Promise.resolve(null);
|
|
23457
23481
|
}
|
|
23458
23482
|
var urlPerformanceEntries = /** @type {PerformanceResourceTiming[]} */ (
|
|
@@ -23573,7 +23597,7 @@ function initXhrObserver(cb, win, options) {
|
|
|
23573
23597
|
)
|
|
23574
23598
|
.then(function(entry) {
|
|
23575
23599
|
if (!entry) {
|
|
23576
|
-
logger$
|
|
23600
|
+
logger$5.error('Failed to get performance entry for XHR request to ' + req.url);
|
|
23577
23601
|
return;
|
|
23578
23602
|
}
|
|
23579
23603
|
/** @type {NetworkRequest} */
|
|
@@ -23593,7 +23617,7 @@ function initXhrObserver(cb, win, options) {
|
|
|
23593
23617
|
cb({ requests: [request] });
|
|
23594
23618
|
})
|
|
23595
23619
|
.catch(function(e) {
|
|
23596
|
-
logger$
|
|
23620
|
+
logger$5.error('Error recording XHR request to ' + req.url + ': ' + String(e));
|
|
23597
23621
|
});
|
|
23598
23622
|
});
|
|
23599
23623
|
|
|
@@ -23685,7 +23709,7 @@ function initFetchObserver(cb, win, options) {
|
|
|
23685
23709
|
})
|
|
23686
23710
|
.then(function(entry) {
|
|
23687
23711
|
if (!entry) {
|
|
23688
|
-
logger$
|
|
23712
|
+
logger$5.error('Failed to get performance entry for fetch request to ' + req.url);
|
|
23689
23713
|
return;
|
|
23690
23714
|
}
|
|
23691
23715
|
/** @type {NetworkRequest} */
|
|
@@ -23705,7 +23729,7 @@ function initFetchObserver(cb, win, options) {
|
|
|
23705
23729
|
cb({ requests: [request] });
|
|
23706
23730
|
})
|
|
23707
23731
|
.catch(function (e) {
|
|
23708
|
-
logger$
|
|
23732
|
+
logger$5.error('Error recording fetch request to ' + req.url + ': ' + String(e));
|
|
23709
23733
|
});
|
|
23710
23734
|
|
|
23711
23735
|
return originalFetchPromise;
|
|
@@ -23778,7 +23802,7 @@ var getRecordNetworkPlugin = function(options) {
|
|
|
23778
23802
|
*/
|
|
23779
23803
|
|
|
23780
23804
|
|
|
23781
|
-
var logger$
|
|
23805
|
+
var logger$4 = console_with_prefix('recorder');
|
|
23782
23806
|
var CompressionStream = win['CompressionStream'];
|
|
23783
23807
|
|
|
23784
23808
|
var RECORDER_BATCHER_LIB_CONFIG = {
|
|
@@ -23872,14 +23896,15 @@ var SessionRecording = function(options) {
|
|
|
23872
23896
|
|
|
23873
23897
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23874
23898
|
this.recordMinMs = 0;
|
|
23899
|
+
this._recordMinMsCheckStart = null;
|
|
23875
23900
|
|
|
23876
23901
|
// disable persistence if localStorage is not supported
|
|
23877
23902
|
// request-queue will automatically disable persistence if indexedDB fails to initialize
|
|
23878
|
-
var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
|
|
23903
|
+
var usePersistence = localStorageSupported(options.sharedLockStorage || getLocalStorage(), true) && !this.getConfig('disable_persistence');
|
|
23879
23904
|
|
|
23880
23905
|
// each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
|
|
23881
23906
|
this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
|
|
23882
|
-
this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
|
|
23907
|
+
this.queueStorage = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_EVENTS_STORE_NAME, RECORDER_VERSION_DATA);
|
|
23883
23908
|
this.batcher = new RequestBatcher(this.batcherKey, {
|
|
23884
23909
|
errorReporter: this.reportError.bind(this),
|
|
23885
23910
|
flushOnlyOnInterval: true,
|
|
@@ -23958,14 +23983,14 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
23958
23983
|
}
|
|
23959
23984
|
|
|
23960
23985
|
if (this._stopRecording !== null) {
|
|
23961
|
-
logger$
|
|
23986
|
+
logger$4.log('Recording already in progress, skipping startRecording.');
|
|
23962
23987
|
return;
|
|
23963
23988
|
}
|
|
23964
23989
|
|
|
23965
23990
|
this.recordMaxMs = this.getConfig('record_max_ms');
|
|
23966
23991
|
if (this.recordMaxMs > MAX_RECORDING_MS) {
|
|
23967
23992
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23968
|
-
logger$
|
|
23993
|
+
logger$4.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
23969
23994
|
}
|
|
23970
23995
|
|
|
23971
23996
|
if (!this.maxExpires) {
|
|
@@ -23987,6 +24012,7 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
23987
24012
|
// this also applies if the minimum recording length has not been hit yet
|
|
23988
24013
|
// so that we don't send data until we know the recording will be long enough
|
|
23989
24014
|
this.batcher.stop();
|
|
24015
|
+
this._recordMinMsCheckStart = null;
|
|
23990
24016
|
} else {
|
|
23991
24017
|
this.batcher.start();
|
|
23992
24018
|
}
|
|
@@ -24029,7 +24055,7 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
24029
24055
|
);
|
|
24030
24056
|
}
|
|
24031
24057
|
|
|
24032
|
-
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$
|
|
24058
|
+
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$4);
|
|
24033
24059
|
|
|
24034
24060
|
try {
|
|
24035
24061
|
this._stopRecording = this._rrwebRecord({
|
|
@@ -24038,9 +24064,11 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
24038
24064
|
this._onIdleTimeout();
|
|
24039
24065
|
return;
|
|
24040
24066
|
}
|
|
24067
|
+
if (this._recordMinMsCheckStart === null) {
|
|
24068
|
+
this._recordMinMsCheckStart = ev.timestamp;
|
|
24069
|
+
}
|
|
24041
24070
|
if (isUserEvent(ev)) {
|
|
24042
|
-
if (this.batcher.stopped &&
|
|
24043
|
-
// start flushing again after user activity
|
|
24071
|
+
if (this.batcher.stopped && ev.timestamp - this._recordMinMsCheckStart >= this.recordMinMs) {
|
|
24044
24072
|
this.batcher.start();
|
|
24045
24073
|
}
|
|
24046
24074
|
resetIdleTimeout();
|
|
@@ -24291,14 +24319,14 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
24291
24319
|
|
|
24292
24320
|
|
|
24293
24321
|
SessionRecording.prototype.reportError = function(msg, err) {
|
|
24294
|
-
logger$
|
|
24322
|
+
logger$4.error.apply(logger$4.error, arguments);
|
|
24295
24323
|
try {
|
|
24296
24324
|
if (!err && !(msg instanceof Error)) {
|
|
24297
24325
|
msg = new Error(msg);
|
|
24298
24326
|
}
|
|
24299
24327
|
this.getConfig('error_reporter')(msg, err);
|
|
24300
24328
|
} catch(err) {
|
|
24301
|
-
logger$
|
|
24329
|
+
logger$4.error(err);
|
|
24302
24330
|
}
|
|
24303
24331
|
};
|
|
24304
24332
|
|
|
@@ -24327,7 +24355,7 @@ SessionRecording.prototype._getRecordMinMs = function() {
|
|
|
24327
24355
|
var configValue = this.getConfig('record_min_ms');
|
|
24328
24356
|
|
|
24329
24357
|
if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
24330
|
-
logger$
|
|
24358
|
+
logger$4.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
24331
24359
|
return MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
24332
24360
|
}
|
|
24333
24361
|
|
|
@@ -24369,7 +24397,7 @@ SessionRecording.prototype._getMaskFn = function(shouldMaskFn, privacyConfig) {
|
|
|
24369
24397
|
*/
|
|
24370
24398
|
var RecordingRegistry = function (options) {
|
|
24371
24399
|
/** @type {IDBStorageWrapper} */
|
|
24372
|
-
this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
24400
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
24373
24401
|
this.errorReporter = options.errorReporter;
|
|
24374
24402
|
this.mixpanelInstance = options.mixpanelInstance;
|
|
24375
24403
|
this.sharedLockStorage = options.sharedLockStorage;
|
|
@@ -24490,7 +24518,7 @@ RecordingRegistry.prototype.flushInactiveRecordings = function () {
|
|
|
24490
24518
|
.catch(this.handleError.bind(this));
|
|
24491
24519
|
};
|
|
24492
24520
|
|
|
24493
|
-
var logger$
|
|
24521
|
+
var logger$3 = console_with_prefix('recorder');
|
|
24494
24522
|
|
|
24495
24523
|
/**
|
|
24496
24524
|
* Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
|
|
@@ -24506,7 +24534,7 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
|
|
|
24506
24534
|
*/
|
|
24507
24535
|
this.recordingRegistry = new RecordingRegistry({
|
|
24508
24536
|
mixpanelInstance: this.mixpanelInstance,
|
|
24509
|
-
errorReporter: logger$
|
|
24537
|
+
errorReporter: logger$3.error,
|
|
24510
24538
|
sharedLockStorage: sharedLockStorage
|
|
24511
24539
|
});
|
|
24512
24540
|
this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
|
|
@@ -24518,17 +24546,17 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
|
|
|
24518
24546
|
MixpanelRecorder.prototype.startRecording = function(options) {
|
|
24519
24547
|
options = options || {};
|
|
24520
24548
|
if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
|
|
24521
|
-
logger$
|
|
24549
|
+
logger$3.log('Recording already in progress, skipping startRecording.');
|
|
24522
24550
|
return;
|
|
24523
24551
|
}
|
|
24524
24552
|
|
|
24525
24553
|
var onIdleTimeout = function () {
|
|
24526
|
-
logger$
|
|
24554
|
+
logger$3.log('Idle timeout reached, restarting recording.');
|
|
24527
24555
|
this.resetRecording();
|
|
24528
24556
|
}.bind(this);
|
|
24529
24557
|
|
|
24530
24558
|
var onMaxLengthReached = function () {
|
|
24531
|
-
logger$
|
|
24559
|
+
logger$3.log('Max recording length reached, stopping recording.');
|
|
24532
24560
|
this.resetRecording();
|
|
24533
24561
|
}.bind(this);
|
|
24534
24562
|
|
|
@@ -24598,7 +24626,7 @@ MixpanelRecorder.prototype.resumeRecording = function (startNewIfInactive) {
|
|
|
24598
24626
|
} else if (startNewIfInactive) {
|
|
24599
24627
|
return this.startRecording({shouldStopBatcher: false});
|
|
24600
24628
|
} else {
|
|
24601
|
-
logger$
|
|
24629
|
+
logger$3.log('No resumable recording found.');
|
|
24602
24630
|
return null;
|
|
24603
24631
|
}
|
|
24604
24632
|
}.bind(this));
|
|
@@ -25263,7 +25291,7 @@ ShadowDOMObserver.prototype.observeShadowRoot = function(shadowRoot) {
|
|
|
25263
25291
|
observer.observe(shadowRoot, this.observerConfig);
|
|
25264
25292
|
this.shadowObservers.push(observer);
|
|
25265
25293
|
} catch (e) {
|
|
25266
|
-
logger$
|
|
25294
|
+
logger$6.critical('Error while observing shadow root', e);
|
|
25267
25295
|
}
|
|
25268
25296
|
};
|
|
25269
25297
|
|
|
@@ -25274,7 +25302,7 @@ ShadowDOMObserver.prototype.start = function() {
|
|
|
25274
25302
|
}
|
|
25275
25303
|
|
|
25276
25304
|
if (!weakSetSupported()) {
|
|
25277
|
-
logger$
|
|
25305
|
+
logger$6.critical('Shadow DOM observation unavailable: WeakSet not supported');
|
|
25278
25306
|
return;
|
|
25279
25307
|
}
|
|
25280
25308
|
|
|
@@ -25290,7 +25318,7 @@ ShadowDOMObserver.prototype.stop = function() {
|
|
|
25290
25318
|
try {
|
|
25291
25319
|
this.shadowObservers[i].disconnect();
|
|
25292
25320
|
} catch (e) {
|
|
25293
|
-
logger$
|
|
25321
|
+
logger$6.critical('Error while disconnecting shadow DOM observer', e);
|
|
25294
25322
|
}
|
|
25295
25323
|
}
|
|
25296
25324
|
this.shadowObservers = [];
|
|
@@ -25478,7 +25506,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
25478
25506
|
|
|
25479
25507
|
this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
|
|
25480
25508
|
} catch (e) {
|
|
25481
|
-
logger$
|
|
25509
|
+
logger$6.critical('Error while setting up mutation observer', e);
|
|
25482
25510
|
}
|
|
25483
25511
|
}
|
|
25484
25512
|
|
|
@@ -25493,7 +25521,7 @@ DeadClickTracker.prototype.startTracking = function() {
|
|
|
25493
25521
|
);
|
|
25494
25522
|
this.shadowDOMObserver.start();
|
|
25495
25523
|
} catch (e) {
|
|
25496
|
-
logger$
|
|
25524
|
+
logger$6.critical('Error while setting up shadow DOM observer', e);
|
|
25497
25525
|
this.shadowDOMObserver = null;
|
|
25498
25526
|
}
|
|
25499
25527
|
}
|
|
@@ -25520,7 +25548,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25520
25548
|
try {
|
|
25521
25549
|
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
25522
25550
|
} catch (e) {
|
|
25523
|
-
logger$
|
|
25551
|
+
logger$6.critical('Error while removing event listener', e);
|
|
25524
25552
|
}
|
|
25525
25553
|
}
|
|
25526
25554
|
this.eventListeners = [];
|
|
@@ -25529,7 +25557,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25529
25557
|
try {
|
|
25530
25558
|
this.mutationObserver.disconnect();
|
|
25531
25559
|
} catch (e) {
|
|
25532
|
-
logger$
|
|
25560
|
+
logger$6.critical('Error while disconnecting mutation observer', e);
|
|
25533
25561
|
}
|
|
25534
25562
|
this.mutationObserver = null;
|
|
25535
25563
|
}
|
|
@@ -25538,7 +25566,7 @@ DeadClickTracker.prototype.stopTracking = function() {
|
|
|
25538
25566
|
try {
|
|
25539
25567
|
this.shadowDOMObserver.stop();
|
|
25540
25568
|
} catch (e) {
|
|
25541
|
-
logger$
|
|
25569
|
+
logger$6.critical('Error while stopping shadow DOM observer', e);
|
|
25542
25570
|
}
|
|
25543
25571
|
this.shadowDOMObserver = null;
|
|
25544
25572
|
}
|
|
@@ -25616,7 +25644,7 @@ var Autocapture = function(mp) {
|
|
|
25616
25644
|
|
|
25617
25645
|
Autocapture.prototype.init = function() {
|
|
25618
25646
|
if (!minDOMApisSupported()) {
|
|
25619
|
-
logger$
|
|
25647
|
+
logger$6.critical('Autocapture unavailable: missing required DOM APIs');
|
|
25620
25648
|
return;
|
|
25621
25649
|
}
|
|
25622
25650
|
this.initPageListeners();
|
|
@@ -25656,7 +25684,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
25656
25684
|
try {
|
|
25657
25685
|
return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
|
|
25658
25686
|
} catch (err) {
|
|
25659
|
-
logger$
|
|
25687
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25660
25688
|
return true;
|
|
25661
25689
|
}
|
|
25662
25690
|
}
|
|
@@ -25669,7 +25697,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
|
|
|
25669
25697
|
try {
|
|
25670
25698
|
return urlMatchesRegexList(currentUrl, blockUrlRegexes);
|
|
25671
25699
|
} catch (err) {
|
|
25672
|
-
logger$
|
|
25700
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25673
25701
|
return true;
|
|
25674
25702
|
}
|
|
25675
25703
|
};
|
|
@@ -25807,7 +25835,7 @@ Autocapture.prototype._initScrollDepthTracking = function() {
|
|
|
25807
25835
|
return;
|
|
25808
25836
|
}
|
|
25809
25837
|
|
|
25810
|
-
logger$
|
|
25838
|
+
logger$6.log('Initializing scroll depth tracking');
|
|
25811
25839
|
|
|
25812
25840
|
this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
|
|
25813
25841
|
|
|
@@ -25828,12 +25856,12 @@ Autocapture.prototype._initScrollDepthTracking = function() {
|
|
|
25828
25856
|
};
|
|
25829
25857
|
|
|
25830
25858
|
Autocapture.prototype.initClickTracking = function() {
|
|
25831
|
-
win.removeEventListener(EV_CLICK, this.listenerClick);
|
|
25859
|
+
win.removeEventListener(EV_CLICK, this.listenerClick, true);
|
|
25832
25860
|
|
|
25833
25861
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
|
|
25834
25862
|
return;
|
|
25835
25863
|
}
|
|
25836
|
-
logger$
|
|
25864
|
+
logger$6.log('Initializing click tracking');
|
|
25837
25865
|
|
|
25838
25866
|
this.listenerClick = function(ev) {
|
|
25839
25867
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
|
|
@@ -25841,7 +25869,7 @@ Autocapture.prototype.initClickTracking = function() {
|
|
|
25841
25869
|
}
|
|
25842
25870
|
this.trackDomEvent(ev, MP_EV_CLICK);
|
|
25843
25871
|
}.bind(this);
|
|
25844
|
-
win.addEventListener(EV_CLICK, this.listenerClick);
|
|
25872
|
+
win.addEventListener(EV_CLICK, this.listenerClick, true);
|
|
25845
25873
|
};
|
|
25846
25874
|
|
|
25847
25875
|
Autocapture.prototype.initDeadClickTracking = function() {
|
|
@@ -25852,7 +25880,7 @@ Autocapture.prototype.initDeadClickTracking = function() {
|
|
|
25852
25880
|
return;
|
|
25853
25881
|
}
|
|
25854
25882
|
|
|
25855
|
-
logger$
|
|
25883
|
+
logger$6.log('Initializing dead click tracking');
|
|
25856
25884
|
if (!this._deadClickTracker) {
|
|
25857
25885
|
this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
|
|
25858
25886
|
this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
|
|
@@ -25876,17 +25904,17 @@ Autocapture.prototype.initDeadClickTracking = function() {
|
|
|
25876
25904
|
}
|
|
25877
25905
|
this._deadClickTracker.trackClick(ev, normalizedConfig);
|
|
25878
25906
|
}.bind(this);
|
|
25879
|
-
win.addEventListener(EV_CLICK, this.listenerDeadClick);
|
|
25907
|
+
win.addEventListener(EV_CLICK, this.listenerDeadClick, true);
|
|
25880
25908
|
}
|
|
25881
25909
|
};
|
|
25882
25910
|
|
|
25883
25911
|
Autocapture.prototype.initInputTracking = function() {
|
|
25884
|
-
win.removeEventListener(EV_CHANGE, this.listenerChange);
|
|
25912
|
+
win.removeEventListener(EV_CHANGE, this.listenerChange, true);
|
|
25885
25913
|
|
|
25886
25914
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
25887
25915
|
return;
|
|
25888
25916
|
}
|
|
25889
|
-
logger$
|
|
25917
|
+
logger$6.log('Initializing input tracking');
|
|
25890
25918
|
|
|
25891
25919
|
this.listenerChange = function(ev) {
|
|
25892
25920
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
@@ -25894,20 +25922,21 @@ Autocapture.prototype.initInputTracking = function() {
|
|
|
25894
25922
|
}
|
|
25895
25923
|
this.trackDomEvent(ev, MP_EV_INPUT);
|
|
25896
25924
|
}.bind(this);
|
|
25897
|
-
win.addEventListener(EV_CHANGE, this.listenerChange);
|
|
25925
|
+
win.addEventListener(EV_CHANGE, this.listenerChange, true);
|
|
25898
25926
|
};
|
|
25899
25927
|
|
|
25900
25928
|
Autocapture.prototype.initPageviewTracking = function() {
|
|
25901
25929
|
win.removeEventListener(EV_MP_LOCATION_CHANGE, this.listenerLocationchange);
|
|
25902
25930
|
|
|
25903
|
-
if (!this.pageviewTrackingConfig()) {
|
|
25931
|
+
if (!this.pageviewTrackingConfig() && !this.mp.get_config('record_heatmap_data')) {
|
|
25904
25932
|
return;
|
|
25905
25933
|
}
|
|
25906
|
-
logger$
|
|
25934
|
+
logger$6.log('Initializing pageview tracking');
|
|
25907
25935
|
|
|
25908
25936
|
var previousTrackedUrl = '';
|
|
25909
25937
|
var tracked = false;
|
|
25910
|
-
if
|
|
25938
|
+
// Track initial pageview if pageview tracking enabled OR heatmap recording is active
|
|
25939
|
+
if ((this.pageviewTrackingConfig() || this.mp.is_recording_heatmap_data()) && !this.currentUrlBlocked()) {
|
|
25911
25940
|
tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
25912
25941
|
}
|
|
25913
25942
|
if (tracked) {
|
|
@@ -25923,6 +25952,10 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
25923
25952
|
var shouldTrack = false;
|
|
25924
25953
|
var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
25925
25954
|
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
25955
|
+
if (!trackPageviewOption && this.mp.is_recording_heatmap_data()) {
|
|
25956
|
+
trackPageviewOption = PAGEVIEW_OPTION_FULL_URL;
|
|
25957
|
+
}
|
|
25958
|
+
|
|
25926
25959
|
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
25927
25960
|
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
25928
25961
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
@@ -25938,7 +25971,7 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
25938
25971
|
}
|
|
25939
25972
|
if (didPathChange) {
|
|
25940
25973
|
this.lastScrollCheckpoint = 0;
|
|
25941
|
-
logger$
|
|
25974
|
+
logger$6.log('Path change: re-initializing scroll depth checkpoints');
|
|
25942
25975
|
}
|
|
25943
25976
|
}
|
|
25944
25977
|
}.bind(this));
|
|
@@ -25946,14 +25979,14 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
25946
25979
|
};
|
|
25947
25980
|
|
|
25948
25981
|
Autocapture.prototype.initRageClickTracking = function() {
|
|
25949
|
-
win.removeEventListener(EV_CLICK, this.listenerRageClick);
|
|
25982
|
+
win.removeEventListener(EV_CLICK, this.listenerRageClick, true);
|
|
25950
25983
|
|
|
25951
25984
|
var rageClickConfig = this._getClickTrackingConfig(CONFIG_TRACK_RAGE_CLICK);
|
|
25952
25985
|
if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
|
|
25953
25986
|
return;
|
|
25954
25987
|
}
|
|
25955
25988
|
|
|
25956
|
-
logger$
|
|
25989
|
+
logger$6.log('Initializing rage click tracking');
|
|
25957
25990
|
if (!this._rageClickTracker) {
|
|
25958
25991
|
this._rageClickTracker = new RageClickTracker();
|
|
25959
25992
|
}
|
|
@@ -25972,7 +26005,7 @@ Autocapture.prototype.initRageClickTracking = function() {
|
|
|
25972
26005
|
this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
|
|
25973
26006
|
}
|
|
25974
26007
|
}.bind(this);
|
|
25975
|
-
win.addEventListener(EV_CLICK, this.listenerRageClick);
|
|
26008
|
+
win.addEventListener(EV_CLICK, this.listenerRageClick, true);
|
|
25976
26009
|
};
|
|
25977
26010
|
|
|
25978
26011
|
Autocapture.prototype.initScrollTracking = function() {
|
|
@@ -25983,7 +26016,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
25983
26016
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
25984
26017
|
return;
|
|
25985
26018
|
}
|
|
25986
|
-
logger$
|
|
26019
|
+
logger$6.log('Initializing scroll tracking');
|
|
25987
26020
|
this.lastScrollCheckpoint = 0;
|
|
25988
26021
|
|
|
25989
26022
|
var scrollTrackFunction = function() {
|
|
@@ -26020,7 +26053,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
26020
26053
|
}
|
|
26021
26054
|
}
|
|
26022
26055
|
} catch (err) {
|
|
26023
|
-
logger$
|
|
26056
|
+
logger$6.critical('Error while calculating scroll percentage', err);
|
|
26024
26057
|
}
|
|
26025
26058
|
if (shouldTrack) {
|
|
26026
26059
|
this.mp.track(MP_EV_SCROLL, props);
|
|
@@ -26033,12 +26066,12 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
26033
26066
|
};
|
|
26034
26067
|
|
|
26035
26068
|
Autocapture.prototype.initSubmitTracking = function() {
|
|
26036
|
-
win.removeEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
26069
|
+
win.removeEventListener(EV_SUBMIT, this.listenerSubmit, true);
|
|
26037
26070
|
|
|
26038
26071
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
26039
26072
|
return;
|
|
26040
26073
|
}
|
|
26041
|
-
logger$
|
|
26074
|
+
logger$6.log('Initializing submit tracking');
|
|
26042
26075
|
|
|
26043
26076
|
this.listenerSubmit = function(ev) {
|
|
26044
26077
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
@@ -26046,7 +26079,7 @@ Autocapture.prototype.initSubmitTracking = function() {
|
|
|
26046
26079
|
}
|
|
26047
26080
|
this.trackDomEvent(ev, MP_EV_SUBMIT);
|
|
26048
26081
|
}.bind(this);
|
|
26049
|
-
win.addEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
26082
|
+
win.addEventListener(EV_SUBMIT, this.listenerSubmit, true);
|
|
26050
26083
|
};
|
|
26051
26084
|
|
|
26052
26085
|
Autocapture.prototype.initPageLeaveTracking = function() {
|
|
@@ -26060,7 +26093,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
|
|
|
26060
26093
|
return;
|
|
26061
26094
|
}
|
|
26062
26095
|
|
|
26063
|
-
logger$
|
|
26096
|
+
logger$6.log('Initializing page visibility tracking.');
|
|
26064
26097
|
this._initScrollDepthTracking();
|
|
26065
26098
|
var previousTrackedUrl = _.info.currentUrl();
|
|
26066
26099
|
|
|
@@ -26102,7 +26135,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
|
|
|
26102
26135
|
|
|
26103
26136
|
Autocapture.prototype.stopDeadClickTracking = function() {
|
|
26104
26137
|
if (this.listenerDeadClick) {
|
|
26105
|
-
win.removeEventListener(EV_CLICK, this.listenerDeadClick);
|
|
26138
|
+
win.removeEventListener(EV_CLICK, this.listenerDeadClick, true);
|
|
26106
26139
|
this.listenerDeadClick = null;
|
|
26107
26140
|
}
|
|
26108
26141
|
|
|
@@ -26145,10 +26178,183 @@ var getTargetingPromise = function(loadExtraBundle, targetingSrc) {
|
|
|
26145
26178
|
return win[TARGETING_GLOBAL_NAME];
|
|
26146
26179
|
};
|
|
26147
26180
|
|
|
26181
|
+
var logger$2 = console_with_prefix('flags');
|
|
26182
|
+
|
|
26183
|
+
var MIXPANEL_FLAGS_DB_NAME = 'mixpanelFlagsDb';
|
|
26184
|
+
var FLAGS_STORE_NAME = 'mixpanelFlags';
|
|
26185
|
+
|
|
26186
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
26187
|
+
var FLAGS_VERSION_DATA = { version: 1, storeNames: [FLAGS_STORE_NAME] };
|
|
26188
|
+
|
|
26189
|
+
var PERSISTED_VARIANTS_KEY_PREFIX = 'persisted_variants_for_';
|
|
26190
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
26191
|
+
|
|
26192
|
+
var VariantLookupPolicy = Object.freeze({
|
|
26193
|
+
NETWORK_ONLY: 'networkOnly',
|
|
26194
|
+
NETWORK_FIRST: 'networkFirst',
|
|
26195
|
+
PERSISTENCE_UNTIL_NETWORK_SUCCESS: 'persistenceUntilNetworkSuccess'
|
|
26196
|
+
});
|
|
26197
|
+
|
|
26198
|
+
var VALID_POLICIES = [
|
|
26199
|
+
VariantLookupPolicy.NETWORK_ONLY,
|
|
26200
|
+
VariantLookupPolicy.NETWORK_FIRST,
|
|
26201
|
+
VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS
|
|
26202
|
+
];
|
|
26203
|
+
|
|
26204
|
+
/**
|
|
26205
|
+
* Module for handling the storage and retrieval of persisted feature flag variants.
|
|
26206
|
+
*/
|
|
26207
|
+
var FeatureFlagPersistence = function(persistenceConfig, token, isGloballyDisabled) {
|
|
26208
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_FLAGS_DB_NAME, FLAGS_STORE_NAME, FLAGS_VERSION_DATA);
|
|
26209
|
+
this.persistenceConfig = persistenceConfig;
|
|
26210
|
+
this.persistedVariantsKey = PERSISTED_VARIANTS_KEY_PREFIX + token;
|
|
26211
|
+
this.isGloballyDisabled = isGloballyDisabled || function() { return false; };
|
|
26212
|
+
};
|
|
26213
|
+
|
|
26214
|
+
FeatureFlagPersistence.prototype.getPolicy = function() {
|
|
26215
|
+
if (this.isGloballyDisabled() || !this._isConfigValid()) {
|
|
26216
|
+
return VariantLookupPolicy.NETWORK_ONLY;
|
|
26217
|
+
}
|
|
26218
|
+
return this.persistenceConfig['variantLookupPolicy'];
|
|
26219
|
+
};
|
|
26220
|
+
|
|
26221
|
+
FeatureFlagPersistence.prototype.getTtlMs = function() {
|
|
26222
|
+
if (!this._isConfigValid()) {
|
|
26223
|
+
return DEFAULT_TTL_MS;
|
|
26224
|
+
}
|
|
26225
|
+
var configuredTtl = this.persistenceConfig['persistenceTtlMs'];
|
|
26226
|
+
return (configuredTtl === undefined || configuredTtl === null) ? DEFAULT_TTL_MS : configuredTtl;
|
|
26227
|
+
};
|
|
26228
|
+
|
|
26229
|
+
FeatureFlagPersistence.prototype._isConfigValid = function() {
|
|
26230
|
+
var config = this.persistenceConfig;
|
|
26231
|
+
if (!config) {
|
|
26232
|
+
return false;
|
|
26233
|
+
}
|
|
26234
|
+
|
|
26235
|
+
if (VALID_POLICIES.indexOf(config['variantLookupPolicy']) === -1) {
|
|
26236
|
+
logger$2.error('Invalid variantLookupPolicy:', config['variantLookupPolicy']);
|
|
26237
|
+
return false;
|
|
26238
|
+
}
|
|
26239
|
+
|
|
26240
|
+
if (config['persistenceTtlMs'] !== undefined &&
|
|
26241
|
+
config['persistenceTtlMs'] !== null &&
|
|
26242
|
+
config['persistenceTtlMs'] <= 0) {
|
|
26243
|
+
logger$2.error('If provided, persistenceTtlMs must be a positive number. Provided value:', config['persistenceTtlMs']);
|
|
26244
|
+
return false;
|
|
26245
|
+
}
|
|
26246
|
+
|
|
26247
|
+
return true;
|
|
26248
|
+
};
|
|
26249
|
+
|
|
26250
|
+
FeatureFlagPersistence.prototype.loadFlagsFromStorage = function(context) {
|
|
26251
|
+
var clearAndReturnNull = _.bind(function() {
|
|
26252
|
+
return this.clear().then(function() { return null; }).catch(function() { return null; });
|
|
26253
|
+
}, this);
|
|
26254
|
+
|
|
26255
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26256
|
+
return clearAndReturnNull();
|
|
26257
|
+
}
|
|
26258
|
+
|
|
26259
|
+
var ttlMs = this.getTtlMs();
|
|
26260
|
+
|
|
26261
|
+
return this.idb.init().then(_.bind(function() {
|
|
26262
|
+
return this.idb.getItem(this.persistedVariantsKey);
|
|
26263
|
+
}, this)).then(_.bind(function(data) {
|
|
26264
|
+
if (!data) {
|
|
26265
|
+
logger$2.log('No persisted variants found in IndexedDB');
|
|
26266
|
+
return null;
|
|
26267
|
+
}
|
|
26268
|
+
|
|
26269
|
+
if (ttlMs && Date.now() - data['persistedAt'] >= ttlMs) {
|
|
26270
|
+
logger$2.log('Persisted variants are expiring');
|
|
26271
|
+
return null;
|
|
26272
|
+
}
|
|
26273
|
+
|
|
26274
|
+
if (!context || data['distinctId'] !== context['distinct_id']) {
|
|
26275
|
+
logger$2.log('Persisted variants found, but for a different distinct_id so clearing.');
|
|
26276
|
+
return clearAndReturnNull();
|
|
26277
|
+
}
|
|
26278
|
+
|
|
26279
|
+
var persistedFlags = new Map();
|
|
26280
|
+
_.each(data['flagVariants'], function(variantData, key) {
|
|
26281
|
+
persistedFlags.set(key, {
|
|
26282
|
+
'key': variantData['variant_key'],
|
|
26283
|
+
'value': variantData['variant_value'],
|
|
26284
|
+
'experiment_id': variantData['experiment_id'],
|
|
26285
|
+
'is_experiment_active': variantData['is_experiment_active'],
|
|
26286
|
+
'is_qa_tester': variantData['is_qa_tester'],
|
|
26287
|
+
'variant_source': 'persistence',
|
|
26288
|
+
'persisted_at_in_ms': data['persistedAt'],
|
|
26289
|
+
'ttl_in_ms': ttlMs
|
|
26290
|
+
});
|
|
26291
|
+
});
|
|
26292
|
+
|
|
26293
|
+
logger$2.log('Loaded', persistedFlags.size, 'variants from IndexedDB for distinct_id', data['distinctId']);
|
|
26294
|
+
|
|
26295
|
+
return {
|
|
26296
|
+
flags: persistedFlags,
|
|
26297
|
+
pendingFirstTimeEvents: data['pendingFirstTimeEvents'] || {},
|
|
26298
|
+
persistedAtMs: data['persistedAt'],
|
|
26299
|
+
ttlMs: ttlMs
|
|
26300
|
+
};
|
|
26301
|
+
}, this)).catch(_.bind(function(error) {
|
|
26302
|
+
logger$2.error('Failed to load persisted variants from IndexedDB, so clearing', error);
|
|
26303
|
+
return clearAndReturnNull();
|
|
26304
|
+
}, this));
|
|
26305
|
+
};
|
|
26306
|
+
|
|
26307
|
+
FeatureFlagPersistence.prototype.save = function(context, flagsMap, pendingFirstTimeEvents) {
|
|
26308
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26309
|
+
return Promise.resolve();
|
|
26310
|
+
}
|
|
26311
|
+
|
|
26312
|
+
var flagVariants = {};
|
|
26313
|
+
flagsMap.forEach(function(variant, key) {
|
|
26314
|
+
flagVariants[key] = {
|
|
26315
|
+
'variant_key': variant['key'],
|
|
26316
|
+
'variant_value': variant['value'],
|
|
26317
|
+
'experiment_id': variant['experiment_id'],
|
|
26318
|
+
'is_experiment_active': variant['is_experiment_active'],
|
|
26319
|
+
'is_qa_tester': variant['is_qa_tester']
|
|
26320
|
+
};
|
|
26321
|
+
});
|
|
26322
|
+
|
|
26323
|
+
var data = {
|
|
26324
|
+
'persistedAt': Date.now(),
|
|
26325
|
+
'distinctId': context && context['distinct_id'],
|
|
26326
|
+
'context': context,
|
|
26327
|
+
'flagVariants': flagVariants,
|
|
26328
|
+
'pendingFirstTimeEvents': pendingFirstTimeEvents || {}
|
|
26329
|
+
};
|
|
26330
|
+
|
|
26331
|
+
return this.idb.init().then(_.bind(function() {
|
|
26332
|
+
return this.idb.setItem(this.persistedVariantsKey, data);
|
|
26333
|
+
}, this)).then(function() {
|
|
26334
|
+
logger$2.log('Saved', flagsMap.size, 'variants to IndexedDB for distinct_id', data['distinctId']);
|
|
26335
|
+
}).catch(function(error) {
|
|
26336
|
+
logger$2.error('Failed to persist variants to IndexedDB:', error);
|
|
26337
|
+
});
|
|
26338
|
+
};
|
|
26339
|
+
|
|
26340
|
+
FeatureFlagPersistence.prototype.clear = function() {
|
|
26341
|
+
if (this.isGloballyDisabled()) {
|
|
26342
|
+
return Promise.resolve();
|
|
26343
|
+
}
|
|
26344
|
+
return this.idb.init().then(_.bind(function() {
|
|
26345
|
+
return this.idb.removeItem(this.persistedVariantsKey);
|
|
26346
|
+
}, this)).then(function() {
|
|
26347
|
+
logger$2.log('Cleared persisted variants from IndexedDB');
|
|
26348
|
+
}).catch(function(error) {
|
|
26349
|
+
logger$2.error('Failed to clear persisted variants from IndexedDB:', error);
|
|
26350
|
+
});
|
|
26351
|
+
};
|
|
26352
|
+
|
|
26148
26353
|
var logger$1 = console_with_prefix('flags');
|
|
26149
26354
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
26150
26355
|
|
|
26151
26356
|
var CONFIG_CONTEXT = 'context';
|
|
26357
|
+
var CONFIG_PERSISTENCE = 'persistence';
|
|
26152
26358
|
var CONFIG_DEFAULTS = {};
|
|
26153
26359
|
CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
26154
26360
|
|
|
@@ -26171,6 +26377,13 @@ var getFlagKeyFromPendingEventKey = function(eventKey) {
|
|
|
26171
26377
|
return eventKey.split(':')[0];
|
|
26172
26378
|
};
|
|
26173
26379
|
|
|
26380
|
+
var withFallbackSource = function(fallback) {
|
|
26381
|
+
if (_.isObject(fallback)) {
|
|
26382
|
+
return _.extend({}, fallback, {'variant_source': 'fallback'});
|
|
26383
|
+
}
|
|
26384
|
+
return {'value': fallback, 'variant_source': 'fallback'};
|
|
26385
|
+
};
|
|
26386
|
+
|
|
26174
26387
|
/**
|
|
26175
26388
|
* FeatureFlagManager: support for Mixpanel's feature flagging product
|
|
26176
26389
|
* @constructor
|
|
@@ -26193,13 +26406,63 @@ FeatureFlagManager.prototype.init = function() {
|
|
|
26193
26406
|
}
|
|
26194
26407
|
|
|
26195
26408
|
this.flags = null;
|
|
26196
|
-
this.fetchFlags().catch(function() {
|
|
26197
|
-
logger$1.error('Error fetching flags during init');
|
|
26198
|
-
});
|
|
26199
|
-
|
|
26200
26409
|
this.trackedFeatures = new Set();
|
|
26201
26410
|
this.pendingFirstTimeEvents = {};
|
|
26202
26411
|
this.activatedFirstTimeEvents = {};
|
|
26412
|
+
this._loadedPersistedAtMs = null;
|
|
26413
|
+
this._loadedTtlMs = null;
|
|
26414
|
+
|
|
26415
|
+
this.persistence = new FeatureFlagPersistence(
|
|
26416
|
+
this.getConfig(CONFIG_PERSISTENCE),
|
|
26417
|
+
this.getMpConfig('token'),
|
|
26418
|
+
_.bind(function() { return this.getMpConfig('disable_persistence'); }, this)
|
|
26419
|
+
);
|
|
26420
|
+
|
|
26421
|
+
this.persistenceLoadedPromise = this.persistence.loadFlagsFromStorage(this._buildContext())
|
|
26422
|
+
.then(_.bind(function(loaded) {
|
|
26423
|
+
if (loaded) {
|
|
26424
|
+
this.flags = loaded.flags;
|
|
26425
|
+
this.pendingFirstTimeEvents = loaded.pendingFirstTimeEvents;
|
|
26426
|
+
this._loadedPersistedAtMs = loaded.persistedAtMs;
|
|
26427
|
+
this._loadedTtlMs = loaded.ttlMs;
|
|
26428
|
+
}
|
|
26429
|
+
}, this));
|
|
26430
|
+
|
|
26431
|
+
return this.persistenceLoadedPromise
|
|
26432
|
+
.then(_.bind(function() {
|
|
26433
|
+
return this.fetchFlags();
|
|
26434
|
+
}, this))
|
|
26435
|
+
.catch(function() {
|
|
26436
|
+
logger$1.error('Error initializing feature flags');
|
|
26437
|
+
});
|
|
26438
|
+
};
|
|
26439
|
+
|
|
26440
|
+
FeatureFlagManager.prototype._buildContext = function() {
|
|
26441
|
+
return _.extend(
|
|
26442
|
+
{'distinct_id': this.getMpProperty('distinct_id'), 'device_id': this.getMpProperty('$device_id')},
|
|
26443
|
+
this.getConfig(CONFIG_CONTEXT)
|
|
26444
|
+
);
|
|
26445
|
+
};
|
|
26446
|
+
|
|
26447
|
+
FeatureFlagManager.prototype.reset = function() {
|
|
26448
|
+
if (!this.persistence) {
|
|
26449
|
+
return Promise.resolve();
|
|
26450
|
+
}
|
|
26451
|
+
|
|
26452
|
+
this.flags = null;
|
|
26453
|
+
this.pendingFirstTimeEvents = {};
|
|
26454
|
+
this.activatedFirstTimeEvents = {};
|
|
26455
|
+
this.trackedFeatures = new Set();
|
|
26456
|
+
this.fetchPromise = null;
|
|
26457
|
+
this._fetchInProgressStartTime = null;
|
|
26458
|
+
this._loadedPersistedAtMs = null;
|
|
26459
|
+
this._loadedTtlMs = null;
|
|
26460
|
+
|
|
26461
|
+
return this.persistence.clear().then(_.bind(function() {
|
|
26462
|
+
return this.fetchFlags();
|
|
26463
|
+
}, this)).catch(function() {
|
|
26464
|
+
logger$1.error('Error during flags reset');
|
|
26465
|
+
});
|
|
26203
26466
|
};
|
|
26204
26467
|
|
|
26205
26468
|
FeatureFlagManager.prototype.getFullConfig = function() {
|
|
@@ -26256,12 +26519,11 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26256
26519
|
return Promise.resolve();
|
|
26257
26520
|
}
|
|
26258
26521
|
|
|
26259
|
-
var
|
|
26260
|
-
var
|
|
26522
|
+
var context = this._buildContext();
|
|
26523
|
+
var distinctId = context['distinct_id'];
|
|
26261
26524
|
var traceparent = generateTraceparent();
|
|
26262
26525
|
logger$1.log('Fetching flags for distinct ID: ' + distinctId);
|
|
26263
26526
|
|
|
26264
|
-
var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
|
|
26265
26527
|
var searchParams = new URLSearchParams();
|
|
26266
26528
|
searchParams.set('context', JSON.stringify(context));
|
|
26267
26529
|
searchParams.set('token', this.getMpConfig('token'));
|
|
@@ -26311,7 +26573,8 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26311
26573
|
'value': data['variant_value'],
|
|
26312
26574
|
'experiment_id': data['experiment_id'],
|
|
26313
26575
|
'is_experiment_active': data['is_experiment_active'],
|
|
26314
|
-
'is_qa_tester': data['is_qa_tester']
|
|
26576
|
+
'is_qa_tester': data['is_qa_tester'],
|
|
26577
|
+
'variant_source': 'network'
|
|
26315
26578
|
});
|
|
26316
26579
|
}
|
|
26317
26580
|
}, this);
|
|
@@ -26353,10 +26616,15 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
26353
26616
|
}
|
|
26354
26617
|
|
|
26355
26618
|
this.flags = flags;
|
|
26619
|
+
this.trackedFeatures = new Set();
|
|
26356
26620
|
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
26621
|
+
this._loadedPersistedAtMs = null;
|
|
26622
|
+
this._loadedTtlMs = null;
|
|
26357
26623
|
this._traceparent = traceparent;
|
|
26358
26624
|
|
|
26359
26625
|
this._loadTargetingIfNeeded();
|
|
26626
|
+
|
|
26627
|
+
this.persistence.save(context, this.flags, this.pendingFirstTimeEvents);
|
|
26360
26628
|
}.bind(this)).catch(function(error) {
|
|
26361
26629
|
if (this._fetchInProgressStartTime) {
|
|
26362
26630
|
this.markFetchComplete();
|
|
@@ -26516,6 +26784,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
26516
26784
|
};
|
|
26517
26785
|
|
|
26518
26786
|
this.flags.set(flagKey, newVariant);
|
|
26787
|
+
this.trackedFeatures.delete(flagKey);
|
|
26519
26788
|
this.activatedFirstTimeEvents[eventKey] = true;
|
|
26520
26789
|
|
|
26521
26790
|
this.recordFirstTimeEvent(
|
|
@@ -26527,8 +26796,8 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
|
|
|
26527
26796
|
};
|
|
26528
26797
|
|
|
26529
26798
|
FeatureFlagManager.prototype.getFirstTimeEventApiRoute = function(flagId) {
|
|
26530
|
-
|
|
26531
|
-
return
|
|
26799
|
+
var base = this.getFullApiRoute().replace(/\/$/, '');
|
|
26800
|
+
return base + '/' + flagId + '/first-time-events';
|
|
26532
26801
|
};
|
|
26533
26802
|
|
|
26534
26803
|
FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId, firstTimeEventHash) {
|
|
@@ -26565,35 +26834,106 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
|
|
|
26565
26834
|
};
|
|
26566
26835
|
|
|
26567
26836
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
26568
|
-
if (!this.
|
|
26837
|
+
if (!this.persistenceLoadedPromise) {
|
|
26569
26838
|
return new Promise(function(resolve) {
|
|
26570
26839
|
logger$1.critical('Feature Flags not initialized');
|
|
26571
|
-
resolve(fallback);
|
|
26840
|
+
resolve(withFallbackSource(fallback));
|
|
26572
26841
|
});
|
|
26573
26842
|
}
|
|
26574
26843
|
|
|
26575
|
-
|
|
26576
|
-
|
|
26577
|
-
|
|
26578
|
-
|
|
26579
|
-
|
|
26580
|
-
|
|
26844
|
+
var policy = this.persistence.getPolicy();
|
|
26845
|
+
|
|
26846
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26847
|
+
// 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.
|
|
26848
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26849
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26850
|
+
return this.getVariantSync(featureName, fallback);
|
|
26851
|
+
}
|
|
26852
|
+
if (!this.fetchPromise) {
|
|
26853
|
+
return withFallbackSource(fallback);
|
|
26854
|
+
}
|
|
26855
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26856
|
+
return this.getVariantSync(featureName, fallback);
|
|
26857
|
+
}, this)).catch(function(error) {
|
|
26858
|
+
logger$1.error(error);
|
|
26859
|
+
return withFallbackSource(fallback);
|
|
26860
|
+
});
|
|
26861
|
+
}
|
|
26862
|
+
|
|
26863
|
+
var serve = _.bind(function() { return this.getVariantSync(featureName, fallback); }, this);
|
|
26864
|
+
if (!this.fetchPromise) {
|
|
26865
|
+
return withFallbackSource(fallback);
|
|
26866
|
+
}
|
|
26867
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26868
|
+
}, this));
|
|
26869
|
+
};
|
|
26870
|
+
|
|
26871
|
+
FeatureFlagManager.prototype._loadedPersistenceIsStale = function() {
|
|
26872
|
+
if (!this._loadedPersistedAtMs || !this._loadedTtlMs) {
|
|
26873
|
+
return false;
|
|
26874
|
+
}
|
|
26875
|
+
return Date.now() - this._loadedPersistedAtMs >= this._loadedTtlMs;
|
|
26581
26876
|
};
|
|
26582
26877
|
|
|
26583
26878
|
FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
|
|
26879
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26880
|
+
logger$1.log('Loaded persisted variants are past TTL so returning fallback for "' + featureName + '"');
|
|
26881
|
+
return withFallbackSource(fallback);
|
|
26882
|
+
}
|
|
26584
26883
|
if (!this.areFlagsReady()) {
|
|
26585
26884
|
logger$1.log('Flags not loaded yet');
|
|
26586
|
-
return fallback;
|
|
26885
|
+
return withFallbackSource(fallback);
|
|
26587
26886
|
}
|
|
26588
26887
|
var feature = this.flags.get(featureName);
|
|
26589
26888
|
if (!feature) {
|
|
26590
26889
|
logger$1.log('No flag found: "' + featureName + '"');
|
|
26591
|
-
return fallback;
|
|
26890
|
+
return withFallbackSource(fallback);
|
|
26592
26891
|
}
|
|
26593
26892
|
this.trackFeatureCheck(featureName, feature);
|
|
26594
26893
|
return feature;
|
|
26595
26894
|
};
|
|
26596
26895
|
|
|
26896
|
+
FeatureFlagManager.prototype.getAllVariants = function() {
|
|
26897
|
+
if (!this.persistenceLoadedPromise) {
|
|
26898
|
+
logger$1.critical('Feature Flags not initialized');
|
|
26899
|
+
return Promise.resolve(new Map());
|
|
26900
|
+
}
|
|
26901
|
+
|
|
26902
|
+
var policy = this.persistence.getPolicy();
|
|
26903
|
+
|
|
26904
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26905
|
+
// 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.
|
|
26906
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26907
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26908
|
+
return this.getAllVariantsSync();
|
|
26909
|
+
}
|
|
26910
|
+
if (!this.fetchPromise) {
|
|
26911
|
+
return new Map();
|
|
26912
|
+
}
|
|
26913
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26914
|
+
return this.getAllVariantsSync();
|
|
26915
|
+
}, this)).catch(function(error) {
|
|
26916
|
+
logger$1.error(error);
|
|
26917
|
+
return new Map();
|
|
26918
|
+
});
|
|
26919
|
+
}
|
|
26920
|
+
|
|
26921
|
+
var serve = _.bind(this.getAllVariantsSync, this);
|
|
26922
|
+
if (!this.fetchPromise) {
|
|
26923
|
+
return new Map();
|
|
26924
|
+
}
|
|
26925
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26926
|
+
}, this));
|
|
26927
|
+
};
|
|
26928
|
+
|
|
26929
|
+
FeatureFlagManager.prototype.getAllVariantsSync = function() {
|
|
26930
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26931
|
+
logger$1.log('Loaded persisted variants are past TTL so returning empty Map');
|
|
26932
|
+
return new Map();
|
|
26933
|
+
}
|
|
26934
|
+
return this.flags || new Map();
|
|
26935
|
+
};
|
|
26936
|
+
|
|
26597
26937
|
FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackValue) {
|
|
26598
26938
|
return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
|
|
26599
26939
|
return feature['value'];
|
|
@@ -26632,6 +26972,10 @@ FeatureFlagManager.prototype.isEnabledSync = function(featureName, fallbackValue
|
|
|
26632
26972
|
return val;
|
|
26633
26973
|
};
|
|
26634
26974
|
|
|
26975
|
+
function isPresent(v) {
|
|
26976
|
+
return v !== undefined && v !== null;
|
|
26977
|
+
}
|
|
26978
|
+
|
|
26635
26979
|
FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature) {
|
|
26636
26980
|
if (this.trackedFeatures.has(featureName)) {
|
|
26637
26981
|
return;
|
|
@@ -26642,21 +26986,30 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
26642
26986
|
'Experiment name': featureName,
|
|
26643
26987
|
'Variant name': feature['key'],
|
|
26644
26988
|
'$experiment_type': 'feature_flag',
|
|
26645
|
-
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
26646
|
-
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
26989
|
+
'Variant fetch start time': isPresent(this._fetchStartTime) ? new Date(this._fetchStartTime).toISOString() : null,
|
|
26990
|
+
'Variant fetch complete time': isPresent(this._fetchCompleteTime) ? new Date(this._fetchCompleteTime).toISOString() : null,
|
|
26647
26991
|
'Variant fetch latency (ms)': this._fetchLatency,
|
|
26648
26992
|
'Variant fetch traceparent': this._traceparent,
|
|
26649
26993
|
};
|
|
26650
26994
|
|
|
26651
|
-
if (feature['experiment_id']
|
|
26995
|
+
if (isPresent(feature['experiment_id'])) {
|
|
26652
26996
|
trackingProperties['$experiment_id'] = feature['experiment_id'];
|
|
26653
26997
|
}
|
|
26654
|
-
if (feature['is_experiment_active']
|
|
26998
|
+
if (isPresent(feature['is_experiment_active'])) {
|
|
26655
26999
|
trackingProperties['$is_experiment_active'] = feature['is_experiment_active'];
|
|
26656
27000
|
}
|
|
26657
|
-
if (feature['is_qa_tester']
|
|
27001
|
+
if (isPresent(feature['is_qa_tester'])) {
|
|
26658
27002
|
trackingProperties['$is_qa_tester'] = feature['is_qa_tester'];
|
|
26659
27003
|
}
|
|
27004
|
+
if (isPresent(feature['variant_source'])) {
|
|
27005
|
+
trackingProperties['$variant_source'] = feature['variant_source'];
|
|
27006
|
+
}
|
|
27007
|
+
if (isPresent(feature['persisted_at_in_ms'])) {
|
|
27008
|
+
trackingProperties['$persisted_at_in_ms'] = feature['persisted_at_in_ms'];
|
|
27009
|
+
}
|
|
27010
|
+
if (isPresent(feature['ttl_in_ms'])) {
|
|
27011
|
+
trackingProperties['$ttl_in_ms'] = feature['ttl_in_ms'];
|
|
27012
|
+
}
|
|
26660
27013
|
|
|
26661
27014
|
this.track('$experiment_started', trackingProperties);
|
|
26662
27015
|
};
|
|
@@ -26680,6 +27033,8 @@ safewrapClass(FeatureFlagManager);
|
|
|
26680
27033
|
FeatureFlagManager.prototype['are_flags_ready'] = FeatureFlagManager.prototype.areFlagsReady;
|
|
26681
27034
|
FeatureFlagManager.prototype['get_variant'] = FeatureFlagManager.prototype.getVariant;
|
|
26682
27035
|
FeatureFlagManager.prototype['get_variant_sync'] = FeatureFlagManager.prototype.getVariantSync;
|
|
27036
|
+
FeatureFlagManager.prototype['get_all_variants'] = FeatureFlagManager.prototype.getAllVariants;
|
|
27037
|
+
FeatureFlagManager.prototype['get_all_variants_sync'] = FeatureFlagManager.prototype.getAllVariantsSync;
|
|
26683
27038
|
FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype.getVariantValue;
|
|
26684
27039
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
26685
27040
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
@@ -26732,7 +27087,7 @@ RecorderManager.prototype.shouldLoadRecorder = function() {
|
|
|
26732
27087
|
return PromisePolyfill.resolve(false);
|
|
26733
27088
|
}
|
|
26734
27089
|
|
|
26735
|
-
var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
27090
|
+
var recording_registry_idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
26736
27091
|
var tab_id = this.getTabId();
|
|
26737
27092
|
return recording_registry_idb.init()
|
|
26738
27093
|
.then(function () {
|
|
@@ -28659,6 +29014,7 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28659
29014
|
'disable_all_events': false,
|
|
28660
29015
|
'identify_called': false
|
|
28661
29016
|
};
|
|
29017
|
+
this._remote_settings_strict_disabled = false;
|
|
28662
29018
|
|
|
28663
29019
|
// set up request queueing/batching
|
|
28664
29020
|
this.request_batchers = {};
|
|
@@ -28733,9 +29089,6 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28733
29089
|
this.flags.init();
|
|
28734
29090
|
this['flags'] = this.flags;
|
|
28735
29091
|
|
|
28736
|
-
this.autocapture = new Autocapture(this);
|
|
28737
|
-
this.autocapture.init();
|
|
28738
|
-
|
|
28739
29092
|
this._init_tab_id();
|
|
28740
29093
|
|
|
28741
29094
|
// Based on remote_settings_mode, fetch remote settings and then start session recording if applicable
|
|
@@ -28747,6 +29100,9 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
28747
29100
|
} else {
|
|
28748
29101
|
this.__session_recording_init_promise = this._check_and_start_session_recording();
|
|
28749
29102
|
}
|
|
29103
|
+
|
|
29104
|
+
this.autocapture = new Autocapture(this);
|
|
29105
|
+
this.autocapture.init();
|
|
28750
29106
|
};
|
|
28751
29107
|
|
|
28752
29108
|
/**
|
|
@@ -28793,9 +29149,19 @@ MixpanelLib.prototype._check_and_start_session_recording = addOptOutCheckMixpane
|
|
|
28793
29149
|
return this.recorderManager.checkAndStartSessionRecording(force_start);
|
|
28794
29150
|
});
|
|
28795
29151
|
|
|
28796
|
-
MixpanelLib.prototype._start_recording_on_event = function(event_name, properties) {
|
|
28797
|
-
|
|
28798
|
-
|
|
29152
|
+
MixpanelLib.prototype._start_recording_on_event = safewrap(function(event_name, properties) {
|
|
29153
|
+
// Wait for recording init to complete before evaluating event triggers.
|
|
29154
|
+
// This ensures recording_event_triggers config is fully loaded when remote settings are used.
|
|
29155
|
+
if (this.__session_recording_init_promise) {
|
|
29156
|
+
this.__session_recording_init_promise.then(_.bind(function() {
|
|
29157
|
+
// In strict mode, skip recording if remote settings failed
|
|
29158
|
+
if (this._remote_settings_strict_disabled) {
|
|
29159
|
+
return;
|
|
29160
|
+
}
|
|
29161
|
+
return this.recorderManager.startRecordingOnEvent(event_name, properties);
|
|
29162
|
+
}, this));
|
|
29163
|
+
}
|
|
29164
|
+
});
|
|
28799
29165
|
|
|
28800
29166
|
MixpanelLib.prototype.start_session_recording = function () {
|
|
28801
29167
|
return this._check_and_start_session_recording(true);
|
|
@@ -29094,6 +29460,7 @@ MixpanelLib.prototype._fetch_remote_settings = function(mode) {
|
|
|
29094
29460
|
var disableRecordingIfStrict = function() {
|
|
29095
29461
|
if (mode === 'strict') {
|
|
29096
29462
|
self.set_config({'record_sessions_percent': 0});
|
|
29463
|
+
self._remote_settings_strict_disabled = true;
|
|
29097
29464
|
}
|
|
29098
29465
|
};
|
|
29099
29466
|
|
|
@@ -29719,6 +30086,10 @@ MixpanelLib.prototype.track_pageview = addOptOutCheckMixpanelLib(function(proper
|
|
|
29719
30086
|
properties
|
|
29720
30087
|
);
|
|
29721
30088
|
|
|
30089
|
+
if (this.is_recording_heatmap_data()) {
|
|
30090
|
+
event_properties['$captured_for_heatmap'] = true;
|
|
30091
|
+
}
|
|
30092
|
+
|
|
29722
30093
|
return this.track(event_name, event_properties);
|
|
29723
30094
|
});
|
|
29724
30095
|
|
|
@@ -30062,6 +30433,7 @@ MixpanelLib.prototype.reset = function() {
|
|
|
30062
30433
|
'$device_id': uuid
|
|
30063
30434
|
}, '');
|
|
30064
30435
|
this._check_and_start_session_recording();
|
|
30436
|
+
this.flags.reset();
|
|
30065
30437
|
};
|
|
30066
30438
|
|
|
30067
30439
|
/**
|