| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import { useCallback, useEffect, useMemo, useState } from 'react'; |
| export function useMatrixHub({ hubUrl, enabled = true }) { |
| const [items, setItems] = useState([]); |
| const [total, setTotal] = useState(0); |
| const [loading, setLoading] = useState(false); |
| const [error, setError] = useState(null); |
| const [search, setSearch] = useState(''); |
| const [healthy, setHealthy] = useState(null); |
| const baseUrl = hubUrl.replace(/\/+$/, ''); |
| |
| useEffect(() => { |
| if (!enabled) |
| return; |
| let cancelled = false; |
| (async () => { |
| try { |
| const res = await fetch(`${baseUrl}/health`, { signal: AbortSignal.timeout(5000) }); |
| if (!cancelled) |
| setHealthy(res.ok); |
| } |
| catch { |
| if (!cancelled) |
| setHealthy(false); |
| } |
| })(); |
| return () => { cancelled = true; }; |
| }, [baseUrl, enabled]); |
| |
| const fetchCatalog = useCallback(async () => { |
| if (!enabled || healthy === false) |
| return; |
| setLoading(true); |
| setError(null); |
| try { |
| let url; |
| if (search.trim()) { |
| const q = encodeURIComponent(search.trim()); |
| url = `${baseUrl}/catalog/search?q=${q}&type=mcp_server&limit=50`; |
| } |
| else { |
| url = `${baseUrl}/catalog?type=mcp_server&limit=100&offset=0`; |
| } |
| const res = await fetch(url, { signal: AbortSignal.timeout(10000) }); |
| if (!res.ok) |
| throw new Error(`HTTP ${res.status}`); |
| const data = await res.json(); |
| |
| const serverItems = data.items || data.entities || []; |
| setItems(serverItems); |
| setTotal(data.total ?? serverItems.length); |
| } |
| catch (e) { |
| setError(e?.message || 'Failed to reach MatrixHub'); |
| setItems([]); |
| setTotal(0); |
| } |
| finally { |
| setLoading(false); |
| } |
| }, [baseUrl, enabled, search, healthy]); |
| useEffect(() => { |
| void fetchCatalog(); |
| }, [fetchCatalog]); |
| |
| const capabilities = useMemo(() => { |
| const set = new Set(); |
| items.forEach((i) => i.capabilities?.forEach((c) => set.add(c))); |
| return Array.from(set).sort(); |
| }, [items]); |
| return { |
| items, |
| total, |
| loading, |
| error, |
| healthy, |
| search, |
| setSearch, |
| capabilities, |
| refresh: fetchCatalog, |
| }; |
| } |
|
|