@multiplayer-app/session-recorder-browser 2.0.36 → 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.
package/dist/index.js CHANGED
@@ -24263,7 +24263,7 @@ const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
24263
24263
  const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
24264
24264
  const REMOTE_SESSION_RECORDING_START = 'remote-session-recording:start';
24265
24265
  const REMOTE_SESSION_RECORDING_STOP = 'remote-session-recording:stop';
24266
- const PACKAGE_VERSION_EXPORT = "2.0.36" || 0;
24266
+ const PACKAGE_VERSION_EXPORT = "2.0.38" || 0;
24267
24267
  // Regex patterns for OpenTelemetry ignore URLs
24268
24268
  const OTEL_IGNORE_URLS = [
24269
24269
  // Traces endpoint
@@ -26335,10 +26335,11 @@ class ApiService {
26335
26335
 
26336
26336
 
26337
26337
  class CrashBufferService {
26338
- constructor(db, tabId, windowMs) {
26338
+ constructor(db, tabId, windowMs, ready = Promise.resolve()) {
26339
26339
  this.db = db;
26340
26340
  this.tabId = tabId;
26341
26341
  this.windowMs = windowMs;
26342
+ this.ready = ready;
26342
26343
  this.lastPruneAt = 0;
26343
26344
  this.pruneInFlight = null;
26344
26345
  this.isActive = true;
@@ -26361,6 +26362,7 @@ class CrashBufferService {
26361
26362
  if (!this.isActive)
26362
26363
  return;
26363
26364
  const isFullSnapshot = Boolean(payload.isFullSnapshot);
26365
+ await this.ready;
26364
26366
  await this._safe(async () => {
26365
26367
  await this.db.appendEvent({
26366
26368
  tabId: this.tabId,
@@ -26381,6 +26383,7 @@ class CrashBufferService {
26381
26383
  if (!this.isActive)
26382
26384
  return;
26383
26385
  let errorEvent = null;
26386
+ await this.ready;
26384
26387
  await this._safe(async () => {
26385
26388
  const records = payload.map((p) => {
26386
26389
  var _a, _b;
@@ -26429,6 +26432,7 @@ class CrashBufferService {
26429
26432
  }
26430
26433
  async snapshot(_windowMs, now = Date.now()) {
26431
26434
  var _a, _b;
26435
+ await this.ready;
26432
26436
  const stoppedAt = now;
26433
26437
  const startedAt = Math.max(0, stoppedAt - this.windowMs);
26434
26438
  // Always include a full snapshot "anchor" if one exists at/before the window start.
@@ -27063,6 +27067,8 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
27063
27067
  this.sessionId = null;
27064
27068
  this.usePostMessage = false;
27065
27069
  this.isInitialized = false;
27070
+ this.lastUserPayload = null;
27071
+ this.lastSubscribeSession = null;
27066
27072
  this.options = {
27067
27073
  apiKey: '',
27068
27074
  socketUrl: '',
@@ -27125,6 +27131,15 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
27125
27131
  this.isConnecting = false;
27126
27132
  this.isConnected = true;
27127
27133
  this.usePostMessage = false;
27134
+ // Re-establish identity and session on every (re)connect: socket.io's auto-reconnect
27135
+ // fires 'ready' again after a drop, but the server has no memory of the previous
27136
+ // setUser/subscribe calls — the client must replay them.
27137
+ if (this.lastUserPayload && this.socket) {
27138
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, this.lastUserPayload);
27139
+ }
27140
+ if (this.lastSubscribeSession) {
27141
+ this._emitSubscribe(this.lastSubscribeSession);
27142
+ }
27128
27143
  this.flushQueue();
27129
27144
  });
27130
27145
  this.socket.on('disconnect', (err) => {
@@ -27191,16 +27206,33 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
27191
27206
  this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_ADD_EVENT, event);
27192
27207
  }
27193
27208
  subscribeToSession(session) {
27209
+ // Remember the session so reconnects replay subscribe + started.
27210
+ this.lastSubscribeSession = session;
27211
+ this._emitSubscribe(session);
27212
+ }
27213
+ _emitSubscribe(session) {
27194
27214
  this.sessionId = session.shortId || session._id;
27195
- const payload = {
27215
+ const subscribePayload = {
27196
27216
  projectId: session.project,
27197
27217
  workspaceId: session.workspace,
27198
27218
  debugSessionId: this.sessionId,
27199
27219
  sessionType: session.creationType,
27200
27220
  };
27201
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, payload);
27202
- // use long id instead of short id
27203
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, { debugSessionId: session._id });
27221
+ const startedPayload = { debugSessionId: session._id };
27222
+ // Send directly (not via the queue). The queue would cause a duplicate emit on
27223
+ // the next 'ready' alongside the replay, since 'ready' also replays lastSubscribeSession.
27224
+ if (this.usePostMessage) {
27225
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
27226
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
27227
+ }
27228
+ else if (this.socket && this.isConnected) {
27229
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
27230
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
27231
+ }
27232
+ else {
27233
+ // Not connected: 'ready' will replay via lastSubscribeSession once the socket is up.
27234
+ this._initConnection();
27235
+ }
27204
27236
  }
27205
27237
  unsubscribeFromSession(stopSession) {
27206
27238
  if (this.sessionId) {
@@ -27209,9 +27241,23 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
27209
27241
  this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STOPPED_EVENT, {});
27210
27242
  }
27211
27243
  }
27244
+ this.lastSubscribeSession = null;
27212
27245
  }
27213
27246
  setUser(data) {
27214
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
27247
+ // Remember the last identity so 'ready' (initial connect + every reconnect) can replay it.
27248
+ // Send directly here rather than queuing: the queue would cause a duplicate emit on the
27249
+ // next 'ready' alongside the replay.
27250
+ this.lastUserPayload = data;
27251
+ if (this.usePostMessage) {
27252
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
27253
+ }
27254
+ else if (this.socket && this.isConnected) {
27255
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
27256
+ }
27257
+ else {
27258
+ // Not connected yet: 'ready' will replay lastUserPayload once the socket is up.
27259
+ this._initConnection();
27260
+ }
27215
27261
  }
27216
27262
  close() {
27217
27263
  return new Promise((resolve) => {
@@ -27452,13 +27498,11 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
27452
27498
  this._start();
27453
27499
  }
27454
27500
  else {
27455
- // Buffer-only recording when there is no active debug session.
27456
27501
  this._startBufferOnlyRecording();
27457
27502
  }
27458
27503
  this._registerWidgetEvents();
27459
27504
  this._registerSocketServiceListeners();
27460
27505
  _services_messaging_service__WEBPACK_IMPORTED_MODULE_9__["default"].sendMessage('state-change', this.sessionState);
27461
- // Emit init observable event
27462
27506
  this.emit('init', [this]);
27463
27507
  }
27464
27508
  _setupCrashBuffer() {
@@ -27466,7 +27510,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
27466
27510
  if ((_a = this._configs.buffering) === null || _a === void 0 ? void 0 : _a.enabled) {
27467
27511
  const windowMinutes = this._configs.buffering.windowMinutes || 0.5;
27468
27512
  const windowMs = Math.max(10000, windowMinutes * 60 * 1000);
27469
- this._crashBuffer = new _services_crashBuffer_service__WEBPACK_IMPORTED_MODULE_13__.CrashBufferService(this._bufferDb, this._tabId, windowMs);
27513
+ const ready = this._bufferDb.clearTab(this._tabId).catch(() => undefined);
27514
+ this._crashBuffer = new _services_crashBuffer_service__WEBPACK_IMPORTED_MODULE_13__.CrashBufferService(this._bufferDb, this._tabId, windowMs, ready);
27470
27515
  this._recorder.setCrashBuffer(this._crashBuffer);
27471
27516
  this._tracer.setCrashBuffer(this._crashBuffer);
27472
27517
  this._crashBuffer.on('error-span-appended', (payload) => {
@@ -27700,12 +27745,7 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
27700
27745
  }
27701
27746
  }
27702
27747
  async _flushBuffer(sessionId) {
27703
- var _a, _b;
27704
- if (!sessionId ||
27705
- !this._crashBuffer ||
27706
- this._isFlushingBuffer ||
27707
- !((_b = (_a = this._configs) === null || _a === void 0 ? void 0 : _a.buffering) === null || _b === void 0 ? void 0 : _b.enabled) ||
27708
- this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped) {
27748
+ if (!sessionId || !this._crashBuffer || this._isFlushingBuffer) {
27709
27749
  return null;
27710
27750
  }
27711
27751
  this._isFlushingBuffer = true;
@@ -27895,6 +27935,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
27895
27935
  });
27896
27936
  this._socketService.on(_config__WEBPACK_IMPORTED_MODULE_5__.SESSION_SAVE_BUFFER_EVENT, (payload) => {
27897
27937
  var _a;
27938
+ if (this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped)
27939
+ return;
27898
27940
  this._flushBuffer((_a = payload === null || payload === void 0 ? void 0 : payload.debugSession) === null || _a === void 0 ? void 0 : _a._id);
27899
27941
  });
27900
27942
  }