import type { Event } from 'nostr-tools' import { generateReviewTipHashId } from '../hashIdGenerator' import type { ExtractedReviewTip } from './types' import { readAmountSats, readPaymentHash, readPayerPubkeyFromZapReceipt, readTagValue, readZapReceiptKind } from './utils' export async function extractReviewTipFromEvent(event: Event): Promise { if (event.kind !== 9735 || readZapReceiptKind(event) !== 'review_tip') { return null } const extracted = readReviewTipFields(event) if (!extracted) { return null } const id = await generateReviewTipHashId(extracted) return { type: 'review_tip', id, ...extracted, eventId: event.id } } function readReviewTipFields(event: Event): Omit | null { const payerPubkey = readPayerPubkeyFromZapReceipt(event) const amount = readAmountSats(event) const paymentHash = readPaymentHash(event) const reviewerPubkey = readTagValue(event, 'reviewer') ?? readTagValue(event, 'p') const authorPubkey = readTagValue(event, 'author') const articleId = readTagValue(event, 'article') const reviewId = readTagValue(event, 'review_id') ?? readTagValue(event, 'e') const required = { payerPubkey, reviewerPubkey, authorPubkey, articleId, reviewId, paymentHash } if (!hasRequiredReviewTipFields(required) || amount === undefined) { console.error('[metadataExtractor] Invalid review_tip zap receipt: missing required fields', { eventId: event.id }) return null } return { payerPubkey: required.payerPubkey, reviewerPubkey: required.reviewerPubkey, authorPubkey: required.authorPubkey, articleId: required.articleId, reviewId: required.reviewId, amount, paymentHash: required.paymentHash, } } function hasRequiredReviewTipFields(values: { payerPubkey: string | undefined reviewerPubkey: string | undefined authorPubkey: string | undefined articleId: string | undefined reviewId: string | undefined paymentHash: string | undefined }): values is { payerPubkey: string reviewerPubkey: string authorPubkey: string articleId: string reviewId: string paymentHash: string } { const requiredKeys: ReadonlyArray = [ 'payerPubkey', 'reviewerPubkey', 'authorPubkey', 'articleId', 'reviewId', 'paymentHash', ] return requiredKeys.every((key) => isNonEmptyString(values[key])) } function isNonEmptyString(value: unknown): value is string { return typeof value === 'string' && value.length > 0 }