@decentnetwork/peer 0.1.19 → 0.1.21

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.js CHANGED
@@ -188,6 +188,10 @@ export class Peer {
188
188
  // session entry exists yet so the connection loop does not flood DHT-PK
189
189
  // requests when route discovery keeps failing.
190
190
  #dhtPkSendCooldown = new Map();
191
+ // Per-friend cooldown for re-asserting the TCP-relay route toward an
192
+ // unconnected friend (the "accepted friend that never connects" wedge —
193
+ // requestRoute only fired once at startup and was never retried).
194
+ #routeRequestCooldown = new Map();
191
195
  // Per-friend consecutive "no routes available" count for DHT-PK so the
192
196
  // backoff grows if a friend stays unreachable, instead of retrying every
193
197
  // 25s forever for stale persisted entries.
@@ -719,7 +723,8 @@ export class Peer {
719
723
  address,
720
724
  nospam,
721
725
  hello: hello ?? existing?.hello,
722
- status: existing?.status ?? "requested"
726
+ status: existing?.status ?? "requested",
727
+ requestedAt: existing?.requestedAt ?? Date.now()
723
728
  });
724
729
  this.#persistFriends();
725
730
  // Tell every connected TCP relay we want this friend routed; the
@@ -2387,6 +2392,29 @@ export class Peer {
2387
2392
  // nothing re-tried it. Counting the relay route lets the retry fire.
2388
2393
  const haveEndpoint = (friend.remoteHost && friend.remotePort) || session?.remote || session?.hasTcpRoute;
2389
2394
  if (!haveEndpoint) {
2395
+ // No UDP endpoint AND no relay route yet. For a peer whose DHT
2396
+ // self-announce never stored (WSL2, symmetric NAT, restrictive
2397
+ // firewall), neither onion discovery nor UDP punch can ever find
2398
+ // them — the ONLY bootstrap is the TCP relay: ask our relays to
2399
+ // route to the friend's pubkey, and when they're also connected to
2400
+ // a shared relay the pool fires `friendOnline` -> #initiateSession.
2401
+ // requestRoute was only issued once at start(); if the friend or a
2402
+ // relay wasn't connected in that instant it was never retried, so an
2403
+ // accepted friend could sit at "requested" forever (the WSL-client-
2404
+ // never-gets-an-IP bug). Re-assert it here on a cooldown — cheap and
2405
+ // idempotent — so it eventually catches once both ends share a relay.
2406
+ const lastRouteReq = this.#routeRequestCooldown.get(friendId) ?? 0;
2407
+ if (this.#tcpRelays && now - lastRouteReq > 15_000) {
2408
+ try {
2409
+ const pk = base58ToBytes(friend.pubkey);
2410
+ if (pk.length === 32) {
2411
+ this.#tcpRelays.requestRoute(pk);
2412
+ this.#routeRequestCooldown.set(friendId, now);
2413
+ this.#debugLog(`re-requesting relay route for unconnected friend ${friendId}`);
2414
+ }
2415
+ }
2416
+ catch { /* skip malformed pubkey */ }
2417
+ }
2390
2418
  const dhtPk = session?.friendDhtPublicKey;
2391
2419
  if (dhtPk) {
2392
2420
  const found = await this.#discoverAndCacheFriendEndpoint(friendId, dhtPk).catch(() => false);
@@ -9,5 +9,9 @@ export type FriendRecord = {
9
9
  remoteHost?: string;
10
10
  remotePort?: number;
11
11
  hello?: string;
12
+ /** When we sent the outbound friend request (ms epoch). Set once, even
13
+ * while status stays "requested", so UIs can show how long a request
14
+ * has been pending. */
15
+ requestedAt?: number;
12
16
  acceptedAt?: number;
13
17
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/peer",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
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",