mixpanel-browser 2.76.0 → 2.78.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 (52) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/.github/dependabot.yml +8 -0
  3. package/.github/workflows/integration-tests.yml +2 -2
  4. package/.github/workflows/unit-tests.yml +2 -2
  5. package/CHANGELOG.md +8 -0
  6. package/dist/async-modules/mixpanel-recorder-BjSlYaNJ.min.js +2 -0
  7. package/dist/async-modules/mixpanel-recorder-BjSlYaNJ.min.js.map +1 -0
  8. package/dist/async-modules/{mixpanel-recorder-bIS4LMGd.js → mixpanel-recorder-zMBXIyeG.js} +84 -10
  9. package/dist/async-modules/{mixpanel-targeting-VOeN7RWY.min.js → mixpanel-targeting-BSHal4N9.min.js} +2 -2
  10. package/dist/async-modules/{mixpanel-targeting-VOeN7RWY.min.js.map → mixpanel-targeting-BSHal4N9.min.js.map} +1 -1
  11. package/dist/async-modules/{mixpanel-targeting-BcAPS-Mz.js → mixpanel-targeting-UHf4eBfC.js} +1 -1
  12. package/dist/mixpanel-core.cjs.d.ts +3 -1
  13. package/dist/mixpanel-core.cjs.js +292 -130
  14. package/dist/mixpanel-recorder.js +84 -10
  15. package/dist/mixpanel-recorder.min.js +1 -1
  16. package/dist/mixpanel-recorder.min.js.map +1 -1
  17. package/dist/mixpanel-targeting.js +1 -1
  18. package/dist/mixpanel-targeting.min.js +1 -1
  19. package/dist/mixpanel-targeting.min.js.map +1 -1
  20. package/dist/mixpanel-with-async-modules.cjs.d.ts +3 -1
  21. package/dist/mixpanel-with-async-modules.cjs.js +294 -132
  22. package/dist/mixpanel-with-async-recorder.cjs.d.ts +3 -1
  23. package/dist/mixpanel-with-async-recorder.cjs.js +294 -132
  24. package/dist/mixpanel-with-recorder.d.ts +3 -1
  25. package/dist/mixpanel-with-recorder.js +381 -168
  26. package/dist/mixpanel-with-recorder.min.d.ts +3 -1
  27. package/dist/mixpanel-with-recorder.min.js +1 -1
  28. package/dist/mixpanel.amd.d.ts +3 -1
  29. package/dist/mixpanel.amd.js +381 -168
  30. package/dist/mixpanel.cjs.d.ts +3 -1
  31. package/dist/mixpanel.cjs.js +381 -168
  32. package/dist/mixpanel.globals.js +294 -132
  33. package/dist/mixpanel.min.js +191 -186
  34. package/dist/mixpanel.module.d.ts +3 -1
  35. package/dist/mixpanel.module.js +381 -168
  36. package/dist/mixpanel.umd.d.ts +3 -1
  37. package/dist/mixpanel.umd.js +381 -168
  38. package/dist/rrweb-bundled.js +61 -9
  39. package/dist/rrweb-compiled.js +56 -9
  40. package/package.json +6 -5
  41. package/src/config.js +1 -1
  42. package/src/flags/CLAUDE.md +24 -0
  43. package/src/flags/index.js +109 -80
  44. package/src/index.d.ts +3 -1
  45. package/src/mixpanel-core.js +4 -2
  46. package/src/recorder/session-recording.js +5 -1
  47. package/src/recorder/utils.js +27 -1
  48. package/src/recorder-manager.js +110 -2
  49. package/testServer.js +16 -1
  50. package/dist/async-modules/mixpanel-recorder-hFoTniVR.min.js +0 -2
  51. package/dist/async-modules/mixpanel-recorder-hFoTniVR.min.js.map +0 -1
  52. /package/src/loaders/{loader-module-with-async-recorder.d.ts → loader-module-with-async-modules.d.ts} +0 -0
@@ -31,7 +31,7 @@
31
31
 
32
32
  var Config = {
33
33
  DEBUG: false,
34
- LIB_VERSION: '2.76.0'
34
+ LIB_VERSION: '2.78.0'
35
35
  };
36
36
 
37
37
  // Window global names for async modules
@@ -10739,13 +10739,7 @@
10739
10739
  };
10740
10740
  while(_this.mapRemoves.length){
10741
10741
  var removedNode = _this.mapRemoves.shift();
10742
- if (removedNode.nodeName === "IFRAME") {
10743
- try {
10744
- _this.iframeManager.removeIframe(removedNode);
10745
- } catch (e2) {}
10746
- } else {
10747
- _this.stylesheetManager.cleanupStylesheetsForRemovedNode(removedNode);
10748
- }
10742
+ _this.cleanupRemovedNode(removedNode);
10749
10743
  _this.mirror.removeNodeFromMap(removedNode);
10750
10744
  }
10751
10745
  for(var _iterator = _create_for_of_iterator_helper_loose(_this.movedSet), _step; !(_step = _iterator()).done;){
@@ -11065,6 +11059,20 @@
11065
11059
  }
11066
11060
  }
11067
11061
  });
11062
+ __publicField$1(this, "cleanupRemovedNode", function(node2) {
11063
+ if (node2.nodeName === "IFRAME") {
11064
+ try {
11065
+ _this.iframeManager.removeIframe(node2);
11066
+ } catch (e2) {}
11067
+ } else {
11068
+ try {
11069
+ _this.stylesheetManager.cleanupStylesheetsForRemovedNode(node2);
11070
+ } catch (e2) {}
11071
+ }
11072
+ node2.childNodes.forEach(function(child) {
11073
+ _this.cleanupRemovedNode(child);
11074
+ });
11075
+ });
11068
11076
  }
11069
11077
  var _proto = MutationBuffer.prototype;
11070
11078
  _proto.init = function init(options) {
@@ -13292,6 +13300,31 @@
13292
13300
  _proto.destroy = function destroy() {};
13293
13301
  return ProcessedNodeManager;
13294
13302
  }();
13303
+ function toOrigin(url) {
13304
+ try {
13305
+ var origin = new URL(url).origin;
13306
+ return origin !== "null" ? origin : null;
13307
+ } catch (e) {
13308
+ return null;
13309
+ }
13310
+ }
13311
+ function buildAllowedOriginSet(origins) {
13312
+ if (!Array.isArray(origins) || origins.length === 0) {
13313
+ throw new Error("[rrweb] allowedIframeOrigins must be a non-empty array of origin strings.");
13314
+ }
13315
+ var set = /* @__PURE__ */ new Set();
13316
+ for(var i2 = 0; i2 < origins.length; i2++){
13317
+ var entry = origins[i2];
13318
+ if (typeof entry !== "string") {
13319
+ throw new Error("[rrweb] allowedIframeOrigins[" + i2 + "] must be a string, got " + (typeof entry === "undefined" ? "undefined" : _type_of(entry)) + ".");
13320
+ }
13321
+ var origin = toOrigin(entry);
13322
+ if (origin) {
13323
+ set.add(origin);
13324
+ }
13325
+ }
13326
+ return Object.freeze(set);
13327
+ }
13295
13328
  var wrappedEmit;
13296
13329
  var takeFullSnapshot$1;
13297
13330
  var canvasManager;
@@ -13313,10 +13346,17 @@
13313
13346
  var mirror = createMirror$2();
13314
13347
  function record(options) {
13315
13348
  if (options === void 0) options = {};
13316
- 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() {
13349
+ 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() {
13317
13350
  return false;
13318
13351
  } : _options_keepIframeSrcFn, _options_ignoreCSSAttributes = options.ignoreCSSAttributes, ignoreCSSAttributes = _options_ignoreCSSAttributes === void 0 ? /* @__PURE__ */ new Set([]) : _options_ignoreCSSAttributes, errorHandler2 = options.errorHandler;
13319
13352
  registerErrorHandler(errorHandler2);
13353
+ var validatedOrigins;
13354
+ if (recordCrossOriginIframes && allowedIframeOrigins && allowedIframeOrigins.length > 0) {
13355
+ validatedOrigins = buildAllowedOriginSet(allowedIframeOrigins);
13356
+ if (validatedOrigins.size === 0) {
13357
+ validatedOrigins = void 0;
13358
+ }
13359
+ }
13320
13360
  var inEmittingFrame = recordCrossOriginIframes ? window.parent === window : true;
13321
13361
  var passEmitsToParent = false;
13322
13362
  if (!inEmittingFrame) {
@@ -13408,7 +13448,14 @@
13408
13448
  origin: window.location.origin,
13409
13449
  isCheckout: isCheckout
13410
13450
  };
13411
- window.parent.postMessage(message, "*");
13451
+ if (validatedOrigins) {
13452
+ for(var _iterator = _create_for_of_iterator_helper_loose(validatedOrigins), _step; !(_step = _iterator()).done;){
13453
+ var targetOrigin = _step.value;
13454
+ window.parent.postMessage(message, targetOrigin);
13455
+ }
13456
+ } else {
13457
+ window.parent.postMessage(message, "*");
13458
+ }
13412
13459
  }
13413
13460
  if (e2.type === EventType.FullSnapshot) {
13414
13461
  lastFullSnapshotEvent = e2;
@@ -21192,7 +21239,7 @@
21192
21239
  };
21193
21240
  }
21194
21241
 
21195
- var logger$7 = console_with_prefix('lock');
21242
+ var logger$8 = console_with_prefix('lock');
21196
21243
 
21197
21244
  /**
21198
21245
  * SharedLock: a mutex built on HTML5 localStorage, to ensure that only one browser
@@ -21244,7 +21291,7 @@
21244
21291
 
21245
21292
  var delay = function(cb) {
21246
21293
  if (new Date().getTime() - startTime > timeoutMS) {
21247
- logger$7.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
21294
+ logger$8.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
21248
21295
  storage.removeItem(keyZ);
21249
21296
  storage.removeItem(keyY);
21250
21297
  loop();
@@ -21391,7 +21438,7 @@
21391
21438
  }, this));
21392
21439
  };
21393
21440
 
21394
- var logger$6 = console_with_prefix('batch');
21441
+ var logger$7 = console_with_prefix('batch');
21395
21442
 
21396
21443
  /**
21397
21444
  * RequestQueue: queue for batching API requests with localStorage backup for retries.
@@ -21420,7 +21467,7 @@
21420
21467
  timeoutMS: options.sharedLockTimeoutMS,
21421
21468
  });
21422
21469
  }
21423
- this.reportError = options.errorReporter || _.bind(logger$6.error, logger$6);
21470
+ this.reportError = options.errorReporter || _.bind(logger$7.error, logger$7);
21424
21471
 
21425
21472
  this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
21426
21473
 
@@ -21753,7 +21800,7 @@
21753
21800
  // maximum interval between request retries after exponential backoff
21754
21801
  var MAX_RETRY_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
21755
21802
 
21756
- var logger$5 = console_with_prefix('batch');
21803
+ var logger$6 = console_with_prefix('batch');
21757
21804
 
21758
21805
  /**
21759
21806
  * RequestBatcher: manages the queueing, flushing, retry etc of requests of one
@@ -21881,7 +21928,7 @@
21881
21928
  */
21882
21929
  RequestBatcher.prototype.flush = function(options) {
21883
21930
  if (this.requestInProgress) {
21884
- logger$5.log('Flush: Request already in progress');
21931
+ logger$6.log('Flush: Request already in progress');
21885
21932
  return PromisePolyfill.resolve();
21886
21933
  }
21887
21934
 
@@ -22058,7 +22105,7 @@
22058
22105
  if (options.unloading) {
22059
22106
  requestOptions.transport = 'sendBeacon';
22060
22107
  }
22061
- logger$5.log('MIXPANEL REQUEST:', dataForRequest);
22108
+ logger$6.log('MIXPANEL REQUEST:', dataForRequest);
22062
22109
  return this.sendRequestPromise(dataForRequest, requestOptions).then(batchSendCallback);
22063
22110
  }, this))
22064
22111
  .catch(_.bind(function(err) {
@@ -22071,7 +22118,7 @@
22071
22118
  * Log error to global logger and optional user-defined logger.
22072
22119
  */
22073
22120
  RequestBatcher.prototype.reportError = function(msg, err) {
22074
- logger$5.error.apply(logger$5.error, arguments);
22121
+ logger$6.error.apply(logger$6.error, arguments);
22075
22122
  if (this.errorReporter) {
22076
22123
  try {
22077
22124
  if (!(err instanceof Error)) {
@@ -22079,7 +22126,7 @@
22079
22126
  }
22080
22127
  this.errorReporter(msg, err);
22081
22128
  } catch(err) {
22082
- logger$5.error(err);
22129
+ logger$6.error(err);
22083
22130
  }
22084
22131
  }
22085
22132
  };
@@ -22096,6 +22143,29 @@
22096
22143
 
22097
22144
  var RECORD_ENQUEUE_THROTTLE_MS = 250;
22098
22145
 
22146
+ var validateAllowedOrigins = function(origins, logger) {
22147
+ if (!_.isArray(origins)) {
22148
+ if (origins) {
22149
+ logger.critical('record_allowed_iframe_origins must be an array of origin strings, cross-origin recording will be disabled.');
22150
+ }
22151
+ return [];
22152
+ }
22153
+ var valid = [];
22154
+ for (var i = 0; i < origins.length; i++) {
22155
+ try {
22156
+ var origin = new URL(origins[i]).origin;
22157
+ if (origin === 'null') {
22158
+ logger.critical(origins[i] + ' has an opaque origin. Skipping this entry.');
22159
+ continue;
22160
+ }
22161
+ valid.push(origin);
22162
+ } catch (e) {
22163
+ logger.critical(origins[i] + ' is not a valid origin URL. Skipping this entry.');
22164
+ }
22165
+ }
22166
+ return valid;
22167
+ };
22168
+
22099
22169
  // stateless utils
22100
22170
  // mostly from https://github.com/mixpanel/mixpanel-js/blob/989ada50f518edab47b9c4fd9535f9fbd5ec5fc0/src/autotrack-utils.js
22101
22171
 
@@ -22201,7 +22271,7 @@
22201
22271
 
22202
22272
  var MAX_DEPTH = 5;
22203
22273
 
22204
- var logger$4 = console_with_prefix('autocapture');
22274
+ var logger$5 = console_with_prefix('autocapture');
22205
22275
 
22206
22276
 
22207
22277
  function getClasses(el) {
@@ -22465,7 +22535,7 @@
22465
22535
  return false;
22466
22536
  }
22467
22537
  } catch (err) {
22468
- logger$4.critical('Error while checking element in allowElementCallback', err);
22538
+ logger$5.critical('Error while checking element in allowElementCallback', err);
22469
22539
  return false;
22470
22540
  }
22471
22541
  }
@@ -22482,7 +22552,7 @@
22482
22552
  return true;
22483
22553
  }
22484
22554
  } catch (err) {
22485
- logger$4.critical('Error while checking selector: ' + sel, err);
22555
+ logger$5.critical('Error while checking selector: ' + sel, err);
22486
22556
  }
22487
22557
  }
22488
22558
  return false;
@@ -22497,7 +22567,7 @@
22497
22567
  return true;
22498
22568
  }
22499
22569
  } catch (err) {
22500
- logger$4.critical('Error while checking element in blockElementCallback', err);
22570
+ logger$5.critical('Error while checking element in blockElementCallback', err);
22501
22571
  return true;
22502
22572
  }
22503
22573
  }
@@ -22511,7 +22581,7 @@
22511
22581
  return true;
22512
22582
  }
22513
22583
  } catch (err) {
22514
- logger$4.critical('Error while checking selector: ' + sel, err);
22584
+ logger$5.critical('Error while checking selector: ' + sel, err);
22515
22585
  }
22516
22586
  }
22517
22587
  }
@@ -23067,7 +23137,7 @@
23067
23137
  *
23068
23138
  */
23069
23139
 
23070
- var logger$3 = console_with_prefix('network-plugin');
23140
+ var logger$4 = console_with_prefix('network-plugin');
23071
23141
 
23072
23142
  /**
23073
23143
  * Get the time origin for converting performance timestamps to absolute timestamps.
@@ -23219,7 +23289,7 @@
23219
23289
  return str;
23220
23290
  }
23221
23291
  if (str.length > MAX_BODY_SIZE) {
23222
- logger$3.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
23292
+ logger$4.error('Body truncated from ' + str.length + ' to ' + MAX_BODY_SIZE + ' characters');
23223
23293
  return str.substring(0, MAX_BODY_SIZE) + '... [truncated]';
23224
23294
  }
23225
23295
  return str;
@@ -23233,7 +23303,7 @@
23233
23303
  */
23234
23304
  function initPerformanceObserver(cb, win, options) {
23235
23305
  if (!win.PerformanceObserver) {
23236
- logger$3.error('PerformanceObserver not supported');
23306
+ logger$4.error('PerformanceObserver not supported');
23237
23307
  return function() {
23238
23308
  //
23239
23309
  };
@@ -23386,7 +23456,7 @@
23386
23456
  attempt = 0;
23387
23457
  }
23388
23458
  if (attempt > 10) {
23389
- logger$3.error('Cannot find performance entry');
23459
+ logger$4.error('Cannot find performance entry');
23390
23460
  return Promise.resolve(null);
23391
23461
  }
23392
23462
  var urlPerformanceEntries = /** @type {PerformanceResourceTiming[]} */ (
@@ -23507,7 +23577,7 @@
23507
23577
  )
23508
23578
  .then(function(entry) {
23509
23579
  if (!entry) {
23510
- logger$3.error('Failed to get performance entry for XHR request to ' + req.url);
23580
+ logger$4.error('Failed to get performance entry for XHR request to ' + req.url);
23511
23581
  return;
23512
23582
  }
23513
23583
  /** @type {NetworkRequest} */
@@ -23527,7 +23597,7 @@
23527
23597
  cb({ requests: [request] });
23528
23598
  })
23529
23599
  .catch(function(e) {
23530
- logger$3.error('Error recording XHR request to ' + req.url + ': ' + String(e));
23600
+ logger$4.error('Error recording XHR request to ' + req.url + ': ' + String(e));
23531
23601
  });
23532
23602
  });
23533
23603
 
@@ -23619,7 +23689,7 @@
23619
23689
  })
23620
23690
  .then(function(entry) {
23621
23691
  if (!entry) {
23622
- logger$3.error('Failed to get performance entry for fetch request to ' + req.url);
23692
+ logger$4.error('Failed to get performance entry for fetch request to ' + req.url);
23623
23693
  return;
23624
23694
  }
23625
23695
  /** @type {NetworkRequest} */
@@ -23639,7 +23709,7 @@
23639
23709
  cb({ requests: [request] });
23640
23710
  })
23641
23711
  .catch(function (e) {
23642
- logger$3.error('Error recording fetch request to ' + req.url + ': ' + String(e));
23712
+ logger$4.error('Error recording fetch request to ' + req.url + ': ' + String(e));
23643
23713
  });
23644
23714
 
23645
23715
  return originalFetchPromise;
@@ -23712,7 +23782,7 @@
23712
23782
  */
23713
23783
 
23714
23784
 
23715
- var logger$2 = console_with_prefix('recorder');
23785
+ var logger$3 = console_with_prefix('recorder');
23716
23786
  var CompressionStream = win['CompressionStream'];
23717
23787
 
23718
23788
  var RECORDER_BATCHER_LIB_CONFIG = {
@@ -23892,14 +23962,14 @@
23892
23962
  }
23893
23963
 
23894
23964
  if (this._stopRecording !== null) {
23895
- logger$2.log('Recording already in progress, skipping startRecording.');
23965
+ logger$3.log('Recording already in progress, skipping startRecording.');
23896
23966
  return;
23897
23967
  }
23898
23968
 
23899
23969
  this.recordMaxMs = this.getConfig('record_max_ms');
23900
23970
  if (this.recordMaxMs > MAX_RECORDING_MS) {
23901
23971
  this.recordMaxMs = MAX_RECORDING_MS;
23902
- logger$2.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
23972
+ logger$3.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
23903
23973
  }
23904
23974
 
23905
23975
  if (!this.maxExpires) {
@@ -23963,6 +24033,8 @@
23963
24033
  );
23964
24034
  }
23965
24035
 
24036
+ var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$3);
24037
+
23966
24038
  try {
23967
24039
  this._stopRecording = this._rrwebRecord({
23968
24040
  'emit': function (ev) {
@@ -23997,6 +24069,8 @@
23997
24069
  'maskTextSelector': '*',
23998
24070
  'maskInputFn': this._getMaskFn(shouldMaskInput, privacyConfig),
23999
24071
  'maskTextFn': this._getMaskFn(shouldMaskText, privacyConfig),
24072
+ 'recordCrossOriginIframes': validatedOrigins.length > 0,
24073
+ 'allowedIframeOrigins': validatedOrigins,
24000
24074
  'recordCanvas': this.getConfig('record_canvas'),
24001
24075
  'sampling': {
24002
24076
  'canvas': 15
@@ -24221,14 +24295,14 @@
24221
24295
 
24222
24296
 
24223
24297
  SessionRecording.prototype.reportError = function(msg, err) {
24224
- logger$2.error.apply(logger$2.error, arguments);
24298
+ logger$3.error.apply(logger$3.error, arguments);
24225
24299
  try {
24226
24300
  if (!err && !(msg instanceof Error)) {
24227
24301
  msg = new Error(msg);
24228
24302
  }
24229
24303
  this.getConfig('error_reporter')(msg, err);
24230
24304
  } catch(err) {
24231
- logger$2.error(err);
24305
+ logger$3.error(err);
24232
24306
  }
24233
24307
  };
24234
24308
 
@@ -24257,7 +24331,7 @@
24257
24331
  var configValue = this.getConfig('record_min_ms');
24258
24332
 
24259
24333
  if (configValue > MAX_VALUE_FOR_MIN_RECORDING_MS) {
24260
- logger$2.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
24334
+ logger$3.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
24261
24335
  return MAX_VALUE_FOR_MIN_RECORDING_MS;
24262
24336
  }
24263
24337
 
@@ -24420,7 +24494,7 @@
24420
24494
  .catch(this.handleError.bind(this));
24421
24495
  };
24422
24496
 
24423
- var logger$1 = console_with_prefix('recorder');
24497
+ var logger$2 = console_with_prefix('recorder');
24424
24498
 
24425
24499
  /**
24426
24500
  * Recorder API: bundles rrweb and and exposes methods to start and stop recordings.
@@ -24436,7 +24510,7 @@
24436
24510
  */
24437
24511
  this.recordingRegistry = new RecordingRegistry({
24438
24512
  mixpanelInstance: this.mixpanelInstance,
24439
- errorReporter: logger$1.error,
24513
+ errorReporter: logger$2.error,
24440
24514
  sharedLockStorage: sharedLockStorage
24441
24515
  });
24442
24516
  this._flushInactivePromise = this.recordingRegistry.flushInactiveRecordings();
@@ -24448,17 +24522,17 @@
24448
24522
  MixpanelRecorder.prototype.startRecording = function(options) {
24449
24523
  options = options || {};
24450
24524
  if (this.activeRecording && !this.activeRecording.isRrwebStopped()) {
24451
- logger$1.log('Recording already in progress, skipping startRecording.');
24525
+ logger$2.log('Recording already in progress, skipping startRecording.');
24452
24526
  return;
24453
24527
  }
24454
24528
 
24455
24529
  var onIdleTimeout = function () {
24456
- logger$1.log('Idle timeout reached, restarting recording.');
24530
+ logger$2.log('Idle timeout reached, restarting recording.');
24457
24531
  this.resetRecording();
24458
24532
  }.bind(this);
24459
24533
 
24460
24534
  var onMaxLengthReached = function () {
24461
- logger$1.log('Max recording length reached, stopping recording.');
24535
+ logger$2.log('Max recording length reached, stopping recording.');
24462
24536
  this.resetRecording();
24463
24537
  }.bind(this);
24464
24538
 
@@ -24528,7 +24602,7 @@
24528
24602
  } else if (startNewIfInactive) {
24529
24603
  return this.startRecording({shouldStopBatcher: false});
24530
24604
  } else {
24531
- logger$1.log('No resumable recording found.');
24605
+ logger$2.log('No resumable recording found.');
24532
24606
  return null;
24533
24607
  }
24534
24608
  }.bind(this));
@@ -25193,7 +25267,7 @@
25193
25267
  observer.observe(shadowRoot, this.observerConfig);
25194
25268
  this.shadowObservers.push(observer);
25195
25269
  } catch (e) {
25196
- logger$4.critical('Error while observing shadow root', e);
25270
+ logger$5.critical('Error while observing shadow root', e);
25197
25271
  }
25198
25272
  };
25199
25273
 
@@ -25204,7 +25278,7 @@
25204
25278
  }
25205
25279
 
25206
25280
  if (!weakSetSupported()) {
25207
- logger$4.critical('Shadow DOM observation unavailable: WeakSet not supported');
25281
+ logger$5.critical('Shadow DOM observation unavailable: WeakSet not supported');
25208
25282
  return;
25209
25283
  }
25210
25284
 
@@ -25220,7 +25294,7 @@
25220
25294
  try {
25221
25295
  this.shadowObservers[i].disconnect();
25222
25296
  } catch (e) {
25223
- logger$4.critical('Error while disconnecting shadow DOM observer', e);
25297
+ logger$5.critical('Error while disconnecting shadow DOM observer', e);
25224
25298
  }
25225
25299
  }
25226
25300
  this.shadowObservers = [];
@@ -25408,7 +25482,7 @@
25408
25482
 
25409
25483
  this.mutationObserver.observe(document.body || document.documentElement, MUTATION_OBSERVER_CONFIG);
25410
25484
  } catch (e) {
25411
- logger$4.critical('Error while setting up mutation observer', e);
25485
+ logger$5.critical('Error while setting up mutation observer', e);
25412
25486
  }
25413
25487
  }
25414
25488
 
@@ -25423,7 +25497,7 @@
25423
25497
  );
25424
25498
  this.shadowDOMObserver.start();
25425
25499
  } catch (e) {
25426
- logger$4.critical('Error while setting up shadow DOM observer', e);
25500
+ logger$5.critical('Error while setting up shadow DOM observer', e);
25427
25501
  this.shadowDOMObserver = null;
25428
25502
  }
25429
25503
  }
@@ -25450,7 +25524,7 @@
25450
25524
  try {
25451
25525
  listener.target.removeEventListener(listener.event, listener.handler, listener.options);
25452
25526
  } catch (e) {
25453
- logger$4.critical('Error while removing event listener', e);
25527
+ logger$5.critical('Error while removing event listener', e);
25454
25528
  }
25455
25529
  }
25456
25530
  this.eventListeners = [];
@@ -25459,7 +25533,7 @@
25459
25533
  try {
25460
25534
  this.mutationObserver.disconnect();
25461
25535
  } catch (e) {
25462
- logger$4.critical('Error while disconnecting mutation observer', e);
25536
+ logger$5.critical('Error while disconnecting mutation observer', e);
25463
25537
  }
25464
25538
  this.mutationObserver = null;
25465
25539
  }
@@ -25468,7 +25542,7 @@
25468
25542
  try {
25469
25543
  this.shadowDOMObserver.stop();
25470
25544
  } catch (e) {
25471
- logger$4.critical('Error while stopping shadow DOM observer', e);
25545
+ logger$5.critical('Error while stopping shadow DOM observer', e);
25472
25546
  }
25473
25547
  this.shadowDOMObserver = null;
25474
25548
  }
@@ -25546,7 +25620,7 @@
25546
25620
 
25547
25621
  Autocapture.prototype.init = function() {
25548
25622
  if (!minDOMApisSupported()) {
25549
- logger$4.critical('Autocapture unavailable: missing required DOM APIs');
25623
+ logger$5.critical('Autocapture unavailable: missing required DOM APIs');
25550
25624
  return;
25551
25625
  }
25552
25626
  this.initPageListeners();
@@ -25586,7 +25660,7 @@
25586
25660
  try {
25587
25661
  return !urlMatchesRegexList(currentUrl, allowUrlRegexes);
25588
25662
  } catch (err) {
25589
- logger$4.critical('Error while checking block URL regexes: ', err);
25663
+ logger$5.critical('Error while checking block URL regexes: ', err);
25590
25664
  return true;
25591
25665
  }
25592
25666
  }
@@ -25599,7 +25673,7 @@
25599
25673
  try {
25600
25674
  return urlMatchesRegexList(currentUrl, blockUrlRegexes);
25601
25675
  } catch (err) {
25602
- logger$4.critical('Error while checking block URL regexes: ', err);
25676
+ logger$5.critical('Error while checking block URL regexes: ', err);
25603
25677
  return true;
25604
25678
  }
25605
25679
  };
@@ -25737,7 +25811,7 @@
25737
25811
  return;
25738
25812
  }
25739
25813
 
25740
- logger$4.log('Initializing scroll depth tracking');
25814
+ logger$5.log('Initializing scroll depth tracking');
25741
25815
 
25742
25816
  this.maxScrollViewDepth = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
25743
25817
 
@@ -25763,7 +25837,7 @@
25763
25837
  if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
25764
25838
  return;
25765
25839
  }
25766
- logger$4.log('Initializing click tracking');
25840
+ logger$5.log('Initializing click tracking');
25767
25841
 
25768
25842
  this.listenerClick = function(ev) {
25769
25843
  if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
@@ -25782,7 +25856,7 @@
25782
25856
  return;
25783
25857
  }
25784
25858
 
25785
- logger$4.log('Initializing dead click tracking');
25859
+ logger$5.log('Initializing dead click tracking');
25786
25860
  if (!this._deadClickTracker) {
25787
25861
  this._deadClickTracker = new DeadClickTracker(function(deadClickEvent) {
25788
25862
  this.trackDomEvent(deadClickEvent, MP_EV_DEAD_CLICK);
@@ -25816,7 +25890,7 @@
25816
25890
  if (!this.getConfig(CONFIG_TRACK_INPUT)) {
25817
25891
  return;
25818
25892
  }
25819
- logger$4.log('Initializing input tracking');
25893
+ logger$5.log('Initializing input tracking');
25820
25894
 
25821
25895
  this.listenerChange = function(ev) {
25822
25896
  if (!this.getConfig(CONFIG_TRACK_INPUT)) {
@@ -25833,7 +25907,7 @@
25833
25907
  if (!this.pageviewTrackingConfig()) {
25834
25908
  return;
25835
25909
  }
25836
- logger$4.log('Initializing pageview tracking');
25910
+ logger$5.log('Initializing pageview tracking');
25837
25911
 
25838
25912
  var previousTrackedUrl = '';
25839
25913
  var tracked = false;
@@ -25868,7 +25942,7 @@
25868
25942
  }
25869
25943
  if (didPathChange) {
25870
25944
  this.lastScrollCheckpoint = 0;
25871
- logger$4.log('Path change: re-initializing scroll depth checkpoints');
25945
+ logger$5.log('Path change: re-initializing scroll depth checkpoints');
25872
25946
  }
25873
25947
  }
25874
25948
  }.bind(this));
@@ -25883,7 +25957,7 @@
25883
25957
  return;
25884
25958
  }
25885
25959
 
25886
- logger$4.log('Initializing rage click tracking');
25960
+ logger$5.log('Initializing rage click tracking');
25887
25961
  if (!this._rageClickTracker) {
25888
25962
  this._rageClickTracker = new RageClickTracker();
25889
25963
  }
@@ -25913,7 +25987,7 @@
25913
25987
  if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
25914
25988
  return;
25915
25989
  }
25916
- logger$4.log('Initializing scroll tracking');
25990
+ logger$5.log('Initializing scroll tracking');
25917
25991
  this.lastScrollCheckpoint = 0;
25918
25992
 
25919
25993
  var scrollTrackFunction = function() {
@@ -25950,7 +26024,7 @@
25950
26024
  }
25951
26025
  }
25952
26026
  } catch (err) {
25953
- logger$4.critical('Error while calculating scroll percentage', err);
26027
+ logger$5.critical('Error while calculating scroll percentage', err);
25954
26028
  }
25955
26029
  if (shouldTrack) {
25956
26030
  this.mp.track(MP_EV_SCROLL, props);
@@ -25968,7 +26042,7 @@
25968
26042
  if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
25969
26043
  return;
25970
26044
  }
25971
- logger$4.log('Initializing submit tracking');
26045
+ logger$5.log('Initializing submit tracking');
25972
26046
 
25973
26047
  this.listenerSubmit = function(ev) {
25974
26048
  if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
@@ -25990,7 +26064,7 @@
25990
26064
  return;
25991
26065
  }
25992
26066
 
25993
- logger$4.log('Initializing page visibility tracking.');
26067
+ logger$5.log('Initializing page visibility tracking.');
25994
26068
  this._initScrollDepthTracking();
25995
26069
  var previousTrackedUrl = _.info.currentUrl();
25996
26070
 
@@ -26075,7 +26149,7 @@
26075
26149
  return win[TARGETING_GLOBAL_NAME];
26076
26150
  };
26077
26151
 
26078
- var logger = console_with_prefix('flags');
26152
+ var logger$1 = console_with_prefix('flags');
26079
26153
  var FLAGS_CONFIG_KEY = 'flags';
26080
26154
 
26081
26155
  var CONFIG_CONTEXT = 'context';
@@ -26118,12 +26192,14 @@
26118
26192
 
26119
26193
  FeatureFlagManager.prototype.init = function() {
26120
26194
  if (!this.minApisSupported()) {
26121
- logger.critical('Feature Flags unavailable: missing minimum required APIs');
26195
+ logger$1.critical('Feature Flags unavailable: missing minimum required APIs');
26122
26196
  return;
26123
26197
  }
26124
26198
 
26125
26199
  this.flags = null;
26126
- this.fetchFlags();
26200
+ this.fetchFlags().catch(function() {
26201
+ logger$1.error('Error fetching flags during init');
26202
+ });
26127
26203
 
26128
26204
  this.trackedFeatures = new Set();
26129
26205
  this.pendingFirstTimeEvents = {};
@@ -26153,7 +26229,7 @@
26153
26229
 
26154
26230
  FeatureFlagManager.prototype.updateContext = function(newContext, options) {
26155
26231
  if (!this.isSystemEnabled()) {
26156
- logger.critical('Feature Flags not enabled, cannot update context');
26232
+ logger$1.critical('Feature Flags not enabled, cannot update context');
26157
26233
  return Promise.resolve();
26158
26234
  }
26159
26235
 
@@ -26164,13 +26240,17 @@
26164
26240
  var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
26165
26241
  ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
26166
26242
 
26167
- this.setMpConfig(FLAGS_CONFIG_KEY, ffConfig);
26168
- return this.fetchFlags();
26243
+ var configUpdate = {};
26244
+ configUpdate[FLAGS_CONFIG_KEY] = ffConfig;
26245
+ this.setMpConfig(configUpdate);
26246
+ return this.fetchFlags().catch(function() {
26247
+ logger$1.error('Error fetching flags during updateContext');
26248
+ });
26169
26249
  };
26170
26250
 
26171
26251
  FeatureFlagManager.prototype.areFlagsReady = function() {
26172
26252
  if (!this.isSystemEnabled()) {
26173
- logger.error('Feature Flags not enabled');
26253
+ logger$1.error('Feature Flags not enabled');
26174
26254
  }
26175
26255
  return !!this.flags;
26176
26256
  };
@@ -26183,7 +26263,7 @@
26183
26263
  var distinctId = this.getMpProperty('distinct_id');
26184
26264
  var deviceId = this.getMpProperty('$device_id');
26185
26265
  var traceparent = generateTraceparent();
26186
- logger.log('Fetching flags for distinct ID: ' + distinctId);
26266
+ logger$1.log('Fetching flags for distinct ID: ' + distinctId);
26187
26267
 
26188
26268
  var context = _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT));
26189
26269
  var searchParams = new URLSearchParams();
@@ -26202,99 +26282,113 @@
26202
26282
  }
26203
26283
  }).then(function(response) {
26204
26284
  this.markFetchComplete();
26205
- return response.json().then(function(responseBody) {
26206
- var responseFlags = responseBody['flags'];
26207
- if (!responseFlags) {
26208
- throw new Error('No flags in API response');
26209
- }
26210
- var flags = new Map();
26211
- var pendingFirstTimeEvents = {};
26212
-
26213
- // Process flags from response
26214
- _.each(responseFlags, function(data, key) {
26215
- // Check if this flag has any activated first-time events this session
26216
- var hasActivatedEvent = false;
26217
- var prefix = key + ':';
26218
- _.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
26219
- if (eventKey.startsWith(prefix)) {
26220
- hasActivatedEvent = true;
26221
- }
26222
- });
26285
+ return response.json();
26286
+ }.bind(this)).then(function(responseBody) {
26287
+ var responseFlags = responseBody['flags'];
26288
+ if (!responseFlags) {
26289
+ throw new Error('No flags in API response');
26290
+ }
26291
+ var flags = new Map();
26292
+ var pendingFirstTimeEvents = {};
26293
+
26294
+ // Process flags from response
26295
+ _.each(responseFlags, function(data, key) {
26296
+ // Check if this flag has any activated first-time events this session
26297
+ var hasActivatedEvent = false;
26298
+ var prefix = key + ':';
26299
+ _.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
26300
+ if (eventKey.startsWith(prefix)) {
26301
+ hasActivatedEvent = true;
26302
+ }
26303
+ });
26223
26304
 
26224
- if (hasActivatedEvent) {
26225
- // Preserve the activated variant, don't overwrite with server's current variant
26226
- var currentFlag = this.flags && this.flags.get(key);
26227
- if (currentFlag) {
26228
- flags.set(key, currentFlag);
26229
- }
26230
- } else {
26231
- // Use server's current variant
26232
- flags.set(key, {
26233
- 'key': data['variant_key'],
26234
- 'value': data['variant_value'],
26235
- 'experiment_id': data['experiment_id'],
26236
- 'is_experiment_active': data['is_experiment_active'],
26237
- 'is_qa_tester': data['is_qa_tester']
26238
- });
26305
+ if (hasActivatedEvent) {
26306
+ // Preserve the activated variant, don't overwrite with server's current variant
26307
+ var currentFlag = this.flags && this.flags.get(key);
26308
+ if (currentFlag) {
26309
+ flags.set(key, currentFlag);
26239
26310
  }
26240
- }, this);
26311
+ } else {
26312
+ // Use server's current variant
26313
+ flags.set(key, {
26314
+ 'key': data['variant_key'],
26315
+ 'value': data['variant_value'],
26316
+ 'experiment_id': data['experiment_id'],
26317
+ 'is_experiment_active': data['is_experiment_active'],
26318
+ 'is_qa_tester': data['is_qa_tester']
26319
+ });
26320
+ }
26321
+ }, this);
26241
26322
 
26242
- // Process top-level pending_first_time_events array
26243
- var topLevelDefinitions = responseBody['pending_first_time_events'];
26244
- if (topLevelDefinitions && topLevelDefinitions.length > 0) {
26245
- _.each(topLevelDefinitions, function(def) {
26246
- var flagKey = def['flag_key'];
26247
- var eventKey = getPendingEventKey(flagKey, def['first_time_event_hash']);
26323
+ // Process top-level pending_first_time_events array
26324
+ var topLevelDefinitions = responseBody['pending_first_time_events'];
26325
+ if (topLevelDefinitions && topLevelDefinitions.length > 0) {
26326
+ _.each(topLevelDefinitions, function(def) {
26327
+ var flagKey = def['flag_key'];
26328
+ var eventKey = getPendingEventKey(flagKey, def['first_time_event_hash']);
26248
26329
 
26249
- // Skip if this specific event has already been activated this session
26250
- if (this.activatedFirstTimeEvents[eventKey]) {
26251
- return;
26252
- }
26330
+ // Skip if this specific event has already been activated this session
26331
+ if (this.activatedFirstTimeEvents[eventKey]) {
26332
+ return;
26333
+ }
26253
26334
 
26254
- // Store pending event definition using composite key
26255
- pendingFirstTimeEvents[eventKey] = {
26256
- 'flag_key': flagKey,
26257
- 'flag_id': def['flag_id'],
26258
- 'project_id': def['project_id'],
26259
- 'first_time_event_hash': def['first_time_event_hash'],
26260
- 'event_name': def['event_name'],
26261
- 'property_filters': def['property_filters'],
26262
- 'pending_variant': def['pending_variant']
26263
- };
26264
- }, this);
26265
- }
26335
+ // Store pending event definition using composite key
26336
+ pendingFirstTimeEvents[eventKey] = {
26337
+ 'flag_key': flagKey,
26338
+ 'flag_id': def['flag_id'],
26339
+ 'project_id': def['project_id'],
26340
+ 'first_time_event_hash': def['first_time_event_hash'],
26341
+ 'event_name': def['event_name'],
26342
+ 'property_filters': def['property_filters'],
26343
+ 'pending_variant': def['pending_variant']
26344
+ };
26345
+ }, this);
26346
+ }
26266
26347
 
26267
- // Preserve any activated orphaned flags (flags that were activated but are no longer in response)
26268
- if (this.activatedFirstTimeEvents) {
26269
- _.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
26270
- var flagKey = getFlagKeyFromPendingEventKey(eventKey);
26271
- if (activated && !flags.has(flagKey) && this.flags && this.flags.has(flagKey)) {
26272
- // Keep the activated flag even though it's not in the new response
26273
- flags.set(flagKey, this.flags.get(flagKey));
26274
- }
26275
- }, this);
26276
- }
26348
+ // Preserve any activated orphaned flags (flags that were activated but are no longer in response)
26349
+ if (this.activatedFirstTimeEvents) {
26350
+ _.each(this.activatedFirstTimeEvents, function(activated, eventKey) {
26351
+ var flagKey = getFlagKeyFromPendingEventKey(eventKey);
26352
+ if (activated && !flags.has(flagKey) && this.flags && this.flags.has(flagKey)) {
26353
+ // Keep the activated flag even though it's not in the new response
26354
+ flags.set(flagKey, this.flags.get(flagKey));
26355
+ }
26356
+ }, this);
26357
+ }
26277
26358
 
26278
- this.flags = flags;
26279
- this.pendingFirstTimeEvents = pendingFirstTimeEvents;
26280
- this._traceparent = traceparent;
26359
+ this.flags = flags;
26360
+ this.pendingFirstTimeEvents = pendingFirstTimeEvents;
26361
+ this._traceparent = traceparent;
26281
26362
 
26282
- this._loadTargetingIfNeeded();
26283
- }.bind(this)).catch(function(error) {
26284
- this.markFetchComplete();
26285
- logger.error(error);
26286
- }.bind(this));
26363
+ this._loadTargetingIfNeeded();
26287
26364
  }.bind(this)).catch(function(error) {
26288
- this.markFetchComplete();
26289
- logger.error(error);
26365
+ if (this._fetchInProgressStartTime) {
26366
+ this.markFetchComplete();
26367
+ }
26368
+ logger$1.error(error);
26369
+ throw error;
26290
26370
  }.bind(this));
26291
26371
 
26292
26372
  return this.fetchPromise;
26293
26373
  };
26294
26374
 
26375
+ FeatureFlagManager.prototype.loadFlags = function() {
26376
+ if (!this.isSystemEnabled()) {
26377
+ return Promise.resolve();
26378
+ }
26379
+ if (!this.trackedFeatures) {
26380
+ logger$1.error('loadFlags called before init');
26381
+ return Promise.resolve();
26382
+ }
26383
+ if (this._fetchInProgressStartTime) {
26384
+ return this.fetchPromise;
26385
+ }
26386
+ return this.fetchFlags();
26387
+ };
26388
+
26295
26389
  FeatureFlagManager.prototype.markFetchComplete = function() {
26296
26390
  if (!this._fetchInProgressStartTime) {
26297
- logger.error('Fetch in progress started time not set, cannot mark fetch complete');
26391
+ logger$1.error('Fetch in progress started time not set, cannot mark fetch complete');
26298
26392
  return;
26299
26393
  }
26300
26394
  this._fetchStartTime = this._fetchInProgressStartTime;
@@ -26316,7 +26410,7 @@
26316
26410
 
26317
26411
  if (hasPropertyFilters) {
26318
26412
  this.getTargeting().then(function() {
26319
- logger.log('targeting loaded for property filter evaluation');
26413
+ logger$1.log('targeting loaded for property filter evaluation');
26320
26414
  });
26321
26415
  }
26322
26416
  };
@@ -26331,7 +26425,7 @@
26331
26425
  this.loadExtraBundle.bind(this),
26332
26426
  this.targetingSrc
26333
26427
  ).catch(function(error) {
26334
- logger.error('Failed to load targeting: ' + error);
26428
+ logger$1.error('Failed to load targeting: ' + error);
26335
26429
  }.bind(this));
26336
26430
  };
26337
26431
 
@@ -26385,7 +26479,7 @@
26385
26479
 
26386
26480
  // If no targeting library and event has property filters, skip it
26387
26481
  if (!targeting && pendingEvent['property_filters'] && !_.isEmptyObject(pendingEvent['property_filters'])) {
26388
- logger.warn('Skipping event check for "' + flagKey + '" - property filters require targeting library');
26482
+ logger$1.warn('Skipping event check for "' + flagKey + '" - property filters require targeting library');
26389
26483
  return;
26390
26484
  }
26391
26485
 
@@ -26408,7 +26502,7 @@
26408
26502
  }
26409
26503
 
26410
26504
  if (matchResult.error) {
26411
- logger.error('Error checking first-time event for flag "' + flagKey + '": ' + matchResult.error);
26505
+ logger$1.error('Error checking first-time event for flag "' + flagKey + '": ' + matchResult.error);
26412
26506
  return;
26413
26507
  }
26414
26508
 
@@ -26416,7 +26510,7 @@
26416
26510
  return;
26417
26511
  }
26418
26512
 
26419
- logger.log('First-time event matched for flag "' + flagKey + '": ' + eventName);
26513
+ logger$1.log('First-time event matched for flag "' + flagKey + '": ' + eventName);
26420
26514
 
26421
26515
  var newVariant = {
26422
26516
  'key': pendingEvent['pending_variant']['variant_key'],
@@ -26457,7 +26551,7 @@
26457
26551
  'first_time_event_hash': firstTimeEventHash
26458
26552
  };
26459
26553
 
26460
- logger.log('Recording first-time event for flag: ' + flagId);
26554
+ logger$1.log('Recording first-time event for flag: ' + flagId);
26461
26555
 
26462
26556
  // Fire-and-forget POST request
26463
26557
  this.fetch.call(win, url, {
@@ -26470,14 +26564,14 @@
26470
26564
  'body': JSON.stringify(payload)
26471
26565
  }).catch(function(error) {
26472
26566
  // Silent failure - cohort sync will catch up
26473
- logger.error('Failed to record first-time event for flag ' + flagId + ': ' + error);
26567
+ logger$1.error('Failed to record first-time event for flag ' + flagId + ': ' + error);
26474
26568
  });
26475
26569
  };
26476
26570
 
26477
26571
  FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
26478
26572
  if (!this.fetchPromise) {
26479
26573
  return new Promise(function(resolve) {
26480
- logger.critical('Feature Flags not initialized');
26574
+ logger$1.critical('Feature Flags not initialized');
26481
26575
  resolve(fallback);
26482
26576
  });
26483
26577
  }
@@ -26485,19 +26579,19 @@
26485
26579
  return this.fetchPromise.then(function() {
26486
26580
  return this.getVariantSync(featureName, fallback);
26487
26581
  }.bind(this)).catch(function(error) {
26488
- logger.error(error);
26582
+ logger$1.error(error);
26489
26583
  return fallback;
26490
26584
  });
26491
26585
  };
26492
26586
 
26493
26587
  FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
26494
26588
  if (!this.areFlagsReady()) {
26495
- logger.log('Flags not loaded yet');
26589
+ logger$1.log('Flags not loaded yet');
26496
26590
  return fallback;
26497
26591
  }
26498
26592
  var feature = this.flags.get(featureName);
26499
26593
  if (!feature) {
26500
- logger.log('No flag found: "' + featureName + '"');
26594
+ logger$1.log('No flag found: "' + featureName + '"');
26501
26595
  return fallback;
26502
26596
  }
26503
26597
  this.trackFeatureCheck(featureName, feature);
@@ -26508,14 +26602,14 @@
26508
26602
  return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
26509
26603
  return feature['value'];
26510
26604
  }).catch(function(error) {
26511
- logger.error(error);
26605
+ logger$1.error(error);
26512
26606
  return fallbackValue;
26513
26607
  });
26514
26608
  };
26515
26609
 
26516
26610
  // TODO remove deprecated method
26517
26611
  FeatureFlagManager.prototype.getFeatureData = function(featureName, fallbackValue) {
26518
- logger.critical('mixpanel.flags.get_feature_data() is deprecated and will be removed in a future release. Use mixpanel.flags.get_variant_value() instead.');
26612
+ 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.');
26519
26613
  return this.getVariantValue(featureName, fallbackValue);
26520
26614
  };
26521
26615
 
@@ -26527,7 +26621,7 @@
26527
26621
  return this.getVariantValue(featureName).then(function() {
26528
26622
  return this.isEnabledSync(featureName, fallbackValue);
26529
26623
  }.bind(this)).catch(function(error) {
26530
- logger.error(error);
26624
+ logger$1.error(error);
26531
26625
  return fallbackValue;
26532
26626
  });
26533
26627
  };
@@ -26536,7 +26630,7 @@
26536
26630
  fallbackValue = fallbackValue || false;
26537
26631
  var val = this.getVariantValueSync(featureName, fallbackValue);
26538
26632
  if (val !== true && val !== false) {
26539
- logger.error('Feature flag "' + featureName + '" value: ' + val + ' is not a boolean; returning fallback value: ' + fallbackValue);
26633
+ logger$1.error('Feature flag "' + featureName + '" value: ' + val + ' is not a boolean; returning fallback value: ' + fallbackValue);
26540
26634
  val = fallbackValue;
26541
26635
  }
26542
26636
  return val;
@@ -26571,6 +26665,13 @@
26571
26665
  this.track('$experiment_started', trackingProperties);
26572
26666
  };
26573
26667
 
26668
+ FeatureFlagManager.prototype.whenReady = function() {
26669
+ if (this.fetchPromise) {
26670
+ return this.fetchPromise;
26671
+ }
26672
+ return Promise.resolve();
26673
+ };
26674
+
26574
26675
  FeatureFlagManager.prototype.minApisSupported = function() {
26575
26676
  return !!this.fetch &&
26576
26677
  typeof Promise !== 'undefined' &&
@@ -26587,7 +26688,9 @@
26587
26688
  FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
26588
26689
  FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
26589
26690
  FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
26691
+ FeatureFlagManager.prototype['load_flags'] = FeatureFlagManager.prototype.loadFlags;
26590
26692
  FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
26693
+ FeatureFlagManager.prototype['when_ready'] = FeatureFlagManager.prototype.whenReady;
26591
26694
 
26592
26695
  // Deprecated method
26593
26696
  FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
@@ -26598,6 +26701,12 @@
26598
26701
  /* eslint camelcase: "off" */
26599
26702
 
26600
26703
 
26704
+ var logger = console_with_prefix('recorder');
26705
+
26706
+ var IFRAME_HANDSHAKE_REQUEST = 'mp_iframe_handshake_request';
26707
+ var IFRAME_HANDSHAKE_RESPONSE = 'mp_iframe_handshake_response';
26708
+
26709
+
26601
26710
  /**
26602
26711
  * RecorderManager: manages session recording initialization, lifecycle and state
26603
26712
  * @constructor
@@ -26617,6 +26726,8 @@
26617
26726
  this.libBasePath = initOptions.libBasePath;
26618
26727
 
26619
26728
  this._recorder = null;
26729
+ this._parentReplayId = null;
26730
+ this._parentFrameRetryInterval = null;
26620
26731
  };
26621
26732
 
26622
26733
  RecorderManager.prototype.shouldLoadRecorder = function() {
@@ -26670,6 +26781,22 @@
26670
26781
  }, this));
26671
26782
  }, this);
26672
26783
 
26784
+ // Cross-origin iframe handling
26785
+ var allowedOrigins = validateAllowedOrigins(this.getMpConfig('record_allowed_iframe_origins'), logger);
26786
+ var isCrossOriginRecordingEnabled = allowedOrigins.length > 0;
26787
+
26788
+ if (isCrossOriginRecordingEnabled) {
26789
+ // listen for handshake requests from their own child iframes (including nested)
26790
+ this._setupParentFrameListener(allowedOrigins);
26791
+
26792
+ if (win.parent !== win) {
26793
+ // also wait for parent's replay ID
26794
+ this._setupChildFrameListener(allowedOrigins, loadRecorder);
26795
+ this._sendParentFrameRequestWithRetry(allowedOrigins);
26796
+ return PromisePolyfill.resolve();
26797
+ }
26798
+ }
26799
+
26673
26800
  /**
26674
26801
  * If the user is sampled or start_session_recording is called, we always load the recorder since it's guaranteed a recording should start.
26675
26802
  * 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.
@@ -26789,6 +26916,10 @@
26789
26916
  };
26790
26917
 
26791
26918
  RecorderManager.prototype.getSessionReplayId = function() {
26919
+ // Child iframe uses parent's replay ID
26920
+ if (this._parentReplayId) {
26921
+ return this._parentReplayId;
26922
+ }
26792
26923
  var replay_id = null;
26793
26924
  if (this._recorder) {
26794
26925
  replay_id = this._recorder['replayId'];
@@ -26801,6 +26932,86 @@
26801
26932
  return this._recorder;
26802
26933
  };
26803
26934
 
26935
+ RecorderManager.prototype._setupChildFrameListener = function(allowedOrigins, loadRecorder) {
26936
+ if (this._childFrameMessageHandler) {
26937
+ return;
26938
+ }
26939
+ var self = this;
26940
+ this._childFrameMessageHandler = function(event) {
26941
+ if (allowedOrigins.indexOf(event.origin) === -1) return;
26942
+ var data = event.data;
26943
+ if (data && data['type'] === IFRAME_HANDSHAKE_RESPONSE && data['token'] === self.getMpConfig('token') && data['replayId']) {
26944
+ self._parentReplayId = data['replayId'];
26945
+ if (data['distinctId']) {
26946
+ self.mixpanelInstance['identify'](data['distinctId']);
26947
+ }
26948
+ self._parentFrameRetryActive = false;
26949
+ win.removeEventListener('message', self._childFrameMessageHandler);
26950
+ self._childFrameMessageHandler = null;
26951
+ loadRecorder(true);
26952
+ }
26953
+ };
26954
+ win.addEventListener('message', this._childFrameMessageHandler);
26955
+ };
26956
+
26957
+ RecorderManager.prototype._sendParentFrameRequest = function(allowedOrigins) {
26958
+ var message = {};
26959
+ message['type'] = IFRAME_HANDSHAKE_REQUEST;
26960
+ message['token'] = this.getMpConfig('token');
26961
+ for (var i = 0; i < allowedOrigins.length; i++) {
26962
+ try {
26963
+ win.parent.postMessage(message, allowedOrigins[i]);
26964
+ } catch (e) {
26965
+ // origin mismatch - ignore
26966
+ }
26967
+ }
26968
+ };
26969
+
26970
+ RecorderManager.prototype._sendParentFrameRequestWithRetry = function(allowedOrigins) {
26971
+ var self = this;
26972
+ var maxRetries = 10;
26973
+ var retryCount = 0;
26974
+ var delay = 50;
26975
+ this._parentFrameRetryActive = true;
26976
+
26977
+ this._sendParentFrameRequest(allowedOrigins);
26978
+
26979
+ function scheduleRetry() {
26980
+ setTimeout(function() {
26981
+ if (!self._parentFrameRetryActive || self._parentReplayId || ++retryCount >= maxRetries) {
26982
+ return;
26983
+ }
26984
+ self._sendParentFrameRequest(allowedOrigins);
26985
+ delay *= 2;
26986
+ scheduleRetry();
26987
+ }, delay);
26988
+ }
26989
+ scheduleRetry();
26990
+ };
26991
+
26992
+ RecorderManager.prototype._setupParentFrameListener = function(allowedOrigins) {
26993
+ if (this._parentFrameMessageHandler) {
26994
+ return;
26995
+ }
26996
+ var self = this;
26997
+ this._parentFrameMessageHandler = function(event) {
26998
+ if (allowedOrigins.indexOf(event.origin) === -1) return;
26999
+ var data = event.data;
27000
+ if (data && data['type'] === IFRAME_HANDSHAKE_REQUEST && data['token'] === self.getMpConfig('token')) {
27001
+ var replayId = self.getSessionReplayId();
27002
+ if (replayId) {
27003
+ var response = {};
27004
+ response['type'] = IFRAME_HANDSHAKE_RESPONSE;
27005
+ response['token'] = self.getMpConfig('token');
27006
+ response['replayId'] = replayId;
27007
+ response['distinctId'] = self.getDistinctId();
27008
+ event.source.postMessage(response, event.origin);
27009
+ }
27010
+ }
27011
+ };
27012
+ win.addEventListener('message', this._parentFrameMessageHandler);
27013
+ };
27014
+
26804
27015
  safewrapClass(RecorderManager);
26805
27016
 
26806
27017
  /* eslint camelcase: "off" */
@@ -28175,7 +28386,6 @@
28175
28386
  /** @const */ var SETTING_FALLBACK = 'fallback';
28176
28387
  /** @const */ var SETTING_DISABLED = 'disabled';
28177
28388
 
28178
-
28179
28389
  /*
28180
28390
  * Dynamic... constants? Is that an oxymoron?
28181
28391
  */
@@ -28260,6 +28470,7 @@
28260
28470
  'batch_request_timeout_ms': 90000,
28261
28471
  'batch_autostart': true,
28262
28472
  'hooks': {},
28473
+ 'record_allowed_iframe_origins': [],
28263
28474
  'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
28264
28475
  'record_block_selector': 'img, video, audio',
28265
28476
  'record_canvas': false,
@@ -29835,7 +30046,9 @@
29835
30046
 
29836
30047
  // check feature flags again if distinct id has changed
29837
30048
  if (new_distinct_id !== previous_distinct_id) {
29838
- this.flags.fetchFlags();
30049
+ this.flags.fetchFlags().catch(function() {
30050
+ console$1.error('[flags] Error fetching flags during identify');
30051
+ });
29839
30052
  }
29840
30053
  };
29841
30054