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.
- package/.claude/settings.local.json +3 -1
- package/CHANGELOG.md +4 -0
- package/dist/async-modules/{mixpanel-recorder-wIWnMDLA.min.js → mixpanel-recorder-BjSlYaNJ.min.js} +2 -2
- package/dist/async-modules/{mixpanel-recorder-wIWnMDLA.min.js.map → mixpanel-recorder-BjSlYaNJ.min.js.map} +1 -1
- package/dist/async-modules/{mixpanel-recorder-DLKbUIEE.js → mixpanel-recorder-zMBXIyeG.js} +1 -1
- package/dist/async-modules/{mixpanel-targeting-CTcftSJC.min.js → mixpanel-targeting-BSHal4N9.min.js} +2 -2
- package/dist/async-modules/{mixpanel-targeting-CTcftSJC.min.js.map → mixpanel-targeting-BSHal4N9.min.js.map} +1 -1
- package/dist/async-modules/{mixpanel-targeting-CmVvUyFM.js → mixpanel-targeting-UHf4eBfC.js} +1 -1
- package/dist/mixpanel-core.cjs.d.ts +1 -0
- package/dist/mixpanel-core.cjs.js +111 -80
- package/dist/mixpanel-recorder.js +1 -1
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-targeting.js +1 -1
- package/dist/mixpanel-targeting.min.js +1 -1
- package/dist/mixpanel-targeting.min.js.map +1 -1
- package/dist/mixpanel-with-async-modules.cjs.d.ts +1 -0
- package/dist/mixpanel-with-async-modules.cjs.js +113 -82
- package/dist/mixpanel-with-async-recorder.cjs.d.ts +1 -0
- package/dist/mixpanel-with-async-recorder.cjs.js +113 -82
- package/dist/mixpanel-with-recorder.d.ts +1 -0
- package/dist/mixpanel-with-recorder.js +111 -80
- package/dist/mixpanel-with-recorder.min.d.ts +1 -0
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.d.ts +1 -0
- package/dist/mixpanel.amd.js +111 -80
- package/dist/mixpanel.cjs.d.ts +1 -0
- package/dist/mixpanel.cjs.js +111 -80
- package/dist/mixpanel.globals.js +113 -82
- package/dist/mixpanel.min.js +180 -179
- package/dist/mixpanel.module.d.ts +1 -0
- package/dist/mixpanel.module.js +111 -80
- package/dist/mixpanel.umd.d.ts +1 -0
- package/dist/mixpanel.umd.js +111 -80
- package/package.json +1 -1
- package/src/config.js +1 -1
- package/src/flags/CLAUDE.md +24 -0
- package/src/flags/index.js +109 -80
- package/src/index.d.ts +1 -0
- package/src/mixpanel-core.js +3 -1
- package/testServer.js +2 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
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
|
-
|
|
4016
|
-
|
|
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()
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
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
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
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
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4104
|
+
// Skip if this specific event has already been activated this session
|
|
4105
|
+
if (this.activatedFirstTimeEvents[eventKey]) {
|
|
4106
|
+
return;
|
|
4107
|
+
}
|
|
4101
4108
|
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
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
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
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
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4133
|
+
this.flags = flags;
|
|
4134
|
+
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
4135
|
+
this._traceparent = traceparent;
|
|
4129
4136
|
|
|
4130
|
-
|
|
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.
|
|
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
|
|