/** * Version management for objects * Handles versioning and hiding of objects * Only the author (pubkey) who published the original note can modify or delete it */ import type { Event } from 'nostr-tools' import { extractTagsFromEvent } from './nostrTagSystem' export interface VersionedObject { event: Event version: number hidden: boolean pubkey: string id: string } /** * Filter events to get only the latest version that is not hidden * Groups events by ID and returns the one with the highest version that is not hidden */ export function getLatestVersion(events: Event[]): Event | null { if (events.length === 0) { return null } // Group by ID and find the latest non-hidden version const byId = new Map() for (const event of events) { const tags = extractTagsFromEvent(event) if (!tags.id) { continue } if (!byId.has(tags.id)) { byId.set(tags.id, []) } byId.get(tags.id)!.push({ event, version: tags.version, hidden: tags.hidden, pubkey: event.pubkey, id: tags.id, }) } // For each ID, find the latest non-hidden version const latestVersions: VersionedObject[] = [] for (const objects of byId.values()) { // Filter out hidden objects const visible = objects.filter((obj) => !obj.hidden) if (visible.length === 0) { // All versions are hidden, skip this object continue } // Sort by version (descending) and take the first (latest) visible.sort((a, b) => b.version - a.version) const latest = visible[0] if (latest) { latestVersions.push(latest) } } // If we have multiple IDs, we need to return the one with the highest version // But typically we expect one ID per query, so return the first if (latestVersions.length === 0) { return null } // Sort by version and return the latest latestVersions.sort((a, b) => b.version - a.version) const latestVersion = latestVersions[0] return latestVersion ? latestVersion.event : null } /** * Get all versions of an object (for version history) */ export function getAllVersions(events: Event[]): VersionedObject[] { const versions: VersionedObject[] = [] for (const event of events) { const tags = extractTagsFromEvent(event) if (!tags.id) { continue } versions.push({ event, version: tags.version, hidden: tags.hidden, pubkey: event.pubkey, id: tags.id, }) } // Sort by version (descending) versions.sort((a, b) => b.version - a.version) return versions } /** * Check if a user can modify or delete an object * Only the original author (pubkey) can modify/delete */ export function canModifyObject(event: Event, userPubkey: string): boolean { return event.pubkey === userPubkey } /** * Get the next version number for an object * Finds the highest version and increments it */ export function getNextVersion(events: Event[]): number { if (events.length === 0) { return 0 } let maxVersion = -1 for (const event of events) { const tags = extractTagsFromEvent(event) if (tags.version > maxVersion) { maxVersion = tags.version } } return maxVersion + 1 } /** * Count objects with the same hash ID (for index calculation) */ export function countObjectsWithSameHash(events: Event[], hashId: string): number { return events.filter((event) => { const tags = extractTagsFromEvent(event) return tags.id === hashId }).length }