@decentnetwork/peer 0.1.43 → 0.1.45

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.
Files changed (2) hide show
  1. package/dist/peer.js +27 -3
  2. package/package.json +1 -1
package/dist/peer.js CHANGED
@@ -1537,6 +1537,16 @@ export class Peer {
1537
1537
  if (!opened) {
1538
1538
  continue;
1539
1539
  }
1540
+ // De-duplicate. The dual-send path delivers each lossless packet over
1541
+ // BOTH the UDP and relay transports with the SAME packet number, so
1542
+ // without this guard every chat message (and every file-data chunk) is
1543
+ // dispatched — and stored / shown / appended — twice. Drop anything at or
1544
+ // below the receive low-water mark, like toxcore net_crypto drops packets
1545
+ // below buffer_start. Must run BEFORE the nonce advance below so a
1546
+ // duplicate doesn't desync the receive nonce.
1547
+ if (opened.packetNumber < (state.receiveBufferStart ?? 0)) {
1548
+ continue;
1549
+ }
1540
1550
  state.peerBaseNonce[state.peerBaseNonce.length - 2] = packet[1];
1541
1551
  state.peerBaseNonce[state.peerBaseNonce.length - 1] = packet[2];
1542
1552
  incrementNonce(state.peerBaseNonce);
@@ -2802,9 +2812,23 @@ export class Peer {
2802
2812
  firstError = error;
2803
2813
  }
2804
2814
  }
2805
- // Fresh direct path → send over UDP only: no relay fan-out, no
2806
- // duplicates, no relay backlog. Applies to both data and control.
2807
- if (udpFresh && udpOk) {
2815
+ // Fresh direct path → send over UDP only but ONLY for bulk data.
2816
+ // Bulk is high-volume and must avoid relay fan-out / backlog, so once
2817
+ // the direct path is fresh it rides UDP exclusively.
2818
+ //
2819
+ // Low-volume traffic (chat 64 + control keepalives / endpoint offers /
2820
+ // profile) instead ALSO goes over the relay even when the direct path
2821
+ // looks fresh, because `udpFresh` is derived from INBOUND UDP
2822
+ // (lastUdpRecvMs) and inbound reachability does NOT imply outbound
2823
+ // reachability. On a symmetric / CGNAT peer (e.g. cellular T-Mobile
2824
+ // 172.56.x) the peer's pings keep arriving — so udpFresh stays true —
2825
+ // while our packets to the source port we observed are silently
2826
+ // black-holed: the peer never received from us on that port, so its NAT
2827
+ // has no inbound mapping for our endpoint. Returning UDP-only here would
2828
+ // fire chat into a dead endpoint forever — the exact "peer can send to us
2829
+ // but can't receive from us" one-way failure. net_crypto dedups by packet
2830
+ // number, so the extra relay copy is harmless for sparse chat / control.
2831
+ if (isBulkData && udpFresh && udpOk) {
2808
2832
  return;
2809
2833
  }
2810
2834
  // Tier 2: TURN relay (tokyo) — a fast (~280ms) stable fallback that
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/peer",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
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",