101 lines
4.4 KiB
TypeScript
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 } : {}) }
|
|
}
|