Skip to content

Commit cb9b8be

Browse files
committed
fix: clearer on-chain fetch failures and api preflight
1 parent 499e70c commit cb9b8be

1 file changed

Lines changed: 29 additions & 3 deletions

File tree

app/ClientPage.tsx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,16 @@ export default function ClientPage() {
230230
? "https://api.mainnet.hiro.so"
231231
: "https://api.testnet.hiro.so";
232232

233+
const stacksCoreApiBaseUrl =
234+
typeof STACKS_NETWORK_OBJ === "object" &&
235+
STACKS_NETWORK_OBJ !== null &&
236+
"client" in STACKS_NETWORK_OBJ &&
237+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
238+
typeof (STACKS_NETWORK_OBJ as any).client?.baseUrl === "string"
239+
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
240+
((STACKS_NETWORK_OBJ as any).client.baseUrl as string)
241+
: stacksApiBase;
242+
233243
const getOverrideForToken = useCallback(
234244
(tokenId: number, kind: number | null) => {
235245
const byToken = nftOverrides.byTokenId[String(tokenId)];
@@ -604,6 +614,21 @@ export default function ClientPage() {
604614
const sender = senderOverride || address || caller;
605615

606616
try {
617+
// Quick connectivity check (avoids opaque "Failed to fetch" errors).
618+
try {
619+
const controller = new AbortController();
620+
const t = window.setTimeout(() => controller.abort(), 8000);
621+
const res = await fetch(`${stacksCoreApiBaseUrl}/v2/info`, {
622+
signal: controller.signal,
623+
});
624+
window.clearTimeout(t);
625+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
626+
} catch {
627+
throw new Error(
628+
`Cannot reach Stacks API (${STACKS_NETWORK}). Check your connection and disable adblock/firewall for ${stacksCoreApiBaseUrl}.`
629+
);
630+
}
631+
607632
const [streakCV, lastDayCV] = await Promise.all([
608633
fetchCallReadOnlyFunction({
609634
contractAddress: CONTRACT_ADDRESS,
@@ -842,16 +867,17 @@ export default function ClientPage() {
842867

843868
// Common foot-gun: wallet on testnet while app is set to mainnet (or vice-versa).
844869
const networkHint =
845-
(STACKS_NETWORK === "mainnet" && sender.startsWith("ST")) ||
846-
(STACKS_NETWORK === "testnet" && sender.startsWith("SP"))
870+
walletAddress &&
871+
((STACKS_NETWORK === "mainnet" && walletAddress.startsWith("ST")) ||
872+
(STACKS_NETWORK === "testnet" && walletAddress.startsWith("SP")))
847873
? " (Wallet/network mismatch: switch Leather network to match the app.)"
848874
: "";
849875

850876
setError(`Failed to fetch on-chain data: ${message}${networkHint}`);
851877
} finally {
852878
setIsLoading(false);
853879
}
854-
}, [address, loadOwnedCollectibles]);
880+
}, [address, loadOwnedCollectibles, stacksCoreApiBaseUrl, walletAddress]);
855881

856882
const scheduleRefresh = useCallback(
857883
(senderOverride?: string) => {

0 commit comments

Comments
 (0)