@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.umd.js CHANGED
@@ -24436,7 +24436,7 @@ const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
24436
24436
  const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
24437
24437
  const REMOTE_SESSION_RECORDING_START = 'remote-session-recording:start';
24438
24438
  const REMOTE_SESSION_RECORDING_STOP = 'remote-session-recording:stop';
24439
- const PACKAGE_VERSION_EXPORT = "2.0.36" || 0;
24439
+ const PACKAGE_VERSION_EXPORT = "2.0.38" || 0;
24440
24440
  // Regex patterns for OpenTelemetry ignore URLs
24441
24441
  const OTEL_IGNORE_URLS = [
24442
24442
  // Traces endpoint
@@ -26530,10 +26530,11 @@ class ApiService {
26530
26530
 
26531
26531
 
26532
26532
  class CrashBufferService {
26533
- constructor(db, tabId, windowMs) {
26533
+ constructor(db, tabId, windowMs, ready = Promise.resolve()) {
26534
26534
  this.db = db;
26535
26535
  this.tabId = tabId;
26536
26536
  this.windowMs = windowMs;
26537
+ this.ready = ready;
26537
26538
  this.lastPruneAt = 0;
26538
26539
  this.pruneInFlight = null;
26539
26540
  this.isActive = true;
@@ -26556,6 +26557,7 @@ class CrashBufferService {
26556
26557
  if (!this.isActive)
26557
26558
  return;
26558
26559
  const isFullSnapshot = Boolean(payload.isFullSnapshot);
26560
+ await this.ready;
26559
26561
  await this._safe(async () => {
26560
26562
  await this.db.appendEvent({
26561
26563
  tabId: this.tabId,
@@ -26576,6 +26578,7 @@ class CrashBufferService {
26576
26578
  if (!this.isActive)
26577
26579
  return;
26578
26580
  let errorEvent = null;
26581
+ await this.ready;
26579
26582
  await this._safe(async () => {
26580
26583
  const records = payload.map((p) => {
26581
26584
  var _a, _b;
@@ -26624,6 +26627,7 @@ class CrashBufferService {
26624
26627
  }
26625
26628
  async snapshot(_windowMs, now = Date.now()) {
26626
26629
  var _a, _b;
26630
+ await this.ready;
26627
26631
  const stoppedAt = now;
26628
26632
  const startedAt = Math.max(0, stoppedAt - this.windowMs);
26629
26633
  // Always include a full snapshot "anchor" if one exists at/before the window start.
@@ -27261,6 +27265,8 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
27261
27265
  this.sessionId = null;
27262
27266
  this.usePostMessage = false;
27263
27267
  this.isInitialized = false;
27268
+ this.lastUserPayload = null;
27269
+ this.lastSubscribeSession = null;
27264
27270
  this.options = {
27265
27271
  apiKey: '',
27266
27272
  socketUrl: '',
@@ -27323,6 +27329,15 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
27323
27329
  this.isConnecting = false;
27324
27330
  this.isConnected = true;
27325
27331
  this.usePostMessage = false;
27332
+ // Re-establish identity and session on every (re)connect: socket.io's auto-reconnect
27333
+ // fires 'ready' again after a drop, but the server has no memory of the previous
27334
+ // setUser/subscribe calls — the client must replay them.
27335
+ if (this.lastUserPayload && this.socket) {
27336
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, this.lastUserPayload);
27337
+ }
27338
+ if (this.lastSubscribeSession) {
27339
+ this._emitSubscribe(this.lastSubscribeSession);
27340
+ }
27326
27341
  this.flushQueue();
27327
27342
  });
27328
27343
  this.socket.on('disconnect', (err) => {
@@ -27389,16 +27404,33 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
27389
27404
  this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_ADD_EVENT, event);
27390
27405
  }
27391
27406
  subscribeToSession(session) {
27407
+ // Remember the session so reconnects replay subscribe + started.
27408
+ this.lastSubscribeSession = session;
27409
+ this._emitSubscribe(session);
27410
+ }
27411
+ _emitSubscribe(session) {
27392
27412
  this.sessionId = session.shortId || session._id;
27393
- const payload = {
27413
+ const subscribePayload = {
27394
27414
  projectId: session.project,
27395
27415
  workspaceId: session.workspace,
27396
27416
  debugSessionId: this.sessionId,
27397
27417
  sessionType: session.creationType,
27398
27418
  };
27399
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, payload);
27400
- // use long id instead of short id
27401
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, { debugSessionId: session._id });
27419
+ const startedPayload = { debugSessionId: session._id };
27420
+ // Send directly (not via the queue). The queue would cause a duplicate emit on
27421
+ // the next 'ready' alongside the replay, since 'ready' also replays lastSubscribeSession.
27422
+ if (this.usePostMessage) {
27423
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
27424
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
27425
+ }
27426
+ else if (this.socket && this.isConnected) {
27427
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
27428
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
27429
+ }
27430
+ else {
27431
+ // Not connected: 'ready' will replay via lastSubscribeSession once the socket is up.
27432
+ this._initConnection();
27433
+ }
27402
27434
  }
27403
27435
  unsubscribeFromSession(stopSession) {
27404
27436
  if (this.sessionId) {
@@ -27407,9 +27439,23 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
27407
27439
  this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STOPPED_EVENT, {});
27408
27440
  }
27409
27441
  }
27442
+ this.lastSubscribeSession = null;
27410
27443
  }
27411
27444
  setUser(data) {
27412
- this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
27445
+ // Remember the last identity so 'ready' (initial connect + every reconnect) can replay it.
27446
+ // Send directly here rather than queuing: the queue would cause a duplicate emit on the
27447
+ // next 'ready' alongside the replay.
27448
+ this.lastUserPayload = data;
27449
+ if (this.usePostMessage) {
27450
+ this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
27451
+ }
27452
+ else if (this.socket && this.isConnected) {
27453
+ this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
27454
+ }
27455
+ else {
27456
+ // Not connected yet: 'ready' will replay lastUserPayload once the socket is up.
27457
+ this._initConnection();
27458
+ }
27413
27459
  }
27414
27460
  close() {
27415
27461
  return new Promise((resolve) => {
@@ -27651,13 +27697,11 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
27651
27697
  this._start();
27652
27698
  }
27653
27699
  else {
27654
- // Buffer-only recording when there is no active debug session.
27655
27700
  this._startBufferOnlyRecording();
27656
27701
  }
27657
27702
  this._registerWidgetEvents();
27658
27703
  this._registerSocketServiceListeners();
27659
27704
  _services_messaging_service__WEBPACK_IMPORTED_MODULE_9__["default"].sendMessage('state-change', this.sessionState);
27660
- // Emit init observable event
27661
27705
  this.emit('init', [this]);
27662
27706
  }
27663
27707
  _setupCrashBuffer() {
@@ -27665,7 +27709,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
27665
27709
  if ((_a = this._configs.buffering) === null || _a === void 0 ? void 0 : _a.enabled) {
27666
27710
  const windowMinutes = this._configs.buffering.windowMinutes || 0.5;
27667
27711
  const windowMs = Math.max(10000, windowMinutes * 60 * 1000);
27668
- this._crashBuffer = new _services_crashBuffer_service__WEBPACK_IMPORTED_MODULE_13__.CrashBufferService(this._bufferDb, this._tabId, windowMs);
27712
+ const ready = this._bufferDb.clearTab(this._tabId).catch(() => undefined);
27713
+ this._crashBuffer = new _services_crashBuffer_service__WEBPACK_IMPORTED_MODULE_13__.CrashBufferService(this._bufferDb, this._tabId, windowMs, ready);
27669
27714
  this._recorder.setCrashBuffer(this._crashBuffer);
27670
27715
  this._tracer.setCrashBuffer(this._crashBuffer);
27671
27716
  this._crashBuffer.on('error-span-appended', (payload) => {
@@ -27899,12 +27944,7 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
27899
27944
  }
27900
27945
  }
27901
27946
  async _flushBuffer(sessionId) {
27902
- var _a, _b;
27903
- if (!sessionId ||
27904
- !this._crashBuffer ||
27905
- this._isFlushingBuffer ||
27906
- !((_b = (_a = this._configs) === null || _a === void 0 ? void 0 : _a.buffering) === null || _b === void 0 ? void 0 : _b.enabled) ||
27907
- this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped) {
27947
+ if (!sessionId || !this._crashBuffer || this._isFlushingBuffer) {
27908
27948
  return null;
27909
27949
  }
27910
27950
  this._isFlushingBuffer = true;
@@ -28094,6 +28134,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
28094
28134
  });
28095
28135
  this._socketService.on(_config__WEBPACK_IMPORTED_MODULE_5__.SESSION_SAVE_BUFFER_EVENT, (payload) => {
28096
28136
  var _a;
28137
+ if (this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped)
28138
+ return;
28097
28139
  this._flushBuffer((_a = payload === null || payload === void 0 ? void 0 : payload.debugSession) === null || _a === void 0 ? void 0 : _a._id);
28098
28140
  });
28099
28141
  }