import { useMemo } from 'react'; import { useAppContext } from '@/hooks/useAppContext'; import type { RelayMetadata } from '@/contexts/AppContext'; /** Host (no scheme) for display, falling back to the raw value. */ export function relayHost(url: string): string { try { return new URL(url).host; } catch { return url; } } /** Normalise user input into a `ws(s)://` relay URL, or null if invalid. */ export function normalizeRelayUrl(input: string): string | null { const raw = input.trim(); if (!raw) return null; try { const url = new URL(/^wss?:\/\//i.test(raw) ? raw : `wss://${raw}`); if (url.protocol === 'http:') url.protocol = 'ws:'; if (url.protocol === 'https:') url.protocol = 'wss:'; if (url.protocol !== 'ws:' && url.protocol !== 'wss:') return null; if (!url.host) return null; return url.toString().replace(/\/$/, ''); } catch { return null; } } export interface ResolvedRelays { /** NIP-65 relays with blocked ones removed (read/write flags kept). */ configured: { url: string; read: boolean; write: boolean }[]; /** App-local relays (blocked ones removed). */ local: string[]; /** The blocklist, lower-cased. */ blocked: string[]; /** URLs to read from: local first, then read-enabled configured. */ read: string[]; /** URLs to write to: write-enabled configured, then local. */ write: string[]; } /** * Resolve the effective relay sets from config: blocked relays are removed * everywhere, and local relays are added to both reads and writes. */ export function resolveRelays(metadata: RelayMetadata): ResolvedRelays { const blocked = new Set((metadata.blockedRelays ?? []).map((u) => u.toLowerCase())); const local = (metadata.localRelays ?? []).filter((u) => !blocked.has(u.toLowerCase())); const configured = metadata.relays.filter((r) => !blocked.has(r.url.toLowerCase())); return { configured, local, blocked: [...blocked], read: [...local, ...configured.filter((r) => r.read).map((r) => r.url)], write: [...configured.filter((r) => r.write).map((r) => r.url), ...local], }; } /** React wrapper around {@link resolveRelays} for components/hooks. */ export function useRelays(): ResolvedRelays { const { config } = useAppContext(); return useMemo(() => resolveRelays(config.relayMetadata), [config.relayMetadata]); }