peerline 0.1.0-alpha.9 → 0.1.0-beta.1
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 +24 -14
- package/npm/peerline.js +15 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Peerline is a terminal-first peer-to-peer file transfer tool.
|
|
|
4
4
|
|
|
5
5
|
It is built for the moments when you want to move files, folders, logs, build artifacts, or project snapshots directly between two machines without first uploading them to a cloud drive. One side opens a receive session, shares a human-friendly name and code, and the other side sends one or more paths. Peerline then tries to find the best route between the two peers and transfers the data with application-layer end-to-end encryption.
|
|
6
6
|
|
|
7
|
-
Peerline is not a sync service and it does not keep a permanent hosted copy of your files. It is closer to a
|
|
7
|
+
Peerline is not a sync service and it does not keep a permanent hosted copy of your files. It is closer to a terminal copy workflow: start a receiver, send one or more batches of paths, verify the transfer, and exit when you are done.
|
|
8
8
|
|
|
9
9
|
## Why Peerline Exists
|
|
10
10
|
|
|
@@ -18,12 +18,14 @@ Peerline is not a sync service and it does not keep a permanent hosted copy of y
|
|
|
18
18
|
|
|
19
19
|
Peerline has two roles:
|
|
20
20
|
|
|
21
|
-
- Receiver: runs `peerline recv`,
|
|
21
|
+
- Receiver: runs `peerline recv`, keeps listening for incoming transfers until you quit or the idle timeout expires, and prints a `name`, `code`, and direct endpoint.
|
|
22
22
|
- Sender: runs `peerline send`, points at the receiver by name/code or IP/code, and provides the files or folders to send.
|
|
23
23
|
|
|
24
24
|
For named transfers, the receiver publishes a short-lived descriptor keyed by the shared name and code. The sender derives the same lookup key, discovers candidate routes, and tries them in order. Peerline prefers direct LAN or public TCP endpoints first, then libp2p routes such as DCUtR and WebRTC TURN. Relay data fallback is available only when explicitly enabled.
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Peerline also probes HTTP rendezvous first, with a default endpoint at `https://peerline.pwp.sh`, then falls back to DHT and mDNS. Official builds use a private mTLS-protected rendezvous endpoint; set `PEERLINE_RENDEZVOUS_CLIENT_IDENTITY_PATH` or `PEERLINE_RENDEZVOUS_CLIENT_IDENTITY_PEM` to a PEM bundle with the client certificate and private key, or set `PEERLINE_RENDEZVOUS_URLS` / `PEERLINE_RENDEZVOUS_URL` to point at another compatible rendezvous service. Use `PEERLINE_RENDEZVOUS_TOKEN` only when the rendezvous service expects a shared secret.
|
|
27
|
+
|
|
28
|
+
For direct transfers, the sender can skip discovery and dial an IP address or `host:port` directly. This is useful on the same network, over VPNs, or whenever the receiver already knows which address the sender should use. If you only provide an IP, Peerline probes the default direct window `43117-43121`.
|
|
27
29
|
|
|
28
30
|
During a transfer, Peerline scans the requested paths into a manifest, preserves directories with safe relative paths, compresses when useful, and streams the archive to the receiver. The receiver verifies file sizes and BLAKE3 hashes before writing files into the current directory. Existing files are kept by default; conflicting names receive a non-overwriting suffix unless `--overwrite` is used.
|
|
29
31
|
|
|
@@ -71,40 +73,41 @@ The receiver prints values like:
|
|
|
71
73
|
|
|
72
74
|
```text
|
|
73
75
|
peerline recv
|
|
74
|
-
name:
|
|
75
|
-
code:
|
|
76
|
+
name: frost-827
|
|
77
|
+
code: fig-mint-1234-5678
|
|
76
78
|
direct: 0.0.0.0:43117
|
|
77
|
-
waiting for
|
|
79
|
+
waiting for transfers over direct TCP or libp2p...
|
|
80
|
+
idle timeout: 10 min (change with --idle-timeout-minutes)
|
|
78
81
|
```
|
|
79
82
|
|
|
80
83
|
Send a file, multiple files, or a folder by name and code:
|
|
81
84
|
|
|
82
85
|
```sh
|
|
83
|
-
peerline send
|
|
84
|
-
peerline send
|
|
86
|
+
peerline send frost-827 fig-mint-1234-5678 ./file.txt
|
|
87
|
+
peerline send frost-827 fig-mint-1234-5678 ./file.txt ./notes.md ./photos
|
|
85
88
|
```
|
|
86
89
|
|
|
87
90
|
Receive with a saved name:
|
|
88
91
|
|
|
89
92
|
```sh
|
|
90
|
-
peerline set name
|
|
93
|
+
peerline set name frost-827
|
|
91
94
|
peerline recv
|
|
92
95
|
```
|
|
93
96
|
|
|
94
97
|
After a name is saved, you can receive with only a fresh code:
|
|
95
98
|
|
|
96
99
|
```sh
|
|
97
|
-
peerline recv
|
|
100
|
+
peerline recv fig-mint-1234-5678
|
|
98
101
|
```
|
|
99
102
|
|
|
100
103
|
Use a direct IP address when discovery is not needed:
|
|
101
104
|
|
|
102
105
|
```sh
|
|
103
|
-
peerline send 192.168.1.23:43117 ./file.txt --code=
|
|
104
|
-
peerline send 192.168.1.23 ./folder --code=
|
|
106
|
+
peerline send 192.168.1.23:43117 ./file.txt --code=fig-mint-1234-5678
|
|
107
|
+
peerline send 192.168.1.23 ./folder --code=fig-mint-1234-5678
|
|
105
108
|
```
|
|
106
109
|
|
|
107
|
-
When the port is omitted, Peerline
|
|
110
|
+
When the port is omitted, Peerline probes the default direct window `43117-43121`.
|
|
108
111
|
|
|
109
112
|
## Common Options
|
|
110
113
|
|
|
@@ -115,8 +118,12 @@ peerline recv [NAME_OR_CODE] [CODE] --port 43117
|
|
|
115
118
|
peerline recv [NAME_OR_CODE] [CODE] --overwrite
|
|
116
119
|
peerline recv [NAME_OR_CODE] [CODE] --no-tui
|
|
117
120
|
peerline recv [NAME_OR_CODE] [CODE] --allow-relay-fallback
|
|
121
|
+
peerline recv [NAME_OR_CODE] [CODE] --idle-timeout-minutes 30
|
|
118
122
|
```
|
|
119
123
|
|
|
124
|
+
`--port` starts the 5-port direct window; Peerline will try that port and the next four.
|
|
125
|
+
`--idle-timeout-minutes` defaults to `10`; set it to `0` to wait until you quit manually.
|
|
126
|
+
|
|
120
127
|
Sender options:
|
|
121
128
|
|
|
122
129
|
```sh
|
|
@@ -129,15 +136,18 @@ peerline send --name <name> --code <code> <path...>
|
|
|
129
136
|
```
|
|
130
137
|
|
|
131
138
|
Relay fallback must be enabled on both sides when you want Peerline to use relay data paths. Direct and hole-punched routes are attempted before relay fallback.
|
|
139
|
+
In the send TUI, a failed attempt stays on screen and offers `r` to retry the same send or `q`/Esc to quit.
|
|
132
140
|
|
|
133
141
|
## Current Status
|
|
134
142
|
|
|
135
143
|
- Direct IP send and receive works.
|
|
136
|
-
- Named discovery uses
|
|
144
|
+
- Named discovery now uses HTTP rendezvous first, then Kademlia provider records, mDNS, DCUtR, relay fallback, and libp2p-webrtc's built-in ICE servers.
|
|
137
145
|
- Files, multiple files, and folders are archived with safe relative paths, BLAKE3 integrity checks, and streaming zstd/lzma compression support.
|
|
146
|
+
- Receivers stay open across multiple incoming transfers, with a configurable idle auto-exit.
|
|
138
147
|
- Conflicts default to non-overwrite behavior, with TUI-driven handling in the receiver flow.
|
|
139
148
|
- The receive side includes a modern terminal UI for identity, route state, and transfer progress.
|
|
140
149
|
- The workspace test suite and E2E coverage are in place.
|
|
150
|
+
- The repository also includes a private Cloudflare Worker rendezvous service in `services/peerline-rendezvous`.
|
|
141
151
|
|
|
142
152
|
## License
|
|
143
153
|
|
package/npm/peerline.js
CHANGED
|
@@ -292,7 +292,20 @@ function executeBinary(binaryPath, argv = process.argv.slice(2), deps = {}) {
|
|
|
292
292
|
|
|
293
293
|
async function main(argv = process.argv.slice(2), deps = {}) {
|
|
294
294
|
const result = executeBinary(await resolveBinary(deps), argv, deps);
|
|
295
|
-
process.exit(result
|
|
295
|
+
process.exit(exitCodeForResult(result));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function exitCodeForResult(result) {
|
|
299
|
+
if (Number.isInteger(result?.status)) {
|
|
300
|
+
return result.status;
|
|
301
|
+
}
|
|
302
|
+
if (result?.signal === "SIGINT") {
|
|
303
|
+
return 130;
|
|
304
|
+
}
|
|
305
|
+
if (result?.signal === "SIGTERM") {
|
|
306
|
+
return 143;
|
|
307
|
+
}
|
|
308
|
+
return 1;
|
|
296
309
|
}
|
|
297
310
|
|
|
298
311
|
if (require.main === module) {
|
|
@@ -310,6 +323,7 @@ module.exports = {
|
|
|
310
323
|
downloadReleaseBinary,
|
|
311
324
|
ensureExecutable,
|
|
312
325
|
executeBinary,
|
|
326
|
+
exitCodeForResult,
|
|
313
327
|
copyBinaryToTemporaryLocation,
|
|
314
328
|
formatExecutionFallbackError,
|
|
315
329
|
isRetryableExecutionError,
|