@toon-protocol/client 0.11.0 → 0.12.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.
- package/README.md +1 -26
- package/dist/index.d.ts +141 -180
- package/dist/index.js +186 -193
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
- package/dist/anon-proxy-W3KMM7GU.js +0 -23
- package/dist/anon-proxy-W3KMM7GU.js.map +0 -1
- package/dist/chunk-WHAEQLIW.js +0 -276
- package/dist/chunk-WHAEQLIW.js.map +0 -1
- package/dist/gateway-QOK47RKS.js +0 -13
- package/dist/gateway-QOK47RKS.js.map +0 -1
- package/dist/socks5-WTJBYGME.js +0 -136
- package/dist/socks5-WTJBYGME.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ANON_ASSETS,
|
|
3
|
-
ANON_VERSION,
|
|
4
|
-
selectAnonAsset,
|
|
5
|
-
startManagedAnonProxy
|
|
6
|
-
} from "./chunk-WHAEQLIW.js";
|
|
7
|
-
|
|
8
1
|
// src/ToonClient.ts
|
|
9
2
|
import { generateSecretKey as generateSecretKey3, getPublicKey as getPublicKey2, finalizeEvent } from "nostr-tools/pure";
|
|
10
3
|
|
|
@@ -263,26 +256,49 @@ function getNetworkStatus(config) {
|
|
|
263
256
|
if (!network || network === "custom") return void 0;
|
|
264
257
|
return resolveClientNetwork(network).status;
|
|
265
258
|
}
|
|
259
|
+
function proxyIlpEndpoint(proxyUrl) {
|
|
260
|
+
if (!proxyUrl) return void 0;
|
|
261
|
+
const trimmed = proxyUrl.replace(/\/+$/, "");
|
|
262
|
+
return /\/ilp$/i.test(trimmed) ? trimmed : `${trimmed}/ilp`;
|
|
263
|
+
}
|
|
266
264
|
function validateConfig(config) {
|
|
267
265
|
if (config.connector !== void 0) {
|
|
268
266
|
throw new ValidationError(
|
|
269
267
|
"Embedded mode not yet implemented in ToonClient. Use connectorUrl for HTTP mode."
|
|
270
268
|
);
|
|
271
269
|
}
|
|
272
|
-
if (!config.connectorUrl) {
|
|
270
|
+
if (!config.connectorUrl && !config.proxyUrl) {
|
|
273
271
|
throw new ValidationError(
|
|
274
|
-
'connectorUrl is required for HTTP mode. Example: "http://localhost:8080"'
|
|
272
|
+
'connectorUrl (or proxyUrl) is required for HTTP mode. Example: "http://localhost:8080"'
|
|
275
273
|
);
|
|
276
274
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
275
|
+
if (config.connectorUrl) {
|
|
276
|
+
try {
|
|
277
|
+
const url = new URL(config.connectorUrl);
|
|
278
|
+
if (!url.protocol.startsWith("http")) {
|
|
279
|
+
throw new Error("Must be HTTP or HTTPS");
|
|
280
|
+
}
|
|
281
|
+
} catch (error) {
|
|
282
|
+
throw new ValidationError(
|
|
283
|
+
`Invalid connectorUrl: must be a valid HTTP/HTTPS URL (e.g., "http://localhost:8080"). Error: ${error instanceof Error ? error.message : String(error)}`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
for (const [field, value] of [
|
|
288
|
+
["proxyUrl", config.proxyUrl],
|
|
289
|
+
["faucetUrl", config.faucetUrl]
|
|
290
|
+
]) {
|
|
291
|
+
if (value === void 0) continue;
|
|
292
|
+
try {
|
|
293
|
+
const url = new URL(value);
|
|
294
|
+
if (!url.protocol.startsWith("http")) {
|
|
295
|
+
throw new Error("Must be HTTP or HTTPS");
|
|
296
|
+
}
|
|
297
|
+
} catch (error) {
|
|
298
|
+
throw new ValidationError(
|
|
299
|
+
`Invalid ${field}: must be a valid HTTP/HTTPS URL. Error: ${error instanceof Error ? error.message : String(error)}`
|
|
300
|
+
);
|
|
281
301
|
}
|
|
282
|
-
} catch (error) {
|
|
283
|
-
throw new ValidationError(
|
|
284
|
-
`Invalid connectorUrl: must be a valid HTTP/HTTPS URL (e.g., "http://localhost:8080"). Error: ${error instanceof Error ? error.message : String(error)}`
|
|
285
|
-
);
|
|
286
302
|
}
|
|
287
303
|
if (config.secretKey !== void 0) {
|
|
288
304
|
if (!config.secretKey || config.secretKey.length !== 32) {
|
|
@@ -346,25 +362,6 @@ function validateConfig(config) {
|
|
|
346
362
|
);
|
|
347
363
|
}
|
|
348
364
|
}
|
|
349
|
-
if (config.transport) {
|
|
350
|
-
if (config.transport.type === "socks5") {
|
|
351
|
-
if (!config.transport.socksProxy?.startsWith("socks5h://")) {
|
|
352
|
-
throw new ValidationError(
|
|
353
|
-
'transport.socksProxy must use socks5h:// scheme to prevent DNS leaks. The "h" suffix ensures .anyone hostnames are resolved by the proxy, not locally.'
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
} else if (config.transport.type === "gateway") {
|
|
357
|
-
if (!config.transport.gatewayUrl) {
|
|
358
|
-
throw new ValidationError(
|
|
359
|
-
"transport.gatewayUrl is required for gateway transport"
|
|
360
|
-
);
|
|
361
|
-
}
|
|
362
|
-
} else if (config.transport.type !== "direct") {
|
|
363
|
-
throw new ValidationError(
|
|
364
|
-
`Unknown transport type: "${config.transport.type}"`
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
365
|
if (config.chainRpcUrls && config.supportedChains) {
|
|
369
366
|
for (const chain of Object.keys(config.chainRpcUrls)) {
|
|
370
367
|
if (!config.supportedChains.includes(chain)) {
|
|
@@ -381,19 +378,21 @@ function applyDefaults(rawConfig) {
|
|
|
381
378
|
config.mnemonic,
|
|
382
379
|
config.mnemonicAccountIndex ?? 0
|
|
383
380
|
).secretKey : generateSecretKey2());
|
|
381
|
+
const connectorHttpEndpoint = config.connectorHttpEndpoint ?? proxyIlpEndpoint(config.proxyUrl);
|
|
382
|
+
const connectorUrl = config.connectorUrl ?? config.proxyUrl?.replace(/\/+$/, "");
|
|
384
383
|
let btpUrl = config.btpUrl;
|
|
385
|
-
if (!btpUrl &&
|
|
384
|
+
if (!btpUrl && connectorUrl && !connectorHttpEndpoint) {
|
|
386
385
|
try {
|
|
387
|
-
const url = new URL(
|
|
386
|
+
const url = new URL(connectorUrl);
|
|
388
387
|
const wsProtocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
389
388
|
btpUrl = `${wsProtocol}//${url.hostname}:3000`;
|
|
390
389
|
} catch {
|
|
391
390
|
}
|
|
392
391
|
}
|
|
393
392
|
let destinationAddress = config.destinationAddress;
|
|
394
|
-
if (!destinationAddress &&
|
|
393
|
+
if (!destinationAddress && connectorUrl) {
|
|
395
394
|
try {
|
|
396
|
-
const url = new URL(
|
|
395
|
+
const url = new URL(connectorUrl);
|
|
397
396
|
if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
|
|
398
397
|
if (url.port === "8080") {
|
|
399
398
|
destinationAddress = "g.toon.genesis";
|
|
@@ -416,8 +415,10 @@ function applyDefaults(rawConfig) {
|
|
|
416
415
|
...config,
|
|
417
416
|
secretKey,
|
|
418
417
|
evmPrivateKey,
|
|
419
|
-
connectorUrl
|
|
420
|
-
|
|
418
|
+
// Satisfied by connectorUrl OR proxyUrl (validateConfig enforced one of them).
|
|
419
|
+
connectorUrl,
|
|
420
|
+
// Surface the derived `POST /ilp` endpoint so HTTP mode selects HttpIlpClient.
|
|
421
|
+
...connectorHttpEndpoint ? { connectorHttpEndpoint } : {},
|
|
421
422
|
relayUrl: config.relayUrl ?? "ws://localhost:7100",
|
|
422
423
|
queryTimeout: config.queryTimeout ?? 3e4,
|
|
423
424
|
maxRetries: config.maxRetries ?? 3,
|
|
@@ -480,6 +481,15 @@ function isBase64(str) {
|
|
|
480
481
|
return /^[A-Za-z0-9+/]*={0,2}$/.test(str);
|
|
481
482
|
}
|
|
482
483
|
|
|
484
|
+
// src/utils/store-envelope.ts
|
|
485
|
+
var REQUEST_LINE = "POST /write HTTP/1.1";
|
|
486
|
+
var HEADERS = ["Host: relay", "Content-Type: application/json"];
|
|
487
|
+
function buildStoreWriteEnvelope(event) {
|
|
488
|
+
const body = JSON.stringify({ event });
|
|
489
|
+
const head = [REQUEST_LINE, ...HEADERS].join("\r\n");
|
|
490
|
+
return encodeUtf8(head + "\r\n\r\n" + body);
|
|
491
|
+
}
|
|
492
|
+
|
|
483
493
|
// src/modes/http.ts
|
|
484
494
|
import { BootstrapService, createDiscoveryTracker } from "@toon-protocol/core";
|
|
485
495
|
|
|
@@ -2698,82 +2708,10 @@ var EvmSigner = class {
|
|
|
2698
2708
|
}
|
|
2699
2709
|
};
|
|
2700
2710
|
|
|
2701
|
-
// src/transport/index.ts
|
|
2702
|
-
function isAnyoneHost(url) {
|
|
2703
|
-
if (!url) return false;
|
|
2704
|
-
try {
|
|
2705
|
-
const withScheme = /:\/\//.test(url) ? url : `ws://${url}`;
|
|
2706
|
-
const host = new URL(withScheme).hostname.toLowerCase();
|
|
2707
|
-
return host.endsWith(".anyone");
|
|
2708
|
-
} catch {
|
|
2709
|
-
return false;
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
async function resolveTransport(transport, originalBtpUrl, originalConnectorUrl, managedProxyOptions) {
|
|
2713
|
-
const hasExplicitProxy = !!transport && (transport.type === "socks5" || transport.type === "gateway");
|
|
2714
|
-
const envProxy = process.env["ANYONE_PROXY_URLS"];
|
|
2715
|
-
if (!hasExplicitProxy && managedProxyOptions?.managedAnonProxy !== false && !envProxy && isAnyoneHost(originalBtpUrl)) {
|
|
2716
|
-
const { startManagedAnonProxy: startManagedAnonProxy2 } = await import("./anon-proxy-W3KMM7GU.js");
|
|
2717
|
-
const { createSocks5WebSocketFactory, createSocks5Fetch } = await import("./socks5-WTJBYGME.js");
|
|
2718
|
-
const proxy = await startManagedAnonProxy2({
|
|
2719
|
-
...managedProxyOptions?.managedAnonSocksPort !== void 0 ? { socksPort: managedProxyOptions.managedAnonSocksPort } : {}
|
|
2720
|
-
});
|
|
2721
|
-
try {
|
|
2722
|
-
return {
|
|
2723
|
-
createWebSocket: createSocks5WebSocketFactory(proxy.socksProxy),
|
|
2724
|
-
httpClient: createSocks5Fetch(proxy.socksProxy),
|
|
2725
|
-
stopManagedProxy: proxy.stop
|
|
2726
|
-
};
|
|
2727
|
-
} catch (err) {
|
|
2728
|
-
await proxy.stop();
|
|
2729
|
-
throw err;
|
|
2730
|
-
}
|
|
2731
|
-
}
|
|
2732
|
-
if (!transport || transport.type === "direct") {
|
|
2733
|
-
return {};
|
|
2734
|
-
}
|
|
2735
|
-
if (transport.type === "socks5") {
|
|
2736
|
-
const {
|
|
2737
|
-
createSocks5WebSocketFactory,
|
|
2738
|
-
createSocks5Fetch,
|
|
2739
|
-
probeSocks5Proxy
|
|
2740
|
-
} = await import("./socks5-WTJBYGME.js");
|
|
2741
|
-
await probeSocks5Proxy(transport.socksProxy);
|
|
2742
|
-
return {
|
|
2743
|
-
createWebSocket: createSocks5WebSocketFactory(transport.socksProxy),
|
|
2744
|
-
httpClient: createSocks5Fetch(transport.socksProxy)
|
|
2745
|
-
};
|
|
2746
|
-
}
|
|
2747
|
-
if (transport.type === "gateway") {
|
|
2748
|
-
const { rewriteUrlsForGateway } = await import("./gateway-QOK47RKS.js");
|
|
2749
|
-
const rewritten = rewriteUrlsForGateway(
|
|
2750
|
-
transport.gatewayUrl,
|
|
2751
|
-
originalBtpUrl,
|
|
2752
|
-
originalConnectorUrl
|
|
2753
|
-
);
|
|
2754
|
-
return {
|
|
2755
|
-
btpUrl: rewritten.btpUrl,
|
|
2756
|
-
connectorUrl: rewritten.connectorUrl
|
|
2757
|
-
};
|
|
2758
|
-
}
|
|
2759
|
-
throw new Error(
|
|
2760
|
-
`Unknown transport type: "${transport.type}"`
|
|
2761
|
-
);
|
|
2762
|
-
}
|
|
2763
|
-
|
|
2764
2711
|
// src/modes/http.ts
|
|
2765
2712
|
async function initializeHttpMode(config) {
|
|
2766
|
-
const
|
|
2767
|
-
|
|
2768
|
-
config.btpUrl,
|
|
2769
|
-
config.connectorUrl,
|
|
2770
|
-
{
|
|
2771
|
-
...config.managedAnonProxy !== void 0 ? { managedAnonProxy: config.managedAnonProxy } : {},
|
|
2772
|
-
...config.managedAnonSocksPort !== void 0 ? { managedAnonSocksPort: config.managedAnonSocksPort } : {}
|
|
2773
|
-
}
|
|
2774
|
-
);
|
|
2775
|
-
const effectiveBtpUrl = transport.btpUrl ?? config.btpUrl;
|
|
2776
|
-
const effectiveConnectorUrl = transport.connectorUrl ?? config.connectorUrl;
|
|
2713
|
+
const effectiveBtpUrl = config.btpUrl;
|
|
2714
|
+
const effectiveConnectorUrl = config.connectorUrl;
|
|
2777
2715
|
const settlementInfo = buildSettlementInfo(config);
|
|
2778
2716
|
const discoveredPeer = readDiscoveredIlpPeer({
|
|
2779
2717
|
btpEndpoint: effectiveBtpUrl,
|
|
@@ -2786,8 +2724,7 @@ async function initializeHttpMode(config) {
|
|
|
2786
2724
|
btpClient = new BtpRuntimeClient({
|
|
2787
2725
|
btpUrl: effectiveBtpUrl,
|
|
2788
2726
|
peerId: config.btpPeerId ?? `client`,
|
|
2789
|
-
authToken: config.btpAuthToken ?? ""
|
|
2790
|
-
createWebSocket: transport.createWebSocket
|
|
2727
|
+
authToken: config.btpAuthToken ?? ""
|
|
2791
2728
|
});
|
|
2792
2729
|
await btpClient.connect();
|
|
2793
2730
|
}
|
|
@@ -2799,17 +2736,14 @@ async function initializeHttpMode(config) {
|
|
|
2799
2736
|
...config.btpAuthToken !== void 0 ? { authToken: config.btpAuthToken } : {},
|
|
2800
2737
|
timeout: config.queryTimeout,
|
|
2801
2738
|
maxRetries: config.maxRetries,
|
|
2802
|
-
retryDelay: config.retryDelay
|
|
2803
|
-
...transport.httpClient !== void 0 ? { httpClient: transport.httpClient } : {},
|
|
2804
|
-
...transport.createWebSocket !== void 0 ? { createWebSocket: transport.createWebSocket } : {}
|
|
2739
|
+
retryDelay: config.retryDelay
|
|
2805
2740
|
});
|
|
2806
2741
|
}
|
|
2807
2742
|
const runtimeClient = httpIlpClient ?? btpClient ?? new HttpRuntimeClient({
|
|
2808
2743
|
connectorUrl: effectiveConnectorUrl,
|
|
2809
2744
|
timeout: config.queryTimeout,
|
|
2810
2745
|
maxRetries: config.maxRetries,
|
|
2811
|
-
retryDelay: config.retryDelay
|
|
2812
|
-
httpClient: transport.httpClient
|
|
2746
|
+
retryDelay: config.retryDelay
|
|
2813
2747
|
});
|
|
2814
2748
|
let onChainChannelClient = null;
|
|
2815
2749
|
if (config.chainRpcUrls) {
|
|
@@ -2854,10 +2788,7 @@ async function initializeHttpMode(config) {
|
|
|
2854
2788
|
runtimeClient,
|
|
2855
2789
|
adminClient: null,
|
|
2856
2790
|
btpClient,
|
|
2857
|
-
onChainChannelClient
|
|
2858
|
-
// Teardown handle for a managed `anon` proxy this init STARTED (undefined
|
|
2859
|
-
// for explicit-proxy/direct/gateway). ToonClient.stop() invokes it.
|
|
2860
|
-
stopManagedProxy: transport.stopManagedProxy
|
|
2791
|
+
onChainChannelClient
|
|
2861
2792
|
};
|
|
2862
2793
|
}
|
|
2863
2794
|
|
|
@@ -4023,13 +3954,7 @@ var ToonClient = class {
|
|
|
4023
3954
|
}
|
|
4024
3955
|
}
|
|
4025
3956
|
const initialization = await initializeHttpMode(this.config);
|
|
4026
|
-
const {
|
|
4027
|
-
bootstrapService,
|
|
4028
|
-
discoveryTracker,
|
|
4029
|
-
runtimeClient,
|
|
4030
|
-
btpClient,
|
|
4031
|
-
stopManagedProxy
|
|
4032
|
-
} = initialization;
|
|
3957
|
+
const { bootstrapService, discoveryTracker, runtimeClient, btpClient } = initialization;
|
|
4033
3958
|
if (this.channelManager) {
|
|
4034
3959
|
const cm = this.channelManager;
|
|
4035
3960
|
const nostrPubkey = this.getPublicKey();
|
|
@@ -4117,8 +4042,7 @@ var ToonClient = class {
|
|
|
4117
4042
|
discoveryTracker,
|
|
4118
4043
|
runtimeClient,
|
|
4119
4044
|
peersDiscovered: bootstrapResults.length,
|
|
4120
|
-
btpClient: btpClient ?? void 0
|
|
4121
|
-
...stopManagedProxy ? { stopManagedProxy } : {}
|
|
4045
|
+
btpClient: btpClient ?? void 0
|
|
4122
4046
|
};
|
|
4123
4047
|
return {
|
|
4124
4048
|
peersDiscovered: bootstrapResults.length,
|
|
@@ -4154,13 +4078,9 @@ var ToonClient = class {
|
|
|
4154
4078
|
const toonData = this.config.toonEncoder(event);
|
|
4155
4079
|
const basePricePerByte = 10n;
|
|
4156
4080
|
const amount = options?.ilpAmount !== void 0 ? String(options.ilpAmount) : String(BigInt(toonData.length) * basePricePerByte);
|
|
4081
|
+
const writeData = buildStoreWriteEnvelope(event);
|
|
4157
4082
|
const destination = options?.destination ?? this.config.destinationAddress;
|
|
4158
|
-
|
|
4159
|
-
throw new ToonClientError(
|
|
4160
|
-
"BTP client required for publishing. Configure btpUrl.",
|
|
4161
|
-
"NO_BTP_CLIENT"
|
|
4162
|
-
);
|
|
4163
|
-
}
|
|
4083
|
+
const transport = this.getClaimTransport();
|
|
4164
4084
|
let claimMessage;
|
|
4165
4085
|
if (options?.claim) {
|
|
4166
4086
|
claimMessage = this.buildClaimMessageForProof(options.claim);
|
|
@@ -4189,13 +4109,11 @@ var ToonClient = class {
|
|
|
4189
4109
|
"MISSING_CLAIM"
|
|
4190
4110
|
);
|
|
4191
4111
|
}
|
|
4192
|
-
const response = await
|
|
4112
|
+
const response = await transport.sendIlpPacketWithClaim(
|
|
4193
4113
|
{
|
|
4194
4114
|
destination,
|
|
4195
4115
|
amount,
|
|
4196
|
-
data: toBase64(
|
|
4197
|
-
toonData instanceof Uint8Array ? toonData : new Uint8Array(toonData)
|
|
4198
|
-
)
|
|
4116
|
+
data: toBase64(writeData)
|
|
4199
4117
|
},
|
|
4200
4118
|
claimMessage
|
|
4201
4119
|
);
|
|
@@ -4275,7 +4193,7 @@ var ToonClient = class {
|
|
|
4275
4193
|
* matching `destination`,
|
|
4276
4194
|
* (c) neither -> throw MISSING_CLAIM.
|
|
4277
4195
|
*
|
|
4278
|
-
* @throws {ToonClientError} INVALID_STATE /
|
|
4196
|
+
* @throws {ToonClientError} INVALID_STATE / NO_ILP_TRANSPORT / MISSING_CLAIM
|
|
4279
4197
|
*/
|
|
4280
4198
|
async sendSwapPacket(params) {
|
|
4281
4199
|
if (!this.state) {
|
|
@@ -4284,18 +4202,13 @@ var ToonClient = class {
|
|
|
4284
4202
|
"INVALID_STATE"
|
|
4285
4203
|
);
|
|
4286
4204
|
}
|
|
4287
|
-
|
|
4288
|
-
throw new ToonClientError(
|
|
4289
|
-
"BTP client required for sending swap packets. Configure btpUrl.",
|
|
4290
|
-
"NO_BTP_CLIENT"
|
|
4291
|
-
);
|
|
4292
|
-
}
|
|
4205
|
+
const transport = this.getClaimTransport();
|
|
4293
4206
|
const claimMessage = await this.resolveClaimForDestination(
|
|
4294
4207
|
params.destination,
|
|
4295
4208
|
params.amount,
|
|
4296
4209
|
params.claim
|
|
4297
4210
|
);
|
|
4298
|
-
return
|
|
4211
|
+
return transport.sendIlpPacketWithClaim(
|
|
4299
4212
|
{
|
|
4300
4213
|
destination: params.destination,
|
|
4301
4214
|
amount: String(params.amount),
|
|
@@ -4335,6 +4248,51 @@ var ToonClient = class {
|
|
|
4335
4248
|
}
|
|
4336
4249
|
return EvmSigner.buildClaimMessage(claim, this.getPublicKey());
|
|
4337
4250
|
}
|
|
4251
|
+
/**
|
|
4252
|
+
* Resolve the ILP transport for a paid (claim-bearing) write.
|
|
4253
|
+
*
|
|
4254
|
+
* The connector is a payment-proxy: paid writes carry an ILP PREPARE plus the
|
|
4255
|
+
* signed payment-channel claim. Either transport speaks the SAME claim
|
|
4256
|
+
* contract — the BTP `payment-channel-claim` protocolData entry and the
|
|
4257
|
+
* ILP-over-HTTP `ILP-Payment-Channel-Claim` header serialize the same claim
|
|
4258
|
+
* JSON — so we route through whichever transport is ACTIVE rather than
|
|
4259
|
+
* hard-requiring BTP.
|
|
4260
|
+
*
|
|
4261
|
+
* Selection (mirrors `modes/http.ts` runtime-client precedence):
|
|
4262
|
+
* 1. `runtimeClient` when it implements `sendIlpPacketWithClaim` — this is
|
|
4263
|
+
* the HttpIlpClient (proxy `POST /ilp`) when a `proxyUrl`/
|
|
4264
|
+
* `connectorHttpEndpoint` is configured, else the BtpRuntimeClient.
|
|
4265
|
+
* 2. `btpClient` as an explicit fallback (always present when `btpUrl` is set).
|
|
4266
|
+
*
|
|
4267
|
+
* The level-3 `HttpRuntimeClient` (connector-admin HTTP, no `btpUrl` AND no
|
|
4268
|
+
* proxy) does NOT implement `sendIlpPacketWithClaim`; in that case there is no
|
|
4269
|
+
* paid-write transport and we throw a clear, actionable error.
|
|
4270
|
+
*
|
|
4271
|
+
* @throws {ToonClientError} NO_ILP_TRANSPORT when no active transport can send
|
|
4272
|
+
* a packet+claim.
|
|
4273
|
+
*/
|
|
4274
|
+
getClaimTransport() {
|
|
4275
|
+
const state = this.state;
|
|
4276
|
+
if (!state) {
|
|
4277
|
+
throw new ToonClientError(
|
|
4278
|
+
"Client not started. Call start() first.",
|
|
4279
|
+
"INVALID_STATE"
|
|
4280
|
+
);
|
|
4281
|
+
}
|
|
4282
|
+
const candidates = [
|
|
4283
|
+
state.runtimeClient,
|
|
4284
|
+
state.btpClient
|
|
4285
|
+
];
|
|
4286
|
+
for (const candidate of candidates) {
|
|
4287
|
+
if (candidate && typeof candidate.sendIlpPacketWithClaim === "function") {
|
|
4288
|
+
return candidate;
|
|
4289
|
+
}
|
|
4290
|
+
}
|
|
4291
|
+
throw new ToonClientError(
|
|
4292
|
+
"No ILP transport for paid writes. Configure `proxyUrl`/`connectorHttpEndpoint` (route through the connector proxy over ILP-over-HTTP) or `btpUrl` (BTP socket).",
|
|
4293
|
+
"NO_ILP_TRANSPORT"
|
|
4294
|
+
);
|
|
4295
|
+
}
|
|
4338
4296
|
/**
|
|
4339
4297
|
* Shared claim-resolution logic used by `publishEvent` and `sendSwapPacket`.
|
|
4340
4298
|
* TODO(12.5 followup): also factor `publishEvent`'s inline claim resolution
|
|
@@ -4523,14 +4481,9 @@ var ToonClient = class {
|
|
|
4523
4481
|
"MISSING_CLAIM"
|
|
4524
4482
|
);
|
|
4525
4483
|
}
|
|
4526
|
-
|
|
4527
|
-
throw new ToonClientError(
|
|
4528
|
-
"BTP client required for sending payments. Configure btpUrl.",
|
|
4529
|
-
"NO_BTP_CLIENT"
|
|
4530
|
-
);
|
|
4531
|
-
}
|
|
4484
|
+
const transport = this.getClaimTransport();
|
|
4532
4485
|
const claimMessage = this.buildClaimMessageForProof(params.claim);
|
|
4533
|
-
return
|
|
4486
|
+
return transport.sendIlpPacketWithClaim(
|
|
4534
4487
|
ilpParams,
|
|
4535
4488
|
claimMessage
|
|
4536
4489
|
);
|
|
@@ -4548,14 +4501,10 @@ var ToonClient = class {
|
|
|
4548
4501
|
if (!this.state) {
|
|
4549
4502
|
throw new ToonClientError("Client not started", "INVALID_STATE");
|
|
4550
4503
|
}
|
|
4551
|
-
const stopManagedProxy = this.state.stopManagedProxy;
|
|
4552
4504
|
try {
|
|
4553
4505
|
if (this.state.btpClient) {
|
|
4554
4506
|
await this.state.btpClient.disconnect();
|
|
4555
4507
|
}
|
|
4556
|
-
if (stopManagedProxy) {
|
|
4557
|
-
await stopManagedProxy();
|
|
4558
|
-
}
|
|
4559
4508
|
this.state = null;
|
|
4560
4509
|
} catch (error) {
|
|
4561
4510
|
throw new ToonClientError(
|
|
@@ -4603,26 +4552,6 @@ var ToonClient = class {
|
|
|
4603
4552
|
}
|
|
4604
4553
|
};
|
|
4605
4554
|
|
|
4606
|
-
// src/transport/hs-hostname.ts
|
|
4607
|
-
var HS_HOSTNAME_REGEX = /^[a-z2-7]+\.anyone$/;
|
|
4608
|
-
var HS_HOSTNAME_MAX_LENGTH = 80;
|
|
4609
|
-
function isRoutableHsHostname(s) {
|
|
4610
|
-
return typeof s === "string" && s.length <= HS_HOSTNAME_MAX_LENGTH && HS_HOSTNAME_REGEX.test(s);
|
|
4611
|
-
}
|
|
4612
|
-
function assertRoutableHsHostname(hostname) {
|
|
4613
|
-
if (typeof hostname === "string" && /\.anon$/.test(hostname)) {
|
|
4614
|
-
throw new Error(
|
|
4615
|
-
`"${hostname}" is not a routable hidden-service address; use the .anyone TLD (e.g. "${hostname.replace(/\.anon$/, ".anyone")}"). The anon daemon only resolves hidden services under .anyone \u2014 a .anon name is treated as a clearnet address and fails (HostUnreachable).`
|
|
4616
|
-
);
|
|
4617
|
-
}
|
|
4618
|
-
if (!isRoutableHsHostname(hostname)) {
|
|
4619
|
-
throw new Error(
|
|
4620
|
-
`Invalid hidden-service hostname: ${JSON.stringify(hostname)}. Expected a base32 .anyone address matching ${HS_HOSTNAME_REGEX}.`
|
|
4621
|
-
);
|
|
4622
|
-
}
|
|
4623
|
-
return hostname;
|
|
4624
|
-
}
|
|
4625
|
-
|
|
4626
4555
|
// src/adapters/HttpConnectorAdmin.ts
|
|
4627
4556
|
var HttpConnectorAdmin = class {
|
|
4628
4557
|
adminUrl;
|
|
@@ -5361,6 +5290,75 @@ function buildPetPurchaseRequest(params) {
|
|
|
5361
5290
|
};
|
|
5362
5291
|
}
|
|
5363
5292
|
|
|
5293
|
+
// src/faucet.ts
|
|
5294
|
+
function faucetPath(chain) {
|
|
5295
|
+
switch (chain) {
|
|
5296
|
+
case "evm":
|
|
5297
|
+
return "/api/request";
|
|
5298
|
+
case "solana":
|
|
5299
|
+
return "/api/solana/request";
|
|
5300
|
+
case "mina":
|
|
5301
|
+
return "/api/mina/request";
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
async function fundWallet(faucetUrl, address, chain, options = {}) {
|
|
5305
|
+
if (!faucetUrl) {
|
|
5306
|
+
throw new Error("fundWallet: faucetUrl is required");
|
|
5307
|
+
}
|
|
5308
|
+
if (!address) {
|
|
5309
|
+
throw new Error("fundWallet: address is required");
|
|
5310
|
+
}
|
|
5311
|
+
if (chain === "solana" || chain === "mina") {
|
|
5312
|
+
throw new Error(
|
|
5313
|
+
`fundWallet: ${chain} faucet funding is deferred (WS3) \u2014 not yet implemented`
|
|
5314
|
+
);
|
|
5315
|
+
}
|
|
5316
|
+
const base = faucetUrl.replace(/\/+$/, "");
|
|
5317
|
+
const url = `${base}${faucetPath(chain)}`;
|
|
5318
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
5319
|
+
const timeout = options.timeout ?? 3e4;
|
|
5320
|
+
const controller = new AbortController();
|
|
5321
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
5322
|
+
let response;
|
|
5323
|
+
try {
|
|
5324
|
+
response = await fetchImpl(url, {
|
|
5325
|
+
method: "POST",
|
|
5326
|
+
headers: { "Content-Type": "application/json" },
|
|
5327
|
+
body: JSON.stringify({ address }),
|
|
5328
|
+
signal: controller.signal
|
|
5329
|
+
});
|
|
5330
|
+
} catch (error) {
|
|
5331
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
5332
|
+
throw new NetworkError(
|
|
5333
|
+
`Faucet request timed out after ${timeout}ms (${url})`,
|
|
5334
|
+
error
|
|
5335
|
+
);
|
|
5336
|
+
}
|
|
5337
|
+
throw new NetworkError(
|
|
5338
|
+
`Faucet request failed (${url}): ${error instanceof Error ? error.message : String(error)}`,
|
|
5339
|
+
error instanceof Error ? error : void 0
|
|
5340
|
+
);
|
|
5341
|
+
} finally {
|
|
5342
|
+
clearTimeout(timeoutId);
|
|
5343
|
+
}
|
|
5344
|
+
if (!response.ok) {
|
|
5345
|
+
const detail = await response.text().catch(() => "");
|
|
5346
|
+
throw new NetworkError(
|
|
5347
|
+
`Faucet responded ${response.status} ${response.statusText}${detail ? `: ${detail}` : ""} (${url})`
|
|
5348
|
+
);
|
|
5349
|
+
}
|
|
5350
|
+
const body = await response.text().catch(() => "");
|
|
5351
|
+
let parsed = body;
|
|
5352
|
+
if (body) {
|
|
5353
|
+
try {
|
|
5354
|
+
parsed = JSON.parse(body);
|
|
5355
|
+
} catch {
|
|
5356
|
+
parsed = body;
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5359
|
+
return { chain, address, response: parsed };
|
|
5360
|
+
}
|
|
5361
|
+
|
|
5364
5362
|
// src/keys/KeyManager.ts
|
|
5365
5363
|
import { finalizeEvent as finalizeEvent2 } from "nostr-tools/pure";
|
|
5366
5364
|
import { nip19 } from "nostr-tools";
|
|
@@ -6401,14 +6399,10 @@ function writeKeystoreFile(path, keystore) {
|
|
|
6401
6399
|
});
|
|
6402
6400
|
}
|
|
6403
6401
|
export {
|
|
6404
|
-
ANON_ASSETS,
|
|
6405
|
-
ANON_VERSION,
|
|
6406
6402
|
BtpRuntimeClient,
|
|
6407
6403
|
ChannelManager,
|
|
6408
6404
|
ConnectorError,
|
|
6409
6405
|
EvmSigner,
|
|
6410
|
-
HS_HOSTNAME_MAX_LENGTH,
|
|
6411
|
-
HS_HOSTNAME_REGEX,
|
|
6412
6406
|
Http402Client,
|
|
6413
6407
|
HttpConnectorAdmin,
|
|
6414
6408
|
HttpIlpClient,
|
|
@@ -6426,13 +6420,13 @@ export {
|
|
|
6426
6420
|
ValidationError,
|
|
6427
6421
|
applyDefaults,
|
|
6428
6422
|
applyNetworkPresets,
|
|
6429
|
-
assertRoutableHsHostname,
|
|
6430
6423
|
buildBackupEvent,
|
|
6431
6424
|
buildBackupFilter,
|
|
6432
6425
|
buildPetInteractionRequest,
|
|
6433
6426
|
buildPetListingEvent,
|
|
6434
6427
|
buildPetPurchaseRequest,
|
|
6435
6428
|
buildSettlementInfo,
|
|
6429
|
+
buildStoreWriteEnvelope,
|
|
6436
6430
|
decryptMnemonic2 as decryptMnemonic,
|
|
6437
6431
|
deriveFromNsec,
|
|
6438
6432
|
deriveFullIdentity,
|
|
@@ -6440,6 +6434,7 @@ export {
|
|
|
6440
6434
|
encryptMnemonic2 as encryptMnemonic,
|
|
6441
6435
|
filterPetDvmProviders,
|
|
6442
6436
|
filterPetListings,
|
|
6437
|
+
fundWallet,
|
|
6443
6438
|
generateKeystore,
|
|
6444
6439
|
generateMnemonic,
|
|
6445
6440
|
generateRandomIdentity,
|
|
@@ -6447,7 +6442,6 @@ export {
|
|
|
6447
6442
|
httpEndpointToBtpUrl,
|
|
6448
6443
|
importKeystore,
|
|
6449
6444
|
isPrfSupported,
|
|
6450
|
-
isRoutableHsHostname,
|
|
6451
6445
|
loadKeystore,
|
|
6452
6446
|
parseBackupPayload,
|
|
6453
6447
|
parseHttpResponse,
|
|
@@ -6456,13 +6450,12 @@ export {
|
|
|
6456
6450
|
parsePetListing,
|
|
6457
6451
|
parseX402Body,
|
|
6458
6452
|
parseX402Challenge,
|
|
6453
|
+
proxyIlpEndpoint,
|
|
6459
6454
|
readDiscoveredIlpPeer,
|
|
6460
6455
|
readMinaDepositTotal,
|
|
6461
6456
|
requestBlobStorage,
|
|
6462
|
-
selectAnonAsset,
|
|
6463
6457
|
selectIlpTransport,
|
|
6464
6458
|
serializeHttpRequest,
|
|
6465
|
-
startManagedAnonProxy,
|
|
6466
6459
|
validateConfig,
|
|
6467
6460
|
validateMnemonic,
|
|
6468
6461
|
withRetry,
|