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
@@ -27,7 +27,7 @@
27
27
  }
28
28
 
29
29
  var Config = {
30
- LIB_VERSION: '2.76.0'
30
+ LIB_VERSION: '2.78.0'
31
31
  };
32
32
  var RECORDER_GLOBAL_NAME = '__mp_recorder';
33
33
 
@@ -10728,13 +10728,7 @@
10728
10728
  };
10729
10729
  while(_this.mapRemoves.length){
10730
10730
  var removedNode = _this.mapRemoves.shift();
10731
- if (removedNode.nodeName === "IFRAME") {
10732
- try {
10733
- _this.iframeManager.removeIframe(removedNode);
10734
- } catch (e2) {}
10735
- } else {
10736
- _this.stylesheetManager.cleanupStylesheetsForRemovedNode(removedNode);
10737
- }
10731
+ _this.cleanupRemovedNode(removedNode);
10738
10732
  _this.mirror.removeNodeFromMap(removedNode);
10739
10733
  }
10740
10734
  for(var _iterator = _create_for_of_iterator_helper_loose(_this.movedSet), _step; !(_step = _iterator()).done;){
@@ -11054,6 +11048,20 @@
11054
11048
  }
11055
11049
  }
11056
11050
  });
11051
+ __publicField$1(this, "cleanupRemovedNode", function(node2) {
11052
+ if (node2.nodeName === "IFRAME") {
11053
+ try {
11054
+ _this.iframeManager.removeIframe(node2);
11055
+ } catch (e2) {}
11056
+ } else {
11057
+ try {
11058
+ _this.stylesheetManager.cleanupStylesheetsForRemovedNode(node2);
11059
+ } catch (e2) {}
11060
+ }
11061
+ node2.childNodes.forEach(function(child) {
11062
+ _this.cleanupRemovedNode(child);
11063
+ });
11064
+ });
11057
11065
  }
11058
11066
  var _proto = MutationBuffer.prototype;
11059
11067
  _proto.init = function init(options) {
@@ -13281,6 +13289,31 @@
13281
13289
  _proto.destroy = function destroy() {};
13282
13290
  return ProcessedNodeManager;
13283
13291
  }();
13292
+ function toOrigin(url) {
13293
+ try {
13294
+ var origin = new URL(url).origin;
13295
+ return origin !== "null" ? origin : null;
13296
+ } catch (e) {
13297
+ return null;
13298
+ }
13299
+ }
13300
+ function buildAllowedOriginSet(origins) {
13301
+ if (!Array.isArray(origins) || origins.length === 0) {
13302
+ throw new Error("[rrweb] allowedIframeOrigins must be a non-empty array of origin strings.");
13303
+ }
13304
+ var set = /* @__PURE__ */ new Set();
13305
+ for(var i2 = 0; i2 < origins.length; i2++){
13306
+ var entry = origins[i2];
13307
+ if (typeof entry !== "string") {
13308
+ throw new Error("[rrweb] allowedIframeOrigins[" + i2 + "] must be a string, got " + (typeof entry === "undefined" ? "undefined" : _type_of(entry)) + ".");
13309
+ }
13310
+ var origin = toOrigin(entry);
13311
+ if (origin) {
13312
+ set.add(origin);
13313
+ }
13314
+ }
13315
+ return Object.freeze(set);
13316
+ }
13284
13317
  var wrappedEmit;
13285
13318
  var takeFullSnapshot$1;
13286
13319
  var canvasManager;
@@ -13302,10 +13335,17 @@
13302
13335
  var mirror = createMirror$2();
13303
13336
  function record(options) {
13304
13337
  if (options === void 0) options = {};
13305
- var emit = options.emit, checkoutEveryNms = options.checkoutEveryNms, checkoutEveryNth = options.checkoutEveryNth, _options_blockClass = options.blockClass, blockClass = _options_blockClass === void 0 ? "rr-block" : _options_blockClass, _options_blockSelector = options.blockSelector, blockSelector = _options_blockSelector === void 0 ? null : _options_blockSelector, _options_ignoreClass = options.ignoreClass, ignoreClass = _options_ignoreClass === void 0 ? "rr-ignore" : _options_ignoreClass, _options_ignoreSelector = options.ignoreSelector, ignoreSelector = _options_ignoreSelector === void 0 ? null : _options_ignoreSelector, _options_maskTextClass = options.maskTextClass, maskTextClass = _options_maskTextClass === void 0 ? "rr-mask" : _options_maskTextClass, _options_maskTextSelector = options.maskTextSelector, maskTextSelector = _options_maskTextSelector === void 0 ? null : _options_maskTextSelector, _options_inlineStylesheet = options.inlineStylesheet, inlineStylesheet = _options_inlineStylesheet === void 0 ? true : _options_inlineStylesheet, maskAllInputs = options.maskAllInputs, _maskInputOptions = options.maskInputOptions, _slimDOMOptions = options.slimDOMOptions, maskInputFn = options.maskInputFn, maskTextFn = options.maskTextFn, hooks = options.hooks, packFn = options.packFn, _options_sampling = options.sampling, sampling = _options_sampling === void 0 ? {} : _options_sampling, _options_dataURLOptions = options.dataURLOptions, dataURLOptions = _options_dataURLOptions === void 0 ? {} : _options_dataURLOptions, mousemoveWait = options.mousemoveWait, _options_recordDOM = options.recordDOM, recordDOM = _options_recordDOM === void 0 ? true : _options_recordDOM, _options_recordCanvas = options.recordCanvas, recordCanvas = _options_recordCanvas === void 0 ? false : _options_recordCanvas, _options_recordCrossOriginIframes = options.recordCrossOriginIframes, recordCrossOriginIframes = _options_recordCrossOriginIframes === void 0 ? false : _options_recordCrossOriginIframes, _options_recordAfter = options.recordAfter, recordAfter = _options_recordAfter === void 0 ? options.recordAfter === "DOMContentLoaded" ? options.recordAfter : "load" : _options_recordAfter, _options_userTriggeredOnInput = options.userTriggeredOnInput, userTriggeredOnInput = _options_userTriggeredOnInput === void 0 ? false : _options_userTriggeredOnInput, _options_collectFonts = options.collectFonts, collectFonts = _options_collectFonts === void 0 ? false : _options_collectFonts, _options_inlineImages = options.inlineImages, inlineImages = _options_inlineImages === void 0 ? false : _options_inlineImages, plugins = options.plugins, _options_keepIframeSrcFn = options.keepIframeSrcFn, keepIframeSrcFn = _options_keepIframeSrcFn === void 0 ? function() {
13338
+ var emit = options.emit, checkoutEveryNms = options.checkoutEveryNms, checkoutEveryNth = options.checkoutEveryNth, _options_blockClass = options.blockClass, blockClass = _options_blockClass === void 0 ? "rr-block" : _options_blockClass, _options_blockSelector = options.blockSelector, blockSelector = _options_blockSelector === void 0 ? null : _options_blockSelector, _options_ignoreClass = options.ignoreClass, ignoreClass = _options_ignoreClass === void 0 ? "rr-ignore" : _options_ignoreClass, _options_ignoreSelector = options.ignoreSelector, ignoreSelector = _options_ignoreSelector === void 0 ? null : _options_ignoreSelector, _options_maskTextClass = options.maskTextClass, maskTextClass = _options_maskTextClass === void 0 ? "rr-mask" : _options_maskTextClass, _options_maskTextSelector = options.maskTextSelector, maskTextSelector = _options_maskTextSelector === void 0 ? null : _options_maskTextSelector, _options_inlineStylesheet = options.inlineStylesheet, inlineStylesheet = _options_inlineStylesheet === void 0 ? true : _options_inlineStylesheet, maskAllInputs = options.maskAllInputs, _maskInputOptions = options.maskInputOptions, _slimDOMOptions = options.slimDOMOptions, maskInputFn = options.maskInputFn, maskTextFn = options.maskTextFn, hooks = options.hooks, packFn = options.packFn, _options_sampling = options.sampling, sampling = _options_sampling === void 0 ? {} : _options_sampling, _options_dataURLOptions = options.dataURLOptions, dataURLOptions = _options_dataURLOptions === void 0 ? {} : _options_dataURLOptions, mousemoveWait = options.mousemoveWait, _options_recordDOM = options.recordDOM, recordDOM = _options_recordDOM === void 0 ? true : _options_recordDOM, _options_recordCanvas = options.recordCanvas, recordCanvas = _options_recordCanvas === void 0 ? false : _options_recordCanvas, _options_recordCrossOriginIframes = options.recordCrossOriginIframes, recordCrossOriginIframes = _options_recordCrossOriginIframes === void 0 ? false : _options_recordCrossOriginIframes, allowedIframeOrigins = options.allowedIframeOrigins, _options_recordAfter = options.recordAfter, recordAfter = _options_recordAfter === void 0 ? options.recordAfter === "DOMContentLoaded" ? options.recordAfter : "load" : _options_recordAfter, _options_userTriggeredOnInput = options.userTriggeredOnInput, userTriggeredOnInput = _options_userTriggeredOnInput === void 0 ? false : _options_userTriggeredOnInput, _options_collectFonts = options.collectFonts, collectFonts = _options_collectFonts === void 0 ? false : _options_collectFonts, _options_inlineImages = options.inlineImages, inlineImages = _options_inlineImages === void 0 ? false : _options_inlineImages, plugins = options.plugins, _options_keepIframeSrcFn = options.keepIframeSrcFn, keepIframeSrcFn = _options_keepIframeSrcFn === void 0 ? function() {
13306
13339
  return false;
13307
13340
  } : _options_keepIframeSrcFn, _options_ignoreCSSAttributes = options.ignoreCSSAttributes, ignoreCSSAttributes = _options_ignoreCSSAttributes === void 0 ? /* @__PURE__ */ new Set([]) : _options_ignoreCSSAttributes, errorHandler2 = options.errorHandler;
13308
13341
  registerErrorHandler(errorHandler2);
13342
+ var validatedOrigins;
13343
+ if (recordCrossOriginIframes && allowedIframeOrigins && allowedIframeOrigins.length > 0) {
13344
+ validatedOrigins = buildAllowedOriginSet(allowedIframeOrigins);
13345
+ if (validatedOrigins.size === 0) {
13346
+ validatedOrigins = void 0;
13347
+ }
13348
+ }
13309
13349
  var inEmittingFrame = recordCrossOriginIframes ? window.parent === window : true;
13310
13350
  var passEmitsToParent = false;
13311
13351
  if (!inEmittingFrame) {
@@ -13397,7 +13437,14 @@
13397
13437
  origin: window.location.origin,
13398
13438
  isCheckout: isCheckout
13399
13439
  };
13400
- window.parent.postMessage(message, "*");
13440
+ if (validatedOrigins) {
13441
+ for(var _iterator = _create_for_of_iterator_helper_loose(validatedOrigins), _step; !(_step = _iterator()).done;){
13442
+ var targetOrigin = _step.value;
13443
+ window.parent.postMessage(message, targetOrigin);
13444
+ }
13445
+ } else {
13446
+ window.parent.postMessage(message, "*");
13447
+ }
13401
13448
  }
13402
13449
  if (e2.type === EventType.FullSnapshot) {
13403
13450
  lastFullSnapshotEvent = e2;
@@ -21887,6 +21934,29 @@
21887
21934
 
21888
21935
  var RECORD_ENQUEUE_THROTTLE_MS = 250;
21889
21936
 
21937
+ var validateAllowedOrigins = function(origins, logger) {
21938
+ if (!_.isArray(origins)) {
21939
+ if (origins) {
21940
+ logger.critical('record_allowed_iframe_origins must be an array of origin strings, cross-origin recording will be disabled.');
21941
+ }
21942
+ return [];
21943
+ }
21944
+ var valid = [];
21945
+ for (var i = 0; i < origins.length; i++) {
21946
+ try {
21947
+ var origin = new URL(origins[i]).origin;
21948
+ if (origin === 'null') {
21949
+ logger.critical(origins[i] + ' has an opaque origin. Skipping this entry.');
21950
+ continue;
21951
+ }
21952
+ valid.push(origin);
21953
+ } catch (e) {
21954
+ logger.critical(origins[i] + ' is not a valid origin URL. Skipping this entry.');
21955
+ }
21956
+ }
21957
+ return valid;
21958
+ };
21959
+
21890
21960
  // stateless utils
21891
21961
  // mostly from https://github.com/mixpanel/mixpanel-js/blob/989ada50f518edab47b9c4fd9535f9fbd5ec5fc0/src/autotrack-utils.js
21892
21962
 
@@ -22993,6 +23063,8 @@
22993
23063
  );
22994
23064
  }
22995
23065
 
23066
+ var validatedOrigins = validateAllowedOrigins(this.getConfig('record_allowed_iframe_origins'), logger$1);
23067
+
22996
23068
  try {
22997
23069
  this._stopRecording = this._rrwebRecord({
22998
23070
  'emit': function (ev) {
@@ -23027,6 +23099,8 @@
23027
23099
  'maskTextSelector': '*',
23028
23100
  'maskInputFn': this._getMaskFn(shouldMaskInput, privacyConfig),
23029
23101
  'maskTextFn': this._getMaskFn(shouldMaskText, privacyConfig),
23102
+ 'recordCrossOriginIframes': validatedOrigins.length > 0,
23103
+ 'allowedIframeOrigins': validatedOrigins,
23030
23104
  'recordCanvas': this.getConfig('record_canvas'),
23031
23105
  'sampling': {
23032
23106
  'canvas': 15