@tanstack/solid-pacer 0.18.4 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +8 -8
  2. package/dist/async-batcher/createAsyncBatcher.cjs +32 -2
  3. package/dist/async-batcher/createAsyncBatcher.cjs.map +1 -1
  4. package/dist/async-batcher/createAsyncBatcher.d.cts +28 -2
  5. package/dist/async-batcher/createAsyncBatcher.d.ts +28 -2
  6. package/dist/async-batcher/createAsyncBatcher.js +32 -2
  7. package/dist/async-batcher/createAsyncBatcher.js.map +1 -1
  8. package/dist/async-batcher/index.cjs +1 -0
  9. package/dist/async-batcher/index.d.cts +2 -2
  10. package/dist/async-batcher/index.d.ts +2 -2
  11. package/dist/async-debouncer/createAsyncDebouncer.cjs +26 -3
  12. package/dist/async-debouncer/createAsyncDebouncer.cjs.map +1 -1
  13. package/dist/async-debouncer/createAsyncDebouncer.d.cts +27 -2
  14. package/dist/async-debouncer/createAsyncDebouncer.d.ts +27 -2
  15. package/dist/async-debouncer/createAsyncDebouncer.js +26 -3
  16. package/dist/async-debouncer/createAsyncDebouncer.js.map +1 -1
  17. package/dist/async-debouncer/index.cjs +1 -0
  18. package/dist/async-debouncer/index.d.cts +2 -2
  19. package/dist/async-debouncer/index.d.ts +2 -2
  20. package/dist/async-queuer/createAsyncQueuer.cjs +32 -2
  21. package/dist/async-queuer/createAsyncQueuer.cjs.map +1 -1
  22. package/dist/async-queuer/createAsyncQueuer.d.cts +28 -2
  23. package/dist/async-queuer/createAsyncQueuer.d.ts +28 -2
  24. package/dist/async-queuer/createAsyncQueuer.js +32 -2
  25. package/dist/async-queuer/createAsyncQueuer.js.map +1 -1
  26. package/dist/async-queuer/index.cjs +1 -0
  27. package/dist/async-queuer/index.d.cts +2 -2
  28. package/dist/async-queuer/index.d.ts +2 -2
  29. package/dist/async-rate-limiter/createAsyncRateLimiter.cjs +16 -2
  30. package/dist/async-rate-limiter/createAsyncRateLimiter.cjs.map +1 -1
  31. package/dist/async-rate-limiter/createAsyncRateLimiter.d.cts +15 -2
  32. package/dist/async-rate-limiter/createAsyncRateLimiter.d.ts +15 -2
  33. package/dist/async-rate-limiter/createAsyncRateLimiter.js +16 -2
  34. package/dist/async-rate-limiter/createAsyncRateLimiter.js.map +1 -1
  35. package/dist/async-rate-limiter/index.cjs +1 -0
  36. package/dist/async-rate-limiter/index.d.cts +2 -2
  37. package/dist/async-rate-limiter/index.d.ts +2 -2
  38. package/dist/async-throttler/createAsyncThrottler.cjs +31 -2
  39. package/dist/async-throttler/createAsyncThrottler.cjs.map +1 -1
  40. package/dist/async-throttler/createAsyncThrottler.d.cts +27 -2
  41. package/dist/async-throttler/createAsyncThrottler.d.ts +27 -2
  42. package/dist/async-throttler/createAsyncThrottler.js +31 -2
  43. package/dist/async-throttler/createAsyncThrottler.js.map +1 -1
  44. package/dist/async-throttler/index.cjs +1 -0
  45. package/dist/async-throttler/index.d.cts +2 -2
  46. package/dist/async-throttler/index.d.ts +2 -2
  47. package/dist/batcher/createBatcher.cjs +23 -2
  48. package/dist/batcher/createBatcher.cjs.map +1 -1
  49. package/dist/batcher/createBatcher.d.cts +22 -2
  50. package/dist/batcher/createBatcher.d.ts +22 -2
  51. package/dist/batcher/createBatcher.js +23 -2
  52. package/dist/batcher/createBatcher.js.map +1 -1
  53. package/dist/batcher/index.cjs +1 -0
  54. package/dist/batcher/index.d.cts +2 -2
  55. package/dist/batcher/index.d.ts +2 -2
  56. package/dist/debouncer/createDebouncedSignal.cjs.map +1 -1
  57. package/dist/debouncer/createDebouncedSignal.d.cts +3 -3
  58. package/dist/debouncer/createDebouncedSignal.d.ts +3 -3
  59. package/dist/debouncer/createDebouncedSignal.js.map +1 -1
  60. package/dist/debouncer/createDebouncedValue.cjs.map +1 -1
  61. package/dist/debouncer/createDebouncedValue.d.cts +3 -3
  62. package/dist/debouncer/createDebouncedValue.d.ts +3 -3
  63. package/dist/debouncer/createDebouncedValue.js.map +1 -1
  64. package/dist/debouncer/createDebouncer.cjs +17 -3
  65. package/dist/debouncer/createDebouncer.cjs.map +1 -1
  66. package/dist/debouncer/createDebouncer.d.cts +21 -2
  67. package/dist/debouncer/createDebouncer.d.ts +21 -2
  68. package/dist/debouncer/createDebouncer.js +17 -3
  69. package/dist/debouncer/createDebouncer.js.map +1 -1
  70. package/dist/debouncer/index.cjs +1 -0
  71. package/dist/debouncer/index.d.cts +2 -2
  72. package/dist/debouncer/index.d.ts +2 -2
  73. package/dist/index.cjs +1 -0
  74. package/dist/index.d.cts +11 -11
  75. package/dist/index.d.ts +11 -11
  76. package/dist/provider/index.cjs +1 -0
  77. package/dist/queuer/createQueuedSignal.cjs.map +1 -1
  78. package/dist/queuer/createQueuedSignal.d.cts +3 -3
  79. package/dist/queuer/createQueuedSignal.d.ts +3 -3
  80. package/dist/queuer/createQueuedSignal.js.map +1 -1
  81. package/dist/queuer/createQueuer.cjs +23 -2
  82. package/dist/queuer/createQueuer.cjs.map +1 -1
  83. package/dist/queuer/createQueuer.d.cts +22 -2
  84. package/dist/queuer/createQueuer.d.ts +22 -2
  85. package/dist/queuer/createQueuer.js +23 -2
  86. package/dist/queuer/createQueuer.js.map +1 -1
  87. package/dist/queuer/index.cjs +1 -0
  88. package/dist/queuer/index.d.cts +2 -2
  89. package/dist/queuer/index.d.ts +2 -2
  90. package/dist/rate-limiter/createRateLimitedSignal.cjs.map +1 -1
  91. package/dist/rate-limiter/createRateLimitedSignal.d.cts +3 -3
  92. package/dist/rate-limiter/createRateLimitedSignal.d.ts +3 -3
  93. package/dist/rate-limiter/createRateLimitedSignal.js.map +1 -1
  94. package/dist/rate-limiter/createRateLimitedValue.cjs.map +1 -1
  95. package/dist/rate-limiter/createRateLimitedValue.d.cts +3 -3
  96. package/dist/rate-limiter/createRateLimitedValue.d.ts +3 -3
  97. package/dist/rate-limiter/createRateLimitedValue.js.map +1 -1
  98. package/dist/rate-limiter/createRateLimiter.cjs +9 -2
  99. package/dist/rate-limiter/createRateLimiter.cjs.map +1 -1
  100. package/dist/rate-limiter/createRateLimiter.d.cts +9 -2
  101. package/dist/rate-limiter/createRateLimiter.d.ts +9 -2
  102. package/dist/rate-limiter/createRateLimiter.js +9 -2
  103. package/dist/rate-limiter/createRateLimiter.js.map +1 -1
  104. package/dist/rate-limiter/index.cjs +1 -0
  105. package/dist/rate-limiter/index.d.cts +2 -2
  106. package/dist/rate-limiter/index.d.ts +2 -2
  107. package/dist/throttler/createThrottledSignal.cjs.map +1 -1
  108. package/dist/throttler/createThrottledSignal.d.cts +3 -3
  109. package/dist/throttler/createThrottledSignal.d.ts +3 -3
  110. package/dist/throttler/createThrottledSignal.js.map +1 -1
  111. package/dist/throttler/createThrottledValue.cjs.map +1 -1
  112. package/dist/throttler/createThrottledValue.d.cts +3 -3
  113. package/dist/throttler/createThrottledValue.d.ts +3 -3
  114. package/dist/throttler/createThrottledValue.js.map +1 -1
  115. package/dist/throttler/createThrottler.cjs +17 -3
  116. package/dist/throttler/createThrottler.cjs.map +1 -1
  117. package/dist/throttler/createThrottler.d.cts +21 -2
  118. package/dist/throttler/createThrottler.d.ts +21 -2
  119. package/dist/throttler/createThrottler.js +17 -3
  120. package/dist/throttler/createThrottler.js.map +1 -1
  121. package/dist/throttler/index.cjs +1 -0
  122. package/dist/throttler/index.d.cts +2 -2
  123. package/dist/throttler/index.d.ts +2 -2
  124. package/package.json +33 -32
  125. package/src/async-batcher/createAsyncBatcher.ts +44 -3
  126. package/src/async-debouncer/createAsyncDebouncer.ts +37 -4
  127. package/src/async-queuer/createAsyncQueuer.ts +44 -3
  128. package/src/async-rate-limiter/createAsyncRateLimiter.ts +30 -3
  129. package/src/async-throttler/createAsyncThrottler.ts +43 -3
  130. package/src/batcher/createBatcher.ts +38 -3
  131. package/src/debouncer/createDebouncedSignal.ts +3 -6
  132. package/src/debouncer/createDebouncedValue.ts +3 -6
  133. package/src/debouncer/createDebouncer.ts +30 -4
  134. package/src/queuer/createQueuedSignal.ts +3 -3
  135. package/src/queuer/createQueuer.ts +37 -3
  136. package/src/rate-limiter/createRateLimitedSignal.ts +6 -6
  137. package/src/rate-limiter/createRateLimitedValue.ts +6 -6
  138. package/src/rate-limiter/createRateLimiter.ts +22 -3
  139. package/src/throttler/createThrottledSignal.ts +3 -6
  140. package/src/throttler/createThrottledValue.ts +3 -6
  141. package/src/throttler/createThrottler.ts +30 -4
@@ -1,3 +1,4 @@
1
+ import { createEffect, onCleanup } from 'solid-js'
1
2
  import { AsyncThrottler } from '@tanstack/pacer/async-throttler'
2
3
  import { useStore } from '@tanstack/solid-store'
3
4
  import { useDefaultPacerOptions } from '../provider/PacerProvider'
@@ -9,6 +10,17 @@ import type {
9
10
  AsyncThrottlerState,
10
11
  } from '@tanstack/pacer/async-throttler'
11
12
 
13
+ export interface SolidAsyncThrottlerOptions<
14
+ TFn extends AnyAsyncFunction,
15
+ TSelected = {},
16
+ > extends AsyncThrottlerOptions<TFn> {
17
+ /**
18
+ * Optional callback invoked when the owning component unmounts. Receives the throttler instance.
19
+ * When provided, replaces the default cleanup (cancel + abort); use it to call flush(), reset(), cancel(), add logging, etc.
20
+ */
21
+ onUnmount?: (throttler: SolidAsyncThrottler<TFn, TSelected>) => void
22
+ }
23
+
12
24
  export interface SolidAsyncThrottler<
13
25
  TFn extends AnyAsyncFunction,
14
26
  TSelected = {},
@@ -100,6 +112,24 @@ export interface SolidAsyncThrottler<
100
112
  * - `nextExecutionTime`: Timestamp of the next allowed execution
101
113
  * - `status`: Current execution status ('disabled' | 'idle' | 'pending' | 'executing')
102
114
  *
115
+ * ## Unmount behavior
116
+ *
117
+ * By default, the primitive cancels any pending execution and aborts any in-flight execution when the owning component unmounts.
118
+ * Abort only cancels underlying operations (e.g. fetch) when the abort signal from `getAbortSignal()` is passed to them.
119
+ * Use the `onUnmount` option to customize this. For example, to flush pending work instead:
120
+ *
121
+ * ```tsx
122
+ * const throttler = createAsyncThrottler(fn, {
123
+ * wait: 1000,
124
+ * onUnmount: (t) => t.flush()
125
+ * });
126
+ * ```
127
+ *
128
+ * Note: For async utils, `flush()` returns a Promise and runs fire-and-forget in the cleanup.
129
+ * If your throttled function updates Solid signals, those updates may run after the component has
130
+ * unmounted, which can cause unexpected reactive updates. Guard your callbacks accordingly when
131
+ * using onUnmount with flush.
132
+ *
103
133
  * @example
104
134
  * ```tsx
105
135
  * // Default behavior - no reactive state subscriptions
@@ -147,15 +177,14 @@ export function createAsyncThrottler<
147
177
  TSelected = {},
148
178
  >(
149
179
  fn: TFn,
150
- options: AsyncThrottlerOptions<TFn>,
180
+ options: SolidAsyncThrottlerOptions<TFn, TSelected>,
151
181
  selector: (state: AsyncThrottlerState<TFn>) => TSelected = () =>
152
182
  ({}) as TSelected,
153
183
  ): SolidAsyncThrottler<TFn, TSelected> {
154
184
  const mergedOptions = {
155
185
  ...useDefaultPacerOptions().asyncThrottler,
156
186
  ...options,
157
- } as AsyncThrottlerOptions<TFn>
158
-
187
+ } as SolidAsyncThrottlerOptions<TFn, TSelected>
159
188
  const asyncThrottler = new AsyncThrottler(
160
189
  fn,
161
190
  mergedOptions,
@@ -174,6 +203,17 @@ export function createAsyncThrottler<
174
203
 
175
204
  const state = useStore(asyncThrottler.store, selector)
176
205
 
206
+ createEffect(() => {
207
+ onCleanup(() => {
208
+ if (mergedOptions.onUnmount) {
209
+ mergedOptions.onUnmount(asyncThrottler)
210
+ } else {
211
+ asyncThrottler.cancel()
212
+ asyncThrottler.abort()
213
+ }
214
+ })
215
+ })
216
+
177
217
  return {
178
218
  ...asyncThrottler,
179
219
  state,
@@ -1,10 +1,22 @@
1
1
  import { Batcher } from '@tanstack/pacer/batcher'
2
2
  import { useStore } from '@tanstack/solid-store'
3
+ import { createEffect, onCleanup } from 'solid-js'
3
4
  import { useDefaultPacerOptions } from '../provider/PacerProvider'
4
5
  import type { Store } from '@tanstack/solid-store'
5
6
  import type { Accessor, JSX } from 'solid-js'
6
7
  import type { BatcherOptions, BatcherState } from '@tanstack/pacer/batcher'
7
8
 
9
+ export interface SolidBatcherOptions<
10
+ TValue,
11
+ TSelected = {},
12
+ > extends BatcherOptions<TValue> {
13
+ /**
14
+ * Optional callback invoked when the owning component unmounts. Receives the batcher instance.
15
+ * When provided, replaces the default cleanup (cancel); use it to call flush(), reset(), cancel(), add logging, etc.
16
+ */
17
+ onUnmount?: (batcher: SolidBatcher<TValue, TSelected>) => void
18
+ }
19
+
8
20
  export interface SolidBatcher<TValue, TSelected = {}> extends Omit<
9
21
  Batcher<TValue>,
10
22
  'store'
@@ -82,6 +94,19 @@ export interface SolidBatcher<TValue, TSelected = {}> extends Omit<
82
94
  * - `items`: Array of items currently queued for batching
83
95
  * - `totalItemsProcessed`: Total number of individual items that have been processed across all batches
84
96
  *
97
+ * ## Unmount behavior
98
+ *
99
+ * By default, the primitive cancels any pending batch when the owning component unmounts.
100
+ * Use the `onUnmount` option to customize this. For example, to flush pending work instead:
101
+ *
102
+ * ```tsx
103
+ * const batcher = createBatcher(fn, {
104
+ * maxSize: 10,
105
+ * wait: 2000,
106
+ * onUnmount: (b) => b.flush()
107
+ * });
108
+ * ```
109
+ *
85
110
  * Example usage:
86
111
  * ```tsx
87
112
  * // Default behavior - no reactive state subscriptions
@@ -129,15 +154,14 @@ export interface SolidBatcher<TValue, TSelected = {}> extends Omit<
129
154
  */
130
155
  export function createBatcher<TValue, TSelected = {}>(
131
156
  fn: (items: Array<TValue>) => void,
132
- options: BatcherOptions<TValue> = {},
157
+ options: SolidBatcherOptions<TValue, TSelected> = {},
133
158
  selector: (state: BatcherState<TValue>) => TSelected = () =>
134
159
  ({}) as TSelected,
135
160
  ): SolidBatcher<TValue, TSelected> {
136
161
  const mergedOptions = {
137
162
  ...useDefaultPacerOptions().batcher,
138
163
  ...options,
139
- } as BatcherOptions<TValue>
140
-
164
+ } as SolidBatcherOptions<TValue, TSelected>
141
165
  const batcher = new Batcher(fn, mergedOptions) as unknown as SolidBatcher<
142
166
  TValue,
143
167
  TSelected
@@ -155,6 +179,17 @@ export function createBatcher<TValue, TSelected = {}>(
155
179
  }
156
180
 
157
181
  const state = useStore(batcher.store, selector)
182
+
183
+ createEffect(() => {
184
+ onCleanup(() => {
185
+ if (mergedOptions.onUnmount) {
186
+ mergedOptions.onUnmount(batcher)
187
+ } else {
188
+ batcher.cancel()
189
+ }
190
+ })
191
+ })
192
+
158
193
  return {
159
194
  ...batcher,
160
195
  state,
@@ -1,11 +1,8 @@
1
1
  import { createSignal } from 'solid-js'
2
2
  import { createDebouncer } from './createDebouncer'
3
- import type { SolidDebouncer } from './createDebouncer'
3
+ import type { SolidDebouncer, SolidDebouncerOptions } from './createDebouncer'
4
4
  import type { Accessor, Setter } from 'solid-js'
5
- import type {
6
- DebouncerOptions,
7
- DebouncerState,
8
- } from '@tanstack/pacer/debouncer'
5
+ import type { DebouncerState } from '@tanstack/pacer/debouncer'
9
6
 
10
7
  /**
11
8
  * A Solid hook that creates a debounced state value, combining Solid's createSignal with debouncing functionality.
@@ -80,7 +77,7 @@ import type {
80
77
  */
81
78
  export function createDebouncedSignal<TValue, TSelected = {}>(
82
79
  value: TValue,
83
- initialOptions: DebouncerOptions<Setter<TValue>>,
80
+ initialOptions: SolidDebouncerOptions<Setter<TValue>, TSelected>,
84
81
  selector?: (state: DebouncerState<Setter<TValue>>) => TSelected,
85
82
  ): [
86
83
  Accessor<TValue>,
@@ -1,11 +1,8 @@
1
1
  import { createEffect } from 'solid-js'
2
2
  import { createDebouncedSignal } from './createDebouncedSignal'
3
- import type { SolidDebouncer } from './createDebouncer'
3
+ import type { SolidDebouncer, SolidDebouncerOptions } from './createDebouncer'
4
4
  import type { Accessor, Setter } from 'solid-js'
5
- import type {
6
- DebouncerOptions,
7
- DebouncerState,
8
- } from '@tanstack/pacer/debouncer'
5
+ import type { DebouncerState } from '@tanstack/pacer/debouncer'
9
6
 
10
7
  /**
11
8
  * A Solid hook that creates a debounced value that updates only after a specified delay.
@@ -71,7 +68,7 @@ import type {
71
68
  */
72
69
  export function createDebouncedValue<TValue, TSelected = {}>(
73
70
  value: Accessor<TValue>,
74
- initialOptions: DebouncerOptions<Setter<TValue>>,
71
+ initialOptions: SolidDebouncerOptions<Setter<TValue>, TSelected>,
75
72
  selector?: (state: DebouncerState<Setter<TValue>>) => TSelected,
76
73
  ): [Accessor<TValue>, SolidDebouncer<Setter<TValue>, TSelected>] {
77
74
  const [debouncedValue, setDebouncedValue, debouncer] = createDebouncedSignal(
@@ -10,6 +10,17 @@ import type {
10
10
  DebouncerState,
11
11
  } from '@tanstack/pacer/debouncer'
12
12
 
13
+ export interface SolidDebouncerOptions<
14
+ TFn extends AnyFunction,
15
+ TSelected = {},
16
+ > extends DebouncerOptions<TFn> {
17
+ /**
18
+ * Optional callback invoked when the owning component unmounts. Receives the debouncer instance.
19
+ * When provided, replaces the default cleanup (cancel); use it to call flush(), reset(), cancel(), add logging, etc.
20
+ */
21
+ onUnmount?: (debouncer: SolidDebouncer<TFn, TSelected>) => void
22
+ }
23
+
13
24
  export interface SolidDebouncer<
14
25
  TFn extends AnyFunction,
15
26
  TSelected = {},
@@ -88,6 +99,18 @@ export interface SolidDebouncer<
88
99
  * - `lastArgs`: The arguments from the most recent call to maybeExecute
89
100
  * - `status`: Current execution status ('disabled' | 'idle' | 'pending')
90
101
  *
102
+ * ## Unmount behavior
103
+ *
104
+ * By default, the primitive cancels any pending execution when the owning component unmounts.
105
+ * Use the `onUnmount` option to customize this. For example, to flush pending work instead:
106
+ *
107
+ * ```tsx
108
+ * const debouncer = createDebouncer(fn, {
109
+ * wait: 500,
110
+ * onUnmount: (d) => d.flush()
111
+ * });
112
+ * ```
113
+ *
91
114
  * @example
92
115
  * ```tsx
93
116
  * // Default behavior - no reactive state subscriptions
@@ -132,14 +155,13 @@ export interface SolidDebouncer<
132
155
  */
133
156
  export function createDebouncer<TFn extends AnyFunction, TSelected = {}>(
134
157
  fn: TFn,
135
- options: DebouncerOptions<TFn>,
158
+ options: SolidDebouncerOptions<TFn, TSelected>,
136
159
  selector: (state: DebouncerState<TFn>) => TSelected = () => ({}) as TSelected,
137
160
  ): SolidDebouncer<TFn, TSelected> {
138
161
  const mergedOptions = {
139
162
  ...useDefaultPacerOptions().debouncer,
140
163
  ...options,
141
- } as DebouncerOptions<TFn>
142
-
164
+ } as SolidDebouncerOptions<TFn, TSelected>
143
165
  const asyncDebouncer = new Debouncer<TFn>(
144
166
  fn,
145
167
  mergedOptions,
@@ -160,7 +182,11 @@ export function createDebouncer<TFn extends AnyFunction, TSelected = {}>(
160
182
 
161
183
  createEffect(() => {
162
184
  onCleanup(() => {
163
- asyncDebouncer.cancel()
185
+ if (mergedOptions.onUnmount) {
186
+ mergedOptions.onUnmount(asyncDebouncer)
187
+ } else {
188
+ asyncDebouncer.cancel()
189
+ }
164
190
  })
165
191
  })
166
192
 
@@ -1,6 +1,6 @@
1
1
  import { createQueuer } from './createQueuer'
2
- import type { SolidQueuer } from './createQueuer'
3
- import type { QueuerOptions, QueuerState } from '@tanstack/pacer/queuer'
2
+ import type { SolidQueuer, SolidQueuerOptions } from './createQueuer'
3
+ import type { QueuerState } from '@tanstack/pacer/queuer'
4
4
 
5
5
  /**
6
6
  * A Solid primitive that creates a queuer with managed state, combining Solid's signals with queuing functionality.
@@ -124,7 +124,7 @@ export function createQueuedSignal<
124
124
  >,
125
125
  >(
126
126
  fn: (item: TValue) => void,
127
- options: QueuerOptions<TValue> = {},
127
+ options: SolidQueuerOptions<TValue, TSelected> = {},
128
128
  selector: (state: QueuerState<TValue>) => TSelected = (state) =>
129
129
  ({ items: state.items }) as TSelected,
130
130
  ): [
@@ -1,10 +1,22 @@
1
1
  import { Queuer } from '@tanstack/pacer/queuer'
2
2
  import { useStore } from '@tanstack/solid-store'
3
+ import { createEffect, onCleanup } from 'solid-js'
3
4
  import { useDefaultPacerOptions } from '../provider/PacerProvider'
4
5
  import type { Store } from '@tanstack/solid-store'
5
6
  import type { Accessor, JSX } from 'solid-js'
6
7
  import type { QueuerOptions, QueuerState } from '@tanstack/pacer/queuer'
7
8
 
9
+ export interface SolidQueuerOptions<
10
+ TValue,
11
+ TSelected = {},
12
+ > extends QueuerOptions<TValue> {
13
+ /**
14
+ * Optional callback invoked when the owning component unmounts. Receives the queuer instance.
15
+ * When provided, replaces the default cleanup (stop); use it to call flush(), flushAsBatch(), stop(), add logging, etc.
16
+ */
17
+ onUnmount?: (queuer: SolidQueuer<TValue, TSelected>) => void
18
+ }
19
+
8
20
  export interface SolidQueuer<TValue, TSelected = {}> extends Omit<
9
21
  Queuer<TValue>,
10
22
  'store'
@@ -84,6 +96,19 @@ export interface SolidQueuer<TValue, TSelected = {}> extends Omit<
84
96
  * - `items`: Array of items currently queued for processing
85
97
  * - `rejectionCount`: Number of items that were rejected (expired or failed validation)
86
98
  *
99
+ * ## Unmount behavior
100
+ *
101
+ * By default, the primitive stops the queuer when the owning component unmounts.
102
+ * Use the `onUnmount` option to customize this. For example, to flush pending items instead:
103
+ *
104
+ * ```tsx
105
+ * const queue = createQueuer(fn, {
106
+ * started: true,
107
+ * wait: 1000,
108
+ * onUnmount: (q) => q.flush()
109
+ * });
110
+ * ```
111
+ *
87
112
  * Example usage:
88
113
  * ```tsx
89
114
  * // Default behavior - no reactive state subscriptions
@@ -130,14 +155,13 @@ export interface SolidQueuer<TValue, TSelected = {}> extends Omit<
130
155
  */
131
156
  export function createQueuer<TValue, TSelected = {}>(
132
157
  fn: (item: TValue) => void,
133
- options: QueuerOptions<TValue> = {},
158
+ options: SolidQueuerOptions<TValue, TSelected> = {},
134
159
  selector: (state: QueuerState<TValue>) => TSelected = () => ({}) as TSelected,
135
160
  ): SolidQueuer<TValue, TSelected> {
136
161
  const mergedOptions = {
137
162
  ...useDefaultPacerOptions().queuer,
138
163
  ...options,
139
- } as QueuerOptions<TValue>
140
-
164
+ } as SolidQueuerOptions<TValue, TSelected>
141
165
  const queuer = new Queuer(fn, mergedOptions) as unknown as SolidQueuer<
142
166
  TValue,
143
167
  TSelected
@@ -156,6 +180,16 @@ export function createQueuer<TValue, TSelected = {}>(
156
180
 
157
181
  const state = useStore(queuer.store, selector)
158
182
 
183
+ createEffect(() => {
184
+ onCleanup(() => {
185
+ if (mergedOptions.onUnmount) {
186
+ mergedOptions.onUnmount(queuer)
187
+ } else {
188
+ queuer.stop()
189
+ }
190
+ })
191
+ })
192
+
159
193
  return {
160
194
  ...queuer,
161
195
  state,
@@ -1,11 +1,11 @@
1
1
  import { createSignal } from 'solid-js'
2
2
  import { createRateLimiter } from './createRateLimiter'
3
- import type { SolidRateLimiter } from './createRateLimiter'
4
- import type { Accessor, Setter } from 'solid-js'
5
3
  import type {
6
- RateLimiterOptions,
7
- RateLimiterState,
8
- } from '@tanstack/pacer/rate-limiter'
4
+ SolidRateLimiter,
5
+ SolidRateLimiterOptions,
6
+ } from './createRateLimiter'
7
+ import type { Accessor, Setter } from 'solid-js'
8
+ import type { RateLimiterState } from '@tanstack/pacer/rate-limiter'
9
9
 
10
10
  /**
11
11
  * A Solid hook that creates a rate-limited state value that enforces a hard limit on state updates within a time window.
@@ -94,7 +94,7 @@ import type {
94
94
  */
95
95
  export function createRateLimitedSignal<TValue, TSelected = {}>(
96
96
  value: TValue,
97
- initialOptions: RateLimiterOptions<Setter<TValue>>,
97
+ initialOptions: SolidRateLimiterOptions<Setter<TValue>, TSelected>,
98
98
  selector?: (state: RateLimiterState) => TSelected,
99
99
  ): [
100
100
  Accessor<TValue>,
@@ -1,11 +1,11 @@
1
1
  import { createEffect } from 'solid-js'
2
2
  import { createRateLimitedSignal } from './createRateLimitedSignal'
3
- import type { SolidRateLimiter } from './createRateLimiter'
4
- import type { Accessor, Setter } from 'solid-js'
5
3
  import type {
6
- RateLimiterOptions,
7
- RateLimiterState,
8
- } from '@tanstack/pacer/rate-limiter'
4
+ SolidRateLimiter,
5
+ SolidRateLimiterOptions,
6
+ } from './createRateLimiter'
7
+ import type { Accessor, Setter } from 'solid-js'
8
+ import type { RateLimiterState } from '@tanstack/pacer/rate-limiter'
9
9
 
10
10
  /**
11
11
  * A high-level Solid hook that creates a rate-limited version of a value that updates at most a certain number of times within a time window.
@@ -96,7 +96,7 @@ import type {
96
96
  */
97
97
  export function createRateLimitedValue<TValue, TSelected = {}>(
98
98
  value: Accessor<TValue>,
99
- initialOptions: RateLimiterOptions<Setter<TValue>>,
99
+ initialOptions: SolidRateLimiterOptions<Setter<TValue>, TSelected>,
100
100
  selector?: (state: RateLimiterState) => TSelected,
101
101
  ): [Accessor<TValue>, SolidRateLimiter<Setter<TValue>, TSelected>] {
102
102
  const [rateLimitedValue, setRateLimitedValue, rateLimiter] =
@@ -1,4 +1,5 @@
1
1
  import { RateLimiter } from '@tanstack/pacer/rate-limiter'
2
+ import { createEffect, onCleanup } from 'solid-js'
2
3
  import { useStore } from '@tanstack/solid-store'
3
4
  import { useDefaultPacerOptions } from '../provider/PacerProvider'
4
5
  import type { Store } from '@tanstack/solid-store'
@@ -9,6 +10,17 @@ import type {
9
10
  RateLimiterState,
10
11
  } from '@tanstack/pacer/rate-limiter'
11
12
 
13
+ export interface SolidRateLimiterOptions<
14
+ TFn extends AnyFunction,
15
+ TSelected = {},
16
+ > extends RateLimiterOptions<TFn> {
17
+ /**
18
+ * Optional callback invoked when the owning component unmounts. Receives the rate limiter instance.
19
+ * When provided, replaces the default cleanup; use it to call reset(), add logging, etc.
20
+ */
21
+ onUnmount?: (rateLimiter: SolidRateLimiter<TFn, TSelected>) => void
22
+ }
23
+
12
24
  export interface SolidRateLimiter<
13
25
  TFn extends AnyFunction,
14
26
  TSelected = {},
@@ -172,14 +184,13 @@ export interface SolidRateLimiter<
172
184
  */
173
185
  export function createRateLimiter<TFn extends AnyFunction, TSelected = {}>(
174
186
  fn: TFn,
175
- options: RateLimiterOptions<TFn>,
187
+ options: SolidRateLimiterOptions<TFn, TSelected>,
176
188
  selector: (state: RateLimiterState) => TSelected = () => ({}) as TSelected,
177
189
  ): SolidRateLimiter<TFn, TSelected> {
178
190
  const mergedOptions = {
179
191
  ...useDefaultPacerOptions().rateLimiter,
180
192
  ...options,
181
- } as RateLimiterOptions<TFn>
182
-
193
+ } as SolidRateLimiterOptions<TFn, TSelected>
183
194
  const rateLimiter = new RateLimiter<TFn>(
184
195
  fn,
185
196
  mergedOptions,
@@ -198,6 +209,14 @@ export function createRateLimiter<TFn extends AnyFunction, TSelected = {}>(
198
209
 
199
210
  const state = useStore(rateLimiter.store, selector)
200
211
 
212
+ createEffect(() => {
213
+ onCleanup(() => {
214
+ if (mergedOptions.onUnmount) {
215
+ mergedOptions.onUnmount(rateLimiter)
216
+ }
217
+ })
218
+ })
219
+
201
220
  return {
202
221
  ...rateLimiter,
203
222
  state,
@@ -1,11 +1,8 @@
1
1
  import { createSignal } from 'solid-js'
2
2
  import { createThrottler } from './createThrottler'
3
- import type { SolidThrottler } from './createThrottler'
3
+ import type { SolidThrottler, SolidThrottlerOptions } from './createThrottler'
4
4
  import type { Accessor, Setter } from 'solid-js'
5
- import type {
6
- ThrottlerOptions,
7
- ThrottlerState,
8
- } from '@tanstack/pacer/throttler'
5
+ import type { ThrottlerState } from '@tanstack/pacer/throttler'
9
6
 
10
7
  /**
11
8
  * A Solid hook that creates a throttled state value that updates at most once within a specified time window.
@@ -71,7 +68,7 @@ import type {
71
68
  */
72
69
  export function createThrottledSignal<TValue, TSelected = {}>(
73
70
  value: TValue,
74
- initialOptions: ThrottlerOptions<Setter<TValue>>,
71
+ initialOptions: SolidThrottlerOptions<Setter<TValue>, TSelected>,
75
72
  selector?: (state: ThrottlerState<Setter<TValue>>) => TSelected,
76
73
  ): [
77
74
  Accessor<TValue>,
@@ -1,11 +1,8 @@
1
1
  import { createEffect } from 'solid-js'
2
2
  import { createThrottledSignal } from './createThrottledSignal'
3
- import type { SolidThrottler } from './createThrottler'
3
+ import type { SolidThrottler, SolidThrottlerOptions } from './createThrottler'
4
4
  import type { Accessor, Setter } from 'solid-js'
5
- import type {
6
- ThrottlerOptions,
7
- ThrottlerState,
8
- } from '@tanstack/pacer/throttler'
5
+ import type { ThrottlerState } from '@tanstack/pacer/throttler'
9
6
 
10
7
  /**
11
8
  * A high-level Solid hook that creates a throttled version of a value that updates at most once within a specified time window.
@@ -68,7 +65,7 @@ import type {
68
65
  */
69
66
  export function createThrottledValue<TValue, TSelected = {}>(
70
67
  value: Accessor<TValue>,
71
- initialOptions: ThrottlerOptions<Setter<TValue>>,
68
+ initialOptions: SolidThrottlerOptions<Setter<TValue>, TSelected>,
72
69
  selector?: (state: ThrottlerState<Setter<TValue>>) => TSelected,
73
70
  ): [Accessor<TValue>, SolidThrottler<Setter<TValue>, TSelected>] {
74
71
  const [throttledValue, setThrottledValue, throttler] = createThrottledSignal(
@@ -10,6 +10,17 @@ import type {
10
10
  ThrottlerState,
11
11
  } from '@tanstack/pacer/throttler'
12
12
 
13
+ export interface SolidThrottlerOptions<
14
+ TFn extends AnyFunction,
15
+ TSelected = {},
16
+ > extends ThrottlerOptions<TFn> {
17
+ /**
18
+ * Optional callback invoked when the owning component unmounts. Receives the throttler instance.
19
+ * When provided, replaces the default cleanup (cancel); use it to call flush(), reset(), cancel(), add logging, etc.
20
+ */
21
+ onUnmount?: (throttler: SolidThrottler<TFn, TSelected>) => void
22
+ }
23
+
13
24
  export interface SolidThrottler<
14
25
  TFn extends AnyFunction,
15
26
  TSelected = {},
@@ -87,6 +98,18 @@ export interface SolidThrottler<
87
98
  * - `nextExecutionTime`: Timestamp of the next allowed execution
88
99
  * - `status`: Current execution status ('disabled' | 'idle' | 'pending')
89
100
  *
101
+ * ## Unmount behavior
102
+ *
103
+ * By default, the primitive cancels any pending execution when the owning component unmounts.
104
+ * Use the `onUnmount` option to customize this. For example, to flush pending work instead:
105
+ *
106
+ * ```tsx
107
+ * const throttler = createThrottler(fn, {
108
+ * wait: 1000,
109
+ * onUnmount: (t) => t.flush()
110
+ * });
111
+ * ```
112
+ *
90
113
  * @example
91
114
  * ```tsx
92
115
  * // Default behavior - no reactive state subscriptions
@@ -135,14 +158,13 @@ export interface SolidThrottler<
135
158
  */
136
159
  export function createThrottler<TFn extends AnyFunction, TSelected = {}>(
137
160
  fn: TFn,
138
- options: ThrottlerOptions<TFn>,
161
+ options: SolidThrottlerOptions<TFn, TSelected>,
139
162
  selector: (state: ThrottlerState<TFn>) => TSelected = () => ({}) as TSelected,
140
163
  ): SolidThrottler<TFn, TSelected> {
141
164
  const mergedOptions = {
142
165
  ...useDefaultPacerOptions().throttler,
143
166
  ...options,
144
- } as ThrottlerOptions<TFn>
145
-
167
+ } as SolidThrottlerOptions<TFn, TSelected>
146
168
  const asyncThrottler = new Throttler<TFn>(
147
169
  fn,
148
170
  mergedOptions,
@@ -163,7 +185,11 @@ export function createThrottler<TFn extends AnyFunction, TSelected = {}>(
163
185
 
164
186
  createEffect(() => {
165
187
  onCleanup(() => {
166
- asyncThrottler.cancel()
188
+ if (mergedOptions.onUnmount) {
189
+ mergedOptions.onUnmount(asyncThrottler)
190
+ } else {
191
+ asyncThrottler.cancel()
192
+ }
167
193
  })
168
194
  })
169
195