@certen.io/cli 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -0
- package/README.md +24 -0
- package/dist/commands/auth.js +3 -3
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/billing.d.ts +2 -0
- package/dist/commands/billing.js +174 -0
- package/dist/commands/billing.js.map +1 -0
- package/dist/commands/keys.js +3 -3
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/transaction.js +5 -0
- package/dist/commands/transaction.js.map +1 -1
- package/dist/config.js +5 -6
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +37 -0
- package/dist/errors.js +46 -0
- package/dist/errors.js.map +1 -0
- package/dist/help-json.d.ts +2 -0
- package/dist/help-json.js +51 -0
- package/dist/help-json.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +101 -36
- package/dist/index.js.map +1 -1
- package/dist/output.d.ts +31 -1
- package/dist/output.js +150 -1
- package/dist/output.js.map +1 -1
- package/package.json +57 -56
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Changelog — @certen.io/cli
|
|
2
|
+
|
|
3
|
+
## 0.5.0 — money commands, and a refusal that tells you how to fix it
|
|
4
|
+
|
|
5
|
+
### Added — `certen balance` and `certen fund`
|
|
6
|
+
|
|
7
|
+
`balance` prints available, held, credit line, spendable, and **left to commit** — spendable minus
|
|
8
|
+
what pending intents have already claimed. Showing only the balance would tell you that you can
|
|
9
|
+
afford work that is already spoken for.
|
|
10
|
+
|
|
11
|
+
`fund <amount> --chain <chain>` prints where to send stablecoin and waits until it is credited.
|
|
12
|
+
It never touches a wallet or a key: signing and sending stay with you. `--no-wait` prints the
|
|
13
|
+
details and exits; `--poll-interval` and `--timeout` control the wait. An uncredited or expired
|
|
14
|
+
payment exits non-zero, because a funding script must not read one as paid.
|
|
15
|
+
|
|
16
|
+
Every option is validated before the network call — a typo in `--timeout` used to open a real
|
|
17
|
+
payment intent first.
|
|
18
|
+
|
|
19
|
+
### Changed — a 402 now prints the way out
|
|
20
|
+
|
|
21
|
+
A refusal for lack of funds shows the shortfall, the address, the exact amount, the reference, both
|
|
22
|
+
`certen fund …` and the portal link, and the quote id to retry with — then states plainly that
|
|
23
|
+
nothing was charged and no work was started. All on stderr; stdout is untouched.
|
|
24
|
+
|
|
25
|
+
In `--json`, the failure envelope gains `shortfall_usd`, `quote_id` and `resolve` on payment
|
|
26
|
+
failures only. They are absent on every other error rather than present as nulls. See
|
|
27
|
+
docs/CLI-CONTRACT.md.
|
|
28
|
+
|
|
29
|
+
### Fixed — the error reporter no longer flattens SDK errors
|
|
30
|
+
|
|
31
|
+
`handleError` copied a `CertenError` into an object literal before reporting it. The values
|
|
32
|
+
survived; the class identity did not — so a payment refusal could not be recognised and its payment
|
|
33
|
+
target was silently dropped. The fields it copied are all readable on the instance, `isRetryable`
|
|
34
|
+
getter included, so nothing was gained by the copy.
|
|
35
|
+
|
|
36
|
+
## 0.4.0 — `--json` is a machine contract
|
|
37
|
+
|
|
38
|
+
Adds a stable, tested output contract for scripts and AI agents. **Human output is unchanged**: if
|
|
39
|
+
you do not pass `--json`, this release behaves exactly as 0.3.1 did, with one exception noted under
|
|
40
|
+
Breaking.
|
|
41
|
+
|
|
42
|
+
Before this, every failure exited `1` and explained itself in English on stderr. An automated caller
|
|
43
|
+
could not distinguish "you passed a malformed address" from "the gateway is down" without parsing
|
|
44
|
+
prose — and those want opposite responses. One is a bug to fix; the other is worth retrying. For a
|
|
45
|
+
CLI that authorizes cross-chain execution against real funds, guessing wrong is expensive in a way
|
|
46
|
+
that is not recoverable.
|
|
47
|
+
|
|
48
|
+
The full specification is [docs/CLI-CONTRACT.md](../../docs/CLI-CONTRACT.md), enforced by
|
|
49
|
+
`test/conformance.test.ts`, which runs the built binary as a subprocess and checks the real process's
|
|
50
|
+
stdout and exit code.
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- **Global `--json`**, accepted anywhere in the argument list — `certen --json tx status X` and
|
|
55
|
+
`certen tx status X --json` are identical. It is resolved before argument parsing, so it applies
|
|
56
|
+
even to failures that occur while resolving credentials.
|
|
57
|
+
- **One JSON envelope on stdout and nothing else.** `{"ok":true,"data":…}` or
|
|
58
|
+
`{"ok":false,"error":{"code","message","retryable","status?","requestId?"}}`. A command producing
|
|
59
|
+
several payloads emits an array in `data`; one producing none emits `"data":null`. stdout is never
|
|
60
|
+
empty and never carries two concatenated objects. All human-facing text moves to stderr.
|
|
61
|
+
- **Meaningful exit codes:** `0` ok · `1` operation failed · `2` usage error · `3` gateway
|
|
62
|
+
unreachable. `3` guarantees nothing was submitted, so a retry cannot double-execute.
|
|
63
|
+
- **`error.retryable`**, taken from the SDK's own `CertenError.isRetryable`, so the CLI and the SDK
|
|
64
|
+
hand an automated caller the identical retry decision.
|
|
65
|
+
- **`certen --help --json`** returns the entire command tree — every command, argument, flag and exit
|
|
66
|
+
code — in one call, instead of scraping help text once per subcommand.
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
|
|
70
|
+
- **Usage errors on subcommands bypassed error handling entirely.** `exitOverride()` is not inherited
|
|
71
|
+
by commander subcommands, so a missing required flag (`certen identity create` with no `--name`)
|
|
72
|
+
called `process.exit(1)` inside commander: no envelope was emitted, stdout stayed empty, and a
|
|
73
|
+
usage error was indistinguishable from a failed request. It is now applied to every command in the
|
|
74
|
+
tree.
|
|
75
|
+
|
|
76
|
+
### Breaking
|
|
77
|
+
|
|
78
|
+
- **"No API key configured" now exits `2` instead of `1`.** It is a usage error: nothing was sent,
|
|
79
|
+
and retrying cannot help. The same applies to a config file with unsafe permissions and to a
|
|
80
|
+
missing keyring backend. Scripts treating any non-zero exit as failure are unaffected; scripts
|
|
81
|
+
testing specifically for `-eq 1` need updating.
|
|
82
|
+
|
|
83
|
+
### Note
|
|
84
|
+
|
|
85
|
+
`output: "json"` in `~/.certen/config.json` is **not** this contract. That setting predates the
|
|
86
|
+
envelope and makes commands print their raw payload — no `ok`, no `error`, no exit-code guarantees.
|
|
87
|
+
It is kept for backward compatibility. Automated callers should pass `--json` explicitly rather than
|
|
88
|
+
depend on a machine's local config, which they cannot see.
|
package/README.md
CHANGED
|
@@ -97,6 +97,30 @@ certen admin audit-log | usage
|
|
|
97
97
|
|
|
98
98
|
Run `certen <group> --help` for the flags on any of them.
|
|
99
99
|
|
|
100
|
+
## Scripting and AI agents: `--json`
|
|
101
|
+
|
|
102
|
+
`--json` turns the CLI into a machine interface. It is a contract, documented in full in
|
|
103
|
+
[docs/CLI-CONTRACT.md](../../docs/CLI-CONTRACT.md) and enforced by a conformance suite.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
certen --json tx status <id>
|
|
107
|
+
# {"ok":true,"data":{"intent_id":"…","status":"completed"}}
|
|
108
|
+
|
|
109
|
+
certen --json portfolio
|
|
110
|
+
# {"ok":false,"error":{"code":"NETWORK_ERROR","message":"connect ECONNREFUSED","retryable":true,"status":0}}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- **Exactly one JSON object on stdout**, nothing else. Every human-facing line goes to stderr.
|
|
114
|
+
- **Exit codes:** `0` ok · `1` operation failed · `2` usage error · `3` gateway unreachable. Branch on
|
|
115
|
+
these instead of parsing text. `3` guarantees nothing was submitted, so a retry cannot
|
|
116
|
+
double-execute.
|
|
117
|
+
- **`error.retryable`** comes from the SDK's own `CertenError.isRetryable`, so the CLI and the SDK
|
|
118
|
+
give an identical retry decision.
|
|
119
|
+
- **`certen --help --json`** returns the entire command tree — every command, flag and exit code — in
|
|
120
|
+
one call.
|
|
121
|
+
|
|
122
|
+
Without `--json`, output is the human table format as before. Do not parse it.
|
|
123
|
+
|
|
100
124
|
## Configuration
|
|
101
125
|
|
|
102
126
|
| | |
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readConfig, writeConfig, setApiKey, clearApiKey, DEFAULT_API_URL } from '../config.js';
|
|
2
|
-
import { printOutput } from '../output.js';
|
|
2
|
+
import { printOutput, human } from '../output.js';
|
|
3
3
|
export function registerAuthCommands(program) {
|
|
4
4
|
const auth = program.command('auth').description('Authentication management');
|
|
5
5
|
auth
|
|
@@ -23,14 +23,14 @@ export function registerAuthCommands(program) {
|
|
|
23
23
|
cfg.api_url = opts.apiUrl;
|
|
24
24
|
writeConfig(cfg);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
human(useKeyring ? 'API key saved to OS keyring' : 'API key saved to ~/.certen/config.json (mode 0600)');
|
|
27
27
|
});
|
|
28
28
|
auth
|
|
29
29
|
.command('logout')
|
|
30
30
|
.description('Remove the saved API key from keyring or config file')
|
|
31
31
|
.action(async () => {
|
|
32
32
|
await clearApiKey();
|
|
33
|
-
|
|
33
|
+
human('API key cleared');
|
|
34
34
|
});
|
|
35
35
|
auth
|
|
36
36
|
.command('status')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { CertenClient } from '@certen.io/sdk';
|
|
2
|
+
import { getApiKey, getApiUrl } from '../config.js';
|
|
3
|
+
import { printOutput, human, hint, isJsonMode } from '../output.js';
|
|
4
|
+
import { CliError, EXIT } from '../errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Money commands.
|
|
7
|
+
*
|
|
8
|
+
* These exist because the gateway enforces payment on every execution path while
|
|
9
|
+
* no client surface could add funds — so usage accrued against a credit line with
|
|
10
|
+
* no way to settle it. A developer refused for lack of funds needs the fix in the
|
|
11
|
+
* terminal they were already in, not a link to go and read.
|
|
12
|
+
*
|
|
13
|
+
* `fund` never touches a wallet or a private key. It asks the gateway where to
|
|
14
|
+
* send stablecoin, prints that, and waits. Signing and sending stay entirely with
|
|
15
|
+
* the customer's own wallet.
|
|
16
|
+
*/
|
|
17
|
+
async function getClient() {
|
|
18
|
+
return new CertenClient({ apiKey: await getApiKey(), baseUrl: getApiUrl() });
|
|
19
|
+
}
|
|
20
|
+
/** "12.340000" -> "$12.34". Trims the string; never parses money into a float. */
|
|
21
|
+
function usd(amount) {
|
|
22
|
+
const [whole, frac = ''] = String(amount).split('.');
|
|
23
|
+
const neg = whole.startsWith('-');
|
|
24
|
+
return `${neg ? '-$' : '$'}${neg ? whole.slice(1) : whole}.${(frac + '00').slice(0, 2)}`;
|
|
25
|
+
}
|
|
26
|
+
function minutesUntil(iso) {
|
|
27
|
+
return Math.max(0, Math.round((new Date(iso).getTime() - Date.now()) / 60_000));
|
|
28
|
+
}
|
|
29
|
+
export function registerBillingCommands(program) {
|
|
30
|
+
program
|
|
31
|
+
.command('balance')
|
|
32
|
+
.description('Show your balance and what pending work has already claimed')
|
|
33
|
+
.action(async () => {
|
|
34
|
+
const client = await getClient();
|
|
35
|
+
// Both, because either alone misleads: the balance looks healthy while
|
|
36
|
+
// every cent of it is committed to intents awaiting quorum.
|
|
37
|
+
const [balance, obligations] = await Promise.all([
|
|
38
|
+
client.billing.balance(),
|
|
39
|
+
client.billing.obligations(),
|
|
40
|
+
]);
|
|
41
|
+
printOutput({
|
|
42
|
+
currency: balance.currency,
|
|
43
|
+
available_usd: balance.available_usd,
|
|
44
|
+
held_usd: balance.held_usd,
|
|
45
|
+
credit_limit_usd: balance.credit_limit_usd,
|
|
46
|
+
spendable_usd: balance.spendable_usd,
|
|
47
|
+
remaining_usd: obligations.remaining_usd,
|
|
48
|
+
pending_intents: obligations.pending_intents,
|
|
49
|
+
uncovered_usd: obligations.uncovered_usd,
|
|
50
|
+
status: balance.status,
|
|
51
|
+
});
|
|
52
|
+
if (isJsonMode())
|
|
53
|
+
return;
|
|
54
|
+
human('');
|
|
55
|
+
human(` Available ${usd(balance.available_usd)}`);
|
|
56
|
+
human(` Held for in-flight ${usd(balance.held_usd)}`);
|
|
57
|
+
if (balance.credit_limit_usd !== '0.000000') {
|
|
58
|
+
human(` Credit line ${usd(balance.credit_limit_usd)}`);
|
|
59
|
+
}
|
|
60
|
+
human(` Spendable ${usd(balance.spendable_usd)}`);
|
|
61
|
+
human(` Left to commit ${usd(obligations.remaining_usd)}`);
|
|
62
|
+
human('');
|
|
63
|
+
if (obligations.pending_intents > 0) {
|
|
64
|
+
human(` ${obligations.pending_intents} pending intent(s) have claimed `
|
|
65
|
+
+ `${usd(obligations.uncovered_usd)} of that.`);
|
|
66
|
+
}
|
|
67
|
+
if (Number(obligations.remaining_usd) <= 0) {
|
|
68
|
+
human(' You cannot start new work until you add funds.');
|
|
69
|
+
hint('certen fund <amount> --chain <chain>');
|
|
70
|
+
}
|
|
71
|
+
if (balance.status !== 'active') {
|
|
72
|
+
human(` Account status: ${balance.status}.`);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
program
|
|
76
|
+
.command('fund')
|
|
77
|
+
.argument('<amount>', 'Amount in USD to send, e.g. 25 or 25.50')
|
|
78
|
+
.description('Get payment details for adding funds, and wait until they are credited')
|
|
79
|
+
.option('--chain <chain>', 'Chain to send stablecoin on (e.g. base)')
|
|
80
|
+
.option('--no-wait', 'Print the payment details and exit instead of waiting')
|
|
81
|
+
.option('--timeout <minutes>', 'How long to wait for the deposit', '60')
|
|
82
|
+
// Scripted callers legitimately want a different cadence — a CI job funding a
|
|
83
|
+
// test account should not sit on a 5-second loop, and a long unattended wait
|
|
84
|
+
// should poll gently. Exposed rather than hard-coded.
|
|
85
|
+
.option('--poll-interval <seconds>', 'How often to check for the deposit', '5')
|
|
86
|
+
.action(async (amount, opts) => {
|
|
87
|
+
if (!/^\d+(\.\d{1,6})?$/.test(amount) || Number(amount) <= 0) {
|
|
88
|
+
throw new CliError(`"${amount}" is not a valid amount. Use a number of dollars, e.g. 25 or 25.50`, 'INVALID_AMOUNT', EXIT.USAGE);
|
|
89
|
+
}
|
|
90
|
+
if (!opts.chain) {
|
|
91
|
+
throw new CliError('Which chain will you send on? Pass --chain (e.g. --chain base)', 'CHAIN_REQUIRED', EXIT.USAGE);
|
|
92
|
+
}
|
|
93
|
+
// Every option is validated BEFORE the network call. Checking after would
|
|
94
|
+
// mean a typo in --timeout had already opened a real payment intent that the
|
|
95
|
+
// customer then has to wait out or abandon.
|
|
96
|
+
const timeoutMin = Number(opts.timeout);
|
|
97
|
+
if (!Number.isFinite(timeoutMin) || timeoutMin <= 0) {
|
|
98
|
+
throw new CliError('--timeout must be a positive number of minutes', 'INVALID_TIMEOUT', EXIT.USAGE);
|
|
99
|
+
}
|
|
100
|
+
const pollSec = Number(opts.pollInterval);
|
|
101
|
+
if (!Number.isFinite(pollSec) || pollSec <= 0) {
|
|
102
|
+
throw new CliError('--poll-interval must be a positive number of seconds', 'INVALID_POLL_INTERVAL', EXIT.USAGE);
|
|
103
|
+
}
|
|
104
|
+
const client = await getClient();
|
|
105
|
+
const target = await client.billing.openPayment({ chain: opts.chain, amountUsd: amount });
|
|
106
|
+
const intent = target.deposit_intent;
|
|
107
|
+
if (!intent) {
|
|
108
|
+
// Defensive: an amount was supplied, so the gateway should have opened one.
|
|
109
|
+
throw new CliError('The gateway did not open a payment for that amount. Nothing was sent; try again.', 'PAYMENT_NOT_OPENED', EXIT.FAILED);
|
|
110
|
+
}
|
|
111
|
+
printOutput({
|
|
112
|
+
reference: intent.reference,
|
|
113
|
+
amount_usd: intent.amount_usd,
|
|
114
|
+
expires_at: intent.expires_at,
|
|
115
|
+
chain: target.chain,
|
|
116
|
+
chain_id: target.chain_id,
|
|
117
|
+
token_symbol: target.token_symbol,
|
|
118
|
+
token_address: target.token_address,
|
|
119
|
+
deposit_address: target.deposit_address,
|
|
120
|
+
min_confirmations: target.min_confirmations,
|
|
121
|
+
});
|
|
122
|
+
if (!isJsonMode()) {
|
|
123
|
+
human('');
|
|
124
|
+
human(` Send exactly ${intent.amount_usd} ${target.token_symbol} on ${target.chain} to:`);
|
|
125
|
+
human('');
|
|
126
|
+
human(` ${target.deposit_address}`);
|
|
127
|
+
human('');
|
|
128
|
+
human(` Reference ${intent.reference} · expires in ${minutesUntil(intent.expires_at)} min`);
|
|
129
|
+
human(' The exact amount is how we know the payment is yours, so send it to the cent.');
|
|
130
|
+
human(` Credited after ${target.min_confirmations} confirmation(s).`);
|
|
131
|
+
human('');
|
|
132
|
+
}
|
|
133
|
+
if (!opts.wait) {
|
|
134
|
+
hint('certen fund --no-wait was used; check later with certen balance');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (!isJsonMode()) {
|
|
138
|
+
human(' Waiting for your deposit. Ctrl-C is safe — the payment stays open.');
|
|
139
|
+
}
|
|
140
|
+
let lastSeen = '';
|
|
141
|
+
const final = await client.billing.waitForPayment(intent.reference, {
|
|
142
|
+
intervalMs: pollSec * 1_000,
|
|
143
|
+
timeoutMs: timeoutMin * 60_000,
|
|
144
|
+
onPoll: (s) => {
|
|
145
|
+
// Only speak when something changed, so a long wait is not a wall of text.
|
|
146
|
+
if (!isJsonMode() && s.status !== lastSeen) {
|
|
147
|
+
lastSeen = s.status;
|
|
148
|
+
if (s.status !== 'open')
|
|
149
|
+
human(` Payment ${s.status}.`);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
if (final.status === 'matched') {
|
|
154
|
+
if (!isJsonMode()) {
|
|
155
|
+
const balance = await client.billing.balance().catch(() => null);
|
|
156
|
+
human(` Credited ${usd(final.amount_usd)}.`);
|
|
157
|
+
if (balance)
|
|
158
|
+
human(` Available now ${usd(balance.available_usd)}.`);
|
|
159
|
+
human('');
|
|
160
|
+
hint('Paying from this wallet again? Register it once in the portal and every '
|
|
161
|
+
+ 'future deposit credits automatically: /portal');
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// Not credited. This is an ordinary outcome, not a crash — but the exit code
|
|
166
|
+
// has to say so, or a script will treat an expired payment as funded.
|
|
167
|
+
const why = final.status === 'open'
|
|
168
|
+
? `still waiting after ${timeoutMin} min`
|
|
169
|
+
: `payment ${final.status}`;
|
|
170
|
+
throw new CliError(`Deposit not credited (${why}). Nothing was charged. `
|
|
171
|
+
+ 'Check with: certen balance', 'DEPOSIT_NOT_CREDITED', EXIT.FAILED);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=billing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.js","sourceRoot":"","sources":["../../src/commands/billing.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/keys.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { printOutput } from '../output.js';
|
|
1
|
+
import { printOutput, human } from '../output.js';
|
|
2
2
|
import { resolvePassphrase, resolveNewPassphrase, PASSPHRASE_ENV_VAR } from '../passphrase.js';
|
|
3
3
|
import { generateKey, listKeys, getKeyInfo, deleteKey, signHash, selfTest, keyPath, KEYS_DIR, } from '../keystore.js';
|
|
4
4
|
/**
|
|
@@ -41,7 +41,7 @@ export function registerKeysCommands(program) {
|
|
|
41
41
|
.action(() => {
|
|
42
42
|
const all = listKeys();
|
|
43
43
|
if (all.length === 0) {
|
|
44
|
-
|
|
44
|
+
human(`(no keys in ${KEYS_DIR})`);
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
printOutput(all.map((k) => ({
|
|
@@ -96,7 +96,7 @@ export function registerKeysCommands(program) {
|
|
|
96
96
|
// should not be deletable by an accidental Enter on a y/N prompt.
|
|
97
97
|
const path = keyPath(name);
|
|
98
98
|
deleteKey(name);
|
|
99
|
-
|
|
99
|
+
human(`Deleted ${path}`);
|
|
100
100
|
console.error('If this key was on a key page, it is still on that page — remove it there too.');
|
|
101
101
|
});
|
|
102
102
|
keys
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Option } from 'commander';
|
|
1
2
|
import { readFileSync } from 'node:fs';
|
|
2
3
|
import { CertenClient } from '@certen.io/sdk';
|
|
3
4
|
import { getApiKey, getApiUrl } from '../config.js';
|
|
@@ -42,6 +43,9 @@ export function registerTransactionCommands(program) {
|
|
|
42
43
|
.option('--contract-address <addr...>', 'Contract addresses this intent touches')
|
|
43
44
|
.option('--signer-key-page <url>', 'Which key page signs, e.g. acc://org.acme/book/2')
|
|
44
45
|
.option('--signer-public-key <hex>', 'Which seat on the page signs (64 hex)')
|
|
46
|
+
// Validated here so a typo is caught before a request goes out, rather than surfacing from the
|
|
47
|
+
// proof service later with no obvious connection to the flag that caused it.
|
|
48
|
+
.addOption(new Option('--proof-class <class>', 'When the proof runs: on_demand starts now (~60-110s); on_cadence batches it (cheaper, slower)').choices(['on_demand', 'on_cadence']))
|
|
45
49
|
.option('--idempotency-key <key>', 'Idempotency key (one is generated if omitted)')
|
|
46
50
|
.option('--sign-with <key>', 'Local key: sign the returned hash and submit it in one step')
|
|
47
51
|
.action(async (opts) => {
|
|
@@ -75,6 +79,7 @@ export function registerTransactionCommands(program) {
|
|
|
75
79
|
intent,
|
|
76
80
|
contractAddresses: opts.contractAddress,
|
|
77
81
|
signerKeyPage: opts.signerKeyPage,
|
|
82
|
+
proofClass: opts.proofClass,
|
|
78
83
|
signerPublicKey: opts.signerPublicKey ?? signer?.publicKey,
|
|
79
84
|
idempotencyKey: opts.idempotencyKey,
|
|
80
85
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/commands/transaction.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/commands/transaction.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, statSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
|
+
import { UsageError } from './errors.js';
|
|
4
5
|
const CONFIG_DIR = join(homedir(), '.certen');
|
|
5
6
|
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
6
7
|
export function readConfig() {
|
|
@@ -86,19 +87,17 @@ export async function getApiKey() {
|
|
|
86
87
|
return v;
|
|
87
88
|
}
|
|
88
89
|
else {
|
|
89
|
-
|
|
90
|
-
process.exit(1);
|
|
90
|
+
throw new UsageError('storage=keyring requested but `keytar` is not installed; install it or set CERTEN_API_KEY.', 'KEYRING_UNAVAILABLE');
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
if (cfg.api_key) {
|
|
94
94
|
if (!configFileIsSecure()) {
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
throw new UsageError('refusing to read ~/.certen/config.json — file permissions are not 0600. '
|
|
96
|
+
+ 'Run `certen auth login` again to fix.', 'CONFIG_PERMISSIONS');
|
|
97
97
|
}
|
|
98
98
|
return cfg.api_key;
|
|
99
99
|
}
|
|
100
|
-
|
|
101
|
-
process.exit(1);
|
|
100
|
+
throw new UsageError('No API key configured. Run "certen auth login --api-key <key>" or set CERTEN_API_KEY.', 'NO_API_KEY');
|
|
102
101
|
}
|
|
103
102
|
export async function setApiKey(apiKey, useKeyring) {
|
|
104
103
|
const prefix = apiKey.substring(0, 12);
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC7F,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit codes and the local error taxonomy.
|
|
3
|
+
*
|
|
4
|
+
* The CLI used to exit `1` for everything — a bad flag, a rejected request, and an unreachable
|
|
5
|
+
* gateway were indistinguishable without reading English off stderr. An automated caller cannot
|
|
6
|
+
* make a retry decision from that: "you passed a malformed address" and "the gateway is down" want
|
|
7
|
+
* opposite responses, and only one of them is worth retrying.
|
|
8
|
+
*
|
|
9
|
+
* These four codes are a contract. See docs/CLI-CONTRACT.md.
|
|
10
|
+
*/
|
|
11
|
+
export declare const EXIT: {
|
|
12
|
+
/** Success. */
|
|
13
|
+
readonly OK: 0;
|
|
14
|
+
/** The request was well-formed and the gateway answered, but the operation did not succeed. */
|
|
15
|
+
readonly FAILED: 1;
|
|
16
|
+
/** The invocation was wrong: unknown command, missing flag, no API key configured. */
|
|
17
|
+
readonly USAGE: 2;
|
|
18
|
+
/** The gateway could not be reached at all. Nothing was submitted. */
|
|
19
|
+
readonly UNREACHABLE: 3;
|
|
20
|
+
};
|
|
21
|
+
export type ExitCode = (typeof EXIT)[keyof typeof EXIT];
|
|
22
|
+
/**
|
|
23
|
+
* An error raised by the CLI itself rather than by the gateway.
|
|
24
|
+
*
|
|
25
|
+
* `code` is machine-readable and lives in the same namespace as the gateway's codes, so a caller
|
|
26
|
+
* branching on `error.code` does not need to know whether the failure was local or remote.
|
|
27
|
+
*/
|
|
28
|
+
export declare class CliError extends Error {
|
|
29
|
+
readonly code: string;
|
|
30
|
+
readonly exitCode: ExitCode;
|
|
31
|
+
readonly retryable: boolean;
|
|
32
|
+
constructor(message: string, code: string, exitCode?: ExitCode, retryable?: boolean);
|
|
33
|
+
}
|
|
34
|
+
/** A wrong invocation: exits 2, never retryable. */
|
|
35
|
+
export declare class UsageError extends CliError {
|
|
36
|
+
constructor(message: string, code?: string);
|
|
37
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit codes and the local error taxonomy.
|
|
3
|
+
*
|
|
4
|
+
* The CLI used to exit `1` for everything — a bad flag, a rejected request, and an unreachable
|
|
5
|
+
* gateway were indistinguishable without reading English off stderr. An automated caller cannot
|
|
6
|
+
* make a retry decision from that: "you passed a malformed address" and "the gateway is down" want
|
|
7
|
+
* opposite responses, and only one of them is worth retrying.
|
|
8
|
+
*
|
|
9
|
+
* These four codes are a contract. See docs/CLI-CONTRACT.md.
|
|
10
|
+
*/
|
|
11
|
+
export const EXIT = {
|
|
12
|
+
/** Success. */
|
|
13
|
+
OK: 0,
|
|
14
|
+
/** The request was well-formed and the gateway answered, but the operation did not succeed. */
|
|
15
|
+
FAILED: 1,
|
|
16
|
+
/** The invocation was wrong: unknown command, missing flag, no API key configured. */
|
|
17
|
+
USAGE: 2,
|
|
18
|
+
/** The gateway could not be reached at all. Nothing was submitted. */
|
|
19
|
+
UNREACHABLE: 3,
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* An error raised by the CLI itself rather than by the gateway.
|
|
23
|
+
*
|
|
24
|
+
* `code` is machine-readable and lives in the same namespace as the gateway's codes, so a caller
|
|
25
|
+
* branching on `error.code` does not need to know whether the failure was local or remote.
|
|
26
|
+
*/
|
|
27
|
+
export class CliError extends Error {
|
|
28
|
+
code;
|
|
29
|
+
exitCode;
|
|
30
|
+
retryable;
|
|
31
|
+
constructor(message, code, exitCode = EXIT.FAILED, retryable = false) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'CliError';
|
|
34
|
+
this.code = code;
|
|
35
|
+
this.exitCode = exitCode;
|
|
36
|
+
this.retryable = retryable;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** A wrong invocation: exits 2, never retryable. */
|
|
40
|
+
export class UsageError extends CliError {
|
|
41
|
+
constructor(message, code = 'USAGE_ERROR') {
|
|
42
|
+
super(message, code, EXIT.USAGE, false);
|
|
43
|
+
this.name = 'UsageError';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,eAAe;IACf,EAAE,EAAE,CAAC;IACL,+FAA+F;IAC/F,MAAM,EAAE,CAAC;IACT,sFAAsF;IACtF,KAAK,EAAE,CAAC;IACR,sEAAsE;IACtE,WAAW,EAAE,CAAC;CACN,CAAC;AAIX;;;;;GAKG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAS;IACb,QAAQ,CAAW;IACnB,SAAS,CAAU;IAE5B,YAAY,OAAe,EAAE,IAAY,EAAE,WAAqB,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK;QAC5F,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED,oDAAoD;AACpD,MAAM,OAAO,UAAW,SAAQ,QAAQ;IACtC,YAAY,OAAe,EAAE,IAAI,GAAG,aAAa;QAC/C,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function optionNode(o) {
|
|
2
|
+
return {
|
|
3
|
+
flags: o.flags,
|
|
4
|
+
name: o.attributeName ? o.attributeName() : (o.long ?? o.short ?? o.flags).replace(/^--?/, ''),
|
|
5
|
+
description: o.description ?? '',
|
|
6
|
+
required: Boolean(o.mandatory),
|
|
7
|
+
// `required` on a commander Option means "this flag takes a mandatory value", not "this flag
|
|
8
|
+
// must be present" — that is `mandatory`. Conflating them is an easy and very confusing bug.
|
|
9
|
+
takesValue: Boolean(o.required || o.optional),
|
|
10
|
+
...(o.defaultValue !== undefined ? { default: o.defaultValue } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function argumentsOf(cmd) {
|
|
14
|
+
// `registeredArguments` is commander >= 12; `_args` is the older internal. Fall back rather than
|
|
15
|
+
// throw, so a commander bump degrades the help tree instead of breaking the command.
|
|
16
|
+
const raw = (cmd.registeredArguments
|
|
17
|
+
?? cmd._args
|
|
18
|
+
?? []);
|
|
19
|
+
return raw.map((a) => ({
|
|
20
|
+
name: a.name(),
|
|
21
|
+
required: Boolean(a.required),
|
|
22
|
+
description: a.description ?? '',
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
function walk(cmd, prefix) {
|
|
26
|
+
const path = [...prefix, cmd.name()].filter(Boolean);
|
|
27
|
+
return {
|
|
28
|
+
name: cmd.name(),
|
|
29
|
+
description: cmd.description(),
|
|
30
|
+
path: path.join(' '),
|
|
31
|
+
arguments: argumentsOf(cmd),
|
|
32
|
+
options: cmd.options.map(optionNode),
|
|
33
|
+
commands: cmd.commands.map((c) => walk(c, path)),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function commandTree(program, version) {
|
|
37
|
+
return JSON.stringify({
|
|
38
|
+
ok: true,
|
|
39
|
+
data: {
|
|
40
|
+
...walk(program, []),
|
|
41
|
+
version,
|
|
42
|
+
exitCodes: {
|
|
43
|
+
0: 'ok',
|
|
44
|
+
1: 'operation failed',
|
|
45
|
+
2: 'usage error',
|
|
46
|
+
3: 'gateway unreachable',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=help-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help-json.js","sourceRoot":"","sources":["../src/help-json.ts"],"names":[],"mappings":"AAoDA,SAAS,UAAU,CAAC,CAAsB;IACxC,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9F,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;QAChC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9B,6FAA6F;QAC7F,6FAA6F;QAC7F,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC;QAC7C,GAAG,CAAC,CAAC,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,GAAY;IAC/B,iGAAiG;IACjG,qFAAqF;IACrF,MAAM,GAAG,GACP,CAAE,GAAoE,CAAC,mBAAmB;WACpF,GAAsD,CAAC,KAAK;WAC7D,EAAE,CAAC,CAAC;IACX,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QACd,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;KACjC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,SAAS,IAAI,CAAC,GAAY,EAAE,MAAgB;IAC1C,MAAM,IAAI,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrD,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;QAChB,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE;QAC9B,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QACpB,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC;QAC3B,OAAO,EAAG,GAAG,CAAC,OAA4C,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1E,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAY,EAAE,IAAI,CAAC,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAgB,EAAE,OAAe;IAC3D,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,EAAE,EAAE,IAAI;QACR,IAAI,EAAE;YACJ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACpB,OAAO;YACP,SAAS,EAAE;gBACT,CAAC,EAAE,IAAI;gBACP,CAAC,EAAE,kBAAkB;gBACrB,CAAC,EAAE,aAAa;gBAChB,CAAC,EAAE,qBAAqB;aACzB;SACF;KACF,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { Command } from 'commander';
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
|
+
import { Command, CommanderError } from 'commander';
|
|
6
6
|
import { CertenError } from '@certen.io/sdk';
|
|
7
|
+
import { EXIT } from './errors.js';
|
|
8
|
+
import { setJsonMode, flushSuccess, emitFailure } from './output.js';
|
|
9
|
+
import { commandTree } from './help-json.js';
|
|
7
10
|
/** Read the version from package.json — dist/ sits one level below the manifest. */
|
|
8
11
|
function readVersion() {
|
|
9
12
|
try {
|
|
@@ -22,43 +25,105 @@ import { registerPendingCommands } from './commands/pending.js';
|
|
|
22
25
|
import { registerGovernanceCommands } from './commands/governance.js';
|
|
23
26
|
import { registerPortfolioCommands } from './commands/portfolio.js';
|
|
24
27
|
import { registerAdminCommands } from './commands/admin.js';
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
program
|
|
42
|
-
program
|
|
43
|
-
|
|
28
|
+
import { registerBillingCommands } from './commands/billing.js';
|
|
29
|
+
const VERSION = readVersion();
|
|
30
|
+
export function buildProgram() {
|
|
31
|
+
const program = new Command();
|
|
32
|
+
program
|
|
33
|
+
.name('certen')
|
|
34
|
+
.description('CERTEN Gateway CLI')
|
|
35
|
+
// Was hardcoded to 0.1.0 while package.json said 0.2.0, so `certen --version` reported a
|
|
36
|
+
// release that does not exist. Read it from the manifest so the two cannot drift again.
|
|
37
|
+
.version(VERSION)
|
|
38
|
+
// Declared so it appears in --help. It is stripped from argv before parsing (see run()), because
|
|
39
|
+
// a global flag that may appear after a subcommand is not something commander models.
|
|
40
|
+
.option('--json', 'Emit one JSON envelope on stdout; human output goes to stderr');
|
|
41
|
+
registerAuthCommands(program);
|
|
42
|
+
registerKeysCommands(program);
|
|
43
|
+
registerIdentityCommands(program);
|
|
44
|
+
registerTransactionCommands(program);
|
|
45
|
+
registerPendingCommands(program);
|
|
46
|
+
registerGovernanceCommands(program);
|
|
47
|
+
registerPortfolioCommands(program);
|
|
48
|
+
registerBillingCommands(program);
|
|
49
|
+
registerAdminCommands(program);
|
|
50
|
+
// Every command, not just the root. `exitOverride()` is NOT inherited by subcommands, so without
|
|
51
|
+
// this walk a missing required flag on `identity create` called process.exit(1) inside commander:
|
|
52
|
+
// stdout stayed empty, no envelope was ever emitted, and a usage error was indistinguishable from
|
|
53
|
+
// a failed request. Every nested command has to opt in explicitly.
|
|
54
|
+
applyExitOverride(program);
|
|
55
|
+
return program;
|
|
56
|
+
}
|
|
57
|
+
function applyExitOverride(cmd) {
|
|
58
|
+
cmd.exitOverride();
|
|
59
|
+
for (const sub of cmd.commands)
|
|
60
|
+
applyExitOverride(sub);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Map a thrown value to an exit code, and emit the matching envelope.
|
|
64
|
+
*
|
|
65
|
+
* The four codes exist so an automated caller never has to parse English to decide what to do:
|
|
66
|
+
* `2` means fix the invocation, `3` means the gateway was unreachable and nothing was submitted,
|
|
67
|
+
* `1` means the gateway answered and said no.
|
|
68
|
+
*/
|
|
69
|
+
function handleError(err) {
|
|
70
|
+
if (err instanceof CommanderError) {
|
|
71
|
+
// --help and --version are successful terminations that commander reports by throwing.
|
|
72
|
+
if (err.exitCode === 0 || err.code === 'commander.helpDisplayed' || err.code === 'commander.version') {
|
|
73
|
+
return EXIT.OK;
|
|
74
|
+
}
|
|
75
|
+
return emitFailure({
|
|
76
|
+
message: err.message.replace(/^error: /, ''),
|
|
77
|
+
code: 'USAGE_ERROR',
|
|
78
|
+
exitCode: EXIT.USAGE,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (err instanceof CertenError) {
|
|
82
|
+
// Pass the ERROR, not a copy of its fields.
|
|
83
|
+
//
|
|
84
|
+
// This used to flatten it into an object literal. The literal carried the same
|
|
85
|
+
// values but destroyed the class identity, so a 402 reached the reporter as an
|
|
86
|
+
// anonymous shape and its payment target was silently dropped — the refusal
|
|
87
|
+
// printed a code and a message while the fix sat unread on the error.
|
|
88
|
+
//
|
|
89
|
+
// Nothing is lost by passing the instance: message, code, status and requestId
|
|
90
|
+
// are all readable on it, and `isRetryable` is a getter, so the SDK's own retry
|
|
91
|
+
// judgement still reaches both transports.
|
|
92
|
+
return emitFailure(err);
|
|
93
|
+
}
|
|
94
|
+
return emitFailure(err);
|
|
95
|
+
}
|
|
96
|
+
export async function run(argv) {
|
|
97
|
+
// `--json` is resolved before parsing so it applies to every code path, including failures that
|
|
98
|
+
// happen while resolving credentials — those must be reportable in the envelope too.
|
|
99
|
+
const json = argv.includes('--json');
|
|
100
|
+
setJsonMode(json);
|
|
101
|
+
const cleanArgv = argv.filter((a) => a !== '--json');
|
|
102
|
+
const program = buildProgram();
|
|
103
|
+
// `certen --help --json` answers "what can this CLI do" in one call, instead of scraping help
|
|
104
|
+
// text once per subcommand.
|
|
105
|
+
if (json && (cleanArgv.includes('--help') || cleanArgv.includes('-h'))) {
|
|
106
|
+
process.stdout.write(`${commandTree(program, VERSION)}\n`);
|
|
107
|
+
return EXIT.OK;
|
|
108
|
+
}
|
|
44
109
|
try {
|
|
45
|
-
await program.parseAsync(
|
|
110
|
+
await program.parseAsync(cleanArgv);
|
|
111
|
+
flushSuccess();
|
|
112
|
+
return EXIT.OK;
|
|
46
113
|
}
|
|
47
114
|
catch (err) {
|
|
48
|
-
|
|
49
|
-
console.error(`Error [${err.code}]: ${err.message}`);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
if (err instanceof Error) {
|
|
53
|
-
// Commander exit override throws for --help etc
|
|
54
|
-
if (err.exitCode === 0)
|
|
55
|
-
return;
|
|
56
|
-
console.error(`Error: ${err.message}`);
|
|
57
|
-
process.exit(1);
|
|
58
|
-
}
|
|
59
|
-
console.error('Unknown error:', err);
|
|
60
|
-
process.exit(1);
|
|
115
|
+
return handleError(err);
|
|
61
116
|
}
|
|
62
117
|
}
|
|
63
|
-
|
|
118
|
+
/* c8 ignore start — entrypoint wiring, exercised by the conformance suite as a subprocess */
|
|
119
|
+
// Run only when executed as the binary, not when imported by a test. `pathToFileURL` is what makes
|
|
120
|
+
// this correct on Windows, where a naive `file://` + path concatenation produces a URL that never
|
|
121
|
+
// matches `import.meta.url`.
|
|
122
|
+
const invokedDirectly = Boolean(process.argv[1]) && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
123
|
+
if (invokedDirectly) {
|
|
124
|
+
run(process.argv).then((code) => {
|
|
125
|
+
process.exitCode = code;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/* c8 ignore stop */
|
|
64
129
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/output.d.ts
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
|
+
import { type ExitCode } from './errors.js';
|
|
2
|
+
export declare function setJsonMode(on: boolean): void;
|
|
3
|
+
export declare function isJsonMode(): boolean;
|
|
4
|
+
/** Test seam: reset module state between cases. */
|
|
5
|
+
export declare function resetOutput(): void;
|
|
1
6
|
/**
|
|
2
|
-
* Print
|
|
7
|
+
* Print a result. In JSON mode this buffers; call `flushSuccess()` once the command completes.
|
|
3
8
|
*/
|
|
4
9
|
export declare function printOutput(data: Record<string, unknown>[] | Record<string, unknown>, opts?: {
|
|
5
10
|
forceJson?: boolean;
|
|
6
11
|
}): void;
|
|
12
|
+
/**
|
|
13
|
+
* A human-facing note — "API key saved", "(no keys)".
|
|
14
|
+
*
|
|
15
|
+
* In JSON mode this goes to stderr, because stdout is reserved for the single envelope. In table
|
|
16
|
+
* mode it is ordinary output and goes to stdout.
|
|
17
|
+
*/
|
|
18
|
+
export declare function human(message: string): void;
|
|
19
|
+
/** A hint or warning. Always stderr — it is never the result of the command. */
|
|
20
|
+
export declare function hint(message: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Emit the success envelope. No-op outside JSON mode, and safe to call more than once.
|
|
23
|
+
*
|
|
24
|
+
* A command that produced no payload still emits `{"ok":true,"data":null}` rather than nothing, so
|
|
25
|
+
* a caller can always parse stdout instead of special-casing empty output.
|
|
26
|
+
*/
|
|
27
|
+
export declare function flushSuccess(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Emit the failure envelope (JSON mode) or a human error line (table mode), and return the exit code.
|
|
30
|
+
*
|
|
31
|
+
* `retryable` is taken from the SDK's own `CertenError.isRetryable` wherever the error came from the
|
|
32
|
+
* gateway, so the CLI and the SDK hand an automated caller the identical retry decision. That
|
|
33
|
+
* equivalence is the property worth having: a script can switch transports without re-deriving which
|
|
34
|
+
* failures are worth another attempt.
|
|
35
|
+
*/
|
|
36
|
+
export declare function emitFailure(err: unknown): ExitCode;
|
package/dist/output.js
CHANGED
|
@@ -1,13 +1,162 @@
|
|
|
1
|
+
import { CertenPaymentRequiredError } from '@certen.io/sdk';
|
|
1
2
|
import { getOutputFormat } from './config.js';
|
|
3
|
+
import { CliError, EXIT } from './errors.js';
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
5
|
+
* Two output modes with different audiences and different guarantees.
|
|
6
|
+
*
|
|
7
|
+
* Table mode is for humans and is NOT a contract — column widths and wording may change.
|
|
8
|
+
*
|
|
9
|
+
* JSON mode is a machine contract: exactly one envelope object on stdout and nothing else, every
|
|
10
|
+
* human-facing line on stderr, and an exit code that says which kind of failure occurred. See
|
|
11
|
+
* docs/CLI-CONTRACT.md. The single-object guarantee is why payloads are buffered rather than
|
|
12
|
+
* printed as they arrive: a command that prints twice would otherwise emit two top-level objects
|
|
13
|
+
* and break every streaming JSON parser pointed at it.
|
|
14
|
+
*/
|
|
15
|
+
let jsonMode = false;
|
|
16
|
+
/** Payloads collected in JSON mode, flushed as one envelope when the command finishes. */
|
|
17
|
+
let collected = [];
|
|
18
|
+
let flushed = false;
|
|
19
|
+
export function setJsonMode(on) {
|
|
20
|
+
jsonMode = on;
|
|
21
|
+
}
|
|
22
|
+
export function isJsonMode() {
|
|
23
|
+
return jsonMode;
|
|
24
|
+
}
|
|
25
|
+
/** Test seam: reset module state between cases. */
|
|
26
|
+
export function resetOutput() {
|
|
27
|
+
jsonMode = false;
|
|
28
|
+
collected = [];
|
|
29
|
+
flushed = false;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Print a result. In JSON mode this buffers; call `flushSuccess()` once the command completes.
|
|
4
33
|
*/
|
|
5
34
|
export function printOutput(data, opts) {
|
|
35
|
+
if (jsonMode) {
|
|
36
|
+
collected.push(data);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
6
39
|
const format = opts?.forceJson ? 'json' : getOutputFormat();
|
|
7
40
|
if (format === 'json') {
|
|
8
41
|
console.log(JSON.stringify(data, null, 2));
|
|
9
42
|
return;
|
|
10
43
|
}
|
|
44
|
+
printTable(data);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A human-facing note — "API key saved", "(no keys)".
|
|
48
|
+
*
|
|
49
|
+
* In JSON mode this goes to stderr, because stdout is reserved for the single envelope. In table
|
|
50
|
+
* mode it is ordinary output and goes to stdout.
|
|
51
|
+
*/
|
|
52
|
+
export function human(message) {
|
|
53
|
+
if (jsonMode)
|
|
54
|
+
console.error(message);
|
|
55
|
+
else
|
|
56
|
+
console.log(message);
|
|
57
|
+
}
|
|
58
|
+
/** A hint or warning. Always stderr — it is never the result of the command. */
|
|
59
|
+
export function hint(message) {
|
|
60
|
+
console.error(message);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Emit the success envelope. No-op outside JSON mode, and safe to call more than once.
|
|
64
|
+
*
|
|
65
|
+
* A command that produced no payload still emits `{"ok":true,"data":null}` rather than nothing, so
|
|
66
|
+
* a caller can always parse stdout instead of special-casing empty output.
|
|
67
|
+
*/
|
|
68
|
+
export function flushSuccess() {
|
|
69
|
+
if (!jsonMode || flushed)
|
|
70
|
+
return;
|
|
71
|
+
flushed = true;
|
|
72
|
+
const data = collected.length === 0 ? null : collected.length === 1 ? collected[0] : collected;
|
|
73
|
+
process.stdout.write(`${JSON.stringify({ ok: true, data })}\n`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Emit the failure envelope (JSON mode) or a human error line (table mode), and return the exit code.
|
|
77
|
+
*
|
|
78
|
+
* `retryable` is taken from the SDK's own `CertenError.isRetryable` wherever the error came from the
|
|
79
|
+
* gateway, so the CLI and the SDK hand an automated caller the identical retry decision. That
|
|
80
|
+
* equivalence is the property worth having: a script can switch transports without re-deriving which
|
|
81
|
+
* failures are worth another attempt.
|
|
82
|
+
*/
|
|
83
|
+
export function emitFailure(err) {
|
|
84
|
+
const e = (err ?? {});
|
|
85
|
+
const message = e.message ?? String(err);
|
|
86
|
+
const code = e.code ?? 'UNKNOWN_ERROR';
|
|
87
|
+
const retryable = e instanceof CliError ? e.retryable : Boolean(e.isRetryable);
|
|
88
|
+
const exitCode = resolveExitCode(e);
|
|
89
|
+
// A refusal for lack of funds is the one failure that carries its own fix, so it
|
|
90
|
+
// is rendered rather than reduced to a code and a message. The developer is
|
|
91
|
+
// already in a terminal; the next command belongs there, not in documentation.
|
|
92
|
+
const payment = err instanceof CertenPaymentRequiredError ? err : null;
|
|
93
|
+
if (jsonMode) {
|
|
94
|
+
flushed = true;
|
|
95
|
+
process.stdout.write(`${JSON.stringify({
|
|
96
|
+
ok: false,
|
|
97
|
+
error: {
|
|
98
|
+
code,
|
|
99
|
+
message,
|
|
100
|
+
retryable,
|
|
101
|
+
...(e.status !== undefined ? { status: e.status } : {}),
|
|
102
|
+
...(e.requestId ? { requestId: e.requestId } : {}),
|
|
103
|
+
// Additive: a consumer that ignores unknown keys is unaffected, and one
|
|
104
|
+
// that wants to settle automatically no longer has to parse prose.
|
|
105
|
+
...(payment
|
|
106
|
+
? {
|
|
107
|
+
shortfall_usd: payment.shortfallUsd,
|
|
108
|
+
quote_id: payment.quoteId,
|
|
109
|
+
resolve: payment.resolution,
|
|
110
|
+
}
|
|
111
|
+
: {}),
|
|
112
|
+
},
|
|
113
|
+
})}\n`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
console.error(code === 'UNKNOWN_ERROR' ? `Error: ${message}` : `Error [${code}]: ${message}`);
|
|
117
|
+
if (payment)
|
|
118
|
+
emitPaymentFix(payment);
|
|
119
|
+
}
|
|
120
|
+
return exitCode;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Print the way out of a 402.
|
|
124
|
+
*
|
|
125
|
+
* All on stderr: it is guidance, not the result of the command, and a caller
|
|
126
|
+
* piping stdout must still get clean output (or, in JSON mode, exactly one
|
|
127
|
+
* envelope). The closing line matters as much as the address — a developer whose
|
|
128
|
+
* request was refused needs to know nothing was charged and nothing started.
|
|
129
|
+
*/
|
|
130
|
+
function emitPaymentFix(payment) {
|
|
131
|
+
console.error('');
|
|
132
|
+
console.error(` ${payment.summary}`);
|
|
133
|
+
const r = payment.resolution;
|
|
134
|
+
if (r) {
|
|
135
|
+
console.error('');
|
|
136
|
+
console.error(` Send exactly ${r.amount_usd} USD on ${r.chain} to:`);
|
|
137
|
+
console.error(` ${r.to_address}`);
|
|
138
|
+
console.error(` Reference ${r.payment_intent}`);
|
|
139
|
+
console.error('');
|
|
140
|
+
console.error(` Or run: ${r.cli_command}`);
|
|
141
|
+
console.error(` Portal: ${r.portal_url}`);
|
|
142
|
+
}
|
|
143
|
+
if (payment.quoteId) {
|
|
144
|
+
console.error('');
|
|
145
|
+
console.error(` Then retry with --quote-id ${payment.quoteId} to keep this price.`);
|
|
146
|
+
}
|
|
147
|
+
console.error('');
|
|
148
|
+
console.error(' Nothing was charged and no work was started.');
|
|
149
|
+
}
|
|
150
|
+
function resolveExitCode(e) {
|
|
151
|
+
if (typeof e.exitCode === 'number')
|
|
152
|
+
return e.exitCode;
|
|
153
|
+
// status 0 is how the SDK reports "the request never reached the gateway".
|
|
154
|
+
if (e.code === 'NETWORK_ERROR' || e.status === 0)
|
|
155
|
+
return EXIT.UNREACHABLE;
|
|
156
|
+
return EXIT.FAILED;
|
|
157
|
+
}
|
|
158
|
+
// ── table rendering (human mode only) ───────────────────────────────────────────────────────────
|
|
159
|
+
function printTable(data) {
|
|
11
160
|
// Single object: print key-value pairs
|
|
12
161
|
if (!Array.isArray(data)) {
|
|
13
162
|
const entries = Object.entries(data);
|
package/dist/output.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,56 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@certen.io/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Command line for the CERTEN Gateway API",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"certen",
|
|
9
|
-
"accumulate",
|
|
10
|
-
"cli",
|
|
11
|
-
"blockchain"
|
|
12
|
-
],
|
|
13
|
-
"homepage": "https://github.com/certenIO/certen-sdk#readme",
|
|
14
|
-
"repository": {
|
|
15
|
-
"type": "git",
|
|
16
|
-
"url": "git+https://github.com/certenIO/certen-sdk.git",
|
|
17
|
-
"directory": "packages/cli"
|
|
18
|
-
},
|
|
19
|
-
"bugs": {
|
|
20
|
-
"url": "https://github.com/certenIO/certen-sdk/issues"
|
|
21
|
-
},
|
|
22
|
-
"engines": {
|
|
23
|
-
"node": ">=18"
|
|
24
|
-
},
|
|
25
|
-
"bin": {
|
|
26
|
-
"certen": "dist/index.js"
|
|
27
|
-
},
|
|
28
|
-
"//files": "Build output plus docs. Without this npm ships the whole directory, including src/ and test/.",
|
|
29
|
-
"files": [
|
|
30
|
-
"dist/",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"prepack": "
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"dependencies":
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@certen.io/cli",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Command line for the CERTEN Gateway API",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"certen",
|
|
9
|
+
"accumulate",
|
|
10
|
+
"cli",
|
|
11
|
+
"blockchain"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/certenIO/certen-sdk#readme",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/certenIO/certen-sdk.git",
|
|
17
|
+
"directory": "packages/cli"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/certenIO/certen-sdk/issues"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"certen": "dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"//files": "Build output plus docs. Without this npm ships the whole directory, including src/ and test/.",
|
|
29
|
+
"files": [
|
|
30
|
+
"dist/",
|
|
31
|
+
"CHANGELOG.md",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"//prepack": "Build before packing so the published bin can never point at a missing dist/index.js.",
|
|
40
|
+
"prepack": "npm run build",
|
|
41
|
+
"prepublishOnly": "npm run build && npm test"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"//dependencies": "@certen.io/sdk MUST be a version range, not file:../sdk. A published package carrying a file: dependency installs and then fails to resolve on the consumer's machine, because that path does not exist there. Local development uses `npm link` or a workspace instead.",
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@certen.io/sdk": "^0.5.0",
|
|
49
|
+
"commander": "^12.0.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"typescript": "^5.5.0",
|
|
53
|
+
"vitest": "^1.6.1",
|
|
54
|
+
"@types/node": "^22.0.0"
|
|
55
|
+
},
|
|
56
|
+
"//publishConfig": "Provenance is passed as --provenance by .github/workflows/release.yml. Setting it here instead would break every publish outside CI with an error that does not explain itself."
|
|
57
|
+
}
|