@defcomm/meetingsdk 0.1.9 → 0.2.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/index.d.mts CHANGED
@@ -355,6 +355,9 @@ declare class SFUClient {
355
355
  private onError;
356
356
  private autoSubscribe;
357
357
  constructor(options?: SFUClientOptions);
358
+ private heartbeatTimer;
359
+ private startHeartbeat;
360
+ private stopHeartbeat;
358
361
  private createId;
359
362
  private resumeStorageKey;
360
363
  private loadResumeToken;
package/dist/index.d.ts CHANGED
@@ -355,6 +355,9 @@ declare class SFUClient {
355
355
  private onError;
356
356
  private autoSubscribe;
357
357
  constructor(options?: SFUClientOptions);
358
+ private heartbeatTimer;
359
+ private startHeartbeat;
360
+ private stopHeartbeat;
358
361
  private createId;
359
362
  private resumeStorageKey;
360
363
  private loadResumeToken;
package/dist/index.js CHANGED
@@ -428,6 +428,7 @@ var SFUClient = class {
428
428
  this.trackToSource = /* @__PURE__ */ new Map();
429
429
  this.localTrackIds = /* @__PURE__ */ new Map();
430
430
  this.subscriberStatsTimer = null;
431
+ this.heartbeatTimer = null;
431
432
  this.apiBase = options.apiBase || "https://api.example.com/api";
432
433
  this.wsBase = options.wsBase || "wss://api.example.com/ws";
433
434
  this.participantId = options.participantId || this.createId();
@@ -472,6 +473,24 @@ var SFUClient = class {
472
473
  this.onError = options.onError || console.error;
473
474
  this.autoSubscribe = options.autoSubscribe !== false;
474
475
  }
476
+ startHeartbeat() {
477
+ this.stopHeartbeat();
478
+ this.heartbeatTimer = setInterval(() => {
479
+ if (this.ws?.readyState !== WebSocket.OPEN) return;
480
+ this.send({
481
+ type: "ping",
482
+ payload: {
483
+ nonce: crypto.randomUUID()
484
+ }
485
+ });
486
+ }, 1e4);
487
+ }
488
+ stopHeartbeat() {
489
+ if (this.heartbeatTimer) {
490
+ clearInterval(this.heartbeatTimer);
491
+ this.heartbeatTimer = null;
492
+ }
493
+ }
475
494
  createId() {
476
495
  return typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : `id_${Math.random().toString(36).slice(2)}_${Date.now()}`;
477
496
  }
@@ -632,6 +651,7 @@ var SFUClient = class {
632
651
  );
633
652
  this.ws = ws;
634
653
  ws.onopen = () => {
654
+ this.startHeartbeat();
635
655
  this.setState("joining");
636
656
  this.joiningWithResume = Boolean(this.resumeToken);
637
657
  const joinPayload = {
@@ -655,6 +675,7 @@ var SFUClient = class {
655
675
  this.onError(event);
656
676
  };
657
677
  ws.onclose = () => {
678
+ this.stopHeartbeat();
658
679
  if (this.ws !== ws) return;
659
680
  this.ws = null;
660
681
  if (this.intentionalClose || this.state === "leaving") {
@@ -936,11 +957,21 @@ var SFUClient = class {
936
957
  break;
937
958
  }
938
959
  case "error": {
939
- const error = new Error(payload.message || "SFU signaling error");
940
- this.onError(error);
960
+ const message2 = payload.message || "SFU signaling error";
961
+ if (this.state === "reconnecting" && message2.includes("participant session is stale")) {
962
+ console.debug(
963
+ "[SFU] Ignoring stale-session error during recovery",
964
+ message2
965
+ );
966
+ return;
967
+ }
968
+ const error = new Error(message2);
941
969
  if (this.state === "joining" || this.state === "waiting_approval") {
970
+ this.onError(error);
942
971
  this.failJoin(error);
972
+ return;
943
973
  }
974
+ this.onError(error);
944
975
  break;
945
976
  }
946
977
  default:
@@ -1028,18 +1059,6 @@ var SFUClient = class {
1028
1059
  signalingState: publisher.signalingState
1029
1060
  });
1030
1061
  if (state === "failed") {
1031
- const error = new Error("Publisher PeerConnection failed");
1032
- this.onError({
1033
- code: "SFU_ERROR",
1034
- message: error.message,
1035
- raw: error,
1036
- recoverable: true,
1037
- roomId: this.room,
1038
- participantId: this.currentParticipantId,
1039
- peer: "publisher",
1040
- connectionState: publisher.connectionState,
1041
- iceConnectionState: publisher.iceConnectionState
1042
- });
1043
1062
  this.recoverWebRTC("publisher_failed");
1044
1063
  }
1045
1064
  };
@@ -1054,18 +1073,6 @@ var SFUClient = class {
1054
1073
  signalingState: subscriber.signalingState
1055
1074
  });
1056
1075
  if (state === "failed") {
1057
- const error = new Error("Subscriber PeerConnection failed");
1058
- this.onError({
1059
- code: "SFU_ERROR",
1060
- message: error.message,
1061
- raw: error,
1062
- recoverable: true,
1063
- roomId: this.room,
1064
- participantId: this.currentParticipantId,
1065
- peer: "subscriber",
1066
- connectionState: subscriber.connectionState,
1067
- iceConnectionState: subscriber.iceConnectionState
1068
- });
1069
1076
  this.recoverWebRTC("subscriber_failed");
1070
1077
  }
1071
1078
  };
@@ -1555,6 +1562,7 @@ var SFUClient = class {
1555
1562
  }
1556
1563
  }
1557
1564
  async leave() {
1565
+ this.stopHeartbeat();
1558
1566
  this.intentionalClose = true;
1559
1567
  this.setState("leaving");
1560
1568
  if (this.reconnectTimer) {