{"version":3,"file":"useRateLimitedState.cjs","names":["useRateLimiter"],"sources":["../../src/rate-limiter/useRateLimitedState.ts"],"sourcesContent":["import { useState } from 'react'\nimport { useRateLimiter } from './useRateLimiter'\nimport type {\n  ReactRateLimiter,\n  ReactRateLimiterOptions,\n} from './useRateLimiter'\nimport type { RateLimiterState } from '@tanstack/pacer/rate-limiter'\n\n/**\n * A React hook that creates a rate-limited state value that enforces a hard limit on state updates within a time window.\n * This hook combines React's useState with rate limiting functionality to provide controlled state updates.\n *\n * Rate limiting is a simple \"hard limit\" approach - it allows all updates until the limit is reached, then blocks\n * subsequent updates until the window resets. Unlike throttling or debouncing, it does not attempt to space out\n * or intelligently collapse updates. This can lead to bursts of rapid updates followed by periods of no updates.\n *\n * The rate limiter supports two types of windows:\n * - 'fixed': A strict window that resets after the window period. All updates within the window count\n *   towards the limit, and the window resets completely after the period.\n * - 'sliding': A rolling window that allows updates as old ones expire. This provides a more\n *   consistent rate of updates over time.\n *\n * For smoother update patterns, consider:\n * - useThrottledState: When you want consistent spacing between updates (e.g. UI changes)\n * - useDebouncedState: When you want to collapse rapid updates into a single update (e.g. search input)\n *\n * Rate limiting should primarily be used when you need to enforce strict limits, like API rate limits.\n *\n * The hook returns a tuple containing:\n * - The rate-limited state value\n * - A rate-limited setter function that respects the configured limits\n * - The rateLimiter instance for additional control\n *\n * For more direct control over rate limiting without state management,\n * consider using the lower-level useRateLimiter hook instead.\n *\n * ## State Management and Selector\n *\n * The hook uses TanStack Store for reactive state management via the underlying rate limiter instance.\n * The `selector` parameter allows you to specify which rate limiter state changes will trigger a re-render,\n * optimizing performance by preventing unnecessary re-renders when irrelevant state changes occur.\n *\n * **By default, there will be no reactive state subscriptions** and you must opt-in to state\n * tracking by providing a selector function. This prevents unnecessary re-renders and gives you\n * full control over when your component updates. Only when you provide a selector will the\n * component re-render when the selected state values change.\n *\n * Available rate limiter state properties:\n * - `executionCount`: Number of function executions that have been completed\n * - `executionTimes`: Array of timestamps when executions occurred for rate limiting calculations\n * - `rejectionCount`: Number of function executions that have been rejected due to rate limiting\n *\n * @example\n * ```tsx\n * // Default behavior - no reactive state subscriptions\n * const [value, setValue, rateLimiter] = useRateLimitedState(0, {\n *   limit: 5,\n *   window: 60000,\n *   windowType: 'sliding'\n * });\n *\n * // Opt-in to re-render when execution count changes (optimized for tracking successful updates)\n * const [value, setValue, rateLimiter] = useRateLimitedState(\n *   0,\n *   { limit: 5, window: 60000, windowType: 'sliding' },\n *   (state) => ({ executionCount: state.executionCount })\n * );\n *\n * // Opt-in to re-render when rejection count changes (optimized for tracking rate limit violations)\n * const [value, setValue, rateLimiter] = useRateLimitedState(\n *   0,\n *   { limit: 5, window: 60000, windowType: 'sliding' },\n *   (state) => ({ rejectionCount: state.rejectionCount })\n * );\n *\n * // Opt-in to re-render when execution times change (optimized for window calculations)\n * const [value, setValue, rateLimiter] = useRateLimitedState(\n *   0,\n *   { limit: 5, window: 60000, windowType: 'sliding' },\n *   (state) => ({ executionTimes: state.executionTimes })\n * );\n *\n * // With rejection callback and fixed window\n * const [value, setValue] = useRateLimitedState(0, {\n *   limit: 3,\n *   window: 5000,\n *   windowType: 'fixed',\n *   onReject: (rateLimiter) => {\n *     alert(`Rate limit reached. Try again in ${rateLimiter.getMsUntilNextWindow()}ms`);\n *   }\n * });\n *\n * // Access rateLimiter methods if needed\n * const handleSubmit = () => {\n *   const remaining = rateLimiter.getRemainingInWindow();\n *   if (remaining > 0) {\n *     setValue(newValue);\n *   } else {\n *     showRateLimitWarning();\n *   }\n * };\n *\n * // Access the selected rate limiter state (will be empty object {} unless selector provided)\n * const { executionCount, rejectionCount } = rateLimiter.state;\n * ```\n */\nexport function useRateLimitedState<TValue, TSelected = RateLimiterState>(\n  value: TValue,\n  options: ReactRateLimiterOptions<\n    React.Dispatch<React.SetStateAction<TValue>>,\n    TSelected\n  >,\n  selector?: (state: RateLimiterState) => TSelected,\n): [\n  TValue,\n  React.Dispatch<React.SetStateAction<TValue>>,\n  ReactRateLimiter<React.Dispatch<React.SetStateAction<TValue>>, TSelected>,\n] {\n  const [rateLimitedValue, setRateLimitedValue] = useState(value)\n  const rateLimiter = useRateLimiter(setRateLimitedValue, options, selector)\n  return [rateLimitedValue, rateLimiter.maybeExecute, rateLimiter]\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0GA,SAAgB,oBACd,OACA,SAIA,UAKA;CACA,MAAM,CAAC,kBAAkB,2CAAgC,MAAM;CAC/D,MAAM,cAAcA,sCAAe,qBAAqB,SAAS,SAAS;AAC1E,QAAO;EAAC;EAAkB,YAAY;EAAc;EAAY"}