import { getAlbyService } from './alby' import { calculateArticleSplit, PLATFORM_COMMISSIONS } from './platformCommissions' import { buildTags } from './nostrTagSystem' import { PLATFORM_SERVICE } from './platformConfig' import { generatePublicationHashId } from './hashIdGenerator' import type { AlbyInvoice } from '@/types/alby' import type { ArticleDraft } from './articlePublisher' /** * Create Lightning invoice for article with automatic commission split * The invoice is created for the full amount (800 sats) which includes: * - 700 sats for the author * - 100 sats commission for the platform * * The commission is automatically tracked and the split is enforced. * Requires Alby/WebLN to be available and enabled */ export async function createArticleInvoice(draft: ArticleDraft): Promise { // Verify amount matches expected commission structure if (draft.zapAmount !== PLATFORM_COMMISSIONS.article.total) { throw new Error( `Invalid article payment amount: ${draft.zapAmount} sats. Expected ${PLATFORM_COMMISSIONS.article.total} sats (700 to author, 100 commission)` ) } const split = calculateArticleSplit() // Get author's Lightning address from their profile or use platform address as fallback // For now, we'll create the invoice through the platform's wallet // The platform will forward the author's portion after payment const alby = getAlbyService() await alby.enable() const invoice = await alby.createInvoice({ amount: split.total, description: `Article: ${draft.title} (${split.author} sats author, ${split.platform} sats commission)`, expiry: 86400, // 24 hours }) return invoice } /** * Create preview event with invoice tags * If encryptedContent is provided, it will be used instead of preview */ export async function createPreviewEvent( params: { draft: ArticleDraft invoice: AlbyInvoice authorPubkey: string authorPresentationId?: string extraTags?: string[][] encryptedContent?: string encryptedKey?: string } ): Promise<{ kind: 1 created_at: number tags: string[][] content: string }> { const tags = await buildPreviewTags({ draft: params.draft, invoice: params.invoice, authorPubkey: params.authorPubkey, ...(params.authorPresentationId ? { authorPresentationId: params.authorPresentationId } : {}), ...(params.extraTags ? { extraTags: params.extraTags } : {}), ...(params.encryptedKey ? { encryptedKey: params.encryptedKey } : {}), }) return { kind: 1 as const, created_at: Math.floor(Date.now() / 1000), tags, content: params.encryptedContent ?? params.draft.preview, } } async function buildPreviewTags( params: { draft: ArticleDraft invoice: AlbyInvoice authorPubkey: string authorPresentationId?: string extraTags?: string[][] encryptedKey?: string } ): Promise { const category = normalizePublicationCategory(params.draft.category) const hashId = await generatePublicationHashId( buildPublicationHashParams({ draft: params.draft, authorPubkey: params.authorPubkey, category }) ) const tags = buildPublicationTags({ draft: params.draft, invoice: params.invoice, authorPubkey: params.authorPubkey, category, hashId, encryptedKey: params.encryptedKey, }) tags.push(['json', buildPublicationJson({ draft: params.draft, invoice: params.invoice, authorPubkey: params.authorPubkey, category, hashId })]) if (params.extraTags && params.extraTags.length > 0) { tags.push(...params.extraTags) } return tags } function buildPublicationHashParams(params: { draft: ArticleDraft authorPubkey: string category: 'sciencefiction' | 'research' }): Parameters[0] { return { pubkey: params.authorPubkey, title: params.draft.title, preview: params.draft.preview, category: params.category, zapAmount: params.draft.zapAmount, ...(params.draft.seriesId ? { seriesId: params.draft.seriesId } : {}), ...(params.draft.bannerUrl ? { bannerUrl: params.draft.bannerUrl } : {}), } } function buildPublicationTags(params: { draft: ArticleDraft invoice: AlbyInvoice authorPubkey: string category: 'sciencefiction' | 'research' hashId: string encryptedKey: string | undefined }): string[][] { return buildTags({ type: 'publication', category: params.category, id: params.hashId, service: PLATFORM_SERVICE, version: 0, hidden: false, paywall: true, title: params.draft.title, preview: params.draft.preview, zapAmount: params.draft.zapAmount, invoice: params.invoice.invoice, paymentHash: params.invoice.paymentHash, ...(params.draft.seriesId ? { seriesId: params.draft.seriesId } : {}), ...(params.draft.bannerUrl ? { bannerUrl: params.draft.bannerUrl } : {}), ...(params.encryptedKey ? { encryptedKey: params.encryptedKey } : {}), }) } function buildPublicationJson(params: { draft: ArticleDraft invoice: AlbyInvoice authorPubkey: string category: 'sciencefiction' | 'research' hashId: string }): string { return JSON.stringify({ type: 'publication', pubkey: params.authorPubkey, title: params.draft.title, preview: params.draft.preview, category: params.category, seriesId: params.draft.seriesId, bannerUrl: params.draft.bannerUrl, zapAmount: params.draft.zapAmount, invoice: params.invoice.invoice, paymentHash: params.invoice.paymentHash, id: params.hashId, version: 0, index: 0, ...(params.draft.pages && params.draft.pages.length > 0 ? { pages: params.draft.pages } : {}), }) } function normalizePublicationCategory(category: ArticleDraft['category'] | undefined): 'sciencefiction' | 'research' { if (category === 'scientific-research') { return 'research' } return 'sciencefiction' }