@certen.io/cli 0.3.0 → 0.4.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 +55 -0
- package/README.md +160 -132
- package/dist/commands/auth.js +3 -3
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/keys.js +3 -3
- package/dist/commands/keys.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 +96 -36
- package/dist/index.js.map +1 -1
- package/dist/output.d.ts +31 -1
- package/dist/output.js +106 -1
- package/dist/output.js.map +1 -1
- package/package.json +57 -56
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Changelog — @certen.io/cli
|
|
2
|
+
|
|
3
|
+
## 0.4.0 — `--json` is a machine contract
|
|
4
|
+
|
|
5
|
+
Adds a stable, tested output contract for scripts and AI agents. **Human output is unchanged**: if
|
|
6
|
+
you do not pass `--json`, this release behaves exactly as 0.3.1 did, with one exception noted under
|
|
7
|
+
Breaking.
|
|
8
|
+
|
|
9
|
+
Before this, every failure exited `1` and explained itself in English on stderr. An automated caller
|
|
10
|
+
could not distinguish "you passed a malformed address" from "the gateway is down" without parsing
|
|
11
|
+
prose — and those want opposite responses. One is a bug to fix; the other is worth retrying. For a
|
|
12
|
+
CLI that authorizes cross-chain execution against real funds, guessing wrong is expensive in a way
|
|
13
|
+
that is not recoverable.
|
|
14
|
+
|
|
15
|
+
The full specification is [docs/CLI-CONTRACT.md](../../docs/CLI-CONTRACT.md), enforced by
|
|
16
|
+
`test/conformance.test.ts`, which runs the built binary as a subprocess and checks the real process's
|
|
17
|
+
stdout and exit code.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Global `--json`**, accepted anywhere in the argument list — `certen --json tx status X` and
|
|
22
|
+
`certen tx status X --json` are identical. It is resolved before argument parsing, so it applies
|
|
23
|
+
even to failures that occur while resolving credentials.
|
|
24
|
+
- **One JSON envelope on stdout and nothing else.** `{"ok":true,"data":…}` or
|
|
25
|
+
`{"ok":false,"error":{"code","message","retryable","status?","requestId?"}}`. A command producing
|
|
26
|
+
several payloads emits an array in `data`; one producing none emits `"data":null`. stdout is never
|
|
27
|
+
empty and never carries two concatenated objects. All human-facing text moves to stderr.
|
|
28
|
+
- **Meaningful exit codes:** `0` ok · `1` operation failed · `2` usage error · `3` gateway
|
|
29
|
+
unreachable. `3` guarantees nothing was submitted, so a retry cannot double-execute.
|
|
30
|
+
- **`error.retryable`**, taken from the SDK's own `CertenError.isRetryable`, so the CLI and the SDK
|
|
31
|
+
hand an automated caller the identical retry decision.
|
|
32
|
+
- **`certen --help --json`** returns the entire command tree — every command, argument, flag and exit
|
|
33
|
+
code — in one call, instead of scraping help text once per subcommand.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- **Usage errors on subcommands bypassed error handling entirely.** `exitOverride()` is not inherited
|
|
38
|
+
by commander subcommands, so a missing required flag (`certen identity create` with no `--name`)
|
|
39
|
+
called `process.exit(1)` inside commander: no envelope was emitted, stdout stayed empty, and a
|
|
40
|
+
usage error was indistinguishable from a failed request. It is now applied to every command in the
|
|
41
|
+
tree.
|
|
42
|
+
|
|
43
|
+
### Breaking
|
|
44
|
+
|
|
45
|
+
- **"No API key configured" now exits `2` instead of `1`.** It is a usage error: nothing was sent,
|
|
46
|
+
and retrying cannot help. The same applies to a config file with unsafe permissions and to a
|
|
47
|
+
missing keyring backend. Scripts treating any non-zero exit as failure are unaffected; scripts
|
|
48
|
+
testing specifically for `-eq 1` need updating.
|
|
49
|
+
|
|
50
|
+
### Note
|
|
51
|
+
|
|
52
|
+
`output: "json"` in `~/.certen/config.json` is **not** this contract. That setting predates the
|
|
53
|
+
envelope and makes commands print their raw payload — no `ok`, no `error`, no exit-code guarantees.
|
|
54
|
+
It is kept for backward compatibility. Automated callers should pass `--json` explicitly rather than
|
|
55
|
+
depend on a machine's local config, which they cannot see.
|
package/README.md
CHANGED
|
@@ -1,132 +1,160 @@
|
|
|
1
|
-
# `@certen.io/cli`
|
|
2
|
-
|
|
3
|
-
The `certen` command line for the [CERTEN Gateway](https://gateway.kompendium.co/reference) —
|
|
4
|
-
proof-gated cross-chain execution on Accumulate.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
certen keys
|
|
40
|
-
certen keys
|
|
41
|
-
certen keys
|
|
42
|
-
certen keys
|
|
43
|
-
certen keys
|
|
44
|
-
certen keys
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
certen tx
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
certen pending
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
certen
|
|
91
|
-
certen
|
|
92
|
-
certen
|
|
93
|
-
certen
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
1
|
+
# `@certen.io/cli`
|
|
2
|
+
|
|
3
|
+
The `certen` command line for the [CERTEN Gateway](https://gateway.kompendium.co/reference) —
|
|
4
|
+
proof-gated cross-chain execution on Accumulate.
|
|
5
|
+
|
|
6
|
+
**Docs: <https://docs.kompendium.co>** · **Get an API key: <https://gateway.kompendium.co/portal>**
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install -g @certen.io/cli
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Five minutes, start to finish
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# 1. A key. Generated here, encrypted here, and it never leaves this machine.
|
|
16
|
+
certen keys generate --name dev
|
|
17
|
+
|
|
18
|
+
# 2. An API key from the portal at https://gateway.kompendium.co/portal
|
|
19
|
+
certen auth login --api-key ck_live_...
|
|
20
|
+
|
|
21
|
+
# 3. An identity that your key controls.
|
|
22
|
+
certen identity create --name my-org --sign-with dev
|
|
23
|
+
|
|
24
|
+
# 4. Watch it provision (~20s). Wait for status=active AND can_sign=true.
|
|
25
|
+
certen identity get <id>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
That is the whole onboarding path. Step 3 is the one worth understanding: `--sign-with` derives
|
|
29
|
+
the `public_key` and `public_key_hash` from your local key, so the ADI's key page is bound to a
|
|
30
|
+
key only you hold.
|
|
31
|
+
|
|
32
|
+
## Your key never leaves this machine
|
|
33
|
+
|
|
34
|
+
`certen keys generate` creates an Ed25519 key, encrypts it with a passphrase (scrypt + AES-256-GCM),
|
|
35
|
+
and writes it to `~/.certen/keys/<name>.json` with `0600` permissions. The CLI sends **signatures**
|
|
36
|
+
to the gateway. It never sends a private key, and there is no code path that could.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
certen keys generate --name dev # prompts for a passphrase (confirmed)
|
|
40
|
+
certen keys generate --name ci --no-passphrase # unencrypted; file permissions only
|
|
41
|
+
certen keys list # metadata only — never decrypts
|
|
42
|
+
certen keys show dev
|
|
43
|
+
certen keys verify dev # proves the key decrypts and signs correctly
|
|
44
|
+
certen keys sign --name dev --hash <hex> # print a signature, send nothing
|
|
45
|
+
certen keys delete dev --yes
|
|
46
|
+
certen keys path
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Set `CERTEN_KEY_PASSPHRASE` to skip the prompt in CI. When it is set and there is no TTY, the CLI
|
|
50
|
+
uses it; when neither is available it fails with an explanation rather than hanging on a prompt
|
|
51
|
+
nobody can see.
|
|
52
|
+
|
|
53
|
+
**`certen keys sign` sends nothing anywhere.** It is the air-gapped path: generate on one machine,
|
|
54
|
+
carry the hash to it, carry the signature back.
|
|
55
|
+
|
|
56
|
+
## Signing a transaction
|
|
57
|
+
|
|
58
|
+
The one-step form opens the intent, signs the returned hash, and submits the signature:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
certen tx create --identity <uuid> --to-chain ethereum-sepolia \
|
|
62
|
+
--to 0xRecipient --amount 1000000000000000 --sign-with dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or drive the steps yourself — useful when the signer is an HSM, another machine, or your own
|
|
66
|
+
policy engine:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
certen tx create --identity <uuid> ... # returns signing_data.hash_to_sign
|
|
70
|
+
certen keys sign --name dev --hash <hash> # or your HSM
|
|
71
|
+
certen tx sign <intent-id> --signature <sig> --public-key <pub>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`--signature`/`--public-key` remain first-class. `--sign-with` is a convenience, not a replacement.
|
|
75
|
+
|
|
76
|
+
## Multi-party approvals
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
certen pending list
|
|
80
|
+
certen pending sign <id> --identity <adi> --vote approve
|
|
81
|
+
certen pending submit <request-id> --sign-with dev --hash <hash>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`--vote` takes `approve`, `reject`, or `abstain` — lowercase strings. Not `accept`, and not a
|
|
85
|
+
number.
|
|
86
|
+
|
|
87
|
+
## Everything else
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
certen identity get <id> | link-chain <id> --chain <chain>
|
|
91
|
+
certen portfolio # balances across every identity and chain
|
|
92
|
+
certen tx status <id> | list
|
|
93
|
+
certen governance add-delegate | set-threshold
|
|
94
|
+
certen admin api-keys list | create | rotate | revoke
|
|
95
|
+
certen admin audit-log | usage
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Run `certen <group> --help` for the flags on any of them.
|
|
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
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
| | |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `CERTEN_API_KEY` | API key. Always wins, so CI never touches the keyring or config file. |
|
|
129
|
+
| `CERTEN_API_URL` | Gateway base URL. Defaults to `https://gateway.kompendium.co`. |
|
|
130
|
+
| `CERTEN_KEY_PASSPHRASE` | Passphrase for local signing keys. |
|
|
131
|
+
|
|
132
|
+
`certen auth login` stores the API key in your OS keyring by default, or in
|
|
133
|
+
`~/.certen/config.json` at `0600` with `--no-keyring`.
|
|
134
|
+
|
|
135
|
+
## Things that will bite you
|
|
136
|
+
|
|
137
|
+
**Identity creation is asynchronous.** `identity create` returns `202` and provisioning continues.
|
|
138
|
+
Poll until the status is terminal, and check `can_sign` — it derives from the on-chain key page, so
|
|
139
|
+
it can read `true` while the status is still `creating`.
|
|
140
|
+
|
|
141
|
+
**A proof cycle takes 60–110 seconds.** Real validator work, not a tunable delay. Do not wrap it in
|
|
142
|
+
a 30-second timeout.
|
|
143
|
+
|
|
144
|
+
**Sign the bytes, not the text.** If you are producing signatures outside this CLI: sign the raw
|
|
145
|
+
bytes of the hash, do not hash it again, and do not sign the ASCII of the hex string. All three
|
|
146
|
+
mistakes produce a well-formed 128-hex signature the gateway rejects. `certen keys sign` handles
|
|
147
|
+
this for you.
|
|
148
|
+
|
|
149
|
+
## Documentation
|
|
150
|
+
|
|
151
|
+
**<https://docs.kompendium.co>** — getting started, authentication, errors, idempotency, and
|
|
152
|
+
task-shaped guides: onboarding an identity, external signing, proof-gating a contract call, M-of-N
|
|
153
|
+
panels, and verifying a proof.
|
|
154
|
+
|
|
155
|
+
The [live API reference](https://gateway.kompendium.co/reference) is generated from the running
|
|
156
|
+
gateway and is authoritative — when a guide and the spec disagree, the spec is right.
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT
|
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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"}
|
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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"}
|
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,100 @@ 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
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
program
|
|
42
|
-
program
|
|
43
|
-
|
|
28
|
+
const VERSION = readVersion();
|
|
29
|
+
export function buildProgram() {
|
|
30
|
+
const program = new Command();
|
|
31
|
+
program
|
|
32
|
+
.name('certen')
|
|
33
|
+
.description('CERTEN Gateway CLI')
|
|
34
|
+
// Was hardcoded to 0.1.0 while package.json said 0.2.0, so `certen --version` reported a
|
|
35
|
+
// release that does not exist. Read it from the manifest so the two cannot drift again.
|
|
36
|
+
.version(VERSION)
|
|
37
|
+
// Declared so it appears in --help. It is stripped from argv before parsing (see run()), because
|
|
38
|
+
// a global flag that may appear after a subcommand is not something commander models.
|
|
39
|
+
.option('--json', 'Emit one JSON envelope on stdout; human output goes to stderr');
|
|
40
|
+
registerAuthCommands(program);
|
|
41
|
+
registerKeysCommands(program);
|
|
42
|
+
registerIdentityCommands(program);
|
|
43
|
+
registerTransactionCommands(program);
|
|
44
|
+
registerPendingCommands(program);
|
|
45
|
+
registerGovernanceCommands(program);
|
|
46
|
+
registerPortfolioCommands(program);
|
|
47
|
+
registerAdminCommands(program);
|
|
48
|
+
// Every command, not just the root. `exitOverride()` is NOT inherited by subcommands, so without
|
|
49
|
+
// this walk a missing required flag on `identity create` called process.exit(1) inside commander:
|
|
50
|
+
// stdout stayed empty, no envelope was ever emitted, and a usage error was indistinguishable from
|
|
51
|
+
// a failed request. Every nested command has to opt in explicitly.
|
|
52
|
+
applyExitOverride(program);
|
|
53
|
+
return program;
|
|
54
|
+
}
|
|
55
|
+
function applyExitOverride(cmd) {
|
|
56
|
+
cmd.exitOverride();
|
|
57
|
+
for (const sub of cmd.commands)
|
|
58
|
+
applyExitOverride(sub);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Map a thrown value to an exit code, and emit the matching envelope.
|
|
62
|
+
*
|
|
63
|
+
* The four codes exist so an automated caller never has to parse English to decide what to do:
|
|
64
|
+
* `2` means fix the invocation, `3` means the gateway was unreachable and nothing was submitted,
|
|
65
|
+
* `1` means the gateway answered and said no.
|
|
66
|
+
*/
|
|
67
|
+
function handleError(err) {
|
|
68
|
+
if (err instanceof CommanderError) {
|
|
69
|
+
// --help and --version are successful terminations that commander reports by throwing.
|
|
70
|
+
if (err.exitCode === 0 || err.code === 'commander.helpDisplayed' || err.code === 'commander.version') {
|
|
71
|
+
return EXIT.OK;
|
|
72
|
+
}
|
|
73
|
+
return emitFailure({
|
|
74
|
+
message: err.message.replace(/^error: /, ''),
|
|
75
|
+
code: 'USAGE_ERROR',
|
|
76
|
+
exitCode: EXIT.USAGE,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (err instanceof CertenError) {
|
|
80
|
+
// isRetryable is the SDK's own judgement — reuse it so both transports agree.
|
|
81
|
+
return emitFailure({
|
|
82
|
+
message: err.message,
|
|
83
|
+
code: err.code,
|
|
84
|
+
status: err.status,
|
|
85
|
+
requestId: err.requestId,
|
|
86
|
+
isRetryable: err.isRetryable,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return emitFailure(err);
|
|
90
|
+
}
|
|
91
|
+
export async function run(argv) {
|
|
92
|
+
// `--json` is resolved before parsing so it applies to every code path, including failures that
|
|
93
|
+
// happen while resolving credentials — those must be reportable in the envelope too.
|
|
94
|
+
const json = argv.includes('--json');
|
|
95
|
+
setJsonMode(json);
|
|
96
|
+
const cleanArgv = argv.filter((a) => a !== '--json');
|
|
97
|
+
const program = buildProgram();
|
|
98
|
+
// `certen --help --json` answers "what can this CLI do" in one call, instead of scraping help
|
|
99
|
+
// text once per subcommand.
|
|
100
|
+
if (json && (cleanArgv.includes('--help') || cleanArgv.includes('-h'))) {
|
|
101
|
+
process.stdout.write(`${commandTree(program, VERSION)}\n`);
|
|
102
|
+
return EXIT.OK;
|
|
103
|
+
}
|
|
44
104
|
try {
|
|
45
|
-
await program.parseAsync(
|
|
105
|
+
await program.parseAsync(cleanArgv);
|
|
106
|
+
flushSuccess();
|
|
107
|
+
return EXIT.OK;
|
|
46
108
|
}
|
|
47
109
|
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);
|
|
110
|
+
return handleError(err);
|
|
61
111
|
}
|
|
62
112
|
}
|
|
63
|
-
|
|
113
|
+
/* c8 ignore start — entrypoint wiring, exercised by the conformance suite as a subprocess */
|
|
114
|
+
// Run only when executed as the binary, not when imported by a test. `pathToFileURL` is what makes
|
|
115
|
+
// this correct on Windows, where a naive `file://` + path concatenation produces a URL that never
|
|
116
|
+
// matches `import.meta.url`.
|
|
117
|
+
const invokedDirectly = Boolean(process.argv[1]) && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
118
|
+
if (invokedDirectly) {
|
|
119
|
+
run(process.argv).then((code) => {
|
|
120
|
+
process.exitCode = code;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/* c8 ignore stop */
|
|
64
124
|
//# 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,118 @@
|
|
|
1
1
|
import { getOutputFormat } from './config.js';
|
|
2
|
+
import { CliError, EXIT } from './errors.js';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* Two output modes with different audiences and different guarantees.
|
|
5
|
+
*
|
|
6
|
+
* Table mode is for humans and is NOT a contract — column widths and wording may change.
|
|
7
|
+
*
|
|
8
|
+
* JSON mode is a machine contract: exactly one envelope object on stdout and nothing else, every
|
|
9
|
+
* human-facing line on stderr, and an exit code that says which kind of failure occurred. See
|
|
10
|
+
* docs/CLI-CONTRACT.md. The single-object guarantee is why payloads are buffered rather than
|
|
11
|
+
* printed as they arrive: a command that prints twice would otherwise emit two top-level objects
|
|
12
|
+
* and break every streaming JSON parser pointed at it.
|
|
13
|
+
*/
|
|
14
|
+
let jsonMode = false;
|
|
15
|
+
/** Payloads collected in JSON mode, flushed as one envelope when the command finishes. */
|
|
16
|
+
let collected = [];
|
|
17
|
+
let flushed = false;
|
|
18
|
+
export function setJsonMode(on) {
|
|
19
|
+
jsonMode = on;
|
|
20
|
+
}
|
|
21
|
+
export function isJsonMode() {
|
|
22
|
+
return jsonMode;
|
|
23
|
+
}
|
|
24
|
+
/** Test seam: reset module state between cases. */
|
|
25
|
+
export function resetOutput() {
|
|
26
|
+
jsonMode = false;
|
|
27
|
+
collected = [];
|
|
28
|
+
flushed = false;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Print a result. In JSON mode this buffers; call `flushSuccess()` once the command completes.
|
|
4
32
|
*/
|
|
5
33
|
export function printOutput(data, opts) {
|
|
34
|
+
if (jsonMode) {
|
|
35
|
+
collected.push(data);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
6
38
|
const format = opts?.forceJson ? 'json' : getOutputFormat();
|
|
7
39
|
if (format === 'json') {
|
|
8
40
|
console.log(JSON.stringify(data, null, 2));
|
|
9
41
|
return;
|
|
10
42
|
}
|
|
43
|
+
printTable(data);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A human-facing note — "API key saved", "(no keys)".
|
|
47
|
+
*
|
|
48
|
+
* In JSON mode this goes to stderr, because stdout is reserved for the single envelope. In table
|
|
49
|
+
* mode it is ordinary output and goes to stdout.
|
|
50
|
+
*/
|
|
51
|
+
export function human(message) {
|
|
52
|
+
if (jsonMode)
|
|
53
|
+
console.error(message);
|
|
54
|
+
else
|
|
55
|
+
console.log(message);
|
|
56
|
+
}
|
|
57
|
+
/** A hint or warning. Always stderr — it is never the result of the command. */
|
|
58
|
+
export function hint(message) {
|
|
59
|
+
console.error(message);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Emit the success envelope. No-op outside JSON mode, and safe to call more than once.
|
|
63
|
+
*
|
|
64
|
+
* A command that produced no payload still emits `{"ok":true,"data":null}` rather than nothing, so
|
|
65
|
+
* a caller can always parse stdout instead of special-casing empty output.
|
|
66
|
+
*/
|
|
67
|
+
export function flushSuccess() {
|
|
68
|
+
if (!jsonMode || flushed)
|
|
69
|
+
return;
|
|
70
|
+
flushed = true;
|
|
71
|
+
const data = collected.length === 0 ? null : collected.length === 1 ? collected[0] : collected;
|
|
72
|
+
process.stdout.write(`${JSON.stringify({ ok: true, data })}\n`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Emit the failure envelope (JSON mode) or a human error line (table mode), and return the exit code.
|
|
76
|
+
*
|
|
77
|
+
* `retryable` is taken from the SDK's own `CertenError.isRetryable` wherever the error came from the
|
|
78
|
+
* gateway, so the CLI and the SDK hand an automated caller the identical retry decision. That
|
|
79
|
+
* equivalence is the property worth having: a script can switch transports without re-deriving which
|
|
80
|
+
* failures are worth another attempt.
|
|
81
|
+
*/
|
|
82
|
+
export function emitFailure(err) {
|
|
83
|
+
const e = (err ?? {});
|
|
84
|
+
const message = e.message ?? String(err);
|
|
85
|
+
const code = e.code ?? 'UNKNOWN_ERROR';
|
|
86
|
+
const retryable = e instanceof CliError ? e.retryable : Boolean(e.isRetryable);
|
|
87
|
+
const exitCode = resolveExitCode(e);
|
|
88
|
+
if (jsonMode) {
|
|
89
|
+
flushed = true;
|
|
90
|
+
process.stdout.write(`${JSON.stringify({
|
|
91
|
+
ok: false,
|
|
92
|
+
error: {
|
|
93
|
+
code,
|
|
94
|
+
message,
|
|
95
|
+
retryable,
|
|
96
|
+
...(e.status !== undefined ? { status: e.status } : {}),
|
|
97
|
+
...(e.requestId ? { requestId: e.requestId } : {}),
|
|
98
|
+
},
|
|
99
|
+
})}\n`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.error(code === 'UNKNOWN_ERROR' ? `Error: ${message}` : `Error [${code}]: ${message}`);
|
|
103
|
+
}
|
|
104
|
+
return exitCode;
|
|
105
|
+
}
|
|
106
|
+
function resolveExitCode(e) {
|
|
107
|
+
if (typeof e.exitCode === 'number')
|
|
108
|
+
return e.exitCode;
|
|
109
|
+
// status 0 is how the SDK reports "the request never reached the gateway".
|
|
110
|
+
if (e.code === 'NETWORK_ERROR' || e.status === 0)
|
|
111
|
+
return EXIT.UNREACHABLE;
|
|
112
|
+
return EXIT.FAILED;
|
|
113
|
+
}
|
|
114
|
+
// ── table rendering (human mode only) ───────────────────────────────────────────────────────────
|
|
115
|
+
function printTable(data) {
|
|
11
116
|
// Single object: print key-value pairs
|
|
12
117
|
if (!Array.isArray(data)) {
|
|
13
118
|
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.4.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.4.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
|
+
}
|