153 lines
4.1 KiB
TypeScript
153 lines
4.1 KiB
TypeScript
import type { Event } from 'nostr-tools'
|
|
import { nostrService } from './nostr'
|
|
import type { Series } from '@/types/nostr'
|
|
import { parseSeriesFromEvent } from './nostrEventParsing'
|
|
import { buildTagFilter, extractTagsFromEvent } from './nostrTagSystem'
|
|
import { getPrimaryRelaySync } from './config'
|
|
import { PLATFORM_SERVICE, MIN_EVENT_DATE } from './platformConfig'
|
|
import { objectCache } from './objectCache'
|
|
import { parseObjectId } from './urlGenerator'
|
|
|
|
function buildSeriesFilters(authorPubkey: string): Array<{
|
|
kinds: number[]
|
|
authors?: string[]
|
|
'#series'?: string[]
|
|
since: number
|
|
}> {
|
|
const tagFilter = buildTagFilter({
|
|
type: 'series',
|
|
authorPubkey,
|
|
service: PLATFORM_SERVICE,
|
|
})
|
|
|
|
return [
|
|
{
|
|
kinds: tagFilter.kinds as number[],
|
|
...(tagFilter.authors ? { authors: tagFilter.authors as string[] } : {}),
|
|
...(tagFilter['#series'] ? { '#series': tagFilter['#series'] as string[] } : {}),
|
|
since: MIN_EVENT_DATE,
|
|
},
|
|
]
|
|
}
|
|
|
|
export function getSeriesByAuthor(authorPubkey: string, timeoutMs: number = 5000): Promise<Series[]> {
|
|
const pool = nostrService.getPool()
|
|
if (!pool) {
|
|
throw new Error('Pool not initialized')
|
|
}
|
|
const filters = buildSeriesFilters(authorPubkey)
|
|
const { createSubscription } = require('@/types/nostr-tools-extended')
|
|
|
|
return new Promise<Series[]>((resolve) => {
|
|
const results: Series[] = []
|
|
const relayUrl = getPrimaryRelaySync()
|
|
const sub = createSubscription(pool, [relayUrl], filters)
|
|
let finished = false
|
|
|
|
const done = (): void => {
|
|
if (finished) {
|
|
return
|
|
}
|
|
finished = true
|
|
sub.unsub()
|
|
resolve(results)
|
|
}
|
|
|
|
sub.on('event', (event: Event): void => {
|
|
void (async (): Promise<void> => {
|
|
const parsed = await parseSeriesFromEvent(event)
|
|
if (parsed) {
|
|
results.push(parsed)
|
|
}
|
|
})()
|
|
})
|
|
|
|
sub.on('eose', (): void => {
|
|
done()
|
|
})
|
|
setTimeout(() => done(), timeoutMs).unref?.()
|
|
})
|
|
}
|
|
|
|
function buildSeriesByIdFilters(seriesId: string): Array<{
|
|
kinds: number[]
|
|
ids: string[]
|
|
since: number
|
|
[key: string]: unknown
|
|
}> {
|
|
return [
|
|
{
|
|
kinds: [1],
|
|
ids: [seriesId],
|
|
...buildTagFilter({
|
|
type: 'series',
|
|
service: PLATFORM_SERVICE,
|
|
}),
|
|
since: MIN_EVENT_DATE,
|
|
},
|
|
]
|
|
}
|
|
|
|
export async function getSeriesById(seriesId: string, timeoutMs: number = 5000): Promise<Series | null> {
|
|
// Try to parse seriesId as id format (<hash>_<index>_<version>) or use it as hash
|
|
const parsed = parseObjectId(seriesId)
|
|
const hash = parsed.hash ?? seriesId
|
|
|
|
// Check cache first
|
|
const cached = await objectCache.get('series', hash)
|
|
if (cached) {
|
|
return cached as Series
|
|
}
|
|
|
|
const pool = nostrService.getPool()
|
|
if (!pool) {
|
|
throw new Error('Pool not initialized')
|
|
}
|
|
const filters = buildSeriesByIdFilters(seriesId)
|
|
const { createSubscription } = require('@/types/nostr-tools-extended')
|
|
|
|
return new Promise<Series | null>((resolve) => {
|
|
const relayUrl = getPrimaryRelaySync()
|
|
const sub = createSubscription(pool, [relayUrl], filters)
|
|
let finished = false
|
|
|
|
const done = async (value: Series | null): Promise<void> => {
|
|
if (finished) {
|
|
return
|
|
}
|
|
finished = true
|
|
sub.unsub()
|
|
|
|
// Cache the result if found
|
|
if (value && value.hash) {
|
|
// Find the event to cache it
|
|
// Note: We would need the event here, but for now we cache what we have
|
|
// The event will be cached when it's parsed from the subscription
|
|
}
|
|
|
|
resolve(value)
|
|
}
|
|
|
|
sub.on('event', (event: Event): void => {
|
|
void (async (): Promise<void> => {
|
|
const parsed = await parseSeriesFromEvent(event)
|
|
if (parsed) {
|
|
// Cache the parsed series
|
|
const tags = extractTagsFromEvent(event)
|
|
if (parsed.hash) {
|
|
await objectCache.set('series', parsed.hash, event, parsed, tags.version ?? 0, tags.hidden ?? false, parsed.index)
|
|
}
|
|
await done(parsed)
|
|
}
|
|
})()
|
|
})
|
|
|
|
sub.on('eose', (): void => {
|
|
void done(null)
|
|
})
|
|
setTimeout((): void => {
|
|
void done(null)
|
|
}, timeoutMs).unref?.()
|
|
})
|
|
}
|