add docs for graph package (#603)

This commit is contained in:
nexxeln 2025-12-04 18:56:40 +00:00
parent 7a2f2cb99c
commit 1b9b3012e3
8 changed files with 1075 additions and 328 deletions

View file

@ -213,6 +213,18 @@
"ai-sdk/infinite-chat",
"ai-sdk/npm"
]
},
{
"group": "Memory Graph",
"icon": "network",
"pages": [
"memory-graph/overview",
"memory-graph/installation",
"memory-graph/quickstart",
"memory-graph/api-reference",
"memory-graph/examples",
"memory-graph/npm"
]
}
]
}

View file

@ -0,0 +1,334 @@
---
title: 'API Reference'
description: 'Complete reference for Memory Graph props and types'
---
## Component Props
### MemoryGraph
The main graph component.
#### Core Props
<ParamField path="documents" type="DocumentWithMemories[]" required>
Array of documents to display in the graph. Each document must include its memory entries.
</ParamField>
<ParamField path="isLoading" type="boolean" default="false">
Shows a loading indicator when true.
</ParamField>
<ParamField path="error" type="Error | null" default="null">
Error object to display. Shows an error message overlay when set.
</ParamField>
<ParamField path="variant" type='"console" | "consumer"' default='"console"'>
Visual variant:
- `console`: Full-featured dashboard view (0.8x zoom, space selector visible)
- `consumer`: Embedded widget view (0.5x zoom, space selector hidden)
</ParamField>
<ParamField path="children" type="ReactNode">
Content to render when no documents exist. Useful for empty states.
</ParamField>
#### Pagination Props
<ParamField path="isLoadingMore" type="boolean" default="false">
Shows a subtle indicator when loading additional documents.
</ParamField>
<ParamField path="hasMore" type="boolean" default="false">
Whether more documents are available to load.
</ParamField>
<ParamField path="totalLoaded" type="number">
Total number of documents currently loaded. Shown in loading indicator.
</ParamField>
<ParamField path="loadMoreDocuments" type="() => Promise<void>">
Callback to load more documents. Called automatically when viewport shows most documents.
</ParamField>
<ParamField path="autoLoadOnViewport" type="boolean" default="true">
Automatically load more documents when 80% are visible in viewport.
</ParamField>
#### Display Props
<ParamField path="showSpacesSelector" type="boolean">
Show or hide the space filter dropdown. Defaults to `true` for console variant, `false` for consumer.
</ParamField>
<ParamField path="highlightDocumentIds" type="string[]" default="[]">
Array of document IDs to highlight with a pulsing outline. Accepts both `customId` and internal `id`.
</ParamField>
<ParamField path="highlightsVisible" type="boolean" default="true">
Controls whether highlights are shown. Useful for toggling highlights without changing the array.
</ParamField>
<ParamField path="occludedRightPx" type="number" default="0">
Pixels occluded on the right side (e.g., by a sidebar). Graph auto-fits accounting for this space.
</ParamField>
<ParamField path="legendId" type="string">
Custom ID for the legend component. Useful for testing or styling.
</ParamField>
#### Controlled State Props
<ParamField path="selectedSpace" type="string">
Currently selected space. When provided, makes space selection controlled. Use `"all"` for all spaces.
</ParamField>
<ParamField path="onSpaceChange" type="(spaceId: string) => void">
Callback when space selection changes. Required when using `selectedSpace`.
</ParamField>
<ParamField path="memoryLimit" type="number">
Maximum memories to show per document when a specific space is selected. Only applies when `selectedSpace !== "all"`.
</ParamField>
<ParamField path="isExperimental" type="boolean" default="false">
Enable experimental features. Currently unused but reserved for future features.
</ParamField>
## Data Types
### DocumentWithMemories
```typescript
interface DocumentWithMemories {
id: string;
customId?: string | null;
contentHash: string | null;
orgId: string;
userId: string;
connectionId?: string | null;
title?: string | null;
content?: string | null;
summary?: string | null;
url?: string | null;
source?: string | null;
type?: string | null;
status: 'pending' | 'processing' | 'done' | 'failed';
metadata?: Record<string, string | number | boolean> | null;
processingMetadata?: Record<string, unknown> | null;
raw?: string | null;
tokenCount?: number | null;
wordCount?: number | null;
chunkCount?: number | null;
averageChunkSize?: number | null;
summaryEmbedding?: number[] | null;
summaryEmbeddingModel?: string | null;
createdAt: string | Date;
updatedAt: string | Date;
memoryEntries: MemoryEntry[];
}
```
### MemoryEntry
```typescript
interface MemoryEntry {
id: string;
customId?: string | null;
documentId: string;
content: string | null;
summary?: string | null;
title?: string | null;
url?: string | null;
type?: string | null;
metadata?: Record<string, string | number | boolean> | null;
embedding?: number[] | null;
embeddingModel?: string | null;
tokenCount?: number | null;
createdAt: string | Date;
updatedAt: string | Date;
// Fields from join relationship
sourceAddedAt?: Date | null;
sourceRelevanceScore?: number | null;
sourceMetadata?: Record<string, unknown> | null;
spaceContainerTag?: string | null;
// Version chain fields
updatesMemoryId?: string | null;
nextVersionId?: string | null;
relation?: 'updates' | 'extends' | 'derives' | null;
// Memory status fields
isForgotten?: boolean;
forgetAfter?: Date | string | null;
isLatest?: boolean;
// Space/container fields
spaceId?: string | null;
// Legacy fields (for backwards compatibility)
memory?: string | null;
memoryRelations?: Array<{
relationType: 'updates' | 'extends' | 'derives';
targetMemoryId: string;
}> | null;
parentMemoryId?: string | null;
}
```
### GraphNode
Internal type for rendered nodes:
```typescript
interface GraphNode {
id: string;
type: 'document' | 'memory';
x: number;
y: number;
data: DocumentWithMemories | MemoryEntry;
size: number;
color: string;
isHovered: boolean;
isDragging: boolean;
}
```
### GraphEdge
Internal type for connections:
```typescript
interface GraphEdge {
id: string;
source: string;
target: string;
similarity: number;
edgeType: 'doc-memory' | 'doc-doc' | 'version';
relationType?: 'updates' | 'extends' | 'derives';
color: string;
visualProps: {
opacity: number;
thickness: number;
glow: number;
pulseDuration: number;
};
}
```
## Exported Components
Besides `MemoryGraph`, the package exports individual components for advanced use cases:
### GraphCanvas
Low-level canvas renderer. Not recommended for direct use.
```typescript
import { GraphCanvas } from '@supermemory/memory-graph';
```
### Legend
Graph legend showing node types and counts.
```typescript
import { Legend } from '@supermemory/memory-graph';
```
### LoadingIndicator
Loading state indicator with progress counter.
```typescript
import { LoadingIndicator } from '@supermemory/memory-graph';
```
### NodeDetailPanel
Side panel showing node details when clicked.
```typescript
import { NodeDetailPanel } from '@supermemory/memory-graph';
```
### SpacesDropdown
Space filter dropdown.
```typescript
import { SpacesDropdown } from '@supermemory/memory-graph';
```
## Exported Hooks
### useGraphData
Processes documents into graph nodes and edges.
```typescript
import { useGraphData } from '@supermemory/memory-graph';
const { nodes, edges } = useGraphData(
data,
selectedSpace,
nodePositions,
draggingNodeId,
memoryLimit
);
```
### useGraphInteractions
Handles pan, zoom, and node interactions.
```typescript
import { useGraphInteractions } from '@supermemory/memory-graph';
const {
panX,
panY,
zoom,
selectedNode,
handlePanStart,
handleWheel,
// ... more interaction handlers
} = useGraphInteractions('console');
```
## Constants
### colors
Color palette used throughout the graph:
```typescript
import { colors } from '@supermemory/memory-graph';
colors.document.primary; // Document fill color
colors.memory.primary; // Memory fill color
colors.connection.strong; // Strong edge color
```
### GRAPH_SETTINGS
Initial zoom and pan settings for variants:
```typescript
import { GRAPH_SETTINGS } from '@supermemory/memory-graph';
GRAPH_SETTINGS.console.initialZoom; // 0.8
GRAPH_SETTINGS.consumer.initialZoom; // 0.5
```
### LAYOUT_CONSTANTS
Spatial layout configuration:
```typescript
import { LAYOUT_CONSTANTS } from '@supermemory/memory-graph';
LAYOUT_CONSTANTS.clusterRadius; // Memory orbit radius
LAYOUT_CONSTANTS.documentSpacing; // Distance between documents
```

View file

@ -0,0 +1,407 @@
---
title: 'Examples'
description: 'Common use cases and implementation patterns'
---
## With Pagination
Load documents in chunks for better performance with large datasets.
```tsx
'use client';
import { MemoryGraph } from '@supermemory/memory-graph';
import type { DocumentWithMemories } from '@supermemory/memory-graph';
import { useCallback, useEffect, useState } from 'react';
export default function PaginatedGraph() {
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);
// Initial load
useEffect(() => {
fetchPage(1, false);
}, []);
const fetchPage = async (pageNum: number, append: boolean) => {
if (pageNum === 1) {
setIsLoading(true);
} else {
setIsLoadingMore(true);
}
const res = await fetch(`/api/graph?page=${pageNum}&limit=100`);
const data = await res.json();
if (append) {
setDocuments(prev => [...prev, ...data.documents]);
} else {
setDocuments(data.documents);
}
setHasMore(data.pagination.currentPage < data.pagination.totalPages);
setIsLoading(false);
setIsLoadingMore(false);
};
const loadMore = useCallback(async () => {
if (!isLoadingMore && hasMore) {
const nextPage = page + 1;
setPage(nextPage);
await fetchPage(nextPage, true);
}
}, [page, hasMore, isLoadingMore]);
return (
<div style={{ height: '100vh' }}>
<MemoryGraph
documents={documents}
isLoading={isLoading}
isLoadingMore={isLoadingMore}
hasMore={hasMore}
totalLoaded={documents.length}
loadMoreDocuments={loadMore}
/>
</div>
);
}
```
## Highlighting Search Results
```tsx
'use client';
import { MemoryGraph } from '@supermemory/memory-graph';
import { useState } from 'react';
export default function SearchableGraph() {
const [documents, setDocuments] = useState([]);
const [searchResults, setSearchResults] = useState<string[]>([]);
const [searchQuery, setSearchQuery] = useState('');
const handleSearch = async (query: string) => {
setSearchQuery(query);
if (!query) {
setSearchResults([]);
return;
}
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
const data = await res.json();
// Extract document IDs from search results
const docIds = data.results.map(r => r.documentId);
setSearchResults(docIds);
};
return (
<div style={{ height: '100vh' }}>
<div style={{ position: 'absolute', top: 16, left: 16, zIndex: 10 }}>
<input
type="text"
placeholder="Search memories..."
value={searchQuery}
onChange={(e) => handleSearch(e.target.value)}
style={{
padding: '8px 12px',
borderRadius: 8,
border: '1px solid #333',
background: '#1a1a1a',
color: 'white',
}}
/>
</div>
<MemoryGraph
documents={documents}
highlightDocumentIds={searchResults}
highlightsVisible={searchResults.length > 0}
/>
</div>
);
}
```
## Controlled Space Selection
Control space filtering from outside the component.
```tsx
'use client';
import { MemoryGraph } from '@supermemory/memory-graph';
import { useState } from 'react';
export default function ControlledSpaceGraph() {
const [documents, setDocuments] = useState([]);
const [selectedSpace, setSelectedSpace] = useState('all');
// Extract available spaces from documents
const spaces = Array.from(
new Set(
documents.flatMap(doc =>
doc.memoryEntries.map(m => m.spaceId || 'default')
)
)
);
return (
<div style={{ height: '100vh' }}>
<div style={{
position: 'absolute',
top: 16,
right: 16,
zIndex: 10,
background: '#1a1a1a',
padding: 16,
borderRadius: 8,
border: '1px solid #333',
}}>
<h3 style={{ margin: '0 0 12px 0', color: 'white' }}>Filters</h3>
<select
value={selectedSpace}
onChange={(e) => setSelectedSpace(e.target.value)}
style={{
padding: '8px 12px',
borderRadius: 6,
background: '#2a2a2a',
color: 'white',
border: '1px solid #444',
width: '100%',
}}
>
<option value="all">All Spaces</option>
{spaces.map(space => (
<option key={space} value={space}>{space}</option>
))}
</select>
<button
onClick={() => setSelectedSpace('all')}
style={{
marginTop: 12,
padding: '6px 12px',
borderRadius: 6,
background: '#333',
color: 'white',
border: 'none',
width: '100%',
cursor: 'pointer',
}}
>
Reset
</button>
</div>
<MemoryGraph
documents={documents}
selectedSpace={selectedSpace}
onSpaceChange={setSelectedSpace}
showSpacesSelector={false}
/>
</div>
);
}
```
## Embedded Widget
Use the consumer variant for embedded views with custom styling.
```tsx
'use client';
import { MemoryGraph } from '@supermemory/memory-graph';
export default function EmbeddedGraph({ documents }) {
return (
<div
style={{
height: 400,
borderRadius: 12,
overflow: 'hidden',
border: '1px solid #2a2a2a',
}}
>
<MemoryGraph
documents={documents}
variant="consumer"
showSpacesSelector={false}
>
<div style={{
textAlign: 'center',
padding: '2rem',
color: '#888',
}}>
<p>No memories to display</p>
</div>
</MemoryGraph>
</div>
);
}
```
## With Loading States
```tsx
'use client';
import { MemoryGraph } from '@supermemory/memory-graph';
import { useEffect, useState } from 'react';
export default function LoadingGraph() {
const [documents, setDocuments] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
fetch('/api/graph')
.then(res => {
if (!res.ok) throw new Error('Failed to load graph');
return res.json();
})
.then(data => {
setDocuments(data.documents);
setIsLoading(false);
})
.catch(err => {
setError(err);
setIsLoading(false);
});
}, []);
return (
<div style={{ height: '100vh' }}>
<MemoryGraph
documents={documents}
isLoading={isLoading}
error={error}
>
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
color: '#888',
}}>
<div>
<h2>Welcome to your Memory Graph</h2>
<p>Add some content to get started</p>
<button
style={{
marginTop: 16,
padding: '8px 16px',
borderRadius: 6,
background: '#2563eb',
color: 'white',
border: 'none',
cursor: 'pointer',
}}
onClick={() => window.location.href = '/add-memory'}
>
Add First Memory
</button>
</div>
</div>
</MemoryGraph>
</div>
);
}
```
## React Server Component
```tsx
// Next.js App Router with Server Component
import { MemoryGraphClient } from './memory-graph-client';
async function getGraphData() {
const res = await fetch('https://api.supermemory.ai/v3/documents/documents', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
page: 1,
limit: 500,
sort: 'createdAt',
order: 'desc',
}),
cache: 'no-store', // or use revalidation
});
return res.json();
}
export default async function GraphPage() {
const data = await getGraphData();
return <MemoryGraphClient initialDocuments={data.documents} />;
}
```
```tsx
// memory-graph-client.tsx
'use client';
import { MemoryGraph } from '@supermemory/memory-graph';
import type { DocumentWithMemories } from '@supermemory/memory-graph';
interface Props {
initialDocuments: DocumentWithMemories[];
}
export function MemoryGraphClient({ initialDocuments }: Props) {
return (
<div style={{ height: '100vh' }}>
<MemoryGraph
documents={initialDocuments}
isLoading={false}
/>
</div>
);
}
```
## Mobile-Responsive Layout
```tsx
'use client';
import { MemoryGraph } from '@supermemory/memory-graph';
import { useState, useEffect } from 'react';
export default function ResponsiveGraph({ documents }) {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 768);
};
checkMobile();
window.addEventListener('resize', checkMobile);
return () => window.removeEventListener('resize', checkMobile);
}, []);
return (
<div style={{
height: isMobile ? '60vh' : '100vh',
width: '100%',
}}>
<MemoryGraph
documents={documents}
variant={isMobile ? 'consumer' : 'console'}
showSpacesSelector={!isMobile}
/>
</div>
);
}
```

View file

@ -0,0 +1,28 @@
---
title: 'Installation'
description: 'Install and set up the Memory Graph component'
---
## Installation
Install the package using your preferred package manager:
```bash npm
npm install @supermemory/memory-graph
```
## Requirements
- **React**: 18.0.0 or higher
- **react-dom**: 18.0.0 or higher
## Next Steps
<CardGroup cols={2}>
<Card title="Quick Start" icon="rocket" href="/memory-graph/quickstart">
Get the graph running with real data
</Card>
<Card title="API Reference" icon="code" href="/memory-graph/api-reference">
Explore all available props and types
</Card>
</CardGroup>

View file

@ -0,0 +1,5 @@
---
title: "NPM link"
url: "https://www.npmjs.com/package/@supermemory/memory-graph"
icon: npm
---

View file

@ -0,0 +1,38 @@
---
title: 'Overview'
description: 'Interactive visualization for documents, memories and connections'
---
## What is Memory Graph?
Memory Graph is a React component that visualizes your Supermemory documents and memories as an interactive network. Documents appear as rectangular nodes, memories as hexagonal nodes, and connections between them show relationships and similarity.
The graph renders using Canvas 2D, providing smooth interactions with hundreds of nodes through pan, zoom, and drag operations.
## When to Use It
Use Memory Graph when you need to:
- **Visualize knowledge graphs** - Show how documents and memories connect
- **Navigate memory spaces** - Filter and browse by workspace or tag
- **Create memory browsers** - Give users a visual overview of their stored content
## Performance
The graph handles hundreds of nodes efficiently through:
- Canvas-based rendering (not DOM elements)
- Viewport culling (only draws visible nodes)
- Level-of-detail optimization (simplifies rendering when zoomed out)
- Change-based rendering (only redraws when state changes)
- Throttled viewport calculations
For very large datasets (1000+ documents), use pagination to load data in chunks.
## Browser Support
Works in all modern browsers that support:
- Canvas 2D API
- ES2020 JavaScript
- CSS custom properties
Tested on Chrome, Firefox, Safari, and Edge (latest versions).

View file

@ -0,0 +1,207 @@
---
title: 'Quick Start'
description: 'Get Memory Graph running in 2 minutes'
---
## Basic Setup
Here's a minimal example to get the graph running:
```tsx
'use client'; // For Next.js App Router
import { MemoryGraph } from '@supermemory/memory-graph';
import type { DocumentWithMemories } from '@supermemory/memory-graph';
import { useEffect, useState } from 'react';
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')
.then(res => res.json())
.then(data => {
setDocuments(data.documents);
setIsLoading(false);
})
.catch(err => {
setError(err);
setIsLoading(false);
});
}, []);
return (
<div style={{ height: '100vh' }}>
<MemoryGraph
documents={documents}
isLoading={isLoading}
error={error}
variant="console"
/>
</div>
);
}
```
## Backend API Route
Create an API route to fetch documents from Supermemory:
<CodeGroup>
```typescript Next.js App Router
// app/api/graph/route.ts
import { NextResponse } from 'next/server';
export async function GET() {
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',
}),
});
const data = await response.json();
return NextResponse.json(data);
}
```
```typescript Next.js Pages Router
// pages/api/graph.ts
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
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',
}),
});
const data = await response.json();
res.json(data);
}
```
```javascript Express
// routes/graph.js
app.get('/api/graph', async (req, res) => {
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',
}),
});
const data = await response.json();
res.json(data);
});
```
</CodeGroup>
<Warning>
Never expose your Supermemory API key to the client. Always fetch data through your backend.
</Warning>
## Environment Variables
Add your API key to `.env.local`:
```bash
SUPERMEMORY_API_KEY=your_api_key_here
```
Get your API key from the [Supermemory dashboard](https://console.supermemory.ai).
## Common Customizations
### Embedded Mode
For a widget-style view, use the consumer variant:
```tsx
<MemoryGraph
documents={documents}
isLoading={isLoading}
variant="consumer"
/>
```
### CSS Import
The component includes bundled styles. You don't need to import CSS separately. Styles are automatically injected when the component mounts.
If you want explicit control, you can import the stylesheet:
```typescript
import '@supermemory/memory-graph/styles.css';
```
<Note>
The automatic CSS injection works for most setups. Only use the explicit import if you need custom control over style loading order.
</Note>
### Custom Empty State
Show custom content when no documents exist:
```tsx
<MemoryGraph
documents={documents}
isLoading={isLoading}
>
<div style={{ textAlign: 'center', padding: '2rem' }}>
<h2>No memories yet</h2>
<p>Add content to see your knowledge graph</p>
</div>
</MemoryGraph>
```
### Hide Space Selector
```tsx
<MemoryGraph
documents={documents}
isLoading={isLoading}
showSpacesSelector={false}
/>
```
## Next Steps
<CardGroup cols={2}>
<Card title="Examples" icon="code" href="/memory-graph/examples">
See more usage examples
</Card>
<Card title="API Reference" icon="book" href="/memory-graph/api-reference">
Full API documentation
</Card>
</CardGroup>

View file

@ -1,378 +1,94 @@
# @supermemory/memory-graph
> Interactive graph visualization component for Supermemory - visualize and explore your memory connections
Interactive graph visualization for documents and their memory connections.
[![npm version](https://img.shields.io/npm/v/@supermemory/memory-graph.svg)](https://www.npmjs.com/package/@supermemory/memory-graph)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
## Features
- **WebGL-powered rendering** - Smooth performance with hundreds of nodes
- **Interactive exploration** - Pan, zoom, drag nodes, and explore connections
- **Semantic connections** - Visualizes relationships based on content similarity
- **Space filtering with search** - Dynamically search and filter by spaces/tags
- **Memory limit control** - Limit memories per document (50-3000) for performance
- **Controlled/uncontrolled modes** - Flexible state management for integration
- **Responsive design** - Works seamlessly on mobile and desktop
- **Zero configuration** - Works out of the box with automatic CSS injection
- **Lightweight** - Tree-shakeable and optimized bundle
- **TypeScript** - Full TypeScript support with exported types
## Installation
```bash
npm install @supermemory/memory-graph
# or
yarn add @supermemory/memory-graph
bun add @supermemory/memory-graph
# or
pnpm add @supermemory/memory-graph
# or
bun add @supermemory/memory-graph
```
## Quick Start
The component accepts document data directly - you fetch the data from your backend, which proxies requests to the Supermemory API with proper authentication.
```tsx
import { MemoryGraph } from '@supermemory/memory-graph'
import type { DocumentWithMemories } from '@supermemory/memory-graph'
import { MemoryGraph } from '@supermemory/memory-graph';
import type { DocumentWithMemories } from '@supermemory/memory-graph';
function App() {
const [documents, setDocuments] = useState<DocumentWithMemories[]>([])
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<Error | null>(null)
const [documents, setDocuments] = useState<DocumentWithMemories[]>([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Fetch from YOUR backend (which proxies to Supermemory API)
fetch('/api/supermemory-graph')
fetch('/api/graph')
.then(res => res.json())
.then(data => {
setDocuments(data.documents)
setIsLoading(false)
})
.catch(err => {
setError(err)
setIsLoading(false)
})
}, [])
setDocuments(data.documents);
setIsLoading(false);
});
}, []);
return (
<MemoryGraph
documents={documents}
isLoading={isLoading}
error={error}
/>
)
}
```
## Backend Proxy Example
Create an API route in your backend that authenticates and proxies requests to Supermemory:
### Next.js API Route
```typescript
// app/api/supermemory-graph/route.ts
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
// Add your own auth check here
const user = await getAuthenticatedUser(request)
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
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',
}),
})
const data = await response.json()
return NextResponse.json(data)
}
```
## API Reference
### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `documents` | `DocumentWithMemories[]` | **required** | Array of documents to display |
| `isLoading` | `boolean` | `false` | Whether data is currently loading |
| `error` | `Error \| null` | `null` | Error that occurred during fetching |
| `variant` | `"console" \| "consumer"` | `"console"` | Visual variant |
| `showSpacesSelector` | `boolean` | Based on variant | Show/hide the spaces filter |
| `children` | `ReactNode` | - | Content to show when no documents |
| `highlightDocumentIds` | `string[]` | `[]` | Document IDs to highlight |
| `highlightsVisible` | `boolean` | `true` | Whether highlights are visible |
### Space & Memory Control Props (Optional)
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `selectedSpace` | `string` | `"all"` | Currently selected space (controlled) |
| `onSpaceChange` | `(spaceId: string) => void` | - | Callback when space changes |
| `onSearchSpaces` | `(query: string) => Promise<string[]>` | - | Async space search function |
| `memoryLimit` | `number` | `500` | Max memories per document when space selected |
| `onMemoryLimitChange` | `(limit: number) => void` | - | Callback when limit changes |
| `isExperimental` | `boolean` | `false` | Enable experimental features |
### Pagination Props (Optional)
For large datasets, you can implement pagination:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `isLoadingMore` | `boolean` | `false` | Whether loading more data |
| `hasMore` | `boolean` | `false` | Whether more data is available |
| `totalLoaded` | `number` | `documents.length` | Total documents loaded |
| `loadMoreDocuments` | `() => Promise<void>` | - | Callback to load more |
### Types
```typescript
import type {
DocumentWithMemories,
MemoryEntry,
DocumentsResponse,
MemoryGraphProps,
MemoryLimit,
MemoryCountSelectorProps,
GraphNode,
GraphEdge,
MemoryRelation
} from '@supermemory/memory-graph'
// Memory limit can be one of these values
type MemoryLimit = 50 | 100 | 250 | 500 | 1000 | 2000 | 3000
```
## Advanced Usage
### With Pagination
```tsx
import { MemoryGraph } from '@supermemory/memory-graph'
function GraphWithPagination() {
const [documents, setDocuments] = useState([])
const [page, setPage] = useState(1)
const [hasMore, setHasMore] = useState(true)
const [isLoadingMore, setIsLoadingMore] = useState(false)
const loadMore = async () => {
setIsLoadingMore(true)
const res = await fetch(`/api/supermemory-graph?page=${page + 1}`)
const data = await res.json()
setDocuments(prev => [...prev, ...data.documents])
setHasMore(data.pagination.currentPage < data.pagination.totalPages)
setPage(p => p + 1)
setIsLoadingMore(false)
}
return (
<MemoryGraph
documents={documents}
isLoading={isLoading}
isLoadingMore={isLoadingMore}
hasMore={hasMore}
loadMoreDocuments={loadMore}
totalLoaded={documents.length}
/>
)
}
```
### Custom Empty State
```tsx
<MemoryGraph documents={[]} isLoading={false}>
<div className="empty-state">
<h2>No memories yet</h2>
<p>Start adding content to see your knowledge graph</p>
</div>
</MemoryGraph>
```
### Controlled Space Selection & Memory Limiting
Control the selected space and memory limit externally for integration with your app's state management:
```tsx
import { MemoryGraph } from '@supermemory/memory-graph'
function ControlledGraph() {
const [selectedSpace, setSelectedSpace] = useState("all")
const [memoryLimit, setMemoryLimit] = useState(500)
const [searchResults, setSearchResults] = useState([])
// Handle space search via your API
const handleSpaceSearch = async (query: string) => {
const response = await fetch(`/api/spaces/search?q=${query}`)
const spaces = await response.json()
setSearchResults(spaces)
return spaces
}
return (
<div>
{/* Display current state */}
<div className="controls">
<p>Selected Space: {selectedSpace}</p>
<p>Memory Limit: {memoryLimit}</p>
<button onClick={() => {
setSelectedSpace("all")
setMemoryLimit(500)
}}>
Reset Filters
</button>
</div>
{/* Controlled graph */}
<div style={{ height: '100vh' }}>
<MemoryGraph
documents={documents}
selectedSpace={selectedSpace}
onSpaceChange={setSelectedSpace}
onSearchSpaces={handleSpaceSearch}
memoryLimit={memoryLimit}
onMemoryLimitChange={setMemoryLimit}
isLoading={isLoading}
variant="console"
showSpacesSelector={true}
/>
</div>
)
);
}
```
### Uncontrolled Mode (Automatic)
## Features
If you don't provide `selectedSpace` or `memoryLimit` props, the component manages its own state:
- **Interactive canvas visualization** - Pan, zoom, and drag nodes using Canvas 2D rendering
- **Document and memory nodes** - Documents as rectangles, memories as hexagons
- **Relationship visualization** - Edges show document similarity and memory version chains
- **Space filtering** - Filter by workspace or view all memories
- **Two variants** - Full-featured console mode or embedded consumer mode
- **Pagination support** - Load more documents on demand
- **TypeScript support** - Full type definitions included
```tsx
<MemoryGraph
documents={documents}
// Component manages space selection and memory limit internally
onSearchSpaces={handleSpaceSearch} // Still can provide search function
showSpacesSelector={true}
/>
```
## Essential Props
### Space Search Integration
| Prop | Type | Description |
|------|------|-------------|
| `documents` | `DocumentWithMemories[]` | Array of documents with their memory entries |
| `isLoading` | `boolean` | Show loading state |
| `variant` | `"console" \| "consumer"` | Display mode (default: "console") |
| `error` | `Error \| null` | Error to display |
| `loadMoreDocuments` | `() => Promise<void>` | Function to load more data |
| `highlightDocumentIds` | `string[]` | IDs of documents to highlight |
Implement server-side space search for dynamic filtering:
## Documentation
```tsx
// Frontend
const handleSpaceSearch = async (query: string): Promise<string[]> => {
const response = await fetch('/api/spaces/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query })
})
return response.json()
}
Full documentation available at [docs.supermemory.ai](https://docs.supermemory.ai):
<MemoryGraph
documents={documents}
onSearchSpaces={handleSpaceSearch}
showSpacesSelector={true}
/>
// Backend (Next.js example)
// app/api/spaces/search/route.ts
export async function POST(request: Request) {
const { query } = await request.json()
const response = await fetch('https://api.supermemory.ai/v3/search/spaces', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
},
params: { q: query }
})
return response.json()
}
```
### Variants
The `variant` prop controls the visual layout and initial viewport settings:
| Variant | Initial Zoom | Spaces Selector | Legend Position | Use Case |
|---------|-------------|-----------------|-----------------|----------|
| `console` | 0.8 | Shown | Bottom-right | Full-page dashboard views |
| `consumer` | 0.5 | Hidden | Top-right | Embedded/widget views |
```tsx
// Full dashboard view
<MemoryGraph
documents={documents}
variant="console"
/>
// Embedded widget
<MemoryGraph
documents={documents}
variant="consumer"
/>
```
## Interactive Controls
- **Pan**: Click and drag the background
- **Zoom**: Mouse wheel or pinch on mobile
- **Select Node**: Click on any document or memory
- **Drag Nodes**: Click and drag individual nodes
- **Fit to View**: Auto-fit button to center all content
- **Space Filter**: Click the space selector to filter by space
- **Space Search**: Type in the search box and press Enter to find spaces
- **Memory Limit**: Select a limit (50-3K) when filtering by space
## Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers with WebGL support
- [Overview](https://docs.supermemory.ai/memory-graph/overview) - What it is and when to use it
- [Installation](https://docs.supermemory.ai/memory-graph/installation) - Setup and requirements
- [Quick Start](https://docs.supermemory.ai/memory-graph/quickstart) - Get running in 2 minutes
- [API Reference](https://docs.supermemory.ai/memory-graph/api-reference) - Complete API documentation
- [Examples](https://docs.supermemory.ai/memory-graph/examples) - Common use cases
- [Troubleshooting](https://docs.supermemory.ai/memory-graph/troubleshooting) - Common issues
## Requirements
- React 18+
- Modern browser with WebGL support
## Development
```bash
# Install dependencies
bun install
# Build the package
bun run build
# Watch mode for development
bun run dev
# Type checking
bun run check-types
```
- Modern browser
## License
MIT
## Support
## Links
- Issues: [GitHub Issues](https://github.com/supermemoryai/supermemory/issues)
- [GitHub](https://github.com/supermemoryai/supermemory/tree/main/packages/memory-graph)
- [Issues](https://github.com/supermemoryai/supermemory/issues)
- [Supermemory](https://supermemory.ai)