125 lines
3.4 KiB
TypeScript
125 lines
3.4 KiB
TypeScript
/**
|
|
* Helper for grouping and caching events by hash
|
|
* Centralizes the pattern of grouping events by hash ID and caching the latest version
|
|
*/
|
|
|
|
import type { Event } from 'nostr-tools'
|
|
import { extractTagsFromEvent } from '../nostrTagSystem'
|
|
import { parseObjectId } from '../urlGenerator'
|
|
import { getLatestVersion } from '../versionManager'
|
|
import type { ObjectType } from '../objectCache'
|
|
import { writeObjectToCache } from './writeObjectHelper'
|
|
|
|
export interface EventCacheConfig {
|
|
objectType: ObjectType
|
|
extractor: (event: Event) => Promise<unknown | null>
|
|
getHash?: (extracted: unknown) => string | null
|
|
getIndex?: (extracted: unknown) => number
|
|
getVersion?: (event: Event) => number
|
|
getHidden?: (event: Event) => boolean
|
|
}
|
|
|
|
|
|
interface ExtractedObjectWithId {
|
|
id?: string
|
|
index?: number
|
|
}
|
|
|
|
/**
|
|
* Group events by hash ID and cache the latest version of each
|
|
*/
|
|
export async function groupAndCacheEventsByHash(
|
|
events: Event[],
|
|
config: EventCacheConfig
|
|
): Promise<void> {
|
|
const { objectType, extractor, getHash, getIndex, getVersion, getHidden } = config
|
|
|
|
// Group events by hash ID
|
|
const eventsByHashId = new Map<string, Event[]>()
|
|
for (const event of events) {
|
|
const tags = extractTagsFromEvent(event)
|
|
if (tags.id) {
|
|
// Extract hash from id (can be <hash>_<index>_<version> or just hash)
|
|
const parsed = parseObjectId(tags.id)
|
|
const hash = parsed.hash ?? tags.id
|
|
if (!eventsByHashId.has(hash)) {
|
|
eventsByHashId.set(hash, [])
|
|
}
|
|
eventsByHashId.get(hash)!.push(event)
|
|
}
|
|
}
|
|
|
|
// Cache each object (latest version)
|
|
for (const [_hash, hashEvents] of eventsByHashId.entries()) {
|
|
const latestEvent = getLatestVersion(hashEvents)
|
|
if (!latestEvent) {
|
|
continue
|
|
}
|
|
|
|
const extracted = await extractor(latestEvent)
|
|
if (!extracted) {
|
|
continue
|
|
}
|
|
|
|
// Get hash, index, version, hidden
|
|
const extractedHash = getHash ? getHash(extracted) : null
|
|
const extractedObj = extracted as ExtractedObjectWithId
|
|
const extractedId = extractedHash ?? extractedObj.id
|
|
|
|
if (!extractedId) {
|
|
continue
|
|
}
|
|
|
|
const publicationParsed = parseObjectId(extractedId)
|
|
const hash = publicationParsed.hash ?? extractedId
|
|
const index = getIndex ? getIndex(extracted) : publicationParsed.index ?? extractedObj.index ?? 0
|
|
const version = getVersion ? getVersion(latestEvent) : extractTagsFromEvent(latestEvent).version ?? 0
|
|
const hidden = getHidden ? getHidden(latestEvent) : extractTagsFromEvent(latestEvent).hidden ?? false
|
|
|
|
await writeObjectToCache({
|
|
objectType,
|
|
hash,
|
|
event: latestEvent,
|
|
parsed: extracted,
|
|
version,
|
|
hidden,
|
|
index,
|
|
})
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cache a single event as an object
|
|
* Simplified version for direct event caching
|
|
*/
|
|
export async function cacheEventAsObject(
|
|
event: Event,
|
|
objectType: ObjectType,
|
|
extractor: (event: Event) => Promise<unknown | null>
|
|
): Promise<boolean> {
|
|
const extracted = await extractor(event)
|
|
if (!extracted) {
|
|
return false
|
|
}
|
|
|
|
const tags = extractTagsFromEvent(event)
|
|
const hash = (extracted as { hash?: string })?.hash ?? (extracted as { id?: string })?.id ?? ''
|
|
if (!hash) {
|
|
return false
|
|
}
|
|
|
|
const index = (extracted as { index?: number })?.index ?? 0
|
|
|
|
await writeObjectToCache({
|
|
objectType,
|
|
hash,
|
|
event,
|
|
parsed: extracted,
|
|
version: tags.version,
|
|
hidden: tags.hidden,
|
|
index,
|
|
})
|
|
|
|
return true
|
|
}
|