@tanstack/angular-pacer 0.20.0 → 0.22.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.
- package/LICENSE +21 -0
- package/README.md +7 -7
- package/dist/async-batcher/index.d.cts +2 -2
- package/dist/async-batcher/index.d.ts +2 -2
- package/dist/async-batcher/injectAsyncBatcher.cjs +27 -3
- package/dist/async-batcher/injectAsyncBatcher.cjs.map +1 -1
- package/dist/async-batcher/injectAsyncBatcher.d.cts +25 -3
- package/dist/async-batcher/injectAsyncBatcher.d.ts +25 -3
- package/dist/async-batcher/injectAsyncBatcher.js +27 -3
- package/dist/async-batcher/injectAsyncBatcher.js.map +1 -1
- package/dist/async-debouncer/index.d.cts +2 -2
- package/dist/async-debouncer/index.d.ts +2 -2
- package/dist/async-debouncer/injectAsyncDebouncer.cjs +27 -3
- package/dist/async-debouncer/injectAsyncDebouncer.cjs.map +1 -1
- package/dist/async-debouncer/injectAsyncDebouncer.d.cts +25 -3
- package/dist/async-debouncer/injectAsyncDebouncer.d.ts +25 -3
- package/dist/async-debouncer/injectAsyncDebouncer.js +27 -3
- package/dist/async-debouncer/injectAsyncDebouncer.js.map +1 -1
- package/dist/async-queuer/index.d.cts +2 -2
- package/dist/async-queuer/index.d.ts +2 -2
- package/dist/async-queuer/injectAsyncQueuedSignal.cjs.map +1 -1
- package/dist/async-queuer/injectAsyncQueuedSignal.d.cts +5 -10
- package/dist/async-queuer/injectAsyncQueuedSignal.d.ts +5 -10
- package/dist/async-queuer/injectAsyncQueuedSignal.js.map +1 -1
- package/dist/async-queuer/injectAsyncQueuer.cjs +27 -3
- package/dist/async-queuer/injectAsyncQueuer.cjs.map +1 -1
- package/dist/async-queuer/injectAsyncQueuer.d.cts +25 -3
- package/dist/async-queuer/injectAsyncQueuer.d.ts +25 -3
- package/dist/async-queuer/injectAsyncQueuer.js +27 -3
- package/dist/async-queuer/injectAsyncQueuer.js.map +1 -1
- package/dist/async-rate-limiter/index.d.cts +2 -2
- package/dist/async-rate-limiter/index.d.ts +2 -2
- package/dist/async-rate-limiter/injectAsyncRateLimiter.cjs +15 -3
- package/dist/async-rate-limiter/injectAsyncRateLimiter.cjs.map +1 -1
- package/dist/async-rate-limiter/injectAsyncRateLimiter.d.cts +15 -3
- package/dist/async-rate-limiter/injectAsyncRateLimiter.d.ts +15 -3
- package/dist/async-rate-limiter/injectAsyncRateLimiter.js +15 -3
- package/dist/async-rate-limiter/injectAsyncRateLimiter.js.map +1 -1
- package/dist/async-throttler/index.d.cts +2 -2
- package/dist/async-throttler/index.d.ts +2 -2
- package/dist/async-throttler/injectAsyncThrottler.cjs +27 -3
- package/dist/async-throttler/injectAsyncThrottler.cjs.map +1 -1
- package/dist/async-throttler/injectAsyncThrottler.d.cts +25 -3
- package/dist/async-throttler/injectAsyncThrottler.d.ts +25 -3
- package/dist/async-throttler/injectAsyncThrottler.js +27 -3
- package/dist/async-throttler/injectAsyncThrottler.js.map +1 -1
- package/dist/batcher/index.d.cts +2 -2
- package/dist/batcher/index.d.ts +2 -2
- package/dist/batcher/injectBatcher.cjs +22 -3
- package/dist/batcher/injectBatcher.cjs.map +1 -1
- package/dist/batcher/injectBatcher.d.cts +22 -3
- package/dist/batcher/injectBatcher.d.ts +22 -3
- package/dist/batcher/injectBatcher.js +22 -3
- package/dist/batcher/injectBatcher.js.map +1 -1
- package/dist/debouncer/index.d.cts +2 -2
- package/dist/debouncer/index.d.ts +2 -2
- package/dist/debouncer/injectDebouncedSignal.cjs.map +1 -1
- package/dist/debouncer/injectDebouncedSignal.d.cts +5 -10
- package/dist/debouncer/injectDebouncedSignal.d.ts +5 -10
- package/dist/debouncer/injectDebouncedSignal.js.map +1 -1
- package/dist/debouncer/injectDebouncer.cjs +22 -3
- package/dist/debouncer/injectDebouncer.cjs.map +1 -1
- package/dist/debouncer/injectDebouncer.d.cts +22 -3
- package/dist/debouncer/injectDebouncer.d.ts +22 -3
- package/dist/debouncer/injectDebouncer.js +22 -3
- package/dist/debouncer/injectDebouncer.js.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/queuer/index.d.cts +2 -2
- package/dist/queuer/index.d.ts +2 -2
- package/dist/queuer/injectQueuedSignal.cjs.map +1 -1
- package/dist/queuer/injectQueuedSignal.d.cts +5 -10
- package/dist/queuer/injectQueuedSignal.d.ts +5 -10
- package/dist/queuer/injectQueuedSignal.js.map +1 -1
- package/dist/queuer/injectQueuer.cjs +22 -3
- package/dist/queuer/injectQueuer.cjs.map +1 -1
- package/dist/queuer/injectQueuer.d.cts +22 -3
- package/dist/queuer/injectQueuer.d.ts +22 -3
- package/dist/queuer/injectQueuer.js +22 -3
- package/dist/queuer/injectQueuer.js.map +1 -1
- package/dist/rate-limiter/index.d.cts +2 -2
- package/dist/rate-limiter/index.d.ts +2 -2
- package/dist/rate-limiter/injectRateLimitedSignal.cjs.map +1 -1
- package/dist/rate-limiter/injectRateLimitedSignal.d.cts +5 -10
- package/dist/rate-limiter/injectRateLimitedSignal.d.ts +5 -10
- package/dist/rate-limiter/injectRateLimitedSignal.js.map +1 -1
- package/dist/rate-limiter/injectRateLimiter.cjs +13 -3
- package/dist/rate-limiter/injectRateLimiter.cjs.map +1 -1
- package/dist/rate-limiter/injectRateLimiter.d.cts +13 -3
- package/dist/rate-limiter/injectRateLimiter.d.ts +13 -3
- package/dist/rate-limiter/injectRateLimiter.js +13 -3
- package/dist/rate-limiter/injectRateLimiter.js.map +1 -1
- package/dist/throttler/index.d.cts +2 -2
- package/dist/throttler/index.d.ts +2 -2
- package/dist/throttler/injectThrottledSignal.cjs.map +1 -1
- package/dist/throttler/injectThrottledSignal.d.cts +5 -10
- package/dist/throttler/injectThrottledSignal.d.ts +5 -10
- package/dist/throttler/injectThrottledSignal.js.map +1 -1
- package/dist/throttler/injectThrottler.cjs +22 -3
- package/dist/throttler/injectThrottler.cjs.map +1 -1
- package/dist/throttler/injectThrottler.d.cts +22 -3
- package/dist/throttler/injectThrottler.d.ts +22 -3
- package/dist/throttler/injectThrottler.js +22 -3
- package/dist/throttler/injectThrottler.js.map +1 -1
- package/package.json +15 -15
- package/src/async-batcher/injectAsyncBatcher.ts +43 -4
- package/src/async-debouncer/injectAsyncDebouncer.ts +43 -4
- package/src/async-queuer/injectAsyncQueuedSignal.ts +4 -12
- package/src/async-queuer/injectAsyncQueuer.ts +43 -4
- package/src/async-rate-limiter/injectAsyncRateLimiter.ts +32 -4
- package/src/async-throttler/injectAsyncThrottler.ts +43 -4
- package/src/batcher/injectBatcher.ts +39 -4
- package/src/debouncer/injectDebouncedSignal.ts +4 -11
- package/src/debouncer/injectDebouncer.ts +39 -4
- package/src/queuer/injectQueuedSignal.ts +4 -9
- package/src/queuer/injectQueuer.ts +39 -4
- package/src/rate-limiter/injectRateLimitedSignal.ts +4 -11
- package/src/rate-limiter/injectRateLimiter.ts +28 -4
- package/src/throttler/injectThrottledSignal.ts +4 -11
- package/src/throttler/injectThrottler.ts +39 -4
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
import { DestroyRef, inject } from '@angular/core'
|
|
1
2
|
import { injectStore } from '@tanstack/angular-store'
|
|
2
3
|
import { Batcher } from '@tanstack/pacer/batcher'
|
|
3
4
|
import { injectPacerOptions } from '../provider/pacer-context'
|
|
4
5
|
import type { Signal } from '@angular/core'
|
|
5
|
-
import type { Store } from '@tanstack/store'
|
|
6
|
+
import type { Store } from '@tanstack/angular-store'
|
|
6
7
|
import type { BatcherOptions, BatcherState } from '@tanstack/pacer/batcher'
|
|
7
8
|
|
|
9
|
+
export interface AngularBatcherOptions<
|
|
10
|
+
TValue,
|
|
11
|
+
TSelected = {},
|
|
12
|
+
> extends BatcherOptions<TValue> {
|
|
13
|
+
/**
|
|
14
|
+
* Optional callback invoked when the component is destroyed. Receives the batcher instance.
|
|
15
|
+
* When provided, replaces the default cleanup (cancel); use it to call flush(), cancel(), add logging, etc.
|
|
16
|
+
*/
|
|
17
|
+
onUnmount?: (batcher: AngularBatcher<TValue, TSelected>) => void
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
export interface AngularBatcher<TValue, TSelected = {}> extends Omit<
|
|
9
21
|
Batcher<TValue>,
|
|
10
22
|
'store'
|
|
@@ -43,6 +55,18 @@ export interface AngularBatcher<TValue, TSelected = {}> extends Omit<
|
|
|
43
55
|
* tracking by providing a selector function. This prevents unnecessary updates and gives you
|
|
44
56
|
* full control over when your component tracks state changes.
|
|
45
57
|
*
|
|
58
|
+
* ## Cleanup on Destroy
|
|
59
|
+
*
|
|
60
|
+
* By default, the function cancels any pending batch when the component is destroyed.
|
|
61
|
+
* Use the `onUnmount` option to customize this. For example, to flush pending work instead:
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* const batcher = injectBatcher(fn, {
|
|
65
|
+
* maxSize: 5,
|
|
66
|
+
* onUnmount: (b) => b.flush()
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
46
70
|
* @example
|
|
47
71
|
* ```ts
|
|
48
72
|
* // Default behavior - no reactive state subscriptions
|
|
@@ -60,20 +84,31 @@ export interface AngularBatcher<TValue, TSelected = {}> extends Omit<
|
|
|
60
84
|
*/
|
|
61
85
|
export function injectBatcher<TValue, TSelected = {}>(
|
|
62
86
|
fn: (items: Array<TValue>) => void,
|
|
63
|
-
options:
|
|
87
|
+
options: AngularBatcherOptions<TValue, TSelected> = {},
|
|
64
88
|
selector: (state: BatcherState<TValue>) => TSelected = () =>
|
|
65
89
|
({}) as TSelected,
|
|
66
90
|
): AngularBatcher<TValue, TSelected> {
|
|
67
91
|
const mergedOptions = {
|
|
68
92
|
...injectPacerOptions().batcher,
|
|
69
93
|
...options,
|
|
70
|
-
} as
|
|
94
|
+
} as AngularBatcherOptions<TValue, TSelected>
|
|
71
95
|
|
|
72
96
|
const batcher = new Batcher<TValue>(fn, mergedOptions)
|
|
73
97
|
const state = injectStore(batcher.store, selector)
|
|
74
98
|
|
|
75
|
-
|
|
99
|
+
const result = {
|
|
76
100
|
...batcher,
|
|
77
101
|
state,
|
|
78
102
|
} as AngularBatcher<TValue, TSelected>
|
|
103
|
+
|
|
104
|
+
const destroyRef = inject(DestroyRef, { optional: true })
|
|
105
|
+
destroyRef?.onDestroy(() => {
|
|
106
|
+
if (mergedOptions.onUnmount) {
|
|
107
|
+
mergedOptions.onUnmount(result)
|
|
108
|
+
} else {
|
|
109
|
+
batcher.cancel()
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
return result
|
|
79
114
|
}
|
|
@@ -8,17 +8,10 @@ import type {
|
|
|
8
8
|
|
|
9
9
|
type Setter<T> = (value: T | ((prev: T) => T)) => void
|
|
10
10
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* Set or update the debounced value. This calls `debouncer.maybeExecute(...)`.
|
|
16
|
-
*/
|
|
17
|
-
readonly set: Setter<TValue>
|
|
18
|
-
/**
|
|
19
|
-
* The debouncer instance with additional control methods and state signals.
|
|
20
|
-
*/
|
|
21
|
-
readonly debouncer: AngularDebouncer<Setter<TValue>, TSelected>
|
|
11
|
+
export interface DebouncedSignal<TValue, TSelected = {}> {
|
|
12
|
+
(): TValue
|
|
13
|
+
set: Setter<TValue>
|
|
14
|
+
debouncer: AngularDebouncer<Setter<TValue>, TSelected>
|
|
22
15
|
}
|
|
23
16
|
|
|
24
17
|
/**
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
+
import { DestroyRef, inject } from '@angular/core'
|
|
1
2
|
import { injectStore } from '@tanstack/angular-store'
|
|
2
3
|
import { Debouncer } from '@tanstack/pacer/debouncer'
|
|
3
4
|
import { injectPacerOptions } from '../provider/pacer-context'
|
|
4
5
|
import type { Signal } from '@angular/core'
|
|
5
|
-
import type { Store } from '@tanstack/store'
|
|
6
|
+
import type { Store } from '@tanstack/angular-store'
|
|
6
7
|
import type { AnyFunction } from '@tanstack/pacer/types'
|
|
7
8
|
import type {
|
|
8
9
|
DebouncerOptions,
|
|
9
10
|
DebouncerState,
|
|
10
11
|
} from '@tanstack/pacer/debouncer'
|
|
11
12
|
|
|
13
|
+
export interface AngularDebouncerOptions<
|
|
14
|
+
TFn extends AnyFunction,
|
|
15
|
+
TSelected = {},
|
|
16
|
+
> extends DebouncerOptions<TFn> {
|
|
17
|
+
/**
|
|
18
|
+
* Optional callback invoked when the component is destroyed. Receives the debouncer instance.
|
|
19
|
+
* When provided, replaces the default cleanup (cancel); use it to call flush(), cancel(), add logging, etc.
|
|
20
|
+
*/
|
|
21
|
+
onUnmount?: (debouncer: AngularDebouncer<TFn, TSelected>) => void
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
export interface AngularDebouncer<
|
|
13
25
|
TFn extends AnyFunction,
|
|
14
26
|
TSelected = {},
|
|
@@ -57,6 +69,18 @@ export interface AngularDebouncer<
|
|
|
57
69
|
* - `lastArgs`: The arguments from the most recent call to maybeExecute
|
|
58
70
|
* - `status`: Current execution status ('disabled' | 'idle' | 'pending')
|
|
59
71
|
*
|
|
72
|
+
* ## Cleanup on Destroy
|
|
73
|
+
*
|
|
74
|
+
* By default, the function cancels any pending execution when the component is destroyed.
|
|
75
|
+
* Use the `onUnmount` option to customize this. For example, to flush pending work instead:
|
|
76
|
+
*
|
|
77
|
+
* ```ts
|
|
78
|
+
* const debouncer = injectDebouncer(fn, {
|
|
79
|
+
* wait: 500,
|
|
80
|
+
* onUnmount: (d) => d.flush()
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
60
84
|
* @example
|
|
61
85
|
* ```ts
|
|
62
86
|
* // Default behavior - no reactive state subscriptions
|
|
@@ -84,19 +108,30 @@ export interface AngularDebouncer<
|
|
|
84
108
|
*/
|
|
85
109
|
export function injectDebouncer<TFn extends AnyFunction, TSelected = {}>(
|
|
86
110
|
fn: TFn,
|
|
87
|
-
options:
|
|
111
|
+
options: AngularDebouncerOptions<TFn, TSelected>,
|
|
88
112
|
selector: (state: DebouncerState<TFn>) => TSelected = () => ({}) as TSelected,
|
|
89
113
|
): AngularDebouncer<TFn, TSelected> {
|
|
90
114
|
const mergedOptions = {
|
|
91
115
|
...injectPacerOptions().debouncer,
|
|
92
116
|
...options,
|
|
93
|
-
} as
|
|
117
|
+
} as AngularDebouncerOptions<TFn, TSelected>
|
|
94
118
|
|
|
95
119
|
const debouncer = new Debouncer<TFn>(fn, mergedOptions)
|
|
96
120
|
const state = injectStore(debouncer.store, selector)
|
|
97
121
|
|
|
98
|
-
|
|
122
|
+
const result = {
|
|
99
123
|
...debouncer,
|
|
100
124
|
state,
|
|
101
125
|
} as AngularDebouncer<TFn, TSelected>
|
|
126
|
+
|
|
127
|
+
const destroyRef = inject(DestroyRef, { optional: true })
|
|
128
|
+
destroyRef?.onDestroy(() => {
|
|
129
|
+
if (mergedOptions.onUnmount) {
|
|
130
|
+
mergedOptions.onUnmount(result)
|
|
131
|
+
} else {
|
|
132
|
+
debouncer.cancel()
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
return result
|
|
102
137
|
}
|
|
@@ -3,15 +3,10 @@ import { injectQueuer } from './injectQueuer'
|
|
|
3
3
|
import type { AngularQueuer } from './injectQueuer'
|
|
4
4
|
import type { QueuerOptions, QueuerState } from '@tanstack/pacer/queuer'
|
|
5
5
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
readonly addItem: AngularQueuer<TValue, TSelected>['addItem']
|
|
11
|
-
/**
|
|
12
|
-
* The queuer instance with additional control methods and state signals.
|
|
13
|
-
*/
|
|
14
|
-
readonly queuer: AngularQueuer<TValue, TSelected>
|
|
6
|
+
export interface QueuedSignal<TValue, TSelected = {}> {
|
|
7
|
+
(): Array<TValue>
|
|
8
|
+
addItem: AngularQueuer<TValue, TSelected>['addItem']
|
|
9
|
+
queuer: AngularQueuer<TValue, TSelected>
|
|
15
10
|
}
|
|
16
11
|
|
|
17
12
|
/**
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
import { DestroyRef, inject } from '@angular/core'
|
|
1
2
|
import { injectStore } from '@tanstack/angular-store'
|
|
2
3
|
import { Queuer } from '@tanstack/pacer/queuer'
|
|
3
4
|
import { injectPacerOptions } from '../provider/pacer-context'
|
|
4
5
|
import type { Signal } from '@angular/core'
|
|
5
|
-
import type { Store } from '@tanstack/store'
|
|
6
|
+
import type { Store } from '@tanstack/angular-store'
|
|
6
7
|
import type { QueuerOptions, QueuerState } from '@tanstack/pacer/queuer'
|
|
7
8
|
|
|
9
|
+
export interface AngularQueuerOptions<
|
|
10
|
+
TValue,
|
|
11
|
+
TSelected = {},
|
|
12
|
+
> extends QueuerOptions<TValue> {
|
|
13
|
+
/**
|
|
14
|
+
* Optional callback invoked when the component is destroyed. Receives the queuer instance.
|
|
15
|
+
* When provided, replaces the default cleanup (stop); use it to call flush(), stop(), add logging, etc.
|
|
16
|
+
*/
|
|
17
|
+
onUnmount?: (queuer: AngularQueuer<TValue, TSelected>) => void
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
export interface AngularQueuer<TValue, TSelected = {}> extends Omit<
|
|
9
21
|
Queuer<TValue>,
|
|
10
22
|
'store'
|
|
@@ -62,22 +74,45 @@ export interface AngularQueuer<TValue, TSelected = {}> extends Omit<
|
|
|
62
74
|
* // Access the selected state
|
|
63
75
|
* const { items, isRunning } = queue.state();
|
|
64
76
|
* ```
|
|
77
|
+
*
|
|
78
|
+
* ## Cleanup on Destroy
|
|
79
|
+
*
|
|
80
|
+
* By default, the function stops the queuer when the component is destroyed.
|
|
81
|
+
* Use the `onUnmount` option to customize this. For example, to flush pending items instead:
|
|
82
|
+
*
|
|
83
|
+
* ```ts
|
|
84
|
+
* const queue = injectQueuer(fn, {
|
|
85
|
+
* started: true,
|
|
86
|
+
* onUnmount: (q) => q.flush()
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
65
89
|
*/
|
|
66
90
|
export function injectQueuer<TValue, TSelected = {}>(
|
|
67
91
|
fn: (item: TValue) => void,
|
|
68
|
-
options:
|
|
92
|
+
options: AngularQueuerOptions<TValue, TSelected> = {},
|
|
69
93
|
selector: (state: QueuerState<TValue>) => TSelected = () => ({}) as TSelected,
|
|
70
94
|
): AngularQueuer<TValue, TSelected> {
|
|
71
95
|
const mergedOptions = {
|
|
72
96
|
...injectPacerOptions().queuer,
|
|
73
97
|
...options,
|
|
74
|
-
} as
|
|
98
|
+
} as AngularQueuerOptions<TValue, TSelected>
|
|
75
99
|
|
|
76
100
|
const queuer = new Queuer<TValue>(fn, mergedOptions)
|
|
77
101
|
const state = injectStore(queuer.store, selector)
|
|
78
102
|
|
|
79
|
-
|
|
103
|
+
const result = {
|
|
80
104
|
...queuer,
|
|
81
105
|
state,
|
|
82
106
|
} as AngularQueuer<TValue, TSelected>
|
|
107
|
+
|
|
108
|
+
const destroyRef = inject(DestroyRef, { optional: true })
|
|
109
|
+
destroyRef?.onDestroy(() => {
|
|
110
|
+
if (mergedOptions.onUnmount) {
|
|
111
|
+
mergedOptions.onUnmount(result)
|
|
112
|
+
} else {
|
|
113
|
+
queuer.stop()
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return result
|
|
83
118
|
}
|
|
@@ -8,17 +8,10 @@ import type {
|
|
|
8
8
|
|
|
9
9
|
type Setter<T> = (value: T | ((prev: T) => T)) => void
|
|
10
10
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* Set or update the rate-limited value. This calls `rateLimiter.maybeExecute(...)`.
|
|
16
|
-
*/
|
|
17
|
-
readonly set: Setter<TValue>
|
|
18
|
-
/**
|
|
19
|
-
* The rate limiter instance with additional control methods and state signals.
|
|
20
|
-
*/
|
|
21
|
-
readonly rateLimiter: AngularRateLimiter<Setter<TValue>, TSelected>
|
|
11
|
+
export interface RateLimitedSignal<TValue, TSelected = {}> {
|
|
12
|
+
(): TValue
|
|
13
|
+
set: Setter<TValue>
|
|
14
|
+
rateLimiter: AngularRateLimiter<Setter<TValue>, TSelected>
|
|
22
15
|
}
|
|
23
16
|
|
|
24
17
|
/**
|
|
@@ -1,14 +1,25 @@
|
|
|
1
|
+
import { DestroyRef, inject } from '@angular/core'
|
|
1
2
|
import { injectStore } from '@tanstack/angular-store'
|
|
2
3
|
import { RateLimiter } from '@tanstack/pacer/rate-limiter'
|
|
3
4
|
import { injectPacerOptions } from '../provider/pacer-context'
|
|
4
5
|
import type { Signal } from '@angular/core'
|
|
5
|
-
import type { Store } from '@tanstack/store'
|
|
6
|
+
import type { Store } from '@tanstack/angular-store'
|
|
6
7
|
import type { AnyFunction } from '@tanstack/pacer/types'
|
|
7
8
|
import type {
|
|
8
9
|
RateLimiterOptions,
|
|
9
10
|
RateLimiterState,
|
|
10
11
|
} from '@tanstack/pacer/rate-limiter'
|
|
11
12
|
|
|
13
|
+
export interface AngularRateLimiterOptions<
|
|
14
|
+
TFn extends AnyFunction,
|
|
15
|
+
TSelected = {},
|
|
16
|
+
> extends RateLimiterOptions<TFn> {
|
|
17
|
+
/**
|
|
18
|
+
* Optional callback invoked when the component is destroyed. Receives the rate limiter instance.
|
|
19
|
+
*/
|
|
20
|
+
onUnmount?: (rateLimiter: AngularRateLimiter<TFn, TSelected>) => void
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
export interface AngularRateLimiter<
|
|
13
24
|
TFn extends AnyFunction,
|
|
14
25
|
TSelected = {},
|
|
@@ -62,6 +73,10 @@ export interface AngularRateLimiter<
|
|
|
62
73
|
* - `executionTimes`: Array of timestamps when executions occurred for rate limiting calculations
|
|
63
74
|
* - `rejectionCount`: Number of function executions that have been rejected due to rate limiting
|
|
64
75
|
*
|
|
76
|
+
* ## Cleanup on Destroy
|
|
77
|
+
*
|
|
78
|
+
* Use the `onUnmount` option to run a callback when the component is destroyed.
|
|
79
|
+
*
|
|
65
80
|
* @example
|
|
66
81
|
* ```ts
|
|
67
82
|
* // Default behavior - no reactive state subscriptions
|
|
@@ -98,19 +113,28 @@ export interface AngularRateLimiter<
|
|
|
98
113
|
*/
|
|
99
114
|
export function injectRateLimiter<TFn extends AnyFunction, TSelected = {}>(
|
|
100
115
|
fn: TFn,
|
|
101
|
-
options:
|
|
116
|
+
options: AngularRateLimiterOptions<TFn, TSelected>,
|
|
102
117
|
selector: (state: RateLimiterState) => TSelected = () => ({}) as TSelected,
|
|
103
118
|
): AngularRateLimiter<TFn, TSelected> {
|
|
104
119
|
const mergedOptions = {
|
|
105
120
|
...injectPacerOptions().rateLimiter,
|
|
106
121
|
...options,
|
|
107
|
-
} as
|
|
122
|
+
} as AngularRateLimiterOptions<TFn, TSelected>
|
|
108
123
|
|
|
109
124
|
const rateLimiter = new RateLimiter<TFn>(fn, mergedOptions)
|
|
110
125
|
const state = injectStore(rateLimiter.store, selector)
|
|
111
126
|
|
|
112
|
-
|
|
127
|
+
const result = {
|
|
113
128
|
...rateLimiter,
|
|
114
129
|
state,
|
|
115
130
|
} as AngularRateLimiter<TFn, TSelected>
|
|
131
|
+
|
|
132
|
+
const destroyRef = inject(DestroyRef, { optional: true })
|
|
133
|
+
destroyRef?.onDestroy(() => {
|
|
134
|
+
if (mergedOptions.onUnmount) {
|
|
135
|
+
mergedOptions.onUnmount(result)
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
return result
|
|
116
140
|
}
|
|
@@ -8,17 +8,10 @@ import type {
|
|
|
8
8
|
|
|
9
9
|
type Setter<T> = (value: T | ((prev: T) => T)) => void
|
|
10
10
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* Set or update the throttled value. This calls `throttler.maybeExecute(...)`.
|
|
16
|
-
*/
|
|
17
|
-
readonly set: Setter<TValue>
|
|
18
|
-
/**
|
|
19
|
-
* The throttler instance with additional control methods and state signals.
|
|
20
|
-
*/
|
|
21
|
-
readonly throttler: AngularThrottler<Setter<TValue>, TSelected>
|
|
11
|
+
export interface ThrottledSignal<TValue, TSelected = {}> {
|
|
12
|
+
(): TValue
|
|
13
|
+
set: Setter<TValue>
|
|
14
|
+
throttler: AngularThrottler<Setter<TValue>, TSelected>
|
|
22
15
|
}
|
|
23
16
|
|
|
24
17
|
/**
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
+
import { DestroyRef, inject } from '@angular/core'
|
|
1
2
|
import { injectStore } from '@tanstack/angular-store'
|
|
2
3
|
import { Throttler } from '@tanstack/pacer/throttler'
|
|
3
4
|
import { injectPacerOptions } from '../provider/pacer-context'
|
|
4
5
|
import type { Signal } from '@angular/core'
|
|
5
|
-
import type { Store } from '@tanstack/store'
|
|
6
|
+
import type { Store } from '@tanstack/angular-store'
|
|
6
7
|
import type { AnyFunction } from '@tanstack/pacer/types'
|
|
7
8
|
import type {
|
|
8
9
|
ThrottlerOptions,
|
|
9
10
|
ThrottlerState,
|
|
10
11
|
} from '@tanstack/pacer/throttler'
|
|
11
12
|
|
|
13
|
+
export interface AngularThrottlerOptions<
|
|
14
|
+
TFn extends AnyFunction,
|
|
15
|
+
TSelected = {},
|
|
16
|
+
> extends ThrottlerOptions<TFn> {
|
|
17
|
+
/**
|
|
18
|
+
* Optional callback invoked when the component is destroyed. Receives the throttler instance.
|
|
19
|
+
* When provided, replaces the default cleanup (cancel); use it to call flush(), cancel(), add logging, etc.
|
|
20
|
+
*/
|
|
21
|
+
onUnmount?: (throttler: AngularThrottler<TFn, TSelected>) => void
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
export interface AngularThrottler<
|
|
13
25
|
TFn extends AnyFunction,
|
|
14
26
|
TSelected = {},
|
|
@@ -58,6 +70,18 @@ export interface AngularThrottler<
|
|
|
58
70
|
* - `nextExecutionTime`: Timestamp of the next allowed execution
|
|
59
71
|
* - `status`: Current execution status ('disabled' | 'idle' | 'pending')
|
|
60
72
|
*
|
|
73
|
+
* ## Cleanup on Destroy
|
|
74
|
+
*
|
|
75
|
+
* By default, the function cancels any pending execution when the component is destroyed.
|
|
76
|
+
* Use the `onUnmount` option to customize this. For example, to flush pending work instead:
|
|
77
|
+
*
|
|
78
|
+
* ```ts
|
|
79
|
+
* const throttler = injectThrottler(fn, {
|
|
80
|
+
* wait: 100,
|
|
81
|
+
* onUnmount: (t) => t.flush()
|
|
82
|
+
* });
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
61
85
|
* @example
|
|
62
86
|
* ```ts
|
|
63
87
|
* // Default behavior - no reactive state subscriptions
|
|
@@ -84,19 +108,30 @@ export interface AngularThrottler<
|
|
|
84
108
|
*/
|
|
85
109
|
export function injectThrottler<TFn extends AnyFunction, TSelected = {}>(
|
|
86
110
|
fn: TFn,
|
|
87
|
-
options:
|
|
111
|
+
options: AngularThrottlerOptions<TFn, TSelected>,
|
|
88
112
|
selector: (state: ThrottlerState<TFn>) => TSelected = () => ({}) as TSelected,
|
|
89
113
|
): AngularThrottler<TFn, TSelected> {
|
|
90
114
|
const mergedOptions = {
|
|
91
115
|
...injectPacerOptions().throttler,
|
|
92
116
|
...options,
|
|
93
|
-
} as
|
|
117
|
+
} as AngularThrottlerOptions<TFn, TSelected>
|
|
94
118
|
|
|
95
119
|
const throttler = new Throttler<TFn>(fn, mergedOptions)
|
|
96
120
|
const state = injectStore(throttler.store, selector)
|
|
97
121
|
|
|
98
|
-
|
|
122
|
+
const result = {
|
|
99
123
|
...throttler,
|
|
100
124
|
state,
|
|
101
125
|
} as AngularThrottler<TFn, TSelected>
|
|
126
|
+
|
|
127
|
+
const destroyRef = inject(DestroyRef, { optional: true })
|
|
128
|
+
destroyRef?.onDestroy(() => {
|
|
129
|
+
if (mergedOptions.onUnmount) {
|
|
130
|
+
mergedOptions.onUnmount(result)
|
|
131
|
+
} else {
|
|
132
|
+
throttler.cancel()
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
return result
|
|
102
137
|
}
|