# TypeScript/Node.js SDK

The official TypeScript SDK for Recall provides full type safety and modern JavaScript features for Node.js applications.

## Installation

```bash
npm 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
import { RecallClient } from "@recall/client";

// Initialize the client
const client = new RecallClient({
  redisUrl: "redis://localhost:6379",
  mem0ApiKey: "your-api-key",
});

// Store a memory
const memory = await client.add({
  content: "User prefers TypeScript for web development",
  userId: "user_123",
  priority: "high",
});

// Search memories
const results = await client.search({
  query: "programming preferences",
  userId: "user_123",
});
```

## Configuration

### Environment Variables

Create a `.env` file:

```env
RECALL_REDIS_URL=redis://localhost:6379
RECALL_MEM0_API_KEY=your-api-key
RECALL_ENVIRONMENT=production
RECALL_LOG_LEVEL=info
```

Load with dotenv:

```typescript
import { 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

```typescript
import { 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

```typescript
import {
  Memory,
  Priority,
  User,
  SearchResult,
  CacheStats,
} from "@recall/client";

// Memory interface
interface Memory {
  id: string;
  content: string;
  userId: string;
  priority: Priority;
  metadata?: Record<string, any>;
  createdAt: Date;
  updatedAt?: Date;
  accessCount?: number;
}

// Priority enum
enum Priority {
  CRITICAL = "critical",
  HIGH = "high",
  MEDIUM = "medium",
  LOW = "low",
}

// Search result with relevance
interface SearchResult extends Memory {
  score: number;
  source: "cache" | "cloud";
  highlights?: string[];
}
```

### Method Signatures

```typescript
class RecallClient {
  // Add a memory
  add(options: AddMemoryOptions): Promise<Memory>;

  // Search memories
  search(options: SearchOptions): Promise<SearchResult[]>;

  // Get specific memory
  get(memoryId: string): Promise<Memory | null>;

  // Update memory
  update(options: UpdateOptions): Promise<Memory>;

  // Delete memory
  delete(memoryId: string): Promise<boolean>;

  // Batch operations
  addBatch(memories: AddMemoryOptions[]): Promise<Memory[]>;
  deleteBatch(memoryIds: string[]): Promise<BatchResult>;
}
```

## Advanced Features

### Async Iteration

```typescript
import { RecallClient } from "@recall/client";

const client = new RecallClient();

// Iterate through search results
for await (const memory of client.searchIterator({
  query: "user preferences",
  userId: "user_123",
  batchSize: 10,
})) {
  console.log(`Processing: ${memory.content}`);
  // Process each memory
}

// Stream all memories
const 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

```typescript
import { RecallClient } from "@recall/client";

const client = new RecallClient();

// Listen to events
client.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

```typescript
import { RecallClient, Middleware } from "@recall/client";

// Custom middleware
class 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 middleware
const client = new RecallClient();
client.use(new LoggingMiddleware());

// Built-in middleware
import {
  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

```typescript
import { RecallClient } from "@recall/client";

const client = new RecallClient();

// Execute operations in a transaction
const result = await client.transaction(async (tx) => {
  // All operations are atomic
  const 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 rollback
try {
  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

```typescript
import { 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

```typescript
import { 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 components
import { useRecallClient } from '@recall/react';

function Component() {
  const client = useRecallClient();

  const handleAction = async () => {
    await client.add({
      content: 'User action',
      userId: 'user_123'
    });
  };
}
```

## Express Middleware

```typescript
import express from "express";
import { recallMiddleware } from "@recall/express";

const app = express();

// Add Recall to all requests
app.use(
  recallMiddleware({
    redisUrl: "redis://localhost:6379",
    mem0ApiKey: "your-api-key",
  }),
);

// Access in routes
app.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

```typescript
import { 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 data
    client.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

```typescript
import {
  createTestMemory,
  createTestUser,
  populateTestData,
  cleanupTestData,
} from "@recall/client/testing";

// Create test fixtures
const memory = createTestMemory({
  content: "Test content",
  priority: "high",
});

const user = createTestUser({
  id: "test_user",
  memories: 10,
});

// Populate database with test data
await populateTestData(client, {
  users: 5,
  memoriesPerUser: 20,
});

// Cleanup after tests
await cleanupTestData(client, "test_*");
```

## Error Handling

### Error Types

```typescript
import {
  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

```typescript
import { withRetry, withFallback } from "@recall/client/resilience";

// Automatic retry
const resilientClient = withRetry(client, {
  maxAttempts: 3,
  backoff: "exponential",
  retryOn: [ConnectionError, TimeoutError],
});

// Fallback to cache on error
const fallbackClient = withFallback(client, {
  fallbackTo: "cache",
  on: [ConnectionError],
});

// Circuit breaker pattern
import { CircuitBreaker } from "@recall/client/resilience";

const breaker = new CircuitBreaker(client, {
  threshold: 5,
  timeout: 60000,
  fallback: async () => {
    return { source: "fallback", memories: [] };
  },
});
```

## Performance

### Connection Pooling

```typescript
import { RecallClient } from "@recall/client";
import Redis from "ioredis";

// Share Redis connection
const redis = new Redis({
  host: "localhost",
  port: 6379,
  maxRetriesPerRequest: 3,
  lazyConnect: true,
});

const client1 = new RecallClient({ redis });
const client2 = new RecallClient({ redis });
```

### Caching Strategies

```typescript
import { RecallClient, CacheStrategy } from "@recall/client";

const client = new RecallClient({
  cacheStrategy: CacheStrategy.WRITE_THROUGH,
  // or WRITE_BEHIND, CACHE_ASIDE, READ_THROUGH

  cacheConfig: {
    ttl: {
      critical: null, // Never expire
      high: 86400, // 24 hours
      medium: 3600, // 1 hour
      low: 300, // 5 minutes
    },
    warmup: true, // Pre-load frequently accessed
    compression: true, // Compress large values
  },
});
```

### Batch Processing

```typescript
import { RecallClient } from "@recall/client";
import { chunk } from "lodash";

const client = new RecallClient();

// Process large dataset in batches
const 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 processing
const results = await Promise.all(
  batches.map((batch) => client.addBatch(batch)),
);
```

## CLI Usage

```bash
# Install CLI globally
npm install -g @recall/cli

# Configure
recall config set redis.url redis://localhost:6379
recall config set mem0.apiKey your-api-key

# Commands
recall add "Memory content" --user user_123 --priority high
recall search "query" --user user_123 --limit 10
recall get mem_abc123
recall delete mem_abc123
recall stats
recall cache clear
recall sync
```

## Deployment

### Docker

```dockerfile
FROM node:18-alpine

WORKDIR /app

# Copy package files
COPY package*.json ./
RUN npm ci --production

# Copy application
COPY . .

# Build TypeScript
RUN npm run build

# Health check
HEALTHCHECK --interval=30s --timeout=3s \
  CMD node -e "require('@recall/client').RecallClient().healthCheck()"

CMD ["node", "dist/index.js"]
```

### Environment-Specific Config

```typescript
import { 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](/docs/integrations/react) for React applications
- Review [API Reference](/docs/api/client) for detailed documentation
- Check [Examples](/docs/examples/typescript-examples) for real-world use cases

Source: https://r3.n3wth.com/docs/sdks/typescript
