{"version":3,"file":"data-loader-batching.mjs","sources":["../../../src/lib/services/data-loader-batching.ts"],"sourcesContent":["/**\n * @file DataLoader Batching\n * @description DataLoader-inspired request batching with automatic coalescing,\n * caching, deduplication, and GraphQL batch query support.\n * Optimized for microservices with N+1 query prevention.\n */\n\nimport { defer, type Deferred } from '../shared/async-utils';\n\n// =============================================================================\n// TYPE DEFINITIONS\n// =============================================================================\n\n/**\n * Batch function that processes multiple keys at once\n */\nexport type BatchFunction<K, V> = (keys: K[]) => Promise<Map<K, V> | V[] | (V | Error)[]>;\n\n/**\n * Cache key serializer\n */\nexport type KeySerializer<K> = (key: K) => string;\n\n/**\n * DataLoader configuration\n */\nexport interface DataLoaderConfig<K, V> {\n  /** Maximum items per batch */\n  maxBatchSize?: number;\n  /** Maximum wait time before executing batch (ms) */\n  batchInterval?: number;\n  /** Batch execution function */\n  batchFn: BatchFunction<K, V>;\n  /** Enable caching */\n  cache?: boolean;\n  /** Cache TTL (ms) */\n  cacheTtl?: number;\n  /** Key serializer for cache */\n  keySerializer?: KeySerializer<K>;\n  /** Handle batch errors */\n  onBatchError?: (error: Error, keys: K[]) => void;\n  /** Handle individual item errors */\n  onItemError?: (error: Error, key: K) => void;\n  /** Enable coalescing of identical requests */\n  coalesce?: boolean;\n  /** Schedule batch on next tick */\n  batchScheduler?: (callback: () => void) => ReturnType<typeof setTimeout>;\n}\n\n/**\n * Cache entry\n */\ninterface CacheEntry<V> {\n  value: V;\n  expiresAt: number;\n}\n\n/**\n * Pending request entry\n */\ninterface PendingRequest<K, V> {\n  key: K;\n  deferred: Deferred<V>;\n}\n\n/**\n * DataLoader statistics\n */\nexport interface DataLoaderStats {\n  /** Total loads requested */\n  totalLoads: number;\n  /** Cache hits */\n  cacheHits: number;\n  /** Cache misses */\n  cacheMisses: number;\n  /** Batches executed */\n  batchesExecuted: number;\n  /** Average batch size */\n  avgBatchSize: number;\n  /** Coalesced requests */\n  coalescedRequests: number;\n  /** Current cache size */\n  cacheSize: number;\n}\n\n// =============================================================================\n// DATALOADER IMPLEMENTATION\n// =============================================================================\n\n/**\n * DataLoader for batching and caching requests\n * Inspired by Facebook's DataLoader pattern\n */\nexport class DataLoader<K, V> {\n  private config: Required<DataLoaderConfig<K, V>>;\n  private batch: Map<string, PendingRequest<K, V>> = new Map();\n  private cache: Map<string, CacheEntry<V>> = new Map();\n  private batchTimer: ReturnType<typeof setTimeout> | null = null;\n  private cacheCleanupTimer: ReturnType<typeof setInterval> | null = null;\n  private stats: DataLoaderStats = {\n    totalLoads: 0,\n    cacheHits: 0,\n    cacheMisses: 0,\n    batchesExecuted: 0,\n    avgBatchSize: 0,\n    coalescedRequests: 0,\n    cacheSize: 0,\n  };\n\n  constructor(config: DataLoaderConfig<K, V>) {\n    this.config = {\n      maxBatchSize: config.maxBatchSize ?? 50,\n      batchInterval: config.batchInterval ?? 16, // ~1 frame\n      batchFn: config.batchFn,\n      cache: config.cache ?? true,\n      cacheTtl: config.cacheTtl ?? 60000, // 1 minute\n      keySerializer: config.keySerializer ?? ((k) => JSON.stringify(k)),\n      onBatchError: config.onBatchError ?? console.error,\n      onItemError: config.onItemError ?? console.error,\n      coalesce: config.coalesce ?? true,\n      batchScheduler: config.batchScheduler ?? ((cb) => setTimeout(cb, this.config.batchInterval)),\n    };\n\n    // Schedule automatic cache cleanup when caching is enabled\n    if (this.config.cache) {\n      this.cacheCleanupTimer = setInterval(() => this.clearExpired(), 30000);\n    }\n  }\n\n  /**\n   * Dispose of the loader and clean up resources\n   */\n  dispose(): void {\n    if (this.batchTimer !== null) {\n      clearTimeout(this.batchTimer);\n      this.batchTimer = null;\n    }\n    if (this.cacheCleanupTimer !== null) {\n      clearInterval(this.cacheCleanupTimer);\n      this.cacheCleanupTimer = null;\n    }\n    this.clearAll();\n    this.batch.clear();\n  }\n\n  /**\n   * Load a single value by key\n   */\n  async load(key: K): Promise<V> {\n    const serializedKey = this.config.keySerializer(key);\n    this.stats.totalLoads++;\n\n    // Check cache first\n    if (this.config.cache) {\n      const cached = this.cache.get(serializedKey);\n      if (cached && cached.expiresAt > Date.now()) {\n        this.stats.cacheHits++;\n        return cached.value;\n      }\n      this.stats.cacheMisses++;\n    }\n\n    // Check if already in current batch (coalescing)\n    if (this.config.coalesce) {\n      const existing = this.batch.get(serializedKey);\n      if (existing) {\n        this.stats.coalescedRequests++;\n        return existing.deferred.promise;\n      }\n    }\n\n    // Add to batch\n    const deferred = defer<V>();\n    this.batch.set(serializedKey, { key, deferred });\n\n    // Schedule batch execution\n    this.scheduleBatch();\n\n    // Check if batch is full\n    if (this.batch.size >= this.config.maxBatchSize) {\n      void this.executeBatch();\n    }\n\n    return deferred.promise;\n  }\n\n  /**\n   * Load multiple values by keys\n   */\n  async loadMany(keys: K[]): Promise<(V | Error)[]> {\n    return Promise.all(keys.map(async (key) => this.load(key).catch((error: Error) => error)));\n  }\n\n  /**\n   * Prime the cache with a value\n   */\n  prime(key: K, value: V): this {\n    const serializedKey = this.config.keySerializer(key);\n    this.cache.set(serializedKey, {\n      value,\n      expiresAt: Date.now() + this.config.cacheTtl,\n    });\n    this.stats.cacheSize = this.cache.size;\n    return this;\n  }\n\n  /**\n   * Prime multiple values\n   */\n  primeMany(entries: Array<[K, V]>): this {\n    for (const [key, value] of entries) {\n      this.prime(key, value);\n    }\n    return this;\n  }\n\n  /**\n   * Clear a specific key from cache\n   */\n  clear(key: K): this {\n    const serializedKey = this.config.keySerializer(key);\n    this.cache.delete(serializedKey);\n    this.stats.cacheSize = this.cache.size;\n    return this;\n  }\n\n  /**\n   * Clear multiple keys from cache\n   */\n  clearMany(keys: K[]): this {\n    for (const key of keys) {\n      this.clear(key);\n    }\n    return this;\n  }\n\n  /**\n   * Clear all cached values\n   */\n  clearAll(): this {\n    this.cache.clear();\n    this.stats.cacheSize = 0;\n    return this;\n  }\n\n  /**\n   * Clear expired cache entries\n   */\n  clearExpired(): this {\n    const now = Date.now();\n    for (const [key, entry] of this.cache.entries()) {\n      if (entry.expiresAt <= now) {\n        this.cache.delete(key);\n      }\n    }\n    this.stats.cacheSize = this.cache.size;\n    return this;\n  }\n\n  /**\n   * Get loader statistics\n   */\n  getStats(): DataLoaderStats {\n    return {\n      ...this.stats,\n      cacheSize: this.cache.size,\n    };\n  }\n\n  /**\n   * Reset statistics\n   */\n  resetStats(): this {\n    this.stats = {\n      totalLoads: 0,\n      cacheHits: 0,\n      cacheMisses: 0,\n      batchesExecuted: 0,\n      avgBatchSize: 0,\n      coalescedRequests: 0,\n      cacheSize: this.cache.size,\n    };\n    return this;\n  }\n\n  /**\n   * Schedule batch execution\n   */\n  private scheduleBatch(): void {\n    if (this.batchTimer !== null) return;\n\n    this.batchTimer = this.config.batchScheduler(() => {\n      this.batchTimer = null;\n      void this.executeBatch();\n    });\n  }\n\n  /**\n   * Execute the current batch\n   */\n  private async executeBatch(): Promise<void> {\n    // Clear timer\n    if (this.batchTimer !== null) {\n      clearTimeout(this.batchTimer);\n      this.batchTimer = null;\n    }\n\n    if (this.batch.size === 0) return;\n\n    // Capture current batch\n    const currentBatch = new Map(this.batch);\n    this.batch.clear();\n\n    const entries = Array.from(currentBatch.values());\n    const keys = entries.map(({ key }) => key);\n\n    // Update stats\n    this.stats.batchesExecuted++;\n    this.stats.avgBatchSize =\n      (this.stats.avgBatchSize * (this.stats.batchesExecuted - 1) + keys.length) / this.stats.batchesExecuted;\n\n    try {\n      const results = await this.config.batchFn(keys);\n\n      // Process results\n      if (results instanceof Map) {\n        this.processMapResults(currentBatch, results);\n      } else if (Array.isArray(results)) {\n        this.processArrayResults(currentBatch, keys, results);\n      }\n    } catch (error) {\n      this.config.onBatchError(error as Error, keys);\n\n      // Reject all pending requests\n      for (const [, { deferred }] of currentBatch) {\n        deferred.reject(error as Error);\n      }\n    }\n  }\n\n  /**\n   * Process Map results from batch function\n   */\n  private processMapResults(batch: Map<string, PendingRequest<K, V>>, results: Map<K, V>): void {\n    for (const [serializedKey, { key, deferred }] of batch) {\n      const value = results.get(key);\n      if (value !== undefined) {\n        // Cache the result\n        if (this.config.cache) {\n          this.cache.set(serializedKey, {\n            value,\n            expiresAt: Date.now() + this.config.cacheTtl,\n          });\n        }\n        deferred.resolve(value);\n      } else {\n        const error = new Error(`No result for key: ${serializedKey}`);\n        this.config.onItemError(error, key);\n        deferred.reject(error);\n      }\n    }\n    this.stats.cacheSize = this.cache.size;\n  }\n\n  /**\n   * Process Array results from batch function\n   */\n  private processArrayResults(\n    batch: Map<string, PendingRequest<K, V>>,\n    _keys: K[],\n    results: V[] | (V | Error)[]\n  ): void {\n    let i = 0;\n    for (const [serializedKey, { key, deferred }] of batch) {\n      if (i < results.length) {\n        const result = results[i];\n\n        if (result instanceof Error) {\n          this.config.onItemError(result, key);\n          deferred.reject(result);\n        } else if (result !== undefined) {\n          // Cache the result\n          if (this.config.cache) {\n            this.cache.set(serializedKey, {\n              value: result,\n              expiresAt: Date.now() + this.config.cacheTtl,\n            });\n          }\n          deferred.resolve(result);\n        } else {\n          const error = new Error(`Result at index ${i} is undefined`);\n          this.config.onItemError(error, key);\n          deferred.reject(error);\n        }\n      } else {\n        const error = new Error('Result array too short');\n        this.config.onItemError(error, key);\n        deferred.reject(error);\n      }\n      i++;\n    }\n    this.stats.cacheSize = this.cache.size;\n  }\n}\n\n// =============================================================================\n// REQUEST DEDUPLICATOR\n// =============================================================================\n\n/**\n * Request deduplication configuration\n */\nexport interface DeduplicatorConfig {\n  /** Deduplication window (ms) */\n  window?: number;\n  /** Key generator for requests */\n  getKey?: (url: string, options?: RequestInit) => string;\n}\n\n/**\n * In-flight request entry\n */\ninterface InFlightRequest<T> {\n  promise: Promise<T>;\n  timestamp: number;\n}\n\n/**\n * Request deduplicator for preventing duplicate concurrent requests\n */\nexport class RequestDeduplicator {\n  private inFlight: Map<string, InFlightRequest<unknown>> = new Map();\n  private config: Required<DeduplicatorConfig>;\n\n  constructor(config: DeduplicatorConfig = {}) {\n    this.config = {\n      window: config.window ?? 100,\n      getKey:\n        config.getKey ??\n        ((url, options) => {\n          const method =\n            options?.method !== null && options?.method !== undefined && options?.method !== ''\n              ? options.method\n              : 'GET';\n          const body =\n            options?.body !== null && options?.body !== undefined\n              ? JSON.stringify(options.body)\n              : '';\n          return `${method}:${url}:${body}`;\n        }),\n    };\n  }\n\n  /**\n   * Execute request with deduplication\n   */\n  async execute<T>(key: string, requestFn: () => Promise<T>): Promise<T> {\n    const existing = this.inFlight.get(key);\n\n    if (existing) {\n      const age = Date.now() - existing.timestamp;\n      if (age < this.config.window) {\n        return existing.promise as Promise<T>;\n      }\n    }\n\n    const promise = requestFn();\n    this.inFlight.set(key, {\n      promise,\n      timestamp: Date.now(),\n    });\n\n    try {\n      return await promise;\n    } finally {\n      // Clean up after request completes (with slight delay for coalescing)\n      setTimeout(() => {\n        this.inFlight.delete(key);\n      }, this.config.window);\n    }\n  }\n\n  /**\n   * Execute fetch with deduplication\n   *\n   * Note: This method intentionally uses raw fetch() rather than apiClient because:\n   * 1. This is a low-level utility that wraps the fetch API for deduplication\n   * 2. Users may want to use this with non-API endpoints\n   * 3. The apiClient already has its own deduplication built-in\n   *\n   * For API calls, prefer using apiClient directly which provides retry,\n   * authentication, and error handling out of the box.\n   *\n   * @see {@link @/lib/api/api-client} for the recommended API client\n   */\n  async fetch<T>(url: string, options?: RequestInit): Promise<T> {\n    const key = this.config.getKey(url, options);\n    return this.execute(key, async () => {\n      // Raw fetch is intentional here - this is a generic deduplication wrapper\n      const response = await fetch(url, options);\n      if (!response.ok) {\n        throw new Error(`Request failed: ${response.status}`);\n      }\n      return (await response.json()) as T;\n    });\n  }\n\n  /**\n   * Clear all in-flight requests\n   */\n  clear(): void {\n    this.inFlight.clear();\n  }\n\n  /**\n   * Get deduplication statistics\n   */\n  getStats(): { inFlight: number } {\n    return { inFlight: this.inFlight.size };\n  }\n}\n\n// =============================================================================\n// GRAPHQL BATCHER\n// =============================================================================\n\n/**\n * GraphQL operation\n */\nexport interface GraphQLOperation {\n  id: string;\n  query: string;\n  variables?: Record<string, unknown> | undefined;\n  operationName?: string | undefined;\n}\n\n/**\n * GraphQL batch response\n */\nexport interface GraphQLBatchResponse {\n  id: string;\n  data?: unknown;\n  errors?: Array<{ message: string; path?: Array<string | number> }>;\n}\n\n/**\n * GraphQL batcher configuration\n */\nexport interface GraphQLBatcherConfig {\n  /** GraphQL endpoint */\n  endpoint: string;\n  /** Maximum batch size */\n  maxBatchSize?: number;\n  /** Batch interval (ms) */\n  batchInterval?: number;\n  /** Request headers */\n  headers?: Record<string, string>;\n  /** Fetch function */\n  fetchFn?: typeof fetch;\n}\n\n/**\n * GraphQL request batcher\n */\nexport class GraphQLBatcher {\n  private queries: Array<{\n    operation: GraphQLOperation;\n    deferred: Deferred<unknown>;\n  }> = [];\n  private batchTimer: ReturnType<typeof setTimeout> | null = null;\n  private config: Required<GraphQLBatcherConfig>;\n\n  constructor(config: GraphQLBatcherConfig) {\n    this.config = {\n      endpoint: config.endpoint,\n      maxBatchSize: config.maxBatchSize ?? 10,\n      batchInterval: config.batchInterval ?? 10,\n      headers: config.headers ?? {},\n      fetchFn: config.fetchFn ?? fetch.bind(window),\n    };\n  }\n\n  /**\n   * Execute a GraphQL query\n   */\n  async query<T>(query: string, variables?: Record<string, unknown>, operationName?: string): Promise<T> {\n    const operation: GraphQLOperation = {\n      id: crypto.randomUUID(),\n      query,\n      variables,\n      operationName,\n    };\n\n    const deferred = defer<T>();\n    this.queries.push({\n      operation,\n      deferred: deferred as Deferred<unknown>,\n    });\n\n    this.scheduleBatch();\n\n    if (this.queries.length >= this.config.maxBatchSize) {\n      void this.executeBatch();\n    }\n\n    return deferred.promise;\n  }\n\n  /**\n   * Execute a GraphQL mutation (not batched by default)\n   */\n  async mutate<T>(mutation: string, variables?: Record<string, unknown>, operationName?: string): Promise<T> {\n    const response = await this.config.fetchFn(this.config.endpoint, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        ...this.config.headers,\n      },\n      body: JSON.stringify({\n        query: mutation,\n        variables,\n        operationName,\n      }),\n    });\n\n    if (!response.ok) {\n      throw new Error(`GraphQL mutation failed: ${response.status}`);\n    }\n\n    const result = await response.json() as { data?: T; errors?: Array<{ message: string }> };\n\n    if (result.errors !== null && result.errors !== undefined && result.errors.length > 0) {\n      throw new Error(result.errors.map((e: { message: string }) => e.message).join(', '));\n    }\n\n    return result.data as T;\n  }\n\n  /**\n   * Flush pending queries immediately\n   */\n  async flush(): Promise<void> {\n    await this.executeBatch();\n  }\n\n  /**\n   * Schedule batch execution\n   */\n  private scheduleBatch(): void {\n    if (this.batchTimer !== null) return;\n\n    this.batchTimer = setTimeout(() => {\n      this.batchTimer = null;\n      void this.executeBatch();\n    }, this.config.batchInterval);\n  }\n\n  /**\n   * Execute batched queries\n   */\n  private async executeBatch(): Promise<void> {\n    if (this.batchTimer !== null) {\n      clearTimeout(this.batchTimer);\n      this.batchTimer = null;\n    }\n\n    if (this.queries.length === 0) return;\n\n    const currentBatch = [...this.queries];\n    this.queries = [];\n\n    // Build batched query\n    const batchedQueries = currentBatch.map(({ operation }) => ({\n      id: operation.id,\n      query: operation.query,\n      variables: operation.variables,\n      operationName: operation.operationName,\n    }));\n\n    try {\n      const response = await this.config.fetchFn(this.config.endpoint, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          ...this.config.headers,\n        },\n        body: JSON.stringify(batchedQueries),\n      });\n\n      if (!response.ok) {\n        throw new Error(`GraphQL batch request failed: ${response.status}`);\n      }\n\n      const results = await response.json() as GraphQLBatchResponse[];\n\n      // Resolve individual queries\n      for (const result of results) {\n        const query = currentBatch.find((q) => q.operation.id === result.id);\n        if (query !== null && query !== undefined) {\n          if (result.errors !== null && result.errors !== undefined && result.errors.length > 0) {\n            query.deferred.reject(new Error(result.errors.map((e) => e.message).join(', ')));\n          } else {\n            query.deferred.resolve(result.data);\n          }\n        }\n      }\n    } catch (error) {\n      // Reject all queries in batch\n      for (const { deferred } of currentBatch) {\n        deferred.reject(error as Error);\n      }\n    }\n  }\n}\n\n// =============================================================================\n// FACTORY FUNCTIONS\n// =============================================================================\n\n/**\n * Create a DataLoader for fetching resources by ID\n */\nexport function createResourceLoader<T extends { id: string }>(\n  fetchMany: (ids: string[]) => Promise<T[]>,\n  config?: Partial<DataLoaderConfig<string, T>>\n): DataLoader<string, T> {\n  return new DataLoader<string, T>({\n    maxBatchSize: config?.maxBatchSize ?? 100,\n    batchInterval: config?.batchInterval ?? 16,\n    cache: config?.cache ?? true,\n    cacheTtl: config?.cacheTtl ?? 60000,\n    batchFn: async (ids) => {\n      const resources = await fetchMany(ids);\n      return new Map(resources.map((r) => [r.id, r]));\n    },\n    ...config,\n  });\n}\n\n/**\n * Create a DataLoader with automatic key serialization\n */\nexport function createKeyedLoader<K extends Record<string, unknown>, V>(\n  batchFn: (keys: K[]) => Promise<Map<K, V> | V[]>,\n  config?: Partial<DataLoaderConfig<K, V>>\n): DataLoader<K, V> {\n  return new DataLoader<K, V>({\n    batchFn,\n    keySerializer: (key) => JSON.stringify(key),\n    ...config,\n  });\n}\n\n// =============================================================================\n// GLOBAL INSTANCES\n// =============================================================================\n\n/**\n * Global request deduplicator\n */\nexport const globalDeduplicator = new RequestDeduplicator();\n\n/**\n * Deduplicated fetch function\n */\nexport async function deduplicatedFetch<T>(url: string, options?: RequestInit): Promise<T> {\n  return globalDeduplicator.fetch<T>(url, options);\n}\n"],"names":["DataLoader","config","k","cb","key","serializedKey","cached","existing","deferred","defer","keys","error","value","entries","now","entry","currentBatch","results","batch","_keys","i","result","RequestDeduplicator","url","options","method","body","requestFn","promise","response","GraphQLBatcher","query","variables","operationName","operation","mutation","e","batchedQueries","q","createResourceLoader","fetchMany","ids","resources","r","createKeyedLoader","batchFn","globalDeduplicator","deduplicatedFetch"],"mappings":"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"}