111 lines
3.9 KiB
TypeScript
111 lines
3.9 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) {
|
|
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)
|
|
|
|
// Publish explicit payment note (kind 1) with project tags
|
|
try {
|
|
const article = await nostrService.getArticleById(articleId)
|
|
if (!article) {
|
|
return logPaymentResult(result, articleId, recipientPubkey, amount)
|
|
}
|
|
|
|
const payerPrivateKey = nostrService.getPrivateKey()
|
|
if (!payerPrivateKey) {
|
|
return logPaymentResult(result, articleId, recipientPubkey, amount)
|
|
}
|
|
|
|
const paymentHash = await resolvePaymentHashForPurchaseNote({
|
|
articlePaymentHash: article.paymentHash,
|
|
articleId,
|
|
...(zapReceiptId ? { zapReceiptId } : {}),
|
|
})
|
|
const category = normalizePurchaseNoteCategory(article.category)
|
|
|
|
await publishPurchaseNote({
|
|
articleId: article.id,
|
|
authorPubkey: article.pubkey,
|
|
payerPubkey: recipientPubkey,
|
|
amount,
|
|
paymentHash,
|
|
...(zapReceiptId ? { zapReceiptId } : {}),
|
|
...(category ? { category } : {}),
|
|
...(article.seriesId ? { seriesId: article.seriesId } : {}),
|
|
payerPrivateKey,
|
|
})
|
|
} catch (error) {
|
|
console.error('Error publishing purchase note:', error)
|
|
// Don't fail the payment if note publication fails
|
|
}
|
|
|
|
return logPaymentResult(result, articleId, recipientPubkey, amount)
|
|
}
|
|
|
|
return logPaymentResult(result, articleId, recipientPubkey, amount)
|
|
}
|
|
|
|
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
|
|
}
|