TypeScript/Node.js SDK
The official TypeScript SDK for Recall provides full type safety and modern JavaScript features for Node.js applications.
Installation
bashnpm install @recall/client
Requirements
- Node.js 16.0 or higher
- TypeScript 4.5+ (optional but recommended)
- Redis 6.0+ (local or cloud)
- Mem0 API key
Quick Start
typescriptimport { RecallClient } from "@recall/client";// Initialize the clientconst client = new RecallClient({redisUrl: "redis://localhost:6379",mem0ApiKey: "your-api-key",});// Store a memoryconst memory = await client.add({content: "User prefers TypeScript for web development",userId: "user_123",priority: "high",});// Search memoriesconst results = await client.search({query: "programming preferences",userId: "user_123",});
Configuration
Environment Variables
Create a .env file:
envRECALL_REDIS_URL=redis://localhost:6379RECALL_MEM0_API_KEY=your-api-keyRECALL_ENVIRONMENT=productionRECALL_LOG_LEVEL=info
Load with dotenv:
typescriptimport { RecallClient } from "@recall/client";import dotenv from "dotenv";dotenv.config();const client = new RecallClient({redisUrl: process.env.RECALL_REDIS_URL,mem0ApiKey: process.env.RECALL_MEM0_API_KEY,environment: process.env.RECALL_ENVIRONMENT,});
Configuration Object
typescriptimport { RecallClient, RecallConfig } from "@recall/client";const config: RecallConfig = {redis: {url: "redis://localhost:6379",options: {maxRetries: 3,retryDelay: 1000,connectionTimeout: 5000,},},mem0: {apiKey: "your-api-key",baseUrl: "https://api.mem0.ai",timeout: 30000,},cache: {ttl: 3600,maxSize: 1000,compression: true,},sync: {mode: "lazy",batchSize: 100,interval: 60000,},};const client = new RecallClient(config);
Type Definitions
Core Types
typescriptimport {Memory,Priority,User,SearchResult,CacheStats,} from "@recall/client";// Memory interfaceinterface Memory {id: string;content: string;userId: string;priority: Priority;metadata?: Record<string, any>;createdAt: Date;updatedAt?: Date;accessCount?: number;}// Priority enumenum Priority {CRITICAL = "critical",HIGH = "high",MEDIUM = "medium",LOW = "low",}// Search result with relevanceinterface SearchResult extends Memory {score: number;source: "cache" | "cloud";highlights?: string[];}
Method Signatures
typescriptclass RecallClient {// Add a memoryadd(options: AddMemoryOptions): Promise<Memory>;// Search memoriessearch(options: SearchOptions): Promise<SearchResult[]>;// Get specific memoryget(memoryId: string): Promise<Memory | null>;// Update memoryupdate(options: UpdateOptions): Promise<Memory>;// Delete memorydelete(memoryId: string): Promise<boolean>;// Batch operationsaddBatch(memories: AddMemoryOptions[]): Promise<Memory[]>;deleteBatch(memoryIds: string[]): Promise<BatchResult>;}
Advanced Features
Async Iteration
typescriptimport { RecallClient } from "@recall/client";const client = new RecallClient();// Iterate through search resultsfor await (const memory of client.searchIterator({query: "user preferences",userId: "user_123",batchSize: 10,})) {console.log(`Processing: ${memory.content}`);// Process each memory}// Stream all memoriesconst stream = client.streamAll({userId: "user_123",batchSize: 50,});for await (const batch of stream) {console.log(`Batch of ${batch.length} memories`);// Process batch}
Event Emitters
typescriptimport { RecallClient } from "@recall/client";const client = new RecallClient();// Listen to eventsclient.on("memory:added", (memory: Memory) => {console.log(`New memory: ${memory.id}`);});client.on("cache:hit", (key: string) => {console.log(`Cache hit for: ${key}`);});client.on("cache:miss", (key: string) => {console.log(`Cache miss for: ${key}`);});client.on("sync:complete", (stats: SyncStats) => {console.log(`Synced ${stats.count} memories`);});client.on("error", (error: Error) => {console.error(`Error: ${error.message}`);});
Middleware
typescriptimport { RecallClient, Middleware } from "@recall/client";// Custom middlewareclass LoggingMiddleware implements Middleware {async process(operation: string,params: any,next: () => Promise<any>,): Promise<any> {console.log(`[${operation}] Starting...`);const startTime = Date.now();try {const result = await next();const duration = Date.now() - startTime;console.log(`[${operation}] Completed in ${duration}ms`);return result;} catch (error) {console.error(`[${operation}] Failed:`, error);throw error;}}}// Apply middlewareconst client = new RecallClient();client.use(new LoggingMiddleware());// Built-in middlewareimport {RetryMiddleware,RateLimitMiddleware,CacheMiddleware,CompressionMiddleware,} from "@recall/client/middleware";client.use(new RetryMiddleware({ maxAttempts: 3 }));client.use(new RateLimitMiddleware({ rps: 100 }));client.use(new CompressionMiddleware());
Transactions
typescriptimport { RecallClient } from "@recall/client";const client = new RecallClient();// Execute operations in a transactionconst result = await client.transaction(async (tx) => {// All operations are atomicconst mem1 = await tx.add({content: "First memory",userId: "user_123",});const mem2 = await tx.add({content: "Second memory",userId: "user_123",});await tx.update({memoryId: mem1.id,priority: "critical",});return [mem1, mem2];});// Transaction with rollbacktry {await client.transaction(async (tx) => {await tx.add({ content: "Memory 1", userId: "user_123" });throw new Error("Rollback!");// All changes rolled back});} catch (error) {console.log("Transaction rolled back");}
React Integration
React Hook
typescriptimport { useRecall } from '@recall/react';function UserPreferences({ userId }: { userId: string }) {const {memories,loading,error,addMemory,searchMemories,refreshMemories} = useRecall(userId);const handleSearch = async (query: string) => {const results = await searchMemories(query);console.log(`Found ${results.length} memories`);};const handleAdd = async (content: string) => {await addMemory({content,priority: 'high'});};if (loading) return <div>Loading memories...</div>;if (error) return <div>Error: {error.message}</div>;return (<div><h2>User Memories ({memories.length})</h2>{memories.map(memory => (<div key={memory.id}>{memory.content}</div>))}</div>);}
React Context Provider
typescriptimport { RecallProvider } from '@recall/react';import { RecallClient } from '@recall/client';const client = new RecallClient({redisUrl: process.env.NEXT_PUBLIC_REDIS_URL,mem0ApiKey: process.env.NEXT_PUBLIC_MEM0_KEY});function App() {return (<RecallProvider client={client}><YourComponents /></RecallProvider>);}// Use in componentsimport { useRecallClient } from '@recall/react';function Component() {const client = useRecallClient();const handleAction = async () => {await client.add({content: 'User action',userId: 'user_123'});};}
Express Middleware
typescriptimport express from "express";import { recallMiddleware } from "@recall/express";const app = express();// Add Recall to all requestsapp.use(recallMiddleware({redisUrl: "redis://localhost:6379",mem0ApiKey: "your-api-key",}),);// Access in routesapp.get("/memories/:userId", async (req, res) => {const { recall } = req;const memories = await recall.getAll({userId: req.params.userId,});res.json(memories);});app.post("/memories", async (req, res) => {const { recall } = req;const memory = await recall.add({content: req.body.content,userId: req.body.userId,});res.json(memory);});
Testing
Mock Client
typescriptimport { MockRecallClient } from "@recall/client/testing";import { describe, it, expect, beforeEach } from "@jest/globals";describe("Memory Service", () => {let client: MockRecallClient;beforeEach(() => {client = new MockRecallClient();});it("should store memories", async () => {const memory = await client.add({content: "Test memory",userId: "test_user",});expect(memory.id).toMatch(/^mem_/);expect(client.getCallCount("add")).toBe(1);expect(client.getLastCall("add")).toMatchObject({content: "Test memory",});});it("should search memories", async () => {// Pre-populate test dataclient.setSearchResults([{ content: "Result 1", score: 0.9 },{ content: "Result 2", score: 0.8 },]);const results = await client.search({query: "test",userId: "test_user",});expect(results).toHaveLength(2);expect(results[0].score).toBe(0.9);});});
Test Utilities
typescriptimport {createTestMemory,createTestUser,populateTestData,cleanupTestData,} from "@recall/client/testing";// Create test fixturesconst memory = createTestMemory({content: "Test content",priority: "high",});const user = createTestUser({id: "test_user",memories: 10,});// Populate database with test dataawait populateTestData(client, {users: 5,memoriesPerUser: 20,});// Cleanup after testsawait cleanupTestData(client, "test_*");
Error Handling
Error Types
typescriptimport {RecallError,ConnectionError,AuthenticationError,ValidationError,RateLimitError,TimeoutError,} from "@recall/client/errors";try {await client.add({content: "",userId: "",});} catch (error) {if (error instanceof ValidationError) {console.error(`Validation failed: ${error.field} - ${error.message}`);} else if (error instanceof ConnectionError) {console.error(`Connection issue: ${error.service}`);} else if (error instanceof RateLimitError) {console.error(`Rate limited. Retry after: ${error.retryAfter}s`);} else if (error instanceof RecallError) {console.error(`Recall error: ${error.message}`);}}
Error Recovery
typescriptimport { withRetry, withFallback } from "@recall/client/resilience";// Automatic retryconst resilientClient = withRetry(client, {maxAttempts: 3,backoff: "exponential",retryOn: [ConnectionError, TimeoutError],});// Fallback to cache on errorconst fallbackClient = withFallback(client, {fallbackTo: "cache",on: [ConnectionError],});// Circuit breaker patternimport { CircuitBreaker } from "@recall/client/resilience";const breaker = new CircuitBreaker(client, {threshold: 5,timeout: 60000,fallback: async () => {return { source: "fallback", memories: [] };},});
Performance
Connection Pooling
typescriptimport { RecallClient } from "@recall/client";import Redis from "ioredis";// Share Redis connectionconst redis = new Redis({host: "localhost",port: 6379,maxRetriesPerRequest: 3,lazyConnect: true,});const client1 = new RecallClient({ redis });const client2 = new RecallClient({ redis });
Caching Strategies
typescriptimport { RecallClient, CacheStrategy } from "@recall/client";const client = new RecallClient({cacheStrategy: CacheStrategy.WRITE_THROUGH,// or WRITE_BEHIND, CACHE_ASIDE, READ_THROUGHcacheConfig: {ttl: {critical: null, // Never expirehigh: 86400, // 24 hoursmedium: 3600, // 1 hourlow: 300, // 5 minutes},warmup: true, // Pre-load frequently accessedcompression: true, // Compress large values},});
Batch Processing
typescriptimport { RecallClient } from "@recall/client";import { chunk } from "lodash";const client = new RecallClient();// Process large dataset in batchesconst memories = generateLargeDataset(10000);const batches = chunk(memories, 100);for (const batch of batches) {await client.addBatch(batch);console.log(`Processed batch of ${batch.length}`);}// Parallel processingconst results = await Promise.all(batches.map((batch) => client.addBatch(batch)),);
CLI Usage
bash# Install CLI globallynpm install -g @recall/cli# Configurerecall config set redis.url redis://localhost:6379recall config set mem0.apiKey your-api-key# Commandsrecall add "Memory content" --user user_123 --priority highrecall search "query" --user user_123 --limit 10recall get mem_abc123recall delete mem_abc123recall statsrecall cache clearrecall sync
Deployment
Docker
dockerfileFROM node:18-alpineWORKDIR /app# Copy package filesCOPY package*.json ./RUN npm ci --production# Copy applicationCOPY . .# Build TypeScriptRUN npm run build# Health checkHEALTHCHECK --interval=30s --timeout=3s \CMD node -e "require('@recall/client').RecallClient().healthCheck()"CMD ["node", "dist/index.js"]
Environment-Specific Config
typescriptimport { RecallClient } from "@recall/client";const config = {development: {redisUrl: "redis://localhost:6379",logLevel: "debug",cache: { ttl: 300 },},production: {redisUrl: process.env.REDIS_URL,logLevel: "error",cache: { ttl: 3600 },},};const environment = process.env.NODE_ENV || "development";const client = new RecallClient(config[environment]);
Migration Guide
From JavaScript to TypeScript
typescript// Before (JavaScript)const client = new RecallClient({redisUrl: "redis://localhost:6379",});// After (TypeScript)import { RecallClient, RecallConfig } from "@recall/client";const config: RecallConfig = {redis: { url: "redis://localhost:6379" },mem0: { apiKey: "your-api-key" },};const client = new RecallClient(config);
From Callbacks to Promises
typescript// Before (Callbacks)client.add(memory, (err, result) => {if (err) console.error(err);else console.log(result);});// After (Promises)try {const result = await client.add(memory);console.log(result);} catch (error) {console.error(error);}
Next Steps
- Explore React Integration for React applications
- Review API Reference for detailed documentation
- Check Examples for real-world use cases