@toon-protocol/rig 3.6.0 → 4.0.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 (34) hide show
  1. package/README.md +112 -152
  2. package/dist/chunk-CDSFVZDV.js +290 -0
  3. package/dist/chunk-CDSFVZDV.js.map +1 -0
  4. package/dist/{chunk-B5ISARMU.js → chunk-GVXBUL3C.js} +15 -2
  5. package/dist/chunk-GVXBUL3C.js.map +1 -0
  6. package/dist/chunk-LTFMPOHU.js +194 -0
  7. package/dist/chunk-LTFMPOHU.js.map +1 -0
  8. package/dist/{chunk-LCYCKWAT.js → chunk-YZRR2UO6.js} +86 -5
  9. package/dist/chunk-YZRR2UO6.js.map +1 -0
  10. package/dist/{chunk-HJDPM37T.js → chunk-ZZBA5VVL.js} +11 -7
  11. package/dist/{chunk-HJDPM37T.js.map → chunk-ZZBA5VVL.js.map} +1 -1
  12. package/dist/cli/rig.js +290 -523
  13. package/dist/cli/rig.js.map +1 -1
  14. package/dist/index.d.ts +3 -115
  15. package/dist/index.js +9 -121
  16. package/dist/index.js.map +1 -1
  17. package/dist/{publisher-BFcnZeJI.d.ts → publisher-CcL96ugq.d.ts} +58 -1
  18. package/dist/standalone/index.d.ts +241 -438
  19. package/dist/standalone/index.js +19 -11
  20. package/dist/standalone-mode-LEAC4A2L.js +390 -0
  21. package/dist/standalone-mode-LEAC4A2L.js.map +1 -0
  22. package/package.json +5 -4
  23. package/dist/chunk-B5ISARMU.js.map +0 -1
  24. package/dist/chunk-IZ6KLYQ6.js +0 -724
  25. package/dist/chunk-IZ6KLYQ6.js.map +0 -1
  26. package/dist/chunk-LCYCKWAT.js.map +0 -1
  27. package/dist/chunk-PWNZWQOH.js +0 -404
  28. package/dist/chunk-PWNZWQOH.js.map +0 -1
  29. package/dist/chunk-UZZ2RN7A.js +0 -469
  30. package/dist/chunk-UZZ2RN7A.js.map +0 -1
  31. package/dist/network-bootstrap-27FYE3N7.js +0 -40
  32. package/dist/network-bootstrap-27FYE3N7.js.map +0 -1
  33. package/dist/standalone-mode-5MNNJC2D.js +0 -928
  34. package/dist/standalone-mode-5MNNJC2D.js.map +0 -1
package/dist/cli/rig.js CHANGED
@@ -18,34 +18,17 @@ import {
18
18
  setHeadSymref,
19
19
  updateRef,
20
20
  writeGitObjects
21
- } from "../chunk-HJDPM37T.js";
21
+ } from "../chunk-ZZBA5VVL.js";
22
22
  import {
23
23
  DEFAULT_KEYSTORE_PASSWORD,
24
- MinaZkAppStore,
25
24
  MissingIdentityError,
26
- TOPOLOGY_CACHE_FILENAME,
27
25
  clientConfigPath,
28
26
  clientKeystorePath,
29
27
  linkKeystoreInClientConfig,
30
28
  readClientConfigFile,
31
29
  resolveAccountIndex,
32
30
  resolveIdentity
33
- } from "../chunk-PWNZWQOH.js";
34
- import {
35
- ChannelMapStore,
36
- RIG_STANDALONE_ENV,
37
- channelStatus,
38
- defaultDaemonPort,
39
- resolveChannelPaths,
40
- resolveConflictingPath,
41
- standaloneForced
42
- } from "../chunk-LCYCKWAT.js";
43
- import {
44
- MAX_OBJECT_SIZE
45
- } from "../chunk-B5ISARMU.js";
46
- import {
47
- minaPresetForChain
48
- } from "../chunk-UZZ2RN7A.js";
31
+ } from "../chunk-LTFMPOHU.js";
49
32
  import {
50
33
  ARWEAVE_GATEWAYS,
51
34
  COMMENT_KIND,
@@ -59,6 +42,20 @@ import {
59
42
  parseMaintainers,
60
43
  queryRelay
61
44
  } from "../chunk-2KJJ7LSO.js";
45
+ import {
46
+ ChannelMapStore,
47
+ RIG_STANDALONE_ENV,
48
+ channelStatus,
49
+ defaultDaemonPort,
50
+ deriveNostrKeyFromMnemonic,
51
+ resolveChannelPaths,
52
+ resolveConflictingPath,
53
+ standaloneForced
54
+ } from "../chunk-YZRR2UO6.js";
55
+ import {
56
+ MAX_OBJECT_SIZE,
57
+ uploadChargeFor
58
+ } from "../chunk-GVXBUL3C.js";
62
59
 
63
60
  // src/cli/rig.ts
64
61
  import { createInterface as createInterface2 } from "readline/promises";
@@ -624,6 +621,21 @@ function generateRigPointerHtml(options) {
624
621
  `;
625
622
  }
626
623
 
624
+ // src/gateway-preference.ts
625
+ var TESTNET_GATEWAY = /(^|\.)ar-io\.dev$/i;
626
+ function isMainnetGateway(url) {
627
+ try {
628
+ return !TESTNET_GATEWAY.test(new URL(url).hostname);
629
+ } catch {
630
+ return false;
631
+ }
632
+ }
633
+ var PREFERRED_GATEWAY = ARWEAVE_GATEWAYS.find(isMainnetGateway) ?? "https://arweave.net";
634
+ function mirrorGatewaysFor(primary) {
635
+ const p = primary.replace(/\/+$/, "");
636
+ return ARWEAVE_GATEWAYS.filter((g) => g.replace(/\/+$/, "") !== p);
637
+ }
638
+
627
639
  // src/cli/rig-pointer-record.ts
628
640
  import { mkdirSync, readFileSync, writeFileSync } from "fs";
629
641
  import { homedir } from "os";
@@ -1098,7 +1110,7 @@ function loadPaidSession(deps, relayUrl) {
1098
1110
  });
1099
1111
  }
1100
1112
  var defaultLoadStandalone = async (options) => {
1101
- const mod = await import("../standalone-mode-5MNNJC2D.js");
1113
+ const mod = await import("../standalone-mode-LEAC4A2L.js");
1102
1114
  return mod.createStandaloneContext(options);
1103
1115
  };
1104
1116
  function identityReport(ctx) {
@@ -1240,11 +1252,10 @@ function parsePushArgs(args) {
1240
1252
  return flags;
1241
1253
  }
1242
1254
  function pointerGateway(env) {
1243
- const preferred = ARWEAVE_GATEWAYS[0] ?? "https://arweave.net";
1244
- return (env["RIG_ARWEAVE_GATEWAY"] ?? preferred).replace(/\/+$/, "");
1255
+ return (env["RIG_ARWEAVE_GATEWAY"] ?? PREFERRED_GATEWAY).replace(/\/+$/, "");
1245
1256
  }
1246
1257
  function mirrorGateways(primary) {
1247
- return ARWEAVE_GATEWAYS.filter((g) => g.replace(/\/+$/, "") !== primary);
1258
+ return mirrorGatewaysFor(primary);
1248
1259
  }
1249
1260
  function planRigPointer(args) {
1250
1261
  const html = generateRigPointerHtml({
@@ -1280,7 +1291,7 @@ function planRigPointer(args) {
1280
1291
  html,
1281
1292
  contentHash,
1282
1293
  bytes,
1283
- fee: args.uploadFee
1294
+ fee: uploadChargeFor(args.feeRates, bytes)
1284
1295
  };
1285
1296
  }
1286
1297
  async function runPush(args, deps) {
@@ -1401,7 +1412,7 @@ async function runPush(args, deps) {
1401
1412
  ownerPubkey: ctx.ownerPubkey,
1402
1413
  repoId,
1403
1414
  relay: relaysUsed[0],
1404
- uploadFee: feeRates.uploadFee
1415
+ feeRates
1405
1416
  });
1406
1417
  }
1407
1418
  } else {
@@ -2041,9 +2052,6 @@ async function runChain(args, deps) {
2041
2052
  }
2042
2053
 
2043
2054
  // src/cli/channel.ts
2044
- import { readFileSync as readFileSync3 } from "fs";
2045
- import { homedir as homedir3 } from "os";
2046
- import { join as join3 } from "path";
2047
2055
  import { parseArgs as parseArgs5 } from "util";
2048
2056
  var CHANNEL_USAGE = `Usage: rig channel <subcommand>
2049
2057
 
@@ -2066,17 +2074,6 @@ Subcommands:
2066
2074
  apex); --deposit adds that much extra collateral after the
2067
2075
  open/resume. On-chain: asks for confirmation (--yes skips).
2068
2076
 
2069
- deploy-zkapp [--graphql-url <url>]
2070
- deploy a dedicated Mina PaymentChannel zkApp for THIS
2071
- identity (the zkApp is single-pair; Mina channels open on
2072
- an identity-owned deployment). Normally automatic \u2014 the
2073
- Mina open path deploys one when needed \u2014 this explicit
2074
- form pre-deploys it (compile \u22481-3 min, inclusion \u22483-6 min).
2075
- On-chain: costs the 1 MINA account-creation fee + tx fee
2076
- from the wallet's MINA. The zkApp key is saved under
2077
- TOON_CLIENT_HOME/keys/. Asks for confirmation (--yes
2078
- skips).
2079
-
2080
2077
  close <channelId>
2081
2078
  close a recorded channel \u2014 an on-chain tx that starts the
2082
2079
  settlement challenge window (the peer's settlementTimeout).
@@ -2100,8 +2097,6 @@ async function runChannel(args, deps) {
2100
2097
  return runChannelList(rest, deps);
2101
2098
  case "open":
2102
2099
  return runChannelOpen(rest, deps);
2103
- case "deploy-zkapp":
2104
- return runChannelDeployZkApp(rest, deps);
2105
2100
  case "close":
2106
2101
  return runChannelWithdrawStep(rest, deps, "close");
2107
2102
  case "settle":
@@ -2294,9 +2289,6 @@ async function runChannelOpen(args, deps) {
2294
2289
  io2.out(
2295
2290
  "If a live channel is already recorded for this peer it is RESUMED (no on-chain spend); otherwise an on-chain channel open locks the peer-negotiated initial deposit from your wallet (plus gas)."
2296
2291
  );
2297
- io2.out(
2298
- "On a Mina chain a first open may also deploy a dedicated PaymentChannel zkApp for this identity (~1.1 MINA + fees; compile \u22481-3 min, inclusion \u22483-6 min \u2014 progress is printed)."
2299
- );
2300
2292
  }
2301
2293
  const gate = await confirmOnChain(
2302
2294
  io2,
@@ -2355,160 +2347,6 @@ async function runChannelOpen(args, deps) {
2355
2347
  await stopQuietly(ctx);
2356
2348
  }
2357
2349
  }
2358
- async function runChannelDeployZkApp(args, deps) {
2359
- const { io: io2, env } = deps;
2360
- let graphqlFlag;
2361
- let yes = false;
2362
- let json = false;
2363
- try {
2364
- const { values } = parseArgs5({
2365
- args,
2366
- options: {
2367
- "graphql-url": { type: "string" },
2368
- yes: { type: "boolean", default: false },
2369
- json: { type: "boolean", default: false },
2370
- help: { type: "boolean", short: "h", default: false }
2371
- }
2372
- });
2373
- if (values.help) {
2374
- io2.out(CHANNEL_USAGE);
2375
- return 0;
2376
- }
2377
- graphqlFlag = values["graphql-url"];
2378
- yes = values.yes ?? false;
2379
- json = values.json ?? false;
2380
- } catch (err) {
2381
- io2.err(err instanceof Error ? err.message : String(err));
2382
- io2.err(CHANNEL_USAGE);
2383
- return 2;
2384
- }
2385
- try {
2386
- const dir = env["TOON_CLIENT_HOME"] ?? join3(homedir3(), ".toon-client");
2387
- let file = {};
2388
- try {
2389
- file = JSON.parse(readFileSync3(join3(dir, "config.json"), "utf8"));
2390
- } catch {
2391
- }
2392
- const pinned = env["TOON_CLIENT_CHAIN"] ?? file.chain;
2393
- const chain = pinned !== void 0 && pinned.startsWith("mina:") ? pinned : "mina:devnet";
2394
- const graphqlUrl = graphqlFlag ?? file.minaChannel?.graphqlUrl ?? minaPresetForChain(chain)?.graphqlUrl;
2395
- if (!graphqlUrl) {
2396
- throw new Error(
2397
- `no Mina GraphQL endpoint for ${chain} \u2014 pass --graphql-url or set minaChannel.graphqlUrl in the client config`
2398
- );
2399
- }
2400
- const resolved = await resolveIdentity({
2401
- env,
2402
- cwd: deps.cwd,
2403
- warn: (line) => io2.err(line)
2404
- });
2405
- const identity = {
2406
- pubkey: resolved.pubkey,
2407
- source: resolved.source,
2408
- sourceLabel: resolved.sourceLabel
2409
- };
2410
- const store = MinaZkAppStore.forHome(dir);
2411
- const existing = store.lookup(resolved.pubkey, chain);
2412
- if (existing) {
2413
- if (json) {
2414
- io2.emitJson({
2415
- command: "channel deploy-zkapp",
2416
- identity,
2417
- executed: false,
2418
- plan: { chain, graphqlUrl },
2419
- result: {
2420
- zkAppAddress: existing.zkAppAddress,
2421
- deployTxHash: existing.deployTxHash ?? null,
2422
- vkHash: existing.vkHash ?? null,
2423
- storePath: store.filePath
2424
- },
2425
- hint: "a zkApp is already recorded for this identity/chain \u2014 the open path reuses it"
2426
- });
2427
- return 0;
2428
- }
2429
- io2.out(
2430
- `A Mina zkApp is already recorded for this identity on ${chain}: ` + existing.zkAppAddress
2431
- );
2432
- io2.out(`The open path reuses it (record: ${store.filePath}).`);
2433
- return 0;
2434
- }
2435
- const plan = { chain, graphqlUrl };
2436
- if (!json) {
2437
- io2.out("Mina zkApp deploy plan:");
2438
- io2.out(` chain ${chain}`);
2439
- io2.out(` graphql ${graphqlUrl}`);
2440
- io2.out(renderIdentityLine(identity));
2441
- io2.out(
2442
- "Deploys a dedicated PaymentChannel zkApp for this identity \u2014 on-chain: the 1 MINA account-creation fee + a 0.1 MINA tx fee from your wallet. Compile \u22481-3 min; inclusion \u22483-6 min."
2443
- );
2444
- }
2445
- const gate = await confirmOnChain(
2446
- io2,
2447
- { yes, json },
2448
- "Proceed with the on-chain zkApp deploy? [y/N] "
2449
- );
2450
- if (gate === "json-plan") {
2451
- io2.emitJson({
2452
- command: "channel deploy-zkapp",
2453
- identity,
2454
- executed: false,
2455
- plan,
2456
- hint: "plan only \u2014 re-run with --yes to deploy (on-chain: ~1.1 MINA + fees)"
2457
- });
2458
- return 0;
2459
- }
2460
- if (gate !== "proceed") return gate;
2461
- const client = await import("@toon-protocol/client");
2462
- const derived = await client.deriveFullIdentity(
2463
- resolved.mnemonic,
2464
- resolved.accountIndex
2465
- );
2466
- if (!derived.mina.privateKey) {
2467
- throw new Error(
2468
- "no Mina key derived \u2014 the optional `mina-signer` dependency is not installed"
2469
- );
2470
- }
2471
- const record = await client.deployMinaChannelZkApp({
2472
- graphqlUrl,
2473
- payerPrivateKey: derived.mina.privateKey,
2474
- onProgress: (line) => io2.err(`rig: mina: ${line}`)
2475
- });
2476
- store.save({
2477
- identity: resolved.pubkey,
2478
- chain,
2479
- zkAppAddress: record.zkAppAddress,
2480
- zkAppPrivateKey: record.zkAppPrivateKey,
2481
- feePayer: record.feePayer,
2482
- ...record.deployTxHash !== void 0 ? { deployTxHash: record.deployTxHash } : {},
2483
- ...record.vkHash !== void 0 ? { vkHash: record.vkHash } : {},
2484
- deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
2485
- source: "rig channel deploy-zkapp (npm @toon-protocol/mina-zkapp build)"
2486
- });
2487
- if (json) {
2488
- io2.emitJson({
2489
- command: "channel deploy-zkapp",
2490
- identity,
2491
- executed: true,
2492
- plan,
2493
- result: {
2494
- zkAppAddress: record.zkAppAddress,
2495
- deployTxHash: record.deployTxHash ?? null,
2496
- vkHash: record.vkHash ?? null,
2497
- storePath: store.filePath
2498
- }
2499
- });
2500
- return 0;
2501
- }
2502
- io2.out(`Deployed Mina PaymentChannel zkApp ${record.zkAppAddress}.`);
2503
- if (record.deployTxHash) io2.out(` deploy tx ${record.deployTxHash}`);
2504
- if (record.vkHash) io2.out(` vk hash ${record.vkHash}`);
2505
- io2.out(` record ${store.filePath} (holds the zkApp key \u2014 back it up)`);
2506
- io2.out("The next Mina channel open/push finds and reuses this zkApp.");
2507
- return 0;
2508
- } catch (err) {
2509
- return emitCliError(io2, json, "channel deploy-zkapp", err);
2510
- }
2511
- }
2512
2350
  function withdrawPrecheck(step, channelId, watermark, nowSec) {
2513
2351
  const status = channelStatus(watermark, nowSec);
2514
2352
  if (status === "settled") {
@@ -2678,7 +2516,7 @@ async function stopQuietly(ctx) {
2678
2516
 
2679
2517
  // src/cli/clone.ts
2680
2518
  import { mkdtemp, mkdir, readdir, rename, rm, rmdir } from "fs/promises";
2681
- import { basename, dirname as dirname2, join as join4, resolve } from "path";
2519
+ import { basename, dirname as dirname2, join as join3, resolve } from "path";
2682
2520
  import { parseArgs as parseArgs6 } from "util";
2683
2521
  var CLONE_USAGE = `Usage: rig clone <relay-url> <owner>/<repo-id> [dir] [options]
2684
2522
 
@@ -2849,7 +2687,7 @@ async function runClone(args, deps) {
2849
2687
  }
2850
2688
  const parent = dirname2(dest);
2851
2689
  await mkdir(parent, { recursive: true });
2852
- tempDir = await mkdtemp(join4(parent, `.${basename(dest)}.rig-clone-`));
2690
+ tempDir = await mkdtemp(join3(parent, `.${basename(dest)}.rig-clone-`));
2853
2691
  await runGit(tempDir, [
2854
2692
  "init",
2855
2693
  "--quiet",
@@ -4102,48 +3940,39 @@ async function warnIfNotMaintainer(deps, args) {
4102
3940
  }
4103
3941
 
4104
3942
  // src/cli/entry.ts
4105
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
4106
- import { homedir as homedir4 } from "os";
4107
- import { dirname as dirname3, join as join5 } from "path";
3943
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
3944
+ import { homedir as homedir3 } from "os";
3945
+ import { dirname as dirname3, join as join4 } from "path";
4108
3946
  import { parseArgs as parseArgs9 } from "util";
4109
- var SANDBOX_BTP_URL = "wss://proxy.sandbox.devnet.toonprotocol.dev:443";
4110
- var SANDBOX_RELAY_URL = "wss://relay-ws.sandbox.devnet.toonprotocol.dev";
4111
- var ENTRY_USAGE = `Usage: rig entry [apex | sandbox | <wss-url>] [options]
3947
+ var ENTRY_USAGE = `Usage: rig entry [<connector-url> | clear] [options]
4112
3948
 
4113
- Choose which network entry node (payment ingress + relay) rig talks to. Free:
4114
- only the local config file is touched.
3949
+ Name the TOON connector rig pays. A connector describes itself on GET /ilp
3950
+ (its addresses, routes and prices, settlement chains), so its URL is the
3951
+ whole configuration. Free: only the local config file is touched.
4115
3952
 
4116
- rig entry show the effective entry endpoints and their source
4117
- rig entry apex revert to the default apex: clears the btpUrl/
4118
- relayUrl override so core's genesis seed (or a live
4119
- announce) applies \u2014 settles evm | sol | mina
4120
- rig entry sandbox the devnet sandbox entry (Mina USDC ONLY \u2014 the
4121
- cross-currency multihop demo path):
4122
- btp ${SANDBOX_BTP_URL}
4123
- relay ${SANDBOX_RELAY_URL}
4124
- rig entry <wss-url> an explicit BTP endpoint (ws:// or wss://); pass
4125
- --relay <url> to also set the relay
3953
+ rig entry show the effective connector + relay and their source
3954
+ rig entry <connector-url> record the node's client-edge URL (https://\u2026);
3955
+ pass --relay <wss-url> to also record its free-read relay
3956
+ rig entry clear forget the recorded connector (and relay)
4126
3957
 
4127
- Switching entries deletes the cached topology (the next paid command
4128
- re-discovers the new entry's announce) and leaves existing payment channels
4129
- behind \u2014 channels are per-entry-peer; the next paid command opens or resumes
4130
- one with the new peer.
3958
+ Existing payment channels are per node: after switching, the next paid
3959
+ command opens or adopts a channel with the new node.
4131
3960
 
4132
3961
  NOTE for repos: the relay a repo publishes to is its git \`origin\` remote,
4133
- which OVERRIDES the config relayUrl. After switching entries, point the repo
4134
- too: \`rig remote add origin <relay-url>\` (or use a fresh repo).
3962
+ which OVERRIDES the config relayUrl. After switching, point the repo too:
3963
+ \`rig remote add origin <relay-url>\` (or use a fresh repo).
4135
3964
 
4136
3965
  Options:
4137
- --relay <url> with <wss-url>: also set the relay URL
3966
+ --relay <url> with <connector-url>: also record the relay URL (ws:// or wss://)
4138
3967
  --json machine-readable envelope
4139
3968
  -h, --help show this help`;
4140
3969
  function configPathFor2(env) {
4141
- const dir = env["TOON_CLIENT_HOME"] ?? join5(homedir4(), ".toon-client");
4142
- return join5(dir, "config.json");
3970
+ const dir = env["TOON_CLIENT_HOME"] ?? join4(homedir3(), ".toon-client");
3971
+ return join4(dir, "config.json");
4143
3972
  }
4144
3973
  function readEntryConfig(configPath) {
4145
3974
  try {
4146
- return JSON.parse(readFileSync4(configPath, "utf8"));
3975
+ return JSON.parse(readFileSync3(configPath, "utf8"));
4147
3976
  } catch (err) {
4148
3977
  if (err.code === "ENOENT") return {};
4149
3978
  throw new Error(
@@ -4156,20 +3985,28 @@ function writeEntryConfig(configPath, file) {
4156
3985
  writeFileSync3(configPath, `${JSON.stringify(file, null, 2)}
4157
3986
  `, "utf8");
4158
3987
  }
4159
- async function loadGenesisSeedDefault() {
4160
- try {
4161
- const { loadGenesisSeed } = await import("../network-bootstrap-27FYE3N7.js");
4162
- return loadGenesisSeed();
4163
- } catch {
4164
- return void 0;
4165
- }
4166
- }
4167
- function classifyEntry(btpUrl, seedBtp, btpSource) {
4168
- if (btpUrl === null) return null;
4169
- if (btpUrl === SANDBOX_BTP_URL) return "sandbox";
4170
- if (btpSource === "genesis-seed" || btpUrl === seedBtp) return "apex";
4171
- return "custom";
4172
- }
3988
+ function effectiveEntry(env, file) {
3989
+ let connectorUrl = null;
3990
+ let connectorSource = null;
3991
+ if (env["TOON_CONNECTOR"]) {
3992
+ connectorUrl = env["TOON_CONNECTOR"];
3993
+ connectorSource = "env";
3994
+ } else if (env["TOON_CLIENT_PROXY_URL"]) {
3995
+ connectorUrl = env["TOON_CLIENT_PROXY_URL"];
3996
+ connectorSource = "legacy-env";
3997
+ } else if (file.connectorUrl) {
3998
+ connectorUrl = file.connectorUrl;
3999
+ connectorSource = "config";
4000
+ } else if (file.proxyUrl) {
4001
+ connectorUrl = file.proxyUrl;
4002
+ connectorSource = "legacy-config";
4003
+ }
4004
+ const relayUrl = env["TOON_CLIENT_RELAY_URL"] ?? file.relayUrl ?? null;
4005
+ const relaySource = env["TOON_CLIENT_RELAY_URL"] ? "env" : file.relayUrl ? "config" : null;
4006
+ return { connectorUrl, connectorSource, relayUrl, relaySource };
4007
+ }
4008
+ var HTTP_URL = /^https?:\/\/.+/i;
4009
+ var WS_URL = /^wss?:\/\/.+/i;
4173
4010
  async function runEntry(args, deps) {
4174
4011
  const { io: io2, env } = deps;
4175
4012
  let positionals;
@@ -4199,7 +4036,7 @@ async function runEntry(args, deps) {
4199
4036
  }
4200
4037
  if (positionals.length > 1) {
4201
4038
  io2.err(
4202
- `rig entry takes at most one argument, got ${positionals.length}: ${positionals.join(" ")}`
4039
+ `rig entry takes at most one argument, got ${String(positionals.length)}: ${positionals.join(" ")}`
4203
4040
  );
4204
4041
  io2.err(ENTRY_USAGE);
4205
4042
  return 2;
@@ -4207,36 +4044,33 @@ async function runEntry(args, deps) {
4207
4044
  const target = positionals[0];
4208
4045
  let mutation;
4209
4046
  if (target !== void 0) {
4210
- if (target === "apex") {
4047
+ if (target === "clear") {
4211
4048
  if (relayFlag !== void 0) {
4212
- io2.err("--relay only applies to an explicit <wss-url> entry");
4049
+ io2.err("--relay only applies to a <connector-url> entry");
4213
4050
  io2.err(ENTRY_USAGE);
4214
4051
  return 2;
4215
4052
  }
4216
- mutation = { kind: "apex" };
4217
- } else if (target === "sandbox") {
4218
- if (relayFlag !== void 0) {
4219
- io2.err("--relay only applies to an explicit <wss-url> entry");
4220
- io2.err(ENTRY_USAGE);
4221
- return 2;
4222
- }
4223
- mutation = { kind: "sandbox" };
4224
- } else if (/^wss?:\/\/.+/.test(target)) {
4225
- if (relayFlag !== void 0 && !/^wss?:\/\/.+/.test(relayFlag)) {
4226
- io2.err(
4227
- `--relay must be a ws(s) URL, got ${JSON.stringify(relayFlag)}`
4228
- );
4053
+ mutation = { kind: "clear" };
4054
+ } else if (HTTP_URL.test(target)) {
4055
+ if (relayFlag !== void 0 && !WS_URL.test(relayFlag)) {
4056
+ io2.err(`--relay must be a ws(s) URL, got ${JSON.stringify(relayFlag)}`);
4229
4057
  io2.err(ENTRY_USAGE);
4230
4058
  return 2;
4231
4059
  }
4232
4060
  mutation = {
4233
4061
  kind: "url",
4234
- btpUrl: target,
4062
+ connectorUrl: target.replace(/\/+$/, ""),
4235
4063
  ...relayFlag !== void 0 ? { relayUrl: relayFlag } : {}
4236
4064
  };
4065
+ } else if (WS_URL.test(target)) {
4066
+ io2.err(
4067
+ `${JSON.stringify(target)} is a WebSocket URL \u2014 the entry is the connector's http(s) URL (the one whose GET /ilp describes it); pass the relay with --relay`
4068
+ );
4069
+ io2.err(ENTRY_USAGE);
4070
+ return 2;
4237
4071
  } else {
4238
4072
  io2.err(
4239
- `unknown entry ${JSON.stringify(target)} \u2014 expected \`apex\`, \`sandbox\`, or a ws(s):// URL`
4073
+ `unknown entry ${JSON.stringify(target)} \u2014 expected a connector http(s):// URL or \`clear\``
4240
4074
  );
4241
4075
  io2.err(ENTRY_USAGE);
4242
4076
  return 2;
@@ -4245,136 +4079,78 @@ async function runEntry(args, deps) {
4245
4079
  try {
4246
4080
  const configPath = configPathFor2(env);
4247
4081
  const file = readEntryConfig(configPath);
4248
- const seed = await (deps.loadGenesisSeed ?? loadGenesisSeedDefault)();
4249
- const effective = () => {
4250
- const btpExplicit = env["TOON_CLIENT_PROXY_URL"] ?? env["TOON_CLIENT_BTP_URL"] ?? file.proxyUrl ?? file.btpUrl;
4251
- const btpFromEnv = env["TOON_CLIENT_PROXY_URL"] ?? env["TOON_CLIENT_BTP_URL"];
4252
- const relayExplicit = env["TOON_CLIENT_RELAY_URL"] ?? file.relayUrl;
4253
- return {
4254
- btpUrl: btpExplicit ?? seed?.btpEndpoint ?? null,
4255
- btpSource: btpExplicit ? btpFromEnv ? "env" : "config" : seed?.btpEndpoint ? "genesis-seed" : null,
4256
- relayUrl: relayExplicit ?? seed?.relayUrl ?? null,
4257
- relaySource: env["TOON_CLIENT_RELAY_URL"] ? "env" : file.relayUrl ? "config" : seed?.relayUrl ? "genesis-seed" : null
4258
- };
4259
- };
4082
+ const label = (source) => source === "env" ? "env" : source === "legacy-env" ? "env (TOON_CLIENT_PROXY_URL, pre-4.0 spelling \u2014 set TOON_CONNECTOR)" : source === "config" ? `config (${configPath})` : source === "legacy-config" ? `config proxyUrl (${configPath}, pre-4.0 spelling)` : "not configured";
4260
4083
  if (mutation === void 0) {
4261
- const state2 = effective();
4262
- const entry = classifyEntry(state2.btpUrl, seed?.btpEndpoint, state2.btpSource);
4084
+ const state2 = effectiveEntry(env, file);
4263
4085
  if (json) {
4264
4086
  io2.emitJson({
4265
4087
  command: "entry",
4266
- entry,
4267
- btpUrl: state2.btpUrl,
4268
- btpSource: state2.btpSource,
4269
- relayUrl: state2.relayUrl,
4270
- relaySource: state2.relaySource,
4088
+ ...state2,
4271
4089
  configPath
4272
4090
  });
4273
4091
  return 0;
4274
4092
  }
4275
- const label = (source) => source === "env" ? "env" : source === "config" ? `config (${configPath})` : source === "genesis-seed" ? "default apex \u2014 genesis seed" : "not configured";
4276
4093
  io2.out(
4277
- `Entry: ${entry ?? "(none)"}${entry === "sandbox" ? " (Mina USDC only \u2014 multihop demo path)" : ""}`
4094
+ `Connector ${state2.connectorUrl ?? "(none)"} [${label(state2.connectorSource)}]`
4278
4095
  );
4279
- io2.out(` btp ${state2.btpUrl ?? "(none)"} [${label(state2.btpSource)}]`);
4280
- io2.out(` relay ${state2.relayUrl ?? "(none)"} [${label(state2.relaySource)}]`);
4281
4096
  io2.out(
4282
- "Switch with `rig entry apex`, `rig entry sandbox`, or `rig entry <wss-url>`."
4097
+ `Relay ${state2.relayUrl ?? "(none)"} [${label(state2.relaySource)}]`
4283
4098
  );
4284
- return 0;
4285
- }
4286
- const warnings = [];
4287
- for (const envVar of [
4288
- "TOON_CLIENT_BTP_URL",
4289
- "TOON_CLIENT_PROXY_URL",
4290
- "TOON_CLIENT_RELAY_URL"
4291
- ]) {
4292
- if (env[envVar] !== void 0) {
4293
- warnings.push(
4294
- `${envVar}=${env[envVar]} is set in the environment and overrides the config value you just wrote \u2014 unset it for this entry to take effect.`
4099
+ if (!state2.connectorUrl) {
4100
+ io2.out(
4101
+ "Set one with `rig entry <connector-url>` (or export TOON_CONNECTOR)."
4295
4102
  );
4296
4103
  }
4104
+ return 0;
4297
4105
  }
4298
- warnings.push(
4299
- "Payment channels are per-entry-peer: existing channels (see `rig channels`) are not used with the new entry \u2014 the next paid command opens or resumes a channel with the new peer."
4300
- );
4301
- const hadProxyUrl = file.proxyUrl !== void 0;
4302
- let wroteBtp;
4303
- let wroteRelay;
4304
- if (mutation.kind === "apex") {
4305
- wroteBtp = null;
4306
- wroteRelay = null;
4307
- delete file.btpUrl;
4308
- delete file.relayUrl;
4309
- delete file.proxyUrl;
4310
- } else if (mutation.kind === "sandbox") {
4311
- wroteBtp = SANDBOX_BTP_URL;
4312
- wroteRelay = SANDBOX_RELAY_URL;
4313
- file.btpUrl = SANDBOX_BTP_URL;
4314
- file.relayUrl = SANDBOX_RELAY_URL;
4315
- delete file.proxyUrl;
4316
- } else {
4317
- wroteBtp = mutation.btpUrl;
4318
- wroteRelay = mutation.relayUrl ?? null;
4319
- file.btpUrl = mutation.btpUrl;
4320
- if (mutation.relayUrl !== void 0) file.relayUrl = mutation.relayUrl;
4321
- delete file.proxyUrl;
4322
- }
4323
- if (hadProxyUrl) {
4106
+ const warnings = [];
4107
+ const next = { ...file };
4108
+ if (file.proxyUrl !== void 0 || file.btpUrl !== void 0) {
4109
+ delete next.proxyUrl;
4110
+ delete next.btpUrl;
4324
4111
  warnings.push(
4325
- "Removed the legacy `proxyUrl` config field \u2014 it outranks `btpUrl` and would have silently kept the old entry."
4112
+ "removed the pre-4.0 proxyUrl/btpUrl fields (the connector URL replaces both)"
4326
4113
  );
4327
4114
  }
4328
- writeEntryConfig(configPath, file);
4329
- let clearedTopologyCache = false;
4330
- try {
4331
- unlinkSync(join5(dirname3(configPath), TOPOLOGY_CACHE_FILENAME));
4332
- clearedTopologyCache = true;
4333
- } catch {
4115
+ if (mutation.kind === "clear") {
4116
+ delete next.connectorUrl;
4117
+ delete next.relayUrl;
4118
+ } else {
4119
+ next.connectorUrl = mutation.connectorUrl;
4120
+ if (mutation.relayUrl !== void 0) next.relayUrl = mutation.relayUrl;
4334
4121
  }
4335
- if (mutation.kind === "sandbox") {
4336
- const effectiveChain = env["TOON_CLIENT_CHAIN"] ?? file.chain ?? file.supportedChains?.[0];
4337
- if (effectiveChain === void 0 || !effectiveChain.startsWith("mina")) {
4338
- warnings.push(
4339
- "The sandbox entry settles ONLY mina:devnet \u2014 run `rig chain set mina` " + (effectiveChain !== void 0 ? `(currently ${effectiveChain}).` : "to pin it.")
4340
- );
4341
- }
4122
+ if (env["TOON_CONNECTOR"] || env["TOON_CLIENT_PROXY_URL"]) {
4342
4123
  warnings.push(
4343
- `Repos publish to their git \`origin\` relay, which OVERRIDES the config relayUrl \u2014 for the sandbox demo run \`rig remote add origin ${SANDBOX_RELAY_URL}\` in the repo (or use a fresh repo).`
4124
+ "TOON_CONNECTOR / TOON_CLIENT_PROXY_URL is set in this shell and outranks the config file"
4344
4125
  );
4345
4126
  }
4346
- const state = effective();
4127
+ writeEntryConfig(configPath, next);
4128
+ const wrote = {
4129
+ connectorUrl: next.connectorUrl ?? null,
4130
+ relayUrl: next.relayUrl ?? null
4131
+ };
4132
+ const state = effectiveEntry(env, next);
4347
4133
  if (json) {
4348
4134
  io2.emitJson({
4349
4135
  command: "entry",
4350
- entry: mutation.kind === "url" ? "custom" : mutation.kind,
4351
- btpUrl: state.btpUrl,
4352
- btpSource: state.btpSource,
4353
- relayUrl: state.relayUrl,
4354
- relaySource: state.relaySource,
4355
- wrote: { btpUrl: wroteBtp, relayUrl: wroteRelay },
4356
- clearedTopologyCache,
4136
+ ...state,
4137
+ wrote,
4357
4138
  configPath,
4358
- ...warnings.length ? { warnings } : {}
4139
+ ...warnings.length > 0 ? { warnings } : {}
4359
4140
  });
4360
4141
  return 0;
4361
4142
  }
4362
- if (mutation.kind === "apex") {
4363
- io2.out("Entry reverted to the default apex (cleared btpUrl/relayUrl/proxyUrl).");
4364
- io2.out(` btp ${state.btpUrl ?? "(genesis seed unavailable)"}`);
4365
- io2.out(` relay ${state.relayUrl ?? "(genesis seed unavailable)"}`);
4366
- } else if (mutation.kind === "sandbox") {
4367
- io2.out("Entry set to the devnet sandbox (Mina USDC only \u2014 multihop demo path).");
4368
- io2.out(` btp ${SANDBOX_BTP_URL}`);
4369
- io2.out(` relay ${SANDBOX_RELAY_URL}`);
4143
+ if (mutation.kind === "clear") {
4144
+ io2.out(`Cleared the recorded connector in ${configPath}.`);
4370
4145
  } else {
4371
- io2.out(`Entry set to ${mutation.btpUrl}.`);
4372
- if (mutation.relayUrl !== void 0) io2.out(` relay ${mutation.relayUrl}`);
4146
+ io2.out(`Recorded connector ${mutation.connectorUrl} in ${configPath}.`);
4147
+ if (mutation.relayUrl !== void 0)
4148
+ io2.out(`Recorded relay ${mutation.relayUrl}.`);
4373
4149
  }
4150
+ for (const w of warnings) io2.out(`warning: ${w}`);
4374
4151
  io2.out(
4375
- `Saved to ${configPath}.` + (clearedTopologyCache ? " Cleared the cached topology." : "")
4152
+ `Effective connector: ${state.connectorUrl ?? "(none)"} [${label(state.connectorSource)}]`
4376
4153
  );
4377
- for (const w of warnings) io2.err(`warning: ${w}`);
4378
4154
  return 0;
4379
4155
  } catch (err) {
4380
4156
  return emitCliError(io2, json, "entry", err);
@@ -4601,21 +4377,20 @@ async function runFetch(args, deps) {
4601
4377
  }
4602
4378
 
4603
4379
  // src/cli/fund.ts
4604
- import { readFileSync as readFileSync5 } from "fs";
4605
- import { homedir as homedir5 } from "os";
4606
- import { join as join6 } from "path";
4380
+ import { readFileSync as readFileSync4 } from "fs";
4381
+ import { homedir as homedir4 } from "os";
4382
+ import { join as join5 } from "path";
4607
4383
  import { parseArgs as parseArgs11 } from "util";
4608
4384
  var DEVNET_FAUCET_URL = "https://faucet.devnet.toonprotocol.dev";
4609
- var CHAINS = ["evm", "solana", "mina"];
4385
+ var CHAINS = ["evm", "solana"];
4610
4386
  var CHAIN_ALIASES = {
4611
4387
  evm: "evm",
4612
4388
  eth: "evm",
4613
4389
  sol: "solana",
4614
4390
  solana: "solana",
4615
- mina: "mina",
4616
4391
  all: "all"
4617
4392
  };
4618
- var CHAIN_ARG_LIST2 = "evm | sol | solana | mina | all";
4393
+ var CHAIN_ARG_LIST2 = "evm | sol | solana | all";
4619
4394
  function resolveChainArg(raw) {
4620
4395
  if (raw === void 0) return void 0;
4621
4396
  const canonical = CHAIN_ALIASES[raw.toLowerCase()];
@@ -4681,13 +4456,8 @@ function sharedDevnetOrigin(env, file, originRelays = []) {
4681
4456
  }
4682
4457
  return void 0;
4683
4458
  }
4684
- async function loadGenesisSeedDefault2() {
4685
- try {
4686
- const { loadGenesisSeed } = await import("../network-bootstrap-27FYE3N7.js");
4687
- return loadGenesisSeed();
4688
- } catch {
4689
- return void 0;
4690
- }
4459
+ async function loadGenesisSeedDefault() {
4460
+ return void 0;
4691
4461
  }
4692
4462
  async function resolveEffectiveNetwork(opts) {
4693
4463
  const { env, cwd } = opts;
@@ -4705,7 +4475,7 @@ async function resolveEffectiveNetwork(opts) {
4705
4475
  ...originRelays
4706
4476
  ].some((url) => url !== void 0);
4707
4477
  if (!anyConfiguredOrigin) {
4708
- const seed = await (opts.loadGenesisSeed ?? loadGenesisSeedDefault2)();
4478
+ const seed = await (opts.loadGenesisSeed ?? loadGenesisSeedDefault)();
4709
4479
  devnetOrigin = devnetHost(seed?.relayUrl) ?? devnetHost(seed?.btpEndpoint);
4710
4480
  seededOrigin = devnetOrigin !== void 0;
4711
4481
  }
@@ -4748,11 +4518,11 @@ function noFaucetGuidance(network, devnetOrigin) {
4748
4518
  return `${head}. If you meant the shared devnet, set TOON_CLIENT_NETWORK=devnet and re-run \`rig fund\` \u2014 no faucet URL is needed there. If this is a self-hosted network with its own faucet, set TOON_CLIENT_FAUCET_URL (or the faucetUrl config field). ${external}`;
4749
4519
  }
4750
4520
  function readFundConfig(env) {
4751
- const dir = env["TOON_CLIENT_HOME"] ?? join6(homedir5(), ".toon-client");
4752
- const configPath = join6(dir, "config.json");
4521
+ const dir = env["TOON_CLIENT_HOME"] ?? join5(homedir4(), ".toon-client");
4522
+ const configPath = join5(dir, "config.json");
4753
4523
  try {
4754
4524
  return {
4755
- file: JSON.parse(readFileSync5(configPath, "utf8")),
4525
+ file: JSON.parse(readFileSync4(configPath, "utf8")),
4756
4526
  configPath
4757
4527
  };
4758
4528
  } catch (err) {
@@ -4830,14 +4600,13 @@ async function runFund(args, deps) {
4830
4600
  sourceLabel: resolved.sourceLabel
4831
4601
  };
4832
4602
  const client = await import("@toon-protocol/client");
4833
- const derived = await client.deriveFullIdentity(
4834
- resolved.mnemonic,
4835
- resolved.accountIndex
4836
- );
4603
+ const derived = client.deriveFullIdentity(resolved.mnemonic, {
4604
+ accountIndex: resolved.accountIndex,
4605
+ scheme: "legacy"
4606
+ });
4837
4607
  const addresses = {
4838
4608
  evm: derived.evm.address || null,
4839
- solana: derived.solana.publicKey || null,
4840
- mina: derived.mina.publicKey || null
4609
+ solana: derived.solana.publicKey || null
4841
4610
  };
4842
4611
  if (!faucetUrl) {
4843
4612
  const guidance = noFaucetGuidance(network, devnetOrigin);
@@ -4857,14 +4626,13 @@ async function runFund(args, deps) {
4857
4626
  io2.out("Wallet addresses:");
4858
4627
  io2.out(` evm ${addresses.evm ?? "(no key derived)"}`);
4859
4628
  io2.out(` solana ${addresses.solana ?? "(no key derived)"}`);
4860
- io2.out(` mina ${addresses.mina ?? "(no key derived \u2014 optional mina-signer dependency missing)"}`);
4861
4629
  return 0;
4862
4630
  }
4863
4631
  const timeoutEnv = env["TOON_CLIENT_FAUCET_TIMEOUT_MS"];
4864
- const timeoutFor = (chain) => {
4632
+ const timeoutFor = () => {
4865
4633
  if (timeoutEnv && Number.isFinite(Number(timeoutEnv))) return Number(timeoutEnv);
4866
4634
  if (file.faucetTimeoutMs !== void 0) return file.faucetTimeoutMs;
4867
- return chain === "mina" ? 13e4 : 9e4;
4635
+ return 9e4;
4868
4636
  };
4869
4637
  if (!json && inferredDevnet) {
4870
4638
  io2.out(
@@ -4874,7 +4642,7 @@ async function runFund(args, deps) {
4874
4642
  if (!json) {
4875
4643
  const list = targetChains.join(", ");
4876
4644
  io2.out(
4877
- `Requesting ${targetChains.length === 1 ? "" : "parallel "}USDC drip${targetChains.length === 1 ? "" : "s"} from ${faucetUrl} for ${list} \u2026` + (targetChains.includes("mina") ? " (mina settles slowly; this can take ~2 minutes)" : "")
4645
+ `Requesting ${targetChains.length === 1 ? "" : "parallel "}USDC drip${targetChains.length === 1 ? "" : "s"} from ${faucetUrl} for ${list} \u2026`
4878
4646
  );
4879
4647
  }
4880
4648
  const singleChain = targetChains.length === 1;
@@ -4885,13 +4653,13 @@ async function runFund(args, deps) {
4885
4653
  chain,
4886
4654
  funded: false,
4887
4655
  address: null,
4888
- error: `no ${chain} address could be derived for this identity` + (chain === "mina" ? " (install the optional mina-signer dependency)" : "")
4656
+ error: `no ${chain} address could be derived for this identity`
4889
4657
  };
4890
4658
  }
4891
4659
  const started = Date.now();
4892
4660
  try {
4893
4661
  const { response } = await client.fundWallet(faucetUrl, address, chain, {
4894
- timeout: timeoutFor(chain),
4662
+ timeout: timeoutFor(),
4895
4663
  ...deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}
4896
4664
  });
4897
4665
  return {
@@ -5000,7 +4768,8 @@ import { dirname as dirname4 } from "path";
5000
4768
  import { createInterface } from "readline/promises";
5001
4769
  import { parseArgs as parseArgs12 } from "util";
5002
4770
  async function loadKeyOps() {
5003
- return await import("@toon-protocol/client");
4771
+ const { generateKeystore, importKeystore } = await import("@toon-protocol/client");
4772
+ return { generateKeystore, importKeystore, deriveNostrKeyFromMnemonic };
5004
4773
  }
5005
4774
  var IdentityExistsError = class extends Error {
5006
4775
  constructor(pubkey, sourceLabel) {
@@ -5544,12 +5313,6 @@ async function resolveProfileRelay(flagRelay, originRelay, toonRelays) {
5544
5313
  ...toonRelays
5545
5314
  ].filter((u) => u !== void 0 && isWebSocketRelay2(u));
5546
5315
  if (candidates[0] !== void 0) return candidates[0];
5547
- try {
5548
- const { loadGenesisSeed } = await import("../network-bootstrap-27FYE3N7.js");
5549
- const seed = loadGenesisSeed();
5550
- if (seed?.relayUrl && isWebSocketRelay2(seed.relayUrl)) return seed.relayUrl;
5551
- } catch {
5552
- }
5553
5316
  return void 0;
5554
5317
  }
5555
5318
  async function resolveOrInitGitRepo(deps, flags) {
@@ -6314,57 +6077,39 @@ var DvmBuyJobError = class extends Error {
6314
6077
  }
6315
6078
  };
6316
6079
  var defaultSubmitDvmBuyJob = async (request) => {
6317
- const { finalizeEvent } = await import("nostr-tools/pure");
6318
- const event = finalizeEvent(
6319
- {
6080
+ let answer;
6081
+ try {
6082
+ answer = await request.submit({
6320
6083
  kind: ARNS_BUY_JOB_KIND,
6321
- created_at: Math.floor(Date.now() / 1e3),
6322
- content: "",
6323
- tags: [
6324
- ["param", "name", request.name],
6325
- ["param", "type", request.type],
6326
- ...request.years !== null ? [["param", "years", String(request.years)]] : [],
6327
- ["param", "processId", request.processId]
6084
+ params: [
6085
+ ["name", request.name],
6086
+ ["type", request.type],
6087
+ ...request.years !== null ? [["years", String(request.years)]] : [],
6088
+ ["processId", request.processId]
6328
6089
  ]
6329
- },
6330
- request.nostrSecretKey
6331
- );
6332
- const url = `${request.viaUrl.replace(/\/+$/, "")}/store`;
6333
- let response;
6334
- try {
6335
- response = await fetch(url, {
6336
- method: "POST",
6337
- headers: { "content-type": "application/json" },
6338
- body: JSON.stringify({ event })
6339
6090
  });
6340
6091
  } catch (err) {
6341
6092
  throw new DvmBuyJobError(
6342
- `could not reach the DVM at ${url}: ${err instanceof Error ? err.message : String(err)}`
6093
+ `could not reach the DVM at ${request.destination}: ${err instanceof Error ? err.message : String(err)}`
6343
6094
  );
6344
6095
  }
6345
- let body;
6346
- try {
6347
- body = await response.json();
6348
- } catch {
6096
+ if (!answer.accept) {
6349
6097
  throw new DvmBuyJobError(
6350
- `the DVM at ${url} returned a non-JSON response (HTTP ${response.status})`
6098
+ `the DVM at ${request.destination} rejected the kind:${ARNS_BUY_JOB_KIND} buy job (HTTP ${answer.status}${answer.code ? `, ${answer.code}` : ""})${answer.message ? `: ${answer.message}` : ""}`
6351
6099
  );
6352
6100
  }
6353
- if (!response.ok || body.accept !== true) {
6354
- throw new DvmBuyJobError(
6355
- `the DVM rejected the kind:${ARNS_BUY_JOB_KIND} buy job (HTTP ${response.status}${body.code ? `, ${body.code}` : ""})${body.message ? `: ${body.message}` : ""}`
6356
- );
6357
- }
6358
- const registryTxId = body.result?.registryTxId;
6101
+ const registryTxId = answer.result?.["registryTxId"];
6359
6102
  if (typeof registryTxId !== "string" || registryTxId.length === 0) {
6360
6103
  throw new DvmBuyJobError(
6361
- `the DVM accepted the job but returned no registryTxId \u2014 response: ` + JSON.stringify(body.result ?? null)
6104
+ `the DVM accepted the job but returned no registryTxId \u2014 response: ` + JSON.stringify(answer.result ?? null)
6362
6105
  );
6363
6106
  }
6107
+ const quotedMario = answer.result?.["quotedMario"];
6108
+ const syncAttributesTxId = answer.result?.["syncAttributesTxId"];
6364
6109
  return {
6365
6110
  registryTxId,
6366
- quotedMario: typeof body.result?.quotedMario === "string" ? body.result.quotedMario : null,
6367
- syncAttributesTxId: typeof body.result?.syncAttributesTxId === "string" ? body.result.syncAttributesTxId : null
6111
+ quotedMario: typeof quotedMario === "string" ? quotedMario : null,
6112
+ syncAttributesTxId: typeof syncAttributesTxId === "string" ? syncAttributesTxId : null
6368
6113
  };
6369
6114
  };
6370
6115
  var GAS_STATION_JOB_KIND = 5096;
@@ -6376,47 +6121,23 @@ var GasStationJobError = class extends Error {
6376
6121
  }
6377
6122
  reason;
6378
6123
  };
6379
- async function postGasStationJob(viaUrl, params, nostrSecretKey) {
6380
- const { finalizeEvent } = await import("nostr-tools/pure");
6381
- const event = finalizeEvent(
6382
- {
6383
- kind: GAS_STATION_JOB_KIND,
6384
- created_at: Math.floor(Date.now() / 1e3),
6385
- content: "",
6386
- tags: params.map(([k, v]) => ["param", k, v])
6387
- },
6388
- nostrSecretKey
6389
- );
6390
- const url = `${viaUrl.replace(/\/+$/, "")}/store`;
6391
- let response;
6124
+ async function submitGasStationJob(destination, params, submit) {
6125
+ let answer;
6392
6126
  try {
6393
- response = await fetch(url, {
6394
- method: "POST",
6395
- headers: { "content-type": "application/json" },
6396
- body: JSON.stringify({ event })
6397
- });
6127
+ answer = await submit({ kind: GAS_STATION_JOB_KIND, params });
6398
6128
  } catch (err) {
6399
6129
  throw new GasStationJobError(
6400
6130
  "unreachable",
6401
- `could not reach the DVM at ${url}: ${err instanceof Error ? err.message : String(err)}`
6131
+ `could not reach the DVM at ${destination}: ${err instanceof Error ? err.message : String(err)}`
6402
6132
  );
6403
6133
  }
6404
- let body;
6405
- try {
6406
- body = await response.json();
6407
- } catch {
6408
- throw new GasStationJobError(
6409
- "bad_response",
6410
- `the DVM at ${url} returned a non-JSON response (HTTP ${response.status})`
6411
- );
6412
- }
6413
- if (!response.ok || body.accept !== true || !body.result) {
6134
+ if (!answer.accept || !answer.result) {
6414
6135
  throw new GasStationJobError(
6415
- String(body.code ?? "rejected"),
6416
- `the DVM rejected the kind:${GAS_STATION_JOB_KIND} job (HTTP ${response.status}${body.code ? `, ${body.code}` : ""})${body.message ? `: ${body.message}` : ""}`
6136
+ String(answer.code ?? "rejected"),
6137
+ `the DVM at ${destination} rejected the kind:${GAS_STATION_JOB_KIND} job (HTTP ${answer.status}${answer.code ? `, ${answer.code}` : ""})${answer.message ? `: ${answer.message}` : ""}`
6417
6138
  );
6418
6139
  }
6419
- const result = body.result;
6140
+ const result = answer.result;
6420
6141
  if (result["status"] === "failed") {
6421
6142
  throw new GasStationJobError(
6422
6143
  String(result["reason"] ?? "failed"),
@@ -6427,13 +6148,13 @@ async function postGasStationJob(viaUrl, params, nostrSecretKey) {
6427
6148
  }
6428
6149
  var defaultGasStationClient = {
6429
6150
  quote: async (args) => {
6430
- const result = await postGasStationJob(
6431
- args.viaUrl,
6151
+ const result = await submitGasStationJob(
6152
+ args.destination,
6432
6153
  [
6433
6154
  ["phase", "quote"],
6434
6155
  ...args.transaction !== void 0 ? [["transaction", args.transaction]] : []
6435
6156
  ],
6436
- args.nostrSecretKey
6157
+ args.submit
6437
6158
  );
6438
6159
  const { quoteId, feePayer, maxLamports, recentBlockhash, expiresAt } = result;
6439
6160
  if (typeof quoteId !== "string" || typeof feePayer !== "string" || typeof maxLamports !== "string" || typeof recentBlockhash !== "string" || typeof expiresAt !== "number") {
@@ -6445,15 +6166,15 @@ var defaultGasStationClient = {
6445
6166
  return { quoteId, feePayer, maxLamports, recentBlockhash, expiresAt };
6446
6167
  },
6447
6168
  execute: async (args) => {
6448
- const result = await postGasStationJob(
6449
- args.viaUrl,
6169
+ const result = await submitGasStationJob(
6170
+ args.destination,
6450
6171
  [
6451
6172
  ["phase", "execute"],
6452
6173
  ["transaction", args.transaction],
6453
6174
  ["quoteId", args.quoteId],
6454
6175
  ["idempotencyKey", args.idempotencyKey]
6455
6176
  ],
6456
- args.nostrSecretKey
6177
+ args.submit
6457
6178
  );
6458
6179
  const signature = result["signature"];
6459
6180
  if (typeof signature !== "string" || signature.length === 0) {
@@ -6470,7 +6191,7 @@ var defaultGasStationClient = {
6470
6191
  };
6471
6192
  }
6472
6193
  };
6473
- var DEVNET_DVM_URL = "https://dvm.devnet.toonprotocol.dev";
6194
+ var DEVNET_DVM_DESTINATION = "g.toon.ario";
6474
6195
  var NAME_USAGE = `Usage: rig name <buy|set|status> <name> [options]
6475
6196
 
6476
6197
  ArNS naming for Arweave-served artifacts. A name registered on the ar.io
@@ -6483,7 +6204,7 @@ mnemonic that pays for pushes (derived at m/44'/501'/0'/0'). Fund it with
6483
6204
  registry program \u2014 NOT through TOON ILP payment channels.
6484
6205
 
6485
6206
  Commands:
6486
- name buy <name> [--years n | --permabuy] [--via <dvm-url>]
6207
+ name buy <name> [--years n | --permabuy] [--via <destination>]
6487
6208
  quote (mARIO) \u2192 confirm \u2192 register. The spawned ANT is
6488
6209
  owned by this identity's Solana key. Default: 1-year
6489
6210
  lease. PAID \u2014 spends mARIO from the Solana wallet.
@@ -6491,7 +6212,7 @@ Commands:
6491
6212
  the ANT (dust SOL only), then a store DVM executes the
6492
6213
  kind:5095 buy job and pays the mARIO from ITS wallet;
6493
6214
  the name is owned by your ANT from inception.
6494
- name set <name> <txId> [--undername <sub>] [--ttl <seconds>] [--via <dvm-url>]
6215
+ name set <name> <txId> [--undername <sub>] [--ttl <seconds>] [--via <destination>]
6495
6216
  point the name (or an undername) at an Arweave txId
6496
6217
  (typically a deployed path manifest). Signs an ANT
6497
6218
  record update with the Solana key. With --via: the
@@ -6523,17 +6244,24 @@ Options:
6523
6244
  unverified.
6524
6245
  --process-id <id> explicit ArNS registry program id \u2014 a Solana program
6525
6246
  address (overrides --network; or RIG_ARIO_PROCESS_ID)
6526
- --via <dvm-url> broker buy/set through a store DVM's job endpoint (or
6527
- RIG_ARNS_DVM_URL). The DVM pays the mARIO; you own the
6528
- name via your spawned ANT. Direct backend targeting
6529
- stubs the job payment (dev/e2e) \u2014 the paid path runs
6530
- the same job through the connector payment proxy.
6247
+ --via <destination> broker buy/set through a store node's DVM, naming its
6248
+ ILP DESTINATION (or RIG_ARNS_DVM_DESTINATION), e.g.
6249
+ --via ${DEVNET_DVM_DESTINATION}. The DVM pays the mARIO;
6250
+ you own the name via your spawned ANT.
6251
+ The job travels as a PAID packet, exactly as a git-object
6252
+ store write does \u2014 the store sits behind the connector's
6253
+ payment termination, so there is no unpaid endpoint to
6254
+ aim at. That node's ingress, route price and payment
6255
+ channel are all discovered from its own announce, so the
6256
+ destination is the only thing you supply.
6257
+ Costs one store-route packet per job (two for set:
6258
+ quote + execute).
6531
6259
  DEVNET DEFAULT: with --network devnet and the TOON
6532
6260
  network on devnet too, buy/set default to the deployed
6533
- devnet store DVM (${DEVNET_DVM_URL})
6261
+ devnet store DVM (${DEVNET_DVM_DESTINATION})
6534
6262
  unless --direct opts out.
6535
6263
  --direct force the direct wallet-paid path: never default (or
6536
- read RIG_ARNS_DVM_URL as) a --via DVM. Mutually
6264
+ read RIG_ARNS_DVM_DESTINATION as) a --via DVM. Mutually
6537
6265
  exclusive with an explicit --via.
6538
6266
  --yes skip the confirmation (required when not a TTY) for
6539
6267
  buy/set
@@ -6543,6 +6271,25 @@ Options:
6543
6271
  var DEFAULT_TTL_SECONDS = 3600;
6544
6272
  var DEFAULT_LEASE_YEARS = 1;
6545
6273
  var NETWORKS = ["mainnet", "devnet"];
6274
+ async function openStoreJobSession(deps, destination) {
6275
+ const ctx = await (deps.loadStandalone ?? defaultLoadStandalone)({
6276
+ env: deps.env,
6277
+ cwd: deps.cwd,
6278
+ warn: (line) => deps.io.err(line),
6279
+ storeDestination: destination
6280
+ });
6281
+ const submitStoreJob = ctx.publisher.submitStoreJob;
6282
+ if (!submitStoreJob) {
6283
+ await ctx.stop();
6284
+ throw new Error(
6285
+ "the active publisher cannot submit a store job (submitStoreJob unavailable) \u2014 `rig name --via` requires the standalone publisher"
6286
+ );
6287
+ }
6288
+ return {
6289
+ submit: (request) => submitStoreJob.call(ctx.publisher, request),
6290
+ stop: () => ctx.stop()
6291
+ };
6292
+ }
6546
6293
  async function resolveNameContext(deps, network, processId, mode) {
6547
6294
  const { io: io2, env } = deps;
6548
6295
  const resolved = await resolveIdentity({
@@ -6556,10 +6303,10 @@ async function resolveNameContext(deps, network, processId, mode) {
6556
6303
  sourceLabel: resolved.sourceLabel
6557
6304
  };
6558
6305
  const client = await import("@toon-protocol/client");
6559
- const derived = await client.deriveFullIdentity(
6560
- resolved.mnemonic,
6561
- resolved.accountIndex
6562
- );
6306
+ const derived = client.deriveFullIdentity(resolved.mnemonic, {
6307
+ accountIndex: resolved.accountIndex,
6308
+ scheme: "legacy"
6309
+ });
6563
6310
  const solanaAddress = derived.solana.publicKey;
6564
6311
  if (!solanaAddress) {
6565
6312
  throw new Error(
@@ -6573,7 +6320,7 @@ async function resolveNameContext(deps, network, processId, mode) {
6573
6320
  network,
6574
6321
  ...processId !== void 0 ? { processId } : {}
6575
6322
  });
6576
- const nostrSecretKey = client.deriveNostrKeyFromMnemonic(
6323
+ const nostrSecretKey = deriveNostrKeyFromMnemonic(
6577
6324
  resolved.mnemonic,
6578
6325
  resolved.accountIndex
6579
6326
  ).secretKey;
@@ -6644,12 +6391,17 @@ function parseNameFlags(args, env) {
6644
6391
  "--direct and --via are mutually exclusive: --direct forces the wallet-paid path, --via brokers through a DVM"
6645
6392
  );
6646
6393
  }
6647
- const viaRaw = values.direct ? void 0 : values.via ?? env["RIG_ARNS_DVM_URL"];
6394
+ const viaRaw = values.direct ? void 0 : values.via ?? env["RIG_ARNS_DVM_DESTINATION"] ?? env["RIG_ARNS_DVM_URL"];
6648
6395
  let via;
6649
6396
  if (viaRaw !== void 0) {
6650
- if (!/^https?:\/\/.+/.test(viaRaw)) {
6397
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(viaRaw)) {
6398
+ throw new Error(
6399
+ `--via names an ILP destination, not a URL (got ${JSON.stringify(viaRaw)}). Brokered ArNS jobs travel as paid packets to a store node, e.g. --via ${DEVNET_DVM_DESTINATION}. The node's endpoint, price and payment channel are discovered from its own announce.`
6400
+ );
6401
+ }
6402
+ if (!/^g\.[a-z0-9]+(\.[a-z0-9-]+)*$/i.test(viaRaw)) {
6651
6403
  throw new Error(
6652
- `--via must be an http(s) DVM endpoint URL, got ${JSON.stringify(viaRaw)}`
6404
+ `--via must be an ILP destination like ${DEVNET_DVM_DESTINATION}, got ${JSON.stringify(viaRaw)}`
6653
6405
  );
6654
6406
  }
6655
6407
  via = viaRaw;
@@ -6755,14 +6507,20 @@ async function runBuy(name, flags, deps) {
6755
6507
  io2.out(`Spawned ANT ${spawn3.processId} (tx ${spawn3.signature})`);
6756
6508
  }
6757
6509
  const submit = deps.submitDvmBuyJob ?? defaultSubmitDvmBuyJob;
6758
- const receipt2 = await submit({
6759
- viaUrl: via,
6760
- name,
6761
- type,
6762
- years,
6763
- processId: spawn3.processId,
6764
- nostrSecretKey: signed.nostrSecretKey
6765
- });
6510
+ const session = await openStoreJobSession(deps, via);
6511
+ let receipt2;
6512
+ try {
6513
+ receipt2 = await submit({
6514
+ destination: via,
6515
+ name,
6516
+ type,
6517
+ years,
6518
+ processId: spawn3.processId,
6519
+ submit: session.submit
6520
+ });
6521
+ } finally {
6522
+ await session.stop();
6523
+ }
6766
6524
  const result2 = {
6767
6525
  registryTxId: receipt2.registryTxId,
6768
6526
  antProcessId: spawn3.processId,
@@ -6910,25 +6668,32 @@ async function runSet(name, txId, flags, deps) {
6910
6668
  );
6911
6669
  if (via !== null) {
6912
6670
  const gas = deps.gasStation ?? defaultGasStationClient;
6913
- const quote = await gas.quote({
6914
- viaUrl: via,
6915
- nostrSecretKey: signed.nostrSecretKey
6916
- });
6917
- const wireTx = await signed.sdk.buildSetRecordTransaction({
6918
- antProcessId,
6919
- undername: undername ?? "@",
6920
- transactionId: txId,
6921
- ttlSeconds: flags.ttl,
6922
- feePayer: quote.feePayer,
6923
- recentBlockhash: quote.recentBlockhash
6924
- });
6925
- const executed = await gas.execute({
6926
- viaUrl: via,
6927
- transaction: wireTx,
6928
- quoteId: quote.quoteId,
6929
- idempotencyKey: randomUUID(),
6930
- nostrSecretKey: signed.nostrSecretKey
6931
- });
6671
+ const session = await openStoreJobSession(deps, via);
6672
+ let quote;
6673
+ let executed;
6674
+ try {
6675
+ quote = await gas.quote({
6676
+ destination: via,
6677
+ submit: session.submit
6678
+ });
6679
+ const wireTx = await signed.sdk.buildSetRecordTransaction({
6680
+ antProcessId,
6681
+ undername: undername ?? "@",
6682
+ transactionId: txId,
6683
+ ttlSeconds: flags.ttl,
6684
+ feePayer: quote.feePayer,
6685
+ recentBlockhash: quote.recentBlockhash
6686
+ });
6687
+ executed = await gas.execute({
6688
+ destination: via,
6689
+ transaction: wireTx,
6690
+ quoteId: quote.quoteId,
6691
+ idempotencyKey: randomUUID(),
6692
+ submit: session.submit
6693
+ });
6694
+ } finally {
6695
+ await session.stop();
6696
+ }
6932
6697
  const gasStation = {
6933
6698
  quoteId: quote.quoteId,
6934
6699
  feePayer: quote.feePayer,
@@ -7092,9 +6857,9 @@ async function runName(args, deps) {
7092
6857
  } catch {
7093
6858
  }
7094
6859
  if (toonDevnet) {
7095
- flags = { ...flags, via: DEVNET_DVM_URL };
6860
+ flags = { ...flags, via: DEVNET_DVM_DESTINATION };
7096
6861
  io2.err(
7097
- `Brokering via the devnet store DVM ${DEVNET_DVM_URL} (no --via given; pass --direct for a wallet-paid ${sub}).`
6862
+ `Brokering via the devnet store DVM ${DEVNET_DVM_DESTINATION} (no --via given; pass --direct for a wallet-paid ${sub}).`
7098
6863
  );
7099
6864
  }
7100
6865
  }
@@ -7140,22 +6905,22 @@ function buildArweaveManifest(entries, indexPath = DEFAULT_INDEX, fallbackTxId)
7140
6905
  }
7141
6906
 
7142
6907
  // src/cli/site-record.ts
7143
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
7144
- import { homedir as homedir6 } from "os";
7145
- import { join as join7 } from "path";
6908
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
6909
+ import { homedir as homedir5 } from "os";
6910
+ import { join as join6 } from "path";
7146
6911
  var SITE_MANIFEST_FILENAME = "site-manifests.json";
7147
6912
  function storeDir2(env) {
7148
- return env["TOON_CLIENT_HOME"] ?? join7(homedir6(), ".toon-client");
6913
+ return env["TOON_CLIENT_HOME"] ?? join6(homedir5(), ".toon-client");
7149
6914
  }
7150
6915
  function storePath2(env) {
7151
- return join7(storeDir2(env), SITE_MANIFEST_FILENAME);
6916
+ return join6(storeDir2(env), SITE_MANIFEST_FILENAME);
7152
6917
  }
7153
6918
  function keyOf(repoId, ref) {
7154
6919
  return `${repoId}\0${ref}`;
7155
6920
  }
7156
6921
  function readFile2(env) {
7157
6922
  try {
7158
- const parsed = JSON.parse(readFileSync6(storePath2(env), "utf8"));
6923
+ const parsed = JSON.parse(readFileSync5(storePath2(env), "utf8"));
7159
6924
  if (parsed && typeof parsed === "object") return parsed;
7160
6925
  return {};
7161
6926
  } catch {
@@ -7176,7 +6941,7 @@ function writeSiteRecord(env, record) {
7176
6941
 
7177
6942
  // src/cli/site.ts
7178
6943
  var MANIFEST_CONTENT_TYPE = "application/x.arweave-manifest+json";
7179
- var DEFAULT_GATEWAY = ARWEAVE_GATEWAYS[0] ?? "https://arweave.net";
6944
+ var DEFAULT_GATEWAY = PREFERRED_GATEWAY;
7180
6945
  var SITE_USAGE = `Usage: rig site <publish|url> [ref] [options]
7181
6946
 
7182
6947
  Serve a pushed repo as a permanent, path-routed website. \`rig push\` already
@@ -7364,7 +7129,6 @@ async function runSitePublish(args, deps) {
7364
7129
  }
7365
7130
  }
7366
7131
  const feeRates = await ctx.publisher.getFeeRates();
7367
- const { uploadFee } = feeRates;
7368
7132
  const previewEntries = blobs.map((b) => ({
7369
7133
  path: b.path,
7370
7134
  txId: known.get(b.sha) ?? PLACEHOLDER_TX
@@ -7380,9 +7144,12 @@ async function runSitePublish(args, deps) {
7380
7144
  if (flags.forceReupload) {
7381
7145
  const { objects } = await reader.statObjects(uniqueShas);
7382
7146
  reuploadBytes = objects.reduce((sum, o) => sum + o.size, 0);
7383
- reuploadFee = BigInt(objects.length) * uploadFee;
7147
+ reuploadFee = objects.reduce(
7148
+ (sum, o) => sum + uploadChargeFor(feeRates, o.size),
7149
+ 0n
7150
+ );
7384
7151
  }
7385
- const manifestFee = uploadFee;
7152
+ const manifestFee = uploadChargeFor(feeRates, manifestBytes);
7386
7153
  const totalFee = manifestFee + reuploadFee;
7387
7154
  const gateway = flags.gateway ?? deps.env["RIG_ARWEAVE_GATEWAY"] ?? DEFAULT_GATEWAY;
7388
7155
  const baseJson = () => ({