Browse Source

bug-fixes

imwald
Silberengel 3 weeks ago
parent
commit
fa2238d888
  1. 4
      package-lock.json
  2. 2
      package.json
  3. 2
      src/components/ZapDialog/index.tsx
  4. 6
      src/index.css
  5. 202
      src/services/lightning.service.ts
  6. 7
      src/services/relay-info.service.ts

4
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "imwald", "name": "imwald",
"version": "22.3.2", "version": "22.4.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "imwald", "name": "imwald",
"version": "22.3.2", "version": "22.4.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@asciidoctor/core": "^3.0.4", "@asciidoctor/core": "^3.0.4",

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "imwald", "name": "imwald",
"version": "22.3.2", "version": "22.4.0",
"description": "Imwald — a user-friendly Nostr client focused on relay feed browsing, publications, and relay discovery", "description": "Imwald — a user-friendly Nostr client focused on relay feed browsing, publications, and relay discovery",
"private": true, "private": true,
"type": "module", "type": "module",

2
src/components/ZapDialog/index.tsx

@ -110,7 +110,7 @@ export default function ZapDialog({
return ( return (
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
<DialogContent onOpenAutoFocus={(e) => e.preventDefault()}> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle className="flex gap-2 items-center"> <DialogTitle className="flex gap-2 items-center">
<div className="shrink-0">{t('Zap to')}</div> <div className="shrink-0">{t('Zap to')}</div>

6
src/index.css

@ -611,6 +611,12 @@
.yarl__portal { .yarl__portal {
pointer-events: auto; pointer-events: auto;
} }
/* Bitcoin Connect (Alby) payment UI: web component on document.body while a Sheet/Dialog may
still be tearing down; same pointer-events issue as the lightbox when nested under Radix. */
bc-modal {
pointer-events: auto;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.yarl__slide_captions_container { .yarl__slide_captions_container {
padding: 12px; padding: 12px;

202
src/services/lightning.service.ts

@ -103,58 +103,62 @@ class LightningService {
} }
return new Promise((resolve) => { return new Promise((resolve) => {
// Close our Radix dialog first; opening bc-modal in the same turn can leave body
// pointer-events stuck so the payment UI is visible but inert (esp. from Sheet / secondary pane).
closeOuterModel?.() closeOuterModel?.()
let checkPaymentInterval: ReturnType<typeof setInterval> | undefined window.setTimeout(() => {
let subCloser: SubCloser | undefined let checkPaymentInterval: ReturnType<typeof setInterval> | undefined
const { setPaid } = launchPaymentModal({ let subCloser: SubCloser | undefined
invoice: pr, const { setPaid } = launchPaymentModal({
onPaid: (response) => { invoice: pr,
clearInterval(checkPaymentInterval) onPaid: (response) => {
subCloser?.close() clearInterval(checkPaymentInterval)
resolve({ preimage: response.preimage, invoice: pr }) subCloser?.close()
}, resolve({ preimage: response.preimage, invoice: pr })
onCancelled: () => { },
clearInterval(checkPaymentInterval) onCancelled: () => {
subCloser?.close() clearInterval(checkPaymentInterval)
resolve(null) subCloser?.close()
} resolve(null)
}) }
})
if (verify) { if (verify) {
checkPaymentInterval = setInterval(async () => { checkPaymentInterval = setInterval(async () => {
const invoice = new Invoice({ pr, verify }) const invoice = new Invoice({ pr, verify })
const paid = await invoice.verifyPayment() const paid = await invoice.verifyPayment()
if (paid && invoice.preimage) { if (paid && invoice.preimage) {
setPaid({ setPaid({
preimage: invoice.preimage preimage: invoice.preimage
}) })
}
}, 1000)
} else {
const filter: Filter = {
kinds: [kinds.Zap],
'#p': [recipient],
since: dayjs().subtract(1, 'minute').unix()
} }
}, 1000) if (event) {
} else { filter['#e'] = [event.id]
const filter: Filter = { }
kinds: [kinds.Zap], subCloser = client.subscribe(
'#p': [recipient], senderRelayList.write.concat(FAST_READ_RELAY_URLS).slice(0, 4),
since: dayjs().subtract(1, 'minute').unix() filter,
} {
if (event) { onevent: (evt) => {
filter['#e'] = [event.id] const info = getZapInfoFromEvent(evt)
} if (!info) return
subCloser = client.subscribe(
senderRelayList.write.concat(FAST_READ_RELAY_URLS).slice(0, 4),
filter,
{
onevent: (evt) => {
const info = getZapInfoFromEvent(evt)
if (!info) return
if (info.invoice === pr) { if (info.invoice === pr) {
setPaid({ preimage: info.preimage ?? '' }) setPaid({ preimage: info.preimage ?? '' })
}
} }
} }
} )
) }
} }, 0)
}) })
} }
@ -228,55 +232,57 @@ class LightningService {
return new Promise((resolve) => { return new Promise((resolve) => {
closeOuterModel?.() closeOuterModel?.()
let checkPaymentInterval: ReturnType<typeof setInterval> | undefined window.setTimeout(() => {
let subCloser: SubCloser | undefined let checkPaymentInterval: ReturnType<typeof setInterval> | undefined
const { setPaid } = launchPaymentModal({ let subCloser: SubCloser | undefined
invoice: pr, const { setPaid } = launchPaymentModal({
onPaid: (response) => { invoice: pr,
clearInterval(checkPaymentInterval) onPaid: (response) => {
subCloser?.close() clearInterval(checkPaymentInterval)
resolve({ preimage: response.preimage, invoice: pr }) subCloser?.close()
}, resolve({ preimage: response.preimage, invoice: pr })
onCancelled: () => { },
clearInterval(checkPaymentInterval) onCancelled: () => {
subCloser?.close() clearInterval(checkPaymentInterval)
resolve(null) subCloser?.close()
} resolve(null)
}) }
})
if (verify) { if (verify) {
checkPaymentInterval = setInterval(async () => { checkPaymentInterval = setInterval(async () => {
const invoice = new Invoice({ pr, verify }) const invoice = new Invoice({ pr, verify })
const paid = await invoice.verifyPayment() const paid = await invoice.verifyPayment()
if (paid && invoice.preimage) { if (paid && invoice.preimage) {
setPaid({ setPaid({
preimage: invoice.preimage preimage: invoice.preimage
}) })
}
}, 1000)
} else {
const filter: Filter = {
kinds: [kinds.Zap],
'#p': [rec],
'#e': [pollEvent.id],
since: dayjs().subtract(1, 'minute').unix()
} }
}, 1000) subCloser = client.subscribe(
} else { senderRelayList.write.concat(FAST_READ_RELAY_URLS).slice(0, 4),
const filter: Filter = { filter,
kinds: [kinds.Zap], {
'#p': [rec], onevent: (evt) => {
'#e': [pollEvent.id], const info = getZapInfoFromEvent(evt)
since: dayjs().subtract(1, 'minute').unix() if (!info) return
}
subCloser = client.subscribe(
senderRelayList.write.concat(FAST_READ_RELAY_URLS).slice(0, 4),
filter,
{
onevent: (evt) => {
const info = getZapInfoFromEvent(evt)
if (!info) return
if (info.invoice === pr) { if (info.invoice === pr) {
setPaid({ preimage: info.preimage ?? '' }) setPaid({ preimage: info.preimage ?? '' })
}
} }
} }
} )
) }
} }, 0)
}) })
} }
@ -292,15 +298,17 @@ class LightningService {
return new Promise((resolve) => { return new Promise((resolve) => {
closeOuterModel?.() closeOuterModel?.()
launchPaymentModal({ window.setTimeout(() => {
invoice: invoice, launchPaymentModal({
onPaid: (response) => { invoice: invoice,
resolve({ preimage: response.preimage, invoice: invoice }) onPaid: (response) => {
}, resolve({ preimage: response.preimage, invoice: invoice })
onCancelled: () => { },
resolve(null) onCancelled: () => {
} resolve(null)
}) }
})
}, 0)
}) })
} }

7
src/services/relay-info.service.ts

@ -187,7 +187,12 @@ class RelayInfoService {
}) })
return data return data
} catch (err) { } catch (err) {
logger.warn('[RelayInfo] NIP-11 fetch threw', { url, err }) // Browser NIP-11 is often cross-origin without CORS → TypeError / "NetworkError". Expected; Firefox still logs CORS separately.
if (err instanceof TypeError) {
logger.debug('[RelayInfo] NIP-11 fetch failed (likely CORS or network)', { url })
} else {
logger.warn('[RelayInfo] NIP-11 fetch threw', { url, err })
}
return undefined return undefined
} }
} }

Loading…
Cancel
Save