mixpanel-browser 2.61.1 → 2.62.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/CHANGELOG.md +8 -0
- package/dist/mixpanel-core.cjs.js +23 -67
- package/dist/mixpanel-recorder.js +28 -68
- package/dist/mixpanel-recorder.min.js +10 -10
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +23 -67
- package/dist/mixpanel.amd.js +29 -70
- package/dist/mixpanel.cjs.js +29 -70
- package/dist/mixpanel.globals.js +23 -67
- package/dist/mixpanel.min.js +140 -141
- package/dist/mixpanel.module.js +29 -70
- package/dist/mixpanel.umd.js +29 -70
- package/package.json +1 -1
- package/src/config.js +1 -1
- package/src/mixpanel-core.js +2 -3
- package/src/mixpanel-persistence.js +2 -2
- package/src/recorder/session-recording.js +6 -3
- package/src/utils.js +20 -64
- package/src/window.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
**2.62.0** (26 Mar 2025)
|
|
2
|
+
- Replace UUID generator with UUIDv4 (using native API when available)
|
|
3
|
+
- Consistently use native JSON serialization when available
|
|
4
|
+
- Fix for session recording idle timeout race condition
|
|
5
|
+
|
|
6
|
+
**2.61.2** (14 Mar 2025)
|
|
7
|
+
- Revert 10ms throttle on enqueueing events to improve tracking reliability on page unload
|
|
8
|
+
|
|
1
9
|
**2.61.1** (11 Mar 2025)
|
|
2
10
|
- Session recording stops if initial DOM snapshot fails
|
|
3
11
|
- Errors triggered by rrweb's record function are now caught
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
5
|
+
LIB_VERSION: '2.62.0'
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
@@ -12,6 +12,7 @@ if (typeof(window) === 'undefined') {
|
|
|
12
12
|
hostname: ''
|
|
13
13
|
};
|
|
14
14
|
win = {
|
|
15
|
+
crypto: {randomUUID: function() {throw Error('unsupported');}},
|
|
15
16
|
navigator: { userAgent: '', onLine: true },
|
|
16
17
|
document: {
|
|
17
18
|
createElement: function() { return {}; },
|
|
@@ -1225,71 +1226,27 @@ _.utf8Encode = function(string) {
|
|
|
1225
1226
|
return utftext;
|
|
1226
1227
|
};
|
|
1227
1228
|
|
|
1228
|
-
_.UUID =
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
ticks = 0;
|
|
1239
|
-
|
|
1240
|
-
// this while loop figures how many browser ticks go by
|
|
1241
|
-
// before 1*new Date() returns a new number, ie the amount
|
|
1242
|
-
// of ticks that go by per millisecond
|
|
1243
|
-
while (time == 1 * new Date()) {
|
|
1244
|
-
ticks++;
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
return time.toString(16) + Math.floor(ticks).toString(16);
|
|
1248
|
-
};
|
|
1249
|
-
|
|
1250
|
-
// Math.Random entropy
|
|
1251
|
-
var R = function() {
|
|
1252
|
-
return Math.random().toString(16).replace('.', '');
|
|
1253
|
-
};
|
|
1254
|
-
|
|
1255
|
-
// User agent entropy
|
|
1256
|
-
// This function takes the user agent string, and then xors
|
|
1257
|
-
// together each sequence of 8 bytes. This produces a final
|
|
1258
|
-
// sequence of 8 bytes which it returns as hex.
|
|
1259
|
-
var UA = function() {
|
|
1260
|
-
var ua = userAgent,
|
|
1261
|
-
i, ch, buffer = [],
|
|
1262
|
-
ret = 0;
|
|
1263
|
-
|
|
1264
|
-
function xor(result, byte_array) {
|
|
1265
|
-
var j, tmp = 0;
|
|
1266
|
-
for (j = 0; j < byte_array.length; j++) {
|
|
1267
|
-
tmp |= (buffer[j] << j * 8);
|
|
1268
|
-
}
|
|
1269
|
-
return result ^ tmp;
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
for (i = 0; i < ua.length; i++) {
|
|
1273
|
-
ch = ua.charCodeAt(i);
|
|
1274
|
-
buffer.unshift(ch & 0xFF);
|
|
1275
|
-
if (buffer.length >= 4) {
|
|
1276
|
-
ret = xor(ret, buffer);
|
|
1277
|
-
buffer = [];
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
if (buffer.length > 0) {
|
|
1282
|
-
ret = xor(ret, buffer);
|
|
1229
|
+
_.UUID = function() {
|
|
1230
|
+
try {
|
|
1231
|
+
// use native Crypto API when available
|
|
1232
|
+
return win['crypto']['randomUUID']();
|
|
1233
|
+
} catch (err) {
|
|
1234
|
+
// fall back to generating our own UUID
|
|
1235
|
+
// based on https://gist.github.com/scwood/3bff42cc005cc20ab7ec98f0d8e1d59d
|
|
1236
|
+
var uuid = new Array(36);
|
|
1237
|
+
for (var i = 0; i < 36; i++) {
|
|
1238
|
+
uuid[i] = Math.floor(Math.random() * 16);
|
|
1283
1239
|
}
|
|
1240
|
+
uuid[14] = 4; // set bits 12-15 of time-high-and-version to 0100
|
|
1241
|
+
uuid[19] = uuid[19] &= ~(1 << 2); // set bit 6 of clock-seq-and-reserved to zero
|
|
1242
|
+
uuid[19] = uuid[19] |= (1 << 3); // set bit 7 of clock-seq-and-reserved to one
|
|
1243
|
+
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
|
|
1284
1244
|
|
|
1285
|
-
return
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
return (T() + '-' + R() + '-' + UA() + '-' + se + '-' + T());
|
|
1291
|
-
};
|
|
1292
|
-
})();
|
|
1245
|
+
return _.map(uuid, function(x) {
|
|
1246
|
+
return x.toString(16);
|
|
1247
|
+
}).join('');
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1293
1250
|
|
|
1294
1251
|
// _.isBlockedUA()
|
|
1295
1252
|
// This is to block various web spiders from executing our JS and
|
|
@@ -5231,7 +5188,7 @@ MixpanelPersistence.prototype.save = function() {
|
|
|
5231
5188
|
|
|
5232
5189
|
this.storage.set(
|
|
5233
5190
|
this.name,
|
|
5234
|
-
|
|
5191
|
+
JSONStringify(this['props']),
|
|
5235
5192
|
this.expire_days,
|
|
5236
5193
|
this.cross_subdomain,
|
|
5237
5194
|
this.secure,
|
|
@@ -6506,7 +6463,6 @@ MixpanelLib.prototype.init_batchers = function() {
|
|
|
6506
6463
|
}, this),
|
|
6507
6464
|
stopAllBatchingFunc: _.bind(this.stop_batch_senders, this),
|
|
6508
6465
|
usePersistence: true,
|
|
6509
|
-
enqueueThrottleMs: 10,
|
|
6510
6466
|
}
|
|
6511
6467
|
);
|
|
6512
6468
|
}, this);
|
|
@@ -6576,7 +6532,7 @@ MixpanelLib.prototype.disable = function(events) {
|
|
|
6576
6532
|
};
|
|
6577
6533
|
|
|
6578
6534
|
MixpanelLib.prototype._encode_data_for_request = function(data) {
|
|
6579
|
-
var encoded_data =
|
|
6535
|
+
var encoded_data = JSONStringify(data);
|
|
6580
6536
|
if (this.get_config('api_payload_format') === PAYLOAD_TYPE_BASE64) {
|
|
6581
6537
|
encoded_data = _.base64Encode(encoded_data);
|
|
6582
6538
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
hostname: ''
|
|
9
9
|
};
|
|
10
10
|
win = {
|
|
11
|
+
crypto: {randomUUID: function() {throw Error('unsupported');}},
|
|
11
12
|
navigator: { userAgent: '', onLine: true },
|
|
12
13
|
document: {
|
|
13
14
|
createElement: function() { return {}; },
|
|
@@ -4894,7 +4895,7 @@
|
|
|
4894
4895
|
|
|
4895
4896
|
var Config = {
|
|
4896
4897
|
DEBUG: false,
|
|
4897
|
-
LIB_VERSION: '2.
|
|
4898
|
+
LIB_VERSION: '2.62.0'
|
|
4898
4899
|
};
|
|
4899
4900
|
|
|
4900
4901
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -5683,71 +5684,27 @@
|
|
|
5683
5684
|
return utftext;
|
|
5684
5685
|
};
|
|
5685
5686
|
|
|
5686
|
-
_.UUID =
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
ticks = 0;
|
|
5697
|
-
|
|
5698
|
-
// this while loop figures how many browser ticks go by
|
|
5699
|
-
// before 1*new Date() returns a new number, ie the amount
|
|
5700
|
-
// of ticks that go by per millisecond
|
|
5701
|
-
while (time == 1 * new Date()) {
|
|
5702
|
-
ticks++;
|
|
5703
|
-
}
|
|
5704
|
-
}
|
|
5705
|
-
return time.toString(16) + Math.floor(ticks).toString(16);
|
|
5706
|
-
};
|
|
5707
|
-
|
|
5708
|
-
// Math.Random entropy
|
|
5709
|
-
var R = function() {
|
|
5710
|
-
return Math.random().toString(16).replace('.', '');
|
|
5711
|
-
};
|
|
5712
|
-
|
|
5713
|
-
// User agent entropy
|
|
5714
|
-
// This function takes the user agent string, and then xors
|
|
5715
|
-
// together each sequence of 8 bytes. This produces a final
|
|
5716
|
-
// sequence of 8 bytes which it returns as hex.
|
|
5717
|
-
var UA = function() {
|
|
5718
|
-
var ua = userAgent,
|
|
5719
|
-
i, ch, buffer = [],
|
|
5720
|
-
ret = 0;
|
|
5721
|
-
|
|
5722
|
-
function xor(result, byte_array) {
|
|
5723
|
-
var j, tmp = 0;
|
|
5724
|
-
for (j = 0; j < byte_array.length; j++) {
|
|
5725
|
-
tmp |= (buffer[j] << j * 8);
|
|
5726
|
-
}
|
|
5727
|
-
return result ^ tmp;
|
|
5728
|
-
}
|
|
5729
|
-
|
|
5730
|
-
for (i = 0; i < ua.length; i++) {
|
|
5731
|
-
ch = ua.charCodeAt(i);
|
|
5732
|
-
buffer.unshift(ch & 0xFF);
|
|
5733
|
-
if (buffer.length >= 4) {
|
|
5734
|
-
ret = xor(ret, buffer);
|
|
5735
|
-
buffer = [];
|
|
5736
|
-
}
|
|
5737
|
-
}
|
|
5738
|
-
|
|
5739
|
-
if (buffer.length > 0) {
|
|
5740
|
-
ret = xor(ret, buffer);
|
|
5687
|
+
_.UUID = function() {
|
|
5688
|
+
try {
|
|
5689
|
+
// use native Crypto API when available
|
|
5690
|
+
return win['crypto']['randomUUID']();
|
|
5691
|
+
} catch (err) {
|
|
5692
|
+
// fall back to generating our own UUID
|
|
5693
|
+
// based on https://gist.github.com/scwood/3bff42cc005cc20ab7ec98f0d8e1d59d
|
|
5694
|
+
var uuid = new Array(36);
|
|
5695
|
+
for (var i = 0; i < 36; i++) {
|
|
5696
|
+
uuid[i] = Math.floor(Math.random() * 16);
|
|
5741
5697
|
}
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5698
|
+
uuid[14] = 4; // set bits 12-15 of time-high-and-version to 0100
|
|
5699
|
+
uuid[19] = uuid[19] &= ~(1 << 2); // set bit 6 of clock-seq-and-reserved to zero
|
|
5700
|
+
uuid[19] = uuid[19] |= (1 << 3); // set bit 7 of clock-seq-and-reserved to one
|
|
5701
|
+
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
|
|
5702
|
+
|
|
5703
|
+
return _.map(uuid, function(x) {
|
|
5704
|
+
return x.toString(16);
|
|
5705
|
+
}).join('');
|
|
5706
|
+
}
|
|
5707
|
+
};
|
|
5751
5708
|
|
|
5752
5709
|
// _.isBlockedUA()
|
|
5753
5710
|
// This is to block various web spiders from executing our JS and
|
|
@@ -7991,6 +7948,7 @@
|
|
|
7991
7948
|
this.idleTimeoutId = setTimeout(this._onIdleTimeout, idleTimeoutMs);
|
|
7992
7949
|
this.idleExpires = new Date().getTime() + idleTimeoutMs;
|
|
7993
7950
|
}.bind(this);
|
|
7951
|
+
resetIdleTimeout();
|
|
7994
7952
|
|
|
7995
7953
|
var blockSelector = this.getConfig('record_block_selector');
|
|
7996
7954
|
if (blockSelector === '' || blockSelector === null) {
|
|
@@ -8000,6 +7958,10 @@
|
|
|
8000
7958
|
try {
|
|
8001
7959
|
this._stopRecording = this._rrwebRecord({
|
|
8002
7960
|
'emit': function (ev) {
|
|
7961
|
+
if (this.idleExpires && this.idleExpires < ev.timestamp) {
|
|
7962
|
+
this._onIdleTimeout();
|
|
7963
|
+
return;
|
|
7964
|
+
}
|
|
8003
7965
|
if (isUserEvent(ev)) {
|
|
8004
7966
|
if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
|
|
8005
7967
|
// start flushing again after user activity
|
|
@@ -8036,8 +7998,6 @@
|
|
|
8036
7998
|
return;
|
|
8037
7999
|
}
|
|
8038
8000
|
|
|
8039
|
-
resetIdleTimeout();
|
|
8040
|
-
|
|
8041
8001
|
var maxTimeoutMs = this.maxExpires - new Date().getTime();
|
|
8042
8002
|
this.maxTimeoutId = setTimeout(this._onMaxLengthReached.bind(this), maxTimeoutMs);
|
|
8043
8003
|
};
|
|
@@ -8216,7 +8176,7 @@
|
|
|
8216
8176
|
'replay_start_url': this.replayStartUrl,
|
|
8217
8177
|
'seq': this.seqNo
|
|
8218
8178
|
};
|
|
8219
|
-
var eventsJson =
|
|
8179
|
+
var eventsJson = JSON.stringify(data);
|
|
8220
8180
|
|
|
8221
8181
|
// send ID management props if they exist
|
|
8222
8182
|
var deviceId = this._mixpanel.get_property('$device_id');
|