import { useCurrentUser } from './useCurrentUser'; import { useViewerGraph, deriveLocalScore } from './useViewerGraph'; import { useTrustAssertions } from './useTrustAssertions'; import { bucketFromAssertion, bucketFromLocalScore, type TrustBucket } from '@/lib/trustLadder'; import type { UserTrustAssertion } from '@/lib/nip85'; export interface TrustBucketResult { bucket: TrustBucket; /** Provider assertion backing the bucket, when one exists. */ assertion?: UserTrustAssertion; /** Local web-of-trust score (0-100), when available. */ localScore?: number; /** The viewer directly follows this account (or it is the viewer). */ directFollow: boolean; isLoading: boolean; } /** * Resolve a viewer-facing trust bucket for one pubkey. Prefers a NIP-85 * assertion (it can both verify and flag); otherwise falls back to the local * web-of-trust ladder (verify only — it has no negative signal). * * Both inputs are batched/shared: the assertion read is a shared per-viewer * batch, and the local graph is computed once per viewer — so a grid of badges * costs no per-card network work. */ export function useTrustBucket(pubkey: string | undefined): TrustBucketResult { const { user } = useCurrentUser(); const { data: graph, isLoading: graphLoading } = useViewerGraph(); const { data: assertions, isLoading: assertionsLoading } = useTrustAssertions( pubkey ? [pubkey] : [], ); const assertion = pubkey ? assertions?.get(pubkey) : undefined; const localScore = deriveLocalScore(graph, pubkey, user?.pubkey); const bucket = assertion ? bucketFromAssertion(assertion) : bucketFromLocalScore(localScore); const directFollow = localScore !== undefined && localScore >= 90; return { bucket, assertion, localScore, directFollow, isLoading: graphLoading || assertionsLoading, }; }