story-research-zapwall/lib/sponsoringQueries.ts
2026-01-06 21:16:28 +01:00

160 lines
4.3 KiB
TypeScript

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<Sponsoring | null> {
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<Sponsoring | null>((resolve) => {
const relayUrl = getPrimaryRelaySync()
const sub = createSubscription(pool, [relayUrl], filters)
let finished = false
const done = async (value: Sponsoring | null): Promise<void> => {
if (finished) {
return
}
finished = true
sub.unsub()
resolve(value)
}
sub.on('event', (event: Event): void => {
void (async (): Promise<void> => {
const sponsoringParsed = await parseSponsoringFromEvent(event)
if (sponsoringParsed?.id === sponsoringId) {
// Cache the parsed sponsoring
if (sponsoringParsed.hash) {
await objectCache.set('sponsoring', sponsoringParsed.hash, event, sponsoringParsed, 0, false, sponsoringParsed.index ?? 0)
}
done(sponsoringParsed)
}
})()
})
sub.on('eose', (): void => {
void done(null)
})
setTimeout((): void => {
void done(null)
}, timeoutMs).unref?.()
})
}
export function getSponsoringByAuthor(authorPubkey: string, timeoutMs: number = 5000): Promise<Sponsoring[]> {
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<Sponsoring[]>((resolve) => {
const results: Sponsoring[] = []
const relayUrl = getPrimaryRelaySync()
const sub = createSubscription(pool, [relayUrl], filters)
let finished = false
const done = async (): Promise<void> => {
if (finished) {
return
}
finished = true
sub.unsub()
resolve(results)
}
sub.on('event', (event: Event): void => {
void (async (): Promise<void> => {
const sponsoringParsed = await parseSponsoringFromEvent(event)
if (sponsoringParsed?.authorPubkey === authorPubkey) {
// Cache the parsed sponsoring
if (sponsoringParsed.hash) {
await objectCache.set('sponsoring', sponsoringParsed.hash, event, sponsoringParsed, 0, false, sponsoringParsed.index ?? 0)
}
results.push(sponsoringParsed)
}
})()
})
sub.on('eose', (): void => {
void done()
})
setTimeout(() => done(), timeoutMs).unref?.()
})
}