@toon-protocol/rig 3.5.3 → 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 +298 -529
  13. package/dist/cli/rig.js.map +1 -1
  14. package/dist/index.d.ts +3 -109
  15. package/dist/index.js +9 -108
  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 -378
  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-4CAOEXGQ.js +0 -631
  24. package/dist/chunk-4CAOEXGQ.js.map +0 -1
  25. package/dist/chunk-B5ISARMU.js.map +0 -1
  26. package/dist/chunk-FFQXFV4W.js +0 -400
  27. package/dist/chunk-FFQXFV4W.js.map +0 -1
  28. package/dist/chunk-LCYCKWAT.js.map +0 -1
  29. package/dist/chunk-TTJCBGKW.js +0 -447
  30. package/dist/chunk-TTJCBGKW.js.map +0 -1
  31. package/dist/network-bootstrap-CTYIZMP6.js +0 -40
  32. package/dist/network-bootstrap-CTYIZMP6.js.map +0 -1
  33. package/dist/standalone-mode-LBWGU7NV.js +0 -724
  34. package/dist/standalone-mode-LBWGU7NV.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-FFQXFV4W.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-TTJCBGKW.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-LBWGU7NV.js");
1113
+ const mod = await import("../standalone-mode-LEAC4A2L.js");
1102
1114
  return mod.createStandaloneContext(options);
1103
1115
  };
1104
1116
  function identityReport(ctx) {
@@ -1240,13 +1252,10 @@ function parsePushArgs(args) {
1240
1252
  return flags;
1241
1253
  }
1242
1254
  function pointerGateway(env) {
1243
- return (env["RIG_ARWEAVE_GATEWAY"] ?? "https://ar-io.dev").replace(
1244
- /\/+$/,
1245
- ""
1246
- );
1255
+ return (env["RIG_ARWEAVE_GATEWAY"] ?? PREFERRED_GATEWAY).replace(/\/+$/, "");
1247
1256
  }
1248
- function mirrorGateway(primary) {
1249
- return ARWEAVE_GATEWAYS.find((g) => g !== primary);
1257
+ function mirrorGateways(primary) {
1258
+ return mirrorGatewaysFor(primary);
1250
1259
  }
1251
1260
  function planRigPointer(args) {
1252
1261
  const html = generateRigPointerHtml({
@@ -1282,7 +1291,7 @@ function planRigPointer(args) {
1282
1291
  html,
1283
1292
  contentHash,
1284
1293
  bytes,
1285
- fee: args.uploadFee
1294
+ fee: uploadChargeFor(args.feeRates, bytes)
1286
1295
  };
1287
1296
  }
1288
1297
  async function runPush(args, deps) {
@@ -1403,7 +1412,7 @@ async function runPush(args, deps) {
1403
1412
  ownerPubkey: ctx.ownerPubkey,
1404
1413
  repoId,
1405
1414
  relay: relaysUsed[0],
1406
- uploadFee: feeRates.uploadFee
1415
+ feeRates
1407
1416
  });
1408
1417
  }
1409
1418
  } else {
@@ -1459,11 +1468,15 @@ async function runPush(args, deps) {
1459
1468
  io2.out(
1460
1469
  `Rig page: ${rigPage2.url}` + (rigPage2.status === "published" ? ` paid ${rigPage2.feePaid}` : "") + " (renders this repo from Arweave)"
1461
1470
  );
1462
- const mirror = rigPage2.txId ? mirrorGateway(gateway) : void 0;
1463
- if (mirror) {
1471
+ const mirrors = rigPage2.txId ? mirrorGateways(gateway) : [];
1472
+ if (mirrors.length > 0 && rigPage2.txId) {
1473
+ const txId = rigPage2.txId;
1464
1474
  io2.out(
1465
- ` also: ${mirror}/${rigPage2.txId} (same page; gateways index fresh uploads at different speeds)`
1475
+ " also: (same page \u2014 try these if the address above does not load; gateways index fresh uploads at different speeds, and any one of them can be down)"
1466
1476
  );
1477
+ for (const mirror of mirrors) {
1478
+ io2.out(` ${mirror}/${txId}`);
1479
+ }
1467
1480
  }
1468
1481
  } else if (rigPage2.detail) {
1469
1482
  io2.err(`rig page: ${rigPage2.detail}`);
@@ -2039,9 +2052,6 @@ async function runChain(args, deps) {
2039
2052
  }
2040
2053
 
2041
2054
  // src/cli/channel.ts
2042
- import { readFileSync as readFileSync3 } from "fs";
2043
- import { homedir as homedir3 } from "os";
2044
- import { join as join3 } from "path";
2045
2055
  import { parseArgs as parseArgs5 } from "util";
2046
2056
  var CHANNEL_USAGE = `Usage: rig channel <subcommand>
2047
2057
 
@@ -2064,17 +2074,6 @@ Subcommands:
2064
2074
  apex); --deposit adds that much extra collateral after the
2065
2075
  open/resume. On-chain: asks for confirmation (--yes skips).
2066
2076
 
2067
- deploy-zkapp [--graphql-url <url>]
2068
- deploy a dedicated Mina PaymentChannel zkApp for THIS
2069
- identity (the zkApp is single-pair; Mina channels open on
2070
- an identity-owned deployment). Normally automatic \u2014 the
2071
- Mina open path deploys one when needed \u2014 this explicit
2072
- form pre-deploys it (compile \u22481-3 min, inclusion \u22483-6 min).
2073
- On-chain: costs the 1 MINA account-creation fee + tx fee
2074
- from the wallet's MINA. The zkApp key is saved under
2075
- TOON_CLIENT_HOME/keys/. Asks for confirmation (--yes
2076
- skips).
2077
-
2078
2077
  close <channelId>
2079
2078
  close a recorded channel \u2014 an on-chain tx that starts the
2080
2079
  settlement challenge window (the peer's settlementTimeout).
@@ -2098,8 +2097,6 @@ async function runChannel(args, deps) {
2098
2097
  return runChannelList(rest, deps);
2099
2098
  case "open":
2100
2099
  return runChannelOpen(rest, deps);
2101
- case "deploy-zkapp":
2102
- return runChannelDeployZkApp(rest, deps);
2103
2100
  case "close":
2104
2101
  return runChannelWithdrawStep(rest, deps, "close");
2105
2102
  case "settle":
@@ -2292,9 +2289,6 @@ async function runChannelOpen(args, deps) {
2292
2289
  io2.out(
2293
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)."
2294
2291
  );
2295
- io2.out(
2296
- "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)."
2297
- );
2298
2292
  }
2299
2293
  const gate = await confirmOnChain(
2300
2294
  io2,
@@ -2353,160 +2347,6 @@ async function runChannelOpen(args, deps) {
2353
2347
  await stopQuietly(ctx);
2354
2348
  }
2355
2349
  }
2356
- async function runChannelDeployZkApp(args, deps) {
2357
- const { io: io2, env } = deps;
2358
- let graphqlFlag;
2359
- let yes = false;
2360
- let json = false;
2361
- try {
2362
- const { values } = parseArgs5({
2363
- args,
2364
- options: {
2365
- "graphql-url": { type: "string" },
2366
- yes: { type: "boolean", default: false },
2367
- json: { type: "boolean", default: false },
2368
- help: { type: "boolean", short: "h", default: false }
2369
- }
2370
- });
2371
- if (values.help) {
2372
- io2.out(CHANNEL_USAGE);
2373
- return 0;
2374
- }
2375
- graphqlFlag = values["graphql-url"];
2376
- yes = values.yes ?? false;
2377
- json = values.json ?? false;
2378
- } catch (err) {
2379
- io2.err(err instanceof Error ? err.message : String(err));
2380
- io2.err(CHANNEL_USAGE);
2381
- return 2;
2382
- }
2383
- try {
2384
- const dir = env["TOON_CLIENT_HOME"] ?? join3(homedir3(), ".toon-client");
2385
- let file = {};
2386
- try {
2387
- file = JSON.parse(readFileSync3(join3(dir, "config.json"), "utf8"));
2388
- } catch {
2389
- }
2390
- const pinned = env["TOON_CLIENT_CHAIN"] ?? file.chain;
2391
- const chain = pinned !== void 0 && pinned.startsWith("mina:") ? pinned : "mina:devnet";
2392
- const graphqlUrl = graphqlFlag ?? file.minaChannel?.graphqlUrl ?? minaPresetForChain(chain)?.graphqlUrl;
2393
- if (!graphqlUrl) {
2394
- throw new Error(
2395
- `no Mina GraphQL endpoint for ${chain} \u2014 pass --graphql-url or set minaChannel.graphqlUrl in the client config`
2396
- );
2397
- }
2398
- const resolved = await resolveIdentity({
2399
- env,
2400
- cwd: deps.cwd,
2401
- warn: (line) => io2.err(line)
2402
- });
2403
- const identity = {
2404
- pubkey: resolved.pubkey,
2405
- source: resolved.source,
2406
- sourceLabel: resolved.sourceLabel
2407
- };
2408
- const store = MinaZkAppStore.forHome(dir);
2409
- const existing = store.lookup(resolved.pubkey, chain);
2410
- if (existing) {
2411
- if (json) {
2412
- io2.emitJson({
2413
- command: "channel deploy-zkapp",
2414
- identity,
2415
- executed: false,
2416
- plan: { chain, graphqlUrl },
2417
- result: {
2418
- zkAppAddress: existing.zkAppAddress,
2419
- deployTxHash: existing.deployTxHash ?? null,
2420
- vkHash: existing.vkHash ?? null,
2421
- storePath: store.filePath
2422
- },
2423
- hint: "a zkApp is already recorded for this identity/chain \u2014 the open path reuses it"
2424
- });
2425
- return 0;
2426
- }
2427
- io2.out(
2428
- `A Mina zkApp is already recorded for this identity on ${chain}: ` + existing.zkAppAddress
2429
- );
2430
- io2.out(`The open path reuses it (record: ${store.filePath}).`);
2431
- return 0;
2432
- }
2433
- const plan = { chain, graphqlUrl };
2434
- if (!json) {
2435
- io2.out("Mina zkApp deploy plan:");
2436
- io2.out(` chain ${chain}`);
2437
- io2.out(` graphql ${graphqlUrl}`);
2438
- io2.out(renderIdentityLine(identity));
2439
- io2.out(
2440
- "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."
2441
- );
2442
- }
2443
- const gate = await confirmOnChain(
2444
- io2,
2445
- { yes, json },
2446
- "Proceed with the on-chain zkApp deploy? [y/N] "
2447
- );
2448
- if (gate === "json-plan") {
2449
- io2.emitJson({
2450
- command: "channel deploy-zkapp",
2451
- identity,
2452
- executed: false,
2453
- plan,
2454
- hint: "plan only \u2014 re-run with --yes to deploy (on-chain: ~1.1 MINA + fees)"
2455
- });
2456
- return 0;
2457
- }
2458
- if (gate !== "proceed") return gate;
2459
- const client = await import("@toon-protocol/client");
2460
- const derived = await client.deriveFullIdentity(
2461
- resolved.mnemonic,
2462
- resolved.accountIndex
2463
- );
2464
- if (!derived.mina.privateKey) {
2465
- throw new Error(
2466
- "no Mina key derived \u2014 the optional `mina-signer` dependency is not installed"
2467
- );
2468
- }
2469
- const record = await client.deployMinaChannelZkApp({
2470
- graphqlUrl,
2471
- payerPrivateKey: derived.mina.privateKey,
2472
- onProgress: (line) => io2.err(`rig: mina: ${line}`)
2473
- });
2474
- store.save({
2475
- identity: resolved.pubkey,
2476
- chain,
2477
- zkAppAddress: record.zkAppAddress,
2478
- zkAppPrivateKey: record.zkAppPrivateKey,
2479
- feePayer: record.feePayer,
2480
- ...record.deployTxHash !== void 0 ? { deployTxHash: record.deployTxHash } : {},
2481
- ...record.vkHash !== void 0 ? { vkHash: record.vkHash } : {},
2482
- deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
2483
- source: "rig channel deploy-zkapp (npm @toon-protocol/mina-zkapp build)"
2484
- });
2485
- if (json) {
2486
- io2.emitJson({
2487
- command: "channel deploy-zkapp",
2488
- identity,
2489
- executed: true,
2490
- plan,
2491
- result: {
2492
- zkAppAddress: record.zkAppAddress,
2493
- deployTxHash: record.deployTxHash ?? null,
2494
- vkHash: record.vkHash ?? null,
2495
- storePath: store.filePath
2496
- }
2497
- });
2498
- return 0;
2499
- }
2500
- io2.out(`Deployed Mina PaymentChannel zkApp ${record.zkAppAddress}.`);
2501
- if (record.deployTxHash) io2.out(` deploy tx ${record.deployTxHash}`);
2502
- if (record.vkHash) io2.out(` vk hash ${record.vkHash}`);
2503
- io2.out(` record ${store.filePath} (holds the zkApp key \u2014 back it up)`);
2504
- io2.out("The next Mina channel open/push finds and reuses this zkApp.");
2505
- return 0;
2506
- } catch (err) {
2507
- return emitCliError(io2, json, "channel deploy-zkapp", err);
2508
- }
2509
- }
2510
2350
  function withdrawPrecheck(step, channelId, watermark, nowSec) {
2511
2351
  const status = channelStatus(watermark, nowSec);
2512
2352
  if (status === "settled") {
@@ -2676,7 +2516,7 @@ async function stopQuietly(ctx) {
2676
2516
 
2677
2517
  // src/cli/clone.ts
2678
2518
  import { mkdtemp, mkdir, readdir, rename, rm, rmdir } from "fs/promises";
2679
- import { basename, dirname as dirname2, join as join4, resolve } from "path";
2519
+ import { basename, dirname as dirname2, join as join3, resolve } from "path";
2680
2520
  import { parseArgs as parseArgs6 } from "util";
2681
2521
  var CLONE_USAGE = `Usage: rig clone <relay-url> <owner>/<repo-id> [dir] [options]
2682
2522
 
@@ -2847,7 +2687,7 @@ async function runClone(args, deps) {
2847
2687
  }
2848
2688
  const parent = dirname2(dest);
2849
2689
  await mkdir(parent, { recursive: true });
2850
- tempDir = await mkdtemp(join4(parent, `.${basename(dest)}.rig-clone-`));
2690
+ tempDir = await mkdtemp(join3(parent, `.${basename(dest)}.rig-clone-`));
2851
2691
  await runGit(tempDir, [
2852
2692
  "init",
2853
2693
  "--quiet",
@@ -4100,48 +3940,39 @@ async function warnIfNotMaintainer(deps, args) {
4100
3940
  }
4101
3941
 
4102
3942
  // src/cli/entry.ts
4103
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
4104
- import { homedir as homedir4 } from "os";
4105
- 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";
4106
3946
  import { parseArgs as parseArgs9 } from "util";
4107
- var SANDBOX_BTP_URL = "wss://proxy.sandbox.devnet.toonprotocol.dev:443";
4108
- var SANDBOX_RELAY_URL = "wss://relay-ws.sandbox.devnet.toonprotocol.dev";
4109
- var ENTRY_USAGE = `Usage: rig entry [apex | sandbox | <wss-url>] [options]
3947
+ var ENTRY_USAGE = `Usage: rig entry [<connector-url> | clear] [options]
4110
3948
 
4111
- Choose which network entry node (payment ingress + relay) rig talks to. Free:
4112
- 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.
4113
3952
 
4114
- rig entry show the effective entry endpoints and their source
4115
- rig entry apex revert to the default apex: clears the btpUrl/
4116
- relayUrl override so core's genesis seed (or a live
4117
- announce) applies \u2014 settles evm | sol | mina
4118
- rig entry sandbox the devnet sandbox entry (Mina USDC ONLY \u2014 the
4119
- cross-currency multihop demo path):
4120
- btp ${SANDBOX_BTP_URL}
4121
- relay ${SANDBOX_RELAY_URL}
4122
- rig entry <wss-url> an explicit BTP endpoint (ws:// or wss://); pass
4123
- --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)
4124
3957
 
4125
- Switching entries deletes the cached topology (the next paid command
4126
- re-discovers the new entry's announce) and leaves existing payment channels
4127
- behind \u2014 channels are per-entry-peer; the next paid command opens or resumes
4128
- 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.
4129
3960
 
4130
3961
  NOTE for repos: the relay a repo publishes to is its git \`origin\` remote,
4131
- which OVERRIDES the config relayUrl. After switching entries, point the repo
4132
- 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).
4133
3964
 
4134
3965
  Options:
4135
- --relay <url> with <wss-url>: also set the relay URL
3966
+ --relay <url> with <connector-url>: also record the relay URL (ws:// or wss://)
4136
3967
  --json machine-readable envelope
4137
3968
  -h, --help show this help`;
4138
3969
  function configPathFor2(env) {
4139
- const dir = env["TOON_CLIENT_HOME"] ?? join5(homedir4(), ".toon-client");
4140
- return join5(dir, "config.json");
3970
+ const dir = env["TOON_CLIENT_HOME"] ?? join4(homedir3(), ".toon-client");
3971
+ return join4(dir, "config.json");
4141
3972
  }
4142
3973
  function readEntryConfig(configPath) {
4143
3974
  try {
4144
- return JSON.parse(readFileSync4(configPath, "utf8"));
3975
+ return JSON.parse(readFileSync3(configPath, "utf8"));
4145
3976
  } catch (err) {
4146
3977
  if (err.code === "ENOENT") return {};
4147
3978
  throw new Error(
@@ -4154,20 +3985,28 @@ function writeEntryConfig(configPath, file) {
4154
3985
  writeFileSync3(configPath, `${JSON.stringify(file, null, 2)}
4155
3986
  `, "utf8");
4156
3987
  }
4157
- async function loadGenesisSeedDefault() {
4158
- try {
4159
- const { loadGenesisSeed } = await import("../network-bootstrap-CTYIZMP6.js");
4160
- return loadGenesisSeed();
4161
- } catch {
4162
- return void 0;
4163
- }
4164
- }
4165
- function classifyEntry(btpUrl, seedBtp, btpSource) {
4166
- if (btpUrl === null) return null;
4167
- if (btpUrl === SANDBOX_BTP_URL) return "sandbox";
4168
- if (btpSource === "genesis-seed" || btpUrl === seedBtp) return "apex";
4169
- return "custom";
4170
- }
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;
4171
4010
  async function runEntry(args, deps) {
4172
4011
  const { io: io2, env } = deps;
4173
4012
  let positionals;
@@ -4197,7 +4036,7 @@ async function runEntry(args, deps) {
4197
4036
  }
4198
4037
  if (positionals.length > 1) {
4199
4038
  io2.err(
4200
- `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(" ")}`
4201
4040
  );
4202
4041
  io2.err(ENTRY_USAGE);
4203
4042
  return 2;
@@ -4205,36 +4044,33 @@ async function runEntry(args, deps) {
4205
4044
  const target = positionals[0];
4206
4045
  let mutation;
4207
4046
  if (target !== void 0) {
4208
- if (target === "apex") {
4209
- if (relayFlag !== void 0) {
4210
- io2.err("--relay only applies to an explicit <wss-url> entry");
4211
- io2.err(ENTRY_USAGE);
4212
- return 2;
4213
- }
4214
- mutation = { kind: "apex" };
4215
- } else if (target === "sandbox") {
4047
+ if (target === "clear") {
4216
4048
  if (relayFlag !== void 0) {
4217
- io2.err("--relay only applies to an explicit <wss-url> entry");
4049
+ io2.err("--relay only applies to a <connector-url> entry");
4218
4050
  io2.err(ENTRY_USAGE);
4219
4051
  return 2;
4220
4052
  }
4221
- mutation = { kind: "sandbox" };
4222
- } else if (/^wss?:\/\/.+/.test(target)) {
4223
- if (relayFlag !== void 0 && !/^wss?:\/\/.+/.test(relayFlag)) {
4224
- io2.err(
4225
- `--relay must be a ws(s) URL, got ${JSON.stringify(relayFlag)}`
4226
- );
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)}`);
4227
4057
  io2.err(ENTRY_USAGE);
4228
4058
  return 2;
4229
4059
  }
4230
4060
  mutation = {
4231
4061
  kind: "url",
4232
- btpUrl: target,
4062
+ connectorUrl: target.replace(/\/+$/, ""),
4233
4063
  ...relayFlag !== void 0 ? { relayUrl: relayFlag } : {}
4234
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;
4235
4071
  } else {
4236
4072
  io2.err(
4237
- `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\``
4238
4074
  );
4239
4075
  io2.err(ENTRY_USAGE);
4240
4076
  return 2;
@@ -4243,136 +4079,78 @@ async function runEntry(args, deps) {
4243
4079
  try {
4244
4080
  const configPath = configPathFor2(env);
4245
4081
  const file = readEntryConfig(configPath);
4246
- const seed = await (deps.loadGenesisSeed ?? loadGenesisSeedDefault)();
4247
- const effective = () => {
4248
- const btpExplicit = env["TOON_CLIENT_PROXY_URL"] ?? env["TOON_CLIENT_BTP_URL"] ?? file.proxyUrl ?? file.btpUrl;
4249
- const btpFromEnv = env["TOON_CLIENT_PROXY_URL"] ?? env["TOON_CLIENT_BTP_URL"];
4250
- const relayExplicit = env["TOON_CLIENT_RELAY_URL"] ?? file.relayUrl;
4251
- return {
4252
- btpUrl: btpExplicit ?? seed?.btpEndpoint ?? null,
4253
- btpSource: btpExplicit ? btpFromEnv ? "env" : "config" : seed?.btpEndpoint ? "genesis-seed" : null,
4254
- relayUrl: relayExplicit ?? seed?.relayUrl ?? null,
4255
- relaySource: env["TOON_CLIENT_RELAY_URL"] ? "env" : file.relayUrl ? "config" : seed?.relayUrl ? "genesis-seed" : null
4256
- };
4257
- };
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";
4258
4083
  if (mutation === void 0) {
4259
- const state2 = effective();
4260
- const entry = classifyEntry(state2.btpUrl, seed?.btpEndpoint, state2.btpSource);
4084
+ const state2 = effectiveEntry(env, file);
4261
4085
  if (json) {
4262
4086
  io2.emitJson({
4263
4087
  command: "entry",
4264
- entry,
4265
- btpUrl: state2.btpUrl,
4266
- btpSource: state2.btpSource,
4267
- relayUrl: state2.relayUrl,
4268
- relaySource: state2.relaySource,
4088
+ ...state2,
4269
4089
  configPath
4270
4090
  });
4271
4091
  return 0;
4272
4092
  }
4273
- const label = (source) => source === "env" ? "env" : source === "config" ? `config (${configPath})` : source === "genesis-seed" ? "default apex \u2014 genesis seed" : "not configured";
4274
4093
  io2.out(
4275
- `Entry: ${entry ?? "(none)"}${entry === "sandbox" ? " (Mina USDC only \u2014 multihop demo path)" : ""}`
4094
+ `Connector ${state2.connectorUrl ?? "(none)"} [${label(state2.connectorSource)}]`
4276
4095
  );
4277
- io2.out(` btp ${state2.btpUrl ?? "(none)"} [${label(state2.btpSource)}]`);
4278
- io2.out(` relay ${state2.relayUrl ?? "(none)"} [${label(state2.relaySource)}]`);
4279
4096
  io2.out(
4280
- "Switch with `rig entry apex`, `rig entry sandbox`, or `rig entry <wss-url>`."
4097
+ `Relay ${state2.relayUrl ?? "(none)"} [${label(state2.relaySource)}]`
4281
4098
  );
4282
- return 0;
4283
- }
4284
- const warnings = [];
4285
- for (const envVar of [
4286
- "TOON_CLIENT_BTP_URL",
4287
- "TOON_CLIENT_PROXY_URL",
4288
- "TOON_CLIENT_RELAY_URL"
4289
- ]) {
4290
- if (env[envVar] !== void 0) {
4291
- warnings.push(
4292
- `${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)."
4293
4102
  );
4294
4103
  }
4104
+ return 0;
4295
4105
  }
4296
- warnings.push(
4297
- "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."
4298
- );
4299
- const hadProxyUrl = file.proxyUrl !== void 0;
4300
- let wroteBtp;
4301
- let wroteRelay;
4302
- if (mutation.kind === "apex") {
4303
- wroteBtp = null;
4304
- wroteRelay = null;
4305
- delete file.btpUrl;
4306
- delete file.relayUrl;
4307
- delete file.proxyUrl;
4308
- } else if (mutation.kind === "sandbox") {
4309
- wroteBtp = SANDBOX_BTP_URL;
4310
- wroteRelay = SANDBOX_RELAY_URL;
4311
- file.btpUrl = SANDBOX_BTP_URL;
4312
- file.relayUrl = SANDBOX_RELAY_URL;
4313
- delete file.proxyUrl;
4314
- } else {
4315
- wroteBtp = mutation.btpUrl;
4316
- wroteRelay = mutation.relayUrl ?? null;
4317
- file.btpUrl = mutation.btpUrl;
4318
- if (mutation.relayUrl !== void 0) file.relayUrl = mutation.relayUrl;
4319
- delete file.proxyUrl;
4320
- }
4321
- 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;
4322
4111
  warnings.push(
4323
- "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)"
4324
4113
  );
4325
4114
  }
4326
- writeEntryConfig(configPath, file);
4327
- let clearedTopologyCache = false;
4328
- try {
4329
- unlinkSync(join5(dirname3(configPath), TOPOLOGY_CACHE_FILENAME));
4330
- clearedTopologyCache = true;
4331
- } 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;
4332
4121
  }
4333
- if (mutation.kind === "sandbox") {
4334
- const effectiveChain = env["TOON_CLIENT_CHAIN"] ?? file.chain ?? file.supportedChains?.[0];
4335
- if (effectiveChain === void 0 || !effectiveChain.startsWith("mina")) {
4336
- warnings.push(
4337
- "The sandbox entry settles ONLY mina:devnet \u2014 run `rig chain set mina` " + (effectiveChain !== void 0 ? `(currently ${effectiveChain}).` : "to pin it.")
4338
- );
4339
- }
4122
+ if (env["TOON_CONNECTOR"] || env["TOON_CLIENT_PROXY_URL"]) {
4340
4123
  warnings.push(
4341
- `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"
4342
4125
  );
4343
4126
  }
4344
- 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);
4345
4133
  if (json) {
4346
4134
  io2.emitJson({
4347
4135
  command: "entry",
4348
- entry: mutation.kind === "url" ? "custom" : mutation.kind,
4349
- btpUrl: state.btpUrl,
4350
- btpSource: state.btpSource,
4351
- relayUrl: state.relayUrl,
4352
- relaySource: state.relaySource,
4353
- wrote: { btpUrl: wroteBtp, relayUrl: wroteRelay },
4354
- clearedTopologyCache,
4136
+ ...state,
4137
+ wrote,
4355
4138
  configPath,
4356
- ...warnings.length ? { warnings } : {}
4139
+ ...warnings.length > 0 ? { warnings } : {}
4357
4140
  });
4358
4141
  return 0;
4359
4142
  }
4360
- if (mutation.kind === "apex") {
4361
- io2.out("Entry reverted to the default apex (cleared btpUrl/relayUrl/proxyUrl).");
4362
- io2.out(` btp ${state.btpUrl ?? "(genesis seed unavailable)"}`);
4363
- io2.out(` relay ${state.relayUrl ?? "(genesis seed unavailable)"}`);
4364
- } else if (mutation.kind === "sandbox") {
4365
- io2.out("Entry set to the devnet sandbox (Mina USDC only \u2014 multihop demo path).");
4366
- io2.out(` btp ${SANDBOX_BTP_URL}`);
4367
- io2.out(` relay ${SANDBOX_RELAY_URL}`);
4143
+ if (mutation.kind === "clear") {
4144
+ io2.out(`Cleared the recorded connector in ${configPath}.`);
4368
4145
  } else {
4369
- io2.out(`Entry set to ${mutation.btpUrl}.`);
4370
- 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}.`);
4371
4149
  }
4150
+ for (const w of warnings) io2.out(`warning: ${w}`);
4372
4151
  io2.out(
4373
- `Saved to ${configPath}.` + (clearedTopologyCache ? " Cleared the cached topology." : "")
4152
+ `Effective connector: ${state.connectorUrl ?? "(none)"} [${label(state.connectorSource)}]`
4374
4153
  );
4375
- for (const w of warnings) io2.err(`warning: ${w}`);
4376
4154
  return 0;
4377
4155
  } catch (err) {
4378
4156
  return emitCliError(io2, json, "entry", err);
@@ -4599,21 +4377,20 @@ async function runFetch(args, deps) {
4599
4377
  }
4600
4378
 
4601
4379
  // src/cli/fund.ts
4602
- import { readFileSync as readFileSync5 } from "fs";
4603
- import { homedir as homedir5 } from "os";
4604
- 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";
4605
4383
  import { parseArgs as parseArgs11 } from "util";
4606
4384
  var DEVNET_FAUCET_URL = "https://faucet.devnet.toonprotocol.dev";
4607
- var CHAINS = ["evm", "solana", "mina"];
4385
+ var CHAINS = ["evm", "solana"];
4608
4386
  var CHAIN_ALIASES = {
4609
4387
  evm: "evm",
4610
4388
  eth: "evm",
4611
4389
  sol: "solana",
4612
4390
  solana: "solana",
4613
- mina: "mina",
4614
4391
  all: "all"
4615
4392
  };
4616
- var CHAIN_ARG_LIST2 = "evm | sol | solana | mina | all";
4393
+ var CHAIN_ARG_LIST2 = "evm | sol | solana | all";
4617
4394
  function resolveChainArg(raw) {
4618
4395
  if (raw === void 0) return void 0;
4619
4396
  const canonical = CHAIN_ALIASES[raw.toLowerCase()];
@@ -4679,13 +4456,8 @@ function sharedDevnetOrigin(env, file, originRelays = []) {
4679
4456
  }
4680
4457
  return void 0;
4681
4458
  }
4682
- async function loadGenesisSeedDefault2() {
4683
- try {
4684
- const { loadGenesisSeed } = await import("../network-bootstrap-CTYIZMP6.js");
4685
- return loadGenesisSeed();
4686
- } catch {
4687
- return void 0;
4688
- }
4459
+ async function loadGenesisSeedDefault() {
4460
+ return void 0;
4689
4461
  }
4690
4462
  async function resolveEffectiveNetwork(opts) {
4691
4463
  const { env, cwd } = opts;
@@ -4703,7 +4475,7 @@ async function resolveEffectiveNetwork(opts) {
4703
4475
  ...originRelays
4704
4476
  ].some((url) => url !== void 0);
4705
4477
  if (!anyConfiguredOrigin) {
4706
- const seed = await (opts.loadGenesisSeed ?? loadGenesisSeedDefault2)();
4478
+ const seed = await (opts.loadGenesisSeed ?? loadGenesisSeedDefault)();
4707
4479
  devnetOrigin = devnetHost(seed?.relayUrl) ?? devnetHost(seed?.btpEndpoint);
4708
4480
  seededOrigin = devnetOrigin !== void 0;
4709
4481
  }
@@ -4746,11 +4518,11 @@ function noFaucetGuidance(network, devnetOrigin) {
4746
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}`;
4747
4519
  }
4748
4520
  function readFundConfig(env) {
4749
- const dir = env["TOON_CLIENT_HOME"] ?? join6(homedir5(), ".toon-client");
4750
- const configPath = join6(dir, "config.json");
4521
+ const dir = env["TOON_CLIENT_HOME"] ?? join5(homedir4(), ".toon-client");
4522
+ const configPath = join5(dir, "config.json");
4751
4523
  try {
4752
4524
  return {
4753
- file: JSON.parse(readFileSync5(configPath, "utf8")),
4525
+ file: JSON.parse(readFileSync4(configPath, "utf8")),
4754
4526
  configPath
4755
4527
  };
4756
4528
  } catch (err) {
@@ -4828,14 +4600,13 @@ async function runFund(args, deps) {
4828
4600
  sourceLabel: resolved.sourceLabel
4829
4601
  };
4830
4602
  const client = await import("@toon-protocol/client");
4831
- const derived = await client.deriveFullIdentity(
4832
- resolved.mnemonic,
4833
- resolved.accountIndex
4834
- );
4603
+ const derived = client.deriveFullIdentity(resolved.mnemonic, {
4604
+ accountIndex: resolved.accountIndex,
4605
+ scheme: "legacy"
4606
+ });
4835
4607
  const addresses = {
4836
4608
  evm: derived.evm.address || null,
4837
- solana: derived.solana.publicKey || null,
4838
- mina: derived.mina.publicKey || null
4609
+ solana: derived.solana.publicKey || null
4839
4610
  };
4840
4611
  if (!faucetUrl) {
4841
4612
  const guidance = noFaucetGuidance(network, devnetOrigin);
@@ -4855,14 +4626,13 @@ async function runFund(args, deps) {
4855
4626
  io2.out("Wallet addresses:");
4856
4627
  io2.out(` evm ${addresses.evm ?? "(no key derived)"}`);
4857
4628
  io2.out(` solana ${addresses.solana ?? "(no key derived)"}`);
4858
- io2.out(` mina ${addresses.mina ?? "(no key derived \u2014 optional mina-signer dependency missing)"}`);
4859
4629
  return 0;
4860
4630
  }
4861
4631
  const timeoutEnv = env["TOON_CLIENT_FAUCET_TIMEOUT_MS"];
4862
- const timeoutFor = (chain) => {
4632
+ const timeoutFor = () => {
4863
4633
  if (timeoutEnv && Number.isFinite(Number(timeoutEnv))) return Number(timeoutEnv);
4864
4634
  if (file.faucetTimeoutMs !== void 0) return file.faucetTimeoutMs;
4865
- return chain === "mina" ? 13e4 : 9e4;
4635
+ return 9e4;
4866
4636
  };
4867
4637
  if (!json && inferredDevnet) {
4868
4638
  io2.out(
@@ -4872,7 +4642,7 @@ async function runFund(args, deps) {
4872
4642
  if (!json) {
4873
4643
  const list = targetChains.join(", ");
4874
4644
  io2.out(
4875
- `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`
4876
4646
  );
4877
4647
  }
4878
4648
  const singleChain = targetChains.length === 1;
@@ -4883,13 +4653,13 @@ async function runFund(args, deps) {
4883
4653
  chain,
4884
4654
  funded: false,
4885
4655
  address: null,
4886
- 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`
4887
4657
  };
4888
4658
  }
4889
4659
  const started = Date.now();
4890
4660
  try {
4891
4661
  const { response } = await client.fundWallet(faucetUrl, address, chain, {
4892
- timeout: timeoutFor(chain),
4662
+ timeout: timeoutFor(),
4893
4663
  ...deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}
4894
4664
  });
4895
4665
  return {
@@ -4998,7 +4768,8 @@ import { dirname as dirname4 } from "path";
4998
4768
  import { createInterface } from "readline/promises";
4999
4769
  import { parseArgs as parseArgs12 } from "util";
5000
4770
  async function loadKeyOps() {
5001
- return await import("@toon-protocol/client");
4771
+ const { generateKeystore, importKeystore } = await import("@toon-protocol/client");
4772
+ return { generateKeystore, importKeystore, deriveNostrKeyFromMnemonic };
5002
4773
  }
5003
4774
  var IdentityExistsError = class extends Error {
5004
4775
  constructor(pubkey, sourceLabel) {
@@ -5542,12 +5313,6 @@ async function resolveProfileRelay(flagRelay, originRelay, toonRelays) {
5542
5313
  ...toonRelays
5543
5314
  ].filter((u) => u !== void 0 && isWebSocketRelay2(u));
5544
5315
  if (candidates[0] !== void 0) return candidates[0];
5545
- try {
5546
- const { loadGenesisSeed } = await import("../network-bootstrap-CTYIZMP6.js");
5547
- const seed = loadGenesisSeed();
5548
- if (seed?.relayUrl && isWebSocketRelay2(seed.relayUrl)) return seed.relayUrl;
5549
- } catch {
5550
- }
5551
5316
  return void 0;
5552
5317
  }
5553
5318
  async function resolveOrInitGitRepo(deps, flags) {
@@ -6312,57 +6077,39 @@ var DvmBuyJobError = class extends Error {
6312
6077
  }
6313
6078
  };
6314
6079
  var defaultSubmitDvmBuyJob = async (request) => {
6315
- const { finalizeEvent } = await import("nostr-tools/pure");
6316
- const event = finalizeEvent(
6317
- {
6080
+ let answer;
6081
+ try {
6082
+ answer = await request.submit({
6318
6083
  kind: ARNS_BUY_JOB_KIND,
6319
- created_at: Math.floor(Date.now() / 1e3),
6320
- content: "",
6321
- tags: [
6322
- ["param", "name", request.name],
6323
- ["param", "type", request.type],
6324
- ...request.years !== null ? [["param", "years", String(request.years)]] : [],
6325
- ["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]
6326
6089
  ]
6327
- },
6328
- request.nostrSecretKey
6329
- );
6330
- const url = `${request.viaUrl.replace(/\/+$/, "")}/store`;
6331
- let response;
6332
- try {
6333
- response = await fetch(url, {
6334
- method: "POST",
6335
- headers: { "content-type": "application/json" },
6336
- body: JSON.stringify({ event })
6337
6090
  });
6338
6091
  } catch (err) {
6339
6092
  throw new DvmBuyJobError(
6340
- `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)}`
6341
6094
  );
6342
6095
  }
6343
- let body;
6344
- try {
6345
- body = await response.json();
6346
- } catch {
6096
+ if (!answer.accept) {
6347
6097
  throw new DvmBuyJobError(
6348
- `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}` : ""}`
6349
6099
  );
6350
6100
  }
6351
- if (!response.ok || body.accept !== true) {
6352
- throw new DvmBuyJobError(
6353
- `the DVM rejected the kind:${ARNS_BUY_JOB_KIND} buy job (HTTP ${response.status}${body.code ? `, ${body.code}` : ""})${body.message ? `: ${body.message}` : ""}`
6354
- );
6355
- }
6356
- const registryTxId = body.result?.registryTxId;
6101
+ const registryTxId = answer.result?.["registryTxId"];
6357
6102
  if (typeof registryTxId !== "string" || registryTxId.length === 0) {
6358
6103
  throw new DvmBuyJobError(
6359
- `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)
6360
6105
  );
6361
6106
  }
6107
+ const quotedMario = answer.result?.["quotedMario"];
6108
+ const syncAttributesTxId = answer.result?.["syncAttributesTxId"];
6362
6109
  return {
6363
6110
  registryTxId,
6364
- quotedMario: typeof body.result?.quotedMario === "string" ? body.result.quotedMario : null,
6365
- syncAttributesTxId: typeof body.result?.syncAttributesTxId === "string" ? body.result.syncAttributesTxId : null
6111
+ quotedMario: typeof quotedMario === "string" ? quotedMario : null,
6112
+ syncAttributesTxId: typeof syncAttributesTxId === "string" ? syncAttributesTxId : null
6366
6113
  };
6367
6114
  };
6368
6115
  var GAS_STATION_JOB_KIND = 5096;
@@ -6374,47 +6121,23 @@ var GasStationJobError = class extends Error {
6374
6121
  }
6375
6122
  reason;
6376
6123
  };
6377
- async function postGasStationJob(viaUrl, params, nostrSecretKey) {
6378
- const { finalizeEvent } = await import("nostr-tools/pure");
6379
- const event = finalizeEvent(
6380
- {
6381
- kind: GAS_STATION_JOB_KIND,
6382
- created_at: Math.floor(Date.now() / 1e3),
6383
- content: "",
6384
- tags: params.map(([k, v]) => ["param", k, v])
6385
- },
6386
- nostrSecretKey
6387
- );
6388
- const url = `${viaUrl.replace(/\/+$/, "")}/store`;
6389
- let response;
6124
+ async function submitGasStationJob(destination, params, submit) {
6125
+ let answer;
6390
6126
  try {
6391
- response = await fetch(url, {
6392
- method: "POST",
6393
- headers: { "content-type": "application/json" },
6394
- body: JSON.stringify({ event })
6395
- });
6127
+ answer = await submit({ kind: GAS_STATION_JOB_KIND, params });
6396
6128
  } catch (err) {
6397
6129
  throw new GasStationJobError(
6398
6130
  "unreachable",
6399
- `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)}`
6400
6132
  );
6401
6133
  }
6402
- let body;
6403
- try {
6404
- body = await response.json();
6405
- } catch {
6134
+ if (!answer.accept || !answer.result) {
6406
6135
  throw new GasStationJobError(
6407
- "bad_response",
6408
- `the DVM at ${url} returned a non-JSON response (HTTP ${response.status})`
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}` : ""}`
6409
6138
  );
6410
6139
  }
6411
- if (!response.ok || body.accept !== true || !body.result) {
6412
- throw new GasStationJobError(
6413
- String(body.code ?? "rejected"),
6414
- `the DVM rejected the kind:${GAS_STATION_JOB_KIND} job (HTTP ${response.status}${body.code ? `, ${body.code}` : ""})${body.message ? `: ${body.message}` : ""}`
6415
- );
6416
- }
6417
- const result = body.result;
6140
+ const result = answer.result;
6418
6141
  if (result["status"] === "failed") {
6419
6142
  throw new GasStationJobError(
6420
6143
  String(result["reason"] ?? "failed"),
@@ -6425,13 +6148,13 @@ async function postGasStationJob(viaUrl, params, nostrSecretKey) {
6425
6148
  }
6426
6149
  var defaultGasStationClient = {
6427
6150
  quote: async (args) => {
6428
- const result = await postGasStationJob(
6429
- args.viaUrl,
6151
+ const result = await submitGasStationJob(
6152
+ args.destination,
6430
6153
  [
6431
6154
  ["phase", "quote"],
6432
6155
  ...args.transaction !== void 0 ? [["transaction", args.transaction]] : []
6433
6156
  ],
6434
- args.nostrSecretKey
6157
+ args.submit
6435
6158
  );
6436
6159
  const { quoteId, feePayer, maxLamports, recentBlockhash, expiresAt } = result;
6437
6160
  if (typeof quoteId !== "string" || typeof feePayer !== "string" || typeof maxLamports !== "string" || typeof recentBlockhash !== "string" || typeof expiresAt !== "number") {
@@ -6443,15 +6166,15 @@ var defaultGasStationClient = {
6443
6166
  return { quoteId, feePayer, maxLamports, recentBlockhash, expiresAt };
6444
6167
  },
6445
6168
  execute: async (args) => {
6446
- const result = await postGasStationJob(
6447
- args.viaUrl,
6169
+ const result = await submitGasStationJob(
6170
+ args.destination,
6448
6171
  [
6449
6172
  ["phase", "execute"],
6450
6173
  ["transaction", args.transaction],
6451
6174
  ["quoteId", args.quoteId],
6452
6175
  ["idempotencyKey", args.idempotencyKey]
6453
6176
  ],
6454
- args.nostrSecretKey
6177
+ args.submit
6455
6178
  );
6456
6179
  const signature = result["signature"];
6457
6180
  if (typeof signature !== "string" || signature.length === 0) {
@@ -6468,7 +6191,7 @@ var defaultGasStationClient = {
6468
6191
  };
6469
6192
  }
6470
6193
  };
6471
- var DEVNET_DVM_URL = "https://dvm.devnet.toonprotocol.dev";
6194
+ var DEVNET_DVM_DESTINATION = "g.toon.ario";
6472
6195
  var NAME_USAGE = `Usage: rig name <buy|set|status> <name> [options]
6473
6196
 
6474
6197
  ArNS naming for Arweave-served artifacts. A name registered on the ar.io
@@ -6481,7 +6204,7 @@ mnemonic that pays for pushes (derived at m/44'/501'/0'/0'). Fund it with
6481
6204
  registry program \u2014 NOT through TOON ILP payment channels.
6482
6205
 
6483
6206
  Commands:
6484
- name buy <name> [--years n | --permabuy] [--via <dvm-url>]
6207
+ name buy <name> [--years n | --permabuy] [--via <destination>]
6485
6208
  quote (mARIO) \u2192 confirm \u2192 register. The spawned ANT is
6486
6209
  owned by this identity's Solana key. Default: 1-year
6487
6210
  lease. PAID \u2014 spends mARIO from the Solana wallet.
@@ -6489,7 +6212,7 @@ Commands:
6489
6212
  the ANT (dust SOL only), then a store DVM executes the
6490
6213
  kind:5095 buy job and pays the mARIO from ITS wallet;
6491
6214
  the name is owned by your ANT from inception.
6492
- name set <name> <txId> [--undername <sub>] [--ttl <seconds>] [--via <dvm-url>]
6215
+ name set <name> <txId> [--undername <sub>] [--ttl <seconds>] [--via <destination>]
6493
6216
  point the name (or an undername) at an Arweave txId
6494
6217
  (typically a deployed path manifest). Signs an ANT
6495
6218
  record update with the Solana key. With --via: the
@@ -6521,17 +6244,24 @@ Options:
6521
6244
  unverified.
6522
6245
  --process-id <id> explicit ArNS registry program id \u2014 a Solana program
6523
6246
  address (overrides --network; or RIG_ARIO_PROCESS_ID)
6524
- --via <dvm-url> broker buy/set through a store DVM's job endpoint (or
6525
- RIG_ARNS_DVM_URL). The DVM pays the mARIO; you own the
6526
- name via your spawned ANT. Direct backend targeting
6527
- stubs the job payment (dev/e2e) \u2014 the paid path runs
6528
- 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).
6529
6259
  DEVNET DEFAULT: with --network devnet and the TOON
6530
6260
  network on devnet too, buy/set default to the deployed
6531
- devnet store DVM (${DEVNET_DVM_URL})
6261
+ devnet store DVM (${DEVNET_DVM_DESTINATION})
6532
6262
  unless --direct opts out.
6533
6263
  --direct force the direct wallet-paid path: never default (or
6534
- read RIG_ARNS_DVM_URL as) a --via DVM. Mutually
6264
+ read RIG_ARNS_DVM_DESTINATION as) a --via DVM. Mutually
6535
6265
  exclusive with an explicit --via.
6536
6266
  --yes skip the confirmation (required when not a TTY) for
6537
6267
  buy/set
@@ -6541,6 +6271,25 @@ Options:
6541
6271
  var DEFAULT_TTL_SECONDS = 3600;
6542
6272
  var DEFAULT_LEASE_YEARS = 1;
6543
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
+ }
6544
6293
  async function resolveNameContext(deps, network, processId, mode) {
6545
6294
  const { io: io2, env } = deps;
6546
6295
  const resolved = await resolveIdentity({
@@ -6554,10 +6303,10 @@ async function resolveNameContext(deps, network, processId, mode) {
6554
6303
  sourceLabel: resolved.sourceLabel
6555
6304
  };
6556
6305
  const client = await import("@toon-protocol/client");
6557
- const derived = await client.deriveFullIdentity(
6558
- resolved.mnemonic,
6559
- resolved.accountIndex
6560
- );
6306
+ const derived = client.deriveFullIdentity(resolved.mnemonic, {
6307
+ accountIndex: resolved.accountIndex,
6308
+ scheme: "legacy"
6309
+ });
6561
6310
  const solanaAddress = derived.solana.publicKey;
6562
6311
  if (!solanaAddress) {
6563
6312
  throw new Error(
@@ -6571,7 +6320,7 @@ async function resolveNameContext(deps, network, processId, mode) {
6571
6320
  network,
6572
6321
  ...processId !== void 0 ? { processId } : {}
6573
6322
  });
6574
- const nostrSecretKey = client.deriveNostrKeyFromMnemonic(
6323
+ const nostrSecretKey = deriveNostrKeyFromMnemonic(
6575
6324
  resolved.mnemonic,
6576
6325
  resolved.accountIndex
6577
6326
  ).secretKey;
@@ -6642,12 +6391,17 @@ function parseNameFlags(args, env) {
6642
6391
  "--direct and --via are mutually exclusive: --direct forces the wallet-paid path, --via brokers through a DVM"
6643
6392
  );
6644
6393
  }
6645
- 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"];
6646
6395
  let via;
6647
6396
  if (viaRaw !== void 0) {
6648
- if (!/^https?:\/\/.+/.test(viaRaw)) {
6397
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(viaRaw)) {
6649
6398
  throw new Error(
6650
- `--via must be an http(s) DVM endpoint URL, got ${JSON.stringify(viaRaw)}`
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)) {
6403
+ throw new Error(
6404
+ `--via must be an ILP destination like ${DEVNET_DVM_DESTINATION}, got ${JSON.stringify(viaRaw)}`
6651
6405
  );
6652
6406
  }
6653
6407
  via = viaRaw;
@@ -6753,14 +6507,20 @@ async function runBuy(name, flags, deps) {
6753
6507
  io2.out(`Spawned ANT ${spawn3.processId} (tx ${spawn3.signature})`);
6754
6508
  }
6755
6509
  const submit = deps.submitDvmBuyJob ?? defaultSubmitDvmBuyJob;
6756
- const receipt2 = await submit({
6757
- viaUrl: via,
6758
- name,
6759
- type,
6760
- years,
6761
- processId: spawn3.processId,
6762
- nostrSecretKey: signed.nostrSecretKey
6763
- });
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
+ }
6764
6524
  const result2 = {
6765
6525
  registryTxId: receipt2.registryTxId,
6766
6526
  antProcessId: spawn3.processId,
@@ -6908,25 +6668,32 @@ async function runSet(name, txId, flags, deps) {
6908
6668
  );
6909
6669
  if (via !== null) {
6910
6670
  const gas = deps.gasStation ?? defaultGasStationClient;
6911
- const quote = await gas.quote({
6912
- viaUrl: via,
6913
- nostrSecretKey: signed.nostrSecretKey
6914
- });
6915
- const wireTx = await signed.sdk.buildSetRecordTransaction({
6916
- antProcessId,
6917
- undername: undername ?? "@",
6918
- transactionId: txId,
6919
- ttlSeconds: flags.ttl,
6920
- feePayer: quote.feePayer,
6921
- recentBlockhash: quote.recentBlockhash
6922
- });
6923
- const executed = await gas.execute({
6924
- viaUrl: via,
6925
- transaction: wireTx,
6926
- quoteId: quote.quoteId,
6927
- idempotencyKey: randomUUID(),
6928
- nostrSecretKey: signed.nostrSecretKey
6929
- });
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
+ }
6930
6697
  const gasStation = {
6931
6698
  quoteId: quote.quoteId,
6932
6699
  feePayer: quote.feePayer,
@@ -7090,9 +6857,9 @@ async function runName(args, deps) {
7090
6857
  } catch {
7091
6858
  }
7092
6859
  if (toonDevnet) {
7093
- flags = { ...flags, via: DEVNET_DVM_URL };
6860
+ flags = { ...flags, via: DEVNET_DVM_DESTINATION };
7094
6861
  io2.err(
7095
- `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}).`
7096
6863
  );
7097
6864
  }
7098
6865
  }
@@ -7138,22 +6905,22 @@ function buildArweaveManifest(entries, indexPath = DEFAULT_INDEX, fallbackTxId)
7138
6905
  }
7139
6906
 
7140
6907
  // src/cli/site-record.ts
7141
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
7142
- import { homedir as homedir6 } from "os";
7143
- 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";
7144
6911
  var SITE_MANIFEST_FILENAME = "site-manifests.json";
7145
6912
  function storeDir2(env) {
7146
- return env["TOON_CLIENT_HOME"] ?? join7(homedir6(), ".toon-client");
6913
+ return env["TOON_CLIENT_HOME"] ?? join6(homedir5(), ".toon-client");
7147
6914
  }
7148
6915
  function storePath2(env) {
7149
- return join7(storeDir2(env), SITE_MANIFEST_FILENAME);
6916
+ return join6(storeDir2(env), SITE_MANIFEST_FILENAME);
7150
6917
  }
7151
6918
  function keyOf(repoId, ref) {
7152
6919
  return `${repoId}\0${ref}`;
7153
6920
  }
7154
6921
  function readFile2(env) {
7155
6922
  try {
7156
- const parsed = JSON.parse(readFileSync6(storePath2(env), "utf8"));
6923
+ const parsed = JSON.parse(readFileSync5(storePath2(env), "utf8"));
7157
6924
  if (parsed && typeof parsed === "object") return parsed;
7158
6925
  return {};
7159
6926
  } catch {
@@ -7174,7 +6941,7 @@ function writeSiteRecord(env, record) {
7174
6941
 
7175
6942
  // src/cli/site.ts
7176
6943
  var MANIFEST_CONTENT_TYPE = "application/x.arweave-manifest+json";
7177
- var DEFAULT_GATEWAY = "https://ar-io.dev";
6944
+ var DEFAULT_GATEWAY = PREFERRED_GATEWAY;
7178
6945
  var SITE_USAGE = `Usage: rig site <publish|url> [ref] [options]
7179
6946
 
7180
6947
  Serve a pushed repo as a permanent, path-routed website. \`rig push\` already
@@ -7362,7 +7129,6 @@ async function runSitePublish(args, deps) {
7362
7129
  }
7363
7130
  }
7364
7131
  const feeRates = await ctx.publisher.getFeeRates();
7365
- const { uploadFee } = feeRates;
7366
7132
  const previewEntries = blobs.map((b) => ({
7367
7133
  path: b.path,
7368
7134
  txId: known.get(b.sha) ?? PLACEHOLDER_TX
@@ -7378,9 +7144,12 @@ async function runSitePublish(args, deps) {
7378
7144
  if (flags.forceReupload) {
7379
7145
  const { objects } = await reader.statObjects(uniqueShas);
7380
7146
  reuploadBytes = objects.reduce((sum, o) => sum + o.size, 0);
7381
- reuploadFee = BigInt(objects.length) * uploadFee;
7147
+ reuploadFee = objects.reduce(
7148
+ (sum, o) => sum + uploadChargeFor(feeRates, o.size),
7149
+ 0n
7150
+ );
7382
7151
  }
7383
- const manifestFee = uploadFee;
7152
+ const manifestFee = uploadChargeFor(feeRates, manifestBytes);
7384
7153
  const totalFee = manifestFee + reuploadFee;
7385
7154
  const gateway = flags.gateway ?? deps.env["RIG_ARWEAVE_GATEWAY"] ?? DEFAULT_GATEWAY;
7386
7155
  const baseJson = () => ({