Browse Source

get rid of long-press zaps

change zaps to tips, inclluding icon
imwald
Silberengel 3 weeks ago
parent
commit
889fa0a286
  1. 7
      src/components/NoteStats/ZapButton.tsx
  2. 2
      src/components/PaymentMethodsSection/index.tsx
  3. 5
      src/components/PaytoDialog/LightningInvoiceSection.tsx
  4. 1
      src/components/Profile/index.tsx
  5. 6
      src/components/ProfileZapButton/index.tsx
  6. 7
      src/components/ZapDialog/index.tsx
  7. 62
      src/hooks/useNip57QuickZap.ts
  8. 20
      src/i18n/locales/de.ts
  9. 20
      src/i18n/locales/en.ts
  10. 4
      src/pages/secondary/ProfileEditorPage/index.tsx
  11. 118
      src/services/lightning.service.ts

7
src/components/NoteStats/ZapButton.tsx

@ -13,7 +13,7 @@ import { useNostr } from '@/providers/NostrProvider' @@ -13,7 +13,7 @@ import { useNostr } from '@/providers/NostrProvider'
import client, { replaceableEventService } from '@/services/client.service'
import type { TProfile } from '@/types'
import { kinds, type Event } from 'nostr-tools'
import { Zap } from 'lucide-react'
import { Coins } from 'lucide-react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import ZapDialog from '../ZapDialog'
@ -217,7 +217,7 @@ export function ZapButtonWithStats({ event, hideCount = false, noteStats }: ZapB @@ -217,7 +217,7 @@ export function ZapButtonWithStats({ event, hideCount = false, noteStats }: ZapB
setOpenPaymentDialog(true)
}
const zapButtonTitle = disable ? t('Zaps') : t('Payment methods')
const zapButtonTitle = disable ? t('Tips') : t('Leave a tip')
return (
<>
@ -233,9 +233,8 @@ export function ZapButtonWithStats({ event, hideCount = false, noteStats }: ZapB @@ -233,9 +233,8 @@ export function ZapButtonWithStats({ event, hideCount = false, noteStats }: ZapB
disabled={disable}
onClick={handleOpenPaymentMethods}
>
<Zap
<Coins
className={cn(
hasZapped && 'fill-yellow-400',
disable
? 'text-muted-foreground/40'
: cn(

2
src/components/PaymentMethodsSection/index.tsx

@ -130,7 +130,7 @@ export default function PaymentMethodsSection({ @@ -130,7 +130,7 @@ export default function PaymentMethodsSection({
return (
<div className={className}>
<div className="text-xs font-semibold text-muted-foreground mb-2">
{title ?? t('Payment Methods')}
{title ?? t('Payment targets')}
</div>
<div className="space-y-3 min-w-0">
<PaymentMethodGroupsList groups={preferredGroups} {...listProps} />

5
src/components/PaytoDialog/LightningInvoiceSection.tsx

@ -195,6 +195,11 @@ export default function LightningInvoiceSection({ @@ -195,6 +195,11 @@ export default function LightningInvoiceSection({
</p>
<p className="break-all text-base font-medium leading-snug sm:text-lg">{lightningAddress}</p>
</div>
<p className="text-sm leading-relaxed text-muted-foreground">
{t(
'Plain Lightning payments do not create NIP-57 zap receipts on Nostr. Use the zap button when available.'
)}
</p>
<div className="min-w-0 space-y-3">
<Label htmlFor="ln-invoice-sats" className="text-sm font-medium text-muted-foreground sm:text-base">

1
src/components/Profile/index.tsx

@ -600,6 +600,7 @@ export default function Profile({ @@ -600,6 +600,7 @@ export default function Profile({
<PaymentMethodsSection
groups={paymentMethodsByType}
recipientPubkey={pubkey}
title={t('Payment targets')}
className="mt-2 mb-4 p-3 pb-4 border rounded-lg bg-muted/50 min-w-0"
/>
)}

6
src/components/ProfileZapButton/index.tsx

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import { Button } from '@/components/ui/button'
import { useRecipientPaymentData } from '@/hooks/useRecipientAlternativePayments'
import { useNostr } from '@/providers/NostrProvider'
import { Zap } from 'lucide-react'
import { Coins } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import ZapDialog from '../ZapDialog'
@ -22,7 +22,7 @@ export default function ProfileZapButton({ @@ -22,7 +22,7 @@ export default function ProfileZapButton({
const setOpen = setOpenZapDialog ?? setInternalOpen
const recipientPayment = useRecipientPaymentData(pubkey, true)
const title = t('Payment methods')
const title = t('Leave a tip')
return (
<>
@ -34,7 +34,7 @@ export default function ProfileZapButton({ @@ -34,7 +34,7 @@ export default function ProfileZapButton({
aria-label={title}
onClick={() => checkLogin(() => setOpen(true))}
>
<Zap className="text-yellow-400" />
<Coins className="text-yellow-400" />
</Button>
{!setOpenZapDialog && (
<ZapDialog open={open} setOpen={setInternalOpen} pubkey={pubkey} prefetchedPayment={recipientPayment} />

7
src/components/ZapDialog/index.tsx

@ -96,13 +96,14 @@ export default function ZapDialog({ @@ -96,13 +96,14 @@ export default function ZapDialog({
}, [recipientPayment, senderPaytoTypes])
const { canQuickNip57Zap, quickZapLabel, sendQuickZap, zapping } = useNip57QuickZap({
enabled: open,
recipientPubkey: pubkey,
referencedEvent: event,
recipientPayment,
onZapDialogClose: () => setOpen(false)
})
const dialogTitle = t('Payment methods')
const dialogTitle = t('Leave a tip')
const body =
paymentGroups.length > 0 || canQuickNip57Zap ? (
<>
@ -116,14 +117,14 @@ export default function ZapDialog({ @@ -116,14 +117,14 @@ export default function ZapDialog({
referencedEvent={event}
offerTipNoticeOnClose={false}
onPostPaymentRequest={openPostPaymentPrompt}
title={t('Payment methods')}
title={t('Tip options')}
className="rounded-lg border border-border bg-muted/40 p-3 min-w-0"
/>
) : null}
</>
) : (
<p className="py-8 text-center text-sm text-muted-foreground">
{t('No payment methods available for this profile')}
{t('No payment targets on this profile')}
</p>
)

62
src/hooks/useNip57QuickZap.ts

@ -6,12 +6,14 @@ import lightning from '@/services/lightning.service' @@ -6,12 +6,14 @@ import lightning from '@/services/lightning.service'
import noteStatsService from '@/services/note-stats.service'
import type { RecipientPaymentData } from '@/hooks/useRecipientAlternativePayments'
import { NostrEvent } from 'nostr-tools'
import { useCallback, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { formatSatsGrouped } from '@/lib/lightning'
export function useNip57QuickZap(opts: {
/** Probe LNURL-pay only while the payment dialog is open (avoids feed-wide fetch storms). */
enabled?: boolean
recipientPubkey: string
referencedEvent?: NostrEvent
recipientPayment: RecipientPaymentData
@ -19,23 +21,55 @@ export function useNip57QuickZap(opts: { @@ -19,23 +21,55 @@ export function useNip57QuickZap(opts: {
}) {
const { t } = useTranslation()
const { pubkey, checkLogin } = useNostr()
const { isWalletConnected, defaultZapSats, defaultZapComment } = useZap()
const { isWalletConnected, defaultZapSats, defaultZapComment, includePublicZapReceipt } = useZap()
const [zapping, setZapping] = useState(false)
const enabled = opts.enabled ?? false
const lightningAddressOptions = useMemo(
const lightningAddressOptionsKey = useMemo(
() =>
buildOrderedZapLightningAddresses({
profileEvent: opts.recipientPayment.profileEvent,
profile: opts.recipientPayment.profile,
paymentInfo: opts.recipientPayment.paymentInfo
}),
[opts.recipientPayment]
}).join('\u0001'),
[
opts.recipientPayment.profileEvent,
opts.recipientPayment.profile,
opts.recipientPayment.paymentInfo
]
)
const [nip57Addresses, setNip57Addresses] = useState<string[] | null>(null)
useEffect(() => {
if (!enabled) {
setNip57Addresses(null)
return
}
let cancelled = false
if (!lightningAddressOptionsKey) {
setNip57Addresses([])
return
}
const candidates = lightningAddressOptionsKey.split('\u0001')
setNip57Addresses(null)
void lightning.filterNip57ZapEnabledAddresses(candidates).then((addrs) => {
if (!cancelled) setNip57Addresses(addrs)
})
return () => {
cancelled = true
}
}, [enabled, lightningAddressOptionsKey])
const canQuickNip57Zap =
enabled &&
isWalletConnected &&
defaultZapSats >= 1 &&
lightningAddressOptions.length > 0 &&
nip57Addresses !== null &&
nip57Addresses.length > 0 &&
!!pubkey &&
pubkey !== opts.recipientPubkey
@ -50,7 +84,7 @@ export function useNip57QuickZap(opts: { @@ -50,7 +84,7 @@ export function useNip57QuickZap(opts: {
})
const sendQuickZap = useCallback(() => {
if (!canQuickNip57Zap || zapping) return
if (!canQuickNip57Zap || zapping || !nip57Addresses?.length) return
checkLogin(async () => {
if (!pubkey) return
try {
@ -63,11 +97,18 @@ export function useNip57QuickZap(opts: { @@ -63,11 +97,18 @@ export function useNip57QuickZap(opts: {
opts.onZapDialogClose,
undefined,
{
address: lightningAddressOptions[0],
candidates: lightningAddressOptions
address: nip57Addresses[0],
candidates: nip57Addresses
}
)
if (!zapResult) return
if (includePublicZapReceipt && zapResult.zapReceipt === null) {
toast.warning(
t(
'Zap paid but no public receipt was published. The recipient may not use a NIP-57 zap wallet.'
)
)
}
if (opts.referencedEvent) {
noteStatsService.addZap(
pubkey,
@ -86,11 +127,12 @@ export function useNip57QuickZap(opts: { @@ -86,11 +127,12 @@ export function useNip57QuickZap(opts: {
}, [
canQuickNip57Zap,
zapping,
nip57Addresses,
checkLogin,
pubkey,
defaultZapSats,
defaultZapComment,
lightningAddressOptions,
includePublicZapReceipt,
opts,
t
])

20
src/i18n/locales/de.ts

@ -212,9 +212,14 @@ export default { @@ -212,9 +212,14 @@ export default {
'Failed to publish payment info': 'Failed to publish payment info',
'Invalid tags JSON': 'Invalid tags JSON',
'Payment methods': 'Zahlungsmethoden',
'Send a payment to this user': 'Zahlung an diese Person senden',
'Leave a tip': 'Trinkgeld geben',
Tips: 'Tipps',
'Payment targets': 'Zahlungsziele',
'Tip options': 'Tipp-Optionen',
'Send a payment to this user': 'Trinkgeld geben',
'No payment methods available for this profile':
'Keine Zahlungsmethoden für dieses Profil hinterlegt',
'Keine Zahlungsziele in diesem Profil',
'No payment targets on this profile': 'Keine Zahlungsziele in diesem Profil',
'Other payment methods': 'Weitere Zahlungsmethoden',
'Lightning address for zap': 'Lightning-Adresse für Zap',
'Select lightning address': 'Lightning-Adresse wählen',
@ -289,7 +294,8 @@ export default { @@ -289,7 +294,8 @@ export default {
'NIP-A3 payto-Tags: Typ (z. B. lightning) und Authority (z. B. user@domain.com).',
'Type (e.g. lightning)': 'Type (e.g. lightning)',
'Authority (e.g. user@domain.com)': 'Authority (e.g. user@domain.com)',
'Add payment method': 'Add payment method',
'Add payment method': 'Zahlungsziel hinzufügen',
'Add payment target': 'Zahlungsziel hinzufügen',
Remove: 'Remove',
'Additional content (JSON)': 'Additional content (JSON)',
'Show full event JSON': 'Show full event JSON',
@ -679,7 +685,7 @@ export default { @@ -679,7 +685,7 @@ export default {
'Quick zap': 'Schneller Zap',
'Preferred payto category': 'Bevorzugte Payto-Kategorie',
'Show this category expanded on payment method lists; other categories collapse behind an accordion.':
'Diese Kategorie in Zahlungsmethodenlisten ausgeklappt anzeigen; andere Kategorien hinter einem Akkordeon einklappen.',
'Diese Kategorie in Tipp-Dialogen ausgeklappt anzeigen; andere Kategorien hinter einem Akkordeon einklappen.',
'Show all categories': 'Alle Kategorien anzeigen',
'Other payment categories ({{count}})': 'Weitere Zahlungskategorien ({{count}})',
'paytoCategory.bitcoin': 'Bitcoin',
@ -694,6 +700,10 @@ export default { @@ -694,6 +700,10 @@ export default {
'Include public zap receipt': 'Include public zap receipt',
'When off, your zap may still succeed but a public receipt may not be published to relays':
'When off, your zap may still succeed but a public receipt may not be published to relays',
'Zap paid but no public receipt was published. The recipient may not use a NIP-57 zap wallet.':
'Zap bezahlt, aber keine öffentliche Quittung veröffentlicht. Der Empfänger nutzt möglicherweise keine NIP-57-Zap-Wallet.',
'Plain Lightning payments do not create NIP-57 zap receipts on Nostr. Use the tip button when available.':
'Einfache Lightning-Zahlungen erstellen keine NIP-57-Zap-Quittungen auf Nostr. Nutze den Tipp-Button, wenn verfügbar.',
All: 'Alle',
Reactions: 'Reaktionen',
Zaps: 'Zaps',
@ -2709,7 +2719,7 @@ export default { @@ -2709,7 +2719,7 @@ export default {
'Add to list': 'Add to list',
'Block relay': 'Block relay',
'Choose app': 'Choose app',
'Payment Methods': 'Payment Methods',
'Payment Methods': 'Zahlungsziele',
'Unfollowed thread notifications': 'Unfollowed thread notifications',
'Unmute thread notifications': 'Unmute thread notifications',
'Unmuted thread notifications': 'Unmuted thread notifications',

20
src/i18n/locales/en.ts

@ -209,9 +209,14 @@ export default { @@ -209,9 +209,14 @@ export default {
'Failed to publish payment info': 'Failed to publish payment info',
'Invalid tags JSON': 'Invalid tags JSON',
'Payment methods': 'Payment methods',
'Send a payment to this user': 'Send a payment to this user',
'Leave a tip': 'Leave a tip',
Tips: 'Tips',
'Payment targets': 'Payment targets',
'Tip options': 'Tip options',
'Send a payment to this user': 'Leave a tip',
'No payment methods available for this profile':
'No payment methods available for this profile',
'No payment targets on this profile',
'No payment targets on this profile': 'No payment targets on this profile',
'Other payment methods': 'Other payment methods',
'Lightning address for zap': 'Lightning address for zap',
'Select lightning address': 'Select lightning address',
@ -285,7 +290,8 @@ export default { @@ -285,7 +290,8 @@ export default {
'NIP-A3 payto tags: type (e.g. lightning) and authority (e.g. user@domain.com).',
'Type (e.g. lightning)': 'Type (e.g. lightning)',
'Authority (e.g. user@domain.com)': 'Authority (e.g. user@domain.com)',
'Add payment method': 'Add payment method',
'Add payment method': 'Add payment target',
'Add payment target': 'Add payment target',
Remove: 'Remove',
'Additional content (JSON)': 'Additional content (JSON)',
'Show full event JSON': 'Show full event JSON',
@ -675,7 +681,7 @@ export default { @@ -675,7 +681,7 @@ export default {
'Quick zap': 'Quick zap',
'Preferred payto category': 'Preferred payto category',
'Show this category expanded on payment method lists; other categories collapse behind an accordion.':
'Show this category expanded on payment method lists; other categories collapse behind an accordion.',
'Show this category expanded on tip dialogs; other categories collapse behind an accordion.',
'Show all categories': 'Show all categories',
'Other payment categories ({{count}})': 'Other payment categories ({{count}})',
'paytoCategory.bitcoin': 'Bitcoin',
@ -690,6 +696,10 @@ export default { @@ -690,6 +696,10 @@ export default {
'Include public zap receipt': 'Include public zap receipt',
'When off, your zap may still succeed but a public receipt may not be published to relays':
'When off, your zap may still succeed but a public receipt may not be published to relays',
'Zap paid but no public receipt was published. The recipient may not use a NIP-57 zap wallet.':
'Zap paid but no public receipt was published. The recipient may not use a NIP-57 zap wallet.',
'Plain Lightning payments do not create NIP-57 zap receipts on Nostr. Use the tip button when available.':
'Plain Lightning payments do not create NIP-57 zap receipts on Nostr. Use the tip button when available.',
All: 'All',
Reactions: 'Reactions',
Zaps: 'Zaps',
@ -2678,7 +2688,7 @@ export default { @@ -2678,7 +2688,7 @@ export default {
'Add to list': 'Add to list',
'Block relay': 'Block relay',
'Choose app': 'Choose app',
'Payment Methods': 'Payment Methods',
'Payment Methods': 'Payment targets',
'Unfollowed thread notifications': 'Unfollowed thread notifications',
'Unmute thread notifications': 'Unmute thread notifications',
'Unmuted thread notifications': 'Unmuted thread notifications',

4
src/pages/secondary/ProfileEditorPage/index.tsx

@ -789,7 +789,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => { @@ -789,7 +789,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
</DialogHeader>
<div className="flex-1 overflow-auto space-y-4 pb-6">
<Item>
<Label className="text-muted-foreground">{t('Payment methods')}</Label>
<Label className="text-muted-foreground">{t('Payment targets')}</Label>
<p className="text-xs text-muted-foreground">
{t('paytoEditor.intro', {
defaultValue:
@ -833,7 +833,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => { @@ -833,7 +833,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
}
>
<Plus className="h-3.5 w-3.5" />
{t('Add payment method')}
{t('Add payment target')}
</Button>
</div>
</Item>

118
src/services/lightning.service.ts

@ -31,7 +31,12 @@ import { TProfile } from '@/types' @@ -31,7 +31,12 @@ import { TProfile } from '@/types'
export type TRecentSupporter = { pubkey: string; amount: number; comment?: string }
export type PaymentFlowResult = { preimage: string; invoice: string } | null
export type PaymentFlowResult = {
preimage: string
invoice: string
/** Set when we waited for a kind 9735 receipt on relays (null = none seen in time). */
zapReceipt?: NostrEvent | null
} | null
/** LNURL-pay limits from the recipient’s `.well-known/lnurlp` metadata. */
export type LnurlPayInvoiceOptions = {
@ -49,8 +54,9 @@ class LightningService { @@ -49,8 +54,9 @@ class LightningService {
private recentSupportersCache: TRecentSupporter[] | null = null
private lnurlPayMetadataCache = new Map<
string,
{ fetchedAt: number; meta: NonNullable<Awaited<ReturnType<LightningService['resolveLnurlPayMetadata']>>> }
{ fetchedAt: number; meta: Awaited<ReturnType<LightningService['resolveLnurlPayMetadata']>> }
>()
private nip57EnabledAddressCache = new Map<string, { fetchedAt: number; addrs: string[] }>()
constructor() {
if (!LightningService.instance) {
@ -141,7 +147,16 @@ class LightningService { @@ -141,7 +147,16 @@ class LightningService {
try {
const { preimage } = await sendWebLNPaymentWithRetry(this.provider, pr)
closeOuterModel?.()
const result = { preimage, invoice: pr }
const zapReceipt =
relays.length > 0
? await this.waitForZapReceipt({
recipient,
event,
invoice: pr,
relayUrls: relays
})
: undefined
const result: PaymentFlowResult = { preimage, invoice: pr, zapReceipt }
onPaymentFlowComplete?.(result)
return result
} catch (error) {
@ -156,19 +171,27 @@ class LightningService { @@ -156,19 +171,27 @@ class LightningService {
closeModal()
let checkPaymentInterval: ReturnType<typeof setInterval> | undefined
let subCloser: SubCloser | undefined
const finish = (result: PaymentFlowResult) => {
const finish = async (result: PaymentFlowResult) => {
clearInterval(checkPaymentInterval)
subCloser?.close()
if (result && relays.length > 0 && result.zapReceipt === undefined) {
result.zapReceipt = await this.waitForZapReceipt({
recipient,
event,
invoice: result.invoice,
relayUrls: relays
})
}
onPaymentFlowComplete?.(result)
resolve(result)
}
const { setPaid } = launchPaymentModal({
invoice: pr,
onPaid: (response) => {
finish({ preimage: response.preimage, invoice: pr })
void finish({ preimage: response.preimage, invoice: pr })
},
onCancelled: () => {
finish(null)
void finish(null)
}
})
@ -211,6 +234,67 @@ class LightningService { @@ -211,6 +234,67 @@ class LightningService {
})
}
/** Lightning addresses whose LNURL-pay endpoint supports NIP-57 (`allowsNostr` + `nostrPubkey`). */
async filterNip57ZapEnabledAddresses(candidates: string[]): Promise<string[]> {
const key = candidates
.map((c) => c.trim().toLowerCase())
.filter(Boolean)
.join('\u0001')
if (!key) return []
const cached = this.nip57EnabledAddressCache.get(key)
if (cached && Date.now() - cached.fetchedAt < 60_000) {
return cached.addrs
}
const enabled: string[] = []
for (const addr of candidates) {
const endpoint = await this.fetchLnurlPayZapEndpoint(addr)
if (endpoint) enabled.push(addr)
}
const addrs = prioritizeZapLightningAddress(enabled, candidates[0])
this.nip57EnabledAddressCache.set(key, { fetchedAt: Date.now(), addrs })
return addrs
}
private waitForZapReceipt(params: {
recipient: string
event?: NostrEvent
invoice: string
relayUrls: string[]
timeoutMs?: number
}): Promise<NostrEvent | null> {
const relayUrls = [...new Set([...params.relayUrls, ...FAST_READ_RELAY_URLS])].slice(0, 8)
if (relayUrls.length === 0) return Promise.resolve(null)
return new Promise((resolve) => {
let subCloser: SubCloser | undefined
const timeout = setTimeout(() => {
subCloser?.close()
resolve(null)
}, params.timeoutMs ?? 20_000)
const filter: Filter = {
kinds: [kinds.Zap],
'#p': [params.recipient],
since: dayjs().subtract(2, 'minute').unix()
}
if (params.event) {
filter['#e'] = [params.event.id]
}
subCloser = client.subscribe(relayUrls, filter, {
onevent: (evt) => {
const info = getZapInfoFromEvent(evt)
if (!info || info.invoice !== params.invoice) return
clearTimeout(timeout)
subCloser?.close()
resolve(evt)
}
})
})
}
async payInvoice(
invoice: string,
closeOuterModel?: () => void,
@ -407,16 +491,23 @@ class LightningService { @@ -407,16 +491,23 @@ class LightningService {
}> {
const cacheKey = lightningAddress.trim().toLowerCase()
const cached = this.lnurlPayMetadataCache.get(cacheKey)
if (cached && Date.now() - cached.fetchedAt < 30_000) {
if (cached && Date.now() - cached.fetchedAt < 60_000) {
return cached.meta
}
const remember = (
meta: Awaited<ReturnType<LightningService['resolveLnurlPayMetadata']>>
) => {
this.lnurlPayMetadataCache.set(cacheKey, { fetchedAt: Date.now(), meta })
return meta
}
try {
let lnurl = ''
if (lightningAddress.includes('@')) {
const [name, domain] = lightningAddress.split('@')
if (!name?.trim() || !domain?.trim()) return null
if (!name?.trim() || !domain?.trim()) return remember(null)
lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString()
} else {
const { words } = bech32.decode(lightningAddress as any, 1000)
@ -432,7 +523,7 @@ class LightningService { @@ -432,7 +523,7 @@ class LightningService {
lnurl,
lightningAddress
})
return null
return remember(null)
}
const text = await res.text()
@ -452,10 +543,10 @@ class LightningService { @@ -452,10 +543,10 @@ class LightningService {
lightningAddress,
preview: text.slice(0, 160)
})
return null
return remember(null)
}
if (typeof body.callback !== 'string' || !body.callback) return null
if (typeof body.callback !== 'string' || !body.callback) return remember(null)
const commentAllowed = parseLnurlCommentAllowed(body.commentAllowed)
@ -468,8 +559,7 @@ class LightningService { @@ -468,8 +559,7 @@ class LightningService {
minSendable: typeof body.minSendable === 'number' ? body.minSendable : undefined,
maxSendable: typeof body.maxSendable === 'number' ? body.maxSendable : undefined
}
this.lnurlPayMetadataCache.set(cacheKey, { fetchedAt: Date.now(), meta })
return meta
return remember(meta)
} catch (err) {
const failedFetch =
err instanceof TypeError || (err instanceof Error && err.message === 'Failed to fetch')
@ -481,7 +571,7 @@ class LightningService { @@ -481,7 +571,7 @@ class LightningService {
})
}
return null
return remember(null)
}
}

Loading…
Cancel
Save