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.
@@ -4513,7 +4513,7 @@
4513
4513
 
4514
4514
  var Config = {
4515
4515
  DEBUG: false,
4516
- LIB_VERSION: '2.55.1'
4516
+ LIB_VERSION: '2.56.0'
4517
4517
  };
4518
4518
 
4519
4519
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -6550,7 +6550,7 @@
6550
6550
  };
6551
6551
  }
6552
6552
 
6553
- var logger$3 = console_with_prefix('lock');
6553
+ var logger$4 = console_with_prefix('lock');
6554
6554
 
6555
6555
  /**
6556
6556
  * SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
@@ -6607,7 +6607,7 @@
6607
6607
 
6608
6608
  var delay = function(cb) {
6609
6609
  if (new Date().getTime() - startTime > timeoutMS) {
6610
- logger$3.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
6610
+ logger$4.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
6611
6611
  storage.removeItem(keyZ);
6612
6612
  storage.removeItem(keyY);
6613
6613
  loop();
@@ -6696,7 +6696,7 @@
6696
6696
  }
6697
6697
  };
6698
6698
 
6699
- var logger$2 = console_with_prefix('batch');
6699
+ var logger$3 = console_with_prefix('batch');
6700
6700
 
6701
6701
  /**
6702
6702
  * RequestQueue: queue for batching API requests with localStorage backup for retries.
@@ -6717,11 +6717,13 @@
6717
6717
  var RequestQueue = function(storageKey, options) {
6718
6718
  options = options || {};
6719
6719
  this.storageKey = storageKey;
6720
- this.storage = options.storage || window.localStorage;
6721
- this.reportError = options.errorReporter || _.bind(logger$2.error, logger$2);
6722
- this.lock = new SharedLock(storageKey, {storage: this.storage});
6723
-
6724
6720
  this.usePersistence = options.usePersistence;
6721
+ if (this.usePersistence) {
6722
+ this.storage = options.storage || window.localStorage;
6723
+ this.lock = new SharedLock(storageKey, {storage: this.storage});
6724
+ }
6725
+ this.reportError = options.errorReporter || _.bind(logger$3.error, logger$3);
6726
+
6725
6727
  this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
6726
6728
 
6727
6729
  this.memQueue = [];
@@ -7000,7 +7002,7 @@
7000
7002
  // maximum interval between request retries after exponential backoff
7001
7003
  var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
7002
7004
 
7003
- var logger$1 = console_with_prefix('batch');
7005
+ var logger$2 = console_with_prefix('batch');
7004
7006
 
7005
7007
  /**
7006
7008
  * RequestBatcher: manages the queueing, flushing, retry etc of requests of one
@@ -7114,7 +7116,7 @@
7114
7116
  try {
7115
7117
 
7116
7118
  if (this.requestInProgress) {
7117
- logger$1.log('Flush: Request already in progress');
7119
+ logger$2.log('Flush: Request already in progress');
7118
7120
  return;
7119
7121
  }
7120
7122
 
@@ -7282,7 +7284,7 @@
7282
7284
  if (options.unloading) {
7283
7285
  requestOptions.transport = 'sendBeacon';
7284
7286
  }
7285
- logger$1.log('MIXPANEL REQUEST:', dataForRequest);
7287
+ logger$2.log('MIXPANEL REQUEST:', dataForRequest);
7286
7288
  this.sendRequest(dataForRequest, requestOptions, batchSendCallback);
7287
7289
  } catch(err) {
7288
7290
  this.reportError('Error flushing request queue', err);
@@ -7294,7 +7296,7 @@
7294
7296
  * Log error to global logger and optional user-defined logger.
7295
7297
  */
7296
7298
  RequestBatcher.prototype.reportError = function(msg, err) {
7297
- logger$1.error.apply(logger$1.error, arguments);
7299
+ logger$2.error.apply(logger$2.error, arguments);
7298
7300
  if (this.errorReporter) {
7299
7301
  try {
7300
7302
  if (!(err instanceof Error)) {
@@ -7302,12 +7304,12 @@
7302
7304
  }
7303
7305
  this.errorReporter(msg, err);
7304
7306
  } catch(err) {
7305
- logger$1.error(err);
7307
+ logger$2.error(err);
7306
7308
  }
7307
7309
  }
7308
7310
  };
7309
7311
 
7310
- var logger = console_with_prefix('recorder');
7312
+ var logger$1 = console_with_prefix('recorder');
7311
7313
  var CompressionStream = win['CompressionStream'];
7312
7314
 
7313
7315
  var RECORDER_BATCHER_LIB_CONFIG = {
@@ -7333,65 +7335,78 @@
7333
7335
  return ev.type === EventType.IncrementalSnapshot && ACTIVE_SOURCES.has(ev.data.source);
7334
7336
  }
7335
7337
 
7336
- var MixpanelRecorder = function(mixpanelInstance) {
7337
- this._mixpanel = mixpanelInstance;
7338
+ /**
7339
+ * This class encapsulates a single session recording and its lifecycle.
7340
+ * @param {Object} [options.mixpanelInstance] - reference to the core MixpanelLib
7341
+ * @param {String} [options.replayId] - unique uuid for a single replay
7342
+ * @param {Function} [options.onIdleTimeout] - callback when a recording reaches idle timeout
7343
+ * @param {Function} [options.onMaxLengthReached] - callback when a recording reaches its maximum length
7344
+ * @param {Function} [options.rrwebRecord] - rrweb's `record` function
7345
+ */
7346
+ var SessionRecording = function(options) {
7347
+ this._mixpanel = options.mixpanelInstance;
7348
+ this._onIdleTimeout = options.onIdleTimeout;
7349
+ this._onMaxLengthReached = options.onMaxLengthReached;
7350
+ this._rrwebRecord = options.rrwebRecord;
7351
+
7352
+ this.replayId = options.replayId;
7338
7353
 
7339
7354
  // internal rrweb stopRecording function
7340
7355
  this._stopRecording = null;
7341
7356
 
7342
- this.recEvents = [];
7343
7357
  this.seqNo = 0;
7344
- this.replayId = null;
7345
7358
  this.replayStartTime = null;
7346
- this.sendBatchId = null;
7359
+ this.batchStartUrl = null;
7347
7360
 
7348
7361
  this.idleTimeoutId = null;
7349
7362
  this.maxTimeoutId = null;
7350
7363
 
7351
7364
  this.recordMaxMs = MAX_RECORDING_MS;
7352
7365
  this.recordMinMs = 0;
7353
- this._initBatcher();
7354
- };
7355
7366
 
7356
-
7357
- MixpanelRecorder.prototype._initBatcher = function () {
7358
- this.batcher = new RequestBatcher('__mprec', {
7359
- libConfig: RECORDER_BATCHER_LIB_CONFIG,
7360
- sendRequestFunc: _.bind(this.flushEventsWithOptOut, this),
7367
+ // each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
7368
+ // this will be important when persistence is introduced
7369
+ var batcherKey = '__mprec_' + this.getConfig('token') + '_' + this.replayId;
7370
+ this.batcher = new RequestBatcher(batcherKey, {
7361
7371
  errorReporter: _.bind(this.reportError, this),
7362
7372
  flushOnlyOnInterval: true,
7373
+ libConfig: RECORDER_BATCHER_LIB_CONFIG,
7374
+ sendRequestFunc: _.bind(this.flushEventsWithOptOut, this),
7363
7375
  usePersistence: false
7364
7376
  });
7365
7377
  };
7366
7378
 
7367
- // eslint-disable-next-line camelcase
7368
- MixpanelRecorder.prototype.get_config = function(configVar) {
7379
+ SessionRecording.prototype.getConfig = function(configVar) {
7369
7380
  return this._mixpanel.get_config(configVar);
7370
7381
  };
7371
7382
 
7372
- MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
7383
+ // Alias for getConfig, used by the common addOptOutCheckMixpanelLib function which
7384
+ // reaches into this class instance and expects the snake case version of the function.
7385
+ // eslint-disable-next-line camelcase
7386
+ SessionRecording.prototype.get_config = function(configVar) {
7387
+ return this.getConfig(configVar);
7388
+ };
7389
+
7390
+ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
7373
7391
  if (this._stopRecording !== null) {
7374
- logger.log('Recording already in progress, skipping startRecording.');
7392
+ logger$1.log('Recording already in progress, skipping startRecording.');
7375
7393
  return;
7376
7394
  }
7377
7395
 
7378
- this.recordMaxMs = this.get_config('record_max_ms');
7396
+ this.recordMaxMs = this.getConfig('record_max_ms');
7379
7397
  if (this.recordMaxMs > MAX_RECORDING_MS) {
7380
7398
  this.recordMaxMs = MAX_RECORDING_MS;
7381
- logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
7399
+ logger$1.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
7382
7400
  }
7383
7401
 
7384
- this.recordMinMs = this.get_config('record_min_ms');
7402
+ this.recordMinMs = this.getConfig('record_min_ms');
7385
7403
  if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) {
7386
7404
  this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS;
7387
- logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
7405
+ logger$1.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
7388
7406
  }
7389
7407
 
7390
- this.recEvents = [];
7391
- this.seqNo = 0;
7392
7408
  this.replayStartTime = new Date().getTime();
7393
-
7394
- this.replayId = _.UUID();
7409
+ this.batchStartUrl = _.info.currentUrl();
7395
7410
 
7396
7411
  if (shouldStopBatcher || this.recordMinMs > 0) {
7397
7412
  // the primary case for shouldStopBatcher is when we're starting recording after a reset
@@ -7406,18 +7421,15 @@
7406
7421
 
7407
7422
  var resetIdleTimeout = _.bind(function () {
7408
7423
  clearTimeout(this.idleTimeoutId);
7409
- this.idleTimeoutId = setTimeout(_.bind(function () {
7410
- logger.log('Idle timeout reached, restarting recording.');
7411
- this.resetRecording();
7412
- }, this), this.get_config('record_idle_timeout_ms'));
7424
+ this.idleTimeoutId = setTimeout(this._onIdleTimeout, this.getConfig('record_idle_timeout_ms'));
7413
7425
  }, this);
7414
7426
 
7415
- var blockSelector = this.get_config('record_block_selector');
7427
+ var blockSelector = this.getConfig('record_block_selector');
7416
7428
  if (blockSelector === '' || blockSelector === null) {
7417
7429
  blockSelector = undefined;
7418
7430
  }
7419
7431
 
7420
- this._stopRecording = record({
7432
+ this._stopRecording = this._rrwebRecord({
7421
7433
  'emit': _.bind(function (ev) {
7422
7434
  this.batcher.enqueue(ev);
7423
7435
  if (isUserEvent(ev)) {
@@ -7428,28 +7440,33 @@
7428
7440
  resetIdleTimeout();
7429
7441
  }
7430
7442
  }, this),
7431
- 'blockClass': this.get_config('record_block_class'),
7443
+ 'blockClass': this.getConfig('record_block_class'),
7432
7444
  'blockSelector': blockSelector,
7433
- 'collectFonts': this.get_config('record_collect_fonts'),
7434
- 'inlineImages': this.get_config('record_inline_images'),
7445
+ 'collectFonts': this.getConfig('record_collect_fonts'),
7435
7446
  'maskAllInputs': true,
7436
- 'maskTextClass': this.get_config('record_mask_text_class'),
7437
- 'maskTextSelector': this.get_config('record_mask_text_selector')
7447
+ 'maskTextClass': this.getConfig('record_mask_text_class'),
7448
+ 'maskTextSelector': this.getConfig('record_mask_text_selector')
7438
7449
  });
7439
7450
 
7440
- resetIdleTimeout();
7451
+ if (typeof this._stopRecording !== 'function') {
7452
+ this.reportError('rrweb failed to start, skipping this recording.');
7453
+ this._stopRecording = null;
7454
+ this.stopRecording(); // stop batcher looping and any timeouts
7455
+ return;
7456
+ }
7441
7457
 
7442
- this.maxTimeoutId = setTimeout(_.bind(this.resetRecording, this), this.recordMaxMs);
7443
- };
7458
+ resetIdleTimeout();
7444
7459
 
7445
- MixpanelRecorder.prototype.resetRecording = function () {
7446
- this.stopRecording();
7447
- this.startRecording(true);
7460
+ this.maxTimeoutId = setTimeout(_.bind(this._onMaxLengthReached, this), this.recordMaxMs);
7448
7461
  };
7449
7462
 
7450
- MixpanelRecorder.prototype.stopRecording = function () {
7451
- if (this._stopRecording !== null) {
7452
- this._stopRecording();
7463
+ SessionRecording.prototype.stopRecording = function () {
7464
+ if (!this.isRrwebStopped()) {
7465
+ try {
7466
+ this._stopRecording();
7467
+ } catch (err) {
7468
+ this.reportError('Error with rrweb stopRecording', err);
7469
+ }
7453
7470
  this._stopRecording = null;
7454
7471
  }
7455
7472
 
@@ -7461,35 +7478,38 @@
7461
7478
  this.batcher.flush();
7462
7479
  this.batcher.stop();
7463
7480
  }
7464
- this.replayId = null;
7465
7481
 
7466
7482
  clearTimeout(this.idleTimeoutId);
7467
7483
  clearTimeout(this.maxTimeoutId);
7468
7484
  };
7469
7485
 
7486
+ SessionRecording.prototype.isRrwebStopped = function () {
7487
+ return this._stopRecording === null;
7488
+ };
7489
+
7470
7490
  /**
7471
7491
  * Flushes the current batch of events to the server, but passes an opt-out callback to make sure
7472
7492
  * we stop recording and dump any queued events if the user has opted out.
7473
7493
  */
7474
- MixpanelRecorder.prototype.flushEventsWithOptOut = function (data, options, cb) {
7494
+ SessionRecording.prototype.flushEventsWithOptOut = function (data, options, cb) {
7475
7495
  this._flushEvents(data, options, cb, _.bind(this._onOptOut, this));
7476
7496
  };
7477
7497
 
7478
- MixpanelRecorder.prototype._onOptOut = function (code) {
7498
+ SessionRecording.prototype._onOptOut = function (code) {
7479
7499
  // addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
7480
7500
  if (code === 0) {
7481
- this.recEvents = [];
7482
7501
  this.stopRecording();
7483
7502
  }
7484
7503
  };
7485
7504
 
7486
- MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
7505
+ SessionRecording.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
7487
7506
  var onSuccess = _.bind(function (response, responseBody) {
7488
- // Increment sequence counter only if the request was successful to guarantee ordering.
7507
+ // Update batch specific props only if the request was successful to guarantee ordering.
7489
7508
  // RequestBatcher will always flush the next batch after the previous one succeeds.
7490
7509
  // extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay
7491
7510
  if (response.status === 200 && this.replayId === currentReplayId) {
7492
7511
  this.seqNo++;
7512
+ this.batchStartUrl = _.info.currentUrl();
7493
7513
  }
7494
7514
  callback({
7495
7515
  status: 0,
@@ -7499,10 +7519,10 @@
7499
7519
  });
7500
7520
  }, this);
7501
7521
 
7502
- win['fetch'](this.get_config('api_host') + '/' + this.get_config('api_routes')['record'] + '?' + new URLSearchParams(reqParams), {
7522
+ win['fetch'](this.getConfig('api_host') + '/' + this.getConfig('api_routes')['record'] + '?' + new URLSearchParams(reqParams), {
7503
7523
  'method': 'POST',
7504
7524
  'headers': {
7505
- 'Authorization': 'Basic ' + btoa(this.get_config('token') + ':'),
7525
+ 'Authorization': 'Basic ' + btoa(this.getConfig('token') + ':'),
7506
7526
  'Content-Type': 'application/octet-stream'
7507
7527
  },
7508
7528
  'body': reqBody,
@@ -7517,7 +7537,7 @@
7517
7537
  });
7518
7538
  };
7519
7539
 
7520
- MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (data, options, callback) {
7540
+ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (data, options, callback) {
7521
7541
  const numEvents = data.length;
7522
7542
 
7523
7543
  if (numEvents > 0) {
@@ -7535,12 +7555,15 @@
7535
7555
  var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime;
7536
7556
 
7537
7557
  var reqParams = {
7538
- 'distinct_id': String(this._mixpanel.get_distinct_id()),
7539
- 'seq': this.seqNo,
7558
+ '$current_url': this.batchStartUrl,
7559
+ '$lib_version': Config.LIB_VERSION,
7540
7560
  'batch_start_time': batchStartTime / 1000,
7561
+ 'distinct_id': String(this._mixpanel.get_distinct_id()),
7562
+ 'mp_lib': 'web',
7541
7563
  'replay_id': replayId,
7542
7564
  'replay_length_ms': replayLengthMs,
7543
- 'replay_start_time': this.replayStartTime / 1000
7565
+ 'replay_start_time': this.replayStartTime / 1000,
7566
+ 'seq': this.seqNo
7544
7567
  };
7545
7568
  var eventsJson = _.JSONEncode(data);
7546
7569
 
@@ -7571,18 +7594,83 @@
7571
7594
  });
7572
7595
 
7573
7596
 
7574
- MixpanelRecorder.prototype.reportError = function(msg, err) {
7575
- logger.error.apply(logger.error, arguments);
7597
+ SessionRecording.prototype.reportError = function(msg, err) {
7598
+ logger$1.error.apply(logger$1.error, arguments);
7576
7599
  try {
7577
7600
  if (!err && !(msg instanceof Error)) {
7578
7601
  msg = new Error(msg);
7579
7602
  }
7580
- this.get_config('error_reporter')(msg, err);
7603
+ this.getConfig('error_reporter')(msg, err);
7581
7604
  } catch(err) {
7582
- logger.error(err);
7605
+ logger$1.error(err);
7606
+ }
7607
+ };
7608
+
7609
+ var logger = console_with_prefix('recorder');
7610
+
7611
+ /**
7612
+ * Recorder API: manages recordings and exposes methods public to the core Mixpanel library.
7613
+ * @param {Object} [options.mixpanelInstance] - reference to the core MixpanelLib
7614
+ */
7615
+ var MixpanelRecorder = function(mixpanelInstance) {
7616
+ this._mixpanel = mixpanelInstance;
7617
+ this.activeRecording = null;
7618
+ };
7619
+
7620
+ MixpanelRecorder.prototype.startRecording = function(shouldStopBatcher) {
7621
+ if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
7622
+ logger.log('Recording already in progress, skipping startRecording.');
7623
+ return;
7624
+ }
7625
+
7626
+ var onIdleTimeout = _.bind(function () {
7627
+ logger.log('Idle timeout reached, restarting recording.');
7628
+ this.resetRecording();
7629
+ }, this);
7630
+
7631
+ var onMaxLengthReached = _.bind(function () {
7632
+ logger.log('Max recording length reached, stopping recording.');
7633
+ this.resetRecording();
7634
+ }, this);
7635
+
7636
+ this.activeRecording = new SessionRecording({
7637
+ mixpanelInstance: this._mixpanel,
7638
+ onIdleTimeout: onIdleTimeout,
7639
+ onMaxLengthReached: onMaxLengthReached,
7640
+ replayId: _.UUID(),
7641
+ rrwebRecord: record
7642
+ });
7643
+
7644
+ this.activeRecording.startRecording(shouldStopBatcher);
7645
+ };
7646
+
7647
+ MixpanelRecorder.prototype.stopRecording = function() {
7648
+ if (this.activeRecording) {
7649
+ this.activeRecording.stopRecording();
7650
+ this.activeRecording = null;
7583
7651
  }
7584
7652
  };
7585
7653
 
7654
+ MixpanelRecorder.prototype.resetRecording = function () {
7655
+ this.stopRecording();
7656
+ this.startRecording(true);
7657
+ };
7658
+
7659
+ MixpanelRecorder.prototype.getActiveReplayId = function () {
7660
+ if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
7661
+ return this.activeRecording.replayId;
7662
+ } else {
7663
+ return null;
7664
+ }
7665
+ };
7666
+
7667
+ // getter so that older mixpanel-core versions can still retrieve the replay ID
7668
+ // when pulling the latest recorder bundle from the CDN
7669
+ Object.defineProperty(MixpanelRecorder.prototype, 'replayId', {
7670
+ get: function () {
7671
+ return this.getActiveReplayId();
7672
+ }
7673
+ });
7586
7674
 
7587
7675
  win['__mp_recorder'] = MixpanelRecorder;
7588
7676
 
@@ -9049,7 +9137,6 @@
9049
9137
  'record_block_selector': 'img, video',
9050
9138
  'record_collect_fonts': false,
9051
9139
  'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
9052
- 'record_inline_images': false,
9053
9140
  'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
9054
9141
  'record_mask_text_selector': '*',
9055
9142
  'record_max_ms': MAX_RECORDING_MS,
@@ -9302,15 +9389,35 @@
9302
9389
 
9303
9390
  MixpanelLib.prototype.get_session_recording_properties = function () {
9304
9391
  var props = {};
9305
- if (this._recorder) {
9306
- var replay_id = this._recorder['replayId'];
9307
- if (replay_id) {
9308
- props['$mp_replay_id'] = replay_id;
9309
- }
9392
+ var replay_id = this._get_session_replay_id();
9393
+ if (replay_id) {
9394
+ props['$mp_replay_id'] = replay_id;
9310
9395
  }
9311
9396
  return props;
9312
9397
  };
9313
9398
 
9399
+ MixpanelLib.prototype.get_session_replay_url = function () {
9400
+ var replay_url = null;
9401
+ var replay_id = this._get_session_replay_id();
9402
+ if (replay_id) {
9403
+ var query_params = _.HTTPBuildQuery({
9404
+ 'replay_id': replay_id,
9405
+ 'distinct_id': this.get_distinct_id(),
9406
+ 'token': this.get_config('token')
9407
+ });
9408
+ replay_url = 'https://mixpanel.com/projects/replay-redirect?' + query_params;
9409
+ }
9410
+ return replay_url;
9411
+ };
9412
+
9413
+ MixpanelLib.prototype._get_session_replay_id = function () {
9414
+ var replay_id = null;
9415
+ if (this._recorder) {
9416
+ replay_id = this._recorder['replayId'];
9417
+ }
9418
+ return replay_id || null;
9419
+ };
9420
+
9314
9421
  // Private methods
9315
9422
 
9316
9423
  MixpanelLib.prototype._loaded = function() {
@@ -11037,6 +11144,7 @@
11037
11144
  MixpanelLib.prototype['start_session_recording'] = MixpanelLib.prototype.start_session_recording;
11038
11145
  MixpanelLib.prototype['stop_session_recording'] = MixpanelLib.prototype.stop_session_recording;
11039
11146
  MixpanelLib.prototype['get_session_recording_properties'] = MixpanelLib.prototype.get_session_recording_properties;
11147
+ MixpanelLib.prototype['get_session_replay_url'] = MixpanelLib.prototype.get_session_replay_url;
11040
11148
  MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES;
11041
11149
 
11042
11150
  // MixpanelPersistence Exports
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixpanel-browser",
3
- "version": "2.55.1",
3
+ "version": "2.56.0",
4
4
  "description": "The official Mixpanel JavaScript browser client library",
5
5
  "main": "dist/mixpanel.cjs.js",
6
6
  "module": "dist/mixpanel.module.js",
package/src/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  var Config = {
2
2
  DEBUG: false,
3
- LIB_VERSION: '2.55.1'
3
+ LIB_VERSION: '2.56.0'
4
4
  };
5
5
 
6
6
  export default Config;
@@ -148,7 +148,6 @@ var DEFAULT_CONFIG = {
148
148
  'record_block_selector': 'img, video',
149
149
  'record_collect_fonts': false,
150
150
  'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
151
- 'record_inline_images': false,
152
151
  'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
153
152
  'record_mask_text_selector': '*',
154
153
  'record_max_ms': MAX_RECORDING_MS,
@@ -401,15 +400,35 @@ MixpanelLib.prototype.stop_session_recording = function () {
401
400
 
402
401
  MixpanelLib.prototype.get_session_recording_properties = function () {
403
402
  var props = {};
404
- if (this._recorder) {
405
- var replay_id = this._recorder['replayId'];
406
- if (replay_id) {
407
- props['$mp_replay_id'] = replay_id;
408
- }
403
+ var replay_id = this._get_session_replay_id();
404
+ if (replay_id) {
405
+ props['$mp_replay_id'] = replay_id;
409
406
  }
410
407
  return props;
411
408
  };
412
409
 
410
+ MixpanelLib.prototype.get_session_replay_url = function () {
411
+ var replay_url = null;
412
+ var replay_id = this._get_session_replay_id();
413
+ if (replay_id) {
414
+ var query_params = _.HTTPBuildQuery({
415
+ 'replay_id': replay_id,
416
+ 'distinct_id': this.get_distinct_id(),
417
+ 'token': this.get_config('token')
418
+ });
419
+ replay_url = 'https://mixpanel.com/projects/replay-redirect?' + query_params;
420
+ }
421
+ return replay_url;
422
+ };
423
+
424
+ MixpanelLib.prototype._get_session_replay_id = function () {
425
+ var replay_id = null;
426
+ if (this._recorder) {
427
+ replay_id = this._recorder['replayId'];
428
+ }
429
+ return replay_id || null;
430
+ };
431
+
413
432
  // Private methods
414
433
 
415
434
  MixpanelLib.prototype._loaded = function() {
@@ -2136,6 +2155,7 @@ MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.protot
2136
2155
  MixpanelLib.prototype['start_session_recording'] = MixpanelLib.prototype.start_session_recording;
2137
2156
  MixpanelLib.prototype['stop_session_recording'] = MixpanelLib.prototype.stop_session_recording;
2138
2157
  MixpanelLib.prototype['get_session_recording_properties'] = MixpanelLib.prototype.get_session_recording_properties;
2158
+ MixpanelLib.prototype['get_session_replay_url'] = MixpanelLib.prototype.get_session_replay_url;
2139
2159
  MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES;
2140
2160
 
2141
2161
  // MixpanelPersistence Exports