mixpanel-browser 2.65.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 +12 -0
- package/README.md +1 -1
- package/dist/mixpanel-core.cjs.js +61 -21
- package/dist/mixpanel-recorder.js +53 -21
- 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 +61 -21
- package/dist/mixpanel-with-recorder.js +113 -41
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.js +113 -41
- package/dist/mixpanel.cjs.js +113 -41
- package/dist/mixpanel.globals.js +61 -21
- package/dist/mixpanel.min.js +140 -139
- package/dist/mixpanel.module.js +113 -41
- package/dist/mixpanel.umd.js +113 -41
- package/package.json +2 -1
- package/src/config.js +1 -1
- package/src/flags/index.js +29 -7
- package/src/index.d.ts +408 -0
- package/src/mixpanel-core.js +29 -11
- package/src/mixpanel-group.js +1 -1
- package/src/mixpanel-people.js +1 -1
- package/src/recorder/recorder.js +15 -7
- package/src/recorder/session-recording.js +37 -13
- package/tunnel.log +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
5
|
+
LIB_VERSION: '2.67.0'
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
@@ -3002,8 +3002,9 @@ CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
|
3002
3002
|
* @constructor
|
|
3003
3003
|
*/
|
|
3004
3004
|
var FeatureFlagManager = function(initOptions) {
|
|
3005
|
+
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
3005
3006
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
3006
|
-
this.
|
|
3007
|
+
this.getMpProperty = initOptions.getPropertyFunc;
|
|
3007
3008
|
this.track = initOptions.trackingFunc;
|
|
3008
3009
|
};
|
|
3009
3010
|
|
|
@@ -3052,12 +3053,14 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
3052
3053
|
return;
|
|
3053
3054
|
}
|
|
3054
3055
|
|
|
3055
|
-
var distinctId = this.
|
|
3056
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
3057
|
+
var deviceId = this.getMpProperty('$device_id');
|
|
3056
3058
|
logger$3.log('Fetching flags for distinct ID: ' + distinctId);
|
|
3057
3059
|
var reqParams = {
|
|
3058
|
-
'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
|
|
3060
|
+
'context': _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT))
|
|
3059
3061
|
};
|
|
3060
|
-
this.
|
|
3062
|
+
this._fetchInProgressStartTime = Date.now();
|
|
3063
|
+
this.fetchPromise = win['fetch'](this.getFullApiRoute(), {
|
|
3061
3064
|
'method': 'POST',
|
|
3062
3065
|
'headers': {
|
|
3063
3066
|
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
@@ -3065,6 +3068,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
3065
3068
|
},
|
|
3066
3069
|
'body': JSON.stringify(reqParams)
|
|
3067
3070
|
}).then(function(response) {
|
|
3071
|
+
this.markFetchComplete();
|
|
3068
3072
|
return response.json().then(function(responseBody) {
|
|
3069
3073
|
var responseFlags = responseBody['flags'];
|
|
3070
3074
|
if (!responseFlags) {
|
|
@@ -3079,9 +3083,24 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
3079
3083
|
});
|
|
3080
3084
|
this.flags = flags;
|
|
3081
3085
|
}.bind(this)).catch(function(error) {
|
|
3086
|
+
this.markFetchComplete();
|
|
3082
3087
|
logger$3.error(error);
|
|
3083
|
-
});
|
|
3084
|
-
}.bind(this)).catch(function() {
|
|
3088
|
+
}.bind(this));
|
|
3089
|
+
}.bind(this)).catch(function(error) {
|
|
3090
|
+
this.markFetchComplete();
|
|
3091
|
+
logger$3.error(error);
|
|
3092
|
+
}.bind(this));
|
|
3093
|
+
};
|
|
3094
|
+
|
|
3095
|
+
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
3096
|
+
if (!this._fetchInProgressStartTime) {
|
|
3097
|
+
logger$3.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3100
|
+
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
3101
|
+
this._fetchCompleteTime = Date.now();
|
|
3102
|
+
this._fetchLatency = this._fetchCompleteTime - this._fetchStartTime;
|
|
3103
|
+
this._fetchInProgressStartTime = null;
|
|
3085
3104
|
};
|
|
3086
3105
|
|
|
3087
3106
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
@@ -3160,7 +3179,10 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
3160
3179
|
this.track('$experiment_started', {
|
|
3161
3180
|
'Experiment name': featureName,
|
|
3162
3181
|
'Variant name': feature['key'],
|
|
3163
|
-
'$experiment_type': 'feature_flag'
|
|
3182
|
+
'$experiment_type': 'feature_flag',
|
|
3183
|
+
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
3184
|
+
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
3185
|
+
'Variant fetch latency (ms)': this._fetchLatency
|
|
3164
3186
|
});
|
|
3165
3187
|
};
|
|
3166
3188
|
|
|
@@ -4789,7 +4811,7 @@ MixpanelGroup.prototype._send_request = function(data, callback) {
|
|
|
4789
4811
|
return this._mixpanel._track_or_batch({
|
|
4790
4812
|
type: 'groups',
|
|
4791
4813
|
data: date_encoded_data,
|
|
4792
|
-
endpoint: this.
|
|
4814
|
+
endpoint: this._mixpanel.get_api_host('groups') + '/' + this._get_config('api_routes')['groups'],
|
|
4793
4815
|
batcher: this._mixpanel.request_batchers.groups
|
|
4794
4816
|
}, callback);
|
|
4795
4817
|
};
|
|
@@ -5141,7 +5163,7 @@ MixpanelPeople.prototype._send_request = function(data, callback) {
|
|
|
5141
5163
|
return this._mixpanel._track_or_batch({
|
|
5142
5164
|
type: 'people',
|
|
5143
5165
|
data: date_encoded_data,
|
|
5144
|
-
endpoint: this.
|
|
5166
|
+
endpoint: this._mixpanel.get_api_host('people') + '/' + this._get_config('api_routes')['engage'],
|
|
5145
5167
|
batcher: this._mixpanel.request_batchers.people
|
|
5146
5168
|
}, callback);
|
|
5147
5169
|
};
|
|
@@ -5901,6 +5923,7 @@ var DEFAULT_API_ROUTES = {
|
|
|
5901
5923
|
*/
|
|
5902
5924
|
var DEFAULT_CONFIG = {
|
|
5903
5925
|
'api_host': 'https://api-js.mixpanel.com',
|
|
5926
|
+
'api_hosts': {},
|
|
5904
5927
|
'api_routes': DEFAULT_API_ROUTES,
|
|
5905
5928
|
'api_extra_query_params': {},
|
|
5906
5929
|
'api_method': 'POST',
|
|
@@ -6170,8 +6193,11 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
6170
6193
|
}
|
|
6171
6194
|
|
|
6172
6195
|
this.flags = new FeatureFlagManager({
|
|
6196
|
+
getFullApiRoute: _.bind(function() {
|
|
6197
|
+
return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
|
|
6198
|
+
}, this),
|
|
6173
6199
|
getConfigFunc: _.bind(this.get_config, this),
|
|
6174
|
-
|
|
6200
|
+
getPropertyFunc: _.bind(this.get_property, this),
|
|
6175
6201
|
trackingFunc: _.bind(this.track, this)
|
|
6176
6202
|
});
|
|
6177
6203
|
this.flags.init();
|
|
@@ -6286,20 +6312,23 @@ MixpanelLib.prototype.start_session_recording = function () {
|
|
|
6286
6312
|
|
|
6287
6313
|
MixpanelLib.prototype.stop_session_recording = function () {
|
|
6288
6314
|
if (this._recorder) {
|
|
6289
|
-
this._recorder['stopRecording']();
|
|
6315
|
+
return this._recorder['stopRecording']();
|
|
6290
6316
|
}
|
|
6317
|
+
return Promise.resolve();
|
|
6291
6318
|
};
|
|
6292
6319
|
|
|
6293
6320
|
MixpanelLib.prototype.pause_session_recording = function () {
|
|
6294
6321
|
if (this._recorder) {
|
|
6295
|
-
this._recorder['pauseRecording']();
|
|
6322
|
+
return this._recorder['pauseRecording']();
|
|
6296
6323
|
}
|
|
6324
|
+
return Promise.resolve();
|
|
6297
6325
|
};
|
|
6298
6326
|
|
|
6299
6327
|
MixpanelLib.prototype.resume_session_recording = function () {
|
|
6300
6328
|
if (this._recorder) {
|
|
6301
|
-
this._recorder['resumeRecording']();
|
|
6329
|
+
return this._recorder['resumeRecording']();
|
|
6302
6330
|
}
|
|
6331
|
+
return Promise.resolve();
|
|
6303
6332
|
};
|
|
6304
6333
|
|
|
6305
6334
|
MixpanelLib.prototype.is_recording_heatmap_data = function () {
|
|
@@ -6654,11 +6683,10 @@ MixpanelLib.prototype.are_batchers_initialized = function() {
|
|
|
6654
6683
|
|
|
6655
6684
|
MixpanelLib.prototype.get_batcher_configs = function() {
|
|
6656
6685
|
var queue_prefix = '__mpq_' + this.get_config('token');
|
|
6657
|
-
var api_routes = this.get_config('api_routes');
|
|
6658
6686
|
this._batcher_configs = this._batcher_configs || {
|
|
6659
|
-
events: {type: 'events',
|
|
6660
|
-
people: {type: 'people',
|
|
6661
|
-
groups: {type: 'groups',
|
|
6687
|
+
events: {type: 'events', api_name: 'track', queue_key: queue_prefix + '_ev'},
|
|
6688
|
+
people: {type: 'people', api_name: 'engage', queue_key: queue_prefix + '_pp'},
|
|
6689
|
+
groups: {type: 'groups', api_name: 'groups', queue_key: queue_prefix + '_gr'}
|
|
6662
6690
|
};
|
|
6663
6691
|
return this._batcher_configs;
|
|
6664
6692
|
};
|
|
@@ -6672,8 +6700,9 @@ MixpanelLib.prototype.init_batchers = function() {
|
|
|
6672
6700
|
libConfig: this['config'],
|
|
6673
6701
|
errorReporter: this.get_config('error_reporter'),
|
|
6674
6702
|
sendRequestFunc: _.bind(function(data, options, cb) {
|
|
6703
|
+
var api_routes = this.get_config('api_routes');
|
|
6675
6704
|
this._send_request(
|
|
6676
|
-
this.
|
|
6705
|
+
this.get_api_host(attrs.api_name) + '/' + api_routes[attrs.api_name],
|
|
6677
6706
|
this._encode_data_for_request(data),
|
|
6678
6707
|
options,
|
|
6679
6708
|
this._prepare_callback(cb, data)
|
|
@@ -6899,7 +6928,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro
|
|
|
6899
6928
|
var ret = this._track_or_batch({
|
|
6900
6929
|
type: 'events',
|
|
6901
6930
|
data: data,
|
|
6902
|
-
endpoint: this.
|
|
6931
|
+
endpoint: this.get_api_host('events') + '/' + this.get_config('api_routes')['track'],
|
|
6903
6932
|
batcher: this.request_batchers.events,
|
|
6904
6933
|
should_send_immediately: should_send_immediately,
|
|
6905
6934
|
send_request_options: options
|
|
@@ -7401,6 +7430,7 @@ MixpanelLib.prototype.identify = function(
|
|
|
7401
7430
|
* Useful for clearing data when a user logs out.
|
|
7402
7431
|
*/
|
|
7403
7432
|
MixpanelLib.prototype.reset = function() {
|
|
7433
|
+
this.stop_session_recording();
|
|
7404
7434
|
this['persistence'].clear();
|
|
7405
7435
|
this._flags.identify_called = false;
|
|
7406
7436
|
var uuid = _.UUID();
|
|
@@ -7408,7 +7438,6 @@ MixpanelLib.prototype.reset = function() {
|
|
|
7408
7438
|
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
7409
7439
|
'$device_id': uuid
|
|
7410
7440
|
}, '');
|
|
7411
|
-
this.stop_session_recording();
|
|
7412
7441
|
this._check_and_start_session_recording();
|
|
7413
7442
|
};
|
|
7414
7443
|
|
|
@@ -7720,6 +7749,16 @@ MixpanelLib.prototype.get_property = function(property_name) {
|
|
|
7720
7749
|
return this['persistence'].load_prop([property_name]);
|
|
7721
7750
|
};
|
|
7722
7751
|
|
|
7752
|
+
/**
|
|
7753
|
+
* Get the API host for a specific endpoint type, falling back to the default api_host if not specified
|
|
7754
|
+
*
|
|
7755
|
+
* @param {String} endpoint_type The type of endpoint (e.g., "events", "people", "groups")
|
|
7756
|
+
* @returns {String} The API host to use for this endpoint
|
|
7757
|
+
*/
|
|
7758
|
+
MixpanelLib.prototype.get_api_host = function(endpoint_type) {
|
|
7759
|
+
return this.get_config('api_hosts')[endpoint_type] || this.get_config('api_host');
|
|
7760
|
+
};
|
|
7761
|
+
|
|
7723
7762
|
MixpanelLib.prototype.toString = function() {
|
|
7724
7763
|
var name = this.get_config('name');
|
|
7725
7764
|
if (name !== PRIMARY_INSTANCE_NAME) {
|
|
@@ -8015,6 +8054,7 @@ MixpanelLib.prototype['alias'] = MixpanelLib.protot
|
|
|
8015
8054
|
MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
|
|
8016
8055
|
MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
|
|
8017
8056
|
MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
|
|
8057
|
+
MixpanelLib.prototype['get_api_host'] = MixpanelLib.prototype.get_api_host;
|
|
8018
8058
|
MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
|
|
8019
8059
|
MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
|
|
8020
8060
|
MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
|
|
@@ -13945,7 +13945,7 @@
|
|
|
13945
13945
|
|
|
13946
13946
|
var Config = {
|
|
13947
13947
|
DEBUG: false,
|
|
13948
|
-
LIB_VERSION: '2.
|
|
13948
|
+
LIB_VERSION: '2.67.0'
|
|
13949
13949
|
};
|
|
13950
13950
|
|
|
13951
13951
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -17063,6 +17063,13 @@
|
|
|
17063
17063
|
* @property {string} replayStartUrl
|
|
17064
17064
|
*/
|
|
17065
17065
|
|
|
17066
|
+
/**
|
|
17067
|
+
* @typedef {Object} UserIdInfo
|
|
17068
|
+
* @property {string} distinct_id
|
|
17069
|
+
* @property {string} user_id
|
|
17070
|
+
* @property {string} device_id
|
|
17071
|
+
*/
|
|
17072
|
+
|
|
17066
17073
|
|
|
17067
17074
|
/**
|
|
17068
17075
|
* This class encapsulates a single session recording and its lifecycle.
|
|
@@ -17118,6 +17125,30 @@
|
|
|
17118
17125
|
});
|
|
17119
17126
|
};
|
|
17120
17127
|
|
|
17128
|
+
/**
|
|
17129
|
+
* @returns {UserIdInfo}
|
|
17130
|
+
*/
|
|
17131
|
+
SessionRecording.prototype.getUserIdInfo = function () {
|
|
17132
|
+
if (this.finalFlushUserIdInfo) {
|
|
17133
|
+
return this.finalFlushUserIdInfo;
|
|
17134
|
+
}
|
|
17135
|
+
|
|
17136
|
+
var userIdInfo = {
|
|
17137
|
+
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
17138
|
+
};
|
|
17139
|
+
|
|
17140
|
+
// send ID management props if they exist
|
|
17141
|
+
var deviceId = this._mixpanel.get_property('$device_id');
|
|
17142
|
+
if (deviceId) {
|
|
17143
|
+
userIdInfo['$device_id'] = deviceId;
|
|
17144
|
+
}
|
|
17145
|
+
var userId = this._mixpanel.get_property('$user_id');
|
|
17146
|
+
if (userId) {
|
|
17147
|
+
userIdInfo['$user_id'] = userId;
|
|
17148
|
+
}
|
|
17149
|
+
return userIdInfo;
|
|
17150
|
+
};
|
|
17151
|
+
|
|
17121
17152
|
SessionRecording.prototype.unloadPersistedData = function () {
|
|
17122
17153
|
this.batcher.stop();
|
|
17123
17154
|
return this.batcher.flush()
|
|
@@ -17242,6 +17273,9 @@
|
|
|
17242
17273
|
};
|
|
17243
17274
|
|
|
17244
17275
|
SessionRecording.prototype.stopRecording = function (skipFlush) {
|
|
17276
|
+
// store the user ID info in case this is getting called in mixpanel.reset()
|
|
17277
|
+
this.finalFlushUserIdInfo = this.getUserIdInfo();
|
|
17278
|
+
|
|
17245
17279
|
if (!this.isRrwebStopped()) {
|
|
17246
17280
|
try {
|
|
17247
17281
|
this._stopRecording();
|
|
@@ -17352,8 +17386,8 @@
|
|
|
17352
17386
|
retryAfter: response.headers.get('Retry-After')
|
|
17353
17387
|
});
|
|
17354
17388
|
}.bind(this);
|
|
17355
|
-
|
|
17356
|
-
win['fetch'](
|
|
17389
|
+
var apiHost = (this._mixpanel.get_api_host && this._mixpanel.get_api_host('record')) || this.getConfig('api_host');
|
|
17390
|
+
win['fetch'](apiHost + '/' + this.getConfig('api_routes')['record'] + '?' + new URLSearchParams(reqParams), {
|
|
17357
17391
|
'method': 'POST',
|
|
17358
17392
|
'headers': {
|
|
17359
17393
|
'Authorization': 'Basic ' + btoa(this.getConfig('token') + ':'),
|
|
@@ -17407,7 +17441,6 @@
|
|
|
17407
17441
|
'$current_url': this.batchStartUrl,
|
|
17408
17442
|
'$lib_version': Config.LIB_VERSION,
|
|
17409
17443
|
'batch_start_time': batchStartTime / 1000,
|
|
17410
|
-
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
17411
17444
|
'mp_lib': 'web',
|
|
17412
17445
|
'replay_id': replayId,
|
|
17413
17446
|
'replay_length_ms': replayLengthMs,
|
|
@@ -17416,16 +17449,7 @@
|
|
|
17416
17449
|
'seq': this.seqNo
|
|
17417
17450
|
};
|
|
17418
17451
|
var eventsJson = JSON.stringify(data);
|
|
17419
|
-
|
|
17420
|
-
// send ID management props if they exist
|
|
17421
|
-
var deviceId = this._mixpanel.get_property('$device_id');
|
|
17422
|
-
if (deviceId) {
|
|
17423
|
-
reqParams['$device_id'] = deviceId;
|
|
17424
|
-
}
|
|
17425
|
-
var userId = this._mixpanel.get_property('$user_id');
|
|
17426
|
-
if (userId) {
|
|
17427
|
-
reqParams['$user_id'] = userId;
|
|
17428
|
-
}
|
|
17452
|
+
Object.assign(reqParams, this.getUserIdInfo());
|
|
17429
17453
|
|
|
17430
17454
|
if (CompressionStream) {
|
|
17431
17455
|
var jsonStream = new Blob([eventsJson], {type: 'application/json'}).stream();
|
|
@@ -17570,6 +17594,7 @@
|
|
|
17570
17594
|
this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
|
|
17571
17595
|
|
|
17572
17596
|
this.activeRecording = null;
|
|
17597
|
+
this.stopRecordingInProgress = false;
|
|
17573
17598
|
};
|
|
17574
17599
|
|
|
17575
17600
|
MixpanelRecorder.prototype.startRecording = function(options) {
|
|
@@ -17618,19 +17643,26 @@
|
|
|
17618
17643
|
};
|
|
17619
17644
|
|
|
17620
17645
|
MixpanelRecorder.prototype.stopRecording = function() {
|
|
17621
|
-
|
|
17622
|
-
this.
|
|
17623
|
-
this.
|
|
17624
|
-
|
|
17646
|
+
// Prevents activeSerializedRecording from being reused when stopping the recording.
|
|
17647
|
+
this.stopRecordingInProgress = true;
|
|
17648
|
+
return this._stopCurrentRecording(false, true).then(function() {
|
|
17649
|
+
return this.recordingRegistry.clearActiveRecording();
|
|
17650
|
+
}.bind(this)).then(function() {
|
|
17651
|
+
this.stopRecordingInProgress = false;
|
|
17652
|
+
}.bind(this));
|
|
17625
17653
|
};
|
|
17626
17654
|
|
|
17627
17655
|
MixpanelRecorder.prototype.pauseRecording = function() {
|
|
17628
17656
|
return this._stopCurrentRecording(false);
|
|
17629
17657
|
};
|
|
17630
17658
|
|
|
17631
|
-
MixpanelRecorder.prototype._stopCurrentRecording = function(skipFlush) {
|
|
17659
|
+
MixpanelRecorder.prototype._stopCurrentRecording = function(skipFlush, disableActiveRecording) {
|
|
17632
17660
|
if (this.activeRecording) {
|
|
17633
|
-
|
|
17661
|
+
var stopRecordingPromise = this.activeRecording.stopRecording(skipFlush);
|
|
17662
|
+
if (disableActiveRecording) {
|
|
17663
|
+
this.activeRecording = null;
|
|
17664
|
+
}
|
|
17665
|
+
return stopRecordingPromise;
|
|
17634
17666
|
}
|
|
17635
17667
|
return PromisePolyfill.resolve();
|
|
17636
17668
|
};
|
|
@@ -17643,7 +17675,7 @@
|
|
|
17643
17675
|
|
|
17644
17676
|
return this.recordingRegistry.getActiveRecording()
|
|
17645
17677
|
.then(function (activeSerializedRecording) {
|
|
17646
|
-
if (activeSerializedRecording) {
|
|
17678
|
+
if (activeSerializedRecording && !this.stopRecordingInProgress) {
|
|
17647
17679
|
return this.startRecording({activeSerializedRecording: activeSerializedRecording});
|
|
17648
17680
|
} else if (startNewIfInactive) {
|
|
17649
17681
|
return this.startRecording({shouldStopBatcher: false});
|
|
@@ -18546,8 +18578,9 @@
|
|
|
18546
18578
|
* @constructor
|
|
18547
18579
|
*/
|
|
18548
18580
|
var FeatureFlagManager = function(initOptions) {
|
|
18581
|
+
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
18549
18582
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
18550
|
-
this.
|
|
18583
|
+
this.getMpProperty = initOptions.getPropertyFunc;
|
|
18551
18584
|
this.track = initOptions.trackingFunc;
|
|
18552
18585
|
};
|
|
18553
18586
|
|
|
@@ -18596,12 +18629,14 @@
|
|
|
18596
18629
|
return;
|
|
18597
18630
|
}
|
|
18598
18631
|
|
|
18599
|
-
var distinctId = this.
|
|
18632
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
18633
|
+
var deviceId = this.getMpProperty('$device_id');
|
|
18600
18634
|
logger.log('Fetching flags for distinct ID: ' + distinctId);
|
|
18601
18635
|
var reqParams = {
|
|
18602
|
-
'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
|
|
18636
|
+
'context': _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT))
|
|
18603
18637
|
};
|
|
18604
|
-
this.
|
|
18638
|
+
this._fetchInProgressStartTime = Date.now();
|
|
18639
|
+
this.fetchPromise = win['fetch'](this.getFullApiRoute(), {
|
|
18605
18640
|
'method': 'POST',
|
|
18606
18641
|
'headers': {
|
|
18607
18642
|
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
@@ -18609,6 +18644,7 @@
|
|
|
18609
18644
|
},
|
|
18610
18645
|
'body': JSON.stringify(reqParams)
|
|
18611
18646
|
}).then(function(response) {
|
|
18647
|
+
this.markFetchComplete();
|
|
18612
18648
|
return response.json().then(function(responseBody) {
|
|
18613
18649
|
var responseFlags = responseBody['flags'];
|
|
18614
18650
|
if (!responseFlags) {
|
|
@@ -18623,9 +18659,24 @@
|
|
|
18623
18659
|
});
|
|
18624
18660
|
this.flags = flags;
|
|
18625
18661
|
}.bind(this)).catch(function(error) {
|
|
18662
|
+
this.markFetchComplete();
|
|
18626
18663
|
logger.error(error);
|
|
18627
|
-
});
|
|
18628
|
-
}.bind(this)).catch(function() {
|
|
18664
|
+
}.bind(this));
|
|
18665
|
+
}.bind(this)).catch(function(error) {
|
|
18666
|
+
this.markFetchComplete();
|
|
18667
|
+
logger.error(error);
|
|
18668
|
+
}.bind(this));
|
|
18669
|
+
};
|
|
18670
|
+
|
|
18671
|
+
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
18672
|
+
if (!this._fetchInProgressStartTime) {
|
|
18673
|
+
logger.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
18674
|
+
return;
|
|
18675
|
+
}
|
|
18676
|
+
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
18677
|
+
this._fetchCompleteTime = Date.now();
|
|
18678
|
+
this._fetchLatency = this._fetchCompleteTime - this._fetchStartTime;
|
|
18679
|
+
this._fetchInProgressStartTime = null;
|
|
18629
18680
|
};
|
|
18630
18681
|
|
|
18631
18682
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
@@ -18704,7 +18755,10 @@
|
|
|
18704
18755
|
this.track('$experiment_started', {
|
|
18705
18756
|
'Experiment name': featureName,
|
|
18706
18757
|
'Variant name': feature['key'],
|
|
18707
|
-
'$experiment_type': 'feature_flag'
|
|
18758
|
+
'$experiment_type': 'feature_flag',
|
|
18759
|
+
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
18760
|
+
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
18761
|
+
'Variant fetch latency (ms)': this._fetchLatency
|
|
18708
18762
|
});
|
|
18709
18763
|
};
|
|
18710
18764
|
|
|
@@ -19145,7 +19199,7 @@
|
|
|
19145
19199
|
return this._mixpanel._track_or_batch({
|
|
19146
19200
|
type: 'groups',
|
|
19147
19201
|
data: date_encoded_data,
|
|
19148
|
-
endpoint: this.
|
|
19202
|
+
endpoint: this._mixpanel.get_api_host('groups') + '/' + this._get_config('api_routes')['groups'],
|
|
19149
19203
|
batcher: this._mixpanel.request_batchers.groups
|
|
19150
19204
|
}, callback);
|
|
19151
19205
|
};
|
|
@@ -19497,7 +19551,7 @@
|
|
|
19497
19551
|
return this._mixpanel._track_or_batch({
|
|
19498
19552
|
type: 'people',
|
|
19499
19553
|
data: date_encoded_data,
|
|
19500
|
-
endpoint: this.
|
|
19554
|
+
endpoint: this._mixpanel.get_api_host('people') + '/' + this._get_config('api_routes')['engage'],
|
|
19501
19555
|
batcher: this._mixpanel.request_batchers.people
|
|
19502
19556
|
}, callback);
|
|
19503
19557
|
};
|
|
@@ -20134,6 +20188,7 @@
|
|
|
20134
20188
|
*/
|
|
20135
20189
|
var DEFAULT_CONFIG = {
|
|
20136
20190
|
'api_host': 'https://api-js.mixpanel.com',
|
|
20191
|
+
'api_hosts': {},
|
|
20137
20192
|
'api_routes': DEFAULT_API_ROUTES,
|
|
20138
20193
|
'api_extra_query_params': {},
|
|
20139
20194
|
'api_method': 'POST',
|
|
@@ -20403,8 +20458,11 @@
|
|
|
20403
20458
|
}
|
|
20404
20459
|
|
|
20405
20460
|
this.flags = new FeatureFlagManager({
|
|
20461
|
+
getFullApiRoute: _.bind(function() {
|
|
20462
|
+
return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
|
|
20463
|
+
}, this),
|
|
20406
20464
|
getConfigFunc: _.bind(this.get_config, this),
|
|
20407
|
-
|
|
20465
|
+
getPropertyFunc: _.bind(this.get_property, this),
|
|
20408
20466
|
trackingFunc: _.bind(this.track, this)
|
|
20409
20467
|
});
|
|
20410
20468
|
this.flags.init();
|
|
@@ -20519,20 +20577,23 @@
|
|
|
20519
20577
|
|
|
20520
20578
|
MixpanelLib.prototype.stop_session_recording = function () {
|
|
20521
20579
|
if (this._recorder) {
|
|
20522
|
-
this._recorder['stopRecording']();
|
|
20580
|
+
return this._recorder['stopRecording']();
|
|
20523
20581
|
}
|
|
20582
|
+
return Promise.resolve();
|
|
20524
20583
|
};
|
|
20525
20584
|
|
|
20526
20585
|
MixpanelLib.prototype.pause_session_recording = function () {
|
|
20527
20586
|
if (this._recorder) {
|
|
20528
|
-
this._recorder['pauseRecording']();
|
|
20587
|
+
return this._recorder['pauseRecording']();
|
|
20529
20588
|
}
|
|
20589
|
+
return Promise.resolve();
|
|
20530
20590
|
};
|
|
20531
20591
|
|
|
20532
20592
|
MixpanelLib.prototype.resume_session_recording = function () {
|
|
20533
20593
|
if (this._recorder) {
|
|
20534
|
-
this._recorder['resumeRecording']();
|
|
20594
|
+
return this._recorder['resumeRecording']();
|
|
20535
20595
|
}
|
|
20596
|
+
return Promise.resolve();
|
|
20536
20597
|
};
|
|
20537
20598
|
|
|
20538
20599
|
MixpanelLib.prototype.is_recording_heatmap_data = function () {
|
|
@@ -20887,11 +20948,10 @@
|
|
|
20887
20948
|
|
|
20888
20949
|
MixpanelLib.prototype.get_batcher_configs = function() {
|
|
20889
20950
|
var queue_prefix = '__mpq_' + this.get_config('token');
|
|
20890
|
-
var api_routes = this.get_config('api_routes');
|
|
20891
20951
|
this._batcher_configs = this._batcher_configs || {
|
|
20892
|
-
events: {type: 'events',
|
|
20893
|
-
people: {type: 'people',
|
|
20894
|
-
groups: {type: 'groups',
|
|
20952
|
+
events: {type: 'events', api_name: 'track', queue_key: queue_prefix + '_ev'},
|
|
20953
|
+
people: {type: 'people', api_name: 'engage', queue_key: queue_prefix + '_pp'},
|
|
20954
|
+
groups: {type: 'groups', api_name: 'groups', queue_key: queue_prefix + '_gr'}
|
|
20895
20955
|
};
|
|
20896
20956
|
return this._batcher_configs;
|
|
20897
20957
|
};
|
|
@@ -20905,8 +20965,9 @@
|
|
|
20905
20965
|
libConfig: this['config'],
|
|
20906
20966
|
errorReporter: this.get_config('error_reporter'),
|
|
20907
20967
|
sendRequestFunc: _.bind(function(data, options, cb) {
|
|
20968
|
+
var api_routes = this.get_config('api_routes');
|
|
20908
20969
|
this._send_request(
|
|
20909
|
-
this.
|
|
20970
|
+
this.get_api_host(attrs.api_name) + '/' + api_routes[attrs.api_name],
|
|
20910
20971
|
this._encode_data_for_request(data),
|
|
20911
20972
|
options,
|
|
20912
20973
|
this._prepare_callback(cb, data)
|
|
@@ -21132,7 +21193,7 @@
|
|
|
21132
21193
|
var ret = this._track_or_batch({
|
|
21133
21194
|
type: 'events',
|
|
21134
21195
|
data: data,
|
|
21135
|
-
endpoint: this.
|
|
21196
|
+
endpoint: this.get_api_host('events') + '/' + this.get_config('api_routes')['track'],
|
|
21136
21197
|
batcher: this.request_batchers.events,
|
|
21137
21198
|
should_send_immediately: should_send_immediately,
|
|
21138
21199
|
send_request_options: options
|
|
@@ -21634,6 +21695,7 @@
|
|
|
21634
21695
|
* Useful for clearing data when a user logs out.
|
|
21635
21696
|
*/
|
|
21636
21697
|
MixpanelLib.prototype.reset = function() {
|
|
21698
|
+
this.stop_session_recording();
|
|
21637
21699
|
this['persistence'].clear();
|
|
21638
21700
|
this._flags.identify_called = false;
|
|
21639
21701
|
var uuid = _.UUID();
|
|
@@ -21641,7 +21703,6 @@
|
|
|
21641
21703
|
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
21642
21704
|
'$device_id': uuid
|
|
21643
21705
|
}, '');
|
|
21644
|
-
this.stop_session_recording();
|
|
21645
21706
|
this._check_and_start_session_recording();
|
|
21646
21707
|
};
|
|
21647
21708
|
|
|
@@ -21953,6 +22014,16 @@
|
|
|
21953
22014
|
return this['persistence'].load_prop([property_name]);
|
|
21954
22015
|
};
|
|
21955
22016
|
|
|
22017
|
+
/**
|
|
22018
|
+
* Get the API host for a specific endpoint type, falling back to the default api_host if not specified
|
|
22019
|
+
*
|
|
22020
|
+
* @param {String} endpoint_type The type of endpoint (e.g., "events", "people", "groups")
|
|
22021
|
+
* @returns {String} The API host to use for this endpoint
|
|
22022
|
+
*/
|
|
22023
|
+
MixpanelLib.prototype.get_api_host = function(endpoint_type) {
|
|
22024
|
+
return this.get_config('api_hosts')[endpoint_type] || this.get_config('api_host');
|
|
22025
|
+
};
|
|
22026
|
+
|
|
21956
22027
|
MixpanelLib.prototype.toString = function() {
|
|
21957
22028
|
var name = this.get_config('name');
|
|
21958
22029
|
if (name !== PRIMARY_INSTANCE_NAME) {
|
|
@@ -22248,6 +22319,7 @@
|
|
|
22248
22319
|
MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
|
|
22249
22320
|
MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
|
|
22250
22321
|
MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
|
|
22322
|
+
MixpanelLib.prototype['get_api_host'] = MixpanelLib.prototype.get_api_host;
|
|
22251
22323
|
MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
|
|
22252
22324
|
MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
|
|
22253
22325
|
MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
|