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