@toon-protocol/relay 1.3.1 → 1.3.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/dist/chunk-4RYYKZXO.js +2033 -0
- package/dist/chunk-4RYYKZXO.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +317 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +918 -6
- package/dist/index.js +37 -734
- package/dist/index.js.map +1 -1
- package/package.json +20 -10
- package/LICENSE +0 -190
package/dist/cli.js
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
startRelay
|
|
4
|
+
} from "./chunk-4RYYKZXO.js";
|
|
5
|
+
|
|
6
|
+
// src/launcher/cli.ts
|
|
7
|
+
import { parseArgs } from "util";
|
|
8
|
+
function printHelp() {
|
|
9
|
+
console.log(
|
|
10
|
+
`
|
|
11
|
+
Usage: toon-town [options]
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--mnemonic <words> BIP-39 mnemonic (12 or 24 words)
|
|
15
|
+
--secret-key <hex> 32-byte secret key in hex
|
|
16
|
+
--relay-port <port> WebSocket relay port (default: 7100)
|
|
17
|
+
--bls-port <port> BLS HTTP port (default: 3100)
|
|
18
|
+
--data-dir <path> Data directory (default: ./data)
|
|
19
|
+
--connector-url <url> Parent connector BTP URL (e.g. ws://apex:3001).
|
|
20
|
+
When set, the embedded connector peers with this
|
|
21
|
+
URL and routes everything outside the local prefix
|
|
22
|
+
through it. --ilp-address becomes REQUIRED and must
|
|
23
|
+
fall under the parent's prefix.
|
|
24
|
+
--parent-peer-id <id> BTP peer id to register the parent under (default: apex)
|
|
25
|
+
--parent-auth-token <t> Auth token for the parent peer (default: empty / no-auth)
|
|
26
|
+
--ilp-address <addr> ILP address for this node (default: g.toon.<pubkey>;
|
|
27
|
+
REQUIRED when --connector-url is set, e.g. g.townhouse.<self>)
|
|
28
|
+
--node-id <id> Stable nodeId for the embedded connector (default: toon-<pubkey>)
|
|
29
|
+
--known-peers <json> Known peers as JSON array
|
|
30
|
+
--dev-mode Enable dev mode (skip verification)
|
|
31
|
+
--x402-enabled Enable x402 /publish endpoint (default: false)
|
|
32
|
+
--discovery <mode> Discovery mode: 'seed-list' or 'genesis' (default: 'genesis')
|
|
33
|
+
--seed-relays <urls> Comma-separated public Nostr relay URLs for seed discovery
|
|
34
|
+
--publish-seed-entry Publish this node as a seed relay entry (default: false)
|
|
35
|
+
--external-relay-url <url> External WebSocket URL of this relay
|
|
36
|
+
--help Show this help message
|
|
37
|
+
|
|
38
|
+
Environment Variables:
|
|
39
|
+
TOON_MNEMONIC Same as --mnemonic
|
|
40
|
+
TOON_SECRET_KEY Same as --secret-key
|
|
41
|
+
TOON_RELAY_PORT Same as --relay-port
|
|
42
|
+
TOON_BLS_PORT Same as --bls-port
|
|
43
|
+
TOON_DATA_DIR Same as --data-dir
|
|
44
|
+
TOON_CONNECTOR_URL Same as --connector-url (parent BTP URL)
|
|
45
|
+
TOON_PARENT_PEER_ID Same as --parent-peer-id
|
|
46
|
+
TOON_PARENT_AUTH_TOKEN Same as --parent-auth-token
|
|
47
|
+
TOON_ILP_ADDRESS Same as --ilp-address (required with TOON_CONNECTOR_URL)
|
|
48
|
+
TOON_NODE_ID Same as --node-id
|
|
49
|
+
TOON_KNOWN_PEERS Same as --known-peers
|
|
50
|
+
TOON_DEV_MODE Same as --dev-mode (set to "true")
|
|
51
|
+
TOON_X402_ENABLED Same as --x402-enabled (set to "true")
|
|
52
|
+
TOON_DISCOVERY Same as --discovery
|
|
53
|
+
TOON_SEED_RELAYS Same as --seed-relays
|
|
54
|
+
TOON_PUBLISH_SEED_ENTRY Same as --publish-seed-entry (set to "true")
|
|
55
|
+
TOON_EXTERNAL_RELAY_URL Same as --external-relay-url
|
|
56
|
+
TOON_FEE_PER_EVENT Fee per event in ILP units (overrides basePricePerByte)
|
|
57
|
+
TOON_SETTLEMENT_PRIVATE_KEY EVM private key (0x-prefixed 32-byte hex) for the
|
|
58
|
+
embedded connector's ClaimReceiver / chainProviders.
|
|
59
|
+
Defaults to the identity-derived secp256k1 hex.
|
|
60
|
+
TOON_PARENT_EVM_ADDRESS EVM treasury address advertised to the parent
|
|
61
|
+
connector as the peer entry's evmAddress (used by the
|
|
62
|
+
apex's PerPacketClaimService when opening a settlement
|
|
63
|
+
channel toward this child).
|
|
64
|
+
|
|
65
|
+
Security:
|
|
66
|
+
Prefer TOON_MNEMONIC or TOON_SECRET_KEY environment variables
|
|
67
|
+
over --mnemonic / --secret-key CLI flags. CLI arguments are visible to
|
|
68
|
+
other users on the system via process listings (e.g. ps aux). See CWE-214.
|
|
69
|
+
`.trim()
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
function parseCli() {
|
|
73
|
+
const { values } = parseArgs({
|
|
74
|
+
options: {
|
|
75
|
+
mnemonic: { type: "string" },
|
|
76
|
+
"secret-key": { type: "string" },
|
|
77
|
+
"relay-port": { type: "string" },
|
|
78
|
+
"bls-port": { type: "string" },
|
|
79
|
+
"data-dir": { type: "string" },
|
|
80
|
+
"connector-url": { type: "string" },
|
|
81
|
+
"parent-peer-id": { type: "string" },
|
|
82
|
+
"parent-auth-token": { type: "string" },
|
|
83
|
+
"ilp-address": { type: "string" },
|
|
84
|
+
"node-id": { type: "string" },
|
|
85
|
+
"known-peers": { type: "string" },
|
|
86
|
+
"dev-mode": { type: "boolean" },
|
|
87
|
+
"x402-enabled": { type: "boolean" },
|
|
88
|
+
discovery: { type: "string" },
|
|
89
|
+
"seed-relays": { type: "string" },
|
|
90
|
+
"publish-seed-entry": { type: "boolean" },
|
|
91
|
+
"external-relay-url": { type: "string" },
|
|
92
|
+
help: { type: "boolean" }
|
|
93
|
+
},
|
|
94
|
+
strict: true,
|
|
95
|
+
allowPositionals: false
|
|
96
|
+
});
|
|
97
|
+
if (values.help) {
|
|
98
|
+
printHelp();
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
if (values.mnemonic) {
|
|
102
|
+
console.warn(
|
|
103
|
+
"Warning: --mnemonic is visible in process listings. Prefer TOON_MNEMONIC environment variable for production use."
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (values["secret-key"]) {
|
|
107
|
+
console.warn(
|
|
108
|
+
"Warning: --secret-key is visible in process listings. Prefer TOON_SECRET_KEY environment variable for production use."
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const mnemonic = values.mnemonic ?? process.env["TOON_MNEMONIC"] ?? void 0;
|
|
112
|
+
const secretKeyHex = values["secret-key"] ?? process.env["TOON_SECRET_KEY"] ?? void 0;
|
|
113
|
+
let secretKey;
|
|
114
|
+
if (secretKeyHex) {
|
|
115
|
+
if (secretKeyHex.length !== 64 || !/^[0-9a-fA-F]{64}$/.test(secretKeyHex)) {
|
|
116
|
+
console.error("Error: --secret-key must be a 64-character hex string");
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
secretKey = Uint8Array.from(Buffer.from(secretKeyHex, "hex"));
|
|
120
|
+
}
|
|
121
|
+
const connectorUrl = values["connector-url"] ?? process.env["TOON_CONNECTOR_URL"] ?? void 0;
|
|
122
|
+
const parentPeerId = values["parent-peer-id"] ?? process.env["TOON_PARENT_PEER_ID"] ?? void 0;
|
|
123
|
+
const parentAuthToken = values["parent-auth-token"] ?? process.env["TOON_PARENT_AUTH_TOKEN"] ?? void 0;
|
|
124
|
+
const ilpAddress = values["ilp-address"] ?? process.env["TOON_ILP_ADDRESS"] ?? void 0;
|
|
125
|
+
const nodeId = values["node-id"] ?? process.env["TOON_NODE_ID"] ?? void 0;
|
|
126
|
+
if (connectorUrl && !ilpAddress) {
|
|
127
|
+
console.error(
|
|
128
|
+
"Error: --ilp-address (or TOON_ILP_ADDRESS) is required when --connector-url is set; it must fall under the parent connector prefix (e.g. g.townhouse.<self>)"
|
|
129
|
+
);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
const relayPortStr = values["relay-port"] ?? process.env["TOON_RELAY_PORT"] ?? void 0;
|
|
133
|
+
const relayPort = relayPortStr ? parseInt(relayPortStr, 10) : void 0;
|
|
134
|
+
if (relayPort !== void 0 && (Number.isNaN(relayPort) || relayPort <= 0 || relayPort > 65535)) {
|
|
135
|
+
console.error("Error: --relay-port must be an integer between 1 and 65535");
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
const blsPortStr = values["bls-port"] ?? process.env["TOON_BLS_PORT"] ?? void 0;
|
|
139
|
+
const blsPort = blsPortStr ? parseInt(blsPortStr, 10) : void 0;
|
|
140
|
+
if (blsPort !== void 0 && (Number.isNaN(blsPort) || blsPort <= 0 || blsPort > 65535)) {
|
|
141
|
+
console.error("Error: --bls-port must be an integer between 1 and 65535");
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
const dataDir = values["data-dir"] ?? process.env["TOON_DATA_DIR"] ?? void 0;
|
|
145
|
+
const devMode = values["dev-mode"] ?? (process.env["TOON_DEV_MODE"] === "true" ? true : void 0);
|
|
146
|
+
const x402Enabled = values["x402-enabled"] ?? (process.env["TOON_X402_ENABLED"] === "true" ? true : void 0);
|
|
147
|
+
const knownPeersJson = values["known-peers"] ?? process.env["TOON_KNOWN_PEERS"] ?? void 0;
|
|
148
|
+
let knownPeers;
|
|
149
|
+
if (knownPeersJson) {
|
|
150
|
+
try {
|
|
151
|
+
const parsed = JSON.parse(knownPeersJson);
|
|
152
|
+
if (Array.isArray(parsed)) {
|
|
153
|
+
knownPeers = parsed.filter(
|
|
154
|
+
(p) => typeof p === "object" && p !== null && typeof p["pubkey"] === "string" && typeof p["btpEndpoint"] === "string"
|
|
155
|
+
).map((p) => ({
|
|
156
|
+
pubkey: p["pubkey"],
|
|
157
|
+
relayUrl: p["relayUrl"] || "ws://localhost:7100",
|
|
158
|
+
btpEndpoint: p["btpEndpoint"]
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
console.error("Error: --known-peers must be valid JSON");
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (!mnemonic && !secretKey) {
|
|
167
|
+
console.error(
|
|
168
|
+
"Error: one of --mnemonic (or TOON_MNEMONIC) or --secret-key (or TOON_SECRET_KEY) is required"
|
|
169
|
+
);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
const discoveryStr = values.discovery ?? process.env["TOON_DISCOVERY"] ?? void 0;
|
|
173
|
+
let discoveryMode;
|
|
174
|
+
if (discoveryStr) {
|
|
175
|
+
if (discoveryStr !== "seed-list" && discoveryStr !== "genesis") {
|
|
176
|
+
console.error('Error: --discovery must be "seed-list" or "genesis"');
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
discoveryMode = discoveryStr;
|
|
180
|
+
}
|
|
181
|
+
const seedRelaysStr = values["seed-relays"] ?? process.env["TOON_SEED_RELAYS"] ?? void 0;
|
|
182
|
+
const seedRelaysArr = seedRelaysStr ? seedRelaysStr.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
183
|
+
if (seedRelaysArr) {
|
|
184
|
+
for (const url of seedRelaysArr) {
|
|
185
|
+
if (!url.startsWith("ws://") && !url.startsWith("wss://")) {
|
|
186
|
+
console.error(
|
|
187
|
+
"Error: --seed-relays contains invalid URL -- must use WebSocket scheme (ws or wss)"
|
|
188
|
+
);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const publishSeedEntry = values["publish-seed-entry"] ?? (process.env["TOON_PUBLISH_SEED_ENTRY"] === "true" ? true : void 0);
|
|
194
|
+
const externalRelayUrl = values["external-relay-url"] ?? process.env["TOON_EXTERNAL_RELAY_URL"] ?? void 0;
|
|
195
|
+
const feePerEventStr = process.env["TOON_FEE_PER_EVENT"] ?? void 0;
|
|
196
|
+
const feePerEvent = feePerEventStr ? parseInt(feePerEventStr, 10) : void 0;
|
|
197
|
+
if (feePerEvent !== void 0 && (Number.isNaN(feePerEvent) || feePerEvent < 0)) {
|
|
198
|
+
console.error("Error: TOON_FEE_PER_EVENT must be a non-negative integer");
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
const btpEndpoint = process.env["TOON_BTP_ENDPOINT"] ?? void 0;
|
|
202
|
+
const assetCode = process.env["TOON_ASSET_CODE"] ?? void 0;
|
|
203
|
+
const assetScaleStr = process.env["TOON_ASSET_SCALE"] ?? void 0;
|
|
204
|
+
const assetScale = assetScaleStr ? parseInt(assetScaleStr, 10) : void 0;
|
|
205
|
+
if (assetScale !== void 0 && (Number.isNaN(assetScale) || assetScale < 0 || assetScale > 18)) {
|
|
206
|
+
console.error("Error: TOON_ASSET_SCALE must be an integer in 0..18");
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
const settlementPrivateKey = process.env["TOON_SETTLEMENT_PRIVATE_KEY"] ?? void 0;
|
|
210
|
+
if (settlementPrivateKey !== void 0 && !/^0x[0-9a-fA-F]{64}$/.test(settlementPrivateKey)) {
|
|
211
|
+
console.error(
|
|
212
|
+
"Error: TOON_SETTLEMENT_PRIVATE_KEY must be a 0x-prefixed 32-byte hex string"
|
|
213
|
+
);
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
const parentEvmAddress = process.env["TOON_PARENT_EVM_ADDRESS"] ?? void 0;
|
|
217
|
+
if (parentEvmAddress !== void 0 && !/^0x[0-9a-fA-F]{40}$/.test(parentEvmAddress)) {
|
|
218
|
+
console.error(
|
|
219
|
+
"Error: TOON_PARENT_EVM_ADDRESS must be a 0x-prefixed 20-byte hex address"
|
|
220
|
+
);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
let chainRpcUrls;
|
|
224
|
+
let tokenNetworks;
|
|
225
|
+
let preferredTokens;
|
|
226
|
+
let settlementAddresses;
|
|
227
|
+
const supportedChainsStr = process.env["SUPPORTED_CHAINS"];
|
|
228
|
+
if (supportedChainsStr) {
|
|
229
|
+
const chains = supportedChainsStr.split(",").map((s) => s.trim()).filter(Boolean);
|
|
230
|
+
for (const chain of chains) {
|
|
231
|
+
const key = chain.replace(/:/g, "_").toUpperCase();
|
|
232
|
+
const addr = process.env[`SETTLEMENT_ADDRESS_${key}`];
|
|
233
|
+
if (addr) (settlementAddresses ??= {})[chain] = addr;
|
|
234
|
+
const rpc = process.env[`CHAIN_RPC_URL_${key}`];
|
|
235
|
+
if (rpc) (chainRpcUrls ??= {})[chain] = rpc;
|
|
236
|
+
const tokenNet = process.env[`TOKEN_NETWORK_${key}`];
|
|
237
|
+
if (tokenNet) (tokenNetworks ??= {})[chain] = tokenNet;
|
|
238
|
+
const token = process.env[`PREFERRED_TOKEN_${key}`];
|
|
239
|
+
if (token) (preferredTokens ??= {})[chain] = token;
|
|
240
|
+
if (!addr) {
|
|
241
|
+
console.warn(
|
|
242
|
+
`[Town] Warning: chain "${chain}" listed in SUPPORTED_CHAINS but no SETTLEMENT_ADDRESS_${key} env var found`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const config = {
|
|
248
|
+
...connectorUrl && { connectorUrl },
|
|
249
|
+
...chainRpcUrls && { chainRpcUrls },
|
|
250
|
+
...tokenNetworks && { tokenNetworks },
|
|
251
|
+
...preferredTokens && { preferredTokens },
|
|
252
|
+
...settlementAddresses && { settlementAddresses },
|
|
253
|
+
...parentPeerId && { parentPeerId },
|
|
254
|
+
...parentAuthToken !== void 0 && { parentAuthToken },
|
|
255
|
+
...ilpAddress && { ilpAddress },
|
|
256
|
+
...nodeId && { nodeId },
|
|
257
|
+
...mnemonic && { mnemonic },
|
|
258
|
+
...secretKey && { secretKey },
|
|
259
|
+
...relayPort !== void 0 && { relayPort },
|
|
260
|
+
...blsPort !== void 0 && { blsPort },
|
|
261
|
+
...dataDir && { dataDir },
|
|
262
|
+
...knownPeers && { knownPeers },
|
|
263
|
+
...devMode !== void 0 && { devMode },
|
|
264
|
+
...x402Enabled !== void 0 && { x402Enabled },
|
|
265
|
+
...discoveryMode && { discovery: discoveryMode },
|
|
266
|
+
...seedRelaysArr && { seedRelays: seedRelaysArr },
|
|
267
|
+
...publishSeedEntry !== void 0 && { publishSeedEntry },
|
|
268
|
+
...externalRelayUrl && { externalRelayUrl },
|
|
269
|
+
...feePerEvent !== void 0 && { feePerEvent },
|
|
270
|
+
...btpEndpoint && { btpEndpoint },
|
|
271
|
+
...assetCode && { assetCode },
|
|
272
|
+
...assetScale !== void 0 && { assetScale },
|
|
273
|
+
...settlementPrivateKey && { settlementPrivateKey },
|
|
274
|
+
...parentEvmAddress && { parentEvmAddress }
|
|
275
|
+
};
|
|
276
|
+
return config;
|
|
277
|
+
}
|
|
278
|
+
async function main() {
|
|
279
|
+
const config = parseCli();
|
|
280
|
+
console.log("\n" + "=".repeat(50));
|
|
281
|
+
console.log("TOON Town Starting");
|
|
282
|
+
console.log("=".repeat(50) + "\n");
|
|
283
|
+
const instance = await startRelay(config);
|
|
284
|
+
console.log("\n" + "=".repeat(50));
|
|
285
|
+
console.log("TOON Town Ready");
|
|
286
|
+
console.log("=".repeat(50));
|
|
287
|
+
console.log(` Pubkey: ${instance.pubkey}`);
|
|
288
|
+
console.log(` EVM Address: ${instance.evmAddress}`);
|
|
289
|
+
console.log(` Relay: ws://localhost:${instance.config.relayPort}`);
|
|
290
|
+
console.log(` BLS: http://localhost:${instance.config.blsPort}`);
|
|
291
|
+
console.log(` ILP Address: ${instance.config.ilpAddress}`);
|
|
292
|
+
if (instance.config.connectorUrl) {
|
|
293
|
+
console.log(` Parent BTP: ${instance.config.connectorUrl}`);
|
|
294
|
+
console.log(` Parent Peer: ${instance.config.parentPeerId}`);
|
|
295
|
+
}
|
|
296
|
+
console.log(` Peers: ${instance.bootstrapResult.peerCount}`);
|
|
297
|
+
console.log(` Channels: ${instance.bootstrapResult.channelCount}`);
|
|
298
|
+
console.log("=".repeat(50) + "\n");
|
|
299
|
+
const shutdown = async (signal) => {
|
|
300
|
+
console.log(`
|
|
301
|
+
[Shutdown] Received ${signal}`);
|
|
302
|
+
await instance.stop();
|
|
303
|
+
console.log("[Shutdown] Complete");
|
|
304
|
+
process.exit(0);
|
|
305
|
+
};
|
|
306
|
+
process.on("SIGINT", () => {
|
|
307
|
+
shutdown("SIGINT").catch(console.error);
|
|
308
|
+
});
|
|
309
|
+
process.on("SIGTERM", () => {
|
|
310
|
+
shutdown("SIGTERM").catch(console.error);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
main().catch((error) => {
|
|
314
|
+
console.error("[Fatal] Startup error:", error);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
});
|
|
317
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/launcher/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * CLI entrypoint for @toon-protocol/relay.\n *\n * Thin wrapper around startRelay() that parses CLI flags and environment\n * variables, then delegates all logic to town.ts.\n *\n * Usage:\n * npx @toon-protocol/relay --mnemonic \"abandon abandon ...\" \\\n * --connector-url \"ws://apex.example:3001\" \\\n * --ilp-address \"g.townhouse.alice\"\n *\n * Environment variables override defaults; CLI flags override environment variables.\n */\n\nimport { parseArgs } from 'node:util';\nimport { startRelay } from './town.js';\nimport type { RelayConfig, RelayInstance } from './town.js';\n\n// ---------- CLI Parsing ----------\n\nfunction printHelp(): void {\n console.log(\n `\nUsage: toon-town [options]\n\nOptions:\n --mnemonic <words> BIP-39 mnemonic (12 or 24 words)\n --secret-key <hex> 32-byte secret key in hex\n --relay-port <port> WebSocket relay port (default: 7100)\n --bls-port <port> BLS HTTP port (default: 3100)\n --data-dir <path> Data directory (default: ./data)\n --connector-url <url> Parent connector BTP URL (e.g. ws://apex:3001).\n When set, the embedded connector peers with this\n URL and routes everything outside the local prefix\n through it. --ilp-address becomes REQUIRED and must\n fall under the parent's prefix.\n --parent-peer-id <id> BTP peer id to register the parent under (default: apex)\n --parent-auth-token <t> Auth token for the parent peer (default: empty / no-auth)\n --ilp-address <addr> ILP address for this node (default: g.toon.<pubkey>;\n REQUIRED when --connector-url is set, e.g. g.townhouse.<self>)\n --node-id <id> Stable nodeId for the embedded connector (default: toon-<pubkey>)\n --known-peers <json> Known peers as JSON array\n --dev-mode Enable dev mode (skip verification)\n --x402-enabled Enable x402 /publish endpoint (default: false)\n --discovery <mode> Discovery mode: 'seed-list' or 'genesis' (default: 'genesis')\n --seed-relays <urls> Comma-separated public Nostr relay URLs for seed discovery\n --publish-seed-entry Publish this node as a seed relay entry (default: false)\n --external-relay-url <url> External WebSocket URL of this relay\n --help Show this help message\n\nEnvironment Variables:\n TOON_MNEMONIC Same as --mnemonic\n TOON_SECRET_KEY Same as --secret-key\n TOON_RELAY_PORT Same as --relay-port\n TOON_BLS_PORT Same as --bls-port\n TOON_DATA_DIR Same as --data-dir\n TOON_CONNECTOR_URL Same as --connector-url (parent BTP URL)\n TOON_PARENT_PEER_ID Same as --parent-peer-id\n TOON_PARENT_AUTH_TOKEN Same as --parent-auth-token\n TOON_ILP_ADDRESS Same as --ilp-address (required with TOON_CONNECTOR_URL)\n TOON_NODE_ID Same as --node-id\n TOON_KNOWN_PEERS Same as --known-peers\n TOON_DEV_MODE Same as --dev-mode (set to \"true\")\n TOON_X402_ENABLED Same as --x402-enabled (set to \"true\")\n TOON_DISCOVERY Same as --discovery\n TOON_SEED_RELAYS Same as --seed-relays\n TOON_PUBLISH_SEED_ENTRY Same as --publish-seed-entry (set to \"true\")\n TOON_EXTERNAL_RELAY_URL Same as --external-relay-url\n TOON_FEE_PER_EVENT Fee per event in ILP units (overrides basePricePerByte)\n TOON_SETTLEMENT_PRIVATE_KEY EVM private key (0x-prefixed 32-byte hex) for the\n embedded connector's ClaimReceiver / chainProviders.\n Defaults to the identity-derived secp256k1 hex.\n TOON_PARENT_EVM_ADDRESS EVM treasury address advertised to the parent\n connector as the peer entry's evmAddress (used by the\n apex's PerPacketClaimService when opening a settlement\n channel toward this child).\n\nSecurity:\n Prefer TOON_MNEMONIC or TOON_SECRET_KEY environment variables\n over --mnemonic / --secret-key CLI flags. CLI arguments are visible to\n other users on the system via process listings (e.g. ps aux). See CWE-214.\n`.trim()\n );\n}\n\nfunction parseCli(): RelayConfig {\n const { values } = parseArgs({\n options: {\n mnemonic: { type: 'string' },\n 'secret-key': { type: 'string' },\n 'relay-port': { type: 'string' },\n 'bls-port': { type: 'string' },\n 'data-dir': { type: 'string' },\n 'connector-url': { type: 'string' },\n 'parent-peer-id': { type: 'string' },\n 'parent-auth-token': { type: 'string' },\n 'ilp-address': { type: 'string' },\n 'node-id': { type: 'string' },\n 'known-peers': { type: 'string' },\n 'dev-mode': { type: 'boolean' },\n 'x402-enabled': { type: 'boolean' },\n discovery: { type: 'string' },\n 'seed-relays': { type: 'string' },\n 'publish-seed-entry': { type: 'boolean' },\n 'external-relay-url': { type: 'string' },\n help: { type: 'boolean' },\n },\n strict: true,\n allowPositionals: false,\n });\n\n if (values.help) {\n printHelp();\n process.exit(0);\n }\n\n // Resolve: CLI flags override env vars\n\n // Warn about process-listing exposure (CWE-214) when secrets are passed via CLI flags\n if (values.mnemonic) {\n console.warn(\n 'Warning: --mnemonic is visible in process listings. ' +\n 'Prefer TOON_MNEMONIC environment variable for production use.'\n );\n }\n if (values['secret-key']) {\n console.warn(\n 'Warning: --secret-key is visible in process listings. ' +\n 'Prefer TOON_SECRET_KEY environment variable for production use.'\n );\n }\n\n const mnemonic = values.mnemonic ?? process.env['TOON_MNEMONIC'] ?? undefined;\n\n const secretKeyHex =\n values['secret-key'] ?? process.env['TOON_SECRET_KEY'] ?? undefined;\n\n let secretKey: Uint8Array | undefined;\n if (secretKeyHex) {\n if (secretKeyHex.length !== 64 || !/^[0-9a-fA-F]{64}$/.test(secretKeyHex)) {\n console.error('Error: --secret-key must be a 64-character hex string');\n process.exit(1);\n }\n secretKey = Uint8Array.from(Buffer.from(secretKeyHex, 'hex'));\n }\n\n const connectorUrl =\n values['connector-url'] ?? process.env['TOON_CONNECTOR_URL'] ?? undefined;\n\n const parentPeerId =\n values['parent-peer-id'] ?? process.env['TOON_PARENT_PEER_ID'] ?? undefined;\n\n const parentAuthToken =\n values['parent-auth-token'] ??\n process.env['TOON_PARENT_AUTH_TOKEN'] ??\n undefined;\n\n const ilpAddress =\n values['ilp-address'] ?? process.env['TOON_ILP_ADDRESS'] ?? undefined;\n\n const nodeId = values['node-id'] ?? process.env['TOON_NODE_ID'] ?? undefined;\n\n if (connectorUrl && !ilpAddress) {\n console.error(\n 'Error: --ilp-address (or TOON_ILP_ADDRESS) is required when ' +\n '--connector-url is set; it must fall under the parent connector prefix ' +\n '(e.g. g.townhouse.<self>)'\n );\n process.exit(1);\n }\n\n const relayPortStr =\n values['relay-port'] ?? process.env['TOON_RELAY_PORT'] ?? undefined;\n const relayPort = relayPortStr ? parseInt(relayPortStr, 10) : undefined;\n if (\n relayPort !== undefined &&\n (Number.isNaN(relayPort) || relayPort <= 0 || relayPort > 65535)\n ) {\n console.error('Error: --relay-port must be an integer between 1 and 65535');\n process.exit(1);\n }\n\n const blsPortStr =\n values['bls-port'] ?? process.env['TOON_BLS_PORT'] ?? undefined;\n const blsPort = blsPortStr ? parseInt(blsPortStr, 10) : undefined;\n if (\n blsPort !== undefined &&\n (Number.isNaN(blsPort) || blsPort <= 0 || blsPort > 65535)\n ) {\n console.error('Error: --bls-port must be an integer between 1 and 65535');\n process.exit(1);\n }\n\n const dataDir =\n values['data-dir'] ?? process.env['TOON_DATA_DIR'] ?? undefined;\n\n const devMode =\n values['dev-mode'] ??\n (process.env['TOON_DEV_MODE'] === 'true' ? true : undefined);\n\n const x402Enabled =\n values['x402-enabled'] ??\n (process.env['TOON_X402_ENABLED'] === 'true' ? true : undefined);\n\n const knownPeersJson =\n values['known-peers'] ?? process.env['TOON_KNOWN_PEERS'] ?? undefined;\n\n let knownPeers:\n | { pubkey: string; relayUrl: string; btpEndpoint: string }[]\n | undefined;\n if (knownPeersJson) {\n try {\n const parsed: unknown = JSON.parse(knownPeersJson);\n if (Array.isArray(parsed)) {\n knownPeers = (parsed as unknown[])\n .filter(\n (p): p is Record<string, unknown> =>\n typeof p === 'object' &&\n p !== null &&\n typeof (p as Record<string, unknown>)['pubkey'] === 'string' &&\n typeof (p as Record<string, unknown>)['btpEndpoint'] === 'string'\n )\n .map((p) => ({\n pubkey: p['pubkey'] as string,\n relayUrl: (p['relayUrl'] as string) || 'ws://localhost:7100',\n btpEndpoint: p['btpEndpoint'] as string,\n }));\n }\n } catch {\n console.error('Error: --known-peers must be valid JSON');\n process.exit(1);\n }\n }\n\n if (!mnemonic && !secretKey) {\n console.error(\n 'Error: one of --mnemonic (or TOON_MNEMONIC) or --secret-key (or TOON_SECRET_KEY) is required'\n );\n process.exit(1);\n }\n\n // Discovery mode\n const discoveryStr =\n values.discovery ?? process.env['TOON_DISCOVERY'] ?? undefined;\n let discoveryMode: 'seed-list' | 'genesis' | undefined;\n if (discoveryStr) {\n if (discoveryStr !== 'seed-list' && discoveryStr !== 'genesis') {\n console.error('Error: --discovery must be \"seed-list\" or \"genesis\"');\n process.exit(1);\n }\n discoveryMode = discoveryStr;\n }\n\n // Seed relays (comma-separated list of public Nostr relay URLs)\n const seedRelaysStr =\n values['seed-relays'] ?? process.env['TOON_SEED_RELAYS'] ?? undefined;\n const seedRelaysArr = seedRelaysStr\n ? seedRelaysStr\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n\n // Validate seed relay URLs have WebSocket scheme (CWE-20)\n if (seedRelaysArr) {\n for (const url of seedRelaysArr) {\n // nosemgrep: javascript.lang.security.detect-insecure-websocket.detect-insecure-websocket -- validation check, not a connection\n if (!url.startsWith('ws://') && !url.startsWith('wss://')) {\n console.error(\n 'Error: --seed-relays contains invalid URL -- must use WebSocket scheme (ws or wss)'\n );\n process.exit(1);\n }\n }\n }\n\n // Publish seed entry flag\n const publishSeedEntry =\n values['publish-seed-entry'] ??\n (process.env['TOON_PUBLISH_SEED_ENTRY'] === 'true' ? true : undefined);\n\n // External relay URL\n const externalRelayUrl =\n values['external-relay-url'] ??\n process.env['TOON_EXTERNAL_RELAY_URL'] ??\n undefined;\n\n // Fee per event (overrides basePricePerByte)\n const feePerEventStr = process.env['TOON_FEE_PER_EVENT'] ?? undefined;\n const feePerEvent = feePerEventStr ? parseInt(feePerEventStr, 10) : undefined;\n if (\n feePerEvent !== undefined &&\n (Number.isNaN(feePerEvent) || feePerEvent < 0)\n ) {\n console.error('Error: TOON_FEE_PER_EVENT must be a non-negative integer');\n process.exit(1);\n }\n\n // Public BTP endpoint advertised in this town's kind:10032 (so clients learn\n // how to reach the apex to route packets to g.townhouse.town). Set by the\n // Townhouse orchestrator from the apex's .anyone / direct URL.\n const btpEndpoint = process.env['TOON_BTP_ENDPOINT'] ?? undefined;\n\n // Settlement asset advertised in kind:10032.\n const assetCode = process.env['TOON_ASSET_CODE'] ?? undefined;\n const assetScaleStr = process.env['TOON_ASSET_SCALE'] ?? undefined;\n const assetScale = assetScaleStr ? parseInt(assetScaleStr, 10) : undefined;\n if (\n assetScale !== undefined &&\n (Number.isNaN(assetScale) || assetScale < 0 || assetScale > 18)\n ) {\n console.error('Error: TOON_ASSET_SCALE must be an integer in 0..18');\n process.exit(1);\n }\n\n // Settlement private key — controls the embedded connector's ClaimReceiver\n // signer. CLI flag intentionally omitted (process listings would expose the\n // key via `ps`, CWE-214). Env-only.\n const settlementPrivateKey =\n process.env['TOON_SETTLEMENT_PRIVATE_KEY'] ?? undefined;\n if (\n settlementPrivateKey !== undefined &&\n !/^0x[0-9a-fA-F]{64}$/.test(settlementPrivateKey)\n ) {\n console.error(\n 'Error: TOON_SETTLEMENT_PRIVATE_KEY must be a 0x-prefixed 32-byte hex string'\n );\n process.exit(1);\n }\n\n // Parent EVM address advertised to the apex peer. Public address — safe to\n // ship via env. Validated as 0x + 40 hex chars (ERC-55 mixed-case allowed).\n const parentEvmAddress = process.env['TOON_PARENT_EVM_ADDRESS'] ?? undefined;\n if (\n parentEvmAddress !== undefined &&\n !/^0x[0-9a-fA-F]{40}$/.test(parentEvmAddress)\n ) {\n console.error(\n 'Error: TOON_PARENT_EVM_ADDRESS must be a 0x-prefixed 20-byte hex address'\n );\n process.exit(1);\n }\n\n // Multi-chain settlement advertisement (additive; opt-in via SUPPORTED_CHAINS).\n //\n // The default single-EVM-chain path (TOON_CHAIN/TOON_RPC_URL) is unchanged.\n // When SUPPORTED_CHAINS is set, parse per-chain env vars so the node can\n // advertise additional chains (notably `solana:devnet`) in kind:10032 with a\n // chain-native settlement recipient. Env key convention mirrors the SDK\n // entrypoint (docker/src/shared.ts): \"solana:devnet\" -> \"SOLANA_DEVNET\".\n // SETTLEMENT_ADDRESS_<KEY> recipient address advertised for the chain\n // CHAIN_RPC_URL_<KEY> RPC URL for the chain\n // TOKEN_NETWORK_<KEY> payment-channel program / token-network address\n // PREFERRED_TOKEN_<KEY> preferred token (e.g. USDC mint)\n let chainRpcUrls: Record<string, string> | undefined;\n let tokenNetworks: Record<string, string> | undefined;\n let preferredTokens: Record<string, string> | undefined;\n let settlementAddresses: Record<string, string> | undefined;\n const supportedChainsStr = process.env['SUPPORTED_CHAINS'];\n if (supportedChainsStr) {\n const chains = supportedChainsStr\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n for (const chain of chains) {\n const key = chain.replace(/:/g, '_').toUpperCase();\n const addr = process.env[`SETTLEMENT_ADDRESS_${key}`];\n if (addr) (settlementAddresses ??= {})[chain] = addr;\n const rpc = process.env[`CHAIN_RPC_URL_${key}`];\n if (rpc) (chainRpcUrls ??= {})[chain] = rpc;\n const tokenNet = process.env[`TOKEN_NETWORK_${key}`];\n if (tokenNet) (tokenNetworks ??= {})[chain] = tokenNet;\n const token = process.env[`PREFERRED_TOKEN_${key}`];\n if (token) (preferredTokens ??= {})[chain] = token;\n if (!addr) {\n console.warn(\n `[Town] Warning: chain \"${chain}\" listed in SUPPORTED_CHAINS but no SETTLEMENT_ADDRESS_${key} env var found`\n );\n }\n }\n }\n\n const config: RelayConfig = {\n ...(connectorUrl && { connectorUrl }),\n ...(chainRpcUrls && { chainRpcUrls }),\n ...(tokenNetworks && { tokenNetworks }),\n ...(preferredTokens && { preferredTokens }),\n ...(settlementAddresses && { settlementAddresses }),\n ...(parentPeerId && { parentPeerId }),\n ...(parentAuthToken !== undefined && { parentAuthToken }),\n ...(ilpAddress && { ilpAddress }),\n ...(nodeId && { nodeId }),\n ...(mnemonic && { mnemonic }),\n ...(secretKey && { secretKey }),\n ...(relayPort !== undefined && { relayPort }),\n ...(blsPort !== undefined && { blsPort }),\n ...(dataDir && { dataDir }),\n ...(knownPeers && { knownPeers }),\n ...(devMode !== undefined && { devMode }),\n ...(x402Enabled !== undefined && { x402Enabled }),\n ...(discoveryMode && { discovery: discoveryMode }),\n ...(seedRelaysArr && { seedRelays: seedRelaysArr }),\n ...(publishSeedEntry !== undefined && { publishSeedEntry }),\n ...(externalRelayUrl && { externalRelayUrl }),\n ...(feePerEvent !== undefined && { feePerEvent }),\n ...(btpEndpoint && { btpEndpoint }),\n ...(assetCode && { assetCode }),\n ...(assetScale !== undefined && { assetScale }),\n ...(settlementPrivateKey && { settlementPrivateKey }),\n ...(parentEvmAddress && { parentEvmAddress }),\n };\n\n return config;\n}\n\n// ---------- Main ----------\n\nasync function main(): Promise<void> {\n const config = parseCli();\n\n console.log('\\n' + '='.repeat(50));\n console.log('TOON Town Starting');\n console.log('='.repeat(50) + '\\n');\n\n const instance: RelayInstance = await startRelay(config);\n\n console.log('\\n' + '='.repeat(50));\n console.log('TOON Town Ready');\n console.log('='.repeat(50));\n console.log(` Pubkey: ${instance.pubkey}`);\n console.log(` EVM Address: ${instance.evmAddress}`);\n console.log(` Relay: ws://localhost:${instance.config.relayPort}`);\n console.log(` BLS: http://localhost:${instance.config.blsPort}`);\n console.log(` ILP Address: ${instance.config.ilpAddress}`);\n if (instance.config.connectorUrl) {\n console.log(` Parent BTP: ${instance.config.connectorUrl}`);\n console.log(` Parent Peer: ${instance.config.parentPeerId}`);\n }\n console.log(` Peers: ${instance.bootstrapResult.peerCount}`);\n console.log(` Channels: ${instance.bootstrapResult.channelCount}`);\n console.log('='.repeat(50) + '\\n');\n\n // Wire graceful shutdown\n const shutdown = async (signal: string): Promise<void> => {\n console.log(`\\n[Shutdown] Received ${signal}`);\n await instance.stop();\n console.log('[Shutdown] Complete');\n process.exit(0);\n };\n\n process.on('SIGINT', () => {\n shutdown('SIGINT').catch(console.error);\n });\n process.on('SIGTERM', () => {\n shutdown('SIGTERM').catch(console.error);\n });\n}\n\nmain().catch((error: unknown) => {\n console.error('[Fatal] Startup error:', error);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|