@toon-protocol/client-mcp 0.31.1 → 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.
- package/README.md +48 -7
- package/dist/{chunk-MI2IWKHX.js → chunk-ARFPM2PT.js} +86 -4
- package/dist/{chunk-MI2IWKHX.js.map → chunk-ARFPM2PT.js.map} +1 -1
- package/dist/{chunk-JOGMX4IT.js → chunk-I5L5CB4N.js} +2 -2
- package/dist/{chunk-SECSBCDA.js → chunk-PRFPAEGG.js} +158 -8
- package/dist/chunk-PRFPAEGG.js.map +1 -0
- package/dist/daemon.js +6 -3
- package/dist/daemon.js.map +1 -1
- package/dist/index.d.ts +98 -1
- package/dist/index.js +12 -4
- package/dist/mcp.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-SECSBCDA.js.map +0 -1
- /package/dist/{chunk-JOGMX4IT.js.map → chunk-I5L5CB4N.js.map} +0 -0
|
@@ -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-
|
|
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-
|
|
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
|
-
|
|
7
|
-
|
|
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
|
-
|
|
1136
|
-
|
|
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-
|
|
1717
|
+
//# sourceMappingURL=chunk-PRFPAEGG.js.map
|