mixpanel-browser 2.77.0 → 2.79.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 +6 -9
- package/.eslintrc.json +12 -0
- package/.github/workflows/openfeature-provider-tests.yml +31 -0
- package/CHANGELOG.md +11 -0
- package/build.sh +2 -2
- package/dist/async-modules/{mixpanel-recorder-wIWnMDLA.min.js → mixpanel-recorder-D5HJyV2E.min.js} +2 -2
- package/dist/async-modules/mixpanel-recorder-D5HJyV2E.min.js.map +1 -0
- package/dist/async-modules/{mixpanel-recorder-DLKbUIEE.js → mixpanel-recorder-P6SEnnPV.js} +57 -33
- package/dist/async-modules/mixpanel-targeting-1L9FyetZ.min.js +2 -0
- package/dist/async-modules/mixpanel-targeting-1L9FyetZ.min.js.map +1 -0
- package/dist/async-modules/{mixpanel-targeting-CmVvUyFM.js → mixpanel-targeting-BBMVbgJF.js} +24 -13
- package/dist/mixpanel-core.cjs.d.ts +46 -1
- package/dist/mixpanel-core.cjs.js +671 -272
- package/dist/mixpanel-recorder.js +57 -33
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-targeting.js +24 -13
- 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 +46 -1
- package/dist/mixpanel-with-async-modules.cjs.js +673 -274
- package/dist/mixpanel-with-async-recorder.cjs.d.ts +46 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +673 -274
- package/dist/mixpanel-with-recorder.d.ts +46 -1
- package/dist/mixpanel-with-recorder.js +596 -197
- package/dist/mixpanel-with-recorder.min.d.ts +46 -1
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.d.ts +46 -1
- package/dist/mixpanel.amd.js +596 -197
- package/dist/mixpanel.cjs.d.ts +46 -1
- package/dist/mixpanel.cjs.js +596 -197
- package/dist/mixpanel.globals.js +673 -274
- package/dist/mixpanel.min.js +200 -189
- package/dist/mixpanel.module.d.ts +46 -1
- package/dist/mixpanel.module.js +596 -197
- package/dist/mixpanel.umd.d.ts +46 -1
- package/dist/mixpanel.umd.js +596 -197
- package/package.json +1 -1
- package/packages/openfeature-web-provider/README.md +357 -0
- package/packages/openfeature-web-provider/package-lock.json +1636 -0
- package/packages/openfeature-web-provider/package.json +51 -0
- package/packages/openfeature-web-provider/rollup.config.browser.mjs +26 -0
- package/packages/openfeature-web-provider/src/MixpanelProvider.ts +302 -0
- package/packages/openfeature-web-provider/src/index.ts +1 -0
- package/packages/openfeature-web-provider/src/types.ts +72 -0
- package/packages/openfeature-web-provider/test/MixpanelProvider.spec.ts +484 -0
- package/packages/openfeature-web-provider/tsconfig.json +15 -0
- package/src/autocapture/index.js +7 -2
- package/src/config.js +1 -1
- package/src/flags/CLAUDE.md +24 -0
- package/src/flags/flags-persistence.js +176 -0
- package/src/flags/index.js +278 -98
- package/src/index.d.ts +46 -1
- package/src/mixpanel-core.js +27 -8
- package/src/recorder/idb-config.js +16 -0
- package/src/recorder/recording-registry.js +7 -2
- package/src/recorder/session-recording.js +9 -4
- package/src/recorder-manager.js +7 -2
- package/src/request-queue.js +1 -2
- package/src/shared-lock.js +2 -3
- package/src/storage/indexed-db.js +16 -15
- package/src/storage/local-storage.js +5 -3
- package/src/utils.js +25 -12
- package/testServer.js +2 -0
- package/tsconfig.base.json +9 -0
- package/dist/async-modules/mixpanel-recorder-wIWnMDLA.min.js.map +0 -1
- package/dist/async-modules/mixpanel-targeting-CTcftSJC.min.js +0 -2
- package/dist/async-modules/mixpanel-targeting-CTcftSJC.min.js.map +0 -1
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { _, console_with_prefix } from '../utils'; // eslint-disable-line camelcase
|
|
2
|
+
import { IDBStorageWrapper } from '../storage/indexed-db';
|
|
3
|
+
|
|
4
|
+
var logger = console_with_prefix('flags');
|
|
5
|
+
|
|
6
|
+
var MIXPANEL_FLAGS_DB_NAME = 'mixpanelFlagsDb';
|
|
7
|
+
var FLAGS_STORE_NAME = 'mixpanelFlags';
|
|
8
|
+
|
|
9
|
+
// Keeping these two properties closeby, as adding additional stores to a DB in IndexedDB requires a version increment
|
|
10
|
+
var FLAGS_VERSION_DATA = { version: 1, storeNames: [FLAGS_STORE_NAME] };
|
|
11
|
+
|
|
12
|
+
var PERSISTED_VARIANTS_KEY_PREFIX = 'persisted_variants_for_';
|
|
13
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
14
|
+
|
|
15
|
+
var VariantLookupPolicy = Object.freeze({
|
|
16
|
+
NETWORK_ONLY: 'networkOnly',
|
|
17
|
+
NETWORK_FIRST: 'networkFirst',
|
|
18
|
+
PERSISTENCE_UNTIL_NETWORK_SUCCESS: 'persistenceUntilNetworkSuccess'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
var VALID_POLICIES = [
|
|
22
|
+
VariantLookupPolicy.NETWORK_ONLY,
|
|
23
|
+
VariantLookupPolicy.NETWORK_FIRST,
|
|
24
|
+
VariantLookupPolicy.PERSISTENCE_UNTIL_NETWORK_SUCCESS
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Module for handling the storage and retrieval of persisted feature flag variants.
|
|
29
|
+
*/
|
|
30
|
+
var FeatureFlagPersistence = function(persistenceConfig, token, isGloballyDisabled) {
|
|
31
|
+
this.idb = new IDBStorageWrapper(MIXPANEL_FLAGS_DB_NAME, FLAGS_STORE_NAME, FLAGS_VERSION_DATA);
|
|
32
|
+
this.persistenceConfig = persistenceConfig;
|
|
33
|
+
this.persistedVariantsKey = PERSISTED_VARIANTS_KEY_PREFIX + token;
|
|
34
|
+
this.isGloballyDisabled = isGloballyDisabled || function() { return false; };
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
FeatureFlagPersistence.prototype.getPolicy = function() {
|
|
38
|
+
if (this.isGloballyDisabled() || !this._isConfigValid()) {
|
|
39
|
+
return VariantLookupPolicy.NETWORK_ONLY;
|
|
40
|
+
}
|
|
41
|
+
return this.persistenceConfig['variantLookupPolicy'];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
FeatureFlagPersistence.prototype.getTtlMs = function() {
|
|
45
|
+
if (!this._isConfigValid()) {
|
|
46
|
+
return DEFAULT_TTL_MS;
|
|
47
|
+
}
|
|
48
|
+
var configuredTtl = this.persistenceConfig['persistenceTtlMs'];
|
|
49
|
+
return (configuredTtl === undefined || configuredTtl === null) ? DEFAULT_TTL_MS : configuredTtl;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
FeatureFlagPersistence.prototype._isConfigValid = function() {
|
|
53
|
+
var config = this.persistenceConfig;
|
|
54
|
+
if (!config) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (VALID_POLICIES.indexOf(config['variantLookupPolicy']) === -1) {
|
|
59
|
+
logger.error('Invalid variantLookupPolicy:', config['variantLookupPolicy']);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (config['persistenceTtlMs'] !== undefined &&
|
|
64
|
+
config['persistenceTtlMs'] !== null &&
|
|
65
|
+
config['persistenceTtlMs'] <= 0) {
|
|
66
|
+
logger.error('If provided, persistenceTtlMs must be a positive number. Provided value:', config['persistenceTtlMs']);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return true;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
FeatureFlagPersistence.prototype.loadFlagsFromStorage = function(context) {
|
|
74
|
+
var clearAndReturnNull = _.bind(function() {
|
|
75
|
+
return this.clear().then(function() { return null; }).catch(function() { return null; });
|
|
76
|
+
}, this);
|
|
77
|
+
|
|
78
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
79
|
+
return clearAndReturnNull();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var ttlMs = this.getTtlMs();
|
|
83
|
+
|
|
84
|
+
return this.idb.init().then(_.bind(function() {
|
|
85
|
+
return this.idb.getItem(this.persistedVariantsKey);
|
|
86
|
+
}, this)).then(_.bind(function(data) {
|
|
87
|
+
if (!data) {
|
|
88
|
+
logger.log('No persisted variants found in IndexedDB');
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (ttlMs && Date.now() - data['persistedAt'] >= ttlMs) {
|
|
93
|
+
logger.log('Persisted variants are expiring');
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!context || data['distinctId'] !== context['distinct_id']) {
|
|
98
|
+
logger.log('Persisted variants found, but for a different distinct_id so clearing.');
|
|
99
|
+
return clearAndReturnNull();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
var persistedFlags = new Map();
|
|
103
|
+
_.each(data['flagVariants'], function(variantData, key) {
|
|
104
|
+
persistedFlags.set(key, {
|
|
105
|
+
'key': variantData['variant_key'],
|
|
106
|
+
'value': variantData['variant_value'],
|
|
107
|
+
'experiment_id': variantData['experiment_id'],
|
|
108
|
+
'is_experiment_active': variantData['is_experiment_active'],
|
|
109
|
+
'is_qa_tester': variantData['is_qa_tester'],
|
|
110
|
+
'variant_source': 'persistence',
|
|
111
|
+
'persisted_at_in_ms': data['persistedAt'],
|
|
112
|
+
'ttl_in_ms': ttlMs
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
logger.log('Loaded', persistedFlags.size, 'variants from IndexedDB for distinct_id', data['distinctId']);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
flags: persistedFlags,
|
|
120
|
+
pendingFirstTimeEvents: data['pendingFirstTimeEvents'] || {},
|
|
121
|
+
persistedAtMs: data['persistedAt'],
|
|
122
|
+
ttlMs: ttlMs
|
|
123
|
+
};
|
|
124
|
+
}, this)).catch(_.bind(function(error) {
|
|
125
|
+
logger.error('Failed to load persisted variants from IndexedDB, so clearing', error);
|
|
126
|
+
return clearAndReturnNull();
|
|
127
|
+
}, this));
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
FeatureFlagPersistence.prototype.save = function(context, flagsMap, pendingFirstTimeEvents) {
|
|
131
|
+
if (this.getPolicy() === VariantLookupPolicy.NETWORK_ONLY) {
|
|
132
|
+
return Promise.resolve();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
var flagVariants = {};
|
|
136
|
+
flagsMap.forEach(function(variant, key) {
|
|
137
|
+
flagVariants[key] = {
|
|
138
|
+
'variant_key': variant['key'],
|
|
139
|
+
'variant_value': variant['value'],
|
|
140
|
+
'experiment_id': variant['experiment_id'],
|
|
141
|
+
'is_experiment_active': variant['is_experiment_active'],
|
|
142
|
+
'is_qa_tester': variant['is_qa_tester']
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
var data = {
|
|
147
|
+
'persistedAt': Date.now(),
|
|
148
|
+
'distinctId': context && context['distinct_id'],
|
|
149
|
+
'context': context,
|
|
150
|
+
'flagVariants': flagVariants,
|
|
151
|
+
'pendingFirstTimeEvents': pendingFirstTimeEvents || {}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
return this.idb.init().then(_.bind(function() {
|
|
155
|
+
return this.idb.setItem(this.persistedVariantsKey, data);
|
|
156
|
+
}, this)).then(function() {
|
|
157
|
+
logger.log('Saved', flagsMap.size, 'variants to IndexedDB for distinct_id', data['distinctId']);
|
|
158
|
+
}).catch(function(error) {
|
|
159
|
+
logger.error('Failed to persist variants to IndexedDB:', error);
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
FeatureFlagPersistence.prototype.clear = function() {
|
|
164
|
+
if (this.isGloballyDisabled()) {
|
|
165
|
+
return Promise.resolve();
|
|
166
|
+
}
|
|
167
|
+
return this.idb.init().then(_.bind(function() {
|
|
168
|
+
return this.idb.removeItem(this.persistedVariantsKey);
|
|
169
|
+
}, this)).then(function() {
|
|
170
|
+
logger.log('Cleared persisted variants from IndexedDB');
|
|
171
|
+
}).catch(function(error) {
|
|
172
|
+
logger.error('Failed to clear persisted variants from IndexedDB:', error);
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export { FeatureFlagPersistence, VariantLookupPolicy, FLAGS_STORE_NAME, PERSISTED_VARIANTS_KEY_PREFIX };
|