import type { Event } from 'nostr-tools' import { nostrService } from './nostr' import type { Sponsoring } from '@/types/nostr' import { parseSponsoringFromEvent } from './nostrEventParsing' import { objectCache } from './objectCache' import { getPrimaryRelaySync } from './config' import { MIN_EVENT_DATE } from './platformConfig' import { parseObjectId } from './urlGenerator' function buildSponsoringFilters(authorPubkey?: string, payerPubkey?: string, seriesId?: string, articleId?: string): Array<{ kinds: number[] since?: number authors?: string[] '#p'?: string[] '#series'?: string[] '#article'?: string[] '#kind_type'?: string[] }> { const filters: Array<{ kinds: number[] since?: number authors?: string[] '#p'?: string[] '#series'?: string[] '#article'?: string[] '#kind_type'?: string[] }> = [] const baseFilter: { kinds: number[] since: number '#kind_type': string[] authors?: string[] '#p'?: string[] '#series'?: string[] '#article'?: string[] } = { kinds: [9735], // Zap receipt since: MIN_EVENT_DATE, '#kind_type': ['sponsoring'], } if (payerPubkey) { baseFilter.authors = [payerPubkey] } if (authorPubkey) { baseFilter['#p'] = [authorPubkey] } if (seriesId) { baseFilter['#series'] = [seriesId] } if (articleId) { baseFilter['#article'] = [articleId] } filters.push(baseFilter) return filters } export async function getSponsoringById(sponsoringId: string, timeoutMs: number = 5000): Promise { const parsed = parseObjectId(sponsoringId) const hash = parsed.hash ?? sponsoringId // Check cache first const cached = await objectCache.get('sponsoring', hash) if (cached) { return cached as Sponsoring } const pool = nostrService.getPool() if (!pool) { throw new Error('Pool not initialized') } const filters = buildSponsoringFilters() const { createSubscription } = require('@/types/nostr-tools-extended') return new Promise((resolve) => { const relayUrl = getPrimaryRelaySync() const sub = createSubscription(pool, [relayUrl], filters) let finished = false const done = async (value: Sponsoring | null): Promise => { if (finished) { return } finished = true sub.unsub() resolve(value) } sub.on('event', async (event: Event) => { const parsed = await parseSponsoringFromEvent(event) if (parsed?.id === sponsoringId) { // Cache the parsed sponsoring if (parsed.hash) { await objectCache.set('sponsoring', parsed.hash, event, parsed, 0, false, parsed.index) } done(parsed) } }) sub.on('eose', (): void => { void done(null) }) setTimeout(() => done(null), timeoutMs).unref?.() }) } export function getSponsoringByAuthor(authorPubkey: string, timeoutMs: number = 5000): Promise { const pool = nostrService.getPool() if (!pool) { throw new Error('Pool not initialized') } const filters = buildSponsoringFilters(authorPubkey) const { createSubscription } = require('@/types/nostr-tools-extended') return new Promise((resolve) => { const results: Sponsoring[] = [] const relayUrl = getPrimaryRelaySync() const sub = createSubscription(pool, [relayUrl], filters) let finished = false const done = async (): Promise => { if (finished) { return } finished = true sub.unsub() resolve(results) } sub.on('event', async (event: Event): Promise => { const parsed = await parseSponsoringFromEvent(event) if (parsed?.authorPubkey === authorPubkey) { // Cache the parsed sponsoring if (parsed.hash) { await objectCache.set('sponsoring', parsed.hash, event, parsed, 0, false, parsed.index) } results.push(parsed) } }) sub.on('eose', (): void => { void done() }) setTimeout(() => done(), timeoutMs).unref?.() }) }