import { nostrService } from './nostr' import type { ArticleDraft, PublishedArticle } from './articlePublisherTypes' import type { AlbyInvoice } from '@/types/alby' import { createArticleInvoice, createPreviewEvent } from './articleInvoice' import { encryptArticleContent, encryptDecryptionKey } from './articleEncryption' import { storePrivateContent } from './articleStorage' import type { PublishResult } from './publishResult' export function buildFailure(error?: string): PublishedArticle { const base: PublishedArticle = { articleId: '', previewEventId: '', success: false, } return error ? { ...base, error } : base } export async function publishPreview( draft: ArticleDraft, invoice: AlbyInvoice, authorPubkey: string, presentationId: string, extraTags?: string[][], encryptedContent?: string, encryptedKey?: string, returnStatus?: boolean ): Promise { const previewEvent = await createPreviewEvent(draft, invoice, authorPubkey, presentationId, extraTags, encryptedContent, encryptedKey) if (returnStatus) { return await nostrService.publishEvent(previewEvent, true) } const publishedEvent = await nostrService.publishEvent(previewEvent, false) return publishedEvent ?? null } export function buildArticleExtraTags(draft: ArticleDraft, _category: NonNullable): string[][] { // Media tags are still supported in the new system const extraTags: string[][] = [] if (draft.media && draft.media.length > 0) { draft.media.forEach((m) => { extraTags.push(['media', m.url, m.type]) }) } return extraTags } export async function encryptAndPublish( draft: ArticleDraft, authorPubkey: string, authorPrivateKeyForEncryption: string, category: NonNullable, presentationId: string ): Promise { const { encryptedContent, key, iv } = await encryptArticleContent(draft.content) const encryptedKey = await encryptDecryptionKey(key, iv, authorPrivateKeyForEncryption, authorPubkey) const invoice = await createArticleInvoice(draft) const extraTags = buildArticleExtraTags(draft, category) const publishResult = await publishPreview(draft, invoice, authorPubkey, presentationId, extraTags, encryptedContent, encryptedKey, true) if (!publishResult) { return buildFailure('Failed to publish article') } // Handle both old format (Event | null) and new format (PublishResult) let event: import('nostr-tools').Event | null = null let relayStatuses: import('./publishResult').RelayPublishStatus[] | undefined if (publishResult && 'event' in publishResult && 'relayStatuses' in publishResult) { // New format with statuses event = publishResult.event relayStatuses = publishResult.relayStatuses } else if (publishResult && 'id' in publishResult) { // Old format (Event) event = publishResult } if (!event) { return buildFailure('Failed to publish article') } await storePrivateContent(event.id, draft.content, authorPubkey, invoice, key, iv) console.warn('Article published with encrypted content', { articleId: event.id, authorPubkey, timestamp: new Date().toISOString(), relayStatuses, }) return { articleId: event.id, previewEventId: event.id, invoice, success: true, relayStatuses, } }