OverviewFilesCommitsIssuesDocsReleasesPeers

hypermosh-shell commits / e505875

Package as a bare pgh app + rewrite README for the two auth models
- Add package.json `pgh` section: bin=hypermosh, entrypoint=bin/hypermosh.mjs, runtime=bare, type=terminal, upgrade=pgh://fleeky/hypermosh-shell. Verified the entry (id + SSH-mode serve) boots under `bare`, not just node. - Promote bare-* to real dependencies with correct versions (bare-net 2.3.2, bare-subprocess 6.1.0, …) so `npm install` bundles the shims/prebuilds for the bare runtime. - README: document SSH-style login (default) vs --hyperident (pubkey firewall), the empty-allow-list deny-all warning (the root cause), mosh-not-bundled, and the -v/HYPERMOSH_DEBUG logging. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e505875469a80377569043c3046c8111f92c2bef
by plankatron <fleeky@gmail.com> · 2026-07-19T21:36:38.000Z

Changed files (3) +189 -96

README.md +83 -60
……@@ -1,112 +1,135 @@
11# hypermosh-shell
22
33**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
55[hyperdht](https://github.com/holepunchto/hyperdht) connection, in one command.
66
77`mosh user@host`, but the "host" is a public key and the transport is P2P. For
88nodes with **no reachable UDP port** (behind NAT/CGNAT, or mobile/roaming), where
99a plain reliable-stream shell **dies on every network change** — mosh was designed
1010for exactly that (intermittent links, latency, IP roaming); hypermosh gives it a
11P2P datagram path.
11P2P datagram path, and reconnects the tunnel under it as the network flaps.
1212
1313## One command
1414
1515```sh
16hypermosh <server-pubkey> # interactive mosh session over the DHT
17hypermosh <server-pubkey> -- htop # run a specific command
16hypermosh <user>@<server-pubkey> # interactive login shell over the DHT
17hypermosh <user>@<server-pubkey> -- htop # run a specific command
18hypermosh <server-pubkey> # same, using your local username
1819```
1920
20## How it works
21Add `-v` (or `HYPERMOSH_DEBUG=1`) for connection logging.
2122
22```
23client 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
27The 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
29like `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 —
31just like a public SSH host).
32
33```sh
34# server (needs sshd + mosh installed)
35hypermosh serve
36
37# client
38hypermosh you@<server-pubkey>
2939```
3040
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.
41This is faithful to how mosh actually works: mosh does no auth of its own — its
42wrapper runs `ssh user@host -- mosh-server new …` and lets OpenSSH authenticate.
43hypermosh 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
45logged-in user and **daemonizes independently of the tunnel** — so when the
46network flaps, hypermosh redials and re-bridges the UDP to the *same* running
47`mosh-server`. That is mosh's roaming, preserved.
4048
41Wire 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
51Auth is a hyperdht public-key allow-list instead of sshd. The daemon spawns its
52own `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
56hypermosh serve --hyperident --firewall ~/.hypermosh/allowed # allow-list file
57hypermosh serve --hyperident --disable-firewall # accept any peer
58hypermosh 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.)
4365
4466## Install
4567
4668```sh
47npm install # hyperdht, b4a, hypercore-id-encoding, protomux, compact-encoding
48# requires `mosh` (mosh-server + mosh-client) installed on both ends
69npm install # hyperdht, b4a, hypercore-id-encoding, protomux, bare-* shims
4970```
5071
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
53manager can't configure packages, extract the binaries straight from `.deb`s:
72**mosh is not bundled** — bare runs JavaScript, and `mosh-server`/`mosh-client`
73are 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
75package manager can't configure packages, extract the binaries from `.deb`s:
5476
5577```sh
5678apt-get download mosh libprotobuf23 libssl3 libutempter0
5779for d in *.deb; do dpkg-deb -x "$d" /; done && ldconfig
5880```
5981
82If mosh is missing hypermosh now says so plainly ("is mosh installed locally?" /
83"mosh-server not runnable") instead of hanging.
84
6085Dual-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`, …).
6288
6389## CLI
6490
6591```
6692hypermosh id # this daemon's server pubkey
67hypermosh serve [--firewall <file> | --disable-firewall]
68hypermosh <name-or-pubkey> [-- cmd...]
93hypermosh serve [--hyperident [--firewall <file> | --disable-firewall]]
94hypermosh [user@]<name-or-pubkey> [-- cmd...]
6995hypermosh add-name <name> <pubkey> # optional: remember a name
7096hypermosh names # list known names
7197```
7298
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.
7899- **Names are optional.** A raw public key always works; `add-name` records a
79100 `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```
106client 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
116Wire format: typed frames over the reliable stream —
117`[uint8 type][uint32 len][payload]` (0 control/JSON, 1 mosh datagram, 2 ssh bytes,
1183 ssh-end). The server's UDP bridge is clamped to `127.0.0.1` and mosh's port
119range so an authenticated tunnel can't be abused as an arbitrary loopback proxy.
100120
101121## Tests
102122
103123```sh
104npm 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)
124npm test # frames (unit) · firewall (root-cause regression) · ssh-mode e2e
125npm run test:p2p # relay + one-command loopback (flaky on ONE machine — self-hairpin
126 # DHT; the real proof is a cross-machine run)
108127```
109128
129The `ssh-mode` test stands up an isolated throwaway sshd and runs a full
130SSH-login → mosh session end-to-end over hyperdht (skips if sshd/mosh/python3
131are absent).
132
110133## License
111134
112135Apache-2.0
package-lock.json +92 -28
……@@ -10,6 +10,13 @@
1010 "license": "Apache-2.0",
1111 "dependencies": {
1212 "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",
1320 "compact-encoding": "^2.11.0",
1421 "hypercore-id-encoding": "^1.2.0",
1522 "hyperdht": "^6.6.0",
……@@ -17,14 +24,6 @@
1724 },
1825 "bin": {
1926 "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"
2827 }
2928 },
3029 "node_modules/@hyperswarm/secret-stream": {
……@@ -71,8 +70,7 @@
7170 "version": "2.0.13",
7271 "resolved": "https://registry.npmjs.org/bare-abort/-/bare-abort-2.0.13.tgz",
7372 "integrity": "sha512-zdc8l88eB11Jsz5rDd6sCAgv2kUFXgdrZWoMlgU6JMkfAi1/uuGFC3IEHswKbIRQTk5H3T5CMuechsXYxiaHlQ==",
74 "license": "Apache-2.0",
75 "optional": true
73 "license": "Apache-2.0"
7674 },
7775 "node_modules/bare-addon-resolve": {
7876 "version": "1.10.0",
……@@ -118,23 +116,39 @@
118116 "bare-inspect": "^3.1.2"
119117 }
120118 },
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 },
121128 "node_modules/bare-dgram": {
122129 "version": "1.0.1",
123130 "resolved": "https://registry.npmjs.org/bare-dgram/-/bare-dgram-1.0.1.tgz",
124131 "integrity": "sha512-EdsyRErrkWgN8fENdrDdXFEE9HAuJ/m6ehXz13fVj9JhdCaLWIA+L8o5aYNRLt66x08RlyG2vbrRAZoxGfcdlg==",
125132 "license": "Apache-2.0",
126 "optional": true,
127133 "dependencies": {
128134 "bare-events": "^2.5.0",
129135 "udx-native": "^1.11.2"
130136 }
131137 },
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 },
132147 "node_modules/bare-env": {
133148 "version": "3.0.1",
134149 "resolved": "https://registry.npmjs.org/bare-env/-/bare-env-3.0.1.tgz",
135150 "integrity": "sha512-BdoLvnzaWR0YyyJreEx4zG2Od0AC/s9JSZ+EXyMZKunpn8zEgR/dGv37hdFUaY1bjDkcRKvcKkFyJIwlJ0CaYA==",
136151 "license": "Apache-2.0",
137 "optional": true,
138152 "dependencies": {
139153 "bare-os": "^3.0.1"
140154 }
……@@ -181,8 +195,7 @@
181195 "version": "2.1.1",
182196 "resolved": "https://registry.npmjs.org/bare-hrtime/-/bare-hrtime-2.1.1.tgz",
183197 "integrity": "sha512-VMb3tHo05gsnbu3OXTmkDiwTjMlOsbQmKoysKqKEyR09m77TuDrYFbj3Q5GGk10dAKsUHrnXmwCaeJqzVpB5ZA==",
184 "license": "Apache-2.0",
185 "optional": true
198 "license": "Apache-2.0"
186199 },
187200 "node_modules/bare-inspect": {
188201 "version": "3.1.4",
……@@ -214,12 +227,23 @@
214227 }
215228 }
216229 },
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 },
217242 "node_modules/bare-os": {
218243 "version": "3.9.3",
219244 "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.3.tgz",
220245 "integrity": "sha512-fF4Q7QsyKVF5Rj0qvI8BgUNjqzC2JvQlpTaPLjVJVxYVUX5Zr9un+y3w1HmA4nNKdFmRBT8z/WmrjvXzXVerKQ==",
221246 "license": "Apache-2.0",
222 "optional": true,
223247 "engines": {
224248 "bare": ">=1.14.0"
225249 }
……@@ -235,7 +259,6 @@
235259 "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.2.2.tgz",
236260 "integrity": "sha512-Wkf6//CmKS8inHrkgi3X/xNMeaGfs2I0ayLM0B8cbPB4DxYHcoes6Ng+muCBfXNIJ9qmEjwDDJjAUz7nRxxjgQ==",
237261 "license": "Apache-2.0",
238 "optional": true,
239262 "dependencies": {
240263 "bare-events": "^2.0.0",
241264 "bare-stream": "^2.0.0"
……@@ -248,15 +271,13 @@
248271 "version": "1.0.1",
249272 "resolved": "https://registry.npmjs.org/bare-posix/-/bare-posix-1.0.1.tgz",
250273 "integrity": "sha512-b4quA8dyRVvX0aFIAIiev5zFATHwIUGr42Gmt+CqiBNg/bdsNkrj4bbkeotMOMiljJS4DCME5kywJO/TFwKo1A==",
251 "license": "Apache-2.0",
252 "optional": true
274 "license": "Apache-2.0"
253275 },
254276 "node_modules/bare-process": {
255277 "version": "4.5.1",
256278 "resolved": "https://registry.npmjs.org/bare-process/-/bare-process-4.5.1.tgz",
257279 "integrity": "sha512-CaAvy1trputD49mtwfJ6G75vydhnirLrW/F3Sznp4H556e1uZn8YMo9ELicBTrGYy7RBNUgPl9bpB/ERzRCiDw==",
258280 "license": "Apache-2.0",
259 "optional": true,
260281 "dependencies": {
261282 "bare-abort": "^2.0.13",
262283 "bare-env": "^3.0.0",
……@@ -279,7 +300,6 @@
279300 "resolved": "https://registry.npmjs.org/bare-signals/-/bare-signals-5.0.0.tgz",
280301 "integrity": "sha512-8Gn8bBFUh2AUCJ9wWWFjSGWIo1HIUSIQnXRJGSm/f7GCDMqsuJhRmR1dT+HtDaDBkeu2l8Koxt2JLurfJ5yHVw==",
281302 "license": "Apache-2.0",
282 "optional": true,
283303 "dependencies": {
284304 "bare-events": "^2.5.3"
285305 },
……@@ -292,7 +312,6 @@
292312 "resolved": "https://registry.npmjs.org/bare-stdio/-/bare-stdio-1.0.3.tgz",
293313 "integrity": "sha512-8BRMx7RWMWCbBmKhyHgBco62J+Pgss7+EPI21L3R9+w0UpwDYWUUcbE0YTOesGyt7M6N7VtoshYbzwrP0pI52Q==",
294314 "license": "Apache-2.0",
295 "optional": true,
296315 "dependencies": {
297316 "bare-fs": "^4.5.2",
298317 "bare-pipe": "^4.1.5",
……@@ -326,17 +345,42 @@
326345 }
327346 }
328347 },
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 },
329372 "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==",
333376 "license": "Apache-2.0",
334 "optional": true,
335377 "dependencies": {
336378 "bare-env": "^3.0.0",
337379 "bare-events": "^2.5.4",
338380 "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",
340384 "bare-url": "^2.2.2"
341385 },
342386 "engines": {
……@@ -351,12 +395,33 @@
351395 }
352396 }
353397 },
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 },
354420 "node_modules/bare-tty": {
355421 "version": "5.1.2",
356422 "resolved": "https://registry.npmjs.org/bare-tty/-/bare-tty-5.1.2.tgz",
357423 "integrity": "sha512-wDHPU/yVQtrDCUrKVdIVOLmfIw7dFPETz30UayuFlROvgz8Juv2SmISSMhqxYQVO+fVnG/1ZoLcbGh/35eAjDA==",
358424 "license": "Apache-2.0",
359 "optional": true,
360425 "dependencies": {
361426 "bare-events": "^2.2.0",
362427 "bare-signals": "^5.0.0",
……@@ -380,7 +445,6 @@
380445 "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz",
381446 "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==",
382447 "license": "Apache-2.0",
383 "peer": true,
384448 "dependencies": {
385449 "bare-path": "^3.0.0"
386450 }
package.json +14 -8
……@@ -4,6 +4,14 @@
44 "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.",
55 "type": "module",
66 "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 },
715 "exports": { ".": "./lib/relay.mjs", "./identity": "./lib/identity.mjs" },
816 "imports": {
917 "#node:dgram": { "bare": "bare-dgram", "default": "dgram" },
……@@ -20,19 +28,17 @@
2028 },
2129 "dependencies": {
2230 "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": {
2931 "bare-dgram": "^1.0.0",
30 "bare-net": "^4.0.0",
3132 "bare-fs": "^4.0.0",
33 "bare-net": "^2.3.2",
3234 "bare-os": "^3.0.0",
3335 "bare-path": "^3.0.0",
3436 "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"
3642 },
3743 "license": "Apache-2.0",
3844 "author": "hyper-fleeky"