@decentnetwork/peer 0.1.156 → 0.1.157
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 +61 -2
- package/package.json +1 -1
package/dist/peer.js
CHANGED
|
@@ -527,6 +527,10 @@ export class Peer {
|
|
|
527
527
|
// #initiateSession every few seconds for every friend; without this
|
|
528
528
|
// dedupe, lower-pubkey side floods the log with "deferring to peer".
|
|
529
529
|
#initiateSkipLogged = new Set();
|
|
530
|
+
/** Recently COMPLETED bulkmsg assemblies, same key, kept for the same 60s
|
|
531
|
+
* the assembly itself lives. Without it a retransmitted message reassembles
|
|
532
|
+
* a second time and is delivered twice. */
|
|
533
|
+
#bulkCompleted = new Map();
|
|
530
534
|
// In-flight Carrier BULKMSG reassemblies, keyed `${friendId}:${tid}`.
|
|
531
535
|
// Fragments are appended in arrival order (the lossless stream keeps
|
|
532
536
|
// them ordered) and the message completes when totalsz bytes arrived.
|
|
@@ -1613,6 +1617,29 @@ export class Peer {
|
|
|
1613
1617
|
return;
|
|
1614
1618
|
}
|
|
1615
1619
|
}
|
|
1620
|
+
// Inline files ride the TEXT channel, and the delivery envelope wraps them.
|
|
1621
|
+
//
|
|
1622
|
+
// The call sites check for an inline file BEFORE this function, i.e. before
|
|
1623
|
+
// the envelope comes off — so they were looking at "\x1eDNPACK1:<base64>",
|
|
1624
|
+
// which does not start with "{", and every inline file sent with delivery
|
|
1625
|
+
// tracking was reported as a text message instead. Measured 2026-08-31,
|
|
1626
|
+
// peer to peer: a 95-byte PNG arrived as 200 characters of JSON, and a
|
|
1627
|
+
// 300 KB one as 409,672 characters. Both transferred perfectly; both were
|
|
1628
|
+
// handed to the application as a wall of base64.
|
|
1629
|
+
//
|
|
1630
|
+
// The check belongs here, on the unwrapped text, where it sees what the
|
|
1631
|
+
// sender actually wrote. The call-site checks stay for envelope-less
|
|
1632
|
+
// senders (iOS and Android do not speak this envelope).
|
|
1633
|
+
//
|
|
1634
|
+
// ACK first: an inline file is delivered, and skipping the ACK because we
|
|
1635
|
+
// did not run the text handlers would make the sender retransmit forever.
|
|
1636
|
+
if (this.#tryEmitInlineFile(msg.pubkey, text, msg.via === "offline" ? "offline" : "online")) {
|
|
1637
|
+
if (deliveryId) {
|
|
1638
|
+
this.#rememberDeliveredTextId(deliveryId);
|
|
1639
|
+
void this.#sendTextAck(msg.pubkey, deliveryId).catch(() => undefined);
|
|
1640
|
+
}
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1616
1643
|
if (this.#textHandlers.size === 0) {
|
|
1617
1644
|
if (deliveryId)
|
|
1618
1645
|
this.#debugLog(`text delivery ${deliveryId} from ${msg.pubkey} has no onText handlers; not ACKing`);
|
|
@@ -3179,13 +3206,22 @@ export class Peer {
|
|
|
3179
3206
|
try {
|
|
3180
3207
|
const decoded = decodeCarrierPacket(carrierPacket);
|
|
3181
3208
|
if (decoded.type !== PACKET_TYPE_FRIEND_REQUEST) {
|
|
3209
|
+
// Was a bare `return`. An onion friend-request that arrived and did not
|
|
3210
|
+
// parse left NOTHING anywhere — the sender saw success, the recipient
|
|
3211
|
+
// saw no request, and there was no way to tell "never arrived" from
|
|
3212
|
+
// "arrived and was dropped". That is the single most-reported symptom
|
|
3213
|
+
// on this project and it was undiagnosable by construction.
|
|
3214
|
+
this.#debugLog(`friend-request from ${carrierIdFromPublicKey(senderPublicKey)} DROPPED: ` +
|
|
3215
|
+
`decoded as packet type ${decoded.type}, expected ${PACKET_TYPE_FRIEND_REQUEST}`);
|
|
3182
3216
|
return;
|
|
3183
3217
|
}
|
|
3184
3218
|
hello = decoded.hello;
|
|
3185
3219
|
name = decoded.name;
|
|
3186
3220
|
description = decoded.descr;
|
|
3187
3221
|
}
|
|
3188
|
-
catch {
|
|
3222
|
+
catch (error) {
|
|
3223
|
+
this.#debugLog(`friend-request from ${carrierIdFromPublicKey(senderPublicKey)} DROPPED: ` +
|
|
3224
|
+
`undecodable (${carrierPacket.length} bytes): ${error.message}`);
|
|
3189
3225
|
return;
|
|
3190
3226
|
}
|
|
3191
3227
|
const userid = carrierIdFromPublicKey(senderPublicKey);
|
|
@@ -3227,13 +3263,17 @@ export class Peer {
|
|
|
3227
3263
|
try {
|
|
3228
3264
|
const decoded = decodeCarrierPacket(packet);
|
|
3229
3265
|
if (decoded.type !== PACKET_TYPE_FRIEND_REQUEST) {
|
|
3266
|
+
this.#debugLog(`offline friend-request from ${fromUserId} DROPPED: decoded as packet ` +
|
|
3267
|
+
`type ${decoded.type}, expected ${PACKET_TYPE_FRIEND_REQUEST}`);
|
|
3230
3268
|
return;
|
|
3231
3269
|
}
|
|
3232
3270
|
helloText = decoded.hello;
|
|
3233
3271
|
name = decoded.name;
|
|
3234
3272
|
description = decoded.descr;
|
|
3235
3273
|
}
|
|
3236
|
-
catch {
|
|
3274
|
+
catch (error) {
|
|
3275
|
+
this.#debugLog(`offline friend-request from ${fromUserId} DROPPED: undecodable ` +
|
|
3276
|
+
`(${packet.length} bytes): ${error.message}`);
|
|
3237
3277
|
return;
|
|
3238
3278
|
}
|
|
3239
3279
|
// Already an established friend? Ignore this (re-)request. Auto-friend
|
|
@@ -4763,6 +4803,24 @@ export class Peer {
|
|
|
4763
4803
|
this.#bulkAssembly.delete(key);
|
|
4764
4804
|
}
|
|
4765
4805
|
const key = `${friendId}:${frag.tid.toString()}`;
|
|
4806
|
+
// A completed assembly is deleted, so a second copy of the same fragments
|
|
4807
|
+
// starts a fresh entry and completes AGAIN — the application gets the same
|
|
4808
|
+
// message twice. Duplicate FRAGMENTS were already ignored; a duplicate
|
|
4809
|
+
// whole MESSAGE was not.
|
|
4810
|
+
//
|
|
4811
|
+
// It shows up on the plain send path (a native peer, or a JS peer before
|
|
4812
|
+
// userinfo has settled), because that path carries no delivery id and the
|
|
4813
|
+
// text-level dedupe has nothing to key on. Measured 2026-08-31: one
|
|
4814
|
+
// sendInlineFile call, two `bulkmsg complete (409672 bytes)` and two
|
|
4815
|
+
// identical 300 KB images delivered.
|
|
4816
|
+
for (const [k, at] of this.#bulkCompleted) {
|
|
4817
|
+
if (at < now - 60_000)
|
|
4818
|
+
this.#bulkCompleted.delete(k);
|
|
4819
|
+
}
|
|
4820
|
+
if (this.#bulkCompleted.has(key)) {
|
|
4821
|
+
this.#debugLog(`bulkmsg ${key} already completed — dropping duplicate`);
|
|
4822
|
+
return undefined;
|
|
4823
|
+
}
|
|
4766
4824
|
let entry = this.#bulkAssembly.get(key);
|
|
4767
4825
|
if (!entry) {
|
|
4768
4826
|
entry = { total: 0, frags: new Map(), got: 0, expireAtMs: now + 60_000 };
|
|
@@ -4787,6 +4845,7 @@ export class Peer {
|
|
|
4787
4845
|
if (entry.total === 0 || entry.got < entry.total)
|
|
4788
4846
|
return undefined;
|
|
4789
4847
|
this.#bulkAssembly.delete(key);
|
|
4848
|
+
this.#bulkCompleted.set(key, now);
|
|
4790
4849
|
if (entry.got > entry.total) {
|
|
4791
4850
|
this.#debugLog(`bulkmsg from ${friendId} got ${entry.got} > total ${entry.total} — dropped`);
|
|
4792
4851
|
return undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/peer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.157",
|
|
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",
|