| 89 | } |
| 90 | |
| 91 | export class NwcPaymentsProcessor implements IPaymentsProcessor { |
| 92 | public constructor( |
| 93 | private nwcUrl: string, |
| 94 | private replyTimeoutMs: number, |
| 95 | private settings: Factory<Settings>, |
| 96 | ) {} |
| 97 | |
| 98 | private withReplyTimeout = async <T>(operation: Promise<T>): Promise<T> => { |
| 99 | const controller = new AbortController() |
| 100 | const timeout = sleep(this.replyTimeoutMs, undefined, { |
| 101 | ref: false, |
| 102 | signal: controller.signal, |
| 103 | }) |
| 104 | .then(() => { |
| 105 | throw new nwc.Nip47ReplyTimeoutError(`reply timeout after ${this.replyTimeoutMs}ms`, 'INTERNAL') |
| 106 | }) |
| 107 | .catch((error) => { |
| 108 | if ((error as Error).name === 'AbortError') { |
| 109 | return undefined as never |
| 110 | } |
| 111 | |
| 112 | throw error |
| 113 | }) |
| 114 | |
| 115 | try { |
| 116 | return await Promise.race([operation, timeout]) |
| 117 | } finally { |
| 118 | controller.abort() |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | private withClient = async <T>(fn: (client: nwc.NWCClient) => Promise<T>): Promise<T> => { |
| 123 | const client = new nwc.NWCClient({ nostrWalletConnectUrl: this.nwcUrl }) |
| 124 | let caughtError: unknown |
| 125 | |
| 126 | try { |
| 127 | return await fn(client) |
| 128 | } catch (error) { |
| 129 | caughtError = error |
| 130 | throw error |
| 131 | } finally { |
| 132 | if (caughtError instanceof nwc.Nip47ReplyTimeoutError) { |
| 133 | // The SDK can still emit a late response; this wait must not keep the process alive. |
| 134 | await sleep(this.replyTimeoutMs + 100, undefined, { ref: false }) |
| 135 | } |
| 136 | client.close() |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | public async getInvoice(invoiceOrId: string | Invoice): Promise<GetInvoiceResponse> { |
| 141 | const invoiceId = typeof invoiceOrId === 'string' ? invoiceOrId : invoiceOrId.id |
| 142 | logger('get invoice: %s', invoiceId) |
| 143 | |
| 144 | try { |
| 145 | return await this.withClient(async (client) => { |
| 146 | const transaction = (await this.withReplyTimeout( |
| 147 | client.lookupInvoice({ payment_hash: invoiceId }), |
| 148 | )) as NwcTransaction |