mixpanel-browser 2.55.1 → 2.56.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/.eslintrc.json +31 -1
- package/CHANGELOG.md +8 -0
- package/dist/mixpanel-core.cjs.js +32 -10
- package/dist/mixpanel-recorder.js +162 -74
- package/dist/mixpanel-recorder.min.js +8 -7
- package/dist/mixpanel-recorder.min.js.map +1 -0
- package/dist/mixpanel-with-async-recorder.cjs.js +32 -10
- package/dist/mixpanel.amd.js +188 -80
- package/dist/mixpanel.cjs.js +188 -80
- package/dist/mixpanel.globals.js +32 -10
- package/dist/mixpanel.min.js +106 -105
- package/dist/mixpanel.min.js.map +8 -0
- package/dist/mixpanel.module.js +188 -80
- package/dist/mixpanel.umd.js +188 -80
- package/package.json +1 -1
- package/src/config.js +1 -1
- package/src/mixpanel-core.js +26 -6
- package/src/recorder/index.js +39 -252
- package/src/recorder/rollup.config.js +2 -1
- package/src/recorder/session-recording.js +305 -0
- package/src/request-queue.js +5 -3
package/dist/mixpanel.cjs.js
CHANGED
|
@@ -4509,7 +4509,7 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {
|
|
|
4509
4509
|
|
|
4510
4510
|
var Config = {
|
|
4511
4511
|
DEBUG: false,
|
|
4512
|
-
LIB_VERSION: '2.
|
|
4512
|
+
LIB_VERSION: '2.56.0'
|
|
4513
4513
|
};
|
|
4514
4514
|
|
|
4515
4515
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -6546,7 +6546,7 @@ function _addOptOutCheck(method, getConfigValue) {
|
|
|
6546
6546
|
};
|
|
6547
6547
|
}
|
|
6548
6548
|
|
|
6549
|
-
var logger$
|
|
6549
|
+
var logger$4 = console_with_prefix('lock');
|
|
6550
6550
|
|
|
6551
6551
|
/**
|
|
6552
6552
|
* SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
|
|
@@ -6603,7 +6603,7 @@ SharedLock.prototype.withLock = function(lockedCB, errorCB, pid) {
|
|
|
6603
6603
|
|
|
6604
6604
|
var delay = function(cb) {
|
|
6605
6605
|
if (new Date().getTime() - startTime > timeoutMS) {
|
|
6606
|
-
logger$
|
|
6606
|
+
logger$4.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
|
|
6607
6607
|
storage.removeItem(keyZ);
|
|
6608
6608
|
storage.removeItem(keyY);
|
|
6609
6609
|
loop();
|
|
@@ -6692,7 +6692,7 @@ SharedLock.prototype.withLock = function(lockedCB, errorCB, pid) {
|
|
|
6692
6692
|
}
|
|
6693
6693
|
};
|
|
6694
6694
|
|
|
6695
|
-
var logger$
|
|
6695
|
+
var logger$3 = console_with_prefix('batch');
|
|
6696
6696
|
|
|
6697
6697
|
/**
|
|
6698
6698
|
* RequestQueue: queue for batching API requests with localStorage backup for retries.
|
|
@@ -6713,11 +6713,13 @@ var logger$2 = console_with_prefix('batch');
|
|
|
6713
6713
|
var RequestQueue = function(storageKey, options) {
|
|
6714
6714
|
options = options || {};
|
|
6715
6715
|
this.storageKey = storageKey;
|
|
6716
|
-
this.storage = options.storage || window.localStorage;
|
|
6717
|
-
this.reportError = options.errorReporter || _.bind(logger$2.error, logger$2);
|
|
6718
|
-
this.lock = new SharedLock(storageKey, {storage: this.storage});
|
|
6719
|
-
|
|
6720
6716
|
this.usePersistence = options.usePersistence;
|
|
6717
|
+
if (this.usePersistence) {
|
|
6718
|
+
this.storage = options.storage || window.localStorage;
|
|
6719
|
+
this.lock = new SharedLock(storageKey, {storage: this.storage});
|
|
6720
|
+
}
|
|
6721
|
+
this.reportError = options.errorReporter || _.bind(logger$3.error, logger$3);
|
|
6722
|
+
|
|
6721
6723
|
this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
|
|
6722
6724
|
|
|
6723
6725
|
this.memQueue = [];
|
|
@@ -6996,7 +6998,7 @@ RequestQueue.prototype.clear = function() {
|
|
|
6996
6998
|
// maximum interval between request retries after exponential backoff
|
|
6997
6999
|
var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
|
|
6998
7000
|
|
|
6999
|
-
var logger$
|
|
7001
|
+
var logger$2 = console_with_prefix('batch');
|
|
7000
7002
|
|
|
7001
7003
|
/**
|
|
7002
7004
|
* RequestBatcher: manages the queueing, flushing, retry etc of requests of one
|
|
@@ -7110,7 +7112,7 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
7110
7112
|
try {
|
|
7111
7113
|
|
|
7112
7114
|
if (this.requestInProgress) {
|
|
7113
|
-
logger$
|
|
7115
|
+
logger$2.log('Flush: Request already in progress');
|
|
7114
7116
|
return;
|
|
7115
7117
|
}
|
|
7116
7118
|
|
|
@@ -7278,7 +7280,7 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
7278
7280
|
if (options.unloading) {
|
|
7279
7281
|
requestOptions.transport = 'sendBeacon';
|
|
7280
7282
|
}
|
|
7281
|
-
logger$
|
|
7283
|
+
logger$2.log('MIXPANEL REQUEST:', dataForRequest);
|
|
7282
7284
|
this.sendRequest(dataForRequest, requestOptions, batchSendCallback);
|
|
7283
7285
|
} catch(err) {
|
|
7284
7286
|
this.reportError('Error flushing request queue', err);
|
|
@@ -7290,7 +7292,7 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
7290
7292
|
* Log error to global logger and optional user-defined logger.
|
|
7291
7293
|
*/
|
|
7292
7294
|
RequestBatcher.prototype.reportError = function(msg, err) {
|
|
7293
|
-
logger$
|
|
7295
|
+
logger$2.error.apply(logger$2.error, arguments);
|
|
7294
7296
|
if (this.errorReporter) {
|
|
7295
7297
|
try {
|
|
7296
7298
|
if (!(err instanceof Error)) {
|
|
@@ -7298,12 +7300,12 @@ RequestBatcher.prototype.reportError = function(msg, err) {
|
|
|
7298
7300
|
}
|
|
7299
7301
|
this.errorReporter(msg, err);
|
|
7300
7302
|
} catch(err) {
|
|
7301
|
-
logger$
|
|
7303
|
+
logger$2.error(err);
|
|
7302
7304
|
}
|
|
7303
7305
|
}
|
|
7304
7306
|
};
|
|
7305
7307
|
|
|
7306
|
-
var logger = console_with_prefix('recorder');
|
|
7308
|
+
var logger$1 = console_with_prefix('recorder');
|
|
7307
7309
|
var CompressionStream = win['CompressionStream'];
|
|
7308
7310
|
|
|
7309
7311
|
var RECORDER_BATCHER_LIB_CONFIG = {
|
|
@@ -7329,65 +7331,78 @@ function isUserEvent(ev) {
|
|
|
7329
7331
|
return ev.type === EventType.IncrementalSnapshot && ACTIVE_SOURCES.has(ev.data.source);
|
|
7330
7332
|
}
|
|
7331
7333
|
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
+
/**
|
|
7335
|
+
* This class encapsulates a single session recording and its lifecycle.
|
|
7336
|
+
* @param {Object} [options.mixpanelInstance] - reference to the core MixpanelLib
|
|
7337
|
+
* @param {String} [options.replayId] - unique uuid for a single replay
|
|
7338
|
+
* @param {Function} [options.onIdleTimeout] - callback when a recording reaches idle timeout
|
|
7339
|
+
* @param {Function} [options.onMaxLengthReached] - callback when a recording reaches its maximum length
|
|
7340
|
+
* @param {Function} [options.rrwebRecord] - rrweb's `record` function
|
|
7341
|
+
*/
|
|
7342
|
+
var SessionRecording = function(options) {
|
|
7343
|
+
this._mixpanel = options.mixpanelInstance;
|
|
7344
|
+
this._onIdleTimeout = options.onIdleTimeout;
|
|
7345
|
+
this._onMaxLengthReached = options.onMaxLengthReached;
|
|
7346
|
+
this._rrwebRecord = options.rrwebRecord;
|
|
7347
|
+
|
|
7348
|
+
this.replayId = options.replayId;
|
|
7334
7349
|
|
|
7335
7350
|
// internal rrweb stopRecording function
|
|
7336
7351
|
this._stopRecording = null;
|
|
7337
7352
|
|
|
7338
|
-
this.recEvents = [];
|
|
7339
7353
|
this.seqNo = 0;
|
|
7340
|
-
this.replayId = null;
|
|
7341
7354
|
this.replayStartTime = null;
|
|
7342
|
-
this.
|
|
7355
|
+
this.batchStartUrl = null;
|
|
7343
7356
|
|
|
7344
7357
|
this.idleTimeoutId = null;
|
|
7345
7358
|
this.maxTimeoutId = null;
|
|
7346
7359
|
|
|
7347
7360
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
7348
7361
|
this.recordMinMs = 0;
|
|
7349
|
-
this._initBatcher();
|
|
7350
|
-
};
|
|
7351
7362
|
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
sendRequestFunc: _.bind(this.flushEventsWithOptOut, this),
|
|
7363
|
+
// each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
|
|
7364
|
+
// this will be important when persistence is introduced
|
|
7365
|
+
var batcherKey = '__mprec_' + this.getConfig('token') + '_' + this.replayId;
|
|
7366
|
+
this.batcher = new RequestBatcher(batcherKey, {
|
|
7357
7367
|
errorReporter: _.bind(this.reportError, this),
|
|
7358
7368
|
flushOnlyOnInterval: true,
|
|
7369
|
+
libConfig: RECORDER_BATCHER_LIB_CONFIG,
|
|
7370
|
+
sendRequestFunc: _.bind(this.flushEventsWithOptOut, this),
|
|
7359
7371
|
usePersistence: false
|
|
7360
7372
|
});
|
|
7361
7373
|
};
|
|
7362
7374
|
|
|
7363
|
-
|
|
7364
|
-
MixpanelRecorder.prototype.get_config = function(configVar) {
|
|
7375
|
+
SessionRecording.prototype.getConfig = function(configVar) {
|
|
7365
7376
|
return this._mixpanel.get_config(configVar);
|
|
7366
7377
|
};
|
|
7367
7378
|
|
|
7368
|
-
|
|
7379
|
+
// Alias for getConfig, used by the common addOptOutCheckMixpanelLib function which
|
|
7380
|
+
// reaches into this class instance and expects the snake case version of the function.
|
|
7381
|
+
// eslint-disable-next-line camelcase
|
|
7382
|
+
SessionRecording.prototype.get_config = function(configVar) {
|
|
7383
|
+
return this.getConfig(configVar);
|
|
7384
|
+
};
|
|
7385
|
+
|
|
7386
|
+
SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
|
|
7369
7387
|
if (this._stopRecording !== null) {
|
|
7370
|
-
logger.log('Recording already in progress, skipping startRecording.');
|
|
7388
|
+
logger$1.log('Recording already in progress, skipping startRecording.');
|
|
7371
7389
|
return;
|
|
7372
7390
|
}
|
|
7373
7391
|
|
|
7374
|
-
this.recordMaxMs = this.
|
|
7392
|
+
this.recordMaxMs = this.getConfig('record_max_ms');
|
|
7375
7393
|
if (this.recordMaxMs > MAX_RECORDING_MS) {
|
|
7376
7394
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
7377
|
-
logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
7395
|
+
logger$1.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
7378
7396
|
}
|
|
7379
7397
|
|
|
7380
|
-
this.recordMinMs = this.
|
|
7398
|
+
this.recordMinMs = this.getConfig('record_min_ms');
|
|
7381
7399
|
if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
7382
7400
|
this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
7383
|
-
logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
7401
|
+
logger$1.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
7384
7402
|
}
|
|
7385
7403
|
|
|
7386
|
-
this.recEvents = [];
|
|
7387
|
-
this.seqNo = 0;
|
|
7388
7404
|
this.replayStartTime = new Date().getTime();
|
|
7389
|
-
|
|
7390
|
-
this.replayId = _.UUID();
|
|
7405
|
+
this.batchStartUrl = _.info.currentUrl();
|
|
7391
7406
|
|
|
7392
7407
|
if (shouldStopBatcher || this.recordMinMs > 0) {
|
|
7393
7408
|
// the primary case for shouldStopBatcher is when we're starting recording after a reset
|
|
@@ -7402,18 +7417,15 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
7402
7417
|
|
|
7403
7418
|
var resetIdleTimeout = _.bind(function () {
|
|
7404
7419
|
clearTimeout(this.idleTimeoutId);
|
|
7405
|
-
this.idleTimeoutId = setTimeout(
|
|
7406
|
-
logger.log('Idle timeout reached, restarting recording.');
|
|
7407
|
-
this.resetRecording();
|
|
7408
|
-
}, this), this.get_config('record_idle_timeout_ms'));
|
|
7420
|
+
this.idleTimeoutId = setTimeout(this._onIdleTimeout, this.getConfig('record_idle_timeout_ms'));
|
|
7409
7421
|
}, this);
|
|
7410
7422
|
|
|
7411
|
-
var blockSelector = this.
|
|
7423
|
+
var blockSelector = this.getConfig('record_block_selector');
|
|
7412
7424
|
if (blockSelector === '' || blockSelector === null) {
|
|
7413
7425
|
blockSelector = undefined;
|
|
7414
7426
|
}
|
|
7415
7427
|
|
|
7416
|
-
this._stopRecording =
|
|
7428
|
+
this._stopRecording = this._rrwebRecord({
|
|
7417
7429
|
'emit': _.bind(function (ev) {
|
|
7418
7430
|
this.batcher.enqueue(ev);
|
|
7419
7431
|
if (isUserEvent(ev)) {
|
|
@@ -7424,28 +7436,33 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
7424
7436
|
resetIdleTimeout();
|
|
7425
7437
|
}
|
|
7426
7438
|
}, this),
|
|
7427
|
-
'blockClass': this.
|
|
7439
|
+
'blockClass': this.getConfig('record_block_class'),
|
|
7428
7440
|
'blockSelector': blockSelector,
|
|
7429
|
-
'collectFonts': this.
|
|
7430
|
-
'inlineImages': this.get_config('record_inline_images'),
|
|
7441
|
+
'collectFonts': this.getConfig('record_collect_fonts'),
|
|
7431
7442
|
'maskAllInputs': true,
|
|
7432
|
-
'maskTextClass': this.
|
|
7433
|
-
'maskTextSelector': this.
|
|
7443
|
+
'maskTextClass': this.getConfig('record_mask_text_class'),
|
|
7444
|
+
'maskTextSelector': this.getConfig('record_mask_text_selector')
|
|
7434
7445
|
});
|
|
7435
7446
|
|
|
7436
|
-
|
|
7447
|
+
if (typeof this._stopRecording !== 'function') {
|
|
7448
|
+
this.reportError('rrweb failed to start, skipping this recording.');
|
|
7449
|
+
this._stopRecording = null;
|
|
7450
|
+
this.stopRecording(); // stop batcher looping and any timeouts
|
|
7451
|
+
return;
|
|
7452
|
+
}
|
|
7437
7453
|
|
|
7438
|
-
|
|
7439
|
-
};
|
|
7454
|
+
resetIdleTimeout();
|
|
7440
7455
|
|
|
7441
|
-
|
|
7442
|
-
this.stopRecording();
|
|
7443
|
-
this.startRecording(true);
|
|
7456
|
+
this.maxTimeoutId = setTimeout(_.bind(this._onMaxLengthReached, this), this.recordMaxMs);
|
|
7444
7457
|
};
|
|
7445
7458
|
|
|
7446
|
-
|
|
7447
|
-
if (this.
|
|
7448
|
-
|
|
7459
|
+
SessionRecording.prototype.stopRecording = function () {
|
|
7460
|
+
if (!this.isRrwebStopped()) {
|
|
7461
|
+
try {
|
|
7462
|
+
this._stopRecording();
|
|
7463
|
+
} catch (err) {
|
|
7464
|
+
this.reportError('Error with rrweb stopRecording', err);
|
|
7465
|
+
}
|
|
7449
7466
|
this._stopRecording = null;
|
|
7450
7467
|
}
|
|
7451
7468
|
|
|
@@ -7457,35 +7474,38 @@ MixpanelRecorder.prototype.stopRecording = function () {
|
|
|
7457
7474
|
this.batcher.flush();
|
|
7458
7475
|
this.batcher.stop();
|
|
7459
7476
|
}
|
|
7460
|
-
this.replayId = null;
|
|
7461
7477
|
|
|
7462
7478
|
clearTimeout(this.idleTimeoutId);
|
|
7463
7479
|
clearTimeout(this.maxTimeoutId);
|
|
7464
7480
|
};
|
|
7465
7481
|
|
|
7482
|
+
SessionRecording.prototype.isRrwebStopped = function () {
|
|
7483
|
+
return this._stopRecording === null;
|
|
7484
|
+
};
|
|
7485
|
+
|
|
7466
7486
|
/**
|
|
7467
7487
|
* Flushes the current batch of events to the server, but passes an opt-out callback to make sure
|
|
7468
7488
|
* we stop recording and dump any queued events if the user has opted out.
|
|
7469
7489
|
*/
|
|
7470
|
-
|
|
7490
|
+
SessionRecording.prototype.flushEventsWithOptOut = function (data, options, cb) {
|
|
7471
7491
|
this._flushEvents(data, options, cb, _.bind(this._onOptOut, this));
|
|
7472
7492
|
};
|
|
7473
7493
|
|
|
7474
|
-
|
|
7494
|
+
SessionRecording.prototype._onOptOut = function (code) {
|
|
7475
7495
|
// addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
|
|
7476
7496
|
if (code === 0) {
|
|
7477
|
-
this.recEvents = [];
|
|
7478
7497
|
this.stopRecording();
|
|
7479
7498
|
}
|
|
7480
7499
|
};
|
|
7481
7500
|
|
|
7482
|
-
|
|
7501
|
+
SessionRecording.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
|
|
7483
7502
|
var onSuccess = _.bind(function (response, responseBody) {
|
|
7484
|
-
//
|
|
7503
|
+
// Update batch specific props only if the request was successful to guarantee ordering.
|
|
7485
7504
|
// RequestBatcher will always flush the next batch after the previous one succeeds.
|
|
7486
7505
|
// extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay
|
|
7487
7506
|
if (response.status === 200 && this.replayId === currentReplayId) {
|
|
7488
7507
|
this.seqNo++;
|
|
7508
|
+
this.batchStartUrl = _.info.currentUrl();
|
|
7489
7509
|
}
|
|
7490
7510
|
callback({
|
|
7491
7511
|
status: 0,
|
|
@@ -7495,10 +7515,10 @@ MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, r
|
|
|
7495
7515
|
});
|
|
7496
7516
|
}, this);
|
|
7497
7517
|
|
|
7498
|
-
win['fetch'](this.
|
|
7518
|
+
win['fetch'](this.getConfig('api_host') + '/' + this.getConfig('api_routes')['record'] + '?' + new URLSearchParams(reqParams), {
|
|
7499
7519
|
'method': 'POST',
|
|
7500
7520
|
'headers': {
|
|
7501
|
-
'Authorization': 'Basic ' + btoa(this.
|
|
7521
|
+
'Authorization': 'Basic ' + btoa(this.getConfig('token') + ':'),
|
|
7502
7522
|
'Content-Type': 'application/octet-stream'
|
|
7503
7523
|
},
|
|
7504
7524
|
'body': reqBody,
|
|
@@ -7513,7 +7533,7 @@ MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, r
|
|
|
7513
7533
|
});
|
|
7514
7534
|
};
|
|
7515
7535
|
|
|
7516
|
-
|
|
7536
|
+
SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (data, options, callback) {
|
|
7517
7537
|
const numEvents = data.length;
|
|
7518
7538
|
|
|
7519
7539
|
if (numEvents > 0) {
|
|
@@ -7531,12 +7551,15 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
7531
7551
|
var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime;
|
|
7532
7552
|
|
|
7533
7553
|
var reqParams = {
|
|
7534
|
-
'
|
|
7535
|
-
'
|
|
7554
|
+
'$current_url': this.batchStartUrl,
|
|
7555
|
+
'$lib_version': Config.LIB_VERSION,
|
|
7536
7556
|
'batch_start_time': batchStartTime / 1000,
|
|
7557
|
+
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
7558
|
+
'mp_lib': 'web',
|
|
7537
7559
|
'replay_id': replayId,
|
|
7538
7560
|
'replay_length_ms': replayLengthMs,
|
|
7539
|
-
'replay_start_time': this.replayStartTime / 1000
|
|
7561
|
+
'replay_start_time': this.replayStartTime / 1000,
|
|
7562
|
+
'seq': this.seqNo
|
|
7540
7563
|
};
|
|
7541
7564
|
var eventsJson = _.JSONEncode(data);
|
|
7542
7565
|
|
|
@@ -7567,18 +7590,83 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
7567
7590
|
});
|
|
7568
7591
|
|
|
7569
7592
|
|
|
7570
|
-
|
|
7571
|
-
logger.error.apply(logger.error, arguments);
|
|
7593
|
+
SessionRecording.prototype.reportError = function(msg, err) {
|
|
7594
|
+
logger$1.error.apply(logger$1.error, arguments);
|
|
7572
7595
|
try {
|
|
7573
7596
|
if (!err && !(msg instanceof Error)) {
|
|
7574
7597
|
msg = new Error(msg);
|
|
7575
7598
|
}
|
|
7576
|
-
this.
|
|
7599
|
+
this.getConfig('error_reporter')(msg, err);
|
|
7577
7600
|
} catch(err) {
|
|
7578
|
-
logger.error(err);
|
|
7601
|
+
logger$1.error(err);
|
|
7602
|
+
}
|
|
7603
|
+
};
|
|
7604
|
+
|
|
7605
|
+
var logger = console_with_prefix('recorder');
|
|
7606
|
+
|
|
7607
|
+
/**
|
|
7608
|
+
* Recorder API: manages recordings and exposes methods public to the core Mixpanel library.
|
|
7609
|
+
* @param {Object} [options.mixpanelInstance] - reference to the core MixpanelLib
|
|
7610
|
+
*/
|
|
7611
|
+
var MixpanelRecorder = function(mixpanelInstance) {
|
|
7612
|
+
this._mixpanel = mixpanelInstance;
|
|
7613
|
+
this.activeRecording = null;
|
|
7614
|
+
};
|
|
7615
|
+
|
|
7616
|
+
MixpanelRecorder.prototype.startRecording = function(shouldStopBatcher) {
|
|
7617
|
+
if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
|
|
7618
|
+
logger.log('Recording already in progress, skipping startRecording.');
|
|
7619
|
+
return;
|
|
7620
|
+
}
|
|
7621
|
+
|
|
7622
|
+
var onIdleTimeout = _.bind(function () {
|
|
7623
|
+
logger.log('Idle timeout reached, restarting recording.');
|
|
7624
|
+
this.resetRecording();
|
|
7625
|
+
}, this);
|
|
7626
|
+
|
|
7627
|
+
var onMaxLengthReached = _.bind(function () {
|
|
7628
|
+
logger.log('Max recording length reached, stopping recording.');
|
|
7629
|
+
this.resetRecording();
|
|
7630
|
+
}, this);
|
|
7631
|
+
|
|
7632
|
+
this.activeRecording = new SessionRecording({
|
|
7633
|
+
mixpanelInstance: this._mixpanel,
|
|
7634
|
+
onIdleTimeout: onIdleTimeout,
|
|
7635
|
+
onMaxLengthReached: onMaxLengthReached,
|
|
7636
|
+
replayId: _.UUID(),
|
|
7637
|
+
rrwebRecord: record
|
|
7638
|
+
});
|
|
7639
|
+
|
|
7640
|
+
this.activeRecording.startRecording(shouldStopBatcher);
|
|
7641
|
+
};
|
|
7642
|
+
|
|
7643
|
+
MixpanelRecorder.prototype.stopRecording = function() {
|
|
7644
|
+
if (this.activeRecording) {
|
|
7645
|
+
this.activeRecording.stopRecording();
|
|
7646
|
+
this.activeRecording = null;
|
|
7579
7647
|
}
|
|
7580
7648
|
};
|
|
7581
7649
|
|
|
7650
|
+
MixpanelRecorder.prototype.resetRecording = function () {
|
|
7651
|
+
this.stopRecording();
|
|
7652
|
+
this.startRecording(true);
|
|
7653
|
+
};
|
|
7654
|
+
|
|
7655
|
+
MixpanelRecorder.prototype.getActiveReplayId = function () {
|
|
7656
|
+
if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
|
|
7657
|
+
return this.activeRecording.replayId;
|
|
7658
|
+
} else {
|
|
7659
|
+
return null;
|
|
7660
|
+
}
|
|
7661
|
+
};
|
|
7662
|
+
|
|
7663
|
+
// getter so that older mixpanel-core versions can still retrieve the replay ID
|
|
7664
|
+
// when pulling the latest recorder bundle from the CDN
|
|
7665
|
+
Object.defineProperty(MixpanelRecorder.prototype, 'replayId', {
|
|
7666
|
+
get: function () {
|
|
7667
|
+
return this.getActiveReplayId();
|
|
7668
|
+
}
|
|
7669
|
+
});
|
|
7582
7670
|
|
|
7583
7671
|
win['__mp_recorder'] = MixpanelRecorder;
|
|
7584
7672
|
|
|
@@ -9045,7 +9133,6 @@ var DEFAULT_CONFIG = {
|
|
|
9045
9133
|
'record_block_selector': 'img, video',
|
|
9046
9134
|
'record_collect_fonts': false,
|
|
9047
9135
|
'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
|
|
9048
|
-
'record_inline_images': false,
|
|
9049
9136
|
'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
|
|
9050
9137
|
'record_mask_text_selector': '*',
|
|
9051
9138
|
'record_max_ms': MAX_RECORDING_MS,
|
|
@@ -9298,15 +9385,35 @@ MixpanelLib.prototype.stop_session_recording = function () {
|
|
|
9298
9385
|
|
|
9299
9386
|
MixpanelLib.prototype.get_session_recording_properties = function () {
|
|
9300
9387
|
var props = {};
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
props['$mp_replay_id'] = replay_id;
|
|
9305
|
-
}
|
|
9388
|
+
var replay_id = this._get_session_replay_id();
|
|
9389
|
+
if (replay_id) {
|
|
9390
|
+
props['$mp_replay_id'] = replay_id;
|
|
9306
9391
|
}
|
|
9307
9392
|
return props;
|
|
9308
9393
|
};
|
|
9309
9394
|
|
|
9395
|
+
MixpanelLib.prototype.get_session_replay_url = function () {
|
|
9396
|
+
var replay_url = null;
|
|
9397
|
+
var replay_id = this._get_session_replay_id();
|
|
9398
|
+
if (replay_id) {
|
|
9399
|
+
var query_params = _.HTTPBuildQuery({
|
|
9400
|
+
'replay_id': replay_id,
|
|
9401
|
+
'distinct_id': this.get_distinct_id(),
|
|
9402
|
+
'token': this.get_config('token')
|
|
9403
|
+
});
|
|
9404
|
+
replay_url = 'https://mixpanel.com/projects/replay-redirect?' + query_params;
|
|
9405
|
+
}
|
|
9406
|
+
return replay_url;
|
|
9407
|
+
};
|
|
9408
|
+
|
|
9409
|
+
MixpanelLib.prototype._get_session_replay_id = function () {
|
|
9410
|
+
var replay_id = null;
|
|
9411
|
+
if (this._recorder) {
|
|
9412
|
+
replay_id = this._recorder['replayId'];
|
|
9413
|
+
}
|
|
9414
|
+
return replay_id || null;
|
|
9415
|
+
};
|
|
9416
|
+
|
|
9310
9417
|
// Private methods
|
|
9311
9418
|
|
|
9312
9419
|
MixpanelLib.prototype._loaded = function() {
|
|
@@ -11033,6 +11140,7 @@ MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.protot
|
|
|
11033
11140
|
MixpanelLib.prototype['start_session_recording'] = MixpanelLib.prototype.start_session_recording;
|
|
11034
11141
|
MixpanelLib.prototype['stop_session_recording'] = MixpanelLib.prototype.stop_session_recording;
|
|
11035
11142
|
MixpanelLib.prototype['get_session_recording_properties'] = MixpanelLib.prototype.get_session_recording_properties;
|
|
11143
|
+
MixpanelLib.prototype['get_session_replay_url'] = MixpanelLib.prototype.get_session_replay_url;
|
|
11036
11144
|
MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES;
|
|
11037
11145
|
|
|
11038
11146
|
// MixpanelPersistence Exports
|
package/dist/mixpanel.globals.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var Config = {
|
|
5
5
|
DEBUG: false,
|
|
6
|
-
LIB_VERSION: '2.
|
|
6
|
+
LIB_VERSION: '2.56.0'
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -2057,11 +2057,13 @@
|
|
|
2057
2057
|
var RequestQueue = function(storageKey, options) {
|
|
2058
2058
|
options = options || {};
|
|
2059
2059
|
this.storageKey = storageKey;
|
|
2060
|
-
this.
|
|
2060
|
+
this.usePersistence = options.usePersistence;
|
|
2061
|
+
if (this.usePersistence) {
|
|
2062
|
+
this.storage = options.storage || window.localStorage;
|
|
2063
|
+
this.lock = new SharedLock(storageKey, {storage: this.storage});
|
|
2064
|
+
}
|
|
2061
2065
|
this.reportError = options.errorReporter || _.bind(logger$1.error, logger$1);
|
|
2062
|
-
this.lock = new SharedLock(storageKey, {storage: this.storage});
|
|
2063
2066
|
|
|
2064
|
-
this.usePersistence = options.usePersistence;
|
|
2065
2067
|
this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
|
|
2066
2068
|
|
|
2067
2069
|
this.memQueue = [];
|
|
@@ -4258,7 +4260,6 @@
|
|
|
4258
4260
|
'record_block_selector': 'img, video',
|
|
4259
4261
|
'record_collect_fonts': false,
|
|
4260
4262
|
'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
|
|
4261
|
-
'record_inline_images': false,
|
|
4262
4263
|
'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
|
|
4263
4264
|
'record_mask_text_selector': '*',
|
|
4264
4265
|
'record_max_ms': MAX_RECORDING_MS,
|
|
@@ -4511,15 +4512,35 @@
|
|
|
4511
4512
|
|
|
4512
4513
|
MixpanelLib.prototype.get_session_recording_properties = function () {
|
|
4513
4514
|
var props = {};
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
props['$mp_replay_id'] = replay_id;
|
|
4518
|
-
}
|
|
4515
|
+
var replay_id = this._get_session_replay_id();
|
|
4516
|
+
if (replay_id) {
|
|
4517
|
+
props['$mp_replay_id'] = replay_id;
|
|
4519
4518
|
}
|
|
4520
4519
|
return props;
|
|
4521
4520
|
};
|
|
4522
4521
|
|
|
4522
|
+
MixpanelLib.prototype.get_session_replay_url = function () {
|
|
4523
|
+
var replay_url = null;
|
|
4524
|
+
var replay_id = this._get_session_replay_id();
|
|
4525
|
+
if (replay_id) {
|
|
4526
|
+
var query_params = _.HTTPBuildQuery({
|
|
4527
|
+
'replay_id': replay_id,
|
|
4528
|
+
'distinct_id': this.get_distinct_id(),
|
|
4529
|
+
'token': this.get_config('token')
|
|
4530
|
+
});
|
|
4531
|
+
replay_url = 'https://mixpanel.com/projects/replay-redirect?' + query_params;
|
|
4532
|
+
}
|
|
4533
|
+
return replay_url;
|
|
4534
|
+
};
|
|
4535
|
+
|
|
4536
|
+
MixpanelLib.prototype._get_session_replay_id = function () {
|
|
4537
|
+
var replay_id = null;
|
|
4538
|
+
if (this._recorder) {
|
|
4539
|
+
replay_id = this._recorder['replayId'];
|
|
4540
|
+
}
|
|
4541
|
+
return replay_id || null;
|
|
4542
|
+
};
|
|
4543
|
+
|
|
4523
4544
|
// Private methods
|
|
4524
4545
|
|
|
4525
4546
|
MixpanelLib.prototype._loaded = function() {
|
|
@@ -6246,6 +6267,7 @@
|
|
|
6246
6267
|
MixpanelLib.prototype['start_session_recording'] = MixpanelLib.prototype.start_session_recording;
|
|
6247
6268
|
MixpanelLib.prototype['stop_session_recording'] = MixpanelLib.prototype.stop_session_recording;
|
|
6248
6269
|
MixpanelLib.prototype['get_session_recording_properties'] = MixpanelLib.prototype.get_session_recording_properties;
|
|
6270
|
+
MixpanelLib.prototype['get_session_replay_url'] = MixpanelLib.prototype.get_session_replay_url;
|
|
6249
6271
|
MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES;
|
|
6250
6272
|
|
|
6251
6273
|
// MixpanelPersistence Exports
|