@decentnetwork/beagle 0.1.34 → 0.1.36

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.33";
1
+ window.__DK_UI_VERSION="0.1.35";
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"/>',
@@ -3795,6 +3795,14 @@ function useCallController(selfId, onCallLog) {
3795
3795
  return;
3796
3796
  }
3797
3797
  engine.on("incomingCall", (info) => {
3798
+ const claimedAt = claimedCalls.current.get(String(info.callId).toLowerCase());
3799
+ if (claimedAt && Date.now() - claimedAt < 5 * 6e4) {
3800
+ try {
3801
+ engine.discard && engine.discard(info.callId);
3802
+ } catch (e) {
3803
+ }
3804
+ return;
3805
+ }
3798
3806
  setIncoming(info);
3799
3807
  if (onCallLogRef.current)
3800
3808
  onCallLogRef.current(info.peerId, !!info.video, "incoming");
@@ -3860,6 +3868,7 @@ function useCallController(selfId, onCallLog) {
3860
3868
  }, [active]);
3861
3869
  const claimTabId = React.useRef(Math.random().toString(36).slice(2));
3862
3870
  const claimBus = React.useRef(null);
3871
+ const claimedCalls = React.useRef(/* @__PURE__ */ new Map());
3863
3872
  React.useEffect(() => {
3864
3873
  let ch = null;
3865
3874
  try {
@@ -3872,9 +3881,16 @@ function useCallController(selfId, onCallLog) {
3872
3881
  const m = ev.data || {};
3873
3882
  if (!m || m.tabId === claimTabId.current || m.type !== "claimed")
3874
3883
  return;
3884
+ if (m.callId)
3885
+ claimedCalls.current.set(String(m.callId).toLowerCase(), Date.now());
3875
3886
  const inc = incomingRef.current;
3876
- if (inc && (inc.callId === m.callId || inc.peerId === m.peerId))
3887
+ if (inc && (inc.callId === m.callId || inc.peerId === m.peerId)) {
3877
3888
  setIncoming(null);
3889
+ try {
3890
+ engineRef.current && engineRef.current.discard && engineRef.current.discard(inc.callId);
3891
+ } catch (e) {
3892
+ }
3893
+ }
3878
3894
  };
3879
3895
  return () => {
3880
3896
  try {
@@ -4664,7 +4680,7 @@ function DkApp() {
4664
4680
  }, [refreshBackend]);
4665
4681
  React.useEffect(() => {
4666
4682
  const mine = window.__DK_UI_VERSION;
4667
- const served = me && me.lanVer;
4683
+ const served = me && me.beagleVer;
4668
4684
  if (!mine || !served || mine === served)
4669
4685
  return;
4670
4686
  const key = "dk-reloaded-for-" + served;
@@ -4672,7 +4688,7 @@ function DkApp() {
4672
4688
  return;
4673
4689
  sessionStorage.setItem(key, "1");
4674
4690
  window.location.reload();
4675
- }, [me && me.lanVer]);
4691
+ }, [me && me.beagleVer]);
4676
4692
  const peers = data.peers;
4677
4693
  const [pendingAddr, setPendingAddr] = React.useState(() => dkParseDeepLinkAddress());
4678
4694
  React.useEffect(() => {
@@ -169,11 +169,11 @@ var PeerWebRTC = (() => {
169
169
  ];
170
170
  var ICE_RESTART_MAX = 3;
171
171
  var ICE_DISCONNECT_GRACE_MS = 4e3;
172
- var ICE_FAILED_GRACE_MS = 15e3;
173
- var _opts, _iceServers, _sessions, _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;
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;
174
174
  var CallEngine = class extends Emitter {
175
175
  constructor(opts) {
176
- var _a;
176
+ var _a, _b;
177
177
  super();
178
178
  /** Point the outgoing video sender at `track` (replaceTrack, no renegotiation
179
179
  * needed if a sender exists), flip the transceiver to send, and refresh the
@@ -220,6 +220,8 @@ var PeerWebRTC = (() => {
220
220
  __privateAdd(this, _opts, void 0);
221
221
  __privateAdd(this, _iceServers, void 0);
222
222
  __privateAdd(this, _sessions, /* @__PURE__ */ new Map());
223
+ /** See CallEngineOptions.iceRestartOffers — off by default for native-app safety. */
224
+ __privateAdd(this, _restartOffersEnabled, void 0);
223
225
  __privateAdd(this, _toInfo, (session) => ({
224
226
  callId: session.callId,
225
227
  peerId: session.peerId,
@@ -231,6 +233,7 @@ var PeerWebRTC = (() => {
231
233
  }));
232
234
  __privateSet(this, _opts, opts);
233
235
  __privateSet(this, _iceServers, (_a = opts.iceServers) != null ? _a : DEFAULT_ICE_SERVERS);
236
+ __privateSet(this, _restartOffersEnabled, (_b = opts.iceRestartOffers) != null ? _b : false);
234
237
  opts.signaling.onSignal((peerId, signal) => {
235
238
  try {
236
239
  __privateMethod(this, _handleSignal, handleSignal_fn).call(this, peerId, signal);
@@ -399,6 +402,16 @@ var PeerWebRTC = (() => {
399
402
  var _a;
400
403
  return !!((_a = __privateGet(this, _sessions).get(__privateMethod(this, _normId, normId_fn).call(this, callId))) == null ? void 0 : _a.screenStream);
401
404
  }
405
+ /** Silently drop a call WITHOUT signaling the peer — for a tab that lost
406
+ * the cross-tab answer race: another tab owns the call now, so sending
407
+ * reject/bye from this one would kill the live call. Local cleanup only. */
408
+ discard(callId) {
409
+ const session = __privateGet(this, _sessions).get(__privateMethod(this, _normId, normId_fn).call(this, callId));
410
+ if (!session)
411
+ return;
412
+ __privateMethod(this, _log, log_fn).call(this, `discarding call ${callId} (claimed elsewhere)`);
413
+ __privateMethod(this, _cleanup, cleanup_fn).call(this, session, "close");
414
+ }
402
415
  /** Tear down every call (e.g. on app shutdown). */
403
416
  dispose() {
404
417
  for (const session of [...__privateGet(this, _sessions).values()]) {
@@ -410,6 +423,7 @@ var PeerWebRTC = (() => {
410
423
  _opts = new WeakMap();
411
424
  _iceServers = new WeakMap();
412
425
  _sessions = new WeakMap();
426
+ _restartOffersEnabled = new WeakMap();
413
427
  _setOutgoingVideoTrack = new WeakSet();
414
428
  setOutgoingVideoTrack_fn = async function(session, track, stream) {
415
429
  var _a;
@@ -655,7 +669,7 @@ var PeerWebRTC = (() => {
655
669
  break;
656
670
  case "disconnected":
657
671
  __privateMethod(this, _setState, setState_fn).call(this, session, "disconnected");
658
- if (session.direction === "outgoing" && !session.restartTimer && session.restartAttempts < ICE_RESTART_MAX) {
672
+ if (__privateGet(this, _restartOffersEnabled) && session.direction === "outgoing" && !session.restartTimer && session.restartAttempts < ICE_RESTART_MAX) {
659
673
  session.restartTimer = setTimeout(() => {
660
674
  session.restartTimer = void 0;
661
675
  const st = pc.iceConnectionState;
@@ -667,7 +681,7 @@ var PeerWebRTC = (() => {
667
681
  case "failed":
668
682
  if (session.restartAttempts < ICE_RESTART_MAX) {
669
683
  __privateMethod(this, _setState, setState_fn).call(this, session, "disconnected");
670
- if (session.direction === "outgoing")
684
+ if (__privateGet(this, _restartOffersEnabled) && session.direction === "outgoing")
671
685
  void __privateMethod(this, _restartIce, restartIce_fn).call(this, session);
672
686
  if (session.restartTimer)
673
687
  clearTimeout(session.restartTimer);
package/dist/server.js CHANGED
@@ -1406,6 +1406,11 @@ export function startBeagleServer(opts) {
1406
1406
  autoAccept: typeof node.autoAccept === "boolean" ? node.autoAccept : null,
1407
1407
  avatarUrl: ensPub.get(identity.userid ?? "")?.avatarUrl ?? null,
1408
1408
  punkId: ensPub.get(identity.userid ?? "")?.punkId ?? null,
1409
+ // The UI compares this against its baked-in __DK_UI_VERSION and
1410
+ // reloads itself when they differ — an open tab otherwise runs a
1411
+ // stale bundle forever after a beagle update (multi-tab call fixes
1412
+ // "didn't work" purely because old tabs never picked them up).
1413
+ beagleVer: beagleVersion(),
1409
1414
  };
1410
1415
  const fl = (flist.ok ? (flist.data?.friends ?? []) : []);
1411
1416
  const peers = fl.map((f) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/beagle",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
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.12",
31
+ "@decentnetwork/peer-webrtc": "^0.2.14",
32
32
  "js-yaml": "^4.1.0",
33
33
  "yargs": "^17.7.2"
34
34
  },