p2p-transfer 1.0.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 (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +248 -0
  3. package/p2p.js +289 -0
  4. package/package.json +59 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 P2P Transfer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,248 @@
1
+ # P2P Transfer
2
+
3
+ 🚀 A pure CLI tool for peer-to-peer file transfer between different networks, powered by WebTorrent and BitTorrent DHT.
4
+
5
+ ## ✨ Features
6
+
7
+ - 🌐 **Pure CLI** - No web UI or browser required, operate directly in terminal
8
+ - 🔧 **Zero Configuration** - One command to send, one command to receive
9
+ - 👶 **Beginner Friendly** - Intuitive commands with progress bar and speed display
10
+ - ⚡ **Maximum Speed** - DHT + configurable Tracker subscription for optimal peer discovery
11
+ - 🔒 **Cross-Network** - Transfer between different LANs without requiring public IP
12
+ - 📦 **Large File Support** - Handles files of any size with automatic chunking
13
+
14
+ ## 🚀 Quick Start
15
+
16
+ ### Installation
17
+
18
+ ```bash
19
+ # Install via npm (after publishing)
20
+ npm install -g p2p-transfer
21
+
22
+ # Or use npx directly
23
+ npx p2p-transfer share <file>
24
+ ```
25
+
26
+ ### Basic Usage
27
+
28
+ **Share a file (on sender's machine):**
29
+ ```bash
30
+ p2p share ~/movies/vacation.mp4
31
+ ```
32
+
33
+ **Download a file (on receiver's machine):**
34
+ ```bash
35
+ p2p get "magnet:?xt=urn:btih:abc123..."
36
+ ```
37
+
38
+ ## 📖 Detailed Usage
39
+
40
+ ### Share Command
41
+
42
+ ```bash
43
+ p2p share <file> [options]
44
+
45
+ Options:
46
+ -v, --verbose Show detailed logs
47
+ ```
48
+
49
+ **Example:**
50
+ ```bash
51
+ p2p share ~/documents/report.pdf
52
+ p2p share ./large-video.mp4 --verbose
53
+ ```
54
+
55
+ **Output:**
56
+ ```
57
+ 🚀 Initializing P2P share...
58
+ 📁 File: report.pdf
59
+ 📊 Size: 2.5 MB
60
+
61
+ ✅ Share successful!
62
+
63
+ 🔗 Magnet URI (copy and send to receiver):
64
+ magnet:?xt=urn:btih:abc123def456...
65
+
66
+ 📋 BTIH Hash: abc123def456
67
+
68
+ ⏳ Waiting for connections... (Press Ctrl+C to stop)
69
+ ```
70
+
71
+ ### Download Command
72
+
73
+ ```bash
74
+ p2p get <magnet> [path] [options]
75
+
76
+ Arguments:
77
+ magnet Magnet URI
78
+ path Download directory (default: current directory)
79
+
80
+ Options:
81
+ -v, --verbose Show detailed logs
82
+ ```
83
+
84
+ **Example:**
85
+ ```bash
86
+ p2p get "magnet:?xt=urn:btih:abc123..." ~/Downloads
87
+ p2p get "magnet:?xt=urn:btih:abc123..." ./my-files
88
+ ```
89
+
90
+ **Output:**
91
+ ```
92
+ 📥 Initializing P2P download...
93
+
94
+ ✅ File found!
95
+
96
+ 📁 Filename: report.pdf
97
+ 📊 Total size: 2.5 MB
98
+ 📋 Hash: abc123def456
99
+ 📁 Save to: ~/Downloads
100
+
101
+ 📥 Download Progress |████████████░░░░| 45% | 1.1 MB/2.5 MB | 5.2 MB/s | ETA: 00:00:03
102
+
103
+ ✅ Download complete!
104
+ ⏱️ Total time: 2.50 seconds
105
+ 📁 Location: ~/Downloads/report.pdf
106
+ ```
107
+
108
+ ### Help Command
109
+
110
+ ```bash
111
+ p2p info
112
+ ```
113
+
114
+ ## 🎯 How It Works
115
+
116
+ ```
117
+ ┌─────────────────┐ ┌─────────────────┐
118
+ │ Sender │ P2P │ Receiver │
119
+ │ │◄───────►│ │
120
+ │ 1. Seed file │ DHT │ 2. Download │
121
+ │ 3. Get Magnet │ │ 4. Parse Magnet│
122
+ │ 4. Share Link │ │ 5. Start D/L │
123
+ └─────────────────┘ └─────────────────┘
124
+ ```
125
+
126
+ 1. **Sender** runs `p2p share <file>` to start seeding
127
+ 2. Generates unique **Magnet URI** containing file hash and Tracker addresses
128
+ 3. **Receiver** runs `p2p get <magnet>` with the received URI
129
+ 4. **DHT + Trackers** discover peers automatically
130
+ 5. **P2P connection** established for direct transfer
131
+
132
+ ## 🔧 Technical Details
133
+
134
+ - **Protocol**: BitTorrent
135
+ - **Peer Discovery**: DHT (Distributed Hash Table)
136
+ - **Trackers**: 7 public trackers for maximum connectivity
137
+ - **No Public IP Required**: Works behind NAT and firewalls
138
+
139
+ ### Default Trackers
140
+
141
+ ```
142
+ - udp://tracker.opentrackr.org:1337/announce
143
+ - udp://tracker.openbittorrent.com:6969/announce
144
+ - udp://exodus.desync.com:6969/announce
145
+ - udp://tracker.coppersurfer.tk:6969/announce
146
+ - wss://tracker.btorrent.xyz
147
+ - wss://tracker.openwebtorrent.com
148
+ - wss://tracker.webtorrent.io
149
+ ```
150
+
151
+ ## 💡 Use Cases
152
+
153
+ - **NAS to Local**: Transfer files from NAS to your computer
154
+ - **Cross-Network**: Share files between different networks (home ↔ office)
155
+ - **Quick Sharing**: No need to upload to cloud first
156
+ - **Large Files**: Perfect for big files without size limits
157
+ - **Offline Sharing**: Works without internet servers (via DHT)
158
+
159
+ ## ⚙️ Requirements
160
+
161
+ - Node.js >= 18.0.0
162
+ - npm >= 8.0.0
163
+
164
+ ## 📦 Installation from Source
165
+
166
+ ```bash
167
+ git clone https://gitcode.com/yunqiang_wu/p2p-transfer.git
168
+ cd p2p-transfer
169
+ npm install
170
+ ```
171
+
172
+ ## 🌟 Advanced Usage
173
+
174
+ ### Global Installation
175
+
176
+ ```bash
177
+ npm install -g p2p-transfer
178
+
179
+ # Now you can use it anywhere
180
+ p2p share ~/file.txt
181
+ ```
182
+
183
+ ### Use as Project Dependency
184
+
185
+ ```bash
186
+ npm install p2p-transfer
187
+ ```
188
+
189
+ Then in your code:
190
+ ```javascript
191
+ import { share, get } from 'p2p-transfer';
192
+
193
+ await share('/path/to/file');
194
+ await get('magnet:?xt=urn:btih:...');
195
+ ```
196
+
197
+ ## 🐛 Troubleshooting
198
+
199
+ ### No peers connecting?
200
+
201
+ 1. **Check firewall**: Ensure outbound UDP/TCP is allowed
202
+ 2. **Wait longer**: DHT peer discovery may take 1-2 minutes
203
+ 3. **Try verbose mode**: `p2p share <file> -v`
204
+ 4. **Use more trackers**: Add additional trackers in code
205
+
206
+ ### Download speed is slow?
207
+
208
+ 1. **Wait for more peers**: Speed increases with more seeders
209
+ 2. **Check NAT**: Some networks have bandwidth limits
210
+ 3. **Try different network**: Some ISPs throttle BitTorrent
211
+
212
+ ### Connection issues?
213
+
214
+ - Ensure both sides have internet access
215
+ - Check if magnet link is complete (no truncation)
216
+ - Try restarting both sender and receiver
217
+
218
+ ## 🤝 Contributing
219
+
220
+ Contributions are welcome! Please feel free to submit a Pull Request.
221
+
222
+ ## 📄 License
223
+
224
+ MIT License - see [LICENSE](LICENSE) file for details.
225
+
226
+ ## 🙏 Acknowledgments
227
+
228
+ - [WebTorrent](https://webtorrent.io/) - BitTorrent implementation for Node.js
229
+ - [BitTorrent DHT](https://en.wikipedia.org/wiki/Mainline_DHT) - Distributed hash table
230
+ - All the public tracker operators
231
+
232
+ ## 📈 Roadmap
233
+
234
+ - [ ] Add WebRTC support for browser-based sharing
235
+ - [ ] Implement pause/resume functionality
236
+ - [ ] Add multiple file sharing support
237
+ - [ ] Implement bandwidth limiting
238
+ - [ ] Add encryption option
239
+ - [ ] Create GUI version
240
+
241
+ ## 📞 Support
242
+
243
+ - 🐛 Issues: [GitHub Issues](https://gitcode.com/yunqiang_wu/p2p-transfer/issues)
244
+ - 💬 Discussions: [GitHub Discussions](https://gitcode.com/yunqiang_wu/p2p-transfer/discussions)
245
+
246
+ ---
247
+
248
+ Made with ❤️ for the P2P community
package/p2p.js ADDED
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env node
2
+
3
+ import WebTorrent from 'webtorrent';
4
+ import cliProgress from 'cli-progress';
5
+ import yargs from 'yargs';
6
+ import { hideBin } from 'yargs/helpers';
7
+ import chalk from 'chalk';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import os from 'os';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+
16
+ const DEFAULT_TRACKERS = [
17
+ 'udp://tracker.opentrackr.org:1337/announce',
18
+ 'udp://tracker.openbittorrent.com:6969/announce',
19
+ 'udp://exodus.desync.com:6969/announce',
20
+ 'udp://tracker.coppersurfer.tk:6969/announce',
21
+ 'wss://tracker.btorrent.xyz',
22
+ 'wss://tracker.openwebtorrent.com',
23
+ 'wss://tracker.webtorrent.io',
24
+ ];
25
+
26
+ function formatSize(bytes) {
27
+ if (bytes === 0) return '0 B';
28
+ const k = 1024;
29
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
30
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
31
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
32
+ }
33
+
34
+ function formatSpeed(bytesPerSecond) {
35
+ return formatSize(bytesPerSecond) + '/s';
36
+ }
37
+
38
+ function formatTime(seconds) {
39
+ if (!isFinite(seconds) || seconds < 0) return '--:--:--';
40
+ const h = Math.floor(seconds / 3600);
41
+ const m = Math.floor((seconds % 3600) / 60);
42
+ const s = Math.floor(seconds % 60);
43
+ return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
44
+ }
45
+
46
+ async function shareFile(filePath, options) {
47
+ console.log(chalk.blue('🚀 初始化 P2P 分享...'));
48
+
49
+ const client = new WebTorrent({
50
+ tracker: {
51
+ RTCPeerConnection: false,
52
+ },
53
+ dht: {
54
+ pool: true,
55
+ },
56
+ });
57
+
58
+ const absolutePath = path.resolve(filePath);
59
+
60
+ if (!fs.existsSync(absolutePath)) {
61
+ console.error(chalk.red('❌ 文件不存在: ' + absolutePath));
62
+ client.destroy();
63
+ process.exit(1);
64
+ }
65
+
66
+ const stats = fs.statSync(absolutePath);
67
+ const fileName = path.basename(absolutePath);
68
+
69
+ console.log(chalk.cyan('📁 文件: ') + fileName);
70
+ console.log(chalk.cyan('📊 大小: ') + formatSize(stats.size));
71
+
72
+ return new Promise((resolve, reject) => {
73
+ client.seed(absolutePath, {
74
+ announceList: [DEFAULT_TRACKERS],
75
+ name: fileName,
76
+ }, (torrent) => {
77
+ console.log(chalk.green('\n✅ 分享成功!\n'));
78
+ console.log(chalk.yellow('🔗 Magnet 链接 (复制发送给接收方):'));
79
+ console.log(chalk.white(torrent.magnetURI));
80
+ console.log(chalk.cyan('\n📋 BTIH Hash: ') + torrent.infoHash);
81
+
82
+ console.log(chalk.blue('\n⏳ 等待连接中... (按 Ctrl+C 停止)\n'));
83
+
84
+ torrent.on('wire', (wire) => {
85
+ const peerAddr = wire.remoteAddress || 'unknown';
86
+ console.log(chalk.green('🔗 新连接: ') + peerAddr);
87
+ });
88
+
89
+ torrent.on('error', (err) => {
90
+ console.error(chalk.red('Torrent error:'), err.message);
91
+ });
92
+
93
+ if (options.verbose) {
94
+ torrent.on('warning', (warning) => {
95
+ console.log(chalk.yellow('⚠️ Warning:'), warning.message);
96
+ });
97
+ }
98
+ });
99
+
100
+ client.on('error', (err) => {
101
+ console.error(chalk.red('❌ 客户端错误:'), err.message);
102
+ reject(err);
103
+ });
104
+ });
105
+ }
106
+
107
+ async function getFile(magnetUri, downloadPath, options) {
108
+ console.log(chalk.blue('📥 初始化 P2P 下载...'));
109
+
110
+ const client = new WebTorrent({
111
+ tracker: {
112
+ RTCPeerConnection: false,
113
+ },
114
+ dht: {
115
+ pool: true,
116
+ },
117
+ });
118
+
119
+ const savePath = downloadPath || process.cwd();
120
+
121
+ if (!fs.existsSync(savePath)) {
122
+ fs.mkdirSync(savePath, { recursive: true });
123
+ }
124
+
125
+ return new Promise((resolve, reject) => {
126
+ const torrent = client.add(magnetUri, {
127
+ path: savePath,
128
+ announceList: [DEFAULT_TRACKERS],
129
+ });
130
+
131
+ const progressBar = new cliProgress.SingleBar({
132
+ format: chalk.cyan('📥 下载进度') + ' |' + chalk.cyan('{bar}') + '| {percentage}% | {downloaded}/{total} | {speed} | ETA: {eta}',
133
+ barCompleteChar: '\u2588',
134
+ barIncompleteChar: '\u2591',
135
+ hideCursor: true,
136
+ });
137
+
138
+ let startTime = Date.now();
139
+ let lastDownloaded = 0;
140
+ let updateInterval;
141
+
142
+ torrent.on('metadata', () => {
143
+ console.log(chalk.green('\n✅ 找到文件!\n'));
144
+ console.log(chalk.cyan('📁 文件名: ') + torrent.name);
145
+ console.log(chalk.cyan('📊 总大小: ') + formatSize(torrent.length));
146
+ console.log(chalk.cyan('📋 Hash: ') + torrent.infoHash);
147
+ console.log(chalk.cyan('📁 保存到: ') + savePath);
148
+
149
+ progressBar.start(torrent.length, 0, {
150
+ downloaded: '0 B',
151
+ total: formatSize(torrent.length),
152
+ speed: '0 B/s',
153
+ eta: '--:--:--',
154
+ });
155
+
156
+ updateInterval = setInterval(() => {
157
+ if (torrent.length > 0) {
158
+ const downloaded = torrent.downloaded || 0;
159
+ const speed = torrent.downloadSpeed || 0;
160
+ const eta = torrent.timeRemaining / 1000;
161
+
162
+ progressBar.update(downloaded, {
163
+ downloaded: formatSize(downloaded),
164
+ total: formatSize(torrent.length),
165
+ speed: formatSpeed(speed),
166
+ eta: formatTime(eta),
167
+ });
168
+ }
169
+ }, 500);
170
+ });
171
+
172
+ torrent.on('done', () => {
173
+ clearInterval(updateInterval);
174
+ const totalTime = ((Date.now() - startTime) / 1000).toFixed(2);
175
+ console.log(chalk.green('\n✅ 下载完成!'));
176
+ console.log(chalk.cyan('⏱️ 总耗时: ') + totalTime + ' 秒');
177
+ console.log(chalk.cyan('📁 保存位置: ') + path.join(savePath, torrent.name));
178
+ });
179
+
180
+ torrent.on('wire', (wire) => {
181
+ const peerAddr = wire.remoteAddress || 'unknown';
182
+ console.log(chalk.green('🔗 新连接: ') + peerAddr + ' (已连接: ' + torrent.numPeers + ' 个节点)');
183
+ });
184
+
185
+ torrent.on('peer', (peer) => {
186
+ console.log(chalk.green('➕ 新节点: ') + (peer.remoteAddress || peer.ip || 'unknown'));
187
+ });
188
+
189
+ torrent.on('error', (err) => {
190
+ console.error(chalk.red('❌ 下载错误:'), err.message);
191
+ clearInterval(updateInterval);
192
+ reject(err);
193
+ });
194
+
195
+ client.on('error', (err) => {
196
+ console.error(chalk.red('❌ 客户端错误:'), err.message);
197
+ clearInterval(updateInterval);
198
+ reject(err);
199
+ });
200
+
201
+ process.on('SIGINT', () => {
202
+ console.log(chalk.yellow('\n\n⚠️ 正在停止下载...'));
203
+ clearInterval(updateInterval);
204
+ if (progressBar.isActive) {
205
+ progressBar.stop();
206
+ }
207
+ client.destroy(() => {
208
+ console.log(chalk.green('✅ 已停止。'));
209
+ process.exit(0);
210
+ });
211
+ });
212
+ });
213
+ }
214
+
215
+ function showInfo() {
216
+ console.log(chalk.bold('\n🌐 P2P 文件传输工具\n'));
217
+ console.log(chalk.cyan('使用方法:'));
218
+ console.log(' 发送文件:');
219
+ console.log(chalk.white(' p2p share <文件路径>'));
220
+ console.log(' 例如: p2p share ~/movies/vacation.mp4\n');
221
+ console.log(' 接收文件:');
222
+ console.log(chalk.white(' p2p get <magnet链接> [保存目录]'));
223
+ console.log(' 例如: p2p get "magnet:?xt=..." ~/Downloads\n');
224
+ console.log(chalk.cyan('原理:'));
225
+ console.log(' - 使用 BitTorrent 协议进行 P2P 传输');
226
+ console.log(' - 通过 DHT 网络发现节点,无需公网 IP');
227
+ console.log(' - 支持跨局域网传输\n');
228
+ }
229
+
230
+ const argv = yargs(hideBin(process.argv))
231
+ .usage(chalk.bold('\n🌐 P2P 文件传输工具\n\n用法: $0 <命令> [参数]'))
232
+ .command('share', '分享文件,生成 magnet 链接', (yargs) => {
233
+ return yargs
234
+ .positional('file', {
235
+ describe: '要分享的文件路径',
236
+ type: 'string',
237
+ })
238
+ .option('v', {
239
+ alias: 'verbose',
240
+ describe: '显示详细日志',
241
+ type: 'boolean',
242
+ default: false,
243
+ });
244
+ }, async (argv) => {
245
+ const file = argv._[1];
246
+ if (!file) {
247
+ console.error(chalk.red('❌ 请指定要分享的文件路径'));
248
+ process.exit(1);
249
+ }
250
+ await shareFile(file, argv);
251
+ })
252
+ .command('get', '下载文件', (yargs) => {
253
+ return yargs
254
+ .positional('magnet', {
255
+ describe: 'Magnet 链接',
256
+ type: 'string',
257
+ })
258
+ .positional('path', {
259
+ describe: '保存目录',
260
+ type: 'string',
261
+ default: process.cwd(),
262
+ })
263
+ .option('v', {
264
+ alias: 'verbose',
265
+ describe: '显示详细日志',
266
+ type: 'boolean',
267
+ default: false,
268
+ });
269
+ }, async (argv) => {
270
+ const magnet = argv._[1];
271
+ const savePath = argv._[2] || process.cwd();
272
+ if (!magnet) {
273
+ console.error(chalk.red('❌ 请提供 Magnet 链接'));
274
+ process.exit(1);
275
+ }
276
+ await getFile(magnet, savePath, argv);
277
+ })
278
+ .command('info', '显示帮助信息', {}, () => {
279
+ showInfo();
280
+ })
281
+ .demandCommand(1, chalk.red('❌ 请指定命令: share 或 get'))
282
+ .help('h', '显示帮助')
283
+ .alias('h', 'help')
284
+ .version('v', '版本', '1.0.0')
285
+ .alias('v', 'version')
286
+ .epilog(chalk.cyan('\n💡 提示:'))
287
+ .epilog(chalk.cyan(' 发送方运行: p2p share <文件>'))
288
+ .epilog(chalk.cyan(' 接收方运行: p2p get <magnet链接>'))
289
+ .parse();
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "p2p-transfer",
3
+ "version": "1.0.0",
4
+ "description": "🚀 Pure CLI P2P file transfer tool using WebTorrent and BitTorrent DHT. Transfer files between different networks without public IP.",
5
+ "keywords": [
6
+ "p2p",
7
+ "bittorrent",
8
+ "webtorrent",
9
+ "file-transfer",
10
+ "cli",
11
+ "peer-to-peer",
12
+ "dht",
13
+ "magnet",
14
+ "share",
15
+ "download"
16
+ ],
17
+ "homepage": "https://gitcode.com/yunqiang_wu/p2p-transfer#readme",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://gitcode.com/yunqiang_wu/p2p-transfer.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://gitcode.com/yunqiang_wu/p2p-transfer/issues"
24
+ },
25
+ "license": "MIT",
26
+ "author": {
27
+ "name": "Yunqiang Wu",
28
+ "email": "your.email@example.com",
29
+ "url": "https://gitcode.com/yunqiang_wu"
30
+ },
31
+ "main": "p2p.js",
32
+ "bin": {
33
+ "p2p": "./p2p.js"
34
+ },
35
+ "type": "module",
36
+ "scripts": {
37
+ "start": "node p2p.js",
38
+ "share": "node p2p.js share",
39
+ "get": "node p2p.js get",
40
+ "info": "node p2p.js info",
41
+ "test": "echo \"No tests specified\" && exit 0"
42
+ },
43
+ "dependencies": {
44
+ "webtorrent": "^2.0.0",
45
+ "cli-progress": "^3.12.0",
46
+ "yargs": "^17.7.2",
47
+ "chalk": "^5.3.0"
48
+ },
49
+ "devDependencies": {},
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ },
53
+ "preferGlobal": true,
54
+ "files": [
55
+ "p2p.js",
56
+ "README.md",
57
+ "LICENSE"
58
+ ]
59
+ }