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.umd.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
var Config = {
|
|
33
33
|
DEBUG: false,
|
|
34
|
-
LIB_VERSION: '2.
|
|
34
|
+
LIB_VERSION: '2.80.0'
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
// Window global names for async modules
|
|
@@ -19129,6 +19129,7 @@
|
|
|
19129
19129
|
var console_with_prefix = function(prefix) {
|
|
19130
19130
|
return {
|
|
19131
19131
|
log: log_func_with_prefix(console$1.log, prefix),
|
|
19132
|
+
warn: log_func_with_prefix(console$1.warn, prefix),
|
|
19132
19133
|
error: log_func_with_prefix(console$1.error, prefix),
|
|
19133
19134
|
critical: log_func_with_prefix(console$1.critical, prefix)
|
|
19134
19135
|
};
|
|
@@ -20075,7 +20076,8 @@
|
|
|
20075
20076
|
if (_localStorageSupported !== null && !forceCheck) {
|
|
20076
20077
|
return _localStorageSupported;
|
|
20077
20078
|
}
|
|
20078
|
-
|
|
20079
|
+
|
|
20080
|
+
return _localStorageSupported = _testStorageSupported(storage);
|
|
20079
20081
|
};
|
|
20080
20082
|
|
|
20081
20083
|
var _sessionStorageSupported = null;
|
|
@@ -20083,7 +20085,8 @@
|
|
|
20083
20085
|
if (_sessionStorageSupported !== null && !forceCheck) {
|
|
20084
20086
|
return _sessionStorageSupported;
|
|
20085
20087
|
}
|
|
20086
|
-
|
|
20088
|
+
|
|
20089
|
+
return _sessionStorageSupported = _testStorageSupported(storage);
|
|
20087
20090
|
};
|
|
20088
20091
|
|
|
20089
20092
|
function _storageWrapper(storage, name, is_supported_fn) {
|
|
@@ -20133,17 +20136,26 @@
|
|
|
20133
20136
|
};
|
|
20134
20137
|
}
|
|
20135
20138
|
|
|
20136
|
-
// Safari
|
|
20137
|
-
//
|
|
20138
|
-
var
|
|
20139
|
-
|
|
20140
|
-
|
|
20141
|
-
|
|
20142
|
-
|
|
20143
|
-
|
|
20139
|
+
// Safari and other browsers may error out accessing localStorage/sessionStorage
|
|
20140
|
+
// when cookies are disabled, so wrap access in a try-catch.
|
|
20141
|
+
var getLocalStorage = function() {
|
|
20142
|
+
try {
|
|
20143
|
+
return win.localStorage; // eslint-disable-line no-restricted-properties
|
|
20144
|
+
} catch (_err) {
|
|
20145
|
+
return null;
|
|
20146
|
+
}
|
|
20147
|
+
};
|
|
20148
|
+
|
|
20149
|
+
var getSessionStorage = function() {
|
|
20150
|
+
try {
|
|
20151
|
+
return win.sessionStorage; // eslint-disable-line no-restricted-properties
|
|
20152
|
+
} catch (_err) {
|
|
20153
|
+
return null;
|
|
20154
|
+
}
|
|
20155
|
+
};
|
|
20144
20156
|
|
|
20145
|
-
_.localStorage = _storageWrapper(
|
|
20146
|
-
_.sessionStorage = _storageWrapper(
|
|
20157
|
+
_.localStorage = _storageWrapper(getLocalStorage(), 'localStorage', localStorageSupported);
|
|
20158
|
+
_.sessionStorage = _storageWrapper(getSessionStorage(), 'sessionStorage', sessionStorageSupported);
|
|
20147
20159
|
|
|
20148
20160
|
_.register_event = (function() {
|
|
20149
20161
|
// written by Dean Edwards, 2005
|
|
@@ -20812,29 +20824,26 @@
|
|
|
20812
20824
|
_['toArray'] = _.toArray;
|
|
20813
20825
|
_['NPO'] = NpoPromise;
|
|
20814
20826
|
|
|
20815
|
-
var MIXPANEL_DB_NAME = 'mixpanelBrowserDb';
|
|
20816
|
-
|
|
20817
|
-
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
20818
|
-
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
20819
|
-
|
|
20820
|
-
// note: increment the version number when adding new object stores
|
|
20821
|
-
var DB_VERSION = 1;
|
|
20822
|
-
var OBJECT_STORES = [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME];
|
|
20823
|
-
|
|
20824
20827
|
/**
|
|
20825
20828
|
* @type {import('./wrapper').StorageWrapper}
|
|
20826
20829
|
*/
|
|
20827
|
-
var IDBStorageWrapper = function (storeName) {
|
|
20830
|
+
var IDBStorageWrapper = function (dbName, storeName, versionData) {
|
|
20831
|
+
this.dbName = dbName;
|
|
20832
|
+
this.storeName = storeName;
|
|
20833
|
+
this.version = versionData.version;
|
|
20834
|
+
this.storeNamesInDb = versionData.storeNames;
|
|
20828
20835
|
/**
|
|
20829
20836
|
* @type {Promise<IDBDatabase>|null}
|
|
20830
20837
|
*/
|
|
20831
20838
|
this.dbPromise = null;
|
|
20832
|
-
this.storeName = storeName;
|
|
20833
20839
|
};
|
|
20834
20840
|
|
|
20835
20841
|
IDBStorageWrapper.prototype._openDb = function () {
|
|
20842
|
+
var dbName = this.dbName;
|
|
20843
|
+
var version = this.version;
|
|
20844
|
+
var storeNamesInDb = this.storeNamesInDb;
|
|
20836
20845
|
return new PromisePolyfill(function (resolve, reject) {
|
|
20837
|
-
var openRequest = win.indexedDB.open(
|
|
20846
|
+
var openRequest = win.indexedDB.open(dbName, version);
|
|
20838
20847
|
openRequest['onerror'] = function () {
|
|
20839
20848
|
reject(openRequest.error);
|
|
20840
20849
|
};
|
|
@@ -20846,8 +20855,10 @@
|
|
|
20846
20855
|
openRequest['onupgradeneeded'] = function (ev) {
|
|
20847
20856
|
var db = ev.target.result;
|
|
20848
20857
|
|
|
20849
|
-
|
|
20850
|
-
db.
|
|
20858
|
+
storeNamesInDb.forEach(function (storeName) {
|
|
20859
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
20860
|
+
db.createObjectStore(storeName);
|
|
20861
|
+
}
|
|
20851
20862
|
});
|
|
20852
20863
|
};
|
|
20853
20864
|
});
|
|
@@ -20939,6 +20950,16 @@
|
|
|
20939
20950
|
});
|
|
20940
20951
|
};
|
|
20941
20952
|
|
|
20953
|
+
var MIXPANEL_BROWSER_DB_NAME = 'mixpanelBrowserDb';
|
|
20954
|
+
var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
|
|
20955
|
+
var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
|
|
20956
|
+
|
|
20957
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
20958
|
+
var RECORDER_VERSION_DATA = {
|
|
20959
|
+
version: 1,
|
|
20960
|
+
storeNames: [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME]
|
|
20961
|
+
};
|
|
20962
|
+
|
|
20942
20963
|
/**
|
|
20943
20964
|
* GDPR utils
|
|
20944
20965
|
*
|
|
@@ -21239,7 +21260,7 @@
|
|
|
21239
21260
|
};
|
|
21240
21261
|
}
|
|
21241
21262
|
|
|
21242
|
-
var logger$
|
|
21263
|
+
var logger$9 = console_with_prefix('lock');
|
|
21243
21264
|
|
|
21244
21265
|
/**
|
|
21245
21266
|
* SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
|
|
@@ -21265,7 +21286,7 @@
|
|
|
21265
21286
|
options = options || {};
|
|
21266
21287
|
|
|
21267
21288
|
this.storageKey = key;
|
|
21268
|
-
this.storage = options.storage ||
|
|
21289
|
+
this.storage = options.storage || getLocalStorage();
|
|
21269
21290
|
this.pollIntervalMS = options.pollIntervalMS || 100;
|
|
21270
21291
|
this.timeoutMS = options.timeoutMS || 2000;
|
|
21271
21292
|
|
|
@@ -21291,7 +21312,7 @@
|
|
|
21291
21312
|
|
|
21292
21313
|
var delay = function(cb) {
|
|
21293
21314
|
if (new Date().getTime() - startTime > timeoutMS) {
|
|
21294
|
-
logger$
|
|
21315
|
+
logger$9.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
|
|
21295
21316
|
storage.removeItem(keyZ);
|
|
21296
21317
|
storage.removeItem(keyY);
|
|
21297
21318
|
loop();
|
|
@@ -21393,10 +21414,13 @@
|
|
|
21393
21414
|
* @type {import('./wrapper').StorageWrapper}
|
|
21394
21415
|
*/
|
|
21395
21416
|
var LocalStorageWrapper = function (storageOverride) {
|
|
21396
|
-
this.storage = storageOverride ||
|
|
21417
|
+
this.storage = storageOverride || getLocalStorage();
|
|
21397
21418
|
};
|
|
21398
21419
|
|
|
21399
21420
|
LocalStorageWrapper.prototype.init = function () {
|
|
21421
|
+
if (!this.storage) {
|
|
21422
|
+
return PromisePolyfill.reject(new Error('localStorage is not available'));
|
|
21423
|
+
}
|
|
21400
21424
|
return PromisePolyfill.resolve();
|
|
21401
21425
|
};
|
|
21402
21426
|
|
|
@@ -21438,7 +21462,7 @@
|
|
|
21438
21462
|
}, this));
|
|
21439
21463
|
};
|
|
21440
21464
|
|
|
21441
|
-
var logger$
|
|
21465
|
+
var logger$8 = console_with_prefix('batch');
|
|
21442
21466
|
|
|
21443
21467
|
/**
|
|
21444
21468
|
* RequestQueue: queue for batching API requests with localStorage backup for retries.
|
|
@@ -21463,11 +21487,11 @@
|
|
|
21463
21487
|
if (this.usePersistence) {
|
|
21464
21488
|
this.queueStorage = options.queueStorage || new LocalStorageWrapper();
|
|
21465
21489
|
this.lock = new SharedLock(storageKey, {
|
|
21466
|
-
storage: options.sharedLockStorage
|
|
21490
|
+
storage: options.sharedLockStorage,
|
|
21467
21491
|
timeoutMS: options.sharedLockTimeoutMS,
|
|
21468
21492
|
});
|
|
21469
21493
|
}
|
|
21470
|
-
this.reportError = options.errorReporter || _.bind(logger$
|
|
21494
|
+
this.reportError = options.errorReporter || _.bind(logger$8.error, logger$8);
|
|
21471
21495
|
|
|
21472
21496
|
this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
|
|
21473
21497
|
|
|
@@ -21800,7 +21824,7 @@
|
|
|
21800
21824
|
// maximum interval between request retries after exponential backoff
|
|
21801
21825
|
var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
|
|
21802
21826
|
|
|
21803
|
-
var logger$
|
|
21827
|
+
var logger$7 = console_with_prefix('batch');
|
|
21804
21828
|
|
|
21805
21829
|
/**
|
|
21806
21830
|
* RequestBatcher: manages the queueing, flushing, retry etc of requests of one
|
|
@@ -21928,7 +21952,7 @@
|
|
|
21928
21952
|
*/
|
|
21929
21953
|
RequestBatcher.prototype.flush = function(options) {
|
|
21930
21954
|
if (this.requestInProgress) {
|
|
21931
|
-
logger$
|
|
21955
|
+
logger$7.log('Flush: Request already in progress');
|
|
21932
21956
|
return PromisePolyfill.resolve();
|
|
21933
21957
|
}
|
|
21934
21958
|
|
|
@@ -22105,7 +22129,7 @@
|
|
|
22105
22129
|
if (options.unloading) {
|
|
22106
22130
|
requestOptions.transport = 'sendBeacon';
|
|
22107
22131
|
}
|
|
22108
|
-
logger$
|
|
22132
|
+
logger$7.log('MIXPANEL REQUEST:', dataForRequest);
|
|
22109
22133
|
return this.sendRequestPromise(dataForRequest, requestOptions).then(batchSendCallback);
|
|
22110
22134
|
}, this))
|
|
22111
22135
|
.catch(_.bind(function(err) {
|
|
@@ -22118,7 +22142,7 @@
|
|
|
22118
22142
|
* Log error to global logger and optional user-defined logger.
|
|
22119
22143
|
*/
|
|
22120
22144
|
RequestBatcher.prototype.reportError = function(msg, err) {
|
|
22121
|
-
logger$
|
|
22145
|
+
logger$7.error.apply(logger$7.error, arguments);
|
|
22122
22146
|
if (this.errorReporter) {
|
|
22123
22147
|
try {
|
|
22124
22148
|
if (!(err instanceof Error)) {
|
|
@@ -22126,7 +22150,7 @@
|
|
|
22126
22150
|
}
|
|
22127
22151
|
this.errorReporter(msg, err);
|
|
22128
22152
|
} catch(err) {
|
|
22129
|
-
logger$
|
|
22153
|
+
logger$7.error(err);
|
|
22130
22154
|
}
|
|
22131
22155
|
}
|
|
22132
22156
|
};
|
|
@@ -22271,7 +22295,7 @@
|
|
|
22271
22295
|
|
|
22272
22296
|
var MAX_DEPTH = 5;
|
|
22273
22297
|
|
|
22274
|
-
var logger$
|
|
22298
|
+
var logger$6 = console_with_prefix('autocapture');
|
|
22275
22299
|
|
|
22276
22300
|
|
|
22277
22301
|
function getClasses(el) {
|
|
@@ -22535,7 +22559,7 @@
|
|
|
22535
22559
|
return false;
|
|
22536
22560
|
}
|
|
22537
22561
|
} catch (err) {
|
|
22538
|
-
logger$
|
|
22562
|
+
logger$6.critical('Error while checking element in allowElementCallback', err);
|
|
22539
22563
|
return false;
|
|
22540
22564
|
}
|
|
22541
22565
|
}
|
|
@@ -22552,7 +22576,7 @@
|
|
|
22552
22576
|
return true;
|
|
22553
22577
|
}
|
|
22554
22578
|
} catch (err) {
|
|
22555
|
-
logger$
|
|
22579
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
22556
22580
|
}
|
|
22557
22581
|
}
|
|
22558
22582
|
return false;
|
|
@@ -22567,7 +22591,7 @@
|
|
|
22567
22591
|
return true;
|
|
22568
22592
|
}
|
|
22569
22593
|
} catch (err) {
|
|
22570
|
-
logger$
|
|
22594
|
+
logger$6.critical('Error while checking element in blockElementCallback', err);
|
|
22571
22595
|
return true;
|
|
22572
22596
|
}
|
|
22573
22597
|
}
|
|
@@ -22581,7 +22605,7 @@
|
|
|
22581
22605
|
return true;
|
|
22582
22606
|
}
|
|
22583
22607
|
} catch (err) {
|
|
22584
|
-
logger$
|
|
22608
|
+
logger$6.critical('Error while checking selector: ' + sel, err);
|
|
22585
22609
|
}
|
|
22586
22610
|
}
|
|
22587
22611
|
}
|
|
@@ -23137,7 +23161,7 @@
|
|
|
23137
23161
|
*
|
|
23138
23162
|
*/
|
|
23139
23163
|
|
|
23140
|
-
var logger$
|
|
23164
|
+
var logger$5 = console_with_prefix('network-plugin');
|
|
23141
23165
|
|
|
23142
23166
|
/**
|
|
23143
23167
|
* Get the time origin for converting performance timestamps to absolute timestamps.
|
|
@@ -23289,7 +23313,7 @@
|
|
|
23289
23313
|
return str;
|
|
23290
23314
|
}
|
|
23291
23315
|
if (str.length > MAX_BODY_SIZE) {
|
|
23292
|
-
logger$
|
|
23316
|
+
logger$5.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
|
|
23293
23317
|
return str.substring(0, MAX_BODY_SIZE) + '... [truncated]';
|
|
23294
23318
|
}
|
|
23295
23319
|
return str;
|
|
@@ -23303,7 +23327,7 @@
|
|
|
23303
23327
|
*/
|
|
23304
23328
|
function initPerformanceObserver(cb, win, options) {
|
|
23305
23329
|
if (!win.PerformanceObserver) {
|
|
23306
|
-
logger$
|
|
23330
|
+
logger$5.error('PerformanceObserver not supported');
|
|
23307
23331
|
return function() {
|
|
23308
23332
|
//
|
|
23309
23333
|
};
|
|
@@ -23456,7 +23480,7 @@
|
|
|
23456
23480
|
attempt = 0;
|
|
23457
23481
|
}
|
|
23458
23482
|
if (attempt > 10) {
|
|
23459
|
-
logger$
|
|
23483
|
+
logger$5.error('Cannot find performance entry');
|
|
23460
23484
|
return Promise.resolve(null);
|
|
23461
23485
|
}
|
|
23462
23486
|
var urlPerformanceEntries = /** @type {PerformanceResourceTiming[]} */ (
|
|
@@ -23577,7 +23601,7 @@
|
|
|
23577
23601
|
)
|
|
23578
23602
|
.then(function(entry) {
|
|
23579
23603
|
if (!entry) {
|
|
23580
|
-
logger$
|
|
23604
|
+
logger$5.error('Failed to get performance entry for XHR request to ' + req.url);
|
|
23581
23605
|
return;
|
|
23582
23606
|
}
|
|
23583
23607
|
/** @type {NetworkRequest} */
|
|
@@ -23597,7 +23621,7 @@
|
|
|
23597
23621
|
cb({ requests: [request] });
|
|
23598
23622
|
})
|
|
23599
23623
|
.catch(function(e) {
|
|
23600
|
-
logger$
|
|
23624
|
+
logger$5.error('Error recording XHR request to ' + req.url + ': ' + String(e));
|
|
23601
23625
|
});
|
|
23602
23626
|
});
|
|
23603
23627
|
|
|
@@ -23689,7 +23713,7 @@
|
|
|
23689
23713
|
})
|
|
23690
23714
|
.then(function(entry) {
|
|
23691
23715
|
if (!entry) {
|
|
23692
|
-
logger$
|
|
23716
|
+
logger$5.error('Failed to get performance entry for fetch request to ' + req.url);
|
|
23693
23717
|
return;
|
|
23694
23718
|
}
|
|
23695
23719
|
/** @type {NetworkRequest} */
|
|
@@ -23709,7 +23733,7 @@
|
|
|
23709
23733
|
cb({ requests: [request] });
|
|
23710
23734
|
})
|
|
23711
23735
|
.catch(function (e) {
|
|
23712
|
-
logger$
|
|
23736
|
+
logger$5.error('Error recording fetch request to ' + req.url + ': ' + String(e));
|
|
23713
23737
|
});
|
|
23714
23738
|
|
|
23715
23739
|
return originalFetchPromise;
|
|
@@ -23782,7 +23806,7 @@
|
|
|
23782
23806
|
*/
|
|
23783
23807
|
|
|
23784
23808
|
|
|
23785
|
-
var logger$
|
|
23809
|
+
var logger$4 = console_with_prefix('recorder');
|
|
23786
23810
|
var CompressionStream = win['CompressionStream'];
|
|
23787
23811
|
|
|
23788
23812
|
var RECORDER_BATCHER_LIB_CONFIG = {
|
|
@@ -23876,14 +23900,15 @@
|
|
|
23876
23900
|
|
|
23877
23901
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23878
23902
|
this.recordMinMs = 0;
|
|
23903
|
+
this._recordMinMsCheckStart = null;
|
|
23879
23904
|
|
|
23880
23905
|
// disable persistence if localStorage is not supported
|
|
23881
23906
|
// request-queue will automatically disable persistence if indexedDB fails to initialize
|
|
23882
|
-
var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
|
|
23907
|
+
var usePersistence = localStorageSupported(options.sharedLockStorage || getLocalStorage(), true) && !this.getConfig('disable_persistence');
|
|
23883
23908
|
|
|
23884
23909
|
// each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
|
|
23885
23910
|
this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
|
|
23886
|
-
this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
|
|
23911
|
+
this.queueStorage = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_EVENTS_STORE_NAME, RECORDER_VERSION_DATA);
|
|
23887
23912
|
this.batcher = new RequestBatcher(this.batcherKey, {
|
|
23888
23913
|
errorReporter: this.reportError.bind(this),
|
|
23889
23914
|
flushOnlyOnInterval: true,
|
|
@@ -23962,14 +23987,14 @@
|
|
|
23962
23987
|
}
|
|
23963
23988
|
|
|
23964
23989
|
if (this._stopRecording !== null) {
|
|
23965
|
-
logger$
|
|
23990
|
+
logger$4.log('Recording already in progress, skipping startRecording.');
|
|
23966
23991
|
return;
|
|
23967
23992
|
}
|
|
23968
23993
|
|
|
23969
23994
|
this.recordMaxMs = this.getConfig('record_max_ms');
|
|
23970
23995
|
if (this.recordMaxMs > MAX_RECORDING_MS) {
|
|
23971
23996
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23972
|
-
logger$
|
|
23997
|
+
logger$4.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
23973
23998
|
}
|
|
23974
23999
|
|
|
23975
24000
|
if (!this.maxExpires) {
|
|
@@ -23991,6 +24016,7 @@
|
|
|
23991
24016
|
// this also applies if the minimum recording length has not been hit yet
|
|
23992
24017
|
// so that we don't send data until we know the recording will be long enough
|
|
23993
24018
|
this.batcher.stop();
|
|
24019
|
+
this._recordMinMsCheckStart = null;
|
|
23994
24020
|
} else {
|
|
23995
24021
|
this.batcher.start();
|
|
23996
24022
|
}
|
|
@@ -24033,7 +24059,7 @@
|
|
|
24033
24059
|
);
|
|
24034
24060
|
}
|
|
24035
24061
|
|
|
24036
|
-
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$
|
|
24062
|
+
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$4);
|
|
24037
24063
|
|
|
24038
24064
|
try {
|
|
24039
24065
|
this._stopRecording = this._rrwebRecord({
|
|
@@ -24042,9 +24068,11 @@
|
|
|
24042
24068
|
this._onIdleTimeout();
|
|
24043
24069
|
return;
|
|
24044
24070
|
}
|
|
24071
|
+
if (this._recordMinMsCheckStart === null) {
|
|
24072
|
+
this._recordMinMsCheckStart = ev.timestamp;
|
|
24073
|
+
}
|
|
24045
24074
|
if (isUserEvent(ev)) {
|
|
24046
|
-
if (this.batcher.stopped &&
|
|
24047
|
-
// start flushing again after user activity
|
|
24075
|
+
if (this.batcher.stopped && ev.timestamp - this._recordMinMsCheckStart >= this.recordMinMs) {
|
|
24048
24076
|
this.batcher.start();
|
|
24049
24077
|
}
|
|
24050
24078
|
resetIdleTimeout();
|
|
@@ -24295,14 +24323,14 @@
|
|
|
24295
24323
|
|
|
24296
24324
|
|
|
24297
24325
|
SessionRecording.prototype.reportError = function(msg, err) {
|
|
24298
|
-
logger$
|
|
24326
|
+
logger$4.error.apply(logger$4.error, arguments);
|
|
24299
24327
|
try {
|
|
24300
24328
|
if (!err && !(msg instanceof Error)) {
|
|
24301
24329
|
msg = new Error(msg);
|
|
24302
24330
|
}
|
|
24303
24331
|
this.getConfig('error_reporter')(msg, err);
|
|
24304
24332
|
} catch(err) {
|
|
24305
|
-
logger$
|
|
24333
|
+
logger$4.error(err);
|
|
24306
24334
|
}
|
|
24307
24335
|
};
|
|
24308
24336
|
|
|
@@ -24331,7 +24359,7 @@
|
|
|
24331
24359
|
var configValue = this.getConfig('record_min_ms');
|
|
24332
24360
|
|
|
24333
24361
|
if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
24334
|
-
logger$
|
|
24362
|
+
logger$4.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
24335
24363
|
return MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
24336
24364
|
}
|
|
24337
24365
|
|
|
@@ -24373,7 +24401,7 @@
|
|
|
24373
24401
|
*/
|
|
24374
24402
|
var RecordingRegistry = function (options) {
|
|
24375
24403
|
/** @type {IDBStorageWrapper} */
|
|
24376
|
-
this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
24404
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
24377
24405
|
this.errorReporter = options.errorReporter;
|
|
24378
24406
|
this.mixpanelInstance = options.mixpanelInstance;
|
|
24379
24407
|
this.sharedLockStorage = options.sharedLockStorage;
|
|
@@ -24494,7 +24522,7 @@
|
|
|
24494
24522
|
.catch(this.handleError.bind(this));
|
|
24495
24523
|
};
|
|
24496
24524
|
|
|
24497
|
-
var logger$
|
|
24525
|
+
var logger$3 = console_with_prefix('recorder');
|
|
24498
24526
|
|
|
24499
24527
|
/**
|
|
24500
24528
|
* Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
|
|
@@ -24510,7 +24538,7 @@
|
|
|
24510
24538
|
*/
|
|
24511
24539
|
this.recordingRegistry = new RecordingRegistry({
|
|
24512
24540
|
mixpanelInstance: this.mixpanelInstance,
|
|
24513
|
-
errorReporter: logger$
|
|
24541
|
+
errorReporter: logger$3.error,
|
|
24514
24542
|
sharedLockStorage: sharedLockStorage
|
|
24515
24543
|
});
|
|
24516
24544
|
this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
|
|
@@ -24522,17 +24550,17 @@
|
|
|
24522
24550
|
MixpanelRecorder.prototype.startRecording = function(options) {
|
|
24523
24551
|
options = options || {};
|
|
24524
24552
|
if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
|
|
24525
|
-
logger$
|
|
24553
|
+
logger$3.log('Recording already in progress, skipping startRecording.');
|
|
24526
24554
|
return;
|
|
24527
24555
|
}
|
|
24528
24556
|
|
|
24529
24557
|
var onIdleTimeout = function () {
|
|
24530
|
-
logger$
|
|
24558
|
+
logger$3.log('Idle timeout reached, restarting recording.');
|
|
24531
24559
|
this.resetRecording();
|
|
24532
24560
|
}.bind(this);
|
|
24533
24561
|
|
|
24534
24562
|
var onMaxLengthReached = function () {
|
|
24535
|
-
logger$
|
|
24563
|
+
logger$3.log('Max recording length reached, stopping recording.');
|
|
24536
24564
|
this.resetRecording();
|
|
24537
24565
|
}.bind(this);
|
|
24538
24566
|
|
|
@@ -24602,7 +24630,7 @@
|
|
|
24602
24630
|
} else if (startNewIfInactive) {
|
|
24603
24631
|
return this.startRecording({shouldStopBatcher: false});
|
|
24604
24632
|
} else {
|
|
24605
|
-
logger$
|
|
24633
|
+
logger$3.log('No resumable recording found.');
|
|
24606
24634
|
return null;
|
|
24607
24635
|
}
|
|
24608
24636
|
}.bind(this));
|
|
@@ -25267,7 +25295,7 @@
|
|
|
25267
25295
|
observer.observe(shadowRoot, this.observerConfig);
|
|
25268
25296
|
this.shadowObservers.push(observer);
|
|
25269
25297
|
} catch (e) {
|
|
25270
|
-
logger$
|
|
25298
|
+
logger$6.critical('Error while observing shadow root', e);
|
|
25271
25299
|
}
|
|
25272
25300
|
};
|
|
25273
25301
|
|
|
@@ -25278,7 +25306,7 @@
|
|
|
25278
25306
|
}
|
|
25279
25307
|
|
|
25280
25308
|
if (!weakSetSupported()) {
|
|
25281
|
-
logger$
|
|
25309
|
+
logger$6.critical('Shadow DOM observation unavailable: WeakSet not supported');
|
|
25282
25310
|
return;
|
|
25283
25311
|
}
|
|
25284
25312
|
|
|
@@ -25294,7 +25322,7 @@
|
|
|
25294
25322
|
try {
|
|
25295
25323
|
this.shadowObservers[i].disconnect();
|
|
25296
25324
|
} catch (e) {
|
|
25297
|
-
logger$
|
|
25325
|
+
logger$6.critical('Error while disconnecting shadow DOM observer', e);
|
|
25298
25326
|
}
|
|
25299
25327
|
}
|
|
25300
25328
|
this.shadowObservers = [];
|
|
@@ -25482,7 +25510,7 @@
|
|
|
25482
25510
|
|
|
25483
25511
|
this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
|
|
25484
25512
|
} catch (e) {
|
|
25485
|
-
logger$
|
|
25513
|
+
logger$6.critical('Error while setting up mutation observer', e);
|
|
25486
25514
|
}
|
|
25487
25515
|
}
|
|
25488
25516
|
|
|
@@ -25497,7 +25525,7 @@
|
|
|
25497
25525
|
);
|
|
25498
25526
|
this.shadowDOMObserver.start();
|
|
25499
25527
|
} catch (e) {
|
|
25500
|
-
logger$
|
|
25528
|
+
logger$6.critical('Error while setting up shadow DOM observer', e);
|
|
25501
25529
|
this.shadowDOMObserver = null;
|
|
25502
25530
|
}
|
|
25503
25531
|
}
|
|
@@ -25524,7 +25552,7 @@
|
|
|
25524
25552
|
try {
|
|
25525
25553
|
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
25526
25554
|
} catch (e) {
|
|
25527
|
-
logger$
|
|
25555
|
+
logger$6.critical('Error while removing event listener', e);
|
|
25528
25556
|
}
|
|
25529
25557
|
}
|
|
25530
25558
|
this.eventListeners = [];
|
|
@@ -25533,7 +25561,7 @@
|
|
|
25533
25561
|
try {
|
|
25534
25562
|
this.mutationObserver.disconnect();
|
|
25535
25563
|
} catch (e) {
|
|
25536
|
-
logger$
|
|
25564
|
+
logger$6.critical('Error while disconnecting mutation observer', e);
|
|
25537
25565
|
}
|
|
25538
25566
|
this.mutationObserver = null;
|
|
25539
25567
|
}
|
|
@@ -25542,7 +25570,7 @@
|
|
|
25542
25570
|
try {
|
|
25543
25571
|
this.shadowDOMObserver.stop();
|
|
25544
25572
|
} catch (e) {
|
|
25545
|
-
logger$
|
|
25573
|
+
logger$6.critical('Error while stopping shadow DOM observer', e);
|
|
25546
25574
|
}
|
|
25547
25575
|
this.shadowDOMObserver = null;
|
|
25548
25576
|
}
|
|
@@ -25620,7 +25648,7 @@
|
|
|
25620
25648
|
|
|
25621
25649
|
Autocapture.prototype.init = function() {
|
|
25622
25650
|
if (!minDOMApisSupported()) {
|
|
25623
|
-
logger$
|
|
25651
|
+
logger$6.critical('Autocapture unavailable: missing required DOM APIs');
|
|
25624
25652
|
return;
|
|
25625
25653
|
}
|
|
25626
25654
|
this.initPageListeners();
|
|
@@ -25660,7 +25688,7 @@
|
|
|
25660
25688
|
try {
|
|
25661
25689
|
return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
|
|
25662
25690
|
} catch (err) {
|
|
25663
|
-
logger$
|
|
25691
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25664
25692
|
return true;
|
|
25665
25693
|
}
|
|
25666
25694
|
}
|
|
@@ -25673,7 +25701,7 @@
|
|
|
25673
25701
|
try {
|
|
25674
25702
|
return urlMatchesRegexList(currentUrl, blockUrlRegexes);
|
|
25675
25703
|
} catch (err) {
|
|
25676
|
-
logger$
|
|
25704
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25677
25705
|
return true;
|
|
25678
25706
|
}
|
|
25679
25707
|
};
|
|
@@ -25811,7 +25839,7 @@
|
|
|
25811
25839
|
return;
|
|
25812
25840
|
}
|
|
25813
25841
|
|
|
25814
|
-
logger$
|
|
25842
|
+
logger$6.log('Initializing scroll depth tracking');
|
|
25815
25843
|
|
|
25816
25844
|
this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
|
|
25817
25845
|
|
|
@@ -25832,12 +25860,12 @@
|
|
|
25832
25860
|
};
|
|
25833
25861
|
|
|
25834
25862
|
Autocapture.prototype.initClickTracking = function() {
|
|
25835
|
-
win.removeEventListener(EV_CLICK, this.listenerClick);
|
|
25863
|
+
win.removeEventListener(EV_CLICK, this.listenerClick, true);
|
|
25836
25864
|
|
|
25837
25865
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
|
|
25838
25866
|
return;
|
|
25839
25867
|
}
|
|
25840
|
-
logger$
|
|
25868
|
+
logger$6.log('Initializing click tracking');
|
|
25841
25869
|
|
|
25842
25870
|
this.listenerClick = function(ev) {
|
|
25843
25871
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
|
|
@@ -25845,7 +25873,7 @@
|
|
|
25845
25873
|
}
|
|
25846
25874
|
this.trackDomEvent(ev, MP_EV_CLICK);
|
|
25847
25875
|
}.bind(this);
|
|
25848
|
-
win.addEventListener(EV_CLICK, this.listenerClick);
|
|
25876
|
+
win.addEventListener(EV_CLICK, this.listenerClick, true);
|
|
25849
25877
|
};
|
|
25850
25878
|
|
|
25851
25879
|
Autocapture.prototype.initDeadClickTracking = function() {
|
|
@@ -25856,7 +25884,7 @@
|
|
|
25856
25884
|
return;
|
|
25857
25885
|
}
|
|
25858
25886
|
|
|
25859
|
-
logger$
|
|
25887
|
+
logger$6.log('Initializing dead click tracking');
|
|
25860
25888
|
if (!this._deadClickTracker) {
|
|
25861
25889
|
this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
|
|
25862
25890
|
this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
|
|
@@ -25880,17 +25908,17 @@
|
|
|
25880
25908
|
}
|
|
25881
25909
|
this._deadClickTracker.trackClick(ev, normalizedConfig);
|
|
25882
25910
|
}.bind(this);
|
|
25883
|
-
win.addEventListener(EV_CLICK, this.listenerDeadClick);
|
|
25911
|
+
win.addEventListener(EV_CLICK, this.listenerDeadClick, true);
|
|
25884
25912
|
}
|
|
25885
25913
|
};
|
|
25886
25914
|
|
|
25887
25915
|
Autocapture.prototype.initInputTracking = function() {
|
|
25888
|
-
win.removeEventListener(EV_CHANGE, this.listenerChange);
|
|
25916
|
+
win.removeEventListener(EV_CHANGE, this.listenerChange, true);
|
|
25889
25917
|
|
|
25890
25918
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
25891
25919
|
return;
|
|
25892
25920
|
}
|
|
25893
|
-
logger$
|
|
25921
|
+
logger$6.log('Initializing input tracking');
|
|
25894
25922
|
|
|
25895
25923
|
this.listenerChange = function(ev) {
|
|
25896
25924
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
@@ -25898,20 +25926,21 @@
|
|
|
25898
25926
|
}
|
|
25899
25927
|
this.trackDomEvent(ev, MP_EV_INPUT);
|
|
25900
25928
|
}.bind(this);
|
|
25901
|
-
win.addEventListener(EV_CHANGE, this.listenerChange);
|
|
25929
|
+
win.addEventListener(EV_CHANGE, this.listenerChange, true);
|
|
25902
25930
|
};
|
|
25903
25931
|
|
|
25904
25932
|
Autocapture.prototype.initPageviewTracking = function() {
|
|
25905
25933
|
win.removeEventListener(EV_MP_LOCATION_CHANGE, this.listenerLocationchange);
|
|
25906
25934
|
|
|
25907
|
-
if (!this.pageviewTrackingConfig()) {
|
|
25935
|
+
if (!this.pageviewTrackingConfig() && !this.mp.get_config('record_heatmap_data')) {
|
|
25908
25936
|
return;
|
|
25909
25937
|
}
|
|
25910
|
-
logger$
|
|
25938
|
+
logger$6.log('Initializing pageview tracking');
|
|
25911
25939
|
|
|
25912
25940
|
var previousTrackedUrl = '';
|
|
25913
25941
|
var tracked = false;
|
|
25914
|
-
if
|
|
25942
|
+
// Track initial pageview if pageview tracking enabled OR heatmap recording is active
|
|
25943
|
+
if ((this.pageviewTrackingConfig() || this.mp.is_recording_heatmap_data()) && !this.currentUrlBlocked()) {
|
|
25915
25944
|
tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
25916
25945
|
}
|
|
25917
25946
|
if (tracked) {
|
|
@@ -25927,6 +25956,10 @@
|
|
|
25927
25956
|
var shouldTrack = false;
|
|
25928
25957
|
var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
25929
25958
|
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
25959
|
+
if (!trackPageviewOption && this.mp.is_recording_heatmap_data()) {
|
|
25960
|
+
trackPageviewOption = PAGEVIEW_OPTION_FULL_URL;
|
|
25961
|
+
}
|
|
25962
|
+
|
|
25930
25963
|
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
25931
25964
|
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
25932
25965
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
@@ -25942,7 +25975,7 @@
|
|
|
25942
25975
|
}
|
|
25943
25976
|
if (didPathChange) {
|
|
25944
25977
|
this.lastScrollCheckpoint = 0;
|
|
25945
|
-
logger$
|
|
25978
|
+
logger$6.log('Path change: re-initializing scroll depth checkpoints');
|
|
25946
25979
|
}
|
|
25947
25980
|
}
|
|
25948
25981
|
}.bind(this));
|
|
@@ -25950,14 +25983,14 @@
|
|
|
25950
25983
|
};
|
|
25951
25984
|
|
|
25952
25985
|
Autocapture.prototype.initRageClickTracking = function() {
|
|
25953
|
-
win.removeEventListener(EV_CLICK, this.listenerRageClick);
|
|
25986
|
+
win.removeEventListener(EV_CLICK, this.listenerRageClick, true);
|
|
25954
25987
|
|
|
25955
25988
|
var rageClickConfig = this._getClickTrackingConfig(CONFIG_TRACK_RAGE_CLICK);
|
|
25956
25989
|
if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
|
|
25957
25990
|
return;
|
|
25958
25991
|
}
|
|
25959
25992
|
|
|
25960
|
-
logger$
|
|
25993
|
+
logger$6.log('Initializing rage click tracking');
|
|
25961
25994
|
if (!this._rageClickTracker) {
|
|
25962
25995
|
this._rageClickTracker = new RageClickTracker();
|
|
25963
25996
|
}
|
|
@@ -25976,7 +26009,7 @@
|
|
|
25976
26009
|
this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
|
|
25977
26010
|
}
|
|
25978
26011
|
}.bind(this);
|
|
25979
|
-
win.addEventListener(EV_CLICK, this.listenerRageClick);
|
|
26012
|
+
win.addEventListener(EV_CLICK, this.listenerRageClick, true);
|
|
25980
26013
|
};
|
|
25981
26014
|
|
|
25982
26015
|
Autocapture.prototype.initScrollTracking = function() {
|
|
@@ -25987,7 +26020,7 @@
|
|
|
25987
26020
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
25988
26021
|
return;
|
|
25989
26022
|
}
|
|
25990
|
-
logger$
|
|
26023
|
+
logger$6.log('Initializing scroll tracking');
|
|
25991
26024
|
this.lastScrollCheckpoint = 0;
|
|
25992
26025
|
|
|
25993
26026
|
var scrollTrackFunction = function() {
|
|
@@ -26024,7 +26057,7 @@
|
|
|
26024
26057
|
}
|
|
26025
26058
|
}
|
|
26026
26059
|
} catch (err) {
|
|
26027
|
-
logger$
|
|
26060
|
+
logger$6.critical('Error while calculating scroll percentage', err);
|
|
26028
26061
|
}
|
|
26029
26062
|
if (shouldTrack) {
|
|
26030
26063
|
this.mp.track(MP_EV_SCROLL, props);
|
|
@@ -26037,12 +26070,12 @@
|
|
|
26037
26070
|
};
|
|
26038
26071
|
|
|
26039
26072
|
Autocapture.prototype.initSubmitTracking = function() {
|
|
26040
|
-
win.removeEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
26073
|
+
win.removeEventListener(EV_SUBMIT, this.listenerSubmit, true);
|
|
26041
26074
|
|
|
26042
26075
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
26043
26076
|
return;
|
|
26044
26077
|
}
|
|
26045
|
-
logger$
|
|
26078
|
+
logger$6.log('Initializing submit tracking');
|
|
26046
26079
|
|
|
26047
26080
|
this.listenerSubmit = function(ev) {
|
|
26048
26081
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
@@ -26050,7 +26083,7 @@
|
|
|
26050
26083
|
}
|
|
26051
26084
|
this.trackDomEvent(ev, MP_EV_SUBMIT);
|
|
26052
26085
|
}.bind(this);
|
|
26053
|
-
win.addEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
26086
|
+
win.addEventListener(EV_SUBMIT, this.listenerSubmit, true);
|
|
26054
26087
|
};
|
|
26055
26088
|
|
|
26056
26089
|
Autocapture.prototype.initPageLeaveTracking = function() {
|
|
@@ -26064,7 +26097,7 @@
|
|
|
26064
26097
|
return;
|
|
26065
26098
|
}
|
|
26066
26099
|
|
|
26067
|
-
logger$
|
|
26100
|
+
logger$6.log('Initializing page visibility tracking.');
|
|
26068
26101
|
this._initScrollDepthTracking();
|
|
26069
26102
|
var previousTrackedUrl = _.info.currentUrl();
|
|
26070
26103
|
|
|
@@ -26106,7 +26139,7 @@
|
|
|
26106
26139
|
|
|
26107
26140
|
Autocapture.prototype.stopDeadClickTracking = function() {
|
|
26108
26141
|
if (this.listenerDeadClick) {
|
|
26109
|
-
win.removeEventListener(EV_CLICK, this.listenerDeadClick);
|
|
26142
|
+
win.removeEventListener(EV_CLICK, this.listenerDeadClick, true);
|
|
26110
26143
|
this.listenerDeadClick = null;
|
|
26111
26144
|
}
|
|
26112
26145
|
|
|
@@ -26149,10 +26182,183 @@
|
|
|
26149
26182
|
return win[TARGETING_GLOBAL_NAME];
|
|
26150
26183
|
};
|
|
26151
26184
|
|
|
26185
|
+
var logger$2 = console_with_prefix('flags');
|
|
26186
|
+
|
|
26187
|
+
var MIXPANEL_FLAGS_DB_NAME = 'mixpanelFlagsDb';
|
|
26188
|
+
var FLAGS_STORE_NAME = 'mixpanelFlags';
|
|
26189
|
+
|
|
26190
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
26191
|
+
var FLAGS_VERSION_DATA = { version: 1, storeNames: [FLAGS_STORE_NAME] };
|
|
26192
|
+
|
|
26193
|
+
var PERSISTED_VARIANTS_KEY_PREFIX = 'persisted_variants_for_';
|
|
26194
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
26195
|
+
|
|
26196
|
+
var VariantLookupPolicy = Object.freeze({
|
|
26197
|
+
NETWORK_ONLY: 'networkOnly',
|
|
26198
|
+
NETWORK_FIRST: 'networkFirst',
|
|
26199
|
+
PERSISTENCE_UNTIL_NETWORK_SUCCESS: 'persistenceUntilNetworkSuccess'
|
|
26200
|
+
});
|
|
26201
|
+
|
|
26202
|
+
var VALID_POLICIES = [
|
|
26203
|
+
VariantLookupPolicy.NETWORK_ONLY,
|
|
26204
|
+
VariantLookupPolicy.NETWORK_FIRST,
|
|
26205
|
+
VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS
|
|
26206
|
+
];
|
|
26207
|
+
|
|
26208
|
+
/**
|
|
26209
|
+
* Module for handling the storage and retrieval of persisted feature flag variants.
|
|
26210
|
+
*/
|
|
26211
|
+
var FeatureFlagPersistence = function(persistenceConfig, token, isGloballyDisabled) {
|
|
26212
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_FLAGS_DB_NAME, FLAGS_STORE_NAME, FLAGS_VERSION_DATA);
|
|
26213
|
+
this.persistenceConfig = persistenceConfig;
|
|
26214
|
+
this.persistedVariantsKey = PERSISTED_VARIANTS_KEY_PREFIX + token;
|
|
26215
|
+
this.isGloballyDisabled = isGloballyDisabled || function() { return false; };
|
|
26216
|
+
};
|
|
26217
|
+
|
|
26218
|
+
FeatureFlagPersistence.prototype.getPolicy = function() {
|
|
26219
|
+
if (this.isGloballyDisabled() || !this._isConfigValid()) {
|
|
26220
|
+
return VariantLookupPolicy.NETWORK_ONLY;
|
|
26221
|
+
}
|
|
26222
|
+
return this.persistenceConfig['variantLookupPolicy'];
|
|
26223
|
+
};
|
|
26224
|
+
|
|
26225
|
+
FeatureFlagPersistence.prototype.getTtlMs = function() {
|
|
26226
|
+
if (!this._isConfigValid()) {
|
|
26227
|
+
return DEFAULT_TTL_MS;
|
|
26228
|
+
}
|
|
26229
|
+
var configuredTtl = this.persistenceConfig['persistenceTtlMs'];
|
|
26230
|
+
return (configuredTtl === undefined || configuredTtl === null) ? DEFAULT_TTL_MS : configuredTtl;
|
|
26231
|
+
};
|
|
26232
|
+
|
|
26233
|
+
FeatureFlagPersistence.prototype._isConfigValid = function() {
|
|
26234
|
+
var config = this.persistenceConfig;
|
|
26235
|
+
if (!config) {
|
|
26236
|
+
return false;
|
|
26237
|
+
}
|
|
26238
|
+
|
|
26239
|
+
if (VALID_POLICIES.indexOf(config['variantLookupPolicy']) === -1) {
|
|
26240
|
+
logger$2.error('Invalid variantLookupPolicy:', config['variantLookupPolicy']);
|
|
26241
|
+
return false;
|
|
26242
|
+
}
|
|
26243
|
+
|
|
26244
|
+
if (config['persistenceTtlMs'] !== undefined &&
|
|
26245
|
+
config['persistenceTtlMs'] !== null &&
|
|
26246
|
+
config['persistenceTtlMs'] <= 0) {
|
|
26247
|
+
logger$2.error('If provided, persistenceTtlMs must be a positive number. Provided value:', config['persistenceTtlMs']);
|
|
26248
|
+
return false;
|
|
26249
|
+
}
|
|
26250
|
+
|
|
26251
|
+
return true;
|
|
26252
|
+
};
|
|
26253
|
+
|
|
26254
|
+
FeatureFlagPersistence.prototype.loadFlagsFromStorage = function(context) {
|
|
26255
|
+
var clearAndReturnNull = _.bind(function() {
|
|
26256
|
+
return this.clear().then(function() { return null; }).catch(function() { return null; });
|
|
26257
|
+
}, this);
|
|
26258
|
+
|
|
26259
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26260
|
+
return clearAndReturnNull();
|
|
26261
|
+
}
|
|
26262
|
+
|
|
26263
|
+
var ttlMs = this.getTtlMs();
|
|
26264
|
+
|
|
26265
|
+
return this.idb.init().then(_.bind(function() {
|
|
26266
|
+
return this.idb.getItem(this.persistedVariantsKey);
|
|
26267
|
+
}, this)).then(_.bind(function(data) {
|
|
26268
|
+
if (!data) {
|
|
26269
|
+
logger$2.log('No persisted variants found in IndexedDB');
|
|
26270
|
+
return null;
|
|
26271
|
+
}
|
|
26272
|
+
|
|
26273
|
+
if (ttlMs && Date.now() - data['persistedAt'] >= ttlMs) {
|
|
26274
|
+
logger$2.log('Persisted variants are expiring');
|
|
26275
|
+
return null;
|
|
26276
|
+
}
|
|
26277
|
+
|
|
26278
|
+
if (!context || data['distinctId'] !== context['distinct_id']) {
|
|
26279
|
+
logger$2.log('Persisted variants found, but for a different distinct_id so clearing.');
|
|
26280
|
+
return clearAndReturnNull();
|
|
26281
|
+
}
|
|
26282
|
+
|
|
26283
|
+
var persistedFlags = new Map();
|
|
26284
|
+
_.each(data['flagVariants'], function(variantData, key) {
|
|
26285
|
+
persistedFlags.set(key, {
|
|
26286
|
+
'key': variantData['variant_key'],
|
|
26287
|
+
'value': variantData['variant_value'],
|
|
26288
|
+
'experiment_id': variantData['experiment_id'],
|
|
26289
|
+
'is_experiment_active': variantData['is_experiment_active'],
|
|
26290
|
+
'is_qa_tester': variantData['is_qa_tester'],
|
|
26291
|
+
'variant_source': 'persistence',
|
|
26292
|
+
'persisted_at_in_ms': data['persistedAt'],
|
|
26293
|
+
'ttl_in_ms': ttlMs
|
|
26294
|
+
});
|
|
26295
|
+
});
|
|
26296
|
+
|
|
26297
|
+
logger$2.log('Loaded', persistedFlags.size, 'variants from IndexedDB for distinct_id', data['distinctId']);
|
|
26298
|
+
|
|
26299
|
+
return {
|
|
26300
|
+
flags: persistedFlags,
|
|
26301
|
+
pendingFirstTimeEvents: data['pendingFirstTimeEvents'] || {},
|
|
26302
|
+
persistedAtMs: data['persistedAt'],
|
|
26303
|
+
ttlMs: ttlMs
|
|
26304
|
+
};
|
|
26305
|
+
}, this)).catch(_.bind(function(error) {
|
|
26306
|
+
logger$2.error('Failed to load persisted variants from IndexedDB, so clearing', error);
|
|
26307
|
+
return clearAndReturnNull();
|
|
26308
|
+
}, this));
|
|
26309
|
+
};
|
|
26310
|
+
|
|
26311
|
+
FeatureFlagPersistence.prototype.save = function(context, flagsMap, pendingFirstTimeEvents) {
|
|
26312
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26313
|
+
return Promise.resolve();
|
|
26314
|
+
}
|
|
26315
|
+
|
|
26316
|
+
var flagVariants = {};
|
|
26317
|
+
flagsMap.forEach(function(variant, key) {
|
|
26318
|
+
flagVariants[key] = {
|
|
26319
|
+
'variant_key': variant['key'],
|
|
26320
|
+
'variant_value': variant['value'],
|
|
26321
|
+
'experiment_id': variant['experiment_id'],
|
|
26322
|
+
'is_experiment_active': variant['is_experiment_active'],
|
|
26323
|
+
'is_qa_tester': variant['is_qa_tester']
|
|
26324
|
+
};
|
|
26325
|
+
});
|
|
26326
|
+
|
|
26327
|
+
var data = {
|
|
26328
|
+
'persistedAt': Date.now(),
|
|
26329
|
+
'distinctId': context && context['distinct_id'],
|
|
26330
|
+
'context': context,
|
|
26331
|
+
'flagVariants': flagVariants,
|
|
26332
|
+
'pendingFirstTimeEvents': pendingFirstTimeEvents || {}
|
|
26333
|
+
};
|
|
26334
|
+
|
|
26335
|
+
return this.idb.init().then(_.bind(function() {
|
|
26336
|
+
return this.idb.setItem(this.persistedVariantsKey, data);
|
|
26337
|
+
}, this)).then(function() {
|
|
26338
|
+
logger$2.log('Saved', flagsMap.size, 'variants to IndexedDB for distinct_id', data['distinctId']);
|
|
26339
|
+
}).catch(function(error) {
|
|
26340
|
+
logger$2.error('Failed to persist variants to IndexedDB:', error);
|
|
26341
|
+
});
|
|
26342
|
+
};
|
|
26343
|
+
|
|
26344
|
+
FeatureFlagPersistence.prototype.clear = function() {
|
|
26345
|
+
if (this.isGloballyDisabled()) {
|
|
26346
|
+
return Promise.resolve();
|
|
26347
|
+
}
|
|
26348
|
+
return this.idb.init().then(_.bind(function() {
|
|
26349
|
+
return this.idb.removeItem(this.persistedVariantsKey);
|
|
26350
|
+
}, this)).then(function() {
|
|
26351
|
+
logger$2.log('Cleared persisted variants from IndexedDB');
|
|
26352
|
+
}).catch(function(error) {
|
|
26353
|
+
logger$2.error('Failed to clear persisted variants from IndexedDB:', error);
|
|
26354
|
+
});
|
|
26355
|
+
};
|
|
26356
|
+
|
|
26152
26357
|
var logger$1 = console_with_prefix('flags');
|
|
26153
26358
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
26154
26359
|
|
|
26155
26360
|
var CONFIG_CONTEXT = 'context';
|
|
26361
|
+
var CONFIG_PERSISTENCE = 'persistence';
|
|
26156
26362
|
var CONFIG_DEFAULTS = {};
|
|
26157
26363
|
CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
26158
26364
|
|
|
@@ -26175,6 +26381,13 @@
|
|
|
26175
26381
|
return eventKey.split(':')[0];
|
|
26176
26382
|
};
|
|
26177
26383
|
|
|
26384
|
+
var withFallbackSource = function(fallback) {
|
|
26385
|
+
if (_.isObject(fallback)) {
|
|
26386
|
+
return _.extend({}, fallback, {'variant_source': 'fallback'});
|
|
26387
|
+
}
|
|
26388
|
+
return {'value': fallback, 'variant_source': 'fallback'};
|
|
26389
|
+
};
|
|
26390
|
+
|
|
26178
26391
|
/**
|
|
26179
26392
|
* FeatureFlagManager: support for Mixpanel's feature flagging product
|
|
26180
26393
|
* @constructor
|
|
@@ -26197,13 +26410,63 @@
|
|
|
26197
26410
|
}
|
|
26198
26411
|
|
|
26199
26412
|
this.flags = null;
|
|
26200
|
-
this.fetchFlags().catch(function() {
|
|
26201
|
-
logger$1.error('Error fetching flags during init');
|
|
26202
|
-
});
|
|
26203
|
-
|
|
26204
26413
|
this.trackedFeatures = new Set();
|
|
26205
26414
|
this.pendingFirstTimeEvents = {};
|
|
26206
26415
|
this.activatedFirstTimeEvents = {};
|
|
26416
|
+
this._loadedPersistedAtMs = null;
|
|
26417
|
+
this._loadedTtlMs = null;
|
|
26418
|
+
|
|
26419
|
+
this.persistence = new FeatureFlagPersistence(
|
|
26420
|
+
this.getConfig(CONFIG_PERSISTENCE),
|
|
26421
|
+
this.getMpConfig('token'),
|
|
26422
|
+
_.bind(function() { return this.getMpConfig('disable_persistence'); }, this)
|
|
26423
|
+
);
|
|
26424
|
+
|
|
26425
|
+
this.persistenceLoadedPromise = this.persistence.loadFlagsFromStorage(this._buildContext())
|
|
26426
|
+
.then(_.bind(function(loaded) {
|
|
26427
|
+
if (loaded) {
|
|
26428
|
+
this.flags = loaded.flags;
|
|
26429
|
+
this.pendingFirstTimeEvents = loaded.pendingFirstTimeEvents;
|
|
26430
|
+
this._loadedPersistedAtMs = loaded.persistedAtMs;
|
|
26431
|
+
this._loadedTtlMs = loaded.ttlMs;
|
|
26432
|
+
}
|
|
26433
|
+
}, this));
|
|
26434
|
+
|
|
26435
|
+
return this.persistenceLoadedPromise
|
|
26436
|
+
.then(_.bind(function() {
|
|
26437
|
+
return this.fetchFlags();
|
|
26438
|
+
}, this))
|
|
26439
|
+
.catch(function() {
|
|
26440
|
+
logger$1.error('Error initializing feature flags');
|
|
26441
|
+
});
|
|
26442
|
+
};
|
|
26443
|
+
|
|
26444
|
+
FeatureFlagManager.prototype._buildContext = function() {
|
|
26445
|
+
return _.extend(
|
|
26446
|
+
{'distinct_id': this.getMpProperty('distinct_id'), 'device_id': this.getMpProperty('$device_id')},
|
|
26447
|
+
this.getConfig(CONFIG_CONTEXT)
|
|
26448
|
+
);
|
|
26449
|
+
};
|
|
26450
|
+
|
|
26451
|
+
FeatureFlagManager.prototype.reset = function() {
|
|
26452
|
+
if (!this.persistence) {
|
|
26453
|
+
return Promise.resolve();
|
|
26454
|
+
}
|
|
26455
|
+
|
|
26456
|
+
this.flags = null;
|
|
26457
|
+
this.pendingFirstTimeEvents = {};
|
|
26458
|
+
this.activatedFirstTimeEvents = {};
|
|
26459
|
+
this.trackedFeatures = new Set();
|
|
26460
|
+
this.fetchPromise = null;
|
|
26461
|
+
this._fetchInProgressStartTime = null;
|
|
26462
|
+
this._loadedPersistedAtMs = null;
|
|
26463
|
+
this._loadedTtlMs = null;
|
|
26464
|
+
|
|
26465
|
+
return this.persistence.clear().then(_.bind(function() {
|
|
26466
|
+
return this.fetchFlags();
|
|
26467
|
+
}, this)).catch(function() {
|
|
26468
|
+
logger$1.error('Error during flags reset');
|
|
26469
|
+
});
|
|
26207
26470
|
};
|
|
26208
26471
|
|
|
26209
26472
|
FeatureFlagManager.prototype.getFullConfig = function() {
|
|
@@ -26260,12 +26523,11 @@
|
|
|
26260
26523
|
return Promise.resolve();
|
|
26261
26524
|
}
|
|
26262
26525
|
|
|
26263
|
-
var
|
|
26264
|
-
var
|
|
26526
|
+
var context = this._buildContext();
|
|
26527
|
+
var distinctId = context['distinct_id'];
|
|
26265
26528
|
var traceparent = generateTraceparent();
|
|
26266
26529
|
logger$1.log('Fetching flags for distinct ID: ' + distinctId);
|
|
26267
26530
|
|
|
26268
|
-
var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
|
|
26269
26531
|
var searchParams = new URLSearchParams();
|
|
26270
26532
|
searchParams.set('context', JSON.stringify(context));
|
|
26271
26533
|
searchParams.set('token', this.getMpConfig('token'));
|
|
@@ -26315,7 +26577,8 @@
|
|
|
26315
26577
|
'value': data['variant_value'],
|
|
26316
26578
|
'experiment_id': data['experiment_id'],
|
|
26317
26579
|
'is_experiment_active': data['is_experiment_active'],
|
|
26318
|
-
'is_qa_tester': data['is_qa_tester']
|
|
26580
|
+
'is_qa_tester': data['is_qa_tester'],
|
|
26581
|
+
'variant_source': 'network'
|
|
26319
26582
|
});
|
|
26320
26583
|
}
|
|
26321
26584
|
}, this);
|
|
@@ -26357,10 +26620,15 @@
|
|
|
26357
26620
|
}
|
|
26358
26621
|
|
|
26359
26622
|
this.flags = flags;
|
|
26623
|
+
this.trackedFeatures = new Set();
|
|
26360
26624
|
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
26625
|
+
this._loadedPersistedAtMs = null;
|
|
26626
|
+
this._loadedTtlMs = null;
|
|
26361
26627
|
this._traceparent = traceparent;
|
|
26362
26628
|
|
|
26363
26629
|
this._loadTargetingIfNeeded();
|
|
26630
|
+
|
|
26631
|
+
this.persistence.save(context, this.flags, this.pendingFirstTimeEvents);
|
|
26364
26632
|
}.bind(this)).catch(function(error) {
|
|
26365
26633
|
if (this._fetchInProgressStartTime) {
|
|
26366
26634
|
this.markFetchComplete();
|
|
@@ -26520,6 +26788,7 @@
|
|
|
26520
26788
|
};
|
|
26521
26789
|
|
|
26522
26790
|
this.flags.set(flagKey, newVariant);
|
|
26791
|
+
this.trackedFeatures.delete(flagKey);
|
|
26523
26792
|
this.activatedFirstTimeEvents[eventKey] = true;
|
|
26524
26793
|
|
|
26525
26794
|
this.recordFirstTimeEvent(
|
|
@@ -26531,8 +26800,8 @@
|
|
|
26531
26800
|
};
|
|
26532
26801
|
|
|
26533
26802
|
FeatureFlagManager.prototype.getFirstTimeEventApiRoute = function(flagId) {
|
|
26534
|
-
|
|
26535
|
-
return
|
|
26803
|
+
var base = this.getFullApiRoute().replace(/\/$/, '');
|
|
26804
|
+
return base + '/' + flagId + '/first-time-events';
|
|
26536
26805
|
};
|
|
26537
26806
|
|
|
26538
26807
|
FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId, firstTimeEventHash) {
|
|
@@ -26569,35 +26838,106 @@
|
|
|
26569
26838
|
};
|
|
26570
26839
|
|
|
26571
26840
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
26572
|
-
if (!this.
|
|
26841
|
+
if (!this.persistenceLoadedPromise) {
|
|
26573
26842
|
return new Promise(function(resolve) {
|
|
26574
26843
|
logger$1.critical('Feature Flags not initialized');
|
|
26575
|
-
resolve(fallback);
|
|
26844
|
+
resolve(withFallbackSource(fallback));
|
|
26576
26845
|
});
|
|
26577
26846
|
}
|
|
26578
26847
|
|
|
26579
|
-
|
|
26580
|
-
|
|
26581
|
-
|
|
26582
|
-
|
|
26583
|
-
|
|
26584
|
-
|
|
26848
|
+
var policy = this.persistence.getPolicy();
|
|
26849
|
+
|
|
26850
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26851
|
+
// 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.
|
|
26852
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26853
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26854
|
+
return this.getVariantSync(featureName, fallback);
|
|
26855
|
+
}
|
|
26856
|
+
if (!this.fetchPromise) {
|
|
26857
|
+
return withFallbackSource(fallback);
|
|
26858
|
+
}
|
|
26859
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26860
|
+
return this.getVariantSync(featureName, fallback);
|
|
26861
|
+
}, this)).catch(function(error) {
|
|
26862
|
+
logger$1.error(error);
|
|
26863
|
+
return withFallbackSource(fallback);
|
|
26864
|
+
});
|
|
26865
|
+
}
|
|
26866
|
+
|
|
26867
|
+
var serve = _.bind(function() { return this.getVariantSync(featureName, fallback); }, this);
|
|
26868
|
+
if (!this.fetchPromise) {
|
|
26869
|
+
return withFallbackSource(fallback);
|
|
26870
|
+
}
|
|
26871
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26872
|
+
}, this));
|
|
26873
|
+
};
|
|
26874
|
+
|
|
26875
|
+
FeatureFlagManager.prototype._loadedPersistenceIsStale = function() {
|
|
26876
|
+
if (!this._loadedPersistedAtMs || !this._loadedTtlMs) {
|
|
26877
|
+
return false;
|
|
26878
|
+
}
|
|
26879
|
+
return Date.now() - this._loadedPersistedAtMs >= this._loadedTtlMs;
|
|
26585
26880
|
};
|
|
26586
26881
|
|
|
26587
26882
|
FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
|
|
26883
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26884
|
+
logger$1.log('Loaded persisted variants are past TTL so returning fallback for "' + featureName + '"');
|
|
26885
|
+
return withFallbackSource(fallback);
|
|
26886
|
+
}
|
|
26588
26887
|
if (!this.areFlagsReady()) {
|
|
26589
26888
|
logger$1.log('Flags not loaded yet');
|
|
26590
|
-
return fallback;
|
|
26889
|
+
return withFallbackSource(fallback);
|
|
26591
26890
|
}
|
|
26592
26891
|
var feature = this.flags.get(featureName);
|
|
26593
26892
|
if (!feature) {
|
|
26594
26893
|
logger$1.log('No flag found: "' + featureName + '"');
|
|
26595
|
-
return fallback;
|
|
26894
|
+
return withFallbackSource(fallback);
|
|
26596
26895
|
}
|
|
26597
26896
|
this.trackFeatureCheck(featureName, feature);
|
|
26598
26897
|
return feature;
|
|
26599
26898
|
};
|
|
26600
26899
|
|
|
26900
|
+
FeatureFlagManager.prototype.getAllVariants = function() {
|
|
26901
|
+
if (!this.persistenceLoadedPromise) {
|
|
26902
|
+
logger$1.critical('Feature Flags not initialized');
|
|
26903
|
+
return Promise.resolve(new Map());
|
|
26904
|
+
}
|
|
26905
|
+
|
|
26906
|
+
var policy = this.persistence.getPolicy();
|
|
26907
|
+
|
|
26908
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26909
|
+
// 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.
|
|
26910
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26911
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26912
|
+
return this.getAllVariantsSync();
|
|
26913
|
+
}
|
|
26914
|
+
if (!this.fetchPromise) {
|
|
26915
|
+
return new Map();
|
|
26916
|
+
}
|
|
26917
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26918
|
+
return this.getAllVariantsSync();
|
|
26919
|
+
}, this)).catch(function(error) {
|
|
26920
|
+
logger$1.error(error);
|
|
26921
|
+
return new Map();
|
|
26922
|
+
});
|
|
26923
|
+
}
|
|
26924
|
+
|
|
26925
|
+
var serve = _.bind(this.getAllVariantsSync, this);
|
|
26926
|
+
if (!this.fetchPromise) {
|
|
26927
|
+
return new Map();
|
|
26928
|
+
}
|
|
26929
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26930
|
+
}, this));
|
|
26931
|
+
};
|
|
26932
|
+
|
|
26933
|
+
FeatureFlagManager.prototype.getAllVariantsSync = function() {
|
|
26934
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26935
|
+
logger$1.log('Loaded persisted variants are past TTL so returning empty Map');
|
|
26936
|
+
return new Map();
|
|
26937
|
+
}
|
|
26938
|
+
return this.flags || new Map();
|
|
26939
|
+
};
|
|
26940
|
+
|
|
26601
26941
|
FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackValue) {
|
|
26602
26942
|
return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
|
|
26603
26943
|
return feature['value'];
|
|
@@ -26636,6 +26976,10 @@
|
|
|
26636
26976
|
return val;
|
|
26637
26977
|
};
|
|
26638
26978
|
|
|
26979
|
+
function isPresent(v) {
|
|
26980
|
+
return v !== undefined && v !== null;
|
|
26981
|
+
}
|
|
26982
|
+
|
|
26639
26983
|
FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature) {
|
|
26640
26984
|
if (this.trackedFeatures.has(featureName)) {
|
|
26641
26985
|
return;
|
|
@@ -26646,21 +26990,30 @@
|
|
|
26646
26990
|
'Experiment name': featureName,
|
|
26647
26991
|
'Variant name': feature['key'],
|
|
26648
26992
|
'$experiment_type': 'feature_flag',
|
|
26649
|
-
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
26650
|
-
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
26993
|
+
'Variant fetch start time': isPresent(this._fetchStartTime) ? new Date(this._fetchStartTime).toISOString() : null,
|
|
26994
|
+
'Variant fetch complete time': isPresent(this._fetchCompleteTime) ? new Date(this._fetchCompleteTime).toISOString() : null,
|
|
26651
26995
|
'Variant fetch latency (ms)': this._fetchLatency,
|
|
26652
26996
|
'Variant fetch traceparent': this._traceparent,
|
|
26653
26997
|
};
|
|
26654
26998
|
|
|
26655
|
-
if (feature['experiment_id']
|
|
26999
|
+
if (isPresent(feature['experiment_id'])) {
|
|
26656
27000
|
trackingProperties['$experiment_id'] = feature['experiment_id'];
|
|
26657
27001
|
}
|
|
26658
|
-
if (feature['is_experiment_active']
|
|
27002
|
+
if (isPresent(feature['is_experiment_active'])) {
|
|
26659
27003
|
trackingProperties['$is_experiment_active'] = feature['is_experiment_active'];
|
|
26660
27004
|
}
|
|
26661
|
-
if (feature['is_qa_tester']
|
|
27005
|
+
if (isPresent(feature['is_qa_tester'])) {
|
|
26662
27006
|
trackingProperties['$is_qa_tester'] = feature['is_qa_tester'];
|
|
26663
27007
|
}
|
|
27008
|
+
if (isPresent(feature['variant_source'])) {
|
|
27009
|
+
trackingProperties['$variant_source'] = feature['variant_source'];
|
|
27010
|
+
}
|
|
27011
|
+
if (isPresent(feature['persisted_at_in_ms'])) {
|
|
27012
|
+
trackingProperties['$persisted_at_in_ms'] = feature['persisted_at_in_ms'];
|
|
27013
|
+
}
|
|
27014
|
+
if (isPresent(feature['ttl_in_ms'])) {
|
|
27015
|
+
trackingProperties['$ttl_in_ms'] = feature['ttl_in_ms'];
|
|
27016
|
+
}
|
|
26664
27017
|
|
|
26665
27018
|
this.track('$experiment_started', trackingProperties);
|
|
26666
27019
|
};
|
|
@@ -26684,6 +27037,8 @@
|
|
|
26684
27037
|
FeatureFlagManager.prototype['are_flags_ready'] = FeatureFlagManager.prototype.areFlagsReady;
|
|
26685
27038
|
FeatureFlagManager.prototype['get_variant'] = FeatureFlagManager.prototype.getVariant;
|
|
26686
27039
|
FeatureFlagManager.prototype['get_variant_sync'] = FeatureFlagManager.prototype.getVariantSync;
|
|
27040
|
+
FeatureFlagManager.prototype['get_all_variants'] = FeatureFlagManager.prototype.getAllVariants;
|
|
27041
|
+
FeatureFlagManager.prototype['get_all_variants_sync'] = FeatureFlagManager.prototype.getAllVariantsSync;
|
|
26687
27042
|
FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype.getVariantValue;
|
|
26688
27043
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
26689
27044
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
@@ -26736,7 +27091,7 @@
|
|
|
26736
27091
|
return PromisePolyfill.resolve(false);
|
|
26737
27092
|
}
|
|
26738
27093
|
|
|
26739
|
-
var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
27094
|
+
var recording_registry_idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
26740
27095
|
var tab_id = this.getTabId();
|
|
26741
27096
|
return recording_registry_idb.init()
|
|
26742
27097
|
.then(function () {
|
|
@@ -28663,6 +29018,7 @@
|
|
|
28663
29018
|
'disable_all_events': false,
|
|
28664
29019
|
'identify_called': false
|
|
28665
29020
|
};
|
|
29021
|
+
this._remote_settings_strict_disabled = false;
|
|
28666
29022
|
|
|
28667
29023
|
// set up request queueing/batching
|
|
28668
29024
|
this.request_batchers = {};
|
|
@@ -28737,9 +29093,6 @@
|
|
|
28737
29093
|
this.flags.init();
|
|
28738
29094
|
this['flags'] = this.flags;
|
|
28739
29095
|
|
|
28740
|
-
this.autocapture = new Autocapture(this);
|
|
28741
|
-
this.autocapture.init();
|
|
28742
|
-
|
|
28743
29096
|
this._init_tab_id();
|
|
28744
29097
|
|
|
28745
29098
|
// Based on remote_settings_mode, fetch remote settings and then start session recording if applicable
|
|
@@ -28751,6 +29104,9 @@
|
|
|
28751
29104
|
} else {
|
|
28752
29105
|
this.__session_recording_init_promise = this._check_and_start_session_recording();
|
|
28753
29106
|
}
|
|
29107
|
+
|
|
29108
|
+
this.autocapture = new Autocapture(this);
|
|
29109
|
+
this.autocapture.init();
|
|
28754
29110
|
};
|
|
28755
29111
|
|
|
28756
29112
|
/**
|
|
@@ -28797,9 +29153,19 @@
|
|
|
28797
29153
|
return this.recorderManager.checkAndStartSessionRecording(force_start);
|
|
28798
29154
|
});
|
|
28799
29155
|
|
|
28800
|
-
MixpanelLib.prototype._start_recording_on_event = function(event_name, properties) {
|
|
28801
|
-
|
|
28802
|
-
|
|
29156
|
+
MixpanelLib.prototype._start_recording_on_event = safewrap(function(event_name, properties) {
|
|
29157
|
+
// Wait for recording init to complete before evaluating event triggers.
|
|
29158
|
+
// This ensures recording_event_triggers config is fully loaded when remote settings are used.
|
|
29159
|
+
if (this.__session_recording_init_promise) {
|
|
29160
|
+
this.__session_recording_init_promise.then(_.bind(function() {
|
|
29161
|
+
// In strict mode, skip recording if remote settings failed
|
|
29162
|
+
if (this._remote_settings_strict_disabled) {
|
|
29163
|
+
return;
|
|
29164
|
+
}
|
|
29165
|
+
return this.recorderManager.startRecordingOnEvent(event_name, properties);
|
|
29166
|
+
}, this));
|
|
29167
|
+
}
|
|
29168
|
+
});
|
|
28803
29169
|
|
|
28804
29170
|
MixpanelLib.prototype.start_session_recording = function () {
|
|
28805
29171
|
return this._check_and_start_session_recording(true);
|
|
@@ -29098,6 +29464,7 @@
|
|
|
29098
29464
|
var disableRecordingIfStrict = function() {
|
|
29099
29465
|
if (mode === 'strict') {
|
|
29100
29466
|
self.set_config({'record_sessions_percent': 0});
|
|
29467
|
+
self._remote_settings_strict_disabled = true;
|
|
29101
29468
|
}
|
|
29102
29469
|
};
|
|
29103
29470
|
|
|
@@ -29723,6 +30090,10 @@
|
|
|
29723
30090
|
properties
|
|
29724
30091
|
);
|
|
29725
30092
|
|
|
30093
|
+
if (this.is_recording_heatmap_data()) {
|
|
30094
|
+
event_properties['$captured_for_heatmap'] = true;
|
|
30095
|
+
}
|
|
30096
|
+
|
|
29726
30097
|
return this.track(event_name, event_properties);
|
|
29727
30098
|
});
|
|
29728
30099
|
|
|
@@ -30066,6 +30437,7 @@
|
|
|
30066
30437
|
'$device_id': uuid
|
|
30067
30438
|
}, '');
|
|
30068
30439
|
this._check_and_start_session_recording();
|
|
30440
|
+
this.flags.reset();
|
|
30069
30441
|
};
|
|
30070
30442
|
|
|
30071
30443
|
/**
|