story-research-zapwall/lib/reviewRewardUpdate.ts
2026-01-07 02:06:09 +01:00

169 lines
5.0 KiB
TypeScript

import { nostrService } from './nostr'
import { PLATFORM_COMMISSIONS } from './platformCommissions'
import type { Event } from 'nostr-tools'
import { objectCache } from './objectCache'
export async function fetchOriginalReviewEvent(reviewId: string): Promise<Event | null> {
// Read only from IndexedDB cache
const parsed = await objectCache.getById('review', reviewId)
if (parsed) {
// Get the event from cache
const event = await objectCache.getEventById('review', reviewId)
if (event) {
return event
}
}
// Not found in cache - return null (no network request)
return null
}
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.warn('Review already marked as rewarded', {
reviewId,
timestamp: new Date().toISOString(),
})
}
return alreadyRewarded
}
export async function publishRewardEvent(
updatedEventTemplate: {
kind: number
created_at: number
tags: string[][]
content: string
},
reviewId: string
): Promise<void> {
try {
// Get original review to extract hash and parsed data
const originalEvent = await fetchOriginalReviewEvent(reviewId)
if (!originalEvent) {
throw new Error('Original review event not found in cache')
}
const { parseReviewFromEvent } = await import('./nostrEventParsing')
const originalParsed = await parseReviewFromEvent(originalEvent)
if (!originalParsed) {
throw new Error('Failed to parse original review')
}
// Increment version for update
const newVersion = (originalParsed.version ?? 0) + 1
const {hash} = originalParsed
const index = originalParsed.index ?? 0
// Build updated parsed Review object
const updatedParsed = {
...originalParsed,
version: newVersion,
rewarded: true,
rewardAmount: PLATFORM_COMMISSIONS.review.total,
}
// Set private key in orchestrator
const privateKey = nostrService.getPrivateKey()
if (!privateKey) {
throw new Error('Private key required for signing')
}
const { writeOrchestrator } = await import('./writeOrchestrator')
writeOrchestrator.setPrivateKey(privateKey)
// Finalize event
const { finalizeEvent } = await import('nostr-tools')
const { hexToBytes } = await import('nostr-tools/utils')
const secretKey = hexToBytes(privateKey)
const event = finalizeEvent(updatedEventTemplate, secretKey)
// Get active relays
const { relaySessionManager } = await import('./relaySessionManager')
const activeRelays = await relaySessionManager.getActiveRelays()
const { getPrimaryRelay } = await import('./config')
const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()]
// Publish via writeOrchestrator (parallel network + local write)
const result = await writeOrchestrator.writeAndPublish(
{
objectType: 'review',
hash,
event,
parsed: updatedParsed,
version: newVersion,
hidden: false,
index,
},
relays
)
if (result.success) {
console.warn('Review updated with reward tag', {
reviewId,
updatedEventId: event.id,
timestamp: new Date().toISOString(),
})
} else {
console.error('Failed to publish updated review event', {
reviewId,
timestamp: new Date().toISOString(),
})
}
} catch (error) {
console.error('Error publishing reward event', {
reviewId,
error: error instanceof Error ? error.message : 'Unknown error',
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(),
})
}
}