story-research-zapwall/lib/helpers/eventCacheHelper.ts
2026-01-09 13:13:24 +01:00

158 lines
4.2 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
}
function groupEventsByHashId(events: Event[]): Map<string, Event[]> {
const eventsByHashId = new Map<string, Event[]>()
for (const event of events) {
const tags = extractTagsFromEvent(event)
const { id } = tags
if (id) {
const parsed = parseObjectId(id)
const hash = parsed.hash ?? id
const current = eventsByHashId.get(hash)
if (current) {
current.push(event)
} else {
eventsByHashId.set(hash, [event])
}
}
}
return eventsByHashId
}
function resolveExtractedId(extracted: unknown, getHash: EventCacheConfig['getHash']): string | undefined {
const extractedHash = getHash ? getHash(extracted) : null
const extractedObj = extracted as ExtractedObjectWithId
return extractedHash ?? extractedObj.id
}
function resolveHashAndIndex(
extractedId: string,
extracted: unknown,
getIndex: EventCacheConfig['getIndex']
): { hash: string; index: number } {
const parsed = parseObjectId(extractedId)
const extractedObj = extracted as ExtractedObjectWithId
const hash = parsed.hash ?? extractedId
const index = getIndex ? getIndex(extracted) : (parsed.index ?? extractedObj.index ?? 0)
return { hash, index }
}
function resolveVersionAndHidden(
latestEvent: Event,
getVersion: EventCacheConfig['getVersion'],
getHidden: EventCacheConfig['getHidden']
): { version: number; hidden: boolean } {
const tags = extractTagsFromEvent(latestEvent)
const version = getVersion ? getVersion(latestEvent) : (tags.version ?? 0)
const hidden = getHidden ? getHidden(latestEvent) : (tags.hidden ?? false)
return { version, hidden }
}
async function cacheLatestEventForHashGroup(hashEvents: Event[], config: EventCacheConfig): Promise<void> {
const { objectType, extractor, getHash, getIndex, getVersion, getHidden } = config
const latestEvent = getLatestVersion(hashEvents)
if (!latestEvent) {
return
}
const extracted = await extractor(latestEvent)
if (!extracted) {
return
}
const extractedId = resolveExtractedId(extracted, getHash)
if (!extractedId) {
return
}
const { hash, index } = resolveHashAndIndex(extractedId, extracted, getIndex)
const { version, hidden } = resolveVersionAndHidden(latestEvent, getVersion, getHidden)
await writeObjectToCache({
objectType,
hash,
event: latestEvent,
parsed: extracted,
version,
hidden,
index,
})
}
/**
* Group events by hash ID and cache the latest version of each
*/
export async function groupAndCacheEventsByHash(
events: Event[],
config: EventCacheConfig
): Promise<void> {
const eventsByHashId = groupEventsByHashId(events)
for (const hashEvents of eventsByHashId.values()) {
await cacheLatestEventForHashGroup(hashEvents, config)
}
}
/**
* 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
}