diff options
| author | Adam Soltys <[email protected]> | 2026-09-29 11:05:41 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-29 11:05:41 -0700 |
| commit | c7186db46f6e45969f01709bc4a0a9472a40dff1 (patch) | |
| tree | d89b6801d1eb74459f40f31d5358d5be45ef94cb /src | |
| parent | 3948ad95beb6e5e40dd275b7c4909ec8c4dee8a9 (diff) | |
| download | coinosv3-c7186db46f6e45969f01709bc4a0a9472a40dff1.tar.gz coinosv3-c7186db46f6e45969f01709bc4a0a9472a40dff1.zip | |
A zap to a Lightning address that doesn't answer says so, naming the host, instead of "signal is aborted without reason".
[email protected]: the lnurlp endpoint answers in 0.15 s but its invoice
callback hangs 30 s then 502s; our 8 s timeout surfaced as the browser's
raw AbortError text. Errors now name the host, a timeout says their
address may be down, and an error response's LNURL reason is shown.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
Diffstat (limited to 'src')
| -rw-r--r-- | src/lnurl.js | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/src/lnurl.js b/src/lnurl.js index f641707..3f1b39b 100644 --- a/src/lnurl.js +++ b/src/lnurl.js @@ -68,13 +68,26 @@ export function zapTargetFromProfile(profile, pk) { function safeEncode(url) { try { return encodeLnurl(url); } catch { return null; } } +// Errors name the server: the recipient's Lightning address lives on THEIR +// host, and a bare "signal is aborted without reason" (the browser's words +// for our timeout) read as though the wallet had broken. async function fetchJson(url, ms = 8000) { const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), ms); + let host = 'their Lightning server'; + try { host = new URL(url).host; } catch {} try { const r = await fetch(url, { signal: ctrl.signal, headers: { Accept: 'application/json' } }); - if (!r.ok) throw new Error(`HTTP ${r.status}`); + if (!r.ok) { + // LNURL servers say why in a JSON { status: 'ERROR', reason } body + const reason = await r.json().then((d) => d && d.reason).catch(() => null); + throw new Error(reason ? `${host}: ${reason}` : `${host} answered with an error (HTTP ${r.status})`); + } return await r.json(); + } catch (e) { + if (ctrl.signal.aborted || e?.name === 'AbortError') throw new Error(`${host} didn’t answer in ${Math.round(ms / 1000)}s — their Lightning address may be down`); + if (e instanceof TypeError) throw new Error(`couldn’t reach ${host}`); + throw e; } finally { clearTimeout(timer); } } |
