fix(receive): probe mint reachability in route loader#1037
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
| } | ||
|
|
||
| // Keysets are warm in cache from the probe, so this resolves fast. | ||
| const token = await decodeCashuToken(hash); |
There was a problem hiding this comment.
async part of the decode process is only present for v2 keysets, right? if so, should we avoid these network requests when token is using v1?
also can you remind me, why do we need to decode the token here?
There was a problem hiding this comment.
yea only v2, but most tokens are v2 so not sure its worth handling v1. Also cashu-ts v4 makes keysetIds required https://github.com/cashubtc/cashu-ts/blob/main/src/utils/core.ts#L332-L336
001429f to
b4e6085
Compare
b4e6085 to
9140ee4
Compare
When a Cashu token's source mint is unreachable, detect it in the
clientLoader before mounting the receive component, so the receive
flow itself never has to know about offline mints.
The loader pre-fetches mintInfo, allMintKeysets, and mintKeys with
a 10s timeout race. On NetworkError it returns a discriminated
{ kind: 'mint-offline', mintUrl } and the component renders an
inline <TokenErrorDisplay>. On success the queryClient cache is
warm, so getInitializedCashuWallet resolves from cache when the
component mounts — no race window where the wallet ends up with
unloaded mint info.
Same pattern in both the protected and public token-receive routes.
TokenErrorDisplay is lifted into its own file so the routes can
import it without pulling in receive-cashu-token internals.
Fixes Sentry: AGICASH-9S, 9Y, 93, 7G, 7F.
9140ee4 to
795af31
Compare
| }); | ||
| queryClient.cancelQueries({ queryKey: mintKeysQueryKey(mintUrl) }); | ||
| reject(new NetworkError('Mint request timed out')); | ||
| }, 10_000); |
There was a problem hiding this comment.
10 seconds is too long. I would put it to 3 seconds or something like that.
| * in-flight queries on timeout so they don't populate the cache after the fact. | ||
| * Throws `NetworkError` if the mint is unreachable or the timeout elapses. | ||
| */ | ||
| export async function fetchMintDataWithTimeout( |
There was a problem hiding this comment.
I'd call this just fetchMintData
| // Probe mint reachability before mounting the receive flow. Side effect: primes | ||
| // the query cache so the component's wallet init resolves without a round-trip. | ||
| try { | ||
| await fetchMintDataWithTimeout(extracted.metadata.mint, queryClient); |
There was a problem hiding this comment.
The only thing I am not sure with this approach is that now the page will load slower. Could we make it so that we only check if the token is supported in the loader and then handle offline mint differently but without changing the ui too much so there is no weird change to different page?
There was a problem hiding this comment.
This is not ideal especially in the timeout scenario because the page will show loading state for a long time and look broken.
| queryClient.fetchQuery(mintKeysQueryOptions(mintUrl)), | ||
| ]), | ||
| new Promise<never>((_, reject) => { | ||
| setTimeout(() => { |
There was a problem hiding this comment.
should we store this timeout to variable and clear it when the the Promise.race resolves?
something like:
let timer: ReturnType<typeof setTimeout>;
try {
return await Promise.race([
Promise.all([...]),
new Promise<never>((_, reject) => {
timer = setTimeout(() => { /* cancel + reject */ }, 10_000);
}),
]);
} finally {
timer && clearTimeout(timer);
}
I don't think it matters a lot but no need to still have the timeout scheduled when the mint info wins the race

This is an alternative to #1029 which makes it so the receive cashu token routes don't even load the components that require the source account to be online
This mint is offline if you want to test:
Summary
When a Cashu token's source mint is unreachable, detect it in the clientLoader before mounting the receive component, so the receive flow itself never has to know about offline mints.
The loader pre-fetches mintInfo, allMintKeysets, and mintKeys with a 10s timeout race. On NetworkError it returns a discriminated { kind: 'mint-offline', mintUrl } and the component renders an inline . On success the queryClient cache is warm, so getInitializedCashuWallet resolves from cache when the component mounts — no race window where the wallet ends up with unloaded mint info.
Same pattern in both the protected and public token-receive routes. TokenErrorDisplay is lifted into its own file so the routes can import it without pulling in receive-cashu-token internals.
Fixes Sentry: AGICASH-9S, 9Y, 93, 7G, 7F.