@decentnetwork/lan 0.1.73 → 0.1.75

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.
Binary file
Binary file
Binary file
Binary file
@@ -51,11 +51,25 @@ export declare class DaemonServer {
51
51
  */
52
52
  private startPeerStatusSummary;
53
53
  getStatus(): DaemonStatus;
54
+ /** Per-peer timestamp of the last self-heal friend-request re-send, so
55
+ * the watchdog escalates at most once per SELF_HEAL_REFRIEND_MS. */
56
+ private reFriendAt;
57
+ /** How long a friend must stay non-online before we re-send the
58
+ * friend-request again. Long enough not to flood express for a roster
59
+ * full of genuinely-dead nodes, short enough to recover a wedged but
60
+ * live peer in well under a minute. */
61
+ private static readonly SELF_HEAL_REFRIEND_MS;
54
62
  /**
55
- * Periodically poke the SDK to (re-)initiate a session with the friend.
56
- * This works around the asymmetric friendOnline issue: without this,
57
- * one side may never spontaneously try to talk to the other and the
58
- * friend stays perpetually offline.
63
+ * Periodically poke the SDK to (re-)initiate a session with the friend,
64
+ * and SELF-HEAL a wedged one. `kickSessionEstablishment` is the weak
65
+ * nudge; for a friend that's accepted but stuck `offline` (the classic
66
+ * NAT-to-NAT case where one side restarted, or a connection that simply
67
+ * died and never recovered) it isn't enough. So when a peer stays
68
+ * non-online, we escalate to re-sending the actual friend-request — the
69
+ * strong kick that forces a fresh Carrier handshake. This is the
70
+ * automatic version of `agentnet friend-request <addr>`, so a private or
71
+ * friend-invited exit recovers on its own instead of needing a human to
72
+ * run a command (which an invited operator never will).
59
73
  */
60
74
  private kickSessionForever;
61
75
  /**
@@ -649,16 +649,47 @@ export class DaemonServer {
649
649
  activeSessions: this.packetRouter?.getStats().activeSessions || 0,
650
650
  };
651
651
  }
652
+ /** Per-peer timestamp of the last self-heal friend-request re-send, so
653
+ * the watchdog escalates at most once per SELF_HEAL_REFRIEND_MS. */
654
+ reFriendAt = new Map();
655
+ /** How long a friend must stay non-online before we re-send the
656
+ * friend-request again. Long enough not to flood express for a roster
657
+ * full of genuinely-dead nodes, short enough to recover a wedged but
658
+ * live peer in well under a minute. */
659
+ static SELF_HEAL_REFRIEND_MS = 45_000;
652
660
  /**
653
- * Periodically poke the SDK to (re-)initiate a session with the friend.
654
- * This works around the asymmetric friendOnline issue: without this,
655
- * one side may never spontaneously try to talk to the other and the
656
- * friend stays perpetually offline.
661
+ * Periodically poke the SDK to (re-)initiate a session with the friend,
662
+ * and SELF-HEAL a wedged one. `kickSessionEstablishment` is the weak
663
+ * nudge; for a friend that's accepted but stuck `offline` (the classic
664
+ * NAT-to-NAT case where one side restarted, or a connection that simply
665
+ * died and never recovered) it isn't enough. So when a peer stays
666
+ * non-online, we escalate to re-sending the actual friend-request — the
667
+ * strong kick that forces a fresh Carrier handshake. This is the
668
+ * automatic version of `agentnet friend-request <addr>`, so a private or
669
+ * friend-invited exit recovers on its own instead of needing a human to
670
+ * run a command (which an invited operator never will).
657
671
  */
658
672
  async kickSessionForever(carrierId, name) {
659
673
  while (this.isRunning) {
660
674
  try {
661
675
  await this.peerManager.kickSessionEstablishment(carrierId);
676
+ const f = this.peerManager
677
+ .getFriends()
678
+ .find((x) => x.carrierId === carrierId || x.pubkey === carrierId);
679
+ if (f && f.status === "online") {
680
+ // Healthy — clear the timer so a future drop re-heals promptly.
681
+ this.reFriendAt.delete(carrierId);
682
+ }
683
+ else if (f && f.status !== "online" && f.address) {
684
+ const last = this.reFriendAt.get(carrierId) ?? 0;
685
+ if (Date.now() - last >= DaemonServer.SELF_HEAL_REFRIEND_MS) {
686
+ this.reFriendAt.set(carrierId, Date.now());
687
+ this.logger.info(`Self-heal: ${name} is ${f.status} — re-sending friend-request to re-establish the session`);
688
+ void this.peerManager
689
+ .sendFriendRequest(f.address, "decentlan: self-heal")
690
+ .catch((err) => this.logger.debug(`self-heal friend-request ${name}: ${err instanceof Error ? err.message : err}`));
691
+ }
692
+ }
662
693
  }
663
694
  catch (err) {
664
695
  this.logger.debug(`kickSessionEstablishment ${name}: ${err}`);
@@ -33,16 +33,18 @@ export const BUILTIN_REGION_DOMAINS = {
33
33
  ".volcfcdn.com", ".volccdn.com", ".byteimg.com", ".bytedance.com",
34
34
  ".weibo.com", ".weibocdn.com", ".sinaimg.cn", ".youku.cn",
35
35
  ],
36
- // Japan-region sites / services that geo-fence to a JP IP, plus Binance
37
- // (routed through the Japan exit it's blocked/geo-restricted on many
38
- // other paths). .bnbstatic.com is Binance's asset CDN; without it the
39
- // site loads blank.
36
+ // Japan-region sites / services that geo-fence to a JP IP, plus crypto /
37
+ // prediction-market venues that geo-block the US (Binance, Hyperliquid,
38
+ // Polymarket) — routed through the Japan exit. .bnbstatic.com is Binance's
39
+ // asset CDN; without it the site loads blank.
40
40
  japan: [
41
41
  ".jp",
42
42
  ".nicovideo.jp", ".nimg.jp", ".dmm.com", ".dmm.co.jp",
43
43
  ".abema.tv", ".abema.io", ".tver.jp", ".unext.jp",
44
44
  ".radiko.jp", ".pixiv.net", ".pximg.net",
45
45
  ".binance.com", ".binance.org", ".bnbstatic.com", ".binancecnt.com",
46
+ ".hyperliquid.xyz", ".hyperliquid.cloud",
47
+ ".polymarket.com",
46
48
  ],
47
49
  // US region: Western sites commonly blocked/throttled from China (route via
48
50
  // a US exit), plus US-geo-fenced streaming.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/lan",
3
- "version": "0.1.73",
3
+ "version": "0.1.75",
4
4
  "description": "Private virtual LAN for self-hosted services and AI agents, built on Elastos Carrier. NAT-traversal, name service, ACL, all over a peer-to-peer mesh — no public IP required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",