import Nostr from '@/lib/nostr' import { string } from '@/lib/yup' import { parseNwcUrl } from '@/lib/url' import { NDKNwc } from '@nostr-dev-kit/ndk' import { TimeoutError } from '@/lib/time' const NWC_CONNECT_TIMEOUT_MS = 15_000 export const name = 'nwc' export const walletType = 'NWC' export const walletField = 'walletNWC' export const fields = [ { name: 'nwcUrl', label: 'connection', type: 'password', optional: 'for sending', clientOnly: true, requiredWithout: 'nwcUrlRecv', validate: string().nwcUrl() }, { name: 'nwcUrlRecv', label: 'connection', type: 'password', optional: 'for receiving', serverOnly: true, requiredWithout: 'nwcUrl', validate: string().nwcUrl() } ] export const card = { title: 'NWC', subtitle: 'use Nostr Wallet Connect for payments' } async function getNwc (nostr, nwcUrl, { signal }) { const ndk = nostr.ndk const { walletPubkey, secret, relayUrls } = parseNwcUrl(nwcUrl) const nwc = new NDKNwc({ ndk, pubkey: walletPubkey, relayUrls, secret }) // TODO: support AbortSignal try { await nwc.blockUntilReady(NWC_CONNECT_TIMEOUT_MS) } catch (err) { if (err.message === 'Timeout') { throw new TimeoutError(NWC_CONNECT_TIMEOUT_MS) } throw err } return nwc } /** * Run a nwc function and throw if it errors * (workaround to handle ambiguous NDK error handling) * @param {function} fun - the nwc function to run * @returns - the result of the nwc function */ export async function nwcTryRun (fun, { nwcUrl }, { signal }) { const nostr = new Nostr() try { const nwc = await getNwc(nostr, nwcUrl, { signal }) const { error, result } = await fun(nwc) if (error) throw new Error(error.message || error.code) return result } catch (e) { if (e.error) throw new Error(e.error.message || e.error.code) throw e } finally { nostr.close() } } export async function supportedMethods (nwcUrl, { signal }) { const result = await nwcTryRun(nwc => nwc.getInfo(), { nwcUrl }, { signal }) return result.methods }