peerline 0.1.0-alpha.9 → 0.1.0-beta.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.
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 one-shot terminal copy workflow: start a receiver, send the paths, verify the transfer, and exit.
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`, listens for one incoming transfer, and prints a `name`, `code`, and direct endpoint.
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
- 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.
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: river-mango-42
75
- code: rose-lime-iris-jade-1234
76
+ name: frost-827
77
+ code: fig-mint-1234-5678
76
78
  direct: 0.0.0.0:43117
77
- waiting for one transfer over direct TCP or libp2p...
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 river-mango-42 rose-lime-iris-jade-1234 ./file.txt
84
- peerline send river-mango-42 rose-lime-iris-jade-1234 ./file.txt ./notes.md ./photos
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 river-mango-42
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 rose-lime-iris-jade-1234
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=rose-lime-iris-jade-1234
104
- peerline send 192.168.1.23 ./folder --code=rose-lime-iris-jade-1234
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 uses the default direct port `43117`.
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 saved names, generated codes, OPAQUE PAKE, Kademlia provider records, mDNS, DCUtR, relay fallback, and libp2p-webrtc's built-in ICE servers.
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.status ?? 1);
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peerline",
3
- "version": "0.1.0-alpha.9",
3
+ "version": "0.1.0-beta.0",
4
4
  "description": "P2P post-quantum encrypted file transfer CLI",
5
5
  "repository": {
6
6
  "type": "git",