diff --git a/src/api/hooks/nostr/useSignerStream.ts b/src/api/hooks/nostr/useSignerStream.ts index 216c3a8e31..56db382b17 100644 --- a/src/api/hooks/nostr/useSignerStream.ts +++ b/src/api/hooks/nostr/useSignerStream.ts @@ -1,9 +1,10 @@ import { NiceRelay } from 'nostr-machina'; +import { type Event } from 'nostr-tools'; import { useEffect, useMemo } from 'react'; import { nip04, signEvent } from 'soapbox/features/nostr/sign'; import { useInstance } from 'soapbox/hooks'; -import { connectRequestSchema } from 'soapbox/schemas/nostr'; +import { connectRequestSchema, nwcRequestSchema } from 'soapbox/schemas/nostr'; import { jsonSchema } from 'soapbox/schemas/utils'; function useSignerStream() { @@ -18,35 +19,64 @@ function useSignerStream() { } }, [relayUrl]); - useEffect(() => { + async function handleConnectEvent(event: Event) { + if (!relay || !pubkey) return; + const decrypted = await nip04.decrypt(pubkey, event.content); + + const reqMsg = jsonSchema.pipe(connectRequestSchema).safeParse(decrypted); + if (!reqMsg.success) { + console.warn(decrypted); + console.warn(reqMsg.error); + return; + } + + const respMsg = { + id: reqMsg.data.id, + result: await signEvent(reqMsg.data.params[0], reqMsg.data.params[1]), + }; + + const respEvent = await signEvent({ + kind: 24133, + content: await nip04.encrypt(pubkey, JSON.stringify(respMsg)), + tags: [['p', pubkey]], + created_at: Math.floor(Date.now() / 1000), + }); + + relay.send(['EVENT', respEvent]); + } + + async function handleWalletEvent(event: Event) { if (!relay || !pubkey) return; - const sub = relay.req([{ kinds: [24133], authors: [pubkey], limit: 0 }]); + const decrypted = await nip04.decrypt(pubkey, event.content); + + const reqMsg = jsonSchema.pipe(nwcRequestSchema).safeParse(decrypted); + if (!reqMsg.success) { + console.warn(decrypted); + console.warn(reqMsg.error); + return; + } + + // @ts-ignore + await window.webln?.enable(); + // @ts-ignore + await window.webln?.sendPayment(reqMsg.data.params.invoice); + } + + useEffect(() => { + if (!relay || !pubkey) return; + const sub = relay.req([{ kinds: [24133, 23194], authors: [pubkey], limit: 0 }]); const readEvents = async () => { for await (const event of sub) { - const decrypted = await nip04.decrypt(pubkey, event.content); - - const reqMsg = jsonSchema.pipe(connectRequestSchema).safeParse(decrypted); - if (!reqMsg.success) { - console.warn(decrypted); - console.warn(reqMsg.error); - return; + switch (event.kind) { + case 24133: + await handleConnectEvent(event); + break; + case 23194: + await handleWalletEvent(event); + break; } - - const respMsg = { - id: reqMsg.data.id, - result: await signEvent(reqMsg.data.params[0], reqMsg.data.params[1]), - }; - - const respEvent = await signEvent({ - kind: 24133, - content: await nip04.encrypt(pubkey, JSON.stringify(respMsg)), - tags: [['p', pubkey]], - created_at: Math.floor(Date.now() / 1000), - }); - - relay.send(['EVENT', respEvent]); } }; diff --git a/src/schemas/nostr.ts b/src/schemas/nostr.ts index e8aa80e9ed..549bd497ad 100644 --- a/src/schemas/nostr.ts +++ b/src/schemas/nostr.ts @@ -36,4 +36,12 @@ const connectRequestSchema = z.object({ params: z.tuple([eventTemplateSchema]).or(z.tuple([eventTemplateSchema, signEventOptsSchema])), }); -export { nostrIdSchema, kindSchema, eventSchema, signedEventSchema, connectRequestSchema }; \ No newline at end of file +/** NIP-47 signer response. */ +const nwcRequestSchema = z.object({ + method: z.literal('pay_invoice'), + params: z.object({ + invoice: z.string(), + }), +}); + +export { nostrIdSchema, kindSchema, eventSchema, signedEventSchema, connectRequestSchema, nwcRequestSchema }; \ No newline at end of file