@decentnetwork/beagle 0.1.35 → 0.1.37

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.34";
1
+ window.__DK_UI_VERSION="0.1.36";
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"/>',
@@ -1622,7 +1622,7 @@ function DkGroupSender({ grp, T, avatar }) {
1622
1622
  title: grp.sender,
1623
1623
  style: { display: "inline-flex", alignItems: "center", gap: 5, background: "none", border: "none", padding: 0, cursor: "pointer" }
1624
1624
  },
1625
- avatar ? /* @__PURE__ */ React.createElement(DkIdenticon, { seed, size: 24, radius: 6 }) : /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)" } }, grp.sender)
1625
+ avatar ? /* @__PURE__ */ React.createElement(DkEnsAvatar, { userid: grp.senderId, fallbackSeed: seed, size: 24, radius: 6 }) : /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)" } }, grp.sender)
1626
1626
  ), open && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { onClick: () => setOpen(false), style: { position: "fixed", inset: 0, zIndex: 40 } }), /* @__PURE__ */ React.createElement("span", { style: {
1627
1627
  position: "absolute",
1628
1628
  left: 0,
@@ -1637,7 +1637,7 @@ function DkGroupSender({ grp, T, avatar }) {
1637
1637
  display: "flex",
1638
1638
  flexDirection: "column",
1639
1639
  gap: 8
1640
- } }, /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement(DkIdenticon, { seed, size: 34, radius: 8 }), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12.5, fontWeight: 700, color: "var(--text)", wordBreak: "break-all" } }, grp.sender)), grp.senderId ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Mono, { size: 10.5, dim: true, copy: grp.senderId, title: grp.senderId }, shortKey(grp.senderId, 12, 8)), /* @__PURE__ */ React.createElement(
1640
+ } }, /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement(DkEnsAvatar, { userid: grp.senderId, fallbackSeed: seed, size: 34, radius: 8 }), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12.5, fontWeight: 700, color: "var(--text)", wordBreak: "break-all" } }, grp.sender)), grp.senderId ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Mono, { size: 10.5, dim: true, copy: grp.senderId, title: grp.senderId }, shortKey(grp.senderId, 12, 8)), /* @__PURE__ */ React.createElement(
1641
1641
  "button",
1642
1642
  {
1643
1643
  onClick: addFriend,
@@ -2874,6 +2874,39 @@ function DkPunkAvatar({ id, size, radius, fallbackSeed }) {
2874
2874
  }
2875
2875
  );
2876
2876
  }
2877
+ const dkEnsAvCache = /* @__PURE__ */ new Map();
2878
+ function DkEnsAvatar({ userid, fallbackSeed, size, radius }) {
2879
+ const [pub, setPub] = React.useState(() => userid && dkEnsAvCache.has(userid) ? dkEnsAvCache.get(userid) : void 0);
2880
+ React.useEffect(() => {
2881
+ let dead = false;
2882
+ if (!userid) {
2883
+ setPub(null);
2884
+ return void 0;
2885
+ }
2886
+ if (dkEnsAvCache.has(userid)) {
2887
+ setPub(dkEnsAvCache.get(userid));
2888
+ return void 0;
2889
+ }
2890
+ fetch(`/api/ens-profile?userid=${encodeURIComponent(userid)}`).then((r) => r.json()).then((d) => {
2891
+ var _a;
2892
+ const v = d.ok && d.profile ? { avatarUrl: d.profile.avatarUrl || null, punkId: (_a = d.profile.punkId) != null ? _a : null } : null;
2893
+ dkEnsAvCache.set(userid, v);
2894
+ if (!dead)
2895
+ setPub(v);
2896
+ }).catch(() => {
2897
+ if (!dead)
2898
+ setPub(null);
2899
+ });
2900
+ return () => {
2901
+ dead = true;
2902
+ };
2903
+ }, [userid]);
2904
+ if (pub && pub.avatarUrl)
2905
+ return /* @__PURE__ */ React.createElement(DkImgAvatar, { url: pub.avatarUrl, seed: fallbackSeed || userid, size, radius });
2906
+ if (pub && pub.punkId != null)
2907
+ return /* @__PURE__ */ React.createElement(DkPunkAvatar, { id: pub.punkId, size, radius, fallbackSeed: fallbackSeed || userid });
2908
+ return /* @__PURE__ */ React.createElement(DkIdenticon, { seed: fallbackSeed || userid || "x", size, radius });
2909
+ }
2877
2910
  function DkPunkPicker({ T, onPick, onClose }) {
2878
2911
  const TYPES = ["any", "female", "male", "zombie", "ape", "alien"];
2879
2912
  const tLabel = (t) => T && T["pt_" + t] || t;
@@ -3211,7 +3244,7 @@ function ProfileTab({ T, me, onEdit }) {
3211
3244
  setEditing(false);
3212
3245
  } }));
3213
3246
  }
3214
- Object.assign(window, { ProfileTab, DkPunkAvatar, DkPublicProfile });
3247
+ Object.assign(window, { ProfileTab, DkPunkAvatar, DkEnsAvatar, DkPublicProfile });
3215
3248
  function DkDirAvatar({ p, size }) {
3216
3249
  const [broken, setBroken] = React.useState(false);
3217
3250
  if (p.punkId != null && !(p.avatar && !broken)) {
@@ -3795,6 +3828,14 @@ function useCallController(selfId, onCallLog) {
3795
3828
  return;
3796
3829
  }
3797
3830
  engine.on("incomingCall", (info) => {
3831
+ const claimedAt = claimedCalls.current.get(String(info.callId).toLowerCase());
3832
+ if (claimedAt && Date.now() - claimedAt < 5 * 6e4) {
3833
+ try {
3834
+ engine.discard && engine.discard(info.callId);
3835
+ } catch (e) {
3836
+ }
3837
+ return;
3838
+ }
3798
3839
  setIncoming(info);
3799
3840
  if (onCallLogRef.current)
3800
3841
  onCallLogRef.current(info.peerId, !!info.video, "incoming");
@@ -3860,6 +3901,7 @@ function useCallController(selfId, onCallLog) {
3860
3901
  }, [active]);
3861
3902
  const claimTabId = React.useRef(Math.random().toString(36).slice(2));
3862
3903
  const claimBus = React.useRef(null);
3904
+ const claimedCalls = React.useRef(/* @__PURE__ */ new Map());
3863
3905
  React.useEffect(() => {
3864
3906
  let ch = null;
3865
3907
  try {
@@ -3872,9 +3914,16 @@ function useCallController(selfId, onCallLog) {
3872
3914
  const m = ev.data || {};
3873
3915
  if (!m || m.tabId === claimTabId.current || m.type !== "claimed")
3874
3916
  return;
3917
+ if (m.callId)
3918
+ claimedCalls.current.set(String(m.callId).toLowerCase(), Date.now());
3875
3919
  const inc = incomingRef.current;
3876
- if (inc && (inc.callId === m.callId || inc.peerId === m.peerId))
3920
+ if (inc && (inc.callId === m.callId || inc.peerId === m.peerId)) {
3877
3921
  setIncoming(null);
3922
+ try {
3923
+ engineRef.current && engineRef.current.discard && engineRef.current.discard(inc.callId);
3924
+ } catch (e) {
3925
+ }
3926
+ }
3878
3927
  };
3879
3928
  return () => {
3880
3929
  try {
@@ -4664,7 +4713,7 @@ function DkApp() {
4664
4713
  }, [refreshBackend]);
4665
4714
  React.useEffect(() => {
4666
4715
  const mine = window.__DK_UI_VERSION;
4667
- const served = me && me.lanVer;
4716
+ const served = me && me.beagleVer;
4668
4717
  if (!mine || !served || mine === served)
4669
4718
  return;
4670
4719
  const key = "dk-reloaded-for-" + served;
@@ -4672,7 +4721,7 @@ function DkApp() {
4672
4721
  return;
4673
4722
  sessionStorage.setItem(key, "1");
4674
4723
  window.location.reload();
4675
- }, [me && me.lanVer]);
4724
+ }, [me && me.beagleVer]);
4676
4725
  const peers = data.peers;
4677
4726
  const [pendingAddr, setPendingAddr] = React.useState(() => dkParseDeepLinkAddress());
4678
4727
  React.useEffect(() => {
@@ -402,6 +402,16 @@ var PeerWebRTC = (() => {
402
402
  var _a;
403
403
  return !!((_a = __privateGet(this, _sessions).get(__privateMethod(this, _normId, normId_fn).call(this, callId))) == null ? void 0 : _a.screenStream);
404
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
+ }
405
415
  /** Tear down every call (e.g. on app shutdown). */
406
416
  dispose() {
407
417
  for (const session of [...__privateGet(this, _sessions).values()]) {
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.35",
3
+ "version": "0.1.37",
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.13",
31
+ "@decentnetwork/peer-webrtc": "^0.2.14",
32
32
  "js-yaml": "^4.1.0",
33
33
  "yargs": "^17.7.2"
34
34
  },