| … | … | @@ -1,112 +1,135 @@ |
| 1 | 1 | # hypermosh-shell |
| 2 | 2 | |
| 3 | 3 | **Resilient, roaming terminal sessions to peers you reach by public key** — real |
| 4 | [mosh](https://mosh.org) tunneled over a hole-punched | |
| 4 | [mosh](https://mosh.org) tunnelled over a hole-punched | |
| 5 | 5 | [hyperdht](https://github.com/holepunchto/hyperdht) connection, in one command. |
| 6 | 6 | |
| 7 | 7 | `mosh user@host`, but the "host" is a public key and the transport is P2P. For |
| 8 | 8 | nodes with **no reachable UDP port** (behind NAT/CGNAT, or mobile/roaming), where |
| 9 | 9 | a plain reliable-stream shell **dies on every network change** — mosh was designed |
| 10 | 10 | for exactly that (intermittent links, latency, IP roaming); hypermosh gives it a |
| 11 | P2P datagram path. | |
| 11 | P2P datagram path, and reconnects the tunnel under it as the network flaps. | |
| 12 | 12 | |
| 13 | 13 | ## One command |
| 14 | 14 | |
| 15 | 15 | ```sh |
| 16 | hypermosh <server-pubkey> # interactive mosh session over the DHT | |
| 17 | hypermosh <server-pubkey> -- htop # run a specific command | |
| 16 | hypermosh <user>@<server-pubkey> # interactive login shell over the DHT | |
| 17 | hypermosh <user>@<server-pubkey> -- htop # run a specific command | |
| 18 | hypermosh <server-pubkey> # same, using your local username | |
| 18 | 19 | ``` |
| 19 | 20 | |
| 20 | ## How it works | |
| 21 | Add `-v` (or `HYPERMOSH_DEBUG=1`) for connection logging. | |
| 21 | 22 | |
| 22 | ``` | |
| 23 | client server | |
| 24 | hypermosh <key> ─┐ hypermosh serve | |
| 25 | spawns │ hyperdht stream (identity-keyed, on connection: | |
| 26 | mosh-client ─UDP┤ firewalled, auto-reconnect) spawns mosh-server | |
| 27 | └── control: {term,cmd} → {ok,key} ──────┐ bridges its UDP | |
| 28 | data: UDP datagrams ⇄ UDP ───────┘ | |
| 23 | ## Two auth models | |
| 24 | ||
| 25 | ### Default — SSH-style login (recommended) | |
| 26 | ||
| 27 | The tunnel carries a **normal SSH connection to the server's system sshd** | |
| 28 | (`127.0.0.1:22`), so **password / ssh-key / `authorized_keys` all work exactly | |
| 29 | like `mosh user@host`.** sshd is the auth gate; the hyperdht firewall is open | |
| 30 | (anyone with the pubkey can *reach* it, only valid SSH credentials get a shell — | |
| 31 | just like a public SSH host). | |
| 32 | ||
| 33 | ```sh | |
| 34 | # server (needs sshd + mosh installed) | |
| 35 | hypermosh serve | |
| 36 | ||
| 37 | # client | |
| 38 | hypermosh you@<server-pubkey> | |
| 29 | 39 | ``` |
| 30 | 40 | |
| 31 | - `hypermosh serve` runs a small daemon on its own key. Per connection it **spawns | |
| 32 | a fresh `mosh-server`**, sends the client the one-time key over a control frame, | |
| 33 | and bridges the mosh UDP datagrams over the hyperdht stream. | |
| 34 | - `hypermosh <key>` connects, receives the key, spawns `mosh-client` at a local UDP | |
| 35 | port, and bridges. mosh's **SSP** does the rest — it survives packet loss, | |
| 36 | latency, and roaming, so when the network flaps the stream reconnects and the | |
| 37 | session **resyncs**. Nothing lost. | |
| 38 | - Addressed by **public key**, firewalled by an allow-list. The relay is a dumb | |
| 39 | UDP↔stream bridge; mosh provides all the resilience. | |
| 41 | This is faithful to how mosh actually works: mosh does no auth of its own — its | |
| 42 | wrapper runs `ssh user@host -- mosh-server new …` and lets OpenSSH authenticate. | |
| 43 | hypermosh does the same, just over hyperdht instead of a direct socket. Because | |
| 44 | `mosh-server` is launched **inside the authenticated SSH session**, it runs as the | |
| 45 | logged-in user and **daemonizes independently of the tunnel** — so when the | |
| 46 | network flaps, hypermosh redials and re-bridges the UDP to the *same* running | |
| 47 | `mosh-server`. That is mosh's roaming, preserved. | |
| 40 | 48 | |
| 41 | Wire format: typed frames over the reliable stream — | |
| 42 | `[uint8 type][uint32 len][payload]` (type 0 control/JSON, type 1 datagram). | |
| 49 | ### `--hyperident` — pubkey firewall (no SSH) | |
| 50 | ||
| 51 | Auth is a hyperdht public-key allow-list instead of sshd. The daemon spawns its | |
| 52 | own `mosh-server` per connection and hands the client the one-time key over the | |
| 53 | (encrypted) control channel. The client presents its `~/.hyperident` device key. | |
| 54 | ||
| 55 | ```sh | |
| 56 | hypermosh serve --hyperident --firewall ~/.hypermosh/allowed # allow-list file | |
| 57 | hypermosh serve --hyperident --disable-firewall # accept any peer | |
| 58 | hypermosh you@<server-pubkey> --hyperident # client | |
| 59 | ``` | |
| 60 | ||
| 61 | > **⚠ An empty allow-list means DENY-ALL.** `hypermosh serve --hyperident` with no | |
| 62 | > `--firewall` file and no `--disable-firewall` denies **every** peer — the daemon | |
| 63 | > now says so loudly at startup. (An empty allow-list silently denying everyone was | |
| 64 | > the original "hypermosh just doesn't connect" bug.) | |
| 43 | 65 | |
| 44 | 66 | ## Install |
| 45 | 67 | |
| 46 | 68 | ```sh |
| 47 | npm install # hyperdht, b4a, hypercore-id-encoding, protomux, compact-encoding | |
| 48 | # requires `mosh` (mosh-server + mosh-client) installed on both ends | |
| 69 | npm install # hyperdht, b4a, hypercore-id-encoding, protomux, bare-* shims | |
| 49 | 70 | ``` |
| 50 | 71 | |
| 51 | **mosh is not bundled** — install it via your package manager (`apt install mosh`, | |
| 52 | `brew install mosh`, …). On a minimal or locked-down target where the package | |
| 53 | manager can't configure packages, extract the binaries straight from `.deb`s: | |
| 72 | **mosh is not bundled** — bare runs JavaScript, and `mosh-server`/`mosh-client` | |
| 73 | are C++ binaries. Install mosh on **both ends** via your package manager | |
| 74 | (`apt install mosh`, `brew install mosh`, …). On a locked-down target where the | |
| 75 | package manager can't configure packages, extract the binaries from `.deb`s: | |
| 54 | 76 | |
| 55 | 77 | ```sh |
| 56 | 78 | apt-get download mosh libprotobuf23 libssl3 libutempter0 |
| 57 | 79 | for d in *.deb; do dpkg-deb -x "$d" /; done && ldconfig |
| 58 | 80 | ``` |
| 59 | 81 | |
| 82 | If mosh is missing hypermosh now says so plainly ("is mosh installed locally?" / | |
| 83 | "mosh-server not runnable") instead of hanging. | |
| 84 | ||
| 60 | 85 | Dual-runtime: Node and [Bare](https://github.com/holepunchto/bare) via the |
| 61 | `#node:*` import map (`dgram`→`bare-dgram`, `child_process`→`bare-subprocess`, …). | |
| 86 | `#node:*` import map (`net`→`bare-net`, `dgram`→`bare-dgram`, | |
| 87 | `child_process`→`bare-subprocess`, …). | |
| 62 | 88 | |
| 63 | 89 | ## CLI |
| 64 | 90 | |
| 65 | 91 | ``` |
| 66 | 92 | hypermosh id # this daemon's server pubkey |
| 67 | hypermosh serve [--firewall <file> | --disable-firewall] | |
| 68 | hypermosh <name-or-pubkey> [-- cmd...] | |
| 93 | hypermosh serve [--hyperident [--firewall <file> | --disable-firewall]] | |
| 94 | hypermosh [user@]<name-or-pubkey> [-- cmd...] | |
| 69 | 95 | hypermosh add-name <name> <pubkey> # optional: remember a name |
| 70 | 96 | hypermosh names # list known names |
| 71 | 97 | ``` |
| 72 | 98 | |
| 73 | - `serve` runs on its own key (persisted under `~/.hypermosh/`). `--firewall` is an | |
| 74 | allow-list file of client public keys (one z-base32/hex key per line, `#` | |
| 75 | comments); `--disable-firewall` accepts any peer. | |
| 76 | - The client presents an identity keypair (the hyperident vault at `~/.hyperident`) | |
| 77 | to the daemon's firewall. | |
| 78 | 99 | - **Names are optional.** A raw public key always works; `add-name` records a |
| 79 | 100 | `name -> pubkey` mapping in `~/.hypermosh/names` (SSH-known_hosts style) so you can |
| 80 | say `hypermosh myserver`. A future P2P name registry slots in behind the same | |
| 81 | resolver. | |
| 82 | ||
| 83 | ## Design notes | |
| 84 | ||
| 85 | - **mosh-server daemonizes.** `mosh-server new` prints `MOSH CONNECT …` then forks a | |
| 86 | *detached* daemon and the spawned parent exits immediately. Do **not** tie the | |
| 87 | tunnel socket to that parent's exit — an early `socket.end()` closes the write | |
| 88 | side before any session data flows. Track the detached pid for cleanup instead. | |
| 89 | - **Attach the data handler immediately** (before the hyperdht `open` event) — | |
| 90 | attaching it inside `open` stalled the read side after the first frame. | |
| 91 | - **No `writable` guard on writes** — the UDX stream buffers pre-connection writes, | |
| 92 | so mosh's earliest packets survive the DHT connect instead of being dropped. | |
| 93 | - **Auto-reconnect = roaming.** On stream close the client redials the pubkey; mosh | |
| 94 | resyncs the session across it. | |
| 95 | - **Bare compatibility.** Node globals are *not* globals in Bare — each one | |
| 96 | (`process`, `Buffer`, …) must be imported. This code imports `process` and routes | |
| 97 | `fs`/`dgram`/`child_process`/etc. through the `#node:*` map, so it runs on Bare as | |
| 98 | well as Node. If you add code touching a Node global directly, expect | |
| 99 | `process is not defined` on Bare until you import it. | |
| 101 | say `hypermosh you@myserver`. | |
| 102 | ||
| 103 | ## How it works (default SSH mode) | |
| 104 | ||
| 105 | ``` | |
| 106 | client server (hypermosh serve) | |
| 107 | hypermosh you@<key> ─┐ on connection, per stream: | |
| 108 | ssh ─TCP─────────► │ one hyperdht stream, framed ├─ ssh channel ⇄ sshd :22 | |
| 109 | │ • ssh channel (auth+boot) └─ udp channel ⇄ mosh-server | |
| 110 | mosh-client ─UDP──►│ • udp channel (mosh data) | |
| 111 | └── ssh runs `mosh-server new`, we parse MOSH CONNECT, | |
| 112 | bridge its UDP, spawn mosh-client. mosh's SSP does the | |
| 113 | rest — survives loss, latency, and roaming. | |
| 114 | ``` | |
| 115 | ||
| 116 | Wire format: typed frames over the reliable stream — | |
| 117 | `[uint8 type][uint32 len][payload]` (0 control/JSON, 1 mosh datagram, 2 ssh bytes, | |
| 118 | 3 ssh-end). The server's UDP bridge is clamped to `127.0.0.1` and mosh's port | |
| 119 | range so an authenticated tunnel can't be abused as an arbitrary loopback proxy. | |
| 100 | 120 | |
| 101 | 121 | ## Tests |
| 102 | 122 | |
| 103 | 123 | ```sh |
| 104 | npm test | |
| 105 | # [1] loopback: UDP echo through the hyperdht tunnel ✅ | |
| 106 | # [2] real mosh: session through the tunnel ✅ | |
| 107 | # [session] one-command mosh session end-to-end ✅ (mosh-dependent tests skip if mosh absent) | |
| 124 | npm test # frames (unit) · firewall (root-cause regression) · ssh-mode e2e | |
| 125 | npm run test:p2p # relay + one-command loopback (flaky on ONE machine — self-hairpin | |
| 126 | # DHT; the real proof is a cross-machine run) | |
| 108 | 127 | ``` |
| 109 | 128 | |
| 129 | The `ssh-mode` test stands up an isolated throwaway sshd and runs a full | |
| 130 | SSH-login → mosh session end-to-end over hyperdht (skips if sshd/mosh/python3 | |
| 131 | are absent). | |
| 132 | ||
| 110 | 133 | ## License |
| 111 | 134 | |
| 112 | 135 | Apache-2.0 |
| … | … | @@ -10,6 +10,13 @@ |
| 10 | 10 | "license": "Apache-2.0", |
| 11 | 11 | "dependencies": { |
| 12 | 12 | "b4a": "^1.6.0", |
| 13 | "bare-dgram": "^1.0.0", | |
| 14 | "bare-fs": "^4.0.0", | |
| 15 | "bare-net": "^2.3.2", | |
| 16 | "bare-os": "^3.0.0", | |
| 17 | "bare-path": "^3.0.0", | |
| 18 | "bare-process": "^4.0.0", | |
| 19 | "bare-subprocess": "^6.1.0", | |
| 13 | 20 | "compact-encoding": "^2.11.0", |
| 14 | 21 | "hypercore-id-encoding": "^1.2.0", |
| 15 | 22 | "hyperdht": "^6.6.0", |
| … | … | @@ -17,14 +24,6 @@ |
| 17 | 24 | }, |
| 18 | 25 | "bin": { |
| 19 | 26 | "hypermosh": "bin/hypermosh.mjs" |
| 20 | }, | |
| 21 | "optionalDependencies": { | |
| 22 | "bare-dgram": "^1.0.0", | |
| 23 | "bare-fs": "^4.0.0", | |
| 24 | "bare-os": "^3.0.0", | |
| 25 | "bare-path": "^3.0.0", | |
| 26 | "bare-process": "^4.0.0", | |
| 27 | "bare-subprocess": "^5.0.0" | |
| 28 | 27 | } |
| 29 | 28 | }, |
| 30 | 29 | "node_modules/@hyperswarm/secret-stream": { |
| … | … | @@ -71,8 +70,7 @@ |
| 71 | 70 | "version": "2.0.13", |
| 72 | 71 | "resolved": "https://registry.npmjs.org/bare-abort/-/bare-abort-2.0.13.tgz", |
| 73 | 72 | "integrity": "sha512-zdc8l88eB11Jsz5rDd6sCAgv2kUFXgdrZWoMlgU6JMkfAi1/uuGFC3IEHswKbIRQTk5H3T5CMuechsXYxiaHlQ==", |
| 74 | "license": "Apache-2.0", | |
| 75 | "optional": true | |
| 73 | "license": "Apache-2.0" | |
| 76 | 74 | }, |
| 77 | 75 | "node_modules/bare-addon-resolve": { |
| 78 | 76 | "version": "1.10.0", |
| … | … | @@ -118,23 +116,39 @@ |
| 118 | 116 | "bare-inspect": "^3.1.2" |
| 119 | 117 | } |
| 120 | 118 | }, |
| 119 | "node_modules/bare-buffer": { | |
| 120 | "version": "3.6.2", | |
| 121 | "resolved": "https://registry.npmjs.org/bare-buffer/-/bare-buffer-3.6.2.tgz", | |
| 122 | "integrity": "sha512-WT9xx12FJvWbBCkgfjuAeWfY40RW6BKVr2fK9UGrTEYKbvqhcaW0J9AMkA3Sj36Wgi+DUuGXYkZPxn5jVH61LA==", | |
| 123 | "license": "Apache-2.0", | |
| 124 | "engines": { | |
| 125 | "bare": ">=1.20.0" | |
| 126 | } | |
| 127 | }, | |
| 121 | 128 | "node_modules/bare-dgram": { |
| 122 | 129 | "version": "1.0.1", |
| 123 | 130 | "resolved": "https://registry.npmjs.org/bare-dgram/-/bare-dgram-1.0.1.tgz", |
| 124 | 131 | "integrity": "sha512-EdsyRErrkWgN8fENdrDdXFEE9HAuJ/m6ehXz13fVj9JhdCaLWIA+L8o5aYNRLt66x08RlyG2vbrRAZoxGfcdlg==", |
| 125 | 132 | "license": "Apache-2.0", |
| 126 | "optional": true, | |
| 127 | 133 | "dependencies": { |
| 128 | 134 | "bare-events": "^2.5.0", |
| 129 | 135 | "udx-native": "^1.11.2" |
| 130 | 136 | } |
| 131 | 137 | }, |
| 138 | "node_modules/bare-dns": { | |
| 139 | "version": "2.1.4", | |
| 140 | "resolved": "https://registry.npmjs.org/bare-dns/-/bare-dns-2.1.4.tgz", | |
| 141 | "integrity": "sha512-abwjHmpWqSRNB7V5615QxPH92L71AVzFm/kKTs8VYiNTAi2xVdonpv0BjJ0hwXLwomoW+xsSOPjW6PZPO14asg==", | |
| 142 | "license": "Apache-2.0", | |
| 143 | "engines": { | |
| 144 | "bare": ">=1.7.0" | |
| 145 | } | |
| 146 | }, | |
| 132 | 147 | "node_modules/bare-env": { |
| 133 | 148 | "version": "3.0.1", |
| 134 | 149 | "resolved": "https://registry.npmjs.org/bare-env/-/bare-env-3.0.1.tgz", |
| 135 | 150 | "integrity": "sha512-BdoLvnzaWR0YyyJreEx4zG2Od0AC/s9JSZ+EXyMZKunpn8zEgR/dGv37hdFUaY1bjDkcRKvcKkFyJIwlJ0CaYA==", |
| 136 | 151 | "license": "Apache-2.0", |
| 137 | "optional": true, | |
| 138 | 152 | "dependencies": { |
| 139 | 153 | "bare-os": "^3.0.1" |
| 140 | 154 | } |
| … | … | @@ -181,8 +195,7 @@ |
| 181 | 195 | "version": "2.1.1", |
| 182 | 196 | "resolved": "https://registry.npmjs.org/bare-hrtime/-/bare-hrtime-2.1.1.tgz", |
| 183 | 197 | "integrity": "sha512-VMb3tHo05gsnbu3OXTmkDiwTjMlOsbQmKoysKqKEyR09m77TuDrYFbj3Q5GGk10dAKsUHrnXmwCaeJqzVpB5ZA==", |
| 184 | "license": "Apache-2.0", | |
| 185 | "optional": true | |
| 198 | "license": "Apache-2.0" | |
| 186 | 199 | }, |
| 187 | 200 | "node_modules/bare-inspect": { |
| 188 | 201 | "version": "3.1.4", |
| … | … | @@ -214,12 +227,23 @@ |
| 214 | 227 | } |
| 215 | 228 | } |
| 216 | 229 | }, |
| 230 | "node_modules/bare-net": { | |
| 231 | "version": "2.3.2", | |
| 232 | "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.3.2.tgz", | |
| 233 | "integrity": "sha512-I+yz+pqbYsBkxDsnu5vkKvy7RSNY9CcAvu2jZT6PsmdXJQG1i3dmD5V7xc3334OVp2absgtUEYLmmuNFlphBzg==", | |
| 234 | "license": "Apache-2.0", | |
| 235 | "dependencies": { | |
| 236 | "bare-events": "^2.2.2", | |
| 237 | "bare-pipe": "^4.0.0", | |
| 238 | "bare-stream": "^2.0.0", | |
| 239 | "bare-tcp": "^2.0.0" | |
| 240 | } | |
| 241 | }, | |
| 217 | 242 | "node_modules/bare-os": { |
| 218 | 243 | "version": "3.9.3", |
| 219 | 244 | "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.3.tgz", |
| 220 | 245 | "integrity": "sha512-fF4Q7QsyKVF5Rj0qvI8BgUNjqzC2JvQlpTaPLjVJVxYVUX5Zr9un+y3w1HmA4nNKdFmRBT8z/WmrjvXzXVerKQ==", |
| 221 | 246 | "license": "Apache-2.0", |
| 222 | "optional": true, | |
| 223 | 247 | "engines": { |
| 224 | 248 | "bare": ">=1.14.0" |
| 225 | 249 | } |
| … | … | @@ -235,7 +259,6 @@ |
| 235 | 259 | "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.2.2.tgz", |
| 236 | 260 | "integrity": "sha512-Wkf6//CmKS8inHrkgi3X/xNMeaGfs2I0ayLM0B8cbPB4DxYHcoes6Ng+muCBfXNIJ9qmEjwDDJjAUz7nRxxjgQ==", |
| 237 | 261 | "license": "Apache-2.0", |
| 238 | "optional": true, | |
| 239 | 262 | "dependencies": { |
| 240 | 263 | "bare-events": "^2.0.0", |
| 241 | 264 | "bare-stream": "^2.0.0" |
| … | … | @@ -248,15 +271,13 @@ |
| 248 | 271 | "version": "1.0.1", |
| 249 | 272 | "resolved": "https://registry.npmjs.org/bare-posix/-/bare-posix-1.0.1.tgz", |
| 250 | 273 | "integrity": "sha512-b4quA8dyRVvX0aFIAIiev5zFATHwIUGr42Gmt+CqiBNg/bdsNkrj4bbkeotMOMiljJS4DCME5kywJO/TFwKo1A==", |
| 251 | "license": "Apache-2.0", | |
| 252 | "optional": true | |
| 274 | "license": "Apache-2.0" | |
| 253 | 275 | }, |
| 254 | 276 | "node_modules/bare-process": { |
| 255 | 277 | "version": "4.5.1", |
| 256 | 278 | "resolved": "https://registry.npmjs.org/bare-process/-/bare-process-4.5.1.tgz", |
| 257 | 279 | "integrity": "sha512-CaAvy1trputD49mtwfJ6G75vydhnirLrW/F3Sznp4H556e1uZn8YMo9ELicBTrGYy7RBNUgPl9bpB/ERzRCiDw==", |
| 258 | 280 | "license": "Apache-2.0", |
| 259 | "optional": true, | |
| 260 | 281 | "dependencies": { |
| 261 | 282 | "bare-abort": "^2.0.13", |
| 262 | 283 | "bare-env": "^3.0.0", |
| … | … | @@ -279,7 +300,6 @@ |
| 279 | 300 | "resolved": "https://registry.npmjs.org/bare-signals/-/bare-signals-5.0.0.tgz", |
| 280 | 301 | "integrity": "sha512-8Gn8bBFUh2AUCJ9wWWFjSGWIo1HIUSIQnXRJGSm/f7GCDMqsuJhRmR1dT+HtDaDBkeu2l8Koxt2JLurfJ5yHVw==", |
| 281 | 302 | "license": "Apache-2.0", |
| 282 | "optional": true, | |
| 283 | 303 | "dependencies": { |
| 284 | 304 | "bare-events": "^2.5.3" |
| 285 | 305 | }, |
| … | … | @@ -292,7 +312,6 @@ |
| 292 | 312 | "resolved": "https://registry.npmjs.org/bare-stdio/-/bare-stdio-1.0.3.tgz", |
| 293 | 313 | "integrity": "sha512-8BRMx7RWMWCbBmKhyHgBco62J+Pgss7+EPI21L3R9+w0UpwDYWUUcbE0YTOesGyt7M6N7VtoshYbzwrP0pI52Q==", |
| 294 | 314 | "license": "Apache-2.0", |
| 295 | "optional": true, | |
| 296 | 315 | "dependencies": { |
| 297 | 316 | "bare-fs": "^4.5.2", |
| 298 | 317 | "bare-pipe": "^4.1.5", |
| … | … | @@ -326,17 +345,42 @@ |
| 326 | 345 | } |
| 327 | 346 | } |
| 328 | 347 | }, |
| 348 | "node_modules/bare-structured-clone": { | |
| 349 | "version": "1.6.0", | |
| 350 | "resolved": "https://registry.npmjs.org/bare-structured-clone/-/bare-structured-clone-1.6.0.tgz", | |
| 351 | "integrity": "sha512-AZjEERyqF7kAuudlmgrweT2KwwWM0LsGG4Gx/bWyFwJrKU7E3wNG8c09z2DIrdw93p3vDtfOX8fyHOcXfy5m+g==", | |
| 352 | "license": "Apache-2.0", | |
| 353 | "dependencies": { | |
| 354 | "bare-buffer": "^3.6.0", | |
| 355 | "bare-type": "^1.1.0", | |
| 356 | "bare-url": "^2.4.0", | |
| 357 | "compact-encoding": "^3.0.1" | |
| 358 | }, | |
| 359 | "engines": { | |
| 360 | "bare": ">=1.2.0" | |
| 361 | } | |
| 362 | }, | |
| 363 | "node_modules/bare-structured-clone/node_modules/compact-encoding": { | |
| 364 | "version": "3.3.0", | |
| 365 | "resolved": "https://registry.npmjs.org/compact-encoding/-/compact-encoding-3.3.0.tgz", | |
| 366 | "integrity": "sha512-e64XyzlBvTRJ3iScuU/U2w25Dglkm7fhrRbrGaHIwuTlNnzjRKMaQBCVl7mJRvZg7wI5a9wX1IVTXCuaAANNkw==", | |
| 367 | "license": "Apache-2.0", | |
| 368 | "dependencies": { | |
| 369 | "b4a": "^1.3.0" | |
| 370 | } | |
| 371 | }, | |
| 329 | 372 | "node_modules/bare-subprocess": { |
| 330 | "version": "5.2.3", | |
| 331 | "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-5.2.3.tgz", | |
| 332 | "integrity": "sha512-07wwswlV7M3sC9IykbZRZ/jHAkrXFWVLqdBWGv1y0ojCimtRD9hGwxdHmR5FUFmDUZLNsBmTYJNQqgio5+A85Q==", | |
| 373 | "version": "6.1.0", | |
| 374 | "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-6.1.0.tgz", | |
| 375 | "integrity": "sha512-8L6KtbmreDy4Fc1BdDqaDo9fg0nbedUmTSFQxYPV0uHIM2BBAX8+E0LyMDKgkk0I+mlKto80WYzOnIhT8VDdOg==", | |
| 333 | 376 | "license": "Apache-2.0", |
| 334 | "optional": true, | |
| 335 | 377 | "dependencies": { |
| 336 | 378 | "bare-env": "^3.0.0", |
| 337 | 379 | "bare-events": "^2.5.4", |
| 338 | 380 | "bare-os": "^3.0.1", |
| 339 | "bare-pipe": "^4.0.0", | |
| 381 | "bare-pipe": "^4.2.0", | |
| 382 | "bare-structured-clone": "^1.5.2", | |
| 383 | "bare-tcp": "^2.4.1", | |
| 340 | 384 | "bare-url": "^2.2.2" |
| 341 | 385 | }, |
| 342 | 386 | "engines": { |
| … | … | @@ -351,12 +395,33 @@ |
| 351 | 395 | } |
| 352 | 396 | } |
| 353 | 397 | }, |
| 398 | "node_modules/bare-tcp": { | |
| 399 | "version": "2.5.2", | |
| 400 | "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.5.2.tgz", | |
| 401 | "integrity": "sha512-9SAF0r+p5w3QxsI9BGBqj/0VlNwJGkEj/1AAJi+4Pl0W7ke2JiYmt7GhJss/uaEnY0s4/N/A/Os6Dr+dVfVzyQ==", | |
| 402 | "license": "Apache-2.0", | |
| 403 | "dependencies": { | |
| 404 | "bare-dns": "^2.0.4", | |
| 405 | "bare-events": "^2.5.4", | |
| 406 | "bare-stream": "^2.6.4" | |
| 407 | }, | |
| 408 | "engines": { | |
| 409 | "bare": ">=1.16.0" | |
| 410 | }, | |
| 411 | "peerDependencies": { | |
| 412 | "bare-pipe": "*" | |
| 413 | }, | |
| 414 | "peerDependenciesMeta": { | |
| 415 | "bare-pipe": { | |
| 416 | "optional": true | |
| 417 | } | |
| 418 | } | |
| 419 | }, | |
| 354 | 420 | "node_modules/bare-tty": { |
| 355 | 421 | "version": "5.1.2", |
| 356 | 422 | "resolved": "https://registry.npmjs.org/bare-tty/-/bare-tty-5.1.2.tgz", |
| 357 | 423 | "integrity": "sha512-wDHPU/yVQtrDCUrKVdIVOLmfIw7dFPETz30UayuFlROvgz8Juv2SmISSMhqxYQVO+fVnG/1ZoLcbGh/35eAjDA==", |
| 358 | 424 | "license": "Apache-2.0", |
| 359 | "optional": true, | |
| 360 | 425 | "dependencies": { |
| 361 | 426 | "bare-events": "^2.2.0", |
| 362 | 427 | "bare-signals": "^5.0.0", |
| … | … | @@ -380,7 +445,6 @@ |
| 380 | 445 | "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz", |
| 381 | 446 | "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==", |
| 382 | 447 | "license": "Apache-2.0", |
| 383 | "peer": true, | |
| 384 | 448 | "dependencies": { |
| 385 | 449 | "bare-path": "^3.0.0" |
| 386 | 450 | } |
| … | … | @@ -4,6 +4,14 @@ |
| 4 | 4 | "description": "Resilient, roaming terminal sessions to identity-keyed P2P nodes — mosh tunneled over a hole-punched hyperdht connection. Built for celltron-class nodes (NAT'd, Doze-prone phones) where a plain stream shell dies on every network flap.", |
| 5 | 5 | "type": "module", |
| 6 | 6 | "bin": { "hypermosh": "./bin/hypermosh.mjs" }, |
| 7 | "pgh": { | |
| 8 | "bin": "hypermosh", | |
| 9 | "entrypoint": "bin/hypermosh.mjs", | |
| 10 | "runtime": "bare", | |
| 11 | "type": "terminal", | |
| 12 | "upgrade": "pgh://fleeky/hypermosh-shell", | |
| 13 | "requires": { "bare": ">=1.6" } | |
| 14 | }, | |
| 7 | 15 | "exports": { ".": "./lib/relay.mjs", "./identity": "./lib/identity.mjs" }, |
| 8 | 16 | "imports": { |
| 9 | 17 | "#node:dgram": { "bare": "bare-dgram", "default": "dgram" }, |
| … | … | @@ -20,19 +28,17 @@ |
| 20 | 28 | }, |
| 21 | 29 | "dependencies": { |
| 22 | 30 | "b4a": "^1.6.0", |
| 23 | "compact-encoding": "^2.11.0", | |
| 24 | "hypercore-id-encoding": "^1.2.0", | |
| 25 | "hyperdht": "^6.6.0", | |
| 26 | "protomux": "^3.4.0" | |
| 27 | }, | |
| 28 | "optionalDependencies": { | |
| 29 | 31 | "bare-dgram": "^1.0.0", |
| 30 | "bare-net": "^4.0.0", | |
| 31 | 32 | "bare-fs": "^4.0.0", |
| 33 | "bare-net": "^2.3.2", | |
| 32 | 34 | "bare-os": "^3.0.0", |
| 33 | 35 | "bare-path": "^3.0.0", |
| 34 | 36 | "bare-process": "^4.0.0", |
| 35 | "bare-subprocess": "^5.0.0" | |
| 37 | "bare-subprocess": "^6.1.0", | |
| 38 | "compact-encoding": "^2.11.0", | |
| 39 | "hypercore-id-encoding": "^1.2.0", | |
| 40 | "hyperdht": "^6.6.0", | |
| 41 | "protomux": "^3.4.0" | |
| 36 | 42 | }, |
| 37 | 43 | "license": "Apache-2.0", |
| 38 | 44 | "author": "hyper-fleeky" |