mixpanel-browser 2.71.0 → 2.72.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 (39) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.github/workflows/tests.yml +1 -0
  3. package/CHANGELOG.md +10 -0
  4. package/dist/mixpanel-core.cjs.d.ts +47 -10
  5. package/dist/mixpanel-core.cjs.js +57 -21
  6. package/dist/mixpanel-recorder.js +681 -113
  7. package/dist/mixpanel-recorder.min.js +1 -1
  8. package/dist/mixpanel-recorder.min.js.map +1 -1
  9. package/dist/mixpanel-with-async-recorder.cjs.d.ts +47 -10
  10. package/dist/mixpanel-with-async-recorder.cjs.js +57 -21
  11. package/dist/mixpanel-with-recorder.d.ts +47 -10
  12. package/dist/mixpanel-with-recorder.js +737 -133
  13. package/dist/mixpanel-with-recorder.min.d.ts +47 -10
  14. package/dist/mixpanel-with-recorder.min.js +1 -1
  15. package/dist/mixpanel.amd.d.ts +47 -10
  16. package/dist/mixpanel.amd.js +737 -133
  17. package/dist/mixpanel.cjs.d.ts +47 -10
  18. package/dist/mixpanel.cjs.js +737 -133
  19. package/dist/mixpanel.globals.js +57 -21
  20. package/dist/mixpanel.min.js +149 -149
  21. package/dist/mixpanel.module.d.ts +47 -10
  22. package/dist/mixpanel.module.js +737 -133
  23. package/dist/mixpanel.umd.d.ts +47 -10
  24. package/dist/mixpanel.umd.js +737 -133
  25. package/dist/rrweb-bundled.js +12760 -0
  26. package/dist/rrweb-compiled.js +2496 -7176
  27. package/package.json +3 -2
  28. package/rollup.config.mjs +15 -4
  29. package/src/autocapture/index.js +7 -5
  30. package/src/autocapture/rageclick.js +20 -1
  31. package/src/autocapture/shadow-dom-observer.js +3 -15
  32. package/src/autocapture/utils.js +30 -0
  33. package/src/config.js +1 -1
  34. package/src/index.d.ts +47 -10
  35. package/src/mixpanel-core.js +1 -0
  36. package/src/recorder/recorder.js +1 -1
  37. package/src/recorder/rrweb-entrypoint.js +6 -0
  38. package/src/recorder/session-recording.js +69 -12
  39. package/src/utils.js +24 -0
@@ -3,7 +3,7 @@
3
3
 
4
4
  var Config = {
5
5
  DEBUG: false,
6
- LIB_VERSION: '2.71.0'
6
+ LIB_VERSION: '2.72.0'
7
7
  };
8
8
 
9
9
  // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
@@ -2893,20 +2893,65 @@
2893
2893
  return false;
2894
2894
  }
2895
2895
 
2896
+ /**
2897
+ * Get the composed path of a click event for elements embedded in shadow DOM.
2898
+ * @param {Event} event - event to get the composed path from
2899
+ * @returns {Array} the composed path of the click event
2900
+ */
2901
+ function getClickEventComposedPath(event) {
2902
+ if ('composedPath' in event) {
2903
+ return event['composedPath']();
2904
+ }
2905
+
2906
+ return [];
2907
+ }
2908
+
2909
+ /**
2910
+ * Get the element from a click event, accounting for elements embedded in shadow DOM.
2911
+ * @param {Event} event - event to get the target from
2912
+ * @returns {Element | null} the element that was the target of the click event
2913
+ */
2914
+ function getClickEventTargetElement(event) {
2915
+ var path = getClickEventComposedPath(event);
2916
+
2917
+ if (path && path.length > 0) {
2918
+ return path[0];
2919
+ }
2920
+
2921
+ return event['target'] || event['srcElement'];
2922
+ }
2923
+
2896
2924
  /** @const */ var DEFAULT_RAGE_CLICK_THRESHOLD_PX = 30;
2897
2925
  /** @const */ var DEFAULT_RAGE_CLICK_TIMEOUT_MS = 1000;
2898
2926
  /** @const */ var DEFAULT_RAGE_CLICK_CLICK_COUNT = 4;
2927
+ /** @const */ var DEFAULT_RAGE_CLICK_INTERACTIVE_ELEMENTS_ONLY = false;
2899
2928
 
2900
2929
  function RageClickTracker() {
2901
2930
  this.clicks = [];
2902
2931
  }
2903
2932
 
2904
- RageClickTracker.prototype.isRageClick = function(x, y, options) {
2933
+ /**
2934
+ * Determines if a click event is part of a rage click sequence.
2935
+ * @param {Event} event - the original click event.
2936
+ * @param {import('../index.d.ts').RageClickConfig} options - configuration options for rage click detection.
2937
+ * @returns {boolean} - true if the click is considered a rage click, false otherwise.
2938
+ */
2939
+ RageClickTracker.prototype.isRageClick = function(event, options) {
2905
2940
  options = options || {};
2906
2941
  var thresholdPx = options['threshold_px'] || DEFAULT_RAGE_CLICK_THRESHOLD_PX;
2907
2942
  var timeoutMs = options['timeout_ms'] || DEFAULT_RAGE_CLICK_TIMEOUT_MS;
2908
2943
  var clickCount = options['click_count'] || DEFAULT_RAGE_CLICK_CLICK_COUNT;
2944
+ var interactiveElementsOnly = options['interactive_elements_only'] || DEFAULT_RAGE_CLICK_INTERACTIVE_ELEMENTS_ONLY;
2945
+
2946
+ if (interactiveElementsOnly) {
2947
+ var target = getClickEventTargetElement(event);
2948
+ if (!target || isDefinitelyNonInteractive(target)) {
2949
+ return false;
2950
+ }
2951
+ }
2952
+
2909
2953
  var timestamp = Date.now();
2954
+ var x = event['pageX'], y = event['pageY'];
2910
2955
 
2911
2956
  var lastClick = this.clicks[this.clicks.length - 1];
2912
2957
  if (
@@ -2937,28 +2982,16 @@
2937
2982
  if (!this.observedShadowRoots) {
2938
2983
  return;
2939
2984
  }
2940
- var path = this.getComposedPath(event);
2941
- if (path && path.length) {
2942
- return path[0];
2943
- }
2944
2985
 
2945
- return event['target'] || event['srcElement'];
2986
+ return getClickEventTargetElement(event);
2946
2987
  };
2947
2988
 
2948
-
2949
- ShadowDOMObserver.prototype.getComposedPath = function(event) {
2950
- if ('composedPath' in event) {
2951
- return event['composedPath']();
2952
- }
2953
-
2954
- return [];
2955
- };
2956
2989
  ShadowDOMObserver.prototype.observeFromEvent = function(event) {
2957
2990
  if (!this.observedShadowRoots) {
2958
2991
  return;
2959
2992
  }
2960
2993
 
2961
- var path = this.getComposedPath(event);
2994
+ var path = getClickEventComposedPath(event);
2962
2995
 
2963
2996
  // Check each element in path for shadow roots
2964
2997
  for (var i = 0; i < path.length; i++) {
@@ -3510,6 +3543,11 @@
3510
3543
  // User has navigated away already ending their impression.
3511
3544
  return;
3512
3545
  }
3546
+
3547
+ if (!this.getConfig(CONFIG_TRACK_PAGE_LEAVE) && !this.mp.is_recording_heatmap_data()) {
3548
+ return;
3549
+ }
3550
+
3513
3551
  this.hasTrackedScrollSession = true;
3514
3552
  var viewportHeight = Math.max(document$1.documentElement.clientHeight, win.innerHeight || 0);
3515
3553
  var scrollPercentage = Math.round(Math.max(this.maxScrollViewDepth - viewportHeight, 0) / (currentScrollHeight - viewportHeight) * 100);
@@ -3529,12 +3567,9 @@
3529
3567
  '$current_url': currentUrl || _.info.currentUrl(),
3530
3568
  '$viewportHeight': viewportHeight, // This is the fold line
3531
3569
  '$viewportWidth': Math.max(document$1.documentElement.clientWidth, win.innerWidth || 0),
3570
+ '$captured_for_heatmap': this.mp.is_recording_heatmap_data()
3532
3571
  }, DEFAULT_PROPS);
3533
3572
 
3534
- if (this.mp.is_recording_heatmap_data() && !this.getConfig(CONFIG_TRACK_PAGE_LEAVE)) {
3535
- props['$captured_for_heatmap'] = true;
3536
- }
3537
-
3538
3573
  // Send with beacon transport to ensure event is sent before unload
3539
3574
  this.mp.track(MP_EV_PAGE_LEAVE, props, {transport: 'sendBeacon'});
3540
3575
  };
@@ -3708,7 +3743,7 @@
3708
3743
  return;
3709
3744
  }
3710
3745
 
3711
- if (this._rageClickTracker.isRageClick(ev['pageX'], ev['pageY'], currentRageClickConfig)) {
3746
+ if (this._rageClickTracker.isRageClick(ev, currentRageClickConfig)) {
3712
3747
  this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
3713
3748
  }
3714
3749
  }.bind(this);
@@ -6896,6 +6931,7 @@
6896
6931
  'record_block_selector': 'img, video, audio',
6897
6932
  'record_canvas': false,
6898
6933
  'record_collect_fonts': false,
6934
+ 'record_console': true,
6899
6935
  'record_heatmap_data': false,
6900
6936
  'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
6901
6937
  'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),