story-research-zapwall/lib/reviewRewardUpdate.ts

126 lines
3.3 KiB
TypeScript

import { nostrService } from './nostr'
import { PLATFORM_COMMISSIONS } from './platformCommissions'
import type { Event } from 'nostr-tools'
export async function fetchOriginalReviewEvent(reviewId: string): Promise<Event | null> {
const pool = nostrService.getPool()
if (!pool) {
throw new Error('Pool not initialized')
}
const { getPrimaryRelaySync } = await import('./config')
const { createSubscription } = await import('@/types/nostr-tools-extended')
const relayUrl = getPrimaryRelaySync()
const filters = [
{
kinds: [1],
ids: [reviewId],
limit: 1,
},
]
return new Promise<Event | null>((resolve) => {
let resolved = false
const sub = createSubscription(pool, [relayUrl], filters)
const finalize = (value: Event | null) => {
if (resolved) {
return
}
resolved = true
sub.unsub()
resolve(value)
}
sub.on('event', (event: Event) => {
finalize(event)
})
sub.on('eose', () => finalize(null))
setTimeout(() => finalize(null), 5000)
})
}
export function buildRewardEvent(originalEvent: Event, reviewId: string): {
kind: number
created_at: number
tags: string[][]
content: string
} {
return {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [
...originalEvent.tags.filter((tag) => tag[0] !== 'rewarded' && tag[0] !== 'reward_amount'),
['e', reviewId],
['rewarded', 'true'],
['reward_amount', PLATFORM_COMMISSIONS.review.total.toString()],
],
content: originalEvent.content,
}
}
export function checkIfAlreadyRewarded(originalEvent: Event, reviewId: string): boolean {
const alreadyRewarded = originalEvent.tags.some((tag) => tag[0] === 'rewarded' && tag[1] === 'true')
if (alreadyRewarded) {
console.log('Review already marked as rewarded', {
reviewId,
timestamp: new Date().toISOString(),
})
}
return alreadyRewarded
}
export async function publishRewardEvent(
updatedEvent: {
kind: number
created_at: number
tags: string[][]
content: string
},
reviewId: string
): Promise<void> {
const publishedEvent = await nostrService.publishEvent(updatedEvent)
if (publishedEvent) {
console.log('Review updated with reward tag', {
reviewId,
updatedEventId: publishedEvent.id,
timestamp: new Date().toISOString(),
})
} else {
console.error('Failed to publish updated review event', {
reviewId,
timestamp: new Date().toISOString(),
})
}
}
export async function updateReviewWithReward(reviewId: string, authorPrivateKey: string): Promise<void> {
try {
const originalEvent = await fetchOriginalReviewEvent(reviewId)
if (!originalEvent) {
console.error('Original review event not found', {
reviewId,
timestamp: new Date().toISOString(),
})
return
}
if (checkIfAlreadyRewarded(originalEvent, reviewId)) {
return
}
nostrService.setPrivateKey(authorPrivateKey)
nostrService.setPublicKey(originalEvent.pubkey)
const updatedEvent = buildRewardEvent(originalEvent, reviewId)
await publishRewardEvent(updatedEvent, reviewId)
} catch (error) {
console.error('Error updating review with reward', {
reviewId,
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: new Date().toISOString(),
})
}
}