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/types/index.d.ts
CHANGED
|
@@ -1,25 +1,49 @@
|
|
|
1
|
+
import { eventWithTime } from 'rrweb';
|
|
2
|
+
|
|
1
3
|
type MaskingOption = "passwords" | "all";
|
|
4
|
+
type RecorderMode = "auto" | "manual";
|
|
2
5
|
interface SessionRecordingOptions {
|
|
3
6
|
TIMEOUT?: number;
|
|
4
7
|
BUFFER_SIZE?: number;
|
|
5
8
|
maskingOptions?: MaskingOption[];
|
|
6
9
|
recordCrossOriginIframes?: boolean;
|
|
7
10
|
}
|
|
8
|
-
interface
|
|
11
|
+
interface EventBatch {
|
|
12
|
+
session_uuid: string;
|
|
13
|
+
chunk_seq: number;
|
|
14
|
+
chunk_start_ts: string;
|
|
15
|
+
chunk_end_ts: string;
|
|
16
|
+
initial_url?: string;
|
|
17
|
+
events: eventWithTime[];
|
|
18
|
+
keepalive?: boolean;
|
|
19
|
+
}
|
|
20
|
+
type OnEventsCallback = (batch: EventBatch) => void | Promise<void>;
|
|
21
|
+
interface AutoModeConfig {
|
|
22
|
+
mode?: "auto";
|
|
9
23
|
WRITE_CODE: string;
|
|
10
24
|
userId: string;
|
|
11
25
|
recordingOptions?: SessionRecordingOptions;
|
|
12
26
|
debug?: boolean;
|
|
13
27
|
}
|
|
28
|
+
interface ManualModeConfig {
|
|
29
|
+
mode: "manual";
|
|
30
|
+
onEvents: OnEventsCallback;
|
|
31
|
+
recordingOptions?: SessionRecordingOptions;
|
|
32
|
+
debug?: boolean;
|
|
33
|
+
}
|
|
34
|
+
type SessionRecorderConfig = AutoModeConfig | ManualModeConfig;
|
|
14
35
|
|
|
15
36
|
declare class SessionRecorder {
|
|
16
37
|
#private;
|
|
38
|
+
private mode;
|
|
17
39
|
private userId?;
|
|
40
|
+
private onEvents?;
|
|
18
41
|
private TIMEOUT;
|
|
19
42
|
private BUFFER_SIZE;
|
|
20
43
|
private maskingOptions;
|
|
21
44
|
private sessionUuid;
|
|
22
45
|
private sessionEvents;
|
|
46
|
+
private bufferBytes;
|
|
23
47
|
private rrwebStop;
|
|
24
48
|
private debug;
|
|
25
49
|
private recordCrossOriginIframes;
|
|
@@ -29,4 +53,4 @@ declare class SessionRecorder {
|
|
|
29
53
|
}
|
|
30
54
|
|
|
31
55
|
export { SessionRecorder as default };
|
|
32
|
-
export type { MaskingOption, SessionRecorderConfig };
|
|
56
|
+
export type { AutoModeConfig, EventBatch, ManualModeConfig, MaskingOption, OnEventsCallback, RecorderMode, SessionRecorderConfig };
|
|
@@ -20675,66 +20675,81 @@
|
|
|
20675
20675
|
return "ok";
|
|
20676
20676
|
};
|
|
20677
20677
|
|
|
20678
|
-
var _SessionRecorder_instances,
|
|
20678
|
+
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;
|
|
20679
|
+
const BUFFER_TIMEOUT_MS = 2000;
|
|
20680
|
+
const MAX_BUFFER_BYTES = 900 * 1024;
|
|
20681
|
+
function estimateEventSize(event) {
|
|
20682
|
+
try {
|
|
20683
|
+
return JSON.stringify(event).length;
|
|
20684
|
+
}
|
|
20685
|
+
catch {
|
|
20686
|
+
return 0;
|
|
20687
|
+
}
|
|
20688
|
+
}
|
|
20679
20689
|
class SessionRecorder {
|
|
20680
20690
|
constructor(config) {
|
|
20681
20691
|
var _a, _b, _c;
|
|
20682
20692
|
_SessionRecorder_instances.add(this);
|
|
20683
20693
|
this.sessionEvents = [];
|
|
20694
|
+
this.bufferBytes = 0;
|
|
20684
20695
|
this.rrwebStop = null;
|
|
20685
20696
|
this.debug = false;
|
|
20686
|
-
_SessionRecorder_trackEventsThrottled.set(this, void 0);
|
|
20687
20697
|
_SessionRecorder_uploading.set(this, false);
|
|
20688
20698
|
_SessionRecorder_uploadingMaxTs.set(this, 0);
|
|
20699
|
+
_SessionRecorder_bufferTimer.set(this, null);
|
|
20689
20700
|
_SessionRecorder_handlePageHide.set(this, () => {
|
|
20690
20701
|
try {
|
|
20691
20702
|
if (this.sessionEvents.length === 0)
|
|
20692
20703
|
return;
|
|
20693
|
-
let
|
|
20704
|
+
let events;
|
|
20694
20705
|
if (__classPrivateFieldGet(this, _SessionRecorder_uploading, "f") && __classPrivateFieldGet(this, _SessionRecorder_uploadingMaxTs, "f") > 0) {
|
|
20695
|
-
|
|
20706
|
+
events = this.sessionEvents.filter((e) => e.timestamp > __classPrivateFieldGet(this, _SessionRecorder_uploadingMaxTs, "f"));
|
|
20696
20707
|
}
|
|
20697
20708
|
else {
|
|
20698
|
-
|
|
20709
|
+
events = [...this.sessionEvents];
|
|
20699
20710
|
}
|
|
20700
|
-
if (
|
|
20711
|
+
if (events.length === 0)
|
|
20701
20712
|
return;
|
|
20702
|
-
let events;
|
|
20703
|
-
if (toUpload[0].type !== 4) {
|
|
20704
|
-
let snapshotPair = [];
|
|
20705
|
-
for (let i = this.sessionEvents.length - 2; i >= 0; i--) {
|
|
20706
|
-
if (this.sessionEvents[i].type === 4 &&
|
|
20707
|
-
this.sessionEvents[i + 1].type === 2) {
|
|
20708
|
-
snapshotPair = [
|
|
20709
|
-
this.sessionEvents[i],
|
|
20710
|
-
this.sessionEvents[i + 1],
|
|
20711
|
-
];
|
|
20712
|
-
break;
|
|
20713
|
-
}
|
|
20714
|
-
}
|
|
20715
|
-
events = [...snapshotPair, ...toUpload];
|
|
20716
|
-
}
|
|
20717
|
-
else {
|
|
20718
|
-
events = toUpload;
|
|
20719
|
-
}
|
|
20720
20713
|
const state = readSessionState();
|
|
20721
20714
|
if (!state)
|
|
20722
20715
|
return;
|
|
20723
20716
|
const chunk_seq = __classPrivateFieldGet(this, _SessionRecorder_uploading, "f") ? state.chunk_seq + 1 : state.chunk_seq;
|
|
20724
20717
|
writeSessionState({ ...state, chunk_seq: chunk_seq + 1 });
|
|
20725
|
-
const start_ts_ms =
|
|
20726
|
-
const end_ts_ms =
|
|
20727
|
-
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
|
|
20736
|
-
|
|
20718
|
+
const start_ts_ms = events[0].timestamp;
|
|
20719
|
+
const end_ts_ms = events[events.length - 1].timestamp;
|
|
20720
|
+
const initial_url = chunk_seq === 0 ? state.initial_url : undefined;
|
|
20721
|
+
const chunk_start_ts = new Date(start_ts_ms).toISOString();
|
|
20722
|
+
const chunk_end_ts = new Date(end_ts_ms).toISOString();
|
|
20723
|
+
if (this.mode === "manual") {
|
|
20724
|
+
try {
|
|
20725
|
+
void this.onEvents({
|
|
20726
|
+
session_uuid: this.sessionUuid,
|
|
20727
|
+
chunk_seq,
|
|
20728
|
+
chunk_start_ts,
|
|
20729
|
+
chunk_end_ts,
|
|
20730
|
+
initial_url,
|
|
20731
|
+
events,
|
|
20732
|
+
keepalive: true,
|
|
20733
|
+
});
|
|
20734
|
+
}
|
|
20735
|
+
catch {
|
|
20736
|
+
// ignore
|
|
20737
|
+
}
|
|
20738
|
+
}
|
|
20739
|
+
else {
|
|
20740
|
+
uploadSessionEvents({
|
|
20741
|
+
user_id: this.userId,
|
|
20742
|
+
session_uuid: this.sessionUuid,
|
|
20743
|
+
chunk_seq,
|
|
20744
|
+
chunk_start_ts,
|
|
20745
|
+
chunk_end_ts,
|
|
20746
|
+
initial_url,
|
|
20747
|
+
events,
|
|
20748
|
+
keepalive: true,
|
|
20749
|
+
}).catch(() => { });
|
|
20750
|
+
}
|
|
20737
20751
|
this.sessionEvents = [];
|
|
20752
|
+
this.bufferBytes = 0;
|
|
20738
20753
|
}
|
|
20739
20754
|
catch (err) {
|
|
20740
20755
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "Page hide handling failed", err);
|
|
@@ -20761,21 +20776,29 @@
|
|
|
20761
20776
|
sessionStorage.setItem(testKey, "1");
|
|
20762
20777
|
sessionStorage.removeItem(testKey);
|
|
20763
20778
|
this.debug = (_a = config.debug) !== null && _a !== void 0 ? _a : false;
|
|
20764
|
-
if (
|
|
20765
|
-
|
|
20779
|
+
if (config.mode === "manual") {
|
|
20780
|
+
this.mode = "manual";
|
|
20781
|
+
if (!config.onEvents || typeof config.onEvents !== "function") {
|
|
20782
|
+
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "onEvents callback is required in manual mode");
|
|
20783
|
+
return;
|
|
20784
|
+
}
|
|
20785
|
+
this.onEvents = config.onEvents;
|
|
20786
|
+
}
|
|
20787
|
+
else {
|
|
20788
|
+
this.mode = "auto";
|
|
20789
|
+
if (!((_b = config.WRITE_CODE) === null || _b === void 0 ? void 0 : _b.trim()) || !((_c = config.userId) === null || _c === void 0 ? void 0 : _c.trim())) {
|
|
20790
|
+
return;
|
|
20791
|
+
}
|
|
20792
|
+
saveWriteCode(config.WRITE_CODE);
|
|
20793
|
+
this.userId = config.userId;
|
|
20766
20794
|
}
|
|
20767
|
-
saveWriteCode(config.WRITE_CODE);
|
|
20768
|
-
this.userId = config.userId;
|
|
20769
20795
|
const { recordingOptions = {} } = config;
|
|
20770
|
-
const { TIMEOUT = 30 * 60 * 1000, BUFFER_SIZE =
|
|
20796
|
+
const { TIMEOUT = 30 * 60 * 1000, BUFFER_SIZE = 30, maskingOptions = ["passwords"], recordCrossOriginIframes = false, } = recordingOptions;
|
|
20771
20797
|
this.TIMEOUT = TIMEOUT;
|
|
20772
20798
|
this.BUFFER_SIZE = BUFFER_SIZE;
|
|
20773
20799
|
this.maskingOptions = maskingOptions;
|
|
20774
20800
|
this.recordCrossOriginIframes = recordCrossOriginIframes;
|
|
20775
20801
|
this.sessionEvents = [];
|
|
20776
|
-
__classPrivateFieldSet(this, _SessionRecorder_trackEventsThrottled, __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_throttle).call(this, () => {
|
|
20777
|
-
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_trackEvents).call(this);
|
|
20778
|
-
}, 5000), "f");
|
|
20779
20802
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_initRecorder).call(this);
|
|
20780
20803
|
}
|
|
20781
20804
|
catch (err) {
|
|
@@ -20802,7 +20825,7 @@
|
|
|
20802
20825
|
}
|
|
20803
20826
|
}
|
|
20804
20827
|
}
|
|
20805
|
-
|
|
20828
|
+
_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) {
|
|
20806
20829
|
if (!this.debug)
|
|
20807
20830
|
return;
|
|
20808
20831
|
if (error) {
|
|
@@ -20825,6 +20848,7 @@
|
|
|
20825
20848
|
},
|
|
20826
20849
|
recordCrossOriginIframes: this.recordCrossOriginIframes,
|
|
20827
20850
|
plugins: [getRecordConsolePlugin()],
|
|
20851
|
+
checkoutEveryNth: 100,
|
|
20828
20852
|
});
|
|
20829
20853
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_initListeners).call(this);
|
|
20830
20854
|
}, _SessionRecorder_isUserInteraction = function _SessionRecorder_isUserInteraction(event) {
|
|
@@ -20835,7 +20859,6 @@
|
|
|
20835
20859
|
}
|
|
20836
20860
|
return false;
|
|
20837
20861
|
}, _SessionRecorder_handleEvent = function _SessionRecorder_handleEvent(event, _isCheckout) {
|
|
20838
|
-
var _a;
|
|
20839
20862
|
try {
|
|
20840
20863
|
const now = Date.now();
|
|
20841
20864
|
const state = readSessionState();
|
|
@@ -20850,13 +20873,29 @@
|
|
|
20850
20873
|
}
|
|
20851
20874
|
}
|
|
20852
20875
|
this.sessionEvents.push(event);
|
|
20853
|
-
|
|
20854
|
-
|
|
20876
|
+
this.bufferBytes += estimateEventSize(event);
|
|
20877
|
+
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_armBufferTimer).call(this);
|
|
20878
|
+
if (this.bufferBytes >= MAX_BUFFER_BYTES) {
|
|
20879
|
+
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_flushBuffer).call(this);
|
|
20855
20880
|
}
|
|
20856
20881
|
}
|
|
20857
20882
|
catch (err) {
|
|
20858
20883
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "Event handling failed", err);
|
|
20859
20884
|
}
|
|
20885
|
+
}, _SessionRecorder_armBufferTimer = function _SessionRecorder_armBufferTimer() {
|
|
20886
|
+
if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
|
|
20887
|
+
clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
|
|
20888
|
+
}
|
|
20889
|
+
__classPrivateFieldSet(this, _SessionRecorder_bufferTimer, setTimeout(() => {
|
|
20890
|
+
__classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
|
|
20891
|
+
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_flushBuffer).call(this);
|
|
20892
|
+
}, BUFFER_TIMEOUT_MS), "f");
|
|
20893
|
+
}, _SessionRecorder_flushBuffer = function _SessionRecorder_flushBuffer() {
|
|
20894
|
+
if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
|
|
20895
|
+
clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
|
|
20896
|
+
__classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
|
|
20897
|
+
}
|
|
20898
|
+
void __classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_trackEvents).call(this);
|
|
20860
20899
|
}, _SessionRecorder_resetSession = function _SessionRecorder_resetSession() {
|
|
20861
20900
|
clearSessionState();
|
|
20862
20901
|
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_clearEvents).call(this);
|
|
@@ -20881,15 +20920,6 @@
|
|
|
20881
20920
|
}
|
|
20882
20921
|
}, _SessionRecorder_initListeners = function _SessionRecorder_initListeners() {
|
|
20883
20922
|
window.addEventListener("pagehide", __classPrivateFieldGet(this, _SessionRecorder_handlePageHide, "f"));
|
|
20884
|
-
}, _SessionRecorder_throttle = function _SessionRecorder_throttle(func, delay) {
|
|
20885
|
-
let lastCall = 0;
|
|
20886
|
-
return (...args) => {
|
|
20887
|
-
const now = Date.now();
|
|
20888
|
-
if (now - lastCall >= delay) {
|
|
20889
|
-
lastCall = now;
|
|
20890
|
-
func.apply(this, args);
|
|
20891
|
-
}
|
|
20892
|
-
};
|
|
20893
20923
|
}, _SessionRecorder_trackEvents = async function _SessionRecorder_trackEvents() {
|
|
20894
20924
|
if (__classPrivateFieldGet(this, _SessionRecorder_uploading, "f"))
|
|
20895
20925
|
return;
|
|
@@ -20908,26 +20938,33 @@
|
|
|
20908
20938
|
return;
|
|
20909
20939
|
}
|
|
20910
20940
|
const chunk_seq = state.chunk_seq;
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
|
|
20914
|
-
|
|
20915
|
-
|
|
20916
|
-
|
|
20917
|
-
|
|
20918
|
-
|
|
20919
|
-
|
|
20920
|
-
|
|
20921
|
-
|
|
20922
|
-
|
|
20923
|
-
takeFullSnapshot(true);
|
|
20924
|
-
}
|
|
20925
|
-
catch (err) {
|
|
20926
|
-
__classPrivateFieldGet(this, _SessionRecorder_instances, "m", _SessionRecorder_log).call(this, "takeFullSnapshot failed", err);
|
|
20941
|
+
const initial_url = chunk_seq === 0 ? state.initial_url : undefined;
|
|
20942
|
+
const chunk_start_ts = new Date(start_ts_ms).toISOString();
|
|
20943
|
+
const chunk_end_ts = new Date(end_ts_ms).toISOString();
|
|
20944
|
+
if (this.mode === "manual") {
|
|
20945
|
+
await this.onEvents({
|
|
20946
|
+
session_uuid: this.sessionUuid,
|
|
20947
|
+
chunk_seq,
|
|
20948
|
+
chunk_start_ts,
|
|
20949
|
+
chunk_end_ts,
|
|
20950
|
+
initial_url,
|
|
20951
|
+
events,
|
|
20952
|
+
});
|
|
20927
20953
|
}
|
|
20928
|
-
|
|
20929
|
-
|
|
20954
|
+
else {
|
|
20955
|
+
await uploadSessionEvents({
|
|
20956
|
+
user_id: this.userId,
|
|
20957
|
+
session_uuid: this.sessionUuid,
|
|
20958
|
+
chunk_seq,
|
|
20959
|
+
chunk_start_ts,
|
|
20960
|
+
chunk_end_ts,
|
|
20961
|
+
initial_url,
|
|
20962
|
+
events,
|
|
20963
|
+
});
|
|
20930
20964
|
}
|
|
20965
|
+
const removedBytes = events.reduce((sum, e) => sum + estimateEventSize(e), 0);
|
|
20966
|
+
this.sessionEvents = this.sessionEvents.slice(snapshot_count);
|
|
20967
|
+
this.bufferBytes = Math.max(0, this.bufferBytes - removedBytes);
|
|
20931
20968
|
const after = readSessionState();
|
|
20932
20969
|
if (after &&
|
|
20933
20970
|
after.session_uuid === state.session_uuid &&
|
|
@@ -20944,6 +20981,11 @@
|
|
|
20944
20981
|
}
|
|
20945
20982
|
}, _SessionRecorder_clearEvents = function _SessionRecorder_clearEvents() {
|
|
20946
20983
|
this.sessionEvents = [];
|
|
20984
|
+
this.bufferBytes = 0;
|
|
20985
|
+
if (__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f") !== null) {
|
|
20986
|
+
clearTimeout(__classPrivateFieldGet(this, _SessionRecorder_bufferTimer, "f"));
|
|
20987
|
+
__classPrivateFieldSet(this, _SessionRecorder_bufferTimer, null, "f");
|
|
20988
|
+
}
|
|
20947
20989
|
};
|
|
20948
20990
|
|
|
20949
20991
|
exports.default = SessionRecorder;
|