Docs/Getting Started

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 client
4const client = new RecallClient({
5 redisUrl: "redis://localhost:6379",
6 mem0ApiKey: "your-api-key",
7});
8
9// Store a memory
10const memory = await client.add({
11 content: "User prefers TypeScript for web development",
12 userId: "user_123",
13 priority: "high",
14});
15
16// Search memories
17const 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:6379
2RECALL_MEM0_API_KEY=your-api-key
3RECALL_ENVIRONMENT=production
4RECALL_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 interface
10interface 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 enum
22enum Priority {
23 CRITICAL = "critical",
24 HIGH = "high",
25 MEDIUM = "medium",
26 LOW = "low",
27}
28
29// Search result with relevance
30interface SearchResult extends Memory {
31 score: number;
32 source: "cache" | "cloud";
33 highlights?: string[];
34}

Method Signatures

TypeScript
1class RecallClient {
2 // Add a memory
3 add(options: AddMemoryOptions): Promise<Memory>;
4
5 // Search memories
6 search(options: SearchOptions): Promise<SearchResult[]>;
7
8 // Get specific memory
9 get(memoryId: string): Promise<Memory | null>;
10
11 // Update memory
12 update(options: UpdateOptions): Promise<Memory>;
13
14 // Delete memory
15 delete(memoryId: string): Promise<boolean>;
16
17 // Batch operations
18 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 results
6for 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 memory
13}
14
15// Stream all memories
16const 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 batch
24}

Event Emitters

TypeScript
1import { RecallClient } from "@recall/client";
2
3const client = new RecallClient();
4
5// Listen to events
6client.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 middleware
4class 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 middleware
26const client = new RecallClient();
27client.use(new LoggingMiddleware());
28
29// Built-in middleware
30import {
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 transaction
6const result = await client.transaction(async (tx) => {
7 // All operations are atomic
8 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 rollback
27try {
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 back
32 });
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 refreshMemories
11 } = 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_KEY
7});
8
9function App() {
10 return (
11 <RecallProvider client={client}>
12 <YourComponents />
13 </RecallProvider>
14 );
15}
16
17// Use in components
18import { 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 requests
7app.use(
8 recallMiddleware({
9 redisUrl: "redis://localhost:6379",
10 mem0ApiKey: "your-api-key",
11 }),
12);
13
14// Access in routes
15app.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 data
26 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 fixtures
9const 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 data
20await populateTestData(client, {
21 users: 5,
22 memoriesPerUser: 20,
23});
24
25// Cleanup after tests
26await 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 retry
4const resilientClient = withRetry(client, {
5 maxAttempts: 3,
6 backoff: "exponential",
7 retryOn: [ConnectionError, TimeoutError],
8});
9
10// Fallback to cache on error
11const fallbackClient = withFallback(client, {
12 fallbackTo: "cache",
13 on: [ConnectionError],
14});
15
16// Circuit breaker pattern
17import { 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 connection
5const 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_THROUGH
6
7 cacheConfig: {
8 ttl: {
9 critical: null, // Never expire
10 high: 86400, // 24 hours
11 medium: 3600, // 1 hour
12 low: 300, // 5 minutes
13 },
14 warmup: true, // Pre-load frequently accessed
15 compression: true, // Compress large values
16 },
17});

Batch Processing

TypeScript
1import { RecallClient } from "@recall/client";
2import { chunk } from "lodash";
3
4const client = new RecallClient();
5
6// Process large dataset in batches
7const 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 processing
16const results = await Promise.all(
17 batches.map((batch) => client.addBatch(batch)),
18);

CLI Usage

Bash
1# Install CLI globally
2npm install -g @recall/cli
3
4# Configure
5recall config set redis.url redis://localhost:6379
6recall config set mem0.apiKey your-api-key
7
8# Commands
9recall add "Memory content" --user user_123 --priority high
10recall search "query" --user user_123 --limit 10
11recall get mem_abc123
12recall delete mem_abc123
13recall stats
14recall cache clear
15recall sync

Deployment

Docker

DOCKERFILE
1FROM node:18-alpine
2
3WORKDIR /app
4
5# Copy package files
6COPY package*.json ./
7RUN npm ci --production
8
9# Copy application
10COPY . .
11
12# Build TypeScript
13RUN npm run build
14
15# Health check
16HEALTHCHECK --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