{"version":3,"file":"usePrefetchRoute.mjs","sources":["../../../src/lib/hooks/usePrefetchRoute.ts"],"sourcesContent":["/**\n * @file usePrefetchRoute Hook\n * @description Hook for prefetching route data and components\n */\n\nimport { useCallback, useRef, useEffect } from 'react';\nimport { useQueryClient } from '@tanstack/react-query';\n\n/**\n * Prefetch options\n */\nexport interface PrefetchOptions {\n  /** Delay before prefetching (ms) */\n  delay?: number;\n\n  /** Only prefetch on hover */\n  onHover?: boolean;\n\n  /** Stale time for prefetched data (ms) */\n  staleTime?: number;\n}\n\n/**\n * Route data loader function\n */\nexport type RouteDataLoader = () => Promise<unknown>;\n\n/**\n * Route prefetch configuration\n */\nexport interface RoutePrefetchConfig {\n  /** Query key for the route data */\n  queryKey: readonly unknown[];\n\n  /** Data loader function */\n  loader: RouteDataLoader;\n\n  /** Stale time override */\n  staleTime?: number;\n}\n\n/**\n * Hook for prefetching route data\n */\nexport function usePrefetchRoute(): {\n  prefetch: (config: RoutePrefetchConfig, options?: PrefetchOptions) => Promise<void>;\n  prefetchMany: (configs: RoutePrefetchConfig[], options?: PrefetchOptions) => Promise<void>;\n  createHoverHandlers: (\n    config: RoutePrefetchConfig,\n    options?: PrefetchOptions\n  ) => {\n    onMouseEnter: () => void;\n    onMouseLeave: () => void;\n    onFocus: () => void;\n  };\n  clearPrefetch: (queryKey: readonly unknown[]) => void;\n  clearAllPrefetch: () => void;\n} {\n  const queryClient = useQueryClient();\n  const prefetchedRoutes = useRef<Set<string>>(new Set());\n  // Track all active timeouts for cleanup on unmount\n  const activeTimeoutsRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n\n  // Cleanup all timeouts on unmount\n  useEffect(() => {\n    const timeouts = activeTimeoutsRef.current;\n    return () => {\n      timeouts.forEach((timeoutId) => clearTimeout(timeoutId));\n      timeouts.clear();\n    };\n  }, []);\n\n  /**\n   * Prefetch route data\n   */\n  const prefetch = useCallback(\n    async (config: RoutePrefetchConfig, options: PrefetchOptions = {}) => {\n      const { delay = 0, staleTime = 5 * 60 * 1000 } = options;\n      const routeKey = JSON.stringify(config.queryKey);\n\n      // Skip if already prefetched recently\n      if (prefetchedRoutes.current.has(routeKey)) {\n        return;\n      }\n\n      const doPrefetch = async (): Promise<void> => {\n        try {\n          await queryClient.prefetchQuery({\n            queryKey: config.queryKey,\n            queryFn: config.loader,\n            staleTime: config.staleTime ?? staleTime,\n          });\n\n          // Mark as prefetched\n          prefetchedRoutes.current.add(routeKey);\n\n          // Clear prefetched marker after stale time\n          const staleTimeoutId = setTimeout(() => {\n            prefetchedRoutes.current.delete(routeKey);\n            // Remove from active timeouts after completion\n            activeTimeoutsRef.current.delete(staleTimeoutId);\n          }, staleTime);\n          // Track timeout for cleanup\n          activeTimeoutsRef.current.add(staleTimeoutId);\n        } catch (error) {\n          // Silently fail prefetch - not critical\n          // Only log in development\n          if (process.env.NODE_ENV === 'development') {\n            console.info('Route prefetch failed:', error);\n          }\n        }\n      };\n\n      if (delay > 0) {\n        const delayTimeoutId = setTimeout(() => {\n          void doPrefetch();\n          // Remove from active timeouts after completion\n          activeTimeoutsRef.current.delete(delayTimeoutId);\n        }, delay);\n        // Track timeout for cleanup\n        activeTimeoutsRef.current.add(delayTimeoutId);\n      } else {\n        await doPrefetch();\n      }\n    },\n    [queryClient]\n  );\n\n  /**\n   * Prefetch multiple routes\n   */\n  const prefetchMany = useCallback(\n    async (configs: RoutePrefetchConfig[], options: PrefetchOptions = {}) => {\n      await Promise.all(configs.map(async (config) => prefetch(config, options)));\n    },\n    [prefetch]\n  );\n\n  /**\n   * Create hover prefetch handlers\n   */\n  const createHoverHandlers = useCallback(\n    (config: RoutePrefetchConfig, options: PrefetchOptions = {}) => {\n      let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n      return {\n        onMouseEnter: (): void => {\n          const delay = options.delay ?? 100;\n          timeoutId = setTimeout(() => {\n            void prefetch(config, { ...options, delay: 0 });\n          }, delay);\n        },\n        onMouseLeave: (): void => {\n          if (timeoutId !== null && timeoutId !== undefined) {\n            clearTimeout(timeoutId);\n            timeoutId = null;\n          }\n        },\n        onFocus: (): void => {\n          void prefetch(config, { ...options, delay: 0 });\n        },\n      };\n    },\n    [prefetch]\n  );\n\n  /**\n   * Clear prefetch cache for a route\n   */\n  const clearPrefetch = useCallback((queryKey: readonly unknown[]) => {\n    const routeKey = JSON.stringify(queryKey);\n    prefetchedRoutes.current.delete(routeKey);\n  }, []);\n\n  /**\n   * Clear all prefetch cache\n   */\n  const clearAllPrefetch = useCallback(() => {\n    prefetchedRoutes.current.clear();\n  }, []);\n\n  return {\n    prefetch,\n    prefetchMany,\n    createHoverHandlers,\n    clearPrefetch,\n    clearAllPrefetch,\n  };\n}\n\n/**\n * Hook for prefetching on link hover\n */\nexport function usePrefetchOnHover(\n  config: RoutePrefetchConfig,\n  options: PrefetchOptions = {}\n): {\n  onMouseEnter: () => void;\n  onMouseLeave: () => void;\n  onFocus: () => void;\n} {\n  const { createHoverHandlers } = usePrefetchRoute();\n  return createHoverHandlers(config, options);\n}\n"],"names":["usePrefetchRoute","queryClient","useQueryClient","prefetchedRoutes","useRef","activeTimeoutsRef","useEffect","timeouts","timeoutId","prefetch","useCallback","config","options","delay","staleTime","routeKey","doPrefetch","staleTimeoutId","error","delayTimeoutId","prefetchMany","configs","createHoverHandlers","clearPrefetch","queryKey","clearAllPrefetch","usePrefetchOnHover"],"mappings":"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"}