import {request} from "@welshman/net" import {clamp} from "@welshman/lib" import type {TrustedEvent} from "@welshman/util" const DEFAULT_ASSERTION_RELAYS = "wss://nip85.brainstorm.world,wss://nip85.nosfabrica.com,wss://nip85.uid.ovh" const toAssertionRelayUrl = (url: string) => { const trimmed = url.trim() if (!trimmed) return "" if (trimmed.startsWith("http://")) return trimmed.replace(/^http:/, "ws:") if (trimmed.startsWith("https://")) return trimmed.replace(/^https:/, "wss:") if (!/^[a-z]+:\/\//i.test(trimmed)) return `wss://${trimmed}` return trimmed } const ASSERTION_RELAYS = String(import.meta.env.VITE_ASSERTION_RELAYS || DEFAULT_ASSERTION_RELAYS) .split(",") .map(toAssertionRelayUrl) .filter(Boolean) const rankCache = new Map() const pendingRankRequests = new Map>() const getMedian = (values: number[]) => { const sorted = [...values].sort((a, b) => a - b) const middle = Math.floor(sorted.length / 2) if (sorted.length % 2 === 1) { return sorted[middle] } return (sorted[middle - 1] + sorted[middle]) / 2 } const getRankFromEvent = (event: TrustedEvent) => { const rankTag = event.tags?.find((tag: string[]) => tag[0] === "rank") const rankValue = rankTag ? Number(rankTag[1]) : null if (rankValue === null || !Number.isFinite(rankValue)) { return null } return clamp([0, 100], rankValue) } const fetchPubkeyRank = async (pubkey: string): Promise => { if (ASSERTION_RELAYS.length === 0) { return 50 } try { const events = await request({ relays: ASSERTION_RELAYS, autoClose: true, filters: [{kinds: [30382], "#d": [pubkey], limit: 8}], }) const ranks = events.map(getRankFromEvent).filter((rank): rank is number => rank !== null) if (ranks.length === 0) { return 50 } const median = getMedian(ranks) return median } catch { return 50 } } export const getPubkeyRank = (pubkey: string): Promise => { if (rankCache.has(pubkey)) { return Promise.resolve(rankCache.get(pubkey) ?? 50) } const pending = pendingRankRequests.get(pubkey) if (pending) { return pending } const requestPromise = fetchPubkeyRank(pubkey).then(rank => { rankCache.set(pubkey, rank ?? 50) pendingRankRequests.delete(pubkey) return rank ?? 50 }) pendingRankRequests.set(pubkey, requestPromise) return requestPromise }