@toon-protocol/client-mcp 0.31.0 → 0.31.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.
@@ -2,7 +2,7 @@ import { createRequire as __cr } from 'module'; const require = __cr(import.meta
2
2
  import {
3
3
  ControlApiError,
4
4
  DaemonUnreachableError
5
- } from "./chunk-QHNSETFB.js";
5
+ } from "./chunk-ARFPM2PT.js";
6
6
 
7
7
  // src/mcp-tools.ts
8
8
  var TOOL_DEFINITIONS = [
@@ -226,4 +226,4 @@ export {
226
226
  TOOL_DEFINITIONS,
227
227
  dispatchTool
228
228
  };
229
- //# sourceMappingURL=chunk-U227QSQG.js.map
229
+ //# sourceMappingURL=chunk-I5L5CB4N.js.map
@@ -1,14 +1,117 @@
1
1
  import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
2
2
  import {
3
+ DEFAULT_KEYSTORE_PASSWORD,
3
4
  ToonError,
4
5
  buildIlpPrepare,
6
+ configDir,
5
7
  decodeEventFromToon,
6
- encodeEventToToon
7
- } from "./chunk-QHNSETFB.js";
8
+ defaultConfigPath,
9
+ deriveFullIdentity,
10
+ encodeEventToToon,
11
+ generateKeystore,
12
+ readConfigFile
13
+ } from "./chunk-ARFPM2PT.js";
14
+ import {
15
+ startManagedAnonProxy
16
+ } from "./chunk-SKQTKZIH.js";
8
17
  import {
9
18
  __require
10
19
  } from "./chunk-F22GNSF6.js";
11
20
 
21
+ // src/daemon/first-run.ts
22
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
23
+ import { dirname, join } from "path";
24
+ function defaultKeystorePath() {
25
+ return join(configDir(), "keystore.json");
26
+ }
27
+ function hasConfiguredIdentity(file) {
28
+ return Boolean(
29
+ process.env["TOON_CLIENT_MNEMONIC"]?.trim() || file.keystorePath || file.mnemonic
30
+ );
31
+ }
32
+ var CONFIG_HELP = {
33
+ transport: "Point btpUrl/relayUrl at your apex. For an .anyone hidden service use ws://<host>.anyone:3000/btp + ws://<host>.anyone:7100 \u2014 the daemon auto-routes through a managed anon proxy. For a direct apex use ws://<host>:3000/btp + ws://<host>:7100.",
34
+ btpUrl: "REQUIRED. BTP WebSocket URL of the apex/connector for paid writes.",
35
+ relayUrl: "Town relay WebSocket URL for FREE reads. Default ws://localhost:7100.",
36
+ managedAnonProxy: "Optional override \u2014 leave unset to auto-infer from btpUrl (.anyone host \u2192 managed anon proxy, anything else \u2192 direct).",
37
+ keystorePath: "Auto-generated encrypted identity. Do not hand-edit; back up your seed phrase."
38
+ };
39
+ async function scaffoldFirstRun(opts = {}) {
40
+ const log = opts.log ?? ((m) => console.error(m));
41
+ const configPath = opts.configPath ?? process.env["TOON_CLIENT_CONFIG"] ?? defaultConfigPath();
42
+ mkdirSync(dirname(configPath), { recursive: true });
43
+ const file = readConfigFile(configPath);
44
+ let updated = { ...file };
45
+ let changed = false;
46
+ if (!hasConfiguredIdentity(file)) {
47
+ const keystorePath = defaultKeystorePath();
48
+ const envPassword = process.env["TOON_CLIENT_KEYSTORE_PASSWORD"];
49
+ const password = envPassword ?? DEFAULT_KEYSTORE_PASSWORD;
50
+ let mnemonic;
51
+ if (existsSync(keystorePath)) {
52
+ mnemonic = "";
53
+ log(
54
+ `[toon-clientd] first run: relinking existing keystore at ${keystorePath}`
55
+ );
56
+ } else {
57
+ const generated = generateKeystore(keystorePath, password);
58
+ mnemonic = generated.mnemonic;
59
+ }
60
+ updated = {
61
+ ...updated,
62
+ keystorePath,
63
+ // Only flag auto-password when WE chose it, so a user-imported keystore
64
+ // (custom password) still requires the env var.
65
+ ...envPassword ? {} : { keystoreAutoPassword: true }
66
+ };
67
+ changed = true;
68
+ if (mnemonic) {
69
+ await printNewIdentity(mnemonic, keystorePath, Boolean(envPassword), log);
70
+ }
71
+ }
72
+ if (!existsSync(configPath)) {
73
+ updated = {
74
+ _help: CONFIG_HELP,
75
+ btpUrl: "",
76
+ relayUrl: "ws://localhost:7100",
77
+ ...updated
78
+ };
79
+ changed = true;
80
+ log(
81
+ `[toon-clientd] wrote starter config at ${configPath} \u2014 set "btpUrl" to your apex before publishing.`
82
+ );
83
+ }
84
+ if (changed) writeConfigFile(configPath, updated);
85
+ }
86
+ async function printNewIdentity(mnemonic, keystorePath, hasEnvPassword, log) {
87
+ const id = await deriveFullIdentity(mnemonic);
88
+ const lines = [
89
+ "",
90
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
91
+ " TOON client: generated a new identity (first run)",
92
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
93
+ ` Nostr pubkey : ${id.nostr.pubkey}`,
94
+ ` EVM address : ${id.evm.address}`,
95
+ ...id.solana.publicKey ? [` Solana : ${id.solana.publicKey}`] : [],
96
+ ...id.mina.publicKey ? [` Mina : ${id.mina.publicKey}`] : [],
97
+ "",
98
+ " Seed phrase (BACK THIS UP \u2014 shown only once):",
99
+ ` ${mnemonic}`,
100
+ "",
101
+ ` Encrypted keystore: ${keystorePath}`,
102
+ hasEnvPassword ? " Encrypted with TOON_CLIENT_KEYSTORE_PASSWORD." : " Encrypted with the default password (set TOON_CLIENT_KEYSTORE_PASSWORD\n + re-import to use your own). Identity reloads automatically on restart.",
103
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
104
+ ""
105
+ ];
106
+ log(lines.join("\n"));
107
+ }
108
+ function writeConfigFile(path, file) {
109
+ writeFileSync(path, JSON.stringify(file, null, 2) + "\n", {
110
+ encoding: "utf8",
111
+ mode: 384
112
+ });
113
+ }
114
+
12
115
  // src/relay-subscription.ts
13
116
  import { createRequire } from "module";
14
117
  var nodeRequire = createRequire(import.meta.url);
@@ -1114,8 +1217,8 @@ function getRandomValues(buf) {
1114
1217
  }
1115
1218
 
1116
1219
  // src/daemon/apex-channel-store.ts
1117
- import { mkdirSync, readFileSync, writeFileSync } from "fs";
1118
- import { dirname } from "path";
1220
+ import { mkdirSync as mkdirSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
1221
+ import { dirname as dirname2 } from "path";
1119
1222
  function key(destination, chain) {
1120
1223
  return `${destination}|${chain}`;
1121
1224
  }
@@ -1132,8 +1235,8 @@ function loadApexChannel(path, destination, chain) {
1132
1235
  function saveApexChannel(path, destination, chain, record) {
1133
1236
  const store = readStore(path);
1134
1237
  store[key(destination, chain)] = record;
1135
- mkdirSync(dirname(path), { recursive: true });
1136
- writeFileSync(path, JSON.stringify(store, null, 2), { mode: 384 });
1238
+ mkdirSync2(dirname2(path), { recursive: true });
1239
+ writeFileSync2(path, JSON.stringify(store, null, 2), { mode: 384 });
1137
1240
  }
1138
1241
 
1139
1242
  // src/daemon/client-runner.ts
@@ -1141,6 +1244,7 @@ var ClientRunner = class {
1141
1244
  config;
1142
1245
  client;
1143
1246
  relay;
1247
+ startReadProxy;
1144
1248
  log;
1145
1249
  startedAt = Date.now();
1146
1250
  bootstrapping = false;
@@ -1148,6 +1252,10 @@ var ClientRunner = class {
1148
1252
  lastError;
1149
1253
  /** Channel opened against the default apex destination. */
1150
1254
  apexChannelId;
1255
+ /** Teardown for a daemon-managed read proxy (btp-direct + relay-`.anyone`). */
1256
+ stopReadProxy;
1257
+ /** Error from the read proxy (kept separate from the paid-path `lastError`). */
1258
+ readProxyError;
1151
1259
  stopped = false;
1152
1260
  constructor(deps) {
1153
1261
  this.config = deps.config;
@@ -1159,6 +1267,10 @@ var ClientRunner = class {
1159
1267
  // The TOON relay sends events TOON-encoded (text) on reads, not as JSON.
1160
1268
  decodeEvent: (raw) => decodeEventFromToon(new TextEncoder().encode(raw))
1161
1269
  });
1270
+ this.startReadProxy = deps.startReadProxy ?? ((opts) => startManagedAnonProxy({
1271
+ socksPort: opts.socksPort,
1272
+ ...opts.log ? { log: opts.log } : {}
1273
+ }));
1162
1274
  this.log = deps.logger ?? (() => void 0);
1163
1275
  }
1164
1276
  /**
@@ -1169,9 +1281,33 @@ var ClientRunner = class {
1169
1281
  start() {
1170
1282
  if (this.bootstrapping || this.ready) return;
1171
1283
  this.bootstrapping = true;
1284
+ if (this.config.manageReadProxy) void this.bringUpReadProxy();
1172
1285
  this.relay.start();
1173
1286
  void this.bootstrap();
1174
1287
  }
1288
+ /** Start the daemon-managed `anon` read proxy (best-effort; logs on failure). */
1289
+ async bringUpReadProxy() {
1290
+ const socksPort = this.config.readProxySocksPort ?? 9050;
1291
+ try {
1292
+ this.log(
1293
+ `[runner] starting managed read proxy on 127.0.0.1:${socksPort}`
1294
+ );
1295
+ const proxy = await this.startReadProxy({
1296
+ socksPort,
1297
+ log: (m) => this.log(`[anon] ${m}`)
1298
+ });
1299
+ if (this.stopped) {
1300
+ await proxy.stop();
1301
+ return;
1302
+ }
1303
+ this.stopReadProxy = () => proxy.stop();
1304
+ this.readProxyError = void 0;
1305
+ this.log("[runner] managed read proxy ready");
1306
+ } catch (err) {
1307
+ this.readProxyError = err instanceof Error ? err.message : String(err);
1308
+ this.log(`[runner] managed read proxy failed: ${this.readProxyError}`);
1309
+ }
1310
+ }
1175
1311
  /** The background bootstrap routine (exposed for awaiting in tests). */
1176
1312
  async bootstrap() {
1177
1313
  try {
@@ -1322,7 +1458,8 @@ var ClientRunner = class {
1322
1458
  url: this.config.relayUrl,
1323
1459
  connected: this.relay.isConnected(),
1324
1460
  buffered: this.relay.bufferedCount(),
1325
- subscriptions: this.relay.activeSubscriptions()
1461
+ subscriptions: this.relay.activeSubscriptions(),
1462
+ ...this.readProxyError ? { proxyError: this.readProxyError } : {}
1326
1463
  },
1327
1464
  ...network ? { network } : {},
1328
1465
  ...this.lastError ? { lastError: this.lastError } : {}
@@ -1435,6 +1572,16 @@ var ClientRunner = class {
1435
1572
  if (this.stopped) return;
1436
1573
  this.stopped = true;
1437
1574
  this.relay.close();
1575
+ if (this.stopReadProxy) {
1576
+ try {
1577
+ await this.stopReadProxy();
1578
+ } catch (err) {
1579
+ this.log(
1580
+ `[runner] read proxy stop error: ${err instanceof Error ? err.message : String(err)}`
1581
+ );
1582
+ }
1583
+ this.stopReadProxy = void 0;
1584
+ }
1438
1585
  try {
1439
1586
  await this.client.stop();
1440
1587
  } catch (err) {
@@ -1558,10 +1705,13 @@ function sendError(reply, status, error, extra = {}) {
1558
1705
  }
1559
1706
 
1560
1707
  export {
1708
+ defaultKeystorePath,
1709
+ hasConfiguredIdentity,
1710
+ scaffoldFirstRun,
1561
1711
  RelaySubscription,
1562
1712
  ClientRunner,
1563
1713
  NotReadyError,
1564
1714
  PublishRejectedError,
1565
1715
  registerRoutes
1566
1716
  };
1567
- //# sourceMappingURL=chunk-4K6S3VPM.js.map
1717
+ //# sourceMappingURL=chunk-PRFPAEGG.js.map