@xyo-network/wallet-xl1-cli 0.1.20 → 0.1.22

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/README.md CHANGED
@@ -17,7 +17,7 @@ The Aries CLI uses this same package for `aries wallet ...`, so the standalone a
17
17
 
18
18
  ### Prerequisites
19
19
 
20
- - Node.js `>=18.17.1`
20
+ - Node.js `>=22.19.0`
21
21
  - A package manager such as `npm`, `pnpm`, or `yarn`
22
22
 
23
23
  ### Global Install
@@ -59,6 +59,58 @@ aries wallet balance 0
59
59
  aries wallet send 0x0000000000000000000000000000000000000000 1.25 --milli --json
60
60
  ```
61
61
 
62
+ ## Requester-scoped Node signing
63
+
64
+ The supported `@xyo-network/wallet-xl1-cli/signing` entry exposes public wallet
65
+ summaries and short-lived, account-bound signing sessions. Install the package
66
+ locally with its `@xyo-network/xl1-sdk` peer. Consumers select the requester ID,
67
+ exact wallet ID, derivation offset, expected account, chain ID, and independently
68
+ verified genesis hash. The wallet itself confirms that selection and prompts on
69
+ the trusted terminal for its password; this API does not accept a password,
70
+ mnemonic, root wallet, or caller-provided signer.
71
+
72
+ ```ts
73
+ import { listSigningWallets, openWalletSigningSession } from '@xyo-network/wallet-xl1-cli/signing'
74
+
75
+ const wallets = listSigningWallets()
76
+ const session = await openWalletSigningSession(selection)
77
+ try {
78
+ const snapshot = await session.snapshot()
79
+ const signed = await session.signTransaction({ requestId, transaction })
80
+ // Persist signed bytes in the participant publication journal before broadcasting.
81
+ } finally {
82
+ await session.close()
83
+ }
84
+ ```
85
+
86
+ Here `selection` is the complete explicit binding and `transaction` is an SDK
87
+ unsigned hydrated transaction. The session signs without publishing bodies or
88
+ broadcasting. It supports secp256k1 wallets; post-quantum transaction signing is
89
+ not qualified. Sessions expire within five minutes. Lock, close, password
90
+ replacement, and wallet replacement revoke authority for new signing.
91
+
92
+ The wallet persists request intent and encrypted signed results in `signing.json`
93
+ under its existing guarded store lease. Retrying the same request returns the
94
+ same bytes. `signingOutcome(requestId)` recovers a retained result through a fresh
95
+ authorized session with the same complete binding. An uncertain intent blocks
96
+ new same-account signing; an error, timeout, or `4001` is never proof that no
97
+ signature exists. Existing CLI `tx sign` and `send` use this same signing ledger,
98
+ with publication remaining a separate command step. Legacy offline signing has
99
+ an explicitly unasserted genesis scope; it cannot authorize public requester
100
+ sessions. This does not reconstruct pre-upgrade or external-key signing history.
101
+
102
+ Run the isolated packed public import, type, real terminal prompt, and process
103
+ recovery fixture from the repository root after both wallet package builds:
104
+
105
+ ```sh
106
+ node packages/wallet-cli/scripts/verifySigningPacked.mjs /absolute/fresh/evidence-directory
107
+ ```
108
+
109
+ The terminal fixture currently qualifies macOS. It creates only a temporary
110
+ public deterministic wallet. Its strict consumer type check uses `skipLibCheck`;
111
+ the full dependency declaration check is retained separately because upstream SDK
112
+ declarations currently fail that broader check.
113
+
62
114
  ## Wallet Storage
63
115
 
64
116
  Wallet CLI data is stored under `~/.xl1/wallet/cli` by default.
@@ -67,7 +119,8 @@ Wallet CLI data is stored under `~/.xl1/wallet/cli` by default.
67
119
  | --- | --- |
68
120
  | `XL1_WALLET_HOME` | Overrides the wallet storage directory. |
69
121
  | `ARIES_WALLET_HOME` | Legacy fallback storage override. Used only when `XL1_WALLET_HOME` is not set. |
70
- | `ARIES_WALLET_PASSWORD` | Supplies the wallet password for non-interactive runs and tests. |
122
+ | `ARIES_WALLET_PASSWORD` | Supplies the wallet password. A nonempty value is validated before any cached session is used. For a new store, it sets the initial password. |
123
+ | `ARIES_WALLET_NON_INTERACTIVE=1` | Refuses terminal password and recovery-phrase prompts. Private-key access requires an unlocked session or `ARIES_WALLET_PASSWORD`; import requires `--phrase-stdin` or `--phrase`. |
71
124
 
72
125
  Wallet seed phrases are encrypted at rest. Commands that need private key access prompt for the wallet password unless `ARIES_WALLET_PASSWORD` is set.
73
126
 
@@ -97,10 +150,45 @@ xl1-wallet network use xl1-sequence
97
150
  Add a local or custom network:
98
151
 
99
152
  ```sh
100
- xl1-wallet network add local http://127.0.0.1:8080/rpc --label "Local XL1" --chain-id 0x1234
153
+ xl1-wallet network add local http://127.0.0.1:8080/rpc --label "Local XL1" --chain-id 1234
101
154
  xl1-wallet network use local
102
155
  ```
103
156
 
157
+ Adding a network preserves the current selection and rejects duplicate IDs.
158
+ New IDs must be nonblank, contain no control characters, fit within 256 UTF-8
159
+ bytes, and not begin with `-`. Optional labels are preserved exactly and may
160
+ contain up to 1024 UTF-8 bytes. Optional chain IDs use the XL1 protocol's
161
+ nonempty lowercase hexadecimal form without a `0x` prefix; there is no fixed
162
+ length requirement. The chain ID is stored metadata: adding a network does not
163
+ probe the endpoint or verify its chain.
164
+
165
+ For endpoints containing path or query credentials, pass the complete URL via
166
+ private stdin instead of a positional argument. Stdin must contain only the URL
167
+ as UTF-8, with no trailing newline, and is limited to 16 KiB. URLs must be complete
168
+ HTTP or HTTPS URLs without controls or fragments. Local HTTP endpoints are
169
+ supported. URL username/password information is rejected because the RPC fetch
170
+ transport does not support it.
171
+
172
+ ```sh
173
+ printf '%s' "$RPC_URL" | xl1-wallet network inspect-add custom \
174
+ --rpc-url-stdin --label="Custom XL1" --chain-id=1234 --json
175
+ printf '%s' "$RPC_URL" | xl1-wallet network add custom \
176
+ --rpc-url-stdin --label="Custom XL1" --chain-id=1234 \
177
+ --expected-state="$REVIEWED_STATE_HASH" --json
178
+ ```
179
+
180
+ `inspect-add` validates the proposed entry and returns its ID, label, optional
181
+ chain ID, current active ID, canonical wallet root, and `stateHash`. Use that
182
+ hash as `REVIEWED_STATE_HASH` for the corresponding add. Inspection does not
183
+ create `networks.json`; the add writes defaults and the custom entry atomically
184
+ under the wallet store lease. If any wallet file changes after review, the
185
+ guarded add fails and must be reviewed again. `--rpc-url-stdin` and a positional
186
+ URL are mutually exclusive.
187
+
188
+ Network list and add support `--json`. Network summaries and
189
+ success messages omit the entire RPC URL, including its hostname. The URL is
190
+ stored in the private wallet configuration for RPC use.
191
+
104
192
  Remove a custom network:
105
193
 
106
194
  ```sh
@@ -115,15 +203,16 @@ xl1-wallet network remove local
115
203
  | --- | --- |
116
204
  | `xl1-wallet create` | Create a new wallet. |
117
205
  | `xl1-wallet import` | Import a recovery phrase. |
118
- | `xl1-wallet export` | Print a wallet recovery phrase after password confirmation. |
206
+ | `xl1-wallet export` | Print a wallet recovery phrase using a password or unlocked session. |
119
207
  | `xl1-wallet list` | List wallets in the current wallet home. |
120
208
  | `xl1-wallet use <id>` | Set the active wallet. |
121
209
  | `xl1-wallet rename <id> <label>` | Rename a wallet. |
122
- | `xl1-wallet remove <id>` | Remove a wallet from local storage. |
123
- | `xl1-wallet reset` | Delete local wallet CLI data after confirmation. |
210
+ | `xl1-wallet remove [id]` | Authenticate and remove a wallet; `--wallet-id` targets an exact ID. |
211
+ | `xl1-wallet reset` | Delete known wallet files after confirmation, preserving unrelated files. |
124
212
  | `xl1-wallet unlock` | Cache an encrypted wallet session for a limited time. |
125
213
  | `xl1-wallet lock` | Clear the cached wallet session. |
126
- | `xl1-wallet password change` | Change the active wallet password. |
214
+ | `xl1-wallet password change` | Change the shared password for every wallet in the store. |
215
+ | `xl1-wallet lifecycle preview --json` | Inspect the canonical store path, state fingerprint, wallets, and known files. |
127
216
 
128
217
  Examples:
129
218
 
@@ -135,17 +224,63 @@ xl1-wallet import --label quant-recovery --phrase "..." --algorithm ml-dsa-65
135
224
  xl1-wallet list
136
225
  xl1-wallet use <wallet-id>
137
226
  xl1-wallet export --id <wallet-id>
227
+ xl1-wallet export --wallet-id <exact-wallet-id> --json
138
228
  ```
139
229
 
140
230
  `create` and `import` default to `--algorithm secp256k1`. Use `--algorithm ml-dsa-65` for `QuantHDWallet` wallets, which derive `qm65...` bech32m addresses. Wallet-signed JWT commands require secp256k1 because ML-DSA-65 does not yet have a standardized JOSE algorithm.
141
- Wallet labels must be unique. If `create` is run without `--label`, the CLI uses the first available `wallet#` label, starting with `wallet0`.
231
+ Wallet labels must be unique, nonblank, and free of NUL characters. Other label text, including surrounding spaces, is preserved. If `create` is run without `--label`, the CLI uses the first available `wallet#` label, starting with `wallet0`.
232
+ Commands accepting a wallet ID or label prefer an exact ID match before looking
233
+ for a matching label.
234
+
235
+ For unattended imports, `--phrase-stdin` reads raw UTF-8 from standard input
236
+ until EOF, up to 16 KiB, and trims surrounding whitespace. It is mutually
237
+ exclusive with `--phrase`. The algorithm, label, and recovery phrase are
238
+ validated before the command initializes a password or stores a wallet.
239
+
240
+ `export --wallet-id` accepts only an exact stored ID and cannot be combined
241
+ with `--id`. The existing `--id` option also accepts labels; omitting both
242
+ options reveals the active wallet.
243
+
244
+ `create --json` and `export --json` emit only
245
+ `{id, label, algorithm, mnemonic}` to stdout. This output contains the recovery
246
+ phrase. `import --json` emits only `{id, label, algorithm}` and does not include
247
+ the phrase. Text output remains the default.
248
+
249
+ Password change requires the current password even with an unlocked session.
250
+ `ARIES_WALLET_PASSWORD` supplies only that current password. For automation,
251
+ `password change --new-password-stdin --json` reads the new password as raw UTF-8
252
+ until EOF, preserving all whitespace, with a 4096-byte limit and no NUL
253
+ characters. Its JSON result is `{changed: true}`. Interactive mode asks for and
254
+ confirms the new password separately. Rotation clears the cached session.
255
+
256
+ `remove --wallet-id=<exact-id> --json` returns `{id, label, removed: true}`.
257
+ The named selector cannot be combined with the positional ID/label. A supplied
258
+ wrong password fails even if an unlocked session exists.
259
+
260
+ Password change, removal, and reset accept `--expected-state=<stateHash>` from
261
+ `lifecycle preview --json`. The CLI checks this fingerprint under its filesystem
262
+ lease before writing; a changed store requires a new review. Preview returns
263
+ `{root, stateHash, wallets, files}` without credentials. If wallet metadata is
264
+ corrupt, `wallets` is `null` with a `metadataError`, so reset can still be reviewed.
265
+
266
+ Updated CLI processes share a canonical-path filesystem lease. Overlapping
267
+ operations report a busy store; a killed owner's lease expires after 30 seconds.
268
+ Older CLI versions and other programs that ignore the lease are not coordinated.
269
+ Password rotation, removal, and reset commit a durable roll-forward journal
270
+ before replacing data files. The journal contains encrypted wallet records and
271
+ password-verifier metadata, never plaintext passwords or recovery phrases.
272
+ The next leased operation completes a valid pending transaction before reading
273
+ the store. After an interrupted rotation, try the new password first. Individual
274
+ files and journals are limited to 16 MiB. File data is synced; directory syncing
275
+ is best effort on Windows where unsupported. A corrupt or unrecoverable journal
276
+ blocks operations, including reset: preserve its files for repair.
142
277
 
143
278
  ### Accounts
144
279
 
145
280
  | Command | Description |
146
281
  | --- | --- |
147
282
  | `xl1-wallet account derive <offset>` | Derive and store an account at an offset. |
148
- | `xl1-wallet account list` | List stored accounts for the active wallet. |
283
+ | `xl1-wallet account list [--wallet <id-or-label>]` | List stored accounts for the active or specified wallet. |
149
284
  | `xl1-wallet account show <offset>` | Show a derived account address. |
150
285
  | `xl1-wallet account label <offset> <label>` | Label an account. |
151
286
  | `xl1-wallet account remove <offset>` | Remove a stored account record. |
@@ -156,8 +291,17 @@ Examples:
156
291
  xl1-wallet account derive 0 --label main
157
292
  xl1-wallet account show 0
158
293
  xl1-wallet account list
294
+ xl1-wallet account derive 4 --wallet-id <wallet-id> --label savings
159
295
  ```
160
296
 
297
+ Account `show`, `derive`, `label`, and `remove` accept `--wallet-id` to target an
298
+ exact stored wallet without changing the active wallet. Labels are not accepted
299
+ by this option. Omitting it keeps the active-wallet default. Desktop account
300
+ changes require an explicit wallet ID so a reviewed change stays attached to
301
+ the intended wallet. Account removal only removes address-book metadata;
302
+ the key remains derivable and funds are unaffected. Account labeling validates
303
+ the derivation path before saving it.
304
+
161
305
  ### Balances And Transfers
162
306
 
163
307
  | Command | Description |
@@ -276,6 +420,60 @@ xl1-wallet backup import wallet-metadata.json
276
420
  xl1-wallet reset
277
421
  ```
278
422
 
423
+ Metadata backups retain the version 1 `network.xyo.wallet.backup` format. They
424
+ contain address-book offsets and labels, and contact addresses, labels, and
425
+ timestamps. They do not contain recovery phrases, passwords, session credentials,
426
+ or network configuration. Imports merge metadata: incoming defined account labels
427
+ and contact labels win, existing account labels survive when incoming labels are omitted, and existing
428
+ contact creation timestamps are preserved. Contact update timestamps never move
429
+ backward when importing an older backup.
430
+
431
+ Review an import or export before applying it:
432
+
433
+ ```sh
434
+ xl1-wallet backup inspect wallet-metadata.json --direction=import --json
435
+ xl1-wallet backup inspect wallet-metadata.json --direction=export --json
436
+ ```
437
+
438
+ The JSON result is `{root, stateHash, path, fileStateHash, exists, addressBooks,
439
+ accounts, contacts}`. `root` and `path` are canonical absolute paths. Counts refer
440
+ to incoming backup entries for import, or the stored metadata to export. The
441
+ inspection exposes only paths, counts, existence, and hashes. To require exactly
442
+ the reviewed wallet and file states, pass both hashes to the subsequent command:
443
+
444
+ ```sh
445
+ xl1-wallet backup import wallet-metadata.json \
446
+ --expected-state=<stateHash> --expected-file-state=<fileStateHash> --json
447
+ xl1-wallet backup export wallet-metadata.json --overwrite \
448
+ --expected-state=<stateHash> --expected-file-state=<fileStateHash> --json
449
+ ```
450
+
451
+ Import returns `{imported: true, addressBooks, accounts, contacts}`; export returns
452
+ `{exported: true, addressBooks, accounts, contacts}`. Existing export destinations
453
+ require `--overwrite`. New exports never overwrite a file created concurrently.
454
+ Exports use private `0600` temporary files, fsync, and atomic publication. Imports
455
+ commit address books and contacts together through the wallet recovery journal
456
+ and never modify their source backup. Cooperating CLI processes coordinate by
457
+ wallet root and export destination, including exports from different wallet roots.
458
+
459
+ Files must be regular files of at most 16 MiB, with one filesystem link. Symlinks,
460
+ directories, special files, wallet storage files, and wallet transaction or lease
461
+ paths are rejected. The parent directory must already exist. Version 1 schemas
462
+ and fields are validated strictly; unknown entries, duplicate books/accounts or
463
+ contacts, invalid legacy or quant addresses, and prototype keys are rejected.
464
+ Labels preserve every string accepted by existing version 1 authoring commands,
465
+ including empty, multiline, and long values, within the overall file size limit.
466
+ Offsets use decimal HD path segments up to `2147483647`, optional hardened
467
+ apostrophes and `m/`, at most 32 segments and 512 characters. Timestamps use UTC
468
+ ISO format with milliseconds, as produced by the CLI.
469
+
470
+ For noninteractive reset, pass both `--confirm=RESET` and `--yes`; `--json`
471
+ returns `{reset: true, removedFiles: number}`. No password is required. Reset
472
+ removes only `password.json`, `phrases.json`, `active.json`, `address-books.json`,
473
+ `contacts.json`, `networks.json`, `session.json`, and `.machine-id`. It preserves
474
+ the directory and unrelated files, and refuses to recurse into a directory
475
+ occupying one of those filenames.
476
+
279
477
  ## Output And Automation
280
478
 
281
479
  Most commands print readable text by default. Commands intended for automation, such as `send`, also support JSON output: