diff --git a/docs/framework/react/reference/functions/pacerprovider.md b/docs/framework/react/reference/functions/pacerprovider.md new file mode 100644 index 00000000..29b75d66 --- /dev/null +++ b/docs/framework/react/reference/functions/pacerprovider.md @@ -0,0 +1,24 @@ +--- +id: PacerProvider +title: PacerProvider +--- + + + +# Function: PacerProvider() + +```ts +function PacerProvider(__namedParameters): Element +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:46](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L46) + +## Parameters + +### \_\_namedParameters + +[`PacerProviderProps`](../../interfaces/pacerproviderprops.md) + +## Returns + +`Element` diff --git a/docs/framework/react/reference/functions/useasyncbatcher.md b/docs/framework/react/reference/functions/useasyncbatcher.md index c06c3070..11761a87 100644 --- a/docs/framework/react/reference/functions/useasyncbatcher.md +++ b/docs/framework/react/reference/functions/useasyncbatcher.md @@ -14,7 +14,7 @@ function useAsyncBatcher( selector): ReactAsyncBatcher ``` -Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:167](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts#L167) +Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:168](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts#L168) A React hook that creates an `AsyncBatcher` instance for managing asynchronous batches of items. diff --git a/docs/framework/react/reference/functions/useasyncdebouncer.md b/docs/framework/react/reference/functions/useasyncdebouncer.md index 696a696e..54fb45ac 100644 --- a/docs/framework/react/reference/functions/useasyncdebouncer.md +++ b/docs/framework/react/reference/functions/useasyncdebouncer.md @@ -14,7 +14,7 @@ function useAsyncDebouncer( selector): ReactAsyncDebouncer ``` -Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:149](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts#L149) +Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:150](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts#L150) A low-level React hook that creates an `AsyncDebouncer` instance to delay execution of an async function. diff --git a/docs/framework/react/reference/functions/useasyncqueuer.md b/docs/framework/react/reference/functions/useasyncqueuer.md index 96329a26..7e86e10b 100644 --- a/docs/framework/react/reference/functions/useasyncqueuer.md +++ b/docs/framework/react/reference/functions/useasyncqueuer.md @@ -14,7 +14,7 @@ function useAsyncQueuer( selector): ReactAsyncQueuer ``` -Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:167](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts#L167) +Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:168](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts#L168) A lower-level React hook that creates an `AsyncQueuer` instance for managing an async queue of items. diff --git a/docs/framework/react/reference/functions/useasyncratelimiter.md b/docs/framework/react/reference/functions/useasyncratelimiter.md index 0d6a2fbe..b209c15f 100644 --- a/docs/framework/react/reference/functions/useasyncratelimiter.md +++ b/docs/framework/react/reference/functions/useasyncratelimiter.md @@ -14,7 +14,7 @@ function useAsyncRateLimiter( selector): ReactAsyncRateLimiter ``` -Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:178](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts#L178) +Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:179](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts#L179) A low-level React hook that creates an `AsyncRateLimiter` instance to limit how many times an async function can execute within a time window. diff --git a/docs/framework/react/reference/functions/useasyncretryer.md b/docs/framework/react/reference/functions/useasyncretryer.md new file mode 100644 index 00000000..2b8a58be --- /dev/null +++ b/docs/framework/react/reference/functions/useasyncretryer.md @@ -0,0 +1,165 @@ +--- +id: useAsyncRetryer +title: useAsyncRetryer +--- + + + +# Function: useAsyncRetryer() + +```ts +function useAsyncRetryer( + fn, + options, +selector): ReactAsyncRetryer +``` + +Defined in: [react-pacer/src/async-retryer/useAsyncRetryer.ts:152](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-retryer/useAsyncRetryer.ts#L152) + +A low-level React hook that creates an `AsyncRetryer` instance to retry execution of an async function. + +This hook is designed to be flexible and state-management agnostic - it simply returns a retryer instance that +you can integrate with any state management solution (useState, Redux, Zustand, Jotai, etc). + +Async retrying automatically re-executes a failed async function up to a specified number of attempts with +configurable backoff strategies. This is useful for handling transient errors like network failures, temporary +server issues, or rate limiting where you want to automatically retry the operation. + +Error Handling: +- If an `onError` handler is provided, it will be called for every error during execution +- If an `onLastError` handler is provided, it will be called only for the final error after all retries fail +- If `throwOnError` is 'last' (default), only the final error after all retries will be thrown +- If `throwOnError` is true, every error will be thrown immediately (disables retrying) +- If `throwOnError` is false, errors are never thrown and undefined is returned instead + +## State Management and Selector + +The hook uses TanStack Store for reactive state management. The `selector` parameter allows you +to specify which state changes will trigger a re-render, optimizing performance by preventing +unnecessary re-renders when irrelevant state changes occur. + +**By default, there will be no reactive state subscriptions** and you must opt-in to state +tracking by providing a selector function. This prevents unnecessary re-renders and gives you +full control over when your component updates. Only when you provide a selector will the +component re-render when the selected state values change. + +Available state properties: +- `currentAttempt`: The current retry attempt number (0 when not executing) +- `executionCount`: Total number of completed executions (successful or failed) +- `isExecuting`: Whether the retryer is currently executing the function +- `lastError`: The most recent error encountered during execution +- `lastExecutionTime`: Timestamp of the last execution completion in milliseconds +- `lastResult`: The result from the most recent successful execution +- `status`: Current execution status ('disabled' | 'idle' | 'executing' | 'retrying') +- `totalExecutionTime`: Total time spent executing (including retries) in milliseconds + +## Type Parameters + +• **TFn** *extends* `AnyAsyncFunction` + +• **TSelected** = \{\} + +## Parameters + +### fn + +`TFn` + +### options + +`AsyncRetryerOptions`\<`TFn`\> + +### selector + +(`state`) => `TSelected` + +## Returns + +[`ReactAsyncRetryer`](../../interfaces/reactasyncretryer.md)\<`TFn`, `TSelected`\> + +## Example + +```tsx +// Default behavior - no reactive state subscriptions +const apiRetryer = useAsyncRetryer( + async (userId: string) => { + const response = await fetch(`/api/users/${userId}`); + if (!response.ok) throw new Error('Failed to fetch user'); + return response.json(); + }, + { maxAttempts: 3, backoff: 'exponential' } +); + +// Opt-in to re-render when execution state changes (optimized for loading indicators) +const apiRetryer = useAsyncRetryer( + async (userId: string) => { + const response = await fetch(`/api/users/${userId}`); + if (!response.ok) throw new Error('Failed to fetch user'); + return response.json(); + }, + { maxAttempts: 3, backoff: 'exponential' }, + (state) => ({ + isExecuting: state.isExecuting, + currentAttempt: state.currentAttempt + }) +); + +// Opt-in to re-render when results are available (optimized for data display) +const apiRetryer = useAsyncRetryer( + async (userId: string) => { + const response = await fetch(`/api/users/${userId}`); + if (!response.ok) throw new Error('Failed to fetch user'); + return response.json(); + }, + { maxAttempts: 3, backoff: 'exponential' }, + (state) => ({ + lastResult: state.lastResult, + executionCount: state.executionCount + }) +); + +// Opt-in to re-render when error state changes (optimized for error handling) +const apiRetryer = useAsyncRetryer( + async (userId: string) => { + const response = await fetch(`/api/users/${userId}`); + if (!response.ok) throw new Error('Failed to fetch user'); + return response.json(); + }, + { + maxAttempts: 3, + backoff: 'exponential', + onError: (error) => console.error('API call failed:', error), + onLastError: (error) => console.error('All retries failed:', error) + }, + (state) => ({ + lastError: state.lastError, + status: state.status + }) +); + +// With state management +const [userData, setUserData] = useState(null); +const { execute, state } = useAsyncRetryer( + async (userId) => { + const response = await fetch(`/api/users/${userId}`); + if (!response.ok) throw new Error('Failed to fetch user'); + const data = await response.json(); + setUserData(data); + return data; + }, + { + maxAttempts: 5, + backoff: 'exponential', + baseWait: 1000, + onRetry: (attempt, error) => { + console.log(`Retry attempt ${attempt} after error:`, error); + }, + onError: (error) => { + console.error('Request failed:', error); + } + } +); + +// Access the selected state (will be empty object {} unless selector provided) +const { isExecuting, currentAttempt } = state; +``` diff --git a/docs/framework/react/reference/functions/useasyncthrottler.md b/docs/framework/react/reference/functions/useasyncthrottler.md index 5802d49c..1feb0fe4 100644 --- a/docs/framework/react/reference/functions/useasyncthrottler.md +++ b/docs/framework/react/reference/functions/useasyncthrottler.md @@ -14,7 +14,7 @@ function useAsyncThrottler( selector): ReactAsyncThrottler ``` -Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:160](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts#L160) +Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:161](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts#L161) A low-level React hook that creates an `AsyncThrottler` instance to limit how often an async function can execute. diff --git a/docs/framework/react/reference/functions/usebatcher.md b/docs/framework/react/reference/functions/usebatcher.md index 8ee2d6c9..f16ec58d 100644 --- a/docs/framework/react/reference/functions/usebatcher.md +++ b/docs/framework/react/reference/functions/usebatcher.md @@ -14,7 +14,7 @@ function useBatcher( selector): ReactBatcher ``` -Defined in: [react-pacer/src/batcher/useBatcher.ts:121](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/batcher/useBatcher.ts#L121) +Defined in: [react-pacer/src/batcher/useBatcher.ts:122](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/batcher/useBatcher.ts#L122) A React hook that creates and manages a Batcher instance. diff --git a/docs/framework/react/reference/functions/usedebouncer.md b/docs/framework/react/reference/functions/usedebouncer.md index b3f3d0b6..5281a2f6 100644 --- a/docs/framework/react/reference/functions/usedebouncer.md +++ b/docs/framework/react/reference/functions/usedebouncer.md @@ -14,7 +14,7 @@ function useDebouncer( selector): ReactDebouncer ``` -Defined in: [react-pacer/src/debouncer/useDebouncer.ts:102](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/debouncer/useDebouncer.ts#L102) +Defined in: [react-pacer/src/debouncer/useDebouncer.ts:103](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/debouncer/useDebouncer.ts#L103) A React hook that creates and manages a Debouncer instance. diff --git a/docs/framework/react/reference/functions/usedefaultpaceroptions.md b/docs/framework/react/reference/functions/usedefaultpaceroptions.md new file mode 100644 index 00000000..bacbe354 --- /dev/null +++ b/docs/framework/react/reference/functions/usedefaultpaceroptions.md @@ -0,0 +1,18 @@ +--- +id: useDefaultPacerOptions +title: useDefaultPacerOptions +--- + + + +# Function: useDefaultPacerOptions() + +```ts +function useDefaultPacerOptions(): PacerProviderOptions +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:68](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L68) + +## Returns + +[`PacerProviderOptions`](../../interfaces/pacerprovideroptions.md) diff --git a/docs/framework/react/reference/functions/usepacercontext.md b/docs/framework/react/reference/functions/usepacercontext.md new file mode 100644 index 00000000..970e19ce --- /dev/null +++ b/docs/framework/react/reference/functions/usepacercontext.md @@ -0,0 +1,18 @@ +--- +id: usePacerContext +title: usePacerContext +--- + + + +# Function: usePacerContext() + +```ts +function usePacerContext(): null | PacerContextValue +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:64](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L64) + +## Returns + +`null` \| `PacerContextValue` diff --git a/docs/framework/react/reference/functions/usequeuer.md b/docs/framework/react/reference/functions/usequeuer.md index 40d322ce..bdbe8fe2 100644 --- a/docs/framework/react/reference/functions/usequeuer.md +++ b/docs/framework/react/reference/functions/usequeuer.md @@ -14,7 +14,7 @@ function useQueuer( selector): ReactQueuer ``` -Defined in: [react-pacer/src/queuer/useQueuer.ts:132](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/queuer/useQueuer.ts#L132) +Defined in: [react-pacer/src/queuer/useQueuer.ts:133](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/queuer/useQueuer.ts#L133) A React hook that creates and manages a Queuer instance. diff --git a/docs/framework/react/reference/functions/useratelimiter.md b/docs/framework/react/reference/functions/useratelimiter.md index e59d9e0d..ac7316b0 100644 --- a/docs/framework/react/reference/functions/useratelimiter.md +++ b/docs/framework/react/reference/functions/useratelimiter.md @@ -14,7 +14,7 @@ function useRateLimiter( selector): ReactRateLimiter ``` -Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:141](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/rate-limiter/useRateLimiter.ts#L141) +Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:142](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/rate-limiter/useRateLimiter.ts#L142) A low-level React hook that creates a `RateLimiter` instance to enforce rate limits on function execution. diff --git a/docs/framework/react/reference/functions/usethrottler.md b/docs/framework/react/reference/functions/usethrottler.md index 666bebaa..601b3927 100644 --- a/docs/framework/react/reference/functions/usethrottler.md +++ b/docs/framework/react/reference/functions/usethrottler.md @@ -14,7 +14,7 @@ function useThrottler( selector): ReactThrottler ``` -Defined in: [react-pacer/src/throttler/useThrottler.ts:107](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/throttler/useThrottler.ts#L107) +Defined in: [react-pacer/src/throttler/useThrottler.ts:108](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/throttler/useThrottler.ts#L108) A low-level React hook that creates a `Throttler` instance that limits how often the provided function can execute. diff --git a/docs/framework/react/reference/index.md b/docs/framework/react/reference/index.md index 1ba0d014..b0415dcc 100644 --- a/docs/framework/react/reference/index.md +++ b/docs/framework/react/reference/index.md @@ -9,10 +9,13 @@ title: "@tanstack/react-pacer" ## Interfaces +- [PacerProviderOptions](../interfaces/pacerprovideroptions.md) +- [PacerProviderProps](../interfaces/pacerproviderprops.md) - [ReactAsyncBatcher](../interfaces/reactasyncbatcher.md) - [ReactAsyncDebouncer](../interfaces/reactasyncdebouncer.md) - [ReactAsyncQueuer](../interfaces/reactasyncqueuer.md) - [ReactAsyncRateLimiter](../interfaces/reactasyncratelimiter.md) +- [ReactAsyncRetryer](../interfaces/reactasyncretryer.md) - [ReactAsyncThrottler](../interfaces/reactasyncthrottler.md) - [ReactBatcher](../interfaces/reactbatcher.md) - [ReactDebouncer](../interfaces/reactdebouncer.md) @@ -22,6 +25,7 @@ title: "@tanstack/react-pacer" ## Functions +- [PacerProvider](../functions/pacerprovider.md) - [useAsyncBatchedCallback](../functions/useasyncbatchedcallback.md) - [useAsyncBatcher](../functions/useasyncbatcher.md) - [useAsyncDebouncedCallback](../functions/useasyncdebouncedcallback.md) @@ -30,6 +34,7 @@ title: "@tanstack/react-pacer" - [useAsyncQueuer](../functions/useasyncqueuer.md) - [useAsyncRateLimitedCallback](../functions/useasyncratelimitedcallback.md) - [useAsyncRateLimiter](../functions/useasyncratelimiter.md) +- [useAsyncRetryer](../functions/useasyncretryer.md) - [useAsyncThrottledCallback](../functions/useasyncthrottledcallback.md) - [useAsyncThrottler](../functions/useasyncthrottler.md) - [useBatchedCallback](../functions/usebatchedcallback.md) @@ -38,6 +43,8 @@ title: "@tanstack/react-pacer" - [useDebouncedState](../functions/usedebouncedstate.md) - [useDebouncedValue](../functions/usedebouncedvalue.md) - [useDebouncer](../functions/usedebouncer.md) +- [useDefaultPacerOptions](../functions/usedefaultpaceroptions.md) +- [usePacerContext](../functions/usepacercontext.md) - [useQueuedState](../functions/usequeuedstate.md) - [useQueuedValue](../functions/usequeuedvalue.md) - [useQueuer](../functions/usequeuer.md) diff --git a/docs/framework/react/reference/interfaces/pacerprovideroptions.md b/docs/framework/react/reference/interfaces/pacerprovideroptions.md new file mode 100644 index 00000000..92ac77e5 --- /dev/null +++ b/docs/framework/react/reference/interfaces/pacerprovideroptions.md @@ -0,0 +1,120 @@ +--- +id: PacerProviderOptions +title: PacerProviderOptions +--- + + + +# Interface: PacerProviderOptions + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:19](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L19) + +## Properties + +### asyncBatcher? + +```ts +optional asyncBatcher: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:20](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L20) + +*** + +### asyncDebouncer? + +```ts +optional asyncDebouncer: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:21](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L21) + +*** + +### asyncQueuer? + +```ts +optional asyncQueuer: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:22](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L22) + +*** + +### asyncRateLimiter? + +```ts +optional asyncRateLimiter: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:23](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L23) + +*** + +### asyncRetryer? + +```ts +optional asyncRetryer: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:24](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L24) + +*** + +### asyncThrottler? + +```ts +optional asyncThrottler: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:25](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L25) + +*** + +### batcher? + +```ts +optional batcher: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:26](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L26) + +*** + +### debouncer? + +```ts +optional debouncer: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:27](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L27) + +*** + +### queuer? + +```ts +optional queuer: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:28](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L28) + +*** + +### rateLimiter? + +```ts +optional rateLimiter: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:29](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L29) + +*** + +### throttler? + +```ts +optional throttler: Partial>; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:30](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L30) diff --git a/docs/framework/react/reference/interfaces/pacerproviderprops.md b/docs/framework/react/reference/interfaces/pacerproviderprops.md new file mode 100644 index 00000000..305b231b --- /dev/null +++ b/docs/framework/react/reference/interfaces/pacerproviderprops.md @@ -0,0 +1,30 @@ +--- +id: PacerProviderProps +title: PacerProviderProps +--- + + + +# Interface: PacerProviderProps + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:39](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L39) + +## Properties + +### children + +```ts +children: ReactNode; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:40](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L40) + +*** + +### defaultOptions? + +```ts +optional defaultOptions: PacerProviderOptions; +``` + +Defined in: [react-pacer/src/provider/PacerProvider.tsx:41](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/provider/PacerProvider.tsx#L41) diff --git a/docs/framework/react/reference/interfaces/reactasyncbatcher.md b/docs/framework/react/reference/interfaces/reactasyncbatcher.md index 3b603968..4335c3c5 100644 --- a/docs/framework/react/reference/interfaces/reactasyncbatcher.md +++ b/docs/framework/react/reference/interfaces/reactasyncbatcher.md @@ -7,7 +7,7 @@ title: ReactAsyncBatcher # Interface: ReactAsyncBatcher\ -Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:10](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts#L10) +Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:11](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts#L11) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:10](https://github readonly state: Readonly; ``` -Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:17](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts#L17) +Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:18](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts#L18) Reactive state that will be updated and re-rendered when the batcher state changes @@ -41,7 +41,7 @@ Use this instead of `batcher.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:23](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts#L23) +Defined in: [react-pacer/src/async-batcher/useAsyncBatcher.ts:24](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts#L24) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactasyncdebouncer.md b/docs/framework/react/reference/interfaces/reactasyncdebouncer.md index bb9bd246..12644ed1 100644 --- a/docs/framework/react/reference/interfaces/reactasyncdebouncer.md +++ b/docs/framework/react/reference/interfaces/reactasyncdebouncer.md @@ -7,7 +7,7 @@ title: ReactAsyncDebouncer # Interface: ReactAsyncDebouncer\ -Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:11](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts#L11) +Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:12](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts#L12) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:11](https://gi readonly state: Readonly; ``` -Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:20](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts#L20) +Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:21](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts#L21) Reactive state that will be updated and re-rendered when the debouncer state changes @@ -41,7 +41,7 @@ Use this instead of `debouncer.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:26](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts#L26) +Defined in: [react-pacer/src/async-debouncer/useAsyncDebouncer.ts:27](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts#L27) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactasyncqueuer.md b/docs/framework/react/reference/interfaces/reactasyncqueuer.md index a37023a9..f07b1116 100644 --- a/docs/framework/react/reference/interfaces/reactasyncqueuer.md +++ b/docs/framework/react/reference/interfaces/reactasyncqueuer.md @@ -7,7 +7,7 @@ title: ReactAsyncQueuer # Interface: ReactAsyncQueuer\ -Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:10](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts#L10) +Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:11](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts#L11) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:10](https://github.c readonly state: Readonly; ``` -Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:17](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts#L17) +Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:18](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts#L18) Reactive state that will be updated and re-rendered when the queuer state changes @@ -41,7 +41,7 @@ Use this instead of `queuer.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:23](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts#L23) +Defined in: [react-pacer/src/async-queuer/useAsyncQueuer.ts:24](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts#L24) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactasyncratelimiter.md b/docs/framework/react/reference/interfaces/reactasyncratelimiter.md index d226ec96..a69d42d2 100644 --- a/docs/framework/react/reference/interfaces/reactasyncratelimiter.md +++ b/docs/framework/react/reference/interfaces/reactasyncratelimiter.md @@ -7,7 +7,7 @@ title: ReactAsyncRateLimiter # Interface: ReactAsyncRateLimiter\ -Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:11](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts#L11) +Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:12](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts#L12) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:11](https readonly state: Readonly; ``` -Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:20](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts#L20) +Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:21](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts#L21) Reactive state that will be updated and re-rendered when the rate limiter state changes @@ -41,7 +41,7 @@ Use this instead of `rateLimiter.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:26](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts#L26) +Defined in: [react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:27](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts#L27) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactasyncretryer.md b/docs/framework/react/reference/interfaces/reactasyncretryer.md new file mode 100644 index 00000000..586aa7e5 --- /dev/null +++ b/docs/framework/react/reference/interfaces/reactasyncretryer.md @@ -0,0 +1,50 @@ +--- +id: ReactAsyncRetryer +title: ReactAsyncRetryer +--- + + + +# Interface: ReactAsyncRetryer\ + +Defined in: [react-pacer/src/async-retryer/useAsyncRetryer.ts:12](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-retryer/useAsyncRetryer.ts#L12) + +## Extends + +- `Omit`\<`AsyncRetryer`\<`TFn`\>, `"store"`\> + +## Type Parameters + +• **TFn** *extends* `AnyAsyncFunction` + +• **TSelected** = \{\} + +## Properties + +### state + +```ts +readonly state: Readonly; +``` + +Defined in: [react-pacer/src/async-retryer/useAsyncRetryer.ts:19](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-retryer/useAsyncRetryer.ts#L19) + +Reactive state that will be updated and re-rendered when the retryer state changes + +Use this instead of `retryer.store.state` + +*** + +### ~~store~~ + +```ts +readonly store: Store>>; +``` + +Defined in: [react-pacer/src/async-retryer/useAsyncRetryer.ts:25](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-retryer/useAsyncRetryer.ts#L25) + +#### Deprecated + +Use `retryer.state` instead of `retryer.store.state` if you want to read reactive state. +The state on the store object is not reactive, as it has not been wrapped in a `useStore` hook internally. +Although, you can make the state reactive by using the `useStore` in your own usage. diff --git a/docs/framework/react/reference/interfaces/reactasyncthrottler.md b/docs/framework/react/reference/interfaces/reactasyncthrottler.md index b7d8b408..24902767 100644 --- a/docs/framework/react/reference/interfaces/reactasyncthrottler.md +++ b/docs/framework/react/reference/interfaces/reactasyncthrottler.md @@ -7,7 +7,7 @@ title: ReactAsyncThrottler # Interface: ReactAsyncThrottler\ -Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:11](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts#L11) +Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:12](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts#L12) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:11](https://gi readonly state: Readonly; ``` -Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:20](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts#L20) +Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:21](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts#L21) Reactive state that will be updated and re-rendered when the throttler state changes @@ -41,7 +41,7 @@ Use this instead of `throttler.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:26](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts#L26) +Defined in: [react-pacer/src/async-throttler/useAsyncThrottler.ts:27](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts#L27) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactbatcher.md b/docs/framework/react/reference/interfaces/reactbatcher.md index b1afe1ea..c231c1eb 100644 --- a/docs/framework/react/reference/interfaces/reactbatcher.md +++ b/docs/framework/react/reference/interfaces/reactbatcher.md @@ -7,7 +7,7 @@ title: ReactBatcher # Interface: ReactBatcher\ -Defined in: [react-pacer/src/batcher/useBatcher.ts:7](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/batcher/useBatcher.ts#L7) +Defined in: [react-pacer/src/batcher/useBatcher.ts:8](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/batcher/useBatcher.ts#L8) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/batcher/useBatcher.ts:7](https://github.com/TanStac readonly state: Readonly; ``` -Defined in: [react-pacer/src/batcher/useBatcher.ts:14](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/batcher/useBatcher.ts#L14) +Defined in: [react-pacer/src/batcher/useBatcher.ts:15](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/batcher/useBatcher.ts#L15) Reactive state that will be updated and re-rendered when the batcher state changes @@ -41,7 +41,7 @@ Use this instead of `batcher.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/batcher/useBatcher.ts:20](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/batcher/useBatcher.ts#L20) +Defined in: [react-pacer/src/batcher/useBatcher.ts:21](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/batcher/useBatcher.ts#L21) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactdebouncer.md b/docs/framework/react/reference/interfaces/reactdebouncer.md index 85cf17e6..c9c0dbf7 100644 --- a/docs/framework/react/reference/interfaces/reactdebouncer.md +++ b/docs/framework/react/reference/interfaces/reactdebouncer.md @@ -7,7 +7,7 @@ title: ReactDebouncer # Interface: ReactDebouncer\ -Defined in: [react-pacer/src/debouncer/useDebouncer.ts:11](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/debouncer/useDebouncer.ts#L11) +Defined in: [react-pacer/src/debouncer/useDebouncer.ts:12](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/debouncer/useDebouncer.ts#L12) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/debouncer/useDebouncer.ts:11](https://github.com/Ta readonly state: Readonly; ``` -Defined in: [react-pacer/src/debouncer/useDebouncer.ts:18](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/debouncer/useDebouncer.ts#L18) +Defined in: [react-pacer/src/debouncer/useDebouncer.ts:19](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/debouncer/useDebouncer.ts#L19) Reactive state that will be updated and re-rendered when the debouncer state changes @@ -41,7 +41,7 @@ Use this instead of `debouncer.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/debouncer/useDebouncer.ts:24](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/debouncer/useDebouncer.ts#L24) +Defined in: [react-pacer/src/debouncer/useDebouncer.ts:25](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/debouncer/useDebouncer.ts#L25) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactqueuer.md b/docs/framework/react/reference/interfaces/reactqueuer.md index e3ccdecf..34b3f68f 100644 --- a/docs/framework/react/reference/interfaces/reactqueuer.md +++ b/docs/framework/react/reference/interfaces/reactqueuer.md @@ -7,7 +7,7 @@ title: ReactQueuer # Interface: ReactQueuer\ -Defined in: [react-pacer/src/queuer/useQueuer.ts:7](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/queuer/useQueuer.ts#L7) +Defined in: [react-pacer/src/queuer/useQueuer.ts:8](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/queuer/useQueuer.ts#L8) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/queuer/useQueuer.ts:7](https://github.com/TanStack/ readonly state: Readonly; ``` -Defined in: [react-pacer/src/queuer/useQueuer.ts:14](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/queuer/useQueuer.ts#L14) +Defined in: [react-pacer/src/queuer/useQueuer.ts:15](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/queuer/useQueuer.ts#L15) Reactive state that will be updated and re-rendered when the queuer state changes @@ -41,7 +41,7 @@ Use this instead of `queuer.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/queuer/useQueuer.ts:20](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/queuer/useQueuer.ts#L20) +Defined in: [react-pacer/src/queuer/useQueuer.ts:21](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/queuer/useQueuer.ts#L21) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactratelimiter.md b/docs/framework/react/reference/interfaces/reactratelimiter.md index 3096a5dc..885732c3 100644 --- a/docs/framework/react/reference/interfaces/reactratelimiter.md +++ b/docs/framework/react/reference/interfaces/reactratelimiter.md @@ -7,7 +7,7 @@ title: ReactRateLimiter # Interface: ReactRateLimiter\ -Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:11](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/rate-limiter/useRateLimiter.ts#L11) +Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:12](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/rate-limiter/useRateLimiter.ts#L12) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:11](https://github.c readonly state: Readonly; ``` -Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:18](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/rate-limiter/useRateLimiter.ts#L18) +Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:19](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/rate-limiter/useRateLimiter.ts#L19) Reactive state that will be updated and re-rendered when the rate limiter state changes @@ -41,7 +41,7 @@ Use this instead of `rateLimiter.store.state` readonly store: Store>; ``` -Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:24](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/rate-limiter/useRateLimiter.ts#L24) +Defined in: [react-pacer/src/rate-limiter/useRateLimiter.ts:25](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/rate-limiter/useRateLimiter.ts#L25) #### Deprecated diff --git a/docs/framework/react/reference/interfaces/reactthrottler.md b/docs/framework/react/reference/interfaces/reactthrottler.md index 14ea1336..d90fc71f 100644 --- a/docs/framework/react/reference/interfaces/reactthrottler.md +++ b/docs/framework/react/reference/interfaces/reactthrottler.md @@ -7,7 +7,7 @@ title: ReactThrottler # Interface: ReactThrottler\ -Defined in: [react-pacer/src/throttler/useThrottler.ts:11](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/throttler/useThrottler.ts#L11) +Defined in: [react-pacer/src/throttler/useThrottler.ts:12](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/throttler/useThrottler.ts#L12) ## Extends @@ -27,7 +27,7 @@ Defined in: [react-pacer/src/throttler/useThrottler.ts:11](https://github.com/Ta readonly state: Readonly; ``` -Defined in: [react-pacer/src/throttler/useThrottler.ts:18](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/throttler/useThrottler.ts#L18) +Defined in: [react-pacer/src/throttler/useThrottler.ts:19](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/throttler/useThrottler.ts#L19) Reactive state that will be updated and re-rendered when the throttler state changes @@ -41,7 +41,7 @@ Use this instead of `throttler.store.state` readonly store: Store>>; ``` -Defined in: [react-pacer/src/throttler/useThrottler.ts:24](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/throttler/useThrottler.ts#L24) +Defined in: [react-pacer/src/throttler/useThrottler.ts:25](https://github.com/TanStack/pacer/blob/main/packages/react-pacer/src/throttler/useThrottler.ts#L25) #### Deprecated diff --git a/docs/reference/classes/asyncbatcher.md b/docs/reference/classes/asyncbatcher.md index 5a92c897..b6c37c15 100644 --- a/docs/reference/classes/asyncbatcher.md +++ b/docs/reference/classes/asyncbatcher.md @@ -7,7 +7,7 @@ title: AsyncBatcher # Class: AsyncBatcher\ -Defined in: [async-batcher.ts:230](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L230) +Defined in: [async-batcher.ts:246](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L246) A class that collects items and processes them in batches asynchronously. @@ -82,7 +82,7 @@ batcher.addItem(2); new AsyncBatcher(fn, initialOptions): AsyncBatcher ``` -Defined in: [async-batcher.ts:238](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L238) +Defined in: [async-batcher.ts:258](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L258) #### Parameters @@ -100,13 +100,23 @@ Defined in: [async-batcher.ts:238](https://github.com/TanStack/pacer/blob/main/p ## Properties +### asyncRetryers + +```ts +asyncRetryers: Map Promise>>; +``` + +Defined in: [async-batcher.ts:252](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L252) + +*** + ### fn() ```ts fn: (items) => Promise; ``` -Defined in: [async-batcher.ts:239](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L239) +Defined in: [async-batcher.ts:259](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L259) #### Parameters @@ -126,7 +136,7 @@ Defined in: [async-batcher.ts:239](https://github.com/TanStack/pacer/blob/main/p key: string; ``` -Defined in: [async-batcher.ts:234](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L234) +Defined in: [async-batcher.ts:250](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L250) *** @@ -136,7 +146,7 @@ Defined in: [async-batcher.ts:234](https://github.com/TanStack/pacer/blob/main/p options: AsyncBatcherOptionsWithOptionalCallbacks; ``` -Defined in: [async-batcher.ts:235](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L235) +Defined in: [async-batcher.ts:251](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L251) *** @@ -146,17 +156,51 @@ Defined in: [async-batcher.ts:235](https://github.com/TanStack/pacer/blob/main/p readonly store: Store>>; ``` -Defined in: [async-batcher.ts:231](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L231) +Defined in: [async-batcher.ts:247](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L247) ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [async-batcher.ts:280](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L280) + +Emits a change event for the async batcher instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + +### abort() + +```ts +abort(): void +``` + +Defined in: [async-batcher.ts:444](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L444) + +Aborts all ongoing executions with the internal abort controllers. +Does NOT cancel any pending execution that have not started yet. +Does NOT clear out the items. + +#### Returns + +`void` + +*** + ### addItem() ```ts -addItem(item): void +addItem(item): Promise ``` -Defined in: [async-batcher.ts:297](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L297) +Defined in: [async-batcher.ts:326](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L326) Adds an item to the async batcher If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed @@ -169,6 +213,30 @@ If the batch size is reached, timeout occurs, or shouldProcess returns true, the #### Returns +`Promise`\<`any`\> + +The result from the batch function, or undefined if an error occurred and was handled by onError + +#### Throws + +The error from the batch function if no onError handler is configured or throwOnError is true + +*** + +### cancel() + +```ts +cancel(): void +``` + +Defined in: [async-batcher.ts:457](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L457) + +Cancels any pending execution that have not started yet. +Does NOT abort any execution already in progress. +Does NOT clear out the items. + +#### Returns + `void` *** @@ -179,7 +247,7 @@ If the batch size is reached, timeout occurs, or shouldProcess returns true, the clear(): void ``` -Defined in: [async-batcher.ts:398](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L398) +Defined in: [async-batcher.ts:435](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L435) Removes all items from the async batcher @@ -195,7 +263,7 @@ Removes all items from the async batcher flush(): Promise ``` -Defined in: [async-batcher.ts:372](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L372) +Defined in: [async-batcher.ts:409](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L409) Processes the current batch of items immediately @@ -211,7 +279,7 @@ Processes the current batch of items immediately peekAllItems(): TValue[] ``` -Defined in: [async-batcher.ts:380](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L380) +Defined in: [async-batcher.ts:417](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L417) Returns a copy of all items in the async batcher @@ -227,7 +295,7 @@ Returns a copy of all items in the async batcher peekFailedItems(): TValue[] ``` -Defined in: [async-batcher.ts:384](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L384) +Defined in: [async-batcher.ts:421](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L421) #### Returns @@ -241,7 +309,7 @@ Defined in: [async-batcher.ts:384](https://github.com/TanStack/pacer/blob/main/p reset(): void ``` -Defined in: [async-batcher.ts:405](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L405) +Defined in: [async-batcher.ts:467](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L467) Resets the async batcher state to its default values @@ -257,7 +325,7 @@ Resets the async batcher state to its default values setOptions(newOptions): void ``` -Defined in: [async-batcher.ts:260](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L260) +Defined in: [async-batcher.ts:285](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L285) Updates the async batcher options diff --git a/docs/reference/classes/asyncdebouncer.md b/docs/reference/classes/asyncdebouncer.md index 31be6ea3..f22d6732 100644 --- a/docs/reference/classes/asyncdebouncer.md +++ b/docs/reference/classes/asyncdebouncer.md @@ -7,7 +7,7 @@ title: AsyncDebouncer # Class: AsyncDebouncer\ -Defined in: [async-debouncer.ts:188](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L188) +Defined in: [async-debouncer.ts:197](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L197) A class that creates an async debounced function. @@ -66,7 +66,7 @@ const results = await asyncDebouncer.maybeExecute(inputElement.value); new AsyncDebouncer(fn, initialOptions): AsyncDebouncer ``` -Defined in: [async-debouncer.ts:200](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L200) +Defined in: [async-debouncer.ts:209](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L209) #### Parameters @@ -84,13 +84,23 @@ Defined in: [async-debouncer.ts:200](https://github.com/TanStack/pacer/blob/main ## Properties +### asyncRetryers + +```ts +asyncRetryers: Map>; +``` + +Defined in: [async-debouncer.ts:203](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L203) + +*** + ### fn ```ts fn: TFn; ``` -Defined in: [async-debouncer.ts:201](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L201) +Defined in: [async-debouncer.ts:210](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L210) *** @@ -100,7 +110,7 @@ Defined in: [async-debouncer.ts:201](https://github.com/TanStack/pacer/blob/main key: string; ``` -Defined in: [async-debouncer.ts:192](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L192) +Defined in: [async-debouncer.ts:201](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L201) *** @@ -110,7 +120,7 @@ Defined in: [async-debouncer.ts:192](https://github.com/TanStack/pacer/blob/main options: AsyncDebouncerOptions; ``` -Defined in: [async-debouncer.ts:193](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L193) +Defined in: [async-debouncer.ts:202](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L202) *** @@ -120,19 +130,53 @@ Defined in: [async-debouncer.ts:193](https://github.com/TanStack/pacer/blob/main readonly store: Store>>; ``` -Defined in: [async-debouncer.ts:189](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L189) +Defined in: [async-debouncer.ts:198](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L198) ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [async-debouncer.ts:231](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L231) + +Emits a change event for the async debouncer instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + +### abort() + +```ts +abort(): void +``` + +Defined in: [async-debouncer.ts:421](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L421) + +Aborts all ongoing executions with the internal abort controllers. +Does NOT cancel any pending execution that have not started yet. + +#### Returns + +`void` + +*** + ### cancel() ```ts cancel(): void ``` -Defined in: [async-debouncer.ts:410](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L410) +Defined in: [async-debouncer.ts:433](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L433) -Cancels any pending execution or aborts any execution in progress +Cancels any pending execution that have not started yet. +Does NOT abort any execution already in progress. #### Returns @@ -146,7 +190,7 @@ Cancels any pending execution or aborts any execution in progress flush(): Promise> ``` -Defined in: [async-debouncer.ts:362](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L362) +Defined in: [async-debouncer.ts:382](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L382) Processes the current pending execution immediately @@ -162,7 +206,7 @@ Processes the current pending execution immediately maybeExecute(...args): Promise> ``` -Defined in: [async-debouncer.ts:282](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L282) +Defined in: [async-debouncer.ts:296](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L296) Attempts to execute the debounced function. If a call is already in progress, it will be queued. @@ -198,7 +242,7 @@ The error from the debounced function if no onError handler is configured reset(): void ``` -Defined in: [async-debouncer.ts:419](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L419) +Defined in: [async-debouncer.ts:441](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L441) Resets the debouncer state to its default values @@ -214,7 +258,7 @@ Resets the debouncer state to its default values setOptions(newOptions): void ``` -Defined in: [async-debouncer.ts:222](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L222) +Defined in: [async-debouncer.ts:236](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L236) Updates the async debouncer options diff --git a/docs/reference/classes/asyncqueuer.md b/docs/reference/classes/asyncqueuer.md index 52edde11..add1fe4d 100644 --- a/docs/reference/classes/asyncqueuer.md +++ b/docs/reference/classes/asyncqueuer.md @@ -7,7 +7,7 @@ title: AsyncQueuer # Class: AsyncQueuer\ -Defined in: [async-queuer.ts:271](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L271) +Defined in: [async-queuer.ts:290](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L290) A flexible asynchronous queue for processing tasks with configurable concurrency, priority, and expiration. @@ -71,7 +71,7 @@ asyncQueuer.start(); new AsyncQueuer(fn, initialOptions): AsyncQueuer ``` -Defined in: [async-queuer.ts:279](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L279) +Defined in: [async-queuer.ts:302](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L302) #### Parameters @@ -89,13 +89,23 @@ Defined in: [async-queuer.ts:279](https://github.com/TanStack/pacer/blob/main/pa ## Properties +### asyncRetryers + +```ts +asyncRetryers: Map Promise>>; +``` + +Defined in: [async-queuer.ts:296](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L296) + +*** + ### fn() ```ts fn: (item) => Promise; ``` -Defined in: [async-queuer.ts:280](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L280) +Defined in: [async-queuer.ts:303](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L303) #### Parameters @@ -115,7 +125,7 @@ Defined in: [async-queuer.ts:280](https://github.com/TanStack/pacer/blob/main/pa key: string; ``` -Defined in: [async-queuer.ts:275](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L275) +Defined in: [async-queuer.ts:294](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L294) *** @@ -125,7 +135,7 @@ Defined in: [async-queuer.ts:275](https://github.com/TanStack/pacer/blob/main/pa options: AsyncQueuerOptions; ``` -Defined in: [async-queuer.ts:276](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L276) +Defined in: [async-queuer.ts:295](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L295) *** @@ -135,10 +145,43 @@ Defined in: [async-queuer.ts:276](https://github.com/TanStack/pacer/blob/main/pa readonly store: Store>>; ``` -Defined in: [async-queuer.ts:272](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L272) +Defined in: [async-queuer.ts:291](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L291) ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [async-queuer.ts:341](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L341) + +Emits a change event for the async queuer instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + +### abort() + +```ts +abort(): void +``` + +Defined in: [async-queuer.ts:785](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L785) + +Aborts all ongoing executions with the internal abort controllers. +Does NOT clear out the items. + +#### Returns + +`void` + +*** + ### addItem() ```ts @@ -148,7 +191,7 @@ addItem( runOnItemsChange): boolean ``` -Defined in: [async-queuer.ts:421](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L421) +Defined in: [async-queuer.ts:449](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L449) Adds an item to the queue. If the queue is full, the item is rejected and onReject is called. Items can be inserted based on priority or at the front/back depending on configuration. @@ -186,9 +229,10 @@ queuer.addItem('task2', 'front'); clear(): void ``` -Defined in: [async-queuer.ts:734](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L734) +Defined in: [async-queuer.ts:776](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L776) -Removes all pending items from the queue. Does not affect active tasks. +Removes all pending items from the queue. +Does NOT affect active tasks. #### Returns @@ -202,7 +246,7 @@ Removes all pending items from the queue. Does not affect active tasks. execute(position?): Promise ``` -Defined in: [async-queuer.ts:556](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L556) +Defined in: [async-queuer.ts:584](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L584) Removes and returns the next item from the queue and executes the task function with it. @@ -232,7 +276,7 @@ queuer.execute('back'); flush(numberOfItems, position?): Promise ``` -Defined in: [async-queuer.ts:591](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L591) +Defined in: [async-queuer.ts:632](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L632) Processes a specified number of items to execute immediately with no wait time If no numberOfItems is provided, all items will be processed @@ -259,7 +303,7 @@ If no numberOfItems is provided, all items will be processed flushAsBatch(batchFunction): Promise ``` -Defined in: [async-queuer.ts:605](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L605) +Defined in: [async-queuer.ts:646](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L646) Processes all items in the queue as a batch using the provided function as an argument The queue is cleared after processing @@ -282,7 +326,7 @@ The queue is cleared after processing getNextItem(position): undefined | TValue ``` -Defined in: [async-queuer.ts:504](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L504) +Defined in: [async-queuer.ts:532](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L532) Removes and returns the next item from the queue without executing the task function. Use for manual queue management. Normally, use execute() to process items. @@ -314,7 +358,7 @@ queuer.getNextItem('back'); peekActiveItems(): TValue[] ``` -Defined in: [async-queuer.ts:697](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L697) +Defined in: [async-queuer.ts:738](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L738) Returns the items currently being processed (active tasks). @@ -330,7 +374,7 @@ Returns the items currently being processed (active tasks). peekAllItems(): TValue[] ``` -Defined in: [async-queuer.ts:690](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L690) +Defined in: [async-queuer.ts:731](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L731) Returns a copy of all items in the queue, including active and pending items. @@ -346,7 +390,7 @@ Returns a copy of all items in the queue, including active and pending items. peekNextItem(position): undefined | TValue ``` -Defined in: [async-queuer.ts:680](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L680) +Defined in: [async-queuer.ts:721](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L721) Returns the next item in the queue without removing it. @@ -375,7 +419,7 @@ queuer.peekNextItem('back'); // back peekPendingItems(): TValue[] ``` -Defined in: [async-queuer.ts:704](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L704) +Defined in: [async-queuer.ts:745](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L745) Returns the items waiting to be processed (pending tasks). @@ -391,7 +435,7 @@ Returns the items waiting to be processed (pending tasks). reset(): void ``` -Defined in: [async-queuer.ts:742](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L742) +Defined in: [async-queuer.ts:796](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L796) Resets the queuer state to its default values @@ -407,7 +451,7 @@ Resets the queuer state to its default values setOptions(newOptions): void ``` -Defined in: [async-queuer.ts:318](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L318) +Defined in: [async-queuer.ts:346](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L346) Updates the queuer options. New options are merged with existing options. @@ -429,7 +473,7 @@ Updates the queuer options. New options are merged with existing options. start(): void ``` -Defined in: [async-queuer.ts:711](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L711) +Defined in: [async-queuer.ts:752](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L752) Starts processing items in the queue. If already running, does nothing. @@ -445,7 +489,7 @@ Starts processing items in the queue. If already running, does nothing. stop(): void ``` -Defined in: [async-queuer.ts:721](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L721) +Defined in: [async-queuer.ts:762](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L762) Stops processing items in the queue. Does not clear the queue. diff --git a/docs/reference/classes/asyncratelimiter.md b/docs/reference/classes/asyncratelimiter.md index 2dc02b87..e11e153c 100644 --- a/docs/reference/classes/asyncratelimiter.md +++ b/docs/reference/classes/asyncratelimiter.md @@ -7,7 +7,7 @@ title: AsyncRateLimiter # Class: AsyncRateLimiter\ -Defined in: [async-rate-limiter.ts:216](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L216) +Defined in: [async-rate-limiter.ts:225](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L225) A class that creates an async rate-limited function. @@ -87,7 +87,7 @@ const data = await rateLimiter.maybeExecute('123'); new AsyncRateLimiter(fn, initialOptions): AsyncRateLimiter ``` -Defined in: [async-rate-limiter.ts:224](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L224) +Defined in: [async-rate-limiter.ts:234](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L234) #### Parameters @@ -105,13 +105,23 @@ Defined in: [async-rate-limiter.ts:224](https://github.com/TanStack/pacer/blob/m ## Properties +### asyncRetryers + +```ts +asyncRetryers: Map>; +``` + +Defined in: [async-rate-limiter.ts:231](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L231) + +*** + ### fn ```ts fn: TFn; ``` -Defined in: [async-rate-limiter.ts:225](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L225) +Defined in: [async-rate-limiter.ts:235](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L235) *** @@ -121,7 +131,7 @@ Defined in: [async-rate-limiter.ts:225](https://github.com/TanStack/pacer/blob/m key: string; ``` -Defined in: [async-rate-limiter.ts:220](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L220) +Defined in: [async-rate-limiter.ts:229](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L229) *** @@ -131,7 +141,7 @@ Defined in: [async-rate-limiter.ts:220](https://github.com/TanStack/pacer/blob/m options: AsyncRateLimiterOptions; ``` -Defined in: [async-rate-limiter.ts:221](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L221) +Defined in: [async-rate-limiter.ts:230](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L230) *** @@ -141,17 +151,50 @@ Defined in: [async-rate-limiter.ts:221](https://github.com/TanStack/pacer/blob/m readonly store: Store>>; ``` -Defined in: [async-rate-limiter.ts:217](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L217) +Defined in: [async-rate-limiter.ts:226](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L226) ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [async-rate-limiter.ts:259](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L259) + +Emits a change event for the async rate limiter instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + +### abort() + +```ts +abort(): void +``` + +Defined in: [async-rate-limiter.ts:491](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L491) + +Aborts all ongoing executions with the internal abort controllers. +Does NOT clear out the execution times or reset the rate limiter. + +#### Returns + +`void` + +*** + ### getMsUntilNextWindow() ```ts getMsUntilNextWindow(): number ``` -Defined in: [async-rate-limiter.ts:457](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L457) +Defined in: [async-rate-limiter.ts:479](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L479) Returns the number of milliseconds until the next execution will be possible For fixed windows, this is the time until the current window resets @@ -169,7 +212,7 @@ For sliding windows, this is the time until the oldest execution expires getRemainingInWindow(): number ``` -Defined in: [async-rate-limiter.ts:447](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L447) +Defined in: [async-rate-limiter.ts:469](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L469) Returns the number of remaining executions allowed in the current window @@ -185,7 +228,7 @@ Returns the number of remaining executions allowed in the current window maybeExecute(...args): Promise> ``` -Defined in: [async-rate-limiter.ts:322](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L322) +Defined in: [async-rate-limiter.ts:337](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L337) Attempts to execute the rate-limited function if within the configured limits. Will reject execution if the number of calls in the current window exceeds the limit. @@ -233,7 +276,7 @@ const result2 = await rateLimiter.maybeExecute('arg1', 'arg2'); // undefined reset(): void ``` -Defined in: [async-rate-limiter.ts:468](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L468) +Defined in: [async-rate-limiter.ts:502](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L502) Resets the rate limiter state @@ -249,7 +292,7 @@ Resets the rate limiter state setOptions(newOptions): void ``` -Defined in: [async-rate-limiter.ts:249](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L249) +Defined in: [async-rate-limiter.ts:264](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L264) Updates the async rate limiter options diff --git a/docs/reference/classes/asyncretryer.md b/docs/reference/classes/asyncretryer.md new file mode 100644 index 00000000..6d097078 --- /dev/null +++ b/docs/reference/classes/asyncretryer.md @@ -0,0 +1,255 @@ +--- +id: AsyncRetryer +title: AsyncRetryer +--- + + + +# Class: AsyncRetryer\ + +Defined in: [async-retryer.ts:214](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L214) + +Provides robust retry functionality for asynchronous functions, supporting configurable backoff strategies, +attempt limits, and detailed state management. The AsyncRetryer class is designed to help you reliably +execute async operations that may fail intermittently, such as network requests or database operations, +by automatically retrying them according to your chosen policy. + +## Retrying Concepts + +- **Retrying**: Automatically re-executes a failed async function up to a specified number of attempts. + Useful for handling transient errors (e.g., network flakiness, rate limits, temporary server issues). +- **Backoff Strategies**: Controls the delay between retry attempts (default: `'exponential'`): + - `'exponential'`: Wait time doubles with each attempt (1s, 2s, 4s, ...) - **DEFAULT** + - `'linear'`: Wait time increases linearly (1s, 2s, 3s, ...) + - `'fixed'`: Waits a constant amount of time (`baseWait`) between each attempt +- **Jitter**: Adds randomness to retry delays to prevent thundering herd problems (default: `0`). + Set to a value between 0-1 to apply that percentage of random variation to each delay. +- **Abort & Cancellation**: Supports cancellation via an internal `AbortController`. If cancelled, retries are stopped. +- **State Management**: Tracks execution status, current attempt, last error, and result using TanStack Store. +- **Callbacks**: Provides hooks for handling success, error, retry, and settled events. + +## State Management +- Uses TanStack Store for fine-grained reactivity. +- State includes: `isExecuting`, `currentAttempt`, `lastError`, `lastResult`, and `status` (`idle`, `executing`, `retrying`, `disabled`). +- State can be accessed via the `store.state` property. + +## Error Handling +The `throwOnError` option controls when errors are thrown (default: `'last'`): +- `'last'`: Only throws the final error after all retries are exhausted - **DEFAULT** +- `true`: Throws every error immediately (no retries) +- `false`: Never throws errors, returns `undefined` instead + +Additional error handling: +- `onError`: Called for every error (including during retries) +- `onLastError`: Called only for the final error after all retries fail +- If `onError` is provided but `throwOnError` is not specified, defaults to `'last'` + +## Usage +- Use for async operations that may fail transiently and benefit from retrying. +- Configure `maxAttempts`, `backoff`, `baseWait`, and `jitter` to control retry behavior. +- Use `onRetry`, `onSuccess`, `onError`, and `onSettled` for custom side effects. + +## Example + +```typescript +// Retry a fetch operation up to 5 times with exponential backoff and jitter +const retryer = new AsyncRetryer(fetchData, { + maxAttempts: 5, + backoff: 'exponential', + baseWait: 1000, + jitter: 0.1, // Add 10% random variation to prevent thundering herd + onRetry: (attempt, error) => console.log(`Retry attempt ${attempt} after error:`, error), + onSuccess: (result) => console.log('Success:', result), + onError: (error) => console.error('Error:', error), + onLastError: (error) => console.error('All retries failed:', error), +}) + +const result = await retryer.execute(userId) +``` + +## Type Parameters + +• **TFn** *extends* [`AnyAsyncFunction`](../../type-aliases/anyasyncfunction.md) + +The async function type to be retried. + +## Constructors + +### new AsyncRetryer() + +```ts +new AsyncRetryer(fn, initialOptions): AsyncRetryer +``` + +Defined in: [async-retryer.ts:227](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L227) + +Creates a new AsyncRetryer instance + +#### Parameters + +##### fn + +`TFn` + +The async function to retry + +##### initialOptions + +[`AsyncRetryerOptions`](../../interfaces/asyncretryeroptions.md)\<`TFn`\> = `{}` + +Configuration options for the retryer + +#### Returns + +[`AsyncRetryer`](../asyncretryer.md)\<`TFn`\> + +## Properties + +### fn + +```ts +fn: TFn; +``` + +Defined in: [async-retryer.ts:228](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L228) + +The async function to retry + +*** + +### key + +```ts +key: string; +``` + +Defined in: [async-retryer.ts:218](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L218) + +*** + +### options + +```ts +options: AsyncRetryerOptions & Omit>, + | "initialState" + | "onError" + | "onSettled" + | "onSuccess" + | "key" + | "onLastError" +| "onRetry">; +``` + +Defined in: [async-retryer.ts:219](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L219) + +*** + +### store + +```ts +readonly store: Store>>; +``` + +Defined in: [async-retryer.ts:215](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L215) + +## Methods + +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [async-retryer.ts:251](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L251) + +Emits a change event for the async retryer instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + +### abort() + +```ts +abort(): void +``` + +Defined in: [async-retryer.ts:452](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L452) + +Cancels the current execution and any pending retries + +#### Returns + +`void` + +*** + +### execute() + +```ts +execute(...args): Promise> +``` + +Defined in: [async-retryer.ts:341](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L341) + +Executes the function with retry logic + +#### Parameters + +##### args + +...`Parameters`\<`TFn`\> + +Arguments to pass to the function + +#### Returns + +`Promise`\<`undefined` \| `ReturnType`\<`TFn`\>\> + +The function result, or undefined if disabled or all retries failed (when throwOnError is false) + +#### Throws + +The last error if throwOnError is true and all retries fail + +*** + +### reset() + +```ts +reset(): void +``` + +Defined in: [async-retryer.ts:465](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L465) + +Resets the retryer to its initial state and cancels any ongoing execution + +#### Returns + +`void` + +*** + +### setOptions() + +```ts +setOptions(newOptions): void +``` + +Defined in: [async-retryer.ts:257](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L257) + +Updates the retryer options + +#### Parameters + +##### newOptions + +`Partial`\<[`AsyncRetryerOptions`](../../interfaces/asyncretryeroptions.md)\<`TFn`\>\> + +Partial options to merge with existing options + +#### Returns + +`void` diff --git a/docs/reference/classes/asyncthrottler.md b/docs/reference/classes/asyncthrottler.md index 0e501414..829b2c1f 100644 --- a/docs/reference/classes/asyncthrottler.md +++ b/docs/reference/classes/asyncthrottler.md @@ -7,7 +7,7 @@ title: AsyncThrottler # Class: AsyncThrottler\ -Defined in: [async-throttler.ts:199](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L199) +Defined in: [async-throttler.ts:208](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L208) A class that creates an async throttled function. @@ -69,7 +69,7 @@ const result = await throttler.maybeExecute(inputElement.value); new AsyncThrottler(fn, initialOptions): AsyncThrottler ``` -Defined in: [async-throttler.ts:211](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L211) +Defined in: [async-throttler.ts:220](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L220) #### Parameters @@ -87,13 +87,23 @@ Defined in: [async-throttler.ts:211](https://github.com/TanStack/pacer/blob/main ## Properties +### asyncRetryers + +```ts +asyncRetryers: Map>; +``` + +Defined in: [async-throttler.ts:214](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L214) + +*** + ### fn ```ts fn: TFn; ``` -Defined in: [async-throttler.ts:212](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L212) +Defined in: [async-throttler.ts:221](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L221) *** @@ -103,7 +113,7 @@ Defined in: [async-throttler.ts:212](https://github.com/TanStack/pacer/blob/main key: string; ``` -Defined in: [async-throttler.ts:203](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L203) +Defined in: [async-throttler.ts:212](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L212) *** @@ -113,7 +123,7 @@ Defined in: [async-throttler.ts:203](https://github.com/TanStack/pacer/blob/main options: AsyncThrottlerOptions; ``` -Defined in: [async-throttler.ts:204](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L204) +Defined in: [async-throttler.ts:213](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L213) *** @@ -123,19 +133,53 @@ Defined in: [async-throttler.ts:204](https://github.com/TanStack/pacer/blob/main readonly store: Store>>; ``` -Defined in: [async-throttler.ts:200](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L200) +Defined in: [async-throttler.ts:209](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L209) ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [async-throttler.ts:242](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L242) + +Emits a change event for the async throttler instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + +### abort() + +```ts +abort(): void +``` + +Defined in: [async-throttler.ts:480](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L480) + +Aborts all ongoing executions with the internal abort controllers. +Does NOT cancel any pending execution that have not started yet. + +#### Returns + +`void` + +*** + ### cancel() ```ts cancel(): void ``` -Defined in: [async-throttler.ts:444](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L444) +Defined in: [async-throttler.ts:490](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L490) -Cancels any pending execution or aborts any execution in progress +Cancels any pending execution that have not started yet. +Does NOT abort any execution already in progress. #### Returns @@ -149,7 +193,7 @@ Cancels any pending execution or aborts any execution in progress flush(): Promise> ``` -Defined in: [async-throttler.ts:393](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L393) +Defined in: [async-throttler.ts:439](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L439) Processes the current pending execution immediately @@ -165,7 +209,7 @@ Processes the current pending execution immediately maybeExecute(...args): Promise> ``` -Defined in: [async-throttler.ts:300](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L300) +Defined in: [async-throttler.ts:315](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L315) Attempts to execute the throttled function. The execution behavior depends on the throttler options: @@ -207,7 +251,7 @@ await throttled.maybeExecute('c', 'd'); reset(): void ``` -Defined in: [async-throttler.ts:452](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L452) +Defined in: [async-throttler.ts:504](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L504) Resets the debouncer state to its default values @@ -223,7 +267,7 @@ Resets the debouncer state to its default values setOptions(newOptions): void ``` -Defined in: [async-throttler.ts:232](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L232) +Defined in: [async-throttler.ts:247](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L247) Updates the async throttler options diff --git a/docs/reference/classes/batcher.md b/docs/reference/classes/batcher.md index 2652c2b6..a54cb8b3 100644 --- a/docs/reference/classes/batcher.md +++ b/docs/reference/classes/batcher.md @@ -127,13 +127,29 @@ Defined in: [batcher.ts:145](https://github.com/TanStack/pacer/blob/main/package ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [batcher.ts:173](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L173) + +Emits a change event for the batcher instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + ### addItem() ```ts addItem(item): void ``` -Defined in: [batcher.ts:204](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L204) +Defined in: [batcher.ts:209](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L209) Adds an item to the batcher If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed @@ -150,13 +166,30 @@ If the batch size is reached, timeout occurs, or shouldProcess returns true, the *** +### cancel() + +```ts +cancel(): void +``` + +Defined in: [batcher.ts:287](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L287) + +Cancels any pending execution that was scheduled. +Does NOT clear out the items. + +#### Returns + +`void` + +*** + ### clear() ```ts clear(): void ``` -Defined in: [batcher.ts:274](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L274) +Defined in: [batcher.ts:279](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L279) Removes all items from the batcher @@ -172,7 +205,7 @@ Removes all items from the batcher flush(): void ``` -Defined in: [batcher.ts:252](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L252) +Defined in: [batcher.ts:257](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L257) Processes the current batch of items immediately @@ -188,7 +221,7 @@ Processes the current batch of items immediately peekAllItems(): TValue[] ``` -Defined in: [batcher.ts:260](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L260) +Defined in: [batcher.ts:265](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L265) Returns a copy of all items in the batcher @@ -204,7 +237,7 @@ Returns a copy of all items in the batcher reset(): void ``` -Defined in: [batcher.ts:281](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L281) +Defined in: [batcher.ts:295](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L295) Resets the batcher state to its default values @@ -220,7 +253,7 @@ Resets the batcher state to its default values setOptions(newOptions): void ``` -Defined in: [batcher.ts:173](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L173) +Defined in: [batcher.ts:178](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L178) Updates the batcher options diff --git a/docs/reference/classes/debouncer.md b/docs/reference/classes/debouncer.md index ea0cbe6c..d3fca780 100644 --- a/docs/reference/classes/debouncer.md +++ b/docs/reference/classes/debouncer.md @@ -110,13 +110,29 @@ Defined in: [debouncer.ts:130](https://github.com/TanStack/pacer/blob/main/packa ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [debouncer.ts:158](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L158) + +Emits a change event for the debouncer instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + ### cancel() ```ts cancel(): void ``` -Defined in: [debouncer.ts:268](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L268) +Defined in: [debouncer.ts:273](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L273) Cancels any pending execution @@ -132,7 +148,7 @@ Cancels any pending execution flush(): void ``` -Defined in: [debouncer.ts:251](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L251) +Defined in: [debouncer.ts:256](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L256) Processes the current pending execution immediately @@ -148,7 +164,7 @@ Processes the current pending execution immediately maybeExecute(...args): void ``` -Defined in: [debouncer.ts:204](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L204) +Defined in: [debouncer.ts:209](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L209) Attempts to execute the debounced function If a call is already in progress, it will be queued @@ -171,7 +187,7 @@ If a call is already in progress, it will be queued reset(): void ``` -Defined in: [debouncer.ts:279](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L279) +Defined in: [debouncer.ts:284](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L284) Resets the debouncer state to its default values @@ -187,7 +203,7 @@ Resets the debouncer state to its default values setOptions(newOptions): void ``` -Defined in: [debouncer.ts:158](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L158) +Defined in: [debouncer.ts:163](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L163) Updates the debouncer options diff --git a/docs/reference/classes/queuer.md b/docs/reference/classes/queuer.md index f96b618c..460f4411 100644 --- a/docs/reference/classes/queuer.md +++ b/docs/reference/classes/queuer.md @@ -160,6 +160,22 @@ Defined in: [queuer.ts:256](https://github.com/TanStack/pacer/blob/main/packages ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [queuer.ts:301](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L301) + +Emits a change event for the queuer instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + ### addItem() ```ts @@ -169,7 +185,7 @@ addItem( runOnItemsChange): boolean ``` -Defined in: [queuer.ts:384](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L384) +Defined in: [queuer.ts:390](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L390) Adds an item to the queue. If the queue is full, the item is rejected and onReject is called. Items can be inserted based on priority or at the front/back depending on configuration. @@ -208,7 +224,7 @@ queuer.addItem('task2', 'front'); clear(): void ``` -Defined in: [queuer.ts:666](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L666) +Defined in: [queuer.ts:672](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L672) Removes all pending items from the queue. Does not affect items being processed. @@ -224,7 +240,7 @@ Removes all pending items from the queue. Does not affect items being processed. execute(position?): undefined | TValue ``` -Defined in: [queuer.ts:520](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L520) +Defined in: [queuer.ts:526](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L526) Removes and returns the next item from the queue and processes it using the provided function. @@ -253,7 +269,7 @@ queuer.execute('back'); flush(numberOfItems, position?): void ``` -Defined in: [queuer.ts:536](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L536) +Defined in: [queuer.ts:542](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L542) Processes a specified number of items to execute immediately with no wait time If no numberOfItems is provided, all items will be processed @@ -280,7 +296,7 @@ If no numberOfItems is provided, all items will be processed flushAsBatch(batchFunction): void ``` -Defined in: [queuer.ts:551](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L551) +Defined in: [queuer.ts:557](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L557) Processes all items in the queue as a batch using the provided function as an argument The queue is cleared after processing @@ -303,7 +319,7 @@ The queue is cleared after processing getNextItem(position): undefined | TValue ``` -Defined in: [queuer.ts:468](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L468) +Defined in: [queuer.ts:474](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L474) Removes and returns the next item from the queue without executing the function. Use for manual queue management. Normally, use execute() to process items. @@ -334,7 +350,7 @@ queuer.getNextItem('back'); peekAllItems(): TValue[] ``` -Defined in: [queuer.ts:634](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L634) +Defined in: [queuer.ts:640](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L640) Returns a copy of all items in the queue. @@ -350,7 +366,7 @@ Returns a copy of all items in the queue. peekNextItem(position): undefined | TValue ``` -Defined in: [queuer.ts:624](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L624) +Defined in: [queuer.ts:630](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L630) Returns the next item in the queue without removing it. @@ -378,7 +394,7 @@ queuer.peekNextItem('back'); // back reset(): void ``` -Defined in: [queuer.ts:674](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L674) +Defined in: [queuer.ts:680](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L680) Resets the queuer state to its default values @@ -394,7 +410,7 @@ Resets the queuer state to its default values setOptions(newOptions): void ``` -Defined in: [queuer.ts:300](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L300) +Defined in: [queuer.ts:306](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L306) Updates the queuer options. New options are merged with existing options. @@ -416,7 +432,7 @@ Updates the queuer options. New options are merged with existing options. start(): void ``` -Defined in: [queuer.ts:641](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L641) +Defined in: [queuer.ts:647](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L647) Starts processing items in the queue. If already isRunning, does nothing. @@ -432,7 +448,7 @@ Starts processing items in the queue. If already isRunning, does nothing. stop(): void ``` -Defined in: [queuer.ts:651](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L651) +Defined in: [queuer.ts:657](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L657) Stops processing items in the queue. Does not clear the queue. diff --git a/docs/reference/classes/ratelimiter.md b/docs/reference/classes/ratelimiter.md index 42ef33ea..651feb05 100644 --- a/docs/reference/classes/ratelimiter.md +++ b/docs/reference/classes/ratelimiter.md @@ -123,13 +123,29 @@ Defined in: [rate-limiter.ts:144](https://github.com/TanStack/pacer/blob/main/pa ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [rate-limiter.ts:174](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L174) + +Emits a change event for the rate limiter instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + ### getMsUntilNextWindow() ```ts getMsUntilNextWindow(): number ``` -Defined in: [rate-limiter.ts:341](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L341) +Defined in: [rate-limiter.ts:346](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L346) Returns the number of milliseconds until the next execution will be possible @@ -145,7 +161,7 @@ Returns the number of milliseconds until the next execution will be possible getRemainingInWindow(): number ``` -Defined in: [rate-limiter.ts:333](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L333) +Defined in: [rate-limiter.ts:338](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L338) Returns the number of remaining executions allowed in the current window @@ -161,7 +177,7 @@ Returns the number of remaining executions allowed in the current window maybeExecute(...args): boolean ``` -Defined in: [rate-limiter.ts:235](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L235) +Defined in: [rate-limiter.ts:240](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L240) Attempts to execute the rate-limited function if within the configured limits. Will reject execution if the number of calls in the current window exceeds the limit. @@ -196,7 +212,7 @@ rateLimiter.maybeExecute('arg1', 'arg2'); // false reset(): void ``` -Defined in: [rate-limiter.ts:352](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L352) +Defined in: [rate-limiter.ts:357](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L357) Resets the rate limiter state @@ -212,7 +228,7 @@ Resets the rate limiter state setOptions(newOptions): void ``` -Defined in: [rate-limiter.ts:174](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L174) +Defined in: [rate-limiter.ts:179](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L179) Updates the rate limiter options diff --git a/docs/reference/classes/throttler.md b/docs/reference/classes/throttler.md index af0001a2..2d156baf 100644 --- a/docs/reference/classes/throttler.md +++ b/docs/reference/classes/throttler.md @@ -114,13 +114,29 @@ Defined in: [throttler.ts:138](https://github.com/TanStack/pacer/blob/main/packa ## Methods +### \_emit() + +```ts +_emit(): void +``` + +Defined in: [throttler.ts:166](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L166) + +Emits a change event for the throttler instance. Mostly useful for devtools. + +#### Returns + +`void` + +*** + ### cancel() ```ts cancel(): void ``` -Defined in: [throttler.ts:305](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L305) +Defined in: [throttler.ts:310](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L310) Cancels any pending trailing execution and clears internal state. @@ -142,7 +158,7 @@ Has no effect if there is no pending execution. flush(): void ``` -Defined in: [throttler.ts:283](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L283) +Defined in: [throttler.ts:288](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L288) Processes the current pending execution immediately @@ -158,7 +174,7 @@ Processes the current pending execution immediately maybeExecute(...args): void ``` -Defined in: [throttler.ts:224](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L224) +Defined in: [throttler.ts:229](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L229) Attempts to execute the throttled function. The execution behavior depends on the throttler options: @@ -200,7 +216,7 @@ throttled.maybeExecute('c', 'd'); reset(): void ``` -Defined in: [throttler.ts:316](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L316) +Defined in: [throttler.ts:321](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L321) Resets the throttler state to its default values @@ -216,7 +232,7 @@ Resets the throttler state to its default values setOptions(newOptions): void ``` -Defined in: [throttler.ts:166](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L166) +Defined in: [throttler.ts:171](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L171) Updates the throttler options diff --git a/docs/reference/functions/asyncbatch.md b/docs/reference/functions/asyncbatch.md index 55a6e9ad..337f8dbc 100644 --- a/docs/reference/functions/asyncbatch.md +++ b/docs/reference/functions/asyncbatch.md @@ -8,10 +8,10 @@ title: asyncBatch # Function: asyncBatch() ```ts -function asyncBatch(fn, options): (item) => void +function asyncBatch(fn, options): (item) => Promise ``` -Defined in: [async-batcher.ts:460](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L460) +Defined in: [async-batcher.ts:522](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L522) Creates an async batcher that processes items in batches @@ -69,7 +69,13 @@ If the batch size is reached, timeout occurs, or shouldProcess returns true, the ### Returns -`void` +`Promise`\<`any`\> + +The result from the batch function, or undefined if an error occurred and was handled by onError + +### Throws + +The error from the batch function if no onError handler is configured or throwOnError is true ## Example diff --git a/docs/reference/functions/asyncdebounce.md b/docs/reference/functions/asyncdebounce.md index 47f3facc..63897d7e 100644 --- a/docs/reference/functions/asyncdebounce.md +++ b/docs/reference/functions/asyncdebounce.md @@ -11,7 +11,7 @@ title: asyncDebounce function asyncDebounce(fn, initialOptions): (...args) => Promise> ``` -Defined in: [async-debouncer.ts:468](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L468) +Defined in: [async-debouncer.ts:490](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L490) Creates an async debounced function that delays execution until after a specified wait time. The debounced function will only execute once the wait period has elapsed without any new calls. diff --git a/docs/reference/functions/asyncqueue.md b/docs/reference/functions/asyncqueue.md index f3155ab6..33a2e33f 100644 --- a/docs/reference/functions/asyncqueue.md +++ b/docs/reference/functions/asyncqueue.md @@ -11,7 +11,7 @@ title: asyncQueue function asyncQueue(fn, initialOptions): (item, position, runOnItemsChange) => boolean ``` -Defined in: [async-queuer.ts:781](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L781) +Defined in: [async-queuer.ts:835](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L835) Creates a new AsyncQueuer instance and returns a bound addItem function for adding tasks. The queuer is started automatically and ready to process items. diff --git a/docs/reference/functions/asyncratelimit.md b/docs/reference/functions/asyncratelimit.md index d74d8276..547e2669 100644 --- a/docs/reference/functions/asyncratelimit.md +++ b/docs/reference/functions/asyncratelimit.md @@ -11,7 +11,7 @@ title: asyncRateLimit function asyncRateLimit(fn, initialOptions): (...args) => Promise> ``` -Defined in: [async-rate-limiter.ts:539](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L539) +Defined in: [async-rate-limiter.ts:573](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L573) Creates an async rate-limited function that will execute the provided function up to a maximum number of times within a time window. diff --git a/docs/reference/functions/asyncretry.md b/docs/reference/functions/asyncretry.md new file mode 100644 index 00000000..3eccab27 --- /dev/null +++ b/docs/reference/functions/asyncretry.md @@ -0,0 +1,61 @@ +--- +id: asyncRetry +title: asyncRetry +--- + + + +# Function: asyncRetry() + +```ts +function asyncRetry(fn, initialOptions): (...args) => Promise> +``` + +Defined in: [async-retryer.ts:488](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L488) + +Creates a retry-enabled version of an async function + +## Type Parameters + +• **TFn** *extends* [`AnyAsyncFunction`](../../type-aliases/anyasyncfunction.md) + +## Parameters + +### fn + +`TFn` + +The async function to add retry functionality to + +### initialOptions + +[`AsyncRetryerOptions`](../../interfaces/asyncretryeroptions.md)\<`TFn`\> = `{}` + +Configuration options for the retry behavior + +## Returns + +`Function` + +A new function that executes the original with retry logic + +### Parameters + +#### args + +...`Parameters`\<`TFn`\> + +### Returns + +`Promise`\<`undefined` \| `ReturnType`\<`TFn`\>\> + +## Example + +```typescript +const retryFetch = asyncRetry(fetch, { + maxAttempts: 3, + backoff: 'exponential' +}) + +const response = await retryFetch('/api/data') +``` diff --git a/docs/reference/functions/asyncthrottle.md b/docs/reference/functions/asyncthrottle.md index 07dfd8a9..0c393f0c 100644 --- a/docs/reference/functions/asyncthrottle.md +++ b/docs/reference/functions/asyncthrottle.md @@ -11,7 +11,7 @@ title: asyncThrottle function asyncThrottle(fn, initialOptions): (...args) => Promise> ``` -Defined in: [async-throttler.ts:500](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L500) +Defined in: [async-throttler.ts:552](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L552) Creates an async throttled function that limits how often the function can execute. The throttled function will execute at most once per wait period, even if called multiple times. diff --git a/docs/reference/functions/batch.md b/docs/reference/functions/batch.md index 4e20536e..bed79642 100644 --- a/docs/reference/functions/batch.md +++ b/docs/reference/functions/batch.md @@ -11,7 +11,7 @@ title: batch function batch(fn, options): (item) => void ``` -Defined in: [batcher.ts:305](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L305) +Defined in: [batcher.ts:319](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/batcher.ts#L319) Creates a batcher that processes items in batches diff --git a/docs/reference/functions/debounce.md b/docs/reference/functions/debounce.md index ebb0464a..c2625f7a 100644 --- a/docs/reference/functions/debounce.md +++ b/docs/reference/functions/debounce.md @@ -11,7 +11,7 @@ title: debounce function debounce(fn, initialOptions): (...args) => void ``` -Defined in: [debouncer.ts:312](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L312) +Defined in: [debouncer.ts:317](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/debouncer.ts#L317) Creates a debounced function that delays invoking the provided function until after a specified wait time. Multiple calls during the wait period will cancel previous pending invocations and reset the timer. diff --git a/docs/reference/functions/queue.md b/docs/reference/functions/queue.md index f3f24895..b2d4e8b1 100644 --- a/docs/reference/functions/queue.md +++ b/docs/reference/functions/queue.md @@ -11,7 +11,7 @@ title: queue function queue(fn, initialOptions): (item, position, runOnItemsChange) => boolean ``` -Defined in: [queuer.ts:717](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L717) +Defined in: [queuer.ts:723](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/queuer.ts#L723) Creates a queue that processes items immediately upon addition. Items are processed sequentially in FIFO order by default. diff --git a/docs/reference/functions/ratelimit.md b/docs/reference/functions/ratelimit.md index 5223c7e1..80de15e6 100644 --- a/docs/reference/functions/ratelimit.md +++ b/docs/reference/functions/ratelimit.md @@ -11,7 +11,7 @@ title: rateLimit function rateLimit(fn, initialOptions): (...args) => boolean ``` -Defined in: [rate-limiter.ts:404](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L404) +Defined in: [rate-limiter.ts:409](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/rate-limiter.ts#L409) Creates a rate-limited function that will execute the provided function up to a maximum number of times within a time window. diff --git a/docs/reference/functions/throttle.md b/docs/reference/functions/throttle.md index 888d4300..f779b3ff 100644 --- a/docs/reference/functions/throttle.md +++ b/docs/reference/functions/throttle.md @@ -11,7 +11,7 @@ title: throttle function throttle(fn, initialOptions): (...args) => void ``` -Defined in: [throttler.ts:355](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L355) +Defined in: [throttler.ts:360](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/throttler.ts#L360) Creates a throttled function that limits how often the provided function can execute. diff --git a/docs/reference/index.md b/docs/reference/index.md index 900c1082..572c1a97 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -13,6 +13,7 @@ title: "@tanstack/pacer" - [AsyncDebouncer](../classes/asyncdebouncer.md) - [AsyncQueuer](../classes/asyncqueuer.md) - [AsyncRateLimiter](../classes/asyncratelimiter.md) +- [AsyncRetryer](../classes/asyncretryer.md) - [AsyncThrottler](../classes/asyncthrottler.md) - [Batcher](../classes/batcher.md) - [Debouncer](../classes/debouncer.md) @@ -30,6 +31,8 @@ title: "@tanstack/pacer" - [AsyncQueuerState](../interfaces/asyncqueuerstate.md) - [AsyncRateLimiterOptions](../interfaces/asyncratelimiteroptions.md) - [AsyncRateLimiterState](../interfaces/asyncratelimiterstate.md) +- [AsyncRetryerOptions](../interfaces/asyncretryeroptions.md) +- [AsyncRetryerState](../interfaces/asyncretryerstate.md) - [AsyncThrottlerOptions](../interfaces/asyncthrottleroptions.md) - [AsyncThrottlerState](../interfaces/asyncthrottlerstate.md) - [BatcherOptions](../interfaces/batcheroptions.md) @@ -62,6 +65,7 @@ title: "@tanstack/pacer" - [asyncDebounce](../functions/asyncdebounce.md) - [asyncQueue](../functions/asyncqueue.md) - [asyncRateLimit](../functions/asyncratelimit.md) +- [asyncRetry](../functions/asyncretry.md) - [asyncThrottle](../functions/asyncthrottle.md) - [batch](../functions/batch.md) - [createKey](../functions/createkey.md) diff --git a/docs/reference/interfaces/asyncbatcheroptions.md b/docs/reference/interfaces/asyncbatcheroptions.md index d8e06dae..29d9a36b 100644 --- a/docs/reference/interfaces/asyncbatcheroptions.md +++ b/docs/reference/interfaces/asyncbatcheroptions.md @@ -7,7 +7,7 @@ title: AsyncBatcherOptions # Interface: AsyncBatcherOptions\ -Defined in: [async-batcher.ts:82](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L82) +Defined in: [async-batcher.ts:89](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L89) Options for configuring an AsyncBatcher instance @@ -17,13 +17,25 @@ Options for configuring an AsyncBatcher instance ## Properties +### asyncRetryerOptions? + +```ts +optional asyncRetryerOptions: AsyncRetryerOptions<(items) => Promise>; +``` + +Defined in: [async-batcher.ts:93](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L93) + +Options for configuring the underlying async retryer + +*** + ### getShouldExecute()? ```ts optional getShouldExecute: (items, batcher) => boolean; ``` -Defined in: [async-batcher.ts:87](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L87) +Defined in: [async-batcher.ts:100](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L100) Custom function to determine if a batch should be processed Return true to process the batch immediately @@ -50,7 +62,7 @@ Return true to process the batch immediately optional initialState: Partial>; ``` -Defined in: [async-batcher.ts:94](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L94) +Defined in: [async-batcher.ts:107](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L107) Initial state for the async batcher @@ -62,7 +74,7 @@ Initial state for the async batcher optional key: string; ``` -Defined in: [async-batcher.ts:99](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L99) +Defined in: [async-batcher.ts:112](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L112) Optional key to identify this async batcher instance. If provided, the async batcher will be identified by this key in the devtools and PacerProvider if applicable. @@ -75,7 +87,7 @@ If provided, the async batcher will be identified by this key in the devtools an optional maxSize: number; ``` -Defined in: [async-batcher.ts:104](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L104) +Defined in: [async-batcher.ts:117](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L117) Maximum number of items in a batch @@ -93,7 +105,7 @@ Infinity optional onError: (error, batch, batcher) => void; ``` -Defined in: [async-batcher.ts:110](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L110) +Defined in: [async-batcher.ts:123](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L123) Optional error handler for when the batch function throws. If provided, the handler will be called with the error, the batch of items that failed, and batcher instance. @@ -103,7 +115,7 @@ This can be used alongside throwOnError - the handler will be called before any ##### error -`unknown` +`Error` ##### batch @@ -125,7 +137,7 @@ This can be used alongside throwOnError - the handler will be called before any optional onItemsChange: (batcher) => void; ``` -Defined in: [async-batcher.ts:118](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L118) +Defined in: [async-batcher.ts:131](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L131) Callback fired after items are added to the batcher @@ -147,7 +159,7 @@ Callback fired after items are added to the batcher optional onSettled: (batch, batcher) => void; ``` -Defined in: [async-batcher.ts:122](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L122) +Defined in: [async-batcher.ts:135](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L135) Optional callback to call when a batch is settled (completed or failed) @@ -173,7 +185,7 @@ Optional callback to call when a batch is settled (completed or failed) optional onSuccess: (result, batch, batcher) => void; ``` -Defined in: [async-batcher.ts:126](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L126) +Defined in: [async-batcher.ts:139](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L139) Optional callback to call when a batch succeeds @@ -203,7 +215,7 @@ Optional callback to call when a batch succeeds optional started: boolean; ``` -Defined in: [async-batcher.ts:135](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L135) +Defined in: [async-batcher.ts:148](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L148) Whether the batcher should start processing immediately @@ -221,7 +233,7 @@ true optional throwOnError: boolean; ``` -Defined in: [async-batcher.ts:141](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L141) +Defined in: [async-batcher.ts:154](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L154) Whether to throw errors when they occur. Defaults to true if no onError handler is provided, false if an onError handler is provided. @@ -235,7 +247,7 @@ Can be explicitly set to override these defaults. optional wait: number | (asyncBatcher) => number; ``` -Defined in: [async-batcher.ts:148](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L148) +Defined in: [async-batcher.ts:161](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L161) Maximum time in milliseconds to wait before processing a batch. If the wait duration has elapsed, the batch will be processed. diff --git a/docs/reference/interfaces/asyncbatcherstate.md b/docs/reference/interfaces/asyncbatcherstate.md index 38bbde18..e1b88961 100644 --- a/docs/reference/interfaces/asyncbatcherstate.md +++ b/docs/reference/interfaces/asyncbatcherstate.md @@ -7,7 +7,7 @@ title: AsyncBatcherState # Interface: AsyncBatcherState\ -Defined in: [async-batcher.ts:6](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L6) +Defined in: [async-batcher.ts:8](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L8) ## Type Parameters @@ -21,19 +21,31 @@ Defined in: [async-batcher.ts:6](https://github.com/TanStack/pacer/blob/main/pac errorCount: number; ``` -Defined in: [async-batcher.ts:10](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L10) +Defined in: [async-batcher.ts:12](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L12) Number of batch executions that have resulted in errors *** +### executeCount + +```ts +executeCount: number; +``` + +Defined in: [async-batcher.ts:16](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L16) + +Number of batch executions that have been executed + +*** + ### failedItems ```ts failedItems: TValue[]; ``` -Defined in: [async-batcher.ts:14](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L14) +Defined in: [async-batcher.ts:20](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L20) Array of items that failed during batch processing @@ -45,7 +57,7 @@ Array of items that failed during batch processing isEmpty: boolean; ``` -Defined in: [async-batcher.ts:18](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L18) +Defined in: [async-batcher.ts:24](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L24) Whether the batcher has no items to process (items array is empty) @@ -57,7 +69,7 @@ Whether the batcher has no items to process (items array is empty) isExecuting: boolean; ``` -Defined in: [async-batcher.ts:22](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L22) +Defined in: [async-batcher.ts:28](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L28) Whether a batch is currently being processed asynchronously @@ -69,7 +81,7 @@ Whether a batch is currently being processed asynchronously isPending: boolean; ``` -Defined in: [async-batcher.ts:26](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L26) +Defined in: [async-batcher.ts:32](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L32) Whether the batcher is waiting for the timeout to trigger batch processing @@ -81,7 +93,7 @@ Whether the batcher is waiting for the timeout to trigger batch processing items: TValue[]; ``` -Defined in: [async-batcher.ts:30](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L30) +Defined in: [async-batcher.ts:36](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L36) Array of items currently queued for batch processing @@ -93,7 +105,7 @@ Array of items currently queued for batch processing lastResult: any; ``` -Defined in: [async-batcher.ts:34](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L34) +Defined in: [async-batcher.ts:40](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L40) The result from the most recent batch execution @@ -105,7 +117,7 @@ The result from the most recent batch execution settleCount: number; ``` -Defined in: [async-batcher.ts:38](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L38) +Defined in: [async-batcher.ts:44](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L44) Number of batch executions that have completed (either successfully or with errors) @@ -117,7 +129,7 @@ Number of batch executions that have completed (either successfully or with erro size: number; ``` -Defined in: [async-batcher.ts:42](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L42) +Defined in: [async-batcher.ts:48](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L48) Number of items currently in the batch queue @@ -129,7 +141,7 @@ Number of items currently in the batch queue status: "idle" | "pending" | "executing" | "populated"; ``` -Defined in: [async-batcher.ts:46](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L46) +Defined in: [async-batcher.ts:52](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L52) Current processing status - 'idle' when not processing, 'pending' when waiting for timeout, 'executing' when processing, 'populated' when items are present, but no wait is configured @@ -141,7 +153,7 @@ Current processing status - 'idle' when not processing, 'pending' when waiting f successCount: number; ``` -Defined in: [async-batcher.ts:50](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L50) +Defined in: [async-batcher.ts:56](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L56) Number of batch executions that have completed successfully @@ -153,7 +165,7 @@ Number of batch executions that have completed successfully totalItemsFailed: number; ``` -Defined in: [async-batcher.ts:54](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L54) +Defined in: [async-batcher.ts:60](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L60) Total number of items that have failed processing across all batches @@ -165,6 +177,6 @@ Total number of items that have failed processing across all batches totalItemsProcessed: number; ``` -Defined in: [async-batcher.ts:58](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L58) +Defined in: [async-batcher.ts:64](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-batcher.ts#L64) Total number of items that have been processed across all batches diff --git a/docs/reference/interfaces/asyncdebounceroptions.md b/docs/reference/interfaces/asyncdebounceroptions.md index cb03a901..cd725cc9 100644 --- a/docs/reference/interfaces/asyncdebounceroptions.md +++ b/docs/reference/interfaces/asyncdebounceroptions.md @@ -7,7 +7,7 @@ title: AsyncDebouncerOptions # Interface: AsyncDebouncerOptions\ -Defined in: [async-debouncer.ts:69](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L69) +Defined in: [async-debouncer.ts:71](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L71) Options for configuring an async debounced function @@ -17,13 +17,25 @@ Options for configuring an async debounced function ## Properties +### asyncRetryerOptions? + +```ts +optional asyncRetryerOptions: AsyncRetryerOptions; +``` + +Defined in: [async-debouncer.ts:75](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L75) + +Options for configuring the underlying async retryer + +*** + ### enabled? ```ts optional enabled: boolean | (debouncer) => boolean; ``` -Defined in: [async-debouncer.ts:75](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L75) +Defined in: [async-debouncer.ts:81](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L81) Whether the debouncer is enabled. When disabled, maybeExecute will not trigger any executions. Can be a boolean or a function that returns a boolean. @@ -37,7 +49,7 @@ Defaults to true. optional initialState: Partial>; ``` -Defined in: [async-debouncer.ts:79](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L79) +Defined in: [async-debouncer.ts:85](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L85) Initial state for the async debouncer @@ -49,7 +61,7 @@ Initial state for the async debouncer optional key: string; ``` -Defined in: [async-debouncer.ts:84](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L84) +Defined in: [async-debouncer.ts:90](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L90) Optional key to identify this async debouncer instance. If provided, the async debouncer will be identified by this key in the devtools and PacerProvider if applicable. @@ -62,7 +74,7 @@ If provided, the async debouncer will be identified by this key in the devtools optional leading: boolean; ``` -Defined in: [async-debouncer.ts:89](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L89) +Defined in: [async-debouncer.ts:95](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L95) Whether to execute on the leading edge of the timeout. Defaults to false. @@ -75,7 +87,7 @@ Defaults to false. optional onError: (error, args, debouncer) => void; ``` -Defined in: [async-debouncer.ts:95](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L95) +Defined in: [async-debouncer.ts:101](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L101) Optional error handler for when the debounced function throws. If provided, the handler will be called with the error and debouncer instance. @@ -85,7 +97,7 @@ This can be used alongside throwOnError - the handler will be called before any ##### error -`unknown` +`Error` ##### args @@ -107,7 +119,7 @@ This can be used alongside throwOnError - the handler will be called before any optional onSettled: (args, debouncer) => void; ``` -Defined in: [async-debouncer.ts:103](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L103) +Defined in: [async-debouncer.ts:109](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L109) Optional callback to call when the debounced function is executed @@ -133,7 +145,7 @@ Optional callback to call when the debounced function is executed optional onSuccess: (result, args, debouncer) => void; ``` -Defined in: [async-debouncer.ts:107](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L107) +Defined in: [async-debouncer.ts:113](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L113) Optional callback to call when the debounced function is executed @@ -163,7 +175,7 @@ Optional callback to call when the debounced function is executed optional throwOnError: boolean; ``` -Defined in: [async-debouncer.ts:117](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L117) +Defined in: [async-debouncer.ts:123](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L123) Whether to throw errors when they occur. Defaults to true if no onError handler is provided, false if an onError handler is provided. @@ -177,7 +189,7 @@ Can be explicitly set to override these defaults. optional trailing: boolean; ``` -Defined in: [async-debouncer.ts:122](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L122) +Defined in: [async-debouncer.ts:128](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L128) Whether to execute on the trailing edge of the timeout. Defaults to true. @@ -190,7 +202,7 @@ Defaults to true. wait: number | (debouncer) => number; ``` -Defined in: [async-debouncer.ts:128](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L128) +Defined in: [async-debouncer.ts:134](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L134) Delay in milliseconds to wait after the last call before executing. Can be a number or a function that returns a number. diff --git a/docs/reference/interfaces/asyncdebouncerstate.md b/docs/reference/interfaces/asyncdebouncerstate.md index dddacaac..420c5edc 100644 --- a/docs/reference/interfaces/asyncdebouncerstate.md +++ b/docs/reference/interfaces/asyncdebouncerstate.md @@ -7,7 +7,7 @@ title: AsyncDebouncerState # Interface: AsyncDebouncerState\ -Defined in: [async-debouncer.ts:6](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L6) +Defined in: [async-debouncer.ts:8](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L8) ## Type Parameters @@ -21,7 +21,7 @@ Defined in: [async-debouncer.ts:6](https://github.com/TanStack/pacer/blob/main/p canLeadingExecute: boolean; ``` -Defined in: [async-debouncer.ts:10](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L10) +Defined in: [async-debouncer.ts:12](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L12) Whether the debouncer can execute on the leading edge of the timeout @@ -33,7 +33,7 @@ Whether the debouncer can execute on the leading edge of the timeout errorCount: number; ``` -Defined in: [async-debouncer.ts:14](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L14) +Defined in: [async-debouncer.ts:16](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L16) Number of function executions that have resulted in errors @@ -45,7 +45,7 @@ Number of function executions that have resulted in errors isExecuting: boolean; ``` -Defined in: [async-debouncer.ts:18](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L18) +Defined in: [async-debouncer.ts:20](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L20) Whether the debounced function is currently executing asynchronously @@ -57,7 +57,7 @@ Whether the debounced function is currently executing asynchronously isPending: boolean; ``` -Defined in: [async-debouncer.ts:22](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L22) +Defined in: [async-debouncer.ts:24](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L24) Whether the debouncer is waiting for the timeout to trigger execution @@ -69,7 +69,7 @@ Whether the debouncer is waiting for the timeout to trigger execution lastArgs: undefined | Parameters; ``` -Defined in: [async-debouncer.ts:26](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L26) +Defined in: [async-debouncer.ts:28](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L28) The arguments from the most recent call to maybeExecute @@ -81,7 +81,7 @@ The arguments from the most recent call to maybeExecute lastResult: undefined | ReturnType; ``` -Defined in: [async-debouncer.ts:30](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L30) +Defined in: [async-debouncer.ts:32](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L32) The result from the most recent successful function execution @@ -93,7 +93,7 @@ The result from the most recent successful function execution maybeExecuteCount: number; ``` -Defined in: [async-debouncer.ts:34](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L34) +Defined in: [async-debouncer.ts:36](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L36) Number of times maybeExecute has been called (for reduction calculations) @@ -105,7 +105,7 @@ Number of times maybeExecute has been called (for reduction calculations) settleCount: number; ``` -Defined in: [async-debouncer.ts:38](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L38) +Defined in: [async-debouncer.ts:40](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L40) Number of function executions that have completed (either successfully or with errors) @@ -117,7 +117,7 @@ Number of function executions that have completed (either successfully or with e status: "disabled" | "idle" | "pending" | "executing" | "settled"; ``` -Defined in: [async-debouncer.ts:42](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L42) +Defined in: [async-debouncer.ts:44](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L44) Current execution status - 'idle' when not active, 'pending' when waiting, 'executing' when running, 'settled' when completed @@ -129,6 +129,6 @@ Current execution status - 'idle' when not active, 'pending' when waiting, 'exec successCount: number; ``` -Defined in: [async-debouncer.ts:46](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L46) +Defined in: [async-debouncer.ts:48](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-debouncer.ts#L48) Number of function executions that have completed successfully diff --git a/docs/reference/interfaces/asyncqueueroptions.md b/docs/reference/interfaces/asyncqueueroptions.md index a97171f6..ea9a244e 100644 --- a/docs/reference/interfaces/asyncqueueroptions.md +++ b/docs/reference/interfaces/asyncqueueroptions.md @@ -7,7 +7,7 @@ title: AsyncQueuerOptions # Interface: AsyncQueuerOptions\ -Defined in: [async-queuer.ts:100](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L100) +Defined in: [async-queuer.ts:112](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L112) ## Type Parameters @@ -21,7 +21,7 @@ Defined in: [async-queuer.ts:100](https://github.com/TanStack/pacer/blob/main/pa optional addItemsTo: QueuePosition; ``` -Defined in: [async-queuer.ts:105](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L105) +Defined in: [async-queuer.ts:121](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L121) Default position to add items to the queuer @@ -33,13 +33,25 @@ Default position to add items to the queuer *** +### asyncRetryerOptions? + +```ts +optional asyncRetryerOptions: AsyncRetryerOptions<(item) => Promise>; +``` + +Defined in: [async-queuer.ts:116](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L116) + +Options for configuring the underlying async retryer + +*** + ### concurrency? ```ts optional concurrency: number | (queuer) => number; ``` -Defined in: [async-queuer.ts:111](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L111) +Defined in: [async-queuer.ts:127](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L127) Maximum number of concurrent tasks to process. Can be a number or a function that returns a number. @@ -58,7 +70,7 @@ Can be a number or a function that returns a number. optional expirationDuration: number; ``` -Defined in: [async-queuer.ts:116](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L116) +Defined in: [async-queuer.ts:132](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L132) Maximum time in milliseconds that an item can stay in the queue If not provided, items will never expire @@ -71,7 +83,7 @@ If not provided, items will never expire optional getIsExpired: (item, addedAt) => boolean; ``` -Defined in: [async-queuer.ts:121](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L121) +Defined in: [async-queuer.ts:137](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L137) Function to determine if an item has expired If provided, this overrides the expirationDuration behavior @@ -98,7 +110,7 @@ If provided, this overrides the expirationDuration behavior optional getItemsFrom: QueuePosition; ``` -Defined in: [async-queuer.ts:126](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L126) +Defined in: [async-queuer.ts:142](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L142) Default position to get items from during processing @@ -116,7 +128,7 @@ Default position to get items from during processing optional getPriority: (item) => number; ``` -Defined in: [async-queuer.ts:132](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L132) +Defined in: [async-queuer.ts:148](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L148) Function to determine priority of items in the queuer Higher priority items will be processed first @@ -140,7 +152,7 @@ If not provided, will use static priority values attached to tasks optional initialItems: TValue[]; ``` -Defined in: [async-queuer.ts:136](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L136) +Defined in: [async-queuer.ts:152](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L152) Initial items to populate the queuer with @@ -152,7 +164,7 @@ Initial items to populate the queuer with optional initialState: Partial>; ``` -Defined in: [async-queuer.ts:140](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L140) +Defined in: [async-queuer.ts:156](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L156) Initial state for the async queuer @@ -164,7 +176,7 @@ Initial state for the async queuer optional key: string; ``` -Defined in: [async-queuer.ts:145](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L145) +Defined in: [async-queuer.ts:161](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L161) Optional key to identify this async queuer instance. If provided, the async queuer will be identified by this key in the devtools and PacerProvider if applicable. @@ -177,7 +189,7 @@ If provided, the async queuer will be identified by this key in the devtools and optional maxSize: number; ``` -Defined in: [async-queuer.ts:149](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L149) +Defined in: [async-queuer.ts:165](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L165) Maximum number of items allowed in the queuer @@ -189,7 +201,7 @@ Maximum number of items allowed in the queuer optional onError: (error, item, queuer) => void; ``` -Defined in: [async-queuer.ts:155](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L155) +Defined in: [async-queuer.ts:171](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L171) Optional error handler for when a task throws. If provided, the handler will be called with the error and queuer instance. @@ -199,7 +211,7 @@ This can be used alongside throwOnError - the handler will be called before any ##### error -`unknown` +`Error` ##### item @@ -221,7 +233,7 @@ This can be used alongside throwOnError - the handler will be called before any optional onExpire: (item, queuer) => void; ``` -Defined in: [async-queuer.ts:159](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L159) +Defined in: [async-queuer.ts:175](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L175) Callback fired whenever an item expires in the queuer @@ -247,7 +259,7 @@ Callback fired whenever an item expires in the queuer optional onItemsChange: (queuer) => void; ``` -Defined in: [async-queuer.ts:163](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L163) +Defined in: [async-queuer.ts:179](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L179) Callback fired whenever an item is added or removed from the queuer @@ -269,7 +281,7 @@ Callback fired whenever an item is added or removed from the queuer optional onReject: (item, queuer) => void; ``` -Defined in: [async-queuer.ts:167](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L167) +Defined in: [async-queuer.ts:183](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L183) Callback fired whenever an item is rejected from being added to the queuer @@ -295,7 +307,7 @@ Callback fired whenever an item is rejected from being added to the queuer optional onSettled: (item, queuer) => void; ``` -Defined in: [async-queuer.ts:171](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L171) +Defined in: [async-queuer.ts:187](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L187) Optional callback to call when a task is settled @@ -321,7 +333,7 @@ Optional callback to call when a task is settled optional onSuccess: (result, item, queuer) => void; ``` -Defined in: [async-queuer.ts:175](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L175) +Defined in: [async-queuer.ts:191](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L191) Optional callback to call when a task succeeds @@ -351,7 +363,7 @@ Optional callback to call when a task succeeds optional started: boolean; ``` -Defined in: [async-queuer.ts:179](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L179) +Defined in: [async-queuer.ts:195](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L195) Whether the queuer should start processing tasks immediately or not. @@ -363,7 +375,7 @@ Whether the queuer should start processing tasks immediately or not. optional throwOnError: boolean; ``` -Defined in: [async-queuer.ts:185](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L185) +Defined in: [async-queuer.ts:201](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L201) Whether to throw errors when they occur. Defaults to true if no onError handler is provided, false if an onError handler is provided. @@ -377,7 +389,7 @@ Can be explicitly set to override these defaults. optional wait: number | (queuer) => number; ``` -Defined in: [async-queuer.ts:191](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L191) +Defined in: [async-queuer.ts:207](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L207) Time in milliseconds to wait between processing items. Can be a number or a function that returns a number. diff --git a/docs/reference/interfaces/asyncqueuerstate.md b/docs/reference/interfaces/asyncqueuerstate.md index 01d49279..c327be73 100644 --- a/docs/reference/interfaces/asyncqueuerstate.md +++ b/docs/reference/interfaces/asyncqueuerstate.md @@ -7,7 +7,7 @@ title: AsyncQueuerState # Interface: AsyncQueuerState\ -Defined in: [async-queuer.ts:7](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L7) +Defined in: [async-queuer.ts:9](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L9) ## Type Parameters @@ -21,7 +21,7 @@ Defined in: [async-queuer.ts:7](https://github.com/TanStack/pacer/blob/main/pack activeItems: TValue[]; ``` -Defined in: [async-queuer.ts:11](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L11) +Defined in: [async-queuer.ts:13](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L13) Items currently being processed by the queuer @@ -33,7 +33,7 @@ Items currently being processed by the queuer addItemCount: number; ``` -Defined in: [async-queuer.ts:15](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L15) +Defined in: [async-queuer.ts:17](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L17) Number of times addItem has been called (for reduction calculations) @@ -45,19 +45,31 @@ Number of times addItem has been called (for reduction calculations) errorCount: number; ``` -Defined in: [async-queuer.ts:19](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L19) +Defined in: [async-queuer.ts:21](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L21) Number of task executions that have resulted in errors *** +### executeCount + +```ts +executeCount: number; +``` + +Defined in: [async-queuer.ts:25](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L25) + +Number of times execute has been called + +*** + ### expirationCount ```ts expirationCount: number; ``` -Defined in: [async-queuer.ts:23](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L23) +Defined in: [async-queuer.ts:29](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L29) Number of items that have been removed from the queue due to expiration @@ -69,19 +81,31 @@ Number of items that have been removed from the queue due to expiration isEmpty: boolean; ``` -Defined in: [async-queuer.ts:27](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L27) +Defined in: [async-queuer.ts:33](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L33) Whether the queuer has no items to process (items array is empty) *** +### isExecuting + +```ts +isExecuting: boolean; +``` + +Defined in: [async-queuer.ts:37](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L37) + +Whether the queuer is currently executing + +*** + ### isFull ```ts isFull: boolean; ``` -Defined in: [async-queuer.ts:31](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L31) +Defined in: [async-queuer.ts:41](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L41) Whether the queuer has reached its maximum capacity @@ -93,7 +117,7 @@ Whether the queuer has reached its maximum capacity isIdle: boolean; ``` -Defined in: [async-queuer.ts:35](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L35) +Defined in: [async-queuer.ts:45](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L45) Whether the queuer is not currently processing any items @@ -105,7 +129,7 @@ Whether the queuer is not currently processing any items isRunning: boolean; ``` -Defined in: [async-queuer.ts:39](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L39) +Defined in: [async-queuer.ts:49](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L49) Whether the queuer is active and will process items automatically @@ -117,7 +141,7 @@ Whether the queuer is active and will process items automatically items: TValue[]; ``` -Defined in: [async-queuer.ts:43](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L43) +Defined in: [async-queuer.ts:53](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L53) Array of items currently waiting to be processed @@ -129,7 +153,7 @@ Array of items currently waiting to be processed itemTimestamps: number[]; ``` -Defined in: [async-queuer.ts:47](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L47) +Defined in: [async-queuer.ts:57](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L57) Timestamps when items were added to the queue for expiration tracking @@ -141,7 +165,7 @@ Timestamps when items were added to the queue for expiration tracking lastResult: any; ``` -Defined in: [async-queuer.ts:51](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L51) +Defined in: [async-queuer.ts:61](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L61) The result from the most recent task execution @@ -153,7 +177,7 @@ The result from the most recent task execution pendingTick: boolean; ``` -Defined in: [async-queuer.ts:55](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L55) +Defined in: [async-queuer.ts:65](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L65) Whether the queuer has a pending timeout for processing the next item @@ -165,7 +189,7 @@ Whether the queuer has a pending timeout for processing the next item rejectionCount: number; ``` -Defined in: [async-queuer.ts:59](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L59) +Defined in: [async-queuer.ts:69](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L69) Number of items that have been rejected from being added to the queue @@ -177,7 +201,7 @@ Number of items that have been rejected from being added to the queue settledCount: number; ``` -Defined in: [async-queuer.ts:63](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L63) +Defined in: [async-queuer.ts:73](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L73) Number of task executions that have completed (either successfully or with errors) @@ -189,7 +213,7 @@ Number of task executions that have completed (either successfully or with error size: number; ``` -Defined in: [async-queuer.ts:67](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L67) +Defined in: [async-queuer.ts:77](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L77) Number of items currently in the queue @@ -201,7 +225,7 @@ Number of items currently in the queue status: "idle" | "running" | "stopped"; ``` -Defined in: [async-queuer.ts:71](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L71) +Defined in: [async-queuer.ts:81](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L81) Current processing status - 'idle' when not processing, 'running' when active, 'stopped' when paused @@ -213,6 +237,6 @@ Current processing status - 'idle' when not processing, 'running' when active, ' successCount: number; ``` -Defined in: [async-queuer.ts:75](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L75) +Defined in: [async-queuer.ts:85](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-queuer.ts#L85) Number of task executions that have completed successfully diff --git a/docs/reference/interfaces/asyncratelimiteroptions.md b/docs/reference/interfaces/asyncratelimiteroptions.md index 89a7bacf..9e418bbc 100644 --- a/docs/reference/interfaces/asyncratelimiteroptions.md +++ b/docs/reference/interfaces/asyncratelimiteroptions.md @@ -7,7 +7,7 @@ title: AsyncRateLimiterOptions # Interface: AsyncRateLimiterOptions\ -Defined in: [async-rate-limiter.ts:69](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L69) +Defined in: [async-rate-limiter.ts:71](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L71) Options for configuring an async rate-limited function @@ -17,13 +17,25 @@ Options for configuring an async rate-limited function ## Properties +### asyncRetryerOptions? + +```ts +optional asyncRetryerOptions: AsyncRetryerOptions; +``` + +Defined in: [async-rate-limiter.ts:75](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L75) + +Options for configuring the underlying async retryer + +*** + ### enabled? ```ts optional enabled: boolean | (rateLimiter) => boolean; ``` -Defined in: [async-rate-limiter.ts:75](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L75) +Defined in: [async-rate-limiter.ts:81](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L81) Whether the rate limiter is enabled. When disabled, maybeExecute will not trigger any executions. Can be a boolean or a function that returns a boolean. @@ -37,7 +49,7 @@ Defaults to true. optional initialState: Partial>; ``` -Defined in: [async-rate-limiter.ts:79](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L79) +Defined in: [async-rate-limiter.ts:85](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L85) Initial state for the rate limiter @@ -49,7 +61,7 @@ Initial state for the rate limiter optional key: string; ``` -Defined in: [async-rate-limiter.ts:84](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L84) +Defined in: [async-rate-limiter.ts:90](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L90) Optional key to identify this async rate limiter instance. If provided, the async rate limiter will be identified by this key in the devtools and PacerProvider if applicable. @@ -62,7 +74,7 @@ If provided, the async rate limiter will be identified by this key in the devtoo limit: number | (rateLimiter) => number; ``` -Defined in: [async-rate-limiter.ts:89](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L89) +Defined in: [async-rate-limiter.ts:95](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L95) Maximum number of executions allowed within the time window. Can be a number or a function that returns a number. @@ -75,7 +87,7 @@ Can be a number or a function that returns a number. optional onError: (error, args, rateLimiter) => void; ``` -Defined in: [async-rate-limiter.ts:95](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L95) +Defined in: [async-rate-limiter.ts:101](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L101) Optional error handler for when the rate-limited function throws. If provided, the handler will be called with the error and rate limiter instance. @@ -85,7 +97,7 @@ This can be used alongside throwOnError - the handler will be called before any ##### error -`unknown` +`Error` ##### args @@ -107,7 +119,7 @@ This can be used alongside throwOnError - the handler will be called before any optional onReject: (args, rateLimiter) => void; ``` -Defined in: [async-rate-limiter.ts:103](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L103) +Defined in: [async-rate-limiter.ts:109](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L109) Optional callback function that is called when an execution is rejected due to rate limiting @@ -133,7 +145,7 @@ Optional callback function that is called when an execution is rejected due to r optional onSettled: (args, rateLimiter) => void; ``` -Defined in: [async-rate-limiter.ts:107](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L107) +Defined in: [async-rate-limiter.ts:113](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L113) Optional function to call when the rate-limited function is executed @@ -159,7 +171,7 @@ Optional function to call when the rate-limited function is executed optional onSuccess: (result, args, rateLimiter) => void; ``` -Defined in: [async-rate-limiter.ts:114](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L114) +Defined in: [async-rate-limiter.ts:120](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L120) Optional function to call when the rate-limited function is executed @@ -189,7 +201,7 @@ Optional function to call when the rate-limited function is executed optional throwOnError: boolean; ``` -Defined in: [async-rate-limiter.ts:124](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L124) +Defined in: [async-rate-limiter.ts:130](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L130) Whether to throw errors when they occur. Defaults to true if no onError handler is provided, false if an onError handler is provided. @@ -203,7 +215,7 @@ Can be explicitly set to override these defaults. window: number | (rateLimiter) => number; ``` -Defined in: [async-rate-limiter.ts:129](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L129) +Defined in: [async-rate-limiter.ts:135](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L135) Time window in milliseconds within which the limit applies. Can be a number or a function that returns a number. @@ -216,7 +228,7 @@ Can be a number or a function that returns a number. optional windowType: "fixed" | "sliding"; ``` -Defined in: [async-rate-limiter.ts:136](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L136) +Defined in: [async-rate-limiter.ts:142](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L142) Type of window to use for rate limiting - 'fixed': Uses a fixed window that resets after the window period diff --git a/docs/reference/interfaces/asyncratelimiterstate.md b/docs/reference/interfaces/asyncratelimiterstate.md index 9efddb6b..3d153430 100644 --- a/docs/reference/interfaces/asyncratelimiterstate.md +++ b/docs/reference/interfaces/asyncratelimiterstate.md @@ -7,7 +7,7 @@ title: AsyncRateLimiterState # Interface: AsyncRateLimiterState\ -Defined in: [async-rate-limiter.ts:6](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L6) +Defined in: [async-rate-limiter.ts:8](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L8) ## Type Parameters @@ -21,7 +21,7 @@ Defined in: [async-rate-limiter.ts:6](https://github.com/TanStack/pacer/blob/mai errorCount: number; ``` -Defined in: [async-rate-limiter.ts:10](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L10) +Defined in: [async-rate-limiter.ts:12](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L12) Number of function executions that have resulted in errors @@ -33,7 +33,7 @@ Number of function executions that have resulted in errors executionTimes: number[]; ``` -Defined in: [async-rate-limiter.ts:14](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L14) +Defined in: [async-rate-limiter.ts:16](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L16) Array of timestamps when executions occurred for rate limiting calculations @@ -45,7 +45,7 @@ Array of timestamps when executions occurred for rate limiting calculations isExceeded: boolean; ``` -Defined in: [async-rate-limiter.ts:18](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L18) +Defined in: [async-rate-limiter.ts:20](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L20) Whether the rate limiter has exceeded the limit @@ -57,7 +57,7 @@ Whether the rate limiter has exceeded the limit isExecuting: boolean; ``` -Defined in: [async-rate-limiter.ts:22](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L22) +Defined in: [async-rate-limiter.ts:24](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L24) Whether the rate-limited function is currently executing asynchronously @@ -69,7 +69,7 @@ Whether the rate-limited function is currently executing asynchronously lastResult: undefined | ReturnType; ``` -Defined in: [async-rate-limiter.ts:26](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L26) +Defined in: [async-rate-limiter.ts:28](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L28) The result from the most recent successful function execution @@ -81,7 +81,7 @@ The result from the most recent successful function execution maybeExecuteCount: number; ``` -Defined in: [async-rate-limiter.ts:46](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L46) +Defined in: [async-rate-limiter.ts:48](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L48) Number of times maybeExecute has been called (for reduction calculations) @@ -93,7 +93,7 @@ Number of times maybeExecute has been called (for reduction calculations) rejectionCount: number; ``` -Defined in: [async-rate-limiter.ts:30](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L30) +Defined in: [async-rate-limiter.ts:32](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L32) Number of function executions that have been rejected due to rate limiting @@ -105,7 +105,7 @@ Number of function executions that have been rejected due to rate limiting settleCount: number; ``` -Defined in: [async-rate-limiter.ts:34](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L34) +Defined in: [async-rate-limiter.ts:36](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L36) Number of function executions that have completed (either successfully or with errors) @@ -117,7 +117,7 @@ Number of function executions that have completed (either successfully or with e status: "disabled" | "idle" | "executing" | "exceeded"; ``` -Defined in: [async-rate-limiter.ts:38](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L38) +Defined in: [async-rate-limiter.ts:40](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L40) Current execution status - 'disabled' when not active, 'executing' when executing, 'idle' when not executing, 'exceeded' when rate limit is exceeded @@ -129,6 +129,6 @@ Current execution status - 'disabled' when not active, 'executing' when executin successCount: number; ``` -Defined in: [async-rate-limiter.ts:42](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L42) +Defined in: [async-rate-limiter.ts:44](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-rate-limiter.ts#L44) Number of function executions that have completed successfully diff --git a/docs/reference/interfaces/asyncretryeroptions.md b/docs/reference/interfaces/asyncretryeroptions.md new file mode 100644 index 00000000..ceed5adc --- /dev/null +++ b/docs/reference/interfaces/asyncretryeroptions.md @@ -0,0 +1,295 @@ +--- +id: AsyncRetryerOptions +title: AsyncRetryerOptions +--- + + + +# Interface: AsyncRetryerOptions\ + +Defined in: [async-retryer.ts:60](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L60) + +## Type Parameters + +• **TFn** *extends* [`AnyAsyncFunction`](../../type-aliases/anyasyncfunction.md) + +## Properties + +### backoff? + +```ts +optional backoff: "linear" | "exponential" | "fixed"; +``` + +Defined in: [async-retryer.ts:68](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L68) + +The backoff strategy for retry delays: +- 'exponential': Wait time doubles with each attempt (1s, 2s, 4s, ...) +- 'linear': Wait time increases linearly (1s, 2s, 3s, ...) +- 'fixed': Same wait time for all attempts + +#### Default + +```ts +'exponential' +``` + +*** + +### baseWait? + +```ts +optional baseWait: number | (retryer) => number; +``` + +Defined in: [async-retryer.ts:73](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L73) + +Base wait time in milliseconds between retries, or a function that returns the wait time + +#### Default + +```ts +1000 +``` + +*** + +### enabled? + +```ts +optional enabled: boolean | (retryer) => boolean; +``` + +Defined in: [async-retryer.ts:78](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L78) + +Whether the retryer is enabled, or a function that determines if it's enabled + +#### Default + +```ts +true +``` + +*** + +### initialState? + +```ts +optional initialState: Partial>; +``` + +Defined in: [async-retryer.ts:82](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L82) + +Initial state to merge with the default state + +*** + +### jitter? + +```ts +optional jitter: number; +``` + +Defined in: [async-retryer.ts:92](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L92) + +Jitter percentage to add to retry delays (0-1). Adds randomness to prevent thundering herd. + +#### Default + +```ts +0 +``` + +*** + +### key? + +```ts +optional key: string; +``` + +Defined in: [async-retryer.ts:87](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L87) + +Optional key to identify this async retryer instance. +If provided, the async retryer will be identified by this key in the devtools and PacerProvider if applicable. + +*** + +### maxAttempts? + +```ts +optional maxAttempts: number | (retryer) => number; +``` + +Defined in: [async-retryer.ts:97](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L97) + +Maximum number of retry attempts, or a function that returns the max attempts + +#### Default + +```ts +3 +``` + +*** + +### onError()? + +```ts +optional onError: (error, args, retryer) => void; +``` + +Defined in: [async-retryer.ts:101](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L101) + +Callback invoked when any error occurs during execution (including retries) + +#### Parameters + +##### error + +`Error` + +##### args + +`Parameters`\<`TFn`\> + +##### retryer + +[`AsyncRetryer`](../../classes/asyncretryer.md)\<`TFn`\> + +#### Returns + +`void` + +*** + +### onLastError()? + +```ts +optional onLastError: (error, retryer) => void; +``` + +Defined in: [async-retryer.ts:109](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L109) + +Callback invoked when the final error occurs after all retries are exhausted + +#### Parameters + +##### error + +`Error` + +##### retryer + +[`AsyncRetryer`](../../classes/asyncretryer.md)\<`TFn`\> + +#### Returns + +`void` + +*** + +### onRetry()? + +```ts +optional onRetry: (attempt, error, retryer) => void; +``` + +Defined in: [async-retryer.ts:113](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L113) + +Callback invoked before each retry attempt + +#### Parameters + +##### attempt + +`number` + +##### error + +`Error` + +##### retryer + +[`AsyncRetryer`](../../classes/asyncretryer.md)\<`TFn`\> + +#### Returns + +`void` + +*** + +### onSettled()? + +```ts +optional onSettled: (args, retryer) => void; +``` + +Defined in: [async-retryer.ts:117](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L117) + +Callback invoked after execution completes (success or failure) + +#### Parameters + +##### args + +`Parameters`\<`TFn`\> + +##### retryer + +[`AsyncRetryer`](../../classes/asyncretryer.md)\<`TFn`\> + +#### Returns + +`void` + +*** + +### onSuccess()? + +```ts +optional onSuccess: (result, args, retryer) => void; +``` + +Defined in: [async-retryer.ts:121](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L121) + +Callback invoked when execution succeeds + +#### Parameters + +##### result + +`ReturnType`\<`TFn`\> + +##### args + +`Parameters`\<`TFn`\> + +##### retryer + +[`AsyncRetryer`](../../classes/asyncretryer.md)\<`TFn`\> + +#### Returns + +`void` + +*** + +### throwOnError? + +```ts +optional throwOnError: boolean | "last"; +``` + +Defined in: [async-retryer.ts:133](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L133) + +Controls when errors are thrown: +- 'last': Only throw the final error after all retries are exhausted +- true: Throw every error immediately (disables retrying) +- false: Never throw errors, return undefined instead + +#### Default + +```ts +'last' +``` diff --git a/docs/reference/interfaces/asyncretryerstate.md b/docs/reference/interfaces/asyncretryerstate.md new file mode 100644 index 00000000..3bc08be1 --- /dev/null +++ b/docs/reference/interfaces/asyncretryerstate.md @@ -0,0 +1,110 @@ +--- +id: AsyncRetryerState +title: AsyncRetryerState +--- + + + +# Interface: AsyncRetryerState\ + +Defined in: [async-retryer.ts:6](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L6) + +## Type Parameters + +• **TFn** *extends* [`AnyAsyncFunction`](../../type-aliases/anyasyncfunction.md) + +## Properties + +### currentAttempt + +```ts +currentAttempt: number; +``` + +Defined in: [async-retryer.ts:10](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L10) + +The current retry attempt number (0 when not executing) + +*** + +### executionCount + +```ts +executionCount: number; +``` + +Defined in: [async-retryer.ts:14](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L14) + +Total number of completed executions (successful or failed) + +*** + +### isExecuting + +```ts +isExecuting: boolean; +``` + +Defined in: [async-retryer.ts:18](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L18) + +Whether the retryer is currently executing the function + +*** + +### lastError + +```ts +lastError: undefined | Error; +``` + +Defined in: [async-retryer.ts:22](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L22) + +The most recent error encountered during execution + +*** + +### lastExecutionTime + +```ts +lastExecutionTime: number; +``` + +Defined in: [async-retryer.ts:26](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L26) + +Timestamp of the last execution completion in milliseconds + +*** + +### lastResult + +```ts +lastResult: undefined | ReturnType; +``` + +Defined in: [async-retryer.ts:30](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L30) + +The result from the most recent successful execution + +*** + +### status + +```ts +status: "disabled" | "idle" | "executing" | "retrying"; +``` + +Defined in: [async-retryer.ts:34](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L34) + +Current execution status - 'disabled' when not enabled, 'idle' when ready, 'executing' when running + +*** + +### totalExecutionTime + +```ts +totalExecutionTime: number; +``` + +Defined in: [async-retryer.ts:38](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-retryer.ts#L38) + +Total time spent executing (including retries) in milliseconds diff --git a/docs/reference/interfaces/asyncthrottleroptions.md b/docs/reference/interfaces/asyncthrottleroptions.md index dd555a61..2a9d28f8 100644 --- a/docs/reference/interfaces/asyncthrottleroptions.md +++ b/docs/reference/interfaces/asyncthrottleroptions.md @@ -7,7 +7,7 @@ title: AsyncThrottlerOptions # Interface: AsyncThrottlerOptions\ -Defined in: [async-throttler.ts:74](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L74) +Defined in: [async-throttler.ts:76](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L76) Options for configuring an async throttled function @@ -17,13 +17,25 @@ Options for configuring an async throttled function ## Properties +### asyncRetryerOptions? + +```ts +optional asyncRetryerOptions: AsyncRetryerOptions; +``` + +Defined in: [async-throttler.ts:80](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L80) + +Options for configuring the underlying async retryer + +*** + ### enabled? ```ts optional enabled: boolean | (throttler) => boolean; ``` -Defined in: [async-throttler.ts:80](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L80) +Defined in: [async-throttler.ts:86](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L86) Whether the throttler is enabled. When disabled, maybeExecute will not trigger any executions. Can be a boolean or a function that returns a boolean. @@ -37,7 +49,7 @@ Defaults to true. optional initialState: Partial>; ``` -Defined in: [async-throttler.ts:84](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L84) +Defined in: [async-throttler.ts:90](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L90) Initial state for the async throttler @@ -49,7 +61,7 @@ Initial state for the async throttler optional key: string; ``` -Defined in: [async-throttler.ts:89](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L89) +Defined in: [async-throttler.ts:95](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L95) Optional key to identify this async throttler instance. If provided, the async throttler will be identified by this key in the devtools and PacerProvider if applicable. @@ -62,7 +74,7 @@ If provided, the async throttler will be identified by this key in the devtools optional leading: boolean; ``` -Defined in: [async-throttler.ts:94](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L94) +Defined in: [async-throttler.ts:100](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L100) Whether to execute the function immediately when called Defaults to true @@ -75,7 +87,7 @@ Defaults to true optional onError: (error, args, asyncThrottler) => void; ``` -Defined in: [async-throttler.ts:100](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L100) +Defined in: [async-throttler.ts:106](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L106) Optional error handler for when the throttled function throws. If provided, the handler will be called with the error and throttler instance. @@ -85,7 +97,7 @@ This can be used alongside throwOnError - the handler will be called before any ##### error -`unknown` +`Error` ##### args @@ -107,7 +119,7 @@ This can be used alongside throwOnError - the handler will be called before any optional onSettled: (args, asyncThrottler) => void; ``` -Defined in: [async-throttler.ts:108](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L108) +Defined in: [async-throttler.ts:114](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L114) Optional function to call when the throttled function is executed @@ -133,7 +145,7 @@ Optional function to call when the throttled function is executed optional onSuccess: (result, args, asyncThrottler) => void; ``` -Defined in: [async-throttler.ts:115](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L115) +Defined in: [async-throttler.ts:121](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L121) Optional function to call when the throttled function is executed @@ -163,7 +175,7 @@ Optional function to call when the throttled function is executed optional throwOnError: boolean; ``` -Defined in: [async-throttler.ts:125](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L125) +Defined in: [async-throttler.ts:131](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L131) Whether to throw errors when they occur. Defaults to true if no onError handler is provided, false if an onError handler is provided. @@ -177,7 +189,7 @@ Can be explicitly set to override these defaults. optional trailing: boolean; ``` -Defined in: [async-throttler.ts:130](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L130) +Defined in: [async-throttler.ts:136](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L136) Whether to execute the function on the trailing edge of the wait period Defaults to true @@ -190,7 +202,7 @@ Defaults to true wait: number | (throttler) => number; ``` -Defined in: [async-throttler.ts:136](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L136) +Defined in: [async-throttler.ts:142](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L142) Time window in milliseconds during which the function can only be executed once. Can be a number or a function that returns a number. diff --git a/docs/reference/interfaces/asyncthrottlerstate.md b/docs/reference/interfaces/asyncthrottlerstate.md index 0b839bcc..2d191757 100644 --- a/docs/reference/interfaces/asyncthrottlerstate.md +++ b/docs/reference/interfaces/asyncthrottlerstate.md @@ -7,7 +7,7 @@ title: AsyncThrottlerState # Interface: AsyncThrottlerState\ -Defined in: [async-throttler.ts:6](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L6) +Defined in: [async-throttler.ts:8](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L8) ## Type Parameters @@ -21,7 +21,7 @@ Defined in: [async-throttler.ts:6](https://github.com/TanStack/pacer/blob/main/p errorCount: number; ``` -Defined in: [async-throttler.ts:10](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L10) +Defined in: [async-throttler.ts:12](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L12) Number of function executions that have resulted in errors @@ -33,7 +33,7 @@ Number of function executions that have resulted in errors isExecuting: boolean; ``` -Defined in: [async-throttler.ts:14](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L14) +Defined in: [async-throttler.ts:16](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L16) Whether the throttled function is currently executing asynchronously @@ -45,7 +45,7 @@ Whether the throttled function is currently executing asynchronously isPending: boolean; ``` -Defined in: [async-throttler.ts:18](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L18) +Defined in: [async-throttler.ts:20](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L20) Whether the throttler is waiting for the timeout to trigger execution @@ -57,7 +57,7 @@ Whether the throttler is waiting for the timeout to trigger execution lastArgs: undefined | Parameters; ``` -Defined in: [async-throttler.ts:22](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L22) +Defined in: [async-throttler.ts:24](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L24) The arguments from the most recent call to maybeExecute @@ -69,7 +69,7 @@ The arguments from the most recent call to maybeExecute lastExecutionTime: number; ``` -Defined in: [async-throttler.ts:26](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L26) +Defined in: [async-throttler.ts:28](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L28) Timestamp of the last function execution in milliseconds @@ -81,7 +81,7 @@ Timestamp of the last function execution in milliseconds lastResult: undefined | ReturnType; ``` -Defined in: [async-throttler.ts:30](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L30) +Defined in: [async-throttler.ts:32](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L32) The result from the most recent successful function execution @@ -93,7 +93,7 @@ The result from the most recent successful function execution maybeExecuteCount: number; ``` -Defined in: [async-throttler.ts:34](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L34) +Defined in: [async-throttler.ts:36](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L36) Number of times maybeExecute has been called (for reduction calculations) @@ -105,7 +105,7 @@ Number of times maybeExecute has been called (for reduction calculations) nextExecutionTime: undefined | number; ``` -Defined in: [async-throttler.ts:38](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L38) +Defined in: [async-throttler.ts:40](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L40) Timestamp when the next execution can occur in milliseconds @@ -117,7 +117,7 @@ Timestamp when the next execution can occur in milliseconds settleCount: number; ``` -Defined in: [async-throttler.ts:42](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L42) +Defined in: [async-throttler.ts:44](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L44) Number of function executions that have completed (either successfully or with errors) @@ -129,7 +129,7 @@ Number of function executions that have completed (either successfully or with e status: "disabled" | "idle" | "pending" | "executing" | "settled"; ``` -Defined in: [async-throttler.ts:46](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L46) +Defined in: [async-throttler.ts:48](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L48) Current execution status - 'idle' when not active, 'pending' when waiting, 'executing' when running, 'settled' when completed @@ -141,6 +141,6 @@ Current execution status - 'idle' when not active, 'pending' when waiting, 'exec successCount: number; ``` -Defined in: [async-throttler.ts:50](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L50) +Defined in: [async-throttler.ts:52](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/async-throttler.ts#L52) Number of function executions that have completed successfully diff --git a/docs/reference/interfaces/pacereventmap.md b/docs/reference/interfaces/pacereventmap.md index c3b2c862..76095348 100644 --- a/docs/reference/interfaces/pacereventmap.md +++ b/docs/reference/interfaces/pacereventmap.md @@ -7,7 +7,7 @@ title: PacerEventMap # Interface: PacerEventMap -Defined in: [event-client.ts:13](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L13) +Defined in: [event-client.ts:14](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L14) ## Properties @@ -17,7 +17,7 @@ Defined in: [event-client.ts:13](https://github.com/TanStack/pacer/blob/main/pac pacer:AsyncBatcher: AsyncBatcher; ``` -Defined in: [event-client.ts:24](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L24) +Defined in: [event-client.ts:26](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L26) *** @@ -27,7 +27,7 @@ Defined in: [event-client.ts:24](https://github.com/TanStack/pacer/blob/main/pac pacer:AsyncDebouncer: AsyncDebouncer; ``` -Defined in: [event-client.ts:25](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L25) +Defined in: [event-client.ts:27](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L27) *** @@ -37,7 +37,7 @@ Defined in: [event-client.ts:25](https://github.com/TanStack/pacer/blob/main/pac pacer:AsyncQueuer: AsyncQueuer; ``` -Defined in: [event-client.ts:26](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L26) +Defined in: [event-client.ts:28](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L28) *** @@ -47,7 +47,17 @@ Defined in: [event-client.ts:26](https://github.com/TanStack/pacer/blob/main/pac pacer:AsyncRateLimiter: AsyncRateLimiter; ``` -Defined in: [event-client.ts:27](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L27) +Defined in: [event-client.ts:29](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L29) + +*** + +### pacer:AsyncRetryer + +```ts +pacer:AsyncRetryer: AsyncRetryer; +``` + +Defined in: [event-client.ts:30](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L30) *** @@ -57,7 +67,7 @@ Defined in: [event-client.ts:27](https://github.com/TanStack/pacer/blob/main/pac pacer:AsyncThrottler: AsyncThrottler; ``` -Defined in: [event-client.ts:28](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L28) +Defined in: [event-client.ts:31](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L31) *** @@ -67,7 +77,7 @@ Defined in: [event-client.ts:28](https://github.com/TanStack/pacer/blob/main/pac pacer:Batcher: Batcher; ``` -Defined in: [event-client.ts:29](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L29) +Defined in: [event-client.ts:32](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L32) *** @@ -77,7 +87,7 @@ Defined in: [event-client.ts:29](https://github.com/TanStack/pacer/blob/main/pac pacer:d-AsyncBatcher: AsyncBatcher; ``` -Defined in: [event-client.ts:14](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L14) +Defined in: [event-client.ts:15](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L15) *** @@ -87,7 +97,7 @@ Defined in: [event-client.ts:14](https://github.com/TanStack/pacer/blob/main/pac pacer:d-AsyncDebouncer: AsyncDebouncer; ``` -Defined in: [event-client.ts:15](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L15) +Defined in: [event-client.ts:16](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L16) *** @@ -97,7 +107,7 @@ Defined in: [event-client.ts:15](https://github.com/TanStack/pacer/blob/main/pac pacer:d-AsyncQueuer: AsyncQueuer; ``` -Defined in: [event-client.ts:16](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L16) +Defined in: [event-client.ts:17](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L17) *** @@ -107,7 +117,17 @@ Defined in: [event-client.ts:16](https://github.com/TanStack/pacer/blob/main/pac pacer:d-AsyncRateLimiter: AsyncRateLimiter; ``` -Defined in: [event-client.ts:17](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L17) +Defined in: [event-client.ts:18](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L18) + +*** + +### pacer:d-AsyncRetryer + +```ts +pacer:d-AsyncRetryer: AsyncRetryer; +``` + +Defined in: [event-client.ts:19](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L19) *** @@ -117,7 +137,7 @@ Defined in: [event-client.ts:17](https://github.com/TanStack/pacer/blob/main/pac pacer:d-AsyncThrottler: AsyncThrottler; ``` -Defined in: [event-client.ts:18](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L18) +Defined in: [event-client.ts:20](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L20) *** @@ -127,7 +147,7 @@ Defined in: [event-client.ts:18](https://github.com/TanStack/pacer/blob/main/pac pacer:d-Batcher: Batcher; ``` -Defined in: [event-client.ts:19](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L19) +Defined in: [event-client.ts:21](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L21) *** @@ -137,7 +157,7 @@ Defined in: [event-client.ts:19](https://github.com/TanStack/pacer/blob/main/pac pacer:d-Debouncer: Debouncer; ``` -Defined in: [event-client.ts:20](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L20) +Defined in: [event-client.ts:22](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L22) *** @@ -147,7 +167,7 @@ Defined in: [event-client.ts:20](https://github.com/TanStack/pacer/blob/main/pac pacer:d-Queuer: Queuer; ``` -Defined in: [event-client.ts:21](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L21) +Defined in: [event-client.ts:23](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L23) *** @@ -157,7 +177,7 @@ Defined in: [event-client.ts:21](https://github.com/TanStack/pacer/blob/main/pac pacer:d-RateLimiter: RateLimiter; ``` -Defined in: [event-client.ts:22](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L22) +Defined in: [event-client.ts:24](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L24) *** @@ -167,7 +187,7 @@ Defined in: [event-client.ts:22](https://github.com/TanStack/pacer/blob/main/pac pacer:d-Throttler: Throttler; ``` -Defined in: [event-client.ts:23](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L23) +Defined in: [event-client.ts:25](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L25) *** @@ -177,7 +197,7 @@ Defined in: [event-client.ts:23](https://github.com/TanStack/pacer/blob/main/pac pacer:Debouncer: Debouncer; ``` -Defined in: [event-client.ts:30](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L30) +Defined in: [event-client.ts:33](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L33) *** @@ -187,7 +207,7 @@ Defined in: [event-client.ts:30](https://github.com/TanStack/pacer/blob/main/pac pacer:Queuer: Queuer; ``` -Defined in: [event-client.ts:31](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L31) +Defined in: [event-client.ts:34](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L34) *** @@ -197,7 +217,7 @@ Defined in: [event-client.ts:31](https://github.com/TanStack/pacer/blob/main/pac pacer:RateLimiter: RateLimiter; ``` -Defined in: [event-client.ts:32](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L32) +Defined in: [event-client.ts:35](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L35) *** @@ -207,4 +227,4 @@ Defined in: [event-client.ts:32](https://github.com/TanStack/pacer/blob/main/pac pacer:Throttler: Throttler; ``` -Defined in: [event-client.ts:33](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L33) +Defined in: [event-client.ts:36](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L36) diff --git a/docs/reference/type-aliases/pacereventname.md b/docs/reference/type-aliases/pacereventname.md index 37966115..27060281 100644 --- a/docs/reference/type-aliases/pacereventname.md +++ b/docs/reference/type-aliases/pacereventname.md @@ -11,4 +11,4 @@ title: PacerEventName type PacerEventName = keyof PacerEventMap extends `pacer:${infer T}` ? T : never; ``` -Defined in: [event-client.ts:36](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L36) +Defined in: [event-client.ts:39](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L39) diff --git a/docs/reference/variables/pacereventclient.md b/docs/reference/variables/pacereventclient.md index ea0d496c..eb89579c 100644 --- a/docs/reference/variables/pacereventclient.md +++ b/docs/reference/variables/pacereventclient.md @@ -11,4 +11,4 @@ title: pacerEventClient const pacerEventClient: PacerEventClient; ``` -Defined in: [event-client.ts:63](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L63) +Defined in: [event-client.ts:66](https://github.com/TanStack/pacer/blob/main/packages/pacer/src/event-client.ts#L66) diff --git a/examples/react/asyncBatch/package.json b/examples/react/asyncBatch/package.json index c2df3c42..ac7dbcbf 100644 --- a/examples/react/asyncBatch/package.json +++ b/examples/react/asyncBatch/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/asyncBatch/src/index.tsx b/examples/react/asyncBatch/src/index.tsx index be35e2b1..10e19a77 100644 --- a/examples/react/asyncBatch/src/index.tsx +++ b/examples/react/asyncBatch/src/index.tsx @@ -53,7 +53,7 @@ function App() { } catch (error: any) { setErrors((prev) => [ ...prev, - `Error: ${error.message} (${new Date().toLocaleTimeString()})`, + `Error: ${error} (${new Date().toLocaleTimeString()})`, ]) setErrorCount((prev) => prev + 1) console.error('Batch failed:', error) diff --git a/examples/react/asyncDebounce/package.json b/examples/react/asyncDebounce/package.json index 10d86eb3..e9b44279 100644 --- a/examples/react/asyncDebounce/package.json +++ b/examples/react/asyncDebounce/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/asyncRateLimit/package.json b/examples/react/asyncRateLimit/package.json index f5046768..55c3df58 100644 --- a/examples/react/asyncRateLimit/package.json +++ b/examples/react/asyncRateLimit/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/asyncThrottle/package.json b/examples/react/asyncThrottle/package.json index f9258293..c418fe07 100644 --- a/examples/react/asyncThrottle/package.json +++ b/examples/react/asyncThrottle/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/batch/package.json b/examples/react/batch/package.json index 413d092d..6a5bbb6c 100644 --- a/examples/react/batch/package.json +++ b/examples/react/batch/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/debounce/package.json b/examples/react/debounce/package.json index e2ff68f3..ce3b6ba0 100644 --- a/examples/react/debounce/package.json +++ b/examples/react/debounce/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/queue/package.json b/examples/react/queue/package.json index af4f0939..f2310921 100644 --- a/examples/react/queue/package.json +++ b/examples/react/queue/package.json @@ -14,10 +14,10 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@tanstack/react-devtools": "0.7.0", + "@tanstack/react-devtools": "0.7.1", "@tanstack/react-pacer-devtools": "0.3.1", - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/rateLimit/package.json b/examples/react/rateLimit/package.json index a8534be3..d65194e0 100644 --- a/examples/react/rateLimit/package.json +++ b/examples/react/rateLimit/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/react-query-debounced-prefetch/package.json b/examples/react/react-query-debounced-prefetch/package.json index 61bdb26a..c0362188 100644 --- a/examples/react/react-query-debounced-prefetch/package.json +++ b/examples/react/react-query-debounced-prefetch/package.json @@ -16,8 +16,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/react-query-queued-prefetch/package.json b/examples/react/react-query-queued-prefetch/package.json index be9e132f..d7040d24 100644 --- a/examples/react/react-query-queued-prefetch/package.json +++ b/examples/react/react-query-queued-prefetch/package.json @@ -16,8 +16,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/react-query-throttled-prefetch/package.json b/examples/react/react-query-throttled-prefetch/package.json index d181a72b..45f462a5 100644 --- a/examples/react/react-query-throttled-prefetch/package.json +++ b/examples/react/react-query-throttled-prefetch/package.json @@ -16,8 +16,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/throttle/package.json b/examples/react/throttle/package.json index ed5c7ad2..9d020fc6 100644 --- a/examples/react/throttle/package.json +++ b/examples/react/throttle/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncBatchedCallback/package.json b/examples/react/useAsyncBatchedCallback/package.json index ea84495e..861a326e 100644 --- a/examples/react/useAsyncBatchedCallback/package.json +++ b/examples/react/useAsyncBatchedCallback/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncBatcher/package.json b/examples/react/useAsyncBatcher/package.json index c59844d0..219ded29 100644 --- a/examples/react/useAsyncBatcher/package.json +++ b/examples/react/useAsyncBatcher/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncBatcher/src/index.tsx b/examples/react/useAsyncBatcher/src/index.tsx index c7ea201b..253059a6 100644 --- a/examples/react/useAsyncBatcher/src/index.tsx +++ b/examples/react/useAsyncBatcher/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useAsyncBatcher } from '@tanstack/react-pacer/async-batcher' +import { PacerProvider } from '@tanstack/react-pacer/provider' const fakeProcessingTime = 1000 @@ -15,7 +16,6 @@ function App() { Array<{ items: Array; result: string; timestamp: number }> >([]) const [errors, setErrors] = useState>([]) - const [shouldFail, setShouldFail] = useState(false) // The async function that will process a batch of items async function processBatch(items: Array): Promise { @@ -25,9 +25,8 @@ function App() { await new Promise((resolve) => setTimeout(resolve, fakeProcessingTime)) // Simulate occasional failures for demo purposes - if (shouldFail && Math.random() < 0.3) { - throw new Error(`Processing failed for batch with ${items.length} items`) - } + + // throw new Error(`Processing failed for batch with ${items.length} items`) // Return a result from the batch processing const result = `Processed ${items.length} items: ${items.map((item) => item.value).join(', ')}` @@ -60,7 +59,7 @@ function App() { console.error('Batch failed:', error) setErrors((prev) => [ ...prev, - `Error: ${error.message} (${new Date().toLocaleTimeString()})`, + `Error: ${error} (${new Date().toLocaleTimeString()})`, ]) }, onSettled: (batch, batcher) => { @@ -165,17 +164,6 @@ function App() { Clear Current Batch - -
- -
@@ -215,4 +203,15 @@ function App() { } const root = ReactDOM.createRoot(document.getElementById('root')!) -root.render() +root.render( + // optionally, provide default options to an optional PacerProvider + + + , +) diff --git a/examples/react/useAsyncDebouncedCallback/package.json b/examples/react/useAsyncDebouncedCallback/package.json index 12f220ec..86820e92 100644 --- a/examples/react/useAsyncDebouncedCallback/package.json +++ b/examples/react/useAsyncDebouncedCallback/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncDebouncer/package.json b/examples/react/useAsyncDebouncer/package.json index f3315969..53d35083 100644 --- a/examples/react/useAsyncDebouncer/package.json +++ b/examples/react/useAsyncDebouncer/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncDebouncer/src/index.tsx b/examples/react/useAsyncDebouncer/src/index.tsx index 956aded5..620111e4 100644 --- a/examples/react/useAsyncDebouncer/src/index.tsx +++ b/examples/react/useAsyncDebouncer/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useAsyncDebouncer } from '@tanstack/react-pacer/async-debouncer' +import { PacerProvider } from '@tanstack/react-pacer/provider' interface SearchResult { id: number @@ -23,7 +24,6 @@ function App() { // The function that will become debounced const handleSearch = async (term: string) => { - throw new Error('Test error') if (!term) { setResults([]) return @@ -106,13 +106,29 @@ function App() { const root = ReactDOM.createRoot(document.getElementById('root')!) +function renderApp(mounted: boolean) { + root.render( + mounted ? ( + // defaultOptions can be provided to the PacerProvider to set default options for all instances + + + + ) : null, + ) +} + let mounted = true -root.render() +renderApp(mounted) -// demo unmounting and cancellation document.addEventListener('keydown', (e) => { if (e.shiftKey && e.key === 'Enter') { mounted = !mounted - root.render(mounted ? : null) + renderApp(mounted) } }) diff --git a/examples/react/useAsyncQueuedState/package.json b/examples/react/useAsyncQueuedState/package.json index e96187da..3f9984d9 100644 --- a/examples/react/useAsyncQueuedState/package.json +++ b/examples/react/useAsyncQueuedState/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncQueuedState/src/index.tsx b/examples/react/useAsyncQueuedState/src/index.tsx index 0153e792..0c2e5ead 100644 --- a/examples/react/useAsyncQueuedState/src/index.tsx +++ b/examples/react/useAsyncQueuedState/src/index.tsx @@ -31,7 +31,7 @@ function App() { asyncQueuer.store.state.rejectionCount, ) }, - onError: (error: unknown, item: Item, asyncQueuer) => { + onError: (error, item: Item, asyncQueuer) => { console.error( `Error processing item: ${item}`, error, diff --git a/examples/react/useAsyncQueuer/package.json b/examples/react/useAsyncQueuer/package.json index 0a6c8374..dac66649 100644 --- a/examples/react/useAsyncQueuer/package.json +++ b/examples/react/useAsyncQueuer/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncQueuer/src/index.tsx b/examples/react/useAsyncQueuer/src/index.tsx index 28899e78..4c611363 100644 --- a/examples/react/useAsyncQueuer/src/index.tsx +++ b/examples/react/useAsyncQueuer/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useAsyncQueuer } from '@tanstack/react-pacer/async-queuer' +import { PacerProvider } from '@tanstack/react-pacer/provider' const fakeWaitTime = 500 @@ -30,7 +31,7 @@ function App() { asyncQueuer.store.state.rejectionCount, ) }, - onError: (error: unknown, item: Item, asyncQueuer) => { + onError: (error, item: Item, asyncQueuer) => { console.error( `Error processing item: ${item}`, error, @@ -142,4 +143,15 @@ function App() { } const root = ReactDOM.createRoot(document.getElementById('root')!) -root.render() +root.render( + // optionally, provide default options to an optional PacerProvider + + + , +) diff --git a/examples/react/useAsyncRateLimiter/package.json b/examples/react/useAsyncRateLimiter/package.json index 90c8fb84..0682a88f 100644 --- a/examples/react/useAsyncRateLimiter/package.json +++ b/examples/react/useAsyncRateLimiter/package.json @@ -15,8 +15,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncRateLimiter/src/index.tsx b/examples/react/useAsyncRateLimiter/src/index.tsx index e88ef1e3..2e157f67 100644 --- a/examples/react/useAsyncRateLimiter/src/index.tsx +++ b/examples/react/useAsyncRateLimiter/src/index.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react' import ReactDOM from 'react-dom/client' import { useAsyncRateLimiter } from '@tanstack/react-pacer/async-rate-limiter' +import { PacerProvider } from '@tanstack/react-pacer/provider' interface SearchResult { id: number @@ -165,12 +166,36 @@ function App() { const root = ReactDOM.createRoot(document.getElementById('root')!) let mounted = true -root.render() +root.render( + // optionally, provide default options to an optional PacerProvider + + + , +) // demo unmounting and cancellation document.addEventListener('keydown', (e) => { if (e.key === 'Enter') { mounted = !mounted - root.render(mounted ? : null) + root.render( + mounted ? ( + // optionally, provide default options to an optional PacerProvider + + + + ) : null, + ) } }) diff --git a/examples/react/useAsyncRateLimiterWithPersister/package.json b/examples/react/useAsyncRateLimiterWithPersister/package.json index a6b0e50e..099da11a 100644 --- a/examples/react/useAsyncRateLimiterWithPersister/package.json +++ b/examples/react/useAsyncRateLimiterWithPersister/package.json @@ -15,8 +15,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncRetryer/.eslintrc.cjs b/examples/react/useAsyncRetryer/.eslintrc.cjs new file mode 100644 index 00000000..9ff0b9fc --- /dev/null +++ b/examples/react/useAsyncRetryer/.eslintrc.cjs @@ -0,0 +1,13 @@ +// @ts-check + +/** @type {import('eslint').Linter.Config} */ +const config = { + settings: { + extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], + rules: { + 'react/no-children-prop': 'off', + }, + }, +} + +module.exports = config diff --git a/examples/react/useAsyncRetryer/.gitignore b/examples/react/useAsyncRetryer/.gitignore new file mode 100644 index 00000000..4673b022 --- /dev/null +++ b/examples/react/useAsyncRetryer/.gitignore @@ -0,0 +1,27 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +pnpm-lock.yaml +yarn.lock +package-lock.json + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/examples/react/useAsyncRetryer/README.md b/examples/react/useAsyncRetryer/README.md new file mode 100644 index 00000000..1cf88926 --- /dev/null +++ b/examples/react/useAsyncRetryer/README.md @@ -0,0 +1,6 @@ +# Example + +To run this example: + +- `npm install` +- `npm run dev` diff --git a/examples/react/useAsyncRetryer/index.html b/examples/react/useAsyncRetryer/index.html new file mode 100644 index 00000000..701aa26e --- /dev/null +++ b/examples/react/useAsyncRetryer/index.html @@ -0,0 +1,16 @@ + + + + + + + + + TanStack Pacer Example + + + +
+ + + diff --git a/examples/react/useAsyncRetryer/package.json b/examples/react/useAsyncRetryer/package.json new file mode 100644 index 00000000..07d3f48f --- /dev/null +++ b/examples/react/useAsyncRetryer/package.json @@ -0,0 +1,34 @@ +{ + "name": "@tanstack/pacer-example-react-use-async-retryer", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3005", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/react-pacer": "^0.16.4", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", + "@vitejs/plugin-react": "^5.0.4", + "vite": "^7.1.7" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/examples/react/useAsyncRetryer/public/emblem-light.svg b/examples/react/useAsyncRetryer/public/emblem-light.svg new file mode 100644 index 00000000..a58e69ad --- /dev/null +++ b/examples/react/useAsyncRetryer/public/emblem-light.svg @@ -0,0 +1,13 @@ + + + + emblem-light + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/examples/react/useAsyncRetryer/src/index.tsx b/examples/react/useAsyncRetryer/src/index.tsx new file mode 100644 index 00000000..0cc442b8 --- /dev/null +++ b/examples/react/useAsyncRetryer/src/index.tsx @@ -0,0 +1,169 @@ +import { useState } from 'react' +import ReactDOM from 'react-dom/client' +import { useAsyncRetryer } from '@tanstack/react-pacer/async-retryer' + +interface UserData { + id: number + name: string + email: string +} + +// Simulate API call with fake data that fails randomly +const fakeApi = async (userId: string): Promise => { + await new Promise((resolve) => setTimeout(resolve, 800)) // Simulate network delay + + // Randomly fail 60% of the time to demonstrate retry functionality + if (Math.random() < 0.6) { + throw new Error(`Network error fetching user ${userId}`) + } + + return { + id: parseInt(userId), + name: `User ${userId}`, + email: `user${userId}@example.com`, + } +} + +function App() { + const [userId, setUserId] = useState('123') + const [userData, setUserData] = useState(null) + + // The function that will be retried + const fetchUser = async (id: string) => { + const data = await fakeApi(id) + setUserData(data) + return data + } + + // hook that gives you an async retryer instance + const asyncRetryer = useAsyncRetryer( + fetchUser, + { + maxAttempts: 5, // Retry up to 5 times + backoff: 'exponential', // Exponential backoff (1s, 2s, 4s, 8s, 16s) + baseWait: 1000, // Start with 1 second wait + onRetry: (attempt, error) => { + console.log(`Retry attempt ${attempt} after error:`, error) + }, + onError: (error) => { + console.error('Request failed:', error) + }, + onLastError: (error) => { + console.error('All retries failed:', error) + setUserData(null) + }, + onSuccess: (result) => { + console.log('Request succeeded:', result) + }, + }, + // Optional Selector function to pick the state you want to track and use + (state) => ({ + isExecuting: state.isExecuting, + currentAttempt: state.currentAttempt, + executionCount: state.executionCount, + lastError: state.lastError, + status: state.status, + }), + ) + + // get and name our retry function + const handleFetchUser = asyncRetryer.execute + + // event handler that calls the retry function + async function onFetchUser() { + const result = await handleFetchUser(userId) // optionally await result if you need to + console.log('Final result:', result) + } + + return ( +
+

TanStack Pacer useAsyncRetryer Example

+
+ setUserId(e.target.value)} + placeholder="Enter user ID..." + style={{ marginRight: '10px' }} + /> + +
+ +
+ + +
+ +
+

+ Status: {asyncRetryer.state.status} +

+ {asyncRetryer.state.currentAttempt > 0 && ( +

+ Current Attempt:{' '} + {asyncRetryer.state.currentAttempt} +

+ )} +

+ Total Executions: {asyncRetryer.state.executionCount} +

+ {asyncRetryer.state.lastError && ( +

+ Last Error: {asyncRetryer.state.lastError.message} +

+ )} +
+ + {userData && ( +
+

User Data:

+

+ ID: {userData.id} +

+

+ Name: {userData.name} +

+

+ Email: {userData.email} +

+
+ )} + +
+        {JSON.stringify(asyncRetryer.store.state, null, 2)}
+      
+
+ ) +} + +const root = ReactDOM.createRoot(document.getElementById('root')!) + +let mounted = true +root.render() + +// demo unmounting and cancellation +document.addEventListener('keydown', (e) => { + if (e.shiftKey && e.key === 'Enter') { + mounted = !mounted + root.render(mounted ? : null) + } +}) diff --git a/examples/react/useAsyncRetryer/tsconfig.json b/examples/react/useAsyncRetryer/tsconfig.json new file mode 100644 index 00000000..6e9088d6 --- /dev/null +++ b/examples/react/useAsyncRetryer/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/react/useAsyncRetryer/vite.config.ts b/examples/react/useAsyncRetryer/vite.config.ts new file mode 100644 index 00000000..4e194366 --- /dev/null +++ b/examples/react/useAsyncRetryer/vite.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react({ + // babel: { + // plugins: [['babel-plugin-react-compiler', { target: '19' }]], + // }, + }), + ], +}) diff --git a/examples/react/useAsyncThrottler/package.json b/examples/react/useAsyncThrottler/package.json index 6ee9940f..5719042a 100644 --- a/examples/react/useAsyncThrottler/package.json +++ b/examples/react/useAsyncThrottler/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useAsyncThrottler/src/index.tsx b/examples/react/useAsyncThrottler/src/index.tsx index 2ef4878a..c9dedf1e 100644 --- a/examples/react/useAsyncThrottler/src/index.tsx +++ b/examples/react/useAsyncThrottler/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useAsyncThrottler } from '@tanstack/react-pacer/async-throttler' +import { PacerProvider } from '@tanstack/react-pacer/provider' interface SearchResult { id: number @@ -29,7 +30,7 @@ function App() { return } - throw new Error('Test error') // you don't have to catch errors here (though you still can). The onError optional handler will catch it + // throw new Error('Test error') // you don't have to catch errors here (though you still can). The onError optional handler will catch it const data = await fakeApi(term) setResults(data) @@ -54,11 +55,7 @@ function App() { // throwOnError: true, }, // Optional Selector function to pick the state you want to track and use - (state) => ({ - successCount: state.successCount, - isPending: state.isPending, - isExecuting: state.isExecuting, - }), + (state) => state, ) // get and name our throttled function @@ -114,13 +111,15 @@ function App() { const root = ReactDOM.createRoot(document.getElementById('root')!) -let mounted = true -root.render() - -// demo unmounting and cancellation -document.addEventListener('keydown', (e) => { - if (e.shiftKey && e.key === 'Enter') { - mounted = !mounted - root.render(mounted ? : null) - } -}) +// optionally, provide default options to an optional PacerProvider +root.render( + + + , +) diff --git a/examples/react/useBatchedCallback/package.json b/examples/react/useBatchedCallback/package.json index 9461039b..a94437b0 100644 --- a/examples/react/useBatchedCallback/package.json +++ b/examples/react/useBatchedCallback/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useBatcher/package.json b/examples/react/useBatcher/package.json index 17016793..6bb11067 100644 --- a/examples/react/useBatcher/package.json +++ b/examples/react/useBatcher/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useBatcher/src/index.tsx b/examples/react/useBatcher/src/index.tsx index 03e9bd8b..2fed18f9 100644 --- a/examples/react/useBatcher/src/index.tsx +++ b/examples/react/useBatcher/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useBatcher } from '@tanstack/react-pacer/batcher' +import { PacerProvider } from '@tanstack/react-pacer/provider' function App1() { // Use your state management library of choice @@ -83,8 +84,17 @@ function App1() { const root = ReactDOM.createRoot(document.getElementById('root')!) root.render( -
- -
-
, + // optionally, provide default options to an optional PacerProvider + +
+ +
+
+
, ) diff --git a/examples/react/useDebouncedCallback/package.json b/examples/react/useDebouncedCallback/package.json index c74350ba..ae3369b8 100644 --- a/examples/react/useDebouncedCallback/package.json +++ b/examples/react/useDebouncedCallback/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useDebouncedState/package.json b/examples/react/useDebouncedState/package.json index ca6349e8..4f3ef77b 100644 --- a/examples/react/useDebouncedState/package.json +++ b/examples/react/useDebouncedState/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useDebouncedValue/package.json b/examples/react/useDebouncedValue/package.json index ea922329..73df68c8 100644 --- a/examples/react/useDebouncedValue/package.json +++ b/examples/react/useDebouncedValue/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useDebouncer/package.json b/examples/react/useDebouncer/package.json index 6e4d2974..02c8e5e1 100644 --- a/examples/react/useDebouncer/package.json +++ b/examples/react/useDebouncer/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useDebouncer/src/index.tsx b/examples/react/useDebouncer/src/index.tsx index 575945e7..b5173af8 100644 --- a/examples/react/useDebouncer/src/index.tsx +++ b/examples/react/useDebouncer/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useDebouncer } from '@tanstack/react-pacer/debouncer' +import { PacerProvider } from '@tanstack/react-pacer/provider' function App1() { // Use your state management library of choice @@ -254,11 +255,21 @@ function App3() { const root = ReactDOM.createRoot(document.getElementById('root')!) root.render( -
- -
- -
- -
, + // optionally, provide default options to an optional PacerProvider + +
+ +
+ +
+ +
+ , +
, ) diff --git a/examples/react/useQueuedState/package.json b/examples/react/useQueuedState/package.json index 232cd32f..57a50791 100644 --- a/examples/react/useQueuedState/package.json +++ b/examples/react/useQueuedState/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useQueuedValue/package.json b/examples/react/useQueuedValue/package.json index 95bf5425..5877b47e 100644 --- a/examples/react/useQueuedValue/package.json +++ b/examples/react/useQueuedValue/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useQueuer/package.json b/examples/react/useQueuer/package.json index d142e381..c68ddf4c 100644 --- a/examples/react/useQueuer/package.json +++ b/examples/react/useQueuer/package.json @@ -15,10 +15,10 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@tanstack/react-devtools": "0.7.0", + "@tanstack/react-devtools": "0.7.1", "@tanstack/react-pacer-devtools": "0.3.1", - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useQueuer/src/index.tsx b/examples/react/useQueuer/src/index.tsx index acd29667..243e5ff3 100644 --- a/examples/react/useQueuer/src/index.tsx +++ b/examples/react/useQueuer/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useQueuer } from '@tanstack/react-pacer/queuer' +import { PacerProvider } from '@tanstack/react-pacer/provider' import { PacerDevtoolsPanel } from '@tanstack/react-pacer-devtools' import { TanStackDevtools } from '@tanstack/react-devtools' @@ -232,15 +233,24 @@ function App2() { const root = ReactDOM.createRoot(document.getElementById('root')!) root.render( -
- -
- + // optionally, provide default options to an optional PacerProvider + +
+ +
+ +
}]} /> -
, + , ) diff --git a/examples/react/useQueuerWithPersister/package.json b/examples/react/useQueuerWithPersister/package.json index a061d5f4..529083a5 100644 --- a/examples/react/useQueuerWithPersister/package.json +++ b/examples/react/useQueuerWithPersister/package.json @@ -15,8 +15,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useRateLimitedCallback/package.json b/examples/react/useRateLimitedCallback/package.json index c96f000d..0adab469 100644 --- a/examples/react/useRateLimitedCallback/package.json +++ b/examples/react/useRateLimitedCallback/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useRateLimitedState/package.json b/examples/react/useRateLimitedState/package.json index c009dd23..b87cbd31 100644 --- a/examples/react/useRateLimitedState/package.json +++ b/examples/react/useRateLimitedState/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useRateLimitedValue/package.json b/examples/react/useRateLimitedValue/package.json index 970459db..23fec07a 100644 --- a/examples/react/useRateLimitedValue/package.json +++ b/examples/react/useRateLimitedValue/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useRateLimiter/package.json b/examples/react/useRateLimiter/package.json index 9478a211..62e94ac4 100644 --- a/examples/react/useRateLimiter/package.json +++ b/examples/react/useRateLimiter/package.json @@ -15,8 +15,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useRateLimiter/src/index.tsx b/examples/react/useRateLimiter/src/index.tsx index 5ca429a6..03abd849 100644 --- a/examples/react/useRateLimiter/src/index.tsx +++ b/examples/react/useRateLimiter/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useRateLimiter } from '@tanstack/react-pacer/rate-limiter' +import { PacerProvider } from '@tanstack/react-pacer/provider' function App1() { const [windowType, setWindowType] = useState<'fixed' | 'sliding'>('fixed') @@ -310,11 +311,20 @@ function App3() { const root = ReactDOM.createRoot(document.getElementById('root')!) root.render( -
- -
- -
- -
, + // optionally, provide default options to an optional PacerProvider + +
+ +
+ +
+ +
+
, ) diff --git a/examples/react/useRateLimiterWithPersister/package.json b/examples/react/useRateLimiterWithPersister/package.json index 7e7c075c..eb32e0a5 100644 --- a/examples/react/useRateLimiterWithPersister/package.json +++ b/examples/react/useRateLimiterWithPersister/package.json @@ -15,8 +15,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useThrottledCallback/package.json b/examples/react/useThrottledCallback/package.json index ec3b6d07..42ded86f 100644 --- a/examples/react/useThrottledCallback/package.json +++ b/examples/react/useThrottledCallback/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useThrottledState/package.json b/examples/react/useThrottledState/package.json index ce684751..f12e3fe0 100644 --- a/examples/react/useThrottledState/package.json +++ b/examples/react/useThrottledState/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useThrottledValue/package.json b/examples/react/useThrottledValue/package.json index 65e9992f..d832cc80 100644 --- a/examples/react/useThrottledValue/package.json +++ b/examples/react/useThrottledValue/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useThrottler/package.json b/examples/react/useThrottler/package.json index 51b44518..5666131e 100644 --- a/examples/react/useThrottler/package.json +++ b/examples/react/useThrottler/package.json @@ -14,8 +14,8 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/react/useThrottler/src/index.tsx b/examples/react/useThrottler/src/index.tsx index 991b77f1..f381e048 100644 --- a/examples/react/useThrottler/src/index.tsx +++ b/examples/react/useThrottler/src/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' import ReactDOM from 'react-dom/client' import { useThrottler } from '@tanstack/react-pacer/throttler' +import { PacerProvider } from '@tanstack/react-pacer/provider' function App1() { // Use your state management library of choice @@ -226,11 +227,20 @@ function App3() { const root = ReactDOM.createRoot(document.getElementById('root')!) root.render( -
- -
- -
- -
, + // optionally, provide default options to an optional PacerProvider + +
+ +
+ +
+ +
+
, ) diff --git a/examples/react/util-comparison/package.json b/examples/react/util-comparison/package.json index 1fef05d6..d56c587b 100644 --- a/examples/react/util-comparison/package.json +++ b/examples/react/util-comparison/package.json @@ -14,10 +14,10 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@tanstack/react-devtools": "0.7.0", + "@tanstack/react-devtools": "0.7.1", "@tanstack/react-pacer-devtools": "0.3.1", - "@types/react": "^19.1.15", - "@types/react-dom": "^19.1.9", + "@types/react": "^19.1.17", + "@types/react-dom": "^19.1.11", "@vitejs/plugin-react": "^5.0.4", "vite": "^7.1.7" }, diff --git a/examples/solid/asyncBatch/package.json b/examples/solid/asyncBatch/package.json index 61dbef5e..76a1feb6 100644 --- a/examples/solid/asyncBatch/package.json +++ b/examples/solid/asyncBatch/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/asyncBatch/src/index.tsx b/examples/solid/asyncBatch/src/index.tsx index 9d6c3435..9e4ee525 100644 --- a/examples/solid/asyncBatch/src/index.tsx +++ b/examples/solid/asyncBatch/src/index.tsx @@ -52,7 +52,7 @@ function App() { } catch (error: any) { setErrors((prev) => [ ...prev, - `Error: ${error.message} (${new Date().toLocaleTimeString()})`, + `Error: ${error} (${new Date().toLocaleTimeString()})`, ]) setErrorCount((prev) => prev + 1) console.error('Batch failed:', error) diff --git a/examples/solid/asyncDebounce/package.json b/examples/solid/asyncDebounce/package.json index e5fd33b0..3bda1992 100644 --- a/examples/solid/asyncDebounce/package.json +++ b/examples/solid/asyncDebounce/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/asyncRateLimit/package.json b/examples/solid/asyncRateLimit/package.json index d15b55c5..b51fada5 100644 --- a/examples/solid/asyncRateLimit/package.json +++ b/examples/solid/asyncRateLimit/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/asyncThrottle/package.json b/examples/solid/asyncThrottle/package.json index 7d238c2f..91635f30 100644 --- a/examples/solid/asyncThrottle/package.json +++ b/examples/solid/asyncThrottle/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/batch/package.json b/examples/solid/batch/package.json index ba7c7d70..5ba90e80 100644 --- a/examples/solid/batch/package.json +++ b/examples/solid/batch/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createAsyncBatcher/package.json b/examples/solid/createAsyncBatcher/package.json index 8c5faec9..a4aa4756 100644 --- a/examples/solid/createAsyncBatcher/package.json +++ b/examples/solid/createAsyncBatcher/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createAsyncBatcher/src/index.tsx b/examples/solid/createAsyncBatcher/src/index.tsx index 1f40d553..01c4b412 100644 --- a/examples/solid/createAsyncBatcher/src/index.tsx +++ b/examples/solid/createAsyncBatcher/src/index.tsx @@ -61,7 +61,7 @@ function App() { console.error('Batch failed:', error) setErrors((prev) => [ ...prev, - `Error: ${error.message} (${new Date().toLocaleTimeString()})`, + `Error: ${error} (${new Date().toLocaleTimeString()})`, ]) }, onSettled: (batch, batcher) => { diff --git a/examples/solid/createAsyncDebouncer/package.json b/examples/solid/createAsyncDebouncer/package.json index a48e6618..e4da60d2 100644 --- a/examples/solid/createAsyncDebouncer/package.json +++ b/examples/solid/createAsyncDebouncer/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createAsyncQueuer/package.json b/examples/solid/createAsyncQueuer/package.json index d8e706c0..212328f4 100644 --- a/examples/solid/createAsyncQueuer/package.json +++ b/examples/solid/createAsyncQueuer/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createAsyncRateLimiter/package.json b/examples/solid/createAsyncRateLimiter/package.json index f56fadff..bf1fa596 100644 --- a/examples/solid/createAsyncRateLimiter/package.json +++ b/examples/solid/createAsyncRateLimiter/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createAsyncThrottler/package.json b/examples/solid/createAsyncThrottler/package.json index df3fe98f..93188419 100644 --- a/examples/solid/createAsyncThrottler/package.json +++ b/examples/solid/createAsyncThrottler/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createBatcher/package.json b/examples/solid/createBatcher/package.json index ba33be3f..28448153 100644 --- a/examples/solid/createBatcher/package.json +++ b/examples/solid/createBatcher/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createDebouncedSignal/package.json b/examples/solid/createDebouncedSignal/package.json index 39686f9a..626cab55 100644 --- a/examples/solid/createDebouncedSignal/package.json +++ b/examples/solid/createDebouncedSignal/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createDebouncedValue/package.json b/examples/solid/createDebouncedValue/package.json index dc776301..e871da96 100644 --- a/examples/solid/createDebouncedValue/package.json +++ b/examples/solid/createDebouncedValue/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createDebouncer/package.json b/examples/solid/createDebouncer/package.json index 252778c0..a41155f9 100644 --- a/examples/solid/createDebouncer/package.json +++ b/examples/solid/createDebouncer/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createQueuer/package.json b/examples/solid/createQueuer/package.json index fcfbc9ba..0dcfb86b 100644 --- a/examples/solid/createQueuer/package.json +++ b/examples/solid/createQueuer/package.json @@ -9,14 +9,14 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/solid-devtools": "0.7.0", + "@tanstack/solid-devtools": "0.7.1", "@tanstack/solid-pacer": "^0.14.4", "@tanstack/solid-pacer-devtools": "0.3.1", "solid-js": "^1.9.9" }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createRateLimitedSignal/package.json b/examples/solid/createRateLimitedSignal/package.json index 6ce08629..81be94c2 100644 --- a/examples/solid/createRateLimitedSignal/package.json +++ b/examples/solid/createRateLimitedSignal/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createRateLimitedValue/package.json b/examples/solid/createRateLimitedValue/package.json index 9427eeba..cf29a7ef 100644 --- a/examples/solid/createRateLimitedValue/package.json +++ b/examples/solid/createRateLimitedValue/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createRateLimiter/package.json b/examples/solid/createRateLimiter/package.json index a81f5f87..306ca83a 100644 --- a/examples/solid/createRateLimiter/package.json +++ b/examples/solid/createRateLimiter/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createThrottledSignal/package.json b/examples/solid/createThrottledSignal/package.json index e41af8ec..1047facd 100644 --- a/examples/solid/createThrottledSignal/package.json +++ b/examples/solid/createThrottledSignal/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createThrottledValue/package.json b/examples/solid/createThrottledValue/package.json index 1319ddac..a707991c 100644 --- a/examples/solid/createThrottledValue/package.json +++ b/examples/solid/createThrottledValue/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/createThrottler/package.json b/examples/solid/createThrottler/package.json index 1315d041..523364e7 100644 --- a/examples/solid/createThrottler/package.json +++ b/examples/solid/createThrottler/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/debounce/package.json b/examples/solid/debounce/package.json index 13c7ac06..c34f23ef 100644 --- a/examples/solid/debounce/package.json +++ b/examples/solid/debounce/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/queue/package.json b/examples/solid/queue/package.json index 88807dcb..5be7b6a6 100644 --- a/examples/solid/queue/package.json +++ b/examples/solid/queue/package.json @@ -9,14 +9,14 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/solid-devtools": "0.7.0", + "@tanstack/solid-devtools": "0.7.1", "@tanstack/solid-pacer": "^0.14.4", "@tanstack/solid-pacer-devtools": "0.3.1", "solid-js": "^1.9.9" }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/rateLimit/package.json b/examples/solid/rateLimit/package.json index 495a75bf..26767754 100644 --- a/examples/solid/rateLimit/package.json +++ b/examples/solid/rateLimit/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/examples/solid/throttle/package.json b/examples/solid/throttle/package.json index 08394f10..0fb47204 100644 --- a/examples/solid/throttle/package.json +++ b/examples/solid/throttle/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "vite": "^7.1.7", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "browserslist": { "production": [ diff --git a/nx.json b/nx.json index be6938dc..adfddd41 100644 --- a/nx.json +++ b/nx.json @@ -1,5 +1,8 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", + "tui": { + "enabled": false + }, "defaultBase": "main", "useInferencePlugins": false, "parallel": 5, diff --git a/package.json b/package.json index 435a568a..ba55a416 100644 --- a/package.json +++ b/package.json @@ -58,22 +58,22 @@ "@size-limit/preset-small-lib": "^11.2.0", "@svitejs/changesets-changelog-github-compact": "^1.2.0", "@tanstack/config": "0.20.3", - "@testing-library/jest-dom": "^6.8.0", - "@types/node": "^24.3.1", + "@testing-library/jest-dom": "^6.9.1", + "@types/node": "^24.6.1", "eslint": "^9.36.0", "eslint-plugin-unused-imports": "^4.2.0", "fast-glob": "^3.3.3", "jsdom": "^27.0.0", "knip": "^5.64.1", "markdown-link-extractor": "^4.0.2", - "nx": "^21.5.3", + "nx": "^21.6.2", "premove": "^4.0.0", "prettier": "^3.6.2", "prettier-plugin-svelte": "^3.4.0", "publint": "^0.3.13", "sherif": "^1.6.1", "size-limit": "^11.2.0", - "typescript": "5.9.2", + "typescript": "5.9.3", "vite": "^7.1.7", "vitest": "^3.2.4" }, diff --git a/packages/pacer-devtools/package.json b/packages/pacer-devtools/package.json index 90e5b6db..95b5f8a2 100644 --- a/packages/pacer-devtools/package.json +++ b/packages/pacer-devtools/package.json @@ -71,6 +71,6 @@ "solid-js": "^1.9.9" }, "devDependencies": { - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" } } diff --git a/packages/pacer/package.json b/packages/pacer/package.json index 9d026557..32ed59b4 100644 --- a/packages/pacer/package.json +++ b/packages/pacer/package.json @@ -77,6 +77,16 @@ "default": "./dist/cjs/async-rate-limiter.cjs" } }, + "./async-retryer": { + "import": { + "types": "./dist/esm/async-retryer.d.ts", + "default": "./dist/esm/async-retryer.js" + }, + "require": { + "types": "./dist/cjs/async-retryer.d.cts", + "default": "./dist/cjs/async-retryer.cjs" + } + }, "./async-throttler": { "import": { "types": "./dist/esm/async-throttler.d.ts", diff --git a/packages/pacer/src/async-batcher.ts b/packages/pacer/src/async-batcher.ts index bfc9059f..17033087 100644 --- a/packages/pacer/src/async-batcher.ts +++ b/packages/pacer/src/async-batcher.ts @@ -1,6 +1,8 @@ import { Store } from '@tanstack/store' +import { AsyncRetryer } from './async-retryer' import { createKey, parseFunctionOrValue } from './utils' import { emitChange, pacerEventClient } from './event-client' +import type { AsyncRetryerOptions } from './async-retryer' import type { OptionalKeys } from './types' export interface AsyncBatcherState { @@ -8,6 +10,10 @@ export interface AsyncBatcherState { * Number of batch executions that have resulted in errors */ errorCount: number + /** + * Number of batch executions that have been executed + */ + executeCount: number /** * Array of items that failed during batch processing */ @@ -61,6 +67,7 @@ export interface AsyncBatcherState { function getDefaultAsyncBatcherState(): AsyncBatcherState { return { errorCount: 0, + executeCount: 0, failedItems: [], isEmpty: true, isExecuting: false, @@ -80,6 +87,12 @@ function getDefaultAsyncBatcherState(): AsyncBatcherState { * Options for configuring an AsyncBatcher instance */ export interface AsyncBatcherOptions { + /** + * Options for configuring the underlying async retryer + */ + asyncRetryerOptions?: AsyncRetryerOptions< + (items: Array) => Promise + > /** * Custom function to determine if a batch should be processed * Return true to process the batch immediately @@ -108,7 +121,7 @@ export interface AsyncBatcherOptions { * This can be used alongside throwOnError - the handler will be called before any error is thrown. */ onError?: ( - error: unknown, + error: Error, batch: Array, batcher: AsyncBatcher, ) => void @@ -159,6 +172,9 @@ type AsyncBatcherOptionsWithOptionalCallbacks = OptionalKeys< > const defaultOptions: AsyncBatcherOptionsWithOptionalCallbacks = { + asyncRetryerOptions: { + maxAttempts: 1, + }, getShouldExecute: () => false, maxSize: Infinity, started: true, @@ -233,6 +249,10 @@ export class AsyncBatcher { ) key: string options: AsyncBatcherOptionsWithOptionalCallbacks + asyncRetryers = new Map< + number, + AsyncRetryer<(items: Array) => Promise> + >() #timeoutId: NodeJS.Timeout | null = null constructor( @@ -254,6 +274,11 @@ export class AsyncBatcher { }) } + /** + * Emits a change event for the async batcher instance. Mostly useful for devtools. + */ + _emit = () => emitChange('AsyncBatcher', this) + /** * Updates the async batcher options */ @@ -293,8 +318,12 @@ export class AsyncBatcher { /** * Adds an item to the async batcher * If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed + * + * @returns The result from the batch function, or undefined if an error occurred and was handled by onError + * + * @throws The error from the batch function if no onError handler is configured or throwOnError is true */ - addItem = (item: TValue): void => { + addItem = async (item: TValue): Promise => { this.#setState({ items: [...this.store.state.items, item], isPending: this.options.wait !== Infinity, @@ -306,10 +335,11 @@ export class AsyncBatcher { this.options.getShouldExecute(this.store.state.items, this) if (shouldProcess) { - this.#execute() + return await this.#execute() } else if (this.options.wait !== Infinity) { this.#clearTimeout() // clear any pending timeout to replace it with a new one this.#timeoutId = setTimeout(() => this.#execute(), this.#getWait()) + await new Promise((resolve) => setTimeout(resolve, this.#getWait())) } } @@ -330,14 +360,20 @@ export class AsyncBatcher { return undefined } + const currentExecuteCount = this.store.state.executeCount + 1 const batch = this.peekAllItems() // copy of the items to be processed (to prevent race conditions) this.clear() // Clear items before processing to prevent race conditions this.options.onItemsChange?.(this) - this.#setState({ isExecuting: true }) + this.#setState({ isExecuting: true, executeCount: currentExecuteCount }) try { - const result = await this.fn(batch) // EXECUTE + const currentAsyncRetryer = new AsyncRetryer( + this.fn, + this.options.asyncRetryerOptions, + ) + this.asyncRetryers.set(currentExecuteCount, currentAsyncRetryer) + const result = await currentAsyncRetryer.execute(batch) // EXECUTE this.#setState({ totalItemsProcessed: this.store.state.totalItemsProcessed + batch.length, @@ -352,12 +388,13 @@ export class AsyncBatcher { failedItems: [...this.store.state.failedItems, ...batch], totalItemsFailed: this.store.state.totalItemsFailed + batch.length, }) - this.options.onError?.(error, batch, this) + this.options.onError?.(error as Error, batch, this) if (this.options.throwOnError) { throw error } return undefined } finally { + this.asyncRetryers.delete(currentExecuteCount) // dispose retryer this.#setState({ isExecuting: false, settleCount: this.store.state.settleCount + 1, @@ -399,6 +436,31 @@ export class AsyncBatcher { this.#setState({ items: [], failedItems: [], isPending: false }) } + /** + * Aborts all ongoing executions with the internal abort controllers. + * Does NOT cancel any pending execution that have not started yet. + * Does NOT clear out the items. + */ + abort = (): void => { + this.asyncRetryers.forEach((retryer) => retryer.abort()) + this.asyncRetryers.clear() + this.#setState({ + isExecuting: false, + }) + } + + /** + * Cancels any pending execution that have not started yet. + * Does NOT abort any execution already in progress. + * Does NOT clear out the items. + */ + cancel = (): void => { + this.#clearTimeout() + this.#setState({ + isPending: false, + }) + } + /** * Resets the async batcher state to its default values */ diff --git a/packages/pacer/src/async-debouncer.ts b/packages/pacer/src/async-debouncer.ts index 4185ed3d..ad2c5fc5 100644 --- a/packages/pacer/src/async-debouncer.ts +++ b/packages/pacer/src/async-debouncer.ts @@ -1,6 +1,8 @@ import { Store } from '@tanstack/store' +import { AsyncRetryer } from './async-retryer' import { createKey, parseFunctionOrValue } from './utils' import { emitChange, pacerEventClient } from './event-client' +import type { AsyncRetryerOptions } from './async-retryer' import type { AnyAsyncFunction, OptionalKeys } from './types' export interface AsyncDebouncerState { @@ -67,6 +69,10 @@ function getDefaultAsyncDebouncerState< * Options for configuring an async debounced function */ export interface AsyncDebouncerOptions { + /** + * Options for configuring the underlying async retryer + */ + asyncRetryerOptions?: AsyncRetryerOptions /** * Whether the debouncer is enabled. When disabled, maybeExecute will not trigger any executions. * Can be a boolean or a function that returns a boolean. @@ -93,7 +99,7 @@ export interface AsyncDebouncerOptions { * This can be used alongside throwOnError - the handler will be called before any error is thrown. */ onError?: ( - error: unknown, + error: Error, args: Parameters, debouncer: AsyncDebouncer, ) => void @@ -134,6 +140,9 @@ type AsyncDebouncerOptionsWithOptionalCallbacks = OptionalKeys< > const defaultOptions: AsyncDebouncerOptionsWithOptionalCallbacks = { + asyncRetryerOptions: { + maxAttempts: 1, + }, enabled: true, leading: false, trailing: true, @@ -191,7 +200,7 @@ export class AsyncDebouncer { >(getDefaultAsyncDebouncerState()) key: string options: AsyncDebouncerOptions - #abortController: AbortController | null = null + asyncRetryers = new Map>() #timeoutId: NodeJS.Timeout | null = null #resolvePreviousPromise: | ((value?: ReturnType | undefined) => void) @@ -216,6 +225,11 @@ export class AsyncDebouncer { }) } + /** + * Emits a change event for the async debouncer instance. Mostly useful for devtools. + */ + _emit = () => emitChange('AsyncDebouncer', this) + /** * Updates the async debouncer options */ @@ -326,31 +340,37 @@ export class AsyncDebouncer { ...args: Parameters ): Promise | undefined> => { if (!this.#getEnabled()) return undefined - this.#abortController = new AbortController() + const currentMaybeExecuteCount = this.store.state.maybeExecuteCount + 1 + try { this.#setState({ isExecuting: true }) - const result = await this.fn(...args) // EXECUTE! + const currentAsyncRetryer = new AsyncRetryer(this.fn, { + ...this.options.asyncRetryerOptions, + key: `${this.key}-retryer-${currentMaybeExecuteCount}`, + }) + this.asyncRetryers.set(currentMaybeExecuteCount, currentAsyncRetryer) + const result = await currentAsyncRetryer.execute(...args) // EXECUTE! this.#setState({ lastResult: result, successCount: this.store.state.successCount + 1, }) - this.options.onSuccess?.(result, args, this) + this.options.onSuccess?.(result as ReturnType, args, this) } catch (error) { this.#setState({ errorCount: this.store.state.errorCount + 1, }) - this.options.onError?.(error, args, this) + this.options.onError?.(error as Error, args, this) if (this.options.throwOnError) { throw error } } finally { + this.asyncRetryers.delete(currentMaybeExecuteCount) // dispose retryer this.#setState({ isExecuting: false, isPending: false, lastArgs: undefined, settleCount: this.store.state.settleCount + 1, }) - this.#abortController = null this.options.onSettled?.(args, this) } return this.store.state.lastResult @@ -361,14 +381,9 @@ export class AsyncDebouncer { */ flush = async (): Promise | undefined> => { if (this.store.state.isPending && this.store.state.lastArgs) { - this.#abortExecution() // abort any current execution - this.#clearTimeout() // clear any existing timeout - const result = await this.#execute(...this.store.state.lastArgs) - - // Resolve any pending promise from maybeExecute - this.#resolvePreviousPromiseInternal() - - return result + const { lastArgs } = this.store.state + this.#cancelPendingExecution() + return await this.#execute(...lastArgs) } return undefined } @@ -387,29 +402,36 @@ export class AsyncDebouncer { } } + /** + * Internal cancel without resetting the leading execute state + */ #cancelPendingExecution = (): void => { this.#clearTimeout() this.#resolvePreviousPromiseInternal() this.#setState({ isPending: false, - isExecuting: false, lastArgs: undefined, }) } - #abortExecution = (): void => { - if (this.#abortController) { - this.#abortController.abort() - this.#abortController = null - } + /** + * Aborts all ongoing executions with the internal abort controllers. + * Does NOT cancel any pending execution that have not started yet. + */ + abort = (): void => { + this.asyncRetryers.forEach((retryer) => retryer.abort()) + this.asyncRetryers.clear() + this.#setState({ + isExecuting: false, + }) } /** - * Cancels any pending execution or aborts any execution in progress + * Cancels any pending execution that have not started yet. + * Does NOT abort any execution already in progress. */ cancel = (): void => { this.#cancelPendingExecution() - this.#abortExecution() this.#setState({ canLeadingExecute: true }) } diff --git a/packages/pacer/src/async-queuer.ts b/packages/pacer/src/async-queuer.ts index dc985232..b4f40d50 100644 --- a/packages/pacer/src/async-queuer.ts +++ b/packages/pacer/src/async-queuer.ts @@ -1,6 +1,8 @@ import { Store } from '@tanstack/store' +import { AsyncRetryer } from './async-retryer' import { createKey, parseFunctionOrValue } from './utils' import { emitChange, pacerEventClient } from './event-client' +import type { AsyncRetryerOptions } from './async-retryer' import type { OptionalKeys } from './types' import type { QueuePosition } from './queuer' @@ -17,6 +19,10 @@ export interface AsyncQueuerState { * Number of task executions that have resulted in errors */ errorCount: number + /** + * Number of times execute has been called + */ + executeCount: number /** * Number of items that have been removed from the queue due to expiration */ @@ -25,6 +31,10 @@ export interface AsyncQueuerState { * Whether the queuer has no items to process (items array is empty) */ isEmpty: boolean + /** + * Whether the queuer is currently executing + */ + isExecuting: boolean /** * Whether the queuer has reached its maximum capacity */ @@ -80,8 +90,10 @@ function getDefaultAsyncQueuerState(): AsyncQueuerState { activeItems: [], addItemCount: 0, errorCount: 0, + executeCount: 0, expirationCount: 0, isEmpty: true, + isExecuting: false, isFull: false, isIdle: true, isRunning: true, @@ -98,6 +110,10 @@ function getDefaultAsyncQueuerState(): AsyncQueuerState { } export interface AsyncQueuerOptions { + /** + * Options for configuring the underlying async retryer + */ + asyncRetryerOptions?: AsyncRetryerOptions<(item: TValue) => Promise> /** * Default position to add items to the queuer * @default 'back' @@ -152,7 +168,7 @@ export interface AsyncQueuerOptions { * If provided, the handler will be called with the error and queuer instance. * This can be used alongside throwOnError - the handler will be called before any error is thrown. */ - onError?: (error: unknown, item: TValue, queuer: AsyncQueuer) => void + onError?: (error: Error, item: TValue, queuer: AsyncQueuer) => void /** * Callback fired whenever an item expires in the queuer */ @@ -206,6 +222,9 @@ type AsyncQueuerOptionsWithOptionalCallbacks = OptionalKeys< const defaultOptions: AsyncQueuerOptionsWithOptionalCallbacks = { addItemsTo: 'back', + asyncRetryerOptions: { + maxAttempts: 1, + }, concurrency: 1, expirationDuration: Infinity, getIsExpired: () => false, @@ -274,6 +293,10 @@ export class AsyncQueuer { >(getDefaultAsyncQueuerState()) key: string options: AsyncQueuerOptions + asyncRetryers = new Map< + number, + AsyncRetryer<(item: TValue) => Promise> + >() #timeoutIds: Set = new Set() constructor( @@ -312,6 +335,11 @@ export class AsyncQueuer { }) } + /** + * Emits a change event for the async queuer instance. Mostly useful for devtools. + */ + _emit = () => emitChange('AsyncQueuer', this) + /** * Updates the queuer options. New options are merged with existing options. */ @@ -555,9 +583,20 @@ export class AsyncQueuer { */ execute = async (position?: QueuePosition): Promise => { const item = this.getNextItem(position) + if (item !== undefined) { + const currentExecuteCount = this.store.state.executeCount + 1 + this.#setState({ + executeCount: currentExecuteCount, + isExecuting: true, + }) try { - const lastResult = await this.fn(item) // EXECUTE! + const currentAsyncRetryer = new AsyncRetryer(this.fn, { + ...this.options.asyncRetryerOptions, + key: `${this.key}-retryer-${currentExecuteCount}`, + }) + this.asyncRetryers.set(currentExecuteCount, currentAsyncRetryer) + const lastResult = await currentAsyncRetryer.execute(item) // EXECUTE! this.#setState({ successCount: this.store.state.successCount + 1, lastResult, @@ -567,15 +606,17 @@ export class AsyncQueuer { this.#setState({ errorCount: this.store.state.errorCount + 1, }) - this.options.onError?.(error, item, this) + this.options.onError?.(error as Error, item, this) if (this.options.throwOnError) { throw error } } finally { + this.asyncRetryers.delete(currentExecuteCount) // dispose retryer this.#setState({ activeItems: this.store.state.activeItems.filter( (activeItem) => activeItem !== item, ), + isExecuting: false, settledCount: this.store.state.settledCount + 1, }) this.options.onSettled?.(item, this) @@ -729,13 +770,26 @@ export class AsyncQueuer { } /** - * Removes all pending items from the queue. Does not affect active tasks. + * Removes all pending items from the queue. + * Does NOT affect active tasks. */ clear = (): void => { this.#setState({ items: [], itemTimestamps: [] }) this.options.onItemsChange?.(this) } + /** + * Aborts all ongoing executions with the internal abort controllers. + * Does NOT clear out the items. + */ + abort = (): void => { + this.asyncRetryers.forEach((retryer) => retryer.abort()) + this.asyncRetryers.clear() + this.#setState({ + isExecuting: false, + }) + } + /** * Resets the queuer state to its default values */ diff --git a/packages/pacer/src/async-rate-limiter.ts b/packages/pacer/src/async-rate-limiter.ts index 9d1f664b..ab982d51 100644 --- a/packages/pacer/src/async-rate-limiter.ts +++ b/packages/pacer/src/async-rate-limiter.ts @@ -1,6 +1,8 @@ import { Store } from '@tanstack/store' +import { AsyncRetryer } from './async-retryer' import { createKey, parseFunctionOrValue } from './utils' import { emitChange, pacerEventClient } from './event-client' +import type { AsyncRetryerOptions } from './async-retryer' import type { AnyAsyncFunction } from './types' export interface AsyncRateLimiterState { @@ -67,6 +69,10 @@ function getDefaultAsyncRateLimiterState< * Options for configuring an async rate-limited function */ export interface AsyncRateLimiterOptions { + /** + * Options for configuring the underlying async retryer + */ + asyncRetryerOptions?: AsyncRetryerOptions /** * Whether the rate limiter is enabled. When disabled, maybeExecute will not trigger any executions. * Can be a boolean or a function that returns a boolean. @@ -93,7 +99,7 @@ export interface AsyncRateLimiterOptions { * This can be used alongside throwOnError - the handler will be called before any error is thrown. */ onError?: ( - error: unknown, + error: Error, args: Parameters, rateLimiter: AsyncRateLimiter, ) => void @@ -140,6 +146,9 @@ const defaultOptions: Omit< Required>, 'initialState' | 'onError' | 'onReject' | 'onSettled' | 'onSuccess' | 'key' > = { + asyncRetryerOptions: { + maxAttempts: 1, + }, enabled: true, limit: 1, window: 0, @@ -219,6 +228,7 @@ export class AsyncRateLimiter { >(getDefaultAsyncRateLimiterState()) key: string options: AsyncRateLimiterOptions + asyncRetryers = new Map>() #timeoutIds: Set = new Set() constructor( @@ -243,6 +253,11 @@ export class AsyncRateLimiter { }) } + /** + * Emits a change event for the async rate limiter instance. Mostly useful for devtools. + */ + _emit = () => emitChange('AsyncRateLimiter', this) + /** * Updates the async rate limiter options */ @@ -347,6 +362,7 @@ export class AsyncRateLimiter { ): Promise | undefined> => { if (!this.#getEnabled()) return + const currentMaybeExecute = this.store.state.maybeExecuteCount const now = Date.now() const executionTimes = [...this.store.state.executionTimes, now] this.#setState({ @@ -355,22 +371,28 @@ export class AsyncRateLimiter { }) try { - const result = await this.fn(...args) // EXECUTE! + // Create a new AsyncRetryer for this execution to avoid cancelling concurrent executions + const currentAsyncRetryer = new AsyncRetryer(this.fn, { + ...this.options.asyncRetryerOptions, + key: `${this.key}-retryer-${currentMaybeExecute}`, + }) + const result = await currentAsyncRetryer.execute(...args) // EXECUTE! this.#setCleanupTimeout(now) this.#setState({ successCount: this.store.state.successCount + 1, lastResult: result, }) - this.options.onSuccess?.(result, args, this) + this.options.onSuccess?.(result as ReturnType, args, this) } catch (error) { this.#setState({ errorCount: this.store.state.errorCount + 1, }) - this.options.onError?.(error, args, this) + this.options.onError?.(error as Error, args, this) if (this.options.throwOnError) { throw error } } finally { + this.asyncRetryers.delete(currentMaybeExecute) // dispose retryer this.#setState({ isExecuting: false, settleCount: this.store.state.settleCount + 1, @@ -462,6 +484,18 @@ export class AsyncRateLimiter { return oldestExecution + this.#getWindow() - Date.now() } + /** + * Aborts all ongoing executions with the internal abort controllers. + * Does NOT clear out the execution times or reset the rate limiter. + */ + abort = (): void => { + this.asyncRetryers.forEach((retryer) => retryer.abort()) + this.asyncRetryers.clear() + this.#setState({ + isExecuting: false, + }) + } + /** * Resets the rate limiter state */ diff --git a/packages/pacer/src/async-retryer.ts b/packages/pacer/src/async-retryer.ts new file mode 100644 index 00000000..48834a9c --- /dev/null +++ b/packages/pacer/src/async-retryer.ts @@ -0,0 +1,494 @@ +import { Store } from '@tanstack/store' +import { createKey, parseFunctionOrValue } from './utils' +import { emitChange, pacerEventClient } from './event-client' +import type { AnyAsyncFunction } from './types' + +export interface AsyncRetryerState { + /** + * The current retry attempt number (0 when not executing) + */ + currentAttempt: number + /** + * Total number of completed executions (successful or failed) + */ + executionCount: number + /** + * Whether the retryer is currently executing the function + */ + isExecuting: boolean + /** + * The most recent error encountered during execution + */ + lastError: Error | undefined + /** + * Timestamp of the last execution completion in milliseconds + */ + lastExecutionTime: number + /** + * The result from the most recent successful execution + */ + lastResult: ReturnType | undefined + /** + * Current execution status - 'disabled' when not enabled, 'idle' when ready, 'executing' when running + */ + status: 'disabled' | 'idle' | 'executing' | 'retrying' + /** + * Total time spent executing (including retries) in milliseconds + */ + totalExecutionTime: number +} + +/** + * Creates the default initial state for an AsyncRetryer instance + * @returns The default state with all values reset to initial values + */ +function getDefaultAsyncRetryerState< + TFn extends AnyAsyncFunction, +>(): AsyncRetryerState { + return structuredClone({ + currentAttempt: 0, + executionCount: 0, + isExecuting: false, + lastError: undefined, + lastExecutionTime: 0, + lastResult: undefined, + status: 'idle', + totalExecutionTime: 0, + }) +} + +export interface AsyncRetryerOptions { + /** + * The backoff strategy for retry delays: + * - 'exponential': Wait time doubles with each attempt (1s, 2s, 4s, ...) + * - 'linear': Wait time increases linearly (1s, 2s, 3s, ...) + * - 'fixed': Same wait time for all attempts + * @default 'exponential' + */ + backoff?: 'linear' | 'exponential' | 'fixed' + /** + * Base wait time in milliseconds between retries, or a function that returns the wait time + * @default 1000 + */ + baseWait?: number | ((retryer: AsyncRetryer) => number) + /** + * Whether the retryer is enabled, or a function that determines if it's enabled + * @default true + */ + enabled?: boolean | ((retryer: AsyncRetryer) => boolean) + /** + * Initial state to merge with the default state + */ + initialState?: Partial> + /** + * Optional key to identify this async retryer instance. + * If provided, the async retryer will be identified by this key in the devtools and PacerProvider if applicable. + */ + key?: string + /** + * Jitter percentage to add to retry delays (0-1). Adds randomness to prevent thundering herd. + * @default 0 + */ + jitter?: number + /** + * Maximum number of retry attempts, or a function that returns the max attempts + * @default 3 + */ + maxAttempts?: number | ((retryer: AsyncRetryer) => number) + /** + * Callback invoked when any error occurs during execution (including retries) + */ + onError?: ( + error: Error, + args: Parameters, + retryer: AsyncRetryer, + ) => void + /** + * Callback invoked when the final error occurs after all retries are exhausted + */ + onLastError?: (error: Error, retryer: AsyncRetryer) => void + /** + * Callback invoked before each retry attempt + */ + onRetry?: (attempt: number, error: Error, retryer: AsyncRetryer) => void + /** + * Callback invoked after execution completes (success or failure) + */ + onSettled?: (args: Parameters, retryer: AsyncRetryer) => void + /** + * Callback invoked when execution succeeds + */ + onSuccess?: ( + result: ReturnType, + args: Parameters, + retryer: AsyncRetryer, + ) => void + /** + * Controls when errors are thrown: + * - 'last': Only throw the final error after all retries are exhausted + * - true: Throw every error immediately (disables retrying) + * - false: Never throw errors, return undefined instead + * @default 'last' + */ + throwOnError?: boolean | 'last' +} + +const defaultOptions: Omit< + Required>, + | 'initialState' + | 'key' + | 'onError' + | 'onLastError' + | 'onRetry' + | 'onSettled' + | 'onSuccess' +> = { + backoff: 'exponential', + baseWait: 1000, + enabled: true, + jitter: 0, + maxAttempts: 3, + throwOnError: 'last', +} + +/** + * Provides robust retry functionality for asynchronous functions, supporting configurable backoff strategies, + * attempt limits, and detailed state management. The AsyncRetryer class is designed to help you reliably + * execute async operations that may fail intermittently, such as network requests or database operations, + * by automatically retrying them according to your chosen policy. + * + * ## Retrying Concepts + * + * - **Retrying**: Automatically re-executes a failed async function up to a specified number of attempts. + * Useful for handling transient errors (e.g., network flakiness, rate limits, temporary server issues). + * - **Backoff Strategies**: Controls the delay between retry attempts (default: `'exponential'`): + * - `'exponential'`: Wait time doubles with each attempt (1s, 2s, 4s, ...) - **DEFAULT** + * - `'linear'`: Wait time increases linearly (1s, 2s, 3s, ...) + * - `'fixed'`: Waits a constant amount of time (`baseWait`) between each attempt + * - **Jitter**: Adds randomness to retry delays to prevent thundering herd problems (default: `0`). + * Set to a value between 0-1 to apply that percentage of random variation to each delay. + * - **Abort & Cancellation**: Supports cancellation via an internal `AbortController`. If cancelled, retries are stopped. + * - **State Management**: Tracks execution status, current attempt, last error, and result using TanStack Store. + * - **Callbacks**: Provides hooks for handling success, error, retry, and settled events. + * + * ## State Management + * - Uses TanStack Store for fine-grained reactivity. + * - State includes: `isExecuting`, `currentAttempt`, `lastError`, `lastResult`, and `status` (`idle`, `executing`, `retrying`, `disabled`). + * - State can be accessed via the `store.state` property. + * + * ## Error Handling + * The `throwOnError` option controls when errors are thrown (default: `'last'`): + * - `'last'`: Only throws the final error after all retries are exhausted - **DEFAULT** + * - `true`: Throws every error immediately (no retries) + * - `false`: Never throws errors, returns `undefined` instead + * + * Additional error handling: + * - `onError`: Called for every error (including during retries) + * - `onLastError`: Called only for the final error after all retries fail + * - If `onError` is provided but `throwOnError` is not specified, defaults to `'last'` + * + * ## Usage + * - Use for async operations that may fail transiently and benefit from retrying. + * - Configure `maxAttempts`, `backoff`, `baseWait`, and `jitter` to control retry behavior. + * - Use `onRetry`, `onSuccess`, `onError`, and `onSettled` for custom side effects. + * + * @example + * ```typescript + * // Retry a fetch operation up to 5 times with exponential backoff and jitter + * const retryer = new AsyncRetryer(fetchData, { + * maxAttempts: 5, + * backoff: 'exponential', + * baseWait: 1000, + * jitter: 0.1, // Add 10% random variation to prevent thundering herd + * onRetry: (attempt, error) => console.log(`Retry attempt ${attempt} after error:`, error), + * onSuccess: (result) => console.log('Success:', result), + * onError: (error) => console.error('Error:', error), + * onLastError: (error) => console.error('All retries failed:', error), + * }) + * + * const result = await retryer.execute(userId) + * ``` + * + * @template TFn The async function type to be retried. + */ +export class AsyncRetryer { + readonly store: Store>> = new Store( + getDefaultAsyncRetryerState(), + ) + key: string + options: AsyncRetryerOptions & typeof defaultOptions + #abortController: AbortController | null = null + + /** + * Creates a new AsyncRetryer instance + * @param fn The async function to retry + * @param initialOptions Configuration options for the retryer + */ + constructor( + public fn: TFn, + initialOptions: AsyncRetryerOptions = {}, + ) { + this.key = createKey(initialOptions.key) + this.options = { + ...defaultOptions, + ...initialOptions, + throwOnError: + initialOptions.throwOnError ?? + (initialOptions.onError ? false : defaultOptions.throwOnError), + } + this.#setState(this.options.initialState ?? {}) + + pacerEventClient.on('d-AsyncRetryer', (event) => { + if (event.payload.key !== this.key) return + this.#setState(event.payload.store.state as AsyncRetryerState) + this.setOptions(event.payload.options) + }) + } + + /** + * Emits a change event for the async retryer instance. Mostly useful for devtools. + */ + _emit = () => emitChange('AsyncRetryer', this) + + /** + * Updates the retryer options + * @param newOptions Partial options to merge with existing options + */ + setOptions = (newOptions: Partial>): void => { + this.options = { ...this.options, ...newOptions } + } + + #setState = (newState: Partial>): void => { + this.store.setState((state) => { + const combinedState = { + ...state, + ...newState, + } + const { isExecuting, currentAttempt } = combinedState + return { + ...combinedState, + status: !this.#getEnabled() + ? 'disabled' + : isExecuting && currentAttempt === 1 + ? 'executing' + : isExecuting && currentAttempt > 1 + ? 'retrying' + : 'idle', + } + }) + emitChange('AsyncRetryer', this) + } + + #getEnabled = (): boolean => { + return !!parseFunctionOrValue(this.options.enabled, this) + } + + #getMaxAttempts = (): number => { + return parseFunctionOrValue(this.options.maxAttempts, this) + } + + #getBaseWait = (): number => { + return parseFunctionOrValue(this.options.baseWait, this) + } + + #calculateJitter = (waitTime: number): number => { + const jitterAmount = this.options.jitter + if (jitterAmount <= 0) return 0 + + try { + const crypto = + typeof globalThis !== 'undefined' ? globalThis.crypto : undefined + if (crypto?.getRandomValues) { + const array = new Uint32Array(1) + crypto.getRandomValues(array) + // Convert to 0-1 range and apply jitter percentage + const randomFactor = (array[0]! / 0xffffffff) * 2 - 1 // -1 to 1 + return Math.floor(waitTime * jitterAmount * randomFactor) + } + } catch { + // No crypto available + } + return 0 + } + + #calculateWait = (attempt: number): number => { + const baseWait = this.#getBaseWait() + let waitTime: number + + switch (this.options.backoff) { + case 'linear': + waitTime = baseWait * attempt + break + case 'exponential': + waitTime = baseWait * Math.pow(2, attempt - 1) + break + case 'fixed': + default: + waitTime = baseWait + break + } + + const jitter = this.#calculateJitter(waitTime) + return Math.max(0, waitTime + jitter) + } + + /** + * Executes the function with retry logic + * @param args Arguments to pass to the function + * @returns The function result, or undefined if disabled or all retries failed (when throwOnError is false) + * @throws The last error if throwOnError is true and all retries fail + */ + execute = async ( + ...args: Parameters + ): Promise | undefined> => { + if (!this.#getEnabled()) { + return undefined + } + + // Cancel any existing execution + this.abort() + + const startTime = Date.now() + let lastError: Error | undefined + let result: ReturnType | undefined + + this.#abortController = new AbortController() + const signal = this.#abortController.signal + + this.#setState({ + isExecuting: true, + currentAttempt: 0, + lastError: undefined, + }) + + let isLastAttempt = false + for (let attempt = 1; attempt <= this.#getMaxAttempts(); attempt++) { + isLastAttempt = attempt === this.#getMaxAttempts() + this.#setState({ currentAttempt: attempt }) + + try { + if (signal.aborted) { + return undefined + } + result = (await this.fn(...args)) as ReturnType + + // Check if cancelled during execution + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (signal.aborted) { + return undefined + } + + const totalTime = Date.now() - startTime + this.#setState({ + executionCount: this.store.state.executionCount + 1, + isExecuting: false, + lastExecutionTime: Date.now(), + totalExecutionTime: totalTime, + currentAttempt: 0, + lastResult: result, + }) + + this.options.onSuccess?.(result, args, this) + + return result + } catch (error) { + // Treat abort as a non-error cancellation outcome + if ((error as Error).name === 'AbortError') { + return undefined + } + lastError = error instanceof Error ? error : new Error(String(error)) + this.#setState({ lastError }) + + if (attempt < this.#getMaxAttempts()) { + this.options.onRetry?.(attempt, lastError, this) + + const wait = this.#calculateWait(attempt) + if (wait > 0) { + // Eagerly reflect retrying status during the wait window + this.#setState({ isExecuting: true, currentAttempt: attempt + 1 }) + await new Promise((resolve) => { + const timeout = setTimeout(() => { + signal.removeEventListener('abort', onAbort) + resolve() + }, wait) + const onAbort = () => { + clearTimeout(timeout) + signal.removeEventListener('abort', onAbort) + resolve() + } + signal.addEventListener('abort', onAbort) + }) + if (signal.aborted) { + // When cancelled during retry wait, surface the last error exactly once + this.options.onError?.(lastError, args, this) + return undefined + } + } + } + } finally { + this.options.onSettled?.(args, this) + } + } + + // Exhausted retries - finalize state + this.#setState({ isExecuting: false }) + this.options.onLastError?.(lastError as Error, this) + this.options.onError?.(lastError as Error, args, this) + this.options.onSettled?.(args, this) + + if ( + (this.options.throwOnError === 'last' && isLastAttempt) || + this.options.throwOnError === true + ) { + throw lastError + } + + return undefined + } + + /** + * Cancels the current execution and any pending retries + */ + abort = (): void => { + if (this.#abortController) { + this.#abortController.abort() + this.#abortController = null + this.#setState({ + isExecuting: false, + }) + } + } + + /** + * Resets the retryer to its initial state and cancels any ongoing execution + */ + reset = (): void => { + this.abort() + this.#setState(getDefaultAsyncRetryerState()) + } +} + +/** + * Creates a retry-enabled version of an async function + * + * @param fn The async function to add retry functionality to + * @param initialOptions Configuration options for the retry behavior + * @returns A new function that executes the original with retry logic + * + * @example + * ```typescript + * const retryFetch = asyncRetry(fetch, { + * maxAttempts: 3, + * backoff: 'exponential' + * }) + * + * const response = await retryFetch('/api/data') + * ``` + */ +export function asyncRetry( + fn: TFn, + initialOptions: AsyncRetryerOptions = {}, +): (...args: Parameters) => Promise | undefined> { + const retryer = new AsyncRetryer(fn, initialOptions) + return retryer.execute +} diff --git a/packages/pacer/src/async-throttler.ts b/packages/pacer/src/async-throttler.ts index adbe3cd5..124f2667 100644 --- a/packages/pacer/src/async-throttler.ts +++ b/packages/pacer/src/async-throttler.ts @@ -1,6 +1,8 @@ import { Store } from '@tanstack/store' +import { AsyncRetryer } from './async-retryer' import { createKey, parseFunctionOrValue } from './utils' import { emitChange, pacerEventClient } from './event-client' +import type { AsyncRetryerOptions } from './async-retryer' import type { AnyAsyncFunction, OptionalKeys } from './types' export interface AsyncThrottlerState { @@ -72,6 +74,10 @@ function getDefaultAsyncThrottlerState< * Options for configuring an async throttled function */ export interface AsyncThrottlerOptions { + /** + * Options for configuring the underlying async retryer + */ + asyncRetryerOptions?: AsyncRetryerOptions /** * Whether the throttler is enabled. When disabled, maybeExecute will not trigger any executions. * Can be a boolean or a function that returns a boolean. @@ -98,7 +104,7 @@ export interface AsyncThrottlerOptions { * This can be used alongside throwOnError - the handler will be called before any error is thrown. */ onError?: ( - error: unknown, + error: Error, args: Parameters, asyncThrottler: AsyncThrottler, ) => void @@ -142,6 +148,9 @@ type AsyncThrottlerOptionsWithOptionalCallbacks = OptionalKeys< > const defaultOptions: AsyncThrottlerOptionsWithOptionalCallbacks = { + asyncRetryerOptions: { + maxAttempts: 1, + }, enabled: true, leading: true, trailing: true, @@ -202,7 +211,7 @@ export class AsyncThrottler { >(getDefaultAsyncThrottlerState()) key: string options: AsyncThrottlerOptions - #abortController: AbortController | null = null + asyncRetryers = new Map>() #timeoutId: NodeJS.Timeout | null = null #resolvePreviousPromise: | ((value?: ReturnType | undefined) => void) @@ -219,6 +228,7 @@ export class AsyncThrottler { throwOnError: initialOptions.throwOnError ?? !initialOptions.onError, } this.#setState(this.options.initialState ?? {}) + pacerEventClient.on('d-AsyncThrottler', (event) => { if (event.payload.key !== this.key) return this.#setState(event.payload.store.state as AsyncThrottlerState) @@ -226,6 +236,11 @@ export class AsyncThrottler { }) } + /** + * Emits a change event for the async throttler instance. Mostly useful for devtools. + */ + _emit = () => emitChange('AsyncThrottler', this) + /** * Updates the async throttler options */ @@ -301,88 +316,119 @@ export class AsyncThrottler { ...args: Parameters ): Promise | undefined> => { if (!this.#getEnabled()) return undefined + const now = Date.now() const timeSinceLastExecution = now - this.store.state.lastExecutionTime const wait = this.#getWait() - // Store the most recent arguments for potential trailing execution + this.#setState({ - lastArgs: args, maybeExecuteCount: this.store.state.maybeExecuteCount + 1, + lastArgs: args, // store the arguments for potential trailing execution }) + const thisMaybeExecuteNumber = this.store.state.maybeExecuteCount + this.#resolvePreviousPromiseInternal() - // Handle leading execution - if (this.options.leading && timeSinceLastExecution >= wait) { - await this.#execute(...args) - return this.store.state.lastResult - } else { + // Wait for the wait period for the previous execution to complete if it's still running + for ( + let maxNumIterations = wait / 10; + this.store.state.isExecuting && maxNumIterations > 0; + maxNumIterations-- + ) { + await new Promise((resolve) => setTimeout(resolve, 10)) + if (this.store.state.maybeExecuteCount !== thisMaybeExecuteNumber) { + // cancel the current maybeExecute loop because a new maybeExecute call was made + return this.store.state.lastResult + } + } + + if ( + this.options.leading && + !this.store.state.isPending && + timeSinceLastExecution >= wait + ) { + await this.#execute(...args) // Leading EXECUTE! + } else if (this.options.trailing) { + // replace old pending execution with a new one + this.cancel() + this.#setState({ + isPending: true, + }) + + // Set up new trailing execution return new Promise((resolve, reject) => { this.#resolvePreviousPromise = resolve - // Clear any existing timeout to ensure we use the latest arguments - this.#clearTimeout() - - // Set up trailing execution if enabled - if (this.options.trailing) { - const _timeSinceLastExecution = this.store.state.lastExecutionTime - ? now - this.store.state.lastExecutionTime - : 0 - const timeoutDuration = wait - _timeSinceLastExecution - this.#setState({ isPending: true }) - this.#timeoutId = setTimeout(async () => { - if (this.store.state.lastArgs !== undefined) { - try { - await this.#execute(...this.store.state.lastArgs) // EXECUTE! - } catch (error) { - reject(error) - } + + const newTimeSinceLastExecution = this.store.state.lastExecutionTime + ? now - this.store.state.lastExecutionTime + : 0 + const timeoutDuration = Math.max(0, wait - newTimeSinceLastExecution) + + this.#timeoutId = setTimeout(async () => { + this.#clearTimeout() + if (this.store.state.lastArgs !== undefined) { + try { + await this.#execute(...this.store.state.lastArgs) // Trailing EXECUTE! + } catch (error) { + reject(error) } - this.#resolvePreviousPromise = null - resolve(this.store.state.lastResult) - }, timeoutDuration) - } + } + this.#resolvePreviousPromise = null + resolve(this.store.state.lastResult) + }, timeoutDuration) }) } + return this.store.state.lastResult } #execute = async ( ...args: Parameters ): Promise | undefined> => { - if (!this.#getEnabled() || this.store.state.isExecuting) return undefined - this.#abortController = new AbortController() + if (!this.#getEnabled()) return undefined + + const currentMaybeExecute = this.store.state.maybeExecuteCount + try { this.#setState({ isExecuting: true }) - const result = await this.fn(...args) // EXECUTE! + const currentAsyncRetryer = new AsyncRetryer(this.fn, { + ...this.options.asyncRetryerOptions, + key: `${this.key}-retryer-${currentMaybeExecute}`, + }) + this.asyncRetryers.set(currentMaybeExecute, currentAsyncRetryer) + const result = await currentAsyncRetryer.execute(...args) // EXECUTE! this.#setState({ lastResult: result, successCount: this.store.state.successCount + 1, }) - this.options.onSuccess?.(result, args, this) + this.options.onSuccess?.(result as ReturnType, args, this) } catch (error) { this.#setState({ errorCount: this.store.state.errorCount + 1, }) - this.options.onError?.(error, args, this) + this.options.onError?.(error as Error, args, this) if (this.options.throwOnError) { throw error } } finally { + this.asyncRetryers.delete(currentMaybeExecute) // dispose retryer const lastExecutionTime = Date.now() - const nextExecutionTime = lastExecutionTime + this.#getWait() + const wait = this.#getWait() + const nextExecutionTime = lastExecutionTime + wait this.#setState({ isExecuting: false, - isPending: false, + isPending: !!this.#timeoutId, settleCount: this.store.state.settleCount + 1, lastExecutionTime, nextExecutionTime, }) - this.#abortController = null this.options.onSettled?.(args, this) setTimeout(() => { if (!this.store.state.isPending) { + // clear nextExecutionTime if there is no pending execution this.#setState({ nextExecutionTime: undefined }) } - }, this.#getWait()) + }, wait) } return this.store.state.lastResult } @@ -392,12 +438,21 @@ export class AsyncThrottler { */ flush = async (): Promise | undefined> => { if (this.store.state.isPending && this.store.state.lastArgs) { - this.#abortExecution() // abort any current execution - this.#clearTimeout() // clear any existing timeout + // Store the pending promise resolver before clearing timeout + const resolvePromise = this.#resolvePreviousPromise + + // Clear timeout and state without resolving the promise + this.#clearTimeout() + this.#setState({ + isPending: false, + }) + const result = await this.#execute(...this.store.state.lastArgs) - // Resolve any pending promise from maybeExecute - this.#resolvePreviousPromiseInternal() + // Resolve the pending promise with the result + if (resolvePromise) { + resolvePromise(result) + } return result } @@ -418,7 +473,21 @@ export class AsyncThrottler { } } - #cancelPendingExecution = (): void => { + /** + * Aborts all ongoing executions with the internal abort controllers. + * Does NOT cancel any pending execution that have not started yet. + */ + abort = (): void => { + this.asyncRetryers.forEach((retryer) => retryer.abort()) + this.asyncRetryers.clear() + this.#setState({ isExecuting: false }) + } + + /** + * Cancels any pending execution that have not started yet. + * Does NOT abort any execution already in progress. + */ + cancel = (): void => { this.#clearTimeout() if (this.#resolvePreviousPromise) { this.#resolvePreviousPromiseInternal() @@ -426,26 +495,9 @@ export class AsyncThrottler { } this.#setState({ isPending: false, - isExecuting: false, - lastArgs: undefined, }) } - #abortExecution = (): void => { - if (this.#abortController) { - this.#abortController.abort() - this.#abortController = null - } - } - - /** - * Cancels any pending execution or aborts any execution in progress - */ - cancel = (): void => { - this.#cancelPendingExecution() - this.#abortExecution() - } - /** * Resets the debouncer state to its default values */ diff --git a/packages/pacer/src/batcher.ts b/packages/pacer/src/batcher.ts index 9308cf30..c62c7f92 100644 --- a/packages/pacer/src/batcher.ts +++ b/packages/pacer/src/batcher.ts @@ -167,6 +167,11 @@ export class Batcher { }) } + /** + * Emits a change event for the batcher instance. Mostly useful for devtools. + */ + _emit = () => emitChange('Batcher', this) + /** * Updates the batcher options */ @@ -275,6 +280,15 @@ export class Batcher { this.#setState({ items: [], isPending: false }) } + /** + * Cancels any pending execution that was scheduled. + * Does NOT clear out the items. + */ + cancel = (): void => { + this.#clearTimeout() + this.#setState({ isPending: false }) + } + /** * Resets the batcher state to its default values */ diff --git a/packages/pacer/src/debouncer.ts b/packages/pacer/src/debouncer.ts index e91fa626..0e1ff6af 100644 --- a/packages/pacer/src/debouncer.ts +++ b/packages/pacer/src/debouncer.ts @@ -152,6 +152,11 @@ export class Debouncer { }) } + /** + * Emits a change event for the debouncer instance. Mostly useful for devtools. + */ + _emit = () => emitChange('Debouncer', this) + /** * Updates the debouncer options */ diff --git a/packages/pacer/src/event-client.ts b/packages/pacer/src/event-client.ts index 341cf1f3..255ebcd9 100644 --- a/packages/pacer/src/event-client.ts +++ b/packages/pacer/src/event-client.ts @@ -3,6 +3,7 @@ import type { AsyncBatcher } from './async-batcher' import type { AsyncDebouncer } from './async-debouncer' import type { AsyncQueuer } from './async-queuer' import type { AsyncRateLimiter } from './async-rate-limiter' +import type { AsyncRetryer } from './async-retryer' import type { AsyncThrottler } from './async-throttler' import type { Debouncer } from './debouncer' import type { Batcher } from './batcher' @@ -15,6 +16,7 @@ export interface PacerEventMap { 'pacer:d-AsyncDebouncer': AsyncDebouncer 'pacer:d-AsyncQueuer': AsyncQueuer 'pacer:d-AsyncRateLimiter': AsyncRateLimiter + 'pacer:d-AsyncRetryer': AsyncRetryer 'pacer:d-AsyncThrottler': AsyncThrottler 'pacer:d-Batcher': Batcher 'pacer:d-Debouncer': Debouncer @@ -25,6 +27,7 @@ export interface PacerEventMap { 'pacer:AsyncDebouncer': AsyncDebouncer 'pacer:AsyncQueuer': AsyncQueuer 'pacer:AsyncRateLimiter': AsyncRateLimiter + 'pacer:AsyncRetryer': AsyncRetryer 'pacer:AsyncThrottler': AsyncThrottler 'pacer:Batcher': Batcher 'pacer:Debouncer': Debouncer diff --git a/packages/pacer/src/index.ts b/packages/pacer/src/index.ts index 2e510c02..e1348ef1 100644 --- a/packages/pacer/src/index.ts +++ b/packages/pacer/src/index.ts @@ -2,6 +2,7 @@ export * from './async-batcher' export * from './async-debouncer' export * from './async-queuer' export * from './async-rate-limiter' +export * from './async-retryer' export * from './async-throttler' export * from './batcher' export * from './debouncer' @@ -10,5 +11,6 @@ export * from './rate-limiter' export * from './throttler' export * from './types' export * from './utils' + export { pacerEventClient } from './event-client' export type { PacerEventMap, PacerEventName } from './event-client' diff --git a/packages/pacer/src/queuer.ts b/packages/pacer/src/queuer.ts index 7a5e57f9..fe3277a2 100644 --- a/packages/pacer/src/queuer.ts +++ b/packages/pacer/src/queuer.ts @@ -287,6 +287,7 @@ export class Queuer { this.addItem(item, this.options.addItemsTo ?? 'back', isLast) } } + pacerEventClient.on('d-Queuer', (event) => { if (event.payload.key !== this.key) return this.#setState(event.payload.store.state) @@ -294,6 +295,11 @@ export class Queuer { }) } + /** + * Emits a change event for the queuer instance. Mostly useful for devtools. + */ + _emit = () => emitChange('Queuer', this) + /** * Updates the queuer options. New options are merged with existing options. */ diff --git a/packages/pacer/src/rate-limiter.ts b/packages/pacer/src/rate-limiter.ts index 66b3cd94..78aa8217 100644 --- a/packages/pacer/src/rate-limiter.ts +++ b/packages/pacer/src/rate-limiter.ts @@ -168,6 +168,11 @@ export class RateLimiter { }) } + /** + * Emits a change event for the rate limiter instance. Mostly useful for devtools. + */ + _emit = () => emitChange('RateLimiter', this) + /** * Updates the rate limiter options */ diff --git a/packages/pacer/src/throttler.ts b/packages/pacer/src/throttler.ts index 7978f51e..0137dca2 100644 --- a/packages/pacer/src/throttler.ts +++ b/packages/pacer/src/throttler.ts @@ -160,6 +160,11 @@ export class Throttler { }) } + /** + * Emits a change event for the throttler instance. Mostly useful for devtools. + */ + _emit = () => emitChange('Throttler', this) + /** * Updates the throttler options */ diff --git a/packages/pacer/tests/async-batcher.test.ts b/packages/pacer/tests/async-batcher.test.ts index 4be62363..6ac6898c 100644 --- a/packages/pacer/tests/async-batcher.test.ts +++ b/packages/pacer/tests/async-batcher.test.ts @@ -71,20 +71,20 @@ describe('AsyncBatcher', () => { }) it('should track execution state during async processing', async () => { - let resolvePromise: (value: any) => void - const promise = new Promise((resolve) => { - resolvePromise = resolve - }) - const mockFn = vi.fn().mockReturnValue(promise) - const batcher = new AsyncBatcher(mockFn, { maxSize: 1 }) + const mockFn = vi.fn().mockResolvedValue('result') + const batcher = new AsyncBatcher(mockFn, { maxSize: 2 }) + // Add item without triggering execution (since maxSize is 2) batcher.addItem(1) + expect(batcher.store.state.isExecuting).toBe(false) + expect(batcher.store.state.status).toBe('populated') + + // Use flush to trigger execution and wait for completion + const executionPromise = batcher.flush() expect(batcher.store.state.isExecuting).toBe(true) expect(batcher.store.state.status).toBe('executing') - resolvePromise!('result') - await promise - + await executionPromise expect(batcher.store.state.isExecuting).toBe(false) expect(batcher.store.state.status).toBe('idle') }) diff --git a/packages/pacer/tests/async-retryer.test.ts b/packages/pacer/tests/async-retryer.test.ts new file mode 100644 index 00000000..0aacb81a --- /dev/null +++ b/packages/pacer/tests/async-retryer.test.ts @@ -0,0 +1,614 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { AsyncRetryer, asyncRetry } from '../src/async-retryer' + +describe('AsyncRetryer', () => { + beforeEach(() => { + vi.useFakeTimers() + }) + + describe('Constructor and Defaults', () => { + it('should create with default options', () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn) + + expect(retryer.options.backoff).toBe('exponential') + expect(retryer.options.baseWait).toBe(1000) + expect(retryer.options.enabled).toBe(true) + expect(retryer.options.maxAttempts).toBe(3) + expect(retryer.options.throwOnError).toBe('last') + }) + + it('should merge custom options with defaults', () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 5, + backoff: 'linear', + baseWait: 500, + }) + + expect(retryer.options.maxAttempts).toBe(5) + expect(retryer.options.backoff).toBe('linear') + expect(retryer.options.baseWait).toBe(500) + expect(retryer.options.enabled).toBe(true) // Still default + }) + + it('should initialize with default state', () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn) + + expect(retryer.store.state).toEqual({ + currentAttempt: 0, + executionCount: 0, + isExecuting: false, + lastError: undefined, + lastExecutionTime: 0, + lastResult: undefined, + status: 'idle', + totalExecutionTime: 0, + }) + }) + + it('should merge initial state', () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn, { + initialState: { executionCount: 5 }, + }) + + expect(retryer.store.state.executionCount).toBe(5) + expect(retryer.store.state.currentAttempt).toBe(0) // Other defaults preserved + }) + }) + + describe('Successful Execution', () => { + it('should execute function successfully on first attempt', async () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn) + + const result = await retryer.execute('arg1', 'arg2') + + expect(result).toBe('success') + expect(mockFn).toHaveBeenCalledTimes(1) + expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2') + expect(retryer.store.state.executionCount).toBe(1) + expect(retryer.store.state.lastResult).toBe('success') + expect(retryer.store.state.status).toBe('idle') + expect(retryer.store.state.currentAttempt).toBe(0) + }) + + it('should call onSuccess callback', async () => { + const mockFn = vi.fn().mockResolvedValue('success') + const onSuccess = vi.fn() + const retryer = new AsyncRetryer(mockFn, { onSuccess }) + + await retryer.execute('arg1') + + expect(onSuccess).toHaveBeenCalledTimes(1) + expect(onSuccess).toHaveBeenCalledWith('success', ['arg1'], retryer) + }) + + it('should update execution time and timestamp', async () => { + const mockFn = vi.fn().mockImplementation(async () => { + vi.advanceTimersByTime(100) + return 'success' + }) + const retryer = new AsyncRetryer(mockFn) + + const beforeTime = Date.now() + await retryer.execute() + const afterTime = Date.now() + + expect(retryer.store.state.totalExecutionTime).toBeGreaterThan(0) + expect(retryer.store.state.lastExecutionTime).toBeGreaterThanOrEqual( + beforeTime, + ) + expect(retryer.store.state.lastExecutionTime).toBeLessThanOrEqual( + afterTime, + ) + }) + }) + + describe('Retry Logic', () => { + it('should retry on failure and succeed on second attempt', async () => { + const mockFn = vi + .fn() + .mockRejectedValueOnce(new Error('First failure')) + .mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn, { + baseWait: 100, + throwOnError: 'last', + }) + + const executePromise = retryer.execute('arg1') + + // Let the retry timer run + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + + const result = await executePromise + + expect(result).toBe('success') + expect(mockFn).toHaveBeenCalledTimes(2) + expect(retryer.store.state.executionCount).toBe(1) + expect(retryer.store.state.lastResult).toBe('success') + expect(retryer.store.state.status).toBe('idle') + }) + + it('should call onRetry callback for each retry', async () => { + const mockFn = vi + .fn() + .mockRejectedValueOnce(new Error('First failure')) + .mockRejectedValueOnce(new Error('Second failure')) + .mockResolvedValue('success') + const onRetry = vi.fn() + const retryer = new AsyncRetryer(mockFn, { onRetry, baseWait: 100 }) + + const executePromise = retryer.execute() + + // Let first retry happen + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + + // Let second retry happen + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(200) // Exponential backoff: 100 * 2^1 + + await executePromise + + expect(onRetry).toHaveBeenCalledTimes(2) + expect(onRetry).toHaveBeenNthCalledWith(1, 1, expect.any(Error), retryer) + expect(onRetry).toHaveBeenNthCalledWith(2, 2, expect.any(Error), retryer) + }) + + it('should fail after exhausting all retries', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Persistent failure')) + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 2, + baseWait: 0, // No delay to avoid timer issues + throwOnError: 'last', + }) + + await expect(retryer.execute()).rejects.toThrow('Persistent failure') + + expect(mockFn).toHaveBeenCalledTimes(2) + expect(retryer.store.state.lastError?.message).toBe('Persistent failure') + expect(retryer.store.state.status).toBe('idle') + }) + }) + + describe('Backoff Strategies', () => { + it('should use exponential backoff by default', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Failure')) + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 3, + baseWait: 100, + throwOnError: false, + }) + + const executePromise = retryer.execute() + + // First retry: wait 100ms (100 * 2^0) + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + + // Second retry: wait 200ms (100 * 2^1) + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(200) + + // Third attempt will not retry, just finish + await executePromise + + expect(mockFn).toHaveBeenCalledTimes(3) + expect(retryer.store.state.currentAttempt).toBe(3) + }) + + it('should use linear backoff', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Failure')) + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 3, + baseWait: 100, + backoff: 'linear', + throwOnError: false, + }) + + const executePromise = retryer.execute() + + // First retry should wait 100ms (100 * 1) + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + + // Second retry should wait 200ms (100 * 2) + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(200) + + await executePromise + expect(mockFn).toHaveBeenCalledTimes(3) + }) + + it('should use fixed backoff', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Failure')) + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 3, + baseWait: 150, + backoff: 'fixed', + throwOnError: false, + }) + + const executePromise = retryer.execute() + + // Both retries should wait 150ms + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(150) + + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(150) + + await executePromise + expect(mockFn).toHaveBeenCalledTimes(3) + }) + }) + + describe('Error Handling', () => { + it('should throw on last error by default', async () => { + const error = new Error('Test error') + const mockFn = vi.fn().mockRejectedValue(error) + const retryer = new AsyncRetryer(mockFn, { maxAttempts: 1 }) + + await expect(retryer.execute()).rejects.toThrow('Test error') + }) + + it('should not throw when throwOnError is false', async () => { + const error = new Error('Test error') + const mockFn = vi.fn().mockRejectedValue(error) + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 1, + throwOnError: false, + }) + + const result = await retryer.execute() + expect(result).toBeUndefined() + }) + + it('should throw after retries when throwOnError is true', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Test error')) + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 3, + baseWait: 0, // No delay to avoid timer issues + throwOnError: true, + }) + + await expect(retryer.execute()).rejects.toThrow('Test error') + + expect(mockFn).toHaveBeenCalledTimes(3) // Should still retry but throw at end + }) + + it('should call onError for every error', async () => { + const error = new Error('Test error') + const mockFn = vi.fn().mockRejectedValue(error) + const onError = vi.fn() + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 2, + baseWait: 100, + onError, + throwOnError: false, + }) + + const executePromise = retryer.execute('arg1') + + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + await executePromise + + expect(onError).toHaveBeenCalledTimes(1) // Only called once at the end after all retries fail + expect(onError).toHaveBeenCalledWith(error, ['arg1'], retryer) + }) + + it('should call onLastError only for final error', async () => { + const error = new Error('Test error') + const mockFn = vi.fn().mockRejectedValue(error) + const onLastError = vi.fn() + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 2, + baseWait: 100, + onLastError, + throwOnError: false, + }) + + const executePromise = retryer.execute() + + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + await executePromise + + expect(onLastError).toHaveBeenCalledTimes(1) + expect(onLastError).toHaveBeenCalledWith(error, retryer) + }) + }) + + describe('State Management', () => { + it('should track execution state correctly', async () => { + const mockFn = vi.fn().mockImplementation(async () => { + vi.advanceTimersByTime(50) + return 'success' + }) + const retryer = new AsyncRetryer(mockFn) + + expect(retryer.store.state.status).toBe('idle') + expect(retryer.store.state.isExecuting).toBe(false) + + const executePromise = retryer.execute() + + // Should be executing now + expect(retryer.store.state.status).toBe('executing') + expect(retryer.store.state.isExecuting).toBe(true) + expect(retryer.store.state.currentAttempt).toBe(1) + + await executePromise + + expect(retryer.store.state.status).toBe('idle') + expect(retryer.store.state.isExecuting).toBe(false) + expect(retryer.store.state.currentAttempt).toBe(0) + }) + + it('should show retrying status during retries', async () => { + const mockFn = vi + .fn() + .mockRejectedValueOnce(new Error('Failure')) + .mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn, { + baseWait: 100, + throwOnError: false, + }) + + // Start execution but do not await yet + const executePromise = retryer.execute() + + // After first rejection, status should be 'retrying' + // Allow microtasks to schedule the retry wait without advancing timers + await Promise.resolve() + expect(retryer.store.state.status).toBe('retrying') + + // Fast-forward the retry wait time + vi.advanceTimersByTime(100) + await executePromise + + // After completion, status should be 'idle' + expect(retryer.store.state.status).toBe('idle') + }) + + it('should show disabled status when not enabled', async () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn, { enabled: false }) + + expect(retryer.store.state.status).toBe('disabled') + + const result = await retryer.execute() + expect(result).toBeUndefined() + expect(mockFn).not.toHaveBeenCalled() + }) + }) + + describe('Callbacks', () => { + it('should call onSettled after every execution attempt', async () => { + const mockFn = vi + .fn() + .mockRejectedValueOnce(new Error('Failure')) + .mockResolvedValue('success') + const onSettled = vi.fn() + const retryer = new AsyncRetryer(mockFn, { onSettled, baseWait: 100 }) + + const executePromise = retryer.execute('arg1') + + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + await executePromise + + // Called after each attempt (failed + successful) + expect(onSettled).toHaveBeenCalledTimes(2) + expect(onSettled).toHaveBeenCalledWith(['arg1'], retryer) + }) + }) + + describe('Dynamic Options', () => { + it('should support function-based maxAttempts', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Failure')) + const maxAttemptsFn = vi.fn().mockReturnValue(2) + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: maxAttemptsFn, + baseWait: 100, + throwOnError: false, + }) + + const executePromise = retryer.execute() + + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + await executePromise + + expect(maxAttemptsFn).toHaveBeenCalledWith(retryer) + expect(mockFn).toHaveBeenCalledTimes(2) + }) + + it('should support function-based baseWait', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Failure')) + const baseWaitFn = vi.fn().mockReturnValue(200) + const retryer = new AsyncRetryer(mockFn, { + maxAttempts: 2, + baseWait: baseWaitFn, + throwOnError: false, + }) + + const executePromise = retryer.execute() + + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(200) // Should use function return value + await executePromise + + expect(baseWaitFn).toHaveBeenCalledWith(retryer) + }) + + it('should support function-based enabled', async () => { + const mockFn = vi.fn().mockResolvedValue('success') + const enabledFn = vi.fn().mockReturnValue(false) + const retryer = new AsyncRetryer(mockFn, { enabled: enabledFn }) + + const result = await retryer.execute() + + expect(enabledFn).toHaveBeenCalledWith(retryer) + expect(result).toBeUndefined() + expect(mockFn).not.toHaveBeenCalled() + }) + }) + + describe('Cancellation', () => { + it('should allow new executions after cancel and resolve undefined without error', async () => { + const mockFn = vi.fn().mockResolvedValue('success') + const onError = vi.fn() + const retryer = new AsyncRetryer(mockFn, { onError, throwOnError: false }) + + // Start and immediately cancel + const executePromise1 = retryer.execute() + retryer.abort() + + const result1 = await executePromise1 + expect(result1).toBeUndefined() + expect(onError).not.toHaveBeenCalled() + + // Should be able to execute again after cancel + const result2 = await retryer.execute() + + expect(result2).toBe('success') + expect(retryer.store.state.isExecuting).toBe(false) + }) + + it('should cancel retry delays without error', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Failure')) + const onError = vi.fn() + const retryer = new AsyncRetryer(mockFn, { + baseWait: 1000, + throwOnError: false, + onError, + }) + + const executePromise = retryer.execute() + + // Wait for first attempt to fail and retry wait to be scheduled + await Promise.resolve() + + // Cancel during retry delay + retryer.abort() + + const result = await executePromise + expect(result).toBeUndefined() + expect(mockFn).toHaveBeenCalledTimes(1) // Only first attempt + expect(onError).toHaveBeenCalledTimes(1) // only final onError after loop completion before cancel + }) + }) + + describe('Reset', () => { + it('should reset to initial state', async () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn) + + await retryer.execute() + expect(retryer.store.state.executionCount).toBe(1) + expect(retryer.store.state.lastResult).toBe('success') + + retryer.reset() + + expect(retryer.store.state).toEqual({ + currentAttempt: 0, + executionCount: 0, + isExecuting: false, + lastError: undefined, + lastExecutionTime: 0, + lastResult: undefined, + status: 'idle', + totalExecutionTime: 0, + }) + }) + + it('should cancel ongoing execution when resetting', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Failure')) + const retryer = new AsyncRetryer(mockFn, { + baseWait: 1000, + throwOnError: false, + }) + + const executePromise = retryer.execute() + + // Wait for first attempt to fail and retry wait to be scheduled + await Promise.resolve() + + retryer.reset() + + const result = await executePromise + expect(result).toBeUndefined() + expect(mockFn).toHaveBeenCalledTimes(1) // Only first attempt before reset + }) + }) + + describe('setOptions', () => { + it('should update options', () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryer = new AsyncRetryer(mockFn, { maxAttempts: 3 }) + + expect(retryer.options.maxAttempts).toBe(3) + + retryer.setOptions({ maxAttempts: 5, backoff: 'linear' }) + + expect(retryer.options.maxAttempts).toBe(5) + expect(retryer.options.backoff).toBe('linear') + expect(retryer.options.baseWait).toBe(1000) // Unchanged + }) + }) +}) + +describe('asyncRetry utility function', () => { + beforeEach(() => { + vi.useFakeTimers() + }) + + it('should create a retry-enabled function', async () => { + const mockFn = vi.fn().mockResolvedValue('success') + const retryFn = asyncRetry(mockFn, { maxAttempts: 2 }) + + const result = await retryFn('arg1', 'arg2') + + expect(result).toBe('success') + expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2') + }) + + it('should retry on failure', async () => { + const mockFn = vi + .fn() + .mockRejectedValueOnce(new Error('Failure')) + .mockResolvedValue('success') + const retryFn = asyncRetry(mockFn, { baseWait: 100, throwOnError: 'last' }) + + const executePromise = retryFn() + + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(100) + const result = await executePromise + + expect(result).toBe('success') + expect(mockFn).toHaveBeenCalledTimes(2) + }) + + it('should use default options', async () => { + const mockFn = vi.fn().mockRejectedValue(new Error('Failure')) + const retryFn = asyncRetry(mockFn, { throwOnError: false }) + + const executePromise = retryFn() + + // Should retry 3 times by default + vi.advanceTimersByTime(1000) // First retry: 1000ms + await vi.runOnlyPendingTimersAsync() + vi.advanceTimersByTime(2000) // Second retry: 2000ms + await vi.runOnlyPendingTimersAsync() + + const result = await executePromise + expect(result).toBeUndefined() + expect(mockFn).toHaveBeenCalledTimes(3) // Default maxAttempts + }) +}) diff --git a/packages/pacer/tests/async-throttler.test.ts b/packages/pacer/tests/async-throttler.test.ts index 010a04cf..115715bb 100644 --- a/packages/pacer/tests/async-throttler.test.ts +++ b/packages/pacer/tests/async-throttler.test.ts @@ -175,12 +175,37 @@ describe('AsyncThrottler', () => { expect(throttler.store.state.nextExecutionTime).toBe(now + 200) }) + it('should handle basic throttling behavior correctly', async () => { + const mockFn = vi.fn().mockResolvedValue('result') + const throttler = new AsyncThrottler(mockFn, { wait: 100 }) + + // First call should execute immediately + const result1 = await throttler.maybeExecute('first') + expect(mockFn).toHaveBeenCalledTimes(1) + expect(result1).toBe('result') + + // Second call within wait period should set up trailing execution + const promise2 = throttler.maybeExecute('second') + expect(mockFn).toHaveBeenCalledTimes(1) // Still only one call + + // Advance timers to trigger trailing execution + vi.advanceTimersByTime(100) + const result2 = await promise2 + expect(result2).toBe('result') // Returns result from trailing execution + + // After wait period, should execute again + vi.advanceTimersByTime(100) + const result3 = await throttler.maybeExecute('third') + expect(mockFn).toHaveBeenCalledTimes(3) // First call + trailing execution + third call + expect(result3).toBe('result') + }) + it('should cancel pending execution', async () => { const mockFn = vi.fn().mockResolvedValue(undefined) const throttler = new AsyncThrottler(mockFn, { wait: 100 }) // First call executes immediately - throttler.maybeExecute('first') + await throttler.maybeExecute('first') expect(mockFn).toHaveBeenCalledTimes(1) expect(mockFn).toHaveBeenLastCalledWith('first') @@ -189,6 +214,9 @@ describe('AsyncThrottler', () => { // Cancel it immediately throttler.cancel() + // Advance timers to allow any waiting loops to exit + await vi.advanceTimersByTimeAsync(10) + // Wait for the promise to settle await expect(promise).resolves.toBeUndefined() expect(mockFn).toHaveBeenCalledTimes(1) @@ -199,12 +227,15 @@ describe('AsyncThrottler', () => { const mockFn = vi.fn().mockResolvedValue(undefined) const throttler = new AsyncThrottler(mockFn, { wait: 100 }) - throttler.maybeExecute('first') + await throttler.maybeExecute('first') const promise = throttler.maybeExecute('second') throttler.cancel() + + // Advance timers to allow any waiting loops to exit + await vi.advanceTimersByTimeAsync(10) await promise - vi.advanceTimersByTime(100) + await vi.advanceTimersByTimeAsync(100) await throttler.maybeExecute('third') expect(mockFn).toHaveBeenCalledTimes(2) @@ -217,13 +248,16 @@ describe('AsyncThrottler', () => { const throttler = new AsyncThrottler(mockFn, { wait: 100 }) // First call should execute - throttler.maybeExecute('first') + await throttler.maybeExecute('first') expect(mockFn).toHaveBeenCalledTimes(1) expect(mockFn).toHaveBeenLastCalledWith('first') // Second call should be cancelled const promise = throttler.maybeExecute('second') throttler.cancel() + + // Advance timers to allow any waiting loops to exit + await vi.advanceTimersByTimeAsync(10) await promise // Multiple cancels should not throw @@ -245,14 +279,24 @@ describe('AsyncThrottler', () => { // Start first long-running call const promise1 = throttler.maybeExecute('first') const promise2 = throttler.maybeExecute('second') + + // Advance timers to allow waiting loop to start + await vi.advanceTimersByTimeAsync(50) + throttler.cancel() + // Advance timers to allow cancel to take effect + await vi.advanceTimersByTimeAsync(50) + resolveFirst!({}) await promise1 - await promise2 - expect(mockFn).toHaveBeenCalledTimes(1) - expect(mockFn).toHaveBeenLastCalledWith('first') + // The second promise should resolve with the result from the first execution + const result2 = await promise2 + expect(result2).toEqual({}) + + expect(mockFn).toHaveBeenCalledTimes(2) // First call + second call that triggered trailing execution + expect(mockFn).toHaveBeenLastCalledWith('second') }) it('should cancel pending calls when cancel is called', async () => { @@ -368,7 +412,10 @@ describe('AsyncThrottler', () => { expect(mockFn).toHaveBeenCalledTimes(1) expect(mockFn).toHaveBeenCalledWith('first') expect(flushResult).toBe('result') - expect(await promise).toBe('result') + + // The promise gets resolved by flush with the result + const promiseResult = await promise + expect(promiseResult).toBe('result') }) it('should update state correctly after flush', async () => { diff --git a/packages/react-pacer-devtools/package.json b/packages/react-pacer-devtools/package.json index 46f61ee0..fbe49934 100644 --- a/packages/react-pacer-devtools/package.json +++ b/packages/react-pacer-devtools/package.json @@ -69,7 +69,7 @@ "@tanstack/pacer-devtools": "workspace:*" }, "devDependencies": { - "@eslint-react/eslint-plugin": "^1.53.1", + "@eslint-react/eslint-plugin": "^2.0.4", "@vitejs/plugin-react": "^5.0.4", "eslint-plugin-react-compiler": "19.1.0-rc.2", "eslint-plugin-react-hooks": "^5.2.0" diff --git a/packages/react-pacer/package.json b/packages/react-pacer/package.json index 4c43a1d8..76ad58fc 100644 --- a/packages/react-pacer/package.json +++ b/packages/react-pacer/package.json @@ -77,6 +77,16 @@ "default": "./dist/cjs/async-rate-limiter/index.cjs" } }, + "./async-retryer": { + "import": { + "types": "./dist/esm/async-retryer/index.d.ts", + "default": "./dist/esm/async-retryer/index.js" + }, + "require": { + "types": "./dist/cjs/async-retryer/index.d.cts", + "default": "./dist/cjs/async-retryer/index.cjs" + } + }, "./async-throttler": { "import": { "types": "./dist/esm/async-throttler/index.d.ts", @@ -127,6 +137,16 @@ "default": "./dist/cjs/rate-limiter/index.cjs" } }, + "./provider": { + "import": { + "types": "./dist/esm/provider/index.d.ts", + "default": "./dist/esm/provider/index.js" + }, + "require": { + "types": "./dist/cjs/provider/index.d.cts", + "default": "./dist/cjs/provider/index.cjs" + } + }, "./throttler": { "import": { "types": "./dist/esm/throttler/index.d.ts", @@ -175,8 +195,8 @@ "@tanstack/react-store": "^0.7.7" }, "devDependencies": { - "@eslint-react/eslint-plugin": "^1.53.1", - "@types/react": "^19.1.15", + "@eslint-react/eslint-plugin": "^2.0.4", + "@types/react": "^19.1.17", "@vitejs/plugin-react": "^5.0.4", "eslint-plugin-react-compiler": "19.1.0-rc.2", "eslint-plugin-react-hooks": "^5.2.0", diff --git a/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts b/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts index ec9aa342..1d0f32c5 100644 --- a/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts +++ b/packages/react-pacer/src/async-batcher/useAsyncBatcher.ts @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react' import { AsyncBatcher } from '@tanstack/pacer/async-batcher' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { AsyncBatcherOptions, @@ -170,12 +171,19 @@ export function useAsyncBatcher( selector: (state: AsyncBatcherState) => TSelected = () => ({}) as TSelected, ): ReactAsyncBatcher { - const [asyncBatcher] = useState(() => new AsyncBatcher(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().asyncBatcher, + ...options, + } as AsyncBatcherOptions - const state = useStore(asyncBatcher.store, selector) + const [asyncBatcher] = useState( + () => new AsyncBatcher(fn, mergedOptions), + ) asyncBatcher.fn = fn - asyncBatcher.setOptions(options) + asyncBatcher.setOptions(mergedOptions) + + const state = useStore(asyncBatcher.store, selector) return useMemo( () => diff --git a/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts b/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts index 86637757..36b8ae99 100644 --- a/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts +++ b/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts @@ -1,6 +1,7 @@ import { useEffect, useMemo, useState } from 'react' import { AsyncDebouncer } from '@tanstack/pacer/async-debouncer' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { AnyAsyncFunction } from '@tanstack/pacer/types' import type { @@ -152,12 +153,19 @@ export function useAsyncDebouncer( selector: (state: AsyncDebouncerState) => TSelected = () => ({}) as TSelected, ): ReactAsyncDebouncer { - const [asyncDebouncer] = useState(() => new AsyncDebouncer(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().asyncDebouncer, + ...options, + } as AsyncDebouncerOptions - const state = useStore(asyncDebouncer.store, selector) + const [asyncDebouncer] = useState( + () => new AsyncDebouncer(fn, mergedOptions), + ) asyncDebouncer.fn = fn - asyncDebouncer.setOptions(options) + asyncDebouncer.setOptions(mergedOptions) + + const state = useStore(asyncDebouncer.store, selector) useEffect(() => { return () => { diff --git a/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts b/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts index 2e925fd7..0d88f364 100644 --- a/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts +++ b/packages/react-pacer/src/async-queuer/useAsyncQueuer.ts @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react' import { AsyncQueuer } from '@tanstack/pacer/async-queuer' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { AsyncQueuerOptions, @@ -170,12 +171,19 @@ export function useAsyncQueuer( selector: (state: AsyncQueuerState) => TSelected = () => ({}) as TSelected, ): ReactAsyncQueuer { - const [asyncQueuer] = useState(() => new AsyncQueuer(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().asyncQueuer, + ...options, + } as AsyncQueuerOptions - const state = useStore(asyncQueuer.store, selector) + const [asyncQueuer] = useState( + () => new AsyncQueuer(fn, mergedOptions), + ) asyncQueuer.fn = fn - asyncQueuer.setOptions(options) + asyncQueuer.setOptions(mergedOptions) + + const state = useStore(asyncQueuer.store, selector) return useMemo( () => diff --git a/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts b/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts index 179a8277..81bf9f6d 100644 --- a/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts +++ b/packages/react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react' import { AsyncRateLimiter } from '@tanstack/pacer/async-rate-limiter' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { AnyAsyncFunction } from '@tanstack/pacer/types' import type { @@ -184,14 +185,19 @@ export function useAsyncRateLimiter< selector: (state: AsyncRateLimiterState) => TSelected = () => ({}) as TSelected, ): ReactAsyncRateLimiter { + const mergedOptions = { + ...useDefaultPacerOptions().asyncRateLimiter, + ...options, + } as AsyncRateLimiterOptions + const [asyncRateLimiter] = useState( - () => new AsyncRateLimiter(fn, options), + () => new AsyncRateLimiter(fn, mergedOptions), ) - const state = useStore(asyncRateLimiter.store, selector) - asyncRateLimiter.fn = fn - asyncRateLimiter.setOptions(options) + asyncRateLimiter.setOptions(mergedOptions) + + const state = useStore(asyncRateLimiter.store, selector) return useMemo( () => diff --git a/packages/react-pacer/src/async-retryer/index.ts b/packages/react-pacer/src/async-retryer/index.ts new file mode 100644 index 00000000..6ec6da8e --- /dev/null +++ b/packages/react-pacer/src/async-retryer/index.ts @@ -0,0 +1 @@ +export * from './useAsyncRetryer' diff --git a/packages/react-pacer/src/async-retryer/useAsyncRetryer.ts b/packages/react-pacer/src/async-retryer/useAsyncRetryer.ts new file mode 100644 index 00000000..e059c95f --- /dev/null +++ b/packages/react-pacer/src/async-retryer/useAsyncRetryer.ts @@ -0,0 +1,186 @@ +import { useEffect, useMemo, useState } from 'react' +import { AsyncRetryer } from '@tanstack/pacer/async-retryer' +import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' +import type { Store } from '@tanstack/react-store' +import type { AnyAsyncFunction } from '@tanstack/pacer/types' +import type { + AsyncRetryerOptions, + AsyncRetryerState, +} from '@tanstack/pacer/async-retryer' + +export interface ReactAsyncRetryer + extends Omit, 'store'> { + /** + * Reactive state that will be updated and re-rendered when the retryer state changes + * + * Use this instead of `retryer.store.state` + */ + readonly state: Readonly + /** + * @deprecated Use `retryer.state` instead of `retryer.store.state` if you want to read reactive state. + * The state on the store object is not reactive, as it has not been wrapped in a `useStore` hook internally. + * Although, you can make the state reactive by using the `useStore` in your own usage. + */ + readonly store: Store>> +} + +/** + * A low-level React hook that creates an `AsyncRetryer` instance to retry execution of an async function. + * + * This hook is designed to be flexible and state-management agnostic - it simply returns a retryer instance that + * you can integrate with any state management solution (useState, Redux, Zustand, Jotai, etc). + * + * Async retrying automatically re-executes a failed async function up to a specified number of attempts with + * configurable backoff strategies. This is useful for handling transient errors like network failures, temporary + * server issues, or rate limiting where you want to automatically retry the operation. + * + * Error Handling: + * - If an `onError` handler is provided, it will be called for every error during execution + * - If an `onLastError` handler is provided, it will be called only for the final error after all retries fail + * - If `throwOnError` is 'last' (default), only the final error after all retries will be thrown + * - If `throwOnError` is true, every error will be thrown immediately (disables retrying) + * - If `throwOnError` is false, errors are never thrown and undefined is returned instead + * + * ## State Management and Selector + * + * The hook uses TanStack Store for reactive state management. The `selector` parameter allows you + * to specify which state changes will trigger a re-render, optimizing performance by preventing + * unnecessary re-renders when irrelevant state changes occur. + * + * **By default, there will be no reactive state subscriptions** and you must opt-in to state + * tracking by providing a selector function. This prevents unnecessary re-renders and gives you + * full control over when your component updates. Only when you provide a selector will the + * component re-render when the selected state values change. + * + * Available state properties: + * - `currentAttempt`: The current retry attempt number (0 when not executing) + * - `executionCount`: Total number of completed executions (successful or failed) + * - `isExecuting`: Whether the retryer is currently executing the function + * - `lastError`: The most recent error encountered during execution + * - `lastExecutionTime`: Timestamp of the last execution completion in milliseconds + * - `lastResult`: The result from the most recent successful execution + * - `status`: Current execution status ('disabled' | 'idle' | 'executing' | 'retrying') + * - `totalExecutionTime`: Total time spent executing (including retries) in milliseconds + * + * @example + * ```tsx + * // Default behavior - no reactive state subscriptions + * const apiRetryer = useAsyncRetryer( + * async (userId: string) => { + * const response = await fetch(`/api/users/${userId}`); + * if (!response.ok) throw new Error('Failed to fetch user'); + * return response.json(); + * }, + * { maxAttempts: 3, backoff: 'exponential' } + * ); + * + * // Opt-in to re-render when execution state changes (optimized for loading indicators) + * const apiRetryer = useAsyncRetryer( + * async (userId: string) => { + * const response = await fetch(`/api/users/${userId}`); + * if (!response.ok) throw new Error('Failed to fetch user'); + * return response.json(); + * }, + * { maxAttempts: 3, backoff: 'exponential' }, + * (state) => ({ + * isExecuting: state.isExecuting, + * currentAttempt: state.currentAttempt + * }) + * ); + * + * // Opt-in to re-render when results are available (optimized for data display) + * const apiRetryer = useAsyncRetryer( + * async (userId: string) => { + * const response = await fetch(`/api/users/${userId}`); + * if (!response.ok) throw new Error('Failed to fetch user'); + * return response.json(); + * }, + * { maxAttempts: 3, backoff: 'exponential' }, + * (state) => ({ + * lastResult: state.lastResult, + * executionCount: state.executionCount + * }) + * ); + * + * // Opt-in to re-render when error state changes (optimized for error handling) + * const apiRetryer = useAsyncRetryer( + * async (userId: string) => { + * const response = await fetch(`/api/users/${userId}`); + * if (!response.ok) throw new Error('Failed to fetch user'); + * return response.json(); + * }, + * { + * maxAttempts: 3, + * backoff: 'exponential', + * onError: (error) => console.error('API call failed:', error), + * onLastError: (error) => console.error('All retries failed:', error) + * }, + * (state) => ({ + * lastError: state.lastError, + * status: state.status + * }) + * ); + * + * // With state management + * const [userData, setUserData] = useState(null); + * const { execute, state } = useAsyncRetryer( + * async (userId) => { + * const response = await fetch(`/api/users/${userId}`); + * if (!response.ok) throw new Error('Failed to fetch user'); + * const data = await response.json(); + * setUserData(data); + * return data; + * }, + * { + * maxAttempts: 5, + * backoff: 'exponential', + * baseWait: 1000, + * onRetry: (attempt, error) => { + * console.log(`Retry attempt ${attempt} after error:`, error); + * }, + * onError: (error) => { + * console.error('Request failed:', error); + * } + * } + * ); + * + * // Access the selected state (will be empty object {} unless selector provided) + * const { isExecuting, currentAttempt } = state; + * ``` + */ +export function useAsyncRetryer( + fn: TFn, + options: AsyncRetryerOptions, + selector: (state: AsyncRetryerState) => TSelected = () => + ({}) as TSelected, +): ReactAsyncRetryer { + const mergedOptions = { + ...useDefaultPacerOptions().asyncRetryer, + ...options, + } as AsyncRetryerOptions + + const [asyncRetryer] = useState( + () => new AsyncRetryer(fn, mergedOptions), + ) + + asyncRetryer.fn = fn + asyncRetryer.setOptions(mergedOptions) + + const state = useStore(asyncRetryer.store, selector) + + useEffect(() => { + return () => { + asyncRetryer.abort() + } + }, [asyncRetryer]) + + return useMemo( + () => + ({ + ...asyncRetryer, + state, + }) as ReactAsyncRetryer, // omit `store` in favor of `state` + [asyncRetryer, state], + ) +} diff --git a/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts b/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts index 08f083b8..1f583c5c 100644 --- a/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts +++ b/packages/react-pacer/src/async-throttler/useAsyncThrottler.ts @@ -1,6 +1,7 @@ import { useEffect, useMemo, useState } from 'react' import { AsyncThrottler } from '@tanstack/pacer/async-throttler' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { AnyAsyncFunction } from '@tanstack/pacer/types' import type { @@ -163,12 +164,19 @@ export function useAsyncThrottler( selector: (state: AsyncThrottlerState) => TSelected = () => ({}) as TSelected, ): ReactAsyncThrottler { - const [asyncThrottler] = useState(() => new AsyncThrottler(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().asyncThrottler, + ...options, + } as AsyncThrottlerOptions - const state = useStore(asyncThrottler.store, selector) + const [asyncThrottler] = useState( + () => new AsyncThrottler(fn, mergedOptions), + ) asyncThrottler.fn = fn - asyncThrottler.setOptions(options) + asyncThrottler.setOptions(mergedOptions) + + const state = useStore(asyncThrottler.store, selector) useEffect(() => { return () => asyncThrottler.cancel() diff --git a/packages/react-pacer/src/batcher/useBatcher.ts b/packages/react-pacer/src/batcher/useBatcher.ts index 2709d6d0..b40d86e1 100644 --- a/packages/react-pacer/src/batcher/useBatcher.ts +++ b/packages/react-pacer/src/batcher/useBatcher.ts @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react' import { Batcher } from '@tanstack/pacer/batcher' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { BatcherOptions, BatcherState } from '@tanstack/pacer/batcher' @@ -124,12 +125,17 @@ export function useBatcher( selector: (state: BatcherState) => TSelected = () => ({}) as TSelected, ): ReactBatcher { - const [batcher] = useState(() => new Batcher(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().batcher, + ...options, + } as BatcherOptions - const state = useStore(batcher.store, selector) + const [batcher] = useState(() => new Batcher(fn, mergedOptions)) batcher.fn = fn - batcher.setOptions(options) + batcher.setOptions(mergedOptions) + + const state = useStore(batcher.store, selector) return useMemo( () => diff --git a/packages/react-pacer/src/debouncer/useDebouncer.ts b/packages/react-pacer/src/debouncer/useDebouncer.ts index 24674b64..cb9030dc 100644 --- a/packages/react-pacer/src/debouncer/useDebouncer.ts +++ b/packages/react-pacer/src/debouncer/useDebouncer.ts @@ -1,6 +1,7 @@ import { useEffect, useMemo, useState } from 'react' import { Debouncer } from '@tanstack/pacer/debouncer' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { DebouncerOptions, @@ -104,12 +105,15 @@ export function useDebouncer( options: DebouncerOptions, selector: (state: DebouncerState) => TSelected = () => ({}) as TSelected, ): ReactDebouncer { - const [debouncer] = useState(() => new Debouncer(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().debouncer, + ...options, + } as DebouncerOptions - const state = useStore(debouncer.store, selector) + const [debouncer] = useState(() => new Debouncer(fn, mergedOptions)) debouncer.fn = fn - debouncer.setOptions(options) + debouncer.setOptions(mergedOptions) useEffect(() => { return () => { @@ -117,6 +121,8 @@ export function useDebouncer( } }, [debouncer]) + const state = useStore(debouncer.store, selector) + return useMemo( () => ({ diff --git a/packages/react-pacer/src/index.ts b/packages/react-pacer/src/index.ts index 49344428..5ba57315 100644 --- a/packages/react-pacer/src/index.ts +++ b/packages/react-pacer/src/index.ts @@ -1,6 +1,9 @@ // re-export everything from the core pacer package export * from '@tanstack/pacer' +// provider +export * from './provider/PacerProvider' + /** * Export every hook individually - DON'T export from barrel files */ @@ -21,6 +24,9 @@ export * from './async-queuer/useAsyncQueuedState' export * from './async-rate-limiter/useAsyncRateLimiter' export * from './async-rate-limiter/useAsyncRateLimitedCallback' +// async-retryer +export * from './async-retryer/useAsyncRetryer' + // async-throttler export * from './async-throttler/useAsyncThrottler' export * from './async-throttler/useAsyncThrottledCallback' diff --git a/packages/react-pacer/src/provider/PacerProvider.tsx b/packages/react-pacer/src/provider/PacerProvider.tsx new file mode 100644 index 00000000..06df8207 --- /dev/null +++ b/packages/react-pacer/src/provider/PacerProvider.tsx @@ -0,0 +1,71 @@ +import React, { createContext, useContext, useMemo } from 'react' +import type { ReactNode } from 'react' +import type { + AnyAsyncFunction, + AnyFunction, + AsyncBatcherOptions, + AsyncDebouncerOptions, + AsyncQueuerOptions, + AsyncRateLimiterOptions, + AsyncRetryerOptions, + AsyncThrottlerOptions, + BatcherOptions, + DebouncerOptions, + QueuerOptions, + RateLimiterOptions, + ThrottlerOptions, +} from '@tanstack/pacer' + +export interface PacerProviderOptions { + asyncBatcher?: Partial> + asyncDebouncer?: Partial> + asyncQueuer?: Partial> + asyncRateLimiter?: Partial> + asyncRetryer?: Partial> + asyncThrottler?: Partial> + batcher?: Partial> + debouncer?: Partial> + queuer?: Partial> + rateLimiter?: Partial> + throttler?: Partial> +} + +interface PacerContextValue { + defaultOptions: PacerProviderOptions +} + +const PacerContext = createContext(null) + +export interface PacerProviderProps { + children: ReactNode + defaultOptions?: PacerProviderOptions +} + +const DEFAULT_OPTIONS: PacerProviderOptions = {} + +export function PacerProvider({ + children, + defaultOptions = DEFAULT_OPTIONS, +}: PacerProviderProps) { + const contextValue: PacerContextValue = useMemo( + () => ({ + defaultOptions, + }), + [defaultOptions], + ) + + return ( + + {children} + + ) +} + +export function usePacerContext() { + return useContext(PacerContext) +} + +export function useDefaultPacerOptions() { + const context = useContext(PacerContext) + return context?.defaultOptions ?? {} +} diff --git a/packages/react-pacer/src/provider/index.ts b/packages/react-pacer/src/provider/index.ts new file mode 100644 index 00000000..5f4fe385 --- /dev/null +++ b/packages/react-pacer/src/provider/index.ts @@ -0,0 +1 @@ +export * from './PacerProvider' diff --git a/packages/react-pacer/src/queuer/useQueuer.ts b/packages/react-pacer/src/queuer/useQueuer.ts index dec8992b..6bedc088 100644 --- a/packages/react-pacer/src/queuer/useQueuer.ts +++ b/packages/react-pacer/src/queuer/useQueuer.ts @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react' import { Queuer } from '@tanstack/pacer/queuer' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { QueuerOptions, QueuerState } from '@tanstack/pacer/queuer' @@ -134,12 +135,17 @@ export function useQueuer( options: QueuerOptions = {}, selector: (state: QueuerState) => TSelected = () => ({}) as TSelected, ): ReactQueuer { - const [queuer] = useState(() => new Queuer(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().queuer, + ...options, + } as QueuerOptions - const state = useStore(queuer.store, selector) + const [queuer] = useState(() => new Queuer(fn, mergedOptions)) queuer.fn = fn - queuer.setOptions(options) + queuer.setOptions(mergedOptions) + + const state = useStore(queuer.store, selector) return useMemo( () => diff --git a/packages/react-pacer/src/rate-limiter/useRateLimiter.ts b/packages/react-pacer/src/rate-limiter/useRateLimiter.ts index 8bf4442f..dfc2a4c5 100644 --- a/packages/react-pacer/src/rate-limiter/useRateLimiter.ts +++ b/packages/react-pacer/src/rate-limiter/useRateLimiter.ts @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react' import { RateLimiter } from '@tanstack/pacer/rate-limiter' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { RateLimiterOptions, @@ -143,12 +144,17 @@ export function useRateLimiter( options: RateLimiterOptions, selector: (state: RateLimiterState) => TSelected = () => ({}) as TSelected, ): ReactRateLimiter { - const [rateLimiter] = useState(() => new RateLimiter(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().rateLimiter, + ...options, + } as RateLimiterOptions - const state = useStore(rateLimiter.store, selector) + const [rateLimiter] = useState(() => new RateLimiter(fn, mergedOptions)) rateLimiter.fn = fn - rateLimiter.setOptions(options) + rateLimiter.setOptions(mergedOptions) + + const state = useStore(rateLimiter.store, selector) return useMemo( () => diff --git a/packages/react-pacer/src/throttler/useThrottler.ts b/packages/react-pacer/src/throttler/useThrottler.ts index 3bed9bef..327b5ba1 100644 --- a/packages/react-pacer/src/throttler/useThrottler.ts +++ b/packages/react-pacer/src/throttler/useThrottler.ts @@ -1,6 +1,7 @@ import { useEffect, useMemo, useState } from 'react' import { Throttler } from '@tanstack/pacer/throttler' import { useStore } from '@tanstack/react-store' +import { useDefaultPacerOptions } from '../provider/PacerProvider' import type { Store } from '@tanstack/react-store' import type { AnyFunction } from '@tanstack/pacer/types' import type { @@ -109,12 +110,17 @@ export function useThrottler( options: ThrottlerOptions, selector: (state: ThrottlerState) => TSelected = () => ({}) as TSelected, ): ReactThrottler { - const [throttler] = useState(() => new Throttler(fn, options)) + const mergedOptions = { + ...useDefaultPacerOptions().throttler, + ...options, + } as ThrottlerOptions - const state = useStore(throttler.store, selector) + const [throttler] = useState(() => new Throttler(fn, mergedOptions)) throttler.fn = fn - throttler.setOptions(options) + throttler.setOptions(mergedOptions) + + const state = useStore(throttler.store, selector) useEffect(() => { return () => { diff --git a/packages/react-pacer/vite.config.ts b/packages/react-pacer/vite.config.ts index 2657f80b..4d8e77bf 100644 --- a/packages/react-pacer/vite.config.ts +++ b/packages/react-pacer/vite.config.ts @@ -23,10 +23,12 @@ export default mergeConfig( './src/async-debouncer/index.ts', './src/async-queuer/index.ts', './src/async-rate-limiter/index.ts', + './src/async-retryer/index.ts', './src/async-throttler/index.ts', './src/batcher/index.ts', './src/debouncer/index.ts', './src/index.ts', + './src/provider/index.ts', './src/queuer/index.ts', './src/rate-limiter/index.ts', './src/throttler/index.ts', diff --git a/packages/solid-pacer-devtools/package.json b/packages/solid-pacer-devtools/package.json index f83ec566..a81a5bb7 100644 --- a/packages/solid-pacer-devtools/package.json +++ b/packages/solid-pacer-devtools/package.json @@ -66,6 +66,6 @@ "@tanstack/pacer-devtools": "workspace:*" }, "devDependencies": { - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" } } diff --git a/packages/solid-pacer/package.json b/packages/solid-pacer/package.json index cbf7d99a..96527581 100644 --- a/packages/solid-pacer/package.json +++ b/packages/solid-pacer/package.json @@ -176,7 +176,7 @@ }, "devDependencies": { "solid-js": "^1.9.9", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.9" }, "peerDependencies": { "solid-js": ">=1.9.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32e94549..f85f47d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,19 +22,19 @@ importers: version: 1.2.0 '@tanstack/config': specifier: 0.20.3 - version: 0.20.3(@types/node@24.6.1)(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(rollup@4.52.3)(typescript@5.9.2)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + version: 0.20.3(@types/node@24.6.1)(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(rollup@4.52.3)(typescript@5.9.3)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) '@testing-library/jest-dom': - specifier: ^6.8.0 - version: 6.9.0 + specifier: ^6.9.1 + version: 6.9.1 '@types/node': - specifier: ^24.3.1 + specifier: ^24.6.1 version: 24.6.1 eslint: specifier: ^9.36.0 version: 9.36.0(jiti@2.6.0) eslint-plugin-unused-imports: specifier: ^4.2.0 - version: 4.2.0(@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0)) + version: 4.2.0(@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0)) fast-glob: specifier: ^3.3.3 version: 3.3.3 @@ -43,12 +43,12 @@ importers: version: 27.0.0(postcss@8.5.6) knip: specifier: ^5.64.1 - version: 5.64.1(@types/node@24.6.1)(typescript@5.9.2) + version: 5.64.1(@types/node@24.6.1)(typescript@5.9.3) markdown-link-extractor: specifier: ^4.0.2 version: 4.0.2 nx: - specifier: ^21.5.3 + specifier: ^21.6.2 version: 21.6.2 premove: specifier: ^4.0.0 @@ -69,8 +69,8 @@ importers: specifier: ^11.2.0 version: 11.2.0 typescript: - specifier: 5.9.2 - version: 5.9.2 + specifier: 5.9.3 + version: 5.9.3 vite: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) @@ -91,11 +91,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -116,11 +116,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -141,11 +141,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -166,11 +166,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -191,11 +191,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -216,11 +216,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -241,17 +241,17 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@tanstack/react-devtools': - specifier: 0.7.0 - version: 0.7.0(@types/react-dom@19.1.9(@types/react@19.1.16))(@types/react@19.1.16)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9) + specifier: 0.7.1 + version: 0.7.1(@types/react-dom@19.2.0(@types/react@19.2.0))(@types/react@19.2.0)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9) '@tanstack/react-pacer-devtools': specifier: 0.3.1 version: link:../../../packages/react-pacer-devtools '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -272,11 +272,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -303,11 +303,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -334,11 +334,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -365,11 +365,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -390,11 +390,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -415,11 +415,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -440,11 +440,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -465,11 +465,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -490,11 +490,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -515,11 +515,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -540,11 +540,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -568,11 +568,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -596,11 +596,36 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) + '@vitejs/plugin-react': + specifier: ^5.0.4 + version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + vite: + specifier: ^7.1.7 + version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) + + examples/react/useAsyncRetryer: + dependencies: + '@tanstack/react-pacer': + specifier: ^0.16.4 + version: link:../../../packages/react-pacer + react: + specifier: ^19.1.1 + version: 19.1.1 + react-dom: + specifier: ^19.1.1 + version: 19.1.1(react@19.1.1) + devDependencies: + '@types/react': + specifier: ^19.1.17 + version: 19.2.0 + '@types/react-dom': + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -621,11 +646,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -646,11 +671,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -671,11 +696,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -696,11 +721,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -721,11 +746,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -746,11 +771,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -771,11 +796,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -796,11 +821,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -821,11 +846,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -849,17 +874,17 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@tanstack/react-devtools': - specifier: 0.7.0 - version: 0.7.0(@types/react-dom@19.1.9(@types/react@19.1.16))(@types/react@19.1.16)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9) + specifier: 0.7.1 + version: 0.7.1(@types/react-dom@19.2.0(@types/react@19.2.0))(@types/react@19.2.0)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9) '@tanstack/react-pacer-devtools': specifier: 0.3.1 version: link:../../../packages/react-pacer-devtools '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -883,11 +908,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -908,11 +933,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -933,11 +958,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -958,11 +983,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -986,11 +1011,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1014,11 +1039,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1039,11 +1064,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1064,11 +1089,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1089,11 +1114,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1114,11 +1139,11 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1139,17 +1164,17 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@tanstack/react-devtools': - specifier: 0.7.0 - version: 0.7.0(@types/react-dom@19.1.9(@types/react@19.1.16))(@types/react@19.1.16)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9) + specifier: 0.7.1 + version: 0.7.1(@types/react-dom@19.2.0(@types/react@19.2.0))(@types/react@19.2.0)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9) '@tanstack/react-pacer-devtools': specifier: 0.3.1 version: link:../../../packages/react-pacer-devtools '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@types/react-dom': - specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.16) + specifier: ^19.1.11 + version: 19.2.0(@types/react@19.2.0) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1170,8 +1195,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/asyncDebounce: dependencies: @@ -1186,8 +1211,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/asyncRateLimit: dependencies: @@ -1202,8 +1227,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/asyncThrottle: dependencies: @@ -1218,8 +1243,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/batch: dependencies: @@ -1234,8 +1259,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createAsyncBatcher: dependencies: @@ -1250,8 +1275,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createAsyncDebouncer: dependencies: @@ -1266,8 +1291,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createAsyncQueuer: dependencies: @@ -1282,8 +1307,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createAsyncRateLimiter: dependencies: @@ -1298,8 +1323,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createAsyncThrottler: dependencies: @@ -1314,8 +1339,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createBatcher: dependencies: @@ -1330,8 +1355,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createDebouncedSignal: dependencies: @@ -1346,8 +1371,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createDebouncedValue: dependencies: @@ -1362,8 +1387,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createDebouncer: dependencies: @@ -1378,14 +1403,14 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createQueuer: dependencies: '@tanstack/solid-devtools': - specifier: 0.7.0 - version: 0.7.0(csstype@3.1.3)(solid-js@1.9.9) + specifier: 0.7.1 + version: 0.7.1(csstype@3.1.3)(solid-js@1.9.9) '@tanstack/solid-pacer': specifier: ^0.14.4 version: link:../../../packages/solid-pacer @@ -1400,8 +1425,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createRateLimitedSignal: dependencies: @@ -1416,8 +1441,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createRateLimitedValue: dependencies: @@ -1432,8 +1457,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createRateLimiter: dependencies: @@ -1448,8 +1473,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createThrottledSignal: dependencies: @@ -1464,8 +1489,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createThrottledValue: dependencies: @@ -1480,8 +1505,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/createThrottler: dependencies: @@ -1496,8 +1521,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/debounce: dependencies: @@ -1512,14 +1537,14 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/queue: dependencies: '@tanstack/solid-devtools': - specifier: 0.7.0 - version: 0.7.0(csstype@3.1.3)(solid-js@1.9.9) + specifier: 0.7.1 + version: 0.7.1(csstype@3.1.3)(solid-js@1.9.9) '@tanstack/solid-pacer': specifier: ^0.14.4 version: link:../../../packages/solid-pacer @@ -1534,8 +1559,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/rateLimit: dependencies: @@ -1550,8 +1575,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) examples/solid/throttle: dependencies: @@ -1566,8 +1591,8 @@ importers: specifier: ^7.1.7 version: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) packages/pacer: dependencies: @@ -1585,7 +1610,7 @@ importers: version: 0.3.5(csstype@3.1.3)(solid-js@1.9.9) '@tanstack/devtools-utils': specifier: ^0.0.3 - version: 0.0.3(@types/react@19.1.16)(csstype@3.1.3)(react@19.1.1)(solid-js@1.9.9) + version: 0.0.3(@types/react@19.2.0)(csstype@3.1.3)(react@19.1.1)(solid-js@1.9.9) '@tanstack/pacer': specifier: '>=0.15.0' version: link:../pacer @@ -1606,8 +1631,8 @@ importers: version: 1.9.9 devDependencies: vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) packages/react-pacer: dependencies: @@ -1616,17 +1641,17 @@ importers: version: link:../pacer '@tanstack/react-store': specifier: ^0.7.7 - version: 0.7.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 0.7.7(react-dom@19.1.0(react@19.1.1))(react@19.1.1) react-dom: specifier: '>=16.8' - version: 19.1.1(react@19.1.1) + version: 19.1.0(react@19.1.1) devDependencies: '@eslint-react/eslint-plugin': - specifier: ^1.53.1 - version: 1.53.1(eslint@9.36.0(jiti@2.6.0))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2) + specifier: ^2.0.4 + version: 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@types/react': - specifier: ^19.1.15 - version: 19.1.16 + specifier: ^19.1.17 + version: 19.2.0 '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1644,7 +1669,7 @@ importers: dependencies: '@tanstack/devtools-utils': specifier: ^0.0.3 - version: 0.0.3(@types/react@19.1.16)(csstype@3.1.3)(react@19.1.1)(solid-js@1.9.9) + version: 0.0.3(@types/react@19.1.16)(react@19.1.1)(solid-js@1.9.9) '@tanstack/pacer-devtools': specifier: workspace:* version: link:../pacer-devtools @@ -1662,8 +1687,8 @@ importers: version: 19.1.1(react@19.1.1) devDependencies: '@eslint-react/eslint-plugin': - specifier: ^1.53.1 - version: 1.53.1(eslint@9.36.0(jiti@2.6.0))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2) + specifier: ^2.0.4 + version: 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) @@ -1687,30 +1712,34 @@ importers: specifier: ^1.9.9 version: 1.9.9 vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) packages/solid-pacer-devtools: dependencies: '@tanstack/devtools-utils': specifier: ^0.0.3 - version: 0.0.3(@types/react@19.1.16)(csstype@3.1.3)(react@19.1.1)(solid-js@1.9.9) + version: 0.0.3(@types/react@19.2.0)(react@19.1.1)(solid-js@1.9.7) '@tanstack/pacer-devtools': specifier: workspace:* version: link:../pacer-devtools solid-js: specifier: '>=1.9.7' - version: 1.9.9 + version: 1.9.7 devDependencies: vite-plugin-solid: - specifier: ^2.11.8 - version: 2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + specifier: ^2.11.9 + version: 2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.7)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@asamuzakjp/css-color@4.0.5': resolution: {integrity: sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==} @@ -1720,6 +1749,10 @@ packages: '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -1728,10 +1761,26 @@ packages: resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} engines: {node: '>=6.9.0'} + '@babel/core@7.26.10': + resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} + engines: {node: '>=6.9.0'} + '@babel/core@7.28.4': resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} engines: {node: '>=6.9.0'} + '@babel/generator@7.26.9': + resolution: {integrity: sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.27.0': + resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.0': + resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.28.3': resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} @@ -1740,6 +1789,10 @@ packages: resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.26.5': + resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} @@ -1762,10 +1815,20 @@ packages: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.28.3': resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} @@ -1790,22 +1853,48 @@ packages: resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.27.1': resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.27.0': + resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==} + engines: {node: '>=6.9.0'} + '@babel/helpers@7.28.4': resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} + '@babel/parser@7.27.0': + resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.28.0': + resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/parser@7.28.4': resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} engines: {node: '>=6.0.0'} @@ -1840,14 +1929,46 @@ packages: resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} + '@babel/template@7.26.9': + resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.0': + resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.26.9': + resolution: {integrity: sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.27.0': + resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.0': + resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.28.4': resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} engines: {node: '>=6.9.0'} + '@babel/types@7.26.9': + resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.27.0': + resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.0': + resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==} + engines: {node: '>=6.9.0'} + '@babel/types@7.28.4': resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} @@ -2127,39 +2248,36 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint-react/ast@1.53.1': - resolution: {integrity: sha512-qvUC99ewtriJp9quVEOvZ6+RHcsMLfVQ0OhZ4/LupZUDhjW7GiX1dxJsFaxHdJ9rLNLhQyLSPmbAToeqUrSruQ==} - engines: {node: '>=18.18.0'} + '@eslint-react/ast@2.0.4': + resolution: {integrity: sha512-n05swQRVYbeAi0kLXrnrxHmfacptOOlZzpCKSt8L2fobVx+xgMc0w+trRnyrlwcjGnf3IC1ZYT8h/AuqE4OJdw==} + engines: {node: '>=20.19.0'} - '@eslint-react/core@1.53.1': - resolution: {integrity: sha512-8prroos5/Uvvh8Tjl1HHCpq4HWD3hV9tYkm7uXgKA6kqj0jHlgRcQzuO6ZPP7feBcK3uOeug7xrq03BuG8QKCA==} - engines: {node: '>=18.18.0'} + '@eslint-react/core@2.0.4': + resolution: {integrity: sha512-TJDvUdID0fUhXrOlgK992WhEV2qOvmYdjE+bPLVLPFU2eVk0li0L+G9w+KWKDzUdIS2OVjIxmDWdg98eqJOyfQ==} + engines: {node: '>=20.19.0'} - '@eslint-react/eff@1.53.1': - resolution: {integrity: sha512-uq20lPRAmsWRjIZm+mAV/2kZsU2nDqn5IJslxGWe3Vfdw23hoyhEw3S1KKlxbftwbTvsZjKvVP0iw3bZo/NUpg==} - engines: {node: '>=18.18.0'} + '@eslint-react/eff@2.0.4': + resolution: {integrity: sha512-5+cEbTkpjP+sEszzOEF4lW176uSaez7S0t1jqXBQ0RortHVrm9OGPY9zx2ehNozYa2hqvztQa6mgmRMZGeC8xg==} + engines: {node: '>=20.19.0'} - '@eslint-react/eslint-plugin@1.53.1': - resolution: {integrity: sha512-JZ2ciXNCC9CtBBAqYtwWH+Jy/7ZzLw+whei8atP4Fxsbh+Scs30MfEwBzuiEbNw6uF9eZFfPidchpr5RaEhqxg==} - engines: {node: '>=18.18.0'} + '@eslint-react/eslint-plugin@2.0.4': + resolution: {integrity: sha512-jrYOfOW5YYJMQfekn3SctF0QD2WhVrjqrJ1yw+FBEMgL3eie7Jxkm4OerDVGP5+M6kjAaEew89ifNsMJKKNRbQ==} + engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ^4.9.5 || ^5.3.3 - peerDependenciesMeta: - typescript: - optional: true + eslint: ^9.36.0 + typescript: ^5.9.2 - '@eslint-react/kit@1.53.1': - resolution: {integrity: sha512-zOi2le9V4rMrJvQV4OeedGvMGvDT46OyFPOwXKs7m0tQu5vXVJ8qwIPaVQT1n/WIuvOg49OfmAVaHpGxK++xLQ==} - engines: {node: '>=18.18.0'} + '@eslint-react/kit@2.0.4': + resolution: {integrity: sha512-v/kG7X+vfMIfquKZOtXMgfZPp6+tVds97mBpmvQvpivd5XYLM3SrR/cODa0EpvOy6mF0XO4RCkJqjAptaJKKew==} + engines: {node: '>=20.19.0'} - '@eslint-react/shared@1.53.1': - resolution: {integrity: sha512-gomJQmFqQgQVI3Ra4vTMG/s6a4bx3JqeNiTBjxBJt4C9iGaBj458GkP4LJHX7TM6xUzX+fMSKOPX7eV3C/+UCw==} - engines: {node: '>=18.18.0'} + '@eslint-react/shared@2.0.4': + resolution: {integrity: sha512-nO1pO8GBNiFyoSFfplHG/cni0INs70OoKIgZtnKkm73L99h2sxX1S+ZH+f5p2vzltDYVaiJ41xzwMuuf+57ubA==} + engines: {node: '>=20.19.0'} - '@eslint-react/var@1.53.1': - resolution: {integrity: sha512-yzwopvPntcHU7mmDvWzRo1fb8QhjD8eDRRohD11rTV1u7nWO4QbJi0pOyugQakvte1/W11Y0Vr8Of0Ojk/A6zg==} - engines: {node: '>=18.18.0'} + '@eslint-react/var@2.0.4': + resolution: {integrity: sha512-lgw3Hv8vH3dh9e7FacX+IoBdfckvg1j77Nlei4T7kYzj4ziD0wziwQ6foLfKwfdvbgHbw2pBJmkwgs0iSC6w6w==} + engines: {node: '>=20.19.0'} '@eslint/config-array@0.21.0': resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} @@ -2244,6 +2362,10 @@ packages: '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} @@ -2251,6 +2373,10 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -2693,8 +2819,8 @@ packages: solid-js: optional: true - '@tanstack/devtools@0.6.14': - resolution: {integrity: sha512-dOtHoeLjjcHeNscu+ZEf89EFboQsy0ggb6pf8Sha59qBUeQbjUsaAvwP8Ogwg89oJxFQbTP7DKYNBNw5CxlNEA==} + '@tanstack/devtools@0.6.15': + resolution: {integrity: sha512-rfa1Kb0wrvsn4eYsCnYXuTzK2BEmHXCEmk3kuGdbZrHo2UTqjxFRK4E1NEGxd1yUgkzbn1VToO3GzDdt9mQTwA==} engines: {node: '>=18'} peerDependencies: solid-js: '>=1.9.7' @@ -2717,8 +2843,8 @@ packages: '@tanstack/query-devtools@5.90.1': resolution: {integrity: sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==} - '@tanstack/react-devtools@0.7.0': - resolution: {integrity: sha512-HJH+oNBYQotgsKWAQqvkY8KnfQbbZptHbrkPGVaIwj393vVFGT1BuXMYy+rlmOYxczyerb90ltRFgsQyUtJTuw==} + '@tanstack/react-devtools@0.7.1': + resolution: {integrity: sha512-PluCZ9ytBVKJrgaNYC9wcNfwwm6ysGZampUiXCs9A4HmXA7moAfcxbLKnQ+EFsuF4bg5Qqn/9ofhKxpvP1Fcmg==} engines: {node: '>=18'} peerDependencies: '@types/react': '>=16.8' @@ -2750,8 +2876,8 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/solid-devtools@0.7.0': - resolution: {integrity: sha512-BOwIadgyg0ISx7awjbCQEDwelMExZ2vuLQ6NO2Z7H2DSPPBultIBEWPK//cZhvdVrDaTmsEK+AvMDWI4SsSQ8w==} + '@tanstack/solid-devtools@0.7.1': + resolution: {integrity: sha512-YoWS6EqXkiWGfpPTlcF53XPjB4s6BtpAsBiI96prYWtAUghJTQ0v4zbAMK1m1uCemVXZMhNTUDPpcpzuuSIcTw==} engines: {node: '>=18'} peerDependencies: solid-js: '>=1.9.7' @@ -2772,8 +2898,8 @@ packages: resolution: {integrity: sha512-p1HuuSD3OUoVMYHfjkzUJqVBUurp1BDrGwT3302GRpSjpBHiJvZex3+NzRIXdG9NdjeJ0mT7DYpNMoii7GVROQ==} engines: {node: '>=18'} - '@testing-library/jest-dom@6.9.0': - resolution: {integrity: sha512-QHdxYMJ0YPGKYofMc6zYvo7LOViVhdc6nPg/OtM2cf9MQrwEcTxFCs7d/GJ5eSyPkHzOiBkc/KfLdFJBHzldtQ==} + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} '@tybys/wasm-util@0.10.1': @@ -2826,9 +2952,17 @@ packages: peerDependencies: '@types/react': ^19.0.0 + '@types/react-dom@19.2.0': + resolution: {integrity: sha512-brtBs0MnE9SMx7px208g39lRmC5uHZs96caOJfTjFcYSLHNamvaSMfJNagChVNkup2SdtOxKX1FDBkRSJe1ZAg==} + peerDependencies: + '@types/react': ^19.2.0 + '@types/react@19.1.16': resolution: {integrity: sha512-WBM/nDbEZmDUORKnh5i1bTnAz6vTohUf9b8esSMu+b24+srbaxa04UbJgWx78CVfNXA20sNu0odEIluZDFdCog==} + '@types/react@19.2.0': + resolution: {integrity: sha512-1LOH8xovvsKsCBq1wnT4ntDUdCJKmnEakhsuoUSy6ExlHCkGP2hqnatagYTgFk6oeL0VU31u7SNjunPN+GchtA==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -3550,35 +3684,26 @@ packages: peerDependencies: eslint: '>=7' - eslint-plugin-react-debug@1.53.1: - resolution: {integrity: sha512-WNOiQ6jhodJE88VjBU/IVDM+2Zr9gKHlBFDUSA3fQ0dMB5RiBVj5wMtxbxRuipK/GqNJbteqHcZoYEod7nfddg==} - engines: {node: '>=18.18.0'} + eslint-plugin-react-debug@2.0.4: + resolution: {integrity: sha512-0H4ELREV7fr1eA4be7QQZHiR/rzxhV3iquR/HQSQy5Ab3x7Bv7fTdA3dhWOlF9m/XTtfeNKz5iD66u9XFTGQzA==} + engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ^4.9.5 || ^5.3.3 - peerDependenciesMeta: - typescript: - optional: true + eslint: ^9.36.0 + typescript: ^5.9.2 - eslint-plugin-react-dom@1.53.1: - resolution: {integrity: sha512-UYrWJ2cS4HpJ1A5XBuf1HfMpPoLdfGil+27g/ldXfGemb4IXqlxHt4ANLyC8l2CWcE3SXGJW7mTslL34MG0qTQ==} - engines: {node: '>=18.18.0'} + eslint-plugin-react-dom@2.0.4: + resolution: {integrity: sha512-YQ7BAaFPEvh+sjVJp7STeCk5Uz6cKTVOXFAiOKYKX1FJ34xHhma1csfkDwIgEyr37mglS6wn/VRkS5HGx2/cHw==} + engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ^4.9.5 || ^5.3.3 - peerDependenciesMeta: - typescript: - optional: true + eslint: ^9.36.0 + typescript: ^5.9.2 - eslint-plugin-react-hooks-extra@1.53.1: - resolution: {integrity: sha512-fshTnMWNn9NjFLIuy7HzkRgGK29vKv4ZBO9UMr+kltVAfKLMeXXP6021qVKk66i/XhQjbktiS+vQsu1Rd3ZKvg==} - engines: {node: '>=18.18.0'} + eslint-plugin-react-hooks-extra@2.0.4: + resolution: {integrity: sha512-K4XEvsRD1NWj4phthkOMgBpRnexyP6f1+GLBv0i+Bo2sxS7qP/y/UgI5m8ZI6xCuh0H+MqWrUq1a8eku3hdb7g==} + engines: {node: '>=20.0.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ^4.9.5 || ^5.3.3 - peerDependenciesMeta: - typescript: - optional: true + eslint: ^9.36.0 + typescript: ^5.9.2 eslint-plugin-react-hooks@5.2.0: resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} @@ -3586,38 +3711,26 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react-naming-convention@1.53.1: - resolution: {integrity: sha512-rvZ/B/CSVF8d34HQ4qIt90LRuxotVx+KUf3i1OMXAyhsagEFMRe4gAlPJiRufZ+h9lnuu279bEdd+NINsXOteA==} - engines: {node: '>=18.18.0'} + eslint-plugin-react-naming-convention@2.0.4: + resolution: {integrity: sha512-/7cAWZyW/M5HH4WolPb9CwCf4HxribmQQ/tBrg28hexVx8EPDZO+PbONyESC6DvF2Y1P2N8lYo657h+y0tJhTg==} + engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ^4.9.5 || ^5.3.3 - peerDependenciesMeta: - typescript: - optional: true + eslint: ^9.36.0 + typescript: ^5.9.2 - eslint-plugin-react-web-api@1.53.1: - resolution: {integrity: sha512-INVZ3Cbl9/b+sizyb43ChzEPXXYuDsBGU9BIg7OVTNPyDPloCXdI+dQFAcSlDocZhPrLxhPV3eT6+gXbygzYXg==} - engines: {node: '>=18.18.0'} + eslint-plugin-react-web-api@2.0.4: + resolution: {integrity: sha512-U4ql2C+AQVnZeQ+nxBb3A8NA58W4tx4Fdc+cEro5/QMJKuiXltNUnhAJ5N4ttS6K0D/Iz1nHtkyULuWXFq+p1w==} + engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ^4.9.5 || ^5.3.3 - peerDependenciesMeta: - typescript: - optional: true + eslint: ^9.36.0 + typescript: ^5.9.2 - eslint-plugin-react-x@1.53.1: - resolution: {integrity: sha512-MwMNnVwiPem0U6SlejDF/ddA4h/lmP6imL1RDZ2m3pUBrcdcOwOx0gyiRVTA3ENnhRlWfHljHf5y7m8qDSxMEg==} - engines: {node: '>=18.18.0'} + eslint-plugin-react-x@2.0.4: + resolution: {integrity: sha512-9YqZGzu5lvevtzQjkaQZut2dMvOl9bjNgn+LUcwBdhqWkvoD7dFC6I0p6jgIZdA4ql8CGoYBlcYqve55wddOWw==} + engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - ts-api-utils: ^2.1.0 - typescript: ^4.9.5 || ^5.3.3 - peerDependenciesMeta: - ts-api-utils: - optional: true - typescript: - optional: true + eslint: ^9.36.0 + typescript: ^5.9.2 eslint-plugin-unused-imports@4.2.0: resolution: {integrity: sha512-hLbJ2/wnjKq4kGA9AUaExVFIbNzyxYdVo49QZmKCnhk5pc9wcYRbfgLHvWJ8tnsdcseGhoUAddm9gn/lt+d74w==} @@ -3713,6 +3826,14 @@ packages: fd-package-json@2.0.0: resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} + fdir@6.4.3: + resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -3820,6 +3941,10 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -4019,6 +4144,10 @@ packages: resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + jiti@2.6.0: resolution: {integrity: sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==} hasBin: true @@ -4373,6 +4502,9 @@ packages: parse5-parser-stream@7.1.2: resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -4408,6 +4540,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -4474,6 +4610,11 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + react-dom@19.1.0: + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + peerDependencies: + react: ^19.1.0 + react-dom@19.1.1: resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} peerDependencies: @@ -4667,6 +4808,9 @@ packages: resolution: {integrity: sha512-rInDH6lCNiEyn3+hH8KVGFdbjc099j47+OSgbMrfDYX1CmXLfdKd7qi6IfcWj2wFxvSVkuI46M+wPGYfEOEj6g==} engines: {node: '>= 18'} + solid-js@1.9.7: + resolution: {integrity: sha512-/saTKi8iWEM233n5OSi1YHCCuh66ZIQ7aK2hsToPe4tqGm7qAejU1SwNuTPivbWAYq7SjuHVVYxxuZQNRbICiw==} + solid-js@1.9.9: resolution: {integrity: sha512-A0ZBPJQldAeGCTW0YRYJmt7RCeh5rbFfPZ2aOttgYnctHE7HgKeHCBB/PVc2P7eOfmNXqMFFFoYYdm3S4dcbkA==} @@ -4784,6 +4928,14 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.12: + resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} + engines: {node: '>=12.0.0'} + + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -4895,8 +5047,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true @@ -4964,8 +5116,8 @@ packages: peerDependencies: vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 - vite-plugin-solid@2.11.8: - resolution: {integrity: sha512-hFrCxBfv3B1BmFqnJF4JOCYpjrmi/zwyeKjcomQ0khh8HFyQ8SbuBWQ7zGojfrz6HUOBFrJBNySDi/JgAHytWg==} + vite-plugin-solid@2.11.9: + resolution: {integrity: sha512-bTA6p+bspXZsuulSd2y6aTzegF8xGaJYcq1Uyh/mv+W4DQtzCgL9nN6n2fsTaxp/dMk+ZHHKgGndlNeooqHLKw==} peerDependencies: '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* solid-js: ^1.7.2 @@ -5186,6 +5338,11 @@ snapshots: '@adobe/css-tools@4.4.4': {} + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@asamuzakjp/css-color@4.0.5': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -5204,6 +5361,12 @@ snapshots: '@asamuzakjp/nwsapi@2.3.9': {} + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -5212,6 +5375,26 @@ snapshots: '@babel/compat-data@7.28.4': {} + '@babel/core@7.26.10': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.27.0 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) + '@babel/helpers': 7.27.0 + '@babel/parser': 7.27.0 + '@babel/template': 7.27.0 + '@babel/traverse': 7.27.0 + '@babel/types': 7.27.0 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/core@7.28.4': dependencies: '@babel/code-frame': 7.27.1 @@ -5232,6 +5415,30 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/generator@7.26.9': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@7.27.0': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.27.0 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@7.28.0': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + '@babel/generator@7.28.3': dependencies: '@babel/parser': 7.28.4 @@ -5244,6 +5451,14 @@ snapshots: dependencies: '@babel/types': 7.28.4 + '@babel/helper-compilation-targets@7.26.5': + dependencies: + '@babel/compat-data': 7.28.4 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.26.2 + lru-cache: 5.1.1 + semver: 6.3.1 + '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.28.4 @@ -5252,13 +5467,13 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4)': + '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.26.10 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-member-expression-to-functions': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.26.10) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 '@babel/traverse': 7.28.4 semver: 6.3.1 @@ -5278,10 +5493,26 @@ snapshots: dependencies: '@babel/types': 7.28.4 + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.9 transitivePeerDependencies: - supports-color @@ -5300,9 +5531,9 @@ snapshots: '@babel/helper-plugin-utils@7.27.1': {} - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.4)': + '@babel/helper-replace-supers@7.27.1(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.26.10 '@babel/helper-member-expression-to-functions': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1 '@babel/traverse': 7.28.4 @@ -5316,25 +5547,44 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-string-parser@7.25.9': {} + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-option@7.25.9': {} + '@babel/helper-validator-option@7.27.1': {} + '@babel/helpers@7.27.0': + dependencies: + '@babel/template': 7.27.0 + '@babel/types': 7.27.0 + '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 '@babel/types': 7.28.4 + '@babel/parser@7.27.0': + dependencies: + '@babel/types': 7.27.0 + + '@babel/parser@7.28.0': + dependencies: + '@babel/types': 7.28.0 + '@babel/parser@7.28.4': dependencies: '@babel/types': 7.28.4 - '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.28.4)': + '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/core': 7.26.10 + '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -5356,11 +5606,59 @@ snapshots: '@babel/runtime@7.28.4': {} + '@babel/template@7.26.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.4 + + '@babel/template@7.27.0': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.28.0 + '@babel/types': 7.27.0 + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 + + '@babel/traverse@7.26.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.9 + '@babel/parser': 7.28.0 + '@babel/template': 7.26.9 + '@babel/types': 7.26.9 + debug: 4.4.3 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/traverse@7.27.0': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.27.0 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.0 + '@babel/types': 7.27.0 + debug: 4.4.3 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/traverse@7.28.0': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/types': 7.28.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color '@babel/traverse@7.28.4': dependencies: @@ -5374,6 +5672,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/types@7.26.9': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@babel/types@7.27.0': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@babel/types@7.28.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.28.4': dependencies: '@babel/helper-string-parser': 7.27.1 @@ -5663,30 +5976,28 @@ snapshots: '@eslint-community/regexpp@4.12.1': {} - '@eslint-react/ast@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@eslint-react/ast@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: - '@eslint-react/eff': 1.53.1 + '@eslint-react/eff': 2.0.4 '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) string-ts: 2.2.1 - ts-pattern: 5.8.0 transitivePeerDependencies: - eslint - supports-color - typescript - '@eslint-react/core@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@eslint-react/core@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: - '@eslint-react/ast': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/shared': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/var': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/ast': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/shared': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/var': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) birecord: 0.1.1 ts-pattern: 5.8.0 transitivePeerDependencies: @@ -5694,46 +6005,43 @@ snapshots: - supports-color - typescript - '@eslint-react/eff@1.53.1': {} + '@eslint-react/eff@2.0.4': {} - '@eslint-react/eslint-plugin@1.53.1(eslint@9.36.0(jiti@2.6.0))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2)': + '@eslint-react/eslint-plugin@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/shared': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/shared': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) eslint: 9.36.0(jiti@2.6.0) - eslint-plugin-react-debug: 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - eslint-plugin-react-dom: 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - eslint-plugin-react-hooks-extra: 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - eslint-plugin-react-naming-convention: 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - eslint-plugin-react-web-api: 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - eslint-plugin-react-x: 1.53.1(eslint@9.36.0(jiti@2.6.0))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2) - optionalDependencies: - typescript: 5.9.2 + eslint-plugin-react-debug: 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + eslint-plugin-react-dom: 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + eslint-plugin-react-hooks-extra: 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + eslint-plugin-react-naming-convention: 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + eslint-plugin-react-web-api: 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + eslint-plugin-react-x: 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - - ts-api-utils - '@eslint-react/kit@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@eslint-react/kit@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: - '@eslint-react/eff': 1.53.1 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - ts-pattern: 5.8.0 - zod: 4.1.11 + '@eslint-react/eff': 2.0.4 + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) transitivePeerDependencies: - eslint - supports-color - typescript - '@eslint-react/shared@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@eslint-react/shared@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) ts-pattern: 5.8.0 zod: 4.1.11 transitivePeerDependencies: @@ -5741,14 +6049,13 @@ snapshots: - supports-color - typescript - '@eslint-react/var@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@eslint-react/var@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: - '@eslint-react/ast': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/eff': 1.53.1 + '@eslint-react/ast': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/eff': 2.0.4 '@typescript-eslint/scope-manager': 8.45.0 '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - string-ts: 2.2.1 + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) ts-pattern: 5.8.0 transitivePeerDependencies: - eslint @@ -5837,6 +6144,12 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/remapping@2.3.5': dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -5844,6 +6157,8 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/set-array@1.2.1': {} + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -6215,12 +6530,12 @@ snapshots: transitivePeerDependencies: - encoding - '@tanstack/config@0.20.3(@types/node@24.6.1)(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(rollup@4.52.3)(typescript@5.9.2)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1))': + '@tanstack/config@0.20.3(@types/node@24.6.1)(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(rollup@4.52.3)(typescript@5.9.3)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1))': dependencies: - '@tanstack/eslint-config': 0.3.2(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@tanstack/eslint-config': 0.3.2(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@tanstack/publish-config': 0.2.1 - '@tanstack/typedoc-config': 0.2.1(typescript@5.9.2) - '@tanstack/vite-config': 0.3.0(@types/node@24.6.1)(rollup@4.52.3)(typescript@5.9.2)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + '@tanstack/typedoc-config': 0.2.1(typescript@5.9.3) + '@tanstack/vite-config': 0.3.0(@types/node@24.6.1)(rollup@4.52.3)(typescript@5.9.3)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) transitivePeerDependencies: - '@types/node' - '@typescript-eslint/utils' @@ -6248,9 +6563,25 @@ snapshots: transitivePeerDependencies: - csstype - '@tanstack/devtools-utils@0.0.3(@types/react@19.1.16)(csstype@3.1.3)(react@19.1.1)(solid-js@1.9.9)': + '@tanstack/devtools-ui@0.3.5(solid-js@1.9.7)': dependencies: - '@tanstack/devtools-ui': 0.3.5(csstype@3.1.3)(solid-js@1.9.9) + clsx: 2.1.1 + goober: 2.1.16(csstype@3.1.3) + solid-js: 1.9.7 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools-ui@0.3.5(solid-js@1.9.9)': + dependencies: + clsx: 2.1.1 + goober: 2.1.16(csstype@3.1.3) + solid-js: 1.9.9 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools-utils@0.0.3(@types/react@19.1.16)(react@19.1.1)(solid-js@1.9.9)': + dependencies: + '@tanstack/devtools-ui': 0.3.5(solid-js@1.9.9) optionalDependencies: '@types/react': 19.1.16 react: 19.1.1 @@ -6258,7 +6589,27 @@ snapshots: transitivePeerDependencies: - csstype - '@tanstack/devtools@0.6.14(csstype@3.1.3)(solid-js@1.9.9)': + '@tanstack/devtools-utils@0.0.3(@types/react@19.2.0)(csstype@3.1.3)(react@19.1.1)(solid-js@1.9.9)': + dependencies: + '@tanstack/devtools-ui': 0.3.5(csstype@3.1.3)(solid-js@1.9.9) + optionalDependencies: + '@types/react': 19.2.0 + react: 19.1.1 + solid-js: 1.9.9 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools-utils@0.0.3(@types/react@19.2.0)(react@19.1.1)(solid-js@1.9.7)': + dependencies: + '@tanstack/devtools-ui': 0.3.5(solid-js@1.9.7) + optionalDependencies: + '@types/react': 19.2.0 + react: 19.1.1 + solid-js: 1.9.7 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools@0.6.15(csstype@3.1.3)(solid-js@1.9.9)': dependencies: '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.9) '@tanstack/devtools-event-bus': 0.3.2 @@ -6271,14 +6622,14 @@ snapshots: - csstype - utf-8-validate - '@tanstack/eslint-config@0.3.2(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@tanstack/eslint-config@0.3.2(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: '@eslint/js': 9.36.0 '@stylistic/eslint-plugin': 5.4.0(eslint@9.36.0(jiti@2.6.0)) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0)) - eslint-plugin-n: 17.23.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0)) + eslint-plugin-n: 17.23.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) globals: 16.4.0 - typescript-eslint: 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + typescript-eslint: 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) vue-eslint-parser: 10.2.0(eslint@9.36.0(jiti@2.6.0)) transitivePeerDependencies: - '@typescript-eslint/utils' @@ -6302,11 +6653,11 @@ snapshots: '@tanstack/query-devtools@5.90.1': {} - '@tanstack/react-devtools@0.7.0(@types/react-dom@19.1.9(@types/react@19.1.16))(@types/react@19.1.16)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9)': + '@tanstack/react-devtools@0.7.1(@types/react-dom@19.2.0(@types/react@19.2.0))(@types/react@19.2.0)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9)': dependencies: - '@tanstack/devtools': 0.6.14(csstype@3.1.3)(solid-js@1.9.9) - '@types/react': 19.1.16 - '@types/react-dom': 19.1.9(@types/react@19.1.16) + '@tanstack/devtools': 0.6.15(csstype@3.1.3)(solid-js@1.9.9) + '@types/react': 19.2.0 + '@types/react-dom': 19.2.0(@types/react@19.2.0) react: 19.1.1 react-dom: 19.1.1(react@19.1.1) transitivePeerDependencies: @@ -6332,16 +6683,16 @@ snapshots: '@tanstack/query-core': 5.90.2 react: 19.1.1 - '@tanstack/react-store@0.7.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@tanstack/react-store@0.7.7(react-dom@19.1.0(react@19.1.1))(react@19.1.1)': dependencies: '@tanstack/store': 0.7.7 react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react-dom: 19.1.0(react@19.1.1) use-sync-external-store: 1.5.0(react@19.1.1) - '@tanstack/solid-devtools@0.7.0(csstype@3.1.3)(solid-js@1.9.9)': + '@tanstack/solid-devtools@0.7.1(csstype@3.1.3)(solid-js@1.9.9)': dependencies: - '@tanstack/devtools': 0.6.14(csstype@3.1.3)(solid-js@1.9.9) + '@tanstack/devtools': 0.6.15(csstype@3.1.3)(solid-js@1.9.9) solid-js: 1.9.9 transitivePeerDependencies: - bufferutil @@ -6355,20 +6706,20 @@ snapshots: '@tanstack/store@0.7.7': {} - '@tanstack/typedoc-config@0.2.1(typescript@5.9.2)': + '@tanstack/typedoc-config@0.2.1(typescript@5.9.3)': dependencies: - typedoc: 0.27.9(typescript@5.9.2) - typedoc-plugin-frontmatter: 1.2.1(typedoc-plugin-markdown@4.4.2(typedoc@0.27.9(typescript@5.9.2))) - typedoc-plugin-markdown: 4.4.2(typedoc@0.27.9(typescript@5.9.2)) + typedoc: 0.27.9(typescript@5.9.3) + typedoc-plugin-frontmatter: 1.2.1(typedoc-plugin-markdown@4.4.2(typedoc@0.27.9(typescript@5.9.3))) + typedoc-plugin-markdown: 4.4.2(typedoc@0.27.9(typescript@5.9.3)) transitivePeerDependencies: - typescript - '@tanstack/vite-config@0.3.0(@types/node@24.6.1)(rollup@4.52.3)(typescript@5.9.2)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1))': + '@tanstack/vite-config@0.3.0(@types/node@24.6.1)(rollup@4.52.3)(typescript@5.9.3)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1))': dependencies: rollup-plugin-preserve-directives: 0.4.0(rollup@4.52.3) - vite-plugin-dts: 4.2.3(@types/node@24.6.1)(rollup@4.52.3)(typescript@5.9.2)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + vite-plugin-dts: 4.2.3(@types/node@24.6.1)(rollup@4.52.3)(typescript@5.9.3)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) vite-plugin-externalize-deps: 0.9.0(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) - vite-tsconfig-paths: 5.1.4(typescript@5.9.2)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + vite-tsconfig-paths: 5.1.4(typescript@5.9.3)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) transitivePeerDependencies: - '@types/node' - rollup @@ -6376,7 +6727,7 @@ snapshots: - typescript - vite - '@testing-library/jest-dom@6.9.0': + '@testing-library/jest-dom@6.9.1': dependencies: '@adobe/css-tools': 4.4.4 aria-query: 5.3.2 @@ -6406,12 +6757,12 @@ snapshots: '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.27.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.0 + '@babel/types': 7.27.0 '@types/babel__traverse@7.28.0': dependencies: @@ -6445,47 +6796,55 @@ snapshots: dependencies: '@types/react': 19.1.16 + '@types/react-dom@19.2.0(@types/react@19.2.0)': + dependencies: + '@types/react': 19.2.0 + '@types/react@19.1.16': dependencies: csstype: 3.1.3 + '@types/react@19.2.0': + dependencies: + csstype: 3.1.3 + '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.45.0 eslint: 9.36.0(jiti@2.6.0) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.45.0 '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.45.0 debug: 4.4.3 eslint: 9.36.0(jiti@2.6.0) - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.45.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.45.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3) '@typescript-eslint/types': 8.45.0 debug: 4.4.3 - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -6494,28 +6853,28 @@ snapshots: '@typescript-eslint/types': 8.45.0 '@typescript-eslint/visitor-keys': 8.45.0 - '@typescript-eslint/tsconfig-utils@8.45.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.45.0(typescript@5.9.3)': dependencies: - typescript: 5.9.2 + typescript: 5.9.3 - '@typescript-eslint/type-utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) debug: 4.4.3 eslint: 9.36.0(jiti@2.6.0) - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@8.45.0': {} - '@typescript-eslint/typescript-estree@8.45.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.45.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.45.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.2) + '@typescript-eslint/project-service': 8.45.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3) '@typescript-eslint/types': 8.45.0 '@typescript-eslint/visitor-keys': 8.45.0 debug: 4.4.3 @@ -6523,19 +6882,19 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + '@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.6.0)) '@typescript-eslint/scope-manager': 8.45.0 '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) eslint: 9.36.0(jiti@2.6.0) - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -6687,7 +7046,7 @@ snapshots: de-indent: 1.0.2 he: 1.2.0 - '@vue/language-core@2.1.6(typescript@5.9.2)': + '@vue/language-core@2.1.6(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.23 '@vue/compiler-dom': 3.5.22 @@ -6698,7 +7057,7 @@ snapshots: muggle-string: 0.4.1 path-browserify: 1.0.1 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 '@vue/shared@3.5.22': {} @@ -6801,6 +7160,13 @@ snapshots: parse5: 7.3.0 validate-html-nesting: 1.2.3 + babel-preset-solid@1.9.9(@babel/core@7.28.4)(solid-js@1.9.7): + dependencies: + '@babel/core': 7.28.4 + babel-plugin-jsx-dom-expressions: 0.40.1(@babel/core@7.28.4) + optionalDependencies: + solid-js: 1.9.7 + babel-preset-solid@1.9.9(@babel/core@7.28.4)(solid-js@1.9.9): dependencies: '@babel/core': 7.28.4 @@ -7181,7 +7547,7 @@ snapshots: eslint: 9.36.0(jiti@2.6.0) eslint-compat-utils: 0.5.1(eslint@9.36.0(jiti@2.6.0)) - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0)): dependencies: '@typescript-eslint/types': 8.45.0 comment-parser: 1.4.1 @@ -7194,11 +7560,11 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) transitivePeerDependencies: - supports-color - eslint-plugin-n@17.23.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + eslint-plugin-n@17.23.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.6.0)) enhanced-resolve: 5.18.3 @@ -7209,15 +7575,15 @@ snapshots: globrex: 0.1.2 ignore: 5.3.2 semver: 7.7.2 - ts-declaration-location: 1.0.7(typescript@5.9.2) + ts-declaration-location: 1.0.7(typescript@5.9.3) transitivePeerDependencies: - typescript eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.36.0(jiti@2.6.0)): dependencies: - '@babel/core': 7.28.4 - '@babel/parser': 7.28.4 - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.28.4) + '@babel/core': 7.26.10 + '@babel/parser': 7.27.0 + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.26.10) eslint: 9.36.0(jiti@2.6.0) hermes-parser: 0.25.1 zod: 3.25.76 @@ -7225,63 +7591,60 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-react-debug@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + eslint-plugin-react-debug@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: - '@eslint-react/ast': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/core': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/shared': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/var': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/ast': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/core': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/shared': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/var': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) eslint: 9.36.0(jiti@2.6.0) string-ts: 2.2.1 ts-pattern: 5.8.0 - optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-dom@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + eslint-plugin-react-dom@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: - '@eslint-react/ast': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/core': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/shared': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/var': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/ast': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/core': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/shared': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/var': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) compare-versions: 6.1.1 eslint: 9.36.0(jiti@2.6.0) string-ts: 2.2.1 ts-pattern: 5.8.0 - optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks-extra@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + eslint-plugin-react-hooks-extra@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: - '@eslint-react/ast': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/core': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/shared': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/var': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/ast': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/core': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/shared': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/var': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) eslint: 9.36.0(jiti@2.6.0) string-ts: 2.2.1 ts-pattern: 5.8.0 - optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -7289,73 +7652,70 @@ snapshots: dependencies: eslint: 9.36.0(jiti@2.6.0) - eslint-plugin-react-naming-convention@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + eslint-plugin-react-naming-convention@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: - '@eslint-react/ast': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/core': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/shared': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/var': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/ast': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/core': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/shared': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/var': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) eslint: 9.36.0(jiti@2.6.0) string-ts: 2.2.1 ts-pattern: 5.8.0 - optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-web-api@1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + eslint-plugin-react-web-api@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: - '@eslint-react/ast': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/core': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/shared': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/var': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/ast': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/core': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/shared': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/var': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) eslint: 9.36.0(jiti@2.6.0) string-ts: 2.2.1 ts-pattern: 5.8.0 - optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-x@1.53.1(eslint@9.36.0(jiti@2.6.0))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2): + eslint-plugin-react-x@2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: - '@eslint-react/ast': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/core': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/eff': 1.53.1 - '@eslint-react/kit': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/shared': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@eslint-react/var': 1.53.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@eslint-react/ast': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/core': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/eff': 2.0.4 + '@eslint-react/kit': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/shared': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@eslint-react/var': 2.0.4(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) compare-versions: 6.1.1 eslint: 9.36.0(jiti@2.6.0) - is-immutable-type: 5.0.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + is-immutable-type: 5.0.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) string-ts: 2.2.1 + ts-api-utils: 2.1.0(typescript@5.9.3) ts-pattern: 5.8.0 - optionalDependencies: - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-unused-imports@4.2.0(@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0)): + eslint-plugin-unused-imports@4.2.0(@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0)): dependencies: eslint: 9.36.0(jiti@2.6.0) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) eslint-scope@8.4.0: dependencies: @@ -7466,6 +7826,10 @@ snapshots: dependencies: walk-up-path: 4.0.0 + fdir@6.4.3(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -7572,6 +7936,8 @@ snapshots: dependencies: is-glob: 4.0.3 + globals@11.12.0: {} + globals@14.0.0: {} globals@15.15.0: {} @@ -7693,13 +8059,13 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-immutable-type@5.0.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + is-immutable-type@5.0.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) eslint: 9.36.0(jiti@2.6.0) - ts-api-utils: 2.1.0(typescript@5.9.2) - ts-declaration-location: 1.0.7(typescript@5.9.2) - typescript: 5.9.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + ts-declaration-location: 1.0.7(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -7742,6 +8108,8 @@ snapshots: chalk: 4.1.2 pretty-format: 30.2.0 + jiti@2.4.2: {} + jiti@2.6.0: {} jju@1.4.0: {} @@ -7817,7 +8185,7 @@ snapshots: dependencies: json-buffer: 3.0.1 - knip@5.64.1(@types/node@24.6.1)(typescript@5.9.2): + knip@5.64.1(@types/node@24.6.1)(typescript@5.9.3): dependencies: '@nodelib/fs.walk': 1.2.8 '@types/node': 24.6.1 @@ -7831,7 +8199,7 @@ snapshots: picomatch: 4.0.3 smol-toml: 1.4.2 strip-json-comments: 5.0.2 - typescript: 5.9.2 + typescript: 5.9.3 zod: 4.1.11 kolorist@1.8.0: {} @@ -8149,11 +8517,15 @@ snapshots: parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 - parse5: 7.3.0 + parse5: 7.2.1 parse5-parser-stream@7.1.2: dependencies: - parse5: 7.3.0 + parse5: 7.2.1 + + parse5@7.2.1: + dependencies: + entities: 4.5.0 parse5@7.3.0: dependencies: @@ -8177,6 +8549,8 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.2: {} + picomatch@4.0.3: {} pify@4.0.1: {} @@ -8229,6 +8603,11 @@ snapshots: queue-microtask@1.2.3: {} + react-dom@19.1.0(react@19.1.1): + dependencies: + react: 19.1.1 + scheduler: 0.26.0 + react-dom@19.1.1(react@19.1.1): dependencies: react: 19.1.1 @@ -8404,22 +8783,37 @@ snapshots: dependencies: bytes-iec: 3.1.1 chokidar: 4.0.3 - jiti: 2.6.0 + jiti: 2.4.2 lilconfig: 3.1.3 nanospinner: 1.2.2 picocolors: 1.1.1 - tinyglobby: 0.2.15 + tinyglobby: 0.2.12 slash@3.0.0: {} smol-toml@1.4.2: {} + solid-js@1.9.7: + dependencies: + csstype: 3.1.3 + seroval: 1.3.2 + seroval-plugins: 1.3.3(seroval@1.3.2) + solid-js@1.9.9: dependencies: csstype: 3.1.3 seroval: 1.3.2 seroval-plugins: 1.3.3(seroval@1.3.2) + solid-refresh@0.6.3(solid-js@1.9.7): + dependencies: + '@babel/generator': 7.28.3 + '@babel/helper-module-imports': 7.27.1 + '@babel/types': 7.28.4 + solid-js: 1.9.7 + transitivePeerDependencies: + - supports-color + solid-refresh@0.6.3(solid-js@1.9.9): dependencies: '@babel/generator': 7.28.3 @@ -8529,6 +8923,16 @@ snapshots: tinyexec@0.3.2: {} + tinyglobby@0.2.12: + dependencies: + fdir: 6.4.3(picomatch@4.0.2) + picomatch: 4.0.2 + + tinyglobby@0.2.14: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -8564,20 +8968,20 @@ snapshots: tree-kill@1.2.2: {} - ts-api-utils@2.1.0(typescript@5.9.2): + ts-api-utils@2.1.0(typescript@5.9.3): dependencies: - typescript: 5.9.2 + typescript: 5.9.3 - ts-declaration-location@1.0.7(typescript@5.9.2): + ts-declaration-location@1.0.7(typescript@5.9.3): dependencies: picomatch: 4.0.3 - typescript: 5.9.2 + typescript: 5.9.3 ts-pattern@5.8.0: {} - tsconfck@3.1.6(typescript@5.9.2): + tsconfck@3.1.6(typescript@5.9.3): optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 tsconfig-paths@4.2.0: dependencies: @@ -8591,38 +8995,38 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typedoc-plugin-frontmatter@1.2.1(typedoc-plugin-markdown@4.4.2(typedoc@0.27.9(typescript@5.9.2))): + typedoc-plugin-frontmatter@1.2.1(typedoc-plugin-markdown@4.4.2(typedoc@0.27.9(typescript@5.9.3))): dependencies: - typedoc-plugin-markdown: 4.4.2(typedoc@0.27.9(typescript@5.9.2)) + typedoc-plugin-markdown: 4.4.2(typedoc@0.27.9(typescript@5.9.3)) yaml: 2.8.1 - typedoc-plugin-markdown@4.4.2(typedoc@0.27.9(typescript@5.9.2)): + typedoc-plugin-markdown@4.4.2(typedoc@0.27.9(typescript@5.9.3)): dependencies: - typedoc: 0.27.9(typescript@5.9.2) + typedoc: 0.27.9(typescript@5.9.3) - typedoc@0.27.9(typescript@5.9.2): + typedoc@0.27.9(typescript@5.9.3): dependencies: '@gerrit0/mini-shiki': 1.27.2 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 - typescript: 5.9.2 + typescript: 5.9.3 yaml: 2.8.1 - typescript-eslint@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + typescript-eslint@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.3) eslint: 9.36.0(jiti@2.6.0) - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color typescript@5.4.2: {} - typescript@5.9.2: {} + typescript@5.9.3: {} uc.micro@2.1.0: {} @@ -8699,18 +9103,18 @@ snapshots: - tsx - yaml - vite-plugin-dts@4.2.3(@types/node@24.6.1)(rollup@4.52.3)(typescript@5.9.2)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)): + vite-plugin-dts@4.2.3(@types/node@24.6.1)(rollup@4.52.3)(typescript@5.9.3)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)): dependencies: '@microsoft/api-extractor': 7.47.7(@types/node@24.6.1) '@rollup/pluginutils': 5.3.0(rollup@4.52.3) '@volar/typescript': 2.4.23 - '@vue/language-core': 2.1.6(typescript@5.9.2) + '@vue/language-core': 2.1.6(typescript@5.9.3) compare-versions: 6.1.1 debug: 4.4.3 kolorist: 1.8.0 local-pkg: 0.5.1 magic-string: 0.30.19 - typescript: 5.9.2 + typescript: 5.9.3 optionalDependencies: vite: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) transitivePeerDependencies: @@ -8722,7 +9126,22 @@ snapshots: dependencies: vite: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) - vite-plugin-solid@2.11.8(@testing-library/jest-dom@6.9.0)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)): + vite-plugin-solid@2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.7)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)): + dependencies: + '@babel/core': 7.28.4 + '@types/babel__core': 7.20.5 + babel-preset-solid: 1.9.9(@babel/core@7.28.4)(solid-js@1.9.7) + merge-anything: 5.1.7 + solid-js: 1.9.7 + solid-refresh: 0.6.3(solid-js@1.9.7) + vite: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) + vitefu: 1.1.1(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) + optionalDependencies: + '@testing-library/jest-dom': 6.9.1 + transitivePeerDependencies: + - supports-color + + vite-plugin-solid@2.11.9(@testing-library/jest-dom@6.9.1)(solid-js@1.9.9)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)): dependencies: '@babel/core': 7.28.4 '@types/babel__core': 7.20.5 @@ -8733,15 +9152,15 @@ snapshots: vite: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) vitefu: 1.1.1(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)) optionalDependencies: - '@testing-library/jest-dom': 6.9.0 + '@testing-library/jest-dom': 6.9.1 transitivePeerDependencies: - supports-color - vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)): dependencies: debug: 4.4.3 globrex: 0.1.2 - tsconfck: 3.1.6(typescript@5.9.2) + tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: vite: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1) transitivePeerDependencies: @@ -8781,11 +9200,11 @@ snapshots: expect-type: 1.2.2 magic-string: 0.30.19 pathe: 2.0.3 - picomatch: 4.0.3 + picomatch: 4.0.2 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.15 + tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 vite: 7.1.7(@types/node@24.6.1)(jiti@2.6.0)(yaml@2.8.1)