SkateSpots/src/hooks/useTrustBucket.ts
SkateSpots 0f8c77908b perf(trust): compute the local WoT graph once per viewer
TrustBadge called useTrustScore per card, which fetched the viewer's
follow list plus up to 100 friends' follow lists for EVERY card. The
graph does not depend on the target, so useViewerGraph computes it once
per viewer (one shared React Query) and deriveLocalScore returns the same
100/90/60/0 ladder (the NIP-05 30 tier classified as unknown anyway).
TrustBadge now costs no per-card network work on top of the batched
assertion read. Behaviour preserved; logged-out users still use the house
graph. Also records the ANALYZE=1 bundle findings in AGENTS.md.
2026-10-09 18:04:16 +07:00

46 lines
1.8 KiB
TypeScript

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,
};
}