import { nostrService } from './nostr' import { getPrimaryRelaySync } from './config' import type { Event } from 'nostr-tools' import { createSubscription } from '@/types/nostr-tools-extended' export function createMessageVerificationFilters(messageEventId: string, authorPubkey: string, recipientPubkey: string, articleId: string): Array<{ kinds: number[] ids: string[] authors: string[] '#p': string[] '#e': string[] limit: number }> { return [ { kinds: [4], ids: [messageEventId], authors: [authorPubkey], '#p': [recipientPubkey], '#e': [articleId], limit: 1, }, ] } interface MessageVerificationContext { messageEventId: string articleId: string recipientPubkey: string authorPubkey: string } export function handleMessageVerificationEvent( event: import('nostr-tools').Event, ctx: MessageVerificationContext, finalize: (value: boolean) => void ): void { console.warn('Private message verified on relay', { messageEventId: event.id, articleId: ctx.articleId, recipientPubkey: ctx.recipientPubkey, authorPubkey: ctx.authorPubkey, timestamp: new Date().toISOString(), }) finalize(true) } export function setupMessageVerificationHandlers( params: { sub: import('@/types/nostr-tools-extended').Subscription ctx: MessageVerificationContext finalize: (value: boolean) => void isResolved: () => boolean } ): void { params.sub.on('event', (event: Event): void => { handleMessageVerificationEvent(event, params.ctx, params.finalize) }) params.sub.on('eose', (): void => { console.warn('Private message not found on relay after EOSE', { messageEventId: params.ctx.messageEventId, articleId: params.ctx.articleId, recipientPubkey: params.ctx.recipientPubkey, timestamp: new Date().toISOString(), }) params.finalize(false) }) setTimeout(() => { if (!params.isResolved()) { console.warn('Timeout verifying private message on relay', { messageEventId: params.ctx.messageEventId, articleId: params.ctx.articleId, recipientPubkey: params.ctx.recipientPubkey, timestamp: new Date().toISOString(), }) params.finalize(false) } }, 5000) } function createMessageVerificationSubscription( params: { pool: import('nostr-tools').SimplePool; ctx: MessageVerificationContext } ): ReturnType { const filters = createMessageVerificationFilters( params.ctx.messageEventId, params.ctx.authorPubkey, params.ctx.recipientPubkey, params.ctx.articleId ) const relayUrl = getPrimaryRelaySync() return createSubscription(params.pool, [relayUrl], filters) } function createVerificationPromise( params: { sub: import('@/types/nostr-tools-extended').Subscription; ctx: MessageVerificationContext } ): Promise { return new Promise((resolve) => { let resolved = false const finalize = (value: boolean): void => { if (resolved) { return } resolved = true params.sub.unsub() resolve(value) } setupMessageVerificationHandlers({ sub: params.sub, ctx: params.ctx, finalize, isResolved: () => resolved }) }) } export function verifyPrivateMessagePublished( messageEventId: string, authorPubkey: string, recipientPubkey: string, articleId: string ): Promise { try { const pool = nostrService.getPool() if (!pool) { console.error('Pool not initialized for message verification', { messageEventId, articleId, recipientPubkey, }) return Promise.resolve(false) } const ctx: MessageVerificationContext = { messageEventId, articleId, recipientPubkey, authorPubkey } const sub = createMessageVerificationSubscription({ pool, ctx }) return createVerificationPromise({ sub, ctx }) } catch (error) { console.error('Error verifying private message', { messageEventId, articleId, recipientPubkey, error: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }) return Promise.resolve(false) } } export async function publishAndVerifyMessage( articleId: string, recipientPubkey: string, authorPubkey: string, messageEventId: string ): Promise { const verified = await verifyPrivateMessagePublished(messageEventId, authorPubkey, recipientPubkey, articleId) if (verified) { console.warn('Private message verified on relay', { messageEventId, articleId, recipientPubkey }) } else { console.warn('Private message published but not yet verified on relay', { messageEventId, articleId, recipientPubkey }) } return verified }