/**
* useMemory Hook
* Manage a single memory with CRUD operations
*/
import { useState, useEffect, useCallback, useRef } from 'react';
import { useMemoryStackClient } from './useMemoryStack';
import type { Memory, UseMemoryResult } from '../types';
/**
* Hook to manage a single memory
*
* @example
* ```tsx
* function MemoryDetail({ memoryId }: { memoryId: string }) {
* const { memory, isLoading, error, update, remove, refetch } = useMemory(memoryId);
*
* if (isLoading) {
* return ;
* }
*
* if (error) {
* return Error: {error.message};
* }
*
* if (!memory) {
* return Memory not found;
* }
*
* return (
*
* {memory.content}
* Type: {memory.memory_type}
* Confidence: {memory.confidence}
*
* );
* }
* ```
*/
export function useMemory(memoryId: string | null | undefined): UseMemoryResult {
const client = useMemoryStackClient();
const [memory, setMemory] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
const isMountedRef = useRef(true);
// Cleanup on unmount
useEffect(() => {
isMountedRef.current = true;
return () => {
isMountedRef.current = false;
};
}, []);
// Fetch memory
const fetchMemory = useCallback(async () => {
if (!client || !memoryId) {
setMemory(null);
setIsLoading(false);
return;
}
try {
setIsLoading(true);
setError(null);
const result = await client.getMemory(memoryId);
if (!isMountedRef.current) return;
setMemory(result);
} catch (err) {
if (!isMountedRef.current) return;
setError(err instanceof Error ? err : new Error('Failed to fetch memory'));
setMemory(null);
} finally {
if (isMountedRef.current) {
setIsLoading(false);
}
}
}, [client, memoryId]);
// Initial fetch
useEffect(() => {
fetchMemory();
}, [memoryId]);
// Update memory
const update = useCallback(async (updates: {
content?: string;
memory_type?: string;
confidence?: number;
metadata?: Record;
}) => {
if (!client || !memoryId) {
throw new Error('Cannot update: no memory ID');
}
try {
setIsLoading(true);
setError(null);
const response = await client.updateMemory(memoryId, updates);
if (!isMountedRef.current) return;
setMemory(response.memory);
} catch (err) {
if (!isMountedRef.current) return;
const error = err instanceof Error ? err : new Error('Failed to update memory');
setError(error);
throw error;
} finally {
if (isMountedRef.current) {
setIsLoading(false);
}
}
}, [client, memoryId]);
// Delete memory
const remove = useCallback(async (hard: boolean = false) => {
if (!client || !memoryId) {
throw new Error('Cannot delete: no memory ID');
}
try {
setIsLoading(true);
setError(null);
await client.deleteMemory(memoryId, hard);
if (!isMountedRef.current) return;
setMemory(null);
} catch (err) {
if (!isMountedRef.current) return;
const error = err instanceof Error ? err : new Error('Failed to delete memory');
setError(error);
throw error;
} finally {
if (isMountedRef.current) {
setIsLoading(false);
}
}
}, [client, memoryId]);
// Refetch
const refetch = useCallback(async () => {
await fetchMemory();
}, [fetchMemory]);
return {
memory,
isLoading,
error,
update,
remove,
refetch,
};
}
export default useMemory;