mixpanel-browser 2.54.1 → 2.55.1
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/CHANGELOG.md +9 -0
- package/README.md +20 -29
- package/build.sh +1 -0
- package/dist/mixpanel-core.cjs.js +21 -6
- package/dist/mixpanel-recorder.js +55 -19
- package/dist/mixpanel-recorder.min.js +9 -9
- package/dist/mixpanel-with-async-recorder.cjs.js +21 -6
- package/dist/mixpanel.amd.js +56 -19
- package/dist/mixpanel.cjs.js +56 -19
- package/dist/mixpanel.globals.js +21 -6
- package/dist/mixpanel.min.js +98 -97
- package/dist/mixpanel.module.js +11168 -0
- package/dist/mixpanel.umd.js +56 -19
- package/package.json +2 -1
- package/src/config.js +1 -1
- package/src/mixpanel-core.js +1 -0
- package/src/recorder/index.js +34 -14
- package/src/request-batcher.js +7 -2
- package/src/utils.js +26 -13
package/dist/mixpanel.umd.js
CHANGED
|
@@ -4513,7 +4513,7 @@
|
|
|
4513
4513
|
|
|
4514
4514
|
var Config = {
|
|
4515
4515
|
DEBUG: false,
|
|
4516
|
-
LIB_VERSION: '2.
|
|
4516
|
+
LIB_VERSION: '2.55.1'
|
|
4517
4517
|
};
|
|
4518
4518
|
|
|
4519
4519
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -4525,7 +4525,7 @@
|
|
|
4525
4525
|
hostname: ''
|
|
4526
4526
|
};
|
|
4527
4527
|
win = {
|
|
4528
|
-
navigator: { userAgent: '' },
|
|
4528
|
+
navigator: { userAgent: '', onLine: true },
|
|
4529
4529
|
document: {
|
|
4530
4530
|
location: loc,
|
|
4531
4531
|
referrer: ''
|
|
@@ -4539,6 +4539,8 @@
|
|
|
4539
4539
|
|
|
4540
4540
|
// Maximum allowed session recording length
|
|
4541
4541
|
var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
4542
|
+
// Maximum allowed value for minimum session recording length
|
|
4543
|
+
var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds
|
|
4542
4544
|
|
|
4543
4545
|
/*
|
|
4544
4546
|
* Saved references to long variable names, so that closure compiler can
|
|
@@ -5479,7 +5481,7 @@
|
|
|
5479
5481
|
_.getQueryParam = function(url, param) {
|
|
5480
5482
|
// Expects a raw URL
|
|
5481
5483
|
|
|
5482
|
-
param = param.replace(/[[]
|
|
5484
|
+
param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]');
|
|
5483
5485
|
var regexS = '[\\?&]' + param + '=([^&#]*)',
|
|
5484
5486
|
regex = new RegExp(regexS),
|
|
5485
5487
|
results = regex.exec(url);
|
|
@@ -5936,8 +5938,8 @@
|
|
|
5936
5938
|
};
|
|
5937
5939
|
})();
|
|
5938
5940
|
|
|
5939
|
-
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
|
|
5940
|
-
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
|
|
5941
|
+
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic'];
|
|
5942
|
+
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid'];
|
|
5941
5943
|
|
|
5942
5944
|
_.info = {
|
|
5943
5945
|
campaignParams: function(default_value) {
|
|
@@ -6219,6 +6221,15 @@
|
|
|
6219
6221
|
return matches ? matches[0] : '';
|
|
6220
6222
|
};
|
|
6221
6223
|
|
|
6224
|
+
/**
|
|
6225
|
+
* Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE)
|
|
6226
|
+
* @returns {boolean}
|
|
6227
|
+
*/
|
|
6228
|
+
var isOnline = function() {
|
|
6229
|
+
var onLine = win.navigator['onLine'];
|
|
6230
|
+
return _.isUndefined(onLine) || onLine;
|
|
6231
|
+
};
|
|
6232
|
+
|
|
6222
6233
|
var JSONStringify = null, JSONParse = null;
|
|
6223
6234
|
if (typeof JSON !== 'undefined') {
|
|
6224
6235
|
JSONStringify = JSON.stringify;
|
|
@@ -7182,7 +7193,12 @@
|
|
|
7182
7193
|
this.flush();
|
|
7183
7194
|
} else if (
|
|
7184
7195
|
_.isObject(res) &&
|
|
7185
|
-
(
|
|
7196
|
+
(
|
|
7197
|
+
res.httpStatusCode >= 500
|
|
7198
|
+
|| res.httpStatusCode === 429
|
|
7199
|
+
|| (res.httpStatusCode <= 0 && !isOnline())
|
|
7200
|
+
|| res.error === 'timeout'
|
|
7201
|
+
)
|
|
7186
7202
|
) {
|
|
7187
7203
|
// network or API error, or 429 Too Many Requests, retry
|
|
7188
7204
|
var retryMS = this.flushInterval * 2;
|
|
@@ -7333,6 +7349,7 @@
|
|
|
7333
7349
|
this.maxTimeoutId = null;
|
|
7334
7350
|
|
|
7335
7351
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
7352
|
+
this.recordMinMs = 0;
|
|
7336
7353
|
this._initBatcher();
|
|
7337
7354
|
};
|
|
7338
7355
|
|
|
@@ -7364,16 +7381,24 @@
|
|
|
7364
7381
|
logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
7365
7382
|
}
|
|
7366
7383
|
|
|
7384
|
+
this.recordMinMs = this.get_config('record_min_ms');
|
|
7385
|
+
if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
7386
|
+
this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
7387
|
+
logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
7388
|
+
}
|
|
7389
|
+
|
|
7367
7390
|
this.recEvents = [];
|
|
7368
7391
|
this.seqNo = 0;
|
|
7369
|
-
this.replayStartTime =
|
|
7392
|
+
this.replayStartTime = new Date().getTime();
|
|
7370
7393
|
|
|
7371
7394
|
this.replayId = _.UUID();
|
|
7372
7395
|
|
|
7373
|
-
if (shouldStopBatcher) {
|
|
7374
|
-
//
|
|
7396
|
+
if (shouldStopBatcher || this.recordMinMs > 0) {
|
|
7397
|
+
// the primary case for shouldStopBatcher is when we're starting recording after a reset
|
|
7375
7398
|
// and don't want to send anything over the network until there's
|
|
7376
7399
|
// actual user activity
|
|
7400
|
+
// this also applies if the minimum recording length has not been hit yet
|
|
7401
|
+
// so that we don't send data until we know the recording will be long enough
|
|
7377
7402
|
this.batcher.stop();
|
|
7378
7403
|
} else {
|
|
7379
7404
|
this.batcher.start();
|
|
@@ -7387,11 +7412,16 @@
|
|
|
7387
7412
|
}, this), this.get_config('record_idle_timeout_ms'));
|
|
7388
7413
|
}, this);
|
|
7389
7414
|
|
|
7415
|
+
var blockSelector = this.get_config('record_block_selector');
|
|
7416
|
+
if (blockSelector === '' || blockSelector === null) {
|
|
7417
|
+
blockSelector = undefined;
|
|
7418
|
+
}
|
|
7419
|
+
|
|
7390
7420
|
this._stopRecording = record({
|
|
7391
7421
|
'emit': _.bind(function (ev) {
|
|
7392
7422
|
this.batcher.enqueue(ev);
|
|
7393
7423
|
if (isUserEvent(ev)) {
|
|
7394
|
-
if (this.batcher.stopped) {
|
|
7424
|
+
if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
|
|
7395
7425
|
// start flushing again after user activity
|
|
7396
7426
|
this.batcher.start();
|
|
7397
7427
|
}
|
|
@@ -7399,7 +7429,7 @@
|
|
|
7399
7429
|
}
|
|
7400
7430
|
}, this),
|
|
7401
7431
|
'blockClass': this.get_config('record_block_class'),
|
|
7402
|
-
'blockSelector':
|
|
7432
|
+
'blockSelector': blockSelector,
|
|
7403
7433
|
'collectFonts': this.get_config('record_collect_fonts'),
|
|
7404
7434
|
'inlineImages': this.get_config('record_inline_images'),
|
|
7405
7435
|
'maskAllInputs': true,
|
|
@@ -7453,14 +7483,14 @@
|
|
|
7453
7483
|
}
|
|
7454
7484
|
};
|
|
7455
7485
|
|
|
7456
|
-
MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) {
|
|
7486
|
+
MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
|
|
7457
7487
|
var onSuccess = _.bind(function (response, responseBody) {
|
|
7458
7488
|
// Increment sequence counter only if the request was successful to guarantee ordering.
|
|
7459
7489
|
// RequestBatcher will always flush the next batch after the previous one succeeds.
|
|
7460
|
-
if
|
|
7490
|
+
// extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay
|
|
7491
|
+
if (response.status === 200 && this.replayId === currentReplayId) {
|
|
7461
7492
|
this.seqNo++;
|
|
7462
7493
|
}
|
|
7463
|
-
|
|
7464
7494
|
callback({
|
|
7465
7495
|
status: 0,
|
|
7466
7496
|
httpStatusCode: response.status,
|
|
@@ -7483,7 +7513,7 @@
|
|
|
7483
7513
|
callback({error: error});
|
|
7484
7514
|
});
|
|
7485
7515
|
}).catch(function (error) {
|
|
7486
|
-
callback({error: error});
|
|
7516
|
+
callback({error: error, httpStatusCode: 0});
|
|
7487
7517
|
});
|
|
7488
7518
|
};
|
|
7489
7519
|
|
|
@@ -7491,9 +7521,15 @@
|
|
|
7491
7521
|
const numEvents = data.length;
|
|
7492
7522
|
|
|
7493
7523
|
if (numEvents > 0) {
|
|
7524
|
+
var replayId = this.replayId;
|
|
7494
7525
|
// each rrweb event has a timestamp - leverage those to get time properties
|
|
7495
7526
|
var batchStartTime = data[0].timestamp;
|
|
7496
|
-
if (this.seqNo === 0) {
|
|
7527
|
+
if (this.seqNo === 0 || !this.replayStartTime) {
|
|
7528
|
+
// extra safety net so that we don't send a null replay start time
|
|
7529
|
+
if (this.seqNo !== 0) {
|
|
7530
|
+
this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
|
|
7531
|
+
}
|
|
7532
|
+
|
|
7497
7533
|
this.replayStartTime = batchStartTime;
|
|
7498
7534
|
}
|
|
7499
7535
|
var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime;
|
|
@@ -7502,7 +7538,7 @@
|
|
|
7502
7538
|
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
7503
7539
|
'seq': this.seqNo,
|
|
7504
7540
|
'batch_start_time': batchStartTime / 1000,
|
|
7505
|
-
'replay_id':
|
|
7541
|
+
'replay_id': replayId,
|
|
7506
7542
|
'replay_length_ms': replayLengthMs,
|
|
7507
7543
|
'replay_start_time': this.replayStartTime / 1000
|
|
7508
7544
|
};
|
|
@@ -7525,11 +7561,11 @@
|
|
|
7525
7561
|
.blob()
|
|
7526
7562
|
.then(_.bind(function(compressedBlob) {
|
|
7527
7563
|
reqParams['format'] = 'gzip';
|
|
7528
|
-
this._sendRequest(reqParams, compressedBlob, callback);
|
|
7564
|
+
this._sendRequest(replayId, reqParams, compressedBlob, callback);
|
|
7529
7565
|
}, this));
|
|
7530
7566
|
} else {
|
|
7531
7567
|
reqParams['format'] = 'body';
|
|
7532
|
-
this._sendRequest(reqParams, eventsJson, callback);
|
|
7568
|
+
this._sendRequest(replayId, reqParams, eventsJson, callback);
|
|
7533
7569
|
}
|
|
7534
7570
|
}
|
|
7535
7571
|
});
|
|
@@ -9017,6 +9053,7 @@
|
|
|
9017
9053
|
'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
|
|
9018
9054
|
'record_mask_text_selector': '*',
|
|
9019
9055
|
'record_max_ms': MAX_RECORDING_MS,
|
|
9056
|
+
'record_min_ms': 0,
|
|
9020
9057
|
'record_sessions_percent': 0,
|
|
9021
9058
|
'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js'
|
|
9022
9059
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mixpanel-browser",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.55.1",
|
|
4
4
|
"description": "The official Mixpanel JavaScript browser client library",
|
|
5
5
|
"main": "dist/mixpanel.cjs.js",
|
|
6
|
+
"module": "dist/mixpanel.module.js",
|
|
6
7
|
"directories": {
|
|
7
8
|
"test": "tests"
|
|
8
9
|
},
|
package/src/config.js
CHANGED
package/src/mixpanel-core.js
CHANGED
|
@@ -152,6 +152,7 @@ var DEFAULT_CONFIG = {
|
|
|
152
152
|
'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
|
|
153
153
|
'record_mask_text_selector': '*',
|
|
154
154
|
'record_max_ms': MAX_RECORDING_MS,
|
|
155
|
+
'record_min_ms': 0,
|
|
155
156
|
'record_sessions_percent': 0,
|
|
156
157
|
'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js'
|
|
157
158
|
};
|
package/src/recorder/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { record } from 'rrweb';
|
|
2
2
|
import { IncrementalSource, EventType } from '@rrweb/types';
|
|
3
3
|
|
|
4
|
-
import { MAX_RECORDING_MS, console_with_prefix, _, window} from '../utils'; // eslint-disable-line camelcase
|
|
4
|
+
import { MAX_RECORDING_MS, MAX_VALUE_FOR_MIN_RECORDING_MS, console_with_prefix, _, window} from '../utils'; // eslint-disable-line camelcase
|
|
5
5
|
import { addOptOutCheckMixpanelLib } from '../gdpr-utils';
|
|
6
6
|
import { RequestBatcher } from '../request-batcher';
|
|
7
7
|
|
|
@@ -47,6 +47,7 @@ var MixpanelRecorder = function(mixpanelInstance) {
|
|
|
47
47
|
this.maxTimeoutId = null;
|
|
48
48
|
|
|
49
49
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
50
|
+
this.recordMinMs = 0;
|
|
50
51
|
this._initBatcher();
|
|
51
52
|
};
|
|
52
53
|
|
|
@@ -78,16 +79,24 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
78
79
|
logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
this.recordMinMs = this.get_config('record_min_ms');
|
|
83
|
+
if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
84
|
+
this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
85
|
+
logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
86
|
+
}
|
|
87
|
+
|
|
81
88
|
this.recEvents = [];
|
|
82
89
|
this.seqNo = 0;
|
|
83
|
-
this.replayStartTime =
|
|
90
|
+
this.replayStartTime = new Date().getTime();
|
|
84
91
|
|
|
85
92
|
this.replayId = _.UUID();
|
|
86
93
|
|
|
87
|
-
if (shouldStopBatcher) {
|
|
88
|
-
//
|
|
94
|
+
if (shouldStopBatcher || this.recordMinMs > 0) {
|
|
95
|
+
// the primary case for shouldStopBatcher is when we're starting recording after a reset
|
|
89
96
|
// and don't want to send anything over the network until there's
|
|
90
97
|
// actual user activity
|
|
98
|
+
// this also applies if the minimum recording length has not been hit yet
|
|
99
|
+
// so that we don't send data until we know the recording will be long enough
|
|
91
100
|
this.batcher.stop();
|
|
92
101
|
} else {
|
|
93
102
|
this.batcher.start();
|
|
@@ -101,11 +110,16 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
101
110
|
}, this), this.get_config('record_idle_timeout_ms'));
|
|
102
111
|
}, this);
|
|
103
112
|
|
|
113
|
+
var blockSelector = this.get_config('record_block_selector');
|
|
114
|
+
if (blockSelector === '' || blockSelector === null) {
|
|
115
|
+
blockSelector = undefined;
|
|
116
|
+
}
|
|
117
|
+
|
|
104
118
|
this._stopRecording = record({
|
|
105
119
|
'emit': _.bind(function (ev) {
|
|
106
120
|
this.batcher.enqueue(ev);
|
|
107
121
|
if (isUserEvent(ev)) {
|
|
108
|
-
if (this.batcher.stopped) {
|
|
122
|
+
if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
|
|
109
123
|
// start flushing again after user activity
|
|
110
124
|
this.batcher.start();
|
|
111
125
|
}
|
|
@@ -113,7 +127,7 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
113
127
|
}
|
|
114
128
|
}, this),
|
|
115
129
|
'blockClass': this.get_config('record_block_class'),
|
|
116
|
-
'blockSelector':
|
|
130
|
+
'blockSelector': blockSelector,
|
|
117
131
|
'collectFonts': this.get_config('record_collect_fonts'),
|
|
118
132
|
'inlineImages': this.get_config('record_inline_images'),
|
|
119
133
|
'maskAllInputs': true,
|
|
@@ -167,14 +181,14 @@ MixpanelRecorder.prototype._onOptOut = function (code) {
|
|
|
167
181
|
}
|
|
168
182
|
};
|
|
169
183
|
|
|
170
|
-
MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) {
|
|
184
|
+
MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
|
|
171
185
|
var onSuccess = _.bind(function (response, responseBody) {
|
|
172
186
|
// Increment sequence counter only if the request was successful to guarantee ordering.
|
|
173
187
|
// RequestBatcher will always flush the next batch after the previous one succeeds.
|
|
174
|
-
if
|
|
188
|
+
// extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay
|
|
189
|
+
if (response.status === 200 && this.replayId === currentReplayId) {
|
|
175
190
|
this.seqNo++;
|
|
176
191
|
}
|
|
177
|
-
|
|
178
192
|
callback({
|
|
179
193
|
status: 0,
|
|
180
194
|
httpStatusCode: response.status,
|
|
@@ -197,7 +211,7 @@ MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback)
|
|
|
197
211
|
callback({error: error});
|
|
198
212
|
});
|
|
199
213
|
}).catch(function (error) {
|
|
200
|
-
callback({error: error});
|
|
214
|
+
callback({error: error, httpStatusCode: 0});
|
|
201
215
|
});
|
|
202
216
|
};
|
|
203
217
|
|
|
@@ -205,9 +219,15 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
205
219
|
const numEvents = data.length;
|
|
206
220
|
|
|
207
221
|
if (numEvents > 0) {
|
|
222
|
+
var replayId = this.replayId;
|
|
208
223
|
// each rrweb event has a timestamp - leverage those to get time properties
|
|
209
224
|
var batchStartTime = data[0].timestamp;
|
|
210
|
-
if (this.seqNo === 0) {
|
|
225
|
+
if (this.seqNo === 0 || !this.replayStartTime) {
|
|
226
|
+
// extra safety net so that we don't send a null replay start time
|
|
227
|
+
if (this.seqNo !== 0) {
|
|
228
|
+
this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
|
|
229
|
+
}
|
|
230
|
+
|
|
211
231
|
this.replayStartTime = batchStartTime;
|
|
212
232
|
}
|
|
213
233
|
var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime;
|
|
@@ -216,7 +236,7 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
216
236
|
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
217
237
|
'seq': this.seqNo,
|
|
218
238
|
'batch_start_time': batchStartTime / 1000,
|
|
219
|
-
'replay_id':
|
|
239
|
+
'replay_id': replayId,
|
|
220
240
|
'replay_length_ms': replayLengthMs,
|
|
221
241
|
'replay_start_time': this.replayStartTime / 1000
|
|
222
242
|
};
|
|
@@ -239,11 +259,11 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
239
259
|
.blob()
|
|
240
260
|
.then(_.bind(function(compressedBlob) {
|
|
241
261
|
reqParams['format'] = 'gzip';
|
|
242
|
-
this._sendRequest(reqParams, compressedBlob, callback);
|
|
262
|
+
this._sendRequest(replayId, reqParams, compressedBlob, callback);
|
|
243
263
|
}, this));
|
|
244
264
|
} else {
|
|
245
265
|
reqParams['format'] = 'body';
|
|
246
|
-
this._sendRequest(reqParams, eventsJson, callback);
|
|
266
|
+
this._sendRequest(replayId, reqParams, eventsJson, callback);
|
|
247
267
|
}
|
|
248
268
|
}
|
|
249
269
|
});
|
package/src/request-batcher.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Config from './config';
|
|
2
2
|
import { RequestQueue } from './request-queue';
|
|
3
|
-
import { console_with_prefix, _ } from './utils'; // eslint-disable-line camelcase
|
|
3
|
+
import { console_with_prefix, isOnline, _ } from './utils'; // eslint-disable-line camelcase
|
|
4
4
|
|
|
5
5
|
// maximum interval between request retries after exponential backoff
|
|
6
6
|
var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
|
|
@@ -198,7 +198,12 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
198
198
|
this.flush();
|
|
199
199
|
} else if (
|
|
200
200
|
_.isObject(res) &&
|
|
201
|
-
(
|
|
201
|
+
(
|
|
202
|
+
res.httpStatusCode >= 500
|
|
203
|
+
|| res.httpStatusCode === 429
|
|
204
|
+
|| (res.httpStatusCode <= 0 && !isOnline())
|
|
205
|
+
|| res.error === 'timeout'
|
|
206
|
+
)
|
|
202
207
|
) {
|
|
203
208
|
// network or API error, or 429 Too Many Requests, retry
|
|
204
209
|
var retryMS = this.flushInterval * 2;
|
package/src/utils.js
CHANGED
|
@@ -8,7 +8,7 @@ if (typeof(window) === 'undefined') {
|
|
|
8
8
|
hostname: ''
|
|
9
9
|
};
|
|
10
10
|
win = {
|
|
11
|
-
navigator: { userAgent: '' },
|
|
11
|
+
navigator: { userAgent: '', onLine: true },
|
|
12
12
|
document: {
|
|
13
13
|
location: loc,
|
|
14
14
|
referrer: ''
|
|
@@ -22,6 +22,8 @@ if (typeof(window) === 'undefined') {
|
|
|
22
22
|
|
|
23
23
|
// Maximum allowed session recording length
|
|
24
24
|
var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
25
|
+
// Maximum allowed value for minimum session recording length
|
|
26
|
+
var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds
|
|
25
27
|
|
|
26
28
|
/*
|
|
27
29
|
* Saved references to long variable names, so that closure compiler can
|
|
@@ -962,7 +964,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) {
|
|
|
962
964
|
_.getQueryParam = function(url, param) {
|
|
963
965
|
// Expects a raw URL
|
|
964
966
|
|
|
965
|
-
param = param.replace(/[[]
|
|
967
|
+
param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]');
|
|
966
968
|
var regexS = '[\\?&]' + param + '=([^&#]*)',
|
|
967
969
|
regex = new RegExp(regexS),
|
|
968
970
|
results = regex.exec(url);
|
|
@@ -1419,8 +1421,8 @@ _.dom_query = (function() {
|
|
|
1419
1421
|
};
|
|
1420
1422
|
})();
|
|
1421
1423
|
|
|
1422
|
-
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
|
|
1423
|
-
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
|
|
1424
|
+
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic'];
|
|
1425
|
+
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid'];
|
|
1424
1426
|
|
|
1425
1427
|
_.info = {
|
|
1426
1428
|
campaignParams: function(default_value) {
|
|
@@ -1702,6 +1704,15 @@ var extract_domain = function(hostname) {
|
|
|
1702
1704
|
return matches ? matches[0] : '';
|
|
1703
1705
|
};
|
|
1704
1706
|
|
|
1707
|
+
/**
|
|
1708
|
+
* Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE)
|
|
1709
|
+
* @returns {boolean}
|
|
1710
|
+
*/
|
|
1711
|
+
var isOnline = function() {
|
|
1712
|
+
var onLine = win.navigator['onLine'];
|
|
1713
|
+
return _.isUndefined(onLine) || onLine;
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1705
1716
|
var JSONStringify = null, JSONParse = null;
|
|
1706
1717
|
if (typeof JSON !== 'undefined') {
|
|
1707
1718
|
JSONStringify = JSON.stringify;
|
|
@@ -1724,18 +1735,20 @@ _['info']['browserVersion'] = _.info.browserVersion;
|
|
|
1724
1735
|
_['info']['properties'] = _.info.properties;
|
|
1725
1736
|
|
|
1726
1737
|
export {
|
|
1727
|
-
MAX_RECORDING_MS,
|
|
1728
1738
|
_,
|
|
1729
|
-
userAgent,
|
|
1730
|
-
console,
|
|
1731
|
-
win as window,
|
|
1732
|
-
document,
|
|
1733
|
-
navigator,
|
|
1734
1739
|
cheap_guid,
|
|
1735
1740
|
console_with_prefix,
|
|
1741
|
+
console,
|
|
1742
|
+
document,
|
|
1736
1743
|
extract_domain,
|
|
1737
|
-
localStorageSupported,
|
|
1738
|
-
JSONStringify,
|
|
1739
1744
|
JSONParse,
|
|
1740
|
-
|
|
1745
|
+
JSONStringify,
|
|
1746
|
+
isOnline,
|
|
1747
|
+
localStorageSupported,
|
|
1748
|
+
MAX_RECORDING_MS,
|
|
1749
|
+
MAX_VALUE_FOR_MIN_RECORDING_MS,
|
|
1750
|
+
navigator,
|
|
1751
|
+
slice,
|
|
1752
|
+
userAgent,
|
|
1753
|
+
win as window
|
|
1741
1754
|
};
|