{"_id":"@bpwme/ra-ts","_rev":"2-ca1311bf8659ac705cd1fa3eba029e73","name":"@bpwme/ra-ts","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"@bpwme/ra-ts","version":"0.0.1","license":"MIT","_id":"@bpwme/ra-ts@0.0.1","maintainers":[{"name":"bpwme","email":"bpw.merks@gmail.com"}],"dist":{"shasum":"b91ac57a6e4c6643618eed30c935e085cb4ff054","tarball":"https://registry.npmjs.org/@bpwme/ra-ts/-/ra-ts-0.0.1.tgz","fileCount":43,"integrity":"sha512-CH4ZHq5Q7iUuBYaz2wOfgqG8o742IMQFp9BmHygGN1mfu2/qnpHVJjFTsVsp1AFfBAt7OoWjmsc7xQiWNIFMPA==","signatures":[{"sig":"MEUCIEQpGXyBybOIQmhTXz1m9vmuBJMAkPYL5tPhofQORT+OAiEA2qBbyug/eIwzky+pncOn3F5//x93oTmb3VDjRl4K41g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1080875},"main":"./dist/index.cjs.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.es.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.es.js","require":"./dist/index.cjs.js"}},"gitHead":"fff9fb30dc3d038423cb2f494ee2d45823a78954","scripts":{"dev":"vite build --watch","lint":"eslint .","test":"vitest run","build":"vite build && tsc --emitDeclarationOnly","preview":"vite preview","lint:fix":"eslint . --fix","test:basic":"tsx test.ts","test:watch":"vitest watch"},"_npmUser":{"name":"bpwme","email":"bpw.merks@gmail.com"},"_npmVersion":"10.9.2","description":"**Ra-ts** - A powerful, type-safe data management library with caching, queuing, rate limiting, and advanced request handling capabilities.","directories":{},"_nodeVersion":"22.15.1","_hasShrinkwrap":false,"devDependencies":{"jiti":"^2.4.2","vite":"^6.3.5","jsdom":"^26.1.0","eslint":"^9.28.0","vitest":"^3.1.4","typescript":"^5.8.3","@types/node":"^22.15.29","typescript-eslint":"^8.33.0","@vitest/coverage-v8":"^3.1.4"},"peerDependencies":{"validator":"^13.15.15","isomorphic-dompurify":"^2.25.0"},"peerDependenciesMeta":{"validator":{"optional":true},"isomorphic-dompurify":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ra-ts_0.0.1_1748781114457_0.11859860580802484","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@bpwme/ra-ts","version":"0.0.2","description":"A TypeScript library for building requests.","keywords":["typescript","adapter","rate-limiting","caching","batching","streaming","request","http","middleware","composable"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/bpwme/ra-ts.git"},"bugs":{"url":"https://github.com/bpwme/ra-ts/issues"},"homepage":"https://github.com/bpwme/ra-ts#readme","engines":{"node":">=18.0.0"},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.es.js","require":"./dist/index.cjs.js"}},"main":"./dist/index.cjs.js","module":"./dist/index.es.js","types":"./dist/index.d.ts","scripts":{"dev":"vite build --watch","build":"vite build && tsc --emitDeclarationOnly","preview":"vite preview","test":"vitest run","test:coverage":"vitest run --coverage","test:watch":"vitest watch","lint":"eslint .","lint:fix":"eslint . --fix"},"devDependencies":{"@types/node":"^22.15.29","@vitest/coverage-v8":"^3.1.4","eslint":"^9.28.0","jiti":"^2.4.2","jsdom":"^26.1.0","typescript":"^5.8.3","typescript-eslint":"^8.33.0","vite":"^6.3.5","vitest":"^3.1.4"},"peerDependencies":{"isomorphic-dompurify":"^2.25.0","validator":"^13.15.15"},"peerDependenciesMeta":{"isomorphic-dompurify":{"optional":true},"validator":{"optional":true}},"_id":"@bpwme/ra-ts@0.0.2","gitHead":"7164712d577a6b63cc1cc7bfd4594ea5d3a5cadf","_nodeVersion":"22.15.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-kylktJpGWEXzgNneFIucqNsTZKHKGKR+xDy8/aPIKfsKdas2E/0PFGr6eTkkrmU8CDKH/Njc4gf6uEXVW0jBdg==","shasum":"a14a978203806e35ed461506fdaa527a62e04bf7","tarball":"https://registry.npmjs.org/@bpwme/ra-ts/-/ra-ts-0.0.2.tgz","fileCount":47,"unpackedSize":972786,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDvwmE/VXC0O1e8+aI+M3k7VA6mpm3rqR+y16NsNDtDqgIgfdbUdKFKZNuhVVA7IF7ADBkScvZSAygtTEmJBHkh52E="}]},"_npmUser":{"name":"bpwme","email":"bpw.merks@gmail.com"},"directories":{},"maintainers":[{"name":"bpwme","email":"bpw.merks@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ra-ts_0.0.2_1748796058333_0.08332356242269445"},"_hasShrinkwrap":false}},"time":{"created":"2025-06-01T12:31:54.398Z","modified":"2025-06-01T16:40:59.030Z","0.0.1":"2025-06-01T12:31:54.675Z","0.0.2":"2025-06-01T16:40:58.578Z"},"license":"MIT","description":"A TypeScript library for building requests.","maintainers":[{"name":"bpwme","email":"bpw.merks@gmail.com"}],"readme":"# Ra-ts Documentation\n\n-- Docs are generated (for now) --\n\n**Ra-ts** - A powerful, type-safe data management library with caching, queuing, rate limiting, and advanced request handling capabilities.\n\nRa-ts provides a robust foundation for managing data in modern applications with type safety, performance, and developer experience in mind. The modular adapter system allows you to customize behavior for your specific needs while maintaining a consistent API across your application. \n\n## Table of Contents\n\n- [Overview](#overview)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Core Concepts](#core-concepts)\n- [API Reference](#api-reference)\n- [Examples](#examples)\n- [Adapters](#adapters)\n- [Advanced Usage](#advanced-usage)\n- [Error Handling](#error-handling)\n- [Best Practices](#best-practices)\n\n## Overview\n\nRa-ts is a comprehensive data management solution that provides:\n\n- **Type-safe operations** with explicit error handling using Either types\n- **Advanced caching** with multiple storage backends (Memory, IndexedDB, LocalStorage)\n- **Request deduplication** to prevent duplicate network calls\n- **Rate limiting** with multiple strategies (Token Bucket, Concurrency, Adaptive)\n- **Optimistic updates** for better UX\n- **Queue management** for offline/background operations\n- **Data validation** and sanitization\n- **Monitoring and logging** capabilities\n- **Encryption support** for sensitive data\n\n## Installation\n\n```bash\nnpm install ra-ts\n# or\npnpm add ra-ts\n# or\nyarn add ra-ts\n```\n\n### Peer Dependencies\n\nFor validation and security features:\n\n```bash\nnpm install validator isomorphic-dompurify\n```\n\n## Quick Start\n\n```typescript\nimport { DataManager, MemoryCache, ConsoleLogger } from 'ra-ts'\n\n// Create a DataManager instance\nconst dataManager = new DataManager({\n  cache: new MemoryCache({ maxSize: 500 }),\n  logger: new ConsoleLogger(),\n  defaultTTL: 300000, // 5 minutes\n  enableOptimisticUpdates: true\n})\n\n// Fetch user data with caching\nconst fetchUser = async (userId: number) => {\n  return dataManager\n    .query<User>(`user:${userId}`)\n    .staleTime(60000)  // Consider stale after 1 minute\n    .ttl(300000)       // Cache for 5 minutes\n    .retries(3)        // Retry up to 3 times\n    .fetch(async () => {\n      const response = await fetch(`/api/users/${userId}`)\n      if (!response.ok) {\n        return error(new NetworkError('Failed to fetch user'))\n      }\n      const userData = await response.json()\n      return success(userData)\n    })\n}\n\n// Update user with optimistic updates\nconst updateUser = async (userId: number, userData: Partial<User>) => {\n  return dataManager\n    .mutate<User>(`user:${userId}`)\n    .optimistic({ ...currentUser, ...userData })  // Show immediately\n    .invalidates('user:*', 'users:list')          // Clear related cache\n    .retries(2)\n    .execute(async () => {\n      const response = await fetch(`/api/users/${userId}`, {\n        method: 'PATCH',\n        body: JSON.stringify(userData),\n        headers: { 'Content-Type': 'application/json' }\n      })\n      \n      if (!response.ok) {\n        return error(new NetworkError('Failed to update user'))\n      }\n      \n      const updatedUser = await response.json()\n      return success(updatedUser)\n    })\n}\n```\n\n## Core Concepts\n\n### Either Type System\n\nRa-ts uses explicit error handling with Either types instead of throwing exceptions:\n\n```typescript\nimport { Either, success, error, isSuccess, isError } from 'ra-ts'\n\n// Function returns Either<ErrorType, SuccessType>\nconst fetchData = async (): Promise<Either<NetworkError, User>> => {\n  try {\n    const response = await fetch('/api/user')\n    if (!response.ok) {\n      return error(new NetworkError('Request failed'))\n    }\n    const user = await response.json()\n    return success(user)\n  } catch (err) {\n    return error(new NetworkError('Network error'))\n  }\n}\n\n// Handle the result\nconst result = await fetchData()\nif (isSuccess(result)) {\n  console.log('User:', result.data)\n} else {\n  console.error('Error:', result.error.message)\n}\n```\n\n### Builder Pattern\n\nFluent API for configuring queries and mutations:\n\n```typescript\n// Query builder\nconst userQuery = dataManager\n  .query<User>('user:123')\n  .staleTime(30000)      // Stale after 30 seconds\n  .ttl(600000)           // Cache for 10 minutes\n  .retries(3)            // Retry failed requests\n  .sanitize()            // Enable data sanitization\n  .validate(userSchema)  // Validate with schema\n\n// Mutation builder\nconst userMutation = dataManager\n  .mutate<User>('user:123')\n  .optimistic(optimisticData)\n  .invalidates('user:*', 'profile:*')\n  .ttl(300000)\n  .validate(userSchema)\n```\n\n## API Reference\n\n### DataManager\n\nThe main class that coordinates all operations.\n\n#### Constructor\n\n```typescript\nconst dataManager = new DataManager(config?: DataManagerConfig)\n```\n\n**DataManagerConfig:**\n```typescript\ntype DataManagerConfig = {\n  cache?: CacheAdapter\n  queue?: QueueAdapter\n  rateLimiter?: RateLimiter\n  logger?: Logger\n  monitor?: Monitor\n  securityValidator?: Validator\n  defaultTTL?: number\n  enableOptimisticUpdates?: boolean\n  enableSanitization?: boolean\n}\n```\n\n#### Methods\n\n##### `query<T>(key: string): QueryBuilder<T>`\n\nCreates a query builder for the given cache key.\n\n##### `mutate<T>(key: string): MutationBuilder<T>`\n\nCreates a mutation builder for the given cache key.\n\n### QueryBuilder\n\nFluent interface for configuring data fetching operations.\n\n#### Methods\n\n##### `staleTime(ms: number): this`\nSets how long cached data is considered fresh.\n\n##### `ttl(ms: number): this`\nSets cache time-to-live.\n\n##### `retries(count: number): this`\nSets maximum retry attempts.\n\n##### `validate<S>(schema: Validator<S>): QueryBuilder<S>`\nAdds schema validation.\n\n##### `sanitize(): this` / `skipSanitization(): this`\nControls data sanitization.\n\n##### `fetch(fetcher: () => Promise<Either<any, T>>): Promise<Either<any, T>>`\nExecutes the query with configured options.\n\n### MutationBuilder\n\nFluent interface for configuring data modification operations.\n\n#### Methods\n\n##### `optimistic(data: T): this`\nSets optimistic update data to show immediately.\n\n##### `invalidates(...patterns: string[]): this`\nCache patterns to clear after successful mutation.\n\n##### `retries(count: number): this`\nSets maximum retry attempts.\n\n##### `ttl(ms: number): this`\nSets TTL for mutation result.\n\n##### `validate<S>(schema: Validator<S>): MutationBuilder<S>`\nAdds schema validation.\n\n##### `execute(mutator: () => Promise<Either<any, T>>): Promise<Either<any, T>>`\nExecutes the mutation with configured options.\n\n## Examples\n\n### Basic Data Fetching\n\n```typescript\nimport { DataManager, MemoryCache, success, error } from 'ra-ts'\n\nconst dm = new DataManager({\n  cache: new MemoryCache({ maxSize: 100 })\n})\n\ninterface User {\n  id: number\n  name: string\n  email: string\n}\n\n// Simple fetch with caching\nconst getUser = async (id: number): Promise<Either<any, User>> => {\n  return dm.query<User>(`user:${id}`)\n    .staleTime(60000)\n    .fetch(async () => {\n      const response = await fetch(`/api/users/${id}`)\n      if (!response.ok) {\n        return error(new Error('Failed to fetch user'))\n      }\n      const user = await response.json()\n      return success(user)\n    })\n}\n```\n\n### Data Validation with Zod\n\n```typescript\nimport { z } from 'zod'\n\nconst userSchema = {\n  parse: (data: unknown) => {\n    const schema = z.object({\n      id: z.number(),\n      name: z.string().min(1),\n      email: z.string().email()\n    })\n    \n    try {\n      const validated = schema.parse(data)\n      return success(validated)\n    } catch (err) {\n      return error(new ValidationError('Invalid user data', err))\n    }\n  },\n  safeParse: function(data: unknown) { return this.parse(data) }\n}\n\nconst getValidatedUser = async (id: number) => {\n  return dm.query<User>(`user:${id}`)\n    .validate(userSchema)\n    .fetch(fetchUserData)\n}\n```\n\n### Optimistic Updates\n\n```typescript\nconst updateUserProfile = async (\n  userId: number, \n  updates: Partial<User>\n): Promise<Either<any, User>> => {\n  const currentUser = await getCurrentUser(userId)\n  \n  if (isError(currentUser)) {\n    return currentUser\n  }\n\n  const optimisticUser = { ...currentUser.data, ...updates }\n\n  return dm.mutate<User>(`user:${userId}`)\n    .optimistic(optimisticUser)\n    .invalidates('user:*', 'profile:*')\n    .execute(async () => {\n      const response = await fetch(`/api/users/${userId}`, {\n        method: 'PATCH',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify(updates)\n      })\n\n      if (!response.ok) {\n        return error(new NetworkError('Update failed'))\n      }\n\n      const updatedUser = await response.json()\n      return success(updatedUser)\n    })\n}\n```\n\n### Batch Operations\n\n```typescript\nconst getUsersWithPosts = async (userIds: number[]) => {\n  const userPromises = userIds.map(id => \n    dm.query<User>(`user:${id}`)\n      .staleTime(120000)\n      .fetch(() => fetchUser(id))\n  )\n\n  const postPromises = userIds.map(id =>\n    dm.query<Post[]>(`user:${id}:posts`)\n      .staleTime(60000)\n      .fetch(() => fetchUserPosts(id))\n  )\n\n  const [users, posts] = await Promise.all([\n    Promise.all(userPromises),\n    Promise.all(postPromises)\n  ])\n\n  // Handle results...\n  return { users, posts }\n}\n```\n\n### Error Recovery\n\n```typescript\nconst robustDataFetch = async <T>(\n  key: string,\n  fetcher: () => Promise<Either<any, T>>,\n  fallback?: T\n): Promise<Either<any, T>> => {\n  const result = await dm.query<T>(key)\n    .retries(3)\n    .staleTime(30000)\n    .fetch(fetcher)\n\n  if (isError(result) && fallback) {\n    // Return fallback data if available\n    return success(fallback)\n  }\n\n  return result\n}\n```\n\n### Batch Loading with DataLoader\n\nFor efficient request batching and caching, use the DataLoader pattern:\n\n```typescript\nimport { DataLoader, success, error, NetworkError } from 'ra-ts'\n\ninterface User {\n  id: number\n  name: string\n  email: string\n}\n\n// Create a DataLoader for batching user requests\nconst userLoader = new DataLoader<number, User>({\n  batchLoadFn: async (userIds: number[]) => {\n    console.log('Batching user requests:', userIds)\n    \n    const response = await fetch('/api/users/batch', {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ ids: userIds })\n    })\n\n    if (!response.ok) {\n      return error(new NetworkError('Failed to load users'))\n    }\n\n    const users = await response.json()\n    return success(users)\n  },\n  maxBatchSize: 25,        // Batch up to 25 requests\n  batchDelay: 16,          // Wait 16ms before executing batch\n  cache: true,             // Enable result caching\n  cacheTTL: 300000,        // Cache for 5 minutes\n  logger: new ConsoleLogger()\n})\n\n// Load individual users - requests will be automatically batched\nconst loadUser = async (userId: number) => {\n  return userLoader.load(userId)\n}\n\n// Load multiple users efficiently\nconst loadUsers = async (userIds: number[]) => {\n  return userLoader.loadMany(userIds)\n}\n\n// Usage example - these will be batched together\nconst getUsersExample = async () => {\n  const users = await loadUsers([1,2,3])\n\n  // or\n  \n  const [user1, user2, user3] = await Promise.all([\n    loadUser(1),\n    loadUser(2), \n    loadUser(3)\n  ])\n  \n  // Get performance stats\n  const stats = userLoader.getStats()\n  console.log('Batch stats:', stats)\n}\n```\n\n## Adapters\n\n### Cache Adapters\n\n#### MemoryCache\n\nHigh-performance in-memory cache with LRU eviction:\n\n```typescript\nimport { MemoryCache } from 'ra-ts'\n\nconst memoryCache = new MemoryCache({\n  maxSize: 1000,           // Maximum entries\n  defaultTTL: 300000,      // 5 minutes default TTL\n  cleanupInterval: 60000   // Cleanup every minute\n})\n\n// Get cache statistics\nconst stats = memoryCache.getStats()\nconsole.log('Cache size:', stats.size)\nconsole.log('Expired entries:', stats.expiredCount)\n```\n\n#### IndexedDBCache\n\nBrowser persistent storage:\n\n```typescript\nimport { IndexedDBCache } from 'ra-ts'\n\nconst indexedDBCache = new IndexedDBCache({\n  dbName: 'MyAppCache',\n  version: 1,\n  defaultTTL: 86400000,    // 24 hours\n  maxSize: 50 * 1024 * 1024, // 50MB\n  compressionThreshold: 1024  // Compress data > 1KB\n})\n```\n\n#### LocalStorageCache\n\nBrowser localStorage with quotas:\n\n```typescript\nimport { LocalStorageCache } from 'ra-ts'\n\nconst localStorageCache = new LocalStorageCache({\n  prefix: 'myapp:',\n  defaultTTL: 3600000,     // 1 hour\n  maxSize: 5 * 1024 * 1024, // 5MB quota\n  compression: true\n})\n```\n\n#### EncryptedCache\n\nEncrypted storage for sensitive data:\n\n```typescript\nimport { EncryptedCache, MemoryCache } from 'ra-ts'\n\nconst encryptedCache = new EncryptedCache({\n  baseCache: new MemoryCache(),\n  encryptionKey: 'your-32-char-encryption-key-here',\n  algorithm: 'AES-GCM'\n})\n```\n\n### Rate Limiters\n\n#### TokenBucketLimiter\n\nClassic token bucket algorithm:\n\n```typescript\nimport { TokenBucketLimiter } from 'ra-ts'\n\nconst rateLimiter = new TokenBucketLimiter({\n  capacity: 10,        // 10 tokens\n  refillRate: 1,       // 1 token per second\n  refillInterval: 1000 // Every 1000ms\n})\n```\n\n#### ConcurrencyLimiter\n\nLimits concurrent operations:\n\n```typescript\nimport { ConcurrencyLimiter } from 'ra-ts'\n\nconst concurrencyLimiter = new ConcurrencyLimiter({\n  maxConcurrent: 3,    // Max 3 simultaneous requests\n  queueTimeout: 5000   // Queue timeout 5 seconds\n})\n```\n\n#### AdaptiveRateLimiter\n\nAdjusts limits based on success/failure rates:\n\n```typescript\nimport { AdaptiveRateLimiter } from 'ra-ts'\n\nconst adaptiveLimiter = new AdaptiveRateLimiter({\n  initialRate: 10,\n  minRate: 1,\n  maxRate: 50,\n  adjustmentFactor: 0.1,\n  windowSize: 100\n})\n```\n\n### Queue Adapters\n\n#### BrowserQueue\n\nQueue for offline/background operations:\n\n```typescript\nimport { BrowserQueue, JobStatus } from 'ra-ts'\n\nconst queue = new BrowserQueue({\n  storage: 'indexeddb',\n  maxRetries: 3,\n  retryDelay: 1000,\n  concurrency: 2\n})\n\n// Add job to queue\nawait queue.add({\n  id: 'unique-job-id',\n  type: 'api-call',\n  payload: { method: 'POST', url: '/api/data', body: data },\n  retries: 0,\n  maxRetries: 3,\n  createdAt: new Date()\n})\n\n// Process queued jobs\nqueue.process(async (job) => {\n  // Handle job execution\n  return success(result)\n})\n\n// Get queue statistics\nconst stats = await queue.getStats()\nconsole.log('Pending jobs:', stats.pending)\nconsole.log('Failed jobs:', stats.failed)\n```\n\n### Stream Adapters\n\n#### WebSocketAdapter\n\nReal-time data streaming with advanced reconnection and health monitoring:\n\n```typescript\nimport { WebSocketAdapter, ConsoleLogger } from 'ra-ts'\n\nconst wsAdapter = new WebSocketAdapter({\n  url: 'wss://api.example.com/realtime',\n  protocols: ['protocol1', 'protocol2'],\n  \n  // Automatic reconnection with exponential backoff\n  reconnection: {\n    enabled: true,\n    maxAttempts: 5,\n    baseDelay: 1000,     // Start with 1 second\n    maxDelay: 30000,     // Max 30 seconds\n    backoffFactor: 2     // Double delay each attempt\n  },\n  \n  // Health monitoring with ping/pong\n  healthcheck: {\n    enabled: true,\n    interval: 30000,     // Ping every 30 seconds\n    timeout: 5000,       // Expect pong within 5 seconds\n    pingMessage: { type: 'ping' },\n    pongMessage: { type: 'pong' }\n  },\n  \n  connectionTimeout: 10000,  // 10 second connection timeout\n  maxQueueSize: 100,         // Queue up to 100 messages when offline\n  logger: new ConsoleLogger()\n})\n\n// Connect to WebSocket\nconst connectResult = await wsAdapter.connect()\nif (connectResult.error) {\n  console.error('Failed to connect:', connectResult.error)\n}\n\n// Subscribe to channels\nawait wsAdapter.subscribe('user-updates', async (message) => {\n  console.log('User update received:', message.data)\n  \n  // Update cache based on real-time data\n  await dataManager.mutate(`user:${message.data.userId}`)\n    .optimistic(message.data)\n    .execute(async () => success(message.data))\n})\n\nawait wsAdapter.subscribe('notifications', async (message) => {\n  console.log('New notification:', message.data)\n  // Handle notifications\n})\n\n// Send messages\nawait wsAdapter.sendMessage({\n  channel: 'user-actions',\n  type: 'status-update',\n  data: { status: 'online' },\n  timestamp: new Date(),\n  messageId: 'unique-id-123'\n})\n\n// Monitor connection stats\nconst stats = wsAdapter.getStats()\nconsole.log('WebSocket stats:', {\n  connectionCount: stats.connectionCount,\n  messagesReceived: stats.messagesReceived,\n  messagesSent: stats.messagesSent,\n  subscriptionCount: stats.subscriptionCount\n})\n\n// Graceful disconnection\nawait wsAdapter.disconnect()\n```\n\n### Monitoring\n\n#### ConsoleMonitor\n\nDevelopment monitoring with console output:\n\n```typescript\nimport { ConsoleMonitor } from 'ra-ts'\n\nconst monitor = new ConsoleMonitor({\n  enableTiming: true,\n  enableEvents: true,\n  enableMetrics: true,\n  logLevel: 'debug'\n})\n\nconst dm = new DataManager({ monitor })\n```\n\n#### PerformanceProfiler\n\nAdvanced performance profiling with detailed timing and memory analysis:\n\n```typescript\nimport { PerformanceProfiler, ConsoleLogger } from 'ra-ts'\n\nconst profiler = new PerformanceProfiler({\n  enabled: true,\n  sampleRate: 0.1,        // Profile 10% of operations\n  maxProfiles: 1000,      // Keep last 1000 profiles\n  minDuration: 1,         // Only capture operations > 1ms\n  memoryProfiling: true,  // Track memory usage\n  logger: new ConsoleLogger()\n})\n\n// Manual profiling\nconst profileId = profiler.startProfile('user-fetch', { userId: 123 })\ntry {\n  const user = await fetchUser(123)\n  profiler.endProfile(profileId, { success: true, userType: user.type })\n} catch (error) {\n  profiler.endProfile(profileId, { success: false, error: error.message })\n}\n\n// Automatic function profiling\nconst fetchUserProfiled = async (userId: number) => {\n  return profiler.profileFunction(\n    'fetch-user-operation',\n    async () => {\n      const response = await fetch(`/api/users/${userId}`)\n      const user = await response.json()\n      return user\n    },\n    { userId, operation: 'api-fetch' }\n  )\n}\n\n// Get performance statistics\nconst stats = profiler.getStats()\nconsole.log('Performance Stats:', {\n  totalProfiles: stats.totalProfiles,\n  averageDuration: stats.averageDuration,\n  p95Duration: stats.p95Duration,\n  p99Duration: stats.p99Duration,\n  memoryStats: stats.memoryStats\n})\n\n// Find slow operations\nconst slowOps = profiler.getSlowOperations(100) // Operations > 100ms\nconsole.log('Slow operations:', slowOps)\n\n// Generate detailed report\nconsole.log(profiler.generateReport())\n\n// Use with DataManager for automatic profiling\nconst profiledDataManager = new DataManager({\n  cache: new MemoryCache(),\n  monitor: {\n    track: (event, data) => profiler.startProfile(event, data),\n    startTimer: (name) => {\n      const profileId = profiler.startProfile(name)\n      return () => profiler.endProfile(profileId)\n    },\n    recordMetric: (name, value) => {\n      // Custom metric recording\n      console.log(`Metric ${name}:`, value)\n    }\n  }\n})\n```\n\n#### TelemetryMonitor\n\nOpenTelemetry-compatible monitoring with distributed tracing:\n\n```typescript\nimport { TelemetryMonitor, ConsoleLogger } from 'ra-ts'\n\nconst telemetry = new TelemetryMonitor({\n  tracing: true,\n  metrics: true,\n  logs: true,\n  serviceName: 'my-app',\n  serviceVersion: '1.0.0',\n  sampleRate: 1.0,        // Trace 100% of operations\n  \n  // Export callback for external telemetry systems\n  onExport: (data) => {\n    console.log('Telemetry export:', data)\n    // Send to external systems like Jaeger, Zipkin, etc.\n  },\n  \n  // Global attributes for all spans\n  attributes: {\n    environment: 'production',\n    datacenter: 'us-east-1'\n  },\n  \n  logger: new ConsoleLogger()\n})\n\n// Manual span creation\nconst span = telemetry.createSpan('user-operation')\ntelemetry.setActiveSpan(span)\n\n// Add attributes and events to spans\ntelemetry.addSpanAttributes(span.spanId, { userId: 123, operation: 'fetch' })\ntelemetry.addSpanEvent(span.spanId, 'cache-miss', { cacheKey: 'user:123' })\n\n// Finish the span\ntelemetry.finishSpan(span, { result: 'success' })\n\n// Traced operations with automatic span management\nconst result = await telemetry.withTrace(\n  'complex-user-operation',\n  async (span) => {\n    // This code runs within a traced span\n    const user = await fetchUser(123)\n    \n    // Add attributes based on result\n    telemetry.addSpanAttributes(span.spanId, {\n      userId: user.id,\n      userType: user.type,\n      hasPermissions: user.permissions.length > 0\n    })\n    \n    const posts = await fetchUserPosts(user.id)\n    telemetry.addSpanEvent(span.spanId, 'posts-loaded', { count: posts.length })\n    \n    return { user, posts }\n  },\n  { operationType: 'user-dashboard' }\n)\n\n// Record metrics\ntelemetry.recordMetric('api.requests', 1, { endpoint: '/users', method: 'GET' })\ntelemetry.recordMetric('cache.hit_rate', 0.85, { cache: 'user-cache' })\n\n// Error tracking\ntry {\n  await riskyOperation()\n} catch (error) {\n  telemetry.recordError(error, { operation: 'risky-operation', userId: 123 })\n  throw error\n}\n\n// Health checks\ntelemetry.registerHealthCheck('database', async () => {\n  try {\n    await database.ping()\n    return { status: 'pass', message: 'Database connection healthy' }\n  } catch (error) {\n    return { status: 'fail', message: 'Database connection failed', details: error }\n  }\n})\n\ntelemetry.registerHealthCheck('cache', async () => {\n  const hitRate = cache.getHitRate()\n  return {\n    status: hitRate > 0.7 ? 'pass' : 'warn',\n    message: `Cache hit rate: ${(hitRate * 100).toFixed(1)}%`,\n    details: { hitRate }\n  }\n})\n\n// Execute health checks\nconst health = await telemetry.executeHealthChecks()\nconsole.log('Health status:', health)\n\n// Use with DataManager for automatic tracing\nconst tracedDataManager = new DataManager({\n  cache: new MemoryCache(),\n  monitor: telemetry\n})\n\n// Get telemetry statistics\nconst telemetryStats = telemetry.getStats()\nconsole.log('Telemetry stats:', telemetryStats)\n```\n\n### Security\n\n#### SecurityValidator\n\nData validation and sanitization:\n\n```typescript\nimport { SecurityValidator } from 'ra-ts'\n\nconst securityValidator = new SecurityValidator({\n  enableSanitization: true,\n  enableValidation: true,\n  maxStringLength: 10000,\n  allowedTags: ['b', 'i', 'em', 'strong'],\n  strictMode: true\n})\n\nconst dm = new DataManager({\n  securityValidator,\n  enableSanitization: true\n})\n```\n\n## Advanced Usage\n\n### Custom Cache Implementation\n\n```typescript\nimport type { CacheAdapter, Either } from 'ra-ts'\nimport { success, error, CacheError } from 'ra-ts'\n\nclass CustomCache implements CacheAdapter {\n  private store = new Map<string, any>()\n\n  async get<T>(key: string): Promise<Either<CacheError, T | undefined>> {\n    try {\n      const value = this.store.get(key)\n      return success(value)\n    } catch (err) {\n      return error(new CacheError('Get failed', { key, err }))\n    }\n  }\n\n  async set<T>(key: string, value: T, ttl?: number): Promise<Either<CacheError, void>> {\n    try {\n      this.store.set(key, value)\n      // Handle TTL logic...\n      return success(undefined)\n    } catch (err) {\n      return error(new CacheError('Set failed', { key, err }))\n    }\n  }\n\n  async delete(key: string): Promise<Either<CacheError, void>> {\n    try {\n      this.store.delete(key)\n      return success(undefined)\n    } catch (err) {\n      return error(new CacheError('Delete failed', { key, err }))\n    }\n  }\n\n  async clear(): Promise<Either<CacheError, void>> {\n    try {\n      this.store.clear()\n      return success(undefined)\n    } catch (err) {\n      return error(new CacheError('Clear failed', { err }))\n    }\n  }\n\n  async invalidate(pattern: string): Promise<Either<CacheError, void>> {\n    try {\n      // Implement pattern matching...\n      return success(undefined)\n    } catch (err) {\n      return error(new CacheError('Invalidate failed', { pattern, err }))\n    }\n  }\n}\n```\n\n### Multiple DataManager Instances\n\n```typescript\n// API client with aggressive caching\nconst apiClient = new DataManager({\n  cache: new IndexedDBCache({ defaultTTL: 3600000 }),\n  rateLimiter: new TokenBucketLimiter({ capacity: 20, refillRate: 2 }),\n  logger: new ConsoleLogger()\n})\n\n// Real-time data with minimal caching\nconst realtimeClient = new DataManager({\n  cache: new MemoryCache({ maxSize: 50, defaultTTL: 5000 }),\n  rateLimiter: new ConcurrencyLimiter({ maxConcurrent: 10 }),\n  enableOptimisticUpdates: false\n})\n\n// Background sync with queue\nconst syncClient = new DataManager({\n  queue: new BrowserQueue({ storage: 'indexeddb' }),\n  rateLimiter: new AdaptiveRateLimiter({ initialRate: 5 })\n})\n```\n\n### Complex Data Dependencies\n\n```typescript\nconst getUserDashboard = async (userId: number) => {\n  // Fetch user profile\n  const userResult = await dm.query<User>(`user:${userId}`)\n    .staleTime(300000)\n    .fetch(() => fetchUser(userId))\n\n  if (isError(userResult)) {\n    return userResult\n  }\n\n  const user = userResult.data\n\n  // Fetch user's data in parallel\n  const [postsResult, settingsResult, notificationsResult] = await Promise.all([\n    dm.query<Post[]>(`user:${userId}:posts`)\n      .staleTime(60000)\n      .fetch(() => fetchUserPosts(userId)),\n    \n    dm.query<Settings>(`user:${userId}:settings`)\n      .staleTime(600000)\n      .fetch(() => fetchUserSettings(userId)),\n    \n    dm.query<Notification[]>(`user:${userId}:notifications`)\n      .staleTime(30000)\n      .fetch(() => fetchUserNotifications(userId))\n  ])\n\n  // Handle any errors\n  if (isError(postsResult)) return postsResult\n  if (isError(settingsResult)) return settingsResult\n  if (isError(notificationsResult)) return notificationsResult\n\n  return success({\n    user,\n    posts: postsResult.data,\n    settings: settingsResult.data,\n    notifications: notificationsResult.data\n  })\n}\n```\n\n## Error Handling\n\n### Error Types\n\nRa-ts provides specific error types for different scenarios:\n\n```typescript\nimport {\n  DataManagerError,\n  ValidationError,\n  NetworkError,\n  CacheError,\n  RateLimitError,\n  QueueError\n} from 'ra-ts'\n\nconst handleError = (error: any) => {\n  if (error instanceof ValidationError) {\n    console.error('Data validation failed:', error.message)\n  } else if (error instanceof NetworkError) {\n    console.error('Network request failed:', error.message)\n  } else if (error instanceof CacheError) {\n    console.error('Cache operation failed:', error.message)\n  } else if (error instanceof RateLimitError) {\n    console.error('Rate limit exceeded:', error.message)\n  } else if (error instanceof QueueError) {\n    console.error('Queue operation failed:', error.message)\n  }\n}\n```\n\n### Graceful Degradation\n\n```typescript\nconst getDataWithFallback = async <T>(\n  key: string,\n  fetcher: () => Promise<Either<any, T>>,\n  fallbackFetcher?: () => Promise<Either<any, T>>\n): Promise<Either<any, T>> => {\n  \n  // Try primary data source\n  const result = await dm.query<T>(key)\n    .retries(2)\n    .fetch(fetcher)\n\n  if (isSuccess(result)) {\n    return result\n  }\n\n  // Try fallback if available\n  if (fallbackFetcher) {\n    console.warn(`Primary fetch failed for ${key}, trying fallback`)\n    return dm.query<T>(`${key}:fallback`)\n      .retries(1)\n      .fetch(fallbackFetcher)\n  }\n\n  return result\n}\n```\n\n## Best Practices\n\n### 1. Cache Key Strategy\n\nUse consistent, hierarchical cache keys:\n\n```typescript\n// Good\nconst keys = {\n  user: (id: number) => `user:${id}`,\n  userPosts: (id: number) => `user:${id}:posts`,\n  userSettings: (id: number) => `user:${id}:settings`,\n  postComments: (postId: number) => `post:${postId}:comments`\n}\n\n// Invalidation patterns\nawait dm.mutate('user:123')\n  .invalidates('user:123:*') // Invalidates all user sub-resources\n  .execute(updateUser)\n```\n\n### 2. Error Boundaries\n\nWrap operations in try-catch for unexpected errors:\n\n```typescript\nconst safeQuery = async <T>(\n  key: string,\n  fetcher: () => Promise<Either<any, T>>\n): Promise<Either<any, T>> => {\n  try {\n    return await dm.query<T>(key).fetch(fetcher)\n  } catch (unexpectedError) {\n    console.error('Unexpected error:', unexpectedError)\n    return error(new DataManagerError(\n      'Unexpected error occurred',\n      'UNEXPECTED_ERROR',\n      { key, error: unexpectedError }\n    ))\n  }\n}\n```\n\n### 3. Resource Management\n\nClean up resources when done:\n\n```typescript\n// Clean up cache periodically\nconst cleanupCache = async () => {\n  if (dm._cache && 'cleanup' in dm._cache) {\n    const removed = await dm._cache.cleanup()\n    console.log(`Cleaned up ${removed} expired entries`)\n  }\n}\n\n// Run cleanup every 10 minutes\nsetInterval(cleanupCache, 600000)\n```\n\n### 4. Type Safety\n\nUse proper TypeScript types:\n\n```typescript\ninterface ApiResponse<T> {\n  data: T\n  status: 'success' | 'error'\n  message?: string\n}\n\nconst fetchTypedData = async <T>(\n  endpoint: string\n): Promise<Either<NetworkError, T>> => {\n  const response = await fetch(endpoint)\n  \n  if (!response.ok) {\n    return error(new NetworkError(`HTTP ${response.status}`))\n  }\n\n  const apiResponse: ApiResponse<T> = await response.json()\n  \n  if (apiResponse.status === 'error') {\n    return error(new NetworkError(apiResponse.message || 'API error'))\n  }\n\n  return success(apiResponse.data)\n}\n```\n\n### 5. Performance Optimization\n\nConfigure appropriate cache sizes and TTLs:\n\n```typescript\n// For frequently accessed, stable data\nconst staticDataManager = new DataManager({\n  cache: new IndexedDBCache({\n    defaultTTL: 86400000, // 24 hours\n    maxSize: 100 * 1024 * 1024 // 100MB\n  })\n})\n\n// For real-time, frequently changing data\nconst realtimeDataManager = new DataManager({\n  cache: new MemoryCache({\n    defaultTTL: 30000, // 30 seconds\n    maxSize: 100\n  }),\n  enableOptimisticUpdates: true\n})\n```","readmeFilename":"README.md","homepage":"https://github.com/bpwme/ra-ts#readme","keywords":["typescript","adapter","rate-limiting","caching","batching","streaming","request","http","middleware","composable"],"repository":{"type":"git","url":"git+https://github.com/bpwme/ra-ts.git"},"bugs":{"url":"https://github.com/bpwme/ra-ts/issues"}}