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
package/dist/mixpanel.globals.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var Config = {
|
|
5
5
|
DEBUG: false,
|
|
6
|
-
LIB_VERSION: '2.
|
|
6
|
+
LIB_VERSION: '2.78.0'
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
// Window global names for async modules
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
var RECORDER_GLOBAL_NAME = '__mp_recorder';
|
|
12
12
|
|
|
13
13
|
// Constants that are injected at build-time for the names of async modules.
|
|
14
|
-
var RECORDER_FILENAME = 'mixpanel-recorder-
|
|
15
|
-
var TARGETING_FILENAME = 'mixpanel-targeting-
|
|
14
|
+
var RECORDER_FILENAME = 'mixpanel-recorder-zMBXIyeG.js';
|
|
15
|
+
var TARGETING_FILENAME = 'mixpanel-targeting-UHf4eBfC.js';
|
|
16
16
|
|
|
17
17
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
18
18
|
var win;
|
|
@@ -3972,7 +3972,9 @@
|
|
|
3972
3972
|
}
|
|
3973
3973
|
|
|
3974
3974
|
this.flags = null;
|
|
3975
|
-
this.fetchFlags()
|
|
3975
|
+
this.fetchFlags().catch(function() {
|
|
3976
|
+
logger$4.error('Error fetching flags during init');
|
|
3977
|
+
});
|
|
3976
3978
|
|
|
3977
3979
|
this.trackedFeatures = new Set();
|
|
3978
3980
|
this.pendingFirstTimeEvents = {};
|
|
@@ -4013,8 +4015,12 @@
|
|
|
4013
4015
|
var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
|
|
4014
4016
|
ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
|
|
4015
4017
|
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
+
var configUpdate = {};
|
|
4019
|
+
configUpdate[FLAGS_CONFIG_KEY] = ffConfig;
|
|
4020
|
+
this.setMpConfig(configUpdate);
|
|
4021
|
+
return this.fetchFlags().catch(function() {
|
|
4022
|
+
logger$4.error('Error fetching flags during updateContext');
|
|
4023
|
+
});
|
|
4018
4024
|
};
|
|
4019
4025
|
|
|
4020
4026
|
FeatureFlagManager.prototype.areFlagsReady = function() {
|
|
@@ -4051,96 +4057,110 @@
|
|
|
4051
4057
|
}
|
|
4052
4058
|
}).then(function(response) {
|
|
4053
4059
|
this.markFetchComplete();
|
|
4054
|
-
return response.json()
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
}
|
|
4060
|
+
return response.json();
|
|
4061
|
+
}.bind(this)).then(function(responseBody) {
|
|
4062
|
+
var responseFlags = responseBody['flags'];
|
|
4063
|
+
if (!responseFlags) {
|
|
4064
|
+
throw new Error('No flags in API response');
|
|
4065
|
+
}
|
|
4066
|
+
var flags = new Map();
|
|
4067
|
+
var pendingFirstTimeEvents = {};
|
|
4068
|
+
|
|
4069
|
+
// Process flags from response
|
|
4070
|
+
_.each(responseFlags, function(data, key) {
|
|
4071
|
+
// Check if this flag has any activated first-time events this session
|
|
4072
|
+
var hasActivatedEvent = false;
|
|
4073
|
+
var prefix = key + ':';
|
|
4074
|
+
_.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
|
|
4075
|
+
if (eventKey.startsWith(prefix)) {
|
|
4076
|
+
hasActivatedEvent = true;
|
|
4077
|
+
}
|
|
4078
|
+
});
|
|
4072
4079
|
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
}
|
|
4079
|
-
} else {
|
|
4080
|
-
// Use server's current variant
|
|
4081
|
-
flags.set(key, {
|
|
4082
|
-
'key': data['variant_key'],
|
|
4083
|
-
'value': data['variant_value'],
|
|
4084
|
-
'experiment_id': data['experiment_id'],
|
|
4085
|
-
'is_experiment_active': data['is_experiment_active'],
|
|
4086
|
-
'is_qa_tester': data['is_qa_tester']
|
|
4087
|
-
});
|
|
4080
|
+
if (hasActivatedEvent) {
|
|
4081
|
+
// Preserve the activated variant, don't overwrite with server's current variant
|
|
4082
|
+
var currentFlag = this.flags && this.flags.get(key);
|
|
4083
|
+
if (currentFlag) {
|
|
4084
|
+
flags.set(key, currentFlag);
|
|
4088
4085
|
}
|
|
4089
|
-
}
|
|
4086
|
+
} else {
|
|
4087
|
+
// Use server's current variant
|
|
4088
|
+
flags.set(key, {
|
|
4089
|
+
'key': data['variant_key'],
|
|
4090
|
+
'value': data['variant_value'],
|
|
4091
|
+
'experiment_id': data['experiment_id'],
|
|
4092
|
+
'is_experiment_active': data['is_experiment_active'],
|
|
4093
|
+
'is_qa_tester': data['is_qa_tester']
|
|
4094
|
+
});
|
|
4095
|
+
}
|
|
4096
|
+
}, this);
|
|
4090
4097
|
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4098
|
+
// Process top-level pending_first_time_events array
|
|
4099
|
+
var topLevelDefinitions = responseBody['pending_first_time_events'];
|
|
4100
|
+
if (topLevelDefinitions && topLevelDefinitions.length > 0) {
|
|
4101
|
+
_.each(topLevelDefinitions, function(def) {
|
|
4102
|
+
var flagKey = def['flag_key'];
|
|
4103
|
+
var eventKey = getPendingEventKey(flagKey, def['first_time_event_hash']);
|
|
4097
4104
|
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4105
|
+
// Skip if this specific event has already been activated this session
|
|
4106
|
+
if (this.activatedFirstTimeEvents[eventKey]) {
|
|
4107
|
+
return;
|
|
4108
|
+
}
|
|
4102
4109
|
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4110
|
+
// Store pending event definition using composite key
|
|
4111
|
+
pendingFirstTimeEvents[eventKey] = {
|
|
4112
|
+
'flag_key': flagKey,
|
|
4113
|
+
'flag_id': def['flag_id'],
|
|
4114
|
+
'project_id': def['project_id'],
|
|
4115
|
+
'first_time_event_hash': def['first_time_event_hash'],
|
|
4116
|
+
'event_name': def['event_name'],
|
|
4117
|
+
'property_filters': def['property_filters'],
|
|
4118
|
+
'pending_variant': def['pending_variant']
|
|
4119
|
+
};
|
|
4120
|
+
}, this);
|
|
4121
|
+
}
|
|
4115
4122
|
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4123
|
+
// Preserve any activated orphaned flags (flags that were activated but are no longer in response)
|
|
4124
|
+
if (this.activatedFirstTimeEvents) {
|
|
4125
|
+
_.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
|
|
4126
|
+
var flagKey = getFlagKeyFromPendingEventKey(eventKey);
|
|
4127
|
+
if (activated && !flags.has(flagKey) && this.flags && this.flags.has(flagKey)) {
|
|
4128
|
+
// Keep the activated flag even though it's not in the new response
|
|
4129
|
+
flags.set(flagKey, this.flags.get(flagKey));
|
|
4130
|
+
}
|
|
4131
|
+
}, this);
|
|
4132
|
+
}
|
|
4126
4133
|
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4134
|
+
this.flags = flags;
|
|
4135
|
+
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
4136
|
+
this._traceparent = traceparent;
|
|
4130
4137
|
|
|
4131
|
-
|
|
4132
|
-
}.bind(this)).catch(function(error) {
|
|
4133
|
-
this.markFetchComplete();
|
|
4134
|
-
logger$4.error(error);
|
|
4135
|
-
}.bind(this));
|
|
4138
|
+
this._loadTargetingIfNeeded();
|
|
4136
4139
|
}.bind(this)).catch(function(error) {
|
|
4137
|
-
this.
|
|
4140
|
+
if (this._fetchInProgressStartTime) {
|
|
4141
|
+
this.markFetchComplete();
|
|
4142
|
+
}
|
|
4138
4143
|
logger$4.error(error);
|
|
4144
|
+
throw error;
|
|
4139
4145
|
}.bind(this));
|
|
4140
4146
|
|
|
4141
4147
|
return this.fetchPromise;
|
|
4142
4148
|
};
|
|
4143
4149
|
|
|
4150
|
+
FeatureFlagManager.prototype.loadFlags = function() {
|
|
4151
|
+
if (!this.isSystemEnabled()) {
|
|
4152
|
+
return Promise.resolve();
|
|
4153
|
+
}
|
|
4154
|
+
if (!this.trackedFeatures) {
|
|
4155
|
+
logger$4.error('loadFlags called before init');
|
|
4156
|
+
return Promise.resolve();
|
|
4157
|
+
}
|
|
4158
|
+
if (this._fetchInProgressStartTime) {
|
|
4159
|
+
return this.fetchPromise;
|
|
4160
|
+
}
|
|
4161
|
+
return this.fetchFlags();
|
|
4162
|
+
};
|
|
4163
|
+
|
|
4144
4164
|
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
4145
4165
|
if (!this._fetchInProgressStartTime) {
|
|
4146
4166
|
logger$4.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
@@ -4420,6 +4440,13 @@
|
|
|
4420
4440
|
this.track('$experiment_started', trackingProperties);
|
|
4421
4441
|
};
|
|
4422
4442
|
|
|
4443
|
+
FeatureFlagManager.prototype.whenReady = function() {
|
|
4444
|
+
if (this.fetchPromise) {
|
|
4445
|
+
return this.fetchPromise;
|
|
4446
|
+
}
|
|
4447
|
+
return Promise.resolve();
|
|
4448
|
+
};
|
|
4449
|
+
|
|
4423
4450
|
FeatureFlagManager.prototype.minApisSupported = function() {
|
|
4424
4451
|
return !!this.fetch &&
|
|
4425
4452
|
typeof Promise !== 'undefined' &&
|
|
@@ -4436,7 +4463,9 @@
|
|
|
4436
4463
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
4437
4464
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
4438
4465
|
FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
|
|
4466
|
+
FeatureFlagManager.prototype['load_flags'] = FeatureFlagManager.prototype.loadFlags;
|
|
4439
4467
|
FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
|
|
4468
|
+
FeatureFlagManager.prototype['when_ready'] = FeatureFlagManager.prototype.whenReady;
|
|
4440
4469
|
|
|
4441
4470
|
// Deprecated method
|
|
4442
4471
|
FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
|
|
@@ -9143,7 +9172,9 @@
|
|
|
9143
9172
|
|
|
9144
9173
|
// check feature flags again if distinct id has changed
|
|
9145
9174
|
if (new_distinct_id !== previous_distinct_id) {
|
|
9146
|
-
this.flags.fetchFlags()
|
|
9175
|
+
this.flags.fetchFlags().catch(function() {
|
|
9176
|
+
console.error('[flags] Error fetching flags during identify');
|
|
9177
|
+
});
|
|
9147
9178
|
}
|
|
9148
9179
|
};
|
|
9149
9180
|
|