@decentnetwork/peer
v0.1.141
Published
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.
Downloads
5,217
Readme
@decentnetwork/peer
Pure TypeScript / Node.js port of the Elastos Carrier Native SDK (Carrier-flavored toxcore). Wire-compatible with the C SDK and iOS Beagle — the same DHT, onion routing, FlatBuffers app payloads, TCP relay protocol, and Express HTTP store-and-forward relay. End-to-end interop with iOS Beagle on iPad is verified working.
pnpm add @decentnetwork/peer
# or
npm install @decentnetwork/peer30-second example
import { Peer } from "@decentnetwork/peer";
const peer = await Peer.create({
keyFile: "./peer.save",
bootstrapNodes: [
{
host: "47.100.103.201",
port: 33445,
pk: "CX1XH419p4xJ5SV4KvDxBeKYSRdMJW9QpdWJY8owUxHd"
}
// (more bootstraps recommended — see docs/USAGE_GUIDE.md)
],
compatibilityMode: "legacy"
});
await peer.start();
await peer.joinNetwork();
console.log("my address:", peer.address());
peer.onText((msg) => {
console.log(`from ${msg.pubkey}: ${msg.text}`);
});
// Send a friend request to a peer (their address comes from their UI):
await peer.sendFriendRequest(
"ZJxuWL9SDqdvunnCSMLUd5jyGCaBV44G6THYaQS7ZaZAz1wmt4nz",
"hello!"
);
// Once they accept and the session establishes, send a message:
await peer.sendText(
"FhbohSLrj5UjdyFKCEYNeEWAPq3QD9hRg6hsso5ipag2",
"first message via @decentnetwork/peer"
);
await peer.stop();Optional CLI
For users who just want to run a peer without writing JS, the package
also ships an optional decent-peer binary (the library export is
unchanged — the CLI is additive):
npm install -g @decentnetwork/peer
decent-peer init # creates ~/.decent-peer/
decent-peer address # print your address
decent-peer listen # daemon mode (Ctrl-C to stop)
decent-peer send <addr> "hello" # one-shot send
decent-peer add-friend <addr> "hi from me" # one-shot friend request
decent-peer accept <pubkey> # accept a pending request
# zero-install:
npx @decentnetwork/peer listenConfig lives at ~/.decent-peer/config.json (override with the
DECENT_PEER_CONFIG env var). The keyfile at ~/.decent-peer/peer.save
is your identity — back it up.
Documentation
- Usage guide: full developer-facing tutorial with sample apps —
see
docs/USAGE_GUIDE.md - Protocol overview: actors, identities, lifecycle —
docs/PROTOCOL_OVERVIEW.md - Carrier vs Tox/Onion: where Carrier diverges from upstream toxcore —
docs/CARRIER_VS_TOX.md - Discovery flow: the four discovery stages with timing budgets —
docs/DISCOVERY_FLOW.md - iOS interop playbook: real-world bug catalog and debug markers —
docs/IOS_INTEROP_PLAYBOOK.md
License
GPL-3.0-or-later. Same as upstream toxcore.
Tuning peer discovery
Discovery is the loop that finds a friend's current UDP endpoint when there is no live session. It costs real CPU — every onion request is three X25519 scalar multiplications, one per layer — so the defaults are a compromise, and a node with unusual friend counts or hardware may want to move them.
All are environment variables read at startup.
| Axis | Variable | Default | What it controls |
|---|---|---|---|
| Interval | DECENT_DHT_PK_ANNOUNCE_COOLDOWN_MS | 25000 | Minimum gap between lookups for the same friend |
| Backoff cap | DECENT_ONION_LOOKUP_MAX_BACKOFF_MS | 120000 | Ceiling once a friend keeps failing to resolve |
| Breadth | DECENT_FRIEND_ROUTE_MAX_ATTEMPTS | 24 | Nodes queried per sweep |
| Depth | DECENT_ONION_DATA_ATTEMPTS | 5 | Retries per onion data packet |
| Self-announce interval | DECENT_SELF_ANNOUNCE_INTERVAL_MS | 20000 | How often we re-announce ourselves |
| Self-announce breadth | DECENT_SELF_ANNOUNCE_TARGETS | 16 | Nodes we announce to |
Which knob to turn
Turn the interval, not the breadth. Cost is breadth x frequency, so both
reduce CPU — but they fail differently. Narrowing breadth was tried and
reverted: iOS peers appear in short windows and are only caught by a wide
sweep, so a narrow one loses them outright rather than finding them late.
Lengthening the interval degrades gracefully — the worst case is simply
ONION_LOOKUP_MAX_BACKOFF_MS, the longest you can go without noticing a peer
that came back.
Read the backoff cap as exactly that: the worst-case time to notice a friend returning. Raising it to save CPU is a direct trade against how quickly the node reacts.
Symptoms and responses
- High steady CPU with offline friends. Expected: each unreachable friend
is swept on its own schedule, so cost scales with how many friends are not
there. Raise
DECENT_ONION_LOOKUP_MAX_BACKOFF_MS. Measured on a 2-core box with ~5 unreachable friends, a flat 25s interval held the daemon at ~22% of a core purely on lookups. - A peer is online but never seen. Lower the interval, or raise breadth if it was lowered. Do not lower breadth further.
- Small or battery-powered device. Raise the interval and the backoff cap together; leave breadth alone.
