Skip to content

feat(cli): add --json output to text view and text set#110

Merged
andrew-ifrita merged 1 commit into
mainfrom
feat/cli-json-text
Apr 28, 2026
Merged

feat(cli): add --json output to text view and text set#110
andrew-ifrita merged 1 commit into
mainfrom
feat/cli-json-text

Conversation

@EnderOfWorlds007
Copy link
Copy Markdown
Contributor

Summary

Mirrors #76 for the text namespace — the last on-chain CLI commands that didn't have machine-readable output. Unblocks bulletin-deploy #173 (set name + description text records at deploy time).

Follows the exact pattern that #76 established for register/content/pop:

  • CLI wrapper uses getJsonFlag / maybeQuiet / emitJsonResult / handleCommandError from jsonHelpers.ts.
  • Underlying viewDomainText / setDomainText now return structured results (TextViewResult / TextSetResult) — same shift viewDomainContentHash / setDomainContentHash did in feat(cli): add --json output to register, content, and pop commands #76.
  • --json flag suppresses chalk/ora output via withCapturedConsole.
  • Banner is already gated by process.argv.includes("--json") in program.ts, so it's silent under --json.

JSON output shapes

dotns text view <name> <key> --json
→ { "domain": "....dot", "key": "...", "exists": true, "owner": "0x...", "value": "..." | null }

# unregistered domain:
→ { "domain": "....dot", "key": "...", "exists": false, "owner": null, "value": null }

dotns text set <name> <key> <value> --json
→ { "ok": true, "domain": "....dot", "key": "...", "value": "...", "txHash": "0x..." }

# any error path:
→ stderr: { "error": "<message>" }, exit 1

Reads return data directly (no ok field); writes return { ok: true, ... }. Matches the envelope convention documented in jsonHelpers.ts.

Behaviour change worth flagging

text view previously had a manual piped-stdout fallback: when stdout was a pipe, all chalk output got rerouted to stderr and the bare value was written to stdout, so dotns text view foo bar | xargs ... would just receive the value. That hack is removed — it predated --json and conflicted with the new flag (the redirect would hijack the JSON envelope). Scripted users should now use --json and parse the value field. The non-piped, non-json TTY experience is unchanged.

Tests

  • New unit file tests/unit/text/textJson.test.ts (3 tests): --json flag in help output for both subcommands + JSON error envelope for the pre-chain --mnemonic + --key-uri mutex. Mirrors contentJson.test.ts.
  • New --json cases appended to tests/integration/text/text.test.ts (4 tests): registered-domain happy path for view/set, unregistered-domain returning exists: false (view) and JSON error (set). Mirrors the --json block at the bottom of content.test.ts.
  • bun test tests/unit/163/163 pass (was 159; +4 from this PR — 3 new + the 1 textHelp test count is unchanged but textJson adds 3, totaling +4? actually +4 unit assertions across the 3 tests; verified locally).
  • bun run build → green.
  • bun run lint → clean.
  • bun run format → clean.
  • bun run typecheck → 47 pre-existing errors (same count on main); zero introduced by this PR.

Scope

Deliberately excluded from this PR — should be follow-ups:

  • account address, account info, account map — self-contained namespace, separate concern from text records.
  • auth set/list/use/remove/clear — keystore management, involves interactive password prompts; needs its own design pass.

Closes the upstream gap noted in bulletin-deploy PR #180 (### #173 / text records — NOT in this PR).

Mirrors PR #76: text was the last on-chain namespace without machine-readable
output. Adds --json to both subcommands; the underlying viewDomainText and
setDomainText now return structured TextViewResult / TextSetResult.

JSON output shapes:

  dotns text view <name> <key> --json
  → { domain, key, exists, owner, value }

  dotns text set <name> <key> <value> --json
  → { ok: true, domain, key, value, txHash }

Errors emit { error: "<message>" } on stderr with exit code 1, same as
register/content/pop.

Removes the legacy piped-stdout fallback in 'text view' (output rerouted to
stderr when stdout was a pipe) — superseded by --json. Non-piped, non-json
behaviour is unchanged.

Tests: textHelp (unchanged) + new textJson unit (3 tests) + 4 new --json
integration tests in tests/integration/text/. All 163 unit tests pass.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 26, 2026

CI Summary

Check Result
Lint Passed
Format Passed
Typecheck Passed
Build Passed
Release Passed
Deploy Example Passed
PR Title Passed
Labels Passed
Test Passed - 163 passed, 0 failed

Release - Passed

Test this PR

Download artifact (GitHub CLI required):

gh run download 24953966467 -n cli-release-0.0.0-pr.110 -R paritytech/dotns-sdk

Install globally:

npm install -g ./parity-dotns-cli-0.0.0-pr.110.tgz

Verify:

dotns --help
Deploy Example — Passed
Stage Status
✓ Site validation Site validated
✓ Deploy Deployed
Property Value
Domain pr110.dotns-example-site.dot
CID bafybeicx555prsudvmqsdrap7keoilryrudwycdx3ody2rejwqwjwp52u4
URL (dot.li) https://dot.li/pr110.dotns-example-site.dot
URL (direct) https://pr110.dotns-example-site.dot
Duration 147s

View run

Labels

pkg: cli, type: test

Test - Passed

163 passed, 0 failed across 163 tests.

View run

$ bun test tests/unit/
bun test v1.2.6 (8ebd5d53)

::group::tests/unit/text/textHelp.test.ts:
(pass) text --help lists subcommands and auth options [16.00ms]
(pass) text view --help shows name and key arguments [4.00ms]
(pass) text set --help shows name, key, and value arguments [3.00ms]

::endgroup::

::group::tests/unit/text/textJson.test.ts:
(pass) text view --help shows --json option [4.00ms]
(pass) text set --help shows --json option [3.00ms]
(pass) text set --json emits JSON error when both mnemonic and key-uri provided [3.00ms]

::endgroup::

::group::tests/unit/content/contentJson.test.ts:
(pass) content view --help shows --json option [2.00ms]
(pass) content set --help shows --json option [2.00ms]
(pass) content set --json emits JSON error when both mnemonic and key-uri provided [2.00ms]

::endgroup::

::group::tests/unit/content/contentHelp.test.ts:
result:  {
  exitCode: 0,
  standardOutput: "Usage: dotns content [options] [command]\n\nManage domain content hashes\n\nOptions:\n  --rpc <wsUrl>               WebSocket RPC endpoint (env: DOTNS_RPC)\n  --keystore-path <path>      Keystore path (env: DOTNS_KEYSTORE_PATH)\n  --min-balance <pas>         Minimum balance in PAS (env:\n                              DOTNS_MIN_BALANCE_PAS)\n  --account <name>            Keystore account name (default: keystore default)\n  --password <pw>             Keystore password (env: DOTNS_KEYSTORE_PASSWORD)\n  -m, --mnemonic <phrase>     BIP39 mnemonic phrase (env: DOTNS_MNEMONIC)\n  -k, --key-uri <uri>         Substrate key URI (env: DOTNS_KEY_URI)\n  -h, --help                  display help for command\n\nCommands:\n  view [options] <name>       View domain content hash\n  set [options] <name> <cid>  Set domain content hash (IPFS CID)\n  help [command]              display help for command\n",
  standardError: "",
  combinedOutput: "Usage: dotns content [options] [command]\n\nManage domain content hashes\n\nOptions:\n  --rpc <wsUrl>               WebSocket RPC endpoint (env: DOTNS_RPC)\n  --keystore-path <path>      Keystore path (env: DOTNS_KEYSTORE_PATH)\n  --min-balance <pas>         Minimum balance in PAS (env:\n                              DOTNS_MIN_BALANCE_PAS)\n  --account <name>            Keystore account name (default: keystore default)\n  --password <pw>             Keystore password (env: DOTNS_KEYSTORE_PASSWORD)\n  -m, --mnemonic <phrase>     BIP39 mnemonic phrase (env: DOTNS_MNEMONIC)\n  -k, --key-uri <uri>         Substrate key URI (env: DOTNS_KEY_URI)\n  -h, --help                  display help for command\n\nCommands:\n  view [options] <name>       View domain content hash\n  set [options] <name> <cid>  Set domain content hash (IPFS CID)\n  help [command]              display help for command\n",
}
(pass) content --help lists subcommands and auth options [3.00ms]
(pass) content view --help shows name argument and options [2.00ms]
(pass) content set --help shows name and cid arguments [1.00ms]

::endgroup::

::group::tests/unit/utils/formatting.test.ts:
(pass) native balance formatting uses DOT/PAS 10 decimals > DECIMALS_DOT is 10 (native DOT/PAS) and DECIMALS is 12 (Revive native)
(pass) native balance formatting uses DOT/PAS 10 decimals > formatNativeBalance renders 5000 PAS from 5000 * 10^10 units [1.00ms]
(pass) native balance formatting uses DOT/PAS 10 decimals > formatNativeBalance renders fractional 0.1 PAS as 10^9 units
(pass) native balance formatting uses DOT/PAS 10 decimals > formatNativeBalance renders zero balance
(pass) native balance formatting uses DOT/PAS 10 decimals > parseNativeBalance inverts formatNativeBalance
(pass) native balance formatting uses DOT/PAS 10 decimals > parseNativeBalance('0.1') is 10^9

::endgroup::

::group::tests/unit/utils/contractInteractions.test.ts:
(pass) isRevertFlag matches the EVM revert bit > flags=0n → false
(pass) isRevertFlag matches the EVM revert bit > flags=1n → true
(pass) isRevertFlag matches the EVM revert bit > flags=2n → false
(pass) isRevertFlag matches the EVM revert bit > flags=3n → true
(pass) buildRevertError > empty data returns the unmapped-origin hint
(pass) buildRevertError > known ABI selector decodes to the named error [6.00ms]
(pass) buildRevertError > unknown selector falls back to raw hex [1.00ms]

::endgroup::

::group::tests/unit/auth/auth.test.ts:
(pass) auth set creates keystore and stores multiple accounts [291.00ms]
(pass) auth set accepts account names with special characters [419.01ms]
(pass) auth list reports missing keystore [4.00ms]
(pass) auth list shows all accounts and auth types [272.00ms]
(pass) auth use switches default account [422.01ms]
(pass) auth remove last account clears default [71.00ms]
(pass) auth remove preserves remaining accounts and reassigns default [210.00ms]
(pass) auth clear deletes all accounts [83.00ms]

::endgroup::

::group::tests/unit/auth/authHelp.test.ts:
(pass) root help lists auth command [2.00ms]
(pass) auth help shows options and subcommands [1.00ms]
(pass) auth set help shows all options [2.00ms]
(pass) auth list help shows options [1.00ms]
(pass) auth use help shows options [2.00ms]
(pass) auth remove help shows options [1.00ms]
(pass) auth clear help shows options [2.00ms]
(pass) auth parses keystore-path option [2.00ms]
(pass) auth parses password option [2.00ms]
(pass) auth set parses account option [1.00ms]
(pass) auth set parses mnemonic option [1.00ms]
(pass) auth set parses key-uri option [2.00ms]
(pass) auth help command shows help [2.00ms]
(pass) auth help set shows set command help [1.00ms]
(pass) auth help list shows list command help [2.00ms]
(pass) auth help use shows use command help [2.00ms]
(pass) auth help remove shows remove command help [2.00ms]
(pass) auth help clear shows clear command help [2.00ms]

::endgroup::

::group::tests/unit/auth/authRevert.test.ts:
(pass) auth set rejects account name with forward slash [3.00ms]
(pass) auth set rejects account name with backslash [1.00ms]
(pass) auth set rejects account name that is just a dot [2.00ms]
(pass) auth set rejects account name that is double dots [1.00ms]
(pass) auth set rejects account name starting with dot [2.00ms]
(pass) auth set rejects account name ending with dot [1.00ms]
(pass) auth set rejects account name with special characters [9.00ms]
(pass) auth set rejects account name that is too long [1.00ms]
(pass) auth use rejects non-existent account [67.00ms]
(pass) auth remove rejects non-existent account [79.00ms]

::endgroup::

::group::tests/unit/auth/resolveAuthSourceReadOnly.test.ts:
(pass) resolveAuthSourceReadOnly honours environment variables > $label [1.00ms]
(pass) resolveAuthSourceReadOnly honours environment variables > $label
(pass) resolveAuthSourceReadOnly honours environment variables > $label
(pass) resolveAuthSourceReadOnly honours environment variables > $label
(pass) resolveAuthSourceReadOnly honours environment variables > $label

::endgroup::

::group::tests/unit/store/storeHelp.test.ts:
(pass) store --help lists subcommands [1.00ms]
(pass) store info --help shows auth options [2.00ms]
(pass) store list --help shows options [1.00ms]
(pass) store get --help shows key argument [1.00ms]
(pass) store set --help shows key and value arguments with auth [1.00ms]
(pass) store delete --help shows key argument with auth [1.00ms]
(pass) store check --help shows address argument [1.00ms]
(pass) store authorize --help shows address argument with auth [2.00ms]
(pass) store unauthorize --help shows address argument [1.00ms]
(pass) store authorize-controller --help shows address argument [1.00ms]
(pass) store unauthorize-controller --help shows address argument [1.00ms]
(pass) store ensure-auth --help shows description and auth options [2.00ms]

::endgroup::

::group::tests/unit/pop/popJson.test.ts:
(pass) pop set --help shows --json option [2.00ms]
(pass) pop info --help shows --json option [1.00ms]

::endgroup::

::group::tests/unit/pop/setPopHelp.test.ts:
(pass) root help lists pop command [1.00ms]
(pass) pop help shows commands and description [2.00ms]
(pass) pop help shows auth options [1.00ms]
(pass) pop set help shows status parameter [1.00ms]
(pass) pop set help shows auth options [1.00ms]
(pass) pop info help shows description [1.00ms]
(pass) pop info help shows auth options [1.00ms]
(pass) pop set parses rpc option at pop level [1.00ms]
(pass) pop set parses rpc option at set level [1.00ms]
(pass) pop set parses keystore-path option [2.00ms]
(pass) pop set parses account option at pop level [1.00ms]
(pass) pop set parses account option at set level [1.00ms]
(pass) pop set parses password option
(pass) pop set parses mnemonic option [1.00ms]
(pass) pop set parses key-uri option [2.00ms]
(pass) pop info parses auth options at pop level [1.00ms]
(pass) pop info parses auth options at info level [1.00ms]
(pass) pop set parses mixed options across levels [1.00ms]
(pass) pop help command shows pop help [1.00ms]
(pass) pop help set shows set help [2.00ms]
(pass) pop help info shows info help [1.00ms]

::endgroup::

::group::tests/unit/account/accountHelp.test.ts:
(pass) account --help lists subcommands including is-mapped, is-whitelisted, whitelist [2.00ms]
(pass) account is-mapped --help shows address argument and --json [1.00ms]
(pass) account is-whitelisted --help shows address argument and --json [1.00ms]
(pass) account whitelist --help shows address argument, --remove, and --json [1.00ms]
(pass) account is alias works for is-mapped [2.00ms]
(pass) account iw alias works for is-whitelisted [1.00ms]

::endgroup::

::group::tests/unit/cli/reporter.test.ts:
(pass) cli reporter > stream reporter emits durable progress lines
(pass) cli reporter > withConsoleToStderr redirects console and stdout writes

::endgroup::

::group::tests/unit/bulletin/uploadManifest.test.ts:
(pass) upload manifest resume behavior > returns stale manifest when fingerprint does not match [2.00ms]
(pass) upload manifest resume behavior > deduplicates completed blocks by index

::endgroup::

::group::tests/unit/bulletin/uploadProfiling.test.ts:
(pass) upload profiler > writes schema-complete profile report with peak aggregation [16.00ms]
(pass) upload profiler > default profile path is deterministic for a given fingerprint

::endgroup::

::group::tests/unit/bulletin/bulletinHelp.test.ts:
(pass) root help lists bulletin command [2.00ms]
(pass) bulletin help shows commands and description [1.00ms]
(pass) bulletin upload help shows all options [2.00ms]
(pass) bulletin upload help shows default values [1.00ms]
(pass) bulletin authorize help shows all options [1.00ms]
(pass) bulletin authorize help shows default values [1.00ms]
(pass) bulletin history help shows options [2.00ms]
(pass) bulletin history:remove help shows usage [2.00ms]
(pass) bulletin history:clear help shows description [1.00ms]
(pass) bulletin help command shows bulletin help [1.00ms]
(pass) bulletin help upload shows upload help [2.00ms]
(pass) bulletin help authorize shows authorize help [1.00ms]
(pass) bulletin status help shows all options [1.00ms]
(pass) bulletin help status shows status help [1.00ms]
(pass) bulletin list alias works [1.00ms]
(pass) bulletin verify help shows usage [1.00ms]
(pass) bulletin help verify shows verify help [1.00ms]

::endgroup::

::group::tests/unit/register/registerHelp.test.ts:
(pass) root help lists register command [2.00ms]
(pass) register help shows subcommands [1.00ms]
(pass) register domain help shows options [1.00ms]
(pass) register subname help shows options [1.00ms]
(pass) register domain parses status none [2.00ms]
(pass) register domain parses status lite [1.00ms]
(pass) register domain parses status full [1.00ms]
(pass) register domain parses reverse flag [1.00ms]
(pass) register domain parses governance flag [1.00ms]
(pass) register domain parses owner option [1.00ms]
(pass) register domain parses transfer with destination [1.00ms]
(pass) register domain parses account option [1.00ms]
(pass) register domain parses keystore-path option [1.00ms]
(pass) register domain parses password option [1.00ms]
(pass) register domain parses mnemonic option [1.00ms]
(pass) register domain parses key-uri option [1.00ms]
(pass) register domain parses commitment-buffer option [2.00ms]
(pass) register domain parses commitment-buffer alias --cb [1.00ms]
(pass) register subname parses name and parent [1.00ms]
(pass) register subname parses owner option [1.00ms]
(pass) getCommitmentBufferSeconds defaults to 6 when env is not set
(pass) getCommitmentBufferSeconds reads from DOTNS_COMMITMENT_BUFFER env variable
(pass) COMMITMENT_POLL_INTERVAL_MS is 2000
(pass) COMMITMENT_POLL_TIMEOUT_MS is 30000

::endgroup::

::group::tests/unit/register/registerJson.test.ts:
(pass) register domain --help shows --json option [1.00ms]
(pass) register subname --help shows --json option [1.00ms]
(pass) register domain --json emits JSON error when --transfer without --to [1.00ms]

::endgroup::

::group::tests/unit/lookup/lookupHelp.test.ts:
(pass) lookup --help lists subcommands and auth options [1.00ms]
(pass) lookup name --help shows label argument and options [1.00ms]
(pass) lookup owner-of --help shows label argument and options [1.00ms]
(pass) lookup transfer --help shows label argument and destination option [1.00ms]
(pass) lookup transfer parses destination at transfer level [1.00ms]
(pass) lookup transfer parses auth options at lookup level [2.00ms]

::endgroup::

 163 pass
 0 fail
 570 expect() calls
Ran 163 tests across 21 files. [2.58s]

@andrew-ifrita andrew-ifrita merged commit 1fcba01 into main Apr 28, 2026
21 checks passed
@andrew-ifrita andrew-ifrita deleted the feat/cli-json-text branch April 28, 2026 08:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants