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
@@ -25,7 +25,7 @@ if (typeof(window) === 'undefined') {
25
25
 
26
26
  var Config = {
27
27
  DEBUG: false,
28
- LIB_VERSION: '2.76.0'
28
+ LIB_VERSION: '2.77.0'
29
29
  };
30
30
 
31
31
  // Window global names for async modules
@@ -10733,13 +10733,7 @@ var MutationBuffer = /*#__PURE__*/ function() {
10733
10733
  };
10734
10734
  while(_this.mapRemoves.length){
10735
10735
  var removedNode = _this.mapRemoves.shift();
10736
- if (removedNode.nodeName === "IFRAME") {
10737
- try {
10738
- _this.iframeManager.removeIframe(removedNode);
10739
- } catch (e2) {}
10740
- } else {
10741
- _this.stylesheetManager.cleanupStylesheetsForRemovedNode(removedNode);
10742
- }
10736
+ _this.cleanupRemovedNode(removedNode);
10743
10737
  _this.mirror.removeNodeFromMap(removedNode);
10744
10738
  }
10745
10739
  for(var _iterator = _create_for_of_iterator_helper_loose(_this.movedSet), _step; !(_step = _iterator()).done;){
@@ -11059,6 +11053,20 @@ var MutationBuffer = /*#__PURE__*/ function() {
11059
11053
  }
11060
11054
  }
11061
11055
  });
11056
+ __publicField$1(this, "cleanupRemovedNode", function(node2) {
11057
+ if (node2.nodeName === "IFRAME") {
11058
+ try {
11059
+ _this.iframeManager.removeIframe(node2);
11060
+ } catch (e2) {}
11061
+ } else {
11062
+ try {
11063
+ _this.stylesheetManager.cleanupStylesheetsForRemovedNode(node2);
11064
+ } catch (e2) {}
11065
+ }
11066
+ node2.childNodes.forEach(function(child) {
11067
+ _this.cleanupRemovedNode(child);
11068
+ });
11069
+ });
11062
11070
  }
11063
11071
  var _proto = MutationBuffer.prototype;
11064
11072
  _proto.init = function init(options) {
@@ -13286,6 +13294,31 @@ var ProcessedNodeManager = /*#__PURE__*/ function() {
13286
13294
  _proto.destroy = function destroy() {};
13287
13295
  return ProcessedNodeManager;
13288
13296
  }();
13297
+ function toOrigin(url) {
13298
+ try {
13299
+ var origin = new URL(url).origin;
13300
+ return origin !== "null" ? origin : null;
13301
+ } catch (e) {
13302
+ return null;
13303
+ }
13304
+ }
13305
+ function buildAllowedOriginSet(origins) {
13306
+ if (!Array.isArray(origins) || origins.length === 0) {
13307
+ throw new Error("[rrweb] allowedIframeOrigins must be a non-empty array of origin strings.");
13308
+ }
13309
+ var set = /* @__PURE__ */ new Set();
13310
+ for(var i2 = 0; i2 < origins.length; i2++){
13311
+ var entry = origins[i2];
13312
+ if (typeof entry !== "string") {
13313
+ throw new Error("[rrweb] allowedIframeOrigins[" + i2 + "] must be a string, got " + (typeof entry === "undefined" ? "undefined" : _type_of(entry)) + ".");
13314
+ }
13315
+ var origin = toOrigin(entry);
13316
+ if (origin) {
13317
+ set.add(origin);
13318
+ }
13319
+ }
13320
+ return Object.freeze(set);
13321
+ }
13289
13322
  var wrappedEmit;
13290
13323
  var takeFullSnapshot$1;
13291
13324
  var canvasManager;
@@ -13307,10 +13340,17 @@ try {
13307
13340
  var mirror = createMirror$2();
13308
13341
  function record(options) {
13309
13342
  if (options === void 0) options = {};
13310
- 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() {
13343
+ 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() {
13311
13344
  return false;
13312
13345
  } : _options_keepIframeSrcFn, _options_ignoreCSSAttributes = options.ignoreCSSAttributes, ignoreCSSAttributes = _options_ignoreCSSAttributes === void 0 ? /* @__PURE__ */ new Set([]) : _options_ignoreCSSAttributes, errorHandler2 = options.errorHandler;
13313
13346
  registerErrorHandler(errorHandler2);
13347
+ var validatedOrigins;
13348
+ if (recordCrossOriginIframes && allowedIframeOrigins && allowedIframeOrigins.length > 0) {
13349
+ validatedOrigins = buildAllowedOriginSet(allowedIframeOrigins);
13350
+ if (validatedOrigins.size === 0) {
13351
+ validatedOrigins = void 0;
13352
+ }
13353
+ }
13314
13354
  var inEmittingFrame = recordCrossOriginIframes ? window.parent === window : true;
13315
13355
  var passEmitsToParent = false;
13316
13356
  if (!inEmittingFrame) {
@@ -13402,7 +13442,14 @@ function record(options) {
13402
13442
  origin: window.location.origin,
13403
13443
  isCheckout: isCheckout
13404
13444
  };
13405
- window.parent.postMessage(message, "*");
13445
+ if (validatedOrigins) {
13446
+ for(var _iterator = _create_for_of_iterator_helper_loose(validatedOrigins), _step; !(_step = _iterator()).done;){
13447
+ var targetOrigin = _step.value;
13448
+ window.parent.postMessage(message, targetOrigin);
13449
+ }
13450
+ } else {
13451
+ window.parent.postMessage(message, "*");
13452
+ }
13406
13453
  }
13407
13454
  if (e2.type === EventType.FullSnapshot) {
13408
13455
  lastFullSnapshotEvent = e2;
@@ -21186,7 +21233,7 @@ function _addOptOutCheck(method, getConfigValue) {
21186
21233
  };
21187
21234
  }
21188
21235
 
21189
- var logger$7 = console_with_prefix('lock');
21236
+ var logger$8 = console_with_prefix('lock');
21190
21237
 
21191
21238
  /**
21192
21239
  * SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
@@ -21238,7 +21285,7 @@ SharedLock.prototype.withLock = function(lockedCB, pid) {
21238
21285
 
21239
21286
  var delay = function(cb) {
21240
21287
  if (new Date().getTime() - startTime > timeoutMS) {
21241
- logger$7.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
21288
+ logger$8.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
21242
21289
  storage.removeItem(keyZ);
21243
21290
  storage.removeItem(keyY);
21244
21291
  loop();
@@ -21385,7 +21432,7 @@ LocalStorageWrapper.prototype.removeItem = function (key) {
21385
21432
  }, this));
21386
21433
  };
21387
21434
 
21388
- var logger$6 = console_with_prefix('batch');
21435
+ var logger$7 = console_with_prefix('batch');
21389
21436
 
21390
21437
  /**
21391
21438
  * RequestQueue: queue for batching API requests with localStorage backup for retries.
@@ -21414,7 +21461,7 @@ var RequestQueue = function (storageKey, options) {
21414
21461
  timeoutMS: options.sharedLockTimeoutMS,
21415
21462
  });
21416
21463
  }
21417
- this.reportError = options.errorReporter || _.bind(logger$6.error, logger$6);
21464
+ this.reportError = options.errorReporter || _.bind(logger$7.error, logger$7);
21418
21465
 
21419
21466
  this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
21420
21467
 
@@ -21747,7 +21794,7 @@ RequestQueue.prototype.clear = function () {
21747
21794
  // maximum interval between request retries after exponential backoff
21748
21795
  var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
21749
21796
 
21750
- var logger$5 = console_with_prefix('batch');
21797
+ var logger$6 = console_with_prefix('batch');
21751
21798
 
21752
21799
  /**
21753
21800
  * RequestBatcher: manages the queueing, flushing, retry etc of requests of one
@@ -21875,7 +21922,7 @@ RequestBatcher.prototype.sendRequestPromise = function(data, options) {
21875
21922
  */
21876
21923
  RequestBatcher.prototype.flush = function(options) {
21877
21924
  if (this.requestInProgress) {
21878
- logger$5.log('Flush: Request already in progress');
21925
+ logger$6.log('Flush: Request already in progress');
21879
21926
  return PromisePolyfill.resolve();
21880
21927
  }
21881
21928
 
@@ -22052,7 +22099,7 @@ RequestBatcher.prototype.flush = function(options) {
22052
22099
  if (options.unloading) {
22053
22100
  requestOptions.transport = 'sendBeacon';
22054
22101
  }
22055
- logger$5.log('MIXPANEL REQUEST:', dataForRequest);
22102
+ logger$6.log('MIXPANEL REQUEST:', dataForRequest);
22056
22103
  return this.sendRequestPromise(dataForRequest, requestOptions).then(batchSendCallback);
22057
22104
  }, this))
22058
22105
  .catch(_.bind(function(err) {
@@ -22065,7 +22112,7 @@ RequestBatcher.prototype.flush = function(options) {
22065
22112
  * Log error to global logger and optional user-defined logger.
22066
22113
  */
22067
22114
  RequestBatcher.prototype.reportError = function(msg, err) {
22068
- logger$5.error.apply(logger$5.error, arguments);
22115
+ logger$6.error.apply(logger$6.error, arguments);
22069
22116
  if (this.errorReporter) {
22070
22117
  try {
22071
22118
  if (!(err instanceof Error)) {
@@ -22073,7 +22120,7 @@ RequestBatcher.prototype.reportError = function(msg, err) {
22073
22120
  }
22074
22121
  this.errorReporter(msg, err);
22075
22122
  } catch(err) {
22076
- logger$5.error(err);
22123
+ logger$6.error(err);
22077
22124
  }
22078
22125
  }
22079
22126
  };
@@ -22090,6 +22137,29 @@ var isRecordingExpired = function(serializedRecording) {
22090
22137
 
22091
22138
  var RECORD_ENQUEUE_THROTTLE_MS = 250;
22092
22139
 
22140
+ var validateAllowedOrigins = function(origins, logger) {
22141
+ if (!_.isArray(origins)) {
22142
+ if (origins) {
22143
+ logger.critical('record_allowed_iframe_origins must be an array of origin strings, cross-origin recording will be disabled.');
22144
+ }
22145
+ return [];
22146
+ }
22147
+ var valid = [];
22148
+ for (var i = 0; i < origins.length; i++) {
22149
+ try {
22150
+ var origin = new URL(origins[i]).origin;
22151
+ if (origin === 'null') {
22152
+ logger.critical(origins[i] + ' has an opaque origin. Skipping this entry.');
22153
+ continue;
22154
+ }
22155
+ valid.push(origin);
22156
+ } catch (e) {
22157
+ logger.critical(origins[i] + ' is not a valid origin URL. Skipping this entry.');
22158
+ }
22159
+ }
22160
+ return valid;
22161
+ };
22162
+
22093
22163
  // stateless utils
22094
22164
  // mostly from https://github.com/mixpanel/mixpanel-js/blob/989ada50f518edab47b9c4fd9535f9fbd5ec5fc0/src/autotrack-utils.js
22095
22165
 
@@ -22195,7 +22265,7 @@ var EVENT_HANDLER_ATTRIBUTES = [
22195
22265
 
22196
22266
  var MAX_DEPTH = 5;
22197
22267
 
22198
- var logger$4 = console_with_prefix('autocapture');
22268
+ var logger$5 = console_with_prefix('autocapture');
22199
22269
 
22200
22270
 
22201
22271
  function getClasses(el) {
@@ -22459,7 +22529,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
22459
22529
  return false;
22460
22530
  }
22461
22531
  } catch (err) {
22462
- logger$4.critical('Error while checking element in allowElementCallback', err);
22532
+ logger$5.critical('Error while checking element in allowElementCallback', err);
22463
22533
  return false;
22464
22534
  }
22465
22535
  }
@@ -22476,7 +22546,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
22476
22546
  return true;
22477
22547
  }
22478
22548
  } catch (err) {
22479
- logger$4.critical('Error while checking selector: ' + sel, err);
22549
+ logger$5.critical('Error while checking selector: ' + sel, err);
22480
22550
  }
22481
22551
  }
22482
22552
  return false;
@@ -22491,7 +22561,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
22491
22561
  return true;
22492
22562
  }
22493
22563
  } catch (err) {
22494
- logger$4.critical('Error while checking element in blockElementCallback', err);
22564
+ logger$5.critical('Error while checking element in blockElementCallback', err);
22495
22565
  return true;
22496
22566
  }
22497
22567
  }
@@ -22505,7 +22575,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
22505
22575
  return true;
22506
22576
  }
22507
22577
  } catch (err) {
22508
- logger$4.critical('Error while checking selector: ' + sel, err);
22578
+ logger$5.critical('Error while checking selector: ' + sel, err);
22509
22579
  }
22510
22580
  }
22511
22581
  }
@@ -23061,7 +23131,7 @@ function shouldMaskText(element, privacyConfig) {
23061
23131
  *
23062
23132
  */
23063
23133
 
23064
- var logger$3 = console_with_prefix('network-plugin');
23134
+ var logger$4 = console_with_prefix('network-plugin');
23065
23135
 
23066
23136
  /**
23067
23137
  * Get the time origin for converting performance timestamps to absolute timestamps.
@@ -23213,7 +23283,7 @@ function truncateBody(str) {
23213
23283
  return str;
23214
23284
  }
23215
23285
  if (str.length > MAX_BODY_SIZE) {
23216
- logger$3.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
23286
+ logger$4.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
23217
23287
  return str.substring(0, MAX_BODY_SIZE) + '... [truncated]';
23218
23288
  }
23219
23289
  return str;
@@ -23227,7 +23297,7 @@ function truncateBody(str) {
23227
23297
  */
23228
23298
  function initPerformanceObserver(cb, win, options) {
23229
23299
  if (!win.PerformanceObserver) {
23230
- logger$3.error('PerformanceObserver not supported');
23300
+ logger$4.error('PerformanceObserver not supported');
23231
23301
  return function() {
23232
23302
  //
23233
23303
  };
@@ -23380,7 +23450,7 @@ function getRequestPerformanceEntry(win, initiatorType, url, after, before, atte
23380
23450
  attempt = 0;
23381
23451
  }
23382
23452
  if (attempt > 10) {
23383
- logger$3.error('Cannot find performance entry');
23453
+ logger$4.error('Cannot find performance entry');
23384
23454
  return Promise.resolve(null);
23385
23455
  }
23386
23456
  var urlPerformanceEntries = /** @type {PerformanceResourceTiming[]} */ (
@@ -23501,7 +23571,7 @@ function initXhrObserver(cb, win, options) {
23501
23571
  )
23502
23572
  .then(function(entry) {
23503
23573
  if (!entry) {
23504
- logger$3.error('Failed to get performance entry for XHR request to ' + req.url);
23574
+ logger$4.error('Failed to get performance entry for XHR request to ' + req.url);
23505
23575
  return;
23506
23576
  }
23507
23577
  /** @type {NetworkRequest} */
@@ -23521,7 +23591,7 @@ function initXhrObserver(cb, win, options) {
23521
23591
  cb({ requests: [request] });
23522
23592
  })
23523
23593
  .catch(function(e) {
23524
- logger$3.error('Error recording XHR request to ' + req.url + ': ' + String(e));
23594
+ logger$4.error('Error recording XHR request to ' + req.url + ': ' + String(e));
23525
23595
  });
23526
23596
  });
23527
23597
 
@@ -23613,7 +23683,7 @@ function initFetchObserver(cb, win, options) {
23613
23683
  })
23614
23684
  .then(function(entry) {
23615
23685
  if (!entry) {
23616
- logger$3.error('Failed to get performance entry for fetch request to ' + req.url);
23686
+ logger$4.error('Failed to get performance entry for fetch request to ' + req.url);
23617
23687
  return;
23618
23688
  }
23619
23689
  /** @type {NetworkRequest} */
@@ -23633,7 +23703,7 @@ function initFetchObserver(cb, win, options) {
23633
23703
  cb({ requests: [request] });
23634
23704
  })
23635
23705
  .catch(function (e) {
23636
- logger$3.error('Error recording fetch request to ' + req.url + ': ' + String(e));
23706
+ logger$4.error('Error recording fetch request to ' + req.url + ': ' + String(e));
23637
23707
  });
23638
23708
 
23639
23709
  return originalFetchPromise;
@@ -23706,7 +23776,7 @@ var getRecordNetworkPlugin = function(options) {
23706
23776
  */
23707
23777
 
23708
23778
 
23709
- var logger$2 = console_with_prefix('recorder');
23779
+ var logger$3 = console_with_prefix('recorder');
23710
23780
  var CompressionStream = win['CompressionStream'];
23711
23781
 
23712
23782
  var RECORDER_BATCHER_LIB_CONFIG = {
@@ -23886,14 +23956,14 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
23886
23956
  }
23887
23957
 
23888
23958
  if (this._stopRecording !== null) {
23889
- logger$2.log('Recording already in progress, skipping startRecording.');
23959
+ logger$3.log('Recording already in progress, skipping startRecording.');
23890
23960
  return;
23891
23961
  }
23892
23962
 
23893
23963
  this.recordMaxMs = this.getConfig('record_max_ms');
23894
23964
  if (this.recordMaxMs > MAX_RECORDING_MS) {
23895
23965
  this.recordMaxMs = MAX_RECORDING_MS;
23896
- logger$2.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
23966
+ logger$3.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
23897
23967
  }
23898
23968
 
23899
23969
  if (!this.maxExpires) {
@@ -23957,6 +24027,8 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
23957
24027
  );
23958
24028
  }
23959
24029
 
24030
+ var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$3);
24031
+
23960
24032
  try {
23961
24033
  this._stopRecording = this._rrwebRecord({
23962
24034
  'emit': function (ev) {
@@ -23991,6 +24063,8 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
23991
24063
  'maskTextSelector': '*',
23992
24064
  'maskInputFn': this._getMaskFn(shouldMaskInput, privacyConfig),
23993
24065
  'maskTextFn': this._getMaskFn(shouldMaskText, privacyConfig),
24066
+ 'recordCrossOriginIframes': validatedOrigins.length > 0,
24067
+ 'allowedIframeOrigins': validatedOrigins,
23994
24068
  'recordCanvas': this.getConfig('record_canvas'),
23995
24069
  'sampling': {
23996
24070
  'canvas': 15
@@ -24215,14 +24289,14 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
24215
24289
 
24216
24290
 
24217
24291
  SessionRecording.prototype.reportError = function(msg, err) {
24218
- logger$2.error.apply(logger$2.error, arguments);
24292
+ logger$3.error.apply(logger$3.error, arguments);
24219
24293
  try {
24220
24294
  if (!err && !(msg instanceof Error)) {
24221
24295
  msg = new Error(msg);
24222
24296
  }
24223
24297
  this.getConfig('error_reporter')(msg, err);
24224
24298
  } catch(err) {
24225
- logger$2.error(err);
24299
+ logger$3.error(err);
24226
24300
  }
24227
24301
  };
24228
24302
 
@@ -24251,7 +24325,7 @@ SessionRecording.prototype._getRecordMinMs = function() {
24251
24325
  var configValue = this.getConfig('record_min_ms');
24252
24326
 
24253
24327
  if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
24254
- logger$2.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
24328
+ logger$3.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
24255
24329
  return MAX_VALUE_FOR_MIN_RECORDING_MS;
24256
24330
  }
24257
24331
 
@@ -24414,7 +24488,7 @@ RecordingRegistry.prototype.flushInactiveRecordings = function () {
24414
24488
  .catch(this.handleError.bind(this));
24415
24489
  };
24416
24490
 
24417
- var logger$1 = console_with_prefix('recorder');
24491
+ var logger$2 = console_with_prefix('recorder');
24418
24492
 
24419
24493
  /**
24420
24494
  * Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
@@ -24430,7 +24504,7 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
24430
24504
  */
24431
24505
  this.recordingRegistry = new RecordingRegistry({
24432
24506
  mixpanelInstance: this.mixpanelInstance,
24433
- errorReporter: logger$1.error,
24507
+ errorReporter: logger$2.error,
24434
24508
  sharedLockStorage: sharedLockStorage
24435
24509
  });
24436
24510
  this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
@@ -24442,17 +24516,17 @@ var MixpanelRecorder = function(mixpanelInstance, rrwebRecord, sharedLockStorage
24442
24516
  MixpanelRecorder.prototype.startRecording = function(options) {
24443
24517
  options = options || {};
24444
24518
  if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
24445
- logger$1.log('Recording already in progress, skipping startRecording.');
24519
+ logger$2.log('Recording already in progress, skipping startRecording.');
24446
24520
  return;
24447
24521
  }
24448
24522
 
24449
24523
  var onIdleTimeout = function () {
24450
- logger$1.log('Idle timeout reached, restarting recording.');
24524
+ logger$2.log('Idle timeout reached, restarting recording.');
24451
24525
  this.resetRecording();
24452
24526
  }.bind(this);
24453
24527
 
24454
24528
  var onMaxLengthReached = function () {
24455
- logger$1.log('Max recording length reached, stopping recording.');
24529
+ logger$2.log('Max recording length reached, stopping recording.');
24456
24530
  this.resetRecording();
24457
24531
  }.bind(this);
24458
24532
 
@@ -24522,7 +24596,7 @@ MixpanelRecorder.prototype.resumeRecording = function (startNewIfInactive) {
24522
24596
  } else if (startNewIfInactive) {
24523
24597
  return this.startRecording({shouldStopBatcher: false});
24524
24598
  } else {
24525
- logger$1.log('No resumable recording found.');
24599
+ logger$2.log('No resumable recording found.');
24526
24600
  return null;
24527
24601
  }
24528
24602
  }.bind(this));
@@ -25187,7 +25261,7 @@ ShadowDOMObserver.prototype.observeShadowRoot = function(shadowRoot) {
25187
25261
  observer.observe(shadowRoot, this.observerConfig);
25188
25262
  this.shadowObservers.push(observer);
25189
25263
  } catch (e) {
25190
- logger$4.critical('Error while observing shadow root', e);
25264
+ logger$5.critical('Error while observing shadow root', e);
25191
25265
  }
25192
25266
  };
25193
25267
 
@@ -25198,7 +25272,7 @@ ShadowDOMObserver.prototype.start = function() {
25198
25272
  }
25199
25273
 
25200
25274
  if (!weakSetSupported()) {
25201
- logger$4.critical('Shadow DOM observation unavailable: WeakSet not supported');
25275
+ logger$5.critical('Shadow DOM observation unavailable: WeakSet not supported');
25202
25276
  return;
25203
25277
  }
25204
25278
 
@@ -25214,7 +25288,7 @@ ShadowDOMObserver.prototype.stop = function() {
25214
25288
  try {
25215
25289
  this.shadowObservers[i].disconnect();
25216
25290
  } catch (e) {
25217
- logger$4.critical('Error while disconnecting shadow DOM observer', e);
25291
+ logger$5.critical('Error while disconnecting shadow DOM observer', e);
25218
25292
  }
25219
25293
  }
25220
25294
  this.shadowObservers = [];
@@ -25402,7 +25476,7 @@ DeadClickTracker.prototype.startTracking = function() {
25402
25476
 
25403
25477
  this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
25404
25478
  } catch (e) {
25405
- logger$4.critical('Error while setting up mutation observer', e);
25479
+ logger$5.critical('Error while setting up mutation observer', e);
25406
25480
  }
25407
25481
  }
25408
25482
 
@@ -25417,7 +25491,7 @@ DeadClickTracker.prototype.startTracking = function() {
25417
25491
  );
25418
25492
  this.shadowDOMObserver.start();
25419
25493
  } catch (e) {
25420
- logger$4.critical('Error while setting up shadow DOM observer', e);
25494
+ logger$5.critical('Error while setting up shadow DOM observer', e);
25421
25495
  this.shadowDOMObserver = null;
25422
25496
  }
25423
25497
  }
@@ -25444,7 +25518,7 @@ DeadClickTracker.prototype.stopTracking = function() {
25444
25518
  try {
25445
25519
  listener.target.removeEventListener(listener.event, listener.handler, listener.options);
25446
25520
  } catch (e) {
25447
- logger$4.critical('Error while removing event listener', e);
25521
+ logger$5.critical('Error while removing event listener', e);
25448
25522
  }
25449
25523
  }
25450
25524
  this.eventListeners = [];
@@ -25453,7 +25527,7 @@ DeadClickTracker.prototype.stopTracking = function() {
25453
25527
  try {
25454
25528
  this.mutationObserver.disconnect();
25455
25529
  } catch (e) {
25456
- logger$4.critical('Error while disconnecting mutation observer', e);
25530
+ logger$5.critical('Error while disconnecting mutation observer', e);
25457
25531
  }
25458
25532
  this.mutationObserver = null;
25459
25533
  }
@@ -25462,7 +25536,7 @@ DeadClickTracker.prototype.stopTracking = function() {
25462
25536
  try {
25463
25537
  this.shadowDOMObserver.stop();
25464
25538
  } catch (e) {
25465
- logger$4.critical('Error while stopping shadow DOM observer', e);
25539
+ logger$5.critical('Error while stopping shadow DOM observer', e);
25466
25540
  }
25467
25541
  this.shadowDOMObserver = null;
25468
25542
  }
@@ -25540,7 +25614,7 @@ var Autocapture = function(mp) {
25540
25614
 
25541
25615
  Autocapture.prototype.init = function() {
25542
25616
  if (!minDOMApisSupported()) {
25543
- logger$4.critical('Autocapture unavailable: missing required DOM APIs');
25617
+ logger$5.critical('Autocapture unavailable: missing required DOM APIs');
25544
25618
  return;
25545
25619
  }
25546
25620
  this.initPageListeners();
@@ -25580,7 +25654,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
25580
25654
  try {
25581
25655
  return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
25582
25656
  } catch (err) {
25583
- logger$4.critical('Error while checking block URL regexes: ', err);
25657
+ logger$5.critical('Error while checking block URL regexes: ', err);
25584
25658
  return true;
25585
25659
  }
25586
25660
  }
@@ -25593,7 +25667,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
25593
25667
  try {
25594
25668
  return urlMatchesRegexList(currentUrl, blockUrlRegexes);
25595
25669
  } catch (err) {
25596
- logger$4.critical('Error while checking block URL regexes: ', err);
25670
+ logger$5.critical('Error while checking block URL regexes: ', err);
25597
25671
  return true;
25598
25672
  }
25599
25673
  };
@@ -25731,7 +25805,7 @@ Autocapture.prototype._initScrollDepthTracking = function() {
25731
25805
  return;
25732
25806
  }
25733
25807
 
25734
- logger$4.log('Initializing scroll depth tracking');
25808
+ logger$5.log('Initializing scroll depth tracking');
25735
25809
 
25736
25810
  this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
25737
25811
 
@@ -25757,7 +25831,7 @@ Autocapture.prototype.initClickTracking = function() {
25757
25831
  if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
25758
25832
  return;
25759
25833
  }
25760
- logger$4.log('Initializing click tracking');
25834
+ logger$5.log('Initializing click tracking');
25761
25835
 
25762
25836
  this.listenerClick = function(ev) {
25763
25837
  if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
@@ -25776,7 +25850,7 @@ Autocapture.prototype.initDeadClickTracking = function() {
25776
25850
  return;
25777
25851
  }
25778
25852
 
25779
- logger$4.log('Initializing dead click tracking');
25853
+ logger$5.log('Initializing dead click tracking');
25780
25854
  if (!this._deadClickTracker) {
25781
25855
  this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
25782
25856
  this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
@@ -25810,7 +25884,7 @@ Autocapture.prototype.initInputTracking = function() {
25810
25884
  if (!this.getConfig(CONFIG_TRACK_INPUT)) {
25811
25885
  return;
25812
25886
  }
25813
- logger$4.log('Initializing input tracking');
25887
+ logger$5.log('Initializing input tracking');
25814
25888
 
25815
25889
  this.listenerChange = function(ev) {
25816
25890
  if (!this.getConfig(CONFIG_TRACK_INPUT)) {
@@ -25827,7 +25901,7 @@ Autocapture.prototype.initPageviewTracking = function() {
25827
25901
  if (!this.pageviewTrackingConfig()) {
25828
25902
  return;
25829
25903
  }
25830
- logger$4.log('Initializing pageview tracking');
25904
+ logger$5.log('Initializing pageview tracking');
25831
25905
 
25832
25906
  var previousTrackedUrl = '';
25833
25907
  var tracked = false;
@@ -25862,7 +25936,7 @@ Autocapture.prototype.initPageviewTracking = function() {
25862
25936
  }
25863
25937
  if (didPathChange) {
25864
25938
  this.lastScrollCheckpoint = 0;
25865
- logger$4.log('Path change: re-initializing scroll depth checkpoints');
25939
+ logger$5.log('Path change: re-initializing scroll depth checkpoints');
25866
25940
  }
25867
25941
  }
25868
25942
  }.bind(this));
@@ -25877,7 +25951,7 @@ Autocapture.prototype.initRageClickTracking = function() {
25877
25951
  return;
25878
25952
  }
25879
25953
 
25880
- logger$4.log('Initializing rage click tracking');
25954
+ logger$5.log('Initializing rage click tracking');
25881
25955
  if (!this._rageClickTracker) {
25882
25956
  this._rageClickTracker = new RageClickTracker();
25883
25957
  }
@@ -25907,7 +25981,7 @@ Autocapture.prototype.initScrollTracking = function() {
25907
25981
  if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
25908
25982
  return;
25909
25983
  }
25910
- logger$4.log('Initializing scroll tracking');
25984
+ logger$5.log('Initializing scroll tracking');
25911
25985
  this.lastScrollCheckpoint = 0;
25912
25986
 
25913
25987
  var scrollTrackFunction = function() {
@@ -25944,7 +26018,7 @@ Autocapture.prototype.initScrollTracking = function() {
25944
26018
  }
25945
26019
  }
25946
26020
  } catch (err) {
25947
- logger$4.critical('Error while calculating scroll percentage', err);
26021
+ logger$5.critical('Error while calculating scroll percentage', err);
25948
26022
  }
25949
26023
  if (shouldTrack) {
25950
26024
  this.mp.track(MP_EV_SCROLL, props);
@@ -25962,7 +26036,7 @@ Autocapture.prototype.initSubmitTracking = function() {
25962
26036
  if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
25963
26037
  return;
25964
26038
  }
25965
- logger$4.log('Initializing submit tracking');
26039
+ logger$5.log('Initializing submit tracking');
25966
26040
 
25967
26041
  this.listenerSubmit = function(ev) {
25968
26042
  if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
@@ -25984,7 +26058,7 @@ Autocapture.prototype.initPageLeaveTracking = function() {
25984
26058
  return;
25985
26059
  }
25986
26060
 
25987
- logger$4.log('Initializing page visibility tracking.');
26061
+ logger$5.log('Initializing page visibility tracking.');
25988
26062
  this._initScrollDepthTracking();
25989
26063
  var previousTrackedUrl = _.info.currentUrl();
25990
26064
 
@@ -26069,7 +26143,7 @@ var getTargetingPromise = function(loadExtraBundle, targetingSrc) {
26069
26143
  return win[TARGETING_GLOBAL_NAME];
26070
26144
  };
26071
26145
 
26072
- var logger = console_with_prefix('flags');
26146
+ var logger$1 = console_with_prefix('flags');
26073
26147
  var FLAGS_CONFIG_KEY = 'flags';
26074
26148
 
26075
26149
  var CONFIG_CONTEXT = 'context';
@@ -26112,7 +26186,7 @@ var FeatureFlagManager = function(initOptions) {
26112
26186
 
26113
26187
  FeatureFlagManager.prototype.init = function() {
26114
26188
  if (!this.minApisSupported()) {
26115
- logger.critical('Feature Flags unavailable: missing minimum required APIs');
26189
+ logger$1.critical('Feature Flags unavailable: missing minimum required APIs');
26116
26190
  return;
26117
26191
  }
26118
26192
 
@@ -26147,7 +26221,7 @@ FeatureFlagManager.prototype.isSystemEnabled = function() {
26147
26221
 
26148
26222
  FeatureFlagManager.prototype.updateContext = function(newContext, options) {
26149
26223
  if (!this.isSystemEnabled()) {
26150
- logger.critical('Feature Flags not enabled, cannot update context');
26224
+ logger$1.critical('Feature Flags not enabled, cannot update context');
26151
26225
  return Promise.resolve();
26152
26226
  }
26153
26227
 
@@ -26164,7 +26238,7 @@ FeatureFlagManager.prototype.updateContext = function(newContext, options) {
26164
26238
 
26165
26239
  FeatureFlagManager.prototype.areFlagsReady = function() {
26166
26240
  if (!this.isSystemEnabled()) {
26167
- logger.error('Feature Flags not enabled');
26241
+ logger$1.error('Feature Flags not enabled');
26168
26242
  }
26169
26243
  return !!this.flags;
26170
26244
  };
@@ -26177,7 +26251,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
26177
26251
  var distinctId = this.getMpProperty('distinct_id');
26178
26252
  var deviceId = this.getMpProperty('$device_id');
26179
26253
  var traceparent = generateTraceparent();
26180
- logger.log('Fetching flags for distinct ID: ' + distinctId);
26254
+ logger$1.log('Fetching flags for distinct ID: ' + distinctId);
26181
26255
 
26182
26256
  var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
26183
26257
  var searchParams = new URLSearchParams();
@@ -26276,11 +26350,11 @@ FeatureFlagManager.prototype.fetchFlags = function() {
26276
26350
  this._loadTargetingIfNeeded();
26277
26351
  }.bind(this)).catch(function(error) {
26278
26352
  this.markFetchComplete();
26279
- logger.error(error);
26353
+ logger$1.error(error);
26280
26354
  }.bind(this));
26281
26355
  }.bind(this)).catch(function(error) {
26282
26356
  this.markFetchComplete();
26283
- logger.error(error);
26357
+ logger$1.error(error);
26284
26358
  }.bind(this));
26285
26359
 
26286
26360
  return this.fetchPromise;
@@ -26288,7 +26362,7 @@ FeatureFlagManager.prototype.fetchFlags = function() {
26288
26362
 
26289
26363
  FeatureFlagManager.prototype.markFetchComplete = function() {
26290
26364
  if (!this._fetchInProgressStartTime) {
26291
- logger.error('Fetch in progress started time not set, cannot mark fetch complete');
26365
+ logger$1.error('Fetch in progress started time not set, cannot mark fetch complete');
26292
26366
  return;
26293
26367
  }
26294
26368
  this._fetchStartTime = this._fetchInProgressStartTime;
@@ -26310,7 +26384,7 @@ FeatureFlagManager.prototype._loadTargetingIfNeeded = function() {
26310
26384
 
26311
26385
  if (hasPropertyFilters) {
26312
26386
  this.getTargeting().then(function() {
26313
- logger.log('targeting loaded for property filter evaluation');
26387
+ logger$1.log('targeting loaded for property filter evaluation');
26314
26388
  });
26315
26389
  }
26316
26390
  };
@@ -26325,7 +26399,7 @@ FeatureFlagManager.prototype.getTargeting = function() {
26325
26399
  this.loadExtraBundle.bind(this),
26326
26400
  this.targetingSrc
26327
26401
  ).catch(function(error) {
26328
- logger.error('Failed to load targeting: ' + error);
26402
+ logger$1.error('Failed to load targeting: ' + error);
26329
26403
  }.bind(this));
26330
26404
  };
26331
26405
 
@@ -26379,7 +26453,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
26379
26453
 
26380
26454
  // If no targeting library and event has property filters, skip it
26381
26455
  if (!targeting && pendingEvent['property_filters'] && !_.isEmptyObject(pendingEvent['property_filters'])) {
26382
- logger.warn('Skipping event check for "' + flagKey + '" - property filters require targeting library');
26456
+ logger$1.warn('Skipping event check for "' + flagKey + '" - property filters require targeting library');
26383
26457
  return;
26384
26458
  }
26385
26459
 
@@ -26402,7 +26476,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
26402
26476
  }
26403
26477
 
26404
26478
  if (matchResult.error) {
26405
- logger.error('Error checking first-time event for flag "' + flagKey + '": ' + matchResult.error);
26479
+ logger$1.error('Error checking first-time event for flag "' + flagKey + '": ' + matchResult.error);
26406
26480
  return;
26407
26481
  }
26408
26482
 
@@ -26410,7 +26484,7 @@ FeatureFlagManager.prototype._processFirstTimeEventCheck = function(eventName, p
26410
26484
  return;
26411
26485
  }
26412
26486
 
26413
- logger.log('First-time event matched for flag "' + flagKey + '": ' + eventName);
26487
+ logger$1.log('First-time event matched for flag "' + flagKey + '": ' + eventName);
26414
26488
 
26415
26489
  var newVariant = {
26416
26490
  'key': pendingEvent['pending_variant']['variant_key'],
@@ -26451,7 +26525,7 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
26451
26525
  'first_time_event_hash': firstTimeEventHash
26452
26526
  };
26453
26527
 
26454
- logger.log('Recording first-time event for flag: ' + flagId);
26528
+ logger$1.log('Recording first-time event for flag: ' + flagId);
26455
26529
 
26456
26530
  // Fire-and-forget POST request
26457
26531
  this.fetch.call(win, url, {
@@ -26464,14 +26538,14 @@ FeatureFlagManager.prototype.recordFirstTimeEvent = function(flagId, projectId,
26464
26538
  'body': JSON.stringify(payload)
26465
26539
  }).catch(function(error) {
26466
26540
  // Silent failure - cohort sync will catch up
26467
- logger.error('Failed to record first-time event for flag ' + flagId + ': ' + error);
26541
+ logger$1.error('Failed to record first-time event for flag ' + flagId + ': ' + error);
26468
26542
  });
26469
26543
  };
26470
26544
 
26471
26545
  FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
26472
26546
  if (!this.fetchPromise) {
26473
26547
  return new Promise(function(resolve) {
26474
- logger.critical('Feature Flags not initialized');
26548
+ logger$1.critical('Feature Flags not initialized');
26475
26549
  resolve(fallback);
26476
26550
  });
26477
26551
  }
@@ -26479,19 +26553,19 @@ FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
26479
26553
  return this.fetchPromise.then(function() {
26480
26554
  return this.getVariantSync(featureName, fallback);
26481
26555
  }.bind(this)).catch(function(error) {
26482
- logger.error(error);
26556
+ logger$1.error(error);
26483
26557
  return fallback;
26484
26558
  });
26485
26559
  };
26486
26560
 
26487
26561
  FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
26488
26562
  if (!this.areFlagsReady()) {
26489
- logger.log('Flags not loaded yet');
26563
+ logger$1.log('Flags not loaded yet');
26490
26564
  return fallback;
26491
26565
  }
26492
26566
  var feature = this.flags.get(featureName);
26493
26567
  if (!feature) {
26494
- logger.log('No flag found: "' + featureName + '"');
26568
+ logger$1.log('No flag found: "' + featureName + '"');
26495
26569
  return fallback;
26496
26570
  }
26497
26571
  this.trackFeatureCheck(featureName, feature);
@@ -26502,14 +26576,14 @@ FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackVal
26502
26576
  return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
26503
26577
  return feature['value'];
26504
26578
  }).catch(function(error) {
26505
- logger.error(error);
26579
+ logger$1.error(error);
26506
26580
  return fallbackValue;
26507
26581
  });
26508
26582
  };
26509
26583
 
26510
26584
  // TODO remove deprecated method
26511
26585
  FeatureFlagManager.prototype.getFeatureData = function(featureName, fallbackValue) {
26512
- logger.critical('mixpanel.flags.get_feature_data() is deprecated and will be removed in a future release. Use mixpanel.flags.get_variant_value() instead.');
26586
+ 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.');
26513
26587
  return this.getVariantValue(featureName, fallbackValue);
26514
26588
  };
26515
26589
 
@@ -26521,7 +26595,7 @@ FeatureFlagManager.prototype.isEnabled = function(featureName, fallbackValue) {
26521
26595
  return this.getVariantValue(featureName).then(function() {
26522
26596
  return this.isEnabledSync(featureName, fallbackValue);
26523
26597
  }.bind(this)).catch(function(error) {
26524
- logger.error(error);
26598
+ logger$1.error(error);
26525
26599
  return fallbackValue;
26526
26600
  });
26527
26601
  };
@@ -26530,7 +26604,7 @@ FeatureFlagManager.prototype.isEnabledSync = function(featureName, fallbackValue
26530
26604
  fallbackValue = fallbackValue || false;
26531
26605
  var val = this.getVariantValueSync(featureName, fallbackValue);
26532
26606
  if (val !== true && val !== false) {
26533
- logger.error('Feature flag "' + featureName + '" value: ' + val + ' is not a boolean; returning fallback value: ' + fallbackValue);
26607
+ logger$1.error('Feature flag "' + featureName + '" value: ' + val + ' is not a boolean; returning fallback value: ' + fallbackValue);
26534
26608
  val = fallbackValue;
26535
26609
  }
26536
26610
  return val;
@@ -26592,6 +26666,12 @@ FeatureFlagManager.prototype['getTargeting'] = FeatureFlagManager.prototype.getT
26592
26666
  /* eslint camelcase: "off" */
26593
26667
 
26594
26668
 
26669
+ var logger = console_with_prefix('recorder');
26670
+
26671
+ var IFRAME_HANDSHAKE_REQUEST = 'mp_iframe_handshake_request';
26672
+ var IFRAME_HANDSHAKE_RESPONSE = 'mp_iframe_handshake_response';
26673
+
26674
+
26595
26675
  /**
26596
26676
  * RecorderManager: manages session recording initialization, lifecycle and state
26597
26677
  * @constructor
@@ -26611,6 +26691,8 @@ var RecorderManager = function(initOptions) {
26611
26691
  this.libBasePath = initOptions.libBasePath;
26612
26692
 
26613
26693
  this._recorder = null;
26694
+ this._parentReplayId = null;
26695
+ this._parentFrameRetryInterval = null;
26614
26696
  };
26615
26697
 
26616
26698
  RecorderManager.prototype.shouldLoadRecorder = function() {
@@ -26664,6 +26746,22 @@ RecorderManager.prototype.checkAndStartSessionRecording = function(force_start,
26664
26746
  }, this));
26665
26747
  }, this);
26666
26748
 
26749
+ // Cross-origin iframe handling
26750
+ var allowedOrigins = validateAllowedOrigins(this.getMpConfig('record_allowed_iframe_origins'), logger);
26751
+ var isCrossOriginRecordingEnabled = allowedOrigins.length > 0;
26752
+
26753
+ if (isCrossOriginRecordingEnabled) {
26754
+ // listen for handshake requests from their own child iframes (including nested)
26755
+ this._setupParentFrameListener(allowedOrigins);
26756
+
26757
+ if (win.parent !== win) {
26758
+ // also wait for parent's replay ID
26759
+ this._setupChildFrameListener(allowedOrigins, loadRecorder);
26760
+ this._sendParentFrameRequestWithRetry(allowedOrigins);
26761
+ return PromisePolyfill.resolve();
26762
+ }
26763
+ }
26764
+
26667
26765
  /**
26668
26766
  * If the user is sampled or start_session_recording is called, we always load the recorder since it's guaranteed a recording should start.
26669
26767
  * 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.
@@ -26783,6 +26881,10 @@ RecorderManager.prototype.getSessionReplayUrl = function() {
26783
26881
  };
26784
26882
 
26785
26883
  RecorderManager.prototype.getSessionReplayId = function() {
26884
+ // Child iframe uses parent's replay ID
26885
+ if (this._parentReplayId) {
26886
+ return this._parentReplayId;
26887
+ }
26786
26888
  var replay_id = null;
26787
26889
  if (this._recorder) {
26788
26890
  replay_id = this._recorder['replayId'];
@@ -26795,6 +26897,86 @@ RecorderManager.prototype.getRecorder = function() {
26795
26897
  return this._recorder;
26796
26898
  };
26797
26899
 
26900
+ RecorderManager.prototype._setupChildFrameListener = function(allowedOrigins, loadRecorder) {
26901
+ if (this._childFrameMessageHandler) {
26902
+ return;
26903
+ }
26904
+ var self = this;
26905
+ this._childFrameMessageHandler = function(event) {
26906
+ if (allowedOrigins.indexOf(event.origin) === -1) return;
26907
+ var data = event.data;
26908
+ if (data && data['type'] === IFRAME_HANDSHAKE_RESPONSE && data['token'] === self.getMpConfig('token') && data['replayId']) {
26909
+ self._parentReplayId = data['replayId'];
26910
+ if (data['distinctId']) {
26911
+ self.mixpanelInstance['identify'](data['distinctId']);
26912
+ }
26913
+ self._parentFrameRetryActive = false;
26914
+ win.removeEventListener('message', self._childFrameMessageHandler);
26915
+ self._childFrameMessageHandler = null;
26916
+ loadRecorder(true);
26917
+ }
26918
+ };
26919
+ win.addEventListener('message', this._childFrameMessageHandler);
26920
+ };
26921
+
26922
+ RecorderManager.prototype._sendParentFrameRequest = function(allowedOrigins) {
26923
+ var message = {};
26924
+ message['type'] = IFRAME_HANDSHAKE_REQUEST;
26925
+ message['token'] = this.getMpConfig('token');
26926
+ for (var i = 0; i < allowedOrigins.length; i++) {
26927
+ try {
26928
+ win.parent.postMessage(message, allowedOrigins[i]);
26929
+ } catch (e) {
26930
+ // origin mismatch - ignore
26931
+ }
26932
+ }
26933
+ };
26934
+
26935
+ RecorderManager.prototype._sendParentFrameRequestWithRetry = function(allowedOrigins) {
26936
+ var self = this;
26937
+ var maxRetries = 10;
26938
+ var retryCount = 0;
26939
+ var delay = 50;
26940
+ this._parentFrameRetryActive = true;
26941
+
26942
+ this._sendParentFrameRequest(allowedOrigins);
26943
+
26944
+ function scheduleRetry() {
26945
+ setTimeout(function() {
26946
+ if (!self._parentFrameRetryActive || self._parentReplayId || ++retryCount >= maxRetries) {
26947
+ return;
26948
+ }
26949
+ self._sendParentFrameRequest(allowedOrigins);
26950
+ delay *= 2;
26951
+ scheduleRetry();
26952
+ }, delay);
26953
+ }
26954
+ scheduleRetry();
26955
+ };
26956
+
26957
+ RecorderManager.prototype._setupParentFrameListener = function(allowedOrigins) {
26958
+ if (this._parentFrameMessageHandler) {
26959
+ return;
26960
+ }
26961
+ var self = this;
26962
+ this._parentFrameMessageHandler = function(event) {
26963
+ if (allowedOrigins.indexOf(event.origin) === -1) return;
26964
+ var data = event.data;
26965
+ if (data && data['type'] === IFRAME_HANDSHAKE_REQUEST && data['token'] === self.getMpConfig('token')) {
26966
+ var replayId = self.getSessionReplayId();
26967
+ if (replayId) {
26968
+ var response = {};
26969
+ response['type'] = IFRAME_HANDSHAKE_RESPONSE;
26970
+ response['token'] = self.getMpConfig('token');
26971
+ response['replayId'] = replayId;
26972
+ response['distinctId'] = self.getDistinctId();
26973
+ event.source.postMessage(response, event.origin);
26974
+ }
26975
+ }
26976
+ };
26977
+ win.addEventListener('message', this._parentFrameMessageHandler);
26978
+ };
26979
+
26798
26980
  safewrapClass(RecorderManager);
26799
26981
 
26800
26982
  /* eslint camelcase: "off" */
@@ -28169,7 +28351,6 @@ var INIT_SNIPPET = 1;
28169
28351
  /** @const */ var SETTING_FALLBACK = 'fallback';
28170
28352
  /** @const */ var SETTING_DISABLED = 'disabled';
28171
28353
 
28172
-
28173
28354
  /*
28174
28355
  * Dynamic... constants? Is that an oxymoron?
28175
28356
  */
@@ -28254,6 +28435,7 @@ var DEFAULT_CONFIG = {
28254
28435
  'batch_request_timeout_ms': 90000,
28255
28436
  'batch_autostart': true,
28256
28437
  'hooks': {},
28438
+ 'record_allowed_iframe_origins': [],
28257
28439
  'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
28258
28440
  'record_block_selector': 'img, video, audio',
28259
28441
  'record_canvas': false,