169 lines
5.0 KiB
TypeScript
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(),
|
|
})
|
|
}
|
|
}
|