Auto-heal wallets stuck on a CORS-blocked mint
- useCashu now probes existing mints on every init (not just when empty); if none are browser-reachable it adds a reachable candidate mint. This fixes existing users whose only saved mint is the legacy CORS-blocked mint.minibits.cash default. - CashuWallet active-mint selection now prefers the first browser-reachable mint instead of blindly mints[0], so users aren't stuck with a mint that fails every invoice. Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
a0c59375ed
commit
b830bf965d
2 changed files with 53 additions and 13 deletions
|
|
@ -98,11 +98,31 @@ export function CashuWallet() {
|
|||
mints,
|
||||
});
|
||||
|
||||
// Set first mint as active if none selected
|
||||
// Pick an active mint when none is selected — prefer a browser-REACHABLE mint
|
||||
// so a user whose first saved mint is CORS-blocked (e.g. legacy minibits)
|
||||
// doesn't get stuck with a mint that fails every invoice.
|
||||
useEffect(() => {
|
||||
if (mints.length > 0 && !activeMintUrl) {
|
||||
setActiveMintUrl(mints[0].url);
|
||||
}
|
||||
if (mints.length === 0 || activeMintUrl) return;
|
||||
let cancelled = false;
|
||||
|
||||
(async () => {
|
||||
// Probe mints in order; select the first reachable one.
|
||||
for (const m of mints) {
|
||||
const { probeMintReachability } = await import('@/lib/mintReachability');
|
||||
const probe = await probeMintReachability(m.url);
|
||||
if (cancelled) return;
|
||||
if (probe.reachability === 'ok') {
|
||||
setActiveMintUrl(m.url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Fallback: nothing reachable — select the first so the UI still renders.
|
||||
if (!cancelled) setActiveMintUrl(mints[0].url);
|
||||
})();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [mints, activeMintUrl, setActiveMintUrl]);
|
||||
|
||||
// Show wallet loading state
|
||||
|
|
|
|||
|
|
@ -167,35 +167,55 @@ export function useCashu(): UseCashuReturn {
|
|||
console.warn('[Cashu] Failed to enable some coco services:', err);
|
||||
}
|
||||
|
||||
// Add a default mint if the user has none yet.
|
||||
// Ensure the user has at least one BROWSER-REACHABLE mint.
|
||||
//
|
||||
// A mint MUST send permissive CORS headers or the browser blocks every
|
||||
// request with a NetworkError ("Failed to fetch mint"). We can't know from
|
||||
// build time which mint is reachable in THIS browser, so we probe an
|
||||
// ordered list of web-friendly candidates and add the first that works.
|
||||
// (mint.minibits.cash is intentionally excluded — it's mobile-app only.)
|
||||
// build time which mint is reachable in THIS browser, so we probe.
|
||||
//
|
||||
// This runs on every init so it also AUTO-HEALS an existing user whose
|
||||
// only saved mint is CORS-blocked (e.g. legacy mint.minibits.cash default):
|
||||
// if none of their mints are reachable, we add a working one and — since
|
||||
// the UI picks the first mint — keep the broken one but ensure a good one
|
||||
// exists. (mint.minibits.cash is excluded from candidates — mobile only.)
|
||||
try {
|
||||
const existingMints = await coco.mint.getAllTrustedMints();
|
||||
if (existingMints.length === 0) {
|
||||
|
||||
// Does the user already have at least one reachable mint?
|
||||
let hasReachable = false;
|
||||
for (const m of existingMints) {
|
||||
const probe = await probeMintReachability(m.mintUrl);
|
||||
if (probe.reachability === 'ok') {
|
||||
hasReachable = true;
|
||||
break;
|
||||
}
|
||||
console.warn('[Cashu] Existing mint not usable in browser:', m.mintUrl, probe.reachability);
|
||||
}
|
||||
|
||||
if (!hasReachable) {
|
||||
const CANDIDATE_MINTS = [
|
||||
'https://mint.coinos.io',
|
||||
'https://21mint.me',
|
||||
'https://stablenut.cashu.network',
|
||||
'https://mint.lnvoltz.com',
|
||||
];
|
||||
const alreadyHave = new Set(
|
||||
existingMints.map((m: Mint) => m.mintUrl.toLowerCase()),
|
||||
);
|
||||
for (const url of CANDIDATE_MINTS) {
|
||||
if (alreadyHave.has(url.toLowerCase())) continue;
|
||||
const probe = await probeMintReachability(url);
|
||||
if (probe.reachability === 'ok') {
|
||||
console.log('[Cashu] Adding default mint:', url);
|
||||
console.log('[Cashu] Adding reachable mint:', url);
|
||||
await coco.mint.addMint(url, { trusted: true });
|
||||
console.log('[Cashu] Default mint added successfully');
|
||||
console.log('[Cashu] Reachable mint added successfully');
|
||||
break;
|
||||
}
|
||||
console.warn('[Cashu] Skipping unreachable default candidate:', url, probe.reachability);
|
||||
console.warn('[Cashu] Skipping unreachable candidate:', url, probe.reachability);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[Cashu] Failed to add default mint:', err);
|
||||
console.warn('[Cashu] Failed to ensure a reachable mint:', err);
|
||||
}
|
||||
|
||||
setIsInitialized(true);
|
||||
|
|
|
|||
Loading…
Reference in a new issue