@toon-protocol/relay 1.3.4 → 2.0.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
@@ -1,8 +1,12 @@
1
1
  # @toon-protocol/relay
2
2
 
3
- ILP-gated Nostr relay with payment verification, event storage, and dynamic pricing.
3
+ A Nostr relay app: free NIP-01 WebSocket reads plus an HTTP `POST /write`
4
+ surface for storing events.
4
5
 
5
- > This is an internal package. Most users should start with [`@toon-protocol/town`](../town) which wraps this into a single command, or [`@toon-protocol/sdk`](../sdk) for custom services.
6
+ The relay contains **no ILP, connector, settlement, or pricing logic**. Payment
7
+ is enforced entirely upstream by an external terminator — by the time a write
8
+ reaches this process it is already proven paid, so the relay simply stores the
9
+ event and serves reads.
6
10
 
7
11
  ## Install
8
12
 
@@ -10,6 +14,41 @@ ILP-gated Nostr relay with payment verification, event storage, and dynamic pric
10
14
  npm install @toon-protocol/relay
11
15
  ```
12
16
 
17
+ ## Run (CLI)
18
+
19
+ ```bash
20
+ NOSTR_SECRET_KEY=<64-char-hex> npx @toon-protocol/relay
21
+ # reads: ws://localhost:7100
22
+ # writes: http://localhost:3100/write
23
+ # health: http://localhost:3100/health
24
+ ```
25
+
26
+ | Env var | Default | Description |
27
+ |---------|---------|-------------|
28
+ | `TOON_SECRET_KEY` / `NOSTR_SECRET_KEY` | — | 64-char hex identity key (one of these or `TOON_MNEMONIC` is required) |
29
+ | `TOON_MNEMONIC` | — | BIP-39 mnemonic (NIP-06 derivation) |
30
+ | `TOON_RELAY_PORT` | `7100` | WebSocket read port |
31
+ | `TOON_BLS_PORT` | `3100` | HTTP write/health port |
32
+ | `TOON_DATA_DIR` | `./data` | SQLite data directory |
33
+ | `TOON_DEV_MODE` | `false` | Skip event-signature verification on `POST /write` |
34
+
35
+ ## Run (programmatic)
36
+
37
+ ```ts
38
+ import { startRelay } from '@toon-protocol/relay';
39
+
40
+ const relay = await startRelay({ secretKey });
41
+ // ... POST /write on 3100, read NIP-01 on 7100 ...
42
+ await relay.stop();
43
+ ```
44
+
45
+ ## HTTP surface
46
+
47
+ | Method | Path | Description |
48
+ |--------|------|-------------|
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. |
50
+ | `GET` | `/health` | Liveness, identity (`pubkey`), `capabilities`, and `version`. |
51
+
13
52
  ## WebSocket Relay Server
14
53
 
15
54
  NIP-01 compliant WebSocket server that stores and serves Nostr events in TOON format.
@@ -21,124 +60,43 @@ const eventStore = new SqliteEventStore('./events.db');
21
60
  const relay = new NostrRelayServer({ port: 7100 }, eventStore);
22
61
 
23
62
  await relay.start();
24
- console.log(`Relay listening on port ${relay.getPort()}`);
25
- console.log(`Connected clients: ${relay.getClientCount()}`);
26
-
27
- // Push an event to all matching subscriptions
28
- relay.broadcastEvent(event);
29
-
63
+ relay.broadcastEvent(event); // push to matching subscriptions
30
64
  await relay.stop();
31
65
  ```
32
66
 
33
- ### Configuration
34
-
35
- ```ts
36
- import { DEFAULT_RELAY_CONFIG } from '@toon-protocol/relay';
37
-
38
- const config = {
39
- port: 7100, // Default: 7000
40
- maxConnections: 100, // Default: 100
41
- maxSubscriptionsPerConnection: 20, // Default: 20
42
- maxFiltersPerSubscription: 10, // Default: 10
43
- databasePath: './events.db', // Default: ':memory:'
44
- };
45
- ```
46
-
47
67
  ## Event Storage
48
68
 
49
- Two built-in storage backends.
50
-
51
69
  ```ts
52
70
  import { InMemoryEventStore, SqliteEventStore } from '@toon-protocol/relay';
53
71
 
54
- // In-memory (for testing or ephemeral nodes)
55
- const memStore = new InMemoryEventStore();
56
-
57
- // SQLite (for persistent storage)
58
- const sqlStore = new SqliteEventStore('./events.db');
72
+ const memStore = new InMemoryEventStore(); // ephemeral
73
+ const sqlStore = new SqliteEventStore('./events.db'); // persistent
59
74
 
60
- // Both implement the EventStore interface
61
75
  memStore.store(event);
62
76
  const found = memStore.get(event.id);
63
77
  const results = memStore.query([{ kinds: [1], limit: 10 }]);
64
78
  ```
65
79
 
66
- ## Business Logic Server (BLS)
67
-
68
- HTTP server that verifies ILP payment packets, validates events, and gates writes behind payment.
69
-
70
- ```ts
71
- import { BusinessLogicServer, SqliteEventStore } from '@toon-protocol/relay';
72
-
73
- const eventStore = new SqliteEventStore('./events.db');
74
- const bls = new BusinessLogicServer({
75
- basePricePerByte: 10n,
76
- ownerPubkey: 'abc123...', // Owner events bypass payment
77
- }, eventStore);
78
-
79
- // Start HTTP server
80
- bls.listen(3100);
81
-
82
- // Or handle packets directly
83
- const response = bls.handlePacket({
84
- amount: '5000',
85
- destination: 'g.toon.node-a',
86
- data: 'base64-encoded-toon-event',
87
- });
88
-
89
- if (response.accept) {
90
- console.log('Event stored:', response.metadata?.eventId);
91
- }
92
- ```
93
-
94
- ### Endpoints
95
-
96
- | Method | Path | Description |
97
- |--------|------|-------------|
98
- | `GET` | `/health` | Health check with pricing, capabilities, chain info |
99
- | `POST` | `/handle-packet` | Process ILP payment packets |
100
-
101
- ## Pricing Service
102
-
103
- Dynamic per-byte pricing with kind-specific overrides.
104
-
105
- ```ts
106
- import { PricingService } from '@toon-protocol/relay';
107
-
108
- const pricing = new PricingService({
109
- basePricePerByte: 10n,
110
- kindOverrides: new Map([
111
- [1, 5n], // Short notes: cheaper
112
- [30023, 20n], // Long-form articles: premium
113
- ]),
114
- });
115
-
116
- const price = pricing.computePrice(1, eventSizeInBytes);
117
- ```
118
-
119
80
  ## TOON Codec
120
81
 
121
- Re-exported from [`@toon-protocol/core`](../core) for convenience.
82
+ Re-exported from [`@toon-protocol/core`](https://github.com/toon-protocol/core) for convenience.
122
83
 
123
84
  ```ts
124
85
  import { encodeEventToToon, decodeEventFromToon } from '@toon-protocol/relay';
125
-
126
- const toonBytes = encodeEventToToon(nostrEvent);
127
- const event = decodeEventFromToon(toonBytes);
128
86
  ```
129
87
 
130
88
  ## Full API
131
89
 
132
90
  | Category | Exports |
133
91
  |----------|---------|
134
- | **Relay** | `NostrRelayServer`, `ConnectionHandler`, `RelayConfig`, `DEFAULT_RELAY_CONFIG` |
135
- | **Storage** | `EventStore`, `InMemoryEventStore`, `SqliteEventStore` |
136
- | **BLS** | `BusinessLogicServer`, `BlsConfig`, `HandlePacketRequest/Response` |
137
- | **Pricing** | `PricingService`, `PricingConfig`, `loadPricingConfigFromEnv`, `loadPricingConfigFromFile` |
92
+ | **Launcher** | `startRelay`, `RelayConfig`, `RelayInstance`, `RelaySubscription`, `ResolvedRelayConfig` |
93
+ | **Relay** | `NostrRelayServer`, `ConnectionHandler`, `RelayServerConfig`, `DEFAULT_RELAY_CONFIG` |
94
+ | **Storage** | `EventStore`, `InMemoryEventStore`, `SqliteEventStore`, `RelayError` |
95
+ | **Write/Health** | `createWriteHandler`, `createHealthResponse` |
138
96
  | **Codec** | `encodeEventToToon`, `decodeEventFromToon`, `ToonEncodeError`, `ToonDecodeError` |
97
+ | **Subscriber** | `RelaySubscriber`, `RelaySubscriberConfig` |
139
98
  | **Filter** | `matchFilter` |
140
- | **Errors** | `RelayError`, `BlsError`, `PricingError` |
141
- | **Constants** | `ILP_ERROR_CODES`, `PUBKEY_REGEX`, `VERSION` |
99
+ | **Constants** | `VERSION` |
142
100
 
143
101
  ## License
144
102