@decentnetwork/peer 0.1.2 → 0.1.4

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/peer.d.ts CHANGED
@@ -71,6 +71,28 @@ export declare class Peer {
71
71
  hasTcpRoute: boolean;
72
72
  transport: "udp" | "tcp-relay" | "both" | "none";
73
73
  lastPingRecvMs: number | null;
74
+ /** OS-assigned UDP port THIS node is listening on. Useful to confirm
75
+ * we even have a UDP socket bound. */
76
+ ourLocalUdpPort: number | null;
77
+ /** Cached UDP endpoint for the peer from a previous online state
78
+ * (persisted across restarts). Set != null means UDP holepunch
79
+ * has succeeded at some point — but null when we've only ever
80
+ * reached them via TCP-relay. Tells us whether discovery has
81
+ * ever found a usable UDP endpoint. */
82
+ friendUdpEndpoint: {
83
+ host: string;
84
+ port: number;
85
+ } | null;
86
+ /** UDP endpoints picked up by recent DHT discovery for this peer,
87
+ * whether or not the cookie exchange has succeeded yet. If this
88
+ * is empty AND friendUdpEndpoint is null AND we keep getting
89
+ * tcp-relay, discovery itself is broken — we don't even know
90
+ * where to send a cookie request. */
91
+ endpointCandidatesCount: number;
92
+ /** Last time we sent an outbound cookie request via UDP for this
93
+ * peer (null = never). Used to confirm Phase 1.2 retries are
94
+ * actually firing. */
95
+ cookieRequestSentMs: number | null;
74
96
  } | null;
75
97
  waitForFriendRequest(timeoutMs?: number): Promise<FriendRequest>;
76
98
  }
package/dist/peer.js CHANGED
@@ -772,6 +772,7 @@ export class Peer {
772
772
  const s = this.#friendSessions.get(pubkey);
773
773
  if (!s)
774
774
  return null;
775
+ const friend = this.#friends.get(pubkey);
775
776
  // session.remote can be a synthetic `tcp:<dhtpk>:0` placeholder
776
777
  // when the TCP relay path reports an endpoint with no real UDP
777
778
  // address; treat those as no-UDP for reporting.
@@ -785,12 +786,22 @@ export class Peer {
785
786
  : s.hasTcpRoute
786
787
  ? "tcp-relay"
787
788
  : "none";
789
+ const friendUdp = friend?.remoteHost &&
790
+ friend.remotePort &&
791
+ !friend.remoteHost.startsWith("tcp:") &&
792
+ friend.remotePort !== 0
793
+ ? { host: friend.remoteHost, port: friend.remotePort }
794
+ : null;
788
795
  return {
789
796
  established: s.established === true,
790
797
  udpRemote: realUdp,
791
798
  hasTcpRoute: s.hasTcpRoute === true,
792
799
  transport,
793
800
  lastPingRecvMs: s.lastPingRecvMs ?? null,
801
+ ourLocalUdpPort: this.#udp?.localPort() ?? null,
802
+ friendUdpEndpoint: friendUdp,
803
+ endpointCandidatesCount: s.endpointCandidates?.length ?? 0,
804
+ cookieRequestSentMs: s.cookieRequestSentMs ?? null,
794
805
  };
795
806
  }
796
807
  waitForFriendRequest(timeoutMs = 30000) {
@@ -2080,13 +2091,20 @@ export class Peer {
2080
2091
  void this.#sendOnionDhtPk(friendRealPk).catch((error) => {
2081
2092
  this.#debugLog(`UDP retry: dhtpk_send for ${friendId} failed: ${error.message}`);
2082
2093
  });
2083
- // 2. Try to discover the peer's UDP endpoint and kick a fresh
2084
- // cookie request via UDP. If it lands, session.remote
2085
- // becomes a real UDP endpoint and the next outbound
2086
- // packet goes direct.
2094
+ // 2. Try to discover the peer's UDP endpoint and kick a
2095
+ // fresh cookie request via UDP. discoverAndCacheFriend
2096
+ // Endpoint accepts EITHER the DHT-PK (preferred
2097
+ // direct DHT lookup) OR the friend's real identity
2098
+ // public key (onion-routed lookup). When the session
2099
+ // came up via TCP-relay only, neither side has
2100
+ // received an onion DHT-PK from the other yet, so
2101
+ // session.friendDhtPublicKey is null. Falling back
2102
+ // to friendRealPk keeps the retry from being a no-op
2103
+ // in exactly the case it was designed to fix.
2087
2104
  const dhtPk = session.friendDhtPublicKey;
2088
- if (dhtPk) {
2089
- void this.#discoverAndCacheFriendEndpoint(friendId, dhtPk)
2105
+ const searchKey = dhtPk ?? friendRealPk;
2106
+ if (searchKey && searchKey.length === 32) {
2107
+ void this.#discoverAndCacheFriendEndpoint(friendId, searchKey)
2090
2108
  .then((found) => {
2091
2109
  if (found) {
2092
2110
  return this.#initiateSession(friendId).catch(() => undefined);
@@ -2094,12 +2112,13 @@ export class Peer {
2094
2112
  })
2095
2113
  .catch(() => undefined);
2096
2114
  }
2097
- else if (friend.remoteHost && friend.remotePort) {
2098
- // We already have a real UDP endpoint cached — just
2099
- // retry the cookie request to it.
2115
+ // Always also retry initiate if we have a cached real
2116
+ // UDP endpoint covers the case where discovery
2117
+ // succeeded earlier but the cookie request was lost.
2118
+ if (friend.remoteHost && friend.remotePort) {
2100
2119
  void this.#initiateSession(friendId).catch(() => undefined);
2101
2120
  }
2102
- this.#debugLog(`UDP retry attempt for ${friendId} (currently on TCP relay)`);
2121
+ this.#debugLog(`UDP retry attempt for ${friendId} (currently on TCP relay, search=${dhtPk ? "dht-pk" : "real-pk"})`);
2103
2122
  }
2104
2123
  }
2105
2124
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/peer",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Pure TypeScript port of Elastos Carrier (toxcore-derived) P2P messaging. DHT, onion routing, TCP relay, FlatBuffers app payloads, Express offline relay. Wire-compatible with iOS Beagle and the Carrier C SDK.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",