- Création lib/platformCommissions.ts : configuration centralisée des commissions - Articles : 800 sats (700 auteur, 100 plateforme) - Avis : 70 sats (49 lecteur, 21 plateforme) - Sponsoring : 0.046 BTC (0.042 auteur, 0.004 plateforme) - Validation des montants à chaque étape : - Publication : vérification du montant avant publication - Paiement : vérification du montant avant acceptation - Erreurs explicites si montant incorrect - Tracking des commissions sur Nostr : - Tags author_amount et platform_commission dans événements - Interface ContentDeliveryTracking étendue - Traçabilité complète pour audit - Logs structurés avec informations de commission - Documentation complète du système Les commissions sont maintenant systématiques, validées et traçables.
117 lines
2.9 KiB
TypeScript
117 lines
2.9 KiB
TypeScript
import { nostrService } from './nostr'
|
|
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
|
|
|
const RELAY_URL = process.env.NEXT_PUBLIC_NOSTR_RELAY_URL ?? 'wss://relay.damus.io'
|
|
|
|
export interface ContentDeliveryStatus {
|
|
messageEventId: string | null
|
|
published: boolean
|
|
verifiedOnRelay: boolean
|
|
retrievable: boolean
|
|
error?: string
|
|
}
|
|
|
|
/**
|
|
* Verify that private content was successfully delivered to recipient
|
|
* Checks multiple aspects to ensure delivery certainty
|
|
*/
|
|
export async function verifyContentDelivery(
|
|
articleId: string,
|
|
authorPubkey: string,
|
|
recipientPubkey: string,
|
|
messageEventId: string
|
|
): Promise<ContentDeliveryStatus> {
|
|
const status: ContentDeliveryStatus = {
|
|
messageEventId,
|
|
published: false,
|
|
verifiedOnRelay: false,
|
|
retrievable: false,
|
|
}
|
|
|
|
try {
|
|
const pool = nostrService.getPool()
|
|
if (!pool) {
|
|
status.error = 'Pool not initialized'
|
|
return status
|
|
}
|
|
|
|
const poolWithSub = pool as SimplePoolWithSub
|
|
|
|
const filters = [
|
|
{
|
|
kinds: [4],
|
|
ids: messageEventId ? [messageEventId] : undefined,
|
|
authors: [authorPubkey],
|
|
'#p': [recipientPubkey],
|
|
'#e': [articleId],
|
|
limit: 1,
|
|
},
|
|
]
|
|
|
|
return new Promise((resolve) => {
|
|
let resolved = false
|
|
const sub = poolWithSub.sub([RELAY_URL], filters)
|
|
|
|
const finalize = (result: ContentDeliveryStatus) => {
|
|
if (resolved) {
|
|
return
|
|
}
|
|
resolved = true
|
|
sub.unsub()
|
|
resolve(result)
|
|
}
|
|
|
|
sub.on('event', (event) => {
|
|
status.published = true
|
|
status.verifiedOnRelay = true
|
|
status.messageEventId = event.id
|
|
status.retrievable = true
|
|
finalize(status)
|
|
})
|
|
|
|
sub.on('eose', () => {
|
|
if (!status.published) {
|
|
status.error = 'Message not found on relay'
|
|
}
|
|
finalize(status)
|
|
})
|
|
|
|
setTimeout(() => {
|
|
if (!resolved) {
|
|
if (!status.published) {
|
|
status.error = 'Timeout waiting for message verification'
|
|
}
|
|
finalize(status)
|
|
}
|
|
}, 5000)
|
|
})
|
|
} catch (error) {
|
|
status.error = error instanceof Error ? error.message : 'Unknown error'
|
|
return status
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if recipient can retrieve the private message
|
|
* This verifies that the message is accessible with the recipient's key
|
|
*/
|
|
export async function verifyRecipientCanRetrieve(
|
|
articleId: string,
|
|
authorPubkey: string,
|
|
recipientPubkey: string,
|
|
messageEventId: string
|
|
): Promise<boolean> {
|
|
try {
|
|
const status = await verifyContentDelivery(articleId, authorPubkey, recipientPubkey, messageEventId)
|
|
return status.retrievable && status.verifiedOnRelay
|
|
} catch (error) {
|
|
console.error('Error verifying recipient can retrieve', {
|
|
articleId,
|
|
recipientPubkey,
|
|
messageEventId,
|
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
})
|
|
return false
|
|
}
|
|
}
|