posthog-js 1.84.2 → 1.84.4

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.
Files changed (77) hide show
  1. package/dist/array.full.js +1 -10
  2. package/dist/array.full.js.map +1 -1
  3. package/dist/array.js +1 -10
  4. package/dist/array.js.map +1 -1
  5. package/dist/es.js +1 -10
  6. package/dist/es.js.map +1 -1
  7. package/dist/module.d.ts +32 -148
  8. package/dist/module.js +1 -10
  9. package/dist/module.js.map +1 -1
  10. package/dist/recorder-v2.js +2 -2
  11. package/dist/recorder-v2.js.map +1 -1
  12. package/dist/recorder.js +1 -1
  13. package/dist/recorder.js.map +1 -1
  14. package/dist/surveys.js +1 -1
  15. package/dist/surveys.js.map +1 -1
  16. package/lib/package.json +9 -4
  17. package/lib/src/autocapture-utils.js +6 -6
  18. package/lib/src/autocapture-utils.js.map +1 -1
  19. package/lib/src/autocapture.js +5 -5
  20. package/lib/src/autocapture.js.map +1 -1
  21. package/lib/src/constants.d.ts +1 -0
  22. package/lib/src/constants.js +1 -0
  23. package/lib/src/constants.js.map +1 -1
  24. package/lib/src/extensions/exceptions/error-conversion.js +3 -2
  25. package/lib/src/extensions/exceptions/error-conversion.js.map +1 -1
  26. package/lib/src/extensions/exceptions/exception-autocapture.js +4 -7
  27. package/lib/src/extensions/exceptions/exception-autocapture.js.map +1 -1
  28. package/lib/src/extensions/exceptions/stack-trace.js +3 -2
  29. package/lib/src/extensions/exceptions/stack-trace.js.map +1 -1
  30. package/lib/src/extensions/exceptions/type-checking.js +3 -2
  31. package/lib/src/extensions/exceptions/type-checking.js.map +1 -1
  32. package/lib/src/extensions/{sessionrecording-utils.js → replay/sessionrecording-utils.js} +3 -2
  33. package/lib/src/extensions/replay/sessionrecording-utils.js.map +1 -0
  34. package/lib/src/extensions/{sessionrecording.d.ts → replay/sessionrecording.d.ts} +27 -19
  35. package/lib/src/extensions/{sessionrecording.js → replay/sessionrecording.js} +217 -92
  36. package/lib/src/extensions/replay/sessionrecording.js.map +1 -0
  37. package/lib/src/extensions/{web-performance.d.ts → replay/web-performance.d.ts} +2 -2
  38. package/lib/src/extensions/{web-performance.js → replay/web-performance.js} +3 -3
  39. package/lib/src/extensions/replay/web-performance.js.map +1 -0
  40. package/lib/src/extensions/surveys.js +3 -2
  41. package/lib/src/extensions/surveys.js.map +1 -1
  42. package/lib/src/loader-recorder-v2.js +2 -3
  43. package/lib/src/loader-recorder-v2.js.map +1 -1
  44. package/lib/src/loader-recorder.js +2 -1
  45. package/lib/src/loader-recorder.js.map +1 -1
  46. package/lib/src/loader-surveys.js +2 -1
  47. package/lib/src/loader-surveys.js.map +1 -1
  48. package/lib/src/posthog-core.d.ts +2 -2
  49. package/lib/src/posthog-core.js +14 -14
  50. package/lib/src/posthog-core.js.map +1 -1
  51. package/lib/src/posthog-featureflags.js +4 -4
  52. package/lib/src/posthog-featureflags.js.map +1 -1
  53. package/lib/src/posthog-persistence.js +4 -4
  54. package/lib/src/posthog-persistence.js.map +1 -1
  55. package/lib/src/request-queue.js +2 -2
  56. package/lib/src/request-queue.js.map +1 -1
  57. package/lib/src/retry-queue.js +7 -3
  58. package/lib/src/retry-queue.js.map +1 -1
  59. package/lib/src/send-request.js +3 -3
  60. package/lib/src/send-request.js.map +1 -1
  61. package/lib/src/sessionid.d.ts +6 -4
  62. package/lib/src/sessionid.js +17 -15
  63. package/lib/src/sessionid.js.map +1 -1
  64. package/lib/src/storage.js +7 -7
  65. package/lib/src/storage.js.map +1 -1
  66. package/lib/src/types.d.ts +3 -0
  67. package/lib/src/types.js.map +1 -1
  68. package/lib/src/utils.d.ts +8 -10
  69. package/lib/src/utils.js +42 -31
  70. package/lib/src/utils.js.map +1 -1
  71. package/lib/src/uuidv7.js +6 -4
  72. package/lib/src/uuidv7.js.map +1 -1
  73. package/package.json +9 -4
  74. package/lib/src/extensions/sessionrecording-utils.js.map +0 -1
  75. package/lib/src/extensions/sessionrecording.js.map +0 -1
  76. package/lib/src/extensions/web-performance.js.map +0 -1
  77. /package/lib/src/extensions/{sessionrecording-utils.d.ts → replay/sessionrecording-utils.d.ts} +0 -0
@@ -36,13 +36,14 @@ 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 '../constants';
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 '../config';
43
- import { logger, loadScript, _timestamp, window } from '../utils';
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
+ export var TEN_MINUTES_IN_MS = 10 * 60 * 1000;
46
47
  export var RECORDING_MAX_EVENT_SIZE = 1024 * 1024 * 0.9; // ~1mb (with some wiggle room)
47
48
  export var RECORDING_BUFFER_TIMEOUT = 2000; // 2 seconds
48
49
  export var SESSION_RECORDING_BATCH_KEY = 'recordings';
@@ -82,80 +83,176 @@ var ACTIVE_SOURCES = [
82
83
  var SessionRecording = /** @class */ (function () {
83
84
  function SessionRecording(instance) {
84
85
  var _this = this;
86
+ this._linkedFlagSeen = false;
85
87
  this._lastActivityTimestamp = Date.now();
86
88
  this.isIdle = false;
89
+ this._linkedFlag = null;
90
+ this._sampleRate = null;
91
+ this._minimumDuration = null;
87
92
  this.instance = instance;
88
- this.captureStarted = false;
89
- this.snapshots = [];
90
- this.emit = false; // Controls whether data is sent to the server or not
93
+ this._captureStarted = false;
91
94
  this._endpoint = BASE_ENDPOINT;
92
95
  this.stopRrweb = undefined;
93
- this.windowId = null;
94
- this.sessionId = null;
95
96
  this.receivedDecide = false;
96
97
  window.addEventListener('beforeunload', function () {
97
98
  _this._flushBuffer();
98
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();
99
108
  }
100
- Object.defineProperty(SessionRecording.prototype, "lastActivityTimestamp", {
109
+ Object.defineProperty(SessionRecording.prototype, "started", {
101
110
  get: function () {
102
- return this._lastActivityTimestamp;
111
+ // TODO could we use status instead of _captureStarted?
112
+ return this._captureStarted;
103
113
  },
104
114
  enumerable: false,
105
115
  configurable: true
106
116
  });
107
- Object.defineProperty(SessionRecording.prototype, "endpoint", {
117
+ Object.defineProperty(SessionRecording.prototype, "sessionManager", {
108
118
  get: function () {
109
- return this._endpoint;
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
+ }
110
199
  },
111
200
  enumerable: false,
112
201
  configurable: true
113
202
  });
114
- SessionRecording.prototype.getSessionManager = function () {
115
- if (!this.instance.sessionManager) {
116
- logger.error('Session recording started without valid sessionManager');
117
- return;
118
- }
119
- return this.instance.sessionManager;
120
- };
121
203
  SessionRecording.prototype.startRecordingIfEnabled = function () {
122
- if (this.isRecordingEnabled()) {
204
+ if (this.isRecordingEnabled) {
123
205
  this.startCaptureAndTrySendingQueuedSnapshots();
124
206
  }
125
207
  else {
126
208
  this.stopRecording();
209
+ this.clearBuffer();
127
210
  }
128
211
  };
129
- SessionRecording.prototype.started = function () {
130
- return this.captureStarted;
131
- };
132
212
  SessionRecording.prototype.stopRecording = function () {
133
- if (this.captureStarted && this.stopRrweb) {
213
+ if (this._captureStarted && this.stopRrweb) {
134
214
  this.stopRrweb();
135
215
  this.stopRrweb = undefined;
136
- this.captureStarted = false;
216
+ this._captureStarted = false;
137
217
  }
138
218
  };
139
- SessionRecording.prototype.isRecordingEnabled = function () {
140
- var enabled_server_side = !!this.instance.get_property(SESSION_RECORDING_ENABLED_SERVER_SIDE);
141
- var enabled_client_side = !this.instance.config.disable_session_recording;
142
- return enabled_server_side && enabled_client_side;
143
- };
144
- SessionRecording.prototype.isConsoleLogCaptureEnabled = function () {
145
- var enabled_server_side = !!this.instance.get_property(CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE);
146
- var enabled_client_side = this.instance.config.enable_recording_console_log;
147
- return enabled_client_side !== null && enabled_client_side !== void 0 ? enabled_client_side : enabled_server_side;
148
- };
149
- SessionRecording.prototype.getRecordingVersion = function () {
150
- var _a;
151
- var recordingVersion_server_side = this.instance.get_property(SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE);
152
- var recordingVersion_client_side = (_a = this.instance.config.session_recording) === null || _a === void 0 ? void 0 : _a.recorderVersion;
153
- return recordingVersion_client_side || recordingVersion_server_side || 'v1';
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));
154
251
  };
155
252
  SessionRecording.prototype.afterDecideResponse = function (response) {
156
253
  var _a;
157
- var _b, _c, _d, _e, _f;
158
- this.receivedDecide = true;
254
+ var _this = this;
255
+ var _b, _c, _d, _e, _f, _g, _h;
159
256
  if (this.instance.persistence) {
160
257
  this.instance.persistence.register((_a = {},
161
258
  _a[SESSION_RECORDING_ENABLED_SERVER_SIDE] = !!response['sessionRecording'],
@@ -163,12 +260,27 @@ var SessionRecording = /** @class */ (function () {
163
260
  _a[SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE] = (_c = response.sessionRecording) === null || _c === void 0 ? void 0 : _c.recorderVersion,
164
261
  _a));
165
262
  }
166
- if ((_d = response.sessionRecording) === null || _d === void 0 ? void 0 : _d.endpoint) {
167
- this._endpoint = (_e = response.sessionRecording) === null || _e === void 0 ? void 0 : _e.endpoint;
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
+ });
168
276
  }
169
- if ((_f = response.sessionRecording) === null || _f === void 0 ? void 0 : _f.recorderVersion) {
170
- this.recorderVersion = response.sessionRecording.recorderVersion;
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
+ });
171
282
  }
283
+ this.receivedDecide = true;
172
284
  this.startRecordingIfEnabled();
173
285
  };
174
286
  SessionRecording.prototype.log = function (message, level) {
@@ -181,7 +293,7 @@ var SessionRecording = /** @class */ (function () {
181
293
  payload: {
182
294
  level: level,
183
295
  trace: [],
184
- // Even though it is a string we stringify it as thats what rrweb expects
296
+ // Even though it is a string we stringify it as that's what rrweb expects
185
297
  payload: [JSON.stringify(message)],
186
298
  },
187
299
  },
@@ -189,22 +301,11 @@ var SessionRecording = /** @class */ (function () {
189
301
  });
190
302
  };
191
303
  SessionRecording.prototype.startCaptureAndTrySendingQueuedSnapshots = function () {
192
- var _this = this;
193
- // Only submit data after we've received a decide response to account for
194
- // changing endpoints and the feature being disabled on the server side.
195
- if (this.receivedDecide) {
196
- this.emit = true;
197
- this.snapshots.forEach(function (properties) { return _this._captureSnapshotBuffered(properties); });
198
- }
199
304
  this._startCapture();
200
305
  };
201
306
  SessionRecording.prototype._startCapture = function () {
202
307
  var _this = this;
203
- var sessionManager = this.getSessionManager();
204
- if (!sessionManager) {
205
- return;
206
- }
207
- if (typeof Object.assign === 'undefined') {
308
+ if (_isUndefined(Object.assign)) {
208
309
  // According to the rrweb docs, rrweb is not supported on IE11 and below:
209
310
  // "rrweb does not support IE11 and below because it uses the MutationObserver API which was supported by these browsers."
210
311
  // https://github.com/rrweb-io/rrweb/blob/master/guide.md#compatibility-note
@@ -215,17 +316,17 @@ var SessionRecording = /** @class */ (function () {
215
316
  return;
216
317
  }
217
318
  // We do not switch recorder versions midway through a recording.
218
- if (this.captureStarted || this.instance.config.disable_session_recording) {
319
+ if (this._captureStarted || this.instance.config.disable_session_recording) {
219
320
  return;
220
321
  }
221
- this.captureStarted = true;
322
+ this._captureStarted = true;
222
323
  // We want to ensure the sessionManager is reset if necessary on load of the recorder
223
- sessionManager.checkAndGetSessionAndWindowId();
224
- var recorderJS = this.getRecordingVersion() === 'v2' ? 'recorder-v2.js' : 'recorder.js';
324
+ this.sessionManager.checkAndGetSessionAndWindowId();
325
+ var recorderJS = this.recordingVersion === 'v2' ? 'recorder-v2.js' : 'recorder.js';
225
326
  // If recorder.js is already loaded (if array.full.js snippet is used or posthog-js/dist/recorder is
226
327
  // imported) or matches the requested recorder version, don't load script. Otherwise, remotely import
227
328
  // recorder.js from cdn since it hasn't been loaded.
228
- if (this.instance.__loaded_recorder_version !== this.getRecordingVersion()) {
329
+ if (this.instance.__loaded_recorder_version !== this.recordingVersion) {
229
330
  loadScript(this.instance.config.api_host + "/static/".concat(recorderJS, "?v=").concat(Config.LIB_VERSION), function (err) {
230
331
  if (err) {
231
332
  return logger.error("Could not load ".concat(recorderJS), err);
@@ -242,10 +343,6 @@ var SessionRecording = /** @class */ (function () {
242
343
  return event.type === INCREMENTAL_SNAPSHOT_EVENT_TYPE && ACTIVE_SOURCES.indexOf((_a = event.data) === null || _a === void 0 ? void 0 : _a.source) !== -1;
243
344
  };
244
345
  SessionRecording.prototype._updateWindowAndSessionIds = function (event) {
245
- var sessionManager = this.getSessionManager();
246
- if (!sessionManager) {
247
- return;
248
- }
249
346
  // Some recording events are triggered by non-user events (e.g. "X minutes ago" text updating on the screen).
250
347
  // We don't want to extend the session or trigger a new session in these cases. These events are designated by event
251
348
  // type -> incremental update, and source -> mutation.
@@ -259,7 +356,7 @@ var SessionRecording = /** @class */ (function () {
259
356
  if (isUserInteraction) {
260
357
  this._lastActivityTimestamp = event.timestamp;
261
358
  if (this.isIdle) {
262
- // Remove the idle state if set and trigger a full snapshot as we will have ingored previous mutations
359
+ // Remove the idle state if set and trigger a full snapshot as we will have ignored previous mutations
263
360
  this.isIdle = false;
264
361
  this._tryTakeFullSnapshot();
265
362
  }
@@ -268,17 +365,20 @@ var SessionRecording = /** @class */ (function () {
268
365
  return;
269
366
  }
270
367
  // We only want to extend the session if it is an interactive event.
271
- 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;
272
373
  if ([FULL_SNAPSHOT_EVENT_TYPE, META_EVENT_TYPE].indexOf(event.type) === -1 &&
273
- (this.windowId !== windowId || this.sessionId !== sessionId)) {
374
+ (windowIdChanged || sessionIdChanged)) {
274
375
  this._tryTakeFullSnapshot();
275
376
  }
276
- this.windowId = windowId;
277
- this.sessionId = sessionId;
278
377
  };
279
378
  SessionRecording.prototype._tryTakeFullSnapshot = function () {
280
379
  var _a;
281
- if (!this.captureStarted) {
380
+ // TODO this should ignore based on emit?
381
+ if (!this._captureStarted) {
282
382
  return false;
283
383
  }
284
384
  try {
@@ -312,13 +412,15 @@ var SessionRecording = /** @class */ (function () {
312
412
  collectFonts: false,
313
413
  inlineStylesheet: true,
314
414
  recordCrossOriginIframes: false,
415
+ //take a full snapshot after every N ms
416
+ checkoutEveryNms: TEN_MINUTES_IN_MS,
315
417
  };
316
418
  // We switched from loading all of rrweb to just the record part, but
317
419
  // keep backwards compatibility if someone hasn't upgraded PostHog
318
420
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
319
421
  // @ts-ignore
320
422
  this.rrwebRecord = window.rrweb ? window.rrweb.record : window.rrwebRecord;
321
- // only allows user to set our 'allowlisted' options
423
+ // only allows user to set our allow-listed options
322
424
  var userSessionRecordingOptions = this.instance.config.session_recording;
323
425
  try {
324
426
  for (var _c = __values(Object.entries(userSessionRecordingOptions || {})), _d = _c.next(); !_d.done; _d = _c.next()) {
@@ -353,14 +455,15 @@ var SessionRecording = /** @class */ (function () {
353
455
  });
354
456
  this.stopRrweb = this.rrwebRecord(__assign({ emit: function (event) {
355
457
  _this.onRRwebEmit(event);
356
- }, plugins: window.rrwebConsoleRecord && this.isConsoleLogCaptureEnabled()
458
+ }, plugins: window.rrwebConsoleRecord && this.isConsoleLogCaptureEnabled
357
459
  ? [window.rrwebConsoleRecord.getRecordConsolePlugin()]
358
460
  : [] }, sessionRecordingOptions));
359
461
  // :TRICKY: rrweb does not capture navigation within SPA-s, so hook into our $pageview events to get access to all events.
360
462
  // Dropping the initial event is fine (it's always captured by rrweb).
361
463
  this.instance._addCaptureHook(function (eventName) {
362
464
  var _a;
363
- // If anything could go wrong here it has the potential to block the main loop so we catch all errors.
465
+ // If anything could go wrong here it has the potential to block the main loop,
466
+ // so we catch all errors.
364
467
  try {
365
468
  if (eventName === '$pageview') {
366
469
  var href = _this._maskUrl(window.location.href);
@@ -379,7 +482,7 @@ var SessionRecording = /** @class */ (function () {
379
482
  this.isIdle = false;
380
483
  };
381
484
  SessionRecording.prototype.onRRwebEmit = function (rawEvent) {
382
- if (!rawEvent || typeof rawEvent !== 'object') {
485
+ if (!rawEvent || !_isObject(rawEvent)) {
383
486
  return;
384
487
  }
385
488
  if (rawEvent.type === EventType.Meta) {
@@ -396,22 +499,22 @@ var SessionRecording = /** @class */ (function () {
396
499
  return;
397
500
  }
398
501
  var _a = ensureMaxMessageSize(truncateLargeConsoleLogs(throttledEvent)), event = _a.event, size = _a.size;
399
- this._updateWindowAndSessionIds(event);
400
- if (this.isIdle) {
401
- // When in an idle state we keep recording, but don't capture the events
402
- return;
403
- }
404
502
  var properties = {
405
503
  $snapshot_bytes: size,
406
504
  $snapshot_data: event,
407
505
  $session_id: this.sessionId,
408
506
  $window_id: this.windowId,
409
507
  };
410
- if (this.emit) {
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') {
411
514
  this._captureSnapshotBuffered(properties);
412
515
  }
413
516
  else {
414
- this.snapshots.push(properties);
517
+ this.clearBuffer();
415
518
  }
416
519
  };
417
520
  SessionRecording.prototype._maskUrl = function (url) {
@@ -425,11 +528,36 @@ var SessionRecording = /** @class */ (function () {
425
528
  }
426
529
  return url;
427
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
428
546
  SessionRecording.prototype._flushBuffer = function () {
547
+ var _this = this;
429
548
  if (this.flushBufferTimer) {
430
549
  clearTimeout(this.flushBufferTimer);
431
550
  this.flushBufferTimer = undefined;
432
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
+ }
433
561
  if (this.buffer && this.buffer.data.length !== 0) {
434
562
  this._captureSnapshot({
435
563
  $snapshot_bytes: this.buffer.size,
@@ -437,14 +565,11 @@ var SessionRecording = /** @class */ (function () {
437
565
  $session_id: this.buffer.sessionId,
438
566
  $window_id: this.buffer.windowId,
439
567
  });
568
+ return this.clearBuffer();
569
+ }
570
+ else {
571
+ return this.buffer || this.clearBuffer();
440
572
  }
441
- this.buffer = undefined;
442
- return {
443
- size: 0,
444
- data: [],
445
- sessionId: this.sessionId,
446
- windowId: this.windowId,
447
- };
448
573
  };
449
574
  SessionRecording.prototype._captureSnapshotBuffered = function (properties) {
450
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 '../posthog-core';
2
- import { DecideResponse } from '../types';
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 '../utils';
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) === undefined) {
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] !== undefined) {
180
+ if (!_isUndefined(eventJson[key])) {
181
181
  properties[PERFORMANCE_EVENTS_MAPPING[key]] = eventJson[key];
182
182
  }
183
183
  }