Files
qapi/src/main.tsx
T
grenadeandClaude Opus 5 0448d9df7a
deploy / build (push) Successful in 5m28s
deploy / deploy-web (push) Successful in 8s
fix: say what is happening while connecting, and stop defaulting to a light client
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
2026-09-16 09:14:22 +03:00

53 lines
1.8 KiB
TypeScript

import { dynamicBuilder$, getDefaultChain } from "@/state/chains/chain.state"
import { RemoveSubscribe, Subscribe } from "@react-rxjs/core"
import { MultisigExternalSignerModal, PolkaHubProvider } from "polkahub"
import { StrictMode } from "react"
import { createRoot } from "react-dom/client"
import { BrowserRouter } from "react-router-dom"
import { merge } from "rxjs"
import App from "./App.tsx"
import { TooltipProvider } from "./components/ui/tooltip.tsx"
import "./index.css"
import { BootSplash } from "./components/BootSplash.tsx"
import { codeSplit$ } from "./lib/externalState.ts"
import { explorer$ } from "./pages/Explorer"
import { polkaHub } from "./state/polkahub.ts"
import { ThemeProvider } from "./ThemeProvider.tsx"
const metrics$ = codeSplit$(() =>
import("./pages/Metrics/metrics.state.ts").then((r) => r.blockStats$),
)
// Without a fallback, `Subscribe` renders null until `dynamicBuilder$` emits —
// which is after a chain has been followed and its metadata decoded. On a slow
// connection that is seconds of empty black page; on a chain the console cannot
// read, it is forever, and indistinguishable from a crash.
const initial = getDefaultChain()
createRoot(document.getElementById("root")!).render(
<Subscribe
fallback={
<BootSplash
endpoint={initial.endpoint}
network={initial.network.display}
/>
}
source$={merge(dynamicBuilder$, explorer$, metrics$)}
>
<RemoveSubscribe>
<StrictMode>
<ThemeProvider>
<PolkaHubProvider polkaHub={polkaHub}>
<BrowserRouter>
<TooltipProvider delayDuration={500}>
<App />
</TooltipProvider>
</BrowserRouter>
<MultisigExternalSignerModal />
</PolkaHubProvider>
</ThemeProvider>
</StrictMode>
</RemoveSubscribe>
</Subscribe>,
)