mixpanel-browser 2.76.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 (49) hide show
  1. package/.github/dependabot.yml +8 -0
  2. package/.github/workflows/integration-tests.yml +2 -2
  3. package/.github/workflows/unit-tests.yml +2 -2
  4. package/CHANGELOG.md +4 -0
  5. package/dist/async-modules/{mixpanel-recorder-bIS4LMGd.js → mixpanel-recorder-DLKbUIEE.js} +84 -10
  6. package/dist/async-modules/mixpanel-recorder-wIWnMDLA.min.js +2 -0
  7. package/dist/async-modules/mixpanel-recorder-wIWnMDLA.min.js.map +1 -0
  8. package/dist/async-modules/{mixpanel-targeting-VOeN7RWY.min.js → mixpanel-targeting-CTcftSJC.min.js} +2 -2
  9. package/dist/async-modules/{mixpanel-targeting-VOeN7RWY.min.js.map → mixpanel-targeting-CTcftSJC.min.js.map} +1 -1
  10. package/dist/async-modules/{mixpanel-targeting-BcAPS-Mz.js → mixpanel-targeting-CmVvUyFM.js} +1 -1
  11. package/dist/mixpanel-core.cjs.d.ts +2 -1
  12. package/dist/mixpanel-core.cjs.js +183 -52
  13. package/dist/mixpanel-recorder.js +84 -10
  14. package/dist/mixpanel-recorder.min.js +1 -1
  15. package/dist/mixpanel-recorder.min.js.map +1 -1
  16. package/dist/mixpanel-targeting.js +1 -1
  17. package/dist/mixpanel-targeting.min.js +1 -1
  18. package/dist/mixpanel-targeting.min.js.map +1 -1
  19. package/dist/mixpanel-with-async-modules.cjs.d.ts +2 -1
  20. package/dist/mixpanel-with-async-modules.cjs.js +185 -54
  21. package/dist/mixpanel-with-async-recorder.cjs.d.ts +2 -1
  22. package/dist/mixpanel-with-async-recorder.cjs.js +185 -54
  23. package/dist/mixpanel-with-recorder.d.ts +2 -1
  24. package/dist/mixpanel-with-recorder.js +272 -90
  25. package/dist/mixpanel-with-recorder.min.d.ts +2 -1
  26. package/dist/mixpanel-with-recorder.min.js +1 -1
  27. package/dist/mixpanel.amd.d.ts +2 -1
  28. package/dist/mixpanel.amd.js +272 -90
  29. package/dist/mixpanel.cjs.d.ts +2 -1
  30. package/dist/mixpanel.cjs.js +272 -90
  31. package/dist/mixpanel.globals.js +185 -54
  32. package/dist/mixpanel.min.js +190 -186
  33. package/dist/mixpanel.module.d.ts +2 -1
  34. package/dist/mixpanel.module.js +272 -90
  35. package/dist/mixpanel.umd.d.ts +2 -1
  36. package/dist/mixpanel.umd.js +272 -90
  37. package/dist/rrweb-bundled.js +61 -9
  38. package/dist/rrweb-compiled.js +56 -9
  39. package/package.json +6 -5
  40. package/src/config.js +1 -1
  41. package/src/index.d.ts +2 -1
  42. package/src/mixpanel-core.js +1 -1
  43. package/src/recorder/session-recording.js +5 -1
  44. package/src/recorder/utils.js +27 -1
  45. package/src/recorder-manager.js +110 -2
  46. package/testServer.js +14 -1
  47. package/dist/async-modules/mixpanel-recorder-hFoTniVR.min.js +0 -2
  48. package/dist/async-modules/mixpanel-recorder-hFoTniVR.min.js.map +0 -1
  49. /package/src/loaders/{loader-module-with-async-recorder.d.ts → loader-module-with-async-modules.d.ts} +0 -0
@@ -27,7 +27,7 @@ if (typeof(window) === 'undefined') {
27
27
 
28
28
  var Config = {
29
29
  DEBUG: false,
30
- LIB_VERSION: '2.76.0'
30
+ LIB_VERSION: '2.77.0'
31
31
  };
32
32
 
33
33
  // Window global names for async modules
@@ -10735,13 +10735,7 @@ var MutationBuffer = /*#__PURE__*/ function() {
10735
10735
  };
10736
10736
  while(_this.mapRemoves.length){
10737
10737
  var removedNode = _this.mapRemoves.shift();
10738
- if (removedNode.nodeName === "IFRAME") {
10739
- try {
10740
- _this.iframeManager.removeIframe(removedNode);
10741
- } catch (e2) {}
10742
- } else {
10743
- _this.stylesheetManager.cleanupStylesheetsForRemovedNode(removedNode);
10744
- }
10738
+ _this.cleanupRemovedNode(removedNode);
10745
10739
  _this.mirror.removeNodeFromMap(removedNode);
10746
10740
  }
10747
10741
  for(var _iterator = _create_for_of_iterator_helper_loose(_this.movedSet), _step; !(_step = _iterator()).done;){
@@ -11061,6 +11055,20 @@ var MutationBuffer = /*#__PURE__*/ function() {
11061
11055
  }
11062
11056
  }
11063
11057
  });
11058
+ __publicField$1(this, "cleanupRemovedNode", function(node2) {
11059
+ if (node2.nodeName === "IFRAME") {
11060
+ try {
11061
+ _this.iframeManager.removeIframe(node2);
11062
+ } catch (e2) {}
11063
+ } else {
11064
+ try {
11065
+ _this.stylesheetManager.cleanupStylesheetsForRemovedNode(node2);
11066
+ } catch (e2) {}
11067
+ }
11068
+ node2.childNodes.forEach(function(child) {
11069
+ _this.cleanupRemovedNode(child);
11070
+ });
11071
+ });
11064
11072
  }
11065
11073
  var _proto = MutationBuffer.prototype;
11066
11074
  _proto.init = function init(options) {
@@ -13288,6 +13296,31 @@ var ProcessedNodeManager = /*#__PURE__*/ function() {
13288
13296
  _proto.destroy = function destroy() {};
13289
13297
  return ProcessedNodeManager;
13290
13298
  }();
13299
+ function toOrigin(url) {
13300
+ try {
13301
+ var origin = new URL(url).origin;
13302
+ return origin !== "null" ? origin : null;
13303
+ } catch (e) {
13304
+ return null;
13305
+ }
13306
+ }
13307
+ function buildAllowedOriginSet(origins) {
13308
+ if (!Array.isArray(origins) || origins.length === 0) {
13309
+ throw new Error("[rrweb] allowedIframeOrigins must be a non-empty array of origin strings.");
13310
+ }
13311
+ var set = /* @__PURE__ */ new Set();
13312
+ for(var i2 = 0; i2 < origins.length; i2++){
13313
+ var entry = origins[i2];
13314
+ if (typeof entry !== "string") {
13315
+ throw new Error("[rrweb] allowedIframeOrigins[" + i2 + "] must be a string, got " + (typeof entry === "undefined" ? "undefined" : _type_of(entry)) + ".");
13316
+ }
13317
+ var origin = toOrigin(entry);
13318
+ if (origin) {
13319
+ set.add(origin);
13320
+ }
13321
+ }
13322
+ return Object.freeze(set);
13323
+ }
13291
13324
  var wrappedEmit;
13292
13325
  var takeFullSnapshot$1;
13293
13326
  var canvasManager;
@@ -13309,10 +13342,17 @@ try {
13309
13342
  var mirror = createMirror$2();
13310
13343
  function record(options) {
13311
13344
  if (options === void 0) options = {};
13312
- 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() {
13345
+ 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() {
13313
13346
  return false;
13314
13347
  } : _options_keepIframeSrcFn, _options_ignoreCSSAttributes = options.ignoreCSSAttributes, ignoreCSSAttributes = _options_ignoreCSSAttributes === void 0 ? /* @__PURE__ */ new Set([]) : _options_ignoreCSSAttributes, errorHandler2 = options.errorHandler;
13315
13348
  registerErrorHandler(errorHandler2);
13349
+ var validatedOrigins;
13350
+ if (recordCrossOriginIframes && allowedIframeOrigins && allowedIframeOrigins.length > 0) {
13351
+ validatedOrigins = buildAllowedOriginSet(allowedIframeOrigins);
13352
+ if (validatedOrigins.size === 0) {
13353
+ validatedOrigins = void 0;
13354
+ }
13355
+ }
13316
13356
  var inEmittingFrame = recordCrossOriginIframes ? window.parent === window : true;
13317
13357
  var passEmitsToParent = false;
13318
13358
  if (!inEmittingFrame) {
@@ -13404,7 +13444,14 @@ function record(options) {
13404
13444
  origin: window.location.origin,
13405
13445
  isCheckout: isCheckout
13406
13446
  };
13407
- window.parent.postMessage(message, "*");
13447
+ if (validatedOrigins) {
13448
+ for(var _iterator = _create_for_of_iterator_helper_loose(validatedOrigins), _step; !(_step = _iterator()).done;){
13449
+ var targetOrigin = _step.value;
13450
+ window.parent.postMessage(message, targetOrigin);
13451
+ }
13452
+ } else {
13453
+ window.parent.postMessage(message, "*");
13454
+ }
13408
13455
  }
13409
13456
  if (e2.type === EventType.FullSnapshot) {
13410
13457
  lastFullSnapshotEvent = e2;
@@ -21188,7 +21235,7 @@ function _addOptOutCheck(method, getConfigValue) {
21188
21235
  };
21189
21236
  }
21190
21237
 
21191
- var logger$7 = console_with_prefix('lock');
21238
+ var logger$8 = console_with_prefix('lock');
21192
21239
 
21193
21240
  /**
21194
21241
  * SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
@@ -21240,7 +21287,7 @@ SharedLock.prototype.withLock = function(lockedCB, pid) {
21240
21287
 
21241
21288
  var delay = function(cb) {
21242
21289
  if (new Date().getTime() - startTime > timeoutMS) {
21243
- logger$7.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
21290
+ logger$8.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
21244
21291
  storage.removeItem(keyZ);
21245
21292
  storage.removeItem(keyY);
21246
21293
  loop();
@@ -21387,7 +21434,7 @@ LocalStorageWrapper.prototype.removeItem = function (key) {
21387
21434
  }, this));
21388
21435
  };
21389
21436
 
21390
- var logger$6 = console_with_prefix('batch');
21437
+ var logger$7 = console_with_prefix('batch');
21391
21438
 
21392
21439
  /**
21393
21440
  * RequestQueue: queue for batching API requests with localStorage backup for retries.
@@ -21416,7 +21463,7 @@ var RequestQueue = function (storageKey, options) {
21416
21463
  timeoutMS: options.sharedLockTimeoutMS,
21417
21464
  });
21418
21465
  }
21419
- this.reportError = options.errorReporter || _.bind(logger$6.error, logger$6);
21466
+ this.reportError = options.errorReporter || _.bind(logger$7.error, logger$7);
21420
21467
 
21421
21468
  this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
21422
21469
 
@@ -21749,7 +21796,7 @@ RequestQueue.prototype.clear = function () {
21749
21796
  // maximum interval between request retries after exponential backoff
21750
21797
  var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
21751
21798
 
21752
- var logger$5 = console_with_prefix('batch');
21799
+ var logger$6 = console_with_prefix('batch');
21753
21800
 
21754
21801
  /**
21755
21802
  * RequestBatcher: manages the queueing, flushing, retry etc of requests of one
@@ -21877,7 +21924,7 @@ RequestBatcher.prototype.sendRequestPromise = function(data, options) {
21877
21924
  */
21878
21925
  RequestBatcher.prototype.flush = function(options) {
21879
21926
  if (this.requestInProgress) {
21880
- logger$5.log('Flush: Request already in progress');
21927
+ logger$6.log('Flush: Request already in progress');
21881
21928
  return PromisePolyfill.resolve();
21882
21929
  }
21883
21930
 
@@ -22054,7 +22101,7 @@ RequestBatcher.prototype.flush = function(options) {
22054
22101
  if (options.unloading) {
22055
22102
  requestOptions.transport = 'sendBeacon';
22056
22103
  }
22057
- logger$5.log('MIXPANEL REQUEST:', dataForRequest);
22104
+ logger$6.log('MIXPANEL REQUEST:', dataForRequest);
22058
22105
  return this.sendRequestPromise(dataForRequest, requestOptions).then(batchSendCallback);
22059
22106
  }, this))
22060
22107
  .catch(_.bind(function(err) {
@@ -22067,7 +22114,7 @@ RequestBatcher.prototype.flush = function(options) {
22067
22114
  * Log error to global logger and optional user-defined logger.
22068
22115
  */
22069
22116
  RequestBatcher.prototype.reportError = function(msg, err) {
22070
- logger$5.error.apply(logger$5.error, arguments);
22117
+ logger$6.error.apply(logger$6.error, arguments);
22071
22118
  if (this.errorReporter) {
22072
22119
  try {
22073
22120
  if (!(err instanceof Error)) {
@@ -22075,7 +22122,7 @@ RequestBatcher.prototype.reportError = function(msg, err) {
22075
22122
  }
22076
22123
  this.errorReporter(msg, err);
22077
22124
  } catch(err) {
22078
- logger$5.error(err);
22125
+ logger$6.error(err);
22079
22126
  }
22080
22127
  }
22081
22128
  };
@@ -22092,6 +22139,29 @@ var isRecordingExpired = function(serializedRecording) {
22092
22139
 
22093
22140
  var RECORD_ENQUEUE_THROTTLE_MS = 250;
22094
22141
 
22142
+ var validateAllowedOrigins = function(origins, logger) {
22143
+ if (!_.isArray(origins)) {
22144
+ if (origins) {
22145
+ logger.critical('record_allowed_iframe_origins must be an array of origin strings, cross-origin recording will be disabled.');
22146
+ }
22147
+ return [];
22148
+ }
22149
+ var valid = [];
22150
+ for (var i = 0; i < origins.length; i++) {
22151
+ try {
22152
+ var origin = new URL(origins[i]).origin;
22153
+ if (origin === 'null') {
22154
+ logger.critical(origins[i] + ' has an opaque origin. Skipping this entry.');
22155
+ continue;
22156
+ }
22157
+ valid.push(origin);
22158
+ } catch (e) {
22159
+ logger.critical(origins[i] + ' is not a valid origin URL. Skipping this entry.');
22160
+ }
22161
+ }
22162
+ return valid;
22163
+ };
22164
+
22095
22165
  // stateless utils
22096
22166
  // mostly from https://github.com/mixpanel/mixpanel-js/blob/989ada50f518edab47b9c4fd9535f9fbd5ec5fc0/src/autotrack-utils.js
22097
22167
 
@@ -22197,7 +22267,7 @@ var EVENT_HANDLER_ATTRIBUTES = [
22197
22267
 
22198
22268
  var MAX_DEPTH = 5;
22199
22269
 
22200
- var logger$4 = console_with_prefix('autocapture');
22270
+ var logger$5 = console_with_prefix('autocapture');
22201
22271
 
22202
22272
 
22203
22273
  function getClasses(el) {
@@ -22461,7 +22531,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
22461
22531
  return false;
22462
22532
  }
22463
22533
  } catch (err) {
22464
- logger$4.critical('Error while checking element in allowElementCallback', err);
22534
+ logger$5.critical('Error while checking element in allowElementCallback', err);
22465
22535
  return false;
22466
22536
  }
22467
22537
  }
@@ -22478,7 +22548,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
22478
22548
  return true;
22479
22549
  }
22480
22550
  } catch (err) {
22481
- logger$4.critical('Error while checking selector: ' + sel, err);
22551
+ logger$5.critical('Error while checking selector: ' + sel, err);
22482
22552
  }
22483
22553
  }
22484
22554
  return false;
@@ -22493,7 +22563,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
22493
22563
  return true;
22494
22564
  }
22495
22565
  } catch (err) {
22496
- logger$4.critical('Error while checking element in blockElementCallback', err);
22566
+ logger$5.critical('Error while checking element in blockElementCallback', err);
22497
22567
  return true;
22498
22568
  }
22499
22569
  }
@@ -22507,7 +22577,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
22507
22577
  return true;
22508
22578
  }
22509
22579
  } catch (err) {
22510
- logger$4.critical('Error while checking selector: ' + sel, err);
22580
+ logger$5.critical('Error while checking selector: ' + sel, err);
22511
22581
  }
22512
22582
  }
22513
22583
  }
@@ -23063,7 +23133,7 @@ function shouldMaskText(element, privacyConfig) {
23063
23133
  *
23064
23134
  */
23065
23135
 
23066
- var logger$3 = console_with_prefix('network-plugin');
23136
+ var logger$4 = console_with_prefix('network-plugin');
23067
23137
 
23068
23138
  /**
23069
23139
  * Get the time origin for converting performance timestamps to absolute timestamps.
@@ -23215,7 +23285,7 @@ function truncateBody(str) {
23215
23285
  return str;
23216
23286
  }
23217
23287
  if (str.length > MAX_BODY_SIZE) {
23218
- logger$3.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
23288
+ logger$4.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
23219
23289
  return str.substring(0, MAX_BODY_SIZE) + '... [truncated]';
23220
23290
  }
23221
23291
  return str;
@@ -23229,7 +23299,7 @@ function truncateBody(str) {
23229
23299
  */
23230
23300
  function initPerformanceObserver(cb, win, options) {
23231
23301
  if (!win.PerformanceObserver) {
23232
- logger$3.error('PerformanceObserver not supported');
23302
+ logger$4.error('PerformanceObserver not supported');
23233
23303
  return function() {
23234
23304
  //
23235
23305
  };
@@ -23382,7 +23452,7 @@ function getRequestPerformanceEntry(win, initiatorType, url, after, before, atte
23382
23452
  attempt = 0;
23383
23453
  }
23384
23454
  if (attempt > 10) {
23385
- logger$3.error('Cannot find performance entry');
23455
+ logger$4.error('Cannot find performance entry');
23386
23456
  return Promise.resolve(null);
23387
23457
  }
23388
23458
  var urlPerformanceEntries = /** @type {PerformanceResourceTiming[]} */ (
@@ -23503,7 +23573,7 @@ function initXhrObserver(cb, win, options) {
23503
23573
  )
23504
23574
  .then(function(entry) {
23505
23575
  if (!entry) {
23506
- logger$3.error('Failed to get performance entry for XHR request to ' + req.url);
23576
+ logger$4.error('Failed to get performance entry for XHR request to ' + req.url);
23507
23577
  return;
23508
23578
  }
23509
23579
  /** @type {NetworkRequest} */
@@ -23523,7 +23593,7 @@ function initXhrObserver(cb, win, options) {
23523
23593
  cb({ requests: [request] });
23524
23594
  })
23525
23595
  .catch(function(e) {
23526
- logger$3.error('Error recording XHR request to ' + req.url + ': ' + String(e));
23596
+ logger$4.error('Error recording XHR request to ' + req.url + ': ' + String(e));
23527
23597
  });
23528
23598
  });
23529
23599
 
@@ -23615,7 +23685,7 @@ function initFetchObserver(cb, win, options) {
23615
23685
  })
23616
23686
  .then(function(entry) {
23617
23687
  if (!entry) {
23618
- logger$3.error('Failed to get performance entry for fetch request to ' + req.url);
23688
+ logger$4.error('Failed to get performance entry for fetch request to ' + req.url);
23619
23689
  return;
23620
23690
  }
23621
23691
  /** @type {NetworkRequest} */
@@ -23635,7 +23705,7 @@ function initFetchObserver(cb, win, options) {
23635
23705
  cb({ requests: [request] });
23636
23706
  })
23637
23707
  .catch(function (e) {
23638
- logger$3.error('Error recording fetch request to ' + req.url + ': ' + String(e));
23708
+ logger$4.error('Error recording fetch request to ' + req.url + ': ' + String(e));
23639
23709
  });
23640
23710
 
23641
23711
  return originalFetchPromise;
@@ -23708,7 +23778,7 @@ var getRecordNetworkPlugin = function(options) {
23708
23778
  */
23709
23779
 
23710
23780
 
23711
- var logger$2 = console_with_prefix('recorder');
23781
+ var logger$3 = console_with_prefix('recorder');
23712
23782
  var CompressionStream = win['CompressionStream'];
23713
23783
 
23714
23784
  var RECORDER_BATCHER_LIB_CONFIG = {
@@ -23888,14 +23958,14 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
23888
23958
  }
23889
23959
 
23890
23960
  if (this._stopRecording !== null) {
23891
- logger$2.log('Recording already in progress, skipping startRecording.');
23961
+ logger$3.log('Recording already in progress, skipping startRecording.');
23892
23962
  return;
23893
23963
  }
23894
23964
 
23895
23965
  this.recordMaxMs = this.getConfig('record_max_ms');
23896
23966
  if (this.recordMaxMs > MAX_RECORDING_MS) {
23897
23967
  this.recordMaxMs = MAX_RECORDING_MS;
23898
- logger$2.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
23968
+ logger$3.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
23899
23969
  }
23900
23970
 
23901
23971
  if (!this.maxExpires) {
@@ -23959,6 +24029,8 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
23959
24029
  );
23960
24030
  }
23961
24031
 
24032
+ var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$3);
24033
+
23962
24034
  try {
23963
24035
  this._stopRecording = this._rrwebRecord({
23964
24036
  'emit': function (ev) {
@@ -23993,6 +24065,8 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
23993
24065
  'maskTextSelector': '*',
23994
24066
  'maskInputFn': this._getMaskFn(shouldMaskInput, privacyConfig),
23995
24067
  'maskTextFn': this._getMaskFn(shouldMaskText, privacyConfig),
24068
+ 'recordCrossOriginIframes': validatedOrigins.length > 0,
24069
+ 'allowedIframeOrigins': validatedOrigins,
23996
24070
  'recordCanvas': this.getConfig('record_canvas'),
23997
24071
  'sampling': {
23998
24072
  'canvas': 15
@@ -24217,14 +24291,14 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
24217
24291
 
24218
24292
 
24219
24293
  SessionRecording.prototype.reportError = function(msg, err) {
24220
- logger$2.error.apply(logger$2.error, arguments);
24294
+ logger$3.error.apply(logger$3.error, arguments);
24221
24295
  try {
24222
24296
  if (!err && !(msg instanceof Error)) {
24223
24297
  msg = new Error(msg);
24224
24298
  }
24225
24299
  this.getConfig('error_reporter')(msg, err);
24226
24300
  } catch(err) {
24227
- logger$2.error(err);
24301
+ logger$3.error(err);
24228
24302
  }
24229
24303
  };
24230
24304
 
@@ -24253,7 +24327,7 @@ SessionRecording.prototype._getRecordMinMs = function() {
24253
24327
  var configValue = this.getConfig('record_min_ms');
24254
24328
 
24255
24329
  if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
24256
- logger$2.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
24330
+ logger$3.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
24257
24331
  return MAX_VALUE_FOR_MIN_RECORDING_MS;
24258
24332
  }
24259
24333
 
@@ -24416,7 +24490,7 @@ RecordingRegistry.prototype.flushInactiveRecordings = function () {
24416
24490
  .catch(this.handleError.bind(this));
24417
24491
  };
24418
24492
 
24419
- var logger$1 = console_with_prefix('recorder');
24493
+ var logger$2 = console_with_prefix('recorder');
24420
24494
 
24421
24495
  /**
24422
24496
  * Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
@@ -24432,7 +24506,7 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
24432
24506
  */
24433
24507
  this.recordingRegistry = new RecordingRegistry({
24434
24508
  mixpanelInstance: this.mixpanelInstance,
24435
- errorReporter: logger$1.error,
24509
+ errorReporter: logger$2.error,
24436
24510
  sharedLockStorage: sharedLockStorage
24437
24511
  });
24438
24512
  this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
@@ -24444,17 +24518,17 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
24444
24518
  MixpanelRecorder.prototype.startRecording = function(options) {
24445
24519
  options = options || {};
24446
24520
  if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
24447
- logger$1.log('Recording already in progress, skipping startRecording.');
24521
+ logger$2.log('Recording already in progress, skipping startRecording.');
24448
24522
  return;
24449
24523
  }
24450
24524
 
24451
24525
  var onIdleTimeout = function () {
24452
- logger$1.log('Idle timeout reached, restarting recording.');
24526
+ logger$2.log('Idle timeout reached, restarting recording.');
24453
24527
  this.resetRecording();
24454
24528
  }.bind(this);
24455
24529
 
24456
24530
  var onMaxLengthReached = function () {
24457
- logger$1.log('Max recording length reached, stopping recording.');
24531
+ logger$2.log('Max recording length reached, stopping recording.');
24458
24532
  this.resetRecording();
24459
24533
  }.bind(this);
24460
24534
 
@@ -24524,7 +24598,7 @@ MixpanelRecorder.prototype.resumeRecording = function (startNewIfInactive) {
24524
24598
  } else if (startNewIfInactive) {
24525
24599
  return this.startRecording({shouldStopBatcher: false});
24526
24600
  } else {
24527
- logger$1.log('No resumable recording found.');
24601
+ logger$2.log('No resumable recording found.');
24528
24602
  return null;
24529
24603
  }
24530
24604
  }.bind(this));
@@ -25189,7 +25263,7 @@ ShadowDOMObserver.prototype.observeShadowRoot = function(shadowRoot) {
25189
25263
  observer.observe(shadowRoot, this.observerConfig);
25190
25264
  this.shadowObservers.push(observer);
25191
25265
  } catch (e) {
25192
- logger$4.critical('Error while observing shadow root', e);
25266
+ logger$5.critical('Error while observing shadow root', e);
25193
25267
  }
25194
25268
  };
25195
25269
 
@@ -25200,7 +25274,7 @@ ShadowDOMObserver.prototype.start = function() {
25200
25274
  }
25201
25275
 
25202
25276
  if (!weakSetSupported()) {
25203
- logger$4.critical('Shadow DOM observation unavailable: WeakSet not supported');
25277
+ logger$5.critical('Shadow DOM observation unavailable: WeakSet not supported');
25204
25278
  return;
25205
25279
  }
25206
25280
 
@@ -25216,7 +25290,7 @@ ShadowDOMObserver.prototype.stop = function() {
25216
25290
  try {
25217
25291
  this.shadowObservers[i].disconnect();
25218
25292
  } catch (e) {
25219
- logger$4.critical('Error while disconnecting shadow DOM observer', e);
25293
+ logger$5.critical('Error while disconnecting shadow DOM observer', e);
25220
25294
  }
25221
25295
  }
25222
25296
  this.shadowObservers = [];
@@ -25404,7 +25478,7 @@ DeadClickTracker.prototype.startTracking = function() {
25404
25478
 
25405
25479
  this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
25406
25480
  } catch (e) {
25407
- logger$4.critical('Error while setting up mutation observer', e);
25481
+ logger$5.critical('Error while setting up mutation observer', e);
25408
25482
  }
25409
25483
  }
25410
25484
 
@@ -25419,7 +25493,7 @@ DeadClickTracker.prototype.startTracking = function() {
25419
25493
  );
25420
25494
  this.shadowDOMObserver.start();
25421
25495
  } catch (e) {
25422
- logger$4.critical('Error while setting up shadow DOM observer', e);
25496
+ logger$5.critical('Error while setting up shadow DOM observer', e);
25423
25497
  this.shadowDOMObserver = null;
25424
25498
  }
25425
25499
  }
@@ -25446,7 +25520,7 @@ DeadClickTracker.prototype.stopTracking = function() {
25446
25520
  try {
25447
25521
  listener.target.removeEventListener(listener.event, listener.handler, listener.options);
25448
25522
  } catch (e) {
25449
- logger$4.critical('Error while removing event listener', e);
25523
+ logger$5.critical('Error while removing event listener', e);
25450
25524
  }
25451
25525
  }
25452
25526
  this.eventListeners = [];
@@ -25455,7 +25529,7 @@ DeadClickTracker.prototype.stopTracking = function() {
25455
25529
  try {
25456
25530
  this.mutationObserver.disconnect();
25457
25531
  } catch (e) {
25458
- logger$4.critical('Error while disconnecting mutation observer', e);
25532
+ logger$5.critical('Error while disconnecting mutation observer', e);
25459
25533
  }
25460
25534
  this.mutationObserver = null;
25461
25535
  }
@@ -25464,7 +25538,7 @@ DeadClickTracker.prototype.stopTracking = function() {
25464
25538
  try {
25465
25539
  this.shadowDOMObserver.stop();
25466
25540
  } catch (e) {
25467
- logger$4.critical('Error while stopping shadow DOM observer', e);
25541
+ logger$5.critical('Error while stopping shadow DOM observer', e);
25468
25542
  }
25469
25543
  this.shadowDOMObserver = null;
25470
25544
  }
@@ -25542,7 +25616,7 @@ var Autocapture = function(mp) {
25542
25616
 
25543
25617
  Autocapture.prototype.init = function() {
25544
25618
  if (!minDOMApisSupported()) {
25545
- logger$4.critical('Autocapture unavailable: missing required DOM APIs');
25619
+ logger$5.critical('Autocapture unavailable: missing required DOM APIs');
25546
25620
  return;
25547
25621
  }
25548
25622
  this.initPageListeners();
@@ -25582,7 +25656,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
25582
25656
  try {
25583
25657
  return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
25584
25658
  } catch (err) {
25585
- logger$4.critical('Error while checking block URL regexes: ', err);
25659
+ logger$5.critical('Error while checking block URL regexes: ', err);
25586
25660
  return true;
25587
25661
  }
25588
25662
  }
@@ -25595,7 +25669,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
25595
25669
  try {
25596
25670
  return urlMatchesRegexList(currentUrl, blockUrlRegexes);
25597
25671
  } catch (err) {
25598
- logger$4.critical('Error while checking block URL regexes: ', err);
25672
+ logger$5.critical('Error while checking block URL regexes: ', err);
25599
25673
  return true;
25600
25674
  }
25601
25675
  };
@@ -25733,7 +25807,7 @@ Autocapture.prototype._initScrollDepthTracking = function() {
25733
25807
  return;
25734
25808
  }
25735
25809
 
25736
- logger$4.log('Initializing scroll depth tracking');
25810
+ logger$5.log('Initializing scroll depth tracking');
25737
25811
 
25738
25812
  this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
25739
25813
 
@@ -25759,7 +25833,7 @@ Autocapture.prototype.initClickTracking = function() {
25759
25833
  if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
25760
25834
  return;
25761
25835
  }
25762
- logger$4.log('Initializing click tracking');
25836
+ logger$5.log('Initializing click tracking');
25763
25837
 
25764
25838
  this.listenerClick = function(ev) {
25765
25839
  if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
@@ -25778,7 +25852,7 @@ Autocapture.prototype.initDeadClickTracking = function() {
25778
25852
  return;
25779
25853
  }
25780
25854
 
25781
- logger$4.log('Initializing dead click tracking');
25855
+ logger$5.log('Initializing dead click tracking');
25782
25856
  if (!this._deadClickTracker) {
25783
25857
  this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
25784
25858
  this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
@@ -25812,7 +25886,7 @@ Autocapture.prototype.initInputTracking = function() {
25812
25886
  if (!this.getConfig(CONFIG_TRACK_INPUT)) {
25813
25887
  return;
25814
25888
  }
25815
- logger$4.log('Initializing input tracking');
25889
+ logger$5.log('Initializing input tracking');
25816
25890
 
25817
25891
  this.listenerChange = function(ev) {
25818
25892
  if (!this.getConfig(CONFIG_TRACK_INPUT)) {
@@ -25829,7 +25903,7 @@ Autocapture.prototype.initPageviewTracking = function() {
25829
25903
  if (!this.pageviewTrackingConfig()) {
25830
25904
  return;
25831
25905
  }
25832
- logger$4.log('Initializing pageview tracking');
25906
+ logger$5.log('Initializing pageview tracking');
25833
25907
 
25834
25908
  var previousTrackedUrl = '';
25835
25909
  var tracked = false;
@@ -25864,7 +25938,7 @@ Autocapture.prototype.initPageviewTracking = function() {
25864
25938
  }
25865
25939
  if (didPathChange) {
25866
25940
  this.lastScrollCheckpoint = 0;
25867
- logger$4.log('Path change: re-initializing scroll depth checkpoints');
25941
+ logger$5.log('Path change: re-initializing scroll depth checkpoints');
25868
25942
  }
25869
25943
  }
25870
25944
  }.bind(this));
@@ -25879,7 +25953,7 @@ Autocapture.prototype.initRageClickTracking = function() {
25879
25953
  return;
25880
25954
  }
25881
25955
 
25882
- logger$4.log('Initializing rage click tracking');
25956
+ logger$5.log('Initializing rage click tracking');
25883
25957
  if (!this._rageClickTracker) {
25884
25958
  this._rageClickTracker = new RageClickTracker();
25885
25959
  }
@@ -25909,7 +25983,7 @@ Autocapture.prototype.initScrollTracking = function() {
25909
25983
  if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
25910
25984
  return;
25911
25985
  }
25912
- logger$4.log('Initializing scroll tracking');
25986
+ logger$5.log('Initializing scroll tracking');
25913
25987
  this.lastScrollCheckpoint = 0;
25914
25988
 
25915
25989
  var scrollTrackFunction = function() {
@@ -25946,7 +26020,7 @@ Autocapture.prototype.initScrollTracking = function() {
25946
26020
  }
25947
26021
  }
25948
26022
  } catch (err) {
25949
- logger$4.critical('Error while calculating scroll percentage', err);
26023
+ logger$5.critical('Error while calculating scroll percentage', err);
25950
26024
  }
25951
26025
  if (shouldTrack) {
25952
26026
  this.mp.track(MP_EV_SCROLL, props);
@@ -25964,7 +26038,7 @@ Autocapture.prototype.initSubmitTracking = function() {
25964
26038
  if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
25965
26039
  return;
25966
26040
  }
25967
- logger$4.log('Initializing submit tracking');
26041
+ logger$5.log('Initializing submit tracking');
25968
26042
 
25969
26043
  this.listenerSubmit = function(ev) {
25970
26044
  if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
@@ -25986,7 +26060,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
25986
26060
  return;
25987
26061
  }
25988
26062
 
25989
- logger$4.log('Initializing page visibility tracking.');
26063
+ logger$5.log('Initializing page visibility tracking.');
25990
26064
  this._initScrollDepthTracking();
25991
26065
  var previousTrackedUrl = _.info.currentUrl();
25992
26066
 
@@ -26071,7 +26145,7 @@ var getTargetingPromise = function(loadExtraBundle, targetingSrc) {
26071
26145
  return win[TARGETING_GLOBAL_NAME];
26072
26146
  };
26073
26147
 
26074
- var logger = console_with_prefix('flags');
26148
+ var logger$1 = console_with_prefix('flags');
26075
26149
  var FLAGS_CONFIG_KEY = 'flags';
26076
26150
 
26077
26151
  var CONFIG_CONTEXT = 'context';
@@ -26114,7 +26188,7 @@ var FeatureFlagManager = function(initOptions) {
26114
26188
 
26115
26189
  FeatureFlagManager.prototype.init = function() {
26116
26190
  if (!this.minApisSupported()) {
26117
- logger.critical('Feature Flags unavailable: missing minimum required APIs');
26191
+ logger$1.critical('Feature Flags unavailable: missing minimum required APIs');
26118
26192
  return;
26119
26193
  }
26120
26194
 
@@ -26149,7 +26223,7 @@ FeatureFlagManager.prototype.isSystemEnabled = function() {
26149
26223
 
26150
26224
  FeatureFlagManager.prototype.updateContext = function(newContext, options) {
26151
26225
  if (!this.isSystemEnabled()) {
26152
- logger.critical('Feature Flags not enabled, cannot update context');
26226
+ logger$1.critical('Feature Flags not enabled, cannot update context');
26153
26227
  return Promise.resolve();
26154
26228
  }
26155
26229
 
@@ -26166,7 +26240,7 @@ FeatureFlagManager.prototype.updateContext = function(newContext, options) {
26166
26240
 
26167
26241
  FeatureFlagManager.prototype.areFlagsReady = function() {
26168
26242
  if (!this.isSystemEnabled()) {
26169
- logger.error('Feature Flags not enabled');
26243
+ logger$1.error('Feature Flags not enabled');
26170
26244
  }
26171
26245
  return !!this.flags;
26172
26246
  };
@@ -26179,7 +26253,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
26179
26253
  var distinctId = this.getMpProperty('distinct_id');
26180
26254
  var deviceId = this.getMpProperty('$device_id');
26181
26255
  var traceparent = generateTraceparent();
26182
- logger.log('Fetching flags for distinct ID: ' + distinctId);
26256
+ logger$1.log('Fetching flags for distinct ID: ' + distinctId);
26183
26257
 
26184
26258
  var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
26185
26259
  var searchParams = new URLSearchParams();
@@ -26278,11 +26352,11 @@ FeatureFlagManager.prototype.fetchFlags = function() {
26278
26352
  this._loadTargetingIfNeeded();
26279
26353
  }.bind(this)).catch(function(error) {
26280
26354
  this.markFetchComplete();
26281
- logger.error(error);
26355
+ logger$1.error(error);
26282
26356
  }.bind(this));
26283
26357
  }.bind(this)).catch(function(error) {
26284
26358
  this.markFetchComplete();
26285
- logger.error(error);
26359
+ logger$1.error(error);
26286
26360
  }.bind(this));
26287
26361
 
26288
26362
  return this.fetchPromise;
@@ -26290,7 +26364,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
26290
26364
 
26291
26365
  FeatureFlagManager.prototype.markFetchComplete = function() {
26292
26366
  if (!this._fetchInProgressStartTime) {
26293
- logger.error('Fetch in progress started time not set, cannot mark fetch complete');
26367
+ logger$1.error('Fetch in progress started time not set, cannot mark fetch complete');
26294
26368
  return;
26295
26369
  }
26296
26370
  this._fetchStartTime = this._fetchInProgressStartTime;
@@ -26312,7 +26386,7 @@ FeatureFlagManager.prototype._loadTargetingIfNeeded = function() {
26312
26386
 
26313
26387
  if (hasPropertyFilters) {
26314
26388
  this.getTargeting().then(function() {
26315
- logger.log('targeting loaded for property filter evaluation');
26389
+ logger$1.log('targeting loaded for property filter evaluation');
26316
26390
  });
26317
26391
  }
26318
26392
  };
@@ -26327,7 +26401,7 @@ FeatureFlagManager.prototype.getTargeting = function() {
26327
26401
  this.loadExtraBundle.bind(this),
26328
26402
  this.targetingSrc
26329
26403
  ).catch(function(error) {
26330
- logger.error('Failed to load targeting: ' + error);
26404
+ logger$1.error('Failed to load targeting: ' + error);
26331
26405
  }.bind(this));
26332
26406
  };
26333
26407
 
@@ -26381,7 +26455,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
26381
26455
 
26382
26456
  // If no targeting library and event has property filters, skip it
26383
26457
  if (!targeting && pendingEvent['property_filters'] && !_.isEmptyObject(pendingEvent['property_filters'])) {
26384
- logger.warn('Skipping event check for "' + flagKey + '" - property filters require targeting library');
26458
+ logger$1.warn('Skipping event check for "' + flagKey + '" - property filters require targeting library');
26385
26459
  return;
26386
26460
  }
26387
26461
 
@@ -26404,7 +26478,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
26404
26478
  }
26405
26479
 
26406
26480
  if (matchResult.error) {
26407
- logger.error('Error checking first-time event for flag "' + flagKey + '": ' + matchResult.error);
26481
+ logger$1.error('Error checking first-time event for flag "' + flagKey + '": ' + matchResult.error);
26408
26482
  return;
26409
26483
  }
26410
26484
 
@@ -26412,7 +26486,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
26412
26486
  return;
26413
26487
  }
26414
26488
 
26415
- logger.log('First-time event matched for flag "' + flagKey + '": ' + eventName);
26489
+ logger$1.log('First-time event matched for flag "' + flagKey + '": ' + eventName);
26416
26490
 
26417
26491
  var newVariant = {
26418
26492
  'key': pendingEvent['pending_variant']['variant_key'],
@@ -26453,7 +26527,7 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
26453
26527
  'first_time_event_hash': firstTimeEventHash
26454
26528
  };
26455
26529
 
26456
- logger.log('Recording first-time event for flag: ' + flagId);
26530
+ logger$1.log('Recording first-time event for flag: ' + flagId);
26457
26531
 
26458
26532
  // Fire-and-forget POST request
26459
26533
  this.fetch.call(win, url, {
@@ -26466,14 +26540,14 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
26466
26540
  'body': JSON.stringify(payload)
26467
26541
  }).catch(function(error) {
26468
26542
  // Silent failure - cohort sync will catch up
26469
- logger.error('Failed to record first-time event for flag ' + flagId + ': ' + error);
26543
+ logger$1.error('Failed to record first-time event for flag ' + flagId + ': ' + error);
26470
26544
  });
26471
26545
  };
26472
26546
 
26473
26547
  FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
26474
26548
  if (!this.fetchPromise) {
26475
26549
  return new Promise(function(resolve) {
26476
- logger.critical('Feature Flags not initialized');
26550
+ logger$1.critical('Feature Flags not initialized');
26477
26551
  resolve(fallback);
26478
26552
  });
26479
26553
  }
@@ -26481,19 +26555,19 @@ FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
26481
26555
  return this.fetchPromise.then(function() {
26482
26556
  return this.getVariantSync(featureName, fallback);
26483
26557
  }.bind(this)).catch(function(error) {
26484
- logger.error(error);
26558
+ logger$1.error(error);
26485
26559
  return fallback;
26486
26560
  });
26487
26561
  };
26488
26562
 
26489
26563
  FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
26490
26564
  if (!this.areFlagsReady()) {
26491
- logger.log('Flags not loaded yet');
26565
+ logger$1.log('Flags not loaded yet');
26492
26566
  return fallback;
26493
26567
  }
26494
26568
  var feature = this.flags.get(featureName);
26495
26569
  if (!feature) {
26496
- logger.log('No flag found: "' + featureName + '"');
26570
+ logger$1.log('No flag found: "' + featureName + '"');
26497
26571
  return fallback;
26498
26572
  }
26499
26573
  this.trackFeatureCheck(featureName, feature);
@@ -26504,14 +26578,14 @@ FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackVal
26504
26578
  return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
26505
26579
  return feature['value'];
26506
26580
  }).catch(function(error) {
26507
- logger.error(error);
26581
+ logger$1.error(error);
26508
26582
  return fallbackValue;
26509
26583
  });
26510
26584
  };
26511
26585
 
26512
26586
  // TODO remove deprecated method
26513
26587
  FeatureFlagManager.prototype.getFeatureData = function(featureName, fallbackValue) {
26514
- logger.critical('mixpanel.flags.get_feature_data() is deprecated and will be removed in a future release. Use mixpanel.flags.get_variant_value() instead.');
26588
+ logger$1.critical('mixpanel.flags.get_feature_data() is deprecated and will be removed in a future release. Use mixpanel.flags.get_variant_value() instead.');
26515
26589
  return this.getVariantValue(featureName, fallbackValue);
26516
26590
  };
26517
26591
 
@@ -26523,7 +26597,7 @@ FeatureFlagManager.prototype.isEnabled = function(featureName, fallbackValue) {
26523
26597
  return this.getVariantValue(featureName).then(function() {
26524
26598
  return this.isEnabledSync(featureName, fallbackValue);
26525
26599
  }.bind(this)).catch(function(error) {
26526
- logger.error(error);
26600
+ logger$1.error(error);
26527
26601
  return fallbackValue;
26528
26602
  });
26529
26603
  };
@@ -26532,7 +26606,7 @@ FeatureFlagManager.prototype.isEnabledSync = function(featureName, fallbackValue
26532
26606
  fallbackValue = fallbackValue || false;
26533
26607
  var val = this.getVariantValueSync(featureName, fallbackValue);
26534
26608
  if (val !== true && val !== false) {
26535
- logger.error('Feature flag "' + featureName + '" value: ' + val + ' is not a boolean; returning fallback value: ' + fallbackValue);
26609
+ logger$1.error('Feature flag "' + featureName + '" value: ' + val + ' is not a boolean; returning fallback value: ' + fallbackValue);
26536
26610
  val = fallbackValue;
26537
26611
  }
26538
26612
  return val;
@@ -26594,6 +26668,12 @@ FeatureFlagManager.prototype['getTargeting'] = FeatureFlagManager.prototype.getT
26594
26668
  /* eslint camelcase: "off" */
26595
26669
 
26596
26670
 
26671
+ var logger = console_with_prefix('recorder');
26672
+
26673
+ var IFRAME_HANDSHAKE_REQUEST = 'mp_iframe_handshake_request';
26674
+ var IFRAME_HANDSHAKE_RESPONSE = 'mp_iframe_handshake_response';
26675
+
26676
+
26597
26677
  /**
26598
26678
  * RecorderManager: manages session recording initialization, lifecycle and state
26599
26679
  * @constructor
@@ -26613,6 +26693,8 @@ var RecorderManager = function(initOptions) {
26613
26693
  this.libBasePath = initOptions.libBasePath;
26614
26694
 
26615
26695
  this._recorder = null;
26696
+ this._parentReplayId = null;
26697
+ this._parentFrameRetryInterval = null;
26616
26698
  };
26617
26699
 
26618
26700
  RecorderManager.prototype.shouldLoadRecorder = function() {
@@ -26666,6 +26748,22 @@ RecorderManager.prototype.checkAndStartSessionRecording = function(force_start,
26666
26748
  }, this));
26667
26749
  }, this);
26668
26750
 
26751
+ // Cross-origin iframe handling
26752
+ var allowedOrigins = validateAllowedOrigins(this.getMpConfig('record_allowed_iframe_origins'), logger);
26753
+ var isCrossOriginRecordingEnabled = allowedOrigins.length > 0;
26754
+
26755
+ if (isCrossOriginRecordingEnabled) {
26756
+ // listen for handshake requests from their own child iframes (including nested)
26757
+ this._setupParentFrameListener(allowedOrigins);
26758
+
26759
+ if (win.parent !== win) {
26760
+ // also wait for parent's replay ID
26761
+ this._setupChildFrameListener(allowedOrigins, loadRecorder);
26762
+ this._sendParentFrameRequestWithRetry(allowedOrigins);
26763
+ return PromisePolyfill.resolve();
26764
+ }
26765
+ }
26766
+
26669
26767
  /**
26670
26768
  * If the user is sampled or start_session_recording is called, we always load the recorder since it's guaranteed a recording should start.
26671
26769
  * Otherwise, if the recording registry has any records then it's likely there's a recording in progress or orphaned data that needs to be flushed.
@@ -26785,6 +26883,10 @@ RecorderManager.prototype.getSessionReplayUrl = function() {
26785
26883
  };
26786
26884
 
26787
26885
  RecorderManager.prototype.getSessionReplayId = function() {
26886
+ // Child iframe uses parent's replay ID
26887
+ if (this._parentReplayId) {
26888
+ return this._parentReplayId;
26889
+ }
26788
26890
  var replay_id = null;
26789
26891
  if (this._recorder) {
26790
26892
  replay_id = this._recorder['replayId'];
@@ -26797,6 +26899,86 @@ RecorderManager.prototype.getRecorder = function() {
26797
26899
  return this._recorder;
26798
26900
  };
26799
26901
 
26902
+ RecorderManager.prototype._setupChildFrameListener = function(allowedOrigins, loadRecorder) {
26903
+ if (this._childFrameMessageHandler) {
26904
+ return;
26905
+ }
26906
+ var self = this;
26907
+ this._childFrameMessageHandler = function(event) {
26908
+ if (allowedOrigins.indexOf(event.origin) === -1) return;
26909
+ var data = event.data;
26910
+ if (data && data['type'] === IFRAME_HANDSHAKE_RESPONSE && data['token'] === self.getMpConfig('token') && data['replayId']) {
26911
+ self._parentReplayId = data['replayId'];
26912
+ if (data['distinctId']) {
26913
+ self.mixpanelInstance['identify'](data['distinctId']);
26914
+ }
26915
+ self._parentFrameRetryActive = false;
26916
+ win.removeEventListener('message', self._childFrameMessageHandler);
26917
+ self._childFrameMessageHandler = null;
26918
+ loadRecorder(true);
26919
+ }
26920
+ };
26921
+ win.addEventListener('message', this._childFrameMessageHandler);
26922
+ };
26923
+
26924
+ RecorderManager.prototype._sendParentFrameRequest = function(allowedOrigins) {
26925
+ var message = {};
26926
+ message['type'] = IFRAME_HANDSHAKE_REQUEST;
26927
+ message['token'] = this.getMpConfig('token');
26928
+ for (var i = 0; i < allowedOrigins.length; i++) {
26929
+ try {
26930
+ win.parent.postMessage(message, allowedOrigins[i]);
26931
+ } catch (e) {
26932
+ // origin mismatch - ignore
26933
+ }
26934
+ }
26935
+ };
26936
+
26937
+ RecorderManager.prototype._sendParentFrameRequestWithRetry = function(allowedOrigins) {
26938
+ var self = this;
26939
+ var maxRetries = 10;
26940
+ var retryCount = 0;
26941
+ var delay = 50;
26942
+ this._parentFrameRetryActive = true;
26943
+
26944
+ this._sendParentFrameRequest(allowedOrigins);
26945
+
26946
+ function scheduleRetry() {
26947
+ setTimeout(function() {
26948
+ if (!self._parentFrameRetryActive || self._parentReplayId || ++retryCount >= maxRetries) {
26949
+ return;
26950
+ }
26951
+ self._sendParentFrameRequest(allowedOrigins);
26952
+ delay *= 2;
26953
+ scheduleRetry();
26954
+ }, delay);
26955
+ }
26956
+ scheduleRetry();
26957
+ };
26958
+
26959
+ RecorderManager.prototype._setupParentFrameListener = function(allowedOrigins) {
26960
+ if (this._parentFrameMessageHandler) {
26961
+ return;
26962
+ }
26963
+ var self = this;
26964
+ this._parentFrameMessageHandler = function(event) {
26965
+ if (allowedOrigins.indexOf(event.origin) === -1) return;
26966
+ var data = event.data;
26967
+ if (data && data['type'] === IFRAME_HANDSHAKE_REQUEST && data['token'] === self.getMpConfig('token')) {
26968
+ var replayId = self.getSessionReplayId();
26969
+ if (replayId) {
26970
+ var response = {};
26971
+ response['type'] = IFRAME_HANDSHAKE_RESPONSE;
26972
+ response['token'] = self.getMpConfig('token');
26973
+ response['replayId'] = replayId;
26974
+ response['distinctId'] = self.getDistinctId();
26975
+ event.source.postMessage(response, event.origin);
26976
+ }
26977
+ }
26978
+ };
26979
+ win.addEventListener('message', this._parentFrameMessageHandler);
26980
+ };
26981
+
26800
26982
  safewrapClass(RecorderManager);
26801
26983
 
26802
26984
  /* eslint camelcase: "off" */
@@ -28171,7 +28353,6 @@ var INIT_SNIPPET = 1;
28171
28353
  /** @const */ var SETTING_FALLBACK = 'fallback';
28172
28354
  /** @const */ var SETTING_DISABLED = 'disabled';
28173
28355
 
28174
-
28175
28356
  /*
28176
28357
  * Dynamic... constants? Is that an oxymoron?
28177
28358
  */
@@ -28256,6 +28437,7 @@ var DEFAULT_CONFIG = {
28256
28437
  'batch_request_timeout_ms': 90000,
28257
28438
  'batch_autostart': true,
28258
28439
  'hooks': {},
28440
+ 'record_allowed_iframe_origins': [],
28259
28441
  'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
28260
28442
  'record_block_selector': 'img, video, audio',
28261
28443
  'record_canvas': false,