2026-01-13 14:49:19 +01:00

86 lines
4.1 KiB
TypeScript

import type { Article } from '@/types/nostr'
import { nostrService } from '../nostr'
import { getPublishRelays } from '../relaySelection'
import { ensureKeys } from './shared'
export async function deleteArticleEvent(articleId: string, authorPubkey: string, authorPrivateKey?: string): Promise<void> {
ensureKeys(authorPubkey, authorPrivateKey)
const originalEvent = await getOriginalPublicationEventOrThrow(articleId)
assertAuthorOwnsEvent({ eventPubkey: originalEvent.pubkey, authorPubkey })
const deleteEventTemplate = await buildDeleteEventTemplateOrThrow({ originalEvent, authorPubkey })
const originalParsed = await parseOriginalArticleOrThrow(originalEvent)
const deletePayload = await buildDeletedArticlePayload({ originalParsed, deleteEventTemplate })
const event = await finalizeEventTemplate({ template: deleteEventTemplate, authorPrivateKey })
const relays = await getPublishRelays()
await publishDeletion({ event, relays, payload: deletePayload })
}
async function getOriginalPublicationEventOrThrow(articleId: string): Promise<import('nostr-tools').Event> {
const { objectCache } = await import('../objectCache')
const originalEvent = await objectCache.getEventById('publication', articleId)
if (!originalEvent) {
throw new Error('Article not found in cache')
}
return originalEvent
}
function assertAuthorOwnsEvent(params: { eventPubkey: string; authorPubkey: string }): void {
if (params.eventPubkey !== params.authorPubkey) {
throw new Error('Only the author can delete this article')
}
}
async function buildDeleteEventTemplateOrThrow(params: { originalEvent: import('nostr-tools').Event; authorPubkey: string }): Promise<import('nostr-tools').EventTemplate> {
const { buildDeleteEvent } = await import('../objectModification')
const template = await buildDeleteEvent(params.originalEvent, params.authorPubkey)
if (!template) {
throw new Error('Failed to build delete event')
}
return template
}
async function parseOriginalArticleOrThrow(originalEvent: import('nostr-tools').Event): Promise<Article> {
const { parseArticleFromEvent } = await import('../nostrEventParsing')
const parsed = await parseArticleFromEvent(originalEvent)
if (!parsed) {
throw new Error('Failed to parse original article')
}
return parsed
}
async function buildDeletedArticlePayload(params: { originalParsed: Article; deleteEventTemplate: import('nostr-tools').EventTemplate }): Promise<{ hash: string; index: number; version: number; parsed: Article }> {
const { extractTagsFromEvent } = await import('../nostrTagSystem')
const tags = extractTagsFromEvent(params.deleteEventTemplate)
const version = tags.version ?? params.originalParsed.version + 1
const index = params.originalParsed.index ?? 0
const parsed: Article = { ...params.originalParsed, version }
return { hash: params.originalParsed.hash, index, version, parsed }
}
async function finalizeEventTemplate(params: { template: import('nostr-tools').EventTemplate; authorPrivateKey: string | undefined }): Promise<import('nostr-tools').Event> {
const privateKey = params.authorPrivateKey ?? nostrService.getPrivateKey()
if (!privateKey) {
throw new Error('Private key required for signing')
}
const { writeOrchestrator } = await import('../writeOrchestrator')
writeOrchestrator.setPrivateKey(privateKey)
const { finalizeEvent } = await import('nostr-tools')
const { hexToBytes } = await import('nostr-tools/utils')
return finalizeEvent(params.template, hexToBytes(privateKey))
}
async function publishDeletion(params: {
event: import('nostr-tools').Event
relays: string[]
payload: { hash: string; index: number; version: number; parsed: Article }
}): Promise<void> {
const { writeOrchestrator } = await import('../writeOrchestrator')
const result = await writeOrchestrator.writeAndPublish(
{ objectType: 'publication', hash: params.payload.hash, event: params.event, parsed: params.payload.parsed, version: params.payload.version, hidden: true, index: params.payload.index },
params.relays
)
if (!result.success) {
throw new Error('Failed to publish delete event')
}
}