mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-11 07:56:50 +02:00
feat: kind schemas and better man pages
This commit is contained in:
@@ -5,15 +5,15 @@ import { useEventStore, useObservableMemo } from "applesauce-react/hooks";
|
||||
import { isNostrEvent } from "@/lib/type-guards";
|
||||
|
||||
interface UseLiveTimelineOptions {
|
||||
limit?: number;
|
||||
stream?: boolean;
|
||||
limit?: number;
|
||||
stream?: boolean;
|
||||
}
|
||||
|
||||
interface UseLiveTimelineReturn {
|
||||
events: NostrEvent[];
|
||||
loading: boolean;
|
||||
error: Error | null;
|
||||
eoseReceived: boolean;
|
||||
events: NostrEvent[];
|
||||
loading: boolean;
|
||||
error: Error | null;
|
||||
eoseReceived: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,103 +27,103 @@ interface UseLiveTimelineReturn {
|
||||
* @returns Object containing events array (from store, sorted), loading state, and error
|
||||
*/
|
||||
export function useLiveTimeline(
|
||||
id: string,
|
||||
filters: Filter | Filter[],
|
||||
relays: string[],
|
||||
options: UseLiveTimelineOptions = { limit: 200 },
|
||||
id: string,
|
||||
filters: Filter | Filter[],
|
||||
relays: string[],
|
||||
options: UseLiveTimelineOptions = { limit: 1000 },
|
||||
): UseLiveTimelineReturn {
|
||||
const eventStore = useEventStore();
|
||||
const { limit, stream = false } = options;
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const [eoseReceived, setEoseReceived] = useState(false);
|
||||
const eventStore = useEventStore();
|
||||
const { limit, stream = false } = options;
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const [eoseReceived, setEoseReceived] = useState(false);
|
||||
|
||||
// Stabilize filters and relays for dependency array
|
||||
// Using JSON.stringify and .join() for deep comparison - this is intentional
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const stableFilters = useMemo(() => filters, [JSON.stringify(filters)]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const stableRelays = useMemo(() => relays, [relays.join(",")]);
|
||||
// Stabilize filters and relays for dependency array
|
||||
// Using JSON.stringify and .join() for deep comparison - this is intentional
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const stableFilters = useMemo(() => filters, [JSON.stringify(filters)]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const stableRelays = useMemo(() => relays, [relays.join(",")]);
|
||||
|
||||
// 1. Subscription Effect - Fetch data and feed EventStore
|
||||
useEffect(() => {
|
||||
if (relays.length === 0) {
|
||||
// 1. Subscription Effect - Fetch data and feed EventStore
|
||||
useEffect(() => {
|
||||
if (relays.length === 0) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("LiveTimeline: Starting query", {
|
||||
id,
|
||||
relays,
|
||||
filters,
|
||||
limit,
|
||||
stream,
|
||||
});
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setEoseReceived(false);
|
||||
|
||||
// Normalize filters to array
|
||||
const filterArray = Array.isArray(filters) ? filters : [filters];
|
||||
|
||||
// Add limit to filters if specified
|
||||
const filtersWithLimit = filterArray.map((f) => ({
|
||||
...f,
|
||||
limit: limit || f.limit,
|
||||
}));
|
||||
|
||||
const observable = pool.subscription(relays, filtersWithLimit, {
|
||||
retries: 5,
|
||||
reconnect: 5,
|
||||
resubscribe: true,
|
||||
eventStore, // Automatically add events to store
|
||||
});
|
||||
|
||||
const subscription = observable.subscribe(
|
||||
(response) => {
|
||||
// Response can be an event or 'EOSE' string
|
||||
if (typeof response === "string") {
|
||||
console.log("LiveTimeline: EOSE received");
|
||||
setEoseReceived(true);
|
||||
if (!stream) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
} else if (isNostrEvent(response)) {
|
||||
// Event automatically added to store by pool.subscription (via options.eventStore)
|
||||
} else {
|
||||
console.warn("LiveTimeline: Unexpected response type:", response);
|
||||
}
|
||||
},
|
||||
(err: Error) => {
|
||||
console.error("LiveTimeline: Error", err);
|
||||
setError(err);
|
||||
setLoading(false);
|
||||
},
|
||||
() => {
|
||||
// Only set loading to false if not streaming
|
||||
if (!stream) {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
console.log("LiveTimeline: Starting query", {
|
||||
id,
|
||||
relays,
|
||||
filters,
|
||||
limit,
|
||||
stream,
|
||||
});
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setEoseReceived(false);
|
||||
|
||||
// Normalize filters to array
|
||||
const filterArray = Array.isArray(filters) ? filters : [filters];
|
||||
|
||||
// Add limit to filters if specified
|
||||
const filtersWithLimit = filterArray.map((f) => ({
|
||||
...f,
|
||||
limit: limit || f.limit,
|
||||
}));
|
||||
|
||||
const observable = pool.subscription(relays, filtersWithLimit, {
|
||||
retries: 5,
|
||||
reconnect: 5,
|
||||
resubscribe: true,
|
||||
eventStore, // Automatically add events to store
|
||||
});
|
||||
|
||||
const subscription = observable.subscribe(
|
||||
(response) => {
|
||||
// Response can be an event or 'EOSE' string
|
||||
if (typeof response === "string") {
|
||||
console.log("LiveTimeline: EOSE received");
|
||||
setEoseReceived(true);
|
||||
if (!stream) {
|
||||
setLoading(false);
|
||||
}
|
||||
} else if (isNostrEvent(response)) {
|
||||
// Event automatically added to store by pool.subscription (via options.eventStore)
|
||||
} else {
|
||||
console.warn("LiveTimeline: Unexpected response type:", response);
|
||||
}
|
||||
},
|
||||
(err: Error) => {
|
||||
console.error("LiveTimeline: Error", err);
|
||||
setError(err);
|
||||
setLoading(false);
|
||||
},
|
||||
() => {
|
||||
// Only set loading to false if not streaming
|
||||
if (!stream) {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, [id, stableFilters, stableRelays, limit, stream, eventStore]);
|
||||
|
||||
// 2. Observable Effect - Read from EventStore
|
||||
const timelineEvents = useObservableMemo(() => {
|
||||
// eventStore.timeline returns an Observable that emits sorted array of events matching filter
|
||||
// It updates whenever relevant events are added/removed from store
|
||||
return eventStore.timeline(filters);
|
||||
}, [stableFilters]);
|
||||
|
||||
return {
|
||||
events: timelineEvents || [],
|
||||
loading,
|
||||
error,
|
||||
eoseReceived,
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, [id, stableFilters, stableRelays, limit, stream, eventStore]);
|
||||
|
||||
// 2. Observable Effect - Read from EventStore
|
||||
const timelineEvents = useObservableMemo(() => {
|
||||
// eventStore.timeline returns an Observable that emits sorted array of events matching filter
|
||||
// It updates whenever relevant events are added/removed from store
|
||||
return eventStore.timeline(filters);
|
||||
}, [stableFilters]);
|
||||
|
||||
return {
|
||||
events: timelineEvents || [],
|
||||
loading,
|
||||
error,
|
||||
eoseReceived,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user