posthog-js 1.84.3 → 1.85.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/array.full.js +1 -10
- package/dist/array.full.js.map +1 -1
- package/dist/array.js +1 -10
- package/dist/array.js.map +1 -1
- package/dist/es.js +1 -10
- package/dist/es.js.map +1 -1
- package/dist/module.d.ts +32 -148
- package/dist/module.js +1 -10
- package/dist/module.js.map +1 -1
- package/dist/recorder-v2.js +2 -2
- package/dist/recorder-v2.js.map +1 -1
- package/dist/recorder.js +1 -1
- package/dist/recorder.js.map +1 -1
- package/dist/surveys.js +1 -1
- package/dist/surveys.js.map +1 -1
- package/lib/package.json +9 -4
- package/lib/src/autocapture-utils.js +6 -6
- package/lib/src/autocapture-utils.js.map +1 -1
- package/lib/src/autocapture.js +5 -5
- package/lib/src/autocapture.js.map +1 -1
- package/lib/src/constants.d.ts +1 -0
- package/lib/src/constants.js +1 -0
- package/lib/src/constants.js.map +1 -1
- package/lib/src/extensions/exceptions/error-conversion.js +3 -2
- package/lib/src/extensions/exceptions/error-conversion.js.map +1 -1
- package/lib/src/extensions/exceptions/exception-autocapture.js +4 -7
- package/lib/src/extensions/exceptions/exception-autocapture.js.map +1 -1
- package/lib/src/extensions/exceptions/stack-trace.js +3 -2
- package/lib/src/extensions/exceptions/stack-trace.js.map +1 -1
- package/lib/src/extensions/exceptions/type-checking.js +3 -2
- package/lib/src/extensions/exceptions/type-checking.js.map +1 -1
- package/lib/src/extensions/{sessionrecording-utils.js → replay/sessionrecording-utils.js} +3 -2
- package/lib/src/extensions/replay/sessionrecording-utils.js.map +1 -0
- package/lib/src/extensions/{sessionrecording.d.ts → replay/sessionrecording.d.ts} +26 -19
- package/lib/src/extensions/{sessionrecording.js → replay/sessionrecording.js} +214 -92
- package/lib/src/extensions/replay/sessionrecording.js.map +1 -0
- package/lib/src/extensions/{web-performance.d.ts → replay/web-performance.d.ts} +2 -2
- package/lib/src/extensions/{web-performance.js → replay/web-performance.js} +3 -3
- package/lib/src/extensions/replay/web-performance.js.map +1 -0
- package/lib/src/extensions/surveys.js +3 -2
- package/lib/src/extensions/surveys.js.map +1 -1
- package/lib/src/loader-recorder-v2.js +2 -3
- package/lib/src/loader-recorder-v2.js.map +1 -1
- package/lib/src/loader-recorder.js +2 -1
- package/lib/src/loader-recorder.js.map +1 -1
- package/lib/src/loader-surveys.js +2 -1
- package/lib/src/loader-surveys.js.map +1 -1
- package/lib/src/posthog-core.d.ts +2 -2
- package/lib/src/posthog-core.js +14 -14
- package/lib/src/posthog-core.js.map +1 -1
- package/lib/src/posthog-featureflags.js +4 -4
- package/lib/src/posthog-featureflags.js.map +1 -1
- package/lib/src/posthog-persistence.js +4 -4
- package/lib/src/posthog-persistence.js.map +1 -1
- package/lib/src/request-queue.js +2 -2
- package/lib/src/request-queue.js.map +1 -1
- package/lib/src/retry-queue.js +7 -3
- package/lib/src/retry-queue.js.map +1 -1
- package/lib/src/send-request.js +3 -3
- package/lib/src/send-request.js.map +1 -1
- package/lib/src/sessionid.d.ts +6 -4
- package/lib/src/sessionid.js +17 -15
- package/lib/src/sessionid.js.map +1 -1
- package/lib/src/storage.js +7 -7
- package/lib/src/storage.js.map +1 -1
- package/lib/src/types.d.ts +3 -0
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils.d.ts +8 -10
- package/lib/src/utils.js +41 -30
- package/lib/src/utils.js.map +1 -1
- package/lib/src/uuidv7.js +6 -4
- package/lib/src/uuidv7.js.map +1 -1
- package/package.json +9 -4
- package/lib/src/extensions/sessionrecording-utils.js.map +0 -1
- package/lib/src/extensions/sessionrecording.js.map +0 -1
- package/lib/src/extensions/web-performance.js.map +0 -1
- /package/lib/src/extensions/{sessionrecording-utils.d.ts → replay/sessionrecording-utils.d.ts} +0 -0
|
@@ -36,11 +36,11 @@ var __read = (this && this.__read) || function (o, n) {
|
|
|
36
36
|
}
|
|
37
37
|
return ar;
|
|
38
38
|
};
|
|
39
|
-
import { CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE, SESSION_RECORDING_ENABLED_SERVER_SIDE, SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE, } from '
|
|
39
|
+
import { CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE, SESSION_RECORDING_ENABLED_SERVER_SIDE, SESSION_RECORDING_IS_SAMPLED, SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE, } from '../../constants';
|
|
40
40
|
import { ensureMaxMessageSize, FULL_SNAPSHOT_EVENT_TYPE, INCREMENTAL_SNAPSHOT_EVENT_TYPE, META_EVENT_TYPE, MutationRateLimiter, truncateLargeConsoleLogs, } from './sessionrecording-utils';
|
|
41
41
|
import { EventType } from '@rrweb/types';
|
|
42
|
-
import Config from '
|
|
43
|
-
import {
|
|
42
|
+
import Config from '../../config';
|
|
43
|
+
import { _isBoolean, _isNull, _isNumber, _isObject, _isString, _isUndefined, _timestamp, loadScript, logger, } from '../../utils';
|
|
44
44
|
var BASE_ENDPOINT = '/s/';
|
|
45
45
|
export var RECORDING_IDLE_ACTIVITY_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
46
46
|
export var TEN_MINUTES_IN_MS = 10 * 60 * 1000;
|
|
@@ -83,80 +83,176 @@ var ACTIVE_SOURCES = [
|
|
|
83
83
|
var SessionRecording = /** @class */ (function () {
|
|
84
84
|
function SessionRecording(instance) {
|
|
85
85
|
var _this = this;
|
|
86
|
+
this._linkedFlagSeen = false;
|
|
86
87
|
this._lastActivityTimestamp = Date.now();
|
|
87
88
|
this.isIdle = false;
|
|
89
|
+
this._linkedFlag = null;
|
|
90
|
+
this._sampleRate = null;
|
|
91
|
+
this._minimumDuration = null;
|
|
88
92
|
this.instance = instance;
|
|
89
|
-
this.
|
|
90
|
-
this.snapshots = [];
|
|
91
|
-
this.emit = false; // Controls whether data is sent to the server or not
|
|
93
|
+
this._captureStarted = false;
|
|
92
94
|
this._endpoint = BASE_ENDPOINT;
|
|
93
95
|
this.stopRrweb = undefined;
|
|
94
|
-
this.windowId = null;
|
|
95
|
-
this.sessionId = null;
|
|
96
96
|
this.receivedDecide = false;
|
|
97
97
|
window.addEventListener('beforeunload', function () {
|
|
98
98
|
_this._flushBuffer();
|
|
99
99
|
});
|
|
100
|
+
if (!this.instance.sessionManager) {
|
|
101
|
+
logger.error('Session recording started without valid sessionManager');
|
|
102
|
+
throw new Error('Session recording started without valid sessionManager. This is a bug.');
|
|
103
|
+
}
|
|
104
|
+
var _a = this.sessionManager.checkAndGetSessionAndWindowId(true), sessionId = _a.sessionId, windowId = _a.windowId;
|
|
105
|
+
this.windowId = windowId;
|
|
106
|
+
this.sessionId = sessionId;
|
|
107
|
+
this.buffer = this.clearBuffer();
|
|
100
108
|
}
|
|
101
|
-
Object.defineProperty(SessionRecording.prototype, "
|
|
109
|
+
Object.defineProperty(SessionRecording.prototype, "started", {
|
|
102
110
|
get: function () {
|
|
103
|
-
|
|
111
|
+
// TODO could we use status instead of _captureStarted?
|
|
112
|
+
return this._captureStarted;
|
|
104
113
|
},
|
|
105
114
|
enumerable: false,
|
|
106
115
|
configurable: true
|
|
107
116
|
});
|
|
108
|
-
Object.defineProperty(SessionRecording.prototype, "
|
|
117
|
+
Object.defineProperty(SessionRecording.prototype, "sessionManager", {
|
|
109
118
|
get: function () {
|
|
110
|
-
|
|
119
|
+
if (!this.instance.sessionManager) {
|
|
120
|
+
logger.error('Session recording started without valid sessionManager');
|
|
121
|
+
throw new Error('Session recording started without valid sessionManager. This is a bug.');
|
|
122
|
+
}
|
|
123
|
+
return this.instance.sessionManager;
|
|
124
|
+
},
|
|
125
|
+
enumerable: false,
|
|
126
|
+
configurable: true
|
|
127
|
+
});
|
|
128
|
+
Object.defineProperty(SessionRecording.prototype, "isSampled", {
|
|
129
|
+
get: function () {
|
|
130
|
+
if (_isNumber(this._sampleRate)) {
|
|
131
|
+
return this.instance.get_property(SESSION_RECORDING_IS_SAMPLED);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
enumerable: false,
|
|
138
|
+
configurable: true
|
|
139
|
+
});
|
|
140
|
+
Object.defineProperty(SessionRecording.prototype, "sessionDuration", {
|
|
141
|
+
get: function () {
|
|
142
|
+
var _a, _b;
|
|
143
|
+
var mostRecentSnapshot = (_a = this.buffer) === null || _a === void 0 ? void 0 : _a.data[((_b = this.buffer) === null || _b === void 0 ? void 0 : _b.data.length) - 1];
|
|
144
|
+
var sessionStartTimestamp = this.sessionManager.checkAndGetSessionAndWindowId(true).sessionStartTimestamp;
|
|
145
|
+
return mostRecentSnapshot ? mostRecentSnapshot.timestamp - sessionStartTimestamp : null;
|
|
146
|
+
},
|
|
147
|
+
enumerable: false,
|
|
148
|
+
configurable: true
|
|
149
|
+
});
|
|
150
|
+
Object.defineProperty(SessionRecording.prototype, "isRecordingEnabled", {
|
|
151
|
+
get: function () {
|
|
152
|
+
var enabled_server_side = !!this.instance.get_property(SESSION_RECORDING_ENABLED_SERVER_SIDE);
|
|
153
|
+
var enabled_client_side = !this.instance.config.disable_session_recording;
|
|
154
|
+
return enabled_server_side && enabled_client_side;
|
|
155
|
+
},
|
|
156
|
+
enumerable: false,
|
|
157
|
+
configurable: true
|
|
158
|
+
});
|
|
159
|
+
Object.defineProperty(SessionRecording.prototype, "isConsoleLogCaptureEnabled", {
|
|
160
|
+
get: function () {
|
|
161
|
+
var enabled_server_side = !!this.instance.get_property(CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE);
|
|
162
|
+
var enabled_client_side = this.instance.config.enable_recording_console_log;
|
|
163
|
+
return enabled_client_side !== null && enabled_client_side !== void 0 ? enabled_client_side : enabled_server_side;
|
|
164
|
+
},
|
|
165
|
+
enumerable: false,
|
|
166
|
+
configurable: true
|
|
167
|
+
});
|
|
168
|
+
Object.defineProperty(SessionRecording.prototype, "recordingVersion", {
|
|
169
|
+
get: function () {
|
|
170
|
+
var _a;
|
|
171
|
+
var recordingVersion_server_side = this.instance.get_property(SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE);
|
|
172
|
+
var recordingVersion_client_side = (_a = this.instance.config.session_recording) === null || _a === void 0 ? void 0 : _a.recorderVersion;
|
|
173
|
+
return recordingVersion_client_side || recordingVersion_server_side || 'v1';
|
|
174
|
+
},
|
|
175
|
+
enumerable: false,
|
|
176
|
+
configurable: true
|
|
177
|
+
});
|
|
178
|
+
Object.defineProperty(SessionRecording.prototype, "status", {
|
|
179
|
+
/**
|
|
180
|
+
* defaults to buffering mode until a decide response is received
|
|
181
|
+
* once a decide response is received status can be disabled, active or sampled
|
|
182
|
+
*/
|
|
183
|
+
get: function () {
|
|
184
|
+
if (!this.receivedDecide) {
|
|
185
|
+
return 'buffering';
|
|
186
|
+
}
|
|
187
|
+
if (!this.isRecordingEnabled) {
|
|
188
|
+
return 'disabled';
|
|
189
|
+
}
|
|
190
|
+
if (_isString(this._linkedFlag) && !this._linkedFlagSeen) {
|
|
191
|
+
return 'buffering';
|
|
192
|
+
}
|
|
193
|
+
if (_isBoolean(this.isSampled)) {
|
|
194
|
+
return this.isSampled ? 'sampled' : 'disabled';
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
return 'active';
|
|
198
|
+
}
|
|
111
199
|
},
|
|
112
200
|
enumerable: false,
|
|
113
201
|
configurable: true
|
|
114
202
|
});
|
|
115
|
-
SessionRecording.prototype.getSessionManager = function () {
|
|
116
|
-
if (!this.instance.sessionManager) {
|
|
117
|
-
logger.error('Session recording started without valid sessionManager');
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
return this.instance.sessionManager;
|
|
121
|
-
};
|
|
122
203
|
SessionRecording.prototype.startRecordingIfEnabled = function () {
|
|
123
|
-
if (this.isRecordingEnabled
|
|
204
|
+
if (this.isRecordingEnabled) {
|
|
124
205
|
this.startCaptureAndTrySendingQueuedSnapshots();
|
|
125
206
|
}
|
|
126
207
|
else {
|
|
127
208
|
this.stopRecording();
|
|
209
|
+
this.clearBuffer();
|
|
128
210
|
}
|
|
129
211
|
};
|
|
130
|
-
SessionRecording.prototype.started = function () {
|
|
131
|
-
return this.captureStarted;
|
|
132
|
-
};
|
|
133
212
|
SessionRecording.prototype.stopRecording = function () {
|
|
134
|
-
if (this.
|
|
213
|
+
if (this._captureStarted && this.stopRrweb) {
|
|
135
214
|
this.stopRrweb();
|
|
136
215
|
this.stopRrweb = undefined;
|
|
137
|
-
this.
|
|
216
|
+
this._captureStarted = false;
|
|
138
217
|
}
|
|
139
218
|
};
|
|
140
|
-
SessionRecording.prototype.
|
|
141
|
-
var
|
|
142
|
-
var
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
219
|
+
SessionRecording.prototype.makeSamplingDecision = function (sessionId) {
|
|
220
|
+
var _a, _b;
|
|
221
|
+
var _c, _d;
|
|
222
|
+
var sessionIdChanged = this.sessionId !== sessionId;
|
|
223
|
+
if (!_isNumber(this._sampleRate)) {
|
|
224
|
+
(_c = this.instance.persistence) === null || _c === void 0 ? void 0 : _c.register((_a = {},
|
|
225
|
+
_a[SESSION_RECORDING_IS_SAMPLED] = null,
|
|
226
|
+
_a));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
var storedIsSampled = this.isSampled;
|
|
230
|
+
/**
|
|
231
|
+
* if we get this far then we should make a sampling decision.
|
|
232
|
+
* When the session id changes or there is no stored sampling decision for this session id
|
|
233
|
+
* then we should make a new decision.
|
|
234
|
+
*
|
|
235
|
+
* Otherwise, we should use the stored decision.
|
|
236
|
+
*/
|
|
237
|
+
var shouldSample;
|
|
238
|
+
if (sessionIdChanged || !_isBoolean(storedIsSampled)) {
|
|
239
|
+
var randomNumber = Math.random();
|
|
240
|
+
shouldSample = randomNumber < this._sampleRate;
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
shouldSample = storedIsSampled;
|
|
244
|
+
}
|
|
245
|
+
if (!shouldSample) {
|
|
246
|
+
logger.warn("[SessionSampling] Sample rate (".concat(this._sampleRate, ") has determined that this sessionId (").concat(sessionId, ") will not be sent to the server."));
|
|
247
|
+
}
|
|
248
|
+
(_d = this.instance.persistence) === null || _d === void 0 ? void 0 : _d.register((_b = {},
|
|
249
|
+
_b[SESSION_RECORDING_IS_SAMPLED] = shouldSample,
|
|
250
|
+
_b));
|
|
155
251
|
};
|
|
156
252
|
SessionRecording.prototype.afterDecideResponse = function (response) {
|
|
157
253
|
var _a;
|
|
158
|
-
var
|
|
159
|
-
|
|
254
|
+
var _this = this;
|
|
255
|
+
var _b, _c, _d, _e, _f, _g, _h;
|
|
160
256
|
if (this.instance.persistence) {
|
|
161
257
|
this.instance.persistence.register((_a = {},
|
|
162
258
|
_a[SESSION_RECORDING_ENABLED_SERVER_SIDE] = !!response['sessionRecording'],
|
|
@@ -164,12 +260,27 @@ var SessionRecording = /** @class */ (function () {
|
|
|
164
260
|
_a[SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE] = (_c = response.sessionRecording) === null || _c === void 0 ? void 0 : _c.recorderVersion,
|
|
165
261
|
_a));
|
|
166
262
|
}
|
|
167
|
-
|
|
168
|
-
|
|
263
|
+
var receivedSampleRate = (_d = response.sessionRecording) === null || _d === void 0 ? void 0 : _d.sampleRate;
|
|
264
|
+
this._sampleRate =
|
|
265
|
+
_isUndefined(receivedSampleRate) || _isNull(receivedSampleRate) ? null : parseFloat(receivedSampleRate);
|
|
266
|
+
var receivedMinimumDuration = (_e = response.sessionRecording) === null || _e === void 0 ? void 0 : _e.minimumDurationMilliseconds;
|
|
267
|
+
this._minimumDuration = _isUndefined(receivedMinimumDuration) ? null : receivedMinimumDuration;
|
|
268
|
+
this._linkedFlag = ((_f = response.sessionRecording) === null || _f === void 0 ? void 0 : _f.linkedFlag) || null;
|
|
269
|
+
if ((_g = response.sessionRecording) === null || _g === void 0 ? void 0 : _g.endpoint) {
|
|
270
|
+
this._endpoint = (_h = response.sessionRecording) === null || _h === void 0 ? void 0 : _h.endpoint;
|
|
271
|
+
}
|
|
272
|
+
if (_isNumber(this._sampleRate)) {
|
|
273
|
+
this.sessionManager.onSessionId(function (sessionId) {
|
|
274
|
+
_this.makeSamplingDecision(sessionId);
|
|
275
|
+
});
|
|
169
276
|
}
|
|
170
|
-
if ((
|
|
171
|
-
|
|
277
|
+
if (_isString(this._linkedFlag)) {
|
|
278
|
+
var linkedFlag_1 = this._linkedFlag;
|
|
279
|
+
this.instance.onFeatureFlags(function (flags) {
|
|
280
|
+
_this._linkedFlagSeen = flags.includes(linkedFlag_1);
|
|
281
|
+
});
|
|
172
282
|
}
|
|
283
|
+
this.receivedDecide = true;
|
|
173
284
|
this.startRecordingIfEnabled();
|
|
174
285
|
};
|
|
175
286
|
SessionRecording.prototype.log = function (message, level) {
|
|
@@ -182,7 +293,7 @@ var SessionRecording = /** @class */ (function () {
|
|
|
182
293
|
payload: {
|
|
183
294
|
level: level,
|
|
184
295
|
trace: [],
|
|
185
|
-
// Even though it is a string we stringify it as
|
|
296
|
+
// Even though it is a string we stringify it as that's what rrweb expects
|
|
186
297
|
payload: [JSON.stringify(message)],
|
|
187
298
|
},
|
|
188
299
|
},
|
|
@@ -190,22 +301,11 @@ var SessionRecording = /** @class */ (function () {
|
|
|
190
301
|
});
|
|
191
302
|
};
|
|
192
303
|
SessionRecording.prototype.startCaptureAndTrySendingQueuedSnapshots = function () {
|
|
193
|
-
var _this = this;
|
|
194
|
-
// Only submit data after we've received a decide response to account for
|
|
195
|
-
// changing endpoints and the feature being disabled on the server side.
|
|
196
|
-
if (this.receivedDecide) {
|
|
197
|
-
this.emit = true;
|
|
198
|
-
this.snapshots.forEach(function (properties) { return _this._captureSnapshotBuffered(properties); });
|
|
199
|
-
}
|
|
200
304
|
this._startCapture();
|
|
201
305
|
};
|
|
202
306
|
SessionRecording.prototype._startCapture = function () {
|
|
203
307
|
var _this = this;
|
|
204
|
-
|
|
205
|
-
if (!sessionManager) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
if (typeof Object.assign === 'undefined') {
|
|
308
|
+
if (_isUndefined(Object.assign)) {
|
|
209
309
|
// According to the rrweb docs, rrweb is not supported on IE11 and below:
|
|
210
310
|
// "rrweb does not support IE11 and below because it uses the MutationObserver API which was supported by these browsers."
|
|
211
311
|
// https://github.com/rrweb-io/rrweb/blob/master/guide.md#compatibility-note
|
|
@@ -216,17 +316,17 @@ var SessionRecording = /** @class */ (function () {
|
|
|
216
316
|
return;
|
|
217
317
|
}
|
|
218
318
|
// We do not switch recorder versions midway through a recording.
|
|
219
|
-
if (this.
|
|
319
|
+
if (this._captureStarted || this.instance.config.disable_session_recording) {
|
|
220
320
|
return;
|
|
221
321
|
}
|
|
222
|
-
this.
|
|
322
|
+
this._captureStarted = true;
|
|
223
323
|
// We want to ensure the sessionManager is reset if necessary on load of the recorder
|
|
224
|
-
sessionManager.checkAndGetSessionAndWindowId();
|
|
225
|
-
var recorderJS = this.
|
|
324
|
+
this.sessionManager.checkAndGetSessionAndWindowId();
|
|
325
|
+
var recorderJS = this.recordingVersion === 'v2' ? 'recorder-v2.js' : 'recorder.js';
|
|
226
326
|
// If recorder.js is already loaded (if array.full.js snippet is used or posthog-js/dist/recorder is
|
|
227
327
|
// imported) or matches the requested recorder version, don't load script. Otherwise, remotely import
|
|
228
328
|
// recorder.js from cdn since it hasn't been loaded.
|
|
229
|
-
if (this.instance.__loaded_recorder_version !== this.
|
|
329
|
+
if (this.instance.__loaded_recorder_version !== this.recordingVersion) {
|
|
230
330
|
loadScript(this.instance.config.api_host + "/static/".concat(recorderJS, "?v=").concat(Config.LIB_VERSION), function (err) {
|
|
231
331
|
if (err) {
|
|
232
332
|
return logger.error("Could not load ".concat(recorderJS), err);
|
|
@@ -243,10 +343,6 @@ var SessionRecording = /** @class */ (function () {
|
|
|
243
343
|
return event.type === INCREMENTAL_SNAPSHOT_EVENT_TYPE && ACTIVE_SOURCES.indexOf((_a = event.data) === null || _a === void 0 ? void 0 : _a.source) !== -1;
|
|
244
344
|
};
|
|
245
345
|
SessionRecording.prototype._updateWindowAndSessionIds = function (event) {
|
|
246
|
-
var sessionManager = this.getSessionManager();
|
|
247
|
-
if (!sessionManager) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
346
|
// Some recording events are triggered by non-user events (e.g. "X minutes ago" text updating on the screen).
|
|
251
347
|
// We don't want to extend the session or trigger a new session in these cases. These events are designated by event
|
|
252
348
|
// type -> incremental update, and source -> mutation.
|
|
@@ -260,7 +356,7 @@ var SessionRecording = /** @class */ (function () {
|
|
|
260
356
|
if (isUserInteraction) {
|
|
261
357
|
this._lastActivityTimestamp = event.timestamp;
|
|
262
358
|
if (this.isIdle) {
|
|
263
|
-
// Remove the idle state if set and trigger a full snapshot as we will have
|
|
359
|
+
// Remove the idle state if set and trigger a full snapshot as we will have ignored previous mutations
|
|
264
360
|
this.isIdle = false;
|
|
265
361
|
this._tryTakeFullSnapshot();
|
|
266
362
|
}
|
|
@@ -269,17 +365,20 @@ var SessionRecording = /** @class */ (function () {
|
|
|
269
365
|
return;
|
|
270
366
|
}
|
|
271
367
|
// We only want to extend the session if it is an interactive event.
|
|
272
|
-
var _a = sessionManager.checkAndGetSessionAndWindowId(!isUserInteraction, event.timestamp), windowId = _a.windowId, sessionId = _a.sessionId;
|
|
368
|
+
var _a = this.sessionManager.checkAndGetSessionAndWindowId(!isUserInteraction, event.timestamp), windowId = _a.windowId, sessionId = _a.sessionId;
|
|
369
|
+
var sessionIdChanged = this.sessionId !== sessionId;
|
|
370
|
+
var windowIdChanged = this.windowId !== windowId;
|
|
371
|
+
this.windowId = windowId;
|
|
372
|
+
this.sessionId = sessionId;
|
|
273
373
|
if ([FULL_SNAPSHOT_EVENT_TYPE, META_EVENT_TYPE].indexOf(event.type) === -1 &&
|
|
274
|
-
(
|
|
374
|
+
(windowIdChanged || sessionIdChanged)) {
|
|
275
375
|
this._tryTakeFullSnapshot();
|
|
276
376
|
}
|
|
277
|
-
this.windowId = windowId;
|
|
278
|
-
this.sessionId = sessionId;
|
|
279
377
|
};
|
|
280
378
|
SessionRecording.prototype._tryTakeFullSnapshot = function () {
|
|
281
379
|
var _a;
|
|
282
|
-
|
|
380
|
+
// TODO this should ignore based on emit?
|
|
381
|
+
if (!this._captureStarted) {
|
|
283
382
|
return false;
|
|
284
383
|
}
|
|
285
384
|
try {
|
|
@@ -321,7 +420,7 @@ var SessionRecording = /** @class */ (function () {
|
|
|
321
420
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
322
421
|
// @ts-ignore
|
|
323
422
|
this.rrwebRecord = window.rrweb ? window.rrweb.record : window.rrwebRecord;
|
|
324
|
-
// only allows user to set our
|
|
423
|
+
// only allows user to set our allow-listed options
|
|
325
424
|
var userSessionRecordingOptions = this.instance.config.session_recording;
|
|
326
425
|
try {
|
|
327
426
|
for (var _c = __values(Object.entries(userSessionRecordingOptions || {})), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
@@ -356,14 +455,15 @@ var SessionRecording = /** @class */ (function () {
|
|
|
356
455
|
});
|
|
357
456
|
this.stopRrweb = this.rrwebRecord(__assign({ emit: function (event) {
|
|
358
457
|
_this.onRRwebEmit(event);
|
|
359
|
-
}, plugins: window.rrwebConsoleRecord && this.isConsoleLogCaptureEnabled
|
|
458
|
+
}, plugins: window.rrwebConsoleRecord && this.isConsoleLogCaptureEnabled
|
|
360
459
|
? [window.rrwebConsoleRecord.getRecordConsolePlugin()]
|
|
361
460
|
: [] }, sessionRecordingOptions));
|
|
362
461
|
// :TRICKY: rrweb does not capture navigation within SPA-s, so hook into our $pageview events to get access to all events.
|
|
363
462
|
// Dropping the initial event is fine (it's always captured by rrweb).
|
|
364
463
|
this.instance._addCaptureHook(function (eventName) {
|
|
365
464
|
var _a;
|
|
366
|
-
// If anything could go wrong here it has the potential to block the main loop
|
|
465
|
+
// If anything could go wrong here it has the potential to block the main loop,
|
|
466
|
+
// so we catch all errors.
|
|
367
467
|
try {
|
|
368
468
|
if (eventName === '$pageview') {
|
|
369
469
|
var href = _this._maskUrl(window.location.href);
|
|
@@ -382,7 +482,7 @@ var SessionRecording = /** @class */ (function () {
|
|
|
382
482
|
this.isIdle = false;
|
|
383
483
|
};
|
|
384
484
|
SessionRecording.prototype.onRRwebEmit = function (rawEvent) {
|
|
385
|
-
if (!rawEvent ||
|
|
485
|
+
if (!rawEvent || !_isObject(rawEvent)) {
|
|
386
486
|
return;
|
|
387
487
|
}
|
|
388
488
|
if (rawEvent.type === EventType.Meta) {
|
|
@@ -399,22 +499,22 @@ var SessionRecording = /** @class */ (function () {
|
|
|
399
499
|
return;
|
|
400
500
|
}
|
|
401
501
|
var _a = ensureMaxMessageSize(truncateLargeConsoleLogs(throttledEvent)), event = _a.event, size = _a.size;
|
|
402
|
-
this._updateWindowAndSessionIds(event);
|
|
403
|
-
if (this.isIdle) {
|
|
404
|
-
// When in an idle state we keep recording, but don't capture the events
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
502
|
var properties = {
|
|
408
503
|
$snapshot_bytes: size,
|
|
409
504
|
$snapshot_data: event,
|
|
410
505
|
$session_id: this.sessionId,
|
|
411
506
|
$window_id: this.windowId,
|
|
412
507
|
};
|
|
413
|
-
|
|
508
|
+
this._updateWindowAndSessionIds(event);
|
|
509
|
+
if (this.isIdle) {
|
|
510
|
+
// When in an idle state we keep recording, but don't capture the events
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
if (this.status !== 'disabled') {
|
|
414
514
|
this._captureSnapshotBuffered(properties);
|
|
415
515
|
}
|
|
416
516
|
else {
|
|
417
|
-
this.
|
|
517
|
+
this.clearBuffer();
|
|
418
518
|
}
|
|
419
519
|
};
|
|
420
520
|
SessionRecording.prototype._maskUrl = function (url) {
|
|
@@ -428,11 +528,36 @@ var SessionRecording = /** @class */ (function () {
|
|
|
428
528
|
}
|
|
429
529
|
return url;
|
|
430
530
|
};
|
|
531
|
+
SessionRecording.prototype.clearBuffer = function () {
|
|
532
|
+
this.buffer = undefined;
|
|
533
|
+
return {
|
|
534
|
+
size: 0,
|
|
535
|
+
data: [],
|
|
536
|
+
sessionId: this.sessionId,
|
|
537
|
+
windowId: this.windowId,
|
|
538
|
+
};
|
|
539
|
+
};
|
|
540
|
+
// the intention is a buffer that (currently) is used only after a decide response enables session recording
|
|
541
|
+
// it is called ever X seconds using the flushBufferTimer so that we don't have to wait for the buffer to fill up
|
|
542
|
+
// when it is called on a timer it assumes that it can definitely flush
|
|
543
|
+
// it is flushed when the session id changes or the size of the buffered data gets too great (1mb by default)
|
|
544
|
+
// first change: if the recording is in buffering mode,
|
|
545
|
+
// flush buffer simply resets the timer and returns the existing flush buffer
|
|
431
546
|
SessionRecording.prototype._flushBuffer = function () {
|
|
547
|
+
var _this = this;
|
|
432
548
|
if (this.flushBufferTimer) {
|
|
433
549
|
clearTimeout(this.flushBufferTimer);
|
|
434
550
|
this.flushBufferTimer = undefined;
|
|
435
551
|
}
|
|
552
|
+
var minimumDuration = this._minimumDuration;
|
|
553
|
+
var sessionDuration = this.sessionDuration;
|
|
554
|
+
var isBelowMinimumDuration = _isNumber(minimumDuration) && _isNumber(sessionDuration) && sessionDuration < minimumDuration;
|
|
555
|
+
if (this.status === 'buffering' || isBelowMinimumDuration) {
|
|
556
|
+
this.flushBufferTimer = setTimeout(function () {
|
|
557
|
+
_this._flushBuffer();
|
|
558
|
+
}, RECORDING_BUFFER_TIMEOUT);
|
|
559
|
+
return this.buffer || this.clearBuffer();
|
|
560
|
+
}
|
|
436
561
|
if (this.buffer && this.buffer.data.length !== 0) {
|
|
437
562
|
this._captureSnapshot({
|
|
438
563
|
$snapshot_bytes: this.buffer.size,
|
|
@@ -440,14 +565,11 @@ var SessionRecording = /** @class */ (function () {
|
|
|
440
565
|
$session_id: this.buffer.sessionId,
|
|
441
566
|
$window_id: this.buffer.windowId,
|
|
442
567
|
});
|
|
568
|
+
return this.clearBuffer();
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
return this.buffer || this.clearBuffer();
|
|
443
572
|
}
|
|
444
|
-
this.buffer = undefined;
|
|
445
|
-
return {
|
|
446
|
-
size: 0,
|
|
447
|
-
data: [],
|
|
448
|
-
sessionId: this.sessionId,
|
|
449
|
-
windowId: this.windowId,
|
|
450
|
-
};
|
|
451
573
|
};
|
|
452
574
|
SessionRecording.prototype._captureSnapshotBuffered = function (properties) {
|
|
453
575
|
var _this = this;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionrecording.js","sourceRoot":"","sources":["../../../../src/extensions/replay/sessionrecording.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE,\n SESSION_RECORDING_ENABLED_SERVER_SIDE,\n SESSION_RECORDING_IS_SAMPLED,\n SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE,\n} from '../../constants'\nimport {\n ensureMaxMessageSize,\n FULL_SNAPSHOT_EVENT_TYPE,\n INCREMENTAL_SNAPSHOT_EVENT_TYPE,\n META_EVENT_TYPE,\n MutationRateLimiter,\n recordOptions,\n rrwebRecord,\n truncateLargeConsoleLogs,\n} from './sessionrecording-utils'\nimport { PostHog } from '../../posthog-core'\nimport { DecideResponse, NetworkRequest, Properties } from '../../types'\nimport { EventType, type eventWithTime, type listenerHandler } from '@rrweb/types'\nimport Config from '../../config'\nimport {\n _isBoolean,\n _isNull,\n _isNumber,\n _isObject,\n _isString,\n _isUndefined,\n _timestamp,\n loadScript,\n logger,\n} from '../../utils'\n\nconst BASE_ENDPOINT = '/s/'\n\nexport const RECORDING_IDLE_ACTIVITY_TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes\nexport const TEN_MINUTES_IN_MS = 10 * 60 * 1000\nexport const RECORDING_MAX_EVENT_SIZE = 1024 * 1024 * 0.9 // ~1mb (with some wiggle room)\nexport const RECORDING_BUFFER_TIMEOUT = 2000 // 2 seconds\nexport const SESSION_RECORDING_BATCH_KEY = 'recordings'\n\n// NOTE: Importing this type is problematic as we can't safely bundle it to a TS definition so, instead we redefine.\n// import type { record } from 'rrweb2/typings'\n// import type { recordOptions } from 'rrweb/typings/types'\n\n// Copied from rrweb typings to avoid import\nenum IncrementalSource {\n Mutation = 0,\n MouseMove = 1,\n MouseInteraction = 2,\n Scroll = 3,\n ViewportResize = 4,\n Input = 5,\n TouchMove = 6,\n MediaInteraction = 7,\n StyleSheetRule = 8,\n CanvasMutation = 9,\n Font = 10,\n Log = 11,\n Drag = 12,\n StyleDeclaration = 13,\n Selection = 14,\n AdoptedStyleSheet = 15,\n}\n\nconst ACTIVE_SOURCES = [\n IncrementalSource.MouseMove,\n IncrementalSource.MouseInteraction,\n IncrementalSource.Scroll,\n IncrementalSource.ViewportResize,\n IncrementalSource.Input,\n IncrementalSource.TouchMove,\n IncrementalSource.MediaInteraction,\n IncrementalSource.Drag,\n]\n\n/**\n * Session recording starts in buffering mode while waiting for decide response\n * Once the response is received it might be disabled, active or sampled\n * When sampled that means a sample rate is set and the last time the session id was rotated\n * the sample rate determined this session should be sent to the server.\n */\ntype SessionRecordingStatus = 'disabled' | 'sampled' | 'active' | 'buffering'\n\ninterface SnapshotBuffer {\n size: number\n data: any[]\n sessionId: string | null\n windowId: string | null\n}\n\nexport class SessionRecording {\n private _linkedFlagSeen: boolean = false\n private instance: PostHog\n private _endpoint: string\n private windowId: string | null\n private sessionId: string | null\n private _lastActivityTimestamp: number = Date.now()\n private flushBufferTimer?: any\n private buffer?: SnapshotBuffer\n private mutationRateLimiter?: MutationRateLimiter\n private _captureStarted: boolean\n private stopRrweb: listenerHandler | undefined\n private receivedDecide: boolean\n private rrwebRecord: rrwebRecord | undefined\n private isIdle = false\n private _linkedFlag: string | null = null\n private _sampleRate: number | null = null\n private _minimumDuration: number | null = null\n\n public get started(): boolean {\n // TODO could we use status instead of _captureStarted?\n return this._captureStarted\n }\n\n private get sessionManager() {\n if (!this.instance.sessionManager) {\n logger.error('Session recording started without valid sessionManager')\n throw new Error('Session recording started without valid sessionManager. This is a bug.')\n }\n\n return this.instance.sessionManager\n }\n\n private get isSampled(): boolean | null {\n if (_isNumber(this._sampleRate)) {\n return this.instance.get_property(SESSION_RECORDING_IS_SAMPLED)\n } else {\n return null\n }\n }\n\n private get sessionDuration(): number | null {\n const mostRecentSnapshot = this.buffer?.data[this.buffer?.data.length - 1]\n const { sessionStartTimestamp } = this.sessionManager.checkAndGetSessionAndWindowId(true)\n return mostRecentSnapshot ? mostRecentSnapshot.timestamp - sessionStartTimestamp : null\n }\n\n private get isRecordingEnabled() {\n const enabled_server_side = !!this.instance.get_property(SESSION_RECORDING_ENABLED_SERVER_SIDE)\n const enabled_client_side = !this.instance.config.disable_session_recording\n return enabled_server_side && enabled_client_side\n }\n\n private get isConsoleLogCaptureEnabled() {\n const enabled_server_side = !!this.instance.get_property(CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE)\n const enabled_client_side = this.instance.config.enable_recording_console_log\n return enabled_client_side ?? enabled_server_side\n }\n\n private get recordingVersion() {\n const recordingVersion_server_side = this.instance.get_property(SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE)\n const recordingVersion_client_side = this.instance.config.session_recording?.recorderVersion\n return recordingVersion_client_side || recordingVersion_server_side || 'v1'\n }\n\n /**\n * defaults to buffering mode until a decide response is received\n * once a decide response is received status can be disabled, active or sampled\n */\n private get status(): SessionRecordingStatus {\n if (!this.receivedDecide) {\n return 'buffering'\n }\n\n if (!this.isRecordingEnabled) {\n return 'disabled'\n }\n\n if (_isString(this._linkedFlag) && !this._linkedFlagSeen) {\n return 'buffering'\n }\n\n if (_isBoolean(this.isSampled)) {\n return this.isSampled ? 'sampled' : 'disabled'\n } else {\n return 'active'\n }\n }\n\n constructor(instance: PostHog) {\n this.instance = instance\n this._captureStarted = false\n this._endpoint = BASE_ENDPOINT\n this.stopRrweb = undefined\n this.receivedDecide = false\n\n window.addEventListener('beforeunload', () => {\n this._flushBuffer()\n })\n\n if (!this.instance.sessionManager) {\n logger.error('Session recording started without valid sessionManager')\n throw new Error('Session recording started without valid sessionManager. This is a bug.')\n }\n\n const { sessionId, windowId } = this.sessionManager.checkAndGetSessionAndWindowId(true)\n this.windowId = windowId\n this.sessionId = sessionId\n\n this.buffer = this.clearBuffer()\n }\n\n startRecordingIfEnabled() {\n if (this.isRecordingEnabled) {\n this.startCaptureAndTrySendingQueuedSnapshots()\n } else {\n this.stopRecording()\n this.clearBuffer()\n }\n }\n\n stopRecording() {\n if (this._captureStarted && this.stopRrweb) {\n this.stopRrweb()\n this.stopRrweb = undefined\n this._captureStarted = false\n }\n }\n\n private makeSamplingDecision(sessionId: string): void {\n const sessionIdChanged = this.sessionId !== sessionId\n\n if (!_isNumber(this._sampleRate)) {\n this.instance.persistence?.register({\n [SESSION_RECORDING_IS_SAMPLED]: null,\n })\n return\n }\n\n const storedIsSampled = this.isSampled\n\n /**\n * if we get this far then we should make a sampling decision.\n * When the session id changes or there is no stored sampling decision for this session id\n * then we should make a new decision.\n *\n * Otherwise, we should use the stored decision.\n */\n let shouldSample: boolean\n if (sessionIdChanged || !_isBoolean(storedIsSampled)) {\n const randomNumber = Math.random()\n shouldSample = randomNumber < this._sampleRate\n } else {\n shouldSample = storedIsSampled\n }\n\n if (!shouldSample) {\n logger.warn(\n `[SessionSampling] Sample rate (${this._sampleRate}) has determined that this sessionId (${sessionId}) will not be sent to the server.`\n )\n }\n\n this.instance.persistence?.register({\n [SESSION_RECORDING_IS_SAMPLED]: shouldSample,\n })\n }\n\n afterDecideResponse(response: DecideResponse) {\n if (this.instance.persistence) {\n this.instance.persistence.register({\n [SESSION_RECORDING_ENABLED_SERVER_SIDE]: !!response['sessionRecording'],\n [CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE]: response.sessionRecording?.consoleLogRecordingEnabled,\n [SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE]: response.sessionRecording?.recorderVersion,\n })\n }\n\n const receivedSampleRate = response.sessionRecording?.sampleRate\n this._sampleRate =\n _isUndefined(receivedSampleRate) || _isNull(receivedSampleRate) ? null : parseFloat(receivedSampleRate)\n\n const receivedMinimumDuration = response.sessionRecording?.minimumDurationMilliseconds\n this._minimumDuration = _isUndefined(receivedMinimumDuration) ? null : receivedMinimumDuration\n\n this._linkedFlag = response.sessionRecording?.linkedFlag || null\n\n if (response.sessionRecording?.endpoint) {\n this._endpoint = response.sessionRecording?.endpoint\n }\n\n if (_isNumber(this._sampleRate)) {\n this.sessionManager.onSessionId((sessionId) => {\n this.makeSamplingDecision(sessionId)\n })\n }\n\n if (_isString(this._linkedFlag)) {\n const linkedFlag = this._linkedFlag\n this.instance.onFeatureFlags((flags) => {\n this._linkedFlagSeen = flags.includes(linkedFlag)\n })\n }\n\n this.receivedDecide = true\n this.startRecordingIfEnabled()\n }\n\n log(message: string, level: 'log' | 'warn' | 'error' = 'log') {\n this.instance.sessionRecording?.onRRwebEmit({\n type: 6,\n data: {\n plugin: 'rrweb/console@1',\n payload: {\n level,\n trace: [],\n // Even though it is a string we stringify it as that's what rrweb expects\n payload: [JSON.stringify(message)],\n },\n },\n timestamp: _timestamp(),\n })\n }\n\n private startCaptureAndTrySendingQueuedSnapshots() {\n this._startCapture()\n }\n\n private _startCapture() {\n if (_isUndefined(Object.assign)) {\n // According to the rrweb docs, rrweb is not supported on IE11 and below:\n // \"rrweb does not support IE11 and below because it uses the MutationObserver API which was supported by these browsers.\"\n // https://github.com/rrweb-io/rrweb/blob/master/guide.md#compatibility-note\n //\n // However, MutationObserver does exist on IE11, it just doesn't work well and does not detect all changes.\n // Instead, when we load \"recorder.js\", the first JS error is about \"Object.assign\" being undefined.\n // Thus instead of MutationObserver, we look for this function and block recording if it's undefined.\n return\n }\n\n // We do not switch recorder versions midway through a recording.\n if (this._captureStarted || this.instance.config.disable_session_recording) {\n return\n }\n\n this._captureStarted = true\n // We want to ensure the sessionManager is reset if necessary on load of the recorder\n this.sessionManager.checkAndGetSessionAndWindowId()\n\n const recorderJS = this.recordingVersion === 'v2' ? 'recorder-v2.js' : 'recorder.js'\n\n // If recorder.js is already loaded (if array.full.js snippet is used or posthog-js/dist/recorder is\n // imported) or matches the requested recorder version, don't load script. Otherwise, remotely import\n // recorder.js from cdn since it hasn't been loaded.\n if (this.instance.__loaded_recorder_version !== this.recordingVersion) {\n loadScript(this.instance.config.api_host + `/static/${recorderJS}?v=${Config.LIB_VERSION}`, (err) => {\n if (err) {\n return logger.error(`Could not load ${recorderJS}`, err)\n }\n\n this._onScriptLoaded()\n })\n } else {\n this._onScriptLoaded()\n }\n }\n\n private _isInteractiveEvent(event: eventWithTime) {\n return event.type === INCREMENTAL_SNAPSHOT_EVENT_TYPE && ACTIVE_SOURCES.indexOf(event.data?.source) !== -1\n }\n\n private _updateWindowAndSessionIds(event: eventWithTime) {\n // Some recording events are triggered by non-user events (e.g. \"X minutes ago\" text updating on the screen).\n // We don't want to extend the session or trigger a new session in these cases. These events are designated by event\n // type -> incremental update, and source -> mutation.\n\n const isUserInteraction = this._isInteractiveEvent(event)\n\n if (!isUserInteraction && !this.isIdle) {\n // We check if the lastActivityTimestamp is old enough to go idle\n if (event.timestamp - this._lastActivityTimestamp > RECORDING_IDLE_ACTIVITY_TIMEOUT_MS) {\n this.isIdle = true\n }\n }\n\n if (isUserInteraction) {\n this._lastActivityTimestamp = event.timestamp\n if (this.isIdle) {\n // Remove the idle state if set and trigger a full snapshot as we will have ignored previous mutations\n this.isIdle = false\n this._tryTakeFullSnapshot()\n }\n }\n\n if (this.isIdle) {\n return\n }\n\n // We only want to extend the session if it is an interactive event.\n const { windowId, sessionId } = this.sessionManager.checkAndGetSessionAndWindowId(\n !isUserInteraction,\n event.timestamp\n )\n\n const sessionIdChanged = this.sessionId !== sessionId\n const windowIdChanged = this.windowId !== windowId\n this.windowId = windowId\n this.sessionId = sessionId\n\n if (\n [FULL_SNAPSHOT_EVENT_TYPE, META_EVENT_TYPE].indexOf(event.type) === -1 &&\n (windowIdChanged || sessionIdChanged)\n ) {\n this._tryTakeFullSnapshot()\n }\n }\n\n private _tryTakeFullSnapshot(): boolean {\n // TODO this should ignore based on emit?\n if (!this._captureStarted) {\n return false\n }\n try {\n this.rrwebRecord?.takeFullSnapshot()\n return true\n } catch (e) {\n // Sometimes a race can occur where the recorder is not fully started yet, so we can't take a full snapshot.\n logger.error('Error taking full snapshot.', e)\n return false\n }\n }\n\n private _onScriptLoaded() {\n // rrweb config info: https://github.com/rrweb-io/rrweb/blob/7d5d0033258d6c29599fb08412202d9a2c7b9413/src/record/index.ts#L28\n const sessionRecordingOptions: recordOptions<eventWithTime> = {\n // select set of rrweb config options we expose to our users\n // see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n blockClass: 'ph-no-capture',\n blockSelector: undefined,\n ignoreClass: 'ph-ignore-input',\n maskTextClass: 'ph-mask',\n maskTextSelector: undefined,\n maskTextFn: undefined,\n maskAllInputs: true,\n maskInputOptions: {},\n maskInputFn: undefined,\n slimDOMOptions: {},\n collectFonts: false,\n inlineStylesheet: true,\n recordCrossOriginIframes: false,\n //take a full snapshot after every N ms\n checkoutEveryNms: TEN_MINUTES_IN_MS,\n }\n // We switched from loading all of rrweb to just the record part, but\n // keep backwards compatibility if someone hasn't upgraded PostHog\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n this.rrwebRecord = window.rrweb ? window.rrweb.record : window.rrwebRecord\n\n // only allows user to set our allow-listed options\n const userSessionRecordingOptions = this.instance.config.session_recording\n for (const [key, value] of Object.entries(userSessionRecordingOptions || {})) {\n if (key in sessionRecordingOptions) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n sessionRecordingOptions[key] = value\n }\n }\n\n if (!this.rrwebRecord) {\n logger.error(\n 'onScriptLoaded was called but rrwebRecord is not available. This indicates something has gone wrong.'\n )\n return\n }\n\n this.mutationRateLimiter =\n this.mutationRateLimiter ??\n new MutationRateLimiter(this.rrwebRecord, {\n onBlockedNode: (id, node) => {\n const message = `Too many mutations on node '${id}'. Rate limiting. This could be due to SVG animations or something similar`\n logger.info(message, {\n node: node,\n })\n\n this.log('[PostHog Recorder] ' + message, 'warn')\n },\n })\n\n this.stopRrweb = this.rrwebRecord({\n emit: (event) => {\n this.onRRwebEmit(event)\n },\n plugins:\n (window as any).rrwebConsoleRecord && this.isConsoleLogCaptureEnabled\n ? [(window as any).rrwebConsoleRecord.getRecordConsolePlugin()]\n : [],\n ...sessionRecordingOptions,\n })\n\n // :TRICKY: rrweb does not capture navigation within SPA-s, so hook into our $pageview events to get access to all events.\n // Dropping the initial event is fine (it's always captured by rrweb).\n this.instance._addCaptureHook((eventName) => {\n // If anything could go wrong here it has the potential to block the main loop,\n // so we catch all errors.\n try {\n if (eventName === '$pageview') {\n const href = this._maskUrl(window.location.href)\n if (!href) {\n return\n }\n this.rrwebRecord?.addCustomEvent('$pageview', { href })\n }\n } catch (e) {\n logger.error('Could not add $pageview to rrweb session', e)\n }\n })\n\n // We reset the last activity timestamp, resetting the idle timer\n this._lastActivityTimestamp = Date.now()\n this.isIdle = false\n }\n\n onRRwebEmit(rawEvent: eventWithTime) {\n if (!rawEvent || !_isObject(rawEvent)) {\n return\n }\n\n if (rawEvent.type === EventType.Meta) {\n const href = this._maskUrl(rawEvent.data.href)\n if (!href) {\n return\n }\n rawEvent.data.href = href\n }\n\n const throttledEvent = this.mutationRateLimiter\n ? this.mutationRateLimiter.throttleMutations(rawEvent)\n : rawEvent\n\n if (!throttledEvent) {\n return\n }\n\n const { event, size } = ensureMaxMessageSize(truncateLargeConsoleLogs(throttledEvent))\n\n const properties = {\n $snapshot_bytes: size,\n $snapshot_data: event,\n $session_id: this.sessionId,\n $window_id: this.windowId,\n }\n\n this._updateWindowAndSessionIds(event)\n\n if (this.isIdle) {\n // When in an idle state we keep recording, but don't capture the events\n return\n }\n\n if (this.status !== 'disabled') {\n this._captureSnapshotBuffered(properties)\n } else {\n this.clearBuffer()\n }\n }\n\n private _maskUrl(url: string): string | undefined {\n const userSessionRecordingOptions = this.instance.config.session_recording\n\n if (userSessionRecordingOptions.maskNetworkRequestFn) {\n let networkRequest: NetworkRequest | null | undefined = {\n url,\n }\n\n networkRequest = userSessionRecordingOptions.maskNetworkRequestFn(networkRequest)\n\n return networkRequest?.url\n }\n\n return url\n }\n\n private clearBuffer(): SnapshotBuffer {\n this.buffer = undefined\n\n return {\n size: 0,\n data: [],\n sessionId: this.sessionId,\n windowId: this.windowId,\n }\n }\n\n // the intention is a buffer that (currently) is used only after a decide response enables session recording\n // it is called ever X seconds using the flushBufferTimer so that we don't have to wait for the buffer to fill up\n // when it is called on a timer it assumes that it can definitely flush\n // it is flushed when the session id changes or the size of the buffered data gets too great (1mb by default)\n // first change: if the recording is in buffering mode,\n // flush buffer simply resets the timer and returns the existing flush buffer\n private _flushBuffer() {\n if (this.flushBufferTimer) {\n clearTimeout(this.flushBufferTimer)\n this.flushBufferTimer = undefined\n }\n\n const minimumDuration = this._minimumDuration\n const sessionDuration = this.sessionDuration\n const isBelowMinimumDuration =\n _isNumber(minimumDuration) && _isNumber(sessionDuration) && sessionDuration < minimumDuration\n\n if (this.status === 'buffering' || isBelowMinimumDuration) {\n this.flushBufferTimer = setTimeout(() => {\n this._flushBuffer()\n }, RECORDING_BUFFER_TIMEOUT)\n return this.buffer || this.clearBuffer()\n }\n\n if (this.buffer && this.buffer.data.length !== 0) {\n this._captureSnapshot({\n $snapshot_bytes: this.buffer.size,\n $snapshot_data: this.buffer.data,\n $session_id: this.buffer.sessionId,\n $window_id: this.buffer.windowId,\n })\n\n return this.clearBuffer()\n } else {\n return this.buffer || this.clearBuffer()\n }\n }\n\n private _captureSnapshotBuffered(properties: Properties) {\n const additionalBytes = 2 + (this.buffer?.data.length || 0) // 2 bytes for the array brackets and 1 byte for each comma\n if (\n !this.buffer ||\n this.buffer.size + properties.$snapshot_bytes + additionalBytes > RECORDING_MAX_EVENT_SIZE ||\n this.buffer.sessionId !== this.sessionId\n ) {\n this.buffer = this._flushBuffer()\n }\n\n this.buffer.size += properties.$snapshot_bytes\n this.buffer.data.push(properties.$snapshot_data)\n\n if (!this.flushBufferTimer) {\n this.flushBufferTimer = setTimeout(() => {\n this._flushBuffer()\n }, RECORDING_BUFFER_TIMEOUT)\n }\n }\n\n private _captureSnapshot(properties: Properties) {\n // :TRICKY: Make sure we batch these requests, use a custom endpoint and don't truncate the strings.\n this.instance.capture('$snapshot', properties, {\n transport: 'XHR',\n method: 'POST',\n endpoint: this._endpoint,\n _noTruncate: true,\n _batchKey: SESSION_RECORDING_BATCH_KEY,\n _metrics: {\n rrweb_full_snapshot: properties.$snapshot_data.type === FULL_SNAPSHOT_EVENT_TYPE,\n },\n })\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PostHog } from '
|
|
2
|
-
import { DecideResponse } from '
|
|
1
|
+
import { PostHog } from '../../posthog-core';
|
|
2
|
+
import { DecideResponse } from '../../types';
|
|
3
3
|
export declare class WebPerformanceObserver {
|
|
4
4
|
instance: PostHog;
|
|
5
5
|
remoteEnabled: boolean | undefined;
|
|
@@ -9,7 +9,7 @@ var __values = (this && this.__values) || function(o) {
|
|
|
9
9
|
};
|
|
10
10
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
11
11
|
};
|
|
12
|
-
import { isLocalhost, logger } from '
|
|
12
|
+
import { _isUndefined, isLocalhost, logger } from '../../utils';
|
|
13
13
|
var PERFORMANCE_EVENTS_MAPPING = {
|
|
14
14
|
// BASE_PERFORMANCE_EVENT_COLUMNS
|
|
15
15
|
entryType: 0,
|
|
@@ -95,7 +95,7 @@ var WebPerformanceObserver = /** @class */ (function () {
|
|
|
95
95
|
if (this.observer) {
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
|
-
if (((_a = window === null || window === void 0 ? void 0 : window.PerformanceObserver) === null || _a === void 0 ? void 0 : _a.supportedEntryTypes)
|
|
98
|
+
if (_isUndefined((_a = window === null || window === void 0 ? void 0 : window.PerformanceObserver) === null || _a === void 0 ? void 0 : _a.supportedEntryTypes)) {
|
|
99
99
|
logger.info('[PerformanceObserver] not started because PerformanceObserver is not supported by this browser.');
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
@@ -177,7 +177,7 @@ var WebPerformanceObserver = /** @class */ (function () {
|
|
|
177
177
|
// (in this case representing fractions of a millisecond we don't care about anyway)
|
|
178
178
|
properties[PERFORMANCE_EVENTS_MAPPING['timestamp']] = Math.floor(timeOrigin + event.startTime);
|
|
179
179
|
for (var key in PERFORMANCE_EVENTS_MAPPING) {
|
|
180
|
-
if (eventJson[key]
|
|
180
|
+
if (!_isUndefined(eventJson[key])) {
|
|
181
181
|
properties[PERFORMANCE_EVENTS_MAPPING[key]] = eventJson[key];
|
|
182
182
|
}
|
|
183
183
|
}
|