mixpanel-browser 2.75.0 → 2.77.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.
Files changed (62) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/.github/dependabot.yml +8 -0
  3. package/.github/workflows/integration-tests.yml +4 -4
  4. package/.github/workflows/unit-tests.yml +4 -4
  5. package/CHANGELOG.md +14 -0
  6. package/build.sh +10 -8
  7. package/dist/async-modules/mixpanel-recorder-DLKbUIEE.js +23669 -0
  8. package/dist/async-modules/mixpanel-recorder-wIWnMDLA.min.js +2 -0
  9. package/dist/async-modules/mixpanel-recorder-wIWnMDLA.min.js.map +1 -0
  10. package/dist/async-modules/mixpanel-targeting-CTcftSJC.min.js +2 -0
  11. package/dist/async-modules/mixpanel-targeting-CTcftSJC.min.js.map +1 -0
  12. package/dist/async-modules/mixpanel-targeting-CmVvUyFM.js +2520 -0
  13. package/dist/mixpanel-core.cjs.d.ts +70 -1
  14. package/dist/mixpanel-core.cjs.js +724 -426
  15. package/dist/mixpanel-recorder.js +791 -41
  16. package/dist/mixpanel-recorder.min.js +1 -1
  17. package/dist/mixpanel-recorder.min.js.map +1 -1
  18. package/dist/mixpanel-targeting.js +6 -62
  19. package/dist/mixpanel-targeting.min.js +1 -1
  20. package/dist/mixpanel-targeting.min.js.map +1 -1
  21. package/dist/mixpanel-with-async-modules.cjs.d.ts +70 -1
  22. package/dist/mixpanel-with-async-modules.cjs.js +724 -426
  23. package/dist/mixpanel-with-async-recorder.cjs.d.ts +70 -1
  24. package/dist/mixpanel-with-async-recorder.cjs.js +724 -426
  25. package/dist/mixpanel-with-recorder.d.ts +70 -1
  26. package/dist/mixpanel-with-recorder.js +1471 -450
  27. package/dist/mixpanel-with-recorder.min.d.ts +70 -1
  28. package/dist/mixpanel-with-recorder.min.js +1 -1
  29. package/dist/mixpanel.amd.d.ts +70 -1
  30. package/dist/mixpanel.amd.js +1473 -504
  31. package/dist/mixpanel.cjs.d.ts +70 -1
  32. package/dist/mixpanel.cjs.js +1473 -504
  33. package/dist/mixpanel.globals.js +724 -426
  34. package/dist/mixpanel.min.js +189 -182
  35. package/dist/mixpanel.module.d.ts +70 -1
  36. package/dist/mixpanel.module.js +1473 -504
  37. package/dist/mixpanel.umd.d.ts +70 -1
  38. package/dist/mixpanel.umd.js +1473 -504
  39. package/dist/rrweb-bundled.js +61 -9
  40. package/dist/rrweb-compiled.js +56 -9
  41. package/logo.svg +5 -0
  42. package/package.json +6 -4
  43. package/rollup.config.mjs +163 -46
  44. package/src/autocapture/index.js +10 -27
  45. package/src/config.js +9 -3
  46. package/src/flags/index.js +1 -2
  47. package/src/index.d.ts +70 -1
  48. package/src/mixpanel-core.js +77 -112
  49. package/src/recorder/index.js +1 -1
  50. package/src/recorder/recorder.js +5 -1
  51. package/src/recorder/rrweb-network-plugin.js +649 -0
  52. package/src/recorder/session-recording.js +36 -12
  53. package/src/recorder/utils.js +27 -1
  54. package/src/recorder-manager.js +324 -0
  55. package/src/request-batcher.js +1 -1
  56. package/src/targeting/event-matcher.js +2 -57
  57. package/src/targeting/index.js +1 -1
  58. package/src/targeting/loader.js +1 -1
  59. package/src/utils.js +13 -1
  60. package/testServer.js +69 -1
  61. package/src/globals.js +0 -14
  62. /package/src/loaders/{loader-module-with-async-recorder.d.ts → loader-module-with-async-modules.d.ts} +0 -0
@@ -26,12 +26,9 @@
26
26
  win = window;
27
27
  }
28
28
 
29
- /**
30
- * Shared global window property names used across modules
31
- */
32
-
33
-
34
- // Recorder library global (used by recorder and mixpanel-core)
29
+ var Config = {
30
+ LIB_VERSION: '2.77.0'
31
+ };
35
32
  var RECORDER_GLOBAL_NAME = '__mp_recorder';
36
33
 
37
34
  function _array_like_to_array(arr, len) {
@@ -10731,13 +10728,7 @@
10731
10728
  };
10732
10729
  while(_this.mapRemoves.length){
10733
10730
  var removedNode = _this.mapRemoves.shift();
10734
- if (removedNode.nodeName === "IFRAME") {
10735
- try {
10736
- _this.iframeManager.removeIframe(removedNode);
10737
- } catch (e2) {}
10738
- } else {
10739
- _this.stylesheetManager.cleanupStylesheetsForRemovedNode(removedNode);
10740
- }
10731
+ _this.cleanupRemovedNode(removedNode);
10741
10732
  _this.mirror.removeNodeFromMap(removedNode);
10742
10733
  }
10743
10734
  for(var _iterator = _create_for_of_iterator_helper_loose(_this.movedSet), _step; !(_step = _iterator()).done;){
@@ -11057,6 +11048,20 @@
11057
11048
  }
11058
11049
  }
11059
11050
  });
11051
+ __publicField$1(this, "cleanupRemovedNode", function(node2) {
11052
+ if (node2.nodeName === "IFRAME") {
11053
+ try {
11054
+ _this.iframeManager.removeIframe(node2);
11055
+ } catch (e2) {}
11056
+ } else {
11057
+ try {
11058
+ _this.stylesheetManager.cleanupStylesheetsForRemovedNode(node2);
11059
+ } catch (e2) {}
11060
+ }
11061
+ node2.childNodes.forEach(function(child) {
11062
+ _this.cleanupRemovedNode(child);
11063
+ });
11064
+ });
11060
11065
  }
11061
11066
  var _proto = MutationBuffer.prototype;
11062
11067
  _proto.init = function init(options) {
@@ -13284,6 +13289,31 @@
13284
13289
  _proto.destroy = function destroy() {};
13285
13290
  return ProcessedNodeManager;
13286
13291
  }();
13292
+ function toOrigin(url) {
13293
+ try {
13294
+ var origin = new URL(url).origin;
13295
+ return origin !== "null" ? origin : null;
13296
+ } catch (e) {
13297
+ return null;
13298
+ }
13299
+ }
13300
+ function buildAllowedOriginSet(origins) {
13301
+ if (!Array.isArray(origins) || origins.length === 0) {
13302
+ throw new Error("[rrweb] allowedIframeOrigins must be a non-empty array of origin strings.");
13303
+ }
13304
+ var set = /* @__PURE__ */ new Set();
13305
+ for(var i2 = 0; i2 < origins.length; i2++){
13306
+ var entry = origins[i2];
13307
+ if (typeof entry !== "string") {
13308
+ throw new Error("[rrweb] allowedIframeOrigins[" + i2 + "] must be a string, got " + (typeof entry === "undefined" ? "undefined" : _type_of(entry)) + ".");
13309
+ }
13310
+ var origin = toOrigin(entry);
13311
+ if (origin) {
13312
+ set.add(origin);
13313
+ }
13314
+ }
13315
+ return Object.freeze(set);
13316
+ }
13287
13317
  var wrappedEmit;
13288
13318
  var takeFullSnapshot$1;
13289
13319
  var canvasManager;
@@ -13305,10 +13335,17 @@
13305
13335
  var mirror = createMirror$2();
13306
13336
  function record(options) {
13307
13337
  if (options === void 0) options = {};
13308
- var emit = options.emit, checkoutEveryNms = options.checkoutEveryNms, checkoutEveryNth = options.checkoutEveryNth, _options_blockClass = options.blockClass, blockClass = _options_blockClass === void 0 ? "rr-block" : _options_blockClass, _options_blockSelector = options.blockSelector, blockSelector = _options_blockSelector === void 0 ? null : _options_blockSelector, _options_ignoreClass = options.ignoreClass, ignoreClass = _options_ignoreClass === void 0 ? "rr-ignore" : _options_ignoreClass, _options_ignoreSelector = options.ignoreSelector, ignoreSelector = _options_ignoreSelector === void 0 ? null : _options_ignoreSelector, _options_maskTextClass = options.maskTextClass, maskTextClass = _options_maskTextClass === void 0 ? "rr-mask" : _options_maskTextClass, _options_maskTextSelector = options.maskTextSelector, maskTextSelector = _options_maskTextSelector === void 0 ? null : _options_maskTextSelector, _options_inlineStylesheet = options.inlineStylesheet, inlineStylesheet = _options_inlineStylesheet === void 0 ? true : _options_inlineStylesheet, maskAllInputs = options.maskAllInputs, _maskInputOptions = options.maskInputOptions, _slimDOMOptions = options.slimDOMOptions, maskInputFn = options.maskInputFn, maskTextFn = options.maskTextFn, hooks = options.hooks, packFn = options.packFn, _options_sampling = options.sampling, sampling = _options_sampling === void 0 ? {} : _options_sampling, _options_dataURLOptions = options.dataURLOptions, dataURLOptions = _options_dataURLOptions === void 0 ? {} : _options_dataURLOptions, mousemoveWait = options.mousemoveWait, _options_recordDOM = options.recordDOM, recordDOM = _options_recordDOM === void 0 ? true : _options_recordDOM, _options_recordCanvas = options.recordCanvas, recordCanvas = _options_recordCanvas === void 0 ? false : _options_recordCanvas, _options_recordCrossOriginIframes = options.recordCrossOriginIframes, recordCrossOriginIframes = _options_recordCrossOriginIframes === void 0 ? false : _options_recordCrossOriginIframes, _options_recordAfter = options.recordAfter, recordAfter = _options_recordAfter === void 0 ? options.recordAfter === "DOMContentLoaded" ? options.recordAfter : "load" : _options_recordAfter, _options_userTriggeredOnInput = options.userTriggeredOnInput, userTriggeredOnInput = _options_userTriggeredOnInput === void 0 ? false : _options_userTriggeredOnInput, _options_collectFonts = options.collectFonts, collectFonts = _options_collectFonts === void 0 ? false : _options_collectFonts, _options_inlineImages = options.inlineImages, inlineImages = _options_inlineImages === void 0 ? false : _options_inlineImages, plugins = options.plugins, _options_keepIframeSrcFn = options.keepIframeSrcFn, keepIframeSrcFn = _options_keepIframeSrcFn === void 0 ? function() {
13338
+ var emit = options.emit, checkoutEveryNms = options.checkoutEveryNms, checkoutEveryNth = options.checkoutEveryNth, _options_blockClass = options.blockClass, blockClass = _options_blockClass === void 0 ? "rr-block" : _options_blockClass, _options_blockSelector = options.blockSelector, blockSelector = _options_blockSelector === void 0 ? null : _options_blockSelector, _options_ignoreClass = options.ignoreClass, ignoreClass = _options_ignoreClass === void 0 ? "rr-ignore" : _options_ignoreClass, _options_ignoreSelector = options.ignoreSelector, ignoreSelector = _options_ignoreSelector === void 0 ? null : _options_ignoreSelector, _options_maskTextClass = options.maskTextClass, maskTextClass = _options_maskTextClass === void 0 ? "rr-mask" : _options_maskTextClass, _options_maskTextSelector = options.maskTextSelector, maskTextSelector = _options_maskTextSelector === void 0 ? null : _options_maskTextSelector, _options_inlineStylesheet = options.inlineStylesheet, inlineStylesheet = _options_inlineStylesheet === void 0 ? true : _options_inlineStylesheet, maskAllInputs = options.maskAllInputs, _maskInputOptions = options.maskInputOptions, _slimDOMOptions = options.slimDOMOptions, maskInputFn = options.maskInputFn, maskTextFn = options.maskTextFn, hooks = options.hooks, packFn = options.packFn, _options_sampling = options.sampling, sampling = _options_sampling === void 0 ? {} : _options_sampling, _options_dataURLOptions = options.dataURLOptions, dataURLOptions = _options_dataURLOptions === void 0 ? {} : _options_dataURLOptions, mousemoveWait = options.mousemoveWait, _options_recordDOM = options.recordDOM, recordDOM = _options_recordDOM === void 0 ? true : _options_recordDOM, _options_recordCanvas = options.recordCanvas, recordCanvas = _options_recordCanvas === void 0 ? false : _options_recordCanvas, _options_recordCrossOriginIframes = options.recordCrossOriginIframes, recordCrossOriginIframes = _options_recordCrossOriginIframes === void 0 ? false : _options_recordCrossOriginIframes, allowedIframeOrigins = options.allowedIframeOrigins, _options_recordAfter = options.recordAfter, recordAfter = _options_recordAfter === void 0 ? options.recordAfter === "DOMContentLoaded" ? options.recordAfter : "load" : _options_recordAfter, _options_userTriggeredOnInput = options.userTriggeredOnInput, userTriggeredOnInput = _options_userTriggeredOnInput === void 0 ? false : _options_userTriggeredOnInput, _options_collectFonts = options.collectFonts, collectFonts = _options_collectFonts === void 0 ? false : _options_collectFonts, _options_inlineImages = options.inlineImages, inlineImages = _options_inlineImages === void 0 ? false : _options_inlineImages, plugins = options.plugins, _options_keepIframeSrcFn = options.keepIframeSrcFn, keepIframeSrcFn = _options_keepIframeSrcFn === void 0 ? function() {
13309
13339
  return false;
13310
13340
  } : _options_keepIframeSrcFn, _options_ignoreCSSAttributes = options.ignoreCSSAttributes, ignoreCSSAttributes = _options_ignoreCSSAttributes === void 0 ? /* @__PURE__ */ new Set([]) : _options_ignoreCSSAttributes, errorHandler2 = options.errorHandler;
13311
13341
  registerErrorHandler(errorHandler2);
13342
+ var validatedOrigins;
13343
+ if (recordCrossOriginIframes && allowedIframeOrigins && allowedIframeOrigins.length > 0) {
13344
+ validatedOrigins = buildAllowedOriginSet(allowedIframeOrigins);
13345
+ if (validatedOrigins.size === 0) {
13346
+ validatedOrigins = void 0;
13347
+ }
13348
+ }
13312
13349
  var inEmittingFrame = recordCrossOriginIframes ? window.parent === window : true;
13313
13350
  var passEmitsToParent = false;
13314
13351
  if (!inEmittingFrame) {
@@ -13400,7 +13437,14 @@
13400
13437
  origin: window.location.origin,
13401
13438
  isCheckout: isCheckout
13402
13439
  };
13403
- window.parent.postMessage(message, "*");
13440
+ if (validatedOrigins) {
13441
+ for(var _iterator = _create_for_of_iterator_helper_loose(validatedOrigins), _step; !(_step = _iterator()).done;){
13442
+ var targetOrigin = _step.value;
13443
+ window.parent.postMessage(message, targetOrigin);
13444
+ }
13445
+ } else {
13446
+ window.parent.postMessage(message, "*");
13447
+ }
13404
13448
  }
13405
13449
  if (e2.type === EventType.FullSnapshot) {
13406
13450
  lastFullSnapshotEvent = e2;
@@ -18133,7 +18177,7 @@
18133
18177
  var __publicField = function(obj, key, value) {
18134
18178
  return __defNormalProp(obj, (typeof key === "undefined" ? "undefined" : _type_of(key)) !== "symbol" ? key + "" : key, value);
18135
18179
  };
18136
- function patch(source, name, replacement) {
18180
+ function patch$3(source, name, replacement) {
18137
18181
  try {
18138
18182
  if (!(name in source)) {
18139
18183
  return function() {};
@@ -18550,7 +18594,7 @@
18550
18594
  if (!_logger[level]) {
18551
18595
  return function() {};
18552
18596
  }
18553
- return patch(_logger, level, function(original) {
18597
+ return patch$3(_logger, level, function(original) {
18554
18598
  var _this1 = _this;
18555
18599
  return function() {
18556
18600
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
@@ -18971,10 +19015,6 @@
18971
19015
  PromisePolyfill = NpoPromise;
18972
19016
  }
18973
19017
 
18974
- var Config = {
18975
- LIB_VERSION: '2.75.0'
18976
- };
18977
-
18978
19018
  /* eslint camelcase: "off", eqeqeq: "off" */
18979
19019
 
18980
19020
  // Maximum allowed session recording length
@@ -20640,6 +20680,17 @@
20640
20680
 
20641
20681
  var NOOP_FUNC = function () {};
20642
20682
 
20683
+ var urlMatchesRegexList = function (url, regexList) {
20684
+ var matches = false;
20685
+ for (var i = 0; i < regexList.length; i++) {
20686
+ if (url.match(regexList[i])) {
20687
+ matches = true;
20688
+ break;
20689
+ }
20690
+ }
20691
+ return matches;
20692
+ };
20693
+
20643
20694
  var JSONStringify = null, JSONParse = null;
20644
20695
  if (typeof JSON !== 'undefined') {
20645
20696
  JSONStringify = JSON.stringify;
@@ -20979,7 +21030,7 @@
20979
21030
  };
20980
21031
  }
20981
21032
 
20982
- var logger$4 = console_with_prefix('lock');
21033
+ var logger$5 = console_with_prefix('lock');
20983
21034
 
20984
21035
  /**
20985
21036
  * SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
@@ -21031,7 +21082,7 @@
21031
21082
 
21032
21083
  var delay = function(cb) {
21033
21084
  if (new Date().getTime() - startTime > timeoutMS) {
21034
- logger$4.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
21085
+ logger$5.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
21035
21086
  storage.removeItem(keyZ);
21036
21087
  storage.removeItem(keyY);
21037
21088
  loop();
@@ -21178,7 +21229,7 @@
21178
21229
  }, this));
21179
21230
  };
21180
21231
 
21181
- var logger$3 = console_with_prefix('batch');
21232
+ var logger$4 = console_with_prefix('batch');
21182
21233
 
21183
21234
  /**
21184
21235
  * RequestQueue: queue for batching API requests with localStorage backup for retries.
@@ -21207,7 +21258,7 @@
21207
21258
  timeoutMS: options.sharedLockTimeoutMS,
21208
21259
  });
21209
21260
  }
21210
- this.reportError = options.errorReporter || _.bind(logger$3.error, logger$3);
21261
+ this.reportError = options.errorReporter || _.bind(logger$4.error, logger$4);
21211
21262
 
21212
21263
  this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
21213
21264
 
@@ -21540,7 +21591,7 @@
21540
21591
  // maximum interval between request retries after exponential backoff
21541
21592
  var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
21542
21593
 
21543
- var logger$2 = console_with_prefix('batch');
21594
+ var logger$3 = console_with_prefix('batch');
21544
21595
 
21545
21596
  /**
21546
21597
  * RequestBatcher: manages the queueing, flushing, retry etc of requests of one
@@ -21668,7 +21719,7 @@
21668
21719
  */
21669
21720
  RequestBatcher.prototype.flush = function(options) {
21670
21721
  if (this.requestInProgress) {
21671
- logger$2.log('Flush: Request already in progress');
21722
+ logger$3.log('Flush: Request already in progress');
21672
21723
  return PromisePolyfill.resolve();
21673
21724
  }
21674
21725
 
@@ -21845,7 +21896,7 @@
21845
21896
  if (options.unloading) {
21846
21897
  requestOptions.transport = 'sendBeacon';
21847
21898
  }
21848
- logger$2.log('MIXPANEL REQUEST:', dataForRequest);
21899
+ logger$3.log('MIXPANEL REQUEST:', dataForRequest);
21849
21900
  return this.sendRequestPromise(dataForRequest, requestOptions).then(batchSendCallback);
21850
21901
  }, this))
21851
21902
  .catch(_.bind(function(err) {
@@ -21858,7 +21909,7 @@
21858
21909
  * Log error to global logger and optional user-defined logger.
21859
21910
  */
21860
21911
  RequestBatcher.prototype.reportError = function(msg, err) {
21861
- logger$2.error.apply(logger$2.error, arguments);
21912
+ logger$3.error.apply(logger$3.error, arguments);
21862
21913
  if (this.errorReporter) {
21863
21914
  try {
21864
21915
  if (!(err instanceof Error)) {
@@ -21866,7 +21917,7 @@
21866
21917
  }
21867
21918
  this.errorReporter(msg, err);
21868
21919
  } catch(err) {
21869
- logger$2.error(err);
21920
+ logger$3.error(err);
21870
21921
  }
21871
21922
  }
21872
21923
  };
@@ -21883,6 +21934,29 @@
21883
21934
 
21884
21935
  var RECORD_ENQUEUE_THROTTLE_MS = 250;
21885
21936
 
21937
+ var validateAllowedOrigins = function(origins, logger) {
21938
+ if (!_.isArray(origins)) {
21939
+ if (origins) {
21940
+ logger.critical('record_allowed_iframe_origins must be an array of origin strings, cross-origin recording will be disabled.');
21941
+ }
21942
+ return [];
21943
+ }
21944
+ var valid = [];
21945
+ for (var i = 0; i < origins.length; i++) {
21946
+ try {
21947
+ var origin = new URL(origins[i]).origin;
21948
+ if (origin === 'null') {
21949
+ logger.critical(origins[i] + ' has an opaque origin. Skipping this entry.');
21950
+ continue;
21951
+ }
21952
+ valid.push(origin);
21953
+ } catch (e) {
21954
+ logger.critical(origins[i] + ' is not a valid origin URL. Skipping this entry.');
21955
+ }
21956
+ }
21957
+ return valid;
21958
+ };
21959
+
21886
21960
  // stateless utils
21887
21961
  // mostly from https://github.com/mixpanel/mixpanel-js/blob/989ada50f518edab47b9c4fd9535f9fbd5ec5fc0/src/autotrack-utils.js
21888
21962
 
@@ -22084,6 +22158,655 @@
22084
22158
  }
22085
22159
  }
22086
22160
 
22161
+ /**
22162
+ * This is a port of the open rrweb network plugin in this PR https://github.com/rrweb-io/rrweb/pull/1105
22163
+ * the hope is that eventually this can be replaced with the official plugin once it's published (and we sync the mixpanel rrweb fork)
22164
+ *
22165
+ * This plugin incorporates some important fixes for fetch/XHR body recording that are not yet in the main rrweb repo, as well as makes
22166
+ * header and body recording more restrictive by requiring an allowlist instead of content type / blocklist.
22167
+ *
22168
+ */
22169
+
22170
+ var logger$2 = console_with_prefix('network-plugin');
22171
+
22172
+ /**
22173
+ * Get the time origin for converting performance timestamps to absolute timestamps.
22174
+ * Uses Date.now() - performance.now() instead of performance.timeOrigin because
22175
+ * browsers can report timeOrigin values that are skewed from actual time, and some
22176
+ * browsers (notably older Safari versions) don't implement timeOrigin at all.
22177
+ * See: https://github.com/getsentry/sentry-javascript/blob/e856e40b6e71a73252e788cd42b5260f81c9c88e/packages/utils/src/time.ts#L49-L70
22178
+ * @param {Window} win
22179
+ * @returns {number}
22180
+ */
22181
+ function getTimeOrigin(win) {
22182
+ return Math.round(Date.now() - win.performance.now());
22183
+ }
22184
+
22185
+ /**
22186
+ * @typedef {import('../index.d.ts').InitiatorType} InitiatorType
22187
+ * @typedef {import('../index.d.ts').NetworkRequest} NetworkRequest
22188
+ * @typedef {import('../index.d.ts').NetworkRecordOptions} NetworkRecordOptions
22189
+ * @typedef {import('../index.d.ts').NetworkData} NetworkData
22190
+ */
22191
+
22192
+ /**
22193
+ * @typedef {Record<string, string>} Headers
22194
+ */
22195
+
22196
+ /**
22197
+ * @typedef {string | Document | Blob | ArrayBufferView | ArrayBuffer | FormData | URLSearchParams | ReadableStream<Uint8Array> | null} Body
22198
+ */
22199
+
22200
+ /**
22201
+ * @callback networkCallback
22202
+ * @param {NetworkData} data
22203
+ * @returns {void}
22204
+ */
22205
+
22206
+ /**
22207
+ * @callback listenerHandler
22208
+ * @returns {void}
22209
+ */
22210
+
22211
+ /**
22212
+ * @typedef {(PerformanceNavigationTiming | PerformanceResourceTiming) & { responseStatus?: number }} ObservedPerformanceEntry
22213
+ */
22214
+
22215
+ /**
22216
+ * @typedef {Object} RecordPlugin
22217
+ * @property {string} name
22218
+ * @property {(callback: networkCallback, win: Window, options: NetworkRecordOptions) => listenerHandler} observer
22219
+ * @property {NetworkRecordOptions} [options]
22220
+ */
22221
+
22222
+ /** @type {Required<NetworkRecordOptions>} */
22223
+ var defaultNetworkOptions = {
22224
+ initiatorTypes: [
22225
+ 'audio',
22226
+ 'beacon',
22227
+ 'body',
22228
+ 'css',
22229
+ 'early-hint',
22230
+ 'embed',
22231
+ 'fetch',
22232
+ 'frame',
22233
+ 'iframe',
22234
+ 'icon',
22235
+ 'image',
22236
+ 'img',
22237
+ 'input',
22238
+ 'link',
22239
+ 'navigation',
22240
+ 'object',
22241
+ 'ping',
22242
+ 'script',
22243
+ 'track',
22244
+ 'video',
22245
+ 'xmlhttprequest',
22246
+ ],
22247
+ ignoreRequestFn: function() { return false; },
22248
+ recordHeaders: {
22249
+ request: [],
22250
+ response: [],
22251
+ },
22252
+ recordBodyUrls: {
22253
+ request: [],
22254
+ response: [],
22255
+ },
22256
+ recordInitialRequests: false,
22257
+ };
22258
+
22259
+ /**
22260
+ * @param {PerformanceEntry} entry
22261
+ * @returns {entry is PerformanceNavigationTiming}
22262
+ */
22263
+ function isNavigationTiming(entry) {
22264
+ return entry.entryType === 'navigation';
22265
+ }
22266
+
22267
+ /**
22268
+ * @param {PerformanceEntry} entry
22269
+ * @returns {entry is PerformanceResourceTiming}
22270
+ */
22271
+ function isResourceTiming (entry) {
22272
+ return entry.entryType === 'resource';
22273
+ }
22274
+
22275
+ function findLast(array, predicate) {
22276
+ var length = array.length;
22277
+ for (var i = length - 1; i >= 0; i -= 1) {
22278
+ if (predicate(array[i])) {
22279
+ return array[i];
22280
+ }
22281
+ }
22282
+ }
22283
+
22284
+ /**
22285
+ * Monkey-patches a method on an object with a wrapped version, returning a function that restores the original.
22286
+ * Adapted from Sentry's `fill` utility:
22287
+ * https://github.com/getsentry/sentry-javascript/blob/de5c5cbe177b4334386e747857225eec36a91ea1/packages/core/src/utils/object.ts#L67-L95
22288
+ *
22289
+ * @param {object} source - The object containing the method to patch
22290
+ * @param {string} name - The method name to patch
22291
+ * @param {function} replacementFactory - A function that receives the original method and returns the replacement
22292
+ * @returns {function} A function that restores the original method
22293
+ */
22294
+ function patch(source, name, replacementFactory) {
22295
+ if (!(name in source) || typeof source[name] !== 'function') {
22296
+ return function() {};
22297
+ }
22298
+ var original = source[name];
22299
+ var wrapped = replacementFactory(original);
22300
+ source[name] = wrapped;
22301
+ return function() {
22302
+ source[name] = original;
22303
+ };
22304
+ }
22305
+
22306
+
22307
+ /**
22308
+ * Maximum body size to record (1MB)
22309
+ */
22310
+ var MAX_BODY_SIZE = 1024 * 1024;
22311
+
22312
+ /**
22313
+ * Truncate string if it exceeds max size
22314
+ * @param {string} str
22315
+ * @returns {string}
22316
+ */
22317
+ function truncateBody(str) {
22318
+ if (!str || typeof str !== 'string') {
22319
+ return str;
22320
+ }
22321
+ if (str.length > MAX_BODY_SIZE) {
22322
+ logger$2.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
22323
+ return str.substring(0, MAX_BODY_SIZE) + '... [truncated]';
22324
+ }
22325
+ return str;
22326
+ }
22327
+
22328
+ /**
22329
+ * @param {networkCallback} cb
22330
+ * @param {Window} win
22331
+ * @param {Required<NetworkRecordOptions>} options
22332
+ * @returns {listenerHandler}
22333
+ */
22334
+ function initPerformanceObserver(cb, win, options) {
22335
+ if (!win.PerformanceObserver) {
22336
+ logger$2.error('PerformanceObserver not supported');
22337
+ return function() {
22338
+ //
22339
+ };
22340
+ }
22341
+ if (options.recordInitialRequests) {
22342
+ var initialPerformanceEntries = win.performance
22343
+ .getEntries()
22344
+ .filter(function(entry) {
22345
+ return isNavigationTiming(entry) ||
22346
+ (isResourceTiming(entry) &&
22347
+ options.initiatorTypes.includes(entry.initiatorType));
22348
+ });
22349
+ cb({
22350
+ requests: initialPerformanceEntries.map(function(entry) {
22351
+ return {
22352
+ url: entry.name,
22353
+ initiatorType: /** @type {InitiatorType} */ (entry.initiatorType),
22354
+ status: 'responseStatus' in entry ? entry.responseStatus : undefined,
22355
+ startTime: Math.round(entry.startTime),
22356
+ endTime: Math.round(entry.responseEnd),
22357
+ timeOrigin: getTimeOrigin(win),
22358
+ };
22359
+ }),
22360
+ isInitial: true,
22361
+ });
22362
+ }
22363
+ var observer = new win.PerformanceObserver(function(entries) {
22364
+ var performanceEntries = entries
22365
+ .getEntries()
22366
+ .filter(function(entry) {
22367
+ return isResourceTiming(entry) &&
22368
+ options.initiatorTypes.includes(entry.initiatorType) &&
22369
+ entry.initiatorType !== 'xmlhttprequest' &&
22370
+ entry.initiatorType !== 'fetch';
22371
+ });
22372
+ cb({
22373
+ requests: performanceEntries.map(function(entry) {
22374
+ return {
22375
+ url: entry.name,
22376
+ initiatorType: /** @type {InitiatorType} */ (entry.initiatorType),
22377
+ status: 'responseStatus' in entry ? entry.responseStatus : undefined,
22378
+ startTime: Math.round(entry.startTime),
22379
+ endTime: Math.round(entry.responseEnd),
22380
+ timeOrigin: getTimeOrigin(win),
22381
+ };
22382
+ }),
22383
+ });
22384
+ });
22385
+ observer.observe({ entryTypes: ['navigation', 'resource'] });
22386
+ return function() {
22387
+ observer.disconnect();
22388
+ };
22389
+ }
22390
+
22391
+ /**
22392
+ * Variation of the original rrweb function that requires an allowlist for headers instead of supporting boolean options
22393
+ * @param {'request' | 'response'} type
22394
+ * @param {NetworkRecordOptions['recordHeaders']} recordHeaders
22395
+ * @param {string} headerName
22396
+ * @returns {boolean}
22397
+ */
22398
+ function shouldRecordHeader(type, recordHeaders, headerName) {
22399
+ if (!recordHeaders[type] || recordHeaders[type].length === 0) {
22400
+ return false;
22401
+ }
22402
+
22403
+ return recordHeaders[type].includes(headerName.toLowerCase());
22404
+ }
22405
+
22406
+ /**
22407
+ * Variation of the original rrweb function that requires an allowlist for URLs instead of supporting boolean options or by content type
22408
+ * @param {'request' | 'response'} type
22409
+ * @param {NetworkRecordOptions['recordBodyUrls']} recordBodyUrls
22410
+ * @param {string} url
22411
+ * @returns {boolean}
22412
+ */
22413
+ function shouldRecordBody(type, recordBodyUrls, url) {
22414
+ if (!recordBodyUrls[type] || recordBodyUrls[type].length === 0) {
22415
+ return false;
22416
+ }
22417
+
22418
+ return urlMatchesRegexList(url, recordBodyUrls[type]);
22419
+ }
22420
+
22421
+ function tryReadXHRBody(body) {
22422
+ if (body === null || body === undefined) {
22423
+ return null;
22424
+ }
22425
+
22426
+ var result;
22427
+ if (typeof body === 'string') {
22428
+ result = body;
22429
+ } else if (body instanceof Document) {
22430
+ result = body.textContent;
22431
+ } else if (body instanceof FormData) {
22432
+ result = _.HTTPBuildQuery(body);
22433
+ } else if (_.isObject(body)) {
22434
+ try {
22435
+ result = JSON.stringify(body);
22436
+ } catch (e) {
22437
+ return 'Failed to stringify response object';
22438
+ }
22439
+ } else {
22440
+ return 'Cannot read body of type ' + typeof body;
22441
+ }
22442
+
22443
+ return truncateBody(result);
22444
+ }
22445
+
22446
+ /**
22447
+ * @param {Request | Response} r
22448
+ * @returns {Promise<string>}
22449
+ */
22450
+ function tryReadFetchBody(r) {
22451
+ return new Promise(function(resolve) {
22452
+ var timeout = setTimeout(function() {
22453
+ resolve('Timeout while trying to read body');
22454
+ }, 500);
22455
+ try {
22456
+ r.clone()
22457
+ .text()
22458
+ .then(
22459
+ function(txt) {
22460
+ clearTimeout(timeout);
22461
+ resolve(truncateBody(txt));
22462
+ },
22463
+ function(reason) {
22464
+ clearTimeout(timeout);
22465
+ resolve('Failed to read body: ' + String(reason));
22466
+ }
22467
+ );
22468
+ } catch (e) {
22469
+ clearTimeout(timeout);
22470
+ resolve('Failed to read body: ' + String(e));
22471
+ }
22472
+ });
22473
+ }
22474
+
22475
+ /**
22476
+ * @param {Window} win
22477
+ * @param {string} initiatorType
22478
+ * @param {string} url
22479
+ * @param {number} [after]
22480
+ * @param {number} [before]
22481
+ * @param {number} [attempt]
22482
+ * @returns {Promise<PerformanceResourceTiming>}
22483
+ */
22484
+ function getRequestPerformanceEntry(win, initiatorType, url, after, before, attempt) {
22485
+ if (attempt === undefined) {
22486
+ attempt = 0;
22487
+ }
22488
+ if (attempt > 10) {
22489
+ logger$2.error('Cannot find performance entry');
22490
+ return Promise.resolve(null);
22491
+ }
22492
+ var urlPerformanceEntries = /** @type {PerformanceResourceTiming[]} */ (
22493
+ win.performance.getEntriesByName(url)
22494
+ );
22495
+ var performanceEntry = findLast(
22496
+ urlPerformanceEntries,
22497
+ function(entry) {
22498
+ return isResourceTiming(entry) &&
22499
+ entry.initiatorType === initiatorType &&
22500
+ (!after || entry.startTime >= after) &&
22501
+ (!before || entry.startTime <= before);
22502
+ }
22503
+ );
22504
+ if (!performanceEntry) {
22505
+ return new Promise(function(resolve) {
22506
+ setTimeout(resolve, 50 * attempt);
22507
+ }).then(function() {
22508
+ return getRequestPerformanceEntry(
22509
+ win,
22510
+ initiatorType,
22511
+ url,
22512
+ after,
22513
+ before,
22514
+ attempt + 1
22515
+ );
22516
+ });
22517
+ }
22518
+ return Promise.resolve(performanceEntry);
22519
+ }
22520
+
22521
+ /**
22522
+ * @param {networkCallback} cb
22523
+ * @param {Window} win
22524
+ * @param {Required<NetworkRecordOptions>} options
22525
+ * @returns {listenerHandler}
22526
+ */
22527
+ function initXhrObserver(cb, win, options) {
22528
+ if (!options.initiatorTypes.includes('xmlhttprequest')) {
22529
+ return function() {
22530
+ //
22531
+ };
22532
+ }
22533
+ var restorePatch = patch(
22534
+ win.XMLHttpRequest.prototype,
22535
+ 'open',
22536
+ function(/** @type {typeof XMLHttpRequest.prototype.open} */ originalOpen) {
22537
+ return function(
22538
+ /** @type {string} */ method,
22539
+ /** @type {string | URL} */ url,
22540
+ /** @type {boolean} */ async,
22541
+ username, password
22542
+ ) {
22543
+ if (async === undefined) {
22544
+ async = true;
22545
+ }
22546
+ var xhr = /** @type {XMLHttpRequest} */ (this);
22547
+ var req = new Request(url, { method: method });
22548
+ /** @type {Partial<NetworkRequest>} */
22549
+ var networkRequest = {};
22550
+ /** @type {number | undefined} */
22551
+ var after;
22552
+ /** @type {number | undefined} */
22553
+ var before;
22554
+
22555
+ /** @type {Headers} */
22556
+ var requestHeaders = {};
22557
+ var originalSetRequestHeader = xhr.setRequestHeader.bind(xhr);
22558
+ xhr.setRequestHeader = function(/** @type {string} */ header, /** @type {string} */ value) {
22559
+ if (shouldRecordHeader('request', options.recordHeaders, header)) {
22560
+ requestHeaders[header] = value;
22561
+ }
22562
+ return originalSetRequestHeader(header, value);
22563
+ };
22564
+ networkRequest.requestHeaders = requestHeaders;
22565
+
22566
+ var originalSend = xhr.send.bind(xhr);
22567
+ xhr.send = function(/** @type {Body} */ body) {
22568
+ if (shouldRecordBody('request', options.recordBodyUrls, req.url)) {
22569
+ networkRequest.requestBody = tryReadXHRBody(body);
22570
+ }
22571
+ after = win.performance.now();
22572
+ return originalSend(body);
22573
+ };
22574
+ xhr.addEventListener('readystatechange', function() {
22575
+ if (xhr.readyState !== xhr.DONE) {
22576
+ return;
22577
+ }
22578
+ before = win.performance.now();
22579
+ /** @type {Headers} */
22580
+ var responseHeaders = {};
22581
+ var rawHeaders = xhr.getAllResponseHeaders();
22582
+ if (rawHeaders) {
22583
+ var headers = rawHeaders.trim().split(/[\r\n]+/);
22584
+ headers.forEach(function(line) {
22585
+ if (!line) return;
22586
+ var colonIndex = line.indexOf(': ');
22587
+ if (colonIndex === -1) return;
22588
+ var header = line.substring(0, colonIndex);
22589
+ var value = line.substring(colonIndex + 2);
22590
+ if (header && shouldRecordHeader('response', options.recordHeaders, header)) {
22591
+ responseHeaders[header] = value;
22592
+ }
22593
+ });
22594
+ }
22595
+ networkRequest.responseHeaders = responseHeaders;
22596
+ if (
22597
+ shouldRecordBody('response', options.recordBodyUrls, req.url)
22598
+ ) {
22599
+ networkRequest.responseBody = tryReadXHRBody(xhr.response);
22600
+ }
22601
+ getRequestPerformanceEntry(
22602
+ win,
22603
+ 'xmlhttprequest',
22604
+ req.url,
22605
+ after,
22606
+ before
22607
+ )
22608
+ .then(function(entry) {
22609
+ if (!entry) {
22610
+ logger$2.error('Failed to get performance entry for XHR request to ' + req.url);
22611
+ return;
22612
+ }
22613
+ /** @type {NetworkRequest} */
22614
+ var request = {
22615
+ url: entry.name,
22616
+ method: req.method,
22617
+ initiatorType: /** @type {InitiatorType} */ (entry.initiatorType),
22618
+ status: xhr.status,
22619
+ startTime: Math.round(entry.startTime),
22620
+ endTime: Math.round(entry.responseEnd),
22621
+ timeOrigin: getTimeOrigin(win),
22622
+ requestHeaders: networkRequest.requestHeaders,
22623
+ requestBody: networkRequest.requestBody,
22624
+ responseHeaders: networkRequest.responseHeaders,
22625
+ responseBody: networkRequest.responseBody,
22626
+ };
22627
+ cb({ requests: [request] });
22628
+ })
22629
+ .catch(function(e) {
22630
+ logger$2.error('Error recording XHR request to ' + req.url + ': ' + String(e));
22631
+ });
22632
+ });
22633
+
22634
+ originalOpen.call(xhr, method, url, async, username, password);
22635
+ };
22636
+ }
22637
+ );
22638
+ return function() {
22639
+ restorePatch();
22640
+ };
22641
+ }
22642
+
22643
+ /**
22644
+ * @param {networkCallback} cb
22645
+ * @param {Window} win
22646
+ * @param {Required<NetworkRecordOptions>} options
22647
+ * @returns {listenerHandler}
22648
+ */
22649
+ function initFetchObserver(cb, win, options) {
22650
+ if (!options.initiatorTypes.includes('fetch')) {
22651
+ return function() {
22652
+ //
22653
+ };
22654
+ }
22655
+
22656
+ var restorePatch = patch(win, 'fetch', function(/** @type {typeof fetch} */ originalFetch) {
22657
+ return function() {
22658
+ var req = new Request(arguments[0], arguments[1]);
22659
+ /** @type {Response | undefined} */
22660
+ var res;
22661
+ /** @type {Partial<NetworkRequest>} */
22662
+ var networkRequest = {};
22663
+ /** @type {number | undefined} */
22664
+ var after;
22665
+ /** @type {number | undefined} */
22666
+ var before;
22667
+
22668
+ var originalFetchPromise;
22669
+ var requestBodyPromise = Promise.resolve(undefined);
22670
+ var responseBodyPromise = Promise.resolve(undefined);
22671
+ try {
22672
+ /** @type {Headers} */
22673
+ var requestHeaders = {};
22674
+ req.headers.forEach(function(value, header) {
22675
+ if (shouldRecordHeader('request', options.recordHeaders, header)) {
22676
+ requestHeaders[header] = value;
22677
+ }
22678
+ });
22679
+ networkRequest.requestHeaders = requestHeaders;
22680
+
22681
+ if (shouldRecordBody('request', options.recordBodyUrls, req.url)) {
22682
+ requestBodyPromise = tryReadFetchBody(req)
22683
+ .then(function(body) {
22684
+ networkRequest.requestBody = body;
22685
+ });
22686
+ }
22687
+
22688
+ after = win.performance.now();
22689
+ originalFetchPromise = originalFetch.apply(win, arguments).then(function(response) {
22690
+ res = response;
22691
+ before = win.performance.now();
22692
+
22693
+ /** @type {Headers} */
22694
+ var responseHeaders = {};
22695
+ res.headers.forEach(function(value, header) {
22696
+ if (shouldRecordHeader('response', options.recordHeaders, header)) {
22697
+ responseHeaders[header] = value;
22698
+ }
22699
+ });
22700
+ networkRequest.responseHeaders = responseHeaders;
22701
+
22702
+ if (shouldRecordBody('response', options.recordBodyUrls, req.url)) {
22703
+ responseBodyPromise = tryReadFetchBody(res)
22704
+ .then(function(body) {
22705
+ networkRequest.responseBody = body;
22706
+ });
22707
+ }
22708
+
22709
+ return res;
22710
+ });
22711
+ } catch (e) {
22712
+ originalFetchPromise = Promise.reject(e);
22713
+ }
22714
+
22715
+ // await concurrently so we don't delay the fetch response
22716
+ Promise.all([requestBodyPromise, responseBodyPromise, originalFetchPromise])
22717
+ .then(function () {
22718
+ return getRequestPerformanceEntry(win, 'fetch', req.url, after, before);
22719
+ })
22720
+ .then(function(entry) {
22721
+ if (!entry) {
22722
+ logger$2.error('Failed to get performance entry for fetch request to ' + req.url);
22723
+ return;
22724
+ }
22725
+ /** @type {NetworkRequest} */
22726
+ var request = {
22727
+ url: entry.name,
22728
+ method: req.method,
22729
+ initiatorType: /** @type {InitiatorType} */ (entry.initiatorType),
22730
+ status: res ? res.status : undefined,
22731
+ startTime: Math.round(entry.startTime),
22732
+ endTime: Math.round(entry.responseEnd),
22733
+ timeOrigin: getTimeOrigin(win),
22734
+ requestHeaders: networkRequest.requestHeaders,
22735
+ requestBody: networkRequest.requestBody,
22736
+ responseHeaders: networkRequest.responseHeaders,
22737
+ responseBody: networkRequest.responseBody,
22738
+ };
22739
+ cb({ requests: [request] });
22740
+ })
22741
+ .catch(function (e) {
22742
+ logger$2.error('Error recording fetch request to ' + req.url + ': ' + String(e));
22743
+ });
22744
+
22745
+ return originalFetchPromise;
22746
+ };
22747
+ });
22748
+ return function() {
22749
+ restorePatch();
22750
+ };
22751
+ }
22752
+
22753
+ /**
22754
+ * @param {networkCallback} callback
22755
+ * @param {Window} win
22756
+ * @param {NetworkRecordOptions} options
22757
+ * @returns {listenerHandler}
22758
+ */
22759
+ function initNetworkObserver(callback, win, options) {
22760
+ if (!('performance' in win)) {
22761
+ return function() {
22762
+ //
22763
+ };
22764
+ }
22765
+
22766
+ var recordHeaders = Object.assign({}, defaultNetworkOptions.recordHeaders, options.recordHeaders || {});
22767
+ var recordBodyUrls = Object.assign({}, defaultNetworkOptions.recordBodyUrls, options.recordBodyUrls || {});
22768
+ options = Object.assign({}, options, {
22769
+ recordHeaders: recordHeaders,
22770
+ recordBodyUrls: recordBodyUrls,
22771
+ });
22772
+ var networkOptions = /** @type {Required<NetworkRecordOptions>} */ Object.assign({}, defaultNetworkOptions, options);
22773
+
22774
+ /** @type {networkCallback} */
22775
+ var cb = function(data) {
22776
+ var requests = data.requests.filter(function(request) {
22777
+ var shouldIgnoreUrl = urlMatchesRegexList(request.url, networkOptions.ignoreRequestUrls || []);
22778
+ return !shouldIgnoreUrl && !networkOptions.ignoreRequestFn(request);
22779
+ });
22780
+ if (requests.length > 0 || data.isInitial) {
22781
+ callback(Object.assign({}, data, { requests: requests }));
22782
+ }
22783
+ };
22784
+ var performanceObserver = initPerformanceObserver(cb, win, networkOptions);
22785
+ var xhrObserver = initXhrObserver(cb, win, networkOptions);
22786
+ var fetchObserver = initFetchObserver(cb, win, networkOptions);
22787
+ return function() {
22788
+ performanceObserver();
22789
+ xhrObserver();
22790
+ fetchObserver();
22791
+ };
22792
+ }
22793
+
22794
+ // arbitrary .mp suffix in case rrweb does publish this plugin later and we use it but need to handle
22795
+ // a changed format in the mixpanel product.
22796
+ var NETWORK_PLUGIN_NAME = 'rrweb/network@1.mp';
22797
+
22798
+ /**
22799
+ * @param {NetworkRecordOptions} [options]
22800
+ * @returns {RecordPlugin}
22801
+ */
22802
+ var getRecordNetworkPlugin = function(options) {
22803
+ return {
22804
+ name: NETWORK_PLUGIN_NAME,
22805
+ observer: initNetworkObserver,
22806
+ options: options,
22807
+ };
22808
+ };
22809
+
22087
22810
  /**
22088
22811
  * @typedef {import('../index').RecordPrivacyConfig} RecordPrivacyConfig
22089
22812
  */
@@ -22317,6 +23040,31 @@
22317
23040
 
22318
23041
  var privacyConfig = getPrivacyConfig(this._mixpanel);
22319
23042
 
23043
+ var plugins = [];
23044
+ if (this.getConfig('record_network')) {
23045
+ var options = this.getConfig('record_network_options') || {};
23046
+ // don't track requests to Mixpanel /record API
23047
+ var ignoreRequestUrls = (options.ignoreRequestUrls || []).slice();
23048
+ ignoreRequestUrls.push(this._getApiRoute());
23049
+ options.ignoreRequestUrls = ignoreRequestUrls;
23050
+
23051
+ plugins.push(getRecordNetworkPlugin(options));
23052
+ }
23053
+
23054
+ if (this.getConfig('record_console')) {
23055
+ plugins.push(
23056
+ getRecordConsolePlugin({
23057
+ stringifyOptions: {
23058
+ stringLengthLimit: 1000,
23059
+ numOfKeysLimit: 50,
23060
+ depthOfLimit: 2
23061
+ }
23062
+ })
23063
+ );
23064
+ }
23065
+
23066
+ var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$1);
23067
+
22320
23068
  try {
22321
23069
  this._stopRecording = this._rrwebRecord({
22322
23070
  'emit': function (ev) {
@@ -22351,19 +23099,13 @@
22351
23099
  'maskTextSelector': '*',
22352
23100
  'maskInputFn': this._getMaskFn(shouldMaskInput, privacyConfig),
22353
23101
  'maskTextFn': this._getMaskFn(shouldMaskText, privacyConfig),
23102
+ 'recordCrossOriginIframes': validatedOrigins.length > 0,
23103
+ 'allowedIframeOrigins': validatedOrigins,
22354
23104
  'recordCanvas': this.getConfig('record_canvas'),
22355
23105
  'sampling': {
22356
23106
  'canvas': 15
22357
23107
  },
22358
- 'plugins': this.getConfig('record_console') ? [
22359
- getRecordConsolePlugin({
22360
- stringifyOptions: {
22361
- stringLengthLimit: 1000,
22362
- numOfKeysLimit: 50,
22363
- depthOfLimit: 2
22364
- }
22365
- })
22366
- ] : []
23108
+ 'plugins': plugins,
22367
23109
  });
22368
23110
  } catch (err) {
22369
23111
  this.reportError('Unexpected error when starting rrweb recording.', err);
@@ -22478,6 +23220,10 @@
22478
23220
  return recording;
22479
23221
  };
22480
23222
 
23223
+ SessionRecording.prototype._getApiRoute = function () {
23224
+ return this.getConfig('api_routes')['record'];
23225
+ };
23226
+
22481
23227
  SessionRecording.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
22482
23228
  var onSuccess = function (response, responseBody) {
22483
23229
  // Update batch specific props only if the request was successful to guarantee ordering.
@@ -22497,7 +23243,7 @@
22497
23243
  });
22498
23244
  }.bind(this);
22499
23245
  var apiHost = (this._mixpanel.get_api_host && this._mixpanel.get_api_host('record')) || this.getConfig('api_host');
22500
- win['fetch'](apiHost + '/' + this.getConfig('api_routes')['record'] + '?' + new URLSearchParams(reqParams), {
23246
+ win['fetch'](apiHost + '/' + this._getApiRoute() + '?' + new URLSearchParams(reqParams), {
22501
23247
  'method': 'POST',
22502
23248
  'headers': {
22503
23249
  'Authorization': 'Basic ' + btoa(this.getConfig('token') + ':'),
@@ -22898,8 +23644,12 @@
22898
23644
  this.startRecording({shouldStopBatcher: true});
22899
23645
  };
22900
23646
 
23647
+ MixpanelRecorder.prototype.isRecording = function () {
23648
+ return this.activeRecording && !this.activeRecording.isRrwebStopped();
23649
+ };
23650
+
22901
23651
  MixpanelRecorder.prototype.getActiveReplayId = function () {
22902
- if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
23652
+ if (this.isRecording()) {
22903
23653
  return this.activeRecording.replayId;
22904
23654
  } else {
22905
23655
  return null;