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

101 lines
4.4 KiB
TypeScript

import type { ArticleDraft } from '../articlePublisher'
import type { AlbyInvoice } from '@/types/alby'
import type { Article } from '@/types/nostr'
import { createArticleInvoice } from '../articleInvoice'
import { storePrivateContent } from '../articleStorage'
import { buildTags } from '../nostrTagSystem'
import { PLATFORM_SERVICE } from '../platformConfig'
import { generatePublicationHashId } from '../hashIdGenerator'
import { ensureKeys, ensurePresentation, mapDraftCategoryToTag, requireCategory } from './shared'
import { buildParsedArticleFromDraft, publishPreviewWithInvoice } from './publicationPreview'
import type { ArticleUpdateResult } from './types'
export async function publishArticleUpdate(
originalArticleId: string,
draft: ArticleDraft,
authorPubkey: string,
authorPrivateKey?: string
): Promise<ArticleUpdateResult> {
try {
ensureKeys(authorPubkey, authorPrivateKey)
return publishUpdate(draft, authorPubkey, originalArticleId)
} catch (error) {
return updateFailure(originalArticleId, error instanceof Error ? error.message : 'Unknown error')
}
}
async function publishUpdate(draft: ArticleDraft, authorPubkey: string, originalArticleId: string): Promise<ArticleUpdateResult> {
requireCategory(draft.category)
const originalArticle = await loadOriginalArticleForUpdate(originalArticleId)
if (!originalArticle) {
return updateFailure(originalArticleId, 'Original article not found in cache')
}
if (originalArticle.pubkey !== authorPubkey) {
return updateFailure(originalArticleId, 'Only the author can update this article')
}
const presentationId = await ensurePresentation(authorPubkey)
const invoice = await createArticleInvoice(draft)
const newCategory = mapDraftCategoryToTag(draft.category)
const currentVersion = originalArticle.version ?? 0
const updateTags = await buildUpdateTags({ draft, originalArticleId, newCategory, authorPubkey, currentVersion })
const updatedArticle = await buildUpdatedArticleForUpdate({ draft, invoice, authorPubkey, currentVersion })
const publishedEvent = await publishPreviewWithInvoice({ draft, invoice, authorPubkey, presentationId, extraTags: updateTags, customArticle: updatedArticle })
if (!publishedEvent) {
return updateFailure(originalArticleId, 'Failed to publish article update')
}
await storePrivateContent({ articleId: publishedEvent.id, content: draft.content, authorPubkey, invoice })
return { articleId: publishedEvent.id, previewEventId: publishedEvent.id, invoice, success: true, originalArticleId }
}
async function buildUpdateTags(params: {
draft: ArticleDraft
originalArticleId: string
newCategory: 'sciencefiction' | 'research'
authorPubkey: string
currentVersion?: number
}): Promise<string[][]> {
const hashId = await generatePublicationHashId({
pubkey: params.authorPubkey,
title: params.draft.title,
preview: params.draft.preview,
category: params.newCategory,
seriesId: params.draft.seriesId ?? undefined,
bannerUrl: params.draft.bannerUrl ?? undefined,
zapAmount: params.draft.zapAmount,
})
const currentVersion = params.currentVersion ?? 0
const nextVersion = currentVersion + 1
const updateTags = buildTags({
type: 'publication',
category: params.newCategory,
id: hashId,
service: PLATFORM_SERVICE,
version: nextVersion,
hidden: false,
paywall: true,
title: params.draft.title,
preview: params.draft.preview,
zapAmount: params.draft.zapAmount,
...(params.draft.seriesId ? { seriesId: params.draft.seriesId } : {}),
...(params.draft.bannerUrl ? { bannerUrl: params.draft.bannerUrl } : {}),
})
updateTags.push(['e', params.originalArticleId], ['replace', 'article-update'])
return updateTags
}
async function loadOriginalArticleForUpdate(originalArticleId: string): Promise<Article | null> {
const { objectCache } = await import('../objectCache')
return (await objectCache.getById('publication', originalArticleId)) as Article | null
}
async function buildUpdatedArticleForUpdate(params: { draft: ArticleDraft; invoice: AlbyInvoice; authorPubkey: string; currentVersion: number }): Promise<Article> {
const { article } = await buildParsedArticleFromDraft(params.draft, params.invoice, params.authorPubkey)
return { ...article, version: params.currentVersion + 1 }
}
function updateFailure(originalArticleId: string, error?: string): ArticleUpdateResult {
return { articleId: '', previewEventId: '', success: false, originalArticleId, ...(error ? { error } : {}) }
}