@toon-protocol/relay 2.0.0 → 2.0.2

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
@@ -29,8 +29,39 @@ NOSTR_SECRET_KEY=<64-char-hex> npx @toon-protocol/relay
29
29
  | `TOON_MNEMONIC` | — | BIP-39 mnemonic (NIP-06 derivation) |
30
30
  | `TOON_RELAY_PORT` | `7100` | WebSocket read port |
31
31
  | `TOON_BLS_PORT` | `3100` | HTTP write/health port |
32
+ | `TOON_HOST` | `0.0.0.0` | WebSocket bind host |
33
+ | `TOON_WRITE_HOST` | `0.0.0.0` | HTTP write/health bind host (see [write-port exposure](#paid-ephemeral-verify-skip-relay85)) |
32
34
  | `TOON_DATA_DIR` | `./data` | SQLite data directory |
33
35
  | `TOON_DEV_MODE` | `false` | Skip event-signature verification on `POST /write` |
36
+ | `TOON_VERIFY_EPHEMERAL` | `false` | Run FULL schnorr verification on ephemeral kinds too (see below) |
37
+ | `TOON_VERIFY_WORKERS` | CPUs − 1 | Worker threads for persistent-kind signature verification; `0` = inline on the event loop (automatic on 1-core boxes) |
38
+ | `TOON_MAX_CONNECTIONS` | `4096` | Maximum concurrent WebSocket read connections (each costs one file descriptor — mind `ulimit -n`) |
39
+
40
+ ## Paid-ephemeral verify skip (relay#85)
41
+
42
+ By default the relay **skips schnorr verification for ephemeral kinds**
43
+ (NIP-16, `20000 <= kind < 30000`) on `POST /write` and keeps only the SHA-256
44
+ event-id check. This is a deliberate, payment-gated bypass:
45
+
46
+ - **Why it is safe here:** every request reaching `POST /write` has already
47
+ passed the upstream connector's payment claim gate — payment is the
48
+ admission/spam gate. Protocol rule: clients trust the signature chain and
49
+ verify every event themselves, never the relay. Relay-side schnorr on paid
50
+ ephemeral frames buys no additional trust; forging a speaker costs real
51
+ money to emit frames every client discards.
52
+ - **What is still checked:** the SHA-256 id check always runs, so the relay
53
+ never broadcasts bytes that disagree with the event id clients verify by.
54
+ - **When you MUST turn it off:** if your write port is fronted by anything
55
+ other than a payment-gating connector — or you ever add a FREE ephemeral
56
+ write lane — set `TOON_VERIFY_EPHEMERAL=true` (`--verify-ephemeral`,
57
+ `verifyEphemeral: true`). A free lane must NOT reuse this skip.
58
+ - **Exposure guard:** the write port must be reachable only via the
59
+ connector. In docker, never host-publish it (`expose:`, not `ports:` —
60
+ docker-published ports bypass ufw). Outside docker, bind it internally via
61
+ `TOON_WRITE_HOST=127.0.0.1`. At startup the relay logs a prominent warning
62
+ if the write listener binds a non-internal interface while the skip is
63
+ active (warning only — container topologies legitimately bind `0.0.0.0`
64
+ and stay private by not publishing the port).
34
65
 
35
66
  ## Run (programmatic)
36
67
 
@@ -46,8 +77,9 @@ await relay.stop();
46
77
 
47
78
  | Method | Path | Description |
48
79
  |--------|------|-------------|
49
- | `POST` | `/write` | Store an event. Body `{ "event": <NostrEvent> }`. Trusts injected `X-TOON-Payer`/`-Amount`/`-Chain` headers (echoed, not validated); verifies only the event signature. |
80
+ | `POST` | `/write` | Store an event. Body `{ "event": <NostrEvent> }`. Trusts injected `X-TOON-Payer`/`-Amount`/`-Chain` headers (echoed, not validated); verifies only the event signature (ephemeral kinds: id check only by default, see above). |
50
81
  | `GET` | `/health` | Liveness, identity (`pubkey`), `capabilities`, and `version`. |
82
+ | `GET` | `/metrics` | JSON telemetry: `eventLoopDelayMs` (mean/p50/p99/max — loop lag is ephemeral-frame tail latency) and `verify` (per-event verify wall time incl. pool queueing, active implementation, worker count). The trigger metrics for scaling decisions (relay#85). |
51
83
 
52
84
  ## WebSocket Relay Server
53
85
 
@@ -79,7 +111,7 @@ const results = memStore.query([{ kinds: [1], limit: 10 }]);
79
111
 
80
112
  ## TOON Codec
81
113
 
82
- Re-exported from [`@toon-protocol/core`](https://github.com/toon-protocol/core) for convenience.
114
+ Vendored in-repo (`src/toon/codec.ts`) so the relay depends only on the lightweight `@toon-format/toon` encoder rather than `@toon-protocol/core`'s full transitive tree. The relay has no runtime dependency on `@toon-protocol/core`.
83
115
 
84
116
  ```ts
85
117
  import { encodeEventToToon, decodeEventFromToon } from '@toon-protocol/relay';