userlens-session-recorder 2.0.1 → 2.1.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.
package/dist/index.cjs.js CHANGED
@@ -20673,66 +20673,81 @@ const uploadSessionEvents = async (args) => {
20673
20673
  return "ok";
20674
20674
  };
20675
20675
 
20676
- var _SessionRecorder_instances, _SessionRecorder_trackEventsThrottled, _SessionRecorder_uploading, _SessionRecorder_uploadingMaxTs, _SessionRecorder_log, _SessionRecorder_initRecorder, _SessionRecorder_isUserInteraction, _SessionRecorder_handleEvent, _SessionRecorder_resetSession, _SessionRecorder_createSession, _SessionRecorder_handlePageHide, _SessionRecorder_initListeners, _SessionRecorder_throttle, _SessionRecorder_trackEvents, _SessionRecorder_clearEvents;
20676
+ var _SessionRecorder_instances, _SessionRecorder_uploading, _SessionRecorder_uploadingMaxTs, _SessionRecorder_bufferTimer, _SessionRecorder_log, _SessionRecorder_initRecorder, _SessionRecorder_isUserInteraction, _SessionRecorder_handleEvent, _SessionRecorder_armBufferTimer, _SessionRecorder_flushBuffer, _SessionRecorder_resetSession, _SessionRecorder_createSession, _SessionRecorder_handlePageHide, _SessionRecorder_initListeners, _SessionRecorder_trackEvents, _SessionRecorder_clearEvents;
20677
+ const BUFFER_TIMEOUT_MS = 2000;
20678
+ const MAX_BUFFER_BYTES = 900 * 1024;
20679
+ function estimateEventSize(event) {
20680
+ try {
20681
+ return JSON.stringify(event).length;
20682
+ }
20683
+ catch {
20684
+ return 0;
20685
+ }
20686
+ }
20677
20687
  class SessionRecorder {
20678
20688
  constructor(config) {
20679
20689
  var _a, _b, _c;
20680
20690
  _SessionRecorder_instances.add(this);
20681
20691
  this.sessionEvents = [];
20692
+ this.bufferBytes = 0;
20682
20693
  this.rrwebStop = null;
20683
20694
  this.debug = false;
20684
- _SessionRecorder_trackEventsThrottled.set(this, void 0);
20685
20695
  _SessionRecorder_uploading.set(this, false);
20686
20696
  _SessionRecorder_uploadingMaxTs.set(this, 0);
20697
+ _SessionRecorder_bufferTimer.set(this, null);
20687
20698
  _SessionRecorder_handlePageHide.set(this, () => {
20688
20699
  try {
20689
20700
  if (this.sessionEvents.length === 0)
20690
20701
  return;
20691
- let toUpload;
20702
+ let events;
20692
20703
  if (__classPrivateFieldGet(this, _SessionRecorder_uploading, "f") && __classPrivateFieldGet(this, _SessionRecorder_uploadingMaxTs, "f") > 0) {
20693
- toUpload = this.sessionEvents.filter((e) => e.timestamp > __classPrivateFieldGet(this, _SessionRecorder_uploadingMaxTs, "f"));
20704
+ events = this.sessionEvents.filter((e) => e.timestamp > __classPrivateFieldGet(this, _SessionRecorder_uploadingMaxTs, "f"));
20694
20705
  }
20695
20706
  else {
20696
- toUpload = [...this.sessionEvents];
20707
+ events = [...this.sessionEvents];
20697
20708
  }
20698
- if (toUpload.length === 0)
20709
+ if (events.length === 0)
20699
20710
  return;
20700
- let events;
20701
- if (toUpload[0].type !== 4) {
20702
- let snapshotPair = [];
20703
- for (let i = this.sessionEvents.length - 2; i >= 0; i--) {
20704
- if (this.sessionEvents[i].type === 4 &&
20705
- this.sessionEvents[i + 1].type === 2) {
20706
- snapshotPair = [
20707
- this.sessionEvents[i],
20708
- this.sessionEvents[i + 1],
20709
- ];
20710
- break;
20711
- }
20712
- }
20713
- events = [...snapshotPair, ...toUpload];
20714
- }
20715
- else {
20716
- events = toUpload;
20717
- }
20718
20711
  const state = readSessionState();
20719
20712
  if (!state)
20720
20713
  return;
20721
20714
  const chunk_seq = __classPrivateFieldGet(this, _SessionRecorder_uploading, "f") ? state.chunk_seq + 1 : state.chunk_seq;
20722
20715
  writeSessionState({ ...state, chunk_seq: chunk_seq + 1 });
20723
- const start_ts_ms = toUpload[0].timestamp;
20724
- const end_ts_ms = toUpload[toUpload.length - 1].timestamp;
20725
- uploadSessionEvents({
20726
- user_id: this.userId,
20727
- session_uuid: this.sessionUuid,
20728
- chunk_seq,
20729
- chunk_start_ts: new Date(start_ts_ms).toISOString(),
20730
- chunk_end_ts: new Date(end_ts_ms).toISOString(),
20731
- initial_url: chunk_seq === 0 ? state.initial_url : undefined,
20732
- events,
20733
- keepalive: true,
20734
- }).catch(() => { });
20716
+ const start_ts_ms = events[0].timestamp;
20717
+ const end_ts_ms = events[events.length - 1].timestamp;
20718
+ const initial_url = chunk_seq === 0 ? state.initial_url : undefined;
20719
+ const chunk_start_ts = new Date(start_ts_ms).toISOString();
20720
+ const chunk_end_ts = new Date(end_ts_ms).toISOString();
20721
+ if (this.mode === "manual") {
20722
+ try {
20723
+ void this.onEvents({
20724
+ session_uuid: this.sessionUuid,
20725
+ chunk_seq,
20726
+ chunk_start_ts,
20727
+ chunk_end_ts,
20728
+ initial_url,
20729
+ events,
20730
+ keepalive: true,
20731
+ });
20732
+ }
20733
+ catch {
20734
+ // ignore
20735
+ }
20736
+ }
20737
+ else {
20738
+ uploadSessionEvents({
20739
+ user_id: this.userId,
20740
+ session_uuid: this.sessionUuid,
20741
+ chunk_seq,
20742
+ chunk_start_ts,
20743
+ chunk_end_ts,
20744
+ initial_url,
20745
+ events,
20746
+ keepalive: true,
20747
+ }).catch(() => { });
20748
+ }
20735
20749
  this.sessionEvents = [];
20750
+ this.bufferBytes = 0;
20736
20751
  }
20737
20752
  catch (err) {
20738
20753
  __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "Page hide handling failed", err);
@@ -20759,21 +20774,29 @@ class SessionRecorder {
20759
20774
  sessionStorage.setItem(testKey, "1");
20760
20775
  sessionStorage.removeItem(testKey);
20761
20776
  this.debug = (_a = config.debug) !== null && _a !== void 0 ? _a : false;
20762
- if (!((_b = config.WRITE_CODE) === null || _b === void 0 ? void 0 : _b.trim()) || !((_c = config.userId) === null || _c === void 0 ? void 0 : _c.trim())) {
20763
- return;
20777
+ if (config.mode === "manual") {
20778
+ this.mode = "manual";
20779
+ if (!config.onEvents || typeof config.onEvents !== "function") {
20780
+ __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "onEvents callback is required in manual mode");
20781
+ return;
20782
+ }
20783
+ this.onEvents = config.onEvents;
20784
+ }
20785
+ else {
20786
+ this.mode = "auto";
20787
+ if (!((_b = config.WRITE_CODE) === null || _b === void 0 ? void 0 : _b.trim()) || !((_c = config.userId) === null || _c === void 0 ? void 0 : _c.trim())) {
20788
+ return;
20789
+ }
20790
+ saveWriteCode(config.WRITE_CODE);
20791
+ this.userId = config.userId;
20764
20792
  }
20765
- saveWriteCode(config.WRITE_CODE);
20766
- this.userId = config.userId;
20767
20793
  const { recordingOptions = {} } = config;
20768
- const { TIMEOUT = 30 * 60 * 1000, BUFFER_SIZE = 10, maskingOptions = ["passwords"], recordCrossOriginIframes = false, } = recordingOptions;
20794
+ const { TIMEOUT = 30 * 60 * 1000, BUFFER_SIZE = 30, maskingOptions = ["passwords"], recordCrossOriginIframes = false, } = recordingOptions;
20769
20795
  this.TIMEOUT = TIMEOUT;
20770
20796
  this.BUFFER_SIZE = BUFFER_SIZE;
20771
20797
  this.maskingOptions = maskingOptions;
20772
20798
  this.recordCrossOriginIframes = recordCrossOriginIframes;
20773
20799
  this.sessionEvents = [];
20774
- __classPrivateFieldSet(this, _SessionRecorder_trackEventsThrottled, __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_throttle).call(this, () => {
20775
- __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_trackEvents).call(this);
20776
- }, 5000), "f");
20777
20800
  __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_initRecorder).call(this);
20778
20801
  }
20779
20802
  catch (err) {
@@ -20800,7 +20823,7 @@ class SessionRecorder {
20800
20823
  }
20801
20824
  }
20802
20825
  }
20803
- _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploading = new WeakMap(), _SessionRecorder_uploadingMaxTs = new WeakMap(), _SessionRecorder_handlePageHide = new WeakMap(), _SessionRecorder_instances = new WeakSet(), _SessionRecorder_log = function _SessionRecorder_log(message, error) {
20826
+ _SessionRecorder_uploading = new WeakMap(), _SessionRecorder_uploadingMaxTs = new WeakMap(), _SessionRecorder_bufferTimer = new WeakMap(), _SessionRecorder_handlePageHide = new WeakMap(), _SessionRecorder_instances = new WeakSet(), _SessionRecorder_log = function _SessionRecorder_log(message, error) {
20804
20827
  if (!this.debug)
20805
20828
  return;
20806
20829
  if (error) {
@@ -20823,6 +20846,7 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
20823
20846
  },
20824
20847
  recordCrossOriginIframes: this.recordCrossOriginIframes,
20825
20848
  plugins: [getRecordConsolePlugin()],
20849
+ checkoutEveryNth: 100,
20826
20850
  });
20827
20851
  __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_initListeners).call(this);
20828
20852
  }, _SessionRecorder_isUserInteraction = function _SessionRecorder_isUserInteraction(event) {
@@ -20833,7 +20857,6 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
20833
20857
  }
20834
20858
  return false;
20835
20859
  }, _SessionRecorder_handleEvent = function _SessionRecorder_handleEvent(event, _isCheckout) {
20836
- var _a;
20837
20860
  try {
20838
20861
  const now = Date.now();
20839
20862
  const state = readSessionState();
@@ -20848,13 +20871,29 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
20848
20871
  }
20849
20872
  }
20850
20873
  this.sessionEvents.push(event);
20851
- if (this.sessionEvents.length >= this.BUFFER_SIZE) {
20852
- (_a = __classPrivateFieldGet(this, _SessionRecorder_trackEventsThrottled, "f")) === null || _a === void 0 ? void 0 : _a.call(this);
20874
+ this.bufferBytes += estimateEventSize(event);
20875
+ __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_armBufferTimer).call(this);
20876
+ if (this.bufferBytes >= MAX_BUFFER_BYTES) {
20877
+ __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_flushBuffer).call(this);
20853
20878
  }
20854
20879
  }
20855
20880
  catch (err) {
20856
20881
  __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "Event handling failed", err);
20857
20882
  }
20883
+ }, _SessionRecorder_armBufferTimer = function _SessionRecorder_armBufferTimer() {
20884
+ if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
20885
+ clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
20886
+ }
20887
+ __classPrivateFieldSet(this, _SessionRecorder_bufferTimer, setTimeout(() => {
20888
+ __classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
20889
+ __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_flushBuffer).call(this);
20890
+ }, BUFFER_TIMEOUT_MS), "f");
20891
+ }, _SessionRecorder_flushBuffer = function _SessionRecorder_flushBuffer() {
20892
+ if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
20893
+ clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
20894
+ __classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
20895
+ }
20896
+ void __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_trackEvents).call(this);
20858
20897
  }, _SessionRecorder_resetSession = function _SessionRecorder_resetSession() {
20859
20898
  clearSessionState();
20860
20899
  __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_clearEvents).call(this);
@@ -20879,15 +20918,6 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
20879
20918
  }
20880
20919
  }, _SessionRecorder_initListeners = function _SessionRecorder_initListeners() {
20881
20920
  window.addEventListener("pagehide", __classPrivateFieldGet(this, _SessionRecorder_handlePageHide, "f"));
20882
- }, _SessionRecorder_throttle = function _SessionRecorder_throttle(func, delay) {
20883
- let lastCall = 0;
20884
- return (...args) => {
20885
- const now = Date.now();
20886
- if (now - lastCall >= delay) {
20887
- lastCall = now;
20888
- func.apply(this, args);
20889
- }
20890
- };
20891
20921
  }, _SessionRecorder_trackEvents = async function _SessionRecorder_trackEvents() {
20892
20922
  if (__classPrivateFieldGet(this, _SessionRecorder_uploading, "f"))
20893
20923
  return;
@@ -20906,26 +20936,33 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
20906
20936
  return;
20907
20937
  }
20908
20938
  const chunk_seq = state.chunk_seq;
20909
- await uploadSessionEvents({
20910
- user_id: this.userId,
20911
- session_uuid: this.sessionUuid,
20912
- chunk_seq,
20913
- chunk_start_ts: new Date(start_ts_ms).toISOString(),
20914
- chunk_end_ts: new Date(end_ts_ms).toISOString(),
20915
- initial_url: chunk_seq === 0 ? state.initial_url : undefined,
20916
- events,
20917
- });
20918
- const remaining = this.sessionEvents.slice(snapshot_count);
20919
- this.sessionEvents = [];
20920
- try {
20921
- takeFullSnapshot(true);
20922
- }
20923
- catch (err) {
20924
- __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "takeFullSnapshot failed", err);
20939
+ const initial_url = chunk_seq === 0 ? state.initial_url : undefined;
20940
+ const chunk_start_ts = new Date(start_ts_ms).toISOString();
20941
+ const chunk_end_ts = new Date(end_ts_ms).toISOString();
20942
+ if (this.mode === "manual") {
20943
+ await this.onEvents({
20944
+ session_uuid: this.sessionUuid,
20945
+ chunk_seq,
20946
+ chunk_start_ts,
20947
+ chunk_end_ts,
20948
+ initial_url,
20949
+ events,
20950
+ });
20925
20951
  }
20926
- if (remaining.length > 0) {
20927
- this.sessionEvents.push(...remaining);
20952
+ else {
20953
+ await uploadSessionEvents({
20954
+ user_id: this.userId,
20955
+ session_uuid: this.sessionUuid,
20956
+ chunk_seq,
20957
+ chunk_start_ts,
20958
+ chunk_end_ts,
20959
+ initial_url,
20960
+ events,
20961
+ });
20928
20962
  }
20963
+ const removedBytes = events.reduce((sum, e) => sum + estimateEventSize(e), 0);
20964
+ this.sessionEvents = this.sessionEvents.slice(snapshot_count);
20965
+ this.bufferBytes = Math.max(0, this.bufferBytes - removedBytes);
20929
20966
  const after = readSessionState();
20930
20967
  if (after &&
20931
20968
  after.session_uuid === state.session_uuid &&
@@ -20942,6 +20979,11 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
20942
20979
  }
20943
20980
  }, _SessionRecorder_clearEvents = function _SessionRecorder_clearEvents() {
20944
20981
  this.sessionEvents = [];
20982
+ this.bufferBytes = 0;
20983
+ if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
20984
+ clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
20985
+ __classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
20986
+ }
20945
20987
  };
20946
20988
 
20947
20989
  exports.default = SessionRecorder;