@obbyx/cli 0.1.2 → 0.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"balance.d.ts","sourceRoot":"","sources":["../../src/commands/balance.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtD,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,cAAc,GAAG,GAAG,CA6BjE"}
1
+ {"version":3,"file":"balance.d.ts","sourceRoot":"","sources":["../../src/commands/balance.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtD,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,cAAc,GAAG,GAAG,CA0BjE"}
@@ -1,4 +1,5 @@
1
- import { toDisplay } from '@obbyx/obyte';
1
+ import { ObbyxError, toDisplay } from '@obbyx/obyte';
2
+ import { parseBalances } from '@obbyx/x402-obyte';
2
3
  import { loadWallet } from '@obbyx/obyte/wallet';
3
4
  import { connect, resolveNetwork } from '../runtime.js';
4
5
  export function balanceCommand({ out, done }) {
@@ -10,11 +11,12 @@ export function balanceCommand({ out, done }) {
10
11
  const wallet = loadWallet(network);
11
12
  const client = connect(network, a.hub);
12
13
  try {
13
- const balances = (await client.api.getBalances([wallet.address]));
14
- const mine = balances[wallet.address] ?? {};
15
- const bytes = mine['base'] ?? { stable: 0, pending: 0 };
14
+ const mine = parseBalances(await client.api.getBalances([wallet.address]), wallet.address);
15
+ if (mine === undefined)
16
+ throw new ObbyxError('ledger_unavailable', 'Malformed balances');
17
+ const bytes = mine['base'] ?? { stable: 0n, pending: 0n };
16
18
  out(`${wallet.address} on ${network.caip2}`);
17
- out(` GBYTE: ${toDisplay(BigInt(bytes.stable), 9)} stable, ${toDisplay(BigInt(bytes.pending), 9)} pending`);
19
+ out(` GBYTE: ${toDisplay(bytes.stable, 9)} stable, ${toDisplay(bytes.pending, 9)} pending`);
18
20
  for (const [asset, b] of Object.entries(mine)) {
19
21
  if (asset !== 'base')
20
22
  out(` ${asset}: ${b.stable} stable, ${b.pending} pending (atomic units)`);
@@ -1 +1 @@
1
- {"version":3,"file":"balance.js","sourceRoot":"","sources":["../../src/commands/balance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGxD,MAAM,UAAU,cAAc,CAAC,EAAE,GAAG,EAAE,IAAI,EAAkB;IAC1D,OAAO;QACL,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,mBAAmB;QAC7B,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACnB,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAG/D,CAAC;gBACF,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;gBAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;gBACxD,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC7C,GAAG,CACD,YAAY,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,YAAY,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,UAAU,CACxG,CAAC;gBACF,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC9C,IAAI,KAAK,KAAK,MAAM;wBAClB,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,MAAM,YAAY,CAAC,CAAC,OAAO,yBAAyB,CAAC,CAAC;gBAC/E,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;YACD,IAAI,CAAC,CAAC,CAAC,CAAC;QACV,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"balance.js","sourceRoot":"","sources":["../../src/commands/balance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGxD,MAAM,UAAU,cAAc,CAAC,EAAE,GAAG,EAAE,IAAI,EAAkB;IAC1D,OAAO;QACL,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,mBAAmB;QAC7B,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACnB,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC3F,IAAI,IAAI,KAAK,SAAS;oBAAE,MAAM,IAAI,UAAU,CAAC,oBAAoB,EAAE,oBAAoB,CAAC,CAAC;gBACzF,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;gBAC1D,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC7C,GAAG,CACD,YAAY,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,YAAY,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,UAAU,CACxF,CAAC;gBACF,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC9C,IAAI,KAAK,KAAK,MAAM;wBAClB,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,MAAM,YAAY,CAAC,CAAC,OAAO,yBAAyB,CAAC,CAAC;gBAC/E,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;YACD,IAAI,CAAC,CAAC,CAAC,CAAC;QACV,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"pay.d.ts","sourceRoot":"","sources":["../../src/commands/pay.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtD,UAAU,OAAO;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,wBAAgB,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,CA4G3E"}
1
+ {"version":3,"file":"pay.d.ts","sourceRoot":"","sources":["../../src/commands/pay.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtD,UAAU,OAAO;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,wBAAgB,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,CAmF3E"}
@@ -49,34 +49,7 @@ export function payCommand({ out, err, done }) {
49
49
  const logger = cliLogger();
50
50
  const client = connect(network, a.hub);
51
51
  try {
52
- const composer = reservingComposer(client, network, wallet.address, logger);
53
- const mechanism = new ExactObyteClient({
54
- client,
55
- network: network.caip2,
56
- privateKey: wallet.privateKey,
57
- logger,
58
- composer,
59
- maxFee,
60
- });
61
- // Use a payment channel to this seller when one is open (instant, no fee per call).
62
- const batch = new BatchObyteClient({
63
- client,
64
- network,
65
- privateKey: wallet.privateKey,
66
- store: new ClientChannelStore(channelStorePath(network)),
67
- logger,
68
- maxAmount: new Map([['base', max]]),
69
- composer,
70
- });
71
- const headers = {};
72
- for (const h of a.header ?? []) {
73
- const i = h.indexOf(':');
74
- if (i <= 0)
75
- throw new ObbyxError('usage', `Bad --header "${h}" (expected "Name: value")`);
76
- headers[h.slice(0, i).trim()] = h.slice(i + 1).trim();
77
- }
78
- if (a.data !== undefined)
79
- headers['content-type'] ??= 'application/json';
52
+ const headers = parseHeaders(a.header ?? [], a.data !== undefined);
80
53
  const method = a.method ?? (a.data === undefined ? 'GET' : 'POST');
81
54
  try {
82
55
  const result = await payingFetch(a.url, {
@@ -85,7 +58,7 @@ export function payCommand({ out, err, done }) {
85
58
  ...(a.data === undefined ? {} : { body: a.data }),
86
59
  ...(a.payment === undefined ? {} : { paymentHeader: a.payment }),
87
60
  }, {
88
- mechanisms: { exact: mechanism, batch },
61
+ mechanisms: mechanisms({ client, network, wallet, max, maxFee, logger }),
89
62
  network: network.caip2,
90
63
  maxAmount: new Map([['base', max]]),
91
64
  logger,
@@ -112,4 +85,44 @@ export function payCommand({ out, err, done }) {
112
85
  },
113
86
  };
114
87
  }
88
+ /** `--header 'Name: value'` options; a body defaults to JSON. */
89
+ function parseHeaders(list, hasBody) {
90
+ const headers = {};
91
+ for (const h of list) {
92
+ const i = h.indexOf(':');
93
+ if (i <= 0)
94
+ throw new ObbyxError('usage', `Bad --header "${h}" (expected "Name: value")`);
95
+ headers[h.slice(0, i).trim()] = h.slice(i + 1).trim();
96
+ }
97
+ if (hasBody)
98
+ headers['content-type'] ??= 'application/json';
99
+ return headers;
100
+ }
101
+ /**
102
+ * The wallet's payment mechanisms: an open channel to the seller first
103
+ * (instant, no fee per call), otherwise an on-chain unit. One coin composer
104
+ * for both, so concurrent payments never pick the same coins.
105
+ */
106
+ function mechanisms({ client, network, wallet, max, maxFee, logger, }) {
107
+ const composer = reservingComposer(client, network, wallet.address, logger);
108
+ return {
109
+ exact: new ExactObyteClient({
110
+ client,
111
+ network: network.caip2,
112
+ privateKey: wallet.privateKey,
113
+ logger,
114
+ composer,
115
+ maxFee,
116
+ }),
117
+ batch: new BatchObyteClient({
118
+ client,
119
+ network,
120
+ privateKey: wallet.privateKey,
121
+ store: new ClientChannelStore(channelStorePath(network)),
122
+ logger,
123
+ maxAmount: new Map([['base', max]]),
124
+ composer,
125
+ }),
126
+ };
127
+ }
115
128
  //# sourceMappingURL=pay.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pay.js","sourceRoot":"","sources":["../../src/commands/pay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pay.js","sourceRoot":"","sources":["../../src/commands/pay.ts"],"names":[],"mappings":"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"}
@@ -7,18 +7,21 @@ import { type ReservingComposer } from '@obbyx/x402-obyte';
7
7
  * State lives in `$OBBYX_HOME/channels-<network>.db`.
8
8
  */
9
9
  export declare function channelStorePath(network: ObyteNetwork, env?: NodeJS.ProcessEnv): string;
10
- export declare function channelCommand(args: {
10
+ interface ChannelArgs {
11
11
  sub: string | undefined;
12
12
  target: string | undefined;
13
13
  deposit?: string;
14
14
  amount?: string;
15
15
  timeout?: string;
16
- }, ctx: {
16
+ }
17
+ interface ChannelContext {
17
18
  network: ObyteNetwork;
18
19
  client: obyte.Client;
19
20
  privateKey: Uint8Array;
20
21
  logger: Logger;
21
22
  out: (s?: string) => void;
22
23
  composer?: ReservingComposer;
23
- }): Promise<number>;
24
+ }
25
+ export declare function channelCommand(args: ChannelArgs, ctx: ChannelContext): Promise<number>;
26
+ export {};
24
27
  //# sourceMappingURL=channels.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/lib/channels.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAEL,KAAK,YAAY,EAIlB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAQL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAG3B;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,YAAY,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAER;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE;IACJ,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,GAAG,EAAE;IACH,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B,GACA,OAAO,CAAC,MAAM,CAAC,CAuGjB"}
1
+ {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/lib/channels.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAEL,KAAK,YAAY,EAIlB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAQL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAG3B;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,YAAY,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAER;AAED,UAAU,WAAW;IACnB,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAYD,wBAAsB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB5F"}
@@ -9,97 +9,104 @@ import { obbyxHome } from '@obbyx/obyte/wallet';
9
9
  export function channelStorePath(network, env = process.env) {
10
10
  return join(obbyxHome(env), `channels-${network.name}.db`);
11
11
  }
12
+ const gbyte = (v) => `${toDisplay(v, 9)} GBYTE`;
12
13
  export async function channelCommand(args, ctx) {
14
+ const run = SUBCOMMANDS[args.sub ?? ''];
15
+ if (run === undefined) {
16
+ throw new ObbyxError('usage', `channel ${Object.keys(SUBCOMMANDS).join('|')}`);
17
+ }
13
18
  const store = new ClientChannelStore(channelStorePath(ctx.network));
14
- const opts = {
15
- client: ctx.client,
16
- network: ctx.network,
17
- privateKey: ctx.privateKey,
18
- store,
19
- logger: ctx.logger,
20
- ...(ctx.composer ? { composer: ctx.composer } : {}),
21
- };
22
- const { out } = ctx;
23
- const gbyte = (v) => `${toDisplay(v, 9)} GBYTE`;
24
19
  try {
25
- switch (args.sub) {
26
- case 'open': {
27
- if (args.target === undefined)
28
- throw new ObbyxError('usage', 'channel open <seller address> --deposit <GBYTE>');
29
- if (args.deposit === undefined)
30
- throw new ObbyxError('usage', 'channel open needs --deposit <GBYTE>');
31
- const timeout = Number(args.timeout ?? 86_400);
32
- if (!Number.isInteger(timeout) || timeout < 60)
33
- throw new ObbyxError('usage', '--window must be ≥ 60 seconds');
34
- const { aa, unit } = await openChannel(opts, {
35
- payTo: args.target,
36
- deposit: fromDisplay(args.deposit, 9),
37
- timeout,
38
- });
39
- out(`Channel ${aa} opened to ${args.target}`);
40
- out(` deposit: ${args.deposit} GBYTE, dispute window: ${timeout} s`);
41
- out(` unit: ${unit}\n ${explorerUnitUrl(ctx.network, unit)}`);
42
- out('Usable once the deposit is stable (minutes under load, up to ~2 h when the network is quiet): obbyx channel status ' +
43
- aa);
44
- return 0;
45
- }
46
- case 'deposit': {
47
- const ch = need(store, args.target);
48
- if (args.amount === undefined)
49
- throw new ObbyxError('usage', 'channel deposit <aa> --amount <GBYTE>');
50
- const unit = await deposit(opts, ch.aa, fromDisplay(args.amount, 9));
51
- out(`Deposited ${args.amount} GBYTE to ${ch.aa}: ${unit}`);
52
- return 0;
53
- }
54
- case 'list': {
55
- const all = store.list().filter((c) => c.network === ctx.network.caip2);
56
- if (all.length === 0)
57
- out('No channels. Open one with: obbyx channel open <seller> --deposit <GBYTE>');
58
- for (const c of all) {
59
- out(`${c.aa} seller ${c.payTo} period ${c.period} spent ${gbyte(c.committed)}${c.pending ? ' (voucher pending)' : ''}`);
60
- }
61
- return 0;
62
- }
63
- case 'status': {
64
- const ch = need(store, args.target);
65
- const vars = await hubCall(() => ctx.client.api.getAaStateVars({ address: ch.aa }), 15_000);
66
- if (vars.kind !== 'ok')
67
- throw new ObbyxError('ledger_unavailable', vars.error);
68
- const v = vars.value;
69
- out(`Channel ${ch.aa} → seller ${ch.payTo}`);
70
- out(` on-chain: period ${v['period'] ?? '-'}, deposit ${gbyte(BigInt(Number(v['balanceB'] ?? 0)))}` +
71
- (v['close_initiated_by']
72
- ? `, CLOSING (initiated by ${v['close_initiated_by'] === 'A' ? 'seller' : 'you'})`
73
- : ''));
74
- out(` local: period ${ch.period}, spent ${gbyte(ch.committed)}${ch.pending ? `, pending voucher ${ch.pending.amountSpent}` : ''}`);
75
- if (v['period'] === undefined)
76
- out(' The deposit is not credited yet (waiting for stability).');
77
- return 0;
78
- }
79
- case 'close': {
80
- const ch = need(store, args.target);
81
- if (ch.pending) {
82
- throw new ObbyxError('payment_pending', 'A voucher has an unknown outcome; retry that request before closing');
83
- }
84
- const unit = await closeChannel(opts, ch.aa, ch.period, ch.committed);
85
- out(`Close requested for period ${ch.period}, declaring ${gbyte(ch.committed)} spent: ${unit}`);
86
- out(`The seller confirms at once if this is right; otherwise run \`obbyx channel confirm ${ch.aa}\` after ${ch.timeout} s.`);
87
- return 0;
88
- }
89
- case 'confirm': {
90
- const ch = need(store, args.target);
91
- const unit = await confirmClose(opts, ch.aa, ch.period);
92
- out(`Close confirmed for period ${ch.period}: ${unit}`);
93
- return 0;
94
- }
95
- default:
96
- throw new ObbyxError('usage', 'channel open|deposit|list|status|close|confirm');
97
- }
20
+ await run({
21
+ args,
22
+ ctx,
23
+ store,
24
+ opts: {
25
+ client: ctx.client,
26
+ network: ctx.network,
27
+ privateKey: ctx.privateKey,
28
+ store,
29
+ logger: ctx.logger,
30
+ ...(ctx.composer ? { composer: ctx.composer } : {}),
31
+ },
32
+ });
33
+ return 0;
98
34
  }
99
35
  finally {
100
36
  store.close();
101
37
  }
102
38
  }
39
+ const SUBCOMMANDS = {
40
+ open: openCommand,
41
+ deposit: depositCommand,
42
+ list: listCommand,
43
+ status: statusCommand,
44
+ close: closeCommand,
45
+ confirm: confirmCommand,
46
+ };
47
+ async function openCommand({ args, ctx, opts }) {
48
+ if (args.target === undefined)
49
+ throw new ObbyxError('usage', 'channel open <seller address> --deposit <GBYTE>');
50
+ if (args.deposit === undefined)
51
+ throw new ObbyxError('usage', 'channel open needs --deposit <GBYTE>');
52
+ const timeout = Number(args.timeout ?? 86_400);
53
+ if (!Number.isInteger(timeout) || timeout < 60)
54
+ throw new ObbyxError('usage', '--window must be ≥ 60 seconds');
55
+ const { aa, unit } = await openChannel(opts, {
56
+ payTo: args.target,
57
+ deposit: fromDisplay(args.deposit, 9),
58
+ timeout,
59
+ });
60
+ ctx.out(`Channel ${aa} opened to ${args.target}`);
61
+ ctx.out(` deposit: ${args.deposit} GBYTE, dispute window: ${timeout} s`);
62
+ ctx.out(` unit: ${unit}\n ${explorerUnitUrl(ctx.network, unit)}`);
63
+ ctx.out('Usable once the deposit is stable (minutes under load, up to ~2 h when the network is quiet): obbyx channel status ' +
64
+ aa);
65
+ }
66
+ async function depositCommand({ args, ctx, store, opts }) {
67
+ const ch = need(store, args.target);
68
+ if (args.amount === undefined)
69
+ throw new ObbyxError('usage', 'channel deposit <aa> --amount <GBYTE>');
70
+ const unit = await deposit(opts, ch.aa, fromDisplay(args.amount, 9));
71
+ ctx.out(`Deposited ${args.amount} GBYTE to ${ch.aa}: ${unit}`);
72
+ }
73
+ async function listCommand({ ctx, store }) {
74
+ const all = store.list().filter((c) => c.network === ctx.network.caip2);
75
+ if (all.length === 0)
76
+ ctx.out('No channels. Open one with: obbyx channel open <seller> --deposit <GBYTE>');
77
+ for (const c of all) {
78
+ ctx.out(`${c.aa} seller ${c.payTo} period ${c.period} spent ${gbyte(c.committed)}${c.pending ? ' (voucher pending)' : ''}`);
79
+ }
80
+ }
81
+ async function statusCommand({ args, ctx, store }) {
82
+ const ch = need(store, args.target);
83
+ const vars = await hubCall(() => ctx.client.api.getAaStateVars({ address: ch.aa }), 15_000);
84
+ if (vars.kind !== 'ok')
85
+ throw new ObbyxError('ledger_unavailable', vars.error);
86
+ const v = vars.value;
87
+ ctx.out(`Channel ${ch.aa} → seller ${ch.payTo}`);
88
+ ctx.out(` on-chain: period ${v['period'] ?? '-'}, deposit ${gbyte(BigInt(Number(v['balanceB'] ?? 0)))}` +
89
+ (v['close_initiated_by']
90
+ ? `, CLOSING (initiated by ${v['close_initiated_by'] === 'A' ? 'seller' : 'you'})`
91
+ : ''));
92
+ ctx.out(` local: period ${ch.period}, spent ${gbyte(ch.committed)}${ch.pending ? `, pending voucher ${ch.pending.amountSpent}` : ''}`);
93
+ if (v['period'] === undefined)
94
+ ctx.out(' The deposit is not credited yet (waiting for stability).');
95
+ }
96
+ async function closeCommand({ args, ctx, store, opts }) {
97
+ const ch = need(store, args.target);
98
+ if (ch.pending) {
99
+ throw new ObbyxError('payment_pending', 'A voucher has an unknown outcome; retry that request before closing');
100
+ }
101
+ const unit = await closeChannel(opts, ch.aa, ch.period, ch.committed);
102
+ ctx.out(`Close requested for period ${ch.period}, declaring ${gbyte(ch.committed)} spent: ${unit}`);
103
+ ctx.out(`The seller confirms at once if this is right; otherwise run \`obbyx channel confirm ${ch.aa}\` after ${ch.timeout} s.`);
104
+ }
105
+ async function confirmCommand({ args, ctx, store, opts }) {
106
+ const ch = need(store, args.target);
107
+ const unit = await confirmClose(opts, ch.aa, ch.period);
108
+ ctx.out(`Close confirmed for period ${ch.period}: ${unit}`);
109
+ }
103
110
  function need(store, aa) {
104
111
  if (aa === undefined)
105
112
  throw new ObbyxError('usage', 'channel address required');
@@ -1 +1 @@
1
- {"version":3,"file":"channels.js","sourceRoot":"","sources":["../../src/lib/channels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channels.js","sourceRoot":"","sources":["../../src/lib/channels.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/lib/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,cAAc,CAAC;AAW5D,wBAAsB,MAAM,CAC1B,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACrE,OAAO,CAAC,MAAM,CAAC,CAmHjB"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/lib/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,cAAc,CAAC;AAe5D,wBAAsB,MAAM,CAC1B,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACrE,OAAO,CAAC,MAAM,CAAC,CAWjB"}
@@ -1,59 +1,71 @@
1
- import { existsSync, statSync } from 'node:fs';
1
+ import { existsSync, readFileSync, statSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import obyte from 'obyte';
4
4
  import { toDisplay } from '@obbyx/obyte';
5
- import { ClientChannelStore, CoinReservations, hubCall } from '@obbyx/x402-obyte';
5
+ import { ClientChannelStore, CoinReservations, hubCall, parseBalances } from '@obbyx/x402-obyte';
6
6
  import { channelStorePath } from './channels.js';
7
7
  import { obbyxHome, walletPath } from '@obbyx/obyte/wallet';
8
+ const MARK = { ok: '✓', warn: '!', fail: '✗' };
9
+ const HUB_TIMEOUT_MS = 10_000;
8
10
  export async function doctor(network, opts) {
9
11
  const results = [];
10
12
  const report = (status, what, detail = '') => {
11
13
  results.push(status);
12
- opts.out(`${status === 'ok' ? '✓' : status === 'warn' ? '!' : '✗'} ${what}${detail ? ` — ${detail}` : ''}`);
14
+ opts.out(`${MARK[status]} ${what}${detail ? ` — ${detail}` : ''}`);
13
15
  };
14
- // Wallet
16
+ const address = checkWallet(network, report);
17
+ await checkHub(network, opts.hub ?? network.defaultHubUrl, address, report);
18
+ checkLocalState(network, report);
19
+ if (opts.facilitator !== undefined)
20
+ await checkFacilitator(network, opts.facilitator, report);
21
+ return results.includes('fail') ? 1 : 0;
22
+ }
23
+ /** The wallet file exists and only its owner can read it; returns its address. */
24
+ function checkWallet(network, report) {
15
25
  const wallet = walletPath(network);
16
- let address;
17
26
  if (!existsSync(wallet)) {
18
27
  report('fail', 'wallet', `missing; run: obbyx init --network ${network.name}`);
28
+ return undefined;
19
29
  }
20
- else if ((statSync(wallet).mode & 0o077) !== 0) {
30
+ if ((statSync(wallet).mode & 0o077) !== 0) {
21
31
  report('fail', 'wallet', `${wallet} is readable by others; run: chmod 600 ${wallet}`);
32
+ return undefined;
22
33
  }
23
- else {
24
- const { readFileSync } = await import('node:fs');
25
- address = JSON.parse(readFileSync(wallet, 'utf8')).address;
26
- report('ok', 'wallet', `${address} (${wallet})`);
27
- }
28
- // Hub
29
- const client = new obyte.Client(opts.hub ?? network.defaultHubUrl, { testnet: network.testnet });
34
+ const address = JSON.parse(readFileSync(wallet, 'utf8')).address;
35
+ report('ok', 'wallet', `${address} (${wallet})`);
36
+ return address;
37
+ }
38
+ /** The hub answers; then the wallet's bytes balance (empty on testnet is only a warning). */
39
+ async function checkHub(network, hubUrl, address, report) {
40
+ const client = new obyte.Client(hubUrl, { testnet: network.testnet });
30
41
  try {
31
42
  const started = Date.now();
32
- const mci = await hubCall(() => client.api.getLastMci(), 10_000);
43
+ const mci = await hubCall(() => client.api.getLastMci(), HUB_TIMEOUT_MS);
33
44
  if (mci.kind !== 'ok') {
34
- report('fail', 'hub', `${opts.hub ?? network.defaultHubUrl}: ${mci.error}`);
45
+ report('fail', 'hub', `${hubUrl}: ${mci.error}`);
46
+ return;
35
47
  }
36
- else {
37
- report('ok', 'hub', `${opts.hub ?? network.defaultHubUrl}, last MCI ${mci.value}, ${Date.now() - started} ms`);
38
- if (address !== undefined) {
39
- const b = await hubCall(() => client.api.getBalances([address]), 10_000);
40
- if (b.kind === 'ok') {
41
- const base = b.value[address]?.['base'];
42
- const stable = BigInt(base?.stable ?? 0);
43
- const pending = BigInt(base?.pending ?? 0);
44
- report(stable === 0n ? (network.testnet ? 'warn' : 'fail') : 'ok', 'balance', `${toDisplay(stable, 9)} GBYTE stable, ${toDisplay(pending, 9)} pending` +
45
- (stable === 0n && network.testnet ? '; run: obbyx faucet' : ''));
46
- }
47
- else {
48
- report('warn', 'balance', b.error);
49
- }
50
- }
48
+ report('ok', 'hub', `${hubUrl}, last MCI ${mci.value}, ${Date.now() - started} ms`);
49
+ if (address === undefined)
50
+ return;
51
+ const b = await hubCall(() => client.api.getBalances([address]), HUB_TIMEOUT_MS);
52
+ if (b.kind !== 'ok') {
53
+ report('warn', 'balance', b.error);
54
+ return;
51
55
  }
56
+ const base = parseBalances(b.value, address)?.['base'];
57
+ const stable = base?.stable ?? 0n;
58
+ const pending = base?.pending ?? 0n;
59
+ const empty = stable === 0n;
60
+ report(empty ? (network.testnet ? 'warn' : 'fail') : 'ok', 'balance', `${toDisplay(stable, 9)} GBYTE stable, ${toDisplay(pending, 9)} pending` +
61
+ (empty && network.testnet ? '; run: obbyx faucet' : ''));
52
62
  }
53
63
  finally {
54
64
  client.close();
55
65
  }
56
- // Local payment state
66
+ }
67
+ /** Coin reservations and channels with an unknown outcome (warnings, never failures). */
68
+ function checkLocalState(network, report) {
57
69
  const coinsPath = join(obbyxHome(), `coins-${network.name}.db`);
58
70
  if (existsSync(coinsPath)) {
59
71
  const reservations = new CoinReservations(coinsPath);
@@ -74,24 +86,21 @@ export async function doctor(network, opts) {
74
86
  ? `, ${pending.length} with a voucher of unknown outcome (retry that request with --payment)`
75
87
  : ''));
76
88
  }
77
- // Facilitator (optional)
78
- if (opts.facilitator !== undefined) {
79
- try {
80
- const res = await fetch(new URL('/supported', opts.facilitator), {
81
- signal: AbortSignal.timeout(10_000),
82
- });
83
- const supported = (await res.json());
84
- const kinds = (supported.kinds ?? [])
85
- .filter((k) => k.network === network.caip2)
86
- .map((k) => k.scheme);
87
- report(kinds.length > 0 ? 'ok' : 'fail', 'facilitator', kinds.length > 0
88
- ? `${opts.facilitator}: ${kinds.join(', ')}`
89
- : `does not serve ${network.caip2}`);
90
- }
91
- catch (err) {
92
- report('fail', 'facilitator', `${opts.facilitator}: ${err instanceof Error ? err.message : String(err)}`);
93
- }
89
+ }
90
+ /** The facilitator answers /supported and serves this network. */
91
+ async function checkFacilitator(network, facilitator, report) {
92
+ try {
93
+ const res = await fetch(new URL('/supported', facilitator), {
94
+ signal: AbortSignal.timeout(HUB_TIMEOUT_MS),
95
+ });
96
+ const supported = (await res.json());
97
+ const kinds = (supported.kinds ?? [])
98
+ .filter((k) => k.network === network.caip2)
99
+ .map((k) => k.scheme);
100
+ report(kinds.length > 0 ? 'ok' : 'fail', 'facilitator', kinds.length > 0 ? `${facilitator}: ${kinds.join(', ')}` : `does not serve ${network.caip2}`);
101
+ }
102
+ catch (err) {
103
+ report('fail', 'facilitator', `${facilitator}: ${err instanceof Error ? err.message : String(err)}`);
94
104
  }
95
- return results.includes('fail') ? 1 : 0;
96
105
  }
97
106
  //# sourceMappingURL=doctor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/lib/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/lib/doctor.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obbyx/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "obbyx command line: Obyte wallet, testnet faucet, paying x402 APIs, payment channels, diagnostics",
5
5
  "keywords": [
6
6
  "x402",
@@ -37,9 +37,9 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@obbyx/obyte": "^0.1.0",
41
- "@obbyx/sdk": "^0.2.0",
42
- "@obbyx/x402-obyte": "^0.2.1",
40
+ "@obbyx/obyte": "^0.1.1",
41
+ "@obbyx/sdk": "^0.2.1",
42
+ "@obbyx/x402-obyte": "^0.2.2",
43
43
  "@x402/core": "^2.29.0",
44
44
  "obyte": "0.2.1",
45
45
  "yargs": "^18.2.0"
@@ -1,4 +1,5 @@
1
- import { toDisplay } from '@obbyx/obyte';
1
+ import { ObbyxError, toDisplay } from '@obbyx/obyte';
2
+ import { parseBalances } from '@obbyx/x402-obyte';
2
3
  import { loadWallet } from '@obbyx/obyte/wallet';
3
4
  import { connect, resolveNetwork } from '../runtime.js';
4
5
  import type { CommandContext, Cmd } from './types.js';
@@ -12,15 +13,12 @@ export function balanceCommand({ out, done }: CommandContext): Cmd {
12
13
  const wallet = loadWallet(network);
13
14
  const client = connect(network, a.hub);
14
15
  try {
15
- const balances = (await client.api.getBalances([wallet.address])) as Record<
16
- string,
17
- Record<string, { stable: number; pending: number }>
18
- >;
19
- const mine = balances[wallet.address] ?? {};
20
- const bytes = mine['base'] ?? { stable: 0, pending: 0 };
16
+ const mine = parseBalances(await client.api.getBalances([wallet.address]), wallet.address);
17
+ if (mine === undefined) throw new ObbyxError('ledger_unavailable', 'Malformed balances');
18
+ const bytes = mine['base'] ?? { stable: 0n, pending: 0n };
21
19
  out(`${wallet.address} on ${network.caip2}`);
22
20
  out(
23
- ` GBYTE: ${toDisplay(BigInt(bytes.stable), 9)} stable, ${toDisplay(BigInt(bytes.pending), 9)} pending`,
21
+ ` GBYTE: ${toDisplay(bytes.stable, 9)} stable, ${toDisplay(bytes.pending, 9)} pending`,
24
22
  );
25
23
  for (const [asset, b] of Object.entries(mine)) {
26
24
  if (asset !== 'base')
@@ -1,4 +1,6 @@
1
- import { ObbyxError, fromDisplay } from '@obbyx/obyte';
1
+ import type obyte from 'obyte';
2
+ import { ObbyxError, type ObyteNetwork, fromDisplay } from '@obbyx/obyte';
3
+ import type { Logger } from '@obbyx/obyte/logger';
2
4
  import { loadWallet } from '@obbyx/obyte/wallet';
3
5
  import { BatchObyteClient, ClientChannelStore, ExactObyteClient } from '@obbyx/x402-obyte';
4
6
  import { PaymentPendingError, payingFetch } from '@obbyx/sdk';
@@ -71,32 +73,7 @@ export function payCommand({ out, err, done }: CommandContext): Cmd<PayArgs> {
71
73
  const logger = cliLogger();
72
74
  const client = connect(network, a.hub);
73
75
  try {
74
- const composer = reservingComposer(client, network, wallet.address, logger);
75
- const mechanism = new ExactObyteClient({
76
- client,
77
- network: network.caip2,
78
- privateKey: wallet.privateKey,
79
- logger,
80
- composer,
81
- maxFee,
82
- });
83
- // Use a payment channel to this seller when one is open (instant, no fee per call).
84
- const batch = new BatchObyteClient({
85
- client,
86
- network,
87
- privateKey: wallet.privateKey,
88
- store: new ClientChannelStore(channelStorePath(network)),
89
- logger,
90
- maxAmount: new Map([['base', max]]),
91
- composer,
92
- });
93
- const headers: Record<string, string> = {};
94
- for (const h of a.header ?? []) {
95
- const i = h.indexOf(':');
96
- if (i <= 0) throw new ObbyxError('usage', `Bad --header "${h}" (expected "Name: value")`);
97
- headers[h.slice(0, i).trim()] = h.slice(i + 1).trim();
98
- }
99
- if (a.data !== undefined) headers['content-type'] ??= 'application/json';
76
+ const headers = parseHeaders(a.header ?? [], a.data !== undefined);
100
77
  const method = a.method ?? (a.data === undefined ? 'GET' : 'POST');
101
78
  try {
102
79
  const result = await payingFetch(
@@ -108,7 +85,7 @@ export function payCommand({ out, err, done }: CommandContext): Cmd<PayArgs> {
108
85
  ...(a.payment === undefined ? {} : { paymentHeader: a.payment }),
109
86
  },
110
87
  {
111
- mechanisms: { exact: mechanism, batch },
88
+ mechanisms: mechanisms({ client, network, wallet, max, maxFee, logger }),
112
89
  network: network.caip2,
113
90
  maxAmount: new Map([['base', max]]),
114
91
  logger,
@@ -133,3 +110,59 @@ export function payCommand({ out, err, done }: CommandContext): Cmd<PayArgs> {
133
110
  },
134
111
  };
135
112
  }
113
+
114
+ /** `--header 'Name: value'` options; a body defaults to JSON. */
115
+ function parseHeaders(list: readonly string[], hasBody: boolean): Record<string, string> {
116
+ const headers: Record<string, string> = {};
117
+ for (const h of list) {
118
+ const i = h.indexOf(':');
119
+ if (i <= 0) throw new ObbyxError('usage', `Bad --header "${h}" (expected "Name: value")`);
120
+ headers[h.slice(0, i).trim()] = h.slice(i + 1).trim();
121
+ }
122
+ if (hasBody) headers['content-type'] ??= 'application/json';
123
+ return headers;
124
+ }
125
+
126
+ /**
127
+ * The wallet's payment mechanisms: an open channel to the seller first
128
+ * (instant, no fee per call), otherwise an on-chain unit. One coin composer
129
+ * for both, so concurrent payments never pick the same coins.
130
+ */
131
+ function mechanisms({
132
+ client,
133
+ network,
134
+ wallet,
135
+ max,
136
+ maxFee,
137
+ logger,
138
+ }: {
139
+ client: obyte.Client;
140
+ network: ObyteNetwork;
141
+ wallet: { address: string; privateKey: Uint8Array };
142
+ /** Most this call may cost (atomic units of bytes). */
143
+ max: bigint;
144
+ /** Most network fee an on-chain payment may cost (bytes). */
145
+ maxFee: bigint;
146
+ logger: Logger;
147
+ }): { exact: ExactObyteClient; batch: BatchObyteClient } {
148
+ const composer = reservingComposer(client, network, wallet.address, logger);
149
+ return {
150
+ exact: new ExactObyteClient({
151
+ client,
152
+ network: network.caip2,
153
+ privateKey: wallet.privateKey,
154
+ logger,
155
+ composer,
156
+ maxFee,
157
+ }),
158
+ batch: new BatchObyteClient({
159
+ client,
160
+ network,
161
+ privateKey: wallet.privateKey,
162
+ store: new ClientChannelStore(channelStorePath(network)),
163
+ logger,
164
+ maxAmount: new Map([['base', max]]),
165
+ composer,
166
+ }),
167
+ };
168
+ }
@@ -31,127 +31,151 @@ export function channelStorePath(
31
31
  return join(obbyxHome(env), `channels-${network.name}.db`);
32
32
  }
33
33
 
34
- export async function channelCommand(
35
- args: {
36
- sub: string | undefined;
37
- target: string | undefined;
38
- deposit?: string;
39
- amount?: string;
40
- timeout?: string;
41
- },
42
- ctx: {
43
- network: ObyteNetwork;
44
- client: obyte.Client;
45
- privateKey: Uint8Array;
46
- logger: Logger;
47
- out: (s?: string) => void;
48
- composer?: ReservingComposer;
49
- },
50
- ): Promise<number> {
34
+ interface ChannelArgs {
35
+ sub: string | undefined;
36
+ target: string | undefined;
37
+ deposit?: string;
38
+ amount?: string;
39
+ timeout?: string;
40
+ }
41
+
42
+ interface ChannelContext {
43
+ network: ObyteNetwork;
44
+ client: obyte.Client;
45
+ privateKey: Uint8Array;
46
+ logger: Logger;
47
+ out: (s?: string) => void;
48
+ composer?: ReservingComposer;
49
+ }
50
+
51
+ /** What a subcommand gets: the parsed arguments, the context, the open store and client options. */
52
+ interface ChannelRun {
53
+ readonly args: ChannelArgs;
54
+ readonly ctx: ChannelContext;
55
+ readonly store: ClientChannelStore;
56
+ readonly opts: BatchClientOptions;
57
+ }
58
+
59
+ const gbyte = (v: bigint) => `${toDisplay(v, 9)} GBYTE`;
60
+
61
+ export async function channelCommand(args: ChannelArgs, ctx: ChannelContext): Promise<number> {
62
+ const run = SUBCOMMANDS[args.sub ?? ''];
63
+ if (run === undefined) {
64
+ throw new ObbyxError('usage', `channel ${Object.keys(SUBCOMMANDS).join('|')}`);
65
+ }
51
66
  const store = new ClientChannelStore(channelStorePath(ctx.network));
52
- const opts: BatchClientOptions = {
53
- client: ctx.client,
54
- network: ctx.network,
55
- privateKey: ctx.privateKey,
56
- store,
57
- logger: ctx.logger,
58
- ...(ctx.composer ? { composer: ctx.composer } : {}),
59
- };
60
- const { out } = ctx;
61
- const gbyte = (v: bigint) => `${toDisplay(v, 9)} GBYTE`;
62
67
  try {
63
- switch (args.sub) {
64
- case 'open': {
65
- if (args.target === undefined)
66
- throw new ObbyxError('usage', 'channel open <seller address> --deposit <GBYTE>');
67
- if (args.deposit === undefined)
68
- throw new ObbyxError('usage', 'channel open needs --deposit <GBYTE>');
69
- const timeout = Number(args.timeout ?? 86_400);
70
- if (!Number.isInteger(timeout) || timeout < 60)
71
- throw new ObbyxError('usage', '--window must be ≥ 60 seconds');
72
- const { aa, unit } = await openChannel(opts, {
73
- payTo: args.target,
74
- deposit: fromDisplay(args.deposit, 9),
75
- timeout,
76
- });
77
- out(`Channel ${aa} opened to ${args.target}`);
78
- out(` deposit: ${args.deposit} GBYTE, dispute window: ${timeout} s`);
79
- out(` unit: ${unit}\n ${explorerUnitUrl(ctx.network, unit)}`);
80
- out(
81
- 'Usable once the deposit is stable (minutes under load, up to ~2 h when the network is quiet): obbyx channel status ' +
82
- aa,
83
- );
84
- return 0;
85
- }
86
- case 'deposit': {
87
- const ch = need(store, args.target);
88
- if (args.amount === undefined)
89
- throw new ObbyxError('usage', 'channel deposit <aa> --amount <GBYTE>');
90
- const unit = await deposit(opts, ch.aa, fromDisplay(args.amount, 9));
91
- out(`Deposited ${args.amount} GBYTE to ${ch.aa}: ${unit}`);
92
- return 0;
93
- }
94
- case 'list': {
95
- const all = store.list().filter((c) => c.network === ctx.network.caip2);
96
- if (all.length === 0)
97
- out('No channels. Open one with: obbyx channel open <seller> --deposit <GBYTE>');
98
- for (const c of all) {
99
- out(
100
- `${c.aa} seller ${c.payTo} period ${c.period} spent ${gbyte(c.committed)}${c.pending ? ' (voucher pending)' : ''}`,
101
- );
102
- }
103
- return 0;
104
- }
105
- case 'status': {
106
- const ch = need(store, args.target);
107
- const vars = await hubCall(() => ctx.client.api.getAaStateVars({ address: ch.aa }), 15_000);
108
- if (vars.kind !== 'ok') throw new ObbyxError('ledger_unavailable', vars.error);
109
- const v = vars.value as Record<string, number | string | undefined>;
110
- out(`Channel ${ch.aa} → seller ${ch.payTo}`);
111
- out(
112
- ` on-chain: period ${v['period'] ?? '-'}, deposit ${gbyte(BigInt(Number(v['balanceB'] ?? 0)))}` +
113
- (v['close_initiated_by']
114
- ? `, CLOSING (initiated by ${v['close_initiated_by'] === 'A' ? 'seller' : 'you'})`
115
- : ''),
116
- );
117
- out(
118
- ` local: period ${ch.period}, spent ${gbyte(ch.committed)}${ch.pending ? `, pending voucher ${ch.pending.amountSpent}` : ''}`,
119
- );
120
- if (v['period'] === undefined)
121
- out(' The deposit is not credited yet (waiting for stability).');
122
- return 0;
123
- }
124
- case 'close': {
125
- const ch = need(store, args.target);
126
- if (ch.pending) {
127
- throw new ObbyxError(
128
- 'payment_pending',
129
- 'A voucher has an unknown outcome; retry that request before closing',
130
- );
131
- }
132
- const unit = await closeChannel(opts, ch.aa, ch.period, ch.committed);
133
- out(
134
- `Close requested for period ${ch.period}, declaring ${gbyte(ch.committed)} spent: ${unit}`,
135
- );
136
- out(
137
- `The seller confirms at once if this is right; otherwise run \`obbyx channel confirm ${ch.aa}\` after ${ch.timeout} s.`,
138
- );
139
- return 0;
140
- }
141
- case 'confirm': {
142
- const ch = need(store, args.target);
143
- const unit = await confirmClose(opts, ch.aa, ch.period);
144
- out(`Close confirmed for period ${ch.period}: ${unit}`);
145
- return 0;
146
- }
147
- default:
148
- throw new ObbyxError('usage', 'channel open|deposit|list|status|close|confirm');
149
- }
68
+ await run({
69
+ args,
70
+ ctx,
71
+ store,
72
+ opts: {
73
+ client: ctx.client,
74
+ network: ctx.network,
75
+ privateKey: ctx.privateKey,
76
+ store,
77
+ logger: ctx.logger,
78
+ ...(ctx.composer ? { composer: ctx.composer } : {}),
79
+ },
80
+ });
81
+ return 0;
150
82
  } finally {
151
83
  store.close();
152
84
  }
153
85
  }
154
86
 
87
+ const SUBCOMMANDS: Record<string, (run: ChannelRun) => Promise<void>> = {
88
+ open: openCommand,
89
+ deposit: depositCommand,
90
+ list: listCommand,
91
+ status: statusCommand,
92
+ close: closeCommand,
93
+ confirm: confirmCommand,
94
+ };
95
+
96
+ async function openCommand({ args, ctx, opts }: ChannelRun): Promise<void> {
97
+ if (args.target === undefined)
98
+ throw new ObbyxError('usage', 'channel open <seller address> --deposit <GBYTE>');
99
+ if (args.deposit === undefined)
100
+ throw new ObbyxError('usage', 'channel open needs --deposit <GBYTE>');
101
+ const timeout = Number(args.timeout ?? 86_400);
102
+ if (!Number.isInteger(timeout) || timeout < 60)
103
+ throw new ObbyxError('usage', '--window must be ≥ 60 seconds');
104
+ const { aa, unit } = await openChannel(opts, {
105
+ payTo: args.target,
106
+ deposit: fromDisplay(args.deposit, 9),
107
+ timeout,
108
+ });
109
+ ctx.out(`Channel ${aa} opened to ${args.target}`);
110
+ ctx.out(` deposit: ${args.deposit} GBYTE, dispute window: ${timeout} s`);
111
+ ctx.out(` unit: ${unit}\n ${explorerUnitUrl(ctx.network, unit)}`);
112
+ ctx.out(
113
+ 'Usable once the deposit is stable (minutes under load, up to ~2 h when the network is quiet): obbyx channel status ' +
114
+ aa,
115
+ );
116
+ }
117
+
118
+ async function depositCommand({ args, ctx, store, opts }: ChannelRun): Promise<void> {
119
+ const ch = need(store, args.target);
120
+ if (args.amount === undefined)
121
+ throw new ObbyxError('usage', 'channel deposit <aa> --amount <GBYTE>');
122
+ const unit = await deposit(opts, ch.aa, fromDisplay(args.amount, 9));
123
+ ctx.out(`Deposited ${args.amount} GBYTE to ${ch.aa}: ${unit}`);
124
+ }
125
+
126
+ async function listCommand({ ctx, store }: ChannelRun): Promise<void> {
127
+ const all = store.list().filter((c) => c.network === ctx.network.caip2);
128
+ if (all.length === 0)
129
+ ctx.out('No channels. Open one with: obbyx channel open <seller> --deposit <GBYTE>');
130
+ for (const c of all) {
131
+ ctx.out(
132
+ `${c.aa} seller ${c.payTo} period ${c.period} spent ${gbyte(c.committed)}${c.pending ? ' (voucher pending)' : ''}`,
133
+ );
134
+ }
135
+ }
136
+
137
+ async function statusCommand({ args, ctx, store }: ChannelRun): Promise<void> {
138
+ const ch = need(store, args.target);
139
+ const vars = await hubCall(() => ctx.client.api.getAaStateVars({ address: ch.aa }), 15_000);
140
+ if (vars.kind !== 'ok') throw new ObbyxError('ledger_unavailable', vars.error);
141
+ const v = vars.value as Record<string, number | string | undefined>;
142
+ ctx.out(`Channel ${ch.aa} → seller ${ch.payTo}`);
143
+ ctx.out(
144
+ ` on-chain: period ${v['period'] ?? '-'}, deposit ${gbyte(BigInt(Number(v['balanceB'] ?? 0)))}` +
145
+ (v['close_initiated_by']
146
+ ? `, CLOSING (initiated by ${v['close_initiated_by'] === 'A' ? 'seller' : 'you'})`
147
+ : ''),
148
+ );
149
+ ctx.out(
150
+ ` local: period ${ch.period}, spent ${gbyte(ch.committed)}${ch.pending ? `, pending voucher ${ch.pending.amountSpent}` : ''}`,
151
+ );
152
+ if (v['period'] === undefined)
153
+ ctx.out(' The deposit is not credited yet (waiting for stability).');
154
+ }
155
+
156
+ async function closeCommand({ args, ctx, store, opts }: ChannelRun): Promise<void> {
157
+ const ch = need(store, args.target);
158
+ if (ch.pending) {
159
+ throw new ObbyxError(
160
+ 'payment_pending',
161
+ 'A voucher has an unknown outcome; retry that request before closing',
162
+ );
163
+ }
164
+ const unit = await closeChannel(opts, ch.aa, ch.period, ch.committed);
165
+ ctx.out(
166
+ `Close requested for period ${ch.period}, declaring ${gbyte(ch.committed)} spent: ${unit}`,
167
+ );
168
+ ctx.out(
169
+ `The seller confirms at once if this is right; otherwise run \`obbyx channel confirm ${ch.aa}\` after ${ch.timeout} s.`,
170
+ );
171
+ }
172
+
173
+ async function confirmCommand({ args, ctx, store, opts }: ChannelRun): Promise<void> {
174
+ const ch = need(store, args.target);
175
+ const unit = await confirmClose(opts, ch.aa, ch.period);
176
+ ctx.out(`Close confirmed for period ${ch.period}: ${unit}`);
177
+ }
178
+
155
179
  function need(store: ClientChannelStore, aa: string | undefined) {
156
180
  if (aa === undefined) throw new ObbyxError('usage', 'channel address required');
157
181
  const ch = store.get(aa);
package/src/lib/doctor.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { existsSync, statSync } from 'node:fs';
1
+ import { existsSync, readFileSync, statSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import obyte from 'obyte';
4
4
  import { type ObyteNetwork, toDisplay } from '@obbyx/obyte';
5
- import { ClientChannelStore, CoinReservations, hubCall } from '@obbyx/x402-obyte';
5
+ import { ClientChannelStore, CoinReservations, hubCall, parseBalances } from '@obbyx/x402-obyte';
6
6
  import { channelStorePath } from './channels.js';
7
7
  import { obbyxHome, walletPath } from '@obbyx/obyte/wallet';
8
8
 
@@ -11,69 +11,82 @@ import { obbyxHome, walletPath } from '@obbyx/obyte/wallet';
11
11
  * Exit code 0 when nothing failed (warnings allowed).
12
12
  */
13
13
  type Status = 'ok' | 'warn' | 'fail';
14
+ type Report = (status: Status, what: string, detail?: string) => void;
15
+
16
+ const MARK: Record<Status, string> = { ok: '✓', warn: '!', fail: '✗' };
17
+ const HUB_TIMEOUT_MS = 10_000;
14
18
 
15
19
  export async function doctor(
16
20
  network: ObyteNetwork,
17
21
  opts: { hub?: string; facilitator?: string; out: (s: string) => void },
18
22
  ): Promise<number> {
19
23
  const results: Status[] = [];
20
- const report = (status: Status, what: string, detail = '') => {
24
+ const report: Report = (status, what, detail = '') => {
21
25
  results.push(status);
22
- opts.out(
23
- `${status === 'ok' ? '✓' : status === 'warn' ? '!' : '✗'} ${what}${detail ? ` — ${detail}` : ''}`,
24
- );
26
+ opts.out(`${MARK[status]} ${what}${detail ? ` — ${detail}` : ''}`);
25
27
  };
28
+ const address = checkWallet(network, report);
29
+ await checkHub(network, opts.hub ?? network.defaultHubUrl, address, report);
30
+ checkLocalState(network, report);
31
+ if (opts.facilitator !== undefined) await checkFacilitator(network, opts.facilitator, report);
32
+ return results.includes('fail') ? 1 : 0;
33
+ }
26
34
 
27
- // Wallet
35
+ /** The wallet file exists and only its owner can read it; returns its address. */
36
+ function checkWallet(network: ObyteNetwork, report: Report): string | undefined {
28
37
  const wallet = walletPath(network);
29
- let address: string | undefined;
30
38
  if (!existsSync(wallet)) {
31
39
  report('fail', 'wallet', `missing; run: obbyx init --network ${network.name}`);
32
- } else if ((statSync(wallet).mode & 0o077) !== 0) {
40
+ return undefined;
41
+ }
42
+ if ((statSync(wallet).mode & 0o077) !== 0) {
33
43
  report('fail', 'wallet', `${wallet} is readable by others; run: chmod 600 ${wallet}`);
34
- } else {
35
- const { readFileSync } = await import('node:fs');
36
- address = (JSON.parse(readFileSync(wallet, 'utf8')) as { address: string }).address;
37
- report('ok', 'wallet', `${address} (${wallet})`);
44
+ return undefined;
38
45
  }
46
+ const address = (JSON.parse(readFileSync(wallet, 'utf8')) as { address: string }).address;
47
+ report('ok', 'wallet', `${address} (${wallet})`);
48
+ return address;
49
+ }
39
50
 
40
- // Hub
41
- const client = new obyte.Client(opts.hub ?? network.defaultHubUrl, { testnet: network.testnet });
51
+ /** The hub answers; then the wallet's bytes balance (empty on testnet is only a warning). */
52
+ async function checkHub(
53
+ network: ObyteNetwork,
54
+ hubUrl: string,
55
+ address: string | undefined,
56
+ report: Report,
57
+ ): Promise<void> {
58
+ const client = new obyte.Client(hubUrl, { testnet: network.testnet });
42
59
  try {
43
60
  const started = Date.now();
44
- const mci = await hubCall(() => client.api.getLastMci(), 10_000);
61
+ const mci = await hubCall(() => client.api.getLastMci(), HUB_TIMEOUT_MS);
45
62
  if (mci.kind !== 'ok') {
46
- report('fail', 'hub', `${opts.hub ?? network.defaultHubUrl}: ${mci.error}`);
47
- } else {
48
- report(
49
- 'ok',
50
- 'hub',
51
- `${opts.hub ?? network.defaultHubUrl}, last MCI ${mci.value}, ${Date.now() - started} ms`,
52
- );
53
- if (address !== undefined) {
54
- const b = await hubCall(() => client.api.getBalances([address]), 10_000);
55
- if (b.kind === 'ok') {
56
- const base = (
57
- b.value as Record<string, Record<string, { stable: number; pending: number }>>
58
- )[address]?.['base'];
59
- const stable = BigInt(base?.stable ?? 0);
60
- const pending = BigInt(base?.pending ?? 0);
61
- report(
62
- stable === 0n ? (network.testnet ? 'warn' : 'fail') : 'ok',
63
- 'balance',
64
- `${toDisplay(stable, 9)} GBYTE stable, ${toDisplay(pending, 9)} pending` +
65
- (stable === 0n && network.testnet ? '; run: obbyx faucet' : ''),
66
- );
67
- } else {
68
- report('warn', 'balance', b.error);
69
- }
70
- }
63
+ report('fail', 'hub', `${hubUrl}: ${mci.error}`);
64
+ return;
65
+ }
66
+ report('ok', 'hub', `${hubUrl}, last MCI ${mci.value}, ${Date.now() - started} ms`);
67
+ if (address === undefined) return;
68
+ const b = await hubCall(() => client.api.getBalances([address]), HUB_TIMEOUT_MS);
69
+ if (b.kind !== 'ok') {
70
+ report('warn', 'balance', b.error);
71
+ return;
71
72
  }
73
+ const base = parseBalances(b.value, address)?.['base'];
74
+ const stable = base?.stable ?? 0n;
75
+ const pending = base?.pending ?? 0n;
76
+ const empty = stable === 0n;
77
+ report(
78
+ empty ? (network.testnet ? 'warn' : 'fail') : 'ok',
79
+ 'balance',
80
+ `${toDisplay(stable, 9)} GBYTE stable, ${toDisplay(pending, 9)} pending` +
81
+ (empty && network.testnet ? '; run: obbyx faucet' : ''),
82
+ );
72
83
  } finally {
73
84
  client.close();
74
85
  }
86
+ }
75
87
 
76
- // Local payment state
88
+ /** Coin reservations and channels with an unknown outcome (warnings, never failures). */
89
+ function checkLocalState(network: ObyteNetwork, report: Report): void {
77
90
  const coinsPath = join(obbyxHome(), `coins-${network.name}.db`);
78
91
  if (existsSync(coinsPath)) {
79
92
  const reservations = new CoinReservations(coinsPath);
@@ -102,32 +115,32 @@ export async function doctor(
102
115
  : ''),
103
116
  );
104
117
  }
118
+ }
105
119
 
106
- // Facilitator (optional)
107
- if (opts.facilitator !== undefined) {
108
- try {
109
- const res = await fetch(new URL('/supported', opts.facilitator), {
110
- signal: AbortSignal.timeout(10_000),
111
- });
112
- const supported = (await res.json()) as { kinds?: { scheme: string; network: string }[] };
113
- const kinds = (supported.kinds ?? [])
114
- .filter((k) => k.network === network.caip2)
115
- .map((k) => k.scheme);
116
- report(
117
- kinds.length > 0 ? 'ok' : 'fail',
118
- 'facilitator',
119
- kinds.length > 0
120
- ? `${opts.facilitator}: ${kinds.join(', ')}`
121
- : `does not serve ${network.caip2}`,
122
- );
123
- } catch (err) {
124
- report(
125
- 'fail',
126
- 'facilitator',
127
- `${opts.facilitator}: ${err instanceof Error ? err.message : String(err)}`,
128
- );
129
- }
120
+ /** The facilitator answers /supported and serves this network. */
121
+ async function checkFacilitator(
122
+ network: ObyteNetwork,
123
+ facilitator: string,
124
+ report: Report,
125
+ ): Promise<void> {
126
+ try {
127
+ const res = await fetch(new URL('/supported', facilitator), {
128
+ signal: AbortSignal.timeout(HUB_TIMEOUT_MS),
129
+ });
130
+ const supported = (await res.json()) as { kinds?: { scheme: string; network: string }[] };
131
+ const kinds = (supported.kinds ?? [])
132
+ .filter((k) => k.network === network.caip2)
133
+ .map((k) => k.scheme);
134
+ report(
135
+ kinds.length > 0 ? 'ok' : 'fail',
136
+ 'facilitator',
137
+ kinds.length > 0 ? `${facilitator}: ${kinds.join(', ')}` : `does not serve ${network.caip2}`,
138
+ );
139
+ } catch (err) {
140
+ report(
141
+ 'fail',
142
+ 'facilitator',
143
+ `${facilitator}: ${err instanceof Error ? err.message : String(err)}`,
144
+ );
130
145
  }
131
-
132
- return results.includes('fail') ? 1 : 0;
133
146
  }