@certen.io/cli 0.4.0 → 0.7.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 +440 -0
- package/README.md +232 -160
- package/dist/chains.d.ts +67 -0
- package/dist/chains.js +242 -0
- package/dist/chains.js.map +1 -0
- package/dist/commands/admin.js +49 -4
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/auth.js +145 -12
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/billing.d.ts +2 -0
- package/dist/commands/billing.js +782 -0
- package/dist/commands/billing.js.map +1 -0
- package/dist/commands/call.d.ts +2 -0
- package/dist/commands/call.js +168 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/chains.d.ts +2 -0
- package/dist/commands/chains.js +123 -0
- package/dist/commands/chains.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +171 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/errors-catalogue.d.ts +2 -0
- package/dist/commands/errors-catalogue.js +83 -0
- package/dist/commands/errors-catalogue.js.map +1 -0
- package/dist/commands/identity.js +269 -19
- package/dist/commands/identity.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +307 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/keys.js +2 -0
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/oauth-clients.d.ts +2 -0
- package/dist/commands/oauth-clients.js +131 -0
- package/dist/commands/oauth-clients.js.map +1 -0
- package/dist/commands/orgs.d.ts +2 -0
- package/dist/commands/orgs.js +117 -0
- package/dist/commands/orgs.js.map +1 -0
- package/dist/commands/pending.js +13 -1
- package/dist/commands/pending.js.map +1 -1
- package/dist/commands/portfolio.js +34 -1
- package/dist/commands/portfolio.js.map +1 -1
- package/dist/commands/proof.d.ts +2 -0
- package/dist/commands/proof.js +400 -0
- package/dist/commands/proof.js.map +1 -0
- package/dist/commands/signup.d.ts +14 -0
- package/dist/commands/signup.js +271 -0
- package/dist/commands/signup.js.map +1 -0
- package/dist/commands/transaction.js +144 -21
- package/dist/commands/transaction.js.map +1 -1
- package/dist/commands/webhooks.d.ts +2 -0
- package/dist/commands/webhooks.js +200 -0
- package/dist/commands/webhooks.js.map +1 -0
- package/dist/commands/whoami.d.ts +16 -0
- package/dist/commands/whoami.js +98 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config.d.ts +56 -0
- package/dist/config.js +51 -0
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +14 -1
- package/dist/errors.js +15 -1
- package/dist/errors.js.map +1 -1
- package/dist/funding-guard.d.ts +40 -0
- package/dist/funding-guard.js +120 -0
- package/dist/funding-guard.js.map +1 -0
- package/dist/help-root.d.ts +2 -0
- package/dist/help-root.js +94 -0
- package/dist/help-root.js.map +1 -0
- package/dist/index.js +40 -8
- package/dist/index.js.map +1 -1
- package/dist/output.d.ts +23 -0
- package/dist/output.js +90 -0
- package/dist/output.js.map +1 -1
- package/dist/passphrase.d.ts +18 -0
- package/dist/passphrase.js +35 -3
- package/dist/passphrase.js.map +1 -1
- package/dist/payment-uri.d.ts +76 -0
- package/dist/payment-uri.js +135 -0
- package/dist/payment-uri.js.map +1 -0
- package/dist/signer.js +6 -3
- package/dist/signer.js.map +1 -1
- package/dist/solidity-args.d.ts +31 -0
- package/dist/solidity-args.js +111 -0
- package/dist/solidity-args.js.map +1 -0
- package/dist/wait.d.ts +79 -0
- package/dist/wait.js +168 -0
- package/dist/wait.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { CertenClient } from '@certen.io/sdk';
|
|
2
|
+
import { getApiUrl, getOutputFormat } from '../config.js';
|
|
3
|
+
import { printOutput, human, hint, isJsonMode } from '../output.js';
|
|
4
|
+
import { CliError, EXIT } from '../errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* The error vocabulary, read from the gateway you are actually talking to.
|
|
7
|
+
*
|
|
8
|
+
* The catalogue was published in the gateway and then had no client surface for a release — so the
|
|
9
|
+
* codes stayed exactly as discoverable as before, which is to say you found them by provoking them
|
|
10
|
+
* in production. Worse, the SDK ships a vendored copy that is only as current as its release, so a
|
|
11
|
+
* gateway ahead of the SDK raises codes nothing local has heard of.
|
|
12
|
+
*
|
|
13
|
+
* `certen errors <CODE>` is the command that earns this: it is the thing to run when a code shows
|
|
14
|
+
* up in a log and the question is whether to retry, pay, or wake someone.
|
|
15
|
+
*/
|
|
16
|
+
/** No API key: understanding an error should never require holding a credential. */
|
|
17
|
+
function publicClient() {
|
|
18
|
+
return new CertenClient({ apiKey: process.env.CERTEN_API_KEY ?? 'public', baseUrl: getApiUrl() });
|
|
19
|
+
}
|
|
20
|
+
const machineOutput = () => isJsonMode() || getOutputFormat() === 'json';
|
|
21
|
+
function describe(e) {
|
|
22
|
+
human('');
|
|
23
|
+
human(` ${e.code} HTTP ${e.status}`);
|
|
24
|
+
human('');
|
|
25
|
+
human(` ${e.meaning}`);
|
|
26
|
+
human('');
|
|
27
|
+
// These two are the whole decision. `retryable` says whether the same request can ever work;
|
|
28
|
+
// `audience` says whether there is anything on your side to change at all — and being told
|
|
29
|
+
// "nothing you can do" is genuinely useful, because it stops the debugging.
|
|
30
|
+
human(` Retrying this exact request: ${e.retryable ? 'can succeed' : 'will not help'}`);
|
|
31
|
+
if (e.audience === 'platform') {
|
|
32
|
+
human(' Cause: on CERTEN\'s side. Nothing in your request changes this.');
|
|
33
|
+
}
|
|
34
|
+
if (e.action) {
|
|
35
|
+
human('');
|
|
36
|
+
human(` ${e.action}`);
|
|
37
|
+
}
|
|
38
|
+
human('');
|
|
39
|
+
}
|
|
40
|
+
export function registerErrorsCommands(program) {
|
|
41
|
+
program
|
|
42
|
+
.command('errors [code]')
|
|
43
|
+
.description('Every error code this API can return, and what to do about each')
|
|
44
|
+
.option('--retryable', 'Only codes where repeating the request can succeed')
|
|
45
|
+
.action(async (code, opts) => {
|
|
46
|
+
const { errors } = await publicClient().admin.errors();
|
|
47
|
+
if (code) {
|
|
48
|
+
const wanted = code.toUpperCase();
|
|
49
|
+
const found = errors.find((e) => e.code.toUpperCase() === wanted);
|
|
50
|
+
if (!found) {
|
|
51
|
+
// Near-misses beat a bare "not found": the usual reason to be here is a code copied out
|
|
52
|
+
// of a log with a typo, or one this gateway does not raise.
|
|
53
|
+
const near = errors
|
|
54
|
+
.filter((e) => e.code.includes(wanted) || wanted.includes(e.code))
|
|
55
|
+
.map((e) => e.code);
|
|
56
|
+
throw new CliError(`This gateway does not raise "${code}".`
|
|
57
|
+
+ (near.length ? ` Did you mean: ${near.join(', ')}?` : ' See them all: certen errors'), 'UNKNOWN_ERROR_CODE', EXIT.USAGE);
|
|
58
|
+
}
|
|
59
|
+
if (machineOutput()) {
|
|
60
|
+
printOutput({ ...found });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
describe(found);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const shown = opts.retryable ? errors.filter((e) => e.retryable) : errors;
|
|
67
|
+
if (machineOutput()) {
|
|
68
|
+
printOutput({ errors: shown });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const w = Math.max(...shown.map((e) => e.code.length), 4);
|
|
72
|
+
human('');
|
|
73
|
+
for (const e of shown) {
|
|
74
|
+
// `retry` is the one column worth carrying in a list — it is what someone scanning for a
|
|
75
|
+
// code in a log actually wants to know before reading the description.
|
|
76
|
+
human(` ${e.code.padEnd(w)} ${String(e.status).padEnd(3)} ${e.retryable ? 'retry' : ' '} ${e.meaning}`);
|
|
77
|
+
}
|
|
78
|
+
human('');
|
|
79
|
+
human(` ${shown.length} code(s)${opts.retryable ? ' where retrying can succeed' : ''}.`);
|
|
80
|
+
hint('certen errors PLAN_QUOTA_EXCEEDED # what one code means and what to do');
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=errors-catalogue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-catalogue.js","sourceRoot":"","sources":["../../src/commands/errors-catalogue.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { writeFileSync, chmodSync } from 'node:fs';
|
|
2
|
+
import { CertenClient, parseMnemonicTarget } from '@certen.io/sdk';
|
|
3
|
+
import { getApiKey, getApiUrl, getOutputFormat, rememberIdentity, forgetIdentity } from '../config.js';
|
|
4
|
+
import { printOutput, hint, human, isJsonMode } from '../output.js';
|
|
4
5
|
import { resolveSigner } from '../signer.js';
|
|
6
|
+
import { publicKeyHashOf } from '../keystore.js';
|
|
7
|
+
import { assertChain, assertChains } from '../chains.js';
|
|
8
|
+
import { UsageError } from '../errors.js';
|
|
9
|
+
import { resolveWait, parseWaitBudget, waitForIdentity, IDENTITY_WAIT } from '../wait.js';
|
|
10
|
+
import { faucetFor } from '../funding-guard.js';
|
|
5
11
|
async function getClient() {
|
|
6
12
|
return new CertenClient({ apiKey: await getApiKey(), baseUrl: getApiUrl() });
|
|
7
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Render an identity for whoever is reading.
|
|
16
|
+
*
|
|
17
|
+
* Machine consumers get the response verbatim — same keys whether or not the command waited, so
|
|
18
|
+
* nothing has to branch on which flags were passed. Humans get the six fields that decide what to
|
|
19
|
+
* do next, because the table renderer serialises any nested object to a single JSON line: the raw
|
|
20
|
+
* response arrived as one unreadable blob with `can_sign` — the field that determines whether the
|
|
21
|
+
* identity works at all — buried in the middle of it.
|
|
22
|
+
*
|
|
23
|
+
* Table output is explicitly not a contract (docs/CLI-CONTRACT.md), which is what makes this
|
|
24
|
+
* divergence safe.
|
|
25
|
+
*/
|
|
26
|
+
function printIdentity(response) {
|
|
27
|
+
// One parameter, not two. It took a `response` and an `identity` back when the gateway nested the
|
|
28
|
+
// identity inside the response; now that the response carries those fields itself, passing both
|
|
29
|
+
// would be passing the same object twice — and the JSON branch below re-attached the inner object
|
|
30
|
+
// under an `identity` key, reintroducing the shape on the machine interface after the API had
|
|
31
|
+
// dropped it.
|
|
32
|
+
if (isJsonMode() || getOutputFormat() === 'json') {
|
|
33
|
+
printOutput({ ...response });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
printOutput({
|
|
37
|
+
id: response.id,
|
|
38
|
+
adi_url: response.adi_url,
|
|
39
|
+
status: response.status,
|
|
40
|
+
// `?? 'unknown'` is load-bearing: `can_sign` is three-valued and null means the key page could
|
|
41
|
+
// not be read. Printing an empty cell would read as "no".
|
|
42
|
+
can_sign: response.can_sign ?? 'unknown',
|
|
43
|
+
key_page_url: response.key_page_url ?? '-',
|
|
44
|
+
credit_balance: response.credit_balance,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
8
47
|
export function registerIdentityCommands(program) {
|
|
9
48
|
const identity = program.command('identity').description('Identity management');
|
|
10
49
|
identity
|
|
@@ -14,8 +53,15 @@ export function registerIdentityCommands(program) {
|
|
|
14
53
|
.option('--sign-with <key>', 'Local key to own this identity (see `certen keys generate`)')
|
|
15
54
|
.option('--public-key-hash <hash>', 'Public key hash (omit when using --sign-with)')
|
|
16
55
|
.option('--public-key <key>', 'Public key (hex)')
|
|
17
|
-
.option('--chains <chains>', 'Comma-separated
|
|
56
|
+
.option('--chains <chains>', 'Comma-separated chains, e.g. base-sepolia,arbitrum-sepolia')
|
|
18
57
|
.option('--credits <credits>', 'Initial credits', parseInt)
|
|
58
|
+
// Creation is asynchronous and the response says nothing about whether the identity works.
|
|
59
|
+
// Human mode waits; --json keeps the old fire-and-forget default so existing scripts do not
|
|
60
|
+
// silently start blocking. See resolveWait().
|
|
61
|
+
.option('--wait', 'Wait until the identity is provisioned AND can sign (default off --json)')
|
|
62
|
+
.option('--no-wait', 'Return as soon as the gateway accepts the request')
|
|
63
|
+
.option('--timeout <minutes>', `How long to wait (default ${IDENTITY_WAIT.timeoutMin})`)
|
|
64
|
+
.option('--poll-interval <seconds>', `How often to check (default ${IDENTITY_WAIT.intervalSec})`)
|
|
19
65
|
.action(async (opts) => {
|
|
20
66
|
// --public-key-hash was required, which is why the CLI could not create an identity on its
|
|
21
67
|
// own: the hash is sha256 of the RAW 32-byte public key, and working that out was left to
|
|
@@ -23,39 +69,151 @@ export function registerIdentityCommands(program) {
|
|
|
23
69
|
// neither. The explicit flags still work for a key this machine does not hold.
|
|
24
70
|
let publicKeyHash = opts.publicKeyHash;
|
|
25
71
|
let publicKey = opts.publicKey;
|
|
72
|
+
// Chains are validated BEFORE the signer is unlocked and before the request goes out. A
|
|
73
|
+
// typo'd chain used to reach the gateway and come back as a rejection with no visible link
|
|
74
|
+
// to the flag that caused it — after the passphrase prompt, which made the round trip worse.
|
|
75
|
+
const chains = opts.chains ? assertChains(opts.chains) : undefined;
|
|
76
|
+
// Same reasoning for the wait options: a typo'd --timeout must not be discovered after an
|
|
77
|
+
// identity has already been created and has already consumed a slot against the org quota.
|
|
78
|
+
const wait = resolveWait();
|
|
79
|
+
const budget = parseWaitBudget(opts.timeout, opts.pollInterval, IDENTITY_WAIT);
|
|
26
80
|
if (opts.signWith) {
|
|
27
81
|
if (publicKeyHash || publicKey) {
|
|
28
|
-
throw new
|
|
82
|
+
throw new UsageError('Pass either --sign-with or --public-key-hash/--public-key, not both.', 'CONFLICTING_KEY_FLAGS');
|
|
29
83
|
}
|
|
30
84
|
const signer = await resolveSigner(opts.signWith);
|
|
31
85
|
publicKeyHash = signer.publicKeyHash;
|
|
32
86
|
publicKey = signer.publicKey;
|
|
33
87
|
}
|
|
88
|
+
// Derive the hash from the public key rather than demanding both.
|
|
89
|
+
//
|
|
90
|
+
// The hash is sha256 of the RAW 32-byte key — a fact this file already documented while still
|
|
91
|
+
// making the caller compute it. Requiring it alongside the key was pure friction: the CLI has
|
|
92
|
+
// the bytes and the function, and every caller who supplied only `--public-key` was refused
|
|
93
|
+
// and sent to work out a digest by hand.
|
|
94
|
+
//
|
|
95
|
+
// Worse, the refusal steered them wrong. It said `--public-key-hash <hash>` was sufficient,
|
|
96
|
+
// and the gateway rejects a hash-only identity for external signing mode — correctly, since a
|
|
97
|
+
// hash cannot sign. So following the CLI's own advice produced an identity that consumes org
|
|
98
|
+
// quota and can never be used. Found by the end-to-end check on its first real run.
|
|
99
|
+
if (!publicKeyHash && publicKey) {
|
|
100
|
+
const clean = publicKey.trim().toLowerCase().replace(/^0x/, '');
|
|
101
|
+
if (!/^[0-9a-f]{64}$/.test(clean)) {
|
|
102
|
+
throw new UsageError(`"${publicKey}" is not a public key. Expected 64 hex characters (32 bytes).`, 'INVALID_PUBLIC_KEY');
|
|
103
|
+
}
|
|
104
|
+
publicKey = clean;
|
|
105
|
+
publicKeyHash = publicKeyHashOf(Buffer.from(clean, 'hex'));
|
|
106
|
+
}
|
|
34
107
|
if (!publicKeyHash) {
|
|
35
|
-
throw new
|
|
36
|
-
+ 'To make a key: certen keys generate --name dev');
|
|
108
|
+
throw new UsageError('Provide --sign-with <key>, or --public-key <hex>. '
|
|
109
|
+
+ 'To make a key: certen keys generate --name dev', 'MISSING_SIGNING_KEY');
|
|
110
|
+
}
|
|
111
|
+
// A hash with no key is accepted here and refused by the gateway, because a hash cannot sign.
|
|
112
|
+
// Saying so now costs nothing; discovering it after creation costs an identity slot.
|
|
113
|
+
if (!publicKey) {
|
|
114
|
+
hint('No --public-key given, only its hash. The gateway refuses this for external signing:');
|
|
115
|
+
hint('a hash cannot sign, so the identity would consume quota and never be usable.');
|
|
37
116
|
}
|
|
38
117
|
const client = await getClient();
|
|
39
118
|
const result = await client.identity.create({
|
|
40
119
|
name: opts.name,
|
|
41
120
|
publicKeyHash,
|
|
42
121
|
publicKey,
|
|
43
|
-
chains
|
|
122
|
+
chains,
|
|
44
123
|
credits: opts.credits,
|
|
45
124
|
});
|
|
46
|
-
|
|
125
|
+
const id = result.id;
|
|
126
|
+
// Recorded the moment it exists. The gateway has no identity list route and the portfolio
|
|
127
|
+
// view returns no UUIDs, so an id that is only printed is an id that can be lost.
|
|
128
|
+
if (id)
|
|
129
|
+
rememberIdentity({ id, adi_url: result.adi_url, chains: chains ?? [] });
|
|
130
|
+
if (!wait || !id) {
|
|
131
|
+
if (result.id)
|
|
132
|
+
printIdentity(result);
|
|
133
|
+
else
|
|
134
|
+
printOutput(result);
|
|
135
|
+
hint('');
|
|
136
|
+
hint('Provisioning continues in the background. It is not usable until status is terminal');
|
|
137
|
+
hint('AND can_sign is true:');
|
|
138
|
+
hint(` certen identity get ${id ?? '<id>'}`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
// Waiting means the printed result is the one the user can act on, not the 202. Emitting
|
|
142
|
+
// both would put two payloads in the --json envelope for no benefit.
|
|
143
|
+
//
|
|
144
|
+
// The SHAPE stays identical to the no-wait response, because a consumer must not have to
|
|
145
|
+
// parse two different layouts depending on which flags were passed.
|
|
146
|
+
const identity = await waitForIdentity(client, id, budget);
|
|
147
|
+
// Merged, not replaced. `result` carries fields that only the create returns —
|
|
148
|
+
// `mnemonic_retrieval`, `status_url`, `warning` — and `identity` carries the refreshed state.
|
|
149
|
+
// Printing `identity` alone would drop the one-shot mnemonic URL for provider-mode
|
|
150
|
+
// identities, which cannot be recovered afterwards.
|
|
151
|
+
printIdentity({ ...result, ...identity });
|
|
152
|
+
if (isJsonMode())
|
|
153
|
+
return;
|
|
154
|
+
human('');
|
|
155
|
+
human(` Identity ${identity.adi_url} is active and can sign.`);
|
|
156
|
+
human(` ID ${identity.id}`);
|
|
157
|
+
// The abstract account is msg.sender for everything this identity executes, and it starts
|
|
158
|
+
// empty. It was previously buried in a JSON blob under a name that does not say so, which
|
|
159
|
+
// is how the "parks at anchoring forever" failure finds people.
|
|
160
|
+
const accounts = identity.chain_accounts ?? [];
|
|
161
|
+
if (accounts.length > 0) {
|
|
162
|
+
human('');
|
|
163
|
+
human(' Abstract accounts (msg.sender on chain — these need gas before they can execute):');
|
|
164
|
+
for (const account of accounts) {
|
|
165
|
+
human(` ${account.chain_id.padEnd(18)} ${account.address || '(not deployed)'}`);
|
|
166
|
+
}
|
|
167
|
+
const faucets = accounts.map((a) => faucetFor(a.chain_id)).filter(Boolean);
|
|
168
|
+
if (faucets.length > 0) {
|
|
169
|
+
human('');
|
|
170
|
+
human(` Fund them: ${[...new Set(faucets)].join(' ')}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
hint('');
|
|
174
|
+
hint(`Next: certen tx create --identity ${identity.id} --to-chain <chain> --to <addr> --amount <n> --sign-with <key>`);
|
|
47
175
|
});
|
|
48
176
|
identity
|
|
49
177
|
.command('list')
|
|
50
|
-
.description('
|
|
51
|
-
.action(() => {
|
|
178
|
+
.description('List the identities in your organization (via the portfolio view)')
|
|
179
|
+
.action(async () => {
|
|
52
180
|
// This called GET /v1/identities, which 404s: the gateway serves /v1/identity (POST) and
|
|
53
|
-
// /v1/identity/{id} (GET/PATCH/DELETE) and has no collection route.
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
181
|
+
// /v1/identity/{id} (GET/PATCH/DELETE) and has no collection route. It then spent a release
|
|
182
|
+
// as a command whose only behaviour was to explain that it did not work — honest, but the
|
|
183
|
+
// user's actual question ("what identities do I have") was answerable the whole time from
|
|
184
|
+
// /v1/portfolio.
|
|
185
|
+
//
|
|
186
|
+
// It then spent a release answering that question WITHOUT the ids, because the portfolio view
|
|
187
|
+
// withheld them — so anyone who had lost the UUID printed at create time could see their
|
|
188
|
+
// identity listed and still not act on it. The gateway now returns `id` there (it had it in
|
|
189
|
+
// hand all along), and this command is finally a complete answer rather than a partial one
|
|
190
|
+
// with a footnote.
|
|
191
|
+
const client = await getClient();
|
|
192
|
+
const portfolio = await client.portfolio.get();
|
|
193
|
+
const identities = portfolio.identities ?? [];
|
|
194
|
+
if (identities.length === 0) {
|
|
195
|
+
printOutput([]);
|
|
196
|
+
hint('No identities yet. Create one: certen identity create --name <name> --sign-with <key>');
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// `id` first: it is the field every other command takes as an argument, so it is the one a
|
|
200
|
+
// reader is scanning for.
|
|
201
|
+
printOutput(identities.map((i) => ({
|
|
202
|
+
id: i.id ?? '—',
|
|
203
|
+
adi_url: i.adi_url,
|
|
204
|
+
status: i.status,
|
|
205
|
+
credit_balance: i.credit_balance,
|
|
206
|
+
chains: i.chains?.length ?? 0,
|
|
207
|
+
pending_actions: i.pending_actions,
|
|
208
|
+
})));
|
|
209
|
+
// A gateway older than 2026-08 does not return `id` here, and the CLI ships independently of
|
|
210
|
+
// it. Say so only when it is actually true — a permanent caveat about a fixed problem trains
|
|
211
|
+
// people to skip the notes that matter.
|
|
212
|
+
if (identities.some((i) => !i.id)) {
|
|
213
|
+
hint('');
|
|
214
|
+
hint('This gateway does not return identity ids in the portfolio view, so `id` reads "—".');
|
|
215
|
+
hint('Upgrade the gateway, or use the id printed when the identity was created.');
|
|
216
|
+
}
|
|
59
217
|
});
|
|
60
218
|
identity
|
|
61
219
|
.command('get <id>')
|
|
@@ -64,18 +222,110 @@ export function registerIdentityCommands(program) {
|
|
|
64
222
|
const client = await getClient();
|
|
65
223
|
// No `--include`: the route takes no query parameters. It used to be sent and silently ignored.
|
|
66
224
|
const result = await client.identity.get(id);
|
|
225
|
+
printIdentity(result);
|
|
226
|
+
if (isJsonMode())
|
|
227
|
+
return;
|
|
228
|
+
const identity = result;
|
|
229
|
+
// `can_sign` is the field that decides whether this identity is usable, and reading it out
|
|
230
|
+
// of a printed blob is exactly the step people skip. State the conclusion.
|
|
231
|
+
if (identity.can_sign === true) {
|
|
232
|
+
hint('');
|
|
233
|
+
hint(`Ready. Next: certen tx create --identity ${identity.id} --to-chain <chain> --to <addr> --amount <n> --sign-with <key>`);
|
|
234
|
+
}
|
|
235
|
+
else if (identity.can_sign === false) {
|
|
236
|
+
hint('');
|
|
237
|
+
hint('This identity CANNOT sign — its key page is not held by your key. It will fail at the');
|
|
238
|
+
hint('signing step of every flow.');
|
|
239
|
+
}
|
|
240
|
+
else if (['provisioning', 'pending', 'creating'].includes(identity.status)) {
|
|
241
|
+
hint('');
|
|
242
|
+
hint(`Still provisioning. Wait for it: certen identity get ${identity.id}`);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
// null on a terminal status: unknown, not a soft yes. Never round it up.
|
|
246
|
+
hint('');
|
|
247
|
+
hint('Whether this identity can sign is UNKNOWN — its on-chain key page could not be read.');
|
|
248
|
+
hint('Treat it as unusable until that resolves.');
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
identity
|
|
252
|
+
.command('retire <id>')
|
|
253
|
+
.description('Retire an identity, freeing the org quota slot it occupies')
|
|
254
|
+
.requiredOption('--yes', 'Confirm. There is no prompt — see below')
|
|
255
|
+
.action(async (id) => {
|
|
256
|
+
// No y/N prompt: the required --yes IS the confirmation, matching `keys delete`. An identity
|
|
257
|
+
// that a live integration depends on should not be retirable by an accidental Enter.
|
|
258
|
+
const client = await getClient();
|
|
259
|
+
// Resolved first so the confirmation message names what is being retired. An id pasted from
|
|
260
|
+
// the wrong terminal is the mistake worth catching, and it is invisible until something says
|
|
261
|
+
// the ADI out loud.
|
|
262
|
+
// No enrichments: this read exists to name the ADI in the confirmation prompt. Fetching
|
|
263
|
+
// governance, per-chain balances and pending counts to print one URL is work nobody sees.
|
|
264
|
+
const before = await client.identity.get(id, { include: [] }).catch(() => null);
|
|
265
|
+
const result = await client.identity.retire(id);
|
|
266
|
+
// Dropped from the local record too, so `certen init` does not offer to reuse it.
|
|
267
|
+
forgetIdentity(id);
|
|
67
268
|
printOutput(result);
|
|
269
|
+
if (isJsonMode())
|
|
270
|
+
return;
|
|
271
|
+
human('');
|
|
272
|
+
human(` Retired ${before?.adi_url ?? id}. The org quota slot is free.`);
|
|
273
|
+
human('');
|
|
274
|
+
// The distinction people get wrong, and the one that matters if they were retiring for
|
|
275
|
+
// security reasons rather than housekeeping.
|
|
276
|
+
human(' This is a soft delete INSIDE CERTEN. The on-chain ADI, its key book and its key page');
|
|
277
|
+
human(' still exist on Accumulate and are untouched. Retiring is not a way to revoke a key.');
|
|
68
278
|
});
|
|
69
279
|
identity
|
|
70
280
|
.command('link-chain <id>')
|
|
71
281
|
.description('Link a chain to an identity')
|
|
72
|
-
.requiredOption('--chain <chain>', 'Chain
|
|
282
|
+
.requiredOption('--chain <chain>', 'Chain to link, e.g. base-sepolia')
|
|
73
283
|
.action(async (id, opts) => {
|
|
284
|
+
const chain = assertChain(opts.chain);
|
|
74
285
|
const client = await getClient();
|
|
75
286
|
const result = await client.identity.update(id, {
|
|
76
|
-
linkChains: [
|
|
287
|
+
linkChains: [chain],
|
|
77
288
|
});
|
|
78
289
|
printOutput(result);
|
|
79
290
|
});
|
|
291
|
+
identity
|
|
292
|
+
.command('mnemonic <id-or-url> [token]')
|
|
293
|
+
.description('Collect a provider-mode mnemonic — works exactly once')
|
|
294
|
+
.option('--out <file>', 'Where to write it. Defaults to ./<id>-mnemonic.txt, mode 0600.')
|
|
295
|
+
.option('--print', 'Print it to the terminal instead of writing a file')
|
|
296
|
+
.action(async (idOrUrl, token, opts) => {
|
|
297
|
+
const client = await getClient();
|
|
298
|
+
const { mnemonic } = await client.identity.retrieveMnemonic(idOrUrl, token);
|
|
299
|
+
// A machine consumer asked for the value in its output, so give it the value. Anything else
|
|
300
|
+
// would mean a script has to go read a file the CLI chose the name of.
|
|
301
|
+
if (isJsonMode() || getOutputFormat() === 'json') {
|
|
302
|
+
printOutput({ mnemonic });
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (opts.print) {
|
|
306
|
+
human('');
|
|
307
|
+
human(` ${mnemonic}`);
|
|
308
|
+
human('');
|
|
309
|
+
human(' That was the only read. The URL is dead now, and this phrase is in your');
|
|
310
|
+
human(' terminal scrollback — move it somewhere you trust and clear the buffer.');
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
// Writing beats printing by default. A seed phrase on stdout lands in scrollback, in CI
|
|
314
|
+
// logs, and in whatever is recording the session — all places it outlives its usefulness by
|
|
315
|
+
// years. `--print` is there for anyone who genuinely wants that.
|
|
316
|
+
const { id } = parseMnemonicTarget(idOrUrl, token);
|
|
317
|
+
const path = opts.out ?? `${id}-mnemonic.txt`;
|
|
318
|
+
writeFileSync(path, `${mnemonic}\n`, { encoding: 'utf-8', mode: 0o600 });
|
|
319
|
+
try {
|
|
320
|
+
chmodSync(path, 0o600);
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
// Windows has no POSIX mode. The file is still written; permissions are the OS's business.
|
|
324
|
+
}
|
|
325
|
+
human('');
|
|
326
|
+
human(` Written to ${path}`);
|
|
327
|
+
human(' Read once and gone — the retrieval URL no longer works, and CERTEN cannot');
|
|
328
|
+
human(' produce this phrase again. Move it into your secret store and delete the file.');
|
|
329
|
+
});
|
|
80
330
|
}
|
|
81
331
|
//# sourceMappingURL=identity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/commands/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/commands/identity.ts"],"names":[],"mappings":"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"}
|