feat(wallet): distinct error states and a connection timeout - #1797
Open
bilhokista wants to merge 3 commits into
Open
feat(wallet): distinct error states and a connection timeout#1797bilhokista wants to merge 3 commits into
bilhokista wants to merge 3 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1544.
Starting point
The modal was further along than the issue suggests: it already detected a missing extension, linked to the install page, and had a Retry button that re-attempts the last selected wallet. Those three requirements were met, and I did not rewrite them.
What I found instead were two real defects and one genuine gap.
Defect 1 — a declined request showed nothing at all
user_rejectedwas declared in theErrorTypeunion and never assigned. The rejection branch did this:Click a wallet, press Cancel in the extension, and the modal silently resets to the wallet list. No message, no explanation — indistinguishable from a misclick. It is now a first-class state with its own copy, worded as a choice rather than a fault.
Defect 2 — connectivity failures were reported as the wrong Stellar network
"Network request failed", "NetworkError when attempting to fetch", and
net::ERR_INTERNET_DISCONNECTEDall contain the word "network". A user whose connection was down was told to go and switch chains.The wrong-network rule now requires a chain-specific token (
testnet,pubnet,public network,stellar network,wrong network, …) and never bare "network", and genuine connectivity failures are matched first and get their own state. There is a test asserting the old rule's behaviour as a baseline alongside the fixed one.Gap — no timeout
If the extension never answered,
fetchAddress()hung indefinitely and the modal sat on "connecting" with no escape but closing it.withWalletTimeoutnow races the request against a 30s clock and raisesWalletTimeoutError, which classifies to its own state telling the user to check for a pending prompt in the extension.Structure
Classification moves into
frontend/src/lib/wallet-errors.tsas a pure function returning{ type, title, message, hint?, canRetry }. The modal renders that object instead of carrying a chain of ternaries over an error-type string, which is what let the two defects above hide.canRetryis false only fornot_installed, where retrying cannot help until the extension exists — the panel offers the install link instead of a button guaranteed to fail. Every other branch keeps the retry path.Rejection is checked before every other rule: a decline is deliberate, and any other rule matching the same text would mislabel a user's choice as a fault. There is a test for
"User rejected: network request failed"landing onuser_rejected.Scope note
WalletContext.tsxanduseHookErrorMessage.tsare listed in the issue but turned out not to need changes — the failure surfaces entirely inside the modal, anduseHookErrorMessageis a logging helper for hooks rather than a classifier. I left both untouched rather than editing them to match the file list.Tests
New
wallet-errors.test.ts, 17 cases covering all seven branches, the wallet name appearing in the copy, case-insensitivity, non-Errorvalues (string,null,undefined), the rejection-beats-network precedence, the fallback keeping the raw message, and three cases forwithWalletTimeoutincluding a fake-timer test that the unanswered request rejects withWalletTimeoutError.Honest note on verification: I could not run the frontend Vitest suite locally (no full workspace install). All three files were parsed with the TypeScript compiler API, and
wallet-errors.tswas transpiled and executed standalone against 37 assertions — all passed, including a real (60ms) timeout race and the baseline assertion showing the old substring rule classified "Network request failed" aswrong_networkwhile the new one classifies it asnetwork. The modal's rendering needs CI.🤖 Generated with Claude Code
https://claude.ai/code/session_01CrfEY1tvXrbeMDAUzxfuk7