mixpanel-browser 2.61.0 → 2.61.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 +8 -0
- package/dist/mixpanel-core.cjs.js +2 -2
- package/dist/mixpanel-recorder.js +62 -42
- package/dist/mixpanel-recorder.min.js +6 -6
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +2 -2
- package/dist/mixpanel.amd.js +62 -42
- package/dist/mixpanel.cjs.js +62 -42
- package/dist/mixpanel.globals.js +2 -2
- package/dist/mixpanel.min.js +6 -6
- package/dist/mixpanel.module.js +62 -42
- package/dist/mixpanel.umd.js +62 -42
- package/package.json +1 -1
- package/src/config.js +1 -1
- package/src/recorder/session-recording.js +60 -40
- package/src/storage/indexed-db.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
**2.61.1** (11 Mar 2025)
|
|
2
|
+
- Session recording stops if initial DOM snapshot fails
|
|
3
|
+
- Errors triggered by rrweb's record function are now caught
|
|
4
|
+
- Fix for issue causing opt-out check error messages in `debug` mode
|
|
5
|
+
|
|
6
|
+
**2.61.0** (6 Mar 2025)
|
|
7
|
+
- Session recordings now continue across page loads within the same tab, using IndexedDB for persistence
|
|
8
|
+
|
|
1
9
|
**2.60.0** (31 Jan 2025)
|
|
2
10
|
- Expanded Autocapture configs
|
|
3
11
|
- Prevent duplicate values in persistence when using people.union (thanks @chrisdeely)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.61.
|
|
5
|
+
LIB_VERSION: '2.61.1'
|
|
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
|
|
@@ -5624,7 +5624,7 @@ IDBStorageWrapper.prototype.makeTransaction = function (mode, storeCb) {
|
|
|
5624
5624
|
return this.dbPromise
|
|
5625
5625
|
.then(doTransaction)
|
|
5626
5626
|
.catch(function (err) {
|
|
5627
|
-
if (err['name'] === 'InvalidStateError') {
|
|
5627
|
+
if (err && err['name'] === 'InvalidStateError') {
|
|
5628
5628
|
// try reopening the DB if the connection is closed
|
|
5629
5629
|
this.dbPromise = this._openDb();
|
|
5630
5630
|
return this.dbPromise.then(doTransaction);
|
|
@@ -4894,7 +4894,7 @@
|
|
|
4894
4894
|
|
|
4895
4895
|
var Config = {
|
|
4896
4896
|
DEBUG: false,
|
|
4897
|
-
LIB_VERSION: '2.61.
|
|
4897
|
+
LIB_VERSION: '2.61.1'
|
|
4898
4898
|
};
|
|
4899
4899
|
|
|
4900
4900
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -6705,7 +6705,7 @@
|
|
|
6705
6705
|
return this.dbPromise
|
|
6706
6706
|
.then(doTransaction)
|
|
6707
6707
|
.catch(function (err) {
|
|
6708
|
-
if (err['name'] === 'InvalidStateError') {
|
|
6708
|
+
if (err && err['name'] === 'InvalidStateError') {
|
|
6709
6709
|
// try reopening the DB if the connection is closed
|
|
6710
6710
|
this.dbPromise = this._openDb();
|
|
6711
6711
|
return this.dbPromise.then(doTransaction);
|
|
@@ -7997,34 +7997,37 @@
|
|
|
7997
7997
|
blockSelector = undefined;
|
|
7998
7998
|
}
|
|
7999
7999
|
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
if (
|
|
8004
|
-
|
|
8005
|
-
|
|
8000
|
+
try {
|
|
8001
|
+
this._stopRecording = this._rrwebRecord({
|
|
8002
|
+
'emit': function (ev) {
|
|
8003
|
+
if (isUserEvent(ev)) {
|
|
8004
|
+
if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
|
|
8005
|
+
// start flushing again after user activity
|
|
8006
|
+
this.batcher.start();
|
|
8007
|
+
}
|
|
8008
|
+
resetIdleTimeout();
|
|
8006
8009
|
}
|
|
8007
|
-
|
|
8010
|
+
// promise only used to await during tests
|
|
8011
|
+
this.__enqueuePromise = this.batcher.enqueue(ev);
|
|
8012
|
+
}.bind(this),
|
|
8013
|
+
'blockClass': this.getConfig('record_block_class'),
|
|
8014
|
+
'blockSelector': blockSelector,
|
|
8015
|
+
'collectFonts': this.getConfig('record_collect_fonts'),
|
|
8016
|
+
'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
|
|
8017
|
+
'type': 'image/webp',
|
|
8018
|
+
'quality': 0.6
|
|
8019
|
+
},
|
|
8020
|
+
'maskAllInputs': true,
|
|
8021
|
+
'maskTextClass': this.getConfig('record_mask_text_class'),
|
|
8022
|
+
'maskTextSelector': this.getConfig('record_mask_text_selector'),
|
|
8023
|
+
'recordCanvas': this.getConfig('record_canvas'),
|
|
8024
|
+
'sampling': {
|
|
8025
|
+
'canvas': 15
|
|
8008
8026
|
}
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
'blockClass': this.getConfig('record_block_class'),
|
|
8014
|
-
'blockSelector': blockSelector,
|
|
8015
|
-
'collectFonts': this.getConfig('record_collect_fonts'),
|
|
8016
|
-
'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
|
|
8017
|
-
'type': 'image/webp',
|
|
8018
|
-
'quality': 0.6
|
|
8019
|
-
},
|
|
8020
|
-
'maskAllInputs': true,
|
|
8021
|
-
'maskTextClass': this.getConfig('record_mask_text_class'),
|
|
8022
|
-
'maskTextSelector': this.getConfig('record_mask_text_selector'),
|
|
8023
|
-
'recordCanvas': this.getConfig('record_canvas'),
|
|
8024
|
-
'sampling': {
|
|
8025
|
-
'canvas': 15
|
|
8026
|
-
}
|
|
8027
|
-
});
|
|
8027
|
+
});
|
|
8028
|
+
} catch (err) {
|
|
8029
|
+
this.reportError('Unexpected error when starting rrweb recording.', err);
|
|
8030
|
+
}
|
|
8028
8031
|
|
|
8029
8032
|
if (typeof this._stopRecording !== 'function') {
|
|
8030
8033
|
this.reportError('rrweb failed to start, skipping this recording.');
|
|
@@ -8068,12 +8071,21 @@
|
|
|
8068
8071
|
return this._stopRecording === null;
|
|
8069
8072
|
};
|
|
8070
8073
|
|
|
8074
|
+
|
|
8071
8075
|
/**
|
|
8072
8076
|
* Flushes the current batch of events to the server, but passes an opt-out callback to make sure
|
|
8073
8077
|
* we stop recording and dump any queued events if the user has opted out.
|
|
8074
8078
|
*/
|
|
8075
8079
|
SessionRecording.prototype.flushEventsWithOptOut = function (data, options, cb) {
|
|
8076
|
-
|
|
8080
|
+
var onOptOut = function (code) {
|
|
8081
|
+
// addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
|
|
8082
|
+
if (code === 0) {
|
|
8083
|
+
this.stopRecording();
|
|
8084
|
+
cb({error: 'Tracking has been opted out, stopping recording.'});
|
|
8085
|
+
}
|
|
8086
|
+
}.bind(this);
|
|
8087
|
+
|
|
8088
|
+
this._flushEvents(data, options, cb, onOptOut);
|
|
8077
8089
|
};
|
|
8078
8090
|
|
|
8079
8091
|
/**
|
|
@@ -8123,13 +8135,6 @@
|
|
|
8123
8135
|
return recording;
|
|
8124
8136
|
};
|
|
8125
8137
|
|
|
8126
|
-
SessionRecording.prototype._onOptOut = function (code) {
|
|
8127
|
-
// addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
|
|
8128
|
-
if (code === 0) {
|
|
8129
|
-
this.stopRecording();
|
|
8130
|
-
}
|
|
8131
|
-
};
|
|
8132
|
-
|
|
8133
8138
|
SessionRecording.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
|
|
8134
8139
|
var onSuccess = function (response, responseBody) {
|
|
8135
8140
|
// Update batch specific props only if the request was successful to guarantee ordering.
|
|
@@ -8172,17 +8177,32 @@
|
|
|
8172
8177
|
|
|
8173
8178
|
if (numEvents > 0) {
|
|
8174
8179
|
var replayId = this.replayId;
|
|
8180
|
+
|
|
8175
8181
|
// each rrweb event has a timestamp - leverage those to get time properties
|
|
8176
|
-
var batchStartTime =
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8182
|
+
var batchStartTime = Infinity;
|
|
8183
|
+
var batchEndTime = -Infinity;
|
|
8184
|
+
var hasFullSnapshot = false;
|
|
8185
|
+
for (var i = 0; i < numEvents; i++) {
|
|
8186
|
+
batchStartTime = Math.min(batchStartTime, data[i].timestamp);
|
|
8187
|
+
batchEndTime = Math.max(batchEndTime, data[i].timestamp);
|
|
8188
|
+
if (data[i].type === EventType.FullSnapshot) {
|
|
8189
|
+
hasFullSnapshot = true;
|
|
8181
8190
|
}
|
|
8191
|
+
}
|
|
8182
8192
|
|
|
8193
|
+
if (this.seqNo === 0) {
|
|
8194
|
+
if (!hasFullSnapshot) {
|
|
8195
|
+
callback({error: 'First batch does not contain a full snapshot. Aborting recording.'});
|
|
8196
|
+
this.stopRecording(true);
|
|
8197
|
+
return;
|
|
8198
|
+
}
|
|
8199
|
+
this.replayStartTime = batchStartTime;
|
|
8200
|
+
} else if (!this.replayStartTime) {
|
|
8201
|
+
this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
|
|
8183
8202
|
this.replayStartTime = batchStartTime;
|
|
8184
8203
|
}
|
|
8185
|
-
|
|
8204
|
+
|
|
8205
|
+
var replayLengthMs = batchEndTime - this.replayStartTime;
|
|
8186
8206
|
|
|
8187
8207
|
var reqParams = {
|
|
8188
8208
|
'$current_url': this.batchStartUrl,
|