@toon-protocol/rig 4.6.0 → 5.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 (35) hide show
  1. package/README.md +118 -25
  2. package/dist/{chunk-X232W4TG.js → chunk-2TG4YHEC.js} +89 -59
  3. package/dist/chunk-2TG4YHEC.js.map +1 -0
  4. package/dist/{chunk-DCGV6ALH.js → chunk-4WVH2ITA.js} +158 -9
  5. package/dist/chunk-4WVH2ITA.js.map +1 -0
  6. package/dist/{chunk-U5A7MHBP.js → chunk-7VIVQHRG.js} +1 -1
  7. package/dist/chunk-7VIVQHRG.js.map +1 -0
  8. package/dist/chunk-CHVOXCDV.js +0 -0
  9. package/dist/chunk-CHVOXCDV.js.map +1 -0
  10. package/dist/{chunk-XCLUB2CY.js → chunk-LMZSAFAB.js} +44 -15
  11. package/dist/chunk-LMZSAFAB.js.map +1 -0
  12. package/dist/{chunk-JBFBD7HV.js → chunk-QKL53YZS.js} +7 -3
  13. package/dist/chunk-QKL53YZS.js.map +1 -0
  14. package/dist/{chunk-UE5TAFEU.js → chunk-ZQGXFFBP.js} +4 -4
  15. package/dist/chunk-ZQGXFFBP.js.map +1 -0
  16. package/dist/{ci-serve-AYFZOY4O.js → ci-serve-BU7NDT7O.js} +152 -26
  17. package/dist/ci-serve-BU7NDT7O.js.map +1 -0
  18. package/dist/cli/rig.js +6 -5
  19. package/dist/cli/rig.js.map +1 -1
  20. package/dist/index.d.ts +117 -4
  21. package/dist/index.js +40 -7
  22. package/dist/index.js.map +1 -1
  23. package/dist/standalone/index.d.ts +109 -74
  24. package/dist/standalone/index.js +13 -3
  25. package/dist/{standalone-mode-UQSP4677.js → standalone-mode-AT4S5EZG.js} +148 -50
  26. package/dist/standalone-mode-AT4S5EZG.js.map +1 -0
  27. package/package.json +2 -2
  28. package/dist/chunk-DCGV6ALH.js.map +0 -1
  29. package/dist/chunk-JBFBD7HV.js.map +0 -1
  30. package/dist/chunk-U5A7MHBP.js.map +0 -1
  31. package/dist/chunk-UE5TAFEU.js.map +0 -1
  32. package/dist/chunk-X232W4TG.js.map +0 -1
  33. package/dist/chunk-XCLUB2CY.js.map +0 -1
  34. package/dist/ci-serve-AYFZOY4O.js.map +0 -1
  35. package/dist/standalone-mode-UQSP4677.js.map +0 -1
package/README.md CHANGED
@@ -9,7 +9,7 @@ lives in NIP-34 Nostr events and the objects live on Arweave.
9
9
  - **Writes are paid** — pushing objects and publishing events spends from a
10
10
  payment channel funded by your wallet. Writes are permanent and non-refundable.
11
11
  - **One node URL is the whole network configuration** — `rig` embeds its own
12
- payment client (`@toon-protocol/client` 3.x) built from your seed phrase and
12
+ payment client (`@toon-protocol/client` 4.x) built from your seed phrase and
13
13
  pays the TOON connector you name with `rig entry <url>`. The node describes
14
14
  itself on `GET /ilp`; there is nothing to discover (see
15
15
  [Pointing at a node](#pointing-at-a-node)).
@@ -238,20 +238,27 @@ estimate — nothing is executed or paid).
238
238
 
239
239
  ## Money: fund, balance, channels
240
240
 
241
- Paid commands spend from a **payment channel** — an on-chain-collateralized channel
242
- between your wallet and a payment peer, from which each write draws an off-chain
243
- claim. You rarely touch this directly:
241
+ Paid commands spend from a **payment channel**: an x402 `batch-settlement`
242
+ channel between your wallet and the node, collateralized on chain, on which each
243
+ write signs an off-chain voucher naming the running total (connector ADR 0075;
244
+ there is no nonce). You rarely touch this directly:
244
245
 
245
246
  - **`rig fund`** tops up your wallet (devnet faucet, or prints addresses to fund
246
247
  externally). Both the native coin (gas) and USDC (collateral) are needed.
247
248
  - **`rig balance`** shows what your wallet holds across chains.
248
249
  - **Channels open lazily.** The first paid write opens a channel from your funded
249
- wallet and records it under `~/.toon-client` (`rig-channels.json`); later writes
250
- resume the same channel instead of opening a new one.
251
- - **`rig channel list`** (free) shows current holdings and nonce watermarks.
252
- **`rig channel open`** pre-opens one (or `--deposit`s more collateral) using the
253
- exact lazy-open path; **`rig channel close`** starts the settlement challenge
254
- window; **`rig channel settle`** releases collateral once the window elapses.
250
+ wallet (on Solana the node sponsors the open: USDC for the deposit, no SOL) and
251
+ records it under `~/.toon-client` (`rig-channels-x402.json`); later writes
252
+ resume the same channel, and a write it can no longer cover opens a fresh one.
253
+ - **`rig channel list`** (free) shows current holdings and the running totals
254
+ signed. **`rig channel open`** pre-opens one (or `--deposit`s more collateral,
255
+ Base only) using the exact lazy-open path; **`rig channel close`** starts the
256
+ exit window; **`rig channel settle`** releases collateral once the window
257
+ elapses.
258
+ - **Upgrading from a client 3.x rig** (4.7.x and earlier): its toon-channel
259
+ files (`rig-channels.json`, `channels.json`) are never read or written, only
260
+ named. A current connector refuses those claims; take their deposits back
261
+ with the rig that opened them.
255
262
 
256
263
  The `open`/`close`/`settle` lifecycle commands are on-chain wallet operations (gas +
257
264
  collateral movement), so they follow the same confirm idiom as `push`: they print
@@ -459,10 +466,58 @@ rig ci serve --relay wss://<relay> --repo <owner-npub>/<repo-id> [--repo …]
459
466
  | `--gateway <url>` | `RIG_ARWEAVE_GATEWAY`, else rig's preferred Arweave gateway | the gateway that serves the store's raw bytes: prefix for log/artifact URLs (`<gateway>/raw/<txId>`) **and** the first gateway the coordinator reads a commit's objects from (same `/raw/` route), ahead of the shared public list — name a private or local gateway (the sandbox's) and the coordinator needs nothing else to read |
460
467
  | `--act-bin <path>` | `act` on PATH (or `RIG_ACT_BIN`) | the act binary |
461
468
  | `--platform <label>=<image>` | `ubuntu-latest=catthehacker/ubuntu:act-latest` | `runs-on` label → Docker image (repeatable) |
469
+ | `--pull` / `--no-pull` | act's default (pull before each run) | whether act pulls the runner image named by `--platform` before each run |
462
470
  | `--workdir <dir>` | `<state-dir>/work` | where commits are materialized |
463
471
  | `--once` | | stop after the first run concludes (its 9842 and final 39842 are on the relay) — one `rig ci trigger` answered by one bounded serve; ignored or refused triggers do not count |
464
472
  | `--json` | | one JSON document with the coordinator, relay, repos and state dir on start |
465
473
 
474
+ **Two act behaviours decide whether a real workflow passes**, and a workflow
475
+ whose steps only `echo` hides both:
476
+
477
+ - **Write `actions/checkout@v4`, exactly as you would on GitHub.** act copies
478
+ the materialized tree into the job container *at that step*, not when the
479
+ container starts, and short-circuits it to a local `docker cp` — so the step
480
+ needs no network and no node in the image. A workflow without it
481
+ runs its tools against an **empty** container — the steps execute, the files
482
+ are not there:
483
+
484
+ ```
485
+ error: could not find `Cargo.toml` in `/…/work/<repo>-<sha>-1` or any parent directory
486
+ ```
487
+
488
+ That path is the checkout the coordinator materialized under `--workdir`
489
+ (`<repo-id>-<short sha>-<n>`), as the job container sees it.
490
+ - **The default image is not GitHub's hosted runner.** `ubuntu-latest` maps to
491
+ `catthehacker/ubuntu:act-latest`, which carries no language toolchain, so a
492
+ workflow that expects a preinstalled `cargo`, `go` or JDK fails at its first
493
+ step. Either point `--platform` at an image that has one
494
+ (`--platform ubuntu-latest=rust:1-bookworm`) or install it in a step. The
495
+ official `rust` images ship neither rustfmt nor clippy —
496
+ `rustup component add rustfmt clippy` is a step, not a given — and an image
497
+ you built locally needs `--no-pull` (below).
498
+
499
+ A workflow that survives both, run by a coordinator started with
500
+ `--platform ubuntu-latest=rust:1-bookworm`:
501
+
502
+ ```yaml
503
+ # .github/workflows/ci.yml
504
+ name: ci
505
+ on: [push]
506
+ jobs:
507
+ test:
508
+ runs-on: ubuntu-latest
509
+ steps:
510
+ - uses: actions/checkout@v4 # act resolves this to the local copy
511
+ - run: rustup component add rustfmt clippy
512
+ - run: cargo fmt --check
513
+ - run: cargo clippy -- -D warnings
514
+ - run: cargo test
515
+ ```
516
+
517
+ A runner image built or loaded on the coordinator host and never pushed to a
518
+ registry needs `--no-pull`: without it act force-pulls the image named by
519
+ `--platform` and every run fails in *Set up job* with `pull access denied`.
520
+
466
521
  On start the coordinator publishes an **Advertisement** (19843: runner family
467
522
  `act`, its selectors, admission `maintainer-request`, execution
468
523
  `request-required`, billing `out-of-band`, and a fresh `secrets-key`) and renews
@@ -510,9 +565,10 @@ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v rig-ci-state:/st
510
565
  The entrypoint is `rig`, so every verb works (`docker run --rm rig-ci --version`),
511
566
  and every environment variable rig honours means the same inside the image
512
567
  (`TOON_CLIENT_HOME` is `/state`). act launches each job as a container on the
513
- daemon behind the mounted socket and copies the checkout in, so no host path
514
- has to match. Against the [sandbox](#dogfooding-rigs-own-ciyml-on-the-sandbox)
515
- on the same host, run on the host network with the sandbox's own `localhost`
568
+ daemon behind the mounted socket and copies the checkout in at the
569
+ `actions/checkout` step, so no host path has to match. Against the
570
+ [sandbox](#dogfooding-rigs-own-ciyml-on-the-sandbox) on the same host, run on
571
+ the host network with the sandbox's own `localhost`
516
572
  addresses — a client dials the endpoint a node **advertises**, and the sandbox
517
573
  hub advertises `http://127.0.0.1:3200/ilp` so host-run smokes can reach it
518
574
  (sandbox-only; a real connector advertises its public URL, which the default
@@ -565,6 +621,11 @@ git commit --allow-empty -m 'ci: dogfood' && rig push --yes
565
621
  rig ci status HEAD --json | jq .summary
566
622
  ```
567
623
 
624
+ `RIG_ARWEAVE_GATEWAY` in that common env also steers the READ path: `rig clone`
625
+ and `rig fetch` try `http://localhost:3000/raw/<txId>` first, so a repo pushed to
626
+ the sandbox clones back out of it even though the public gateways never see those
627
+ objects (see [Reading through your own gateway](#reading-through-your-own-gateway)).
628
+
568
629
  The same flow, end to end and asserted, is
569
630
  `src/__integration__/ci-sandbox.integration.test.ts`; it runs only with
570
631
  `RIG_CI_SANDBOX=1` and skips itself unless the sandbox's relay, hub, store edge
@@ -583,7 +644,7 @@ network — there is no announce to discover (kind:10032 was removed by connecto
583
644
  ADR 0046) and no topology to negotiate.
584
645
 
585
646
  ```sh
586
- curl -s https://proxy.relay.devnet.toonprotocol.dev/ilp | jq '{ilpAddresses, routes, settlements: [.settlements[].chain]}'
647
+ curl -s https://proxy.relay.devnet.toonprotocol.dev/ilp | jq '{ilpAddresses, routes, batchSettlements: [.batchSettlements[].network]}'
587
648
  ```
588
649
 
589
650
  What rig derives from it, and the knob that overrides each:
@@ -594,16 +655,17 @@ What rig derives from it, and the knob that overrides each:
594
655
  | where events go | the node's first own address it also prices | `TOON_CLIENT_PUBLISH_DESTINATION` / `publishDestination` |
595
656
  | where git objects go | the node's first priced `*.store` route, else `*.ario` | `TOON_CLIENT_STORE_DESTINATION` / `storeDestination`; `rig name --via` per invocation |
596
657
  | a store on another node | — | `storeConnectorUrl` (that node holds its own channel: uploads ride a second client and watermark) or `storeSealTo` (same channel, sealed to that node) |
597
- | settlement chain | the first chain in `settlements[]` your identity holds a key for | `TOON_CLIENT_CHAIN` / `chain` — `evm` or `solana` (`evm:8453` is read by its family) |
658
+ | settlement chain | the first chain in `batchSettlements[]` your identity holds a key for (a phrase holds both: name one) | `TOON_CLIENT_CHAIN` / `chain`: `evm` or `solana` (`evm:8453` is read by its family) |
598
659
  | chain RPC | the client's devnet preset | `TOON_CLIENT_RPC_URL` / `rpcUrl` / `chainRpcUrls[<chain>]` — **set this for a mainnet node** |
599
660
  | who pays | the phrase's key on that chain | `RIG_SOLANA_KEY_FILE` / `solanaKeyFile` (a `solana-keygen` JSON), `RIG_EVM_PRIVATE_KEY` / `evmPrivateKey` |
600
- | claim watermark file | `<TOON_CLIENT_HOME>/channels.json` | `TOON_CLIENT_CHANNEL_STORE` / `channelStorePath` — one file per channel writer, or two processes replay each other's nonces |
601
- | first-open collateral | the client default | `TOON_CLIENT_DEPOSIT` / `deposit` (base units) |
661
+ | x402 channel store | `<TOON_CLIENT_HOME>/channels-x402.json` (+ `.peers.json`, each channel's config: keep both) | `TOON_CLIENT_CHANNEL_STORE` / `channelStorePath`: one file per channel writer, or two processes race each other's running totals. A client 3.x store is refused |
662
+ | channel collateral | the client default (Solana: at least the node's `minDeposit`) | `TOON_CLIENT_DEPOSIT` / `deposit` (base units) |
663
+ | Base deposit facilitator | none on Solana; the client's own on EVM | `TOON_CLIENT_FACILITATOR_URL` / `facilitatorUrl` |
602
664
  | carriage | `auto` (HTTP unless the node requires BTP) | `TOON_CLIENT_TRANSPORT` / `transport` |
603
665
 
604
666
  **Prices are schedules.** A route publishes a base price and, when it meters by
605
667
  size, a `pricePerKib` (connector ADR 0065). `rig push`'s fee table prices every
606
- object by its sealed size with the same rule the client puts on the claim, so
668
+ object by its sealed size with the same rule the client puts on the voucher, so
607
669
  the estimate equals what is paid.
608
670
 
609
671
  **Who pays and who signs are independent.** The repo owner is the phrase's
@@ -612,7 +674,7 @@ Its EVM wallet is that same key (the client's `keyDerivation: 'legacy'`, rig's
612
674
  default, so channels an existing identity funded are still its own); set
613
675
  `TOON_CLIENT_KEY_DERIVATION=standard` for a fresh identity you want to import
614
676
  into MetaMask. The payer key may be a different key entirely: the connector
615
- attributes payment from the claim, never from the event.
677
+ attributes payment from the voucher, never from the event.
616
678
 
617
679
  ### Devnet
618
680
 
@@ -692,13 +754,13 @@ phrase itself is never printed and never written to git config or any repo file.
692
754
  ## What a paid command does first
693
755
 
694
756
  Every standalone paid command bootstraps the same way: resolve the identity,
695
- read the connector's `GET /ilp`, open or adopt the payment channel with that
696
- node, then sign one claim per packet. Adoption is free — a channel's id derives
697
- from its participants, so a node you have paid before is found again without a
698
- transaction. Money state (the claim watermark, the channel map) lives under
699
- `TOON_CLIENT_HOME` and is never cached away.
757
+ read the connector's `GET /ilp`, open or resume the x402 channel with that
758
+ node, then sign one voucher per packet. Resuming is free: the client keeps each
759
+ channel's config in its store, so a node you have paid before is found again
760
+ without a transaction. Money state (the voucher watermark, the channel configs,
761
+ the channel map) lives under `TOON_CLIENT_HOME` and is never cached away.
700
762
 
701
- Two rig processes on one identity race the claim nonce, so a per-identity lock
763
+ Two rig processes on one identity race the running total, so a per-identity lock
702
764
  refuses the second (`RIG_STANDALONE=1` skips only the check for a same-identity
703
765
  `toon-clientd`; the lock stays). The `rig` bin exits as soon as a command
704
766
  finishes and stdio is flushed.
@@ -774,6 +836,37 @@ clone never leaves a partial repo. `rig fetch [remote]` is the same pipeline as
774
836
  delta: only locally-missing objects are downloaded, and `refs/remotes/<remote>/*`
775
837
  (tags → `refs/tags/*`) move with a `git fetch`-style report.
776
838
 
839
+ ### Reading through your own gateway
840
+
841
+ By default both commands read from rig's shared public gateway list. A repository
842
+ whose objects live only on a **private, local or air-gapped** gateway is invisible
843
+ there — so `--gateway <url>` (or `RIG_ARWEAVE_GATEWAY`, the same variable `rig push`,
844
+ `rig site` and `rig ci serve` honour) puts that gateway **first**, on the store's
845
+ raw-bytes route `<url>/raw/<txId>`, with the public list kept behind it as the
846
+ fallback. It is the read-path twin of `rig ci serve --gateway`.
847
+
848
+ ```sh
849
+ export RIG_ARWEAVE_GATEWAY=http://localhost:3000 # the dev sandbox's gateway
850
+ rig clone ws://localhost:7100 <owner-npub>/<repo-id>
851
+ rig fetch # or: rig fetch --gateway http://localhost:3000
852
+ ```
853
+
854
+ `/raw/` and not `/<txId>`: an ar.io node serves raw transaction bytes there whether
855
+ or not it does sandboxed-subdomain redirects, and the TOON store's own gateway
856
+ answers on that route alone. Public gateways serve the same bytes on both, so with
857
+ nothing configured the list is exactly as it always was.
858
+
859
+ The **`Git-SHA` lookup follows the gateway too**. A kind:30618 object map is capped,
860
+ so a SHA it does not carry is resolved by asking a gateway's GraphQL endpoint which
861
+ transaction carries that object — and a configured gateway is asked at
862
+ `<url>/graphql`, never `arweave.net` (which would answer about a *different*
863
+ network, or leak the query off an air-gapped stack). Object bytes are
864
+ content-addressed and SHA-verified, so any mirror may serve them; a tag query is a
865
+ statement about one network, so it goes only to the network you named. Configure
866
+ nothing and it is the shared `arweave.net` resolver, unchanged. A gateway that does
867
+ not serve GraphQL therefore resolves nothing — name one that does (every ar.io node
868
+ does), or leave the variable unset.
869
+
777
870
  `rig issue list|show` and `rig pr list|show` are pure relay reads (kind:1621/1617 by
778
871
  the repo `#a` tag; state from kind:1630-1633, latest wins; comments under `show` —
779
872
  NIP-22 kind:1111 matched on the uppercase `E` root tag, merged with legacy kind:1622
@@ -52,9 +52,14 @@ import {
52
52
  updateRef,
53
53
  writeGitObjects,
54
54
  writeToonConfig
55
- } from "./chunk-DCGV6ALH.js";
55
+ } from "./chunk-4WVH2ITA.js";
56
+ import {
57
+ PREFERRED_GATEWAY,
58
+ mirrorGatewaysFor,
59
+ readGateways,
60
+ shaResolverFor
61
+ } from "./chunk-CHVOXCDV.js";
56
62
  import {
57
- ARWEAVE_GATEWAYS,
58
63
  COMMENT_KIND,
59
64
  DEFAULT_KEYSTORE_PASSWORD,
60
65
  LEGACY_COMMENT_KIND,
@@ -77,33 +82,19 @@ import {
77
82
  readClientConfigFile,
78
83
  resolveAccountIndex,
79
84
  resolveIdentity
80
- } from "./chunk-JBFBD7HV.js";
85
+ } from "./chunk-QKL53YZS.js";
81
86
  import {
82
87
  ChannelMapStore,
83
88
  channelStatus,
89
+ legacyChannelFiles,
84
90
  resolveChannelPaths,
85
91
  resolveConflictingPath
86
- } from "./chunk-XCLUB2CY.js";
92
+ } from "./chunk-LMZSAFAB.js";
87
93
  import {
88
94
  RIG_STANDALONE_ENV,
89
95
  deriveNostrKeyFromMnemonic,
90
96
  uploadChargeFor
91
- } from "./chunk-U5A7MHBP.js";
92
-
93
- // src/gateway-preference.ts
94
- var TESTNET_GATEWAY = /(^|\.)ar-io\.dev$/i;
95
- function isMainnetGateway(url) {
96
- try {
97
- return !TESTNET_GATEWAY.test(new URL(url).hostname);
98
- } catch {
99
- return false;
100
- }
101
- }
102
- var PREFERRED_GATEWAY = ARWEAVE_GATEWAYS.find(isMainnetGateway) ?? "https://arweave.net";
103
- function mirrorGatewaysFor(primary) {
104
- const p = primary.replace(/\/+$/, "");
105
- return ARWEAVE_GATEWAYS.filter((g) => g.replace(/\/+$/, "") !== p);
106
- }
97
+ } from "./chunk-7VIVQHRG.js";
107
98
 
108
99
  // src/cli/render.ts
109
100
  function describeAnnouncementDiff(diff) {
@@ -320,7 +311,7 @@ function loadPaidSession(deps, relayUrl) {
320
311
  });
321
312
  }
322
313
  var defaultLoadStandalone = async (options) => {
323
- const mod = await import("./standalone-mode-UQSP4677.js");
314
+ const mod = await import("./standalone-mode-AT4S5EZG.js");
324
315
  return mod.createStandaloneContext(options);
325
316
  };
326
317
  function identityReport(ctx) {
@@ -1037,7 +1028,10 @@ async function readWalletBounded(read, timeoutMs) {
1037
1028
  if (timeoutMs <= 0) return settled;
1038
1029
  let timer;
1039
1030
  const guard = new Promise((_resolve, reject) => {
1040
- timer = setTimeout(() => reject(new WalletReadTimeoutError(timeoutMs)), timeoutMs);
1031
+ timer = setTimeout(
1032
+ () => reject(new WalletReadTimeoutError(timeoutMs)),
1033
+ timeoutMs
1034
+ );
1041
1035
  });
1042
1036
  settled.catch(() => void 0);
1043
1037
  try {
@@ -1097,7 +1091,6 @@ async function runBalance(args, deps) {
1097
1091
  status: channelStatus(watermark),
1098
1092
  depositTotal: deposited ?? null,
1099
1093
  cumulativeClaimed: claimed ?? null,
1100
- nonce: watermark?.nonce ?? null,
1101
1094
  available,
1102
1095
  overdrawn
1103
1096
  };
@@ -1433,39 +1426,44 @@ async function runChain(args, deps) {
1433
1426
 
1434
1427
  // src/cli/channel.ts
1435
1428
  import { parseArgs as parseArgs4 } from "util";
1429
+ import { dirname as dirname2 } from "path";
1436
1430
  var CHANNEL_USAGE = `Usage: rig channel <subcommand>
1437
1431
 
1438
- Manage the payment channels paid rig commands hold with relay/store peers.
1439
- Paid commands open a channel lazily on first use and record it under
1440
- TOON_CLIENT_HOME (default ~/.toon-client, rig-channels.json), so later
1441
- invocations resume the same channel instead of opening a new one per run.
1432
+ Manage the x402 payment channels paid rig commands pay a node from. Every
1433
+ paid packet carries a voucher naming the channel's running total (client 4.x).
1434
+ Paid commands open a channel on first use and resume it from the client's
1435
+ store (TOON_CLIENT_HOME, default ~/.toon-client, channels-x402.json);
1436
+ \`rig channel open\` also records it in rig-channels-x402.json there.
1442
1437
 
1443
1438
  Subcommands:
1444
1439
  list [--json] show recorded channels \u2014 peer, chain, channel id, deposit,
1445
- cumulative claimed, status. Free: reads local state only.
1440
+ cumulative signed, status. Free: reads local state only.
1446
1441
 
1447
1442
  open [--peer <ilp-destination>] [--deposit <base-units>]
1448
- explicitly open the payment channel for a peer \u2014 the SAME
1449
- path paid commands use lazily: resumes the recorded live
1450
- channel if one exists (no on-chain spend), else opens and
1451
- records a fresh one (locks the peer-negotiated initial
1452
- deposit on-chain). --peer is the ILP destination to anchor
1453
- to (default: the configured destination, e.g. the devnet
1454
- apex); --deposit adds that much extra collateral after the
1455
- open/resume. On-chain: asks for confirmation (--yes skips).
1443
+ explicitly open the channel paid commands draw on: resumes
1444
+ the client's open channel if there is one (no on-chain
1445
+ spend), else opens and records a fresh one, locking the
1446
+ configured deposit (TOON_CLIENT_DEPOSIT) from your wallet.
1447
+ On Solana the node sponsors the open (USDC, no SOL).
1448
+ --peer is the ILP destination to record it under (default:
1449
+ the configured publish destination); --deposit adds that
1450
+ much extra collateral after the open/resume (Base only: a
1451
+ Solana channel is replaced when it runs out, never topped
1452
+ up). Asks for confirmation (--yes skips).
1456
1453
 
1457
1454
  close <channelId>
1458
- close a recorded channel \u2014 an on-chain tx that starts the
1459
- settlement challenge window (the peer's settlementTimeout).
1460
- The channel stops paying immediately; the remaining
1455
+ close a recorded channel: an on-chain tx (Solana
1456
+ request_close, Base timed withdrawal) that starts its exit
1457
+ window, and that of every other channel still open with the
1458
+ node. The channel stops paying immediately; the remaining
1461
1459
  collateral stays locked until \`rig channel settle\` after
1462
1460
  the window elapses. Asks for confirmation (--yes skips).
1463
1461
 
1464
1462
  settle <channelId>
1465
- settle a closed channel once its challenge window elapsed \u2014
1466
- an on-chain tx that releases the remaining collateral back
1467
- to your wallet. Refused (without spending gas) while the
1468
- window is still open. Asks for confirmation (--yes skips).
1463
+ settle a closed channel once its exit window elapsed: an
1464
+ on-chain tx that releases the remaining collateral back to
1465
+ your wallet. Nothing is sent while the window is still
1466
+ open. Asks for confirmation (--yes skips).
1469
1467
 
1470
1468
  Common options: --json (machine-readable envelopes; without --yes lifecycle
1471
1469
  commands emit a pure plan and execute nothing), --yes, -h/--help.`;
@@ -1521,10 +1519,17 @@ function runChannelList(args, deps) {
1521
1519
  const store = new ChannelMapStore(paths);
1522
1520
  const records = store.list();
1523
1521
  const rows = records.map((record) => describeChannel(record, store));
1522
+ const legacy = legacyChannelFiles(dirname2(paths.mapPath));
1523
+ const legacyNote = `client 3.x toon-channel state not shown: ${legacy.join(", ")} (its deposits are left to the rig that opened them: \`npm i -g @toon-protocol/rig@4.7.0\`, then \`rig channel close\`)`;
1524
1524
  if (json) {
1525
- io.emitJson({ command: "channel list", channels: rows });
1525
+ io.emitJson({
1526
+ command: "channel list",
1527
+ channels: rows,
1528
+ ...legacy.length > 0 ? { legacyStateFiles: legacy } : {}
1529
+ });
1526
1530
  return 0;
1527
1531
  }
1532
+ if (legacy.length > 0) io.err(`rig: ${legacyNote}`);
1528
1533
  if (rows.length === 0) {
1529
1534
  io.out(
1530
1535
  "No payment channels recorded \u2014 paid rig commands (push, issue, comment, pr) record the channel they open on first use, and `rig channel open` records an explicit one."
@@ -1556,14 +1561,13 @@ function describeChannel(record, store) {
1556
1561
  tokenNetwork: record.tokenNetwork,
1557
1562
  depositTotal: record.depositTotal ?? null,
1558
1563
  cumulativeClaimed: watermark?.cumulativeAmount ?? null,
1559
- nonce: watermark?.nonce ?? null,
1560
1564
  status: channelStatus(watermark),
1561
1565
  openedAt: record.openedAt,
1562
1566
  lastUsedAt: record.lastUsedAt
1563
1567
  };
1564
1568
  }
1565
1569
  function renderChannel(row) {
1566
- const claimed = row.cumulativeClaimed === null ? "unknown (no local claim state)" : `${row.cumulativeClaimed} base units (nonce ${row.nonce})`;
1570
+ const claimed = row.cumulativeClaimed === null ? "unknown (no local voucher state)" : `${row.cumulativeClaimed} base units signed`;
1567
1571
  return [
1568
1572
  `channel ${row.channelId} [${row.status}]`,
1569
1573
  ` peer ${row.destination} (${row.peerId})`,
@@ -1711,7 +1715,9 @@ async function runChannelOpen(args, deps) {
1711
1715
  io.out(
1712
1716
  outcome.resumed ? `Resumed recorded channel ${outcome.channelId} \u2014 no on-chain open was needed.` : `Opened channel ${outcome.channelId}${outcome.chain ? ` on ${outcome.chain}` : ""} and recorded it for reuse.`
1713
1717
  );
1714
- io.out(` peer ${outcome.destination}${outcome.peerId ? ` (${outcome.peerId})` : ""}`);
1718
+ io.out(
1719
+ ` peer ${outcome.destination}${outcome.peerId ? ` (${outcome.peerId})` : ""}`
1720
+ );
1715
1721
  if (outcome.depositAdded) {
1716
1722
  io.out(
1717
1723
  ` deposited +${outcome.depositAdded} base units` + (outcome.depositTxHash ? ` (tx ${outcome.depositTxHash})` : "")
@@ -1805,7 +1811,9 @@ async function runChannelWithdrawStep(args, deps, step) {
1805
1811
  if (!json) {
1806
1812
  const claimed = watermark?.cumulativeAmount;
1807
1813
  io.out(`Channel ${step} plan:`);
1808
- io.out(` channel ${channelId} [${channelStatus(watermark, nowSec)}]`);
1814
+ io.out(
1815
+ ` channel ${channelId} [${channelStatus(watermark, nowSec)}]`
1816
+ );
1809
1817
  io.out(` peer ${record.destination} (${record.peerId})`);
1810
1818
  io.out(` chain ${record.chain}`);
1811
1819
  io.out(
@@ -2485,7 +2493,7 @@ async function runCi(args, deps) {
2485
2493
  case "status":
2486
2494
  return runCiStatus(rest, deps);
2487
2495
  case "serve":
2488
- return (await import("./ci-serve-AYFZOY4O.js")).runCiServe(rest, deps);
2496
+ return (await import("./ci-serve-BU7NDT7O.js")).runCiServe(rest, deps);
2489
2497
  case "--help":
2490
2498
  case "-h":
2491
2499
  case "help":
@@ -2504,7 +2512,7 @@ async function runCi(args, deps) {
2504
2512
 
2505
2513
  // src/cli/clone.ts
2506
2514
  import { mkdtemp, mkdir, readdir, rename, rm, rmdir } from "fs/promises";
2507
- import { basename, dirname as dirname2, join as join3, resolve } from "path";
2515
+ import { basename, dirname as dirname3, join as join3, resolve } from "path";
2508
2516
  import { parseArgs as parseArgs6 } from "util";
2509
2517
  var CLONE_USAGE = `Usage: rig clone <relay-url> <owner>/<repo-id> [dir] [options]
2510
2518
 
@@ -2525,6 +2533,11 @@ from Arweave gateways. A clone right after a push may report missing
2525
2533
  objects \u2014 retry after propagation.
2526
2534
 
2527
2535
  Options:
2536
+ --gateway <url> gateway to read objects through FIRST, on its raw-bytes
2537
+ route <url>/raw/<txId>, ahead of the public gateway
2538
+ list \u2014 name a private, local or air-gapped gateway to
2539
+ clone a repo the public ones do not carry
2540
+ (env RIG_ARWEAVE_GATEWAY also sets it)
2528
2541
  --concurrency <n> parallel gateway downloads (default 8)
2529
2542
  --json machine-readable result envelope
2530
2543
  -h, --help show this help`;
@@ -2551,6 +2564,7 @@ function parseCloneArgs(args) {
2551
2564
  options: {
2552
2565
  json: { type: "boolean", default: false },
2553
2566
  concurrency: { type: "string" },
2567
+ gateway: { type: "string" },
2554
2568
  help: { type: "boolean", short: "h", default: false }
2555
2569
  },
2556
2570
  allowPositionals: true
@@ -2586,6 +2600,7 @@ function parseCloneArgs(args) {
2586
2600
  repoId,
2587
2601
  dir,
2588
2602
  concurrency,
2603
+ gateway: values.gateway,
2589
2604
  json: values.json === true
2590
2605
  };
2591
2606
  }
@@ -2634,7 +2649,9 @@ async function runClone(args, deps) {
2634
2649
  ownerPubkey: owner,
2635
2650
  repoId,
2636
2651
  ...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {},
2637
- ...deps.resolveSha ? { resolveSha: deps.resolveSha } : {}
2652
+ // The GraphQL fallback for SHAs the map does not cover asks the SAME
2653
+ // permaweb the objects are read from (#183).
2654
+ resolveSha: deps.resolveSha ?? shaResolverFor(parsed.gateway, deps.env)
2638
2655
  });
2639
2656
  if (!remoteState.announced && remoteState.refsEvent === null) {
2640
2657
  throw new RepoNotFoundError(relayUrl, owner, repoId);
@@ -2659,6 +2676,8 @@ async function runClone(args, deps) {
2659
2676
  tips,
2660
2677
  shaToTxId: remoteState.shaToTxId,
2661
2678
  resolveMissing: (shas) => remoteState.resolveMissing(shas),
2679
+ // `--gateway` / RIG_ARWEAVE_GATEWAY first, public list behind it (#176).
2680
+ gateways: readGateways(parsed.gateway, deps.env),
2662
2681
  ...deps.fetchFn ? { fetchFn: deps.fetchFn } : {},
2663
2682
  ...parsed.concurrency !== void 0 ? { concurrency: parsed.concurrency } : {}
2664
2683
  });
@@ -2673,7 +2692,7 @@ async function runClone(args, deps) {
2673
2692
  `warning: unreachable object ${sha} (tx ${txId}) could not be downloaded \u2014 not needed by any ref, continuing`
2674
2693
  );
2675
2694
  }
2676
- const parent = dirname2(dest);
2695
+ const parent = dirname3(dest);
2677
2696
  await mkdir(parent, { recursive: true });
2678
2697
  tempDir = await mkdtemp(join3(parent, `.${basename(dest)}.rig-clone-`));
2679
2698
  await runGit(tempDir, [
@@ -4020,7 +4039,7 @@ async function warnIfNotMaintainer(deps, args) {
4020
4039
  // src/cli/entry.ts
4021
4040
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
4022
4041
  import { homedir as homedir3 } from "os";
4023
- import { dirname as dirname3, join as join4 } from "path";
4042
+ import { dirname as dirname4, join as join4 } from "path";
4024
4043
  import { parseArgs as parseArgs9 } from "util";
4025
4044
  var ENTRY_USAGE = `Usage: rig entry [<connector-url> | clear] [options]
4026
4045
 
@@ -4059,7 +4078,7 @@ function readEntryConfig(configPath) {
4059
4078
  }
4060
4079
  }
4061
4080
  function writeEntryConfig(configPath, file) {
4062
- mkdirSync3(dirname3(configPath), { recursive: true });
4081
+ mkdirSync3(dirname4(configPath), { recursive: true });
4063
4082
  writeFileSync3(configPath, `${JSON.stringify(file, null, 2)}
4064
4083
  `, "utf8");
4065
4084
  }
@@ -4256,6 +4275,11 @@ Options:
4256
4275
  --repo-id <id> repository id / NIP-34 d-tag (default: git config)
4257
4276
  --owner <pubkey> repository owner (npub or 64-char hex; default: git config)
4258
4277
  --relay <url> ad-hoc relay override \u2014 bypasses the remote's URL
4278
+ --gateway <url> gateway to read objects through FIRST, on its raw-bytes
4279
+ route <url>/raw/<txId>, ahead of the public gateway
4280
+ list \u2014 name a private, local or air-gapped gateway to
4281
+ fetch objects the public ones do not carry
4282
+ (env RIG_ARWEAVE_GATEWAY also sets it)
4259
4283
  --concurrency <n> parallel gateway downloads (default 8)
4260
4284
  --json machine-readable result envelope
4261
4285
  -h, --help show this help`;
@@ -4288,6 +4312,7 @@ async function runFetch(args, deps) {
4288
4312
  let relayFlag;
4289
4313
  let repoIdFlag;
4290
4314
  let ownerFlag;
4315
+ let gatewayFlag;
4291
4316
  let concurrency;
4292
4317
  try {
4293
4318
  const { values, positionals } = parseArgs10({
@@ -4297,6 +4322,7 @@ async function runFetch(args, deps) {
4297
4322
  relay: { type: "string" },
4298
4323
  "repo-id": { type: "string" },
4299
4324
  owner: { type: "string" },
4325
+ gateway: { type: "string" },
4300
4326
  concurrency: { type: "string" },
4301
4327
  help: { type: "boolean", short: "h", default: false }
4302
4328
  },
@@ -4316,6 +4342,7 @@ async function runFetch(args, deps) {
4316
4342
  relayFlag = values.relay;
4317
4343
  repoIdFlag = values["repo-id"];
4318
4344
  ownerFlag = values.owner !== void 0 ? ownerToHex(values.owner) : void 0;
4345
+ gatewayFlag = values.gateway;
4319
4346
  if (values.concurrency !== void 0) {
4320
4347
  concurrency = Number.parseInt(values.concurrency, 10);
4321
4348
  if (!Number.isSafeInteger(concurrency) || concurrency < 1) {
@@ -4354,7 +4381,9 @@ async function runFetch(args, deps) {
4354
4381
  ownerPubkey: owner,
4355
4382
  repoId,
4356
4383
  ...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {},
4357
- ...deps.resolveSha ? { resolveSha: deps.resolveSha } : {}
4384
+ // The GraphQL fallback for SHAs the map does not cover asks the SAME
4385
+ // permaweb the objects are read from (#183).
4386
+ resolveSha: deps.resolveSha ?? shaResolverFor(gatewayFlag, deps.env)
4358
4387
  });
4359
4388
  const planned = [];
4360
4389
  for (const [refname, sha] of remoteState.refs) {
@@ -4381,6 +4410,8 @@ async function runFetch(args, deps) {
4381
4410
  shaToTxId: remoteState.shaToTxId,
4382
4411
  resolveMissing: (shas) => remoteState.resolveMissing(shas),
4383
4412
  presentLocally,
4413
+ // `--gateway` / RIG_ARWEAVE_GATEWAY first, public list behind it (#176).
4414
+ gateways: readGateways(gatewayFlag, deps.env),
4384
4415
  ...deps.fetchFn ? { fetchFn: deps.fetchFn } : {},
4385
4416
  ...concurrency !== void 0 ? { concurrency } : {}
4386
4417
  });
@@ -4837,7 +4868,7 @@ var runGitPassthrough = (argv, options = {}) => {
4837
4868
 
4838
4869
  // src/cli/identity-cmd.ts
4839
4870
  import { existsSync, mkdirSync as mkdirSync4 } from "fs";
4840
- import { dirname as dirname4 } from "path";
4871
+ import { dirname as dirname5 } from "path";
4841
4872
  import { createInterface } from "readline/promises";
4842
4873
  import { parseArgs as parseArgs12 } from "util";
4843
4874
  async function loadKeyOps() {
@@ -4889,7 +4920,7 @@ async function prepareKeystoreTarget(input) {
4889
4920
  const envPassword = input.env["TOON_CLIENT_KEYSTORE_PASSWORD"]?.trim() || void 0;
4890
4921
  const autoPassword = envPassword === void 0;
4891
4922
  const password = envPassword ?? DEFAULT_KEYSTORE_PASSWORD;
4892
- mkdirSync4(dirname4(keystorePath), { recursive: true });
4923
+ mkdirSync4(dirname5(keystorePath), { recursive: true });
4893
4924
  return { keystorePath, password, autoPassword, existing, keyOps };
4894
4925
  }
4895
4926
  function readAccountIndex(env) {
@@ -7967,7 +7998,6 @@ async function dispatch(argv, deps) {
7967
7998
  }
7968
7999
 
7969
8000
  export {
7970
- PREFERRED_GATEWAY,
7971
8001
  renderIdentityLine,
7972
8002
  withForcedStandalone,
7973
8003
  loadPaidSession,
@@ -7976,4 +8006,4 @@ export {
7976
8006
  rigVersion,
7977
8007
  dispatch
7978
8008
  };
7979
- //# sourceMappingURL=chunk-X232W4TG.js.map
8009
+ //# sourceMappingURL=chunk-2TG4YHEC.js.map