diff options
| -rw-r--r-- | apps/docs/docs.json | 13 | ||||
| -rw-r--r-- | apps/docs/memory-api/sdks/overview.mdx | 4 | ||||
| -rw-r--r-- | apps/docs/memory-graph/api-reference.mdx | 405 | ||||
| -rw-r--r-- | apps/docs/memory-graph/examples.mdx | 566 | ||||
| -rw-r--r-- | apps/docs/memory-graph/installation.mdx | 141 | ||||
| -rw-r--r-- | apps/docs/memory-graph/npm.mdx | 5 | ||||
| -rw-r--r-- | apps/docs/memory-graph/overview.mdx | 87 | ||||
| -rw-r--r-- | apps/docs/memory-graph/quick-start.mdx | 307 | ||||
| -rw-r--r-- | apps/docs/memory-graph/troubleshooting.mdx | 336 | ||||
| -rw-r--r-- | packages/memory-graph/README.md | 13 |
10 files changed, 1874 insertions, 3 deletions
diff --git a/apps/docs/docs.json b/apps/docs/docs.json index aef210a2..95cbd4f0 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -204,6 +204,19 @@ "ai-sdk/infinite-chat", "ai-sdk/npm" ] + }, + { + "group": "Memory Graph", + "icon": "network", + "pages": [ + "memory-graph/overview", + "memory-graph/installation", + "memory-graph/quick-start", + "memory-graph/api-reference", + "memory-graph/examples", + "memory-graph/troubleshooting", + "memory-graph/npm" + ] } ] } diff --git a/apps/docs/memory-api/sdks/overview.mdx b/apps/docs/memory-api/sdks/overview.mdx index 84719016..ae85c6aa 100644 --- a/apps/docs/memory-api/sdks/overview.mdx +++ b/apps/docs/memory-api/sdks/overview.mdx @@ -18,6 +18,10 @@ title: "Overview" Use supermemory with the python and javascript OpenAI SDKs </Card> + <Card title="Memory Graph" icon="network" href="/memory-graph/overview"> + Interactive canvas-based component to visualize your knowledge graph + </Card> + <Card title="Request more plugins" icon="life-buoy" href="mailto:[email protected]"> We will add support for your favorite SDKs asap. </Card> diff --git a/apps/docs/memory-graph/api-reference.mdx b/apps/docs/memory-graph/api-reference.mdx new file mode 100644 index 00000000..f6dc00c2 --- /dev/null +++ b/apps/docs/memory-graph/api-reference.mdx @@ -0,0 +1,405 @@ +--- +title: "API Reference" +description: "Complete reference for props, types, and configuration options" +sidebarTitle: "API Reference" +--- + +## Component Props + +### Core Props + +<ParamField path="documents" type="DocumentWithMemories[]" required> + Array of documents with their associated memories to display in the graph. This is the primary data source for the visualization. + + ```tsx + <MemoryGraph + documents={[ + { + id: "doc-1", + title: "Meeting Notes", + memoryEntries: [ + { + id: "mem-1", + documentId: "doc-1", + content: "Discussed project roadmap", + // ... other memory fields + } + ] + } + ]} + /> + ``` +</ParamField> + +<ParamField path="isLoading" type="boolean" default="false"> + Indicates whether the initial data is currently loading. Shows a loading indicator overlay. + + ```tsx + <MemoryGraph + documents={documents} + isLoading={true} + /> + ``` +</ParamField> + +<ParamField path="error" type="Error | null" default="null"> + Error object to display if data fetching fails. Shows an error state with the error message. + + ```tsx + <MemoryGraph + documents={documents} + error={new Error('Failed to load graph data')} + /> + ``` +</ParamField> + +<ParamField path="children" type="ReactNode"> + Content to display when no documents are available. Useful for custom empty states. + + ```tsx + <MemoryGraph documents={[]}> + <div> + <h2>No memories yet</h2> + <button>Add Memory</button> + </div> + </MemoryGraph> + ``` +</ParamField> + +### Display Props + +<ParamField path="variant" type="'console' | 'consumer'" default="'console'"> + Visual variant that determines the default zoom level and UI layout. + + - **console**: Full dashboard view (zoom: 0.8, spaces selector shown, legend bottom-right) + - **consumer**: Embedded widget view (zoom: 0.5, spaces selector hidden, legend top-right) + + ```tsx + {/* Full dashboard */} + <MemoryGraph documents={documents} variant="console" /> + + {/* Embedded widget */} + <MemoryGraph documents={documents} variant="consumer" /> + ``` +</ParamField> + +<ParamField path="showSpacesSelector" type="boolean" default="Based on variant"> + Controls visibility of the spaces/container filter dropdown. Defaults to `true` for console variant, `false` for consumer variant. + + ```tsx + {/* Force show on consumer variant */} + <MemoryGraph + documents={documents} + variant="consumer" + showSpacesSelector={true} + /> + ``` +</ParamField> + +<ParamField path="legendId" type="string"> + Custom ID for the legend element. Useful for DOM targeting or testing. + + ```tsx + <MemoryGraph + documents={documents} + legendId="my-custom-legend" + /> + ``` +</ParamField> + +### Highlighting Props + +<ParamField path="highlightDocumentIds" type="string[]" default="[]"> + Array of document IDs to highlight in the graph. Supports both internal IDs and custom IDs. Perfect for showing search results or filtered content. + + ```tsx + <MemoryGraph + documents={documents} + highlightDocumentIds={['doc-123', 'custom-id-456']} + /> + ``` +</ParamField> + +<ParamField path="highlightsVisible" type="boolean" default="true"> + Controls whether highlights are currently visible. Useful for toggling highlights on/off. + + ```tsx + const [showHighlights, setShowHighlights] = useState(true) + + <MemoryGraph + documents={documents} + highlightDocumentIds={searchResults} + highlightsVisible={showHighlights} + /> + ``` +</ParamField> + +### Pagination Props + +For large datasets, implement pagination to load documents incrementally: + +<ParamField path="isLoadingMore" type="boolean" default="false"> + Indicates whether additional data is being loaded. Shows a loading indicator without blocking interactions. + + ```tsx + <MemoryGraph + documents={documents} + isLoadingMore={true} + /> + ``` +</ParamField> + +<ParamField path="hasMore" type="boolean" default="false"> + Indicates whether more documents are available to load. + + ```tsx + <MemoryGraph + documents={documents} + hasMore={page < totalPages} + /> + ``` +</ParamField> + +<ParamField path="totalLoaded" type="number" default="documents.length"> + Total number of documents currently loaded. Displayed in the loading indicator. + + ```tsx + <MemoryGraph + documents={documents} + totalLoaded={documents.length} + /> + ``` +</ParamField> + +<ParamField path="loadMoreDocuments" type="() => Promise<void>"> + Async callback function to load more documents. Called automatically when user scrolls near the viewport edge. + + ```tsx + const loadMore = async () => { + const nextPage = await fetchNextPage() + setDocuments(prev => [...prev, ...nextPage]) + } + + <MemoryGraph + documents={documents} + hasMore={true} + loadMoreDocuments={loadMore} + /> + ``` +</ParamField> + +### Advanced Props + +<ParamField path="occludedRightPx" type="number" default="0"> + Number of pixels occluded on the right side (e.g., by a chat panel). Used to adjust auto-fit calculations. + + ```tsx + {/* Account for 400px chat panel on the right */} + <MemoryGraph + documents={documents} + occludedRightPx={400} + /> + ``` +</ParamField> + +<ParamField path="autoLoadOnViewport" type="boolean" default="true"> + Enable automatic loading when 80% of documents are visible in viewport. Set to `false` for manual pagination control. + + ```tsx + <MemoryGraph + documents={documents} + hasMore={true} + loadMoreDocuments={loadMore} + autoLoadOnViewport={false} + /> + ``` +</ParamField> + +<ParamField path="themeClassName" type="string"> + Custom theme class name for styling overrides. Use with Vanilla Extract theme system. + + ```tsx + import { customTheme } from './my-theme.css' + + <MemoryGraph + documents={documents} + themeClassName={customTheme} + /> + ``` +</ParamField> + +## TypeScript Types + +### Core Data Types + +```typescript +interface DocumentWithMemories { + id: string + customId?: string | null + title?: string + content?: string + summary?: string + url?: string + summaryEmbedding?: number[] // For similarity calculations + memoryEntries: MemoryEntry[] + createdAt: string + updatedAt: string + userId?: string + spaceId?: string + spaceContainerTag?: string +} + +interface MemoryEntry { + id: string + documentId: string + content: string | null + embedding?: number[] + spaceContainerTag?: string + spaceId?: string + updatesMemoryId?: string | null + relation?: 'updates' | 'extends' | 'derives' | null + isForgotten?: boolean + isLatest?: boolean + forgetAfter?: string | null + createdAt: string + updatedAt: string +} +``` + +### Graph Types + +```typescript +interface GraphNode { + id: string + type: 'document' | 'memory' + x: number + y: number + data: DocumentWithMemories | MemoryEntry + size: number + color: string + isHovered: boolean + isDragging: boolean +} + +interface GraphEdge { + id: string + source: string + target: string + similarity: number // 0-1 for semantic similarity + visualProps: { + opacity: number + thickness: number + glow: number + pulseDuration: number + } + color: string + edgeType: 'doc-memory' | 'doc-doc' | 'version' + relationType?: 'updates' | 'extends' | 'derives' +} +``` + +### Component Props Type + +```typescript +interface MemoryGraphProps { + // Core + documents: DocumentWithMemories[] + isLoading?: boolean + error?: Error | null + children?: ReactNode + + // Display + variant?: 'console' | 'consumer' + showSpacesSelector?: boolean + legendId?: string + + // Highlighting + highlightDocumentIds?: string[] + highlightsVisible?: boolean + + // Pagination + isLoadingMore?: boolean + hasMore?: boolean + totalLoaded?: number + loadMoreDocuments?: () => Promise<void> + + // Advanced + occludedRightPx?: number + autoLoadOnViewport?: boolean + themeClassName?: string +} +``` + +## Variants Comparison + +| Feature | Console | Consumer | +|---------|---------|----------| +| **Initial Zoom** | 0.8 (closer view) | 0.5 (wider view) | +| **Spaces Selector** | Shown by default | Hidden by default | +| **Legend Position** | Bottom-right | Top-right | +| **Best For** | Full-page dashboards | Embedded widgets | +| **Use Cases** | Admin panels, analytics | Sidebars, chat integration | + +### Console Variant + +```tsx +<MemoryGraph + documents={documents} + variant="console" + // Spaces selector shown + // Legend in bottom-right + // Closer initial view +/> +``` + +{/* TODO: Add console variant screenshot */} + +### Consumer Variant + +```tsx +<MemoryGraph + documents={documents} + variant="consumer" + // Spaces selector hidden + // Legend in top-right + // Wider initial view +/> +``` + +{/* TODO: Add consumer variant screenshot */} + +## Type Imports + +Import all types you need for TypeScript: + +```typescript +import type { + // Data types + DocumentWithMemories, + MemoryEntry, + DocumentsResponse, + + // Graph types + GraphNode, + GraphEdge, + MemoryRelation, + + // Component types + MemoryGraphProps, + + // Theme types (if customizing) + Sprinkles, +} from '@supermemory/memory-graph' +``` + +## Next Steps + +<CardGroup cols={2}> + <Card title="Examples" icon="code" href="/memory-graph/examples"> + See real-world implementation patterns + </Card> + + <Card title="Troubleshooting" icon="wrench" href="/memory-graph/troubleshooting"> + Solve common issues + </Card> +</CardGroup> diff --git a/apps/docs/memory-graph/examples.mdx b/apps/docs/memory-graph/examples.mdx new file mode 100644 index 00000000..7fa9f578 --- /dev/null +++ b/apps/docs/memory-graph/examples.mdx @@ -0,0 +1,566 @@ +--- +title: "Examples" +description: "Real-world implementation patterns and use cases" +sidebarTitle: "Examples" +--- + +Explore production-ready examples for common use cases and integration patterns. + +## Basic Example + +Simple implementation with static data - perfect for testing and learning: + +```tsx BasicGraph.tsx +'use client' + +import { MemoryGraph } from '@supermemory/memory-graph' +import type { DocumentWithMemories } from '@supermemory/memory-graph' + +// Sample data for testing +const sampleDocuments: DocumentWithMemories[] = [ + { + id: "doc-1", + title: "Project Roadmap", + content: "Q1 goals and milestones", + summary: "Planning for Q1 2024", + memoryEntries: [ + { + id: "mem-1", + documentId: "doc-1", + content: "Launch new feature by end of Q1", + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + } + ], + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + } +] + +export default function BasicGraph() { + return ( + <div style={{ width: '100%', height: '600px' }}> + <MemoryGraph documents={sampleDocuments} /> + </div> + ) +} +``` + +{/* TODO: Add basic example screenshot */} + +## Next.js Integration + +### With App Router + +Complete example with backend proxy, authentication, and error handling: + +```typescript app/api/graph-data/route.ts +import { NextResponse } from 'next/server' +import { auth } from '@/lib/auth' + +export async function GET() { + // Authenticate user + const session = await auth() + if (!session?.user) { + return NextResponse.json( + { error: 'Unauthorized' }, + { status: 401 } + ) + } + + try { + const response = await fetch( + 'https://api.supermemory.ai/v3/documents/documents', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, + }, + body: JSON.stringify({ + page: 1, + limit: 500, + containerTags: [session.user.id], // User isolation + sort: 'createdAt', + order: 'desc', + }), + } + ) + + if (!response.ok) { + throw new Error(`Supermemory API error: ${response.statusText}`) + } + + const data = await response.json() + return NextResponse.json(data) + } catch (error) { + console.error('Graph data fetch error:', error) + return NextResponse.json( + { error: 'Failed to fetch graph data' }, + { status: 500 } + ) + } +} +``` + +```tsx app/graph/page.tsx +'use client' + +import { MemoryGraph } from '@supermemory/memory-graph' +import { useState, useEffect } from 'react' +import type { DocumentWithMemories } from '@supermemory/memory-graph' + +export default function GraphPage() { + const [documents, setDocuments] = useState<DocumentWithMemories[]>([]) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState<Error | null>(null) + + useEffect(() => { + fetch('/api/graph-data') + .then(async (res) => { + if (!res.ok) throw new Error(await res.text()) + return res.json() + }) + .then((data) => { + setDocuments(data.documents) + setIsLoading(false) + }) + .catch((err) => { + setError(err) + setIsLoading(false) + }) + }, []) + + return ( + <main style={{ height: '100vh' }}> + <MemoryGraph + documents={documents} + isLoading={isLoading} + error={error} + variant="console" + /> + </main> + ) +} +``` + +{/* TODO: Add Next.js example screenshot */} + +## With Pagination + +Implement infinite scroll for large datasets: + +```tsx GraphWithPagination.tsx +'use client' + +import { MemoryGraph } from '@supermemory/memory-graph' +import { useState, useCallback } from 'react' +import type { DocumentWithMemories } from '@supermemory/memory-graph' + +export default function GraphWithPagination() { + const [documents, setDocuments] = useState<DocumentWithMemories[]>([]) + const [page, setPage] = useState(1) + const [hasMore, setHasMore] = useState(true) + const [isLoading, setIsLoading] = useState(true) + const [isLoadingMore, setIsLoadingMore] = useState(false) + const [error, setError] = useState<Error | null>(null) + + // Initial load + useState(() => { + fetchPage(1) + }, []) + + const fetchPage = async (pageNum: number) => { + try { + if (pageNum === 1) { + setIsLoading(true) + } else { + setIsLoadingMore(true) + } + + const response = await fetch( + `/api/graph-data?page=${pageNum}&limit=100` + ) + + if (!response.ok) { + throw new Error('Failed to fetch documents') + } + + const data = await response.json() + + setDocuments(prev => + pageNum === 1 ? data.documents : [...prev, ...data.documents] + ) + + setHasMore( + data.pagination.currentPage < data.pagination.totalPages + ) + setPage(pageNum) + } catch (err) { + setError(err instanceof Error ? err : new Error('Unknown error')) + } finally { + setIsLoading(false) + setIsLoadingMore(false) + } + } + + const loadMore = useCallback(async () => { + if (!isLoadingMore && hasMore) { + await fetchPage(page + 1) + } + }, [page, isLoadingMore, hasMore]) + + return ( + <div style={{ width: '100%', height: '100vh' }}> + <MemoryGraph + documents={documents} + isLoading={isLoading} + isLoadingMore={isLoadingMore} + hasMore={hasMore} + totalLoaded={documents.length} + loadMoreDocuments={loadMore} + /> + </div> + ) +} +``` + +<Tip> +The graph automatically loads more documents when 80% of current documents are visible in the viewport. Set `autoLoadOnViewport={false}` for manual control. +</Tip> + +{/* TODO: Add pagination example screenshot */} + +## Search Integration with Highlighting + +Highlight search results in the graph: + +```tsx SearchableGraph.tsx +'use client' + +import { MemoryGraph } from '@supermemory/memory-graph' +import { useState, useEffect } from 'react' +import type { DocumentWithMemories } from '@supermemory/memory-graph' + +export default function SearchableGraph() { + const [documents, setDocuments] = useState<DocumentWithMemories[]>([]) + const [searchQuery, setSearchQuery] = useState('') + const [highlightedIds, setHighlightedIds] = useState<string[]>([]) + const [showHighlights, setShowHighlights] = useState(true) + + // Fetch all documents + useEffect(() => { + fetch('/api/graph-data') + .then(res => res.json()) + .then(data => setDocuments(data.documents)) + }, []) + + // Search and highlight + const handleSearch = async () => { + if (!searchQuery.trim()) { + setHighlightedIds([]) + return + } + + try { + const response = await fetch('/api/search', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ query: searchQuery }) + }) + + const results = await response.json() + + // Extract document IDs from search results + const docIds = results.documents.map((doc: any) => doc.id) + setHighlightedIds(docIds) + setShowHighlights(true) + } catch (error) { + console.error('Search error:', error) + } + } + + return ( + <div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}> + {/* Search bar */} + <div style={{ + padding: '1rem', + display: 'flex', + gap: '0.5rem', + borderBottom: '1px solid #e5e7eb' + }}> + <input + type="text" + value={searchQuery} + onChange={(e) => setSearchQuery(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && handleSearch()} + placeholder="Search documents..." + style={{ flex: 1, padding: '0.5rem', borderRadius: '0.375rem' }} + /> + <button onClick={handleSearch}>Search</button> + <button onClick={() => { + setHighlightedIds([]) + setSearchQuery('') + }}> + Clear + </button> + <label> + <input + type="checkbox" + checked={showHighlights} + onChange={(e) => setShowHighlights(e.target.checked)} + /> + Show highlights + </label> + </div> + + {/* Graph */} + <div style={{ flex: 1 }}> + <MemoryGraph + documents={documents} + highlightDocumentIds={highlightedIds} + highlightsVisible={showHighlights} + variant="console" + /> + </div> + </div> + ) +} +``` + +<Note> +Highlighting supports both internal document IDs and custom IDs. The graph will automatically match either. +</Note> + +{/* TODO: Add search highlighting screenshot */} + +## Custom Empty State + +Provide a custom UI when no documents exist: + +```tsx GraphWithEmpty.tsx +'use client' + +import { MemoryGraph } from '@supermemory/memory-graph' +import { useState, useEffect } from 'react' + +export default function GraphWithEmpty() { + const [documents, setDocuments] = useState([]) + + return ( + <div style={{ width: '100%', height: '100vh' }}> + <MemoryGraph documents={documents}> + <div style={{ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + gap: '2rem', + padding: '2rem', + textAlign: 'center' + }}> + <div> + <svg + width="120" + height="120" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + > + <circle cx="12" cy="12" r="10" /> + <line x1="12" y1="8" x2="12" y2="12" /> + <line x1="12" y1="16" x2="12.01" y2="16" /> + </svg> + </div> + + <div> + <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '0.5rem' }}> + No memories yet + </h2> + <p style={{ color: '#6b7280', maxWidth: '400px' }}> + Start adding content to see your knowledge graph come to life. + Documents and their connections will appear here. + </p> + </div> + + <div style={{ display: 'flex', gap: '1rem' }}> + <button + onClick={() => window.location.href = '/add-memory'} + style={{ + padding: '0.75rem 1.5rem', + backgroundColor: '#3b82f6', + color: 'white', + borderRadius: '0.5rem', + border: 'none', + cursor: 'pointer' + }} + > + Add Your First Memory + </button> + + <button + onClick={() => window.location.href = '/docs'} + style={{ + padding: '0.75rem 1.5rem', + backgroundColor: 'transparent', + border: '1px solid #d1d5db', + borderRadius: '0.5rem', + cursor: 'pointer' + }} + > + Learn More + </button> + </div> + </div> + </MemoryGraph> + </div> + ) +} +``` + +## Backend Patterns + +### Express.js + +```typescript server.ts +import express from 'express' + +const app = express() + +app.get('/api/graph-data', async (req, res) => { + // Authenticate user + const user = await authenticateRequest(req) + if (!user) { + return res.status(401).json({ error: 'Unauthorized' }) + } + + try { + const response = await fetch( + 'https://api.supermemory.ai/v3/documents/documents', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, + }, + body: JSON.stringify({ + page: 1, + limit: 500, + containerTags: [user.id], + }), + } + ) + + const data = await response.json() + res.json(data) + } catch (error) { + console.error('Error:', error) + res.status(500).json({ error: 'Failed to fetch data' }) + } +}) + +app.listen(3000) +``` + +### Cloudflare Workers + +```typescript worker.ts +export default { + async fetch(request: Request, env: Env) { + // Authenticate + const user = await authenticateRequest(request, env) + if (!user) { + return new Response('Unauthorized', { status: 401 }) + } + + try { + const response = await fetch( + 'https://api.supermemory.ai/v3/documents/documents', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${env.SUPERMEMORY_API_KEY}`, + }, + body: JSON.stringify({ + page: 1, + limit: 500, + containerTags: [user.id], + }), + } + ) + + return new Response(await response.text(), { + headers: { 'Content-Type': 'application/json' } + }) + } catch (error) { + return new Response('Internal Server Error', { status: 500 }) + } + } +} +``` + +### User Isolation with Container Tags + +For multi-user applications, always filter documents by user: + +```typescript +// Backend: Filter by user ID +body: JSON.stringify({ + containerTags: [user.id], // Only fetch this user's documents + page: 1, + limit: 500, +}) +``` + +<Warning> +Always implement user isolation on the backend. Never trust client-side filtering for security. +</Warning> + +## React Query Integration + +For better data management and caching: + +```tsx GraphWithReactQuery.tsx +'use client' + +import { MemoryGraph } from '@supermemory/memory-graph' +import { useQuery } from '@tanstack/react-query' + +export default function GraphWithReactQuery() { + const { data, isLoading, error } = useQuery({ + queryKey: ['graph-data'], + queryFn: async () => { + const response = await fetch('/api/graph-data') + if (!response.ok) { + throw new Error('Failed to fetch graph data') + } + return response.json() + }, + staleTime: 5 * 60 * 1000, // 5 minutes + refetchOnWindowFocus: false, + }) + + return ( + <div style={{ height: '100vh' }}> + <MemoryGraph + documents={data?.documents || []} + isLoading={isLoading} + error={error} + /> + </div> + ) +} +``` + +## Next Steps + +<CardGroup cols={2}> + <Card title="API Reference" icon="book" href="/memory-graph/api-reference"> + Explore all props and types + </Card> + + <Card title="Troubleshooting" icon="wrench" href="/memory-graph/troubleshooting"> + Solve common issues + </Card> +</CardGroup> diff --git a/apps/docs/memory-graph/installation.mdx b/apps/docs/memory-graph/installation.mdx new file mode 100644 index 00000000..ffaef93e --- /dev/null +++ b/apps/docs/memory-graph/installation.mdx @@ -0,0 +1,141 @@ +--- +title: "Installation" +description: "Install and set up the graph visualization component" +sidebarTitle: "Installation" +--- + +## Installation + +Install the package using your preferred package manager: + +<CodeGroup> + +```bash npm +npm install @supermemory/memory-graph +``` + +```bash yarn +yarn add @supermemory/memory-graph +``` + +```bash pnpm +pnpm add @supermemory/memory-graph +``` + +```bash bun +bun add @supermemory/memory-graph +``` + +</CodeGroup> + +## Requirements + +### Peer Dependencies + +The package requires React 18 or higher: + +```json +{ + "react": "^18.0.0", + "react-dom": "^18.0.0" +} +``` + +If you don't have React installed, add it first: + +```bash +npm install react react-dom +``` + +### Browser Requirements + +The component works in all modern browsers that support: +- **HTML5 Canvas 2D API**: For rendering the graph +- **ES2020+**: Modern JavaScript features +- **Touch Events**: For mobile gesture support (optional) + +Supported browsers: +- Chrome/Edge 90+ +- Firefox 88+ +- Safari 14+ +- Mobile browsers (iOS Safari, Chrome Mobile) + +## Setup + +### Automatic CSS Injection (Recommended) + +The component automatically injects its styles at runtime - no additional setup needed! + +```tsx +import { MemoryGraph } from '@supermemory/memory-graph' + +// Styles are automatically injected when the component mounts +function App() { + return <MemoryGraph documents={documents} /> +} +``` + +<Note> +The CSS is embedded in the JavaScript bundle and injected only once, even if you use multiple graph components. +</Note> + +### Manual CSS Import (Alternative) + +If you prefer to import CSS manually through your bundler: + +```tsx +import { MemoryGraph } from '@supermemory/memory-graph' +import '@supermemory/memory-graph/styles.css' +``` + +<Warning> +If you import CSS manually, the automatic injection will be skipped. Only use this if you have specific bundler requirements. +</Warning> + +## Verification + +Verify the installation by importing the component and types: + +```tsx +import { MemoryGraph } from '@supermemory/memory-graph' +import type { + DocumentWithMemories, + MemoryEntry, + MemoryGraphProps +} from '@supermemory/memory-graph' + +// TypeScript will provide full type checking +const props: MemoryGraphProps = { + documents: [], + isLoading: false, + error: null +} +``` + +<Tip> +The package exports all types you need for TypeScript. Check the [API Reference](/memory-graph/api-reference) for a complete list. +</Tip> + +## Universal Bundler Support + +The package works with all modern bundlers: + +- **Vite**: ✅ Works out of the box +- **webpack**: ✅ Works out of the box +- **Next.js**: ✅ Supports both App Router and Pages Router +- **Turbopack**: ✅ Fully compatible +- **Parcel**: ✅ Works out of the box + +No special configuration required for any bundler. + +## Next Steps + +<CardGroup cols={2}> + <Card title="Quick Start" icon="rocket" href="/memory-graph/quick-start"> + Build your first graph in 5 minutes + </Card> + + <Card title="API Reference" icon="book" href="/memory-graph/api-reference"> + Explore all available props and types + </Card> +</CardGroup> diff --git a/apps/docs/memory-graph/npm.mdx b/apps/docs/memory-graph/npm.mdx new file mode 100644 index 00000000..73185178 --- /dev/null +++ b/apps/docs/memory-graph/npm.mdx @@ -0,0 +1,5 @@ +--- +title: "NPM link" +url: "https://www.npmjs.com/package/@supermemory/memory-graph" +icon: npm +--- diff --git a/apps/docs/memory-graph/overview.mdx b/apps/docs/memory-graph/overview.mdx new file mode 100644 index 00000000..430e88f8 --- /dev/null +++ b/apps/docs/memory-graph/overview.mdx @@ -0,0 +1,87 @@ +--- +title: "Graph Visualization" +description: "Interactive canvas-based component for visualizing your memory connections" +sidebarTitle: "Overview" +--- + +[](https://www.npmjs.com/package/@supermemory/memory-graph) + +The `@supermemory/memory-graph` package provides an interactive, high-performance visualization component that transforms your documents and memories into an explorable knowledge graph. Built with React and powered by HTML5 Canvas, it offers smooth interactions and sophisticated rendering optimizations. + +{/* TODO: Add graph interaction GIF showing pan, zoom, and node interactions */} + +## Key Features + +<CardGroup cols={2}> + <Card title="High-Performance Rendering" icon="zap"> + Canvas-based rendering with LOD optimization, viewport culling, and change-based rendering for smooth performance with hundreds of nodes + </Card> + + <Card title="Interactive Exploration" icon="move"> + Pan, zoom, drag nodes, double-click to focus, and navigate with intuitive controls on both desktop and mobile + </Card> + + <Card title="Semantic Connections" icon="network"> + Visualizes relationships between documents based on content similarity and memory version chains + </Card> + + <Card title="Zero Configuration" icon="sparkles"> + Works out of the box with automatic CSS injection - no build configuration or style imports needed + </Card> + + <Card title="TypeScript Support" icon="code"> + Full TypeScript support with comprehensive type definitions for all props and data structures + </Card> + + <Card title="Responsive Design" icon="smartphone"> + Optimized for both desktop and mobile with touch gesture support (pinch-to-zoom, pan) + </Card> +</CardGroup> + +## When to Use + +The graph visualization component is ideal for: + +- **Knowledge Management Dashboards**: Visualize how documents and memories connect +- **Document Explorers**: Let users navigate through related content visually +- **Memory Analytics**: Show patterns in how information is structured and related +- **Search Result Visualization**: Display search results in context of the broader knowledge graph + +## Variants + +The component offers two visual variants optimized for different use cases: + +| Variant | Initial Zoom | Spaces Selector | Legend Position | Best For | +|---------|-------------|-----------------|-----------------|----------| +| **Console** | 0.8 (closer) | Shown | Bottom-right | Full-page dashboards, admin panels | +| **Consumer** | 0.5 (wider) | Hidden | Top-right | Embedded widgets, sidebars | + +## Graph Elements + +The visualization displays three types of nodes and three types of connections: + +**Nodes**: +- **Documents**: Rendered as rounded rectangles with glassmorphism styling +- **Memory Entries**: Rendered as hexagons (or circles when zoomed out) +- **Status Indicators**: Visual markers for forgotten, expiring, and new memories + +**Connections**: +- **Doc-Memory**: Solid thin lines connecting documents to their memory chunks +- **Doc-Doc**: Dashed lines showing semantic similarity (threshold: 0.725) +- **Version Chains**: Double-line arrows showing memory evolution (updates/extends/derives) + +## Next Steps + +<CardGroup cols={3}> + <Card title="Installation" icon="download" href="/memory-graph/installation"> + Install the package and get set up + </Card> + + <Card title="Quick Start" icon="rocket" href="/memory-graph/quick-start"> + Build your first graph in 5 minutes + </Card> + + <Card title="Examples" icon="code" href="/memory-graph/examples"> + Explore real-world implementation patterns + </Card> +</CardGroup> diff --git a/apps/docs/memory-graph/quick-start.mdx b/apps/docs/memory-graph/quick-start.mdx new file mode 100644 index 00000000..295f82bf --- /dev/null +++ b/apps/docs/memory-graph/quick-start.mdx @@ -0,0 +1,307 @@ +--- +title: "Quick Start" +description: "Build your first knowledge graph in 5 minutes" +sidebarTitle: "Quick Start" +--- + +Get your first interactive memory graph up and running in just a few minutes. + +<Warning> +**Security First**: Never expose your Supermemory API key in client-side code. Always use a backend proxy to authenticate requests. +</Warning> + +## Step 1: Create Backend Proxy + +Create an API route in your backend that authenticates users and proxies requests to the Supermemory API. + +<CodeGroup> + +```typescript Next.js App Router +// app/api/supermemory-graph/route.ts +import { NextResponse } from 'next/server' + +export async function GET(request: Request) { + // Add your authentication logic here + const user = await getAuthenticatedUser(request) + if (!user) { + return NextResponse.json( + { error: 'Unauthorized' }, + { status: 401 } + ) + } + + try { + const response = await fetch( + 'https://api.supermemory.ai/v3/documents/documents', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, + }, + body: JSON.stringify({ + page: 1, + limit: 500, + sort: 'createdAt', + order: 'desc', + // Optional: Filter by user-specific container + containerTags: [user.id], + }), + } + ) + + if (!response.ok) { + throw new Error('Failed to fetch documents') + } + + const data = await response.json() + return NextResponse.json(data) + } catch (error) { + console.error('Error fetching graph data:', error) + return NextResponse.json( + { error: 'Failed to fetch data' }, + { status: 500 } + ) + } +} +``` + +```typescript Next.js Pages Router +// pages/api/supermemory-graph.ts +import type { NextApiRequest, NextApiResponse } from 'next' + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + // Add your authentication logic here + const user = await getAuthenticatedUser(req) + if (!user) { + return res.status(401).json({ error: 'Unauthorized' }) + } + + try { + const response = await fetch( + 'https://api.supermemory.ai/v3/documents/documents', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, + }, + body: JSON.stringify({ + page: 1, + limit: 500, + sort: 'createdAt', + order: 'desc', + containerTags: [user.id], + }), + } + ) + + const data = await response.json() + res.status(200).json(data) + } catch (error) { + console.error('Error fetching graph data:', error) + res.status(500).json({ error: 'Failed to fetch data' }) + } +} +``` + +</CodeGroup> + +<Tip> +Use `containerTags` to filter documents by user in multi-user applications. This ensures users only see their own data. +</Tip> + +## Step 2: Create Frontend Component + +Create a component that fetches data and renders the graph. + +```tsx GraphComponent.tsx +'use client' // Required for Next.js App Router + +import { MemoryGraph } from '@supermemory/memory-graph' +import { useState, useEffect } from 'react' +import type { DocumentWithMemories } from '@supermemory/memory-graph' + +export default function GraphComponent() { + const [documents, setDocuments] = useState<DocumentWithMemories[]>([]) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState<Error | null>(null) + + useEffect(() => { + fetch('/api/supermemory-graph') + .then(async (res) => { + if (!res.ok) { + throw new Error('Failed to fetch documents') + } + return res.json() + }) + .then((data) => { + setDocuments(data.documents) + setIsLoading(false) + }) + .catch((err) => { + setError(err) + setIsLoading(false) + }) + }, []) + + return ( + {/* CRITICAL: Container must have explicit width and height */} + <div style={{ width: '100%', height: '100vh' }}> + <MemoryGraph + documents={documents} + isLoading={isLoading} + error={error} + > + {/* Custom empty state when no documents exist */} + <div style={{ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + height: '100%', + gap: '1rem' + }}> + <h2>No memories yet</h2> + <p>Start adding content to see your knowledge graph</p> + </div> + </MemoryGraph> + </div> + ) +} +``` + +<Warning> +**Container Sizing**: The graph component requires its parent container to have explicit width and height. Without this, the canvas will have 0 dimensions and won't render. +</Warning> + +## Step 3: Add to Your Page + +Use the component in your page: + +<CodeGroup> + +```tsx Next.js App Router +// app/graph/page.tsx +import GraphComponent from '@/components/GraphComponent' + +export default function GraphPage() { + return ( + <main style={{ height: '100vh' }}> + <GraphComponent /> + </main> + ) +} +``` + +```tsx Next.js Pages Router +// pages/graph.tsx +import GraphComponent from '@/components/GraphComponent' + +export default function GraphPage() { + return ( + <div style={{ height: '100vh' }}> + <GraphComponent /> + </div> + ) +} +``` + +```tsx React SPA +// src/App.tsx +import GraphComponent from './components/GraphComponent' + +function App() { + return ( + <div className="App" style={{ height: '100vh' }}> + <GraphComponent /> + </div> + ) +} + +export default App +``` + +</CodeGroup> + +## Complete Example + +Here's a complete, production-ready example with proper error handling and loading states: + +```tsx +'use client' + +import { MemoryGraph } from '@supermemory/memory-graph' +import { useState, useEffect } from 'react' +import type { DocumentWithMemories } from '@supermemory/memory-graph' + +export default function GraphDashboard() { + const [documents, setDocuments] = useState<DocumentWithMemories[]>([]) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState<Error | null>(null) + + useEffect(() => { + const fetchData = async () => { + try { + const response = await fetch('/api/supermemory-graph') + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`) + } + + const data = await response.json() + setDocuments(data.documents || []) + } catch (err) { + console.error('Failed to fetch graph data:', err) + setError(err instanceof Error ? err : new Error('Unknown error')) + } finally { + setIsLoading(false) + } + } + + fetchData() + }, []) + + return ( + <div className="dashboard" style={{ + width: '100%', + height: '100vh', + position: 'relative' + }}> + <MemoryGraph + documents={documents} + isLoading={isLoading} + error={error} + variant="console" + > + <div className="empty-state"> + <h2>No memories yet</h2> + <p>Start adding content to visualize your knowledge graph</p> + <button onClick={() => window.location.href = '/add-memory'}> + Add Your First Memory + </button> + </div> + </MemoryGraph> + </div> + ) +} +``` + +## Next Steps + +<CardGroup cols={3}> + <Card title="API Reference" icon="book" href="/memory-graph/api-reference"> + Explore all props and customization options + </Card> + + <Card title="Examples" icon="code" href="/memory-graph/examples"> + See advanced patterns like pagination and highlighting + </Card> + + <Card title="Troubleshooting" icon="wrench" href="/memory-graph/troubleshooting"> + Solve common issues + </Card> +</CardGroup> diff --git a/apps/docs/memory-graph/troubleshooting.mdx b/apps/docs/memory-graph/troubleshooting.mdx new file mode 100644 index 00000000..34533ad2 --- /dev/null +++ b/apps/docs/memory-graph/troubleshooting.mdx @@ -0,0 +1,336 @@ +--- +title: "Troubleshooting" +description: "Common issues and their solutions" +sidebarTitle: "Troubleshooting" +--- + +## Graph Not Rendering + +### Container Has No Dimensions + +**Problem**: The graph appears blank or shows nothing. + +**Cause**: The parent container has no explicit width or height (0x0 dimensions). + +**Solution**: Always set explicit dimensions on the container: + +```tsx +{/* ✅ Correct */} +<div style={{ width: '100%', height: '100vh' }}> + <MemoryGraph documents={documents} /> +</div> + +{/* ❌ Wrong - no height set */} +<div style={{ width: '100%' }}> + <MemoryGraph documents={documents} /> +</div> + +{/* ❌ Wrong - using auto height */} +<div style={{ width: '100%', height: 'auto' }}> + <MemoryGraph documents={documents} /> +</div> +``` + +<Tip> +Use browser DevTools to inspect the container element and verify it has non-zero width and height. +</Tip> + +### CSS Not Loading + +**Problem**: Graph renders but has no styling or looks broken. + +**Cause**: CSS injection failed or was blocked. + +**Solution**: + +1. Check browser console for errors +2. Try manual CSS import: + +```tsx +import '@supermemory/memory-graph/styles.css' +import { MemoryGraph } from '@supermemory/memory-graph' +``` + +3. Verify your bundler supports CSS imports + +### No Data Displayed + +**Problem**: Loading completes but no nodes appear. + +**Diagnosis**: + +```tsx +// Add console logs to debug +console.log('Documents:', documents) +console.log('Document count:', documents.length) +console.log('Has memories:', documents.some(d => d.memoryEntries.length > 0)) +``` + +**Common Causes**: +- Empty `documents` array +- Documents have no `memoryEntries` +- Data structure doesn't match expected type + +**Solution**: Verify your data matches the expected structure: + +```typescript +interface DocumentWithMemories { + id: string + title?: string + memoryEntries: MemoryEntry[] // Must be present + // ... other fields +} +``` + +## Performance Issues + +### Slow Rendering with Large Datasets + +**Problem**: Graph becomes sluggish with 500+ documents. + +**Solution**: Implement pagination: + +```tsx +<MemoryGraph + documents={documents} + hasMore={true} + loadMoreDocuments={loadMore} + isLoadingMore={isLoadingMore} +/> +``` + +<Note> +The graph uses viewport culling and Level-of-Detail (LOD) rendering automatically. Performance degradation typically starts around 1000+ nodes. +</Note> + +### High Memory Usage + +**Problem**: Browser uses excessive memory. + +**Cause**: Too many documents loaded at once. + +**Solution**: +1. Limit initial load to 200-500 documents +2. Use pagination to load incrementally +3. Consider filtering by space/container + +```typescript +// Backend: Limit documents +body: JSON.stringify({ + page: 1, + limit: 200, // Start with smaller limit + containerTags: [selectedSpace], +}) +``` + +### Laggy Interactions + +**Problem**: Pan/zoom feels sluggish. + +**Diagnosis**: +1. Check document count: `documents.length` +2. Check browser FPS in DevTools Performance tab +3. Check canvas size (very large canvases are slower) + +**Solutions**: +- Reduce number of visible documents +- Ensure container isn't larger than viewport +- Close other resource-intensive tabs + +## Data Fetching Errors + +### CORS Errors + +**Problem**: `Access-Control-Allow-Origin` error in console. + +**Cause**: Trying to fetch directly from client to Supermemory API. + +**Solution**: Always use a backend proxy: + +```tsx +{/* ❌ Wrong - CORS error */} +fetch('https://api.supermemory.ai/v3/documents/documents', { + headers: { 'Authorization': `Bearer ${apiKey}` } // API key exposed! +}) + +{/* ✅ Correct - through your backend */} +fetch('/api/graph-data') // Your backend proxies the request +``` + +<Warning> +Never call the Supermemory API directly from client code. This exposes your API key and causes CORS errors. +</Warning> + +### 401 Unauthorized + +**Problem**: Backend returns 401 error. + +**Common Causes**: +1. API key is missing or invalid +2. API key not in environment variables +3. Environment variables not loaded + +**Solution**: + +```bash +# .env.local +SUPERMEMORY_API_KEY=your_api_key_here +``` + +```typescript +// Verify in backend +console.log('API Key present:', !!process.env.SUPERMEMORY_API_KEY) +``` + +### 500 Internal Server Error + +**Problem**: Backend returns 500 error. + +**Diagnosis**: Check backend logs for details. + +**Common Causes**: +1. Network error reaching Supermemory API +2. Invalid request body +3. API key lacks permissions + +**Solution**: Add detailed error logging: + +```typescript +try { + const response = await fetch('https://api.supermemory.ai/...') + + if (!response.ok) { + const error = await response.text() + console.error('Supermemory API error:', response.status, error) + throw new Error(`API error: ${response.status}`) + } + + return await response.json() +} catch (error) { + console.error('Fetch error:', error) + throw error +} +``` + +### API Key Exposure Warning + +**Problem**: API key visible in Network tab or client code. + +**Risk**: Anyone can steal your API key and make unauthorized requests. + +**Solution**: +1. Remove API key from client code immediately +2. Rotate your API key in Supermemory dashboard +3. Implement backend proxy (see Quick Start guide) + +```tsx +{/* ❌ NEVER do this */} +const apiKey = 'sk_123...' // Exposed in source code! +fetch(url, { headers: { 'Authorization': `Bearer ${apiKey}` }}) + +{/* ✅ Always use backend proxy */} +fetch('/api/graph-data') // API key stays on server +``` + +## TypeScript Errors + +### Type Mismatch + +**Problem**: TypeScript errors on `documents` prop. + +**Solution**: Import and use the correct type: + +```tsx +import type { DocumentWithMemories } from '@supermemory/memory-graph' + +const [documents, setDocuments] = useState<DocumentWithMemories[]>([]) +``` + +### Missing Type Definitions + +**Problem**: TypeScript can't find types. + +**Solution**: +1. Verify package is installed: `npm list @supermemory/memory-graph` +2. Restart TypeScript server in your IDE +3. Check `node_modules/@supermemory/memory-graph/dist/index.d.ts` exists + +## Browser Compatibility + +### Not Working in Safari + +**Issue**: Graph doesn't render in Safari. + +**Cause**: Older Safari versions lack some Canvas 2D features. + +**Solution**: Ensure users are on Safari 14+ or suggest Chrome/Firefox. + +### Mobile Touch Gestures Not Working + +**Issue**: Can't pinch-to-zoom on mobile. + +**Cause**: Browser or container blocking touch events. + +**Solution**: Ensure parent has no conflicting touch handlers: + +```tsx +<div + style={{ touchAction: 'none' }} // Let graph handle touches + onTouchStart={(e) => e.stopPropagation()} +> + <MemoryGraph documents={documents} /> +</div> +``` + +### Canvas Appears Blurry + +**Issue**: Graph looks pixelated or blurry. + +**Cause**: High-DPI displays not being handled correctly. + +**Solution**: This should be automatic. If it persists: +1. Check browser zoom is at 100% +2. Verify `devicePixelRatio` is being respected +3. Try different browser + +## Build Errors + +### Module Not Found + +**Error**: `Cannot find module '@supermemory/memory-graph'` + +**Solution**: +1. Reinstall package: `npm install @supermemory/memory-graph` +2. Clear node_modules: `rm -rf node_modules && npm install` +3. Check package.json includes the package + +### Build Fails with CSS Error + +**Error**: `Failed to parse CSS` or similar. + +**Cause**: Bundler doesn't support CSS-in-JS. + +**Solution**: The package uses automatic CSS injection - no CSS import needed. If you must import CSS: + +```tsx +import '@supermemory/memory-graph/styles.css' +``` + +## Still Having Issues? + +<CardGroup cols={2}> + <Card title="GitHub Issues" icon="github" href="https://github.com/supermemoryai/supermemory/issues"> + Report bugs or request features + </Card> + + <Card title="Support" icon="life-buoy" href="mailto:[email protected]"> + Contact the Supermemory team + </Card> +</CardGroup> + +When reporting issues, please include: +- Browser and version +- Package version (`npm list @supermemory/memory-graph`) +- Framework (Next.js, React, etc.) and version +- Minimal reproduction code +- Console errors or screenshots diff --git a/packages/memory-graph/README.md b/packages/memory-graph/README.md index 049613bb..c646e22f 100644 --- a/packages/memory-graph/README.md +++ b/packages/memory-graph/README.md @@ -5,9 +5,15 @@ [](https://www.npmjs.com/package/@supermemory/memory-graph) [](https://opensource.org/licenses/MIT) +## Documentation + +📚 **[View full documentation](https://supermemory.ai/docs/memory-graph/overview)** + +Comprehensive guides, API reference, and examples available in the official docs. + ## Features -- **WebGL-powered rendering** - Smooth performance with hundreds of nodes +- **High-performance canvas rendering** - Smooth performance with hundreds of nodes using LOD optimization and viewport culling - **Interactive exploration** - Pan, zoom, drag nodes, and explore connections - **Semantic connections** - Visualizes relationships based on content similarity - **Responsive design** - Works seamlessly on mobile and desktop @@ -220,12 +226,12 @@ The `variant` prop controls the visual layout and initial viewport settings: - Chrome/Edge (latest) - Firefox (latest) - Safari (latest) -- Mobile browsers with WebGL support +- Mobile browsers with Canvas support ## Requirements - React 18+ -- Modern browser with WebGL support +- Modern browser with Canvas 2D support ## Development @@ -249,4 +255,5 @@ MIT ## Support +- Documentation: [docs.supermemory.ai/memory-graph](https://docs.supermemory.ai/memory-graph/overview) - Issues: [GitHub Issues](https://github.com/supermemoryai/supermemory/issues) |