@decentnetwork/peer 0.1.0

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 (79) hide show
  1. package/LICENSE +31 -0
  2. package/README.md +97 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +245 -0
  5. package/dist/compat/address.d.ts +13 -0
  6. package/dist/compat/address.js +69 -0
  7. package/dist/compat/bootstrap.d.ts +29 -0
  8. package/dist/compat/bootstrap.js +178 -0
  9. package/dist/compat/dht.d.ts +3 -0
  10. package/dist/compat/dht.js +9 -0
  11. package/dist/compat/express.d.ts +21 -0
  12. package/dist/compat/express.js +263 -0
  13. package/dist/compat/friend.d.ts +4 -0
  14. package/dist/compat/friend.js +12 -0
  15. package/dist/compat/net-crypto.d.ts +84 -0
  16. package/dist/compat/net-crypto.js +278 -0
  17. package/dist/compat/packet.d.ts +55 -0
  18. package/dist/compat/packet.js +154 -0
  19. package/dist/compat/session.d.ts +3 -0
  20. package/dist/compat/session.js +7 -0
  21. package/dist/compat/tcp-relay-pool.d.ts +85 -0
  22. package/dist/compat/tcp-relay-pool.js +342 -0
  23. package/dist/compat/tcp-relay.d.ts +96 -0
  24. package/dist/compat/tcp-relay.js +489 -0
  25. package/dist/compat/text.d.ts +3 -0
  26. package/dist/compat/text.js +8 -0
  27. package/dist/compat/tox-dht-crypto.d.ts +18 -0
  28. package/dist/compat/tox-dht-crypto.js +69 -0
  29. package/dist/compat/tox-onion.d.ts +66 -0
  30. package/dist/compat/tox-onion.js +172 -0
  31. package/dist/crypto/box.d.ts +1 -0
  32. package/dist/crypto/box.js +3 -0
  33. package/dist/crypto/keypair.d.ts +5 -0
  34. package/dist/crypto/keypair.js +37 -0
  35. package/dist/crypto/nonce.d.ts +1 -0
  36. package/dist/crypto/nonce.js +1 -0
  37. package/dist/crypto/sign.d.ts +1 -0
  38. package/dist/crypto/sign.js +3 -0
  39. package/dist/index.d.ts +10 -0
  40. package/dist/index.js +6 -0
  41. package/dist/peer.d.ts +45 -0
  42. package/dist/peer.js +3425 -0
  43. package/dist/runtime/errors.d.ts +3 -0
  44. package/dist/runtime/errors.js +6 -0
  45. package/dist/runtime/events.d.ts +4 -0
  46. package/dist/runtime/events.js +1 -0
  47. package/dist/runtime/lifecycle.d.ts +7 -0
  48. package/dist/runtime/lifecycle.js +12 -0
  49. package/dist/store/config.d.ts +2 -0
  50. package/dist/store/config.js +1 -0
  51. package/dist/store/friends.d.ts +13 -0
  52. package/dist/store/friends.js +1 -0
  53. package/dist/store/state.d.ts +3 -0
  54. package/dist/store/state.js +1 -0
  55. package/dist/transport/socket.d.ts +4 -0
  56. package/dist/transport/socket.js +1 -0
  57. package/dist/transport/tcp.d.ts +3 -0
  58. package/dist/transport/tcp.js +5 -0
  59. package/dist/transport/udp.d.ts +24 -0
  60. package/dist/transport/udp.js +90 -0
  61. package/dist/types/bootstrap.d.ts +2 -0
  62. package/dist/types/bootstrap.js +1 -0
  63. package/dist/types/dht.d.ts +3 -0
  64. package/dist/types/dht.js +1 -0
  65. package/dist/types/friend.d.ts +1 -0
  66. package/dist/types/friend.js +1 -0
  67. package/dist/types/message.d.ts +1 -0
  68. package/dist/types/message.js +1 -0
  69. package/dist/types/peer.d.ts +51 -0
  70. package/dist/types/peer.js +1 -0
  71. package/dist/types/session.d.ts +1 -0
  72. package/dist/types/session.js +1 -0
  73. package/dist/utils/base58.d.ts +2 -0
  74. package/dist/utils/base58.js +51 -0
  75. package/dist/utils/bytes.d.ts +4 -0
  76. package/dist/utils/bytes.js +31 -0
  77. package/docs/INSTALL.md +103 -0
  78. package/docs/USAGE_GUIDE.md +724 -0
  79. package/package.json +77 -0
@@ -0,0 +1,69 @@
1
+ import nacl from "tweetnacl";
2
+ import { concatBytes, randomBytes } from "../utils/bytes.js";
3
+ export const NET_PACKET_CRYPTO = 0x20;
4
+ export const CRYPTO_PACKET_FRIEND_REQ = 32;
5
+ export const CRYPTO_PACKET_DHTPK = 156;
6
+ export const CRYPTO_PACKET_NAT_PING = 254;
7
+ const PUBLIC_KEY_SIZE = 32;
8
+ const NONCE_SIZE = 24;
9
+ const MAC_SIZE = 16;
10
+ const MAX_CRYPTO_REQUEST_SIZE = 1024;
11
+ export function createToxDhtCryptoRequest(opts) {
12
+ if (opts.receiverPublicKey.length !== PUBLIC_KEY_SIZE) {
13
+ throw new Error(`receiver public key must be ${PUBLIC_KEY_SIZE} bytes`);
14
+ }
15
+ if (!Number.isInteger(opts.requestId) || opts.requestId < 0 || opts.requestId > 0xff) {
16
+ throw new Error("tox DHT crypto request id must be a uint8");
17
+ }
18
+ if (opts.data.length + 1 + MAC_SIZE > MAX_CRYPTO_REQUEST_SIZE) {
19
+ throw new Error("tox DHT crypto request data is too large");
20
+ }
21
+ const nonce = randomBytes(NONCE_SIZE);
22
+ const plain = concatBytes([Uint8Array.of(opts.requestId), opts.data]);
23
+ const encrypted = nacl.box(plain, nonce, opts.receiverPublicKey, opts.sender.secretKey);
24
+ return concatBytes([
25
+ Uint8Array.of(NET_PACKET_CRYPTO),
26
+ opts.receiverPublicKey,
27
+ opts.sender.publicKey,
28
+ nonce,
29
+ encrypted
30
+ ]);
31
+ }
32
+ export function openToxDhtCryptoRequest(packet, self) {
33
+ if (packet.length <= 1 + PUBLIC_KEY_SIZE * 2 + NONCE_SIZE + MAC_SIZE) {
34
+ return undefined;
35
+ }
36
+ if (packet.length > MAX_CRYPTO_REQUEST_SIZE + MAC_SIZE) {
37
+ return undefined;
38
+ }
39
+ if (packet[0] !== NET_PACKET_CRYPTO) {
40
+ return undefined;
41
+ }
42
+ const receiverPublicKey = packet.slice(1, 1 + PUBLIC_KEY_SIZE);
43
+ if (!bytesEqual(receiverPublicKey, self.publicKey)) {
44
+ return undefined;
45
+ }
46
+ const senderPublicKey = packet.slice(1 + PUBLIC_KEY_SIZE, 1 + PUBLIC_KEY_SIZE * 2);
47
+ const nonce = packet.slice(1 + PUBLIC_KEY_SIZE * 2, 1 + PUBLIC_KEY_SIZE * 2 + NONCE_SIZE);
48
+ const encrypted = packet.slice(1 + PUBLIC_KEY_SIZE * 2 + NONCE_SIZE);
49
+ const plain = nacl.box.open(encrypted, nonce, senderPublicKey, self.secretKey);
50
+ if (!plain || plain.length === 0) {
51
+ return undefined;
52
+ }
53
+ return {
54
+ receiverPublicKey,
55
+ senderPublicKey,
56
+ requestId: plain[0],
57
+ data: plain.slice(1)
58
+ };
59
+ }
60
+ function bytesEqual(a, b) {
61
+ if (a.length !== b.length) {
62
+ return false;
63
+ }
64
+ let diff = 0;
65
+ for (let i = 0; i < a.length; i++) {
66
+ diff |= a[i] ^ b[i];
67
+ }
68
+ return diff === 0;
69
+ }
@@ -0,0 +1,66 @@
1
+ export declare const NET_PACKET_ONION_ANNOUNCE_REQUEST = 131;
2
+ export declare const NET_PACKET_ONION_ANNOUNCE_RESPONSE = 132;
3
+ export declare const NET_PACKET_ONION_DATA_REQUEST = 133;
4
+ export declare const NET_PACKET_ONION_DATA_RESPONSE = 134;
5
+ export declare const ONION_FRIEND_REQUEST_ID = 32;
6
+ export declare const NET_PACKET_ONION_REQUEST_0 = 128;
7
+ export type OnionAnnounceResponse = {
8
+ sendBack: Uint8Array;
9
+ isStored: number;
10
+ pingOrDataPublicKey: Uint8Array;
11
+ nodes: Uint8Array;
12
+ };
13
+ export declare function createOnionAnnounceRequest(opts: {
14
+ senderPublicKey: Uint8Array;
15
+ senderSecretKey: Uint8Array;
16
+ nodePublicKey: Uint8Array;
17
+ pingId: Uint8Array;
18
+ searchPublicKey: Uint8Array;
19
+ dataPublicKey: Uint8Array;
20
+ sendBack: Uint8Array;
21
+ }): Uint8Array;
22
+ export declare function openOnionAnnounceResponse(packet: Uint8Array, opts: {
23
+ requesterSecretKey: Uint8Array;
24
+ nodePublicKey: Uint8Array;
25
+ }): OnionAnnounceResponse | undefined;
26
+ export declare function createOnionDataRequest(opts: {
27
+ destinationPublicKey: Uint8Array;
28
+ routePublicKey: Uint8Array;
29
+ nonce: Uint8Array;
30
+ onionDataPacket: Uint8Array;
31
+ }): Uint8Array;
32
+ export declare function createOnionDataPacket(opts: {
33
+ senderPublicKey: Uint8Array;
34
+ senderSecretKey: Uint8Array;
35
+ receiverPublicKey: Uint8Array;
36
+ nonce: Uint8Array;
37
+ innerPacketId: number;
38
+ innerPayload: Uint8Array;
39
+ }): Uint8Array;
40
+ export declare function createOnionRequest0(opts: {
41
+ nodeAPublicKey: Uint8Array;
42
+ nodeBHost: string;
43
+ nodeBPort: number;
44
+ nodeBPublicKey: Uint8Array;
45
+ nodeCHost: string;
46
+ nodeCPort: number;
47
+ nodeCPublicKey: Uint8Array;
48
+ nodeDHost: string;
49
+ nodeDPort: number;
50
+ payloadForNodeD: Uint8Array;
51
+ }): Uint8Array;
52
+ export declare function openOnionDataResponse(packet: Uint8Array, opts: {
53
+ dataSecretKey: Uint8Array;
54
+ }): {
55
+ nonce: Uint8Array;
56
+ sourceTempPublicKey: Uint8Array;
57
+ payload: Uint8Array;
58
+ } | undefined;
59
+ export declare function openOnionDataPacket(payload: Uint8Array, opts: {
60
+ receiverSecretKey: Uint8Array;
61
+ nonce: Uint8Array;
62
+ }): {
63
+ senderPublicKey: Uint8Array;
64
+ innerPacketId: number;
65
+ innerPayload: Uint8Array;
66
+ } | undefined;
@@ -0,0 +1,172 @@
1
+ import nacl from "tweetnacl";
2
+ import { concatBytes, randomBytes } from "../utils/bytes.js";
3
+ export const NET_PACKET_ONION_ANNOUNCE_REQUEST = 0x83;
4
+ export const NET_PACKET_ONION_ANNOUNCE_RESPONSE = 0x84;
5
+ export const NET_PACKET_ONION_DATA_REQUEST = 0x85;
6
+ export const NET_PACKET_ONION_DATA_RESPONSE = 0x86;
7
+ export const ONION_FRIEND_REQUEST_ID = 32;
8
+ export const NET_PACKET_ONION_REQUEST_0 = 0x80;
9
+ const KEY_SIZE = 32;
10
+ const NONCE_SIZE = 24;
11
+ const SEND_BACK_SIZE = 8;
12
+ const PACKED_IP_PORT_SIZE = 19;
13
+ export function createOnionAnnounceRequest(opts) {
14
+ ensureLen(opts.senderPublicKey, KEY_SIZE, "sender public key");
15
+ ensureLen(opts.senderSecretKey, KEY_SIZE, "sender secret key");
16
+ ensureLen(opts.nodePublicKey, KEY_SIZE, "node public key");
17
+ ensureLen(opts.pingId, KEY_SIZE, "ping id");
18
+ ensureLen(opts.searchPublicKey, KEY_SIZE, "search public key");
19
+ ensureLen(opts.dataPublicKey, KEY_SIZE, "data public key");
20
+ ensureLen(opts.sendBack, SEND_BACK_SIZE, "sendback");
21
+ const nonce = randomBytes(NONCE_SIZE);
22
+ const plain = concatBytes([
23
+ opts.pingId,
24
+ opts.searchPublicKey,
25
+ opts.dataPublicKey,
26
+ opts.sendBack
27
+ ]);
28
+ const encrypted = nacl.box(plain, nonce, opts.nodePublicKey, opts.senderSecretKey);
29
+ return concatBytes([
30
+ Uint8Array.of(NET_PACKET_ONION_ANNOUNCE_REQUEST),
31
+ nonce,
32
+ opts.senderPublicKey,
33
+ encrypted
34
+ ]);
35
+ }
36
+ export function openOnionAnnounceResponse(packet, opts) {
37
+ if (packet.length < 1 + SEND_BACK_SIZE + NONCE_SIZE + 1 + KEY_SIZE + 16) {
38
+ return undefined;
39
+ }
40
+ if (packet[0] !== NET_PACKET_ONION_ANNOUNCE_RESPONSE) {
41
+ return undefined;
42
+ }
43
+ const sendBack = packet.slice(1, 1 + SEND_BACK_SIZE);
44
+ const nonce = packet.slice(1 + SEND_BACK_SIZE, 1 + SEND_BACK_SIZE + NONCE_SIZE);
45
+ const encrypted = packet.slice(1 + SEND_BACK_SIZE + NONCE_SIZE);
46
+ const plain = nacl.box.open(encrypted, nonce, opts.nodePublicKey, opts.requesterSecretKey);
47
+ if (!plain || plain.length < 1 + KEY_SIZE) {
48
+ return undefined;
49
+ }
50
+ return {
51
+ sendBack,
52
+ isStored: plain[0],
53
+ pingOrDataPublicKey: plain.slice(1, 1 + KEY_SIZE),
54
+ nodes: plain.slice(1 + KEY_SIZE)
55
+ };
56
+ }
57
+ export function createOnionDataRequest(opts) {
58
+ ensureLen(opts.destinationPublicKey, KEY_SIZE, "destination public key");
59
+ ensureLen(opts.routePublicKey, KEY_SIZE, "route public key");
60
+ ensureLen(opts.nonce, NONCE_SIZE, "nonce");
61
+ if (opts.onionDataPacket.length === 0) {
62
+ throw new Error("onion data payload must not be empty");
63
+ }
64
+ const temp = nacl.box.keyPair();
65
+ const encrypted = nacl.box(opts.onionDataPacket, opts.nonce, opts.routePublicKey, temp.secretKey);
66
+ return concatBytes([
67
+ Uint8Array.of(NET_PACKET_ONION_DATA_REQUEST),
68
+ opts.destinationPublicKey,
69
+ opts.nonce,
70
+ temp.publicKey,
71
+ encrypted
72
+ ]);
73
+ }
74
+ export function createOnionDataPacket(opts) {
75
+ ensureLen(opts.senderPublicKey, KEY_SIZE, "sender public key");
76
+ ensureLen(opts.senderSecretKey, KEY_SIZE, "sender secret key");
77
+ ensureLen(opts.receiverPublicKey, KEY_SIZE, "receiver public key");
78
+ ensureLen(opts.nonce, NONCE_SIZE, "nonce");
79
+ if (!Number.isInteger(opts.innerPacketId) || opts.innerPacketId < 0 || opts.innerPacketId > 0xff) {
80
+ throw new Error("inner packet id must be uint8");
81
+ }
82
+ const plain = concatBytes([Uint8Array.of(opts.innerPacketId), opts.innerPayload]);
83
+ const encrypted = nacl.box(plain, opts.nonce, opts.receiverPublicKey, opts.senderSecretKey);
84
+ return concatBytes([opts.senderPublicKey, encrypted]);
85
+ }
86
+ export function createOnionRequest0(opts) {
87
+ ensureLen(opts.nodeAPublicKey, KEY_SIZE, "node A public key");
88
+ ensureLen(opts.nodeBPublicKey, KEY_SIZE, "node B public key");
89
+ ensureLen(opts.nodeCPublicKey, KEY_SIZE, "node C public key");
90
+ const nonce = randomBytes(NONCE_SIZE);
91
+ const dPart = concatBytes([packIpPort(opts.nodeDHost, opts.nodeDPort), opts.payloadForNodeD]);
92
+ const key2 = nacl.box.keyPair();
93
+ const cEncrypted = nacl.box(dPart, nonce, opts.nodeCPublicKey, key2.secretKey);
94
+ const cPart = concatBytes([
95
+ packIpPort(opts.nodeCHost, opts.nodeCPort),
96
+ key2.publicKey,
97
+ cEncrypted
98
+ ]);
99
+ const key1 = nacl.box.keyPair();
100
+ const bEncrypted = nacl.box(cPart, nonce, opts.nodeBPublicKey, key1.secretKey);
101
+ const bPart = concatBytes([
102
+ packIpPort(opts.nodeBHost, opts.nodeBPort),
103
+ key1.publicKey,
104
+ bEncrypted
105
+ ]);
106
+ const key0 = nacl.box.keyPair();
107
+ const aEncrypted = nacl.box(bPart, nonce, opts.nodeAPublicKey, key0.secretKey);
108
+ return concatBytes([
109
+ Uint8Array.of(NET_PACKET_ONION_REQUEST_0),
110
+ nonce,
111
+ key0.publicKey,
112
+ aEncrypted
113
+ ]);
114
+ }
115
+ export function openOnionDataResponse(packet, opts) {
116
+ if (packet.length < 1 + NONCE_SIZE + KEY_SIZE + 16) {
117
+ return undefined;
118
+ }
119
+ if (packet[0] !== NET_PACKET_ONION_DATA_RESPONSE) {
120
+ return undefined;
121
+ }
122
+ const nonce = packet.slice(1, 1 + NONCE_SIZE);
123
+ const sourceTempPublicKey = packet.slice(1 + NONCE_SIZE, 1 + NONCE_SIZE + KEY_SIZE);
124
+ const encrypted = packet.slice(1 + NONCE_SIZE + KEY_SIZE);
125
+ const plain = nacl.box.open(encrypted, nonce, sourceTempPublicKey, opts.dataSecretKey);
126
+ if (!plain || plain.length < KEY_SIZE + 16) {
127
+ return undefined;
128
+ }
129
+ return { nonce, sourceTempPublicKey, payload: plain };
130
+ }
131
+ export function openOnionDataPacket(payload, opts) {
132
+ if (payload.length < KEY_SIZE + 16 + 1) {
133
+ return undefined;
134
+ }
135
+ const senderPublicKey = payload.slice(0, KEY_SIZE);
136
+ const encrypted = payload.slice(KEY_SIZE);
137
+ const plain = nacl.box.open(encrypted, opts.nonce, senderPublicKey, opts.receiverSecretKey);
138
+ if (!plain || plain.length === 0) {
139
+ return undefined;
140
+ }
141
+ return {
142
+ senderPublicKey,
143
+ innerPacketId: plain[0],
144
+ innerPayload: plain.slice(1)
145
+ };
146
+ }
147
+ function ensureLen(bytes, len, name) {
148
+ if (bytes.length !== len) {
149
+ throw new Error(`${name} must be ${len} bytes`);
150
+ }
151
+ }
152
+ function packIpPort(host, port) {
153
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
154
+ throw new Error("invalid port");
155
+ }
156
+ const out = new Uint8Array(PACKED_IP_PORT_SIZE);
157
+ const ipv4 = host.split(".");
158
+ if (ipv4.length !== 4) {
159
+ throw new Error("only IPv4 onion path packing is currently supported");
160
+ }
161
+ out[0] = 2;
162
+ for (let i = 0; i < 4; i++) {
163
+ const n = Number.parseInt(ipv4[i] ?? "", 10);
164
+ if (!Number.isInteger(n) || n < 0 || n > 255) {
165
+ throw new Error("invalid IPv4 host");
166
+ }
167
+ out[1 + i] = n;
168
+ }
169
+ out[17] = (port >>> 8) & 0xff;
170
+ out[18] = port & 0xff;
171
+ return out;
172
+ }
@@ -0,0 +1 @@
1
+ export declare function sealBox(_payload: Uint8Array): Promise<never>;
@@ -0,0 +1,3 @@
1
+ export async function sealBox(_payload) {
2
+ throw new Error("Legacy-compatible box encryption is not implemented yet");
3
+ }
@@ -0,0 +1,5 @@
1
+ export type KeyPair = {
2
+ publicKey: Uint8Array;
3
+ secretKey: Uint8Array;
4
+ };
5
+ export declare function loadOrCreateKeyPair(path: string): Promise<KeyPair>;
@@ -0,0 +1,37 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import nacl from "tweetnacl";
4
+ import { bytesToHex, hexToBytes } from "../utils/bytes.js";
5
+ export async function loadOrCreateKeyPair(path) {
6
+ try {
7
+ const parsed = JSON.parse(await readFile(path, "utf8"));
8
+ if (parsed.format !== "decent-peer-tox-keypair-v1") {
9
+ throw new Error(`unsupported key file format: ${parsed.format}`);
10
+ }
11
+ const publicKey = hexToBytes(parsed.publicKey);
12
+ const secretKey = hexToBytes(parsed.secretKey);
13
+ if (publicKey.length !== nacl.box.publicKeyLength || secretKey.length !== nacl.box.secretKeyLength) {
14
+ throw new Error("invalid key file key length");
15
+ }
16
+ return { publicKey, secretKey };
17
+ }
18
+ catch (error) {
19
+ const nodeError = error;
20
+ if (nodeError.code && nodeError.code !== "ENOENT") {
21
+ throw error;
22
+ }
23
+ }
24
+ const generated = nacl.box.keyPair();
25
+ const keyPair = {
26
+ publicKey: generated.publicKey,
27
+ secretKey: generated.secretKey
28
+ };
29
+ await mkdir(dirname(path), { recursive: true });
30
+ const stored = {
31
+ format: "decent-peer-tox-keypair-v1",
32
+ publicKey: bytesToHex(keyPair.publicKey),
33
+ secretKey: bytesToHex(keyPair.secretKey)
34
+ };
35
+ await writeFile(path, `${JSON.stringify(stored, null, 2)}\n`);
36
+ return keyPair;
37
+ }
@@ -0,0 +1 @@
1
+ export type Nonce = Uint8Array;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare function signDetached(_payload: Uint8Array): Promise<never>;
@@ -0,0 +1,3 @@
1
+ export async function signDetached(_payload) {
2
+ throw new Error("Legacy-compatible signing is not implemented yet");
3
+ }
@@ -0,0 +1,10 @@
1
+ export { Peer } from "./peer.js";
2
+ export { CARRIER_ADDRESS_SIZE, CARRIER_PUBLIC_KEY_SIZE, carrierAddressFromPublicKey, carrierIdFromAddress, carrierIdFromPublicKey, parseCarrierAddress } from "./compat/address.js";
3
+ export { PACKET_TYPE_FRIEND_REQUEST, PACKET_TYPE_MESSAGE, decodeCarrierPacket, encodeFriendMessagePacket, encodeFriendRequestPacket } from "./compat/packet.js";
4
+ export { CRYPTO_PACKET_DHTPK, CRYPTO_PACKET_FRIEND_REQ, CRYPTO_PACKET_NAT_PING, NET_PACKET_CRYPTO, createToxDhtCryptoRequest, openToxDhtCryptoRequest } from "./compat/tox-dht-crypto.js";
5
+ export { NET_PACKET_ONION_ANNOUNCE_REQUEST, NET_PACKET_ONION_ANNOUNCE_RESPONSE, NET_PACKET_ONION_DATA_REQUEST, NET_PACKET_ONION_DATA_RESPONSE, ONION_FRIEND_REQUEST_ID } from "./compat/tox-onion.js";
6
+ export { LegacyProtocolNotImplementedError } from "./runtime/errors.js";
7
+ export type { CarrierPacket, FriendMessagePacket, FriendRequestPacket } from "./compat/packet.js";
8
+ export type { ToxDhtCryptoRequest } from "./compat/tox-dht-crypto.js";
9
+ export type { CarrierAddressParts } from "./compat/address.js";
10
+ export type { CompatibilityMode, FriendConnectionEvent, FriendConnectionStatus, FriendInfoEvent, FriendRequest, LookupResult, NetworkNode, PeerOptions, TextMessage } from "./types/peer.js";
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { Peer } from "./peer.js";
2
+ export { CARRIER_ADDRESS_SIZE, CARRIER_PUBLIC_KEY_SIZE, carrierAddressFromPublicKey, carrierIdFromAddress, carrierIdFromPublicKey, parseCarrierAddress } from "./compat/address.js";
3
+ export { PACKET_TYPE_FRIEND_REQUEST, PACKET_TYPE_MESSAGE, decodeCarrierPacket, encodeFriendMessagePacket, encodeFriendRequestPacket } from "./compat/packet.js";
4
+ export { CRYPTO_PACKET_DHTPK, CRYPTO_PACKET_FRIEND_REQ, CRYPTO_PACKET_NAT_PING, NET_PACKET_CRYPTO, createToxDhtCryptoRequest, openToxDhtCryptoRequest } from "./compat/tox-dht-crypto.js";
5
+ export { NET_PACKET_ONION_ANNOUNCE_REQUEST, NET_PACKET_ONION_ANNOUNCE_RESPONSE, NET_PACKET_ONION_DATA_REQUEST, NET_PACKET_ONION_DATA_RESPONSE, ONION_FRIEND_REQUEST_ID } from "./compat/tox-onion.js";
6
+ export { LegacyProtocolNotImplementedError } from "./runtime/errors.js";
package/dist/peer.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { type BootstrapResult } from "./compat/bootstrap.js";
2
+ import type { FriendRecord } from "./store/friends.js";
3
+ import type { FriendConnectionEvent, FriendRequest, FriendInfoEvent, LookupResult, NetworkNode, PeerOptions, TextMessage } from "./types/peer.js";
4
+ export declare class Peer {
5
+ #private;
6
+ private constructor();
7
+ static create(opts: PeerOptions): Promise<Peer>;
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ pubkey(): string;
11
+ userid(): string;
12
+ address(): string;
13
+ joinNetwork(): Promise<BootstrapResult>;
14
+ lookup(pubkey: string): Promise<LookupResult>;
15
+ announceSelf(timeoutMs?: number): Promise<NetworkNode[]>;
16
+ addKnownNodes(nodes: NetworkNode[]): void;
17
+ knownNodes(): NetworkNode[];
18
+ sendFriendRequest(pubkey: string, hello?: string): Promise<void>;
19
+ lastFriendRequestDispatch(): {
20
+ transport: "onion" | "direct";
21
+ routes: number;
22
+ targets: number;
23
+ } | undefined;
24
+ acceptFriendRequest(pubkey: string): Promise<void>;
25
+ rejectFriendRequest(pubkey: string): void;
26
+ /**
27
+ * Drop a friend entirely: tear down any active net_crypto session, forget
28
+ * their cached endpoint, clear retry/backoff bookkeeping, and persist the
29
+ * shrunk friend list to disk. Use this to remove stale persisted entries
30
+ * (e.g. an old simulator pubkey) that are still hogging the friend
31
+ * connection loop with cookie requests no peer is going to answer.
32
+ *
33
+ * `pubkey` accepts either the friend's userid (base58 of the real public
34
+ * key) or full Carrier address — both resolve to the same friendId.
35
+ */
36
+ removeFriend(pubkey: string): boolean;
37
+ sendText(pubkey: string, text: string): Promise<void>;
38
+ waitForFriendConnected(pubkey: string, timeoutMs?: number): Promise<boolean>;
39
+ onFriendRequest(cb: (req: FriendRequest) => void): void;
40
+ onText(cb: (msg: TextMessage) => void): void;
41
+ onFriendConnection(cb: (ev: FriendConnectionEvent) => void): void;
42
+ onFriendInfo(cb: (ev: FriendInfoEvent) => void): void;
43
+ friends(): FriendRecord[];
44
+ waitForFriendRequest(timeoutMs?: number): Promise<FriendRequest>;
45
+ }