story-research-zapwall/lib/paymentPollingMain.ts
2026-01-10 09:41:57 +01:00

123 lines
4.0 KiB
TypeScript

import { getStoredPrivateContent } from './articleStorage'
import { nostrService } from './nostr'
import { articlePublisher } from './articlePublisher'
import { validatePaymentData, verifyPaymentAmount } from './paymentPollingValidation'
import { createTrackingData, triggerAutomaticTransfer, logPaymentResult } from './paymentPollingTracking'
import { platformTracking } from './platformTracking'
import { publishPurchaseNote } from './paymentNotes'
/**
* Send private content to user after payment confirmation
* Returns true if content was successfully sent and verified
*/
export async function sendPrivateContentAfterPayment(
articleId: string,
recipientPubkey: string,
amount: number,
zapReceiptId?: string
): Promise<boolean> {
const storedContent = await getStoredPrivateContent(articleId)
const authorPrivateKey = nostrService.getPrivateKey()
const validation = validatePaymentData(storedContent, authorPrivateKey, articleId, recipientPubkey)
if (!validation.valid || !validation.storedContent || !validation.authorPrivateKey) {
return false
}
const result = await articlePublisher.sendPrivateContent(articleId, recipientPubkey, validation.authorPrivateKey)
if (!result.success || !result.messageEventId) {
return logPaymentResult(result, articleId, recipientPubkey, amount)
}
verifyPaymentAmount(amount, articleId)
const trackingData = createTrackingData({
articleId,
authorPubkey: validation.storedContent.authorPubkey,
recipientPubkey,
messageEventId: result.messageEventId,
amount,
verified: result.verified ?? false,
...(zapReceiptId ? { zapReceiptId } : {}),
})
await platformTracking.trackContentDelivery(trackingData, validation.authorPrivateKey)
await triggerAutomaticTransfer(validation.storedContent.authorPubkey, articleId, amount)
await tryPublishPurchaseNote({
articleId,
recipientPubkey,
amount,
...(zapReceiptId ? { zapReceiptId } : {}),
})
return logPaymentResult(result, articleId, recipientPubkey, amount)
}
async function tryPublishPurchaseNote(params: {
articleId: string
recipientPubkey: string
amount: number
zapReceiptId?: string
}): Promise<void> {
try {
const article = await nostrService.getArticleById(params.articleId)
if (!article) {
return
}
const payerPrivateKey = nostrService.getPrivateKey()
if (!payerPrivateKey) {
return
}
const paymentHash = await resolvePaymentHashForPurchaseNote({
articlePaymentHash: article.paymentHash,
articleId: params.articleId,
...(params.zapReceiptId ? { zapReceiptId: params.zapReceiptId } : {}),
})
const category = normalizePurchaseNoteCategory(article.category)
await publishPurchaseNote({
articleId: article.id,
authorPubkey: article.pubkey,
payerPubkey: params.recipientPubkey,
amount: params.amount,
paymentHash,
...(params.zapReceiptId ? { zapReceiptId: params.zapReceiptId } : {}),
...(category ? { category } : {}),
...(article.seriesId ? { seriesId: article.seriesId } : {}),
payerPrivateKey,
})
} catch (error) {
console.error('Error publishing purchase note:', error)
}
}
function normalizePurchaseNoteCategory(category: string | undefined): 'science-fiction' | 'scientific-research' | undefined {
if (category === 'science-fiction' || category === 'scientific-research') {
return category
}
return undefined
}
async function resolvePaymentHashForPurchaseNote(params: {
articlePaymentHash: string | undefined
articleId: string
zapReceiptId?: string
}): Promise<string> {
let paymentHash = params.articlePaymentHash ?? params.articleId
if (!params.zapReceiptId) {
return paymentHash
}
const { getZapReceiptById } = await import('./zapReceiptQueries')
const zapReceipt = await getZapReceiptById(params.zapReceiptId)
const paymentHashTag = zapReceipt?.tags.find((tag) => tag[0] === 'payment_hash')?.[1]
if (paymentHashTag) {
paymentHash = paymentHashTag
}
return paymentHash
}