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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  var Config = {
4
4
  DEBUG: false,
5
- LIB_VERSION: '2.61.0'
5
+ LIB_VERSION: '2.61.2'
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);
@@ -6506,7 +6506,6 @@ MixpanelLib.prototype.init_batchers = function() {
6506
6506
  }, this),
6507
6507
  stopAllBatchingFunc: _.bind(this.stop_batch_senders, this),
6508
6508
  usePersistence: true,
6509
- enqueueThrottleMs: 10,
6510
6509
  }
6511
6510
  );
6512
6511
  }, this);
@@ -4893,7 +4893,7 @@ define((function () { 'use strict';
4893
4893
 
4894
4894
  var Config = {
4895
4895
  DEBUG: false,
4896
- LIB_VERSION: '2.61.0'
4896
+ LIB_VERSION: '2.61.2'
4897
4897
  };
4898
4898
 
4899
4899
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -6756,7 +6756,7 @@ define((function () { 'use strict';
6756
6756
  return this.dbPromise
6757
6757
  .then(doTransaction)
6758
6758
  .catch(function (err) {
6759
- if (err['name'] === 'InvalidStateError') {
6759
+ if (err && err['name'] === 'InvalidStateError') {
6760
6760
  // try reopening the DB if the connection is closed
6761
6761
  this.dbPromise = this._openDb();
6762
6762
  return this.dbPromise.then(doTransaction);
@@ -8180,34 +8180,37 @@ define((function () { 'use strict';
8180
8180
  blockSelector = undefined;
8181
8181
  }
8182
8182
 
8183
- this._stopRecording = this._rrwebRecord({
8184
- 'emit': addOptOutCheckMixpanelLib(function (ev) {
8185
- if (isUserEvent(ev)) {
8186
- if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
8187
- // start flushing again after user activity
8188
- this.batcher.start();
8183
+ try {
8184
+ this._stopRecording = this._rrwebRecord({
8185
+ 'emit': function (ev) {
8186
+ if (isUserEvent(ev)) {
8187
+ if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
8188
+ // start flushing again after user activity
8189
+ this.batcher.start();
8190
+ }
8191
+ resetIdleTimeout();
8189
8192
  }
8190
- resetIdleTimeout();
8193
+ // promise only used to await during tests
8194
+ this.__enqueuePromise = this.batcher.enqueue(ev);
8195
+ }.bind(this),
8196
+ 'blockClass': this.getConfig('record_block_class'),
8197
+ 'blockSelector': blockSelector,
8198
+ 'collectFonts': this.getConfig('record_collect_fonts'),
8199
+ 'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
8200
+ 'type': 'image/webp',
8201
+ 'quality': 0.6
8202
+ },
8203
+ 'maskAllInputs': true,
8204
+ 'maskTextClass': this.getConfig('record_mask_text_class'),
8205
+ 'maskTextSelector': this.getConfig('record_mask_text_selector'),
8206
+ 'recordCanvas': this.getConfig('record_canvas'),
8207
+ 'sampling': {
8208
+ 'canvas': 15
8191
8209
  }
8192
-
8193
- // promise only used to await during tests
8194
- this.__enqueuePromise = this.batcher.enqueue(ev);
8195
- }.bind(this)),
8196
- 'blockClass': this.getConfig('record_block_class'),
8197
- 'blockSelector': blockSelector,
8198
- 'collectFonts': this.getConfig('record_collect_fonts'),
8199
- 'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
8200
- 'type': 'image/webp',
8201
- 'quality': 0.6
8202
- },
8203
- 'maskAllInputs': true,
8204
- 'maskTextClass': this.getConfig('record_mask_text_class'),
8205
- 'maskTextSelector': this.getConfig('record_mask_text_selector'),
8206
- 'recordCanvas': this.getConfig('record_canvas'),
8207
- 'sampling': {
8208
- 'canvas': 15
8209
- }
8210
- });
8210
+ });
8211
+ } catch (err) {
8212
+ this.reportError('Unexpected error when starting rrweb recording.', err);
8213
+ }
8211
8214
 
8212
8215
  if (typeof this._stopRecording !== 'function') {
8213
8216
  this.reportError('rrweb failed to start, skipping this recording.');
@@ -8251,12 +8254,21 @@ define((function () { 'use strict';
8251
8254
  return this._stopRecording === null;
8252
8255
  };
8253
8256
 
8257
+
8254
8258
  /**
8255
8259
  * Flushes the current batch of events to the server, but passes an opt-out callback to make sure
8256
8260
  * we stop recording and dump any queued events if the user has opted out.
8257
8261
  */
8258
8262
  SessionRecording.prototype.flushEventsWithOptOut = function (data, options, cb) {
8259
- this._flushEvents(data, options, cb, this._onOptOut.bind(this));
8263
+ var onOptOut = function (code) {
8264
+ // addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
8265
+ if (code === 0) {
8266
+ this.stopRecording();
8267
+ cb({error: 'Tracking has been opted out, stopping recording.'});
8268
+ }
8269
+ }.bind(this);
8270
+
8271
+ this._flushEvents(data, options, cb, onOptOut);
8260
8272
  };
8261
8273
 
8262
8274
  /**
@@ -8306,13 +8318,6 @@ define((function () { 'use strict';
8306
8318
  return recording;
8307
8319
  };
8308
8320
 
8309
- SessionRecording.prototype._onOptOut = function (code) {
8310
- // addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
8311
- if (code === 0) {
8312
- this.stopRecording();
8313
- }
8314
- };
8315
-
8316
8321
  SessionRecording.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
8317
8322
  var onSuccess = function (response, responseBody) {
8318
8323
  // Update batch specific props only if the request was successful to guarantee ordering.
@@ -8355,17 +8360,32 @@ define((function () { 'use strict';
8355
8360
 
8356
8361
  if (numEvents > 0) {
8357
8362
  var replayId = this.replayId;
8363
+
8358
8364
  // each rrweb event has a timestamp - leverage those to get time properties
8359
- var batchStartTime = data[0].timestamp;
8360
- if (this.seqNo === 0 || !this.replayStartTime) {
8361
- // extra safety net so that we don't send a null replay start time
8362
- if (this.seqNo !== 0) {
8363
- this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
8365
+ var batchStartTime = Infinity;
8366
+ var batchEndTime = -Infinity;
8367
+ var hasFullSnapshot = false;
8368
+ for (var i = 0; i < numEvents; i++) {
8369
+ batchStartTime = Math.min(batchStartTime, data[i].timestamp);
8370
+ batchEndTime = Math.max(batchEndTime, data[i].timestamp);
8371
+ if (data[i].type === EventType.FullSnapshot) {
8372
+ hasFullSnapshot = true;
8364
8373
  }
8374
+ }
8365
8375
 
8376
+ if (this.seqNo === 0) {
8377
+ if (!hasFullSnapshot) {
8378
+ callback({error: 'First batch does not contain a full snapshot. Aborting recording.'});
8379
+ this.stopRecording(true);
8380
+ return;
8381
+ }
8382
+ this.replayStartTime = batchStartTime;
8383
+ } else if (!this.replayStartTime) {
8384
+ this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
8366
8385
  this.replayStartTime = batchStartTime;
8367
8386
  }
8368
- var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime;
8387
+
8388
+ var replayLengthMs = batchEndTime - this.replayStartTime;
8369
8389
 
8370
8390
  var reqParams = {
8371
8391
  '$current_url': this.batchStartUrl,
@@ -11665,7 +11685,6 @@ define((function () { 'use strict';
11665
11685
  }, this),
11666
11686
  stopAllBatchingFunc: _.bind(this.stop_batch_senders, this),
11667
11687
  usePersistence: true,
11668
- enqueueThrottleMs: 10,
11669
11688
  }
11670
11689
  );
11671
11690
  }, this);
@@ -4893,7 +4893,7 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {
4893
4893
 
4894
4894
  var Config = {
4895
4895
  DEBUG: false,
4896
- LIB_VERSION: '2.61.0'
4896
+ LIB_VERSION: '2.61.2'
4897
4897
  };
4898
4898
 
4899
4899
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -6756,7 +6756,7 @@ IDBStorageWrapper.prototype.makeTransaction = function (mode, storeCb) {
6756
6756
  return this.dbPromise
6757
6757
  .then(doTransaction)
6758
6758
  .catch(function (err) {
6759
- if (err['name'] === 'InvalidStateError') {
6759
+ if (err && err['name'] === 'InvalidStateError') {
6760
6760
  // try reopening the DB if the connection is closed
6761
6761
  this.dbPromise = this._openDb();
6762
6762
  return this.dbPromise.then(doTransaction);
@@ -8180,34 +8180,37 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
8180
8180
  blockSelector = undefined;
8181
8181
  }
8182
8182
 
8183
- this._stopRecording = this._rrwebRecord({
8184
- 'emit': addOptOutCheckMixpanelLib(function (ev) {
8185
- if (isUserEvent(ev)) {
8186
- if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
8187
- // start flushing again after user activity
8188
- this.batcher.start();
8183
+ try {
8184
+ this._stopRecording = this._rrwebRecord({
8185
+ 'emit': function (ev) {
8186
+ if (isUserEvent(ev)) {
8187
+ if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
8188
+ // start flushing again after user activity
8189
+ this.batcher.start();
8190
+ }
8191
+ resetIdleTimeout();
8189
8192
  }
8190
- resetIdleTimeout();
8193
+ // promise only used to await during tests
8194
+ this.__enqueuePromise = this.batcher.enqueue(ev);
8195
+ }.bind(this),
8196
+ 'blockClass': this.getConfig('record_block_class'),
8197
+ 'blockSelector': blockSelector,
8198
+ 'collectFonts': this.getConfig('record_collect_fonts'),
8199
+ 'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
8200
+ 'type': 'image/webp',
8201
+ 'quality': 0.6
8202
+ },
8203
+ 'maskAllInputs': true,
8204
+ 'maskTextClass': this.getConfig('record_mask_text_class'),
8205
+ 'maskTextSelector': this.getConfig('record_mask_text_selector'),
8206
+ 'recordCanvas': this.getConfig('record_canvas'),
8207
+ 'sampling': {
8208
+ 'canvas': 15
8191
8209
  }
8192
-
8193
- // promise only used to await during tests
8194
- this.__enqueuePromise = this.batcher.enqueue(ev);
8195
- }.bind(this)),
8196
- 'blockClass': this.getConfig('record_block_class'),
8197
- 'blockSelector': blockSelector,
8198
- 'collectFonts': this.getConfig('record_collect_fonts'),
8199
- 'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
8200
- 'type': 'image/webp',
8201
- 'quality': 0.6
8202
- },
8203
- 'maskAllInputs': true,
8204
- 'maskTextClass': this.getConfig('record_mask_text_class'),
8205
- 'maskTextSelector': this.getConfig('record_mask_text_selector'),
8206
- 'recordCanvas': this.getConfig('record_canvas'),
8207
- 'sampling': {
8208
- 'canvas': 15
8209
- }
8210
- });
8210
+ });
8211
+ } catch (err) {
8212
+ this.reportError('Unexpected error when starting rrweb recording.', err);
8213
+ }
8211
8214
 
8212
8215
  if (typeof this._stopRecording !== 'function') {
8213
8216
  this.reportError('rrweb failed to start, skipping this recording.');
@@ -8251,12 +8254,21 @@ SessionRecording.prototype.isRrwebStopped = function () {
8251
8254
  return this._stopRecording === null;
8252
8255
  };
8253
8256
 
8257
+
8254
8258
  /**
8255
8259
  * Flushes the current batch of events to the server, but passes an opt-out callback to make sure
8256
8260
  * we stop recording and dump any queued events if the user has opted out.
8257
8261
  */
8258
8262
  SessionRecording.prototype.flushEventsWithOptOut = function (data, options, cb) {
8259
- this._flushEvents(data, options, cb, this._onOptOut.bind(this));
8263
+ var onOptOut = function (code) {
8264
+ // addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
8265
+ if (code === 0) {
8266
+ this.stopRecording();
8267
+ cb({error: 'Tracking has been opted out, stopping recording.'});
8268
+ }
8269
+ }.bind(this);
8270
+
8271
+ this._flushEvents(data, options, cb, onOptOut);
8260
8272
  };
8261
8273
 
8262
8274
  /**
@@ -8306,13 +8318,6 @@ SessionRecording.deserialize = function (serializedRecording, options) {
8306
8318
  return recording;
8307
8319
  };
8308
8320
 
8309
- SessionRecording.prototype._onOptOut = function (code) {
8310
- // addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
8311
- if (code === 0) {
8312
- this.stopRecording();
8313
- }
8314
- };
8315
-
8316
8321
  SessionRecording.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
8317
8322
  var onSuccess = function (response, responseBody) {
8318
8323
  // Update batch specific props only if the request was successful to guarantee ordering.
@@ -8355,17 +8360,32 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
8355
8360
 
8356
8361
  if (numEvents > 0) {
8357
8362
  var replayId = this.replayId;
8363
+
8358
8364
  // each rrweb event has a timestamp - leverage those to get time properties
8359
- var batchStartTime = data[0].timestamp;
8360
- if (this.seqNo === 0 || !this.replayStartTime) {
8361
- // extra safety net so that we don't send a null replay start time
8362
- if (this.seqNo !== 0) {
8363
- this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
8365
+ var batchStartTime = Infinity;
8366
+ var batchEndTime = -Infinity;
8367
+ var hasFullSnapshot = false;
8368
+ for (var i = 0; i < numEvents; i++) {
8369
+ batchStartTime = Math.min(batchStartTime, data[i].timestamp);
8370
+ batchEndTime = Math.max(batchEndTime, data[i].timestamp);
8371
+ if (data[i].type === EventType.FullSnapshot) {
8372
+ hasFullSnapshot = true;
8364
8373
  }
8374
+ }
8365
8375
 
8376
+ if (this.seqNo === 0) {
8377
+ if (!hasFullSnapshot) {
8378
+ callback({error: 'First batch does not contain a full snapshot. Aborting recording.'});
8379
+ this.stopRecording(true);
8380
+ return;
8381
+ }
8382
+ this.replayStartTime = batchStartTime;
8383
+ } else if (!this.replayStartTime) {
8384
+ this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
8366
8385
  this.replayStartTime = batchStartTime;
8367
8386
  }
8368
- var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime;
8387
+
8388
+ var replayLengthMs = batchEndTime - this.replayStartTime;
8369
8389
 
8370
8390
  var reqParams = {
8371
8391
  '$current_url': this.batchStartUrl,
@@ -11665,7 +11685,6 @@ MixpanelLib.prototype.init_batchers = function() {
11665
11685
  }, this),
11666
11686
  stopAllBatchingFunc: _.bind(this.stop_batch_senders, this),
11667
11687
  usePersistence: true,
11668
- enqueueThrottleMs: 10,
11669
11688
  }
11670
11689
  );
11671
11690
  }, this);
@@ -3,7 +3,7 @@
3
3
 
4
4
  var Config = {
5
5
  DEBUG: false,
6
- LIB_VERSION: '2.61.0'
6
+ LIB_VERSION: '2.61.2'
7
7
  };
8
8
 
9
9
  // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
@@ -5625,7 +5625,7 @@
5625
5625
  return this.dbPromise
5626
5626
  .then(doTransaction)
5627
5627
  .catch(function (err) {
5628
- if (err['name'] === 'InvalidStateError') {
5628
+ if (err && err['name'] === 'InvalidStateError') {
5629
5629
  // try reopening the DB if the connection is closed
5630
5630
  this.dbPromise = this._openDb();
5631
5631
  return this.dbPromise.then(doTransaction);
@@ -6507,7 +6507,6 @@
6507
6507
  }, this),
6508
6508
  stopAllBatchingFunc: _.bind(this.stop_batch_senders, this),
6509
6509
  usePersistence: true,
6510
- enqueueThrottleMs: 10,
6511
6510
  }
6512
6511
  );
6513
6512
  }, this);