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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  var Config = {
4
4
  DEBUG: false,
5
- LIB_VERSION: '2.65.0'
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.getDistinctId = initOptions.getDistinctIdFunc;
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.getDistinctId();
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.fetchPromise = win['fetch'](this.getMpConfig('api_host') + '/' + this.getMpConfig('api_routes')['flags'], {
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._get_config('api_host') + '/' + this._get_config('api_routes')['groups'],
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._get_config('api_host') + '/' + this._get_config('api_routes')['engage'],
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
- getDistinctIdFunc: _.bind(this.get_distinct_id, this),
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', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'},
6660
- people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'},
6661
- groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'}
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.get_config('api_host') + attrs.endpoint,
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.get_config('api_host') + '/' + this.get_config('api_routes')['track'],
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.65.0'
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'](this.getConfig('api_host') + '/' + this.getConfig('api_routes')['record'] + '?' + new URLSearchParams(reqParams), {
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
- var stopPromise = this._stopCurrentRecording(false);
17622
- this.recordingRegistry.clearActiveRecording();
17623
- this.activeRecording = null;
17624
- return stopPromise;
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
- return this.activeRecording.stopRecording(skipFlush);
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.getDistinctId = initOptions.getDistinctIdFunc;
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.getDistinctId();
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.fetchPromise = win['fetch'](this.getMpConfig('api_host') + '/' + this.getMpConfig('api_routes')['flags'], {
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._get_config('api_host') + '/' + this._get_config('api_routes')['groups'],
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._get_config('api_host') + '/' + this._get_config('api_routes')['engage'],
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
- getDistinctIdFunc: _.bind(this.get_distinct_id, this),
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', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'},
20893
- people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'},
20894
- groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'}
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.get_config('api_host') + attrs.endpoint,
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.get_config('api_host') + '/' + this.get_config('api_routes')['track'],
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;