Skip to main content
Glama
memory-store.ts3.72 kB
import Database from "better-sqlite3"; import path from "path"; import fs from "fs/promises"; import crypto from "crypto"; export interface Memory { id: string; key: string; content: string; metadata?: Record<string, any>; timestamp: string; } export class MemoryStore { private db!: Database.Database; private dataDir: string; constructor(dataDir: string) { this.dataDir = dataDir; } async initialize(): Promise<void> { // Ensure data directory exists await fs.mkdir(this.dataDir, { recursive: true }); // Initialize SQLite database const dbPath = path.join(this.dataDir, "memories.db"); this.db = new Database(dbPath); // Create tables if they don't exist this.db.exec(` CREATE TABLE IF NOT EXISTS memories ( id TEXT PRIMARY KEY, key TEXT UNIQUE NOT NULL, content TEXT NOT NULL, metadata TEXT, timestamp TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_memories_key ON memories(key); CREATE INDEX IF NOT EXISTS idx_memories_timestamp ON memories(timestamp); `); } async set( key: string, content: string, metadata?: Record<string, any> ): Promise<Memory> { const id = crypto.randomUUID(); const timestamp = new Date().toISOString(); const stmt = this.db.prepare(` INSERT OR REPLACE INTO memories (id, key, content, metadata, timestamp) VALUES (?, ?, ?, ?, ?) `); stmt.run( id, key, content, metadata ? JSON.stringify(metadata) : null, timestamp ); return { id, key, content, metadata, timestamp, }; } async get(key: string): Promise<Memory | null> { const stmt = this.db.prepare(` SELECT * FROM memories WHERE key = ? `); const row = stmt.get(key) as any; if (!row) return null; return { id: row.id, key: row.key, content: row.content, metadata: row.metadata ? JSON.parse(row.metadata) : undefined, timestamp: row.timestamp, }; } async getById(id: string): Promise<Memory | null> { const stmt = this.db.prepare(` SELECT * FROM memories WHERE id = ? `); const row = stmt.get(id) as any; if (!row) return null; return { id: row.id, key: row.key, content: row.content, metadata: row.metadata ? JSON.parse(row.metadata) : undefined, timestamp: row.timestamp, }; } async delete(key: string): Promise<boolean> { const stmt = this.db.prepare(` DELETE FROM memories WHERE key = ? `); const result = stmt.run(key); return result.changes > 0; } async list(limit: number = 100, offset: number = 0): Promise<Memory[]> { const stmt = this.db.prepare(` SELECT * FROM memories ORDER BY timestamp DESC LIMIT ? OFFSET ? `); const rows = stmt.all(limit, offset) as any[]; return rows.map((row) => ({ id: row.id, key: row.key, content: row.content, metadata: row.metadata ? JSON.parse(row.metadata) : undefined, timestamp: row.timestamp, })); } async search(query: string): Promise<Memory[]> { const stmt = this.db.prepare(` SELECT * FROM memories WHERE content LIKE ? OR key LIKE ? ORDER BY timestamp DESC LIMIT 20 `); const searchPattern = `%${query}%`; const rows = stmt.all(searchPattern, searchPattern) as any[]; return rows.map((row) => ({ id: row.id, key: row.key, content: row.content, metadata: row.metadata ? JSON.parse(row.metadata) : undefined, timestamp: row.timestamp, })); } close(): void { if (this.db) { this.db.close(); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/notbnull/mcp-rag-context'

If you have feedback or need assistance with the MCP directory API, please join our Discord server