@toon-protocol/client-mcp 0.30.0 → 0.31.1
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/{anon-proxy-W3KMM7GU-L5IBCUAX.js → anon-proxy-W3KMM7GU-FN7ZJY7P.js} +2 -1
- package/dist/chunk-F22GNSF6.js +12 -0
- package/dist/{chunk-CH37M2I2.js → chunk-JOGMX4IT.js} +33 -9
- package/dist/chunk-JOGMX4IT.js.map +1 -0
- package/dist/{chunk-TEMKXTNH.js → chunk-MI2IWKHX.js} +18 -8
- package/dist/{chunk-TEMKXTNH.js.map → chunk-MI2IWKHX.js.map} +1 -1
- package/dist/chunk-SECSBCDA.js +1567 -0
- package/dist/chunk-SECSBCDA.js.map +1 -0
- package/dist/daemon.js +3 -2
- package/dist/daemon.js.map +1 -1
- package/dist/{ed25519-OFFWPWRE.js → ed25519-UB2JDJJK.js} +2 -1
- package/dist/{gateway-QOK47RKS-HB65KIKC.js → gateway-QOK47RKS-SEGTXBR3.js} +2 -1
- package/dist/{gateway-QOK47RKS-HB65KIKC.js.map → gateway-QOK47RKS-SEGTXBR3.js.map} +1 -1
- package/dist/{hmac-7WSXTWW4.js → hmac-26UC6YKX.js} +2 -1
- package/dist/hmac-26UC6YKX.js.map +1 -0
- package/dist/index.d.ts +72 -9
- package/dist/index.js +4 -3
- package/dist/mcp.js +3 -2
- package/dist/mcp.js.map +1 -1
- package/dist/{sha512-LMOIUNFJ.js → sha512-WYC446ZM.js} +2 -1
- package/dist/{sha512-LMOIUNFJ.js.map → sha512-WYC446ZM.js.map} +1 -1
- package/dist/{socks5-WTJBYGME-IXWLQDE7.js → socks5-WTJBYGME-6COK4LXW.js} +2 -1
- package/dist/{socks5-WTJBYGME-IXWLQDE7.js.map → socks5-WTJBYGME-6COK4LXW.js.map} +1 -1
- package/package.json +2 -1
- package/dist/chunk-2MY6AQK6.js +0 -667
- package/dist/chunk-2MY6AQK6.js.map +0 -1
- package/dist/chunk-CH37M2I2.js.map +0 -1
- /package/dist/{anon-proxy-W3KMM7GU-L5IBCUAX.js.map → anon-proxy-W3KMM7GU-FN7ZJY7P.js.map} +0 -0
- /package/dist/{ed25519-OFFWPWRE.js.map → chunk-F22GNSF6.js.map} +0 -0
- /package/dist/{hmac-7WSXTWW4.js.map → ed25519-UB2JDJJK.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NostrEvent } from 'nostr-tools/pure';
|
|
2
|
+
import { SwapPair } from '@toon-protocol/core';
|
|
2
3
|
import { ToonClientConfig } from '@toon-protocol/client';
|
|
3
4
|
import { FastifyInstance } from 'fastify';
|
|
4
5
|
|
|
@@ -116,20 +117,70 @@ interface ChannelInfo {
|
|
|
116
117
|
interface ChannelsResponse {
|
|
117
118
|
channels: ChannelInfo[];
|
|
118
119
|
}
|
|
119
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* `POST /swap` — pay asset A to a mill peer, receive asset B + a signed
|
|
122
|
+
* target-chain claim. The daemon builds the NIP-59 gift-wrapped kind:20032 swap
|
|
123
|
+
* rumor and streams it via SDK `streamSwap`, signing the source-asset claim
|
|
124
|
+
* against the open apex channel (the mill peer must be routed via
|
|
125
|
+
* `apexChildPeers`).
|
|
126
|
+
*/
|
|
120
127
|
interface SwapRequest {
|
|
121
|
-
/** Mill peer ILP destination. */
|
|
128
|
+
/** Mill peer ILP destination (e.g. `g.townhouse.mill`). */
|
|
122
129
|
destination: string;
|
|
123
|
-
/**
|
|
130
|
+
/** Total source-asset amount to swap, in source micro-units. */
|
|
124
131
|
amount: string;
|
|
125
|
-
/**
|
|
126
|
-
|
|
132
|
+
/** Mill's 64-char lowercase hex Nostr pubkey (NIP-59 gift-wrap recipient). */
|
|
133
|
+
millPubkey: string;
|
|
134
|
+
/**
|
|
135
|
+
* The swap pair to execute — from kind:10032 discovery, or operator-supplied
|
|
136
|
+
* when the mill announces pairs to a relay other than the town relay.
|
|
137
|
+
*/
|
|
138
|
+
pair: SwapPair;
|
|
139
|
+
/**
|
|
140
|
+
* Sender's payout address on `pair.to.chain` (EVM 0x-hex / Solana or Mina
|
|
141
|
+
* base58). Echoed on every rumor as the `chain-recipient` tag.
|
|
142
|
+
*/
|
|
143
|
+
chainRecipient: string;
|
|
144
|
+
/** Split the swap into N equal packets (default 1). */
|
|
145
|
+
packetCount?: number;
|
|
146
|
+
}
|
|
147
|
+
/** One accumulated, decrypted claim harvested from a single swap packet. */
|
|
148
|
+
interface SwapClaim {
|
|
149
|
+
/** Source-asset amount sent for this packet (micro-units, decimal). */
|
|
150
|
+
sourceAmount: string;
|
|
151
|
+
/** Target-asset amount claimed (micro-units, decimal). */
|
|
152
|
+
targetAmount: string;
|
|
153
|
+
/** Decrypted signed target-chain claim bytes, base64. */
|
|
154
|
+
claim: string;
|
|
155
|
+
/** Target-chain channel id (real on-chain id, or a dev placeholder). */
|
|
156
|
+
channelId?: string;
|
|
157
|
+
/** Sender's payout address echoed by the mill. */
|
|
158
|
+
recipient?: string;
|
|
159
|
+
/** Mill's on-chain signer address. */
|
|
160
|
+
millSignerAddress?: string;
|
|
161
|
+
/** Mill-side claim id. */
|
|
162
|
+
claimId?: string;
|
|
163
|
+
/** Balance-proof nonce on the target channel (decimal). */
|
|
164
|
+
nonce?: string;
|
|
165
|
+
/** Cumulative transferred on the target channel (micro-units, decimal). */
|
|
166
|
+
cumulativeAmount?: string;
|
|
127
167
|
}
|
|
128
168
|
interface SwapResponse {
|
|
169
|
+
/** True when at least one packet FULFILLed with a usable claim. */
|
|
129
170
|
accepted: boolean;
|
|
130
|
-
/**
|
|
131
|
-
|
|
171
|
+
/** Number of packets the mill FULFILLed. */
|
|
172
|
+
packetsAccepted: number;
|
|
173
|
+
/** Per-packet accumulated claims (settlement metadata + signed claim). */
|
|
174
|
+
claims: SwapClaim[];
|
|
175
|
+
/** Total source sent across accepted packets (micro-units, decimal). */
|
|
176
|
+
cumulativeSource: string;
|
|
177
|
+
/** Total target received across accepted packets (micro-units, decimal). */
|
|
178
|
+
cumulativeTarget: string;
|
|
179
|
+
/** Final stream state. */
|
|
180
|
+
state: 'completed' | 'failed' | 'stopped';
|
|
181
|
+
/** First rejection code from the mill, if any (e.g. `F99`). */
|
|
132
182
|
code?: string;
|
|
183
|
+
/** First rejection message, if any. */
|
|
133
184
|
message?: string;
|
|
134
185
|
}
|
|
135
186
|
/** Uniform error envelope returned with non-2xx responses. */
|
|
@@ -571,7 +622,19 @@ declare class ClientRunner {
|
|
|
571
622
|
}>;
|
|
572
623
|
/** List tracked channels with their nonce watermark + cumulative amount. */
|
|
573
624
|
getChannels(): ChannelsResponse;
|
|
574
|
-
/**
|
|
625
|
+
/**
|
|
626
|
+
* Swap source asset → target asset against a mill peer.
|
|
627
|
+
*
|
|
628
|
+
* Uses SDK `streamSwap`, which builds a NIP-59 gift-wrapped kind:20032 swap
|
|
629
|
+
* rumor per packet and sends it over the open BTP session. The source-asset
|
|
630
|
+
* balance proof is signed by the ToonClient's ChannelManager against the apex
|
|
631
|
+
* channel — so the mill peer MUST be routed via `apexChildPeers` (otherwise
|
|
632
|
+
* there is no channel to sign against and the mill rejects with F99).
|
|
633
|
+
*
|
|
634
|
+
* A fresh ephemeral gift-wrap key is generated per swap (used for sealing the
|
|
635
|
+
* rumor AND decrypting the FULFILL claims) — independent of the daemon's
|
|
636
|
+
* settlement identity, so callers never need to expose a key.
|
|
637
|
+
*/
|
|
575
638
|
swap(req: SwapRequest): Promise<SwapResponse>;
|
|
576
639
|
/** Graceful teardown of the relay subscription + ToonClient. */
|
|
577
640
|
stop(): Promise<void>;
|
|
@@ -662,4 +725,4 @@ declare const TOOL_DEFINITIONS: ToolDefinition[];
|
|
|
662
725
|
*/
|
|
663
726
|
declare function dispatchTool(client: ControlClient, name: string, args: Record<string, unknown>): Promise<ToolResult>;
|
|
664
727
|
|
|
665
|
-
export { type ApexNegotiationConfig, type ChainStatus, type ChannelInfo, type ChannelsResponse, ClientRunner, type ClientRunnerDeps, ControlApiError, ControlClient, type ControlClientOptions, type DaemonConfigFile, DaemonUnreachableError, type DrainResult, type ErrorResponse, type EventsQuery, type EventsResponse, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, RelaySubscription, type RelaySubscriptionOptions, type ResolvedDaemonConfig, type SettlementChain, type StatusResponse, type SubscribeRequest, type SubscribeResponse, type SwapRequest, type SwapResponse, TOOL_DEFINITIONS, type ToolDefinition, type ToolResult, type ToonClientLike, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, dispatchTool, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, spawnDaemonDetached, waitForReady };
|
|
728
|
+
export { type ApexNegotiationConfig, type ChainStatus, type ChannelInfo, type ChannelsResponse, ClientRunner, type ClientRunnerDeps, ControlApiError, ControlClient, type ControlClientOptions, type DaemonConfigFile, DaemonUnreachableError, type DrainResult, type ErrorResponse, type EventsQuery, type EventsResponse, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, RelaySubscription, type RelaySubscriptionOptions, type ResolvedDaemonConfig, type SettlementChain, type StatusResponse, type SubscribeRequest, type SubscribeResponse, type SwapClaim, type SwapRequest, type SwapResponse, TOOL_DEFINITIONS, type ToolDefinition, type ToolResult, type ToonClientLike, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, dispatchTool, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, spawnDaemonDetached, waitForReady };
|
package/dist/index.js
CHANGED
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
PublishRejectedError,
|
|
6
6
|
RelaySubscription,
|
|
7
7
|
registerRoutes
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SECSBCDA.js";
|
|
9
9
|
import {
|
|
10
10
|
TOOL_DEFINITIONS,
|
|
11
11
|
dispatchTool
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JOGMX4IT.js";
|
|
13
13
|
import {
|
|
14
14
|
ControlApiError,
|
|
15
15
|
ControlClient,
|
|
@@ -26,12 +26,13 @@ import {
|
|
|
26
26
|
resolveMnemonic,
|
|
27
27
|
spawnDaemonDetached,
|
|
28
28
|
waitForReady
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-MI2IWKHX.js";
|
|
30
30
|
import "./chunk-32QD72IL.js";
|
|
31
31
|
import "./chunk-QTDCFXPF.js";
|
|
32
32
|
import "./chunk-LR7W2ISE.js";
|
|
33
33
|
import "./chunk-VA7XC4FD.js";
|
|
34
34
|
import "./chunk-SKQTKZIH.js";
|
|
35
|
+
import "./chunk-F22GNSF6.js";
|
|
35
36
|
export {
|
|
36
37
|
ClientRunner,
|
|
37
38
|
ControlApiError,
|
package/dist/mcp.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire as __cr } from 'module'; const require = __cr(import.meta
|
|
|
3
3
|
import {
|
|
4
4
|
TOOL_DEFINITIONS,
|
|
5
5
|
dispatchTool
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JOGMX4IT.js";
|
|
7
7
|
import {
|
|
8
8
|
ControlClient,
|
|
9
9
|
defaultConfigPath,
|
|
@@ -11,12 +11,13 @@ import {
|
|
|
11
11
|
readConfigFile,
|
|
12
12
|
spawnDaemonDetached,
|
|
13
13
|
waitForReady
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-MI2IWKHX.js";
|
|
15
15
|
import "./chunk-32QD72IL.js";
|
|
16
16
|
import "./chunk-QTDCFXPF.js";
|
|
17
17
|
import "./chunk-LR7W2ISE.js";
|
|
18
18
|
import "./chunk-VA7XC4FD.js";
|
|
19
19
|
import "./chunk-SKQTKZIH.js";
|
|
20
|
+
import "./chunk-F22GNSF6.js";
|
|
20
21
|
|
|
21
22
|
// src/mcp.ts
|
|
22
23
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `toon-mcp` — a thin MCP stdio server exposing the TOON client to a Claude\n * agent (Desktop or Code). It holds NO chain keys and NO long-lived\n * connections: every tool maps to an HTTP call against the always-on\n * `toon-clientd` daemon, which it auto-spawns (detached) if it is not running.\n *\n * Works on both surfaces:\n * • Claude Desktop — `claude_desktop_config.json` mcpServers entry.\n * • Claude Code — `claude mcp add toon -- toon-mcp` (or `.mcp.json`).\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n type CallToolResult,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { ControlClient } from './control-client.js';\nimport { dispatchTool, TOOL_DEFINITIONS } from './mcp-tools.js';\nimport { defaultConfigPath, readConfigFile } from './daemon/config.js';\nimport {\n isDaemonRunning,\n spawnDaemonDetached,\n waitForReady,\n} from './daemon/lifecycle.js';\n\n/** stdout carries the MCP protocol — all logging must go to stderr. */\nfunction log(msg: string): void {\n console.error(`[toon-mcp] ${msg}`);\n}\n\n/** Resolve the daemon control-plane URL without needing the mnemonic. */\nfunction controlPlaneUrl(): string {\n const file = readConfigFile(\n process.env['TOON_CLIENT_CONFIG'] ?? defaultConfigPath()\n );\n const port = Number(\n process.env['TOON_CLIENT_HTTP_PORT'] ?? file.httpPort ?? 8787\n );\n return `http://127.0.0.1:${port}`;\n}\n\n/**\n * Make sure the daemon is up: if the lock shows it running, return; otherwise\n * spawn it detached and wait until the control plane is reachable. Best-effort\n * — failures surface as readable tool errors rather than crashing the server.\n */\nasync function ensureDaemon(url: string): Promise<void> {\n if (isDaemonRunning()) return;\n const client = new ControlClient({ baseUrl: url });\n if (await client.ping()) return;\n log('daemon not running — spawning detached');\n try {\n const pid = spawnDaemonDetached();\n log(`spawned toon-clientd (pid ${pid}); waiting for control plane`);\n await waitForReady(url, 20_000);\n } catch (err) {\n log(\n `failed to spawn daemon: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n}\n\nasync function main(): Promise<void> {\n const url = controlPlaneUrl();\n const control = new ControlClient({ baseUrl: url });\n\n // Kick off daemon startup; don't block server init on it (anon bootstrap is\n // slow). Tools report \"bootstrapping — retry\" until it is ready.\n void ensureDaemon(url);\n\n const server = new Server(\n { name: 'toon-client', version: '0.1.0' },\n { capabilities: { tools: {} } }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: TOOL_DEFINITIONS,\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const name = request.params.name;\n const args = (request.params.arguments ?? {}) as Record<string, unknown>;\n // If the daemon went away, try once to bring it back before dispatching.\n if (!(await control.ping())) await ensureDaemon(url);\n // Our ToolResult is a structural subset of CallToolResult (content + isError);\n // the SDK's handler union also carries a task-augmented variant we never use.\n return (await dispatchTool(control, name, args)) as CallToolResult;\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n log(`ready; proxying to ${url}`);\n}\n\nmain().catch((err) => {\n log(err instanceof Error ? (err.stack ?? err.message) : String(err));\n process.exitCode = 1;\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `toon-mcp` — a thin MCP stdio server exposing the TOON client to a Claude\n * agent (Desktop or Code). It holds NO chain keys and NO long-lived\n * connections: every tool maps to an HTTP call against the always-on\n * `toon-clientd` daemon, which it auto-spawns (detached) if it is not running.\n *\n * Works on both surfaces:\n * • Claude Desktop — `claude_desktop_config.json` mcpServers entry.\n * • Claude Code — `claude mcp add toon -- toon-mcp` (or `.mcp.json`).\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n type CallToolResult,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { ControlClient } from './control-client.js';\nimport { dispatchTool, TOOL_DEFINITIONS } from './mcp-tools.js';\nimport { defaultConfigPath, readConfigFile } from './daemon/config.js';\nimport {\n isDaemonRunning,\n spawnDaemonDetached,\n waitForReady,\n} from './daemon/lifecycle.js';\n\n/** stdout carries the MCP protocol — all logging must go to stderr. */\nfunction log(msg: string): void {\n console.error(`[toon-mcp] ${msg}`);\n}\n\n/** Resolve the daemon control-plane URL without needing the mnemonic. */\nfunction controlPlaneUrl(): string {\n const file = readConfigFile(\n process.env['TOON_CLIENT_CONFIG'] ?? defaultConfigPath()\n );\n const port = Number(\n process.env['TOON_CLIENT_HTTP_PORT'] ?? file.httpPort ?? 8787\n );\n return `http://127.0.0.1:${port}`;\n}\n\n/**\n * Make sure the daemon is up: if the lock shows it running, return; otherwise\n * spawn it detached and wait until the control plane is reachable. Best-effort\n * — failures surface as readable tool errors rather than crashing the server.\n */\nasync function ensureDaemon(url: string): Promise<void> {\n if (isDaemonRunning()) return;\n const client = new ControlClient({ baseUrl: url });\n if (await client.ping()) return;\n log('daemon not running — spawning detached');\n try {\n const pid = spawnDaemonDetached();\n log(`spawned toon-clientd (pid ${pid}); waiting for control plane`);\n await waitForReady(url, 20_000);\n } catch (err) {\n log(\n `failed to spawn daemon: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n}\n\nasync function main(): Promise<void> {\n const url = controlPlaneUrl();\n const control = new ControlClient({ baseUrl: url });\n\n // Kick off daemon startup; don't block server init on it (anon bootstrap is\n // slow). Tools report \"bootstrapping — retry\" until it is ready.\n void ensureDaemon(url);\n\n const server = new Server(\n { name: 'toon-client', version: '0.1.0' },\n { capabilities: { tools: {} } }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: TOOL_DEFINITIONS,\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const name = request.params.name;\n const args = (request.params.arguments ?? {}) as Record<string, unknown>;\n // If the daemon went away, try once to bring it back before dispatching.\n if (!(await control.ping())) await ensureDaemon(url);\n // Our ToolResult is a structural subset of CallToolResult (content + isError);\n // the SDK's handler union also carries a task-augmented variant we never use.\n return (await dispatchTool(control, name, args)) as CallToolResult;\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n log(`ready; proxying to ${url}`);\n}\n\nmain().catch((err) => {\n log(err instanceof Error ? (err.stack ?? err.message) : String(err));\n process.exitCode = 1;\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAYA,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAWP,SAAS,IAAI,KAAmB;AAC9B,UAAQ,MAAM,cAAc,GAAG,EAAE;AACnC;AAGA,SAAS,kBAA0B;AACjC,QAAM,OAAO;AAAA,IACX,QAAQ,IAAI,oBAAoB,KAAK,kBAAkB;AAAA,EACzD;AACA,QAAM,OAAO;AAAA,IACX,QAAQ,IAAI,uBAAuB,KAAK,KAAK,YAAY;AAAA,EAC3D;AACA,SAAO,oBAAoB,IAAI;AACjC;AAOA,eAAe,aAAa,KAA4B;AACtD,MAAI,gBAAgB,EAAG;AACvB,QAAM,SAAS,IAAI,cAAc,EAAE,SAAS,IAAI,CAAC;AACjD,MAAI,MAAM,OAAO,KAAK,EAAG;AACzB,MAAI,6CAAwC;AAC5C,MAAI;AACF,UAAM,MAAM,oBAAoB;AAChC,QAAI,6BAA6B,GAAG,8BAA8B;AAClE,UAAM,aAAa,KAAK,GAAM;AAAA,EAChC,SAAS,KAAK;AACZ;AAAA,MACE,2BAA2B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC7E;AAAA,EACF;AACF;AAEA,eAAe,OAAsB;AACnC,QAAM,MAAM,gBAAgB;AAC5B,QAAM,UAAU,IAAI,cAAc,EAAE,SAAS,IAAI,CAAC;AAIlD,OAAK,aAAa,GAAG;AAErB,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,eAAe,SAAS,QAAQ;AAAA,IACxC,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,EAChC;AAEA,SAAO,kBAAkB,wBAAwB,aAAa;AAAA,IAC5D,OAAO;AAAA,EACT,EAAE;AAEF,SAAO,kBAAkB,uBAAuB,OAAO,YAAY;AACjE,UAAM,OAAO,QAAQ,OAAO;AAC5B,UAAM,OAAQ,QAAQ,OAAO,aAAa,CAAC;AAE3C,QAAI,CAAE,MAAM,QAAQ,KAAK,EAAI,OAAM,aAAa,GAAG;AAGnD,WAAQ,MAAM,aAAa,SAAS,MAAM,IAAI;AAAA,EAChD,CAAC;AAED,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAC9B,MAAI,sBAAsB,GAAG,EAAE;AACjC;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,MAAI,eAAe,QAAS,IAAI,SAAS,IAAI,UAAW,OAAO,GAAG,CAAC;AACnE,UAAQ,WAAW;AACrB,CAAC;","names":[]}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
sha512_256
|
|
11
11
|
} from "./chunk-LR7W2ISE.js";
|
|
12
12
|
import "./chunk-VA7XC4FD.js";
|
|
13
|
+
import "./chunk-F22GNSF6.js";
|
|
13
14
|
|
|
14
15
|
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha512.js
|
|
15
16
|
var SHA5122 = SHA512;
|
|
@@ -30,4 +31,4 @@ export {
|
|
|
30
31
|
sha512_2242 as sha512_224,
|
|
31
32
|
sha512_2562 as sha512_256
|
|
32
33
|
};
|
|
33
|
-
//# sourceMappingURL=sha512-
|
|
34
|
+
//# sourceMappingURL=sha512-WYC446ZM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/sha512.ts"],"sourcesContent":["/**\n * SHA2-512 a.k.a. sha512 and sha384. It is slower than sha256 in js because u64 operations are slow.\n *\n * Check out [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and\n * [the paper on truncated SHA512/256](https://eprint.iacr.org/2010/548.pdf).\n * @module\n * @deprecated\n */\nimport {\n SHA384 as SHA384n,\n sha384 as sha384n,\n sha512_224 as sha512_224n,\n SHA512_224 as SHA512_224n,\n sha512_256 as sha512_256n,\n SHA512_256 as SHA512_256n,\n SHA512 as SHA512n,\n sha512 as sha512n,\n} from './sha2.ts';\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const SHA512: typeof SHA512n = SHA512n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const sha512: typeof sha512n = sha512n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const SHA384: typeof SHA384n = SHA384n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const sha384: typeof sha384n = sha384n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const SHA512_224: typeof SHA512_224n = SHA512_224n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const sha512_224: typeof sha512_224n = sha512_224n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const SHA512_256: typeof SHA512_256n = SHA512_256n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const sha512_256: typeof sha512_256n = sha512_256n;\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/sha512.ts"],"sourcesContent":["/**\n * SHA2-512 a.k.a. sha512 and sha384. It is slower than sha256 in js because u64 operations are slow.\n *\n * Check out [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and\n * [the paper on truncated SHA512/256](https://eprint.iacr.org/2010/548.pdf).\n * @module\n * @deprecated\n */\nimport {\n SHA384 as SHA384n,\n sha384 as sha384n,\n sha512_224 as sha512_224n,\n SHA512_224 as SHA512_224n,\n sha512_256 as sha512_256n,\n SHA512_256 as SHA512_256n,\n SHA512 as SHA512n,\n sha512 as sha512n,\n} from './sha2.ts';\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const SHA512: typeof SHA512n = SHA512n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const sha512: typeof sha512n = sha512n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const SHA384: typeof SHA384n = SHA384n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const sha384: typeof sha384n = sha384n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const SHA512_224: typeof SHA512_224n = SHA512_224n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const sha512_224: typeof sha512_224n = sha512_224n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const SHA512_256: typeof SHA512_256n = SHA512_256n;\n/** @deprecated Use import from `noble/hashes/sha2` module */\nexport const sha512_256: typeof sha512_256n = sha512_256n;\n"],"mappings":";;;;;;;;;;;;;;;AAmBO,IAAMA,UAAyB;AAE/B,IAAMC,UAAyB;AAE/B,IAAMC,UAAyB;AAE/B,IAAMC,UAAyB;AAE/B,IAAMC,cAAiC;AAEvC,IAAMC,cAAiC;AAEvC,IAAMC,cAAiC;AAEvC,IAAMC,cAAiC;","names":["SHA512","sha512","SHA384","sha384","SHA512_224","sha512_224","SHA512_256","sha512_256"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
|
|
2
|
+
import "./chunk-F22GNSF6.js";
|
|
2
3
|
|
|
3
4
|
// ../client/dist/socks5-WTJBYGME.js
|
|
4
5
|
import { createConnection } from "net";
|
|
@@ -135,4 +136,4 @@ export {
|
|
|
135
136
|
probeSocks5Proxy,
|
|
136
137
|
validateSocks5hUrl
|
|
137
138
|
};
|
|
138
|
-
//# sourceMappingURL=socks5-WTJBYGME-
|
|
139
|
+
//# sourceMappingURL=socks5-WTJBYGME-6COK4LXW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../client/src/transport/socks5.ts"],"sourcesContent":["/**\n * SOCKS5 transport helpers for Node.js environments.\n *\n * This module is dynamically imported only when `transport.type === 'socks5'`\n * is configured, keeping `ws` and `socks-proxy-agent` out of browser bundles.\n */\n\nimport { createConnection } from 'node:net';\nimport { createRequire } from 'node:module';\nimport type SocksProxyAgentModule from 'socks-proxy-agent';\nimport type WSModule from 'ws';\nimport type httpModule from 'node:http';\nimport type httpsModule from 'node:https';\n\n// ESM-safe require. This module builds as ESM (tsup `format: ['esm']`) with\n// `socks-proxy-agent`/`ws` external, so a bare `require(...)` would be rewritten\n// by esbuild into a `__require` shim that throws\n// `Dynamic require of \"socks-proxy-agent\" is not supported` for any pure-ESM\n// consumer — breaking the SOCKS5/ATOR transport entirely (the npm-consumer\n// toon-client image surfaced this). Building a real require off `import.meta.url`\n// (the same pattern as docker/esbuild.config.mjs's banner) keeps the\n// synchronous, browser-guarded `require(...)` calls below working in the\n// published ESM bundle while leaving the deps external. Browser bundlers never\n// reach this code: the module is dynamically imported only when\n// `transport.type === 'socks5'`, which is Node-only.\nconst require = createRequire(import.meta.url);\n\n/**\n * Parses and validates a `socks5h://` URL.\n * Enforces `socks5h://` scheme (not `socks5://`) to prevent DNS leaks —\n * `.anyone` hostnames must be resolved by the proxy, not locally.\n *\n * Mirrors the connector's `transport/socks-url.ts` validation logic.\n */\nexport function validateSocks5hUrl(socksProxy: string): {\n host: string;\n port: number;\n} {\n if (!socksProxy.startsWith('socks5h://')) {\n throw new Error(\n `SOCKS5 proxy URL must use socks5h:// scheme (got \"${socksProxy.split('://')[0]}://\"). ` +\n 'The \"h\" suffix ensures DNS resolution happens at the proxy, preventing leaks of .anyone hostnames.'\n );\n }\n\n // Parse by converting to http:// for URL constructor compatibility\n const httpUrl = socksProxy.replace(/^socks5h:\\/\\//, 'http://');\n let parsed: URL;\n try {\n parsed = new URL(httpUrl);\n } catch {\n throw new Error(`Malformed SOCKS5 proxy URL: \"${socksProxy}\"`);\n }\n\n const host = parsed.hostname;\n const port = parsed.port ? parseInt(parsed.port, 10) : 1080;\n\n if (!host) {\n throw new Error(`SOCKS5 proxy URL missing host: \"${socksProxy}\"`);\n }\n if (port < 0 || port > 65535 || !Number.isFinite(port)) {\n throw new Error(`SOCKS5 proxy port out of range (0–65535): ${parsed.port}`);\n }\n\n return { host, port };\n}\n\n/**\n * Creates a WebSocket factory that routes connections through a SOCKS5 proxy.\n * Uses the `ws` npm package (Node.js only) which accepts an `agent` option.\n */\nexport function createSocks5WebSocketFactory(\n socksProxy: string\n): (url: string) => WebSocket {\n validateSocks5hUrl(socksProxy);\n\n // Resolved via the module-scoped ESM-safe `require` (createRequire) above.\n const { SocksProxyAgent } =\n require('socks-proxy-agent') as typeof SocksProxyAgentModule;\n const WS = require('ws') as typeof WSModule;\n\n // 120s timeout: the socks library's default is 30s, which is too short for\n // the ATOR network to build circuits to fresh hidden services from certain\n // network paths (e.g., Akash datacenter → public ATOR proxy → local HS).\n // 120s gives the proxy time to find a working introduction-point circuit.\n const agent = new SocksProxyAgent(socksProxy, { timeout: 120_000 });\n\n // CJS/ESM interop: `require('ws')` can return any of three shapes depending on\n // the bundler/loader: the class directly (pure CJS); `{ default: WSClass, ... }`\n // (esModuleInterop=true / synthetic default); or `{ WebSocket: WSClass, ... }`\n // (named export, no default). Walk the ladder so this factory works in all\n // three environments. Pass 2 code review 2026-05-18: previous `(WS as any).default ?? WS`\n // would accept a namespace object as a \"constructor\" and throw cryptically.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ws = WS as any;\n const WSClass = (typeof ws === 'function'\n ? ws\n : typeof ws.default === 'function'\n ? ws.default\n : typeof ws.WebSocket === 'function'\n ? ws.WebSocket\n : null) as unknown as typeof WSModule.prototype.constructor;\n if (WSClass === null) {\n throw new Error(\n \"createSocks5WebSocketFactory: require('ws') did not yield a constructor on .default, .WebSocket, or the module root.\"\n );\n }\n\n return (url: string) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (WSClass as any)(url, { agent }) as unknown as WebSocket;\n}\n\n/**\n * Creates a fetch wrapper that routes HTTP requests through a SOCKS5 proxy.\n * Uses `socks-proxy-agent` with Node.js `http`/`https` modules (not native\n * fetch, which uses undici and doesn't support SocksProxyAgent's dispatcher).\n */\nexport function createSocks5Fetch(socksProxy: string): typeof fetch {\n validateSocks5hUrl(socksProxy);\n\n // Resolved via the module-scoped ESM-safe `require` (createRequire) above.\n const { SocksProxyAgent } =\n require('socks-proxy-agent') as typeof SocksProxyAgentModule;\n const http = require('node:http') as typeof httpModule;\n const https = require('node:https') as typeof httpsModule;\n\n const agent = new SocksProxyAgent(socksProxy);\n\n return (input: string | URL | Request, init?: RequestInit) => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url;\n const parsedUrl = new URL(url);\n const isHttps = parsedUrl.protocol === 'https:';\n const transport = isHttps ? https : http;\n\n return new Promise<Response>((resolve, reject) => {\n const method = init?.method ?? 'GET';\n const headers = init?.headers\n ? Object.fromEntries(\n init.headers instanceof Headers\n ? init.headers.entries()\n : Array.isArray(init.headers)\n ? init.headers\n : Object.entries(init.headers)\n )\n : {};\n\n const req = transport.request(\n url,\n { method, headers, agent, timeout: 30_000 },\n (res) => {\n const chunks: Buffer[] = [];\n res.on('data', (chunk: Buffer) => chunks.push(chunk));\n res.on('end', () => {\n const body = Buffer.concat(chunks);\n const responseHeaders = new Headers();\n for (const [key, val] of Object.entries(res.headers)) {\n if (val)\n responseHeaders.set(\n key,\n Array.isArray(val) ? val.join(', ') : val\n );\n }\n resolve(\n new Response(body, {\n status: res.statusCode ?? 200,\n statusText: res.statusMessage ?? '',\n headers: responseHeaders,\n })\n );\n });\n }\n );\n\n req.on('error', reject);\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('SOCKS5 proxied request timeout'));\n });\n\n if (init?.signal) {\n init.signal.addEventListener('abort', () => {\n req.destroy();\n reject(new Error('Aborted'));\n });\n }\n\n if (init?.body) {\n req.write(typeof init.body === 'string' ? init.body : init.body);\n }\n req.end();\n });\n };\n}\n\n/**\n * Probes SOCKS5 proxy reachability with a TCP connection test.\n * Fail-closed: throws if the proxy is unreachable within the timeout.\n *\n * @param socksProxy - `socks5h://host:port` URL\n * @param timeoutMs - Connection timeout in milliseconds (default: 2000)\n */\nexport async function probeSocks5Proxy(\n socksProxy: string,\n timeoutMs = 2000\n): Promise<void> {\n const { host, port } = validateSocks5hUrl(socksProxy);\n\n return new Promise<void>((resolve, reject) => {\n const socket = createConnection({ host, port }, () => {\n socket.destroy();\n resolve();\n });\n\n socket.setTimeout(timeoutMs, () => {\n socket.destroy();\n reject(\n new Error(\n `SOCKS5 proxy at ${host}:${port} unreachable (timeout ${timeoutMs}ms). ` +\n 'Refusing to start without privacy transport (fail-closed).'\n )\n );\n });\n\n socket.on('error', (err) => {\n socket.destroy();\n reject(\n new Error(\n `SOCKS5 proxy at ${host}:${port} unreachable: ${err.message}. ` +\n 'Refusing to start without privacy transport (fail-closed).'\n )\n );\n });\n });\n}\n"],"mappings":";;;AAOA,SAAS,wBAAwB;AACjC,SAAS,qBAAqB;AAiB9B,IAAMA,WAAU,cAAc,YAAY,GAAG;AAStC,SAAS,mBAAmB,YAGjC;AACA,MAAI,CAAC,WAAW,WAAW,YAAY,GAAG;AACxC,UAAM,IAAI;MACR,qDAAqD,WAAW,MAAM,KAAK,EAAE,CAAC,CAAC;IAEjF;EACF;AAGA,QAAM,UAAU,WAAW,QAAQ,iBAAiB,SAAS;AAC7D,MAAI;AACJ,MAAI;AACF,aAAS,IAAI,IAAI,OAAO;EAC1B,QAAQ;AACN,UAAM,IAAI,MAAM,gCAAgC,UAAU,GAAG;EAC/D;AAEA,QAAM,OAAO,OAAO;AACpB,QAAM,OAAO,OAAO,OAAO,SAAS,OAAO,MAAM,EAAE,IAAI;AAEvD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,mCAAmC,UAAU,GAAG;EAClE;AACA,MAAI,OAAO,KAAK,OAAO,SAAS,CAAC,OAAO,SAAS,IAAI,GAAG;AACtD,UAAM,IAAI,MAAM,kDAA6C,OAAO,IAAI,EAAE;EAC5E;AAEA,SAAO,EAAE,MAAM,KAAK;AACtB;AAMO,SAAS,6BACd,YAC4B;AAC5B,qBAAmB,UAAU;AAG7B,QAAM,EAAE,gBAAgB,IACtBA,SAAQ,mBAAmB;AAC7B,QAAM,KAAKA,SAAQ,IAAI;AAMvB,QAAM,QAAQ,IAAI,gBAAgB,YAAY,EAAE,SAAS,KAAQ,CAAC;AASlE,QAAM,KAAK;AACX,QAAM,UAAW,OAAO,OAAO,aAC3B,KACA,OAAO,GAAG,YAAY,aACpB,GAAG,UACH,OAAO,GAAG,cAAc,aACtB,GAAG,YACH;AACR,MAAI,YAAY,MAAM;AACpB,UAAM,IAAI;MACR;IACF;EACF;AAEA,SAAO,CAAC;;IAEN,IAAK,QAAgB,KAAK,EAAE,MAAM,CAAC;;AACvC;AAOO,SAAS,kBAAkB,YAAkC;AAClE,qBAAmB,UAAU;AAG7B,QAAM,EAAE,gBAAgB,IACtBA,SAAQ,mBAAmB;AAC7B,QAAM,OAAOA,SAAQ,WAAW;AAChC,QAAM,QAAQA,SAAQ,YAAY;AAElC,QAAM,QAAQ,IAAI,gBAAgB,UAAU;AAE5C,SAAO,CAAC,OAA+B,SAAuB;AAC5D,UAAM,MACJ,OAAO,UAAU,WACb,QACA,iBAAiB,MACf,MAAM,OACN,MAAM;AACd,UAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,UAAM,UAAU,UAAU,aAAa;AACvC,UAAM,YAAY,UAAU,QAAQ;AAEpC,WAAO,IAAI,QAAkB,CAAC,SAAS,WAAW;AAChD,YAAM,SAAS,MAAM,UAAU;AAC/B,YAAM,UAAU,MAAM,UAClB,OAAO;QACL,KAAK,mBAAmB,UACpB,KAAK,QAAQ,QAAQ,IACrB,MAAM,QAAQ,KAAK,OAAO,IACxB,KAAK,UACL,OAAO,QAAQ,KAAK,OAAO;MACnC,IACA,CAAC;AAEL,YAAM,MAAM,UAAU;QACpB;QACA,EAAE,QAAQ,SAAS,OAAO,SAAS,IAAO;QAC1C,CAAC,QAAQ;AACP,gBAAM,SAAmB,CAAC;AAC1B,cAAI,GAAG,QAAQ,CAAC,UAAkB,OAAO,KAAK,KAAK,CAAC;AACpD,cAAI,GAAG,OAAO,MAAM;AAClB,kBAAM,OAAO,OAAO,OAAO,MAAM;AACjC,kBAAM,kBAAkB,IAAI,QAAQ;AACpC,uBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AACpD,kBAAI;AACF,gCAAgB;kBACd;kBACA,MAAM,QAAQ,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI;gBACxC;YACJ;AACA;cACE,IAAI,SAAS,MAAM;gBACjB,QAAQ,IAAI,cAAc;gBAC1B,YAAY,IAAI,iBAAiB;gBACjC,SAAS;cACX,CAAC;YACH;UACF,CAAC;QACH;MACF;AAEA,UAAI,GAAG,SAAS,MAAM;AACtB,UAAI,GAAG,WAAW,MAAM;AACtB,YAAI,QAAQ;AACZ,eAAO,IAAI,MAAM,gCAAgC,CAAC;MACpD,CAAC;AAED,UAAI,MAAM,QAAQ;AAChB,aAAK,OAAO,iBAAiB,SAAS,MAAM;AAC1C,cAAI,QAAQ;AACZ,iBAAO,IAAI,MAAM,SAAS,CAAC;QAC7B,CAAC;MACH;AAEA,UAAI,MAAM,MAAM;AACd,YAAI,MAAM,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAK,IAAI;MACjE;AACA,UAAI,IAAI;IACV,CAAC;EACH;AACF;AASA,eAAsB,iBACpB,YACA,YAAY,KACG;AACf,QAAM,EAAE,MAAM,KAAK,IAAI,mBAAmB,UAAU;AAEpD,SAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,UAAM,SAAS,iBAAiB,EAAE,MAAM,KAAK,GAAG,MAAM;AACpD,aAAO,QAAQ;AACf,cAAQ;IACV,CAAC;AAED,WAAO,WAAW,WAAW,MAAM;AACjC,aAAO,QAAQ;AACf;QACE,IAAI;UACF,mBAAmB,IAAI,IAAI,IAAI,yBAAyB,SAAS;QAEnE;MACF;IACF,CAAC;AAED,WAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,aAAO,QAAQ;AACf;QACE,IAAI;UACF,mBAAmB,IAAI,IAAI,IAAI,iBAAiB,IAAI,OAAO;QAE7D;MACF;IACF,CAAC;EACH,CAAC;AACH;","names":["require"]}
|
|
1
|
+
{"version":3,"sources":["../../client/src/transport/socks5.ts"],"sourcesContent":["/**\n * SOCKS5 transport helpers for Node.js environments.\n *\n * This module is dynamically imported only when `transport.type === 'socks5'`\n * is configured, keeping `ws` and `socks-proxy-agent` out of browser bundles.\n */\n\nimport { createConnection } from 'node:net';\nimport { createRequire } from 'node:module';\nimport type SocksProxyAgentModule from 'socks-proxy-agent';\nimport type WSModule from 'ws';\nimport type httpModule from 'node:http';\nimport type httpsModule from 'node:https';\n\n// ESM-safe require. This module builds as ESM (tsup `format: ['esm']`) with\n// `socks-proxy-agent`/`ws` external, so a bare `require(...)` would be rewritten\n// by esbuild into a `__require` shim that throws\n// `Dynamic require of \"socks-proxy-agent\" is not supported` for any pure-ESM\n// consumer — breaking the SOCKS5/ATOR transport entirely (the npm-consumer\n// toon-client image surfaced this). Building a real require off `import.meta.url`\n// (the same pattern as docker/esbuild.config.mjs's banner) keeps the\n// synchronous, browser-guarded `require(...)` calls below working in the\n// published ESM bundle while leaving the deps external. Browser bundlers never\n// reach this code: the module is dynamically imported only when\n// `transport.type === 'socks5'`, which is Node-only.\nconst require = createRequire(import.meta.url);\n\n/**\n * Parses and validates a `socks5h://` URL.\n * Enforces `socks5h://` scheme (not `socks5://`) to prevent DNS leaks —\n * `.anyone` hostnames must be resolved by the proxy, not locally.\n *\n * Mirrors the connector's `transport/socks-url.ts` validation logic.\n */\nexport function validateSocks5hUrl(socksProxy: string): {\n host: string;\n port: number;\n} {\n if (!socksProxy.startsWith('socks5h://')) {\n throw new Error(\n `SOCKS5 proxy URL must use socks5h:// scheme (got \"${socksProxy.split('://')[0]}://\"). ` +\n 'The \"h\" suffix ensures DNS resolution happens at the proxy, preventing leaks of .anyone hostnames.'\n );\n }\n\n // Parse by converting to http:// for URL constructor compatibility\n const httpUrl = socksProxy.replace(/^socks5h:\\/\\//, 'http://');\n let parsed: URL;\n try {\n parsed = new URL(httpUrl);\n } catch {\n throw new Error(`Malformed SOCKS5 proxy URL: \"${socksProxy}\"`);\n }\n\n const host = parsed.hostname;\n const port = parsed.port ? parseInt(parsed.port, 10) : 1080;\n\n if (!host) {\n throw new Error(`SOCKS5 proxy URL missing host: \"${socksProxy}\"`);\n }\n if (port < 0 || port > 65535 || !Number.isFinite(port)) {\n throw new Error(`SOCKS5 proxy port out of range (0–65535): ${parsed.port}`);\n }\n\n return { host, port };\n}\n\n/**\n * Creates a WebSocket factory that routes connections through a SOCKS5 proxy.\n * Uses the `ws` npm package (Node.js only) which accepts an `agent` option.\n */\nexport function createSocks5WebSocketFactory(\n socksProxy: string\n): (url: string) => WebSocket {\n validateSocks5hUrl(socksProxy);\n\n // Resolved via the module-scoped ESM-safe `require` (createRequire) above.\n const { SocksProxyAgent } =\n require('socks-proxy-agent') as typeof SocksProxyAgentModule;\n const WS = require('ws') as typeof WSModule;\n\n // 120s timeout: the socks library's default is 30s, which is too short for\n // the ATOR network to build circuits to fresh hidden services from certain\n // network paths (e.g., Akash datacenter → public ATOR proxy → local HS).\n // 120s gives the proxy time to find a working introduction-point circuit.\n const agent = new SocksProxyAgent(socksProxy, { timeout: 120_000 });\n\n // CJS/ESM interop: `require('ws')` can return any of three shapes depending on\n // the bundler/loader: the class directly (pure CJS); `{ default: WSClass, ... }`\n // (esModuleInterop=true / synthetic default); or `{ WebSocket: WSClass, ... }`\n // (named export, no default). Walk the ladder so this factory works in all\n // three environments. Pass 2 code review 2026-05-18: previous `(WS as any).default ?? WS`\n // would accept a namespace object as a \"constructor\" and throw cryptically.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ws = WS as any;\n const WSClass = (typeof ws === 'function'\n ? ws\n : typeof ws.default === 'function'\n ? ws.default\n : typeof ws.WebSocket === 'function'\n ? ws.WebSocket\n : null) as unknown as typeof WSModule.prototype.constructor;\n if (WSClass === null) {\n throw new Error(\n \"createSocks5WebSocketFactory: require('ws') did not yield a constructor on .default, .WebSocket, or the module root.\"\n );\n }\n\n return (url: string) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (WSClass as any)(url, { agent }) as unknown as WebSocket;\n}\n\n/**\n * Creates a fetch wrapper that routes HTTP requests through a SOCKS5 proxy.\n * Uses `socks-proxy-agent` with Node.js `http`/`https` modules (not native\n * fetch, which uses undici and doesn't support SocksProxyAgent's dispatcher).\n */\nexport function createSocks5Fetch(socksProxy: string): typeof fetch {\n validateSocks5hUrl(socksProxy);\n\n // Resolved via the module-scoped ESM-safe `require` (createRequire) above.\n const { SocksProxyAgent } =\n require('socks-proxy-agent') as typeof SocksProxyAgentModule;\n const http = require('node:http') as typeof httpModule;\n const https = require('node:https') as typeof httpsModule;\n\n const agent = new SocksProxyAgent(socksProxy);\n\n return (input: string | URL | Request, init?: RequestInit) => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url;\n const parsedUrl = new URL(url);\n const isHttps = parsedUrl.protocol === 'https:';\n const transport = isHttps ? https : http;\n\n return new Promise<Response>((resolve, reject) => {\n const method = init?.method ?? 'GET';\n const headers = init?.headers\n ? Object.fromEntries(\n init.headers instanceof Headers\n ? init.headers.entries()\n : Array.isArray(init.headers)\n ? init.headers\n : Object.entries(init.headers)\n )\n : {};\n\n const req = transport.request(\n url,\n { method, headers, agent, timeout: 30_000 },\n (res) => {\n const chunks: Buffer[] = [];\n res.on('data', (chunk: Buffer) => chunks.push(chunk));\n res.on('end', () => {\n const body = Buffer.concat(chunks);\n const responseHeaders = new Headers();\n for (const [key, val] of Object.entries(res.headers)) {\n if (val)\n responseHeaders.set(\n key,\n Array.isArray(val) ? val.join(', ') : val\n );\n }\n resolve(\n new Response(body, {\n status: res.statusCode ?? 200,\n statusText: res.statusMessage ?? '',\n headers: responseHeaders,\n })\n );\n });\n }\n );\n\n req.on('error', reject);\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('SOCKS5 proxied request timeout'));\n });\n\n if (init?.signal) {\n init.signal.addEventListener('abort', () => {\n req.destroy();\n reject(new Error('Aborted'));\n });\n }\n\n if (init?.body) {\n req.write(typeof init.body === 'string' ? init.body : init.body);\n }\n req.end();\n });\n };\n}\n\n/**\n * Probes SOCKS5 proxy reachability with a TCP connection test.\n * Fail-closed: throws if the proxy is unreachable within the timeout.\n *\n * @param socksProxy - `socks5h://host:port` URL\n * @param timeoutMs - Connection timeout in milliseconds (default: 2000)\n */\nexport async function probeSocks5Proxy(\n socksProxy: string,\n timeoutMs = 2000\n): Promise<void> {\n const { host, port } = validateSocks5hUrl(socksProxy);\n\n return new Promise<void>((resolve, reject) => {\n const socket = createConnection({ host, port }, () => {\n socket.destroy();\n resolve();\n });\n\n socket.setTimeout(timeoutMs, () => {\n socket.destroy();\n reject(\n new Error(\n `SOCKS5 proxy at ${host}:${port} unreachable (timeout ${timeoutMs}ms). ` +\n 'Refusing to start without privacy transport (fail-closed).'\n )\n );\n });\n\n socket.on('error', (err) => {\n socket.destroy();\n reject(\n new Error(\n `SOCKS5 proxy at ${host}:${port} unreachable: ${err.message}. ` +\n 'Refusing to start without privacy transport (fail-closed).'\n )\n );\n });\n });\n}\n"],"mappings":"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","names":["require"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toon-protocol/client-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.1",
|
|
4
4
|
"description": "Always-on local daemon + MCP server letting a Claude agent (Desktop or Code) act as a TOON Protocol client: pay-to-write publishing, free reads, channel/balance management, and mill swaps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jonathan Green",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"typescript": "^5.3.0",
|
|
46
46
|
"vitest": "^1.0.0",
|
|
47
47
|
"@toon-protocol/client": "0.9.1",
|
|
48
|
+
"@toon-protocol/sdk": "0.5.0",
|
|
48
49
|
"@toon-protocol/core": "1.4.1"
|
|
49
50
|
},
|
|
50
51
|
"engines": {
|