The deployed page was a bare black screen for minutes with nothing but the tab
spinner to suggest it was not simply broken. Two separate faults.
**No fallback.** `main.tsx` wraps the whole app in
`<Subscribe source$={merge(dynamicBuilder$, …)}>`, and Subscribe's `fallback`
defaults to null — "it will render null until the subscription exists".
`dynamicBuilder$` does not emit until a chain has been followed and its metadata
decoded, so until then the document body is empty. On a slow connection that is
seconds of nothing; on a chain the console cannot read it is forever, and a
visitor cannot tell the two apart. There is now a splash naming the chain and
the endpoint, which escalates at 8s and again at 25s and tells the reader how to
force a different network.
**The default endpoint was the light client.** `defaultSelectedChain` used
LIGHT_CLIENT_ENDPOINT unconditionally, which routes through smoldot — and
smoldot needs a chain spec. The Quantus networks have none
(`hasChainSpecs: false`), so the default asked it to follow a chain it had never
heard of. It now picks AUTO_RPC for any network without chain specs, which is
what the endpoints in quantus.json are for.
This does not make the console work against Quantus. It makes it explain itself
while failing, which it could not do before — the remaining fault is much
deeper and is written up on #1.
Refs #1, #3
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
qapi console
A fork of the papi console, pointed at the Quantus chains and patched to accept their post-quantum signature type.
Deployed at https://qapi.blackbeard.observer.
Why this fork exists
The console is built on polkadot-api,
which shares no code with the polkadot-js stack the Quantus browser extension forks
(quantus/extension, quantus/common, quantus/ui, quantus/wasm). That makes it an
independent implementation of the same wire format — and the only way to find out
whether our stack is right about Quantus or merely self-consistent.
It already is: for the same call, nonce and signature, createV4Tx here produces bytes
identical to quantus/extension's tier-1 harness.
The one patch
getSignerType in @polkadot-api/signers-common reads the extrinsic's Address and
Signature types out of the metadata — the right thing, and better than polkadot-js,
which hardcodes ExtrinsicSignature: 'MultiSignature' in a type definition file. It then
threw that answer away and required the enum to carry Ecdsa, Ed25519 and Sr25519.
Quantus's DilithiumSignatureScheme carries Dilithium87 and Dilithium65, so every
signing attempt raised Unkown signer before reaching code that would have worked —
createV4Tx is entirely length-agnostic, and a 7 219-byte ML-DSA-87 signature drops
straight in.
patches/@polkadot-api__signers-common.patch drops the names and keeps the structural
check. See quantus/papi-console#1.
Develop
pnpm install
pnpm dev
Deploy
Pushes to main deploy to oolon via .gitea/workflows/deploy.yaml. One-time host
provisioning — DNS, certificate, nginx vhost, webroot — is
script/infra-setup.sh, run by an operator:
./script/infra-setup.sh --pubkey ~/.ssh/id_gitea_ci.pub
Conventions: architecture/ —
deployment-gitea-actions.md, reverse-proxies.md, external-tls.md, public-dns.md.
Upstream's own README, and the licence, are unchanged: this is a fork, not a rewrite.