{"version":3,"file":"useSmartPrefetch.mjs","sources":["../../../src/lib/hooks/useSmartPrefetch.ts"],"sourcesContent":["/**\n * @file Smart Prefetching Utilities\n * @description Intelligent prefetching with network awareness and connection quality detection\n * for optimal performance. Pure TypeScript utilities without React dependencies.\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Connection quality type based on Network Information API\n */\nexport type ConnectionType = '4g' | '3g' | '2g' | 'slow-2g' | 'unknown';\n\n/**\n * Network information from the Navigator.connection API\n */\nexport interface NetworkInformation {\n  effectiveType?: ConnectionType;\n  downlink?: number;\n  rtt?: number;\n  saveData?: boolean;\n}\n\n/**\n * Navigator with connection property\n */\ninterface NavigatorWithConnection extends Navigator {\n  connection?: EventTarget & NetworkInformation;\n}\n\n/**\n * Configuration for a prefetch target\n */\nexport interface PrefetchTarget {\n  /** Query key for data prefetching */\n  queryKey: readonly unknown[];\n  /** Data fetcher function */\n  queryFn: () => Promise<unknown>;\n  /** Route module loader for code splitting */\n  moduleLoader?: () => Promise<unknown>;\n  /** Priority (higher = more important, 0-10) */\n  priority?: number;\n  /** Stale time for prefetched data (ms) */\n  staleTime?: number;\n}\n\n/**\n * Options for smart prefetch manager\n */\nexport interface SmartPrefetchOptions {\n  /** Skip prefetch on slow connections or data saver mode */\n  respectDataSaver?: boolean;\n  /** Max concurrent prefetches to avoid overwhelming network */\n  maxConcurrent?: number;\n  /** Minimum connection quality required for prefetching */\n  minConnectionQuality?: ConnectionType;\n}\n\n// ============================================================================\n// Network Quality Utilities\n// ============================================================================\n\n/**\n * Connection quality ranking for comparison\n */\nconst CONNECTION_QUALITY_RANK: Record<ConnectionType, number> = {\n  '4g': 4,\n  '3g': 3,\n  '2g': 2,\n  'slow-2g': 1,\n  unknown: 3, // Assume decent connection if unknown\n};\n\n/**\n * Get current network information\n */\nexport function getNetworkInfo(): NetworkInformation {\n  const navigator = globalThis.navigator as NavigatorWithConnection | undefined;\n  const connection = navigator?.connection;\n\n  return {\n    effectiveType: connection?.effectiveType ?? 'unknown',\n    downlink: connection?.downlink ?? Infinity,\n    rtt: connection?.rtt ?? 0,\n    saveData: connection?.saveData ?? false,\n  };\n}\n\n/**\n * Check if current connection meets minimum quality requirement\n */\nexport function meetsMinimumQuality(\n  current: ConnectionType,\n  minimum: ConnectionType\n): boolean {\n  return CONNECTION_QUALITY_RANK[current] >= CONNECTION_QUALITY_RANK[minimum];\n}\n\n/**\n * Check if prefetching should be allowed based on network conditions\n */\nexport function shouldAllowPrefetch(\n  options: {\n    respectDataSaver?: boolean;\n    minConnectionQuality?: ConnectionType;\n  } = {}\n): boolean {\n  const {\n    respectDataSaver = true,\n    minConnectionQuality = '2g',\n  } = options;\n\n  const networkInfo = getNetworkInfo();\n\n  // Respect data saver mode\n  if (respectDataSaver && networkInfo.saveData === true) {\n    return false;\n  }\n\n  // Check minimum connection quality\n  return meetsMinimumQuality(networkInfo.effectiveType ?? 'unknown', minConnectionQuality);\n\n\n}\n\n// ============================================================================\n// Smart Prefetch Manager\n// ============================================================================\n\n/**\n * Manages intelligent prefetching with network awareness and concurrency control\n */\nexport class SmartPrefetchManager {\n  private prefetchedKeys = new Set<string>();\n  private activePrefetches = 0;\n  private options: Required<SmartPrefetchOptions>;\n\n  constructor(options: SmartPrefetchOptions = {}) {\n    this.options = {\n      respectDataSaver: options.respectDataSaver ?? true,\n      maxConcurrent: options.maxConcurrent ?? 3,\n      minConnectionQuality: options.minConnectionQuality ?? '2g',\n    };\n  }\n\n  /**\n   * Execute prefetch for a target\n   */\n  async prefetch(target: PrefetchTarget): Promise<void> {\n    const key = JSON.stringify(target.queryKey);\n\n    // Skip if already prefetched\n    if (this.prefetchedKeys.has(key)) {\n      return;\n    }\n\n    // Check if we should prefetch\n    if (!this.shouldPrefetch()) {\n      return;\n    }\n\n    this.prefetchedKeys.add(key);\n    this.activePrefetches++;\n\n    try {\n      // Prefetch module code if provided (code splitting)\n      if (target.moduleLoader) {\n        target.moduleLoader().catch(() => {\n          // Silent fail for module prefetch - not critical\n        });\n      }\n\n      // Execute data fetch\n      await target.queryFn();\n    } catch {\n      // Remove from prefetched set on error to allow retry\n      this.prefetchedKeys.delete(key);\n    } finally {\n      this.activePrefetches--;\n    }\n  }\n\n  /**\n   * Prefetch multiple targets during idle time\n   */\n  prefetchOnIdle(targets: PrefetchTarget[]): void {\n    // Sort by priority (highest first)\n    const sorted = [...targets].sort(\n      (a, b) => (b.priority ?? 0) - (a.priority ?? 0)\n    );\n\n    if ('requestIdleCallback' in globalThis) {\n      sorted.forEach((target) => {\n        requestIdleCallback(\n          () => {\n            void this.prefetch(target);\n          },\n          { timeout: 5000 } // 5 second timeout\n        );\n      });\n    } else {\n      // Fallback: staggered setTimeout\n      sorted.forEach((target, index) => {\n        setTimeout(() => {\n          void this.prefetch(target);\n        }, 1000 + index * 200);\n      });\n    }\n  }\n\n  /**\n   * Clear prefetch cache (for testing or reset)\n   */\n  clearCache(): void {\n    this.prefetchedKeys.clear();\n  }\n\n  /**\n   * Get current prefetch stats\n   */\n  getStats(): {\n    prefetchedCount: number;\n    activeCount: number;\n    maxConcurrent: number;\n  } {\n    return {\n      prefetchedCount: this.prefetchedKeys.size,\n      activeCount: this.activePrefetches,\n      maxConcurrent: this.options.maxConcurrent,\n    };\n  }\n\n  /**\n   * Check if prefetching should happen based on network and concurrency\n   */\n  private shouldPrefetch(): boolean {\n    // Don't prefetch if too many active requests\n    if (this.activePrefetches >= this.options.maxConcurrent) {\n      return false;\n    }\n\n    return shouldAllowPrefetch({\n      respectDataSaver: this.options.respectDataSaver,\n      minConnectionQuality: this.options.minConnectionQuality,\n    });\n  }\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Helper to create type-safe prefetch configurations\n */\nexport function createPrefetchConfig<T>(\n  queryKey: readonly unknown[],\n  queryFn: () => Promise<T>,\n  options?: Omit<PrefetchTarget, 'queryKey' | 'queryFn'>\n): PrefetchTarget {\n  return {\n    queryKey,\n    queryFn,\n    ...options,\n  };\n}\n\n/**\n * Create a debounced prefetch function\n */\nexport function createDebouncedPrefetch(\n  manager: SmartPrefetchManager,\n  delay: number = 100\n): (target: PrefetchTarget) => void {\n  const timeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\n  return (target: PrefetchTarget) => {\n    const key = JSON.stringify(target.queryKey);\n\n    // Clear existing timeout\n    const existingTimeout = timeouts.get(key);\n    if (existingTimeout !== undefined && existingTimeout !== null) {\n      clearTimeout(existingTimeout);\n    }\n\n    // Set new timeout\n    const timeout = setTimeout(() => {\n      void manager.prefetch(target);\n      timeouts.delete(key);\n    }, delay);\n\n    timeouts.set(key, timeout);\n  };\n}\n\n/**\n * Monitor network quality changes\n */\nexport function monitorNetworkQuality(\n  callback: (info: NetworkInformation) => void\n): () => void {\n  const navigator = globalThis.navigator as NavigatorWithConnection | undefined;\n  const connection = navigator?.connection;\n\n  if (!connection) {\n    // Return no-op cleanup function\n    return () => {};\n  }\n\n  const handleChange = (): void => {\n    callback(getNetworkInfo());\n  };\n\n  connection.addEventListener('change', handleChange);\n\n  return () => {\n  connection.removeEventListener('change', handleChange);\n};\n}"],"names":["CONNECTION_QUALITY_RANK","getNetworkInfo","connection","meetsMinimumQuality","current","minimum","shouldAllowPrefetch","options","respectDataSaver","minConnectionQuality","networkInfo","SmartPrefetchManager","target","key","targets","sorted","a","b","index","createPrefetchConfig","queryKey","queryFn"],"mappings":"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"}