mixpanel-browser 2.74.0 → 2.76.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/.github/workflows/integration-tests.yml +2 -2
- package/.github/workflows/unit-tests.yml +3 -3
- package/CHANGELOG.md +15 -0
- package/README.md +2 -2
- package/build.sh +10 -8
- package/dist/async-modules/mixpanel-recorder-bIS4LMGd.js +23595 -0
- package/dist/async-modules/mixpanel-recorder-hFoTniVR.min.js +2 -0
- package/dist/async-modules/mixpanel-recorder-hFoTniVR.min.js.map +1 -0
- package/dist/async-modules/mixpanel-targeting-BcAPS-Mz.js +2520 -0
- package/dist/async-modules/mixpanel-targeting-VOeN7RWY.min.js +2 -0
- package/dist/async-modules/mixpanel-targeting-VOeN7RWY.min.js.map +1 -0
- package/dist/mixpanel-core.cjs.d.ts +68 -0
- package/dist/mixpanel-core.cjs.js +802 -337
- package/dist/mixpanel-recorder.js +828 -40
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-targeting.js +2520 -0
- package/dist/mixpanel-targeting.min.js +2 -0
- package/dist/mixpanel-targeting.min.js.map +1 -0
- package/dist/mixpanel-with-async-modules.cjs.d.ts +590 -0
- package/dist/mixpanel-with-async-modules.cjs.js +9867 -0
- package/dist/mixpanel-with-async-recorder.cjs.d.ts +68 -0
- package/dist/mixpanel-with-async-recorder.cjs.js +802 -337
- package/dist/mixpanel-with-recorder.d.ts +68 -0
- package/dist/mixpanel-with-recorder.js +1591 -343
- package/dist/mixpanel-with-recorder.min.d.ts +68 -0
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.d.ts +68 -0
- package/dist/mixpanel.amd.js +2124 -345
- package/dist/mixpanel.cjs.d.ts +68 -0
- package/dist/mixpanel.cjs.js +2124 -345
- package/dist/mixpanel.globals.js +802 -337
- package/dist/mixpanel.min.js +185 -175
- package/dist/mixpanel.module.d.ts +68 -0
- package/dist/mixpanel.module.js +2124 -345
- package/dist/mixpanel.umd.d.ts +68 -0
- package/dist/mixpanel.umd.js +2124 -345
- package/dist/rrweb-bundled.js +119 -5
- package/dist/rrweb-compiled.js +116 -5
- package/logo.svg +5 -0
- package/package.json +5 -3
- package/rollup.config.mjs +189 -40
- package/src/autocapture/index.js +10 -27
- package/src/config.js +9 -3
- package/src/flags/index.js +269 -9
- package/src/index.d.ts +68 -0
- package/src/loaders/loader-module.js +1 -0
- package/src/mixpanel-core.js +83 -109
- package/src/recorder/index.js +2 -1
- package/src/recorder/recorder.js +5 -1
- package/src/recorder/rrweb-network-plugin.js +649 -0
- package/src/recorder/session-recording.js +31 -11
- package/src/recorder-manager.js +216 -0
- package/src/request-batcher.js +1 -1
- package/src/targeting/event-matcher.js +42 -0
- package/src/targeting/index.js +11 -0
- package/src/targeting/loader.js +36 -0
- package/src/utils.js +14 -9
- package/testServer.js +55 -0
- /package/src/loaders/{loader-module-with-async-recorder.js → loader-module-with-async-modules.js} +0 -0
package/src/flags/index.js
CHANGED
|
@@ -1,15 +1,36 @@
|
|
|
1
1
|
import { _, console_with_prefix, generateTraceparent, safewrapClass } from '../utils'; // eslint-disable-line camelcase
|
|
2
2
|
import { window } from '../window';
|
|
3
|
-
import Config from '../config';
|
|
3
|
+
import { Config, TARGETING_GLOBAL_NAME } from '../config';
|
|
4
|
+
import {
|
|
5
|
+
getTargetingPromise
|
|
6
|
+
} from '../targeting/loader';
|
|
4
7
|
|
|
5
8
|
var logger = console_with_prefix('flags');
|
|
6
|
-
|
|
7
9
|
var FLAGS_CONFIG_KEY = 'flags';
|
|
8
10
|
|
|
9
11
|
var CONFIG_CONTEXT = 'context';
|
|
10
12
|
var CONFIG_DEFAULTS = {};
|
|
11
13
|
CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
12
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Generate a unique key for a pending first-time event
|
|
17
|
+
* @param {string} flagKey - The flag key
|
|
18
|
+
* @param {string} firstTimeEventHash - The first_time_event_hash from the pending event definition
|
|
19
|
+
* @returns {string} Composite key in format "flagKey:firstTimeEventHash"
|
|
20
|
+
*/
|
|
21
|
+
var getPendingEventKey = function(flagKey, firstTimeEventHash) {
|
|
22
|
+
return flagKey + ':' + firstTimeEventHash;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extract the flag key from a pending event key
|
|
27
|
+
* @param {string} eventKey - The composite event key in format "flagKey:firstTimeEventHash"
|
|
28
|
+
* @returns {string} The flag key portion
|
|
29
|
+
*/
|
|
30
|
+
var getFlagKeyFromPendingEventKey = function(eventKey) {
|
|
31
|
+
return eventKey.split(':')[0];
|
|
32
|
+
};
|
|
33
|
+
|
|
13
34
|
/**
|
|
14
35
|
* FeatureFlagManager: support for Mixpanel's feature flagging product
|
|
15
36
|
* @constructor
|
|
@@ -21,6 +42,8 @@ var FeatureFlagManager = function(initOptions) {
|
|
|
21
42
|
this.setMpConfig = initOptions.setConfigFunc;
|
|
22
43
|
this.getMpProperty = initOptions.getPropertyFunc;
|
|
23
44
|
this.track = initOptions.trackingFunc;
|
|
45
|
+
this.loadExtraBundle = initOptions.loadExtraBundle || function() {};
|
|
46
|
+
this.targetingSrc = initOptions.targetingSrc || '';
|
|
24
47
|
};
|
|
25
48
|
|
|
26
49
|
FeatureFlagManager.prototype.init = function() {
|
|
@@ -33,6 +56,8 @@ FeatureFlagManager.prototype.init = function() {
|
|
|
33
56
|
this.fetchFlags();
|
|
34
57
|
|
|
35
58
|
this.trackedFeatures = new Set();
|
|
59
|
+
this.pendingFirstTimeEvents = {};
|
|
60
|
+
this.activatedFirstTimeEvents = {};
|
|
36
61
|
};
|
|
37
62
|
|
|
38
63
|
FeatureFlagManager.prototype.getFullConfig = function() {
|
|
@@ -113,17 +138,78 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
113
138
|
throw new Error('No flags in API response');
|
|
114
139
|
}
|
|
115
140
|
var flags = new Map();
|
|
141
|
+
var pendingFirstTimeEvents = {};
|
|
142
|
+
|
|
143
|
+
// Process flags from response
|
|
116
144
|
_.each(responseFlags, function(data, key) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
145
|
+
// Check if this flag has any activated first-time events this session
|
|
146
|
+
var hasActivatedEvent = false;
|
|
147
|
+
var prefix = key + ':';
|
|
148
|
+
_.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
|
|
149
|
+
if (eventKey.startsWith(prefix)) {
|
|
150
|
+
hasActivatedEvent = true;
|
|
151
|
+
}
|
|
123
152
|
});
|
|
124
|
-
|
|
153
|
+
|
|
154
|
+
if (hasActivatedEvent) {
|
|
155
|
+
// Preserve the activated variant, don't overwrite with server's current variant
|
|
156
|
+
var currentFlag = this.flags && this.flags.get(key);
|
|
157
|
+
if (currentFlag) {
|
|
158
|
+
flags.set(key, currentFlag);
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
// Use server's current variant
|
|
162
|
+
flags.set(key, {
|
|
163
|
+
'key': data['variant_key'],
|
|
164
|
+
'value': data['variant_value'],
|
|
165
|
+
'experiment_id': data['experiment_id'],
|
|
166
|
+
'is_experiment_active': data['is_experiment_active'],
|
|
167
|
+
'is_qa_tester': data['is_qa_tester']
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}, this);
|
|
171
|
+
|
|
172
|
+
// Process top-level pending_first_time_events array
|
|
173
|
+
var topLevelDefinitions = responseBody['pending_first_time_events'];
|
|
174
|
+
if (topLevelDefinitions && topLevelDefinitions.length > 0) {
|
|
175
|
+
_.each(topLevelDefinitions, function(def) {
|
|
176
|
+
var flagKey = def['flag_key'];
|
|
177
|
+
var eventKey = getPendingEventKey(flagKey, def['first_time_event_hash']);
|
|
178
|
+
|
|
179
|
+
// Skip if this specific event has already been activated this session
|
|
180
|
+
if (this.activatedFirstTimeEvents[eventKey]) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Store pending event definition using composite key
|
|
185
|
+
pendingFirstTimeEvents[eventKey] = {
|
|
186
|
+
'flag_key': flagKey,
|
|
187
|
+
'flag_id': def['flag_id'],
|
|
188
|
+
'project_id': def['project_id'],
|
|
189
|
+
'first_time_event_hash': def['first_time_event_hash'],
|
|
190
|
+
'event_name': def['event_name'],
|
|
191
|
+
'property_filters': def['property_filters'],
|
|
192
|
+
'pending_variant': def['pending_variant']
|
|
193
|
+
};
|
|
194
|
+
}, this);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Preserve any activated orphaned flags (flags that were activated but are no longer in response)
|
|
198
|
+
if (this.activatedFirstTimeEvents) {
|
|
199
|
+
_.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
|
|
200
|
+
var flagKey = getFlagKeyFromPendingEventKey(eventKey);
|
|
201
|
+
if (activated && !flags.has(flagKey) && this.flags && this.flags.has(flagKey)) {
|
|
202
|
+
// Keep the activated flag even though it's not in the new response
|
|
203
|
+
flags.set(flagKey, this.flags.get(flagKey));
|
|
204
|
+
}
|
|
205
|
+
}, this);
|
|
206
|
+
}
|
|
207
|
+
|
|
125
208
|
this.flags = flags;
|
|
209
|
+
this.pendingFirstTimeEvents = pendingFirstTimeEvents;
|
|
126
210
|
this._traceparent = traceparent;
|
|
211
|
+
|
|
212
|
+
this._loadTargetingIfNeeded();
|
|
127
213
|
}.bind(this)).catch(function(error) {
|
|
128
214
|
this.markFetchComplete();
|
|
129
215
|
logger.error(error);
|
|
@@ -147,6 +233,177 @@ FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
|
147
233
|
this._fetchInProgressStartTime = null;
|
|
148
234
|
};
|
|
149
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Proactively load targeting bundle if any pending events have property filters
|
|
238
|
+
*/
|
|
239
|
+
FeatureFlagManager.prototype._loadTargetingIfNeeded = function() {
|
|
240
|
+
var hasPropertyFilters = false;
|
|
241
|
+
_.each(this.pendingFirstTimeEvents, function(evt) {
|
|
242
|
+
if (evt['property_filters'] && !_.isEmptyObject(evt['property_filters'])) {
|
|
243
|
+
hasPropertyFilters = true;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (hasPropertyFilters) {
|
|
248
|
+
this.getTargeting().then(function() {
|
|
249
|
+
logger.log('targeting loaded for property filter evaluation');
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Get the targeting library (initializes if not already loaded)
|
|
256
|
+
* This method is primarily for testing - production code should rely on automatic loading
|
|
257
|
+
* @returns {Promise} Promise that resolves with targeting library
|
|
258
|
+
*/
|
|
259
|
+
FeatureFlagManager.prototype.getTargeting = function() {
|
|
260
|
+
return getTargetingPromise(
|
|
261
|
+
this.loadExtraBundle.bind(this),
|
|
262
|
+
this.targetingSrc
|
|
263
|
+
).catch(function(error) {
|
|
264
|
+
logger.error('Failed to load targeting: ' + error);
|
|
265
|
+
}.bind(this));
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Check if a tracked event matches any pending first-time events and activate the corresponding flag variant
|
|
270
|
+
* @param {string} eventName - The name of the event being tracked
|
|
271
|
+
* @param {Object} properties - Event properties to evaluate against property filters
|
|
272
|
+
*
|
|
273
|
+
* When a match is found (event name matches and property filters pass), this method:
|
|
274
|
+
* - Switches the flag to the pending variant
|
|
275
|
+
* - Marks the event as activated for this session
|
|
276
|
+
* - Records the activation via the API (fire-and-forget)
|
|
277
|
+
*/
|
|
278
|
+
FeatureFlagManager.prototype.checkFirstTimeEvents = function(eventName, properties) {
|
|
279
|
+
if (!this.pendingFirstTimeEvents || _.isEmptyObject(this.pendingFirstTimeEvents)) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Check if targeting promise exists (either bundled or async loaded)
|
|
284
|
+
if (window[TARGETING_GLOBAL_NAME] && _.isFunction(window[TARGETING_GLOBAL_NAME].then)) {
|
|
285
|
+
window[TARGETING_GLOBAL_NAME].then(function(library) {
|
|
286
|
+
this._processFirstTimeEventCheck(eventName, properties, library);
|
|
287
|
+
}.bind(this)).catch(function() {
|
|
288
|
+
// If targeting failed to load, process with null
|
|
289
|
+
// Events without property filters will still match
|
|
290
|
+
this._processFirstTimeEventCheck(eventName, properties, null);
|
|
291
|
+
}.bind(this));
|
|
292
|
+
} else {
|
|
293
|
+
// No targeting available, process with null
|
|
294
|
+
// Events without property filters will still match
|
|
295
|
+
this._processFirstTimeEventCheck(eventName, properties, null);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Internal method to process first-time event checks with loaded targeting library
|
|
301
|
+
* @param {string} eventName - The name of the event being tracked
|
|
302
|
+
* @param {Object} properties - Event properties to evaluate against property filters
|
|
303
|
+
* @param {Object} targeting - The loaded targeting library
|
|
304
|
+
*/
|
|
305
|
+
FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, properties, targeting) {
|
|
306
|
+
_.each(this.pendingFirstTimeEvents, function(pendingEvent, eventKey) {
|
|
307
|
+
if (this.activatedFirstTimeEvents[eventKey]) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
var flagKey = pendingEvent['flag_key'];
|
|
312
|
+
|
|
313
|
+
// Use targeting module to check if event matches
|
|
314
|
+
var matchResult;
|
|
315
|
+
|
|
316
|
+
// If no targeting library and event has property filters, skip it
|
|
317
|
+
if (!targeting && pendingEvent['property_filters'] && !_.isEmptyObject(pendingEvent['property_filters'])) {
|
|
318
|
+
logger.warn('Skipping event check for "' + flagKey + '" - property filters require targeting library');
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// For simple events (no property filters), just check event name
|
|
323
|
+
if (!targeting) {
|
|
324
|
+
matchResult = {
|
|
325
|
+
matches: eventName === pendingEvent['event_name'],
|
|
326
|
+
error: null
|
|
327
|
+
};
|
|
328
|
+
} else {
|
|
329
|
+
var criteria = {
|
|
330
|
+
'event_name': pendingEvent['event_name'],
|
|
331
|
+
'property_filters': pendingEvent['property_filters']
|
|
332
|
+
};
|
|
333
|
+
matchResult = targeting['eventMatchesCriteria'](
|
|
334
|
+
eventName,
|
|
335
|
+
properties,
|
|
336
|
+
criteria
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (matchResult.error) {
|
|
341
|
+
logger.error('Error checking first-time event for flag "' + flagKey + '": ' + matchResult.error);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (!matchResult.matches) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
logger.log('First-time event matched for flag "' + flagKey + '": ' + eventName);
|
|
350
|
+
|
|
351
|
+
var newVariant = {
|
|
352
|
+
'key': pendingEvent['pending_variant']['variant_key'],
|
|
353
|
+
'value': pendingEvent['pending_variant']['variant_value'],
|
|
354
|
+
'experiment_id': pendingEvent['pending_variant']['experiment_id'],
|
|
355
|
+
'is_experiment_active': pendingEvent['pending_variant']['is_experiment_active']
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
this.flags.set(flagKey, newVariant);
|
|
359
|
+
this.activatedFirstTimeEvents[eventKey] = true;
|
|
360
|
+
|
|
361
|
+
this.recordFirstTimeEvent(
|
|
362
|
+
pendingEvent['flag_id'],
|
|
363
|
+
pendingEvent['project_id'],
|
|
364
|
+
pendingEvent['first_time_event_hash']
|
|
365
|
+
);
|
|
366
|
+
}, this);
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
FeatureFlagManager.prototype.getFirstTimeEventApiRoute = function(flagId) {
|
|
370
|
+
// Construct URL: {api_host}/flags/{flagId}/first-time-events
|
|
371
|
+
return this.getFullApiRoute() + '/' + flagId + '/first-time-events';
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId, firstTimeEventHash) {
|
|
375
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
376
|
+
var traceparent = generateTraceparent();
|
|
377
|
+
|
|
378
|
+
// Build URL with query string parameters
|
|
379
|
+
var searchParams = new URLSearchParams();
|
|
380
|
+
searchParams.set('mp_lib', 'web');
|
|
381
|
+
searchParams.set('$lib_version', Config.LIB_VERSION);
|
|
382
|
+
var url = this.getFirstTimeEventApiRoute(flagId) + '?' + searchParams.toString();
|
|
383
|
+
|
|
384
|
+
var payload = {
|
|
385
|
+
'distinct_id': distinctId,
|
|
386
|
+
'project_id': projectId,
|
|
387
|
+
'first_time_event_hash': firstTimeEventHash
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
logger.log('Recording first-time event for flag: ' + flagId);
|
|
391
|
+
|
|
392
|
+
// Fire-and-forget POST request
|
|
393
|
+
this.fetch.call(window, url, {
|
|
394
|
+
'method': 'POST',
|
|
395
|
+
'headers': {
|
|
396
|
+
'Content-Type': 'application/json',
|
|
397
|
+
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
398
|
+
'traceparent': traceparent
|
|
399
|
+
},
|
|
400
|
+
'body': JSON.stringify(payload)
|
|
401
|
+
}).catch(function(error) {
|
|
402
|
+
// Silent failure - cohort sync will catch up
|
|
403
|
+
logger.error('Failed to record first-time event for flag ' + flagId + ': ' + error);
|
|
404
|
+
});
|
|
405
|
+
};
|
|
406
|
+
|
|
150
407
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
151
408
|
if (!this.fetchPromise) {
|
|
152
409
|
return new Promise(function(resolve) {
|
|
@@ -265,4 +522,7 @@ FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.up
|
|
|
265
522
|
// Deprecated method
|
|
266
523
|
FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
|
|
267
524
|
|
|
525
|
+
// Exports intended only for testing
|
|
526
|
+
FeatureFlagManager.prototype['getTargeting'] = FeatureFlagManager.prototype.getTargeting;
|
|
527
|
+
|
|
268
528
|
export { FeatureFlagManager };
|
package/src/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { RulesLogic } from 'json-logic-js';
|
|
2
|
+
|
|
1
3
|
export type Persistence = "cookie" | "localStorage";
|
|
2
4
|
|
|
3
5
|
export type ApiPayloadFormat = "base64" | "json";
|
|
@@ -8,6 +10,16 @@ export type Query = string | Element | Element[];
|
|
|
8
10
|
|
|
9
11
|
export type RemoteSettingType = "disabled" | "fallback" | "strict";
|
|
10
12
|
|
|
13
|
+
|
|
14
|
+
export interface EventTriggerProps {
|
|
15
|
+
percentage: number;
|
|
16
|
+
property_filters?: RulesLogic;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RecordingEventTriggers {
|
|
20
|
+
[eventName: string]: EventTriggerProps;
|
|
21
|
+
}
|
|
22
|
+
|
|
11
23
|
export interface Dict {
|
|
12
24
|
[key: string]: any;
|
|
13
25
|
}
|
|
@@ -225,6 +237,9 @@ export interface Config {
|
|
|
225
237
|
recorder_src: string;
|
|
226
238
|
record_block_class: string | RegExp;
|
|
227
239
|
record_block_selector: string;
|
|
240
|
+
record_console: boolean;
|
|
241
|
+
record_network: boolean;
|
|
242
|
+
record_network_options: NetworkRecordOptions;
|
|
228
243
|
record_collect_fonts: boolean;
|
|
229
244
|
record_idle_timeout_ms: number;
|
|
230
245
|
record_inline_images: boolean;
|
|
@@ -239,6 +254,7 @@ export interface Config {
|
|
|
239
254
|
record_max_ms: number;
|
|
240
255
|
record_sessions_percent: number;
|
|
241
256
|
record_canvas: boolean;
|
|
257
|
+
recording_event_triggers: RecordingEventTriggers;
|
|
242
258
|
record_heatmap_data: boolean;
|
|
243
259
|
remote_settings_mode: RemoteSettingType;
|
|
244
260
|
hooks: {
|
|
@@ -518,5 +534,57 @@ export function get_session_recording_properties():
|
|
|
518
534
|
| { $mp_replay_id?: string }
|
|
519
535
|
| {};
|
|
520
536
|
|
|
537
|
+
// Network Recording Plugin Types
|
|
538
|
+
export type InitiatorType =
|
|
539
|
+
| 'audio'
|
|
540
|
+
| 'beacon'
|
|
541
|
+
| 'body'
|
|
542
|
+
| 'css'
|
|
543
|
+
| 'early-hint'
|
|
544
|
+
| 'embed'
|
|
545
|
+
| 'fetch'
|
|
546
|
+
| 'frame'
|
|
547
|
+
| 'iframe'
|
|
548
|
+
| 'icon'
|
|
549
|
+
| 'image'
|
|
550
|
+
| 'img'
|
|
551
|
+
| 'input'
|
|
552
|
+
| 'link'
|
|
553
|
+
| 'navigation'
|
|
554
|
+
| 'object'
|
|
555
|
+
| 'ping'
|
|
556
|
+
| 'script'
|
|
557
|
+
| 'track'
|
|
558
|
+
| 'video'
|
|
559
|
+
| 'xmlhttprequest';
|
|
560
|
+
|
|
561
|
+
export interface NetworkRequest {
|
|
562
|
+
url: string;
|
|
563
|
+
method?: string;
|
|
564
|
+
initiatorType: InitiatorType;
|
|
565
|
+
status?: number;
|
|
566
|
+
startTime: number;
|
|
567
|
+
endTime: number;
|
|
568
|
+
timeOrigin: number;
|
|
569
|
+
requestHeaders?: Record<string, string>;
|
|
570
|
+
requestBody?: string;
|
|
571
|
+
responseHeaders?: Record<string, string>;
|
|
572
|
+
responseBody?: string;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export interface NetworkRecordOptions {
|
|
576
|
+
initiatorTypes?: InitiatorType[];
|
|
577
|
+
ignoreRequestUrls?: string[];
|
|
578
|
+
ignoreRequestFn?: (data: NetworkRequest) => boolean;
|
|
579
|
+
recordHeaders?: { request: string[]; response: string[] };
|
|
580
|
+
recordBodyUrls?: { request: string[]; response: string[] };
|
|
581
|
+
recordInitialRequests?: boolean;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export interface NetworkData {
|
|
585
|
+
requests: NetworkRequest[];
|
|
586
|
+
isInitial?: boolean;
|
|
587
|
+
}
|
|
588
|
+
|
|
521
589
|
declare const mixpanel: OverridedMixpanel;
|
|
522
590
|
export default mixpanel;
|