@toon-protocol/hub 0.34.3

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 ADDED
@@ -0,0 +1,226 @@
1
+ # @toon-protocol/hub
2
+
3
+ **The operator CLI for running a TOON Protocol node stack on your own machine.**
4
+
5
+ TOON Protocol is a **pay-to-write, free-to-read** [Nostr](https://nostr.com) network over [Interledger](https://interledger.org): writers attach a tiny signed payment to publish an event, and anyone reads for free. `townhouse` is the command-line tool an **operator** uses to stand up and run that infrastructure — it generates your keys and boots the stack in Docker so paying clients can reach you over BTP.
6
+
7
+ ```bash
8
+ npx @toon-protocol/hub init # 1. create your config + wallet (one time)
9
+ npx @toon-protocol/hub up # 2. boot your apex (direct BTP, default) + children
10
+ npx @toon-protocol/hub node add # 3. add a service node that earns fees (default: a town relay)
11
+ ```
12
+
13
+ `up` boots a **direct-BTP apex** by default and prints `Apex live (direct BTP) at ws://127.0.0.1:3000/btp` once reachable. Clients dial that BTP endpoint directly. Want anonymity instead? `npx @toon-protocol/hub hs up` is the privacy opt-in: it boots the same apex behind an `.anon` hidden service (no public host port) and prints `Apex live at <your-address>.anon`. Either way, share the address with clients; they pay you over it.
14
+
15
+ > **Are you trying to _publish_ events, not run a node?** You want [`@toon-protocol/client`](https://www.npmjs.com/package/@toon-protocol/client) instead — the client library that pays a townhouse apex and publishes to it. `townhouse` (this package) is the **operator** side; `@toon-protocol/client` is the **client** side.
16
+
17
+ ---
18
+
19
+ ## What is a townhouse? (vocabulary)
20
+
21
+ This package uses a few terms precisely. Getting them straight up front prevents a lot of confusion:
22
+
23
+ | Term | What it is |
24
+ | --- | --- |
25
+ | **TOON Protocol** | The pay-to-write Nostr-over-ILP network. Writes cost a signed off-chain payment claim; reads are free. |
26
+ | **townhouse** | This CLI — the **operator product**. It runs one **apex** plus the service nodes you attach to it. |
27
+ | **apex** | What `up` boots: the **ILP connector** (node id `g.townhouse`, the *parent*) + your service nodes. By default it exposes its BTP port (`ws://host:3000/btp`) directly to clients (**direct transport**); `hs up` instead fronts it with an **`.anon` hidden service** (**HS transport**, the privacy opt-in). The apex is the front door — it validates incoming client payments, takes its fee, and forwards traffic to your service nodes. It earns routing fees but is **not** itself a relay/swap/compute node. |
28
+ | **service node** (a **child** of the apex) | What `node add` provisions. Three types **earn fees**: **town** = a Nostr relay (pay-per-event publish); **mill** = a multi-chain token-swap node; **dvm** = a [NIP-90](https://github.com/nostr-protocol/nips/blob/master/90.md) compute node (e.g. Arweave blob storage — the job request *is* the payment). Clients pay at the apex edge; the apex then forwards to the child **for free** (parent→child packets carry no per-packet claim, settled in aggregate). |
29
+ | **operator** (you) | Runs `townhouse`, owns the wallet, earns the fees. |
30
+ | **client** | An end-user or app using [`@toon-protocol/client`](https://www.npmjs.com/package/@toon-protocol/client) to pay your apex and publish. Not this package. |
31
+
32
+ **`town` is one service node; `townhouse` is the whole operator product** (the apex plus every node you attach). Adding a town relay is just `townhouse node add town`.
33
+
34
+ ---
35
+
36
+ ## Before you start
37
+
38
+ You'll need:
39
+
40
+ - [ ] **Docker** running — verify with `docker version` (it pulls and runs the apex and node containers)
41
+ - [ ] **Node.js 20+** — verify with `node --version`
42
+ - [ ] **Network access to `ghcr.io`** — container images are pulled from there
43
+ - [ ] **A few free ports on `127.0.0.1`** — `9401`, `28090`, `7100`, `3100`, `3200`, `3400` (all loopback-only)
44
+ - [ ] A little disk space for container images
45
+
46
+ > Supported on Linux and macOS (including WSL2). Everything binds to `127.0.0.1` only — nothing is exposed to the public internet except your apex's `.anon` hidden-service address.
47
+
48
+ ---
49
+
50
+ ## Quickstart
51
+
52
+ ### 1. Initialize — `init`
53
+
54
+ ```bash
55
+ npx @toon-protocol/hub init
56
+ ```
57
+
58
+ This creates `~/.townhouse/config.yaml` and an encrypted wallet, then **shows your seed phrase once**:
59
+
60
+ ```text
61
+ Config created at ~/.townhouse/config.yaml
62
+
63
+ === IMPORTANT: Back up your seed phrase ===
64
+
65
+ snake juice eternal vendor remove ladder aisle crumble match hockey weasel guide
66
+
67
+ This is the ONLY time your seed phrase will be shown.
68
+ Store it safely. You will need it to recover your node keys.
69
+ ============================================
70
+
71
+ Wallet saved to ~/.townhouse/wallet.enc
72
+
73
+ Derived Node Addresses:
74
+ -----------------------
75
+ town Nostr: 5eb3ba2d... EVM: 0x90bd2F2f...
76
+ mill Nostr: 47838cd5... EVM: 0xAAE12f6B...
77
+ dvm Nostr: 1b52a745... EVM: 0x18Ac7427...
78
+
79
+ Next — start your node:
80
+ npx @toon-protocol/hub up
81
+ ```
82
+
83
+ **Write the seed phrase down.** It is shown only once and is the only way to recover your keys.
84
+
85
+ `init` needs a password to encrypt the wallet. Provide it with the `--password` flag or the `TOWNHOUSE_WALLET_PASSWORD` env var:
86
+
87
+ ```bash
88
+ npx @toon-protocol/hub init --password "<your-password>"
89
+ # or: export TOWNHOUSE_WALLET_PASSWORD=... then run init
90
+ ```
91
+
92
+ ### 2. Boot your apex — `up` (direct BTP, default)
93
+
94
+ ```bash
95
+ npx @toon-protocol/hub up
96
+ ```
97
+
98
+ This starts the **apex** (the ILP connector + the townhouse API) — the front door that clients pay — with the connector's BTP port exposed directly to the host. The first run pulls images and narrates each stage:
99
+
100
+ ```text
101
+ Pulling 2 apex images...
102
+ [1/2] ghcr.io/toon-protocol/connector@sha256:...
103
+ [2/2] ghcr.io/toon-protocol/townhouse-api@sha256:...
104
+ Apex live (direct BTP) at ws://127.0.0.1:3000/btp
105
+ ```
106
+
107
+ The final line is **your apex's BTP dial address** — share it with clients, who pay you over BTP at `ws://<host>:3000/btp`. By default the port binds to `127.0.0.1` only; to accept clients from other machines, **bind it explicitly** with `TOWNHOUSE_BTP_BIND=0.0.0.0 townhouse up` (only do this if you mean to expose the port publicly). On a cold image cache the first boot can take a few minutes; later boots are faster.
108
+
109
+ #### Privacy opt-in: `hs up` (hidden-service apex)
110
+
111
+ Prefer to stay off the public internet entirely? `hs up` boots the same apex behind an **`.anon` v3 hidden service** (no host port exposed) and bootstraps the hidden service, narrating each stage:
112
+
113
+ ```bash
114
+ npx @toon-protocol/hub hs up
115
+ ```
116
+
117
+ ```text
118
+ Bootstrapping hidden service (this takes 30–90s)…
119
+ Apex live at uagxuabpuvm6mf4l4zptgth2442sbct5lvtur2nffpqnouesgawyv2ad.anon
120
+ ```
121
+
122
+ Clients pay you over BTP at `wss://<your-address>.anon/btp` (through a SOCKS5h proxy); the address is saved to `~/.townhouse/host.json`. Direct and HS apexes are **mutually exclusive** (they contend for the same canonical ports / data) — running `up` on a machine that already has an HS apex is refused; tear the HS apex down (`hs down --rotate-keys`) first, or use `hs enable` to switch a running direct apex to HS. If you run `up`/`hs up` in an interactive terminal, a live dashboard opens once the apex is up. Press `Ctrl-C` to exit the dashboard — your apex keeps running.
123
+
124
+ ### 3. Add a service node — `node add`
125
+
126
+ The apex on its own only routes and takes a fee. To actually **earn**, attach a service node (a *child* of the apex). The default is a `town` Nostr relay:
127
+
128
+ ```bash
129
+ npx @toon-protocol/hub node add # provision a town relay (default)
130
+ npx @toon-protocol/hub node add mill --relays wss://relay.damus.io,wss://nos.lol # multi-chain swap node
131
+ npx @toon-protocol/hub node add dvm --turbo-token "$(cat arweave.json)" # NIP-90 compute / Arweave node
132
+ ```
133
+
134
+ `node add` provisions the container, registers it as a child of your apex, and routes paid client traffic to it for free. List and remove nodes with `node list` and `node remove <id>`.
135
+
136
+ **Per-node configuration.** Operator-supplied inputs are resolved in the order **flag → `config.yaml` → environment variable**:
137
+
138
+ | Node | Input | How to supply it |
139
+ | ------ | ---------------------- | ------------------------------------------------------------------------------------------------- |
140
+ | `town` | Settlement chain + token (optional) | `--settlement-chain evm:84532 --asset ETH` · or `nodes.town.settlementChainId`/`assetCode` in `config.yaml` |
141
+ | `mill` | Nostr relay URLs (**required**) | `--relays wss://a,wss://b` · or `nodes.mill.relays` in `config.yaml` · or `MILL_RELAYS` env |
142
+ | `dvm` | Arweave Turbo credential (optional) | `--turbo-token '<jwk>'` · or `TURBO_TOKEN` env (free-tier <100KB uploads work without it) |
143
+
144
+ **Town settlement token/chain.** The town advertises a settlement asset in its kind:10032 so clients know what it prices in. Choose from the chains your deployment supports — run `townhouse chains supported` to list them — and a token that chain supports (EVM: `USDC`/`ETH` · Solana: `USDC`/`SOL` · Mina: `MINA` only). `assetScale` is derived (USDC 6, ETH 18, SOL 9, MINA 9). Unsupported selections are rejected with the list of valid options. Defaults to USDC on the deployment's first supported chain (the native token where USDC isn't available, e.g. Mina).
145
+
146
+ Prefer the flags — they travel with the `node add` request, so you don't have to export `MILL_RELAYS`/`TURBO_TOKEN` **before** `up`/`hs up` (the API container's environment is fixed at boot, so a variable exported afterward is never seen). Mill relays you pass are persisted to `config.yaml`, so a later `node remove && node add` doesn't need the flag again. The DVM Turbo credential is a secret and is **not** written to `config.yaml` — pass it via `--turbo-token` (or `TURBO_TOKEN`) each time.
147
+
148
+ **Restart = auto-rebind.** Your provisioned nodes are recorded in `~/.townhouse/nodes.yaml`. On every `townhouse hs up`, townhouse rebuilds each child's env from the wallet + `config.yaml` and restarts its container, then re-registers it with the apex — so after `hs down && hs up` (or a host reboot followed by `hs up`) your town/mill/dvm come back automatically, no `node add` needed. Editing a value in `config.yaml` (e.g. `nodes.mill.relays`) and re-running `hs up` recreates that child with the new config. The DVM Turbo token isn't persisted, so re-export `TURBO_TOKEN` before `hs up` if you rely on it for large uploads.
149
+
150
+ ### 4. Stop your apex — `hs down`
151
+
152
+ ```bash
153
+ npx @toon-protocol/hub hs down
154
+ ```
155
+
156
+ ```text
157
+ Apex stopped. Volumes preserved — your .anyone address is stable.
158
+ ```
159
+
160
+ Your hidden-service address stays the same across stop/start. To deliberately rotate to a brand-new address, use `npx @toon-protocol/hub hs down --rotate-keys` (this **deletes** the current keypair, so the next `hs up` publishes a different address).
161
+
162
+ ---
163
+
164
+ ## Everyday commands
165
+
166
+ | Command | What it does |
167
+ | -------------------------------------------------- | ------------------------------------------------------------ |
168
+ | `townhouse init` | Create config + wallet (one time) |
169
+ | `townhouse up` | Boot a **direct-BTP** apex + children (default; clients dial `ws://host:3000/btp`). `--dev` = contributor children-only dev stack |
170
+ | `townhouse hs up` | Boot a **hidden-service** apex (opt-in; anonymous `.anon`) |
171
+ | `townhouse hs enable` | Switch a running direct apex to hidden-service mode |
172
+ | `townhouse hs down` | Stop the apex (address preserved) |
173
+ | `townhouse node add [town\|mill\|dvm]` | Provision a service node (child of the apex; default `town`) |
174
+ | `townhouse node list` / `node remove <id>` | List / deprovision service nodes |
175
+ | `townhouse status` | Show apex + node status and connector metrics |
176
+ | `townhouse health` | Probe apex / API / nodes / `.anon` health |
177
+ | `townhouse logs <node-id> [-f]` | Tail a node's logs (`-f` accepted; follow is the default) |
178
+ | `townhouse wallet show` | Show derived addresses for each node |
179
+ | `townhouse wallet seed --confirm` | Reprint your BIP-39 seed phrase (password-gated) |
180
+ | `townhouse credits buy` / `credits balance` | Fund / check Arweave upload credits (for the DVM node) |
181
+ | `townhouse --help` | Full command list |
182
+
183
+ (Prefix each with `npx @toon-protocol/hub`, or install once and call `townhouse` directly.)
184
+
185
+ > Running with a config outside the default `~/.townhouse`? Pass `-c <path-to-config.yaml>` (the path to the **config file**, not its directory) on any command. When you initialize with `init --config-dir <dir>`, `init`'s printed next-step already includes the matching `-c` flag.
186
+
187
+ ---
188
+
189
+ ## Troubleshooting
190
+
191
+ | Symptom | Fix |
192
+ | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
193
+ | `cannot start — host ports already in use` | Another stack is using the canonical ports. Stop it (the message tells you how), or run `hs up --skip-preflight` if you know the conflict is harmless. |
194
+ | Boot fails pulling images | Check your network and that you can reach `ghcr.io`, then retry. |
195
+ | `Docker daemon unreachable` | Start Docker and re-run. |
196
+ | `Wallet password required, but no interactive terminal…` | In CI/SSH there's no prompt — pass `--password` or set `TOWNHOUSE_WALLET_PASSWORD`. |
197
+ | `Wallet not found … Run \`townhouse init\` first.` | Run `init` before `up` / `hs up`. |
198
+ | `Existing hidden-service apex detected…` | `townhouse up` (direct) won't downgrade a running HS apex. Use `hs up` to keep HS, or `hs down --rotate-keys && up` (or `hs enable`'s inverse) to switch to direct. |
199
+ | Forgot your password | The wallet is encrypted and can't be recovered without it. Re-run `init --force` to regenerate (this **replaces** your keys — only do this if you've backed up the seed elsewhere or are starting fresh). |
200
+
201
+ For verbose logs on any failure, re-run with `DEBUG=townhouse:*`.
202
+
203
+ For multi-chain settlement operational issues (Solana + Mina on-chain settle — connector-restart route loss, nonce-watermark persistence, a wedged settlement monitor, the town inbound-session race, and Mina zkApp resets), see [`RUNBOOK.md`](./RUNBOOK.md).
204
+
205
+ ---
206
+
207
+ ## Using it as a library
208
+
209
+ The package also exports its building blocks for programmatic use — `DockerOrchestrator`, `ConnectorAdminClient`, wallet helpers, and the Compose-template loaders:
210
+
211
+ ```typescript
212
+ import {
213
+ materializeComposeTemplate,
214
+ DockerOrchestrator,
215
+ } from '@toon-protocol/hub';
216
+ ```
217
+
218
+ See [`CONTRIBUTING.md`](./CONTRIBUTING.md) for the full API surface and internals.
219
+
220
+ ## Contributing / local development
221
+
222
+ The local multi-node dev stack, the E2E test harnesses, Compose-template internals, and advanced docker-compose operator paths are documented in [`CONTRIBUTING.md`](./CONTRIBUTING.md).
223
+
224
+ ## License
225
+
226
+ MIT