UNPKG

trellis

Version:

Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications

160 lines (158 loc) 4.31 kB
import { TrellisProvider, useTrellis } from "../chunk-RKOK7WEV.js"; import { usePresence, useRoom, useSignal } from "../chunk-O2AV5WMN.js"; import "../chunk-K224QLJL.js"; import "../chunk-2ESYSVXG.js"; // src/react/hooks.ts import { useState, useEffect, useCallback, useRef } from "react"; function useEntity(id, options = {}) { const client = useTrellis(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const fetch = useCallback(async () => { if (!id) { setData(null); setLoading(false); return; } try { setLoading(true); const entity = await client.read(id); setData(entity); setError(null); } catch (err) { setError(err instanceof Error ? err : new Error(String(err))); } finally { setLoading(false); } }, [client, id]); useEffect(() => { fetch(); }, [fetch]); useEffect(() => { if (!options.pollInterval || !id) return; const interval = setInterval(fetch, options.pollInterval); return () => clearInterval(interval); }, [fetch, options.pollInterval, id]); return { data, loading, error, refetch: fetch }; } function useEntities(options = {}) { const client = useTrellis(); const [data, setData] = useState([]); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const optsRef = useRef(options); optsRef.current = options; const fetch = useCallback(async () => { try { setLoading(true); const result = await client.list(optsRef.current.type, { limit: optsRef.current.limit, offset: optsRef.current.offset }); setData(result.data); setTotal(result.total); setError(null); } catch (err) { setError(err instanceof Error ? err : new Error(String(err))); } finally { setLoading(false); } }, [client, options.type, options.limit, options.offset]); useEffect(() => { fetch(); }, [fetch]); useEffect(() => { if (!options.pollInterval) return; const interval = setInterval(fetch, options.pollInterval); return () => clearInterval(interval); }, [fetch, options.pollInterval]); return { data, total, loading, error, refetch: fetch }; } function useQuery(eql, options = {}) { const client = useTrellis(); const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const enabled = options.enabled !== false; const refetch = useCallback(async () => { if (!enabled || !eql.trim()) return; try { setLoading(true); const result = await client.query(eql); setData(result.bindings); setError(null); } catch (err) { setError(err instanceof Error ? err : new Error(String(err))); } finally { setLoading(false); } }, [client, eql, enabled]); useEffect(() => { if (!enabled || !eql.trim()) { setData([]); setLoading(false); return; } setLoading(true); const sub = client.subscribe(eql, (result) => { setData(result); setLoading(false); setError(null); }); return () => { sub.unsubscribe(); }; }, [client, eql, enabled]); return { data, loading, error, refetch }; } function useMutation() { const client = useTrellis(); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); async function run(fn) { setLoading(true); setError(null); try { return await fn(); } catch (err) { const e = err instanceof Error ? err : new Error(String(err)); setError(e); throw e; } finally { setLoading(false); } } const create = useCallback( (type, attributes = {}) => run(() => client.create(type, attributes)), [client] ); const update = useCallback( (id, attributes) => run(() => client.update(id, attributes)), [client] ); const remove = useCallback( (id) => run(() => client.delete(id)), [client] ); return { create, update, remove, loading, error }; } export { TrellisProvider, useEntities, useEntity, useMutation, usePresence, useQuery, useRoom, useSignal, useTrellis };