mirror of
https://github.com/dergigi/boris.git
synced 2025-12-27 19:44:40 +01:00
92 lines
2.6 KiB
TypeScript
92 lines
2.6 KiB
TypeScript
import { RelayPool } from 'applesauce-relay'
|
|
import { lastValueFrom, take } from 'rxjs'
|
|
import { nip19 } from 'nostr-tools'
|
|
import { AddressPointer } from 'nostr-tools/nip19'
|
|
import { Helpers } from 'applesauce-core'
|
|
import { RELAYS } from '../config/relays'
|
|
import { prioritizeLocalRelays, partitionRelays, createParallelReqStreams } from '../utils/helpers'
|
|
import { merge, toArray as rxToArray } from 'rxjs'
|
|
|
|
const { getArticleTitle } = Helpers
|
|
|
|
/**
|
|
* Fetch article title for a single naddr
|
|
* Returns the title or null if not found/error
|
|
*/
|
|
export async function fetchArticleTitle(
|
|
relayPool: RelayPool,
|
|
naddr: string
|
|
): Promise<string | null> {
|
|
try {
|
|
const decoded = nip19.decode(naddr)
|
|
|
|
if (decoded.type !== 'naddr') {
|
|
return null
|
|
}
|
|
|
|
const pointer = decoded.data as AddressPointer
|
|
|
|
// Define relays to query
|
|
const baseRelays = pointer.relays && pointer.relays.length > 0
|
|
? pointer.relays
|
|
: RELAYS
|
|
const orderedRelays = prioritizeLocalRelays(baseRelays)
|
|
const { local: localRelays, remote: remoteRelays } = partitionRelays(orderedRelays)
|
|
|
|
// Fetch the article event
|
|
const filter = {
|
|
kinds: [pointer.kind],
|
|
authors: [pointer.pubkey],
|
|
'#d': [pointer.identifier]
|
|
}
|
|
|
|
// Parallel local+remote: collect up to one event from each
|
|
const { local$, remote$ } = createParallelReqStreams(relayPool, localRelays, remoteRelays, filter, 1200, 5000)
|
|
const events = await lastValueFrom(
|
|
merge(local$.pipe(take(1)), remote$.pipe(take(1))).pipe(rxToArray())
|
|
) as unknown as { created_at: number }[]
|
|
|
|
if (events.length === 0) {
|
|
return null
|
|
}
|
|
|
|
// Sort by created_at and take the most recent
|
|
events.sort((a, b) => b.created_at - a.created_at)
|
|
const article = events[0] as unknown as Parameters<typeof getArticleTitle>[0]
|
|
|
|
return getArticleTitle(article) || null
|
|
} catch (err) {
|
|
console.warn('Failed to fetch article title for', naddr, err)
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch titles for multiple naddrs in parallel
|
|
* Returns a map of naddr -> title
|
|
*/
|
|
export async function fetchArticleTitles(
|
|
relayPool: RelayPool,
|
|
naddrs: string[]
|
|
): Promise<Map<string, string>> {
|
|
const titleMap = new Map<string, string>()
|
|
|
|
// Fetch all titles in parallel
|
|
const results = await Promise.allSettled(
|
|
naddrs.map(async (naddr) => {
|
|
const title = await fetchArticleTitle(relayPool, naddr)
|
|
return { naddr, title }
|
|
})
|
|
)
|
|
|
|
// Process results
|
|
results.forEach((result) => {
|
|
if (result.status === 'fulfilled' && result.value.title) {
|
|
titleMap.set(result.value.naddr, result.value.title)
|
|
}
|
|
})
|
|
|
|
return titleMap
|
|
}
|
|
|