Skip to content

chore(cli): qof fixes#158

Merged
sphamjoli merged 14 commits into
mainfrom
spha/qof
Jun 3, 2026
Merged

chore(cli): qof fixes#158
sphamjoli merged 14 commits into
mainfrom
spha/qof

Conversation

@sphamjoli
Copy link
Copy Markdown
Member

@sphamjoli sphamjoli commented Jun 2, 2026

Description

  • Transaction reliability: fixes stale-nonce failures and the follow-on connection timeout cascade by reading the account nonce per transaction and always tearing down the watch subscription, with timeouts now cancelling the in-flight operation rather than leaking it.
  • JSON errors: error output in JSON mode no longer leaks human-readable text to stderr, restoring the documented error envelope.
  • Store migration: moves the Store CLI to the new owner-bound User Store plus separate Label Store. Adds a claim step, repoints set, get, delete and list at the User Store, reads names from the Label Store, and removes the authorisation and controller commands that no longer exist.
  • Test stability: the content, text and store suites now provision their own fixtures instead of depending on a pre-existing domain that lapses on the testnet. Governance registration tests were removed as they depend on whitelist state rather than code.
  • Cleanup: removes verified-unused dead code (two files, several functions, fifteen unused types).
  • CI: the Deploy UI preview and production jobs now register the base domain when missing, matching the other deploy workflows, which unblocks the failing preview deploy.

Type

  • Bug fix
  • Feature
  • Breaking change
  • Documentation
  • Chore

Package

  • @parity/dotns-cli
  • Root/monorepo
  • Documentation

Related Issues

N/A

Fixes

Deploy UI preview failure on paseo-v2 (base domain not registered).

Checklist

Code

  • Follows project style
  • bun run lint passes
  • bun run format passes
  • bun run typecheck passes

Documentation

  • README updated if needed
  • Types updated if needed

Breaking Changes

  • No breaking changes
  • Breaking changes documented below

Breaking changes:

The Store command surface changed with the move to the owner-bound model. Users must now claim their store once before writing. The check, authorise, unauthorise, authorise-controller, unauthorise-controller and ensure-auth commands have been removed, list now returns key and value entries rather than a flat list, and names are read from the Label Store.

Testing

How to test:

  1. Run the unit suite for the CLI package; all pass.
  2. Run the integration suites one at a time (they share a test account, so concurrent runs collide) against a funded, whitelisted paseo-v2 account, covering store, content and register.

Notes

Integration suites need testnet access and must run sequentially per account. A follow-up will add resumable name registration (retry and clear), tracked separately.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

CI Summary

Check Result
Lint Passed
Lint (UI) Passed
Format Passed
Format (UI) Passed
Typecheck Passed
Typecheck (UI) Passed
Build Passed
Build (UI) Passed
Release Passed
Deploy UI Passed
Deploy Example Passed
Benchmark UI Passed
PR Title Passed
Labels Passed
Test Passed - 219 passed, 0 failed

Release - Passed

Test this PR

Download artifact (GitHub CLI required):

gh run download 26865401753 -n cli-release-0.0.0-pr.158 -R paritytech/dotns-sdk

Install globally:

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

Verify:

dotns --help
Deploy UI — Passed
Stage Status
✓ Build Build succeeded
✓ Deploy Deployed
Property Value
Domain pr158.dotns.dot
CID bafybeih32eydm3mpipkgtgfpjlixmkzx7wedxk2j2lnumaena45n2kwnhu
URL (dot.li) https://dot.li/pr158.dotns.dot
URL (direct) https://pr158.dotns.dot

View run

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

View run

Benchmark UI - Passed (128s)
Property Value
Duration 128s
Domain pr158-ui.bulletin-benchmarks.dot
CID bafybeifbiwhem473ip47p6lexxuhnves7wn3f6opppffgxqpsetkyayivq
Preview (dot.li) open
Preview (direct) open
Workflow view
Labels

pkg: cli, scope: bulletin, type: docs, type: test, dependencies, pkg: ui, scope: benchmark

Test - Passed

219 passed, 0 failed across 219 tests.

Waited for other CI summary workflows and hit the timeout; wrote the latest available summary.

View run

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

::group::tests/unit/utils/formatting.test.ts:
(pass) native balance formatting uses DOT/PAS 10 decimals > defaults to 10 native decimals and 18 EVM decimals [2.00ms]
(pass) native balance formatting uses DOT/PAS 10 decimals > formatNativeBalance renders 5000 PAS from 5000 * 10^10 units
(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 [2.00ms]
(pass) native balance formatting uses DOT/PAS 10 decimals > parseNativeBalance('0.1') is 10^9
(pass) withTimeout cancels and cleans up the losing branch > resolves with the wrapped value when it settles first
(pass) withTimeout cancels and cleans up the losing branch > rejects with a descriptive message when the timeout wins [11.00ms]
(pass) withTimeout cancels and cleans up the losing branch > invokes onTimeout exactly once when the timeout wins [10.00ms]
(pass) withTimeout cancels and cleans up the losing branch > does not invoke onTimeout when the wrapped promise settles first [256.00ms]

::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 [5.00ms]
(pass) buildRevertError > unknown selector falls back to raw hex [1.00ms]

::endgroup::

::group::tests/unit/utils/validation.test.ts:
(pass) countTrailingDigits > returns 0 for a label with no trailing digits [1.00ms]
(pass) countTrailingDigits > returns the digit run length for a label with trailing digits
(pass) countTrailingDigits > does not count interior digits
(pass) stripTrailingDigits > returns the label unchanged when there are no trailing digits
(pass) stripTrailingDigits > strips the trailing digit run
(pass) validateDomainLabel digit-suffix rule > accepts labels with no trailing digits
(pass) validateDomainLabel digit-suffix rule > accepts labels with exactly two trailing digits
(pass) validateDomainLabel digit-suffix rule > rejects labels with exactly one trailing digit
(pass) validateDomainLabel digit-suffix rule > rejects labels with three or more trailing digits
(pass) validateDomainLabel digit-suffix rule > rejects labels shorter than three characters
(pass) validateDomainLabel digit-suffix rule > rejects labels with uppercase characters
(pass) validateDomainLabel digit-suffix rule > rejects labels with leading or trailing hyphen
(pass) validateGovernanceLabel stem-length rule > accepts stems of five characters or fewer
(pass) validateGovernanceLabel stem-length rule > rejects stems longer than five characters
(pass) validateGovernanceLabel stem-length rule > inherits the digit-suffix rule from validateDomainLabel

::endgroup::

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

::endgroup::

::group::tests/unit/account/accountHelp.test.ts:
(pass) account --help lists subcommands including is-mapped, is-whitelisted, whitelist [3.00ms]
(pass) account is-mapped --help shows address argument and --json [2.00ms]
(pass) account is-whitelisted --help shows address argument and --json [3.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 [2.00ms]

::endgroup::

::group::tests/unit/content/contentJson.test.ts:
(pass) content view --help shows --json option [3.00ms]
(pass) content set --help shows --json option [2.00ms]
(pass) content set --json emits JSON error when both mnemonic and key-uri provided [3.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  --env <environment>         DotNS environment: paseo-v2 (env: DOTNS_ENV)\n  --network <environment>     Alias for --env\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  --env <environment>         DotNS environment: paseo-v2 (env: DOTNS_ENV)\n  --network <environment>     Alias for --env\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 [2.00ms]

::endgroup::

::group::tests/unit/cli/environment.test.ts:
(pass) defaults to paseo-v2
(pass) accepts friendly paseo-v2 aliases
(pass) DOTNS_ENV selects rpc and contract set
(pass) --env takes precedence over DOTNS_ENV while --rpc only overrides endpoint

::endgroup::

::group::tests/unit/cli/bulletinRpc.test.ts:
(pass) paseo-v2 default resolves to the existing bulletin RPC
(pass) explicit argument wins over env var and active env
(pass) env var wins over active env config when no explicit argument
(pass) falls back to active env's bulletin RPC [1.00ms]
(pass) throws when nothing is configured (synthetic case)

::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 [1.00ms]

::endgroup::

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

::endgroup::

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

::endgroup::

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

::endgroup::

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

::endgroup::

::group::tests/unit/bulletin/bulletinAuthorizer.test.ts:
(pass) bulletin authorizer default > defaults to //Eve, the seeded AllowedAuthorizers account [1.00ms]
(pass) bulletin authorizer default > is distinct from the sudo key, which stays //Alice
(pass) warnIfDevKeyOnTestnet > warns when the default authorizer is used against previewnet
(pass) warnIfDevKeyOnTestnet > stays silent on paseo-v2 even with the default authorizer
(pass) warnIfDevKeyOnTestnet > stays silent when an explicit signer overrides the default

::endgroup::

::group::tests/unit/bulletin/bulletinHelpers.test.ts:
(pass) clampU32 > accepts zero
(pass) clampU32 > accepts U32_MAX
(pass) clampU32 > accepts number input
(pass) clampU32 > rejects negative bigint with field name in message
(pass) clampU32 > rejects negative number with field name in message
(pass) clampU32 > rejects values above U32_MAX
(pass) isAuthorizationSufficient > returns false when not authorised
(pass) isAuthorizationSufficient > returns false when authorised but expired
(pass) isAuthorizationSufficient > returns true when authorised and not expired
(pass) isAuthorizationSufficient > returns true when authorised and expired is undefined
(pass) isTestnetSpecName > classifies paseo as testnet=%s
(pass) isTestnetSpecName > classifies paseo-asset-hub as testnet=%s
(pass) isTestnetSpecName > classifies westend as testnet=%s
(pass) isTestnetSpecName > classifies rococo as testnet=%s
(pass) isTestnetSpecName > classifies foo-testnet as testnet=%s
(pass) isTestnetSpecName > classifies bar-devnet as testnet=%s
(pass) isTestnetSpecName > classifies something-test as testnet=%s
(pass) isTestnetSpecName > classifies something-dev as testnet=%s
(pass) isTestnetSpecName > classifies PASEO as testnet=%s
(pass) isTestnetSpecName > classifies polkadot as testnet=%s
(pass) isTestnetSpecName > classifies kusama as testnet=%s
(pass) isTestnetSpecName > classifies asset-hub-polkadot as testnet=%s
(pass) isTestnetSpecName > classifies  as testnet=%s
(pass) isTestnetSpecName > returns false for null and undefined

::endgroup::

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

::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 [1.00ms]

::endgroup::

::group::tests/unit/escrow/escrowHelp.test.ts:
(pass) root help lists escrow command [2.00ms]
(pass) escrow help shows the subcommand description and subcommands [2.00ms]
(pass) escrow status help describes the read-only position lookup [1.00ms]
(pass) escrow release help describes the approve-and-release sequence [1.00ms]
(pass) escrow withdraw help describes the post-cooldown step [2.00ms]
(pass) escrow claim-withdrawal help describes the overpayment ledger [1.00ms]
(pass) escrow refunds help lists list/claim/claim-batch [1.00ms]
(pass) escrow refunds list help exposes pagination options [1.00ms]
(pass) escrow refunds claim help requires an entry id positional [1.00ms]
(pass) escrow refunds claim-batch help accepts variadic ids [2.00ms]

::endgroup::

::group::tests/unit/escrow/escrowFormatting.test.ts:
(pass) formatRefundEntryLine > marks entries past their cooldown as claimable [1.00ms]
(pass) formatRefundEntryLine > marks entries inside their cooldown window with remaining seconds [1.00ms]
(pass) formatRefundEntryLine > renders the amount as a PAS decimal string
(pass) formatRefundEntryLine > truncates large tokenIds for terminal display

::endgroup::

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

::endgroup::

::group::tests/unit/auth/auth.test.ts:
(pass) auth set creates keystore and stores multiple accounts [322.01ms]
(pass) auth set accepts account names with special characters [461.01ms]
(pass) auth list reports missing keystore [5.00ms]
(pass) auth list shows all accounts and auth types [299.00ms]
(pass) auth use switches default account [469.01ms]
(pass) auth remove last account clears default [78.00ms]
(pass) auth remove preserves remaining accounts and reassigns default [232.00ms]
(pass) auth clear deletes all accounts [93.00ms]

::endgroup::

::group::tests/unit/auth/resolveAuthSourceReadOnly.test.ts:
(pass) resolveAuthSourceReadOnly honours environment variables > $label
(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/auth/authRevert.test.ts:
(pass) auth set rejects account name with forward slash [1.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 [2.00ms]
(pass) auth set rejects account name with special characters [7.00ms]
(pass) auth set rejects account name that is too long [2.00ms]
(pass) auth use rejects non-existent account [72.00ms]
(pass) auth remove rejects non-existent account [76.00ms]

::endgroup::

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

::endgroup::

::group::tests/unit/register/registerOwnerConflicts.test.ts:
(pass) register domain rejects --owner with --transfer [4.00ms]
(pass) register domain rejects --owner with --reverse [1.00ms]
(pass) register domain rejects --owner with --governance [1.00ms]

::endgroup::

::group::tests/unit/register/registerHelp.test.ts:
(pass) root help lists register command [3.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 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 [2.00ms]
(pass) register domain parses key-uri option [1.00ms]
(pass) register domain parses commitment-buffer option [1.00ms]
(pass) register domain parses commitment-buffer alias --cb [2.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/pop/setPopHelp.test.ts:
(pass) root help lists pop command [2.00ms]
(pass) pop help shows commands and description [1.00ms]
(pass) pop help shows auth options [2.00ms]
(pass) pop info help shows description [1.00ms]
(pass) pop status help shows description [1.00ms]
(pass) pop info help shows auth options [1.00ms]
(pass) pop info parses auth options at pop level [2.00ms]
(pass) pop info parses auth options at info level [1.00ms]
(pass) pop help command shows pop help [2.00ms]
(pass) pop help status shows info help [2.00ms]
(pass) pop help info shows info help [2.00ms]

::endgroup::

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

::endgroup::

 219 pass
 0 fail
 659 expect() calls
Ran 219 tests across 29 files. [3.07s]

@sphamjoli
Copy link
Copy Markdown
Member Author

sphamjoli commented Jun 3, 2026

@andrew-ifrita @waytwotall started this as a small QOF but there were too many related changes, so asked claude to assist in making them

@sphamjoli sphamjoli merged commit d3e59a9 into main Jun 3, 2026
33 of 34 checks passed
@sphamjoli sphamjoli deleted the spha/qof branch June 3, 2026 19:50
Copy link
Copy Markdown

@waytwotall waytwotall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good to me

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.

3 participants