story-research-zapwall/lib/authorQueries.ts
2026-01-06 14:17:55 +01:00

111 lines
3.5 KiB
TypeScript

/**
* Query authors by hash ID or pubkey (for backward compatibility)
*/
import type { Event } from 'nostr-tools'
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
import { buildTagFilter, extractTagsFromEvent } from './nostrTagSystem'
import { getPrimaryRelaySync } from './config'
import { PLATFORM_SERVICE, MIN_EVENT_DATE } from './platformConfig'
import { parsePresentationEvent, fetchAuthorPresentationFromPool } from './articlePublisherHelpersPresentation'
import { getLatestVersion } from './versionManager'
import { objectCache } from './objectCache'
/**
* Fetch author presentation by hash ID or pubkey
* If the parameter looks like a pubkey (64 hex chars), it uses pubkey lookup
* Otherwise, it uses hash ID lookup
*/
export async function fetchAuthorByHashId(
pool: SimplePoolWithSub,
hashIdOrPubkey: string
): Promise<import('@/types/nostr').AuthorPresentationArticle | null> {
// Check if it's a pubkey (64 hex characters) for backward compatibility
if (/^[a-f0-9]{64}$/i.test(hashIdOrPubkey)) {
return fetchAuthorPresentationFromPool(pool, hashIdOrPubkey)
}
// Otherwise, treat as hash ID
const hashId = hashIdOrPubkey
// Check cache first
const cached = await objectCache.get('author', hashId)
if (cached) {
return cached as import('@/types/nostr').AuthorPresentationArticle
}
const filters = [
{
...buildTagFilter({
type: 'author',
id: hashId,
service: PLATFORM_SERVICE,
}),
since: MIN_EVENT_DATE,
limit: 100, // Get all versions to find the latest
},
]
return new Promise<import('@/types/nostr').AuthorPresentationArticle | null>((resolve) => {
let resolved = false
const relayUrl = getPrimaryRelaySync()
const { createSubscription } = require('@/types/nostr-tools-extended')
const sub = createSubscription(pool, [relayUrl], filters)
const events: Event[] = []
const finalize = async (value: import('@/types/nostr').AuthorPresentationArticle | null): Promise<void> => {
if (resolved) {
return
}
resolved = true
sub.unsub()
// Cache the result if found
if (value && events.length > 0) {
const event = events.find(e => e.id === value.id) || events[0]
if (event) {
const tags = extractTagsFromEvent(event)
if (value.hash) {
await objectCache.set('author', value.hash, event, value, tags.version ?? 0, tags.hidden, value.index)
}
}
}
resolve(value)
}
sub.on('event', (event: Event): void => {
// Collect all events first
const tags = extractTagsFromEvent(event)
if (tags.type === 'author' && !tags.hidden && tags.id === hashId) {
events.push(event)
}
})
sub.on('eose', async (): Promise<void> => {
// Get the latest version from all collected events
const latestEvent = getLatestVersion(events)
if (latestEvent) {
const parsed = await parsePresentationEvent(latestEvent)
if (parsed) {
await finalize(parsed)
return
}
}
await finalize(null)
})
setTimeout(async (): Promise<void> => {
// Get the latest version from all collected events
const latestEvent = getLatestVersion(events)
if (latestEvent) {
const parsed = await parsePresentationEvent(latestEvent)
if (parsed) {
await finalize(parsed)
return
}
}
await finalize(null)
}, 5000).unref?.()
})
}