@toon-protocol/client-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +302 -0
  2. package/dist/anon-proxy-W3KMM7GU-FN7ZJY7P.js +25 -0
  3. package/dist/anon-proxy-W3KMM7GU-FN7ZJY7P.js.map +1 -0
  4. package/dist/chunk-32QD72IL.js +83 -0
  5. package/dist/chunk-32QD72IL.js.map +1 -0
  6. package/dist/chunk-3NAWISI5.js +2245 -0
  7. package/dist/chunk-3NAWISI5.js.map +1 -0
  8. package/dist/chunk-5KFXUT5Q.js +11321 -0
  9. package/dist/chunk-5KFXUT5Q.js.map +1 -0
  10. package/dist/chunk-F22GNSF6.js +12 -0
  11. package/dist/chunk-F22GNSF6.js.map +1 -0
  12. package/dist/chunk-FSS45ZX3.js +2633 -0
  13. package/dist/chunk-FSS45ZX3.js.map +1 -0
  14. package/dist/chunk-LR7W2ISE.js +657 -0
  15. package/dist/chunk-LR7W2ISE.js.map +1 -0
  16. package/dist/chunk-SKQTKZIH.js +278 -0
  17. package/dist/chunk-SKQTKZIH.js.map +1 -0
  18. package/dist/chunk-VA7XC4FD.js +185 -0
  19. package/dist/chunk-VA7XC4FD.js.map +1 -0
  20. package/dist/chunk-ZQKYZJWT.js +359 -0
  21. package/dist/chunk-ZQKYZJWT.js.map +1 -0
  22. package/dist/daemon.d.ts +1 -0
  23. package/dist/daemon.js +141 -0
  24. package/dist/daemon.js.map +1 -0
  25. package/dist/ed25519-2QVPINLS.js +27 -0
  26. package/dist/ed25519-2QVPINLS.js.map +1 -0
  27. package/dist/gateway-QOK47RKS-SEGTXBR3.js +16 -0
  28. package/dist/gateway-QOK47RKS-SEGTXBR3.js.map +1 -0
  29. package/dist/hmac-26UC6YKX.js +12 -0
  30. package/dist/hmac-26UC6YKX.js.map +1 -0
  31. package/dist/index.d.ts +965 -0
  32. package/dist/index.js +68 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/mcp.d.ts +1 -0
  35. package/dist/mcp.js +81 -0
  36. package/dist/mcp.js.map +1 -0
  37. package/dist/sha512-WYC446ZM.js +34 -0
  38. package/dist/sha512-WYC446ZM.js.map +1 -0
  39. package/dist/socks5-WTJBYGME-6COK4LXW.js +139 -0
  40. package/dist/socks5-WTJBYGME-6COK4LXW.js.map +1 -0
  41. package/package.json +60 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/cryptoNode.ts","../../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/utils.ts"],"sourcesContent":["/**\n * Internal webcrypto alias.\n * We prefer WebCrypto aka globalThis.crypto, which exists in node.js 16+.\n * Falls back to Node.js built-in crypto for Node.js <=v14.\n * See utils.ts for details.\n * @module\n */\n// @ts-ignore\nimport * as nc from 'node:crypto';\nexport const crypto: any =\n nc && typeof nc === 'object' && 'webcrypto' in nc\n ? (nc.webcrypto as any)\n : nc && typeof nc === 'object' && 'randomBytes' in nc\n ? nc\n : undefined;\n","/**\n * Utilities for hex, bytes, CSPRNG.\n * @module\n */\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n\n// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.\n// node.js versions earlier than v19 don't declare it in global scope.\n// For node.js, package.json#exports field mapping rewrites import\n// from `crypto` to `cryptoNode`, which imports native module.\n// Makes the utils un-importable in browsers without a bundler.\n// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.\nimport { crypto } from '@noble/hashes/crypto';\n\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nexport function isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\n/** Asserts something is positive integer. */\nexport function anumber(n: number): void {\n if (!Number.isSafeInteger(n) || n < 0) throw new Error('positive integer expected, got ' + n);\n}\n\n/** Asserts something is Uint8Array. */\nexport function abytes(b: Uint8Array | undefined, ...lengths: number[]): void {\n if (!isBytes(b)) throw new Error('Uint8Array expected');\n if (lengths.length > 0 && !lengths.includes(b.length))\n throw new Error('Uint8Array expected of length ' + lengths + ', got length=' + b.length);\n}\n\n/** Asserts something is hash */\nexport function ahash(h: IHash): void {\n if (typeof h !== 'function' || typeof h.create !== 'function')\n throw new Error('Hash should be wrapped by utils.createHasher');\n anumber(h.outputLen);\n anumber(h.blockLen);\n}\n\n/** Asserts a hash instance has not been destroyed / finished */\nexport function aexists(instance: any, checkFinished = true): void {\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\n}\n\n/** Asserts output is properly-sized byte array */\nexport function aoutput(out: any, instance: any): void {\n abytes(out);\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error('digestInto() expects output buffer of length at least ' + min);\n }\n}\n\n/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */\n// prettier-ignore\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\n Uint16Array | Int16Array | Uint32Array | Int32Array;\n\n/** Cast u8 / u16 / u32 to u8. */\nexport function u8(arr: TypedArray): Uint8Array {\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** Cast u8 / u16 / u32 to u32. */\nexport function u32(arr: TypedArray): Uint32Array {\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\n}\n\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\nexport function clean(...arrays: TypedArray[]): void {\n for (let i = 0; i < arrays.length; i++) {\n arrays[i].fill(0);\n }\n}\n\n/** Create DataView of an array for easy byte-level manipulation. */\nexport function createView(arr: TypedArray): DataView {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** The rotate right (circular right shift) operation for uint32 */\nexport function rotr(word: number, shift: number): number {\n return (word << (32 - shift)) | (word >>> shift);\n}\n\n/** The rotate left (circular left shift) operation for uint32 */\nexport function rotl(word: number, shift: number): number {\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\n}\n\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\nexport const isLE: boolean = /* @__PURE__ */ (() =>\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\n\n/** The byte swap operation for uint32 */\nexport function byteSwap(word: number): number {\n return (\n ((word << 24) & 0xff000000) |\n ((word << 8) & 0xff0000) |\n ((word >>> 8) & 0xff00) |\n ((word >>> 24) & 0xff)\n );\n}\n/** Conditionally byte swap if on a big-endian platform */\nexport const swap8IfBE: (n: number) => number = isLE\n ? (n: number) => n\n : (n: number) => byteSwap(n);\n\n/** @deprecated */\nexport const byteSwapIfBE: typeof swap8IfBE = swap8IfBE;\n/** In place byte swap for Uint32Array */\nexport function byteSwap32(arr: Uint32Array): Uint32Array {\n for (let i = 0; i < arr.length; i++) {\n arr[i] = byteSwap(arr[i]);\n }\n return arr;\n}\n\nexport const swap32IfBE: (u: Uint32Array) => Uint32Array = isLE\n ? (u: Uint32Array) => u\n : byteSwap32;\n\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\nconst hasHexBuiltin: boolean = /* @__PURE__ */ (() =>\n // @ts-ignore\n typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();\n\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n\n/**\n * Convert byte array to hex string. Uses built-in function, when available.\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n abytes(bytes);\n // @ts-ignore\n if (hasHexBuiltin) return bytes.toHex();\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\n\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\nfunction asciiToBase16(ch: number): number | undefined {\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n return;\n}\n\n/**\n * Convert hex string to byte array. Uses built-in function, when available.\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n // @ts-ignore\n if (hasHexBuiltin) return Uint8Array.fromHex(hex);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\n const array = new Uint8Array(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n const n1 = asciiToBase16(hex.charCodeAt(hi));\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n if (n1 === undefined || n2 === undefined) {\n const char = hex[hi] + hex[hi + 1];\n throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' + hi);\n }\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n }\n return array;\n}\n\n/**\n * There is no setImmediate in browser and setTimeout is slow.\n * Call of async fn will return Promise, which will be fullfiled only on\n * next scheduler queue processing step and this is exactly what we need.\n */\nexport const nextTick = async (): Promise<void> => {};\n\n/** Returns control to thread each 'tick' ms to avoid blocking. */\nexport async function asyncLoop(\n iters: number,\n tick: number,\n cb: (i: number) => void\n): Promise<void> {\n let ts = Date.now();\n for (let i = 0; i < iters; i++) {\n cb(i);\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\n const diff = Date.now() - ts;\n if (diff >= 0 && diff < tick) continue;\n await nextTick();\n ts += diff;\n }\n}\n\n// Global symbols, but ts doesn't see them: https://github.com/microsoft/TypeScript/issues/31535\ndeclare const TextEncoder: any;\ndeclare const TextDecoder: any;\n\n/**\n * Converts string to bytes using UTF8 encoding.\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\n */\nexport function utf8ToBytes(str: string): Uint8Array {\n if (typeof str !== 'string') throw new Error('string expected');\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n\n/**\n * Converts bytes to string using UTF8 encoding.\n * @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'\n */\nexport function bytesToUtf8(bytes: Uint8Array): string {\n return new TextDecoder().decode(bytes);\n}\n\n/** Accepted input of hash functions. Strings are converted to byte arrays. */\nexport type Input = string | Uint8Array;\n/**\n * Normalizes (non-hex) string or Uint8Array to Uint8Array.\n * Warning: when Uint8Array is passed, it would NOT get copied.\n * Keep in mind for future mutable operations.\n */\nexport function toBytes(data: Input): Uint8Array {\n if (typeof data === 'string') data = utf8ToBytes(data);\n abytes(data);\n return data;\n}\n\n/** KDFs can accept string or Uint8Array for user convenience. */\nexport type KDFInput = string | Uint8Array;\n/**\n * Helper for KDFs: consumes uint8array or string.\n * When string is passed, does utf8 decoding, using TextDecoder.\n */\nexport function kdfInputToBytes(data: KDFInput): Uint8Array {\n if (typeof data === 'string') data = utf8ToBytes(data);\n abytes(data);\n return data;\n}\n\n/** Copies several Uint8Arrays into one. */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n let sum = 0;\n for (let i = 0; i < arrays.length; i++) {\n const a = arrays[i];\n abytes(a);\n sum += a.length;\n }\n const res = new Uint8Array(sum);\n for (let i = 0, pad = 0; i < arrays.length; i++) {\n const a = arrays[i];\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n}\n\ntype EmptyObj = {};\nexport function checkOpts<T1 extends EmptyObj, T2 extends EmptyObj>(\n defaults: T1,\n opts?: T2\n): T1 & T2 {\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\n throw new Error('options should be object or undefined');\n const merged = Object.assign(defaults, opts);\n return merged as T1 & T2;\n}\n\n/** Hash interface. */\nexport type IHash = {\n (data: Uint8Array): Uint8Array;\n blockLen: number;\n outputLen: number;\n create: any;\n};\n\n/** For runtime check if class implements interface */\nexport abstract class Hash<T extends Hash<T>> {\n abstract blockLen: number; // Bytes per block\n abstract outputLen: number; // Bytes in output\n abstract update(buf: Input): this;\n // Writes digest into buf\n abstract digestInto(buf: Uint8Array): void;\n abstract digest(): Uint8Array;\n /**\n * Resets internal state. Makes Hash instance unusable.\n * Reset is impossible for keyed hashes if key is consumed into state. If digest is not consumed\n * by user, they will need to manually call `destroy()` when zeroing is necessary.\n */\n abstract destroy(): void;\n /**\n * Clones hash instance. Unsafe: doesn't check whether `to` is valid. Can be used as `clone()`\n * when no options are passed.\n * Reasons to use `_cloneInto` instead of clone: 1) performance 2) reuse instance => all internal\n * buffers are overwritten => causes buffer overwrite which is used for digest in some cases.\n * There are no guarantees for clean-up because it's impossible in JS.\n */\n abstract _cloneInto(to?: T): T;\n // Safe version that clones internal state\n abstract clone(): T;\n}\n\n/**\n * XOF: streaming API to read digest in chunks.\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\n * destroy state, next call can require more bytes.\n */\nexport type HashXOF<T extends Hash<T>> = Hash<T> & {\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\n};\n\n/** Hash function */\nexport type CHash = ReturnType<typeof createHasher>;\n/** Hash function with output */\nexport type CHashO = ReturnType<typeof createOptHasher>;\n/** XOF with output */\nexport type CHashXO = ReturnType<typeof createXOFer>;\n\n/** Wraps hash function, creating an interface on top of it */\nexport function createHasher<T extends Hash<T>>(\n hashCons: () => Hash<T>\n): {\n (msg: Input): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(): Hash<T>;\n} {\n const hashC = (msg: Input): Uint8Array => hashCons().update(toBytes(msg)).digest();\n const tmp = hashCons();\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = () => hashCons();\n return hashC;\n}\n\nexport function createOptHasher<H extends Hash<H>, T extends Object>(\n hashCons: (opts?: T) => Hash<H>\n): {\n (msg: Input, opts?: T): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(opts?: T): Hash<H>;\n} {\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\n const tmp = hashCons({} as T);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts?: T) => hashCons(opts);\n return hashC;\n}\n\nexport function createXOFer<H extends HashXOF<H>, T extends Object>(\n hashCons: (opts?: T) => HashXOF<H>\n): {\n (msg: Input, opts?: T): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(opts?: T): HashXOF<H>;\n} {\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\n const tmp = hashCons({} as T);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts?: T) => hashCons(opts);\n return hashC;\n}\nexport const wrapConstructor: typeof createHasher = createHasher;\nexport const wrapConstructorWithOpts: typeof createOptHasher = createOptHasher;\nexport const wrapXOFConstructorWithOpts: typeof createXOFer = createXOFer;\n\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\nexport function randomBytes(bytesLength = 32): Uint8Array {\n if (crypto && typeof crypto.getRandomValues === 'function') {\n return crypto.getRandomValues(new Uint8Array(bytesLength));\n }\n // Legacy Node.js compatibility\n if (crypto && typeof crypto.randomBytes === 'function') {\n return Uint8Array.from(crypto.randomBytes(bytesLength));\n }\n throw new Error('crypto.getRandomValues must be defined');\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,359 @@
1
+ import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
2
+ import {
3
+ ControlApiError,
4
+ DaemonUnreachableError
5
+ } from "./chunk-5KFXUT5Q.js";
6
+
7
+ // src/mcp-tools.ts
8
+ var TOOL_DEFINITIONS = [
9
+ {
10
+ name: "toon_status",
11
+ description: "Report TOON client daemon health: bootstrapping/ready state, transport, relay connection, buffered-event count, and per-chain settlement status.",
12
+ inputSchema: {
13
+ type: "object",
14
+ properties: {},
15
+ additionalProperties: false
16
+ }
17
+ },
18
+ {
19
+ name: "toon_identity",
20
+ description: "Return this client's public identity (Nostr pubkey + EVM/Solana/Mina addresses). Never returns private keys.",
21
+ inputSchema: {
22
+ type: "object",
23
+ properties: {},
24
+ additionalProperties: false
25
+ }
26
+ },
27
+ {
28
+ name: "toon_publish",
29
+ description: "Pay-to-write: publish a fully-signed Nostr event to the TOON network. Signs an off-chain payment-channel claim and forwards it over BTP. Returns the event id, channel id, and the advanced channel nonce.",
30
+ inputSchema: {
31
+ type: "object",
32
+ properties: {
33
+ event: {
34
+ type: "object",
35
+ description: "A fully-signed Nostr event (must include id, pubkey, sig, kind, created_at, tags, content)."
36
+ },
37
+ destination: {
38
+ type: "string",
39
+ description: "Optional ILP destination override (default: the apex/town)."
40
+ },
41
+ fee: {
42
+ type: "string",
43
+ description: "Optional fee override in base units (default: daemon config)."
44
+ },
45
+ btpUrl: {
46
+ type: "string",
47
+ description: "Which apex (BTP write target) to publish through (default: the config-seeded apex). Use toon_targets to list registered apexes. Writes always go through BTP \u2014 never a relay directly."
48
+ }
49
+ },
50
+ required: ["event"],
51
+ additionalProperties: false
52
+ }
53
+ },
54
+ {
55
+ name: "toon_subscribe",
56
+ description: "Free read: register a persistent town-relay subscription with NIP-01 filter(s). Returns a subscription id to drain with toon_read.",
57
+ inputSchema: {
58
+ type: "object",
59
+ properties: {
60
+ filters: {
61
+ description: "A NIP-01 filter object or an array of OR-ed filters."
62
+ },
63
+ subId: { type: "string", description: "Optional caller-supplied id." },
64
+ relayUrl: {
65
+ type: "string",
66
+ description: "Restrict to one relay. Omit to FAN OUT across every registered relay (reads merge into one ordered stream)."
67
+ }
68
+ },
69
+ required: ["filters"],
70
+ additionalProperties: false
71
+ }
72
+ },
73
+ {
74
+ name: "toon_read",
75
+ description: "Free read: drain buffered events newer than a cursor. Pass back the returned cursor to fetch only events received since the last read.",
76
+ inputSchema: {
77
+ type: "object",
78
+ properties: {
79
+ subId: { type: "string", description: "Restrict to one subscription." },
80
+ cursor: {
81
+ type: "number",
82
+ description: "Cursor from a prior toon_read."
83
+ },
84
+ limit: {
85
+ type: "number",
86
+ description: "Max events to return (default 200)."
87
+ },
88
+ relayUrl: {
89
+ type: "string",
90
+ description: "Restrict the drain to events from a single relay."
91
+ }
92
+ },
93
+ additionalProperties: false
94
+ }
95
+ },
96
+ {
97
+ name: "toon_open_channel",
98
+ description: "Open (or return the existing) payment channel for a destination. Channels open lazily on first publish; use this to pre-open.",
99
+ inputSchema: {
100
+ type: "object",
101
+ properties: {
102
+ destination: {
103
+ type: "string",
104
+ description: "ILP destination (default: apex)."
105
+ }
106
+ },
107
+ additionalProperties: false
108
+ }
109
+ },
110
+ {
111
+ name: "toon_channels",
112
+ description: "List tracked payment channels with their nonce watermark and cumulative transferred amount.",
113
+ inputSchema: {
114
+ type: "object",
115
+ properties: {},
116
+ additionalProperties: false
117
+ }
118
+ },
119
+ {
120
+ name: "toon_swap",
121
+ description: "Pay a mill peer (asset A) to receive asset B plus a signed target-chain claim. Builds the NIP-59 gift-wrapped kind:20032 swap rumor and streams it; the source-asset claim is signed against the open apex channel (the mill must be routed via apexChildPeers). Returns the accumulated, decrypted target-chain claim(s) and settlement metadata.",
122
+ inputSchema: {
123
+ type: "object",
124
+ properties: {
125
+ destination: {
126
+ type: "string",
127
+ description: "Mill peer ILP destination (e.g. g.townhouse.mill)."
128
+ },
129
+ amount: {
130
+ type: "string",
131
+ description: "Total source-asset amount to swap, source micro-units."
132
+ },
133
+ millPubkey: {
134
+ type: "string",
135
+ description: "Mill's 64-char lowercase hex Nostr pubkey (gift-wrap recipient)."
136
+ },
137
+ pair: {
138
+ type: "object",
139
+ description: "The swap pair (from kind:10032 discovery or operator-supplied): { from:{assetCode,assetScale,chain}, to:{...}, rate, minAmount?, maxAmount? }."
140
+ },
141
+ chainRecipient: {
142
+ type: "string",
143
+ description: "Sender's payout address on pair.to.chain (EVM 0x-hex / Solana / Mina base58)."
144
+ },
145
+ packetCount: {
146
+ type: "number",
147
+ description: "Split the swap into N equal packets (default 1)."
148
+ }
149
+ },
150
+ required: [
151
+ "destination",
152
+ "amount",
153
+ "millPubkey",
154
+ "pair",
155
+ "chainRecipient"
156
+ ],
157
+ additionalProperties: false
158
+ }
159
+ },
160
+ {
161
+ name: "toon_targets",
162
+ description: "List every registered target: relays (read sources, with connection + buffered-event status) and apexes (BTP write targets, with ready/channel status). The TOON client is 1-to-many \u2014 many apexes to write through, many relays to read from.",
163
+ inputSchema: {
164
+ type: "object",
165
+ properties: {},
166
+ additionalProperties: false
167
+ }
168
+ },
169
+ {
170
+ name: "toon_add_relay",
171
+ description: "Add a relay READ target at runtime (persisted across restarts). It joins all fan-out reads immediately; `.anyone` hidden-service relays reuse the managed anon read proxy automatically.",
172
+ inputSchema: {
173
+ type: "object",
174
+ properties: {
175
+ relayUrl: {
176
+ type: "string",
177
+ description: "Relay WS URL (ws://host:7100 or a .anyone service)."
178
+ }
179
+ },
180
+ required: ["relayUrl"],
181
+ additionalProperties: false
182
+ }
183
+ },
184
+ {
185
+ name: "toon_remove_relay",
186
+ description: "Remove a relay read target (persisted). The config-seeded default relay cannot be removed.",
187
+ inputSchema: {
188
+ type: "object",
189
+ properties: {
190
+ relayUrl: { type: "string", description: "Relay WS URL to remove." }
191
+ },
192
+ required: ["relayUrl"],
193
+ additionalProperties: false
194
+ }
195
+ },
196
+ {
197
+ name: "toon_add_apex",
198
+ description: "Add an apex WRITE target at runtime (persisted across restarts). Settlement params are DISCOVERED by reading the apex\u2019s kind:10032 announcement off the given relay \u2014 you do not supply chain/settlement details. The relay is added as a read target first if unknown.",
199
+ inputSchema: {
200
+ type: "object",
201
+ properties: {
202
+ ilpAddress: {
203
+ type: "string",
204
+ description: "ILP address of the apex (e.g. g.townhouse.town)."
205
+ },
206
+ relayUrl: {
207
+ type: "string",
208
+ description: "Relay to discover the apex\u2019s kind:10032 on."
209
+ },
210
+ pubkey: {
211
+ type: "string",
212
+ description: "Optional apex Nostr pubkey (64-char hex) to narrow discovery."
213
+ },
214
+ chain: {
215
+ type: "string",
216
+ enum: ["evm", "solana", "mina"],
217
+ description: "Preferred settlement chain (default: apex\u2019s first)."
218
+ },
219
+ childPeers: {
220
+ type: "array",
221
+ items: { type: "string" },
222
+ description: 'Child peers via this apex\u2019s channel (e.g. ["dvm","mill"]).'
223
+ },
224
+ feePerEvent: {
225
+ type: "string",
226
+ description: "Per-write fee override for this apex (base units)."
227
+ }
228
+ },
229
+ required: ["ilpAddress", "relayUrl"],
230
+ additionalProperties: false
231
+ }
232
+ },
233
+ {
234
+ name: "toon_remove_apex",
235
+ description: "Remove an apex write target by its BTP URL (persisted). The config-seeded default apex cannot be removed.",
236
+ inputSchema: {
237
+ type: "object",
238
+ properties: {
239
+ btpUrl: {
240
+ type: "string",
241
+ description: "BTP URL of the apex to remove (from toon_targets)."
242
+ }
243
+ },
244
+ required: ["btpUrl"],
245
+ additionalProperties: false
246
+ }
247
+ }
248
+ ];
249
+ async function dispatchTool(client, name, args) {
250
+ try {
251
+ switch (name) {
252
+ case "toon_status":
253
+ return ok(await client.status());
254
+ case "toon_identity": {
255
+ const s = await client.status();
256
+ return ok({
257
+ identity: s.identity,
258
+ ready: s.ready,
259
+ bootstrapping: s.bootstrapping
260
+ });
261
+ }
262
+ case "toon_publish":
263
+ return ok(await client.publish(args));
264
+ case "toon_subscribe":
265
+ return ok(
266
+ await client.subscribe({
267
+ filters: args["filters"],
268
+ ...typeof args["subId"] === "string" ? { subId: args["subId"] } : {},
269
+ ...typeof args["relayUrl"] === "string" ? { relayUrl: args["relayUrl"] } : {}
270
+ })
271
+ );
272
+ case "toon_read":
273
+ return ok(
274
+ await client.events({
275
+ ...typeof args["subId"] === "string" ? { subId: args["subId"] } : {},
276
+ ...typeof args["cursor"] === "number" ? { cursor: args["cursor"] } : {},
277
+ ...typeof args["limit"] === "number" ? { limit: args["limit"] } : {},
278
+ ...typeof args["relayUrl"] === "string" ? { relayUrl: args["relayUrl"] } : {}
279
+ })
280
+ );
281
+ case "toon_open_channel":
282
+ return ok(
283
+ await client.openChannel(
284
+ typeof args["destination"] === "string" ? { destination: args["destination"] } : {}
285
+ )
286
+ );
287
+ case "toon_channels":
288
+ return ok(await client.channels());
289
+ case "toon_swap":
290
+ return ok(
291
+ await client.swap({
292
+ destination: String(args["destination"]),
293
+ amount: String(args["amount"]),
294
+ millPubkey: String(args["millPubkey"]),
295
+ pair: args["pair"],
296
+ chainRecipient: String(args["chainRecipient"]),
297
+ ...typeof args["packetCount"] === "number" ? { packetCount: args["packetCount"] } : {}
298
+ })
299
+ );
300
+ case "toon_targets":
301
+ return ok(await client.targets());
302
+ case "toon_add_relay":
303
+ return ok(
304
+ await client.addRelay({ relayUrl: String(args["relayUrl"]) })
305
+ );
306
+ case "toon_remove_relay":
307
+ return ok(
308
+ await client.removeRelay({ relayUrl: String(args["relayUrl"]) })
309
+ );
310
+ case "toon_add_apex": {
311
+ const req = {
312
+ ilpAddress: String(args["ilpAddress"]),
313
+ relayUrl: String(args["relayUrl"]),
314
+ ...typeof args["pubkey"] === "string" ? { pubkey: args["pubkey"] } : {},
315
+ ...typeof args["chain"] === "string" ? { chain: args["chain"] } : {},
316
+ ...Array.isArray(args["childPeers"]) ? { childPeers: args["childPeers"].map(String) } : {},
317
+ ...typeof args["feePerEvent"] === "string" ? { feePerEvent: args["feePerEvent"] } : {}
318
+ };
319
+ return ok(await client.addApex(req));
320
+ }
321
+ case "toon_remove_apex":
322
+ return ok(await client.removeApex({ btpUrl: String(args["btpUrl"]) }));
323
+ default:
324
+ return err(`Unknown tool: ${name}`);
325
+ }
326
+ } catch (e) {
327
+ if (e instanceof ControlApiError && e.status === 504) {
328
+ return err(
329
+ `${e.detail ?? e.message} \u2014 retry once the relay is reachable and the apex is online.`
330
+ );
331
+ }
332
+ if (e instanceof ControlApiError && e.retryable) {
333
+ return err(
334
+ `TOON client is still bootstrapping (the anon proxy / BTP session can take 30\u201390s) \u2014 retry shortly. (${e.message})`
335
+ );
336
+ }
337
+ if (e instanceof DaemonUnreachableError) {
338
+ return err(
339
+ `TOON client daemon is not reachable at ${e.baseUrl}. It may have failed to start \u2014 check ~/.toon-client/daemon.log.`
340
+ );
341
+ }
342
+ if (e instanceof ControlApiError) {
343
+ return err(`${e.message}${e.detail ? `: ${e.detail}` : ""}`);
344
+ }
345
+ return err(e instanceof Error ? e.message : String(e));
346
+ }
347
+ }
348
+ function ok(data) {
349
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
350
+ }
351
+ function err(message) {
352
+ return { content: [{ type: "text", text: message }], isError: true };
353
+ }
354
+
355
+ export {
356
+ TOOL_DEFINITIONS,
357
+ dispatchTool
358
+ };
359
+ //# sourceMappingURL=chunk-ZQKYZJWT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp-tools.ts"],"sourcesContent":["/**\n * MCP tool definitions + dispatch. The MCP server is a thin proxy: each tool\n * maps to a `toon-clientd` control-plane call. This module is the testable core\n * (no stdio / SDK transport) so the tool→HTTP mapping and the\n * \"bootstrapping — retry\" handling can be unit-tested directly.\n */\n\nimport { ControlApiError, DaemonUnreachableError } from './control-client.js';\nimport type { ControlClient } from './control-client.js';\nimport type {\n AddApexRequest,\n NostrFilter,\n PublishRequest,\n SettlementChain,\n SwapRequest,\n} from './control-api.js';\n\n/** A JSON-Schema-described MCP tool. */\nexport interface ToolDefinition {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\n/** MCP tool-call result shape (subset of the SDK's CallToolResult). */\nexport interface ToolResult {\n content: { type: 'text'; text: string }[];\n isError?: boolean;\n}\n\nexport const TOOL_DEFINITIONS: ToolDefinition[] = [\n {\n name: 'toon_status',\n description:\n 'Report TOON client daemon health: bootstrapping/ready state, transport, ' +\n 'relay connection, buffered-event count, and per-chain settlement status.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_identity',\n description:\n \"Return this client's public identity (Nostr pubkey + EVM/Solana/Mina \" +\n 'addresses). Never returns private keys.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_publish',\n description:\n 'Pay-to-write: publish a fully-signed Nostr event to the TOON network. ' +\n 'Signs an off-chain payment-channel claim and forwards it over BTP. ' +\n 'Returns the event id, channel id, and the advanced channel nonce.',\n inputSchema: {\n type: 'object',\n properties: {\n event: {\n type: 'object',\n description:\n 'A fully-signed Nostr event (must include id, pubkey, sig, kind, ' +\n 'created_at, tags, content).',\n },\n destination: {\n type: 'string',\n description:\n 'Optional ILP destination override (default: the apex/town).',\n },\n fee: {\n type: 'string',\n description:\n 'Optional fee override in base units (default: daemon config).',\n },\n btpUrl: {\n type: 'string',\n description:\n 'Which apex (BTP write target) to publish through (default: the ' +\n 'config-seeded apex). Use toon_targets to list registered apexes. ' +\n 'Writes always go through BTP — never a relay directly.',\n },\n },\n required: ['event'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_subscribe',\n description:\n 'Free read: register a persistent town-relay subscription with NIP-01 ' +\n 'filter(s). Returns a subscription id to drain with toon_read.',\n inputSchema: {\n type: 'object',\n properties: {\n filters: {\n description: 'A NIP-01 filter object or an array of OR-ed filters.',\n },\n subId: { type: 'string', description: 'Optional caller-supplied id.' },\n relayUrl: {\n type: 'string',\n description:\n 'Restrict to one relay. Omit to FAN OUT across every registered ' +\n 'relay (reads merge into one ordered stream).',\n },\n },\n required: ['filters'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_read',\n description:\n 'Free read: drain buffered events newer than a cursor. Pass back the ' +\n 'returned cursor to fetch only events received since the last read.',\n inputSchema: {\n type: 'object',\n properties: {\n subId: { type: 'string', description: 'Restrict to one subscription.' },\n cursor: {\n type: 'number',\n description: 'Cursor from a prior toon_read.',\n },\n limit: {\n type: 'number',\n description: 'Max events to return (default 200).',\n },\n relayUrl: {\n type: 'string',\n description: 'Restrict the drain to events from a single relay.',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'toon_open_channel',\n description:\n 'Open (or return the existing) payment channel for a destination. ' +\n 'Channels open lazily on first publish; use this to pre-open.',\n inputSchema: {\n type: 'object',\n properties: {\n destination: {\n type: 'string',\n description: 'ILP destination (default: apex).',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'toon_channels',\n description:\n 'List tracked payment channels with their nonce watermark and cumulative ' +\n 'transferred amount.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_swap',\n description:\n 'Pay a mill peer (asset A) to receive asset B plus a signed target-chain ' +\n 'claim. Builds the NIP-59 gift-wrapped kind:20032 swap rumor and streams ' +\n 'it; the source-asset claim is signed against the open apex channel (the ' +\n 'mill must be routed via apexChildPeers). Returns the accumulated, ' +\n 'decrypted target-chain claim(s) and settlement metadata.',\n inputSchema: {\n type: 'object',\n properties: {\n destination: {\n type: 'string',\n description: 'Mill peer ILP destination (e.g. g.townhouse.mill).',\n },\n amount: {\n type: 'string',\n description: 'Total source-asset amount to swap, source micro-units.',\n },\n millPubkey: {\n type: 'string',\n description:\n \"Mill's 64-char lowercase hex Nostr pubkey (gift-wrap recipient).\",\n },\n pair: {\n type: 'object',\n description:\n 'The swap pair (from kind:10032 discovery or operator-supplied): ' +\n '{ from:{assetCode,assetScale,chain}, to:{...}, rate, minAmount?, maxAmount? }.',\n },\n chainRecipient: {\n type: 'string',\n description:\n \"Sender's payout address on pair.to.chain (EVM 0x-hex / Solana / Mina base58).\",\n },\n packetCount: {\n type: 'number',\n description: 'Split the swap into N equal packets (default 1).',\n },\n },\n required: [\n 'destination',\n 'amount',\n 'millPubkey',\n 'pair',\n 'chainRecipient',\n ],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_targets',\n description:\n 'List every registered target: relays (read sources, with connection + ' +\n 'buffered-event status) and apexes (BTP write targets, with ready/' +\n 'channel status). The TOON client is 1-to-many — many apexes to write ' +\n 'through, many relays to read from.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_add_relay',\n description:\n 'Add a relay READ target at runtime (persisted across restarts). It joins ' +\n 'all fan-out reads immediately; `.anyone` hidden-service relays reuse the ' +\n 'managed anon read proxy automatically.',\n inputSchema: {\n type: 'object',\n properties: {\n relayUrl: {\n type: 'string',\n description: 'Relay WS URL (ws://host:7100 or a .anyone service).',\n },\n },\n required: ['relayUrl'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_remove_relay',\n description:\n 'Remove a relay read target (persisted). The config-seeded default relay ' +\n 'cannot be removed.',\n inputSchema: {\n type: 'object',\n properties: {\n relayUrl: { type: 'string', description: 'Relay WS URL to remove.' },\n },\n required: ['relayUrl'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_add_apex',\n description:\n 'Add an apex WRITE target at runtime (persisted across restarts). ' +\n 'Settlement params are DISCOVERED by reading the apex’s kind:10032 ' +\n 'announcement off the given relay — you do not supply chain/settlement ' +\n 'details. The relay is added as a read target first if unknown.',\n inputSchema: {\n type: 'object',\n properties: {\n ilpAddress: {\n type: 'string',\n description: 'ILP address of the apex (e.g. g.townhouse.town).',\n },\n relayUrl: {\n type: 'string',\n description: 'Relay to discover the apex’s kind:10032 on.',\n },\n pubkey: {\n type: 'string',\n description:\n 'Optional apex Nostr pubkey (64-char hex) to narrow discovery.',\n },\n chain: {\n type: 'string',\n enum: ['evm', 'solana', 'mina'],\n description: 'Preferred settlement chain (default: apex’s first).',\n },\n childPeers: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Child peers via this apex’s channel (e.g. [\"dvm\",\"mill\"]).',\n },\n feePerEvent: {\n type: 'string',\n description: 'Per-write fee override for this apex (base units).',\n },\n },\n required: ['ilpAddress', 'relayUrl'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_remove_apex',\n description:\n 'Remove an apex write target by its BTP URL (persisted). The ' +\n 'config-seeded default apex cannot be removed.',\n inputSchema: {\n type: 'object',\n properties: {\n btpUrl: {\n type: 'string',\n description: 'BTP URL of the apex to remove (from toon_targets).',\n },\n },\n required: ['btpUrl'],\n additionalProperties: false,\n },\n },\n];\n\n/**\n * Dispatch an MCP tool call to the daemon control plane. Always resolves with a\n * `ToolResult` (errors are encoded as `isError: true` text, not thrown, so the\n * agent sees a readable message). A retryable error (daemon still\n * bootstrapping) yields a clear \"retry shortly\" message.\n */\nexport async function dispatchTool(\n client: ControlClient,\n name: string,\n args: Record<string, unknown>\n): Promise<ToolResult> {\n try {\n switch (name) {\n case 'toon_status':\n return ok(await client.status());\n case 'toon_identity': {\n const s = await client.status();\n return ok({\n identity: s.identity,\n ready: s.ready,\n bootstrapping: s.bootstrapping,\n });\n }\n case 'toon_publish':\n return ok(await client.publish(args as unknown as PublishRequest));\n case 'toon_subscribe':\n return ok(\n await client.subscribe({\n filters: args['filters'] as NostrFilter | NostrFilter[],\n ...(typeof args['subId'] === 'string'\n ? { subId: args['subId'] }\n : {}),\n ...(typeof args['relayUrl'] === 'string'\n ? { relayUrl: args['relayUrl'] }\n : {}),\n })\n );\n case 'toon_read':\n return ok(\n await client.events({\n ...(typeof args['subId'] === 'string'\n ? { subId: args['subId'] }\n : {}),\n ...(typeof args['cursor'] === 'number'\n ? { cursor: args['cursor'] }\n : {}),\n ...(typeof args['limit'] === 'number'\n ? { limit: args['limit'] }\n : {}),\n ...(typeof args['relayUrl'] === 'string'\n ? { relayUrl: args['relayUrl'] }\n : {}),\n })\n );\n case 'toon_open_channel':\n return ok(\n await client.openChannel(\n typeof args['destination'] === 'string'\n ? { destination: args['destination'] }\n : {}\n )\n );\n case 'toon_channels':\n return ok(await client.channels());\n case 'toon_swap':\n return ok(\n await client.swap({\n destination: String(args['destination']),\n amount: String(args['amount']),\n millPubkey: String(args['millPubkey']),\n pair: args['pair'] as SwapRequest['pair'],\n chainRecipient: String(args['chainRecipient']),\n ...(typeof args['packetCount'] === 'number'\n ? { packetCount: args['packetCount'] }\n : {}),\n })\n );\n case 'toon_targets':\n return ok(await client.targets());\n case 'toon_add_relay':\n return ok(\n await client.addRelay({ relayUrl: String(args['relayUrl']) })\n );\n case 'toon_remove_relay':\n return ok(\n await client.removeRelay({ relayUrl: String(args['relayUrl']) })\n );\n case 'toon_add_apex': {\n const req: AddApexRequest = {\n ilpAddress: String(args['ilpAddress']),\n relayUrl: String(args['relayUrl']),\n ...(typeof args['pubkey'] === 'string'\n ? { pubkey: args['pubkey'] }\n : {}),\n ...(typeof args['chain'] === 'string'\n ? { chain: args['chain'] as SettlementChain }\n : {}),\n ...(Array.isArray(args['childPeers'])\n ? { childPeers: (args['childPeers'] as unknown[]).map(String) }\n : {}),\n ...(typeof args['feePerEvent'] === 'string'\n ? { feePerEvent: args['feePerEvent'] }\n : {}),\n };\n return ok(await client.addApex(req));\n }\n case 'toon_remove_apex':\n return ok(await client.removeApex({ btpUrl: String(args['btpUrl']) }));\n default:\n return err(`Unknown tool: ${name}`);\n }\n } catch (e) {\n // A 504 is a retryable apex-discovery timeout — give a discovery-specific\n // hint rather than the daemon-bootstrapping one.\n if (e instanceof ControlApiError && e.status === 504) {\n return err(\n `${e.detail ?? e.message} — retry once the relay is reachable and the apex is online.`\n );\n }\n if (e instanceof ControlApiError && e.retryable) {\n return err(\n `TOON client is still bootstrapping (the anon proxy / BTP session can take ` +\n `30–90s) — retry shortly. (${e.message})`\n );\n }\n if (e instanceof DaemonUnreachableError) {\n return err(\n `TOON client daemon is not reachable at ${e.baseUrl}. It may have failed ` +\n `to start — check ~/.toon-client/daemon.log.`\n );\n }\n if (e instanceof ControlApiError) {\n return err(`${e.message}${e.detail ? `: ${e.detail}` : ''}`);\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\nfunction ok(data: unknown): ToolResult {\n return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };\n}\n\nfunction err(message: string): ToolResult {\n return { content: [{ type: 'text', text: message }], isError: true };\n}\n"],"mappings":";;;;;;;AA8BO,IAAM,mBAAqC;AAAA,EAChD;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAEF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAEF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAGF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aACE;AAAA,QAEJ;AAAA,QACA,aAAa;AAAA,UACX,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,KAAK;AAAA,UACH,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,aACE;AAAA,QAGJ;AAAA,MACF;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,MAClB,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAEF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS;AAAA,UACP,aAAa;AAAA,QACf;AAAA,QACA,OAAO,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,QACrE,UAAU;AAAA,UACR,MAAM;AAAA,UACN,aACE;AAAA,QAEJ;AAAA,MACF;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,MACpB,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAEF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO,EAAE,MAAM,UAAU,aAAa,gCAAgC;AAAA,QACtE,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,UAAU;AAAA,UACR,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAEF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,aAAa;AAAA,UACX,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAEF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAKF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,aAAa;AAAA,UACX,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,YAAY;AAAA,UACV,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,aACE;AAAA,QAEJ;AAAA,QACA,gBAAgB;AAAA,UACd,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,aAAa;AAAA,UACX,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAIF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAGF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,UAAU;AAAA,UACR,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,UAAU,CAAC,UAAU;AAAA,MACrB,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAEF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,UAAU,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,MACrE;AAAA,MACA,UAAU,CAAC,UAAU;AAAA,MACrB,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAIF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,YAAY;AAAA,UACV,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,UAAU;AAAA,UACR,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,CAAC,OAAO,UAAU,MAAM;AAAA,UAC9B,aAAa;AAAA,QACf;AAAA,QACA,YAAY;AAAA,UACV,MAAM;AAAA,UACN,OAAO,EAAE,MAAM,SAAS;AAAA,UACxB,aACE;AAAA,QACJ;AAAA,QACA,aAAa;AAAA,UACX,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,UAAU,CAAC,cAAc,UAAU;AAAA,MACnC,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAEF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,UAAU,CAAC,QAAQ;AAAA,MACnB,sBAAsB;AAAA,IACxB;AAAA,EACF;AACF;AAQA,eAAsB,aACpB,QACA,MACA,MACqB;AACrB,MAAI;AACF,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,GAAG,MAAM,OAAO,OAAO,CAAC;AAAA,MACjC,KAAK,iBAAiB;AACpB,cAAM,IAAI,MAAM,OAAO,OAAO;AAC9B,eAAO,GAAG;AAAA,UACR,UAAU,EAAE;AAAA,UACZ,OAAO,EAAE;AAAA,UACT,eAAe,EAAE;AAAA,QACnB,CAAC;AAAA,MACH;AAAA,MACA,KAAK;AACH,eAAO,GAAG,MAAM,OAAO,QAAQ,IAAiC,CAAC;AAAA,MACnE,KAAK;AACH,eAAO;AAAA,UACL,MAAM,OAAO,UAAU;AAAA,YACrB,SAAS,KAAK,SAAS;AAAA,YACvB,GAAI,OAAO,KAAK,OAAO,MAAM,WACzB,EAAE,OAAO,KAAK,OAAO,EAAE,IACvB,CAAC;AAAA,YACL,GAAI,OAAO,KAAK,UAAU,MAAM,WAC5B,EAAE,UAAU,KAAK,UAAU,EAAE,IAC7B,CAAC;AAAA,UACP,CAAC;AAAA,QACH;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,MAAM,OAAO,OAAO;AAAA,YAClB,GAAI,OAAO,KAAK,OAAO,MAAM,WACzB,EAAE,OAAO,KAAK,OAAO,EAAE,IACvB,CAAC;AAAA,YACL,GAAI,OAAO,KAAK,QAAQ,MAAM,WAC1B,EAAE,QAAQ,KAAK,QAAQ,EAAE,IACzB,CAAC;AAAA,YACL,GAAI,OAAO,KAAK,OAAO,MAAM,WACzB,EAAE,OAAO,KAAK,OAAO,EAAE,IACvB,CAAC;AAAA,YACL,GAAI,OAAO,KAAK,UAAU,MAAM,WAC5B,EAAE,UAAU,KAAK,UAAU,EAAE,IAC7B,CAAC;AAAA,UACP,CAAC;AAAA,QACH;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,MAAM,OAAO;AAAA,YACX,OAAO,KAAK,aAAa,MAAM,WAC3B,EAAE,aAAa,KAAK,aAAa,EAAE,IACnC,CAAC;AAAA,UACP;AAAA,QACF;AAAA,MACF,KAAK;AACH,eAAO,GAAG,MAAM,OAAO,SAAS,CAAC;AAAA,MACnC,KAAK;AACH,eAAO;AAAA,UACL,MAAM,OAAO,KAAK;AAAA,YAChB,aAAa,OAAO,KAAK,aAAa,CAAC;AAAA,YACvC,QAAQ,OAAO,KAAK,QAAQ,CAAC;AAAA,YAC7B,YAAY,OAAO,KAAK,YAAY,CAAC;AAAA,YACrC,MAAM,KAAK,MAAM;AAAA,YACjB,gBAAgB,OAAO,KAAK,gBAAgB,CAAC;AAAA,YAC7C,GAAI,OAAO,KAAK,aAAa,MAAM,WAC/B,EAAE,aAAa,KAAK,aAAa,EAAE,IACnC,CAAC;AAAA,UACP,CAAC;AAAA,QACH;AAAA,MACF,KAAK;AACH,eAAO,GAAG,MAAM,OAAO,QAAQ,CAAC;AAAA,MAClC,KAAK;AACH,eAAO;AAAA,UACL,MAAM,OAAO,SAAS,EAAE,UAAU,OAAO,KAAK,UAAU,CAAC,EAAE,CAAC;AAAA,QAC9D;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,MAAM,OAAO,YAAY,EAAE,UAAU,OAAO,KAAK,UAAU,CAAC,EAAE,CAAC;AAAA,QACjE;AAAA,MACF,KAAK,iBAAiB;AACpB,cAAM,MAAsB;AAAA,UAC1B,YAAY,OAAO,KAAK,YAAY,CAAC;AAAA,UACrC,UAAU,OAAO,KAAK,UAAU,CAAC;AAAA,UACjC,GAAI,OAAO,KAAK,QAAQ,MAAM,WAC1B,EAAE,QAAQ,KAAK,QAAQ,EAAE,IACzB,CAAC;AAAA,UACL,GAAI,OAAO,KAAK,OAAO,MAAM,WACzB,EAAE,OAAO,KAAK,OAAO,EAAqB,IAC1C,CAAC;AAAA,UACL,GAAI,MAAM,QAAQ,KAAK,YAAY,CAAC,IAChC,EAAE,YAAa,KAAK,YAAY,EAAgB,IAAI,MAAM,EAAE,IAC5D,CAAC;AAAA,UACL,GAAI,OAAO,KAAK,aAAa,MAAM,WAC/B,EAAE,aAAa,KAAK,aAAa,EAAE,IACnC,CAAC;AAAA,QACP;AACA,eAAO,GAAG,MAAM,OAAO,QAAQ,GAAG,CAAC;AAAA,MACrC;AAAA,MACA,KAAK;AACH,eAAO,GAAG,MAAM,OAAO,WAAW,EAAE,QAAQ,OAAO,KAAK,QAAQ,CAAC,EAAE,CAAC,CAAC;AAAA,MACvE;AACE,eAAO,IAAI,iBAAiB,IAAI,EAAE;AAAA,IACtC;AAAA,EACF,SAAS,GAAG;AAGV,QAAI,aAAa,mBAAmB,EAAE,WAAW,KAAK;AACpD,aAAO;AAAA,QACL,GAAG,EAAE,UAAU,EAAE,OAAO;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,aAAa,mBAAmB,EAAE,WAAW;AAC/C,aAAO;AAAA,QACL,iHAC+B,EAAE,OAAO;AAAA,MAC1C;AAAA,IACF;AACA,QAAI,aAAa,wBAAwB;AACvC,aAAO;AAAA,QACL,0CAA0C,EAAE,OAAO;AAAA,MAErD;AAAA,IACF;AACA,QAAI,aAAa,iBAAiB;AAChC,aAAO,IAAI,GAAG,EAAE,OAAO,GAAG,EAAE,SAAS,KAAK,EAAE,MAAM,KAAK,EAAE,EAAE;AAAA,IAC7D;AACA,WAAO,IAAI,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,EACvD;AACF;AAEA,SAAS,GAAG,MAA2B;AACrC,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,CAAC,EAAE;AAC5E;AAEA,SAAS,IAAI,SAA6B;AACxC,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG,SAAS,KAAK;AACrE;","names":[]}
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/daemon.js ADDED
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
3
+ import {
4
+ ClientRunner,
5
+ registerRoutes,
6
+ scaffoldFirstRun
7
+ } from "./chunk-3NAWISI5.js";
8
+ import {
9
+ ControlClient,
10
+ ToonClient,
11
+ acquireLock,
12
+ defaultConfigPath,
13
+ isProcessAlive,
14
+ readConfigFile,
15
+ readPid,
16
+ releaseLock,
17
+ resolveConfig,
18
+ spawnDaemonDetached,
19
+ waitForReady
20
+ } from "./chunk-5KFXUT5Q.js";
21
+ import "./chunk-32QD72IL.js";
22
+ import "./chunk-FSS45ZX3.js";
23
+ import "./chunk-LR7W2ISE.js";
24
+ import "./chunk-VA7XC4FD.js";
25
+ import "./chunk-SKQTKZIH.js";
26
+ import "./chunk-F22GNSF6.js";
27
+
28
+ // src/daemon.ts
29
+ import Fastify from "fastify";
30
+ function baseUrl(config) {
31
+ return `http://127.0.0.1:${config.httpPort}`;
32
+ }
33
+ function loadResolvedConfig() {
34
+ const path = process.env["TOON_CLIENT_CONFIG"] ?? defaultConfigPath();
35
+ return resolveConfig(readConfigFile(path));
36
+ }
37
+ async function runForeground() {
38
+ acquireLock();
39
+ const config = loadResolvedConfig();
40
+ const log = (msg) => console.error(msg);
41
+ const runner = new ClientRunner({
42
+ config,
43
+ createClient: (clientConfig) => new ToonClient(clientConfig),
44
+ logger: log
45
+ });
46
+ const app = Fastify({ logger: false });
47
+ registerRoutes(app, runner);
48
+ runner.start();
49
+ await app.listen({ host: "127.0.0.1", port: config.httpPort });
50
+ log(`[toon-clientd] listening on ${baseUrl(config)}`);
51
+ let shuttingDown = false;
52
+ const shutdown = async (signal) => {
53
+ if (shuttingDown) return;
54
+ shuttingDown = true;
55
+ log(`[toon-clientd] received ${signal}, shutting down`);
56
+ try {
57
+ await app.close();
58
+ } catch {
59
+ }
60
+ await runner.stop();
61
+ releaseLock();
62
+ setTimeout(() => process.exit(0), 500).unref();
63
+ };
64
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
65
+ process.on("SIGINT", () => void shutdown("SIGINT"));
66
+ }
67
+ async function start() {
68
+ const config = loadResolvedConfig();
69
+ const url = baseUrl(config);
70
+ const existing = readPid();
71
+ if (existing !== null && isProcessAlive(existing)) {
72
+ console.log(`toon-clientd already running (pid ${existing}) at ${url}`);
73
+ return;
74
+ }
75
+ const pid = spawnDaemonDetached();
76
+ const ok = await waitForReady(url, 2e4);
77
+ if (ok) {
78
+ console.log(`toon-clientd started (pid ${pid}) at ${url}`);
79
+ } else {
80
+ console.error(
81
+ `toon-clientd spawned (pid ${pid}) but did not become reachable at ${url} in time. Check the daemon log.`
82
+ );
83
+ process.exitCode = 1;
84
+ }
85
+ }
86
+ async function stop() {
87
+ const pid = readPid();
88
+ if (pid === null || !isProcessAlive(pid)) {
89
+ console.log("toon-clientd is not running");
90
+ releaseLock();
91
+ return;
92
+ }
93
+ process.kill(pid, "SIGTERM");
94
+ for (let i = 0; i < 40; i++) {
95
+ if (!isProcessAlive(pid)) break;
96
+ await new Promise((r) => setTimeout(r, 100));
97
+ }
98
+ console.log(`toon-clientd stopped (pid ${pid})`);
99
+ }
100
+ async function status() {
101
+ const config = loadResolvedConfig();
102
+ const client = new ControlClient({ baseUrl: baseUrl(config) });
103
+ try {
104
+ const s = await client.status();
105
+ console.log(JSON.stringify(s, null, 2));
106
+ } catch {
107
+ console.log(JSON.stringify({ running: false }, null, 2));
108
+ process.exitCode = 1;
109
+ }
110
+ }
111
+ async function main() {
112
+ const cmd = process.argv[2] ?? "run";
113
+ switch (cmd) {
114
+ case "run":
115
+ await scaffoldFirstRun();
116
+ await runForeground();
117
+ break;
118
+ case "start":
119
+ await scaffoldFirstRun();
120
+ await start();
121
+ break;
122
+ case "stop":
123
+ await stop();
124
+ break;
125
+ case "status":
126
+ await status();
127
+ break;
128
+ default:
129
+ console.error(
130
+ `Unknown command "${cmd}". Usage: toon-clientd <run|start|stop|status>`
131
+ );
132
+ process.exitCode = 1;
133
+ }
134
+ }
135
+ main().catch((err) => {
136
+ console.error(
137
+ err instanceof Error ? err.stack ?? err.message : String(err)
138
+ );
139
+ process.exitCode = 1;
140
+ });
141
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/daemon.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `toon-clientd` — the always-on, detached TOON client daemon. It owns the two\n * long-lived connections that cannot live in an ephemeral agent session:\n * • a BTP session to the apex/connector (paid writes), and\n * • a persistent town-relay Nostr-WS subscription (free reads),\n * plus the payment channels (with a persisted nonce watermark) and the signer.\n *\n * Subcommands:\n * toon-clientd run Run the daemon in the foreground (used internally by\n * the detached spawn; logs to stdout).\n * toon-clientd start Spawn the daemon detached and wait until reachable.\n * toon-clientd stop Stop a running daemon (SIGTERM the locked PID).\n * toon-clientd status Print the daemon status as JSON.\n */\n\nimport Fastify from 'fastify';\nimport { ToonClient } from '@toon-protocol/client';\nimport {\n defaultConfigPath,\n readConfigFile,\n resolveConfig,\n type ResolvedDaemonConfig,\n} from './daemon/config.js';\nimport { scaffoldFirstRun } from './daemon/first-run.js';\nimport { ClientRunner, type ToonClientLike } from './daemon/client-runner.js';\nimport { registerRoutes } from './daemon/routes.js';\nimport {\n acquireLock,\n isProcessAlive,\n readPid,\n releaseLock,\n spawnDaemonDetached,\n waitForReady,\n} from './daemon/lifecycle.js';\nimport { ControlClient } from './control-client.js';\n\nfunction baseUrl(config: ResolvedDaemonConfig): string {\n return `http://127.0.0.1:${config.httpPort}`;\n}\n\nfunction loadResolvedConfig(): ResolvedDaemonConfig {\n const path = process.env['TOON_CLIENT_CONFIG'] ?? defaultConfigPath();\n return resolveConfig(readConfigFile(path));\n}\n\n/** Run the daemon in the foreground (the detached child's actual work). */\nasync function runForeground(): Promise<void> {\n acquireLock();\n const config = loadResolvedConfig();\n const log = (msg: string): void => console.error(msg);\n\n const runner = new ClientRunner({\n config,\n createClient: (clientConfig) =>\n new ToonClient(clientConfig) as unknown as ToonClientLike,\n logger: log,\n });\n\n const app = Fastify({ logger: false });\n registerRoutes(app, runner);\n\n // Begin bootstrap (non-blocking) before listening so /status is immediately\n // reachable and reports `bootstrapping: true` while anon/BTP come up.\n runner.start();\n\n await app.listen({ host: '127.0.0.1', port: config.httpPort });\n log(`[toon-clientd] listening on ${baseUrl(config)}`);\n\n let shuttingDown = false;\n const shutdown = async (signal: string): Promise<void> => {\n if (shuttingDown) return;\n shuttingDown = true;\n log(`[toon-clientd] received ${signal}, shutting down`);\n try {\n await app.close();\n } catch {\n /* ignore */\n }\n await runner.stop();\n releaseLock();\n setTimeout(() => process.exit(0), 500).unref();\n };\n process.on('SIGTERM', () => void shutdown('SIGTERM'));\n process.on('SIGINT', () => void shutdown('SIGINT'));\n}\n\n/** Spawn the daemon detached and wait until the control plane responds. */\nasync function start(): Promise<void> {\n const config = loadResolvedConfig();\n const url = baseUrl(config);\n const existing = readPid();\n if (existing !== null && isProcessAlive(existing)) {\n console.log(`toon-clientd already running (pid ${existing}) at ${url}`);\n return;\n }\n const pid = spawnDaemonDetached();\n const ok = await waitForReady(url, 20_000);\n if (ok) {\n console.log(`toon-clientd started (pid ${pid}) at ${url}`);\n } else {\n console.error(\n `toon-clientd spawned (pid ${pid}) but did not become reachable at ${url} in time. ` +\n `Check the daemon log.`\n );\n process.exitCode = 1;\n }\n}\n\n/** Stop a running daemon via SIGTERM on the locked PID. */\nasync function stop(): Promise<void> {\n const pid = readPid();\n if (pid === null || !isProcessAlive(pid)) {\n console.log('toon-clientd is not running');\n releaseLock();\n return;\n }\n process.kill(pid, 'SIGTERM');\n // Wait briefly for the process to exit.\n for (let i = 0; i < 40; i++) {\n if (!isProcessAlive(pid)) break;\n await new Promise((r) => setTimeout(r, 100));\n }\n console.log(`toon-clientd stopped (pid ${pid})`);\n}\n\n/** Print the daemon status JSON. */\nasync function status(): Promise<void> {\n const config = loadResolvedConfig();\n const client = new ControlClient({ baseUrl: baseUrl(config) });\n try {\n const s = await client.status();\n console.log(JSON.stringify(s, null, 2));\n } catch {\n console.log(JSON.stringify({ running: false }, null, 2));\n process.exitCode = 1;\n }\n}\n\nasync function main(): Promise<void> {\n const cmd = process.argv[2] ?? 'run';\n switch (cmd) {\n case 'run':\n // First-run onboarding (#251): mint + persist an identity and scaffold\n // the transport config so a fresh install starts with no manual setup.\n await scaffoldFirstRun();\n await runForeground();\n break;\n case 'start':\n await scaffoldFirstRun();\n await start();\n break;\n case 'stop':\n await stop();\n break;\n case 'status':\n await status();\n break;\n default:\n console.error(\n `Unknown command \"${cmd}\". Usage: toon-clientd <run|start|stop|status>`\n );\n process.exitCode = 1;\n }\n}\n\nmain().catch((err) => {\n console.error(\n err instanceof Error ? (err.stack ?? err.message) : String(err)\n );\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,27 @@
1
+ import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
2
+ import {
3
+ ED25519_TORSION_SUBGROUP,
4
+ _map_to_curve_elligator2_curve25519,
5
+ ed25519,
6
+ ed25519_hasher,
7
+ ed25519ctx,
8
+ ed25519ph,
9
+ ristretto255,
10
+ ristretto255_hasher,
11
+ ristretto255_oprf,
12
+ x25519
13
+ } from "./chunk-FSS45ZX3.js";
14
+ import "./chunk-F22GNSF6.js";
15
+ export {
16
+ ED25519_TORSION_SUBGROUP,
17
+ _map_to_curve_elligator2_curve25519,
18
+ ed25519,
19
+ ed25519_hasher,
20
+ ed25519ctx,
21
+ ed25519ph,
22
+ ristretto255,
23
+ ristretto255_hasher,
24
+ ristretto255_oprf,
25
+ x25519
26
+ };
27
+ //# sourceMappingURL=ed25519-2QVPINLS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}