import { useMutation, useQueryClient } from '@tanstack/react-query'; import { nip19 } from 'nostr-tools'; import { useNostrPublish } from '@/hooks/useNostrPublish'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useToast } from '@/hooks/useToast'; import { useTranslation } from '@/contexts/language'; import { NIP85_PROVIDER_LIST_KIND, NIP85_USER_ASSERTION_KIND, type TrustProvider } from '@/lib/nip85'; /** The assertion types we designate (the normative kind-30382 set). */ const ASSERTION_TYPES = ['rank', 'followers', 'reporters', 'muters', 'hops'] as const; /** Accept an npub or a 64-char hex pubkey; return hex or null. */ export function normalizeProviderPubkey(input: string): string | null { const value = input.trim(); if (/^[0-9a-f]{64}$/i.test(value)) return value.toLowerCase(); if (value.startsWith('npub1')) { try { const decoded = nip19.decode(value); if (decoded.type === 'npub') return decoded.data; } catch { return null; } } return null; } /** A relay hint must be a websocket URL. */ export function normalizeProviderRelay(input: string): string | null { const value = input.trim(); if (/^wss?:\/\/.+/i.test(value)) return value; return null; } /** * Publish (or clear) the viewer's NIP-85 kind-10040 provider designation. * Passing `null` clears it, so the app falls back to the community provider. * This is a signed action, so it prompts the signer like any other publish. */ export function useSetTrustProvider() { const { mutateAsync: publish } = useNostrPublish(); const { user } = useCurrentUser(); const { toast } = useToast(); const { t } = useTranslation(); const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: async (provider: TrustProvider | null) => { if (!user) throw new Error(t('trustUi.loggedOutProvider')); const relay = provider?.relay; const tags: string[][] = provider && relay ? ASSERTION_TYPES.map((type) => [`${NIP85_USER_ASSERTION_KIND}:${type}`, provider.pubkey, relay]) : []; await publish({ kind: NIP85_PROVIDER_LIST_KIND, content: '', tags }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['trust-provider', user?.pubkey] }); queryClient.invalidateQueries({ queryKey: ['trust-assertions-batch', user?.pubkey ?? ''] }); toast({ title: t('trustUi.providerSaved') }); }, onError: (error) => { toast({ title: t('trustUi.publishFailed'), description: error instanceof Error ? error.message : undefined, variant: 'destructive', }); }, }); return mutation; }