mixpanel-browser 2.77.0 → 2.78.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.
Files changed (41) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/CHANGELOG.md +4 -0
  3. package/dist/async-modules/{mixpanel-recorder-wIWnMDLA.min.js → mixpanel-recorder-BjSlYaNJ.min.js} +2 -2
  4. package/dist/async-modules/{mixpanel-recorder-wIWnMDLA.min.js.map → mixpanel-recorder-BjSlYaNJ.min.js.map} +1 -1
  5. package/dist/async-modules/{mixpanel-recorder-DLKbUIEE.js → mixpanel-recorder-zMBXIyeG.js} +1 -1
  6. package/dist/async-modules/{mixpanel-targeting-CTcftSJC.min.js → mixpanel-targeting-BSHal4N9.min.js} +2 -2
  7. package/dist/async-modules/{mixpanel-targeting-CTcftSJC.min.js.map → mixpanel-targeting-BSHal4N9.min.js.map} +1 -1
  8. package/dist/async-modules/{mixpanel-targeting-CmVvUyFM.js → mixpanel-targeting-UHf4eBfC.js} +1 -1
  9. package/dist/mixpanel-core.cjs.d.ts +1 -0
  10. package/dist/mixpanel-core.cjs.js +111 -80
  11. package/dist/mixpanel-recorder.js +1 -1
  12. package/dist/mixpanel-recorder.min.js +1 -1
  13. package/dist/mixpanel-recorder.min.js.map +1 -1
  14. package/dist/mixpanel-targeting.js +1 -1
  15. package/dist/mixpanel-targeting.min.js +1 -1
  16. package/dist/mixpanel-targeting.min.js.map +1 -1
  17. package/dist/mixpanel-with-async-modules.cjs.d.ts +1 -0
  18. package/dist/mixpanel-with-async-modules.cjs.js +113 -82
  19. package/dist/mixpanel-with-async-recorder.cjs.d.ts +1 -0
  20. package/dist/mixpanel-with-async-recorder.cjs.js +113 -82
  21. package/dist/mixpanel-with-recorder.d.ts +1 -0
  22. package/dist/mixpanel-with-recorder.js +111 -80
  23. package/dist/mixpanel-with-recorder.min.d.ts +1 -0
  24. package/dist/mixpanel-with-recorder.min.js +1 -1
  25. package/dist/mixpanel.amd.d.ts +1 -0
  26. package/dist/mixpanel.amd.js +111 -80
  27. package/dist/mixpanel.cjs.d.ts +1 -0
  28. package/dist/mixpanel.cjs.js +111 -80
  29. package/dist/mixpanel.globals.js +113 -82
  30. package/dist/mixpanel.min.js +180 -179
  31. package/dist/mixpanel.module.d.ts +1 -0
  32. package/dist/mixpanel.module.js +111 -80
  33. package/dist/mixpanel.umd.d.ts +1 -0
  34. package/dist/mixpanel.umd.js +111 -80
  35. package/package.json +1 -1
  36. package/src/config.js +1 -1
  37. package/src/flags/CLAUDE.md +24 -0
  38. package/src/flags/index.js +109 -80
  39. package/src/index.d.ts +1 -0
  40. package/src/mixpanel-core.js +3 -1
  41. package/testServer.js +2 -0
@@ -27,7 +27,7 @@
27
27
  }
28
28
 
29
29
  var Config = {
30
- LIB_VERSION: '2.77.0'
30
+ LIB_VERSION: '2.78.0'
31
31
  };
32
32
 
33
33
  // Window global names for async modules
@@ -357,6 +357,7 @@ export interface FlagsUpdateContextOptions {
357
357
 
358
358
  export interface FlagsManager {
359
359
  are_flags_ready(): boolean;
360
+ load_flags(): Promise<void>;
360
361
  get_variant(
361
362
  featureName: string,
362
363
  fallback: FlagsVariant
@@ -2,7 +2,7 @@
2
2
 
3
3
  var Config = {
4
4
  DEBUG: false,
5
- LIB_VERSION: '2.77.0'
5
+ LIB_VERSION: '2.78.0'
6
6
  };
7
7
 
8
8
  // Window global names for async modules
@@ -3971,7 +3971,9 @@ FeatureFlagManager.prototype.init = function() {
3971
3971
  }
3972
3972
 
3973
3973
  this.flags = null;
3974
- this.fetchFlags();
3974
+ this.fetchFlags().catch(function() {
3975
+ logger$4.error('Error fetching flags during init');
3976
+ });
3975
3977
 
3976
3978
  this.trackedFeatures = new Set();
3977
3979
  this.pendingFirstTimeEvents = {};
@@ -4012,8 +4014,12 @@ FeatureFlagManager.prototype.updateContext = function(newContext, options) {
4012
4014
  var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
4013
4015
  ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
4014
4016
 
4015
- this.setMpConfig(FLAGS_CONFIG_KEY, ffConfig);
4016
- return this.fetchFlags();
4017
+ var configUpdate = {};
4018
+ configUpdate[FLAGS_CONFIG_KEY] = ffConfig;
4019
+ this.setMpConfig(configUpdate);
4020
+ return this.fetchFlags().catch(function() {
4021
+ logger$4.error('Error fetching flags during updateContext');
4022
+ });
4017
4023
  };
4018
4024
 
4019
4025
  FeatureFlagManager.prototype.areFlagsReady = function() {
@@ -4050,96 +4056,110 @@ FeatureFlagManager.prototype.fetchFlags = function() {
4050
4056
  }
4051
4057
  }).then(function(response) {
4052
4058
  this.markFetchComplete();
4053
- return response.json().then(function(responseBody) {
4054
- var responseFlags = responseBody['flags'];
4055
- if (!responseFlags) {
4056
- throw new Error('No flags in API response');
4057
- }
4058
- var flags = new Map();
4059
- var pendingFirstTimeEvents = {};
4060
-
4061
- // Process flags from response
4062
- _.each(responseFlags, function(data, key) {
4063
- // Check if this flag has any activated first-time events this session
4064
- var hasActivatedEvent = false;
4065
- var prefix = key + ':';
4066
- _.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
4067
- if (eventKey.startsWith(prefix)) {
4068
- hasActivatedEvent = true;
4069
- }
4070
- });
4059
+ return response.json();
4060
+ }.bind(this)).then(function(responseBody) {
4061
+ var responseFlags = responseBody['flags'];
4062
+ if (!responseFlags) {
4063
+ throw new Error('No flags in API response');
4064
+ }
4065
+ var flags = new Map();
4066
+ var pendingFirstTimeEvents = {};
4067
+
4068
+ // Process flags from response
4069
+ _.each(responseFlags, function(data, key) {
4070
+ // Check if this flag has any activated first-time events this session
4071
+ var hasActivatedEvent = false;
4072
+ var prefix = key + ':';
4073
+ _.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
4074
+ if (eventKey.startsWith(prefix)) {
4075
+ hasActivatedEvent = true;
4076
+ }
4077
+ });
4071
4078
 
4072
- if (hasActivatedEvent) {
4073
- // Preserve the activated variant, don't overwrite with server's current variant
4074
- var currentFlag = this.flags && this.flags.get(key);
4075
- if (currentFlag) {
4076
- flags.set(key, currentFlag);
4077
- }
4078
- } else {
4079
- // Use server's current variant
4080
- flags.set(key, {
4081
- 'key': data['variant_key'],
4082
- 'value': data['variant_value'],
4083
- 'experiment_id': data['experiment_id'],
4084
- 'is_experiment_active': data['is_experiment_active'],
4085
- 'is_qa_tester': data['is_qa_tester']
4086
- });
4079
+ if (hasActivatedEvent) {
4080
+ // Preserve the activated variant, don't overwrite with server's current variant
4081
+ var currentFlag = this.flags && this.flags.get(key);
4082
+ if (currentFlag) {
4083
+ flags.set(key, currentFlag);
4087
4084
  }
4088
- }, this);
4085
+ } else {
4086
+ // Use server's current variant
4087
+ flags.set(key, {
4088
+ 'key': data['variant_key'],
4089
+ 'value': data['variant_value'],
4090
+ 'experiment_id': data['experiment_id'],
4091
+ 'is_experiment_active': data['is_experiment_active'],
4092
+ 'is_qa_tester': data['is_qa_tester']
4093
+ });
4094
+ }
4095
+ }, this);
4089
4096
 
4090
- // Process top-level pending_first_time_events array
4091
- var topLevelDefinitions = responseBody['pending_first_time_events'];
4092
- if (topLevelDefinitions && topLevelDefinitions.length > 0) {
4093
- _.each(topLevelDefinitions, function(def) {
4094
- var flagKey = def['flag_key'];
4095
- var eventKey = getPendingEventKey(flagKey, def['first_time_event_hash']);
4097
+ // Process top-level pending_first_time_events array
4098
+ var topLevelDefinitions = responseBody['pending_first_time_events'];
4099
+ if (topLevelDefinitions && topLevelDefinitions.length > 0) {
4100
+ _.each(topLevelDefinitions, function(def) {
4101
+ var flagKey = def['flag_key'];
4102
+ var eventKey = getPendingEventKey(flagKey, def['first_time_event_hash']);
4096
4103
 
4097
- // Skip if this specific event has already been activated this session
4098
- if (this.activatedFirstTimeEvents[eventKey]) {
4099
- return;
4100
- }
4104
+ // Skip if this specific event has already been activated this session
4105
+ if (this.activatedFirstTimeEvents[eventKey]) {
4106
+ return;
4107
+ }
4101
4108
 
4102
- // Store pending event definition using composite key
4103
- pendingFirstTimeEvents[eventKey] = {
4104
- 'flag_key': flagKey,
4105
- 'flag_id': def['flag_id'],
4106
- 'project_id': def['project_id'],
4107
- 'first_time_event_hash': def['first_time_event_hash'],
4108
- 'event_name': def['event_name'],
4109
- 'property_filters': def['property_filters'],
4110
- 'pending_variant': def['pending_variant']
4111
- };
4112
- }, this);
4113
- }
4109
+ // Store pending event definition using composite key
4110
+ pendingFirstTimeEvents[eventKey] = {
4111
+ 'flag_key': flagKey,
4112
+ 'flag_id': def['flag_id'],
4113
+ 'project_id': def['project_id'],
4114
+ 'first_time_event_hash': def['first_time_event_hash'],
4115
+ 'event_name': def['event_name'],
4116
+ 'property_filters': def['property_filters'],
4117
+ 'pending_variant': def['pending_variant']
4118
+ };
4119
+ }, this);
4120
+ }
4114
4121
 
4115
- // Preserve any activated orphaned flags (flags that were activated but are no longer in response)
4116
- if (this.activatedFirstTimeEvents) {
4117
- _.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
4118
- var flagKey = getFlagKeyFromPendingEventKey(eventKey);
4119
- if (activated && !flags.has(flagKey) && this.flags && this.flags.has(flagKey)) {
4120
- // Keep the activated flag even though it's not in the new response
4121
- flags.set(flagKey, this.flags.get(flagKey));
4122
- }
4123
- }, this);
4124
- }
4122
+ // Preserve any activated orphaned flags (flags that were activated but are no longer in response)
4123
+ if (this.activatedFirstTimeEvents) {
4124
+ _.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
4125
+ var flagKey = getFlagKeyFromPendingEventKey(eventKey);
4126
+ if (activated && !flags.has(flagKey) && this.flags && this.flags.has(flagKey)) {
4127
+ // Keep the activated flag even though it's not in the new response
4128
+ flags.set(flagKey, this.flags.get(flagKey));
4129
+ }
4130
+ }, this);
4131
+ }
4125
4132
 
4126
- this.flags = flags;
4127
- this.pendingFirstTimeEvents = pendingFirstTimeEvents;
4128
- this._traceparent = traceparent;
4133
+ this.flags = flags;
4134
+ this.pendingFirstTimeEvents = pendingFirstTimeEvents;
4135
+ this._traceparent = traceparent;
4129
4136
 
4130
- this._loadTargetingIfNeeded();
4131
- }.bind(this)).catch(function(error) {
4132
- this.markFetchComplete();
4133
- logger$4.error(error);
4134
- }.bind(this));
4137
+ this._loadTargetingIfNeeded();
4135
4138
  }.bind(this)).catch(function(error) {
4136
- this.markFetchComplete();
4139
+ if (this._fetchInProgressStartTime) {
4140
+ this.markFetchComplete();
4141
+ }
4137
4142
  logger$4.error(error);
4143
+ throw error;
4138
4144
  }.bind(this));
4139
4145
 
4140
4146
  return this.fetchPromise;
4141
4147
  };
4142
4148
 
4149
+ FeatureFlagManager.prototype.loadFlags = function() {
4150
+ if (!this.isSystemEnabled()) {
4151
+ return Promise.resolve();
4152
+ }
4153
+ if (!this.trackedFeatures) {
4154
+ logger$4.error('loadFlags called before init');
4155
+ return Promise.resolve();
4156
+ }
4157
+ if (this._fetchInProgressStartTime) {
4158
+ return this.fetchPromise;
4159
+ }
4160
+ return this.fetchFlags();
4161
+ };
4162
+
4143
4163
  FeatureFlagManager.prototype.markFetchComplete = function() {
4144
4164
  if (!this._fetchInProgressStartTime) {
4145
4165
  logger$4.error('Fetch in progress started time not set, cannot mark fetch complete');
@@ -4419,6 +4439,13 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
4419
4439
  this.track('$experiment_started', trackingProperties);
4420
4440
  };
4421
4441
 
4442
+ FeatureFlagManager.prototype.whenReady = function() {
4443
+ if (this.fetchPromise) {
4444
+ return this.fetchPromise;
4445
+ }
4446
+ return Promise.resolve();
4447
+ };
4448
+
4422
4449
  FeatureFlagManager.prototype.minApisSupported = function() {
4423
4450
  return !!this.fetch &&
4424
4451
  typeof Promise !== 'undefined' &&
@@ -4435,7 +4462,9 @@ FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype
4435
4462
  FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
4436
4463
  FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
4437
4464
  FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
4465
+ FeatureFlagManager.prototype['load_flags'] = FeatureFlagManager.prototype.loadFlags;
4438
4466
  FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
4467
+ FeatureFlagManager.prototype['when_ready'] = FeatureFlagManager.prototype.whenReady;
4439
4468
 
4440
4469
  // Deprecated method
4441
4470
  FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
@@ -9142,7 +9171,9 @@ MixpanelLib.prototype.identify = function(
9142
9171
 
9143
9172
  // check feature flags again if distinct id has changed
9144
9173
  if (new_distinct_id !== previous_distinct_id) {
9145
- this.flags.fetchFlags();
9174
+ this.flags.fetchFlags().catch(function() {
9175
+ console.error('[flags] Error fetching flags during identify');
9176
+ });
9146
9177
  }
9147
9178
  };
9148
9179
 
@@ -27,7 +27,7 @@
27
27
  }
28
28
 
29
29
  var Config = {
30
- LIB_VERSION: '2.77.0'
30
+ LIB_VERSION: '2.78.0'
31
31
  };
32
32
  var RECORDER_GLOBAL_NAME = '__mp_recorder';
33
33