mixpanel-browser 2.77.0 → 2.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +6 -9
- package/.eslintrc.json +12 -0
- package/.github/workflows/openfeature-provider-tests.yml +31 -0
- package/CHANGELOG.md +11 -0
- package/build.sh +2 -2
- package/dist/async-modules/{mixpanel-recorder-wIWnMDLA.min.js → mixpanel-recorder-D5HJyV2E.min.js} +2 -2
- package/dist/async-modules/mixpanel-recorder-D5HJyV2E.min.js.map +1 -0
- package/dist/async-modules/{mixpanel-recorder-DLKbUIEE.js → mixpanel-recorder-P6SEnnPV.js} +57 -33
- package/dist/async-modules/mixpanel-targeting-1L9FyetZ.min.js +2 -0
- package/dist/async-modules/mixpanel-targeting-1L9FyetZ.min.js.map +1 -0
- package/dist/async-modules/{mixpanel-targeting-CmVvUyFM.js → mixpanel-targeting-BBMVbgJF.js} +24 -13
- package/dist/mixpanel-core.cjs.d.ts +46 -1
- package/dist/mixpanel-core.cjs.js +671 -272
- package/dist/mixpanel-recorder.js +57 -33
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-targeting.js +24 -13
- package/dist/mixpanel-targeting.min.js +1 -1
- package/dist/mixpanel-targeting.min.js.map +1 -1
- package/dist/mixpanel-with-async-modules.cjs.d.ts +46 -1
- package/dist/mixpanel-with-async-modules.cjs.js +673 -274
- package/dist/mixpanel-with-async-recorder.cjs.d.ts +46 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +673 -274
- package/dist/mixpanel-with-recorder.d.ts +46 -1
- package/dist/mixpanel-with-recorder.js +596 -197
- package/dist/mixpanel-with-recorder.min.d.ts +46 -1
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.d.ts +46 -1
- package/dist/mixpanel.amd.js +596 -197
- package/dist/mixpanel.cjs.d.ts +46 -1
- package/dist/mixpanel.cjs.js +596 -197
- package/dist/mixpanel.globals.js +673 -274
- package/dist/mixpanel.min.js +200 -189
- package/dist/mixpanel.module.d.ts +46 -1
- package/dist/mixpanel.module.js +596 -197
- package/dist/mixpanel.umd.d.ts +46 -1
- package/dist/mixpanel.umd.js +596 -197
- package/package.json +1 -1
- package/packages/openfeature-web-provider/README.md +357 -0
- package/packages/openfeature-web-provider/package-lock.json +1636 -0
- package/packages/openfeature-web-provider/package.json +51 -0
- package/packages/openfeature-web-provider/rollup.config.browser.mjs +26 -0
- package/packages/openfeature-web-provider/src/MixpanelProvider.ts +302 -0
- package/packages/openfeature-web-provider/src/index.ts +1 -0
- package/packages/openfeature-web-provider/src/types.ts +72 -0
- package/packages/openfeature-web-provider/test/MixpanelProvider.spec.ts +484 -0
- package/packages/openfeature-web-provider/tsconfig.json +15 -0
- package/src/autocapture/index.js +7 -2
- package/src/config.js +1 -1
- package/src/flags/CLAUDE.md +24 -0
- package/src/flags/flags-persistence.js +176 -0
- package/src/flags/index.js +278 -98
- package/src/index.d.ts +46 -1
- package/src/mixpanel-core.js +27 -8
- package/src/recorder/idb-config.js +16 -0
- package/src/recorder/recording-registry.js +7 -2
- package/src/recorder/session-recording.js +9 -4
- package/src/recorder-manager.js +7 -2
- package/src/request-queue.js +1 -2
- package/src/shared-lock.js +2 -3
- package/src/storage/indexed-db.js +16 -15
- package/src/storage/local-storage.js +5 -3
- package/src/utils.js +25 -12
- package/testServer.js +2 -0
- package/tsconfig.base.json +9 -0
- package/dist/async-modules/mixpanel-recorder-wIWnMDLA.min.js.map +0 -1
- package/dist/async-modules/mixpanel-targeting-CTcftSJC.min.js +0 -2
- package/dist/async-modules/mixpanel-targeting-CTcftSJC.min.js.map +0 -1
package/dist/mixpanel.amd.js
CHANGED
|
@@ -27,7 +27,7 @@ define((function () { 'use strict';
|
|
|
27
27
|
|
|
28
28
|
var Config = {
|
|
29
29
|
DEBUG: false,
|
|
30
|
-
LIB_VERSION: '2.
|
|
30
|
+
LIB_VERSION: '2.79.0'
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
// Window global names for async modules
|
|
@@ -19125,6 +19125,7 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
20129
20132
|
};
|
|
20130
20133
|
}
|
|
20131
20134
|
|
|
20132
|
-
// Safari
|
|
20133
|
-
//
|
|
20134
|
-
var
|
|
20135
|
-
|
|
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
|
+
};
|
|
20140
20144
|
|
|
20141
|
-
|
|
20142
|
-
|
|
20145
|
+
var getSessionStorage = function() {
|
|
20146
|
+
try {
|
|
20147
|
+
return win.sessionStorage; // eslint-disable-line no-restricted-properties
|
|
20148
|
+
} catch (_err) {
|
|
20149
|
+
return null;
|
|
20150
|
+
}
|
|
20151
|
+
};
|
|
20152
|
+
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 @@ define((function () { 'use strict';
|
|
|
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 = {
|
|
@@ -23875,11 +23899,11 @@ define((function () { 'use strict';
|
|
|
23875
23899
|
|
|
23876
23900
|
// disable persistence if localStorage is not supported
|
|
23877
23901
|
// request-queue will automatically disable persistence if indexedDB fails to initialize
|
|
23878
|
-
var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
|
|
23902
|
+
var usePersistence = localStorageSupported(options.sharedLockStorage || getLocalStorage(), true) && !this.getConfig('disable_persistence');
|
|
23879
23903
|
|
|
23880
23904
|
// each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
|
|
23881
23905
|
this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
|
|
23882
|
-
this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
|
|
23906
|
+
this.queueStorage = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_EVENTS_STORE_NAME, RECORDER_VERSION_DATA);
|
|
23883
23907
|
this.batcher = new RequestBatcher(this.batcherKey, {
|
|
23884
23908
|
errorReporter: this.reportError.bind(this),
|
|
23885
23909
|
flushOnlyOnInterval: true,
|
|
@@ -23958,14 +23982,14 @@ define((function () { 'use strict';
|
|
|
23958
23982
|
}
|
|
23959
23983
|
|
|
23960
23984
|
if (this._stopRecording !== null) {
|
|
23961
|
-
logger$
|
|
23985
|
+
logger$4.log('Recording already in progress, skipping startRecording.');
|
|
23962
23986
|
return;
|
|
23963
23987
|
}
|
|
23964
23988
|
|
|
23965
23989
|
this.recordMaxMs = this.getConfig('record_max_ms');
|
|
23966
23990
|
if (this.recordMaxMs > MAX_RECORDING_MS) {
|
|
23967
23991
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
23968
|
-
logger$
|
|
23992
|
+
logger$4.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
23969
23993
|
}
|
|
23970
23994
|
|
|
23971
23995
|
if (!this.maxExpires) {
|
|
@@ -24029,7 +24053,7 @@ define((function () { 'use strict';
|
|
|
24029
24053
|
);
|
|
24030
24054
|
}
|
|
24031
24055
|
|
|
24032
|
-
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$
|
|
24056
|
+
var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$4);
|
|
24033
24057
|
|
|
24034
24058
|
try {
|
|
24035
24059
|
this._stopRecording = this._rrwebRecord({
|
|
@@ -24291,14 +24315,14 @@ define((function () { 'use strict';
|
|
|
24291
24315
|
|
|
24292
24316
|
|
|
24293
24317
|
SessionRecording.prototype.reportError = function(msg, err) {
|
|
24294
|
-
logger$
|
|
24318
|
+
logger$4.error.apply(logger$4.error, arguments);
|
|
24295
24319
|
try {
|
|
24296
24320
|
if (!err && !(msg instanceof Error)) {
|
|
24297
24321
|
msg = new Error(msg);
|
|
24298
24322
|
}
|
|
24299
24323
|
this.getConfig('error_reporter')(msg, err);
|
|
24300
24324
|
} catch(err) {
|
|
24301
|
-
logger$
|
|
24325
|
+
logger$4.error(err);
|
|
24302
24326
|
}
|
|
24303
24327
|
};
|
|
24304
24328
|
|
|
@@ -24327,7 +24351,7 @@ define((function () { 'use strict';
|
|
|
24327
24351
|
var configValue = this.getConfig('record_min_ms');
|
|
24328
24352
|
|
|
24329
24353
|
if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
24330
|
-
logger$
|
|
24354
|
+
logger$4.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
24331
24355
|
return MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
24332
24356
|
}
|
|
24333
24357
|
|
|
@@ -24369,7 +24393,7 @@ define((function () { 'use strict';
|
|
|
24369
24393
|
*/
|
|
24370
24394
|
var RecordingRegistry = function (options) {
|
|
24371
24395
|
/** @type {IDBStorageWrapper} */
|
|
24372
|
-
this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
24396
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
24373
24397
|
this.errorReporter = options.errorReporter;
|
|
24374
24398
|
this.mixpanelInstance = options.mixpanelInstance;
|
|
24375
24399
|
this.sharedLockStorage = options.sharedLockStorage;
|
|
@@ -24490,7 +24514,7 @@ define((function () { 'use strict';
|
|
|
24490
24514
|
.catch(this.handleError.bind(this));
|
|
24491
24515
|
};
|
|
24492
24516
|
|
|
24493
|
-
var logger$
|
|
24517
|
+
var logger$3 = console_with_prefix('recorder');
|
|
24494
24518
|
|
|
24495
24519
|
/**
|
|
24496
24520
|
* Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
|
|
@@ -24506,7 +24530,7 @@ define((function () { 'use strict';
|
|
|
24506
24530
|
*/
|
|
24507
24531
|
this.recordingRegistry = new RecordingRegistry({
|
|
24508
24532
|
mixpanelInstance: this.mixpanelInstance,
|
|
24509
|
-
errorReporter: logger$
|
|
24533
|
+
errorReporter: logger$3.error,
|
|
24510
24534
|
sharedLockStorage: sharedLockStorage
|
|
24511
24535
|
});
|
|
24512
24536
|
this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
|
|
@@ -24518,17 +24542,17 @@ define((function () { 'use strict';
|
|
|
24518
24542
|
MixpanelRecorder.prototype.startRecording = function(options) {
|
|
24519
24543
|
options = options || {};
|
|
24520
24544
|
if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
|
|
24521
|
-
logger$
|
|
24545
|
+
logger$3.log('Recording already in progress, skipping startRecording.');
|
|
24522
24546
|
return;
|
|
24523
24547
|
}
|
|
24524
24548
|
|
|
24525
24549
|
var onIdleTimeout = function () {
|
|
24526
|
-
logger$
|
|
24550
|
+
logger$3.log('Idle timeout reached, restarting recording.');
|
|
24527
24551
|
this.resetRecording();
|
|
24528
24552
|
}.bind(this);
|
|
24529
24553
|
|
|
24530
24554
|
var onMaxLengthReached = function () {
|
|
24531
|
-
logger$
|
|
24555
|
+
logger$3.log('Max recording length reached, stopping recording.');
|
|
24532
24556
|
this.resetRecording();
|
|
24533
24557
|
}.bind(this);
|
|
24534
24558
|
|
|
@@ -24598,7 +24622,7 @@ define((function () { 'use strict';
|
|
|
24598
24622
|
} else if (startNewIfInactive) {
|
|
24599
24623
|
return this.startRecording({shouldStopBatcher: false});
|
|
24600
24624
|
} else {
|
|
24601
|
-
logger$
|
|
24625
|
+
logger$3.log('No resumable recording found.');
|
|
24602
24626
|
return null;
|
|
24603
24627
|
}
|
|
24604
24628
|
}.bind(this));
|
|
@@ -25263,7 +25287,7 @@ define((function () { 'use strict';
|
|
|
25263
25287
|
observer.observe(shadowRoot, this.observerConfig);
|
|
25264
25288
|
this.shadowObservers.push(observer);
|
|
25265
25289
|
} catch (e) {
|
|
25266
|
-
logger$
|
|
25290
|
+
logger$6.critical('Error while observing shadow root', e);
|
|
25267
25291
|
}
|
|
25268
25292
|
};
|
|
25269
25293
|
|
|
@@ -25274,7 +25298,7 @@ define((function () { 'use strict';
|
|
|
25274
25298
|
}
|
|
25275
25299
|
|
|
25276
25300
|
if (!weakSetSupported()) {
|
|
25277
|
-
logger$
|
|
25301
|
+
logger$6.critical('Shadow DOM observation unavailable: WeakSet not supported');
|
|
25278
25302
|
return;
|
|
25279
25303
|
}
|
|
25280
25304
|
|
|
@@ -25290,7 +25314,7 @@ define((function () { 'use strict';
|
|
|
25290
25314
|
try {
|
|
25291
25315
|
this.shadowObservers[i].disconnect();
|
|
25292
25316
|
} catch (e) {
|
|
25293
|
-
logger$
|
|
25317
|
+
logger$6.critical('Error while disconnecting shadow DOM observer', e);
|
|
25294
25318
|
}
|
|
25295
25319
|
}
|
|
25296
25320
|
this.shadowObservers = [];
|
|
@@ -25478,7 +25502,7 @@ define((function () { 'use strict';
|
|
|
25478
25502
|
|
|
25479
25503
|
this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
|
|
25480
25504
|
} catch (e) {
|
|
25481
|
-
logger$
|
|
25505
|
+
logger$6.critical('Error while setting up mutation observer', e);
|
|
25482
25506
|
}
|
|
25483
25507
|
}
|
|
25484
25508
|
|
|
@@ -25493,7 +25517,7 @@ define((function () { 'use strict';
|
|
|
25493
25517
|
);
|
|
25494
25518
|
this.shadowDOMObserver.start();
|
|
25495
25519
|
} catch (e) {
|
|
25496
|
-
logger$
|
|
25520
|
+
logger$6.critical('Error while setting up shadow DOM observer', e);
|
|
25497
25521
|
this.shadowDOMObserver = null;
|
|
25498
25522
|
}
|
|
25499
25523
|
}
|
|
@@ -25520,7 +25544,7 @@ define((function () { 'use strict';
|
|
|
25520
25544
|
try {
|
|
25521
25545
|
listener.target.removeEventListener(listener.event, listener.handler, listener.options);
|
|
25522
25546
|
} catch (e) {
|
|
25523
|
-
logger$
|
|
25547
|
+
logger$6.critical('Error while removing event listener', e);
|
|
25524
25548
|
}
|
|
25525
25549
|
}
|
|
25526
25550
|
this.eventListeners = [];
|
|
@@ -25529,7 +25553,7 @@ define((function () { 'use strict';
|
|
|
25529
25553
|
try {
|
|
25530
25554
|
this.mutationObserver.disconnect();
|
|
25531
25555
|
} catch (e) {
|
|
25532
|
-
logger$
|
|
25556
|
+
logger$6.critical('Error while disconnecting mutation observer', e);
|
|
25533
25557
|
}
|
|
25534
25558
|
this.mutationObserver = null;
|
|
25535
25559
|
}
|
|
@@ -25538,7 +25562,7 @@ define((function () { 'use strict';
|
|
|
25538
25562
|
try {
|
|
25539
25563
|
this.shadowDOMObserver.stop();
|
|
25540
25564
|
} catch (e) {
|
|
25541
|
-
logger$
|
|
25565
|
+
logger$6.critical('Error while stopping shadow DOM observer', e);
|
|
25542
25566
|
}
|
|
25543
25567
|
this.shadowDOMObserver = null;
|
|
25544
25568
|
}
|
|
@@ -25616,7 +25640,7 @@ define((function () { 'use strict';
|
|
|
25616
25640
|
|
|
25617
25641
|
Autocapture.prototype.init = function() {
|
|
25618
25642
|
if (!minDOMApisSupported()) {
|
|
25619
|
-
logger$
|
|
25643
|
+
logger$6.critical('Autocapture unavailable: missing required DOM APIs');
|
|
25620
25644
|
return;
|
|
25621
25645
|
}
|
|
25622
25646
|
this.initPageListeners();
|
|
@@ -25656,7 +25680,7 @@ define((function () { 'use strict';
|
|
|
25656
25680
|
try {
|
|
25657
25681
|
return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
|
|
25658
25682
|
} catch (err) {
|
|
25659
|
-
logger$
|
|
25683
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25660
25684
|
return true;
|
|
25661
25685
|
}
|
|
25662
25686
|
}
|
|
@@ -25669,7 +25693,7 @@ define((function () { 'use strict';
|
|
|
25669
25693
|
try {
|
|
25670
25694
|
return urlMatchesRegexList(currentUrl, blockUrlRegexes);
|
|
25671
25695
|
} catch (err) {
|
|
25672
|
-
logger$
|
|
25696
|
+
logger$6.critical('Error while checking block URL regexes: ', err);
|
|
25673
25697
|
return true;
|
|
25674
25698
|
}
|
|
25675
25699
|
};
|
|
@@ -25807,7 +25831,7 @@ define((function () { 'use strict';
|
|
|
25807
25831
|
return;
|
|
25808
25832
|
}
|
|
25809
25833
|
|
|
25810
|
-
logger$
|
|
25834
|
+
logger$6.log('Initializing scroll depth tracking');
|
|
25811
25835
|
|
|
25812
25836
|
this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
|
|
25813
25837
|
|
|
@@ -25833,7 +25857,7 @@ define((function () { 'use strict';
|
|
|
25833
25857
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
|
|
25834
25858
|
return;
|
|
25835
25859
|
}
|
|
25836
|
-
logger$
|
|
25860
|
+
logger$6.log('Initializing click tracking');
|
|
25837
25861
|
|
|
25838
25862
|
this.listenerClick = function(ev) {
|
|
25839
25863
|
if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
|
|
@@ -25852,7 +25876,7 @@ define((function () { 'use strict';
|
|
|
25852
25876
|
return;
|
|
25853
25877
|
}
|
|
25854
25878
|
|
|
25855
|
-
logger$
|
|
25879
|
+
logger$6.log('Initializing dead click tracking');
|
|
25856
25880
|
if (!this._deadClickTracker) {
|
|
25857
25881
|
this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
|
|
25858
25882
|
this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
|
|
@@ -25886,7 +25910,7 @@ define((function () { 'use strict';
|
|
|
25886
25910
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
25887
25911
|
return;
|
|
25888
25912
|
}
|
|
25889
|
-
logger$
|
|
25913
|
+
logger$6.log('Initializing input tracking');
|
|
25890
25914
|
|
|
25891
25915
|
this.listenerChange = function(ev) {
|
|
25892
25916
|
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
@@ -25900,14 +25924,15 @@ define((function () { 'use strict';
|
|
|
25900
25924
|
Autocapture.prototype.initPageviewTracking = function() {
|
|
25901
25925
|
win.removeEventListener(EV_MP_LOCATION_CHANGE, this.listenerLocationchange);
|
|
25902
25926
|
|
|
25903
|
-
if (!this.pageviewTrackingConfig()) {
|
|
25927
|
+
if (!this.pageviewTrackingConfig() && !this.mp.get_config('record_heatmap_data')) {
|
|
25904
25928
|
return;
|
|
25905
25929
|
}
|
|
25906
|
-
logger$
|
|
25930
|
+
logger$6.log('Initializing pageview tracking');
|
|
25907
25931
|
|
|
25908
25932
|
var previousTrackedUrl = '';
|
|
25909
25933
|
var tracked = false;
|
|
25910
|
-
if
|
|
25934
|
+
// Track initial pageview if pageview tracking enabled OR heatmap recording is active
|
|
25935
|
+
if ((this.pageviewTrackingConfig() || this.mp.is_recording_heatmap_data()) && !this.currentUrlBlocked()) {
|
|
25911
25936
|
tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
25912
25937
|
}
|
|
25913
25938
|
if (tracked) {
|
|
@@ -25923,6 +25948,10 @@ define((function () { 'use strict';
|
|
|
25923
25948
|
var shouldTrack = false;
|
|
25924
25949
|
var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
25925
25950
|
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
25951
|
+
if (!trackPageviewOption && this.mp.is_recording_heatmap_data()) {
|
|
25952
|
+
trackPageviewOption = PAGEVIEW_OPTION_FULL_URL;
|
|
25953
|
+
}
|
|
25954
|
+
|
|
25926
25955
|
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
25927
25956
|
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
25928
25957
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
@@ -25938,7 +25967,7 @@ define((function () { 'use strict';
|
|
|
25938
25967
|
}
|
|
25939
25968
|
if (didPathChange) {
|
|
25940
25969
|
this.lastScrollCheckpoint = 0;
|
|
25941
|
-
logger$
|
|
25970
|
+
logger$6.log('Path change: re-initializing scroll depth checkpoints');
|
|
25942
25971
|
}
|
|
25943
25972
|
}
|
|
25944
25973
|
}.bind(this));
|
|
@@ -25953,7 +25982,7 @@ define((function () { 'use strict';
|
|
|
25953
25982
|
return;
|
|
25954
25983
|
}
|
|
25955
25984
|
|
|
25956
|
-
logger$
|
|
25985
|
+
logger$6.log('Initializing rage click tracking');
|
|
25957
25986
|
if (!this._rageClickTracker) {
|
|
25958
25987
|
this._rageClickTracker = new RageClickTracker();
|
|
25959
25988
|
}
|
|
@@ -25983,7 +26012,7 @@ define((function () { 'use strict';
|
|
|
25983
26012
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
25984
26013
|
return;
|
|
25985
26014
|
}
|
|
25986
|
-
logger$
|
|
26015
|
+
logger$6.log('Initializing scroll tracking');
|
|
25987
26016
|
this.lastScrollCheckpoint = 0;
|
|
25988
26017
|
|
|
25989
26018
|
var scrollTrackFunction = function() {
|
|
@@ -26020,7 +26049,7 @@ define((function () { 'use strict';
|
|
|
26020
26049
|
}
|
|
26021
26050
|
}
|
|
26022
26051
|
} catch (err) {
|
|
26023
|
-
logger$
|
|
26052
|
+
logger$6.critical('Error while calculating scroll percentage', err);
|
|
26024
26053
|
}
|
|
26025
26054
|
if (shouldTrack) {
|
|
26026
26055
|
this.mp.track(MP_EV_SCROLL, props);
|
|
@@ -26038,7 +26067,7 @@ define((function () { 'use strict';
|
|
|
26038
26067
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
26039
26068
|
return;
|
|
26040
26069
|
}
|
|
26041
|
-
logger$
|
|
26070
|
+
logger$6.log('Initializing submit tracking');
|
|
26042
26071
|
|
|
26043
26072
|
this.listenerSubmit = function(ev) {
|
|
26044
26073
|
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
@@ -26060,7 +26089,7 @@ define((function () { 'use strict';
|
|
|
26060
26089
|
return;
|
|
26061
26090
|
}
|
|
26062
26091
|
|
|
26063
|
-
logger$
|
|
26092
|
+
logger$6.log('Initializing page visibility tracking.');
|
|
26064
26093
|
this._initScrollDepthTracking();
|
|
26065
26094
|
var previousTrackedUrl = _.info.currentUrl();
|
|
26066
26095
|
|
|
@@ -26145,10 +26174,183 @@ define((function () { 'use strict';
|
|
|
26145
26174
|
return win[TARGETING_GLOBAL_NAME];
|
|
26146
26175
|
};
|
|
26147
26176
|
|
|
26177
|
+
var logger$2 = console_with_prefix('flags');
|
|
26178
|
+
|
|
26179
|
+
var MIXPANEL_FLAGS_DB_NAME = 'mixpanelFlagsDb';
|
|
26180
|
+
var FLAGS_STORE_NAME = 'mixpanelFlags';
|
|
26181
|
+
|
|
26182
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
26183
|
+
var FLAGS_VERSION_DATA = { version: 1, storeNames: [FLAGS_STORE_NAME] };
|
|
26184
|
+
|
|
26185
|
+
var PERSISTED_VARIANTS_KEY_PREFIX = 'persisted_variants_for_';
|
|
26186
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
26187
|
+
|
|
26188
|
+
var VariantLookupPolicy = Object.freeze({
|
|
26189
|
+
NETWORK_ONLY: 'networkOnly',
|
|
26190
|
+
NETWORK_FIRST: 'networkFirst',
|
|
26191
|
+
PERSISTENCE_UNTIL_NETWORK_SUCCESS: 'persistenceUntilNetworkSuccess'
|
|
26192
|
+
});
|
|
26193
|
+
|
|
26194
|
+
var VALID_POLICIES = [
|
|
26195
|
+
VariantLookupPolicy.NETWORK_ONLY,
|
|
26196
|
+
VariantLookupPolicy.NETWORK_FIRST,
|
|
26197
|
+
VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS
|
|
26198
|
+
];
|
|
26199
|
+
|
|
26200
|
+
/**
|
|
26201
|
+
* Module for handling the storage and retrieval of persisted feature flag variants.
|
|
26202
|
+
*/
|
|
26203
|
+
var FeatureFlagPersistence = function(persistenceConfig, token, isGloballyDisabled) {
|
|
26204
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_FLAGS_DB_NAME, FLAGS_STORE_NAME, FLAGS_VERSION_DATA);
|
|
26205
|
+
this.persistenceConfig = persistenceConfig;
|
|
26206
|
+
this.persistedVariantsKey = PERSISTED_VARIANTS_KEY_PREFIX + token;
|
|
26207
|
+
this.isGloballyDisabled = isGloballyDisabled || function() { return false; };
|
|
26208
|
+
};
|
|
26209
|
+
|
|
26210
|
+
FeatureFlagPersistence.prototype.getPolicy = function() {
|
|
26211
|
+
if (this.isGloballyDisabled() || !this._isConfigValid()) {
|
|
26212
|
+
return VariantLookupPolicy.NETWORK_ONLY;
|
|
26213
|
+
}
|
|
26214
|
+
return this.persistenceConfig['variantLookupPolicy'];
|
|
26215
|
+
};
|
|
26216
|
+
|
|
26217
|
+
FeatureFlagPersistence.prototype.getTtlMs = function() {
|
|
26218
|
+
if (!this._isConfigValid()) {
|
|
26219
|
+
return DEFAULT_TTL_MS;
|
|
26220
|
+
}
|
|
26221
|
+
var configuredTtl = this.persistenceConfig['persistenceTtlMs'];
|
|
26222
|
+
return (configuredTtl === undefined || configuredTtl === null) ? DEFAULT_TTL_MS : configuredTtl;
|
|
26223
|
+
};
|
|
26224
|
+
|
|
26225
|
+
FeatureFlagPersistence.prototype._isConfigValid = function() {
|
|
26226
|
+
var config = this.persistenceConfig;
|
|
26227
|
+
if (!config) {
|
|
26228
|
+
return false;
|
|
26229
|
+
}
|
|
26230
|
+
|
|
26231
|
+
if (VALID_POLICIES.indexOf(config['variantLookupPolicy']) === -1) {
|
|
26232
|
+
logger$2.error('Invalid variantLookupPolicy:', config['variantLookupPolicy']);
|
|
26233
|
+
return false;
|
|
26234
|
+
}
|
|
26235
|
+
|
|
26236
|
+
if (config['persistenceTtlMs'] !== undefined &&
|
|
26237
|
+
config['persistenceTtlMs'] !== null &&
|
|
26238
|
+
config['persistenceTtlMs'] <= 0) {
|
|
26239
|
+
logger$2.error('If provided, persistenceTtlMs must be a positive number. Provided value:', config['persistenceTtlMs']);
|
|
26240
|
+
return false;
|
|
26241
|
+
}
|
|
26242
|
+
|
|
26243
|
+
return true;
|
|
26244
|
+
};
|
|
26245
|
+
|
|
26246
|
+
FeatureFlagPersistence.prototype.loadFlagsFromStorage = function(context) {
|
|
26247
|
+
var clearAndReturnNull = _.bind(function() {
|
|
26248
|
+
return this.clear().then(function() { return null; }).catch(function() { return null; });
|
|
26249
|
+
}, this);
|
|
26250
|
+
|
|
26251
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26252
|
+
return clearAndReturnNull();
|
|
26253
|
+
}
|
|
26254
|
+
|
|
26255
|
+
var ttlMs = this.getTtlMs();
|
|
26256
|
+
|
|
26257
|
+
return this.idb.init().then(_.bind(function() {
|
|
26258
|
+
return this.idb.getItem(this.persistedVariantsKey);
|
|
26259
|
+
}, this)).then(_.bind(function(data) {
|
|
26260
|
+
if (!data) {
|
|
26261
|
+
logger$2.log('No persisted variants found in IndexedDB');
|
|
26262
|
+
return null;
|
|
26263
|
+
}
|
|
26264
|
+
|
|
26265
|
+
if (ttlMs && Date.now() - data['persistedAt'] >= ttlMs) {
|
|
26266
|
+
logger$2.log('Persisted variants are expiring');
|
|
26267
|
+
return null;
|
|
26268
|
+
}
|
|
26269
|
+
|
|
26270
|
+
if (!context || data['distinctId'] !== context['distinct_id']) {
|
|
26271
|
+
logger$2.log('Persisted variants found, but for a different distinct_id so clearing.');
|
|
26272
|
+
return clearAndReturnNull();
|
|
26273
|
+
}
|
|
26274
|
+
|
|
26275
|
+
var persistedFlags = new Map();
|
|
26276
|
+
_.each(data['flagVariants'], function(variantData, key) {
|
|
26277
|
+
persistedFlags.set(key, {
|
|
26278
|
+
'key': variantData['variant_key'],
|
|
26279
|
+
'value': variantData['variant_value'],
|
|
26280
|
+
'experiment_id': variantData['experiment_id'],
|
|
26281
|
+
'is_experiment_active': variantData['is_experiment_active'],
|
|
26282
|
+
'is_qa_tester': variantData['is_qa_tester'],
|
|
26283
|
+
'variant_source': 'persistence',
|
|
26284
|
+
'persisted_at_in_ms': data['persistedAt'],
|
|
26285
|
+
'ttl_in_ms': ttlMs
|
|
26286
|
+
});
|
|
26287
|
+
});
|
|
26288
|
+
|
|
26289
|
+
logger$2.log('Loaded', persistedFlags.size, 'variants from IndexedDB for distinct_id', data['distinctId']);
|
|
26290
|
+
|
|
26291
|
+
return {
|
|
26292
|
+
flags: persistedFlags,
|
|
26293
|
+
pendingFirstTimeEvents: data['pendingFirstTimeEvents'] || {},
|
|
26294
|
+
persistedAtMs: data['persistedAt'],
|
|
26295
|
+
ttlMs: ttlMs
|
|
26296
|
+
};
|
|
26297
|
+
}, this)).catch(_.bind(function(error) {
|
|
26298
|
+
logger$2.error('Failed to load persisted variants from IndexedDB, so clearing', error);
|
|
26299
|
+
return clearAndReturnNull();
|
|
26300
|
+
}, this));
|
|
26301
|
+
};
|
|
26302
|
+
|
|
26303
|
+
FeatureFlagPersistence.prototype.save = function(context, flagsMap, pendingFirstTimeEvents) {
|
|
26304
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
26305
|
+
return Promise.resolve();
|
|
26306
|
+
}
|
|
26307
|
+
|
|
26308
|
+
var flagVariants = {};
|
|
26309
|
+
flagsMap.forEach(function(variant, key) {
|
|
26310
|
+
flagVariants[key] = {
|
|
26311
|
+
'variant_key': variant['key'],
|
|
26312
|
+
'variant_value': variant['value'],
|
|
26313
|
+
'experiment_id': variant['experiment_id'],
|
|
26314
|
+
'is_experiment_active': variant['is_experiment_active'],
|
|
26315
|
+
'is_qa_tester': variant['is_qa_tester']
|
|
26316
|
+
};
|
|
26317
|
+
});
|
|
26318
|
+
|
|
26319
|
+
var data = {
|
|
26320
|
+
'persistedAt': Date.now(),
|
|
26321
|
+
'distinctId': context && context['distinct_id'],
|
|
26322
|
+
'context': context,
|
|
26323
|
+
'flagVariants': flagVariants,
|
|
26324
|
+
'pendingFirstTimeEvents': pendingFirstTimeEvents || {}
|
|
26325
|
+
};
|
|
26326
|
+
|
|
26327
|
+
return this.idb.init().then(_.bind(function() {
|
|
26328
|
+
return this.idb.setItem(this.persistedVariantsKey, data);
|
|
26329
|
+
}, this)).then(function() {
|
|
26330
|
+
logger$2.log('Saved', flagsMap.size, 'variants to IndexedDB for distinct_id', data['distinctId']);
|
|
26331
|
+
}).catch(function(error) {
|
|
26332
|
+
logger$2.error('Failed to persist variants to IndexedDB:', error);
|
|
26333
|
+
});
|
|
26334
|
+
};
|
|
26335
|
+
|
|
26336
|
+
FeatureFlagPersistence.prototype.clear = function() {
|
|
26337
|
+
if (this.isGloballyDisabled()) {
|
|
26338
|
+
return Promise.resolve();
|
|
26339
|
+
}
|
|
26340
|
+
return this.idb.init().then(_.bind(function() {
|
|
26341
|
+
return this.idb.removeItem(this.persistedVariantsKey);
|
|
26342
|
+
}, this)).then(function() {
|
|
26343
|
+
logger$2.log('Cleared persisted variants from IndexedDB');
|
|
26344
|
+
}).catch(function(error) {
|
|
26345
|
+
logger$2.error('Failed to clear persisted variants from IndexedDB:', error);
|
|
26346
|
+
});
|
|
26347
|
+
};
|
|
26348
|
+
|
|
26148
26349
|
var logger$1 = console_with_prefix('flags');
|
|
26149
26350
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
26150
26351
|
|
|
26151
26352
|
var CONFIG_CONTEXT = 'context';
|
|
26353
|
+
var CONFIG_PERSISTENCE = 'persistence';
|
|
26152
26354
|
var CONFIG_DEFAULTS = {};
|
|
26153
26355
|
CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
26154
26356
|
|
|
@@ -26171,6 +26373,13 @@ define((function () { 'use strict';
|
|
|
26171
26373
|
return eventKey.split(':')[0];
|
|
26172
26374
|
};
|
|
26173
26375
|
|
|
26376
|
+
var withFallbackSource = function(fallback) {
|
|
26377
|
+
if (_.isObject(fallback)) {
|
|
26378
|
+
return _.extend({}, fallback, {'variant_source': 'fallback'});
|
|
26379
|
+
}
|
|
26380
|
+
return {'value': fallback, 'variant_source': 'fallback'};
|
|
26381
|
+
};
|
|
26382
|
+
|
|
26174
26383
|
/**
|
|
26175
26384
|
* FeatureFlagManager: support for Mixpanel's feature flagging product
|
|
26176
26385
|
* @constructor
|
|
@@ -26193,11 +26402,63 @@ define((function () { 'use strict';
|
|
|
26193
26402
|
}
|
|
26194
26403
|
|
|
26195
26404
|
this.flags = null;
|
|
26196
|
-
this.fetchFlags();
|
|
26197
|
-
|
|
26198
26405
|
this.trackedFeatures = new Set();
|
|
26199
26406
|
this.pendingFirstTimeEvents = {};
|
|
26200
26407
|
this.activatedFirstTimeEvents = {};
|
|
26408
|
+
this._loadedPersistedAtMs = null;
|
|
26409
|
+
this._loadedTtlMs = null;
|
|
26410
|
+
|
|
26411
|
+
this.persistence = new FeatureFlagPersistence(
|
|
26412
|
+
this.getConfig(CONFIG_PERSISTENCE),
|
|
26413
|
+
this.getMpConfig('token'),
|
|
26414
|
+
_.bind(function() { return this.getMpConfig('disable_persistence'); }, this)
|
|
26415
|
+
);
|
|
26416
|
+
|
|
26417
|
+
this.persistenceLoadedPromise = this.persistence.loadFlagsFromStorage(this._buildContext())
|
|
26418
|
+
.then(_.bind(function(loaded) {
|
|
26419
|
+
if (loaded) {
|
|
26420
|
+
this.flags = loaded.flags;
|
|
26421
|
+
this.pendingFirstTimeEvents = loaded.pendingFirstTimeEvents;
|
|
26422
|
+
this._loadedPersistedAtMs = loaded.persistedAtMs;
|
|
26423
|
+
this._loadedTtlMs = loaded.ttlMs;
|
|
26424
|
+
}
|
|
26425
|
+
}, this));
|
|
26426
|
+
|
|
26427
|
+
return this.persistenceLoadedPromise
|
|
26428
|
+
.then(_.bind(function() {
|
|
26429
|
+
return this.fetchFlags();
|
|
26430
|
+
}, this))
|
|
26431
|
+
.catch(function() {
|
|
26432
|
+
logger$1.error('Error initializing feature flags');
|
|
26433
|
+
});
|
|
26434
|
+
};
|
|
26435
|
+
|
|
26436
|
+
FeatureFlagManager.prototype._buildContext = function() {
|
|
26437
|
+
return _.extend(
|
|
26438
|
+
{'distinct_id': this.getMpProperty('distinct_id'), 'device_id': this.getMpProperty('$device_id')},
|
|
26439
|
+
this.getConfig(CONFIG_CONTEXT)
|
|
26440
|
+
);
|
|
26441
|
+
};
|
|
26442
|
+
|
|
26443
|
+
FeatureFlagManager.prototype.reset = function() {
|
|
26444
|
+
if (!this.persistence) {
|
|
26445
|
+
return Promise.resolve();
|
|
26446
|
+
}
|
|
26447
|
+
|
|
26448
|
+
this.flags = null;
|
|
26449
|
+
this.pendingFirstTimeEvents = {};
|
|
26450
|
+
this.activatedFirstTimeEvents = {};
|
|
26451
|
+
this.trackedFeatures = new Set();
|
|
26452
|
+
this.fetchPromise = null;
|
|
26453
|
+
this._fetchInProgressStartTime = null;
|
|
26454
|
+
this._loadedPersistedAtMs = null;
|
|
26455
|
+
this._loadedTtlMs = null;
|
|
26456
|
+
|
|
26457
|
+
return this.persistence.clear().then(_.bind(function() {
|
|
26458
|
+
return this.fetchFlags();
|
|
26459
|
+
}, this)).catch(function() {
|
|
26460
|
+
logger$1.error('Error during flags reset');
|
|
26461
|
+
});
|
|
26201
26462
|
};
|
|
26202
26463
|
|
|
26203
26464
|
FeatureFlagManager.prototype.getFullConfig = function() {
|
|
@@ -26234,8 +26495,12 @@ define((function () { 'use strict';
|
|
|
26234
26495
|
var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
|
|
26235
26496
|
ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
|
|
26236
26497
|
|
|
26237
|
-
|
|
26238
|
-
|
|
26498
|
+
var configUpdate = {};
|
|
26499
|
+
configUpdate[FLAGS_CONFIG_KEY] = ffConfig;
|
|
26500
|
+
this.setMpConfig(configUpdate);
|
|
26501
|
+
return this.fetchFlags().catch(function() {
|
|
26502
|
+
logger$1.error('Error fetching flags during updateContext');
|
|
26503
|
+
});
|
|
26239
26504
|
};
|
|
26240
26505
|
|
|
26241
26506
|
FeatureFlagManager.prototype.areFlagsReady = function() {
|
|
@@ -26250,12 +26515,11 @@ define((function () { 'use strict';
|
|
|
26250
26515
|
return Promise.resolve();
|
|
26251
26516
|
}
|
|
26252
26517
|
|
|
26253
|
-
var
|
|
26254
|
-
var
|
|
26518
|
+
var context = this._buildContext();
|
|
26519
|
+
var distinctId = context['distinct_id'];
|
|
26255
26520
|
var traceparent = generateTraceparent();
|
|
26256
26521
|
logger$1.log('Fetching flags for distinct ID: ' + distinctId);
|
|
26257
26522
|
|
|
26258
|
-
var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
|
|
26259
26523
|
var searchParams = new URLSearchParams();
|
|
26260
26524
|
searchParams.set('context', JSON.stringify(context));
|
|
26261
26525
|
searchParams.set('token', this.getMpConfig('token'));
|
|
@@ -26272,96 +26536,116 @@ define((function () { 'use strict';
|
|
|
26272
26536
|
}
|
|
26273
26537
|
}).then(function(response) {
|
|
26274
26538
|
this.markFetchComplete();
|
|
26275
|
-
return response.json()
|
|
26276
|
-
|
|
26277
|
-
|
|
26278
|
-
|
|
26279
|
-
|
|
26280
|
-
|
|
26281
|
-
|
|
26282
|
-
|
|
26283
|
-
|
|
26284
|
-
|
|
26285
|
-
|
|
26286
|
-
|
|
26287
|
-
|
|
26288
|
-
|
|
26289
|
-
|
|
26290
|
-
|
|
26291
|
-
|
|
26292
|
-
}
|
|
26539
|
+
return response.json();
|
|
26540
|
+
}.bind(this)).then(function(responseBody) {
|
|
26541
|
+
var responseFlags = responseBody['flags'];
|
|
26542
|
+
if (!responseFlags) {
|
|
26543
|
+
throw new Error('No flags in API response');
|
|
26544
|
+
}
|
|
26545
|
+
var flags = new Map();
|
|
26546
|
+
var pendingFirstTimeEvents = {};
|
|
26547
|
+
|
|
26548
|
+
// Process flags from response
|
|
26549
|
+
_.each(responseFlags, function(data, key) {
|
|
26550
|
+
// Check if this flag has any activated first-time events this session
|
|
26551
|
+
var hasActivatedEvent = false;
|
|
26552
|
+
var prefix = key + ':';
|
|
26553
|
+
_.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
|
|
26554
|
+
if (eventKey.startsWith(prefix)) {
|
|
26555
|
+
hasActivatedEvent = true;
|
|
26556
|
+
}
|
|
26557
|
+
});
|
|
26293
26558
|
|
|
26294
|
-
|
|
26295
|
-
|
|
26296
|
-
|
|
26297
|
-
|
|
26298
|
-
|
|
26299
|
-
}
|
|
26300
|
-
} else {
|
|
26301
|
-
// Use server's current variant
|
|
26302
|
-
flags.set(key, {
|
|
26303
|
-
'key': data['variant_key'],
|
|
26304
|
-
'value': data['variant_value'],
|
|
26305
|
-
'experiment_id': data['experiment_id'],
|
|
26306
|
-
'is_experiment_active': data['is_experiment_active'],
|
|
26307
|
-
'is_qa_tester': data['is_qa_tester']
|
|
26308
|
-
});
|
|
26559
|
+
if (hasActivatedEvent) {
|
|
26560
|
+
// Preserve the activated variant, don't overwrite with server's current variant
|
|
26561
|
+
var currentFlag = this.flags && this.flags.get(key);
|
|
26562
|
+
if (currentFlag) {
|
|
26563
|
+
flags.set(key, currentFlag);
|
|
26309
26564
|
}
|
|
26310
|
-
}
|
|
26565
|
+
} else {
|
|
26566
|
+
// Use server's current variant
|
|
26567
|
+
flags.set(key, {
|
|
26568
|
+
'key': data['variant_key'],
|
|
26569
|
+
'value': data['variant_value'],
|
|
26570
|
+
'experiment_id': data['experiment_id'],
|
|
26571
|
+
'is_experiment_active': data['is_experiment_active'],
|
|
26572
|
+
'is_qa_tester': data['is_qa_tester'],
|
|
26573
|
+
'variant_source': 'network'
|
|
26574
|
+
});
|
|
26575
|
+
}
|
|
26576
|
+
}, this);
|
|
26311
26577
|
|
|
26312
|
-
|
|
26313
|
-
|
|
26314
|
-
|
|
26315
|
-
|
|
26316
|
-
|
|
26317
|
-
|
|
26578
|
+
// Process top-level pending_first_time_events array
|
|
26579
|
+
var topLevelDefinitions = responseBody['pending_first_time_events'];
|
|
26580
|
+
if (topLevelDefinitions && topLevelDefinitions.length > 0) {
|
|
26581
|
+
_.each(topLevelDefinitions, function(def) {
|
|
26582
|
+
var flagKey = def['flag_key'];
|
|
26583
|
+
var eventKey = getPendingEventKey(flagKey, def['first_time_event_hash']);
|
|
26318
26584
|
|
|
26319
|
-
|
|
26320
|
-
|
|
26321
|
-
|
|
26322
|
-
|
|
26585
|
+
// Skip if this specific event has already been activated this session
|
|
26586
|
+
if (this.activatedFirstTimeEvents[eventKey]) {
|
|
26587
|
+
return;
|
|
26588
|
+
}
|
|
26323
26589
|
|
|
26324
|
-
|
|
26325
|
-
|
|
26326
|
-
|
|
26327
|
-
|
|
26328
|
-
|
|
26329
|
-
|
|
26330
|
-
|
|
26331
|
-
|
|
26332
|
-
|
|
26333
|
-
|
|
26334
|
-
|
|
26335
|
-
|
|
26590
|
+
// Store pending event definition using composite key
|
|
26591
|
+
pendingFirstTimeEvents[eventKey] = {
|
|
26592
|
+
'flag_key': flagKey,
|
|
26593
|
+
'flag_id': def['flag_id'],
|
|
26594
|
+
'project_id': def['project_id'],
|
|
26595
|
+
'first_time_event_hash': def['first_time_event_hash'],
|
|
26596
|
+
'event_name': def['event_name'],
|
|
26597
|
+
'property_filters': def['property_filters'],
|
|
26598
|
+
'pending_variant': def['pending_variant']
|
|
26599
|
+
};
|
|
26600
|
+
}, this);
|
|
26601
|
+
}
|
|
26336
26602
|
|
|
26337
|
-
|
|
26338
|
-
|
|
26339
|
-
|
|
26340
|
-
|
|
26341
|
-
|
|
26342
|
-
|
|
26343
|
-
|
|
26344
|
-
|
|
26345
|
-
|
|
26346
|
-
|
|
26603
|
+
// Preserve any activated orphaned flags (flags that were activated but are no longer in response)
|
|
26604
|
+
if (this.activatedFirstTimeEvents) {
|
|
26605
|
+
_.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
|
|
26606
|
+
var flagKey = getFlagKeyFromPendingEventKey(eventKey);
|
|
26607
|
+
if (activated && !flags.has(flagKey) && this.flags && this.flags.has(flagKey)) {
|
|
26608
|
+
// Keep the activated flag even though it's not in the new response
|
|
26609
|
+
flags.set(flagKey, this.flags.get(flagKey));
|
|
26610
|
+
}
|
|
26611
|
+
}, this);
|
|
26612
|
+
}
|
|
26347
26613
|
|
|
26348
|
-
|
|
26349
|
-
|
|
26350
|
-
|
|
26614
|
+
this.flags = flags;
|
|
26615
|
+
this.trackedFeatures = new Set();
|
|
26616
|
+
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
26617
|
+
this._loadedPersistedAtMs = null;
|
|
26618
|
+
this._loadedTtlMs = null;
|
|
26619
|
+
this._traceparent = traceparent;
|
|
26351
26620
|
|
|
26352
|
-
|
|
26353
|
-
|
|
26354
|
-
|
|
26355
|
-
logger$1.error(error);
|
|
26356
|
-
}.bind(this));
|
|
26621
|
+
this._loadTargetingIfNeeded();
|
|
26622
|
+
|
|
26623
|
+
this.persistence.save(context, this.flags, this.pendingFirstTimeEvents);
|
|
26357
26624
|
}.bind(this)).catch(function(error) {
|
|
26358
|
-
this.
|
|
26625
|
+
if (this._fetchInProgressStartTime) {
|
|
26626
|
+
this.markFetchComplete();
|
|
26627
|
+
}
|
|
26359
26628
|
logger$1.error(error);
|
|
26629
|
+
throw error;
|
|
26360
26630
|
}.bind(this));
|
|
26361
26631
|
|
|
26362
26632
|
return this.fetchPromise;
|
|
26363
26633
|
};
|
|
26364
26634
|
|
|
26635
|
+
FeatureFlagManager.prototype.loadFlags = function() {
|
|
26636
|
+
if (!this.isSystemEnabled()) {
|
|
26637
|
+
return Promise.resolve();
|
|
26638
|
+
}
|
|
26639
|
+
if (!this.trackedFeatures) {
|
|
26640
|
+
logger$1.error('loadFlags called before init');
|
|
26641
|
+
return Promise.resolve();
|
|
26642
|
+
}
|
|
26643
|
+
if (this._fetchInProgressStartTime) {
|
|
26644
|
+
return this.fetchPromise;
|
|
26645
|
+
}
|
|
26646
|
+
return this.fetchFlags();
|
|
26647
|
+
};
|
|
26648
|
+
|
|
26365
26649
|
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
26366
26650
|
if (!this._fetchInProgressStartTime) {
|
|
26367
26651
|
logger$1.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
@@ -26496,6 +26780,7 @@ define((function () { 'use strict';
|
|
|
26496
26780
|
};
|
|
26497
26781
|
|
|
26498
26782
|
this.flags.set(flagKey, newVariant);
|
|
26783
|
+
this.trackedFeatures.delete(flagKey);
|
|
26499
26784
|
this.activatedFirstTimeEvents[eventKey] = true;
|
|
26500
26785
|
|
|
26501
26786
|
this.recordFirstTimeEvent(
|
|
@@ -26545,35 +26830,106 @@ define((function () { 'use strict';
|
|
|
26545
26830
|
};
|
|
26546
26831
|
|
|
26547
26832
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
26548
|
-
if (!this.
|
|
26833
|
+
if (!this.persistenceLoadedPromise) {
|
|
26549
26834
|
return new Promise(function(resolve) {
|
|
26550
26835
|
logger$1.critical('Feature Flags not initialized');
|
|
26551
|
-
resolve(fallback);
|
|
26836
|
+
resolve(withFallbackSource(fallback));
|
|
26552
26837
|
});
|
|
26553
26838
|
}
|
|
26554
26839
|
|
|
26555
|
-
|
|
26556
|
-
|
|
26557
|
-
|
|
26558
|
-
|
|
26559
|
-
|
|
26560
|
-
|
|
26840
|
+
var policy = this.persistence.getPolicy();
|
|
26841
|
+
|
|
26842
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26843
|
+
// 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.
|
|
26844
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26845
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26846
|
+
return this.getVariantSync(featureName, fallback);
|
|
26847
|
+
}
|
|
26848
|
+
if (!this.fetchPromise) {
|
|
26849
|
+
return withFallbackSource(fallback);
|
|
26850
|
+
}
|
|
26851
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26852
|
+
return this.getVariantSync(featureName, fallback);
|
|
26853
|
+
}, this)).catch(function(error) {
|
|
26854
|
+
logger$1.error(error);
|
|
26855
|
+
return withFallbackSource(fallback);
|
|
26856
|
+
});
|
|
26857
|
+
}
|
|
26858
|
+
|
|
26859
|
+
var serve = _.bind(function() { return this.getVariantSync(featureName, fallback); }, this);
|
|
26860
|
+
if (!this.fetchPromise) {
|
|
26861
|
+
return withFallbackSource(fallback);
|
|
26862
|
+
}
|
|
26863
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26864
|
+
}, this));
|
|
26865
|
+
};
|
|
26866
|
+
|
|
26867
|
+
FeatureFlagManager.prototype._loadedPersistenceIsStale = function() {
|
|
26868
|
+
if (!this._loadedPersistedAtMs || !this._loadedTtlMs) {
|
|
26869
|
+
return false;
|
|
26870
|
+
}
|
|
26871
|
+
return Date.now() - this._loadedPersistedAtMs >= this._loadedTtlMs;
|
|
26561
26872
|
};
|
|
26562
26873
|
|
|
26563
26874
|
FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
|
|
26875
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26876
|
+
logger$1.log('Loaded persisted variants are past TTL so returning fallback for "' + featureName + '"');
|
|
26877
|
+
return withFallbackSource(fallback);
|
|
26878
|
+
}
|
|
26564
26879
|
if (!this.areFlagsReady()) {
|
|
26565
26880
|
logger$1.log('Flags not loaded yet');
|
|
26566
|
-
return fallback;
|
|
26881
|
+
return withFallbackSource(fallback);
|
|
26567
26882
|
}
|
|
26568
26883
|
var feature = this.flags.get(featureName);
|
|
26569
26884
|
if (!feature) {
|
|
26570
26885
|
logger$1.log('No flag found: "' + featureName + '"');
|
|
26571
|
-
return fallback;
|
|
26886
|
+
return withFallbackSource(fallback);
|
|
26572
26887
|
}
|
|
26573
26888
|
this.trackFeatureCheck(featureName, feature);
|
|
26574
26889
|
return feature;
|
|
26575
26890
|
};
|
|
26576
26891
|
|
|
26892
|
+
FeatureFlagManager.prototype.getAllVariants = function() {
|
|
26893
|
+
if (!this.persistenceLoadedPromise) {
|
|
26894
|
+
logger$1.critical('Feature Flags not initialized');
|
|
26895
|
+
return Promise.resolve(new Map());
|
|
26896
|
+
}
|
|
26897
|
+
|
|
26898
|
+
var policy = this.persistence.getPolicy();
|
|
26899
|
+
|
|
26900
|
+
return this.persistenceLoadedPromise.then(_.bind(function() {
|
|
26901
|
+
// 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.
|
|
26902
|
+
if (policy === VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS) {
|
|
26903
|
+
if (this.areFlagsReady() && !this._loadedPersistenceIsStale()) {
|
|
26904
|
+
return this.getAllVariantsSync();
|
|
26905
|
+
}
|
|
26906
|
+
if (!this.fetchPromise) {
|
|
26907
|
+
return new Map();
|
|
26908
|
+
}
|
|
26909
|
+
return this.fetchPromise.then(_.bind(function() {
|
|
26910
|
+
return this.getAllVariantsSync();
|
|
26911
|
+
}, this)).catch(function(error) {
|
|
26912
|
+
logger$1.error(error);
|
|
26913
|
+
return new Map();
|
|
26914
|
+
});
|
|
26915
|
+
}
|
|
26916
|
+
|
|
26917
|
+
var serve = _.bind(this.getAllVariantsSync, this);
|
|
26918
|
+
if (!this.fetchPromise) {
|
|
26919
|
+
return new Map();
|
|
26920
|
+
}
|
|
26921
|
+
return this.fetchPromise.then(serve).catch(serve);
|
|
26922
|
+
}, this));
|
|
26923
|
+
};
|
|
26924
|
+
|
|
26925
|
+
FeatureFlagManager.prototype.getAllVariantsSync = function() {
|
|
26926
|
+
if (this._loadedPersistenceIsStale()) {
|
|
26927
|
+
logger$1.log('Loaded persisted variants are past TTL so returning empty Map');
|
|
26928
|
+
return new Map();
|
|
26929
|
+
}
|
|
26930
|
+
return this.flags || new Map();
|
|
26931
|
+
};
|
|
26932
|
+
|
|
26577
26933
|
FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackValue) {
|
|
26578
26934
|
return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
|
|
26579
26935
|
return feature['value'];
|
|
@@ -26612,6 +26968,10 @@ define((function () { 'use strict';
|
|
|
26612
26968
|
return val;
|
|
26613
26969
|
};
|
|
26614
26970
|
|
|
26971
|
+
function isPresent(v) {
|
|
26972
|
+
return v !== undefined && v !== null;
|
|
26973
|
+
}
|
|
26974
|
+
|
|
26615
26975
|
FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature) {
|
|
26616
26976
|
if (this.trackedFeatures.has(featureName)) {
|
|
26617
26977
|
return;
|
|
@@ -26622,25 +26982,41 @@ define((function () { 'use strict';
|
|
|
26622
26982
|
'Experiment name': featureName,
|
|
26623
26983
|
'Variant name': feature['key'],
|
|
26624
26984
|
'$experiment_type': 'feature_flag',
|
|
26625
|
-
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
26626
|
-
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
26985
|
+
'Variant fetch start time': isPresent(this._fetchStartTime) ? new Date(this._fetchStartTime).toISOString() : null,
|
|
26986
|
+
'Variant fetch complete time': isPresent(this._fetchCompleteTime) ? new Date(this._fetchCompleteTime).toISOString() : null,
|
|
26627
26987
|
'Variant fetch latency (ms)': this._fetchLatency,
|
|
26628
26988
|
'Variant fetch traceparent': this._traceparent,
|
|
26629
26989
|
};
|
|
26630
26990
|
|
|
26631
|
-
if (feature['experiment_id']
|
|
26991
|
+
if (isPresent(feature['experiment_id'])) {
|
|
26632
26992
|
trackingProperties['$experiment_id'] = feature['experiment_id'];
|
|
26633
26993
|
}
|
|
26634
|
-
if (feature['is_experiment_active']
|
|
26994
|
+
if (isPresent(feature['is_experiment_active'])) {
|
|
26635
26995
|
trackingProperties['$is_experiment_active'] = feature['is_experiment_active'];
|
|
26636
26996
|
}
|
|
26637
|
-
if (feature['is_qa_tester']
|
|
26997
|
+
if (isPresent(feature['is_qa_tester'])) {
|
|
26638
26998
|
trackingProperties['$is_qa_tester'] = feature['is_qa_tester'];
|
|
26639
26999
|
}
|
|
27000
|
+
if (isPresent(feature['variant_source'])) {
|
|
27001
|
+
trackingProperties['$variant_source'] = feature['variant_source'];
|
|
27002
|
+
}
|
|
27003
|
+
if (isPresent(feature['persisted_at_in_ms'])) {
|
|
27004
|
+
trackingProperties['$persisted_at_in_ms'] = feature['persisted_at_in_ms'];
|
|
27005
|
+
}
|
|
27006
|
+
if (isPresent(feature['ttl_in_ms'])) {
|
|
27007
|
+
trackingProperties['$ttl_in_ms'] = feature['ttl_in_ms'];
|
|
27008
|
+
}
|
|
26640
27009
|
|
|
26641
27010
|
this.track('$experiment_started', trackingProperties);
|
|
26642
27011
|
};
|
|
26643
27012
|
|
|
27013
|
+
FeatureFlagManager.prototype.whenReady = function() {
|
|
27014
|
+
if (this.fetchPromise) {
|
|
27015
|
+
return this.fetchPromise;
|
|
27016
|
+
}
|
|
27017
|
+
return Promise.resolve();
|
|
27018
|
+
};
|
|
27019
|
+
|
|
26644
27020
|
FeatureFlagManager.prototype.minApisSupported = function() {
|
|
26645
27021
|
return !!this.fetch &&
|
|
26646
27022
|
typeof Promise !== 'undefined' &&
|
|
@@ -26653,11 +27029,15 @@ define((function () { 'use strict';
|
|
|
26653
27029
|
FeatureFlagManager.prototype['are_flags_ready'] = FeatureFlagManager.prototype.areFlagsReady;
|
|
26654
27030
|
FeatureFlagManager.prototype['get_variant'] = FeatureFlagManager.prototype.getVariant;
|
|
26655
27031
|
FeatureFlagManager.prototype['get_variant_sync'] = FeatureFlagManager.prototype.getVariantSync;
|
|
27032
|
+
FeatureFlagManager.prototype['get_all_variants'] = FeatureFlagManager.prototype.getAllVariants;
|
|
27033
|
+
FeatureFlagManager.prototype['get_all_variants_sync'] = FeatureFlagManager.prototype.getAllVariantsSync;
|
|
26656
27034
|
FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype.getVariantValue;
|
|
26657
27035
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
26658
27036
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
26659
27037
|
FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
|
|
27038
|
+
FeatureFlagManager.prototype['load_flags'] = FeatureFlagManager.prototype.loadFlags;
|
|
26660
27039
|
FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
|
|
27040
|
+
FeatureFlagManager.prototype['when_ready'] = FeatureFlagManager.prototype.whenReady;
|
|
26661
27041
|
|
|
26662
27042
|
// Deprecated method
|
|
26663
27043
|
FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
|
|
@@ -26703,7 +27083,7 @@ define((function () { 'use strict';
|
|
|
26703
27083
|
return PromisePolyfill.resolve(false);
|
|
26704
27084
|
}
|
|
26705
27085
|
|
|
26706
|
-
var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
|
|
27086
|
+
var recording_registry_idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
|
|
26707
27087
|
var tab_id = this.getTabId();
|
|
26708
27088
|
return recording_registry_idb.init()
|
|
26709
27089
|
.then(function () {
|
|
@@ -28630,6 +29010,7 @@ define((function () { 'use strict';
|
|
|
28630
29010
|
'disable_all_events': false,
|
|
28631
29011
|
'identify_called': false
|
|
28632
29012
|
};
|
|
29013
|
+
this._remote_settings_strict_disabled = false;
|
|
28633
29014
|
|
|
28634
29015
|
// set up request queueing/batching
|
|
28635
29016
|
this.request_batchers = {};
|
|
@@ -28704,9 +29085,6 @@ define((function () { 'use strict';
|
|
|
28704
29085
|
this.flags.init();
|
|
28705
29086
|
this['flags'] = this.flags;
|
|
28706
29087
|
|
|
28707
|
-
this.autocapture = new Autocapture(this);
|
|
28708
|
-
this.autocapture.init();
|
|
28709
|
-
|
|
28710
29088
|
this._init_tab_id();
|
|
28711
29089
|
|
|
28712
29090
|
// Based on remote_settings_mode, fetch remote settings and then start session recording if applicable
|
|
@@ -28718,6 +29096,9 @@ define((function () { 'use strict';
|
|
|
28718
29096
|
} else {
|
|
28719
29097
|
this.__session_recording_init_promise = this._check_and_start_session_recording();
|
|
28720
29098
|
}
|
|
29099
|
+
|
|
29100
|
+
this.autocapture = new Autocapture(this);
|
|
29101
|
+
this.autocapture.init();
|
|
28721
29102
|
};
|
|
28722
29103
|
|
|
28723
29104
|
/**
|
|
@@ -28764,9 +29145,19 @@ define((function () { 'use strict';
|
|
|
28764
29145
|
return this.recorderManager.checkAndStartSessionRecording(force_start);
|
|
28765
29146
|
});
|
|
28766
29147
|
|
|
28767
|
-
MixpanelLib.prototype._start_recording_on_event = function(event_name, properties) {
|
|
28768
|
-
|
|
28769
|
-
|
|
29148
|
+
MixpanelLib.prototype._start_recording_on_event = safewrap(function(event_name, properties) {
|
|
29149
|
+
// Wait for recording init to complete before evaluating event triggers.
|
|
29150
|
+
// This ensures recording_event_triggers config is fully loaded when remote settings are used.
|
|
29151
|
+
if (this.__session_recording_init_promise) {
|
|
29152
|
+
this.__session_recording_init_promise.then(_.bind(function() {
|
|
29153
|
+
// In strict mode, skip recording if remote settings failed
|
|
29154
|
+
if (this._remote_settings_strict_disabled) {
|
|
29155
|
+
return;
|
|
29156
|
+
}
|
|
29157
|
+
return this.recorderManager.startRecordingOnEvent(event_name, properties);
|
|
29158
|
+
}, this));
|
|
29159
|
+
}
|
|
29160
|
+
});
|
|
28770
29161
|
|
|
28771
29162
|
MixpanelLib.prototype.start_session_recording = function () {
|
|
28772
29163
|
return this._check_and_start_session_recording(true);
|
|
@@ -29065,6 +29456,7 @@ define((function () { 'use strict';
|
|
|
29065
29456
|
var disableRecordingIfStrict = function() {
|
|
29066
29457
|
if (mode === 'strict') {
|
|
29067
29458
|
self.set_config({'record_sessions_percent': 0});
|
|
29459
|
+
self._remote_settings_strict_disabled = true;
|
|
29068
29460
|
}
|
|
29069
29461
|
};
|
|
29070
29462
|
|
|
@@ -29690,6 +30082,10 @@ define((function () { 'use strict';
|
|
|
29690
30082
|
properties
|
|
29691
30083
|
);
|
|
29692
30084
|
|
|
30085
|
+
if (this.is_recording_heatmap_data()) {
|
|
30086
|
+
event_properties['$captured_for_heatmap'] = true;
|
|
30087
|
+
}
|
|
30088
|
+
|
|
29693
30089
|
return this.track(event_name, event_properties);
|
|
29694
30090
|
});
|
|
29695
30091
|
|
|
@@ -30013,7 +30409,9 @@ define((function () { 'use strict';
|
|
|
30013
30409
|
|
|
30014
30410
|
// check feature flags again if distinct id has changed
|
|
30015
30411
|
if (new_distinct_id !== previous_distinct_id) {
|
|
30016
|
-
this.flags.fetchFlags()
|
|
30412
|
+
this.flags.fetchFlags().catch(function() {
|
|
30413
|
+
console$1.error('[flags] Error fetching flags during identify');
|
|
30414
|
+
});
|
|
30017
30415
|
}
|
|
30018
30416
|
};
|
|
30019
30417
|
|
|
@@ -30031,6 +30429,7 @@ define((function () { 'use strict';
|
|
|
30031
30429
|
'$device_id': uuid
|
|
30032
30430
|
}, '');
|
|
30033
30431
|
this._check_and_start_session_recording();
|
|
30432
|
+
this.flags.reset();
|
|
30034
30433
|
};
|
|
30035
30434
|
|
|
30036
30435
|
/**
|