mixpanel-browser 2.61.0 → 2.61.2
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 +11 -0
- package/dist/mixpanel-core.cjs.js +2 -3
- 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 -3
- package/dist/mixpanel.amd.js +62 -43
- package/dist/mixpanel.cjs.js +62 -43
- package/dist/mixpanel.globals.js +2 -3
- package/dist/mixpanel.min.js +58 -58
- package/dist/mixpanel.module.js +62 -43
- package/dist/mixpanel.umd.js +62 -43
- package/package.json +1 -1
- package/src/config.js +1 -1
- package/src/mixpanel-core.js +0 -1
- package/src/recorder/session-recording.js +60 -40
- package/src/storage/indexed-db.js +1 -1
package/dist/mixpanel.umd.js
CHANGED
|
@@ -4897,7 +4897,7 @@
|
|
|
4897
4897
|
|
|
4898
4898
|
var Config = {
|
|
4899
4899
|
DEBUG: false,
|
|
4900
|
-
LIB_VERSION: '2.61.
|
|
4900
|
+
LIB_VERSION: '2.61.2'
|
|
4901
4901
|
};
|
|
4902
4902
|
|
|
4903
4903
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -6760,7 +6760,7 @@
|
|
|
6760
6760
|
return this.dbPromise
|
|
6761
6761
|
.then(doTransaction)
|
|
6762
6762
|
.catch(function (err) {
|
|
6763
|
-
if (err['name'] === 'InvalidStateError') {
|
|
6763
|
+
if (err && err['name'] === 'InvalidStateError') {
|
|
6764
6764
|
// try reopening the DB if the connection is closed
|
|
6765
6765
|
this.dbPromise = this._openDb();
|
|
6766
6766
|
return this.dbPromise.then(doTransaction);
|
|
@@ -8184,34 +8184,37 @@
|
|
|
8184
8184
|
blockSelector = undefined;
|
|
8185
8185
|
}
|
|
8186
8186
|
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
if (
|
|
8191
|
-
|
|
8192
|
-
|
|
8187
|
+
try {
|
|
8188
|
+
this._stopRecording = this._rrwebRecord({
|
|
8189
|
+
'emit': function (ev) {
|
|
8190
|
+
if (isUserEvent(ev)) {
|
|
8191
|
+
if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
|
|
8192
|
+
// start flushing again after user activity
|
|
8193
|
+
this.batcher.start();
|
|
8194
|
+
}
|
|
8195
|
+
resetIdleTimeout();
|
|
8193
8196
|
}
|
|
8194
|
-
|
|
8197
|
+
// promise only used to await during tests
|
|
8198
|
+
this.__enqueuePromise = this.batcher.enqueue(ev);
|
|
8199
|
+
}.bind(this),
|
|
8200
|
+
'blockClass': this.getConfig('record_block_class'),
|
|
8201
|
+
'blockSelector': blockSelector,
|
|
8202
|
+
'collectFonts': this.getConfig('record_collect_fonts'),
|
|
8203
|
+
'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
|
|
8204
|
+
'type': 'image/webp',
|
|
8205
|
+
'quality': 0.6
|
|
8206
|
+
},
|
|
8207
|
+
'maskAllInputs': true,
|
|
8208
|
+
'maskTextClass': this.getConfig('record_mask_text_class'),
|
|
8209
|
+
'maskTextSelector': this.getConfig('record_mask_text_selector'),
|
|
8210
|
+
'recordCanvas': this.getConfig('record_canvas'),
|
|
8211
|
+
'sampling': {
|
|
8212
|
+
'canvas': 15
|
|
8195
8213
|
}
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
'blockClass': this.getConfig('record_block_class'),
|
|
8201
|
-
'blockSelector': blockSelector,
|
|
8202
|
-
'collectFonts': this.getConfig('record_collect_fonts'),
|
|
8203
|
-
'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
|
|
8204
|
-
'type': 'image/webp',
|
|
8205
|
-
'quality': 0.6
|
|
8206
|
-
},
|
|
8207
|
-
'maskAllInputs': true,
|
|
8208
|
-
'maskTextClass': this.getConfig('record_mask_text_class'),
|
|
8209
|
-
'maskTextSelector': this.getConfig('record_mask_text_selector'),
|
|
8210
|
-
'recordCanvas': this.getConfig('record_canvas'),
|
|
8211
|
-
'sampling': {
|
|
8212
|
-
'canvas': 15
|
|
8213
|
-
}
|
|
8214
|
-
});
|
|
8214
|
+
});
|
|
8215
|
+
} catch (err) {
|
|
8216
|
+
this.reportError('Unexpected error when starting rrweb recording.', err);
|
|
8217
|
+
}
|
|
8215
8218
|
|
|
8216
8219
|
if (typeof this._stopRecording !== 'function') {
|
|
8217
8220
|
this.reportError('rrweb failed to start, skipping this recording.');
|
|
@@ -8255,12 +8258,21 @@
|
|
|
8255
8258
|
return this._stopRecording === null;
|
|
8256
8259
|
};
|
|
8257
8260
|
|
|
8261
|
+
|
|
8258
8262
|
/**
|
|
8259
8263
|
* Flushes the current batch of events to the server, but passes an opt-out callback to make sure
|
|
8260
8264
|
* we stop recording and dump any queued events if the user has opted out.
|
|
8261
8265
|
*/
|
|
8262
8266
|
SessionRecording.prototype.flushEventsWithOptOut = function (data, options, cb) {
|
|
8263
|
-
|
|
8267
|
+
var onOptOut = function (code) {
|
|
8268
|
+
// addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
|
|
8269
|
+
if (code === 0) {
|
|
8270
|
+
this.stopRecording();
|
|
8271
|
+
cb({error: 'Tracking has been opted out, stopping recording.'});
|
|
8272
|
+
}
|
|
8273
|
+
}.bind(this);
|
|
8274
|
+
|
|
8275
|
+
this._flushEvents(data, options, cb, onOptOut);
|
|
8264
8276
|
};
|
|
8265
8277
|
|
|
8266
8278
|
/**
|
|
@@ -8310,13 +8322,6 @@
|
|
|
8310
8322
|
return recording;
|
|
8311
8323
|
};
|
|
8312
8324
|
|
|
8313
|
-
SessionRecording.prototype._onOptOut = function (code) {
|
|
8314
|
-
// addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
|
|
8315
|
-
if (code === 0) {
|
|
8316
|
-
this.stopRecording();
|
|
8317
|
-
}
|
|
8318
|
-
};
|
|
8319
|
-
|
|
8320
8325
|
SessionRecording.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
|
|
8321
8326
|
var onSuccess = function (response, responseBody) {
|
|
8322
8327
|
// Update batch specific props only if the request was successful to guarantee ordering.
|
|
@@ -8359,17 +8364,32 @@
|
|
|
8359
8364
|
|
|
8360
8365
|
if (numEvents > 0) {
|
|
8361
8366
|
var replayId = this.replayId;
|
|
8367
|
+
|
|
8362
8368
|
// each rrweb event has a timestamp - leverage those to get time properties
|
|
8363
|
-
var batchStartTime =
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8369
|
+
var batchStartTime = Infinity;
|
|
8370
|
+
var batchEndTime = -Infinity;
|
|
8371
|
+
var hasFullSnapshot = false;
|
|
8372
|
+
for (var i = 0; i < numEvents; i++) {
|
|
8373
|
+
batchStartTime = Math.min(batchStartTime, data[i].timestamp);
|
|
8374
|
+
batchEndTime = Math.max(batchEndTime, data[i].timestamp);
|
|
8375
|
+
if (data[i].type === EventType.FullSnapshot) {
|
|
8376
|
+
hasFullSnapshot = true;
|
|
8368
8377
|
}
|
|
8378
|
+
}
|
|
8369
8379
|
|
|
8380
|
+
if (this.seqNo === 0) {
|
|
8381
|
+
if (!hasFullSnapshot) {
|
|
8382
|
+
callback({error: 'First batch does not contain a full snapshot. Aborting recording.'});
|
|
8383
|
+
this.stopRecording(true);
|
|
8384
|
+
return;
|
|
8385
|
+
}
|
|
8386
|
+
this.replayStartTime = batchStartTime;
|
|
8387
|
+
} else if (!this.replayStartTime) {
|
|
8388
|
+
this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
|
|
8370
8389
|
this.replayStartTime = batchStartTime;
|
|
8371
8390
|
}
|
|
8372
|
-
|
|
8391
|
+
|
|
8392
|
+
var replayLengthMs = batchEndTime - this.replayStartTime;
|
|
8373
8393
|
|
|
8374
8394
|
var reqParams = {
|
|
8375
8395
|
'$current_url': this.batchStartUrl,
|
|
@@ -11669,7 +11689,6 @@
|
|
|
11669
11689
|
}, this),
|
|
11670
11690
|
stopAllBatchingFunc: _.bind(this.stop_batch_senders, this),
|
|
11671
11691
|
usePersistence: true,
|
|
11672
|
-
enqueueThrottleMs: 10,
|
|
11673
11692
|
}
|
|
11674
11693
|
);
|
|
11675
11694
|
}, this);
|
package/package.json
CHANGED
package/src/config.js
CHANGED
package/src/mixpanel-core.js
CHANGED
|
@@ -193,34 +193,37 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
193
193
|
blockSelector = undefined;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
try {
|
|
197
|
+
this._stopRecording = this._rrwebRecord({
|
|
198
|
+
'emit': function (ev) {
|
|
199
|
+
if (isUserEvent(ev)) {
|
|
200
|
+
if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
|
|
201
|
+
// start flushing again after user activity
|
|
202
|
+
this.batcher.start();
|
|
203
|
+
}
|
|
204
|
+
resetIdleTimeout();
|
|
202
205
|
}
|
|
203
|
-
|
|
206
|
+
// promise only used to await during tests
|
|
207
|
+
this.__enqueuePromise = this.batcher.enqueue(ev);
|
|
208
|
+
}.bind(this),
|
|
209
|
+
'blockClass': this.getConfig('record_block_class'),
|
|
210
|
+
'blockSelector': blockSelector,
|
|
211
|
+
'collectFonts': this.getConfig('record_collect_fonts'),
|
|
212
|
+
'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
|
|
213
|
+
'type': 'image/webp',
|
|
214
|
+
'quality': 0.6
|
|
215
|
+
},
|
|
216
|
+
'maskAllInputs': true,
|
|
217
|
+
'maskTextClass': this.getConfig('record_mask_text_class'),
|
|
218
|
+
'maskTextSelector': this.getConfig('record_mask_text_selector'),
|
|
219
|
+
'recordCanvas': this.getConfig('record_canvas'),
|
|
220
|
+
'sampling': {
|
|
221
|
+
'canvas': 15
|
|
204
222
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
'blockClass': this.getConfig('record_block_class'),
|
|
210
|
-
'blockSelector': blockSelector,
|
|
211
|
-
'collectFonts': this.getConfig('record_collect_fonts'),
|
|
212
|
-
'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
|
|
213
|
-
'type': 'image/webp',
|
|
214
|
-
'quality': 0.6
|
|
215
|
-
},
|
|
216
|
-
'maskAllInputs': true,
|
|
217
|
-
'maskTextClass': this.getConfig('record_mask_text_class'),
|
|
218
|
-
'maskTextSelector': this.getConfig('record_mask_text_selector'),
|
|
219
|
-
'recordCanvas': this.getConfig('record_canvas'),
|
|
220
|
-
'sampling': {
|
|
221
|
-
'canvas': 15
|
|
222
|
-
}
|
|
223
|
-
});
|
|
223
|
+
});
|
|
224
|
+
} catch (err) {
|
|
225
|
+
this.reportError('Unexpected error when starting rrweb recording.', err);
|
|
226
|
+
}
|
|
224
227
|
|
|
225
228
|
if (typeof this._stopRecording !== 'function') {
|
|
226
229
|
this.reportError('rrweb failed to start, skipping this recording.');
|
|
@@ -264,12 +267,21 @@ SessionRecording.prototype.isRrwebStopped = function () {
|
|
|
264
267
|
return this._stopRecording === null;
|
|
265
268
|
};
|
|
266
269
|
|
|
270
|
+
|
|
267
271
|
/**
|
|
268
272
|
* Flushes the current batch of events to the server, but passes an opt-out callback to make sure
|
|
269
273
|
* we stop recording and dump any queued events if the user has opted out.
|
|
270
274
|
*/
|
|
271
275
|
SessionRecording.prototype.flushEventsWithOptOut = function (data, options, cb) {
|
|
272
|
-
|
|
276
|
+
var onOptOut = function (code) {
|
|
277
|
+
// addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
|
|
278
|
+
if (code === 0) {
|
|
279
|
+
this.stopRecording();
|
|
280
|
+
cb({error: 'Tracking has been opted out, stopping recording.'});
|
|
281
|
+
}
|
|
282
|
+
}.bind(this);
|
|
283
|
+
|
|
284
|
+
this._flushEvents(data, options, cb, onOptOut);
|
|
273
285
|
};
|
|
274
286
|
|
|
275
287
|
/**
|
|
@@ -319,13 +331,6 @@ SessionRecording.deserialize = function (serializedRecording, options) {
|
|
|
319
331
|
return recording;
|
|
320
332
|
};
|
|
321
333
|
|
|
322
|
-
SessionRecording.prototype._onOptOut = function (code) {
|
|
323
|
-
// addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
|
|
324
|
-
if (code === 0) {
|
|
325
|
-
this.stopRecording();
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
|
|
329
334
|
SessionRecording.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
|
|
330
335
|
var onSuccess = function (response, responseBody) {
|
|
331
336
|
// Update batch specific props only if the request was successful to guarantee ordering.
|
|
@@ -368,17 +373,32 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
368
373
|
|
|
369
374
|
if (numEvents > 0) {
|
|
370
375
|
var replayId = this.replayId;
|
|
376
|
+
|
|
371
377
|
// each rrweb event has a timestamp - leverage those to get time properties
|
|
372
|
-
var batchStartTime =
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
378
|
+
var batchStartTime = Infinity;
|
|
379
|
+
var batchEndTime = -Infinity;
|
|
380
|
+
var hasFullSnapshot = false;
|
|
381
|
+
for (var i = 0; i < numEvents; i++) {
|
|
382
|
+
batchStartTime = Math.min(batchStartTime, data[i].timestamp);
|
|
383
|
+
batchEndTime = Math.max(batchEndTime, data[i].timestamp);
|
|
384
|
+
if (data[i].type === EventType.FullSnapshot) {
|
|
385
|
+
hasFullSnapshot = true;
|
|
377
386
|
}
|
|
387
|
+
}
|
|
378
388
|
|
|
389
|
+
if (this.seqNo === 0) {
|
|
390
|
+
if (!hasFullSnapshot) {
|
|
391
|
+
callback({error: 'First batch does not contain a full snapshot. Aborting recording.'});
|
|
392
|
+
this.stopRecording(true);
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
this.replayStartTime = batchStartTime;
|
|
396
|
+
} else if (!this.replayStartTime) {
|
|
397
|
+
this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
|
|
379
398
|
this.replayStartTime = batchStartTime;
|
|
380
399
|
}
|
|
381
|
-
|
|
400
|
+
|
|
401
|
+
var replayLengthMs = batchEndTime - this.replayStartTime;
|
|
382
402
|
|
|
383
403
|
var reqParams = {
|
|
384
404
|
'$current_url': this.batchStartUrl,
|
|
@@ -84,7 +84,7 @@ IDBStorageWrapper.prototype.makeTransaction = function (mode, storeCb) {
|
|
|
84
84
|
return this.dbPromise
|
|
85
85
|
.then(doTransaction)
|
|
86
86
|
.catch(function (err) {
|
|
87
|
-
if (err['name'] === 'InvalidStateError') {
|
|
87
|
+
if (err && err['name'] === 'InvalidStateError') {
|
|
88
88
|
// try reopening the DB if the connection is closed
|
|
89
89
|
this.dbPromise = this._openDb();
|
|
90
90
|
return this.dbPromise.then(doTransaction);
|