@multiplayer-app/session-recorder-browser 2.0.35 → 2.0.38

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.
@@ -25163,7 +25163,7 @@ const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
25163
25163
  const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
25164
25164
  const REMOTE_SESSION_RECORDING_START = 'remote-session-recording:start';
25165
25165
  const REMOTE_SESSION_RECORDING_STOP = 'remote-session-recording:stop';
25166
- const PACKAGE_VERSION_EXPORT = "2.0.35" || 0;
25166
+ const PACKAGE_VERSION_EXPORT = "2.0.38" || 0;
25167
25167
  // Regex patterns for OpenTelemetry ignore URLs
25168
25168
  const OTEL_IGNORE_URLS = [
25169
25169
  // Traces endpoint
@@ -27295,10 +27295,11 @@ __webpack_require__.r(__webpack_exports__);
27295
27295
 
27296
27296
 
27297
27297
  class CrashBufferService {
27298
- constructor(db, tabId, windowMs) {
27298
+ constructor(db, tabId, windowMs, ready = Promise.resolve()) {
27299
27299
  this.db = db;
27300
27300
  this.tabId = tabId;
27301
27301
  this.windowMs = windowMs;
27302
+ this.ready = ready;
27302
27303
  this.lastPruneAt = 0;
27303
27304
  this.pruneInFlight = null;
27304
27305
  this.isActive = true;
@@ -27321,6 +27322,7 @@ class CrashBufferService {
27321
27322
  if (!this.isActive)
27322
27323
  return;
27323
27324
  const isFullSnapshot = Boolean(payload.isFullSnapshot);
27325
+ await this.ready;
27324
27326
  await this._safe(async () => {
27325
27327
  await this.db.appendEvent({
27326
27328
  tabId: this.tabId,
@@ -27341,6 +27343,7 @@ class CrashBufferService {
27341
27343
  if (!this.isActive)
27342
27344
  return;
27343
27345
  let errorEvent = null;
27346
+ await this.ready;
27344
27347
  await this._safe(async () => {
27345
27348
  const records = payload.map((p) => {
27346
27349
  var _a, _b;
@@ -27389,6 +27392,7 @@ class CrashBufferService {
27389
27392
  }
27390
27393
  async snapshot(_windowMs, now = Date.now()) {
27391
27394
  var _a, _b;
27395
+ await this.ready;
27392
27396
  const stoppedAt = now;
27393
27397
  const startedAt = Math.max(0, stoppedAt - this.windowMs);
27394
27398
  // Always include a full snapshot "anchor" if one exists at/before the window start.
@@ -28029,6 +28033,8 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
28029
28033
  this.sessionId = null;
28030
28034
  this.usePostMessage = false;
28031
28035
  this.isInitialized = false;
28036
+ this.lastUserPayload = null;
28037
+ this.lastSubscribeSession = null;
28032
28038
  this.options = {
28033
28039
  apiKey: '',
28034
28040
  socketUrl: '',
@@ -28091,6 +28097,15 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
28091
28097
  this.isConnecting = false;
28092
28098
  this.isConnected = true;
28093
28099
  this.usePostMessage = false;
28100
+ // Re-establish identity and session on every (re)connect: socket.io's auto-reconnect
28101
+ // fires 'ready' again after a drop, but the server has no memory of the previous
28102
+ // setUser/subscribe calls — the client must replay them.
28103
+ if (this.lastUserPayload && this.socket) {
28104
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, this.lastUserPayload);
28105
+ }
28106
+ if (this.lastSubscribeSession) {
28107
+ this._emitSubscribe(this.lastSubscribeSession);
28108
+ }
28094
28109
  this.flushQueue();
28095
28110
  });
28096
28111
  this.socket.on('disconnect', (err) => {
@@ -28157,16 +28172,33 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
28157
28172
  this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_ADD_EVENT, event);
28158
28173
  }
28159
28174
  subscribeToSession(session) {
28175
+ // Remember the session so reconnects replay subscribe + started.
28176
+ this.lastSubscribeSession = session;
28177
+ this._emitSubscribe(session);
28178
+ }
28179
+ _emitSubscribe(session) {
28160
28180
  this.sessionId = session.shortId || session._id;
28161
- const payload = {
28181
+ const subscribePayload = {
28162
28182
  projectId: session.project,
28163
28183
  workspaceId: session.workspace,
28164
28184
  debugSessionId: this.sessionId,
28165
28185
  sessionType: session.creationType,
28166
28186
  };
28167
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, payload);
28168
- // use long id instead of short id
28169
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, { debugSessionId: session._id });
28187
+ const startedPayload = { debugSessionId: session._id };
28188
+ // Send directly (not via the queue). The queue would cause a duplicate emit on
28189
+ // the next 'ready' alongside the replay, since 'ready' also replays lastSubscribeSession.
28190
+ if (this.usePostMessage) {
28191
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
28192
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
28193
+ }
28194
+ else if (this.socket && this.isConnected) {
28195
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
28196
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
28197
+ }
28198
+ else {
28199
+ // Not connected: 'ready' will replay via lastSubscribeSession once the socket is up.
28200
+ this._initConnection();
28201
+ }
28170
28202
  }
28171
28203
  unsubscribeFromSession(stopSession) {
28172
28204
  if (this.sessionId) {
@@ -28175,9 +28207,23 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
28175
28207
  this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STOPPED_EVENT, {});
28176
28208
  }
28177
28209
  }
28210
+ this.lastSubscribeSession = null;
28178
28211
  }
28179
28212
  setUser(data) {
28180
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
28213
+ // Remember the last identity so 'ready' (initial connect + every reconnect) can replay it.
28214
+ // Send directly here rather than queuing: the queue would cause a duplicate emit on the
28215
+ // next 'ready' alongside the replay.
28216
+ this.lastUserPayload = data;
28217
+ if (this.usePostMessage) {
28218
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
28219
+ }
28220
+ else if (this.socket && this.isConnected) {
28221
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
28222
+ }
28223
+ else {
28224
+ // Not connected yet: 'ready' will replay lastUserPayload once the socket is up.
28225
+ this._initConnection();
28226
+ }
28181
28227
  }
28182
28228
  close() {
28183
28229
  return new Promise((resolve) => {
@@ -28420,13 +28466,11 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
28420
28466
  this._start();
28421
28467
  }
28422
28468
  else {
28423
- // Buffer-only recording when there is no active debug session.
28424
28469
  this._startBufferOnlyRecording();
28425
28470
  }
28426
28471
  this._registerWidgetEvents();
28427
28472
  this._registerSocketServiceListeners();
28428
28473
  _services_messaging_service__WEBPACK_IMPORTED_MODULE_9__["default"].sendMessage('state-change', this.sessionState);
28429
- // Emit init observable event
28430
28474
  this.emit('init', [this]);
28431
28475
  }
28432
28476
  _setupCrashBuffer() {
@@ -28434,7 +28478,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
28434
28478
  if ((_a = this._configs.buffering) === null || _a === void 0 ? void 0 : _a.enabled) {
28435
28479
  const windowMinutes = this._configs.buffering.windowMinutes || 0.5;
28436
28480
  const windowMs = Math.max(10000, windowMinutes * 60 * 1000);
28437
- this._crashBuffer = new _services_crashBuffer_service__WEBPACK_IMPORTED_MODULE_13__.CrashBufferService(this._bufferDb, this._tabId, windowMs);
28481
+ const ready = this._bufferDb.clearTab(this._tabId).catch(() => undefined);
28482
+ this._crashBuffer = new _services_crashBuffer_service__WEBPACK_IMPORTED_MODULE_13__.CrashBufferService(this._bufferDb, this._tabId, windowMs, ready);
28438
28483
  this._recorder.setCrashBuffer(this._crashBuffer);
28439
28484
  this._tracer.setCrashBuffer(this._crashBuffer);
28440
28485
  this._crashBuffer.on('error-span-appended', (payload) => {
@@ -28668,12 +28713,7 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
28668
28713
  }
28669
28714
  }
28670
28715
  async _flushBuffer(sessionId) {
28671
- var _a, _b;
28672
- if (!sessionId ||
28673
- !this._crashBuffer ||
28674
- this._isFlushingBuffer ||
28675
- !((_b = (_a = this._configs) === null || _a === void 0 ? void 0 : _a.buffering) === null || _b === void 0 ? void 0 : _b.enabled) ||
28676
- this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped) {
28716
+ if (!sessionId || !this._crashBuffer || this._isFlushingBuffer) {
28677
28717
  return null;
28678
28718
  }
28679
28719
  this._isFlushingBuffer = true;
@@ -28863,6 +28903,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
28863
28903
  });
28864
28904
  this._socketService.on(_config__WEBPACK_IMPORTED_MODULE_5__.SESSION_SAVE_BUFFER_EVENT, (payload) => {
28865
28905
  var _a;
28906
+ if (this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped)
28907
+ return;
28866
28908
  this._flushBuffer((_a = payload === null || payload === void 0 ? void 0 : payload.debugSession) === null || _a === void 0 ? void 0 : _a._id);
28867
28909
  });
28868
28910
  }