mixpanel-browser 2.65.0 → 2.67.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/.github/dependabot.yml +7 -0
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/dist/mixpanel-core.cjs.js +61 -21
- package/dist/mixpanel-recorder.js +53 -21
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +61 -21
- package/dist/mixpanel-with-recorder.js +113 -41
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.js +113 -41
- package/dist/mixpanel.cjs.js +113 -41
- package/dist/mixpanel.globals.js +61 -21
- package/dist/mixpanel.min.js +140 -139
- package/dist/mixpanel.module.js +113 -41
- package/dist/mixpanel.umd.js +113 -41
- package/package.json +2 -1
- package/src/config.js +1 -1
- package/src/flags/index.js +29 -7
- package/src/index.d.ts +408 -0
- package/src/mixpanel-core.js +29 -11
- package/src/mixpanel-group.js +1 -1
- package/src/mixpanel-people.js +1 -1
- package/src/recorder/recorder.js +15 -7
- package/src/recorder/session-recording.js +37 -13
- package/tunnel.log +0 -0
package/dist/mixpanel.umd.js
CHANGED
|
@@ -13948,7 +13948,7 @@
|
|
|
13948
13948
|
|
|
13949
13949
|
var Config = {
|
|
13950
13950
|
DEBUG: false,
|
|
13951
|
-
LIB_VERSION: '2.
|
|
13951
|
+
LIB_VERSION: '2.67.0'
|
|
13952
13952
|
};
|
|
13953
13953
|
|
|
13954
13954
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -17066,6 +17066,13 @@
|
|
|
17066
17066
|
* @property {string} replayStartUrl
|
|
17067
17067
|
*/
|
|
17068
17068
|
|
|
17069
|
+
/**
|
|
17070
|
+
* @typedef {Object} UserIdInfo
|
|
17071
|
+
* @property {string} distinct_id
|
|
17072
|
+
* @property {string} user_id
|
|
17073
|
+
* @property {string} device_id
|
|
17074
|
+
*/
|
|
17075
|
+
|
|
17069
17076
|
|
|
17070
17077
|
/**
|
|
17071
17078
|
* This class encapsulates a single session recording and its lifecycle.
|
|
@@ -17121,6 +17128,30 @@
|
|
|
17121
17128
|
});
|
|
17122
17129
|
};
|
|
17123
17130
|
|
|
17131
|
+
/**
|
|
17132
|
+
* @returns {UserIdInfo}
|
|
17133
|
+
*/
|
|
17134
|
+
SessionRecording.prototype.getUserIdInfo = function () {
|
|
17135
|
+
if (this.finalFlushUserIdInfo) {
|
|
17136
|
+
return this.finalFlushUserIdInfo;
|
|
17137
|
+
}
|
|
17138
|
+
|
|
17139
|
+
var userIdInfo = {
|
|
17140
|
+
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
17141
|
+
};
|
|
17142
|
+
|
|
17143
|
+
// send ID management props if they exist
|
|
17144
|
+
var deviceId = this._mixpanel.get_property('$device_id');
|
|
17145
|
+
if (deviceId) {
|
|
17146
|
+
userIdInfo['$device_id'] = deviceId;
|
|
17147
|
+
}
|
|
17148
|
+
var userId = this._mixpanel.get_property('$user_id');
|
|
17149
|
+
if (userId) {
|
|
17150
|
+
userIdInfo['$user_id'] = userId;
|
|
17151
|
+
}
|
|
17152
|
+
return userIdInfo;
|
|
17153
|
+
};
|
|
17154
|
+
|
|
17124
17155
|
SessionRecording.prototype.unloadPersistedData = function () {
|
|
17125
17156
|
this.batcher.stop();
|
|
17126
17157
|
return this.batcher.flush()
|
|
@@ -17245,6 +17276,9 @@
|
|
|
17245
17276
|
};
|
|
17246
17277
|
|
|
17247
17278
|
SessionRecording.prototype.stopRecording = function (skipFlush) {
|
|
17279
|
+
// store the user ID info in case this is getting called in mixpanel.reset()
|
|
17280
|
+
this.finalFlushUserIdInfo = this.getUserIdInfo();
|
|
17281
|
+
|
|
17248
17282
|
if (!this.isRrwebStopped()) {
|
|
17249
17283
|
try {
|
|
17250
17284
|
this._stopRecording();
|
|
@@ -17355,8 +17389,8 @@
|
|
|
17355
17389
|
retryAfter: response.headers.get('Retry-After')
|
|
17356
17390
|
});
|
|
17357
17391
|
}.bind(this);
|
|
17358
|
-
|
|
17359
|
-
win['fetch'](
|
|
17392
|
+
var apiHost = (this._mixpanel.get_api_host && this._mixpanel.get_api_host('record')) || this.getConfig('api_host');
|
|
17393
|
+
win['fetch'](apiHost + '/' + this.getConfig('api_routes')['record'] + '?' + new URLSearchParams(reqParams), {
|
|
17360
17394
|
'method': 'POST',
|
|
17361
17395
|
'headers': {
|
|
17362
17396
|
'Authorization': 'Basic ' + btoa(this.getConfig('token') + ':'),
|
|
@@ -17410,7 +17444,6 @@
|
|
|
17410
17444
|
'$current_url': this.batchStartUrl,
|
|
17411
17445
|
'$lib_version': Config.LIB_VERSION,
|
|
17412
17446
|
'batch_start_time': batchStartTime / 1000,
|
|
17413
|
-
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
17414
17447
|
'mp_lib': 'web',
|
|
17415
17448
|
'replay_id': replayId,
|
|
17416
17449
|
'replay_length_ms': replayLengthMs,
|
|
@@ -17419,16 +17452,7 @@
|
|
|
17419
17452
|
'seq': this.seqNo
|
|
17420
17453
|
};
|
|
17421
17454
|
var eventsJson = JSON.stringify(data);
|
|
17422
|
-
|
|
17423
|
-
// send ID management props if they exist
|
|
17424
|
-
var deviceId = this._mixpanel.get_property('$device_id');
|
|
17425
|
-
if (deviceId) {
|
|
17426
|
-
reqParams['$device_id'] = deviceId;
|
|
17427
|
-
}
|
|
17428
|
-
var userId = this._mixpanel.get_property('$user_id');
|
|
17429
|
-
if (userId) {
|
|
17430
|
-
reqParams['$user_id'] = userId;
|
|
17431
|
-
}
|
|
17455
|
+
Object.assign(reqParams, this.getUserIdInfo());
|
|
17432
17456
|
|
|
17433
17457
|
if (CompressionStream) {
|
|
17434
17458
|
var jsonStream = new Blob([eventsJson], {type: 'application/json'}).stream();
|
|
@@ -17573,6 +17597,7 @@
|
|
|
17573
17597
|
this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
|
|
17574
17598
|
|
|
17575
17599
|
this.activeRecording = null;
|
|
17600
|
+
this.stopRecordingInProgress = false;
|
|
17576
17601
|
};
|
|
17577
17602
|
|
|
17578
17603
|
MixpanelRecorder.prototype.startRecording = function(options) {
|
|
@@ -17621,19 +17646,26 @@
|
|
|
17621
17646
|
};
|
|
17622
17647
|
|
|
17623
17648
|
MixpanelRecorder.prototype.stopRecording = function() {
|
|
17624
|
-
|
|
17625
|
-
this.
|
|
17626
|
-
this.
|
|
17627
|
-
|
|
17649
|
+
// Prevents activeSerializedRecording from being reused when stopping the recording.
|
|
17650
|
+
this.stopRecordingInProgress = true;
|
|
17651
|
+
return this._stopCurrentRecording(false, true).then(function() {
|
|
17652
|
+
return this.recordingRegistry.clearActiveRecording();
|
|
17653
|
+
}.bind(this)).then(function() {
|
|
17654
|
+
this.stopRecordingInProgress = false;
|
|
17655
|
+
}.bind(this));
|
|
17628
17656
|
};
|
|
17629
17657
|
|
|
17630
17658
|
MixpanelRecorder.prototype.pauseRecording = function() {
|
|
17631
17659
|
return this._stopCurrentRecording(false);
|
|
17632
17660
|
};
|
|
17633
17661
|
|
|
17634
|
-
MixpanelRecorder.prototype._stopCurrentRecording = function(skipFlush) {
|
|
17662
|
+
MixpanelRecorder.prototype._stopCurrentRecording = function(skipFlush, disableActiveRecording) {
|
|
17635
17663
|
if (this.activeRecording) {
|
|
17636
|
-
|
|
17664
|
+
var stopRecordingPromise = this.activeRecording.stopRecording(skipFlush);
|
|
17665
|
+
if (disableActiveRecording) {
|
|
17666
|
+
this.activeRecording = null;
|
|
17667
|
+
}
|
|
17668
|
+
return stopRecordingPromise;
|
|
17637
17669
|
}
|
|
17638
17670
|
return PromisePolyfill.resolve();
|
|
17639
17671
|
};
|
|
@@ -17646,7 +17678,7 @@
|
|
|
17646
17678
|
|
|
17647
17679
|
return this.recordingRegistry.getActiveRecording()
|
|
17648
17680
|
.then(function (activeSerializedRecording) {
|
|
17649
|
-
if (activeSerializedRecording) {
|
|
17681
|
+
if (activeSerializedRecording && !this.stopRecordingInProgress) {
|
|
17650
17682
|
return this.startRecording({activeSerializedRecording: activeSerializedRecording});
|
|
17651
17683
|
} else if (startNewIfInactive) {
|
|
17652
17684
|
return this.startRecording({shouldStopBatcher: false});
|
|
@@ -18549,8 +18581,9 @@
|
|
|
18549
18581
|
* @constructor
|
|
18550
18582
|
*/
|
|
18551
18583
|
var FeatureFlagManager = function(initOptions) {
|
|
18584
|
+
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
18552
18585
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
18553
|
-
this.
|
|
18586
|
+
this.getMpProperty = initOptions.getPropertyFunc;
|
|
18554
18587
|
this.track = initOptions.trackingFunc;
|
|
18555
18588
|
};
|
|
18556
18589
|
|
|
@@ -18599,12 +18632,14 @@
|
|
|
18599
18632
|
return;
|
|
18600
18633
|
}
|
|
18601
18634
|
|
|
18602
|
-
var distinctId = this.
|
|
18635
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
18636
|
+
var deviceId = this.getMpProperty('$device_id');
|
|
18603
18637
|
logger.log('Fetching flags for distinct ID: ' + distinctId);
|
|
18604
18638
|
var reqParams = {
|
|
18605
|
-
'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
|
|
18639
|
+
'context': _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT))
|
|
18606
18640
|
};
|
|
18607
|
-
this.
|
|
18641
|
+
this._fetchInProgressStartTime = Date.now();
|
|
18642
|
+
this.fetchPromise = win['fetch'](this.getFullApiRoute(), {
|
|
18608
18643
|
'method': 'POST',
|
|
18609
18644
|
'headers': {
|
|
18610
18645
|
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
@@ -18612,6 +18647,7 @@
|
|
|
18612
18647
|
},
|
|
18613
18648
|
'body': JSON.stringify(reqParams)
|
|
18614
18649
|
}).then(function(response) {
|
|
18650
|
+
this.markFetchComplete();
|
|
18615
18651
|
return response.json().then(function(responseBody) {
|
|
18616
18652
|
var responseFlags = responseBody['flags'];
|
|
18617
18653
|
if (!responseFlags) {
|
|
@@ -18626,9 +18662,24 @@
|
|
|
18626
18662
|
});
|
|
18627
18663
|
this.flags = flags;
|
|
18628
18664
|
}.bind(this)).catch(function(error) {
|
|
18665
|
+
this.markFetchComplete();
|
|
18629
18666
|
logger.error(error);
|
|
18630
|
-
});
|
|
18631
|
-
}.bind(this)).catch(function() {
|
|
18667
|
+
}.bind(this));
|
|
18668
|
+
}.bind(this)).catch(function(error) {
|
|
18669
|
+
this.markFetchComplete();
|
|
18670
|
+
logger.error(error);
|
|
18671
|
+
}.bind(this));
|
|
18672
|
+
};
|
|
18673
|
+
|
|
18674
|
+
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
18675
|
+
if (!this._fetchInProgressStartTime) {
|
|
18676
|
+
logger.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
18677
|
+
return;
|
|
18678
|
+
}
|
|
18679
|
+
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
18680
|
+
this._fetchCompleteTime = Date.now();
|
|
18681
|
+
this._fetchLatency = this._fetchCompleteTime - this._fetchStartTime;
|
|
18682
|
+
this._fetchInProgressStartTime = null;
|
|
18632
18683
|
};
|
|
18633
18684
|
|
|
18634
18685
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
@@ -18707,7 +18758,10 @@
|
|
|
18707
18758
|
this.track('$experiment_started', {
|
|
18708
18759
|
'Experiment name': featureName,
|
|
18709
18760
|
'Variant name': feature['key'],
|
|
18710
|
-
'$experiment_type': 'feature_flag'
|
|
18761
|
+
'$experiment_type': 'feature_flag',
|
|
18762
|
+
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
18763
|
+
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
18764
|
+
'Variant fetch latency (ms)': this._fetchLatency
|
|
18711
18765
|
});
|
|
18712
18766
|
};
|
|
18713
18767
|
|
|
@@ -19148,7 +19202,7 @@
|
|
|
19148
19202
|
return this._mixpanel._track_or_batch({
|
|
19149
19203
|
type: 'groups',
|
|
19150
19204
|
data: date_encoded_data,
|
|
19151
|
-
endpoint: this.
|
|
19205
|
+
endpoint: this._mixpanel.get_api_host('groups') + '/' + this._get_config('api_routes')['groups'],
|
|
19152
19206
|
batcher: this._mixpanel.request_batchers.groups
|
|
19153
19207
|
}, callback);
|
|
19154
19208
|
};
|
|
@@ -19500,7 +19554,7 @@
|
|
|
19500
19554
|
return this._mixpanel._track_or_batch({
|
|
19501
19555
|
type: 'people',
|
|
19502
19556
|
data: date_encoded_data,
|
|
19503
|
-
endpoint: this.
|
|
19557
|
+
endpoint: this._mixpanel.get_api_host('people') + '/' + this._get_config('api_routes')['engage'],
|
|
19504
19558
|
batcher: this._mixpanel.request_batchers.people
|
|
19505
19559
|
}, callback);
|
|
19506
19560
|
};
|
|
@@ -20137,6 +20191,7 @@
|
|
|
20137
20191
|
*/
|
|
20138
20192
|
var DEFAULT_CONFIG = {
|
|
20139
20193
|
'api_host': 'https://api-js.mixpanel.com',
|
|
20194
|
+
'api_hosts': {},
|
|
20140
20195
|
'api_routes': DEFAULT_API_ROUTES,
|
|
20141
20196
|
'api_extra_query_params': {},
|
|
20142
20197
|
'api_method': 'POST',
|
|
@@ -20406,8 +20461,11 @@
|
|
|
20406
20461
|
}
|
|
20407
20462
|
|
|
20408
20463
|
this.flags = new FeatureFlagManager({
|
|
20464
|
+
getFullApiRoute: _.bind(function() {
|
|
20465
|
+
return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
|
|
20466
|
+
}, this),
|
|
20409
20467
|
getConfigFunc: _.bind(this.get_config, this),
|
|
20410
|
-
|
|
20468
|
+
getPropertyFunc: _.bind(this.get_property, this),
|
|
20411
20469
|
trackingFunc: _.bind(this.track, this)
|
|
20412
20470
|
});
|
|
20413
20471
|
this.flags.init();
|
|
@@ -20522,20 +20580,23 @@
|
|
|
20522
20580
|
|
|
20523
20581
|
MixpanelLib.prototype.stop_session_recording = function () {
|
|
20524
20582
|
if (this._recorder) {
|
|
20525
|
-
this._recorder['stopRecording']();
|
|
20583
|
+
return this._recorder['stopRecording']();
|
|
20526
20584
|
}
|
|
20585
|
+
return Promise.resolve();
|
|
20527
20586
|
};
|
|
20528
20587
|
|
|
20529
20588
|
MixpanelLib.prototype.pause_session_recording = function () {
|
|
20530
20589
|
if (this._recorder) {
|
|
20531
|
-
this._recorder['pauseRecording']();
|
|
20590
|
+
return this._recorder['pauseRecording']();
|
|
20532
20591
|
}
|
|
20592
|
+
return Promise.resolve();
|
|
20533
20593
|
};
|
|
20534
20594
|
|
|
20535
20595
|
MixpanelLib.prototype.resume_session_recording = function () {
|
|
20536
20596
|
if (this._recorder) {
|
|
20537
|
-
this._recorder['resumeRecording']();
|
|
20597
|
+
return this._recorder['resumeRecording']();
|
|
20538
20598
|
}
|
|
20599
|
+
return Promise.resolve();
|
|
20539
20600
|
};
|
|
20540
20601
|
|
|
20541
20602
|
MixpanelLib.prototype.is_recording_heatmap_data = function () {
|
|
@@ -20890,11 +20951,10 @@
|
|
|
20890
20951
|
|
|
20891
20952
|
MixpanelLib.prototype.get_batcher_configs = function() {
|
|
20892
20953
|
var queue_prefix = '__mpq_' + this.get_config('token');
|
|
20893
|
-
var api_routes = this.get_config('api_routes');
|
|
20894
20954
|
this._batcher_configs = this._batcher_configs || {
|
|
20895
|
-
events: {type: 'events',
|
|
20896
|
-
people: {type: 'people',
|
|
20897
|
-
groups: {type: 'groups',
|
|
20955
|
+
events: {type: 'events', api_name: 'track', queue_key: queue_prefix + '_ev'},
|
|
20956
|
+
people: {type: 'people', api_name: 'engage', queue_key: queue_prefix + '_pp'},
|
|
20957
|
+
groups: {type: 'groups', api_name: 'groups', queue_key: queue_prefix + '_gr'}
|
|
20898
20958
|
};
|
|
20899
20959
|
return this._batcher_configs;
|
|
20900
20960
|
};
|
|
@@ -20908,8 +20968,9 @@
|
|
|
20908
20968
|
libConfig: this['config'],
|
|
20909
20969
|
errorReporter: this.get_config('error_reporter'),
|
|
20910
20970
|
sendRequestFunc: _.bind(function(data, options, cb) {
|
|
20971
|
+
var api_routes = this.get_config('api_routes');
|
|
20911
20972
|
this._send_request(
|
|
20912
|
-
this.
|
|
20973
|
+
this.get_api_host(attrs.api_name) + '/' + api_routes[attrs.api_name],
|
|
20913
20974
|
this._encode_data_for_request(data),
|
|
20914
20975
|
options,
|
|
20915
20976
|
this._prepare_callback(cb, data)
|
|
@@ -21135,7 +21196,7 @@
|
|
|
21135
21196
|
var ret = this._track_or_batch({
|
|
21136
21197
|
type: 'events',
|
|
21137
21198
|
data: data,
|
|
21138
|
-
endpoint: this.
|
|
21199
|
+
endpoint: this.get_api_host('events') + '/' + this.get_config('api_routes')['track'],
|
|
21139
21200
|
batcher: this.request_batchers.events,
|
|
21140
21201
|
should_send_immediately: should_send_immediately,
|
|
21141
21202
|
send_request_options: options
|
|
@@ -21637,6 +21698,7 @@
|
|
|
21637
21698
|
* Useful for clearing data when a user logs out.
|
|
21638
21699
|
*/
|
|
21639
21700
|
MixpanelLib.prototype.reset = function() {
|
|
21701
|
+
this.stop_session_recording();
|
|
21640
21702
|
this['persistence'].clear();
|
|
21641
21703
|
this._flags.identify_called = false;
|
|
21642
21704
|
var uuid = _.UUID();
|
|
@@ -21644,7 +21706,6 @@
|
|
|
21644
21706
|
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
21645
21707
|
'$device_id': uuid
|
|
21646
21708
|
}, '');
|
|
21647
|
-
this.stop_session_recording();
|
|
21648
21709
|
this._check_and_start_session_recording();
|
|
21649
21710
|
};
|
|
21650
21711
|
|
|
@@ -21956,6 +22017,16 @@
|
|
|
21956
22017
|
return this['persistence'].load_prop([property_name]);
|
|
21957
22018
|
};
|
|
21958
22019
|
|
|
22020
|
+
/**
|
|
22021
|
+
* Get the API host for a specific endpoint type, falling back to the default api_host if not specified
|
|
22022
|
+
*
|
|
22023
|
+
* @param {String} endpoint_type The type of endpoint (e.g., "events", "people", "groups")
|
|
22024
|
+
* @returns {String} The API host to use for this endpoint
|
|
22025
|
+
*/
|
|
22026
|
+
MixpanelLib.prototype.get_api_host = function(endpoint_type) {
|
|
22027
|
+
return this.get_config('api_hosts')[endpoint_type] || this.get_config('api_host');
|
|
22028
|
+
};
|
|
22029
|
+
|
|
21959
22030
|
MixpanelLib.prototype.toString = function() {
|
|
21960
22031
|
var name = this.get_config('name');
|
|
21961
22032
|
if (name !== PRIMARY_INSTANCE_NAME) {
|
|
@@ -22251,6 +22322,7 @@
|
|
|
22251
22322
|
MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
|
|
22252
22323
|
MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
|
|
22253
22324
|
MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
|
|
22325
|
+
MixpanelLib.prototype['get_api_host'] = MixpanelLib.prototype.get_api_host;
|
|
22254
22326
|
MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
|
|
22255
22327
|
MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
|
|
22256
22328
|
MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mixpanel-browser",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.67.0",
|
|
4
4
|
"description": "The official Mixpanel JavaScript browser client library",
|
|
5
5
|
"main": "dist/mixpanel.cjs.js",
|
|
6
6
|
"module": "dist/mixpanel.module.js",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"unit-test": "BABEL_ENV=test mocha --require babel-core/register tests/unit/*.js",
|
|
23
23
|
"validate": "npm ls"
|
|
24
24
|
},
|
|
25
|
+
"types": "./src/index.d.ts",
|
|
25
26
|
"repository": {
|
|
26
27
|
"type": "git",
|
|
27
28
|
"url": "https://github.com/mixpanel/mixpanel-js.git"
|
package/src/config.js
CHANGED
package/src/flags/index.js
CHANGED
|
@@ -15,8 +15,9 @@ CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
|
|
|
15
15
|
* @constructor
|
|
16
16
|
*/
|
|
17
17
|
var FeatureFlagManager = function(initOptions) {
|
|
18
|
+
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
18
19
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
19
|
-
this.
|
|
20
|
+
this.getMpProperty = initOptions.getPropertyFunc;
|
|
20
21
|
this.track = initOptions.trackingFunc;
|
|
21
22
|
};
|
|
22
23
|
|
|
@@ -65,12 +66,14 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
65
66
|
return;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
var distinctId = this.
|
|
69
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
70
|
+
var deviceId = this.getMpProperty('$device_id');
|
|
69
71
|
logger.log('Fetching flags for distinct ID: ' + distinctId);
|
|
70
72
|
var reqParams = {
|
|
71
|
-
'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
|
|
73
|
+
'context': _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT))
|
|
72
74
|
};
|
|
73
|
-
this.
|
|
75
|
+
this._fetchInProgressStartTime = Date.now();
|
|
76
|
+
this.fetchPromise = window['fetch'](this.getFullApiRoute(), {
|
|
74
77
|
'method': 'POST',
|
|
75
78
|
'headers': {
|
|
76
79
|
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
@@ -78,6 +81,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
78
81
|
},
|
|
79
82
|
'body': JSON.stringify(reqParams)
|
|
80
83
|
}).then(function(response) {
|
|
84
|
+
this.markFetchComplete();
|
|
81
85
|
return response.json().then(function(responseBody) {
|
|
82
86
|
var responseFlags = responseBody['flags'];
|
|
83
87
|
if (!responseFlags) {
|
|
@@ -92,9 +96,24 @@ FeatureFlagManager.prototype.fetchFlags = function() {
|
|
|
92
96
|
});
|
|
93
97
|
this.flags = flags;
|
|
94
98
|
}.bind(this)).catch(function(error) {
|
|
99
|
+
this.markFetchComplete();
|
|
95
100
|
logger.error(error);
|
|
96
|
-
});
|
|
97
|
-
}.bind(this)).catch(function() {
|
|
101
|
+
}.bind(this));
|
|
102
|
+
}.bind(this)).catch(function(error) {
|
|
103
|
+
this.markFetchComplete();
|
|
104
|
+
logger.error(error);
|
|
105
|
+
}.bind(this));
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
109
|
+
if (!this._fetchInProgressStartTime) {
|
|
110
|
+
logger.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
114
|
+
this._fetchCompleteTime = Date.now();
|
|
115
|
+
this._fetchLatency = this._fetchCompleteTime - this._fetchStartTime;
|
|
116
|
+
this._fetchInProgressStartTime = null;
|
|
98
117
|
};
|
|
99
118
|
|
|
100
119
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
@@ -173,7 +192,10 @@ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature)
|
|
|
173
192
|
this.track('$experiment_started', {
|
|
174
193
|
'Experiment name': featureName,
|
|
175
194
|
'Variant name': feature['key'],
|
|
176
|
-
'$experiment_type': 'feature_flag'
|
|
195
|
+
'$experiment_type': 'feature_flag',
|
|
196
|
+
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
197
|
+
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
198
|
+
'Variant fetch latency (ms)': this._fetchLatency
|
|
177
199
|
});
|
|
178
200
|
};
|
|
179
201
|
|