TypeScript/Node.js SDK
The official TypeScript SDK for Recall provides full type safety and modern JavaScript features for Node.js applications.
Installation
Bash
1npm 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
TypeScript
1import { RecallClient } from "@recall/client";2
3// Initialize the client4const client = new RecallClient({5 redisUrl: "redis://localhost:6379",6 mem0ApiKey: "your-api-key",7});8
9// Store a memory10const memory = await client.add({11 content: "User prefers TypeScript for web development",12 userId: "user_123",13 priority: "high",14});15
16// Search memories17const results = await client.search({18 query: "programming preferences",19 userId: "user_123",20});
Configuration
Environment Variables
Create a .env
file:
ENV
1RECALL_REDIS_URL=redis://localhost:63792RECALL_MEM0_API_KEY=your-api-key3RECALL_ENVIRONMENT=production4RECALL_LOG_LEVEL=info
Load with dotenv:
TypeScript
1import { RecallClient } from "@recall/client";2import dotenv from "dotenv";3
4dotenv.config();5
6const client = new RecallClient({7 redisUrl: process.env.RECALL_REDIS_URL,8 mem0ApiKey: process.env.RECALL_MEM0_API_KEY,9 environment: process.env.RECALL_ENVIRONMENT,10});
Configuration Object
TypeScript
1import { RecallClient, RecallConfig } from "@recall/client";2
3const config: RecallConfig = {4 redis: {5 url: "redis://localhost:6379",6 options: {7 maxRetries: 3,8 retryDelay: 1000,9 connectionTimeout: 5000,10 },11 },12 mem0: {13 apiKey: "your-api-key",14 baseUrl: "https://api.mem0.ai",15 timeout: 30000,16 },17 cache: {18 ttl: 3600,19 maxSize: 1000,20 compression: true,21 },22 sync: {23 mode: "lazy",24 batchSize: 100,25 interval: 60000,26 },27};28
29const client = new RecallClient(config);
Type Definitions
Core Types
TypeScript
1import {2 Memory,3 Priority,4 User,5 SearchResult,6 CacheStats,7} from "@recall/client";8
9// Memory interface10interface Memory {11 id: string;12 content: string;13 userId: string;14 priority: Priority;15 metadata?: Record<string, any>;16 createdAt: Date;17 updatedAt?: Date;18 accessCount?: number;19}20
21// Priority enum22enum Priority {23 CRITICAL = "critical",24 HIGH = "high",25 MEDIUM = "medium",26 LOW = "low",27}28
29// Search result with relevance30interface SearchResult extends Memory {31 score: number;32 source: "cache" | "cloud";33 highlights?: string[];34}
Method Signatures
TypeScript
1class RecallClient {2 // Add a memory3 add(options: AddMemoryOptions): Promise<Memory>;4
5 // Search memories6 search(options: SearchOptions): Promise<SearchResult[]>;7
8 // Get specific memory9 get(memoryId: string): Promise<Memory | null>;10
11 // Update memory12 update(options: UpdateOptions): Promise<Memory>;13
14 // Delete memory15 delete(memoryId: string): Promise<boolean>;16
17 // Batch operations18 addBatch(memories: AddMemoryOptions[]): Promise<Memory[]>;19 deleteBatch(memoryIds: string[]): Promise<BatchResult>;20}
Advanced Features
Async Iteration
TypeScript
1import { RecallClient } from "@recall/client";2
3const client = new RecallClient();4
5// Iterate through search results6for await (const memory of client.searchIterator({7 query: "user preferences",8 userId: "user_123",9 batchSize: 10,10})) {11 console.log(`Processing: ${memory.content}`);12 // Process each memory13}14
15// Stream all memories16const stream = client.streamAll({17 userId: "user_123",18 batchSize: 50,19});20
21for await (const batch of stream) {22 console.log(`Batch of ${batch.length} memories`);23 // Process batch24}
Event Emitters
TypeScript
1import { RecallClient } from "@recall/client";2
3const client = new RecallClient();4
5// Listen to events6client.on("memory:added", (memory: Memory) => {7 console.log(`New memory: ${memory.id}`);8});9
10client.on("cache:hit", (key: string) => {11 console.log(`Cache hit for: ${key}`);12});13
14client.on("cache:miss", (key: string) => {15 console.log(`Cache miss for: ${key}`);16});17
18client.on("sync:complete", (stats: SyncStats) => {19 console.log(`Synced ${stats.count} memories`);20});21
22client.on("error", (error: Error) => {23 console.error(`Error: ${error.message}`);24});
Middleware
TypeScript
1import { RecallClient, Middleware } from "@recall/client";2
3// Custom middleware4class LoggingMiddleware implements Middleware {5 async process(6 operation: string,7 params: any,8 next: () => Promise<any>,9 ): Promise<any> {10 console.log(`[${operation}] Starting...`);11 const startTime = Date.now();12
13 try {14 const result = await next();15 const duration = Date.now() - startTime;16 console.log(`[${operation}] Completed in ${duration}ms`);17 return result;18 } catch (error) {19 console.error(`[${operation}] Failed:`, error);20 throw error;21 }22 }23}24
25// Apply middleware26const client = new RecallClient();27client.use(new LoggingMiddleware());28
29// Built-in middleware30import {31 RetryMiddleware,32 RateLimitMiddleware,33 CacheMiddleware,34 CompressionMiddleware,35} from "@recall/client/middleware";36
37client.use(new RetryMiddleware({ maxAttempts: 3 }));38client.use(new RateLimitMiddleware({ rps: 100 }));39client.use(new CompressionMiddleware());
Transactions
TypeScript
1import { RecallClient } from "@recall/client";2
3const client = new RecallClient();4
5// Execute operations in a transaction6const result = await client.transaction(async (tx) => {7 // All operations are atomic8 const mem1 = await tx.add({9 content: "First memory",10 userId: "user_123",11 });12
13 const mem2 = await tx.add({14 content: "Second memory",15 userId: "user_123",16 });17
18 await tx.update({19 memoryId: mem1.id,20 priority: "critical",21 });22
23 return [mem1, mem2];24});25
26// Transaction with rollback27try {28 await client.transaction(async (tx) => {29 await tx.add({ content: "Memory 1", userId: "user_123" });30 throw new Error("Rollback!");31 // All changes rolled back32 });33} catch (error) {34 console.log("Transaction rolled back");35}
React Integration
React Hook
TypeScript
1import { useRecall } from '@recall/react';2
3function UserPreferences({ userId }: { userId: string }) {4 const {5 memories,6 loading,7 error,8 addMemory,9 searchMemories,10 refreshMemories11 } = useRecall(userId);12
13 const handleSearch = async (query: string) => {14 const results = await searchMemories(query);15 console.log(`Found ${results.length} memories`);16 };17
18 const handleAdd = async (content: string) => {19 await addMemory({20 content,21 priority: 'high'22 });23 };24
25 if (loading) return <div>Loading memories...</div>;26 if (error) return <div>Error: {error.message}</div>;27
28 return (29 <div>30 <h2>User Memories ({memories.length})</h2>31 {memories.map(memory => (32 <div key={memory.id}>{memory.content}</div>33 ))}34 </div>35 );36}
React Context Provider
TypeScript
1import { RecallProvider } from '@recall/react';2import { RecallClient } from '@recall/client';3
4const client = new RecallClient({5 redisUrl: process.env.NEXT_PUBLIC_REDIS_URL,6 mem0ApiKey: process.env.NEXT_PUBLIC_MEM0_KEY7});8
9function App() {10 return (11 <RecallProvider client={client}>12 <YourComponents />13 </RecallProvider>14 );15}16
17// Use in components18import { useRecallClient } from '@recall/react';19
20function Component() {21 const client = useRecallClient();22
23 const handleAction = async () => {24 await client.add({25 content: 'User action',26 userId: 'user_123'27 });28 };29}
Express Middleware
TypeScript
1import express from "express";2import { recallMiddleware } from "@recall/express";3
4const app = express();5
6// Add Recall to all requests7app.use(8 recallMiddleware({9 redisUrl: "redis://localhost:6379",10 mem0ApiKey: "your-api-key",11 }),12);13
14// Access in routes15app.get("/memories/:userId", async (req, res) => {16 const { recall } = req;17 const memories = await recall.getAll({18 userId: req.params.userId,19 });20 res.json(memories);21});22
23app.post("/memories", async (req, res) => {24 const { recall } = req;25 const memory = await recall.add({26 content: req.body.content,27 userId: req.body.userId,28 });29 res.json(memory);30});
Testing
Mock Client
TypeScript
1import { MockRecallClient } from "@recall/client/testing";2import { describe, it, expect, beforeEach } from "@jest/globals";3
4describe("Memory Service", () => {5 let client: MockRecallClient;6
7 beforeEach(() => {8 client = new MockRecallClient();9 });10
11 it("should store memories", async () => {12 const memory = await client.add({13 content: "Test memory",14 userId: "test_user",15 });16
17 expect(memory.id).toMatch(/^mem_/);18 expect(client.getCallCount("add")).toBe(1);19 expect(client.getLastCall("add")).toMatchObject({20 content: "Test memory",21 });22 });23
24 it("should search memories", async () => {25 // Pre-populate test data26 client.setSearchResults([27 { content: "Result 1", score: 0.9 },28 { content: "Result 2", score: 0.8 },29 ]);30
31 const results = await client.search({32 query: "test",33 userId: "test_user",34 });35
36 expect(results).toHaveLength(2);37 expect(results[0].score).toBe(0.9);38 });39});
Test Utilities
TypeScript
1import {2 createTestMemory,3 createTestUser,4 populateTestData,5 cleanupTestData,6} from "@recall/client/testing";7
8// Create test fixtures9const memory = createTestMemory({10 content: "Test content",11 priority: "high",12});13
14const user = createTestUser({15 id: "test_user",16 memories: 10,17});18
19// Populate database with test data20await populateTestData(client, {21 users: 5,22 memoriesPerUser: 20,23});24
25// Cleanup after tests26await cleanupTestData(client, "test_*");
Error Handling
Error Types
TypeScript
1import {2 RecallError,3 ConnectionError,4 AuthenticationError,5 ValidationError,6 RateLimitError,7 TimeoutError,8} from "@recall/client/errors";9
10try {11 await client.add({12 content: "",13 userId: "",14 });15} catch (error) {16 if (error instanceof ValidationError) {17 console.error(`Validation failed: ${error.field} - ${error.message}`);18 } else if (error instanceof ConnectionError) {19 console.error(`Connection issue: ${error.service}`);20 } else if (error instanceof RateLimitError) {21 console.error(`Rate limited. Retry after: ${error.retryAfter}s`);22 } else if (error instanceof RecallError) {23 console.error(`Recall error: ${error.message}`);24 }25}
Error Recovery
TypeScript
1import { withRetry, withFallback } from "@recall/client/resilience";2
3// Automatic retry4const resilientClient = withRetry(client, {5 maxAttempts: 3,6 backoff: "exponential",7 retryOn: [ConnectionError, TimeoutError],8});9
10// Fallback to cache on error11const fallbackClient = withFallback(client, {12 fallbackTo: "cache",13 on: [ConnectionError],14});15
16// Circuit breaker pattern17import { CircuitBreaker } from "@recall/client/resilience";18
19const breaker = new CircuitBreaker(client, {20 threshold: 5,21 timeout: 60000,22 fallback: async () => {23 return { source: "fallback", memories: [] };24 },25});
Performance
Connection Pooling
TypeScript
1import { RecallClient } from "@recall/client";2import Redis from "ioredis";3
4// Share Redis connection5const redis = new Redis({6 host: "localhost",7 port: 6379,8 maxRetriesPerRequest: 3,9 lazyConnect: true,10});11
12const client1 = new RecallClient({ redis });13const client2 = new RecallClient({ redis });
Caching Strategies
TypeScript
1import { RecallClient, CacheStrategy } from "@recall/client";2
3const client = new RecallClient({4 cacheStrategy: CacheStrategy.WRITE_THROUGH,5 // or WRITE_BEHIND, CACHE_ASIDE, READ_THROUGH6
7 cacheConfig: {8 ttl: {9 critical: null, // Never expire10 high: 86400, // 24 hours11 medium: 3600, // 1 hour12 low: 300, // 5 minutes13 },14 warmup: true, // Pre-load frequently accessed15 compression: true, // Compress large values16 },17});
Batch Processing
TypeScript
1import { RecallClient } from "@recall/client";2import { chunk } from "lodash";3
4const client = new RecallClient();5
6// Process large dataset in batches7const memories = generateLargeDataset(10000);8const batches = chunk(memories, 100);9
10for (const batch of batches) {11 await client.addBatch(batch);12 console.log(`Processed batch of ${batch.length}`);13}14
15// Parallel processing16const results = await Promise.all(17 batches.map((batch) => client.addBatch(batch)),18);
CLI Usage
Bash
1# Install CLI globally2npm install -g @recall/cli3
4# Configure5recall config set redis.url redis://localhost:63796recall config set mem0.apiKey your-api-key7
8# Commands9recall add "Memory content" --user user_123 --priority high10recall search "query" --user user_123 --limit 1011recall get mem_abc12312recall delete mem_abc12313recall stats14recall cache clear15recall sync
Deployment
Docker
DOCKERFILE
1FROM node:18-alpine2
3WORKDIR /app4
5# Copy package files6COPY package*.json ./7RUN npm ci --production8
9# Copy application10COPY . .11
12# Build TypeScript13RUN npm run build14
15# Health check16HEALTHCHECK --interval=30s --timeout=3s \17 CMD node -e "require('@recall/client').RecallClient().healthCheck()"18
19CMD ["node", "dist/index.js"]
Environment-Specific Config
TypeScript
1import { RecallClient } from "@recall/client";2
3const config = {4 development: {5 redisUrl: "redis://localhost:6379",6 logLevel: "debug",7 cache: { ttl: 300 },8 },9 production: {10 redisUrl: process.env.REDIS_URL,11 logLevel: "error",12 cache: { ttl: 3600 },13 },14};15
16const environment = process.env.NODE_ENV || "development";17const client = new RecallClient(config[environment]);
Migration Guide
From JavaScript to TypeScript
TypeScript
1// Before (JavaScript)2const client = new RecallClient({3 redisUrl: "redis://localhost:6379",4});5
6// After (TypeScript)7import { RecallClient, RecallConfig } from "@recall/client";8
9const config: RecallConfig = {10 redis: { url: "redis://localhost:6379" },11 mem0: { apiKey: "your-api-key" },12};13
14const client = new RecallClient(config);
From Callbacks to Promises
TypeScript
1// Before (Callbacks)2client.add(memory, (err, result) => {3 if (err) console.error(err);4 else console.log(result);5});6
7// After (Promises)8try {9 const result = await client.add(memory);10 console.log(result);11} catch (error) {12 console.error(error);13}
Next Steps
- Explore React Integration for React applications
- Review API Reference for detailed documentation
- Check Examples for real-world use cases