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