@statsig/session-replay 3.16.1 → 3.16.2
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/package.json +2 -2
- package/src/SessionReplay.js +4 -0
- package/src/SessionReplayBase.d.ts +1 -0
- package/src/SessionReplayBase.js +19 -5
- package/src/SessionReplayClient.d.ts +0 -1
- package/src/SessionReplayClient.js +1 -3
- package/src/TriggeredSessionReplay.d.ts +1 -0
- package/src/TriggeredSessionReplay.js +70 -3
- package/src/index.d.ts +2 -2
- package/src/index.js +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statsig/session-replay",
|
|
3
|
-
"version": "3.16.
|
|
3
|
+
"version": "3.16.2",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"homepage": "https://github.com/statsig-io/js-client-monorepo",
|
|
6
6
|
"repository": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"rrweb": "2.0.0-alpha.14",
|
|
13
|
-
"@statsig/client-core": "3.16.
|
|
13
|
+
"@statsig/client-core": "3.16.2"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@rrweb/types": "2.0.0-alpha.14"
|
package/src/SessionReplay.js
CHANGED
|
@@ -39,6 +39,10 @@ class SessionReplay extends SessionReplayBase_1.SessionReplayBase {
|
|
|
39
39
|
this._shutdown();
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
+
if ((values === null || values === void 0 ? void 0 : values.passes_session_recording_targeting) === false) {
|
|
43
|
+
this._shutdown();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
42
46
|
if (this._replayer.isRecording()) {
|
|
43
47
|
return;
|
|
44
48
|
}
|
|
@@ -28,6 +28,7 @@ export declare abstract class SessionReplayBase {
|
|
|
28
28
|
protected _getSessionIdFromClient(): string;
|
|
29
29
|
protected abstract _shutdown(endReason?: EndReason): void;
|
|
30
30
|
protected _shutdownImpl(endReason?: EndReason): void;
|
|
31
|
+
private _makeEmptySessionData;
|
|
31
32
|
protected _onRecordingEvent(event: ReplayEvent, data: ReplaySessionData): void;
|
|
32
33
|
}
|
|
33
34
|
export {};
|
package/src/SessionReplayBase.js
CHANGED
|
@@ -8,7 +8,7 @@ const SizeOf_1 = require("./SizeOf");
|
|
|
8
8
|
class SessionReplayBase {
|
|
9
9
|
constructor(client, options) {
|
|
10
10
|
this._sessionData = {
|
|
11
|
-
startTime:
|
|
11
|
+
startTime: -1,
|
|
12
12
|
endTime: 0,
|
|
13
13
|
clickCount: 0,
|
|
14
14
|
};
|
|
@@ -106,13 +106,24 @@ class SessionReplayBase {
|
|
|
106
106
|
_shutdownImpl(endReason) {
|
|
107
107
|
this._replayer.stop();
|
|
108
108
|
client_core_1.StatsigMetadataProvider.add({ isRecordingSession: 'false' });
|
|
109
|
-
this._currentEventIndex = 0;
|
|
110
109
|
if (this._events.length === 0) {
|
|
110
|
+
// only reset if session expired otherwise we might start recording again
|
|
111
|
+
if (endReason === 'session_expired') {
|
|
112
|
+
this._currentEventIndex = 0;
|
|
113
|
+
this._sessionData = this._makeEmptySessionData();
|
|
114
|
+
}
|
|
111
115
|
return;
|
|
112
116
|
}
|
|
113
117
|
this._logRecording(endReason);
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
// only reset if session expired otherwise we might start recording again
|
|
119
|
+
if (endReason === 'session_expired') {
|
|
120
|
+
this._currentEventIndex = 0;
|
|
121
|
+
this._sessionData = this._makeEmptySessionData();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
_makeEmptySessionData() {
|
|
125
|
+
return {
|
|
126
|
+
startTime: -1,
|
|
116
127
|
endTime: 0,
|
|
117
128
|
clickCount: 0,
|
|
118
129
|
};
|
|
@@ -126,7 +137,10 @@ class SessionReplayBase {
|
|
|
126
137
|
event.eventIndex = this._currentEventIndex++;
|
|
127
138
|
// Update the session data
|
|
128
139
|
this._sessionData.clickCount += data.clickCount;
|
|
129
|
-
this._sessionData.startTime =
|
|
140
|
+
this._sessionData.startTime =
|
|
141
|
+
this._sessionData.startTime === -1
|
|
142
|
+
? data.startTime
|
|
143
|
+
: Math.min(this._sessionData.startTime, data.startTime);
|
|
130
144
|
this._sessionData.endTime = Math.max(this._sessionData.endTime, data.endTime);
|
|
131
145
|
const eventApproxSize = (0, SizeOf_1._fastApproxSizeOf)(event, SessionReplayUtils_1.MAX_INDIVIDUAL_EVENT_BYTES);
|
|
132
146
|
if (eventApproxSize > SessionReplayUtils_1.MAX_INDIVIDUAL_EVENT_BYTES) {
|
|
@@ -15,7 +15,6 @@ export declare class SessionReplayClient {
|
|
|
15
15
|
private _stopCallback?;
|
|
16
16
|
private _startTimestamp;
|
|
17
17
|
private _endTimestamp;
|
|
18
|
-
private _eventCounter;
|
|
19
18
|
record(callback: (latest: ReplayEvent, data: ReplaySessionData, isCheckout?: boolean) => void, config: RRWebConfig, stopCallback?: () => void, keepRollingWindow?: boolean): void;
|
|
20
19
|
stop(): void;
|
|
21
20
|
isRecording(): boolean;
|
|
@@ -4,12 +4,11 @@ exports.SessionReplayClient = void 0;
|
|
|
4
4
|
const rrweb = require("rrweb");
|
|
5
5
|
const client_core_1 = require("@statsig/client-core");
|
|
6
6
|
const TIMEOUT_MS = 1000 * 60 * 60 * 4; // 4 hours
|
|
7
|
-
const CHECKOUT_WINDOW_MS = 1000 *
|
|
7
|
+
const CHECKOUT_WINDOW_MS = 1000 * 30; // 30 seconds
|
|
8
8
|
class SessionReplayClient {
|
|
9
9
|
constructor() {
|
|
10
10
|
this._startTimestamp = null;
|
|
11
11
|
this._endTimestamp = null;
|
|
12
|
-
this._eventCounter = 0;
|
|
13
12
|
}
|
|
14
13
|
record(callback, config, stopCallback, keepRollingWindow = false) {
|
|
15
14
|
if ((0, client_core_1._getDocumentSafe)() == null) {
|
|
@@ -18,7 +17,6 @@ class SessionReplayClient {
|
|
|
18
17
|
// Always reset session id and tracking fields for a new recording
|
|
19
18
|
this._startTimestamp = null;
|
|
20
19
|
this._endTimestamp = null;
|
|
21
|
-
this._eventCounter = 0;
|
|
22
20
|
this._stopCallback = stopCallback;
|
|
23
21
|
if (this._stopFn) {
|
|
24
22
|
return;
|
|
@@ -17,6 +17,7 @@ export declare class StatsigTriggeredSessionReplayPlugin implements StatsigPlugi
|
|
|
17
17
|
}
|
|
18
18
|
export declare function runStatsigSessionReplay(client: PrecomputedEvaluationsInterface, options?: SessionReplayOptions): void;
|
|
19
19
|
export declare function startRecording(sdkKey: string): void;
|
|
20
|
+
export declare function forceStartRecording(sdkKey: string): void;
|
|
20
21
|
export declare function stopRecording(sdkKey: string): void;
|
|
21
22
|
export declare class TriggeredSessionReplay extends SessionReplayBase {
|
|
22
23
|
private _runningEventData;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TriggeredSessionReplay = exports.stopRecording = exports.startRecording = exports.runStatsigSessionReplay = exports.StatsigTriggeredSessionReplayPlugin = void 0;
|
|
3
|
+
exports.TriggeredSessionReplay = exports.stopRecording = exports.forceStartRecording = exports.startRecording = exports.runStatsigSessionReplay = exports.StatsigTriggeredSessionReplayPlugin = void 0;
|
|
4
4
|
const client_core_1 = require("@statsig/client-core");
|
|
5
5
|
const SessionReplayBase_1 = require("./SessionReplayBase");
|
|
6
6
|
class StatsigTriggeredSessionReplayPlugin {
|
|
@@ -25,6 +25,14 @@ function startRecording(sdkKey) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
exports.startRecording = startRecording;
|
|
28
|
+
function forceStartRecording(sdkKey) {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
const inst = (_b = (_a = (0, client_core_1._getStatsigGlobal)()) === null || _a === void 0 ? void 0 : _a.srInstances) === null || _b === void 0 ? void 0 : _b[sdkKey];
|
|
31
|
+
if (inst instanceof TriggeredSessionReplay) {
|
|
32
|
+
inst.forceStartRecording();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.forceStartRecording = forceStartRecording;
|
|
28
36
|
function stopRecording(sdkKey) {
|
|
29
37
|
var _a, _b;
|
|
30
38
|
const inst = (_b = (_a = (0, client_core_1._getStatsigGlobal)()) === null || _a === void 0 ? void 0 : _a.srInstances) === null || _b === void 0 ? void 0 : _b[sdkKey];
|
|
@@ -50,6 +58,56 @@ class TriggeredSessionReplay extends SessionReplayBase_1.SessionReplayBase {
|
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
});
|
|
61
|
+
this._client.$on('log_event_called', (event) => {
|
|
62
|
+
var _a;
|
|
63
|
+
if (this._wasStopped) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const values = this._client.getContext().values;
|
|
67
|
+
const passedTargeting = values === null || values === void 0 ? void 0 : values.passes_session_recording_targeting;
|
|
68
|
+
if (passedTargeting === false ||
|
|
69
|
+
(values === null || values === void 0 ? void 0 : values.session_recording_event_triggers) == null) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const trigger = values.session_recording_event_triggers[event.event.eventName];
|
|
73
|
+
if (trigger == null) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const targetValues = trigger.values;
|
|
77
|
+
if (targetValues == null) {
|
|
78
|
+
this._attemptToStartRecording(true);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (targetValues.includes(String((_a = event.event.value) !== null && _a !== void 0 ? _a : ''))) {
|
|
82
|
+
this._attemptToStartRecording(true);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
this._client.$on('gate_evaluation', (event) => {
|
|
87
|
+
var _a, _b;
|
|
88
|
+
if (this._wasStopped) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const values = this._client.getContext().values;
|
|
92
|
+
const passedTargeting = values === null || values === void 0 ? void 0 : values.passes_session_recording_targeting;
|
|
93
|
+
if (passedTargeting === false ||
|
|
94
|
+
(values === null || values === void 0 ? void 0 : values.session_recording_exposure_triggers) == null) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const trigger = (_a = values.session_recording_exposure_triggers[event.gate.name]) !== null && _a !== void 0 ? _a : values.session_recording_exposure_triggers[(0, client_core_1._DJB2)(event.gate.name)];
|
|
98
|
+
if (trigger == null) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const targetValues = trigger.values;
|
|
102
|
+
if (targetValues == null) {
|
|
103
|
+
this._attemptToStartRecording(true);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (targetValues.includes(String((_b = event.gate.value) !== null && _b !== void 0 ? _b : false))) {
|
|
107
|
+
this._attemptToStartRecording(true);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
53
111
|
if (options === null || options === void 0 ? void 0 : options.autoStartRecording) {
|
|
54
112
|
this._attemptToStartRecording((_a = this._options) === null || _a === void 0 ? void 0 : _a.forceRecording);
|
|
55
113
|
}
|
|
@@ -79,7 +137,10 @@ class TriggeredSessionReplay extends SessionReplayBase_1.SessionReplayBase {
|
|
|
79
137
|
for (let i = 0; i < currentEvents.length; i++) {
|
|
80
138
|
currentEvents[i].event.eventIndex = i;
|
|
81
139
|
this._sessionData.clickCount += currentEvents[i].data.clickCount;
|
|
82
|
-
this._sessionData.startTime =
|
|
140
|
+
this._sessionData.startTime =
|
|
141
|
+
this._sessionData.startTime === -1
|
|
142
|
+
? currentEvents[i].data.startTime
|
|
143
|
+
: Math.min(this._sessionData.startTime, currentEvents[i].data.startTime);
|
|
83
144
|
this._sessionData.endTime = Math.max(this._sessionData.endTime, currentEvents[i].data.endTime);
|
|
84
145
|
}
|
|
85
146
|
this._events = currentEvents.map((e) => e.event);
|
|
@@ -90,6 +151,8 @@ class TriggeredSessionReplay extends SessionReplayBase_1.SessionReplayBase {
|
|
|
90
151
|
else {
|
|
91
152
|
this._logRecording();
|
|
92
153
|
}
|
|
154
|
+
// stop recording and since it will be started again
|
|
155
|
+
this._replayer.stop();
|
|
93
156
|
}
|
|
94
157
|
_shutdown(endReason) {
|
|
95
158
|
this._isActiveRecording = false;
|
|
@@ -124,7 +187,7 @@ class TriggeredSessionReplay extends SessionReplayBase_1.SessionReplayBase {
|
|
|
124
187
|
_attemptToStartRollingWindow() {
|
|
125
188
|
var _a, _b;
|
|
126
189
|
const values = this._client.getContext().values;
|
|
127
|
-
if ((values === null || values === void 0 ? void 0 : values.
|
|
190
|
+
if ((values === null || values === void 0 ? void 0 : values.passes_session_recording_targeting) === false) {
|
|
128
191
|
this._shutdown();
|
|
129
192
|
return;
|
|
130
193
|
}
|
|
@@ -142,6 +205,10 @@ class TriggeredSessionReplay extends SessionReplayBase_1.SessionReplayBase {
|
|
|
142
205
|
this._shutdown();
|
|
143
206
|
return;
|
|
144
207
|
}
|
|
208
|
+
if ((values === null || values === void 0 ? void 0 : values.passes_session_recording_targeting) === false) {
|
|
209
|
+
this._shutdown();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
145
212
|
this._handleStartActiveRecording();
|
|
146
213
|
this._wasStopped = false;
|
|
147
214
|
client_core_1.StatsigMetadataProvider.add({ isRecordingSession: 'true' });
|
package/src/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SessionReplay, StatsigSessionReplayPlugin, runStatsigSessionReplay } from './SessionReplay';
|
|
2
2
|
import { SessionReplayClient } from './SessionReplayClient';
|
|
3
|
-
import { StatsigTriggeredSessionReplayPlugin, startRecording, stopRecording } from './TriggeredSessionReplay';
|
|
3
|
+
import { StatsigTriggeredSessionReplayPlugin, forceStartRecording, startRecording, stopRecording } from './TriggeredSessionReplay';
|
|
4
4
|
export type { ReplaySessionData as ReplayData, ReplayEvent, } from './SessionReplayClient';
|
|
5
|
-
export { SessionReplayClient, SessionReplay, runStatsigSessionReplay, StatsigSessionReplayPlugin, StatsigTriggeredSessionReplayPlugin, startRecording, stopRecording, };
|
|
5
|
+
export { SessionReplayClient, SessionReplay, runStatsigSessionReplay, StatsigSessionReplayPlugin, StatsigTriggeredSessionReplayPlugin, startRecording, stopRecording, forceStartRecording, };
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.stopRecording = exports.startRecording = exports.StatsigTriggeredSessionReplayPlugin = exports.StatsigSessionReplayPlugin = exports.runStatsigSessionReplay = exports.SessionReplay = exports.SessionReplayClient = void 0;
|
|
3
|
+
exports.forceStartRecording = exports.stopRecording = exports.startRecording = exports.StatsigTriggeredSessionReplayPlugin = exports.StatsigSessionReplayPlugin = exports.runStatsigSessionReplay = exports.SessionReplay = exports.SessionReplayClient = void 0;
|
|
4
4
|
const client_core_1 = require("@statsig/client-core");
|
|
5
5
|
const SessionReplay_1 = require("./SessionReplay");
|
|
6
6
|
Object.defineProperty(exports, "SessionReplay", { enumerable: true, get: function () { return SessionReplay_1.SessionReplay; } });
|
|
@@ -10,6 +10,7 @@ const SessionReplayClient_1 = require("./SessionReplayClient");
|
|
|
10
10
|
Object.defineProperty(exports, "SessionReplayClient", { enumerable: true, get: function () { return SessionReplayClient_1.SessionReplayClient; } });
|
|
11
11
|
const TriggeredSessionReplay_1 = require("./TriggeredSessionReplay");
|
|
12
12
|
Object.defineProperty(exports, "StatsigTriggeredSessionReplayPlugin", { enumerable: true, get: function () { return TriggeredSessionReplay_1.StatsigTriggeredSessionReplayPlugin; } });
|
|
13
|
+
Object.defineProperty(exports, "forceStartRecording", { enumerable: true, get: function () { return TriggeredSessionReplay_1.forceStartRecording; } });
|
|
13
14
|
Object.defineProperty(exports, "startRecording", { enumerable: true, get: function () { return TriggeredSessionReplay_1.startRecording; } });
|
|
14
15
|
Object.defineProperty(exports, "stopRecording", { enumerable: true, get: function () { return TriggeredSessionReplay_1.stopRecording; } });
|
|
15
16
|
Object.assign((0, client_core_1._getStatsigGlobal)(), {
|