mixpanel-browser 2.66.0 → 2.67.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/.github/dependabot.yml +7 -0
- package/CHANGELOG.md +7 -0
- package/dist/mixpanel-core.cjs.js +48 -39
- package/dist/mixpanel-recorder.js +36 -12
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +48 -39
- package/dist/mixpanel-with-recorder.js +83 -50
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.js +83 -50
- package/dist/mixpanel.cjs.js +83 -50
- package/dist/mixpanel.globals.js +48 -39
- package/dist/mixpanel.min.js +139 -139
- package/dist/mixpanel.module.js +83 -50
- package/dist/mixpanel.umd.js +83 -50
- package/package.json +1 -1
- package/src/config.js +1 -1
- package/src/flags/index.js +29 -7
- package/src/mixpanel-core.js +18 -31
- package/src/recorder/session-recording.js +35 -11
package/dist/mixpanel.module.js
CHANGED
|
@@ -13942,7 +13942,7 @@ if (typeof Promise !== 'undefined' && Promise.toString().indexOf('[native code]'
|
|
|
13942
13942
|
|
|
13943
13943
|
var Config = {
|
|
13944
13944
|
DEBUG: false,
|
|
13945
|
-
LIB_VERSION: '2.
|
|
13945
|
+
LIB_VERSION: '2.67.0'
|
|
13946
13946
|
};
|
|
13947
13947
|
|
|
13948
13948
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -17060,6 +17060,13 @@ function isUserEvent(ev) {
|
|
|
17060
17060
|
* @property {string} replayStartUrl
|
|
17061
17061
|
*/
|
|
17062
17062
|
|
|
17063
|
+
/**
|
|
17064
|
+
* @typedef {Object} UserIdInfo
|
|
17065
|
+
* @property {string} distinct_id
|
|
17066
|
+
* @property {string} user_id
|
|
17067
|
+
* @property {string} device_id
|
|
17068
|
+
*/
|
|
17069
|
+
|
|
17063
17070
|
|
|
17064
17071
|
/**
|
|
17065
17072
|
* This class encapsulates a single session recording and its lifecycle.
|
|
@@ -17115,6 +17122,30 @@ var SessionRecording = function(options) {
|
|
|
17115
17122
|
});
|
|
17116
17123
|
};
|
|
17117
17124
|
|
|
17125
|
+
/**
|
|
17126
|
+
* @returns {UserIdInfo}
|
|
17127
|
+
*/
|
|
17128
|
+
SessionRecording.prototype.getUserIdInfo = function () {
|
|
17129
|
+
if (this.finalFlushUserIdInfo) {
|
|
17130
|
+
return this.finalFlushUserIdInfo;
|
|
17131
|
+
}
|
|
17132
|
+
|
|
17133
|
+
var userIdInfo = {
|
|
17134
|
+
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
17135
|
+
};
|
|
17136
|
+
|
|
17137
|
+
// send ID management props if they exist
|
|
17138
|
+
var deviceId = this._mixpanel.get_property('$device_id');
|
|
17139
|
+
if (deviceId) {
|
|
17140
|
+
userIdInfo['$device_id'] = deviceId;
|
|
17141
|
+
}
|
|
17142
|
+
var userId = this._mixpanel.get_property('$user_id');
|
|
17143
|
+
if (userId) {
|
|
17144
|
+
userIdInfo['$user_id'] = userId;
|
|
17145
|
+
}
|
|
17146
|
+
return userIdInfo;
|
|
17147
|
+
};
|
|
17148
|
+
|
|
17118
17149
|
SessionRecording.prototype.unloadPersistedData = function () {
|
|
17119
17150
|
this.batcher.stop();
|
|
17120
17151
|
return this.batcher.flush()
|
|
@@ -17239,6 +17270,9 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
17239
17270
|
};
|
|
17240
17271
|
|
|
17241
17272
|
SessionRecording.prototype.stopRecording = function (skipFlush) {
|
|
17273
|
+
// store the user ID info in case this is getting called in mixpanel.reset()
|
|
17274
|
+
this.finalFlushUserIdInfo = this.getUserIdInfo();
|
|
17275
|
+
|
|
17242
17276
|
if (!this.isRrwebStopped()) {
|
|
17243
17277
|
try {
|
|
17244
17278
|
this._stopRecording();
|
|
@@ -17404,7 +17438,6 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
17404
17438
|
'$current_url': this.batchStartUrl,
|
|
17405
17439
|
'$lib_version': Config.LIB_VERSION,
|
|
17406
17440
|
'batch_start_time': batchStartTime / 1000,
|
|
17407
|
-
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
17408
17441
|
'mp_lib': 'web',
|
|
17409
17442
|
'replay_id': replayId,
|
|
17410
17443
|
'replay_length_ms': replayLengthMs,
|
|
@@ -17413,16 +17446,7 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
17413
17446
|
'seq': this.seqNo
|
|
17414
17447
|
};
|
|
17415
17448
|
var eventsJson = JSON.stringify(data);
|
|
17416
|
-
|
|
17417
|
-
// send ID management props if they exist
|
|
17418
|
-
var deviceId = this._mixpanel.get_property('$device_id');
|
|
17419
|
-
if (deviceId) {
|
|
17420
|
-
reqParams['$device_id'] = deviceId;
|
|
17421
|
-
}
|
|
17422
|
-
var userId = this._mixpanel.get_property('$user_id');
|
|
17423
|
-
if (userId) {
|
|
17424
|
-
reqParams['$user_id'] = userId;
|
|
17425
|
-
}
|
|
17449
|
+
Object.assign(reqParams, this.getUserIdInfo());
|
|
17426
17450
|
|
|
17427
17451
|
if (CompressionStream) {
|
|
17428
17452
|
var jsonStream = new Blob([eventsJson], {type: 'application/json'}).stream();
|
|
@@ -18551,8 +18575,9 @@ CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
|
18551
18575
|
* @constructor
|
|
18552
18576
|
*/
|
|
18553
18577
|
var FeatureFlagManager = function(initOptions) {
|
|
18578
|
+
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
18554
18579
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
18555
|
-
this.
|
|
18580
|
+
this.getMpProperty = initOptions.getPropertyFunc;
|
|
18556
18581
|
this.track = initOptions.trackingFunc;
|
|
18557
18582
|
};
|
|
18558
18583
|
|
|
@@ -18601,12 +18626,14 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
18601
18626
|
return;
|
|
18602
18627
|
}
|
|
18603
18628
|
|
|
18604
|
-
var distinctId = this.
|
|
18629
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
18630
|
+
var deviceId = this.getMpProperty('$device_id');
|
|
18605
18631
|
logger.log('Fetching flags for distinct ID: ' + distinctId);
|
|
18606
18632
|
var reqParams = {
|
|
18607
|
-
'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
|
|
18633
|
+
'context': _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT))
|
|
18608
18634
|
};
|
|
18609
|
-
this.
|
|
18635
|
+
this._fetchInProgressStartTime = Date.now();
|
|
18636
|
+
this.fetchPromise = win['fetch'](this.getFullApiRoute(), {
|
|
18610
18637
|
'method': 'POST',
|
|
18611
18638
|
'headers': {
|
|
18612
18639
|
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
@@ -18614,6 +18641,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
18614
18641
|
},
|
|
18615
18642
|
'body': JSON.stringify(reqParams)
|
|
18616
18643
|
}).then(function(response) {
|
|
18644
|
+
this.markFetchComplete();
|
|
18617
18645
|
return response.json().then(function(responseBody) {
|
|
18618
18646
|
var responseFlags = responseBody['flags'];
|
|
18619
18647
|
if (!responseFlags) {
|
|
@@ -18628,9 +18656,24 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
18628
18656
|
});
|
|
18629
18657
|
this.flags = flags;
|
|
18630
18658
|
}.bind(this)).catch(function(error) {
|
|
18659
|
+
this.markFetchComplete();
|
|
18631
18660
|
logger.error(error);
|
|
18632
|
-
});
|
|
18633
|
-
}.bind(this)).catch(function() {
|
|
18661
|
+
}.bind(this));
|
|
18662
|
+
}.bind(this)).catch(function(error) {
|
|
18663
|
+
this.markFetchComplete();
|
|
18664
|
+
logger.error(error);
|
|
18665
|
+
}.bind(this));
|
|
18666
|
+
};
|
|
18667
|
+
|
|
18668
|
+
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
18669
|
+
if (!this._fetchInProgressStartTime) {
|
|
18670
|
+
logger.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
18671
|
+
return;
|
|
18672
|
+
}
|
|
18673
|
+
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
18674
|
+
this._fetchCompleteTime = Date.now();
|
|
18675
|
+
this._fetchLatency = this._fetchCompleteTime - this._fetchStartTime;
|
|
18676
|
+
this._fetchInProgressStartTime = null;
|
|
18634
18677
|
};
|
|
18635
18678
|
|
|
18636
18679
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
@@ -18709,7 +18752,10 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
18709
18752
|
this.track('$experiment_started', {
|
|
18710
18753
|
'Experiment name': featureName,
|
|
18711
18754
|
'Variant name': feature['key'],
|
|
18712
|
-
'$experiment_type': 'feature_flag'
|
|
18755
|
+
'$experiment_type': 'feature_flag',
|
|
18756
|
+
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
18757
|
+
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
18758
|
+
'Variant fetch latency (ms)': this._fetchLatency
|
|
18713
18759
|
});
|
|
18714
18760
|
};
|
|
18715
18761
|
|
|
@@ -20409,8 +20455,11 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
20409
20455
|
}
|
|
20410
20456
|
|
|
20411
20457
|
this.flags = new FeatureFlagManager({
|
|
20458
|
+
getFullApiRoute: _.bind(function() {
|
|
20459
|
+
return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
|
|
20460
|
+
}, this),
|
|
20412
20461
|
getConfigFunc: _.bind(this.get_config, this),
|
|
20413
|
-
|
|
20462
|
+
getPropertyFunc: _.bind(this.get_property, this),
|
|
20414
20463
|
trackingFunc: _.bind(this.track, this)
|
|
20415
20464
|
});
|
|
20416
20465
|
this.flags.init();
|
|
@@ -20896,11 +20945,10 @@ MixpanelLib.prototype.are_batchers_initialized = function() {
|
|
|
20896
20945
|
|
|
20897
20946
|
MixpanelLib.prototype.get_batcher_configs = function() {
|
|
20898
20947
|
var queue_prefix = '__mpq_' + this.get_config('token');
|
|
20899
|
-
var api_routes = this.get_config('api_routes');
|
|
20900
20948
|
this._batcher_configs = this._batcher_configs || {
|
|
20901
|
-
events: {type: 'events',
|
|
20902
|
-
people: {type: 'people',
|
|
20903
|
-
groups: {type: 'groups',
|
|
20949
|
+
events: {type: 'events', api_name: 'track', queue_key: queue_prefix + '_ev'},
|
|
20950
|
+
people: {type: 'people', api_name: 'engage', queue_key: queue_prefix + '_pp'},
|
|
20951
|
+
groups: {type: 'groups', api_name: 'groups', queue_key: queue_prefix + '_gr'}
|
|
20904
20952
|
};
|
|
20905
20953
|
return this._batcher_configs;
|
|
20906
20954
|
};
|
|
@@ -20914,8 +20962,9 @@ MixpanelLib.prototype.init_batchers = function() {
|
|
|
20914
20962
|
libConfig: this['config'],
|
|
20915
20963
|
errorReporter: this.get_config('error_reporter'),
|
|
20916
20964
|
sendRequestFunc: _.bind(function(data, options, cb) {
|
|
20965
|
+
var api_routes = this.get_config('api_routes');
|
|
20917
20966
|
this._send_request(
|
|
20918
|
-
this.
|
|
20967
|
+
this.get_api_host(attrs.api_name) + '/' + api_routes[attrs.api_name],
|
|
20919
20968
|
this._encode_data_for_request(data),
|
|
20920
20969
|
options,
|
|
20921
20970
|
this._prepare_callback(cb, data)
|
|
@@ -21643,31 +21692,15 @@ MixpanelLib.prototype.identify = function(
|
|
|
21643
21692
|
* Useful for clearing data when a user logs out.
|
|
21644
21693
|
*/
|
|
21645
21694
|
MixpanelLib.prototype.reset = function() {
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
}, '');
|
|
21656
|
-
};
|
|
21657
|
-
|
|
21658
|
-
if (self._recorder) {
|
|
21659
|
-
self.stop_session_recording()
|
|
21660
|
-
.then(function () {
|
|
21661
|
-
reset();
|
|
21662
|
-
self._check_and_start_session_recording();
|
|
21663
|
-
})
|
|
21664
|
-
.catch(_.bind(function (err) {
|
|
21665
|
-
reset();
|
|
21666
|
-
this.report_error('Error restarting recording session', err);
|
|
21667
|
-
}, this));
|
|
21668
|
-
} else {
|
|
21669
|
-
reset();
|
|
21670
|
-
}
|
|
21695
|
+
this.stop_session_recording();
|
|
21696
|
+
this['persistence'].clear();
|
|
21697
|
+
this._flags.identify_called = false;
|
|
21698
|
+
var uuid = _.UUID();
|
|
21699
|
+
this.register_once({
|
|
21700
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
21701
|
+
'$device_id': uuid
|
|
21702
|
+
}, '');
|
|
21703
|
+
this._check_and_start_session_recording();
|
|
21671
21704
|
};
|
|
21672
21705
|
|
|
21673
21706
|
/**
|
package/dist/mixpanel.umd.js
CHANGED
|
@@ -13948,7 +13948,7 @@
|
|
|
13948
13948
|
|
|
13949
13949
|
var Config = {
|
|
13950
13950
|
DEBUG: false,
|
|
13951
|
-
LIB_VERSION: '2.
|
|
13951
|
+
LIB_VERSION: '2.67.0'
|
|
13952
13952
|
};
|
|
13953
13953
|
|
|
13954
13954
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -17066,6 +17066,13 @@
|
|
|
17066
17066
|
* @property {string} replayStartUrl
|
|
17067
17067
|
*/
|
|
17068
17068
|
|
|
17069
|
+
/**
|
|
17070
|
+
* @typedef {Object} UserIdInfo
|
|
17071
|
+
* @property {string} distinct_id
|
|
17072
|
+
* @property {string} user_id
|
|
17073
|
+
* @property {string} device_id
|
|
17074
|
+
*/
|
|
17075
|
+
|
|
17069
17076
|
|
|
17070
17077
|
/**
|
|
17071
17078
|
* This class encapsulates a single session recording and its lifecycle.
|
|
@@ -17121,6 +17128,30 @@
|
|
|
17121
17128
|
});
|
|
17122
17129
|
};
|
|
17123
17130
|
|
|
17131
|
+
/**
|
|
17132
|
+
* @returns {UserIdInfo}
|
|
17133
|
+
*/
|
|
17134
|
+
SessionRecording.prototype.getUserIdInfo = function () {
|
|
17135
|
+
if (this.finalFlushUserIdInfo) {
|
|
17136
|
+
return this.finalFlushUserIdInfo;
|
|
17137
|
+
}
|
|
17138
|
+
|
|
17139
|
+
var userIdInfo = {
|
|
17140
|
+
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
17141
|
+
};
|
|
17142
|
+
|
|
17143
|
+
// send ID management props if they exist
|
|
17144
|
+
var deviceId = this._mixpanel.get_property('$device_id');
|
|
17145
|
+
if (deviceId) {
|
|
17146
|
+
userIdInfo['$device_id'] = deviceId;
|
|
17147
|
+
}
|
|
17148
|
+
var userId = this._mixpanel.get_property('$user_id');
|
|
17149
|
+
if (userId) {
|
|
17150
|
+
userIdInfo['$user_id'] = userId;
|
|
17151
|
+
}
|
|
17152
|
+
return userIdInfo;
|
|
17153
|
+
};
|
|
17154
|
+
|
|
17124
17155
|
SessionRecording.prototype.unloadPersistedData = function () {
|
|
17125
17156
|
this.batcher.stop();
|
|
17126
17157
|
return this.batcher.flush()
|
|
@@ -17245,6 +17276,9 @@
|
|
|
17245
17276
|
};
|
|
17246
17277
|
|
|
17247
17278
|
SessionRecording.prototype.stopRecording = function (skipFlush) {
|
|
17279
|
+
// store the user ID info in case this is getting called in mixpanel.reset()
|
|
17280
|
+
this.finalFlushUserIdInfo = this.getUserIdInfo();
|
|
17281
|
+
|
|
17248
17282
|
if (!this.isRrwebStopped()) {
|
|
17249
17283
|
try {
|
|
17250
17284
|
this._stopRecording();
|
|
@@ -17410,7 +17444,6 @@
|
|
|
17410
17444
|
'$current_url': this.batchStartUrl,
|
|
17411
17445
|
'$lib_version': Config.LIB_VERSION,
|
|
17412
17446
|
'batch_start_time': batchStartTime / 1000,
|
|
17413
|
-
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
17414
17447
|
'mp_lib': 'web',
|
|
17415
17448
|
'replay_id': replayId,
|
|
17416
17449
|
'replay_length_ms': replayLengthMs,
|
|
@@ -17419,16 +17452,7 @@
|
|
|
17419
17452
|
'seq': this.seqNo
|
|
17420
17453
|
};
|
|
17421
17454
|
var eventsJson = JSON.stringify(data);
|
|
17422
|
-
|
|
17423
|
-
// send ID management props if they exist
|
|
17424
|
-
var deviceId = this._mixpanel.get_property('$device_id');
|
|
17425
|
-
if (deviceId) {
|
|
17426
|
-
reqParams['$device_id'] = deviceId;
|
|
17427
|
-
}
|
|
17428
|
-
var userId = this._mixpanel.get_property('$user_id');
|
|
17429
|
-
if (userId) {
|
|
17430
|
-
reqParams['$user_id'] = userId;
|
|
17431
|
-
}
|
|
17455
|
+
Object.assign(reqParams, this.getUserIdInfo());
|
|
17432
17456
|
|
|
17433
17457
|
if (CompressionStream) {
|
|
17434
17458
|
var jsonStream = new Blob([eventsJson], {type: 'application/json'}).stream();
|
|
@@ -18557,8 +18581,9 @@
|
|
|
18557
18581
|
* @constructor
|
|
18558
18582
|
*/
|
|
18559
18583
|
var FeatureFlagManager = function(initOptions) {
|
|
18584
|
+
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
18560
18585
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
18561
|
-
this.
|
|
18586
|
+
this.getMpProperty = initOptions.getPropertyFunc;
|
|
18562
18587
|
this.track = initOptions.trackingFunc;
|
|
18563
18588
|
};
|
|
18564
18589
|
|
|
@@ -18607,12 +18632,14 @@
|
|
|
18607
18632
|
return;
|
|
18608
18633
|
}
|
|
18609
18634
|
|
|
18610
|
-
var distinctId = this.
|
|
18635
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
18636
|
+
var deviceId = this.getMpProperty('$device_id');
|
|
18611
18637
|
logger.log('Fetching flags for distinct ID: ' + distinctId);
|
|
18612
18638
|
var reqParams = {
|
|
18613
|
-
'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
|
|
18639
|
+
'context': _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT))
|
|
18614
18640
|
};
|
|
18615
|
-
this.
|
|
18641
|
+
this._fetchInProgressStartTime = Date.now();
|
|
18642
|
+
this.fetchPromise = win['fetch'](this.getFullApiRoute(), {
|
|
18616
18643
|
'method': 'POST',
|
|
18617
18644
|
'headers': {
|
|
18618
18645
|
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
@@ -18620,6 +18647,7 @@
|
|
|
18620
18647
|
},
|
|
18621
18648
|
'body': JSON.stringify(reqParams)
|
|
18622
18649
|
}).then(function(response) {
|
|
18650
|
+
this.markFetchComplete();
|
|
18623
18651
|
return response.json().then(function(responseBody) {
|
|
18624
18652
|
var responseFlags = responseBody['flags'];
|
|
18625
18653
|
if (!responseFlags) {
|
|
@@ -18634,9 +18662,24 @@
|
|
|
18634
18662
|
});
|
|
18635
18663
|
this.flags = flags;
|
|
18636
18664
|
}.bind(this)).catch(function(error) {
|
|
18665
|
+
this.markFetchComplete();
|
|
18637
18666
|
logger.error(error);
|
|
18638
|
-
});
|
|
18639
|
-
}.bind(this)).catch(function() {
|
|
18667
|
+
}.bind(this));
|
|
18668
|
+
}.bind(this)).catch(function(error) {
|
|
18669
|
+
this.markFetchComplete();
|
|
18670
|
+
logger.error(error);
|
|
18671
|
+
}.bind(this));
|
|
18672
|
+
};
|
|
18673
|
+
|
|
18674
|
+
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
18675
|
+
if (!this._fetchInProgressStartTime) {
|
|
18676
|
+
logger.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
18677
|
+
return;
|
|
18678
|
+
}
|
|
18679
|
+
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
18680
|
+
this._fetchCompleteTime = Date.now();
|
|
18681
|
+
this._fetchLatency = this._fetchCompleteTime - this._fetchStartTime;
|
|
18682
|
+
this._fetchInProgressStartTime = null;
|
|
18640
18683
|
};
|
|
18641
18684
|
|
|
18642
18685
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
@@ -18715,7 +18758,10 @@
|
|
|
18715
18758
|
this.track('$experiment_started', {
|
|
18716
18759
|
'Experiment name': featureName,
|
|
18717
18760
|
'Variant name': feature['key'],
|
|
18718
|
-
'$experiment_type': 'feature_flag'
|
|
18761
|
+
'$experiment_type': 'feature_flag',
|
|
18762
|
+
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
18763
|
+
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
18764
|
+
'Variant fetch latency (ms)': this._fetchLatency
|
|
18719
18765
|
});
|
|
18720
18766
|
};
|
|
18721
18767
|
|
|
@@ -20415,8 +20461,11 @@
|
|
|
20415
20461
|
}
|
|
20416
20462
|
|
|
20417
20463
|
this.flags = new FeatureFlagManager({
|
|
20464
|
+
getFullApiRoute: _.bind(function() {
|
|
20465
|
+
return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
|
|
20466
|
+
}, this),
|
|
20418
20467
|
getConfigFunc: _.bind(this.get_config, this),
|
|
20419
|
-
|
|
20468
|
+
getPropertyFunc: _.bind(this.get_property, this),
|
|
20420
20469
|
trackingFunc: _.bind(this.track, this)
|
|
20421
20470
|
});
|
|
20422
20471
|
this.flags.init();
|
|
@@ -20902,11 +20951,10 @@
|
|
|
20902
20951
|
|
|
20903
20952
|
MixpanelLib.prototype.get_batcher_configs = function() {
|
|
20904
20953
|
var queue_prefix = '__mpq_' + this.get_config('token');
|
|
20905
|
-
var api_routes = this.get_config('api_routes');
|
|
20906
20954
|
this._batcher_configs = this._batcher_configs || {
|
|
20907
|
-
events: {type: 'events',
|
|
20908
|
-
people: {type: 'people',
|
|
20909
|
-
groups: {type: 'groups',
|
|
20955
|
+
events: {type: 'events', api_name: 'track', queue_key: queue_prefix + '_ev'},
|
|
20956
|
+
people: {type: 'people', api_name: 'engage', queue_key: queue_prefix + '_pp'},
|
|
20957
|
+
groups: {type: 'groups', api_name: 'groups', queue_key: queue_prefix + '_gr'}
|
|
20910
20958
|
};
|
|
20911
20959
|
return this._batcher_configs;
|
|
20912
20960
|
};
|
|
@@ -20920,8 +20968,9 @@
|
|
|
20920
20968
|
libConfig: this['config'],
|
|
20921
20969
|
errorReporter: this.get_config('error_reporter'),
|
|
20922
20970
|
sendRequestFunc: _.bind(function(data, options, cb) {
|
|
20971
|
+
var api_routes = this.get_config('api_routes');
|
|
20923
20972
|
this._send_request(
|
|
20924
|
-
this.
|
|
20973
|
+
this.get_api_host(attrs.api_name) + '/' + api_routes[attrs.api_name],
|
|
20925
20974
|
this._encode_data_for_request(data),
|
|
20926
20975
|
options,
|
|
20927
20976
|
this._prepare_callback(cb, data)
|
|
@@ -21649,31 +21698,15 @@
|
|
|
21649
21698
|
* Useful for clearing data when a user logs out.
|
|
21650
21699
|
*/
|
|
21651
21700
|
MixpanelLib.prototype.reset = function() {
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
|
|
21656
|
-
|
|
21657
|
-
|
|
21658
|
-
|
|
21659
|
-
|
|
21660
|
-
|
|
21661
|
-
}, '');
|
|
21662
|
-
};
|
|
21663
|
-
|
|
21664
|
-
if (self._recorder) {
|
|
21665
|
-
self.stop_session_recording()
|
|
21666
|
-
.then(function () {
|
|
21667
|
-
reset();
|
|
21668
|
-
self._check_and_start_session_recording();
|
|
21669
|
-
})
|
|
21670
|
-
.catch(_.bind(function (err) {
|
|
21671
|
-
reset();
|
|
21672
|
-
this.report_error('Error restarting recording session', err);
|
|
21673
|
-
}, this));
|
|
21674
|
-
} else {
|
|
21675
|
-
reset();
|
|
21676
|
-
}
|
|
21701
|
+
this.stop_session_recording();
|
|
21702
|
+
this['persistence'].clear();
|
|
21703
|
+
this._flags.identify_called = false;
|
|
21704
|
+
var uuid = _.UUID();
|
|
21705
|
+
this.register_once({
|
|
21706
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
21707
|
+
'$device_id': uuid
|
|
21708
|
+
}, '');
|
|
21709
|
+
this._check_and_start_session_recording();
|
|
21677
21710
|
};
|
|
21678
21711
|
|
|
21679
21712
|
/**
|
package/package.json
CHANGED
package/src/config.js
CHANGED
package/src/flags/index.js
CHANGED
|
@@ -15,8 +15,9 @@ CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
|
15
15
|
* @constructor
|
|
16
16
|
*/
|
|
17
17
|
var FeatureFlagManager = function(initOptions) {
|
|
18
|
+
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
18
19
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
19
|
-
this.
|
|
20
|
+
this.getMpProperty = initOptions.getPropertyFunc;
|
|
20
21
|
this.track = initOptions.trackingFunc;
|
|
21
22
|
};
|
|
22
23
|
|
|
@@ -65,12 +66,14 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
65
66
|
return;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
var distinctId = this.
|
|
69
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
70
|
+
var deviceId = this.getMpProperty('$device_id');
|
|
69
71
|
logger.log('Fetching flags for distinct ID: ' + distinctId);
|
|
70
72
|
var reqParams = {
|
|
71
|
-
'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
|
|
73
|
+
'context': _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT))
|
|
72
74
|
};
|
|
73
|
-
this.
|
|
75
|
+
this._fetchInProgressStartTime = Date.now();
|
|
76
|
+
this.fetchPromise = window['fetch'](this.getFullApiRoute(), {
|
|
74
77
|
'method': 'POST',
|
|
75
78
|
'headers': {
|
|
76
79
|
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
@@ -78,6 +81,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
78
81
|
},
|
|
79
82
|
'body': JSON.stringify(reqParams)
|
|
80
83
|
}).then(function(response) {
|
|
84
|
+
this.markFetchComplete();
|
|
81
85
|
return response.json().then(function(responseBody) {
|
|
82
86
|
var responseFlags = responseBody['flags'];
|
|
83
87
|
if (!responseFlags) {
|
|
@@ -92,9 +96,24 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
92
96
|
});
|
|
93
97
|
this.flags = flags;
|
|
94
98
|
}.bind(this)).catch(function(error) {
|
|
99
|
+
this.markFetchComplete();
|
|
95
100
|
logger.error(error);
|
|
96
|
-
});
|
|
97
|
-
}.bind(this)).catch(function() {
|
|
101
|
+
}.bind(this));
|
|
102
|
+
}.bind(this)).catch(function(error) {
|
|
103
|
+
this.markFetchComplete();
|
|
104
|
+
logger.error(error);
|
|
105
|
+
}.bind(this));
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
109
|
+
if (!this._fetchInProgressStartTime) {
|
|
110
|
+
logger.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
114
|
+
this._fetchCompleteTime = Date.now();
|
|
115
|
+
this._fetchLatency = this._fetchCompleteTime - this._fetchStartTime;
|
|
116
|
+
this._fetchInProgressStartTime = null;
|
|
98
117
|
};
|
|
99
118
|
|
|
100
119
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
@@ -173,7 +192,10 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
173
192
|
this.track('$experiment_started', {
|
|
174
193
|
'Experiment name': featureName,
|
|
175
194
|
'Variant name': feature['key'],
|
|
176
|
-
'$experiment_type': 'feature_flag'
|
|
195
|
+
'$experiment_type': 'feature_flag',
|
|
196
|
+
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
197
|
+
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
198
|
+
'Variant fetch latency (ms)': this._fetchLatency
|
|
177
199
|
});
|
|
178
200
|
};
|
|
179
201
|
|
package/src/mixpanel-core.js
CHANGED
|
@@ -369,8 +369,11 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
this.flags = new FeatureFlagManager({
|
|
372
|
+
getFullApiRoute: _.bind(function() {
|
|
373
|
+
return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
|
|
374
|
+
}, this),
|
|
372
375
|
getConfigFunc: _.bind(this.get_config, this),
|
|
373
|
-
|
|
376
|
+
getPropertyFunc: _.bind(this.get_property, this),
|
|
374
377
|
trackingFunc: _.bind(this.track, this)
|
|
375
378
|
});
|
|
376
379
|
this.flags.init();
|
|
@@ -856,11 +859,10 @@ MixpanelLib.prototype.are_batchers_initialized = function() {
|
|
|
856
859
|
|
|
857
860
|
MixpanelLib.prototype.get_batcher_configs = function() {
|
|
858
861
|
var queue_prefix = '__mpq_' + this.get_config('token');
|
|
859
|
-
var api_routes = this.get_config('api_routes');
|
|
860
862
|
this._batcher_configs = this._batcher_configs || {
|
|
861
|
-
events: {type: 'events',
|
|
862
|
-
people: {type: 'people',
|
|
863
|
-
groups: {type: 'groups',
|
|
863
|
+
events: {type: 'events', api_name: 'track', queue_key: queue_prefix + '_ev'},
|
|
864
|
+
people: {type: 'people', api_name: 'engage', queue_key: queue_prefix + '_pp'},
|
|
865
|
+
groups: {type: 'groups', api_name: 'groups', queue_key: queue_prefix + '_gr'}
|
|
864
866
|
};
|
|
865
867
|
return this._batcher_configs;
|
|
866
868
|
};
|
|
@@ -874,8 +876,9 @@ MixpanelLib.prototype.init_batchers = function() {
|
|
|
874
876
|
libConfig: this['config'],
|
|
875
877
|
errorReporter: this.get_config('error_reporter'),
|
|
876
878
|
sendRequestFunc: _.bind(function(data, options, cb) {
|
|
879
|
+
var api_routes = this.get_config('api_routes');
|
|
877
880
|
this._send_request(
|
|
878
|
-
this.
|
|
881
|
+
this.get_api_host(attrs.api_name) + '/' + api_routes[attrs.api_name],
|
|
879
882
|
this._encode_data_for_request(data),
|
|
880
883
|
options,
|
|
881
884
|
this._prepare_callback(cb, data)
|
|
@@ -1603,31 +1606,15 @@ MixpanelLib.prototype.identify = function(
|
|
|
1603
1606
|
* Useful for clearing data when a user logs out.
|
|
1604
1607
|
*/
|
|
1605
1608
|
MixpanelLib.prototype.reset = function() {
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
}, '');
|
|
1616
|
-
};
|
|
1617
|
-
|
|
1618
|
-
if (self._recorder) {
|
|
1619
|
-
self.stop_session_recording()
|
|
1620
|
-
.then(function () {
|
|
1621
|
-
reset();
|
|
1622
|
-
self._check_and_start_session_recording();
|
|
1623
|
-
})
|
|
1624
|
-
.catch(_.bind(function (err) {
|
|
1625
|
-
reset();
|
|
1626
|
-
this.report_error('Error restarting recording session', err);
|
|
1627
|
-
}, this));
|
|
1628
|
-
} else {
|
|
1629
|
-
reset();
|
|
1630
|
-
}
|
|
1609
|
+
this.stop_session_recording();
|
|
1610
|
+
this['persistence'].clear();
|
|
1611
|
+
this._flags.identify_called = false;
|
|
1612
|
+
var uuid = _.UUID();
|
|
1613
|
+
this.register_once({
|
|
1614
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
1615
|
+
'$device_id': uuid
|
|
1616
|
+
}, '');
|
|
1617
|
+
this._check_and_start_session_recording();
|
|
1631
1618
|
};
|
|
1632
1619
|
|
|
1633
1620
|
/**
|