import type { Event, Filter } from 'nostr-tools' import type { SimplePoolWithSub } from '@/types/nostr-tools-extended' import { createSubscription } from '@/types/nostr-tools-extended' import { buildTagFilter, extractTagsFromEvent } from '../nostrTagSystem' import { getPrimaryRelaySync } from '../config' import { MIN_EVENT_DATE, PLATFORM_SERVICE } from '../platformConfig' import { getLatestVersion } from '../versionManager' import { objectCache } from '../objectCache' import { parsePresentationEvent } from './parsePresentationEvent' export async function fetchAuthorPresentationFromPool( pool: SimplePoolWithSub, pubkey: string ): Promise { const cached = await objectCache.getAuthorByPubkey(pubkey) if (cached) { return enrichAuthorPresentationWithSponsoring({ author: cached, pubkey }) } const filters: Filter[] = [ { ...buildTagFilter({ type: 'author', authorPubkey: pubkey, service: PLATFORM_SERVICE }), since: MIN_EVENT_DATE, limit: 100, }, ] return fetchAuthorPresentationFromRelay({ pool, pubkey, filters }) } async function enrichAuthorPresentationWithSponsoring(params: { author: import('@/types/nostr').AuthorPresentationArticle pubkey: string }): Promise { const { getAuthorSponsoring } = await import('../sponsoring') const totalSponsoring = await getAuthorSponsoring(params.pubkey) return { ...params.author, totalSponsoring } } async function fetchAuthorPresentationFromRelay(params: { pool: SimplePoolWithSub pubkey: string filters: Filter[] }): Promise { const relayUrl = getPrimaryRelaySync() const events: Event[] = [] const sub = createSubscription(params.pool, [relayUrl], params.filters) const finalize = createRelayFetchFinalizer({ pubkey: params.pubkey, sub, events }) return new Promise((resolve) => { const finalizeAndResolve = async (value: import('@/types/nostr').AuthorPresentationArticle | null): Promise => { const finalValue = await finalize(value) resolve(finalValue) } sub.on('event', (event: Event): void => { const tags = extractTagsFromEvent(event) if (tags.type === 'author' && !tags.hidden) { events.push(event) } }) sub.on('eose', (): void => { void tryFinalizeFromLatestEvent({ events, finalize: finalizeAndResolve }) }) setTimeout((): void => { void tryFinalizeFromLatestEvent({ events, finalize: finalizeAndResolve }) }, 2000).unref?.() }) } async function tryFinalizeFromLatestEvent(params: { events: Event[] finalize: (value: import('@/types/nostr').AuthorPresentationArticle | null) => Promise }): Promise { const latestEvent = getLatestVersion(params.events) if (!latestEvent) { await params.finalize(null) return } const parsed = await parsePresentationEvent(latestEvent) await params.finalize(parsed) } function createRelayFetchFinalizer(params: { pubkey: string sub: import('@/types/nostr-tools-extended').Subscription events: Event[] }): (value: import('@/types/nostr').AuthorPresentationArticle | null) => Promise { let resolved = false return async (value: import('@/types/nostr').AuthorPresentationArticle | null): Promise => { if (resolved) { return value } resolved = true params.sub.unsub() return cacheAuthorPresentationFromEvents({ value, events: params.events, pubkey: params.pubkey }) } } async function cacheAuthorPresentationFromEvents(params: { value: import('@/types/nostr').AuthorPresentationArticle | null events: Event[] pubkey: string }): Promise { if (!params.value || params.events.length === 0 || !params.value.hash) { return params.value } const event = params.events.find((e) => e.id === params.value?.id) ?? params.events[0] if (!event) { return params.value } const tags = extractTagsFromEvent(event) const cachedValue = await enrichAuthorPresentationWithSponsoring({ author: params.value, pubkey: params.pubkey }) const { writeObjectToCache } = await import('../helpers/writeObjectHelper') await writeObjectToCache({ objectType: 'author', hash: params.value.hash, event, parsed: cachedValue, version: tags.version, hidden: tags.hidden, index: params.value.index, }) return cachedValue }