From a278492ff58f9a8298ef83e04225a3f277835039 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Sep 2024 11:09:14 -0500 Subject: [PATCH] Add update and move methods to the Pharos API --- src/lib/parser.ts | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/lib/parser.ts b/src/lib/parser.ts index 3cd30f5..7e072cb 100644 --- a/src/lib/parser.ts +++ b/src/lib/parser.ts @@ -99,6 +99,11 @@ export default class Pharos { */ private eventIds: Map = new Map(); + /** + * When `true`, `getEvents()` should regenerate the event tree to propagate updates. + */ + private shouldUpdateEventTree: boolean = false; + // #region Public API constructor(ndk: NDK) { @@ -141,6 +146,11 @@ export default class Pharos { * are stored, they will be freshly generated. */ getEvents(pubkey: string): NDKEvent[] { + if (this.shouldUpdateEventTree) { + const stack = this.stackEventNodes(); + return this.generateEvents(stack, pubkey); + } + return Array.from(this.events.values()); } @@ -210,6 +220,69 @@ export default class Pharos { return block.convert(); } + /** + * Updates the `content` field of a Nostr event in-place. + * @param dTag The d tag of the event to update. + * @param content The new content to assign to the event. + * @returns The updated event. + * @remarks Changing the content of a Nostr event changes its hash, but regenerating the event + * tree is expensive. Thus, the event tree will not be regenerated until the consumer next + * invokes `getEvents()`. + */ + updateEventContent(dTag: string, content: string): NDKEvent { + const event = this.events.get(dTag); + if (!event) { + throw new Error(`No event found for #d:${dTag}.`); + } + + event.content = content; + event.id = event.getEventHash(); + + this.events.set(dTag, event); + this.eventIds.set(dTag, event.id); + this.shouldUpdateEventTree = true; + + return event; + } + + /** + * Moves an event within the event tree. + * @param dTag The d tag of the event to be moved. + * @param oldParentDTag The d tag of the moved event's current parent. + * @param newParentDTag The d tag of the moved event's new parent. + * @throws Throws an error if the parameters specify an invalid move. + * @remarks Both the old and new parent events must be kind 30040 index events. Moving the event + * within the tree changes the hash of several events, so the event tree will be regenerated when + * the consumer next invokes `getEvents()`. + */ + moveEvent(dTag: string, oldParentDTag: string, newParentDTag: string): void { + const event = this.events.get(dTag); + if (!event) { + throw new Error(`No event found for #d:${dTag}.`); + } + + if (this.eventToKindMap.get(oldParentDTag) !== 30040) { + throw new Error(`Old parent event #d:${oldParentDTag} is not an index event.`); + } + + if (this.eventToKindMap.get(newParentDTag) !== 30040) { + throw new Error(`New parent event #d:${newParentDTag} is not an index event.`); + } + + const oldParentMap = this.indexToChildEventsMap.get(oldParentDTag); + const newParentMap = this.indexToChildEventsMap.get(newParentDTag); + + if (!oldParentMap?.has(dTag)) { + throw new Error(`Event #d:${dTag} is not a child of parent #d:${oldParentDTag}.`); + } + + // Perform the move. + oldParentMap?.delete(dTag); + newParentMap?.add(dTag); + + this.shouldUpdateEventTree = true; + } + /** * Resets the parser to its initial state, removing any parsed data. */ @@ -380,6 +453,7 @@ export default class Pharos { } } + this.shouldUpdateEventTree = false; return events; }