story-research-zapwall/lib/helpers/eventCacheHelper.ts
2026-01-08 21:49:57 +01:00

122 lines
3.5 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>
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, [])
}
const hashEvents = eventsByHashId.get(hash)
if (hashEvents) {
hashEvents.push(event)
}
}
}
// Cache each object (latest version)
for (const [_hash, hashEvents] of eventsByHashId.entries()) {
const latestEvent = getLatestVersion(hashEvents)
if (latestEvent) {
const extracted = await extractor(latestEvent)
if (extracted) {
// Get hash, index, version, hidden
const extractedHash = getHash ? getHash(extracted) : null
const extractedObj = extracted as ExtractedObjectWithId
const extractedId = extractedHash ?? extractedObj.id
if (extractedId) {
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>
): 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
}