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 +117 -75
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.esm.js +117 -75
- package/dist/index.esm.js.map +1 -1
- package/dist/types/index.d.ts +26 -2
- package/dist/userlens-session-recorder.umd.js +117 -75
- package/dist/userlens-session-recorder.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { MaskingOption, SessionRecorderConfig } from "./types";
|
|
2
|
-
export type { SessionRecorderConfig, MaskingOption, };
|
|
1
|
+
import { MaskingOption, RecorderMode, EventBatch, OnEventsCallback, SessionRecorderConfig, AutoModeConfig, ManualModeConfig } from "./types";
|
|
2
|
+
export type { SessionRecorderConfig, AutoModeConfig, ManualModeConfig, RecorderMode, EventBatch, OnEventsCallback, MaskingOption, };
|
|
3
3
|
export default class SessionRecorder {
|
|
4
4
|
#private;
|
|
5
|
+
private mode;
|
|
5
6
|
private userId?;
|
|
7
|
+
private onEvents?;
|
|
6
8
|
private TIMEOUT;
|
|
7
9
|
private BUFFER_SIZE;
|
|
8
10
|
private maskingOptions;
|
|
9
11
|
private sessionUuid;
|
|
10
12
|
private sessionEvents;
|
|
13
|
+
private bufferBytes;
|
|
11
14
|
private rrwebStop;
|
|
12
15
|
private debug;
|
|
13
16
|
private recordCrossOriginIframes;
|
package/dist/index.esm.js
CHANGED
|
@@ -20669,66 +20669,81 @@ const uploadSessionEvents = async (args) => {
|
|
|
20669
20669
|
return "ok";
|
|
20670
20670
|
};
|
|
20671
20671
|
|
|
20672
|
-
var _SessionRecorder_instances,
|
|
20672
|
+
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;
|
|
20673
|
+
const BUFFER_TIMEOUT_MS = 2000;
|
|
20674
|
+
const MAX_BUFFER_BYTES = 900 * 1024;
|
|
20675
|
+
function estimateEventSize(event) {
|
|
20676
|
+
try {
|
|
20677
|
+
return JSON.stringify(event).length;
|
|
20678
|
+
}
|
|
20679
|
+
catch {
|
|
20680
|
+
return 0;
|
|
20681
|
+
}
|
|
20682
|
+
}
|
|
20673
20683
|
class SessionRecorder {
|
|
20674
20684
|
constructor(config) {
|
|
20675
20685
|
var _a, _b, _c;
|
|
20676
20686
|
_SessionRecorder_instances.add(this);
|
|
20677
20687
|
this.sessionEvents = [];
|
|
20688
|
+
this.bufferBytes = 0;
|
|
20678
20689
|
this.rrwebStop = null;
|
|
20679
20690
|
this.debug = false;
|
|
20680
|
-
_SessionRecorder_trackEventsThrottled.set(this, void 0);
|
|
20681
20691
|
_SessionRecorder_uploading.set(this, false);
|
|
20682
20692
|
_SessionRecorder_uploadingMaxTs.set(this, 0);
|
|
20693
|
+
_SessionRecorder_bufferTimer.set(this, null);
|
|
20683
20694
|
_SessionRecorder_handlePageHide.set(this, () => {
|
|
20684
20695
|
try {
|
|
20685
20696
|
if (this.sessionEvents.length === 0)
|
|
20686
20697
|
return;
|
|
20687
|
-
let
|
|
20698
|
+
let events;
|
|
20688
20699
|
if (__classPrivateFieldGet(this, _SessionRecorder_uploading, "f") && __classPrivateFieldGet(this, _SessionRecorder_uploadingMaxTs, "f") > 0) {
|
|
20689
|
-
|
|
20700
|
+
events = this.sessionEvents.filter((e) => e.timestamp > __classPrivateFieldGet(this, _SessionRecorder_uploadingMaxTs, "f"));
|
|
20690
20701
|
}
|
|
20691
20702
|
else {
|
|
20692
|
-
|
|
20703
|
+
events = [...this.sessionEvents];
|
|
20693
20704
|
}
|
|
20694
|
-
if (
|
|
20705
|
+
if (events.length === 0)
|
|
20695
20706
|
return;
|
|
20696
|
-
let events;
|
|
20697
|
-
if (toUpload[0].type !== 4) {
|
|
20698
|
-
let snapshotPair = [];
|
|
20699
|
-
for (let i = this.sessionEvents.length - 2; i >= 0; i--) {
|
|
20700
|
-
if (this.sessionEvents[i].type === 4 &&
|
|
20701
|
-
this.sessionEvents[i + 1].type === 2) {
|
|
20702
|
-
snapshotPair = [
|
|
20703
|
-
this.sessionEvents[i],
|
|
20704
|
-
this.sessionEvents[i + 1],
|
|
20705
|
-
];
|
|
20706
|
-
break;
|
|
20707
|
-
}
|
|
20708
|
-
}
|
|
20709
|
-
events = [...snapshotPair, ...toUpload];
|
|
20710
|
-
}
|
|
20711
|
-
else {
|
|
20712
|
-
events = toUpload;
|
|
20713
|
-
}
|
|
20714
20707
|
const state = readSessionState();
|
|
20715
20708
|
if (!state)
|
|
20716
20709
|
return;
|
|
20717
20710
|
const chunk_seq = __classPrivateFieldGet(this, _SessionRecorder_uploading, "f") ? state.chunk_seq + 1 : state.chunk_seq;
|
|
20718
20711
|
writeSessionState({ ...state, chunk_seq: chunk_seq + 1 });
|
|
20719
|
-
const start_ts_ms =
|
|
20720
|
-
const end_ts_ms =
|
|
20721
|
-
|
|
20722
|
-
|
|
20723
|
-
|
|
20724
|
-
|
|
20725
|
-
|
|
20726
|
-
|
|
20727
|
-
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20712
|
+
const start_ts_ms = events[0].timestamp;
|
|
20713
|
+
const end_ts_ms = events[events.length - 1].timestamp;
|
|
20714
|
+
const initial_url = chunk_seq === 0 ? state.initial_url : undefined;
|
|
20715
|
+
const chunk_start_ts = new Date(start_ts_ms).toISOString();
|
|
20716
|
+
const chunk_end_ts = new Date(end_ts_ms).toISOString();
|
|
20717
|
+
if (this.mode === "manual") {
|
|
20718
|
+
try {
|
|
20719
|
+
void this.onEvents({
|
|
20720
|
+
session_uuid: this.sessionUuid,
|
|
20721
|
+
chunk_seq,
|
|
20722
|
+
chunk_start_ts,
|
|
20723
|
+
chunk_end_ts,
|
|
20724
|
+
initial_url,
|
|
20725
|
+
events,
|
|
20726
|
+
keepalive: true,
|
|
20727
|
+
});
|
|
20728
|
+
}
|
|
20729
|
+
catch {
|
|
20730
|
+
// ignore
|
|
20731
|
+
}
|
|
20732
|
+
}
|
|
20733
|
+
else {
|
|
20734
|
+
uploadSessionEvents({
|
|
20735
|
+
user_id: this.userId,
|
|
20736
|
+
session_uuid: this.sessionUuid,
|
|
20737
|
+
chunk_seq,
|
|
20738
|
+
chunk_start_ts,
|
|
20739
|
+
chunk_end_ts,
|
|
20740
|
+
initial_url,
|
|
20741
|
+
events,
|
|
20742
|
+
keepalive: true,
|
|
20743
|
+
}).catch(() => { });
|
|
20744
|
+
}
|
|
20731
20745
|
this.sessionEvents = [];
|
|
20746
|
+
this.bufferBytes = 0;
|
|
20732
20747
|
}
|
|
20733
20748
|
catch (err) {
|
|
20734
20749
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "Page hide handling failed", err);
|
|
@@ -20755,21 +20770,29 @@ class SessionRecorder {
|
|
|
20755
20770
|
sessionStorage.setItem(testKey, "1");
|
|
20756
20771
|
sessionStorage.removeItem(testKey);
|
|
20757
20772
|
this.debug = (_a = config.debug) !== null && _a !== void 0 ? _a : false;
|
|
20758
|
-
if (
|
|
20759
|
-
|
|
20773
|
+
if (config.mode === "manual") {
|
|
20774
|
+
this.mode = "manual";
|
|
20775
|
+
if (!config.onEvents || typeof config.onEvents !== "function") {
|
|
20776
|
+
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "onEvents callback is required in manual mode");
|
|
20777
|
+
return;
|
|
20778
|
+
}
|
|
20779
|
+
this.onEvents = config.onEvents;
|
|
20780
|
+
}
|
|
20781
|
+
else {
|
|
20782
|
+
this.mode = "auto";
|
|
20783
|
+
if (!((_b = config.WRITE_CODE) === null || _b === void 0 ? void 0 : _b.trim()) || !((_c = config.userId) === null || _c === void 0 ? void 0 : _c.trim())) {
|
|
20784
|
+
return;
|
|
20785
|
+
}
|
|
20786
|
+
saveWriteCode(config.WRITE_CODE);
|
|
20787
|
+
this.userId = config.userId;
|
|
20760
20788
|
}
|
|
20761
|
-
saveWriteCode(config.WRITE_CODE);
|
|
20762
|
-
this.userId = config.userId;
|
|
20763
20789
|
const { recordingOptions = {} } = config;
|
|
20764
|
-
const { TIMEOUT = 30 * 60 * 1000, BUFFER_SIZE =
|
|
20790
|
+
const { TIMEOUT = 30 * 60 * 1000, BUFFER_SIZE = 30, maskingOptions = ["passwords"], recordCrossOriginIframes = false, } = recordingOptions;
|
|
20765
20791
|
this.TIMEOUT = TIMEOUT;
|
|
20766
20792
|
this.BUFFER_SIZE = BUFFER_SIZE;
|
|
20767
20793
|
this.maskingOptions = maskingOptions;
|
|
20768
20794
|
this.recordCrossOriginIframes = recordCrossOriginIframes;
|
|
20769
20795
|
this.sessionEvents = [];
|
|
20770
|
-
__classPrivateFieldSet(this, _SessionRecorder_trackEventsThrottled, __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_throttle).call(this, () => {
|
|
20771
|
-
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_trackEvents).call(this);
|
|
20772
|
-
}, 5000), "f");
|
|
20773
20796
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_initRecorder).call(this);
|
|
20774
20797
|
}
|
|
20775
20798
|
catch (err) {
|
|
@@ -20796,7 +20819,7 @@ class SessionRecorder {
|
|
|
20796
20819
|
}
|
|
20797
20820
|
}
|
|
20798
20821
|
}
|
|
20799
|
-
|
|
20822
|
+
_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) {
|
|
20800
20823
|
if (!this.debug)
|
|
20801
20824
|
return;
|
|
20802
20825
|
if (error) {
|
|
@@ -20819,6 +20842,7 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
|
|
|
20819
20842
|
},
|
|
20820
20843
|
recordCrossOriginIframes: this.recordCrossOriginIframes,
|
|
20821
20844
|
plugins: [getRecordConsolePlugin()],
|
|
20845
|
+
checkoutEveryNth: 100,
|
|
20822
20846
|
});
|
|
20823
20847
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_initListeners).call(this);
|
|
20824
20848
|
}, _SessionRecorder_isUserInteraction = function _SessionRecorder_isUserInteraction(event) {
|
|
@@ -20829,7 +20853,6 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
|
|
|
20829
20853
|
}
|
|
20830
20854
|
return false;
|
|
20831
20855
|
}, _SessionRecorder_handleEvent = function _SessionRecorder_handleEvent(event, _isCheckout) {
|
|
20832
|
-
var _a;
|
|
20833
20856
|
try {
|
|
20834
20857
|
const now = Date.now();
|
|
20835
20858
|
const state = readSessionState();
|
|
@@ -20844,13 +20867,29 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
|
|
|
20844
20867
|
}
|
|
20845
20868
|
}
|
|
20846
20869
|
this.sessionEvents.push(event);
|
|
20847
|
-
|
|
20848
|
-
|
|
20870
|
+
this.bufferBytes += estimateEventSize(event);
|
|
20871
|
+
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_armBufferTimer).call(this);
|
|
20872
|
+
if (this.bufferBytes >= MAX_BUFFER_BYTES) {
|
|
20873
|
+
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_flushBuffer).call(this);
|
|
20849
20874
|
}
|
|
20850
20875
|
}
|
|
20851
20876
|
catch (err) {
|
|
20852
20877
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "Event handling failed", err);
|
|
20853
20878
|
}
|
|
20879
|
+
}, _SessionRecorder_armBufferTimer = function _SessionRecorder_armBufferTimer() {
|
|
20880
|
+
if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
|
|
20881
|
+
clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
|
|
20882
|
+
}
|
|
20883
|
+
__classPrivateFieldSet(this, _SessionRecorder_bufferTimer, setTimeout(() => {
|
|
20884
|
+
__classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
|
|
20885
|
+
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_flushBuffer).call(this);
|
|
20886
|
+
}, BUFFER_TIMEOUT_MS), "f");
|
|
20887
|
+
}, _SessionRecorder_flushBuffer = function _SessionRecorder_flushBuffer() {
|
|
20888
|
+
if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
|
|
20889
|
+
clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
|
|
20890
|
+
__classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
|
|
20891
|
+
}
|
|
20892
|
+
void __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_trackEvents).call(this);
|
|
20854
20893
|
}, _SessionRecorder_resetSession = function _SessionRecorder_resetSession() {
|
|
20855
20894
|
clearSessionState();
|
|
20856
20895
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_clearEvents).call(this);
|
|
@@ -20875,15 +20914,6 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
|
|
|
20875
20914
|
}
|
|
20876
20915
|
}, _SessionRecorder_initListeners = function _SessionRecorder_initListeners() {
|
|
20877
20916
|
window.addEventListener("pagehide", __classPrivateFieldGet(this, _SessionRecorder_handlePageHide, "f"));
|
|
20878
|
-
}, _SessionRecorder_throttle = function _SessionRecorder_throttle(func, delay) {
|
|
20879
|
-
let lastCall = 0;
|
|
20880
|
-
return (...args) => {
|
|
20881
|
-
const now = Date.now();
|
|
20882
|
-
if (now - lastCall >= delay) {
|
|
20883
|
-
lastCall = now;
|
|
20884
|
-
func.apply(this, args);
|
|
20885
|
-
}
|
|
20886
|
-
};
|
|
20887
20917
|
}, _SessionRecorder_trackEvents = async function _SessionRecorder_trackEvents() {
|
|
20888
20918
|
if (__classPrivateFieldGet(this, _SessionRecorder_uploading, "f"))
|
|
20889
20919
|
return;
|
|
@@ -20902,26 +20932,33 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
|
|
|
20902
20932
|
return;
|
|
20903
20933
|
}
|
|
20904
20934
|
const chunk_seq = state.chunk_seq;
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
|
|
20914
|
-
|
|
20915
|
-
|
|
20916
|
-
|
|
20917
|
-
takeFullSnapshot(true);
|
|
20918
|
-
}
|
|
20919
|
-
catch (err) {
|
|
20920
|
-
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "takeFullSnapshot failed", err);
|
|
20935
|
+
const initial_url = chunk_seq === 0 ? state.initial_url : undefined;
|
|
20936
|
+
const chunk_start_ts = new Date(start_ts_ms).toISOString();
|
|
20937
|
+
const chunk_end_ts = new Date(end_ts_ms).toISOString();
|
|
20938
|
+
if (this.mode === "manual") {
|
|
20939
|
+
await this.onEvents({
|
|
20940
|
+
session_uuid: this.sessionUuid,
|
|
20941
|
+
chunk_seq,
|
|
20942
|
+
chunk_start_ts,
|
|
20943
|
+
chunk_end_ts,
|
|
20944
|
+
initial_url,
|
|
20945
|
+
events,
|
|
20946
|
+
});
|
|
20921
20947
|
}
|
|
20922
|
-
|
|
20923
|
-
|
|
20948
|
+
else {
|
|
20949
|
+
await uploadSessionEvents({
|
|
20950
|
+
user_id: this.userId,
|
|
20951
|
+
session_uuid: this.sessionUuid,
|
|
20952
|
+
chunk_seq,
|
|
20953
|
+
chunk_start_ts,
|
|
20954
|
+
chunk_end_ts,
|
|
20955
|
+
initial_url,
|
|
20956
|
+
events,
|
|
20957
|
+
});
|
|
20924
20958
|
}
|
|
20959
|
+
const removedBytes = events.reduce((sum, e) => sum + estimateEventSize(e), 0);
|
|
20960
|
+
this.sessionEvents = this.sessionEvents.slice(snapshot_count);
|
|
20961
|
+
this.bufferBytes = Math.max(0, this.bufferBytes - removedBytes);
|
|
20925
20962
|
const after = readSessionState();
|
|
20926
20963
|
if (after &&
|
|
20927
20964
|
after.session_uuid === state.session_uuid &&
|
|
@@ -20938,6 +20975,11 @@ _SessionRecorder_trackEventsThrottled = new WeakMap(), _SessionRecorder_uploadin
|
|
|
20938
20975
|
}
|
|
20939
20976
|
}, _SessionRecorder_clearEvents = function _SessionRecorder_clearEvents() {
|
|
20940
20977
|
this.sessionEvents = [];
|
|
20978
|
+
this.bufferBytes = 0;
|
|
20979
|
+
if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
|
|
20980
|
+
clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
|
|
20981
|
+
__classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
|
|
20982
|
+
}
|
|
20941
20983
|
};
|
|
20942
20984
|
|
|
20943
20985
|
export { SessionRecorder as default };
|