@decentnetwork/beagle 0.1.33 → 0.1.35

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.
@@ -1,4 +1,4 @@
1
- window.__DK_UI_VERSION="0.1.32";
1
+ window.__DK_UI_VERSION="0.1.34";
2
2
  const ICON_PATHS = {
3
3
  // ---- tab bar (the four must feel like one set) ----
4
4
  users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
@@ -167,10 +167,13 @@ var PeerWebRTC = (() => {
167
167
  var DEFAULT_ICE_SERVERS = [
168
168
  { urls: "stun:stun.l.google.com:19302" }
169
169
  ];
170
- var _opts, _iceServers, _sessions, _setOutgoingVideoTrack, setOutgoingVideoTrack_fn, _renegotiate, renegotiate_fn, _handleSignal, handleSignal_fn, _onOffer, onOffer_fn, _answerRenegotiation, answerRenegotiation_fn, _onAnswer, onAnswer_fn, _onCandidate, onCandidate_fn, _onBye, onBye_fn, _onAuxiliary, onAuxiliary_fn, _createSession, createSession_fn, _wirePeerConnection, wirePeerConnection_fn, _ensureRemoteStream, ensureRemoteStream_fn, _attachLocalMedia, attachLocalMedia_fn, _flushLocalCandidates, flushLocalCandidates_fn, _drainRemoteCandidates, drainRemoteCandidates_fn, _send, send_fn, _sendByeSafe, sendByeSafe_fn, _cleanup, cleanup_fn, _setState, setState_fn, _normId, normId_fn, _toInfo, _newCallId, newCallId_fn, _log, log_fn;
170
+ var ICE_RESTART_MAX = 3;
171
+ var ICE_DISCONNECT_GRACE_MS = 4e3;
172
+ var ICE_FAILED_GRACE_MS = 12e4;
173
+ var _opts, _iceServers, _sessions, _restartOffersEnabled, _setOutgoingVideoTrack, setOutgoingVideoTrack_fn, _renegotiate, renegotiate_fn, _restartIce, restartIce_fn, _handleSignal, handleSignal_fn, _onOffer, onOffer_fn, _answerRenegotiation, answerRenegotiation_fn, _onAnswer, onAnswer_fn, _onCandidate, onCandidate_fn, _onBye, onBye_fn, _onAuxiliary, onAuxiliary_fn, _createSession, createSession_fn, _wirePeerConnection, wirePeerConnection_fn, _ensureRemoteStream, ensureRemoteStream_fn, _attachLocalMedia, attachLocalMedia_fn, _flushLocalCandidates, flushLocalCandidates_fn, _drainRemoteCandidates, drainRemoteCandidates_fn, _send, send_fn, _sendByeSafe, sendByeSafe_fn, _cleanup, cleanup_fn, _setState, setState_fn, _normId, normId_fn, _toInfo, _newCallId, newCallId_fn, _log, log_fn;
171
174
  var CallEngine = class extends Emitter {
172
175
  constructor(opts) {
173
- var _a;
176
+ var _a, _b;
174
177
  super();
175
178
  /** Point the outgoing video sender at `track` (replaceTrack, no renegotiation
176
179
  * needed if a sender exists), flip the transceiver to send, and refresh the
@@ -179,6 +182,13 @@ var PeerWebRTC = (() => {
179
182
  /** Create + send a fresh offer to renegotiate media (e.g. after adding a
180
183
  * screen-share track). The peer applies it via #onOffer's renegotiation path. */
181
184
  __privateAdd(this, _renegotiate);
185
+ /** Recover a dead transport with an ICE restart (RFC 8445 §12): a re-offer
186
+ * carrying fresh ufrag/pwd, sent over the SAME renegotiation path that
187
+ * screen-share re-offers use — any peer that answers those (web, iOS,
188
+ * Android) cooperates with no new protocol. Only the ORIGINAL CALLER
189
+ * initiates, so both ends noticing the outage can't glare offers at each
190
+ * other; the callee just answers. */
191
+ __privateAdd(this, _restartIce);
182
192
  // ---- internals -------------------------------------------------------
183
193
  __privateAdd(this, _handleSignal);
184
194
  __privateAdd(this, _onOffer);
@@ -210,6 +220,8 @@ var PeerWebRTC = (() => {
210
220
  __privateAdd(this, _opts, void 0);
211
221
  __privateAdd(this, _iceServers, void 0);
212
222
  __privateAdd(this, _sessions, /* @__PURE__ */ new Map());
223
+ /** See CallEngineOptions.iceRestartOffers — off by default for native-app safety. */
224
+ __privateAdd(this, _restartOffersEnabled, void 0);
213
225
  __privateAdd(this, _toInfo, (session) => ({
214
226
  callId: session.callId,
215
227
  peerId: session.peerId,
@@ -221,6 +233,7 @@ var PeerWebRTC = (() => {
221
233
  }));
222
234
  __privateSet(this, _opts, opts);
223
235
  __privateSet(this, _iceServers, (_a = opts.iceServers) != null ? _a : DEFAULT_ICE_SERVERS);
236
+ __privateSet(this, _restartOffersEnabled, (_b = opts.iceRestartOffers) != null ? _b : false);
224
237
  opts.signaling.onSignal((peerId, signal) => {
225
238
  try {
226
239
  __privateMethod(this, _handleSignal, handleSignal_fn).call(this, peerId, signal);
@@ -400,6 +413,7 @@ var PeerWebRTC = (() => {
400
413
  _opts = new WeakMap();
401
414
  _iceServers = new WeakMap();
402
415
  _sessions = new WeakMap();
416
+ _restartOffersEnabled = new WeakMap();
403
417
  _setOutgoingVideoTrack = new WeakSet();
404
418
  setOutgoingVideoTrack_fn = async function(session, track, stream) {
405
419
  var _a;
@@ -440,6 +454,25 @@ var PeerWebRTC = (() => {
440
454
  __privateMethod(this, _log, log_fn).call(this, `renegotiate failed: ${err.message}`);
441
455
  }
442
456
  };
457
+ _restartIce = new WeakSet();
458
+ restartIce_fn = async function(session) {
459
+ if (session.closed)
460
+ return;
461
+ session.restartAttempts += 1;
462
+ __privateMethod(this, _log, log_fn).call(this, `ICE restart ${session.restartAttempts}/${ICE_RESTART_MAX} for call ${session.callId}`);
463
+ try {
464
+ const offer = await session.pc.createOffer({ iceRestart: true });
465
+ await session.pc.setLocalDescription(offer);
466
+ const options = [];
467
+ if (session.audio)
468
+ options.push("audio");
469
+ if (session.video || session.screenStream)
470
+ options.push("video");
471
+ await __privateMethod(this, _send, send_fn).call(this, session.peerId, { type: "offer", sdp: offer.sdp, options, callId: session.callId });
472
+ } catch (err) {
473
+ __privateMethod(this, _log, log_fn).call(this, `ICE restart failed: ${err.message}`);
474
+ }
475
+ };
443
476
  _handleSignal = new WeakSet();
444
477
  handleSignal_fn = function(peerId, signal) {
445
478
  switch (signal.type) {
@@ -578,6 +611,7 @@ var PeerWebRTC = (() => {
578
611
  hasReceivedSdp: false,
579
612
  localCandidateQueue: [],
580
613
  remoteCandidateQueue: [],
614
+ restartAttempts: 0,
581
615
  closed: false
582
616
  };
583
617
  __privateGet(this, _sessions).set(__privateMethod(this, _normId, normId_fn).call(this, callId), session);
@@ -616,14 +650,42 @@ var PeerWebRTC = (() => {
616
650
  switch (pc.iceConnectionState) {
617
651
  case "connected":
618
652
  case "completed":
653
+ if (session.restartTimer) {
654
+ clearTimeout(session.restartTimer);
655
+ session.restartTimer = void 0;
656
+ }
657
+ session.restartAttempts = 0;
619
658
  __privateMethod(this, _setState, setState_fn).call(this, session, "connected");
620
659
  break;
621
660
  case "disconnected":
622
661
  __privateMethod(this, _setState, setState_fn).call(this, session, "disconnected");
662
+ if (__privateGet(this, _restartOffersEnabled) && session.direction === "outgoing" && !session.restartTimer && session.restartAttempts < ICE_RESTART_MAX) {
663
+ session.restartTimer = setTimeout(() => {
664
+ session.restartTimer = void 0;
665
+ const st = pc.iceConnectionState;
666
+ if (!session.closed && (st === "disconnected" || st === "failed"))
667
+ void __privateMethod(this, _restartIce, restartIce_fn).call(this, session);
668
+ }, ICE_DISCONNECT_GRACE_MS);
669
+ }
623
670
  break;
624
671
  case "failed":
625
- __privateMethod(this, _setState, setState_fn).call(this, session, "failed");
626
- __privateMethod(this, _cleanup, cleanup_fn).call(this, session, "close", "failed");
672
+ if (session.restartAttempts < ICE_RESTART_MAX) {
673
+ __privateMethod(this, _setState, setState_fn).call(this, session, "disconnected");
674
+ if (__privateGet(this, _restartOffersEnabled) && session.direction === "outgoing")
675
+ void __privateMethod(this, _restartIce, restartIce_fn).call(this, session);
676
+ if (session.restartTimer)
677
+ clearTimeout(session.restartTimer);
678
+ session.restartTimer = setTimeout(() => {
679
+ session.restartTimer = void 0;
680
+ if (!session.closed && pc.iceConnectionState === "failed") {
681
+ __privateMethod(this, _setState, setState_fn).call(this, session, "failed");
682
+ __privateMethod(this, _cleanup, cleanup_fn).call(this, session, "close", "failed");
683
+ }
684
+ }, ICE_FAILED_GRACE_MS);
685
+ } else {
686
+ __privateMethod(this, _setState, setState_fn).call(this, session, "failed");
687
+ __privateMethod(this, _cleanup, cleanup_fn).call(this, session, "close", "failed");
688
+ }
627
689
  break;
628
690
  case "closed":
629
691
  if (!session.closed)
@@ -713,6 +775,10 @@ var PeerWebRTC = (() => {
713
775
  if (session.closed)
714
776
  return;
715
777
  session.closed = true;
778
+ if (session.restartTimer) {
779
+ clearTimeout(session.restartTimer);
780
+ session.restartTimer = void 0;
781
+ }
716
782
  try {
717
783
  session.pc.onicecandidate = null;
718
784
  session.pc.ontrack = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/beagle",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
4
4
  "description": "Beagle — P2P chat, file transfer and calls for regular users, on the Decent Network. No admin privilege required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,7 +28,7 @@
28
28
  "@decentnetwork/chat-components": "^0.1.3",
29
29
  "@decentnetwork/lan": "^0.1.256",
30
30
  "@decentnetwork/peer": "^0.1.138",
31
- "@decentnetwork/peer-webrtc": "^0.2.11",
31
+ "@decentnetwork/peer-webrtc": "^0.2.13",
32
32
  "js-yaml": "^4.1.0",
33
33
  "yargs": "^17.7.2"
34
34
  },