bun-torrent 0.0.6 → 0.0.8
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/README.md +48 -5
- package/dist/app.d.ts +2 -0
- package/dist/app.js +136 -0
- package/dist/app.js.map +1 -0
- package/dist/client.d.ts +135 -0
- package/dist/client.error.d.ts +11 -0
- package/dist/client.error.js +11 -0
- package/dist/client.error.js.map +1 -1
- package/dist/client.js +130 -3
- package/dist/client.js.map +1 -1
- package/dist/configs/defaults.d.ts +16 -0
- package/dist/configs/defaults.js +11 -0
- package/dist/configs/defaults.js.map +1 -1
- package/dist/dht/DhtClient.d.ts +52 -0
- package/dist/dht/DhtClient.js +279 -0
- package/dist/dht/DhtClient.js.map +1 -0
- package/dist/dht/KBucket.d.ts +12 -0
- package/dist/dht/KBucket.js +43 -0
- package/dist/dht/KBucket.js.map +1 -0
- package/dist/dht/RoutingTable.d.ts +19 -0
- package/dist/dht/RoutingTable.js +75 -0
- package/dist/dht/RoutingTable.js.map +1 -0
- package/dist/dht/errors.d.ts +19 -0
- package/dist/dht/errors.js +24 -0
- package/dist/dht/errors.js.map +1 -0
- package/dist/dht/index.d.ts +8 -0
- package/dist/dht/index.js +5 -0
- package/dist/dht/index.js.map +1 -0
- package/dist/dht/krpc/TransactionId.d.ts +12 -0
- package/dist/dht/krpc/TransactionId.js +23 -0
- package/dist/dht/krpc/TransactionId.js.map +1 -0
- package/dist/dht/krpc/index.d.ts +5 -0
- package/dist/dht/krpc/index.js +4 -0
- package/dist/dht/krpc/index.js.map +1 -0
- package/dist/dht/krpc/messages.d.ts +3 -0
- package/dist/dht/krpc/messages.js +163 -0
- package/dist/dht/krpc/messages.js.map +1 -0
- package/dist/dht/krpc/types.d.ts +54 -0
- package/dist/dht/krpc/types.js +14 -0
- package/dist/dht/krpc/types.js.map +1 -0
- package/dist/dht/routing-table.d.ts +2 -0
- package/dist/dht/routing-table.js +2 -0
- package/dist/dht/routing-table.js.map +1 -0
- package/dist/dht/utils/compact.d.ts +17 -0
- package/dist/dht/utils/compact.js +81 -0
- package/dist/dht/utils/compact.js.map +1 -0
- package/dist/dht/utils/distance.d.ts +5 -0
- package/dist/dht/utils/distance.js +25 -0
- package/dist/dht/utils/distance.js.map +1 -0
- package/dist/magnet/base32/errors.d.ts +11 -1
- package/dist/magnet/base32/errors.js +10 -1
- package/dist/magnet/base32/errors.js.map +1 -1
- package/dist/magnet/parser/errors.d.ts +20 -1
- package/dist/magnet/parser/errors.js +19 -1
- package/dist/magnet/parser/errors.js.map +1 -1
- package/dist/magnet/parser/index.d.ts +10 -2
- package/dist/magnet/parser/index.js +53 -22
- package/dist/magnet/parser/index.js.map +1 -1
- package/dist/peer/PeerPieceAvailability.d.ts +50 -0
- package/dist/peer/PeerPieceAvailability.js +71 -0
- package/dist/peer/PeerPieceAvailability.js.map +1 -0
- package/dist/peer/availability.d.ts +2 -50
- package/dist/peer/availability.js +1 -70
- package/dist/peer/availability.js.map +1 -1
- package/dist/peer/extended/connection.d.ts +3 -1
- package/dist/peer/extended/connection.js +20 -4
- package/dist/peer/extended/connection.js.map +1 -1
- package/dist/peer/extended/errors.d.ts +1 -0
- package/dist/peer/extended/errors.js +1 -0
- package/dist/peer/extended/errors.js.map +1 -1
- package/dist/peer/extended/metadata/MetadataAssembler.d.ts +12 -0
- package/dist/peer/extended/metadata/MetadataAssembler.js +44 -0
- package/dist/peer/extended/metadata/MetadataAssembler.js.map +1 -0
- package/dist/peer/extended/metadata/assembler.d.ts +1 -12
- package/dist/peer/extended/metadata/assembler.js +1 -43
- package/dist/peer/extended/metadata/assembler.js.map +1 -1
- package/dist/peer/extended/metadata/index.d.ts +1 -0
- package/dist/peer/extended/metadata/index.js +20 -8
- package/dist/peer/extended/metadata/index.js.map +1 -1
- package/dist/peer/index.d.ts +2 -2
- package/dist/peer/index.js +1 -1
- package/dist/peer/index.js.map +1 -1
- package/dist/peer/pool/PeerPool.d.ts +65 -0
- package/dist/peer/pool/PeerPool.js +206 -0
- package/dist/peer/pool/PeerPool.js.map +1 -0
- package/dist/peer/pool/index.d.ts +2 -65
- package/dist/peer/pool/index.js +1 -205
- package/dist/peer/pool/index.js.map +1 -1
- package/dist/peer/pool/pool.error.d.ts +14 -1
- package/dist/peer/pool/pool.error.js +13 -1
- package/dist/peer/pool/pool.error.js.map +1 -1
- package/dist/peer/session/PeerSession.d.ts +35 -0
- package/dist/peer/session/PeerSession.js +200 -0
- package/dist/peer/session/PeerSession.js.map +1 -0
- package/dist/peer/session/index.d.ts +2 -35
- package/dist/peer/session/index.js +1 -199
- package/dist/peer/session/index.js.map +1 -1
- package/dist/peer/session/session.error.d.ts +16 -1
- package/dist/peer/session/session.error.js +15 -1
- package/dist/peer/session/session.error.js.map +1 -1
- package/dist/torrent/download/DownloadManager.d.ts +97 -0
- package/dist/torrent/download/DownloadManager.js +383 -0
- package/dist/torrent/download/DownloadManager.js.map +1 -0
- package/dist/torrent/download/index.d.ts +2 -2
- package/dist/torrent/download/index.js +1 -1
- package/dist/torrent/download/index.js.map +1 -1
- package/dist/torrent/download/manager.d.ts +2 -85
- package/dist/torrent/download/manager.js +1 -382
- package/dist/torrent/download/manager.js.map +1 -1
- package/dist/torrent/parser/parser.error.d.ts +11 -1
- package/dist/torrent/parser/parser.error.js +10 -1
- package/dist/torrent/parser/parser.error.js.map +1 -1
- package/dist/torrent/pieces/planner.error.d.ts +10 -1
- package/dist/torrent/pieces/planner.error.js +9 -1
- package/dist/torrent/pieces/planner.error.js.map +1 -1
- package/dist/torrent/session/Torrent.d.ts +160 -0
- package/dist/torrent/session/Torrent.js +192 -0
- package/dist/torrent/session/Torrent.js.map +1 -0
- package/dist/torrent/session/index.d.ts +2 -77
- package/dist/torrent/session/index.js +1 -125
- package/dist/torrent/session/index.js.map +1 -1
- package/dist/torrent/storage/storage.error.d.ts +10 -1
- package/dist/torrent/storage/storage.error.js +9 -1
- package/dist/torrent/storage/storage.error.js.map +1 -1
- package/dist/torrent/types.d.ts +18 -0
- package/dist/tracker/tracker.error.d.ts +12 -1
- package/dist/tracker/tracker.error.js +11 -1
- package/dist/tracker/tracker.error.js.map +1 -1
- package/dist/tracker/udp.js +24 -25
- package/dist/tracker/udp.js.map +1 -1
- package/dist/utils/UdpSocket.d.ts +12 -0
- package/dist/utils/UdpSocket.js +31 -0
- package/dist/utils/UdpSocket.js.map +1 -0
- package/dist/utils/errors.d.ts +20 -1
- package/dist/utils/errors.js +19 -1
- package/dist/utils/errors.js.map +1 -1
- package/examples/download-torrent.ts +32 -0
- package/examples/magnet-dht.ts +32 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A minimal Bun-native BitTorrent download-only client written in TypeScript.
|
|
4
4
|
|
|
5
|
-
`bun-torrent` can parse `.torrent` files and
|
|
5
|
+
`bun-torrent` can parse `.torrent` files and magnet links, announce to HTTP and UDP trackers, discover peers through the BitTorrent DHT, connect to peers, download pieces, validate piece hashes, and write the downloaded files to disk. The public API is intentionally small: create a `Client`, inspect a torrent when you need metadata, then call `download()`.
|
|
6
6
|
|
|
7
7
|
It has no runtime dependencies.
|
|
8
8
|
|
|
@@ -57,6 +57,17 @@ await torrent.done;
|
|
|
57
57
|
|
|
58
58
|
`download()` returns a `Torrent` instance and starts the download immediately.
|
|
59
59
|
|
|
60
|
+
## Runnable Example Files
|
|
61
|
+
|
|
62
|
+
Runnable example files are available in `examples/`:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
bun examples/download-torrent.ts ./example.torrent ./downloads
|
|
66
|
+
bun examples/magnet-dht.ts "magnet:?xt=urn:btih:..." ./downloads
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The magnet example works with tracker-backed and trackerless magnets. It uses the default in-memory DHT node and closes the client before exiting.
|
|
70
|
+
|
|
60
71
|
## Client Setup
|
|
61
72
|
|
|
62
73
|
```ts
|
|
@@ -78,6 +89,7 @@ const client = new Client({
|
|
|
78
89
|
|
|
79
90
|
Client options:
|
|
80
91
|
|
|
92
|
+
- `dht`: optional DHT peer discovery implementation, or `false` to disable DHT. By default, the client creates an in-memory DHT node.
|
|
81
93
|
- `outputDirectory`: directory where downloaded files are written. Defaults to `process.cwd()`.
|
|
82
94
|
- `files`: optional default file selection for downloads.
|
|
83
95
|
- `targetConnections`: preferred number of connected peers. Defaults to `20`.
|
|
@@ -109,9 +121,11 @@ console.log(metadata.files);
|
|
|
109
121
|
|
|
110
122
|
Torrent file input can be a file path, `Uint8Array`, or `ArrayBuffer`.
|
|
111
123
|
|
|
124
|
+
Call `client.close()` when the client should stop accepting work and close active torrents and its DHT socket.
|
|
125
|
+
|
|
112
126
|
## Magnet Links
|
|
113
127
|
|
|
114
|
-
Magnet links are supported
|
|
128
|
+
Magnet links are supported with or without trackers. If `tr` parameters are present, the client asks those trackers first. If no tracker returns peers, or the magnet is trackerless, the client falls back to DHT peer discovery. Metadata is fetched from peers with the `ut_metadata` extension before the normal download flow starts.
|
|
115
129
|
|
|
116
130
|
```ts
|
|
117
131
|
const magnet =
|
|
@@ -134,13 +148,42 @@ const torrent = await client.download(
|
|
|
134
148
|
await torrent.done;
|
|
135
149
|
```
|
|
136
150
|
|
|
151
|
+
Trackerless magnets use the same API. Keep the same `Client` instance if you inspect first and download later, because the default DHT node keeps discovered peers in memory for the current process.
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { Client } from 'bun-torrent';
|
|
155
|
+
|
|
156
|
+
const client = new Client({
|
|
157
|
+
outputDirectory: './downloads',
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const magnet = 'magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567';
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
const metadata = await client.inspect({ magnet });
|
|
164
|
+
|
|
165
|
+
console.log(metadata.name);
|
|
166
|
+
console.log(metadata.files);
|
|
167
|
+
|
|
168
|
+
const torrent = await client.download({ meta: metadata });
|
|
169
|
+
|
|
170
|
+
torrent.on('progress', (progress) => {
|
|
171
|
+
console.log(`${(progress.percent * 100).toFixed(2)}%`, progress.speed);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await torrent.done;
|
|
175
|
+
} finally {
|
|
176
|
+
client.close();
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
137
180
|
Supported magnet fields:
|
|
138
181
|
|
|
139
182
|
- `xt=urn:btih:<infoHash>`: required. Hex-encoded 40-character info hashes and base32 32-character info hashes are supported.
|
|
140
183
|
- `dn`: optional display name.
|
|
141
|
-
- `tr`: optional tracker URL. Multiple `tr` parameters are supported.
|
|
184
|
+
- `tr`: optional tracker URL. Multiple `tr` parameters are supported, but trackerless magnets can resolve through DHT.
|
|
142
185
|
|
|
143
|
-
|
|
186
|
+
The default DHT node is in-memory. It keeps a routing table and a short-lived peer cache for the current process, so a magnet `inspect()` can populate peers that a later `download({ meta })` call can reuse on the same `Client` instance. The DHT state is not persisted to disk.
|
|
144
187
|
|
|
145
188
|
## Download Options
|
|
146
189
|
|
|
@@ -181,7 +224,7 @@ Download options:
|
|
|
181
224
|
- `speedSampleIntervalMs`: override speed sample interval.
|
|
182
225
|
- `onChangeState`: receives client setup states: `parsing`, `tracking`, `connecting`, `downloading`.
|
|
183
226
|
|
|
184
|
-
Tracker announce failures are treated as non-fatal. If
|
|
227
|
+
Tracker announce failures are treated as non-fatal. If trackers are missing or do not return peers, the client falls back to DHT when it is enabled. With DHT disabled, the client can still continue with an empty peer list instead of throwing during tracking when `minConnections` is `0`.
|
|
185
228
|
|
|
186
229
|
## Selecting Files
|
|
187
230
|
|
package/dist/app.d.ts
ADDED
package/dist/app.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { bytesToHex } from './utils/buffers';
|
|
3
|
+
import { formatBytes } from './utils/formats';
|
|
4
|
+
import { Client } from './client';
|
|
5
|
+
const summarizeTorrent = (metadata) => ({
|
|
6
|
+
announce: metadata.announce,
|
|
7
|
+
announceList: metadata.announceList,
|
|
8
|
+
infoHash: bytesToHex(metadata.infoHash),
|
|
9
|
+
name: metadata.name,
|
|
10
|
+
pieceLength: metadata.pieceLength,
|
|
11
|
+
piecesTotal: metadata.pieces.length,
|
|
12
|
+
length: metadata.length,
|
|
13
|
+
files: metadata.files.map((file) => ({
|
|
14
|
+
path: file.path.join('/'),
|
|
15
|
+
length: file.length,
|
|
16
|
+
offset: file.offset,
|
|
17
|
+
})),
|
|
18
|
+
filesTotal: metadata.files.length,
|
|
19
|
+
});
|
|
20
|
+
const usage = () => {
|
|
21
|
+
console.error('Usage:');
|
|
22
|
+
console.error(' bunx bun-torrent inspect <file.torrent>');
|
|
23
|
+
console.error(' bunx bun-torrent inspect <magnet-uri>');
|
|
24
|
+
console.error(' bunx bun-torrent inspect < file.torrent');
|
|
25
|
+
console.error(' bunx bun-torrent download <file.torrent|magnet-uri> [output-directory]');
|
|
26
|
+
};
|
|
27
|
+
const inspect = async (input) => {
|
|
28
|
+
const client = new Client();
|
|
29
|
+
try {
|
|
30
|
+
const metadata = input ? await inspectArgument(client, input) : await inspectStdin(client);
|
|
31
|
+
console.log(JSON.stringify(summarizeTorrent(metadata), null, 2));
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
client.close();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const resolveInput = (input) => {
|
|
38
|
+
if (input.startsWith('magnet:')) {
|
|
39
|
+
return { magnet: input };
|
|
40
|
+
}
|
|
41
|
+
return { torrentFile: input };
|
|
42
|
+
};
|
|
43
|
+
const inspectArgument = async (client, input) => {
|
|
44
|
+
return await client.inspect(resolveInput(input));
|
|
45
|
+
};
|
|
46
|
+
const inspectStdin = async (client) => {
|
|
47
|
+
const input = new Uint8Array(await Bun.stdin.arrayBuffer());
|
|
48
|
+
if (input.byteLength === 0) {
|
|
49
|
+
throw new Error('Expected torrent file bytes on stdin');
|
|
50
|
+
}
|
|
51
|
+
return await client.inspect({ torrentFile: input });
|
|
52
|
+
};
|
|
53
|
+
const download = async (input, outputDirectory = './downloads') => {
|
|
54
|
+
if (!input) {
|
|
55
|
+
throw new Error('Expected file.torrent or magnet URI');
|
|
56
|
+
}
|
|
57
|
+
const client = new Client({ outputDirectory });
|
|
58
|
+
let state = 'starting';
|
|
59
|
+
let progress = null;
|
|
60
|
+
let stats = null;
|
|
61
|
+
const render = () => renderProgressLine(state, progress, stats);
|
|
62
|
+
try {
|
|
63
|
+
render();
|
|
64
|
+
const torrent = await client.download(resolveInput(input), {
|
|
65
|
+
progressEvents: 'block',
|
|
66
|
+
onChangeState: (nextState) => {
|
|
67
|
+
state = nextState;
|
|
68
|
+
render();
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
progress = torrent.progress;
|
|
72
|
+
stats = torrent.stats;
|
|
73
|
+
render();
|
|
74
|
+
torrent.on('progress', (nextProgress) => {
|
|
75
|
+
progress = nextProgress;
|
|
76
|
+
render();
|
|
77
|
+
});
|
|
78
|
+
torrent.on('peer', (nextStats) => {
|
|
79
|
+
stats = nextStats;
|
|
80
|
+
render();
|
|
81
|
+
});
|
|
82
|
+
await torrent.done;
|
|
83
|
+
state = 'completed';
|
|
84
|
+
progress = torrent.progress;
|
|
85
|
+
stats = torrent.stats;
|
|
86
|
+
render();
|
|
87
|
+
process.stdout.write('\nDownload complete\n');
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
client.close();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const renderProgressLine = (state, progress, stats) => {
|
|
94
|
+
const bar = progress ? progressBar(progress.percent) : progressBar(0);
|
|
95
|
+
const percent = progress ? `${(progress.percent * 100).toFixed(2).padStart(6)}%` : ' 0.00%';
|
|
96
|
+
const downloaded = progress ? formatBytes(progress.downloadedBytes) : '0.0 B';
|
|
97
|
+
const total = progress ? formatBytes(progress.totalBytes) : '?';
|
|
98
|
+
const speed = progress?.speed ?? '0.0 Bps';
|
|
99
|
+
const pieces = progress
|
|
100
|
+
? `pieces=${progress.completedPieces}/${progress.totalPieces}`
|
|
101
|
+
: 'pieces=?/?';
|
|
102
|
+
const peers = stats ? `peers=${stats.connections}/${stats.peers}` : 'peers=0/0';
|
|
103
|
+
const line = `${state.padEnd(11)} ${bar} ${percent} ${downloaded}/${total} ${speed} ${pieces} ${peers}`;
|
|
104
|
+
process.stdout.write(`\r${line}\x1b[K`);
|
|
105
|
+
};
|
|
106
|
+
const progressBar = (percent) => {
|
|
107
|
+
const width = 28;
|
|
108
|
+
const normalized = Math.min(1, Math.max(0, percent));
|
|
109
|
+
const filled = Math.round(normalized * width);
|
|
110
|
+
return `[${'#'.repeat(filled)}${'-'.repeat(width - filled)}]`;
|
|
111
|
+
};
|
|
112
|
+
if (import.meta.main) {
|
|
113
|
+
const command = Bun.argv[2];
|
|
114
|
+
const input = Bun.argv[3];
|
|
115
|
+
const outputDirectory = Bun.argv[4];
|
|
116
|
+
try {
|
|
117
|
+
switch (command) {
|
|
118
|
+
case 'inspect':
|
|
119
|
+
await inspect(input);
|
|
120
|
+
break;
|
|
121
|
+
case 'download':
|
|
122
|
+
await download(input, outputDirectory);
|
|
123
|
+
break;
|
|
124
|
+
default:
|
|
125
|
+
usage();
|
|
126
|
+
process.exitCode = 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (command === 'download')
|
|
131
|
+
process.stdout.write('\n');
|
|
132
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
133
|
+
process.exitCode = 1;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -2,24 +2,61 @@ import { type DownloadProgressEventMode } from './torrent/download';
|
|
|
2
2
|
import { Torrent } from './torrent/session/index';
|
|
3
3
|
import type { TorrentMetadata } from './torrent/types';
|
|
4
4
|
import type { TorrentFileSelection } from './torrent/file-selection';
|
|
5
|
+
import type { PeerInfo } from './tracker/types';
|
|
6
|
+
/**
|
|
7
|
+
* Setup phases reported through {@link DownloadOptions.onChangeState} before download starts.
|
|
8
|
+
*
|
|
9
|
+
* The values are emitted in order: `parsing` → `tracking` → `connecting` → `downloading`.
|
|
10
|
+
* Once `downloading` fires, progress events take over via {@link Torrent.on}.
|
|
11
|
+
*/
|
|
5
12
|
export declare enum DownloadState {
|
|
6
13
|
PARSING = "parsing",
|
|
7
14
|
TRACKING = "tracking",
|
|
8
15
|
CONNECTING = "connecting",
|
|
9
16
|
DOWNLOADING = "downloading"
|
|
10
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Minimal DHT contract used by {@link Client} for peer discovery.
|
|
20
|
+
*
|
|
21
|
+
* Implement this to swap the default in-memory DHT for a persistent or
|
|
22
|
+
* shared implementation. `close` is called from {@link Client.close}.
|
|
23
|
+
*/
|
|
24
|
+
export type ClientDht = {
|
|
25
|
+
lookupPeers(infoHash: Uint8Array): Promise<PeerInfo[]>;
|
|
26
|
+
close?(): void;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Default options applied to every download started by a {@link Client}.
|
|
30
|
+
*
|
|
31
|
+
* All fields are optional. Any field can be overridden per-download via
|
|
32
|
+
* {@link DownloadOptions}.
|
|
33
|
+
*/
|
|
11
34
|
export type ClientConfig = {
|
|
35
|
+
/** Custom DHT implementation, or `false` to disable DHT entirely. Defaults to an in-memory {@link DhtClient}. */
|
|
36
|
+
dht?: ClientDht | false;
|
|
37
|
+
/** Default file selection for multi-file torrents. `null`/omitted downloads every file. */
|
|
12
38
|
files?: TorrentFileSelection;
|
|
39
|
+
/** Maximum block requests in flight per peer. Higher values increase throughput but also memory. Defaults to 300. */
|
|
13
40
|
maxInFlightRequestsPerPeer?: number;
|
|
41
|
+
/** Maximum simultaneous peer connection attempts. Defaults to 30. */
|
|
14
42
|
maxConnecting?: number;
|
|
43
|
+
/** Minimum connected peers required before download starts. `0` allows downloads to start with no peers. Defaults to 0. */
|
|
15
44
|
minConnections?: number;
|
|
45
|
+
/** Directory where downloaded files are written. Defaults to `process.cwd()`. */
|
|
16
46
|
outputDirectory?: string;
|
|
47
|
+
/** Timeout for a single peer TCP connect + handshake, in milliseconds. Defaults to 5000. */
|
|
17
48
|
peerConnectTimeoutMs?: number;
|
|
49
|
+
/** Granularity of `progress` events: `'piece'` (once per validated piece) or `'block'` (every received block). Defaults to `'piece'`. */
|
|
18
50
|
progressEvents?: DownloadProgressEventMode;
|
|
51
|
+
/** Timeout for a single block request, in milliseconds. Timed-out requests are retried on other peers. Defaults to 15000. */
|
|
19
52
|
requestTimeoutMs?: number;
|
|
53
|
+
/** Reserved for future seeding support. Currently only `false` is supported. */
|
|
20
54
|
seed?: false;
|
|
55
|
+
/** Minimum interval between speed recalculations, in milliseconds. Defaults to 500. */
|
|
21
56
|
speedSampleIntervalMs?: number;
|
|
57
|
+
/** Preferred number of connected peers. The pool stops opening new connections once this is reached. Defaults to 20. */
|
|
22
58
|
targetConnections?: number;
|
|
59
|
+
/** Timeout for tracker announce requests, in milliseconds. Defaults to 5000. */
|
|
23
60
|
trackerTimeoutMs?: number;
|
|
24
61
|
};
|
|
25
62
|
type InspectInput = {
|
|
@@ -34,32 +71,130 @@ type InspectInput = {
|
|
|
34
71
|
type DownloadInput = {
|
|
35
72
|
meta: TorrentMetadata;
|
|
36
73
|
} | InspectInput;
|
|
74
|
+
/**
|
|
75
|
+
* Entry point of the library. Holds shared state (peer id, DHT node) across downloads.
|
|
76
|
+
*
|
|
77
|
+
* One `Client` instance can run multiple concurrent downloads. The same client is also
|
|
78
|
+
* reused across `inspect` → `download` flows so the DHT routing table and peer cache
|
|
79
|
+
* can warm up once and pay off on subsequent calls.
|
|
80
|
+
*
|
|
81
|
+
* Call {@link Client.close} when the client is no longer needed — it closes every
|
|
82
|
+
* active torrent and the DHT socket. After close, every method throws {@link ClientError}.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const client = new Client({ outputDirectory: './downloads' });
|
|
86
|
+
* try {
|
|
87
|
+
* const torrent = await client.download({ torrentFile: './example.torrent' });
|
|
88
|
+
* await torrent.done;
|
|
89
|
+
* } finally {
|
|
90
|
+
* client.close();
|
|
91
|
+
* }
|
|
92
|
+
*/
|
|
37
93
|
export declare class Client {
|
|
38
94
|
private readonly config;
|
|
39
95
|
private readonly peerId;
|
|
96
|
+
private readonly dhtNodeId;
|
|
97
|
+
private readonly dht?;
|
|
98
|
+
private readonly torrents;
|
|
99
|
+
private closed;
|
|
100
|
+
/**
|
|
101
|
+
* Build a client with optional defaults that apply to every download.
|
|
102
|
+
*
|
|
103
|
+
* The constructor is cheap: it generates a peer id and a DHT node id but does not
|
|
104
|
+
* open any sockets. The default DHT instance opens its UDP socket lazily on the
|
|
105
|
+
* first lookup.
|
|
106
|
+
*
|
|
107
|
+
* @param config - Defaults applied to downloads started by this client.
|
|
108
|
+
*/
|
|
40
109
|
constructor(config?: ClientConfig);
|
|
110
|
+
/**
|
|
111
|
+
* Start downloading a torrent and return a {@link Torrent} that emits progress events.
|
|
112
|
+
*
|
|
113
|
+
* The returned promise settles once the client has parsed metadata, discovered peers,
|
|
114
|
+
* opened the peer pool, and started the download manager. The actual download runs
|
|
115
|
+
* in the background — `await torrent.done` or listen for the `done` event to wait
|
|
116
|
+
* for it to finish.
|
|
117
|
+
*
|
|
118
|
+
* Tracker failures are non-fatal: if no tracker returns peers, DHT lookup is attempted
|
|
119
|
+
* when DHT is enabled. With DHT disabled, the download continues with whatever peers
|
|
120
|
+
* were found provided `minConnections` is `0`.
|
|
121
|
+
*
|
|
122
|
+
* @param input - Torrent source: a `.torrent` file path/bytes, a magnet URI, or already-parsed `meta`.
|
|
123
|
+
* @param options - Per-download overrides for {@link ClientConfig}, plus `announcePort` and `onChangeState`.
|
|
124
|
+
* @returns A {@link Torrent} whose `done` promise settles when the download finishes or fails.
|
|
125
|
+
* @throws {ClientError} When the client is closed, the input is unsupported, or file selection is invalid.
|
|
126
|
+
*/
|
|
41
127
|
download(input: DownloadInput, options?: DownloadOptions): Promise<Torrent>;
|
|
128
|
+
/**
|
|
129
|
+
* Parse a `.torrent` file or magnet URI and return its metadata without starting a download.
|
|
130
|
+
*
|
|
131
|
+
* Useful for showing the file list, computing total size, or letting the user pick
|
|
132
|
+
* a subset of files before calling {@link Client.download}. For magnet links this
|
|
133
|
+
* method fetches the info dictionary from a peer using the `ut_metadata` extension,
|
|
134
|
+
* so it may discover and warm DHT state that a later `download({ meta })` call reuses.
|
|
135
|
+
*
|
|
136
|
+
* @param input - Either `{ torrentFile }` (path/bytes/ArrayBuffer) or `{ magnet }` (URI string).
|
|
137
|
+
* @param options - Optional overrides. `timeout` caps the per-peer metadata fetch for magnets.
|
|
138
|
+
* @returns Parsed torrent metadata, including computed info hash.
|
|
139
|
+
* @throws {ClientError} When the client is closed or no input is provided.
|
|
140
|
+
* @throws {TorrentParseError} When the torrent file or magnet info dictionary cannot be parsed.
|
|
141
|
+
* @throws {MagnetParseError} When the magnet URI is invalid or no peer returned metadata.
|
|
142
|
+
*/
|
|
42
143
|
inspect(input: InspectInput, options?: {
|
|
43
144
|
timeout?: number;
|
|
44
145
|
}): Promise<TorrentMetadata>;
|
|
146
|
+
/**
|
|
147
|
+
* Stop the client, close every active torrent, and release the DHT socket.
|
|
148
|
+
*
|
|
149
|
+
* Idempotent — calling close more than once is a no-op. After close, every other
|
|
150
|
+
* method throws {@link ClientError} with code `CLIENT_CLOSED`.
|
|
151
|
+
*/
|
|
152
|
+
close(): void;
|
|
153
|
+
private discoverPeers;
|
|
45
154
|
private trackPeers;
|
|
155
|
+
private trackTorrent;
|
|
156
|
+
private assertOpen;
|
|
46
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Per-download overrides passed to {@link Client.download}.
|
|
160
|
+
*
|
|
161
|
+
* Every field except `announcePort` and `onChangeState` overrides the matching field
|
|
162
|
+
* in {@link ClientConfig} for this download only.
|
|
163
|
+
*/
|
|
47
164
|
export type DownloadOptions = {
|
|
165
|
+
/** Port sent to trackers in announce requests. Defaults to 6881. */
|
|
48
166
|
announcePort?: number;
|
|
167
|
+
/** Restrict the download to specific files. Selectable by `'a/b.txt'` string or `['a','b.txt']` array. */
|
|
49
168
|
files?: TorrentFileSelection;
|
|
169
|
+
/** Override {@link ClientConfig.maxInFlightRequestsPerPeer} for this download. */
|
|
50
170
|
maxInFlightRequestsPerPeer?: number;
|
|
171
|
+
/** Override {@link ClientConfig.maxConnecting} for this download. */
|
|
51
172
|
maxConnecting?: number;
|
|
173
|
+
/** Override {@link ClientConfig.minConnections} for this download. */
|
|
52
174
|
minConnections?: number;
|
|
175
|
+
/** Called with each setup phase before download starts. See {@link DownloadState}. */
|
|
53
176
|
onChangeState?: (state: DownloadState) => unknown;
|
|
177
|
+
/** Override {@link ClientConfig.outputDirectory} for this download. */
|
|
54
178
|
outputDirectory?: string;
|
|
179
|
+
/** Override {@link ClientConfig.peerConnectTimeoutMs} for this download. */
|
|
55
180
|
peerConnectTimeoutMs?: number;
|
|
181
|
+
/** Override {@link ClientConfig.progressEvents} for this download. */
|
|
56
182
|
progressEvents?: DownloadProgressEventMode;
|
|
183
|
+
/** Override {@link ClientConfig.requestTimeoutMs} for this download. */
|
|
57
184
|
requestTimeoutMs?: number;
|
|
185
|
+
/** Reserved for future seeding support. Currently only `false` is supported. */
|
|
58
186
|
seed?: false;
|
|
187
|
+
/** Override {@link ClientConfig.speedSampleIntervalMs} for this download. */
|
|
59
188
|
speedSampleIntervalMs?: number;
|
|
189
|
+
/** Override {@link ClientConfig.targetConnections} for this download. */
|
|
60
190
|
targetConnections?: number;
|
|
191
|
+
/** Override {@link ClientConfig.trackerTimeoutMs} for this download. */
|
|
61
192
|
trackerTimeoutMs?: number;
|
|
62
193
|
};
|
|
194
|
+
/** Supported torrent file sources. */
|
|
63
195
|
export type TorrentFileInput = string | Uint8Array | ArrayBuffer;
|
|
196
|
+
/**
|
|
197
|
+
* @internal
|
|
198
|
+
*/
|
|
64
199
|
export declare const readTorrentFile: (input: unknown) => Promise<Uint8Array>;
|
|
65
200
|
export { Client as TorrentClient };
|
package/dist/client.error.d.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { BunTorrentError } from './utils/errors';
|
|
2
|
+
/** Error codes set on {@link ClientError.code}. */
|
|
2
3
|
export declare enum ClientErrorCode {
|
|
4
|
+
/** {@link Client.download} or {@link Client.inspect} called after {@link Client.close}. */
|
|
5
|
+
CLOSED = "CLIENT_CLOSED",
|
|
6
|
+
/** `files` option referenced paths that do not exist in the torrent. */
|
|
3
7
|
INVALID_FILE_SELECTION = "CLIENT_INVALID_FILE_SELECTION",
|
|
8
|
+
/** Torrent file input was neither a string path, `Uint8Array`, nor `ArrayBuffer`. */
|
|
4
9
|
UNSUPPORTED_TORRENT_FILE_INPUT = "CLIENT_UNSUPPORTED_TORRENT_FILE_INPUT"
|
|
5
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Errors thrown directly by {@link Client}. See {@link ClientErrorCode}.
|
|
13
|
+
*
|
|
14
|
+
* Errors from underlying subsystems (parser, tracker, peer pool, DHT) are thrown as
|
|
15
|
+
* their own classes — this one only wraps client-level failures.
|
|
16
|
+
*/
|
|
6
17
|
export declare class ClientError extends BunTorrentError {
|
|
7
18
|
constructor(code: ClientErrorCode, message: string);
|
|
8
19
|
}
|
package/dist/client.error.js
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { BunTorrentError } from './utils/errors';
|
|
2
|
+
/** Error codes set on {@link ClientError.code}. */
|
|
2
3
|
export var ClientErrorCode;
|
|
3
4
|
(function (ClientErrorCode) {
|
|
5
|
+
/** {@link Client.download} or {@link Client.inspect} called after {@link Client.close}. */
|
|
6
|
+
ClientErrorCode["CLOSED"] = "CLIENT_CLOSED";
|
|
7
|
+
/** `files` option referenced paths that do not exist in the torrent. */
|
|
4
8
|
ClientErrorCode["INVALID_FILE_SELECTION"] = "CLIENT_INVALID_FILE_SELECTION";
|
|
9
|
+
/** Torrent file input was neither a string path, `Uint8Array`, nor `ArrayBuffer`. */
|
|
5
10
|
ClientErrorCode["UNSUPPORTED_TORRENT_FILE_INPUT"] = "CLIENT_UNSUPPORTED_TORRENT_FILE_INPUT";
|
|
6
11
|
})(ClientErrorCode || (ClientErrorCode = {}));
|
|
12
|
+
/**
|
|
13
|
+
* Errors thrown directly by {@link Client}. See {@link ClientErrorCode}.
|
|
14
|
+
*
|
|
15
|
+
* Errors from underlying subsystems (parser, tracker, peer pool, DHT) are thrown as
|
|
16
|
+
* their own classes — this one only wraps client-level failures.
|
|
17
|
+
*/
|
|
7
18
|
export class ClientError extends BunTorrentError {
|
|
8
19
|
constructor(code, message) {
|
|
9
20
|
super(message, code);
|
package/dist/client.error.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.error.js","sourceRoot":"","sources":["../src/client.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"client.error.js","sourceRoot":"","sources":["../src/client.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,mDAAmD;AACnD,MAAM,CAAN,IAAY,eAOX;AAPD,WAAY,eAAe;IACvB,2FAA2F;IAC3F,2CAAwB,CAAA;IACxB,wEAAwE;IACxE,2EAAwD,CAAA;IACxD,qFAAqF;IACrF,2FAAwE,CAAA;AAC5E,CAAC,EAPW,eAAe,KAAf,eAAe,QAO1B;AAED;;;;;GAKG;AACH,MAAM,OAAO,WAAY,SAAQ,eAAe;IAC5C,YAAY,IAAqB,EAAE,OAAe;QAC9C,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;CACJ"}
|