144 lines
3.4 KiB
TypeScript
144 lines
3.4 KiB
TypeScript
/**
|
|
* 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<string, VersionedObject[]>()
|
|
|
|
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
|
|
}
|