@avatijs/debounce 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md ADDED
@@ -0,0 +1,232 @@
1
+ # Advanced TypeScript Debounce Utility
2
+
3
+ A highly configurable debounce utility with TypeScript support, providing features like leading/trailing edge execution, cancellation, immediate flush, maximum wait time, and proper Promise handling.
4
+
5
+ ## Features
6
+
7
+ - ๐ŸŽฏ Configurable leading/trailing edge execution
8
+ - ๐Ÿšซ Cancelable debounced functions
9
+ - โšก Immediate flush capability
10
+ - โฑ๏ธ Maximum wait time option
11
+ - ๐Ÿ”„ Promise-based return values
12
+ - ๐ŸŽญ AbortController support
13
+ - ๐Ÿž Debug mode
14
+ - ๐Ÿ“ Comprehensive TypeScript types
15
+ - ๐Ÿงน Proper cleanup utilities
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @your-org/debounce-utility
21
+ ```
22
+
23
+ ## Basic Usage
24
+
25
+ ```typescript
26
+ import { debounce } from '@your-org/debounce-utility';
27
+
28
+ // Simple debounce
29
+ const debouncedFn = debounce(async (x: number) => x * 2, {
30
+ wait: 1000,
31
+ });
32
+
33
+ // Call the debounced function
34
+ await debouncedFn(5); // Will execute after 1000ms
35
+
36
+ // With debug logging
37
+ const debuggedFn = debounce(async (x: number) => x * 2, {
38
+ wait: 1000,
39
+ debug: true,
40
+ });
41
+
42
+ // With abort controller
43
+ const controller = new AbortController();
44
+ const abortableFn = debounce(async (x: number) => x * 2, {
45
+ wait: 1000,
46
+ signal: controller.signal,
47
+ });
48
+
49
+ // Cleanup when done
50
+ debouncedFn.cleanup();
51
+ ```
52
+
53
+ ## API Reference
54
+
55
+ ### `debounce<T>(func: T, options?: DebounceOptions): DebouncedFunction<T>`
56
+
57
+ Creates a debounced version of the provided function.
58
+
59
+ #### Parameters
60
+
61
+ ##### `func: T`
62
+
63
+ The function to debounce. Can be synchronous or asynchronous.
64
+
65
+ ##### `options: DebounceOptions`
66
+
67
+ Configuration options for the debounced function.
68
+
69
+ ```typescript
70
+ interface DebounceOptions {
71
+ readonly wait?: number; // Delay in milliseconds (default: 0)
72
+ readonly leading?: boolean; // Execute on leading edge (default: false)
73
+ readonly trailing?: boolean; // Execute on trailing edge (default: true)
74
+ readonly maxWait?: number; // Maximum time to wait
75
+ readonly debug?: boolean; // Enable debug logging (default: false)
76
+ readonly signal?: AbortSignal; // AbortController signal
77
+ }
78
+ ```
79
+
80
+ #### Returns
81
+
82
+ Returns a debounced function with the following interface:
83
+
84
+ ```typescript
85
+ interface DebouncedFunction<T> {
86
+ (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
87
+ readonly cancel: () => void;
88
+ readonly flush: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;
89
+ readonly pending: () => boolean;
90
+ readonly cleanup: () => void;
91
+ }
92
+ ```
93
+
94
+ ## Advanced Usage Examples
95
+
96
+ ### Leading Edge Execution
97
+
98
+ ```typescript
99
+ const leadingDebounce = debounce((value: string) => console.log(value), {
100
+ wait: 1000,
101
+ leading: true,
102
+ trailing: false,
103
+ });
104
+
105
+ // Executes immediately, then ignores calls for 1000ms
106
+ leadingDebounce('First');
107
+ leadingDebounce('Second'); // Ignored
108
+ leadingDebounce('Third'); // Ignored
109
+ ```
110
+
111
+ ### Maximum Wait Time
112
+
113
+ ```typescript
114
+ const maxWaitDebounce = debounce((value: string) => console.log(value), {
115
+ wait: 1000,
116
+ maxWait: 5000,
117
+ });
118
+
119
+ // Will execute after 5000ms maximum, even if called continuously
120
+ const interval = setInterval(() => maxWaitDebounce('test'), 100);
121
+ ```
122
+
123
+ ### With AbortController
124
+
125
+ ```typescript
126
+ const controller = new AbortController();
127
+
128
+ const abortableDebounce = debounce(
129
+ async (value: string) => {
130
+ await someAsyncOperation(value);
131
+ },
132
+ {
133
+ wait: 1000,
134
+ signal: controller.signal,
135
+ }
136
+ );
137
+
138
+ // Later, abort all pending operations
139
+ controller.abort();
140
+ ```
141
+
142
+ ### Debug Mode
143
+
144
+ ```typescript
145
+ const debugDebounce = debounce((value: string) => console.log(value), {
146
+ wait: 1000,
147
+ debug: true,
148
+ });
149
+
150
+ // Will log detailed information about internal state
151
+ debugDebounce('test');
152
+ ```
153
+
154
+ ### Handling Return Values
155
+
156
+ ```typescript
157
+ const asyncDebounce = debounce(
158
+ async (x: number): Promise<number> => {
159
+ await delay(100);
160
+ return x * 2;
161
+ },
162
+ { wait: 1000 }
163
+ );
164
+
165
+ // Get the result
166
+ const result = await asyncDebounce(5);
167
+ console.log(result); // 10
168
+ ```
169
+
170
+ ### Cleanup
171
+
172
+ ```typescript
173
+ const debouncedFn = debounce((x: number) => x * 2, { wait: 1000 });
174
+
175
+ // Use the function
176
+ debouncedFn(5);
177
+
178
+ // Clean up when done
179
+ debouncedFn.cleanup();
180
+ ```
181
+
182
+ ## Best Practices
183
+
184
+ 1. **Always Clean Up**: Call `cleanup()` when you're done with the debounced function to prevent memory leaks:
185
+
186
+ ```typescript
187
+ const debouncedFn = debounce(myFunc, { wait: 1000 });
188
+
189
+ // When done:
190
+ debouncedFn.cleanup();
191
+ ```
192
+
193
+ 2. **Error Handling**: Always handle potential errors in async operations:
194
+
195
+ ```typescript
196
+ const debouncedFn = debounce(async () => {
197
+ try {
198
+ await debouncedOperation();
199
+ } catch (error) {
200
+ // Handle error
201
+ }
202
+ });
203
+ ```
204
+
205
+ 3. **TypeScript Usage**: Leverage TypeScript's type system:
206
+
207
+ ```typescript
208
+ interface MyFuncParams {
209
+ id: number;
210
+ name: string;
211
+ }
212
+
213
+ const typedDebounce = debounce((params: MyFuncParams) => console.log(params), { wait: 1000 });
214
+
215
+ // TypeScript will enforce correct parameter types
216
+ typedDebounce({ id: 1, name: 'test' });
217
+ ```
218
+
219
+ ## Common Gotchas
220
+
221
+ 1. **Memory Leaks**: Not calling `cleanup()` when done can lead to memory leaks.
222
+ 2. **Shared State**: Be careful with shared state in debounced functions.
223
+ 3. **Error Handling**: Always handle potential errors in async operations.
224
+ 4. **Maximum Wait Time**: Setting `maxWait` less than `wait` will throw an error.
225
+
226
+ ## Contributing
227
+
228
+ Contributions are welcome! Please read our [contributing guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
229
+
230
+ ## License
231
+
232
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
package/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # Advanced TypeScript Debounce Utility
2
+
3
+ A highly configurable debounce utility with TypeScript support, providing features like leading/trailing edge execution, cancellation, immediate flush, maximum wait time, and proper Promise handling.
4
+
5
+ ## Features
6
+
7
+ - ๐ŸŽฏ Configurable leading/trailing edge execution
8
+ - ๐Ÿšซ Cancelable debounced functions
9
+ - โšก Immediate flush capability
10
+ - โฑ๏ธ Maximum wait time option
11
+ - ๐Ÿ”„ Promise-based return values
12
+ - ๐ŸŽญ AbortController support
13
+ - ๐Ÿž Debug mode
14
+ - ๐Ÿ“ Comprehensive TypeScript types
15
+ - ๐Ÿงน Proper cleanup utilities
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @avatijs/debounce
21
+ ```
22
+
23
+ ## Basic Usage
24
+
25
+ ```typescript
26
+ import { debounce } from '@your-org/debounce-utility';
27
+
28
+ // Simple debounce
29
+ const debouncedFn = debounce(async (x: number) => x * 2, {
30
+ wait: 1000
31
+ });
32
+
33
+ // Call the debounced function
34
+ await debouncedFn(5); // Will execute after 1000ms
35
+
36
+ // With debug logging
37
+ const debuggedFn = debounce(async (x: number) => x * 2, {
38
+ wait: 1000,
39
+ debug: true
40
+ });
41
+
42
+ // With abort controller
43
+ const controller = new AbortController();
44
+ const abortableFn = debounce(async (x: number) => x * 2, {
45
+ wait: 1000,
46
+ signal: controller.signal
47
+ });
48
+
49
+ // Cleanup when done
50
+ debouncedFn.cleanup();
51
+ ```
52
+
53
+ ## API Reference
54
+
55
+ ### `debounce<T>(func: T, options?: DebounceOptions): DebouncedFunction<T>`
56
+
57
+ Creates a debounced version of the provided function.
58
+
59
+ #### Parameters
60
+
61
+ ##### `func: T`
62
+ The function to debounce. Can be synchronous or asynchronous.
63
+
64
+ ##### `options: DebounceOptions`
65
+ Configuration options for the debounced function.
66
+
67
+ ```typescript
68
+ interface DebounceOptions {
69
+ readonly wait?: number; // Delay in milliseconds (default: 0)
70
+ readonly leading?: boolean; // Execute on leading edge (default: false)
71
+ readonly trailing?: boolean; // Execute on trailing edge (default: true)
72
+ readonly maxWait?: number; // Maximum time to wait
73
+ readonly debug?: boolean; // Enable debug logging (default: false)
74
+ readonly signal?: AbortSignal; // AbortController signal
75
+ }
76
+ ```
77
+
78
+ #### Returns
79
+
80
+ Returns a debounced function with the following interface:
81
+
82
+ ```typescript
83
+ interface DebouncedFunction<T> {
84
+ (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
85
+ readonly cancel: () => void;
86
+ readonly flush: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;
87
+ readonly pending: () => boolean;
88
+ readonly cleanup: () => void;
89
+ }
90
+ ```
91
+
92
+ ## Advanced Usage Examples
93
+
94
+ ### Leading Edge Execution
95
+
96
+ ```typescript
97
+ const leadingDebounce = debounce(
98
+ (value: string) => console.log(value),
99
+ {
100
+ wait: 1000,
101
+ leading: true,
102
+ trailing: false
103
+ }
104
+ );
105
+
106
+ // Executes immediately, then ignores calls for 1000ms
107
+ leadingDebounce("First");
108
+ leadingDebounce("Second"); // Ignored
109
+ leadingDebounce("Third"); // Ignored
110
+ ```
111
+
112
+ ### Maximum Wait Time
113
+
114
+ ```typescript
115
+ const maxWaitDebounce = debounce(
116
+ (value: string) => console.log(value),
117
+ {
118
+ wait: 1000,
119
+ maxWait: 5000
120
+ }
121
+ );
122
+
123
+ // Will execute after 5000ms maximum, even if called continuously
124
+ const interval = setInterval(() => maxWaitDebounce("test"), 100);
125
+ ```
126
+
127
+ ### With AbortController
128
+
129
+ ```typescript
130
+ const controller = new AbortController();
131
+
132
+ const abortableDebounce = debounce(
133
+ async (value: string) => {
134
+ await someAsyncOperation(value);
135
+ },
136
+ {
137
+ wait: 1000,
138
+ signal: controller.signal
139
+ }
140
+ );
141
+
142
+ // Later, abort all pending operations
143
+ controller.abort();
144
+ ```
145
+
146
+ ### Debug Mode
147
+
148
+ ```typescript
149
+ const debugDebounce = debounce(
150
+ (value: string) => console.log(value),
151
+ {
152
+ wait: 1000,
153
+ debug: true
154
+ }
155
+ );
156
+
157
+ // Will log detailed information about internal state
158
+ debugDebounce("test");
159
+ ```
160
+
161
+ ### Handling Return Values
162
+
163
+ ```typescript
164
+ const asyncDebounce = debounce(
165
+ async (x: number): Promise<number> => {
166
+ await delay(100);
167
+ return x * 2;
168
+ },
169
+ { wait: 1000 }
170
+ );
171
+
172
+ // Get the result
173
+ const result = await asyncDebounce(5);
174
+ console.log(result); // 10
175
+ ```
176
+
177
+ ### Cleanup
178
+
179
+ ```typescript
180
+ const debouncedFn = debounce((x: number) => x * 2, { wait: 1000 });
181
+
182
+ // Use the function
183
+ debouncedFn(5);
184
+
185
+ // Clean up when done
186
+ debouncedFn.cleanup();
187
+ ```
188
+
189
+ ## Best Practices
190
+
191
+ 1. **Always Clean Up**: Call `cleanup()` when you're done with the debounced function to prevent memory leaks:
192
+
193
+ ```typescript
194
+ const debouncedFn = debounce(myFunc, { wait: 1000 });
195
+
196
+ // When done:
197
+ debouncedFn.cleanup();
198
+ ```
199
+
200
+ 2. **Error Handling**: Always handle potential errors in async operations:
201
+
202
+ ```typescript
203
+ const debouncedFn = debounce(async () => {
204
+ try {
205
+ await debouncedOperation();
206
+ } catch (error) {
207
+ // Handle error
208
+ }
209
+ });
210
+ ```
211
+
212
+ 3. **TypeScript Usage**: Leverage TypeScript's type system:
213
+
214
+ ```typescript
215
+ interface MyFuncParams {
216
+ id: number;
217
+ name: string;
218
+ }
219
+
220
+ const typedDebounce = debounce(
221
+ (params: MyFuncParams) => console.log(params),
222
+ { wait: 1000 }
223
+ );
224
+
225
+ // TypeScript will enforce correct parameter types
226
+ typedDebounce({ id: 1, name: "test" });
227
+ ```
228
+
229
+ ## Common Gotchas
230
+
231
+ 1. **Memory Leaks**: Not calling `cleanup()` when done can lead to memory leaks.
232
+ 2. **Shared State**: Be careful with shared state in debounced functions.
233
+ 3. **Error Handling**: Always handle potential errors in async operations.
234
+ 4. **Maximum Wait Time**: Setting `maxWait` less than `wait` will throw an error.
235
+
236
+ ## Contributing
237
+
238
+ Contributions are welcome! Please read our [contributing guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
239
+
240
+ ## License
241
+
242
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * @avatijs/debounce 0.1.1
3
+ * Copyright (c) 2024 Khaled Sameer <khaled.smq@hotmail.com>
4
+ * Licensed under MIT, https://opensource.org/licenses/MIT/
5
+ * Please visit https://avati.io/ for details.
6
+ */(()=>{"use strict";var e={d:(n,o)=>{for(var r in o)e.o(o,r)&&!e.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:o[r]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"t",{value:!0})}},n={};e.r(n),e.d(n,{debounce:()=>t});const o=new WeakMap,r=e=>({log:(...n)=>e&&void 0,warn:(...n)=>e&&void 0,error:(...n)=>e&&void 0});function t(e,n={}){if("function"!=typeof e)throw new TypeError("Expected a function");const{wait:t=0,leading:i=!1,trailing:c=!0,maxWait:a,debug:u=!1,signal:d,onError:l}=n;if(0>t||void 0!==a&&t>a)throw new RangeError("Invalid wait/maxWait values");if(!i&&!c)throw Error("At least one of leading or trailing must be true");const s=r(u),f={lastInvokeTime:0,pendingPromises:[],aborted:!1};function v(){void 0!==f.timerId&&(clearTimeout(f.timerId),f.timerId=void 0,s.log("Cleared debounce timer")),void 0!==f.maxTimerId&&(clearTimeout(f.maxTimerId),f.maxTimerId=void 0,s.log("Cleared max wait timer"))}function b(){s.log("Cancelling pending invocations"),v(),f.lastInvokeTime=0,f.lastArgs=void 0,f.lastThis=void 0,f.lastCallTime=void 0,g(Error("Debounced function cancelled")),f.pendingPromises.forEach((({reject:e})=>e(Error("Debounced function cancelled")))),f.pendingPromises=[]}function g(e){if(s.error("Error occurred:",e),l)try{l(e)}catch(e){s.error("Error in onError callback:",e)}}function m(){return void 0!==f.timerId}function w(e){if(f.aborted)return!1;const n=void 0===f.lastCallTime?0:e-f.lastCallTime;return void 0===f.lastCallTime||n>=t||0>n||void 0!==a&&e-f.lastInvokeTime>=a}async function E(n){s.log("Invoking function at "+n),f.lastInvokeTime=n;const o=f.lastArgs,r=f.lastThis;f.lastArgs=void 0,f.lastThis=void 0;try{const n=await e.apply(r,o);return f.result=n,f.pendingPromises.forEach((({resolve:e})=>e(n))),f.pendingPromises=[],s.log("Function invoked successfully",n),n}catch(e){const n=e instanceof Error?e:Error(e+"");s.error("Error in function invocation:",n),g(n);const o=[...f.pendingPromises];f.pendingPromises=[],o.forEach((({reject:e})=>e(n)))}}function p(e){const n=function(e){return Math.max(0,t-(f.lastCallTime?e-f.lastCallTime:0))}(e);if(f.timerId=setTimeout(y,n),s.log(`Started debounce timer for ${n}ms`),void 0!==a&&!f.maxTimerId){const n=a-(e-f.lastCallTime);f.maxTimerId=setTimeout((()=>{s.log("Max wait timer expired"),v(),E(Date.now())}),Math.max(0,n)),s.log(`Started max wait timer for ${n}ms`)}}function y(){const e=Date.now();if(s.log("Debounce timer expired"),w(e))return function(e){s.log("Trailing edge triggered"),v(),c&&f.lastArgs?E(e):(f.pendingPromises.forEach((({resolve:e})=>{e(f.result)})),f.pendingPromises=[])}(e);p(e)}d&&d.addEventListener("abort",(()=>{f.aborted=!0,b()}));const h=function(...e){if(f.aborted)return Promise.reject(Error("Debounced function aborted"));const n=Date.now(),o=w(n);return f.lastArgs=e,f.lastThis=this,f.lastCallTime=n,s.log("Function called",{time:n,isInvoking:o,args:e,pending:m()}),new Promise(((e,o)=>{f.pendingPromises.push({resolve:e,reject:o}),void 0===f.timerId?function(e){s.log("Leading edge triggered"),f.lastInvokeTime=e,p(e),i&&E(e)}(n):(v(),p(n))}))};return o.set(h,f),Object.defineProperties(h,{cancel:{value:b,writable:!1,configurable:!1},flush:{value:async function(...e){s.log("Flush requested");const n=e.length>0?e:f.lastArgs,o=f.lastThis;return v(),n?(f.lastArgs=n,f.lastThis=o,E(Date.now())):Promise.resolve(f.result)},writable:!1,configurable:!1},pending:{value:m,writable:!1,configurable:!1},cleanup:{value:function(){s.log("Cleanup initiated"),b(),o.delete(h)},writable:!1,configurable:!1}}),h}module.exports=n})();
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","mappings":"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","sources":["webpack://@avatijs/debounce/webpack/bootstrap","webpack://@avatijs/debounce/webpack/runtime/define property getters","webpack://@avatijs/debounce/webpack/runtime/hasOwnProperty shorthand","webpack://@avatijs/debounce/webpack/runtime/make namespace object","webpack://@avatijs/debounce/./src/debouce.ts"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Advanced debounce utility with TypeScript support\n * Provides a way to limit the rate at which a function can fire by delaying its execution\n * until after a specified amount of time has elapsed since its last invocation.\n * @module debounce\n */\n\n/**\n * Timer ID type returned by setTimeout\n * Used for managing timers internally\n */\ntype TimerId = ReturnType<typeof setTimeout>;\n\n/**\n * Generic function type that can accept any arguments and return any value\n * Used as a constraint for functions that can be debounced\n */\ntype AnyFunction = (...args: any[]) => any;\n\n/**\n * Configuration options for the debounce function\n * @interface DebounceOptions\n */\ninterface DebounceOptions {\n /** Number of milliseconds to delay execution (default: 0) */\n readonly wait?: number;\n /** Whether to execute on the leading edge of the timeout (default: false) */\n readonly leading?: boolean;\n /** Whether to execute on the trailing edge of the timeout (default: true) */\n readonly trailing?: boolean;\n /** Maximum time the function can be delayed before forced execution */\n readonly maxWait?: number;\n /** Enable debug logging for troubleshooting */\n readonly debug?: boolean;\n /** AbortController signal for cancellation */\n readonly signal?: AbortSignal;\n\n onError?: (error: Error) => void;\n}\n\n/**\n * Interface for the debounced function, including utility methods\n * @interface DebouncedFunction\n * @template T - The type of the original function\n */\ninterface DebouncedFunction<T extends AnyFunction> {\n /** Cancels any pending function invocations */\n readonly cancel: () => void;\n /** Immediately executes any pending function call */\n readonly flush: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;\n /** Checks if there are any pending invocations */\n readonly pending: () => boolean;\n /** Cleans up resources used by the debounced function */\n readonly cleanup: () => void;\n\n /** The debounced function that wraps the original */\n (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;\n}\n\n/**\n * Internal state management for the debounced function\n * @interface PrivateState\n * @template T - The type of the original function\n * @private\n */\ninterface PrivateState<T extends AnyFunction> {\n /** Current timer ID for the debounce delay */\n timerId?: TimerId;\n /** Timer ID for the maximum wait limit */\n maxTimerId?: TimerId;\n /** Timestamp of the last function call */\n lastCallTime?: number;\n /** Timestamp of the last successful function invocation */\n lastInvokeTime: number;\n /** Arguments from the most recent function call */\n lastArgs?: Parameters<T>;\n /** Execution context (this) from the most recent call */\n lastThis?: any;\n /** Result from the last function execution */\n result?: Awaited<ReturnType<T>>;\n /** Array of pending promises waiting for resolution */\n pendingPromises: Array<{\n resolve: (value: Awaited<ReturnType<T>>) => void;\n reject: (reason?: any) => void;\n }>;\n /** Flag indicating if the function has been aborted */\n aborted: boolean;\n}\n\n/** WeakMap to store private state for each debounced function */\nconst privateState = new WeakMap<DebouncedFunction<any>, PrivateState<any>>();\n\n/**\n * Creates a logger instance based on debug flag\n * @param debug - Whether debug logging is enabled\n * @returns Object with logging methods\n * @private\n */\nconst createLogger = (debug: boolean) => ({\n log: (...args: any[]) => debug && console.log('[Debounce]', ...args),\n warn: (...args: any[]) => debug && console.warn('[Debounce]', ...args),\n error: (...args: any[]) => debug && console.error('[Debounce]', ...args),\n});\n\n/**\n * Creates a debounced version of the provided function that delays invoking func until after\n * wait milliseconds have elapsed since the last time the debounced function was invoked.\n *\n * @template T - The type of the function to debounce\n * @param {T} func - The function to debounce\n * @param {DebounceOptions} [options={}] - Configuration options\n * @returns {DebouncedFunction<T>} The debounced function\n * @throws {TypeError} If func is not a function\n * @throws {RangeError} If wait or maxWait values are invalid\n * @throws {Error} If neither leading nor trailing is true\n *\n * @example\n * const debouncedFn = debounce(async (x: number) => x * 2, { wait: 1000 });\n * await debouncedFn(5); // Will execute after 1000ms of inactivity\n * const debouncedFn = debounce(\n * async (x: number) => x * 2,\n * {\n * wait: 1000,\n * onError: (error) => console.error('Error in debounced function:', error)\n * }\n * );\n */\nfunction debounce<T extends AnyFunction>(\n func: T,\n options: DebounceOptions = {},\n): DebouncedFunction<T> {\n // Input validation\n if (typeof func !== 'function') {\n throw new TypeError('Expected a function');\n }\n\n const {\n wait = 0,\n leading = false,\n trailing = true,\n maxWait,\n debug = false,\n signal,\n onError,\n } = options;\n\n // Validate options\n if (wait < 0 || (maxWait !== undefined && maxWait < wait)) {\n throw new RangeError('Invalid wait/maxWait values');\n }\n\n if (!leading && !trailing) {\n throw new Error('At least one of leading or trailing must be true');\n }\n\n const logger = createLogger(debug);\n const state: PrivateState<T> = {\n lastInvokeTime: 0,\n pendingPromises: [],\n aborted: false,\n };\n\n // Setup abort controller handling\n if (signal) {\n signal.addEventListener('abort', () => {\n state.aborted = true;\n cancel();\n });\n }\n\n /**\n * Cancels all active timers\n * @private\n */\n function cancelTimers(): void {\n if (state.timerId !== undefined) {\n clearTimeout(state.timerId);\n state.timerId = undefined;\n logger.log('Cleared debounce timer');\n }\n if (state.maxTimerId !== undefined) {\n clearTimeout(state.maxTimerId);\n state.maxTimerId = undefined;\n logger.log('Cleared max wait timer');\n }\n }\n\n /**\n * Cancels any pending function invocations\n * Rejects all pending promises and resets internal state\n */\n function cancel(): void {\n logger.log('Cancelling pending invocations');\n cancelTimers();\n state.lastInvokeTime = 0;\n state.lastArgs = undefined;\n state.lastThis = undefined;\n state.lastCallTime = undefined;\n const error = new Error('Debounced function cancelled');\n handleError(error);\n state.pendingPromises.forEach(({ reject }) =>\n reject(new Error('Debounced function cancelled')),\n );\n state.pendingPromises = [];\n }\n\n /**\n * Handles errors during function execution\n * @param {Error} error - The error that occurred\n * @private\n */\n function handleError(error: Error): void {\n logger.error('Error occurred:', error);\n if (onError) {\n try {\n onError(error);\n } catch (callbackError) {\n logger.error('Error in onError callback:', callbackError);\n }\n }\n }\n\n /**\n * Checks if there are any pending function invocations\n * @returns {boolean} True if there are pending invocations\n */\n function pending(): boolean {\n return state.timerId !== undefined;\n }\n\n /**\n * Determines if the function should be invoked based on timing conditions\n * @param {number} time - Current timestamp\n * @returns {boolean} True if function should be invoked\n * @private\n */\n function shouldInvoke(time: number): boolean {\n if (state.aborted) return false;\n\n const timeSinceLastCall = state.lastCallTime === undefined ? 0 : time - state.lastCallTime;\n const timeSinceLastInvoke = time - state.lastInvokeTime;\n\n return (\n state.lastCallTime === undefined ||\n timeSinceLastCall >= wait ||\n timeSinceLastCall < 0 ||\n (maxWait !== undefined && timeSinceLastInvoke >= maxWait)\n );\n }\n\n /**\n * Executes the underlying function and manages promise resolution\n * @param {number} time - Current timestamp\n * @returns {Promise} Promise resolving to function result\n * @private\n */\n async function invokeFunc(time: number): Promise<Awaited<ReturnType<T>> | void> {\n logger.log(`Invoking function at ${time}`);\n state.lastInvokeTime = time;\n const args = state.lastArgs!;\n const thisArg = state.lastThis;\n\n state.lastArgs = undefined;\n state.lastThis = undefined;\n\n try {\n const result = await func.apply(thisArg, args);\n state.result = result;\n state.pendingPromises.forEach(({ resolve }) => resolve(result));\n state.pendingPromises = [];\n logger.log('Function invoked successfully', result);\n return result;\n } catch (error) {\n const wrappedError = error instanceof Error ? error : new Error(String(error));\n logger.error('Error in function invocation:', wrappedError);\n handleError(wrappedError);\n\n // Clear pending promises after handling error\n const currentPromises = [...state.pendingPromises];\n state.pendingPromises = [];\n\n // Reject all pending promises\n currentPromises.forEach(({ reject }) => reject(wrappedError));\n }\n }\n\n /**\n * Starts both the debounce timer and maxWait timer if configured\n * @param {number} time - Current timestamp\n * @private\n */\n function startTimer(time: number): void {\n const remainingTime = remainingWait(time);\n state.timerId = setTimeout(timerExpired, remainingTime);\n logger.log(`Started debounce timer for ${remainingTime}ms`);\n\n if (maxWait !== undefined && !state.maxTimerId) {\n const timeToMaxWait = maxWait - (time - state.lastCallTime!);\n state.maxTimerId = setTimeout(\n () => {\n logger.log('Max wait timer expired');\n cancelTimers();\n invokeFunc(Date.now());\n },\n Math.max(0, timeToMaxWait),\n );\n logger.log(`Started max wait timer for ${timeToMaxWait}ms`);\n }\n }\n\n /**\n * Calculates remaining wait time before next execution\n * @param {number} time - Current timestamp\n * @returns {number} Milliseconds until next allowed execution\n * @private\n */\n function remainingWait(time: number): number {\n const timeSinceLastCall = state.lastCallTime ? time - state.lastCallTime : 0;\n return Math.max(0, wait - timeSinceLastCall);\n }\n\n /**\n * Handles timer expiration\n * @private\n */\n function timerExpired(): void {\n const time = Date.now();\n logger.log('Debounce timer expired');\n\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n\n startTimer(time);\n }\n\n /**\n * Handles leading edge execution\n * @param {number} time - Current timestamp\n * @private\n */\n function leadingEdge(time: number): void {\n logger.log('Leading edge triggered');\n state.lastInvokeTime = time;\n startTimer(time);\n\n if (leading) {\n invokeFunc(time);\n }\n }\n\n /**\n * Handles trailing edge execution\n * @param {number} time - Current timestamp\n * @private\n */\n function trailingEdge(time: number): void {\n logger.log('Trailing edge triggered');\n cancelTimers();\n\n if (trailing && state.lastArgs) {\n invokeFunc(time);\n } else {\n state.pendingPromises.forEach(({ resolve }) => {\n resolve(state.result as Awaited<ReturnType<T>>);\n });\n state.pendingPromises = [];\n }\n }\n\n /**\n * Immediately executes the debounced function\n * @param {...Parameters<T>} args - Function arguments\n * @returns {Promise<ReturnType<T>>} Promise resolving to function result\n */\n async function flush(...args: Parameters<T>): Promise<Awaited<ReturnType<T>> | void> {\n logger.log('Flush requested');\n const argsToUse = args.length > 0 ? args : state.lastArgs;\n const thisArg = state.lastThis;\n\n cancelTimers();\n\n if (argsToUse) {\n state.lastArgs = argsToUse;\n state.lastThis = thisArg;\n return invokeFunc(Date.now());\n }\n\n return Promise.resolve(state.result!);\n }\n\n /**\n * Cleans up resources used by the debounced function\n */\n function cleanup(): void {\n logger.log('Cleanup initiated');\n cancel();\n privateState.delete(debounced);\n }\n\n /**\n * The debounced function that wraps the original\n * @param {...Parameters<T>} args - Function arguments\n * @returns {Promise<ReturnType<T>>} Promise resolving to function result\n */\n const debounced = function(\n this: any,\n ...args: Parameters<T>\n ): Promise<Awaited<ReturnType<T>>> {\n if (state.aborted) {\n return Promise.reject(new Error('Debounced function aborted'));\n }\n\n const time = Date.now();\n const isInvoking = shouldInvoke(time);\n\n state.lastArgs = args;\n state.lastThis = this;\n state.lastCallTime = time;\n\n logger.log('Function called', {\n time,\n isInvoking,\n args,\n pending: pending(),\n });\n\n return new Promise((resolve, reject) => {\n state.pendingPromises.push({ resolve, reject });\n\n if (state.timerId === undefined) {\n leadingEdge(time);\n } else {\n cancelTimers();\n startTimer(time);\n }\n });\n } as DebouncedFunction<T>;\n\n // Store private state\n privateState.set(debounced, state);\n\n // Add utility methods\n Object.defineProperties(debounced, {\n cancel: { value: cancel, writable: false, configurable: false },\n flush: { value: flush, writable: false, configurable: false },\n pending: { value: pending, writable: false, configurable: false },\n cleanup: { value: cleanup, writable: false, configurable: false },\n });\n\n return debounced;\n}\n\nexport { debounce, type DebouncedFunction, type DebounceOptions };\n"],"names":["__webpack_require__","exports","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","Symbol","toStringTag","value","privateState","WeakMap","createLogger","debug","log","args","console","warn","error","debounce","func","options","TypeError","wait","leading","trailing","maxWait","signal","onError","undefined","RangeError","Error","logger","state","lastInvokeTime","pendingPromises","aborted","cancelTimers","timerId","clearTimeout","maxTimerId","cancel","lastArgs","lastThis","lastCallTime","handleError","forEach","reject","callbackError","pending","shouldInvoke","time","timeSinceLastCall","async","invokeFunc","thisArg","result","apply","resolve","wrappedError","String","currentPromises","startTimer","remainingTime","Math","max","remainingWait","setTimeout","timerExpired","timeToMaxWait","Date","now","trailingEdge","addEventListener","debounced","Promise","isInvoking","this","push","leadingEdge","set","defineProperties","writable","configurable","flush","argsToUse","length","cleanup","delete"],"sourceRoot":""}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Advanced debounce utility with TypeScript support
3
+ * Provides a way to limit the rate at which a function can fire by delaying its execution
4
+ * until after a specified amount of time has elapsed since its last invocation.
5
+ * @module debounce
6
+ */
7
+ /**
8
+ * Generic function type that can accept any arguments and return any value
9
+ * Used as a constraint for functions that can be debounced
10
+ */
11
+ type AnyFunction = (...args: any[]) => any;
12
+ /**
13
+ * Configuration options for the debounce function
14
+ * @interface DebounceOptions
15
+ */
16
+ interface DebounceOptions {
17
+ /** Number of milliseconds to delay execution (default: 0) */
18
+ readonly wait?: number;
19
+ /** Whether to execute on the leading edge of the timeout (default: false) */
20
+ readonly leading?: boolean;
21
+ /** Whether to execute on the trailing edge of the timeout (default: true) */
22
+ readonly trailing?: boolean;
23
+ /** Maximum time the function can be delayed before forced execution */
24
+ readonly maxWait?: number;
25
+ /** Enable debug logging for troubleshooting */
26
+ readonly debug?: boolean;
27
+ /** AbortController signal for cancellation */
28
+ readonly signal?: AbortSignal;
29
+ onError?: (error: Error) => void;
30
+ }
31
+ /**
32
+ * Interface for the debounced function, including utility methods
33
+ * @interface DebouncedFunction
34
+ * @template T - The type of the original function
35
+ */
36
+ interface DebouncedFunction<T extends AnyFunction> {
37
+ /** Cancels any pending function invocations */
38
+ readonly cancel: () => void;
39
+ /** Immediately executes any pending function call */
40
+ readonly flush: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;
41
+ /** Checks if there are any pending invocations */
42
+ readonly pending: () => boolean;
43
+ /** Cleans up resources used by the debounced function */
44
+ readonly cleanup: () => void;
45
+ /** The debounced function that wraps the original */
46
+ (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
47
+ }
48
+ /**
49
+ * Creates a debounced version of the provided function that delays invoking func until after
50
+ * wait milliseconds have elapsed since the last time the debounced function was invoked.
51
+ *
52
+ * @template T - The type of the function to debounce
53
+ * @param {T} func - The function to debounce
54
+ * @param {DebounceOptions} [options={}] - Configuration options
55
+ * @returns {DebouncedFunction<T>} The debounced function
56
+ * @throws {TypeError} If func is not a function
57
+ * @throws {RangeError} If wait or maxWait values are invalid
58
+ * @throws {Error} If neither leading nor trailing is true
59
+ *
60
+ * @example
61
+ * const debouncedFn = debounce(async (x: number) => x * 2, { wait: 1000 });
62
+ * await debouncedFn(5); // Will execute after 1000ms of inactivity
63
+ * const debouncedFn = debounce(
64
+ * async (x: number) => x * 2,
65
+ * {
66
+ * wait: 1000,
67
+ * onError: (error) => console.error('Error in debounced function:', error)
68
+ * }
69
+ * );
70
+ */
71
+ declare function debounce<T extends AnyFunction>(func: T, options?: DebounceOptions): DebouncedFunction<T>;
72
+ export { debounce, type DebouncedFunction, type DebounceOptions };
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * @avatijs/debounce 0.1.1
3
+ * Copyright (c) 2024 Khaled Sameer <khaled.smq@hotmail.com>
4
+ * Licensed under MIT, https://opensource.org/licenses/MIT/
5
+ * Please visit https://avati.io/ for details.
6
+ */var e={d:(n,r)=>{for(var o in r)e.o(r,o)&&!e.o(n,o)&&Object.defineProperty(n,o,{enumerable:!0,get:r[o]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)},n={};e.d(n,{s:()=>t});const r=new WeakMap,o=e=>({log:(...n)=>e&&void 0,warn:(...n)=>e&&void 0,error:(...n)=>e&&void 0});function t(e,n={}){if("function"!=typeof e)throw new TypeError("Expected a function");const{wait:t=0,leading:i=!1,trailing:c=!0,maxWait:a,debug:u=!1,signal:d,onError:l}=n;if(0>t||void 0!==a&&t>a)throw new RangeError("Invalid wait/maxWait values");if(!i&&!c)throw Error("At least one of leading or trailing must be true");const s=o(u),f={lastInvokeTime:0,pendingPromises:[],aborted:!1};function v(){void 0!==f.timerId&&(clearTimeout(f.timerId),f.timerId=void 0,s.log("Cleared debounce timer")),void 0!==f.maxTimerId&&(clearTimeout(f.maxTimerId),f.maxTimerId=void 0,s.log("Cleared max wait timer"))}function g(){s.log("Cancelling pending invocations"),v(),f.lastInvokeTime=0,f.lastArgs=void 0,f.lastThis=void 0,f.lastCallTime=void 0,b(Error("Debounced function cancelled")),f.pendingPromises.forEach((({reject:e})=>e(Error("Debounced function cancelled")))),f.pendingPromises=[]}function b(e){if(s.error("Error occurred:",e),l)try{l(e)}catch(e){s.error("Error in onError callback:",e)}}function m(){return void 0!==f.timerId}function w(e){if(f.aborted)return!1;const n=void 0===f.lastCallTime?0:e-f.lastCallTime;return void 0===f.lastCallTime||n>=t||0>n||void 0!==a&&e-f.lastInvokeTime>=a}async function E(n){s.log("Invoking function at "+n),f.lastInvokeTime=n;const r=f.lastArgs,o=f.lastThis;f.lastArgs=void 0,f.lastThis=void 0;try{const n=await e.apply(o,r);return f.result=n,f.pendingPromises.forEach((({resolve:e})=>e(n))),f.pendingPromises=[],s.log("Function invoked successfully",n),n}catch(e){const n=e instanceof Error?e:Error(e+"");s.error("Error in function invocation:",n),b(n);const r=[...f.pendingPromises];f.pendingPromises=[],r.forEach((({reject:e})=>e(n)))}}function p(e){const n=function(e){return Math.max(0,t-(f.lastCallTime?e-f.lastCallTime:0))}(e);if(f.timerId=setTimeout(h,n),s.log(`Started debounce timer for ${n}ms`),void 0!==a&&!f.maxTimerId){const n=a-(e-f.lastCallTime);f.maxTimerId=setTimeout((()=>{s.log("Max wait timer expired"),v(),E(Date.now())}),Math.max(0,n)),s.log(`Started max wait timer for ${n}ms`)}}function h(){const e=Date.now();if(s.log("Debounce timer expired"),w(e))return function(e){s.log("Trailing edge triggered"),v(),c&&f.lastArgs?E(e):(f.pendingPromises.forEach((({resolve:e})=>{e(f.result)})),f.pendingPromises=[])}(e);p(e)}d&&d.addEventListener("abort",(()=>{f.aborted=!0,g()}));const x=function(...e){if(f.aborted)return Promise.reject(Error("Debounced function aborted"));const n=Date.now(),r=w(n);return f.lastArgs=e,f.lastThis=this,f.lastCallTime=n,s.log("Function called",{time:n,isInvoking:r,args:e,pending:m()}),new Promise(((e,r)=>{f.pendingPromises.push({resolve:e,reject:r}),void 0===f.timerId?function(e){s.log("Leading edge triggered"),f.lastInvokeTime=e,p(e),i&&E(e)}(n):(v(),p(n))}))};return r.set(x,f),Object.defineProperties(x,{cancel:{value:g,writable:!1,configurable:!1},flush:{value:async function(...e){s.log("Flush requested");const n=e.length>0?e:f.lastArgs,r=f.lastThis;return v(),n?(f.lastArgs=n,f.lastThis=r,E(Date.now())):Promise.resolve(f.result)},writable:!1,configurable:!1},pending:{value:m,writable:!1,configurable:!1},cleanup:{value:function(){s.log("Cleanup initiated"),g(),r.delete(x)},writable:!1,configurable:!1}}),x}var i=n.s;export{i as debounce};
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","mappings":";;;;;GACA,IAAIA,EAAsB,CCA1BA,EAAwB,CAACC,EAASC,KACjC,IAAI,IAAIC,KAAOD,EACXF,EAAoBI,EAAEF,EAAYC,KAASH,EAAoBI,EAAEH,EAASE,IAC5EE,OAAOC,eAAeL,EAASE,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,IAE1E,ECNDH,EAAwB,CAACS,EAAKC,IAAUL,OAAOM,UAAUC,eAAeC,KAAKJ,EAAKC,I,sBC0FlF,MAAMI,EAAe,IAAIC,QAQnBC,EAAgBC,IAAmB,CACrCC,IAAK,IAAIC,IAAgBF,QAASG,EAClCC,KAAM,IAAIF,IAAgBF,QAASG,EACnCE,MAAO,IAAIH,IAAgBF,QAASG,IA0BxC,SAASG,EACLC,EACAC,EAA2B,CAAC,GAG5B,GAAoB,mBAATD,EACP,MAAM,IAAIE,UAAU,uBAGxB,MAAM,KACFC,EAAO,EAAC,QACRC,GAAU,EAAK,SACfC,GAAW,EAAI,QACfC,EAAO,MACPb,GAAQ,EAAK,OACbc,EAAM,QACNC,GACAP,EAGJ,GAAW,EAAPE,QAAyBM,IAAZH,GAAmCH,EAAVG,EACtC,MAAM,IAAII,WAAW,+BAGzB,IAAKN,IAAYC,EACb,MAAUM,MAAM,oDAGpB,MAAMC,EAASpB,EAAaC,GACtBoB,EAAyB,CAC3BC,eAAgB,EAChBC,gBAAiB,GACjBC,SAAS,GAeb,SAASC,SACiBR,IAAlBI,EAAMK,UACNC,aAAaN,EAAMK,SACnBL,EAAMK,aAAUT,EAChBG,EAAOlB,IAAI,gCAEUe,IAArBI,EAAMO,aACND,aAAaN,EAAMO,YACnBP,EAAMO,gBAAaX,EACnBG,EAAOlB,IAAI,0BAEnB,CAMA,SAAS2B,IACLT,EAAOlB,IAAI,kCACXuB,IACAJ,EAAMC,eAAiB,EACvBD,EAAMS,cAAWb,EACjBI,EAAMU,cAAWd,EACjBI,EAAMW,kBAAef,EAErBgB,EADkBd,MAAM,iCAExBE,EAAME,gBAAgBW,SAAQ,EAAGC,YAC7BA,EAAWhB,MAAM,mCAErBE,EAAME,gBAAkB,EAC5B,CAOA,SAASU,EAAY3B,GAEjB,GADAc,EAAOd,MAAM,kBAAmBA,GAC5BU,EACA,IACIA,EAAQV,EACZ,CAAE,MAAO8B,GACLhB,EAAOd,MAAM,6BAA8B8B,EAC/C,CAER,CAMA,SAASC,IACL,YAAyBpB,IAAlBI,EAAMK,OACjB,CAQA,SAASY,EAAaC,GAClB,GAAIlB,EAAMG,QAAS,OAAO,EAE1B,MAAMgB,OAA2CvB,IAAvBI,EAAMW,aAA6B,EAAIO,EAAOlB,EAAMW,aAG9E,YAC2Bf,IAAvBI,EAAMW,cACNQ,GAAqB7B,GACD,EAApB6B,QACavB,IAAZH,GANuByB,EAAOlB,EAAMC,gBAMYR,CAEzD,CAQA2B,eAAeC,EAAWH,GACtBnB,EAAOlB,IAAI,wBAAwBqC,GACnClB,EAAMC,eAAiBiB,EACvB,MAAMpC,EAAOkB,EAAMS,SACba,EAAUtB,EAAMU,SAEtBV,EAAMS,cAAWb,EACjBI,EAAMU,cAAWd,EAEjB,IACI,MAAM2B,QAAepC,EAAKqC,MAAMF,EAASxC,GAKzC,OAJAkB,EAAMuB,OAASA,EACfvB,EAAME,gBAAgBW,SAAQ,EAAGY,aAAcA,EAAQF,KACvDvB,EAAME,gBAAkB,GACxBH,EAAOlB,IAAI,gCAAiC0C,GACrCA,CACX,CAAE,MAAOtC,GACL,MAAMyC,EAAezC,aAAiBa,MAAQb,EAAYa,MAAab,EAAP0C,IAChE5B,EAAOd,MAAM,gCAAiCyC,GAC9Cd,EAAYc,GAGZ,MAAME,EAAkB,IAAI5B,EAAME,iBAClCF,EAAME,gBAAkB,GAGxB0B,EAAgBf,SAAQ,EAAGC,YAAaA,EAAOY,IACnD,CACJ,CAOA,SAASG,EAAWX,GAChB,MAAMY,EAwBV,SAAuBZ,GAEnB,OAAOa,KAAKC,IAAI,EAAG1C,GADOU,EAAMW,aAAeO,EAAOlB,EAAMW,aAAe,GAE/E,CA3B0BsB,CAAcf,GAIpC,GAHAlB,EAAMK,QAAU6B,WAAWC,EAAcL,GACzC/B,EAAOlB,IAAI,8BAA8BiD,YAEzBlC,IAAZH,IAA0BO,EAAMO,WAAY,CAC5C,MAAM6B,EAAgB3C,GAAWyB,EAAOlB,EAAMW,cAC9CX,EAAMO,WAAa2B,YACf,KACInC,EAAOlB,IAAI,0BACXuB,IACAiB,EAAWgB,KAAKC,MAAM,GAE1BP,KAAKC,IAAI,EAAGI,IAEhBrC,EAAOlB,IAAI,8BAA8BuD,MAC7C,CACJ,CAiBA,SAASD,IACL,MAAMjB,EAAOmB,KAAKC,MAGlB,GAFAvC,EAAOlB,IAAI,0BAEPoC,EAAaC,GACb,OA0BR,SAAsBA,GAClBnB,EAAOlB,IAAI,2BACXuB,IAEIZ,GAAYQ,EAAMS,SAClBY,EAAWH,IAEXlB,EAAME,gBAAgBW,SAAQ,EAAGY,cAC7BA,EAAQzB,EAAMuB,OAAiC,IAEnDvB,EAAME,gBAAkB,GAEhC,CAtCeqC,CAAarB,GAGxBW,EAAWX,EACf,CA3KIxB,GACAA,EAAO8C,iBAAiB,SAAS,KAC7BxC,EAAMG,SAAU,EAChBK,GAAQ,IA+OhB,MAAMiC,EAAY,YAEX3D,GAEH,GAAIkB,EAAMG,QACN,OAAOuC,QAAQ5B,OAAWhB,MAAM,+BAGpC,MAAMoB,EAAOmB,KAAKC,MACZK,EAAa1B,EAAaC,GAahC,OAXAlB,EAAMS,SAAW3B,EACjBkB,EAAMU,SAAWkC,KACjB5C,EAAMW,aAAeO,EAErBnB,EAAOlB,IAAI,kBAAmB,CAC1BqC,OACAyB,aACA7D,OACAkC,QAASA,MAGN,IAAI0B,SAAQ,CAACjB,EAASX,KACzBd,EAAME,gBAAgB2C,KAAK,CAAEpB,UAASX,gBAEhBlB,IAAlBI,EAAMK,QAzFlB,SAAqBa,GACjBnB,EAAOlB,IAAI,0BACXmB,EAAMC,eAAiBiB,EACvBW,EAAWX,GAEP3B,GACA8B,EAAWH,EAEnB,CAkFY4B,CAAY5B,IAEZd,IACAyB,EAAWX,GACf,GAER,EAaA,OAVAzC,EAAasE,IAAIN,EAAWzC,GAG5BhC,OAAOgF,iBAAiBP,EAAW,CAC/BjC,OAAQ,CAAEyC,MAAOzC,EAAQ0C,UAAU,EAAOC,cAAc,GACxDC,MAAO,CAAEH,MAtEb7B,kBAAwBtC,GACpBiB,EAAOlB,IAAI,mBACX,MAAMwE,EAAYvE,EAAKwE,OAAS,EAAIxE,EAAOkB,EAAMS,SAC3Ca,EAAUtB,EAAMU,SAItB,OAFAN,IAEIiD,GACArD,EAAMS,SAAW4C,EACjBrD,EAAMU,SAAWY,EACVD,EAAWgB,KAAKC,QAGpBI,QAAQjB,QAAQzB,EAAMuB,OACjC,EAwD2B2B,UAAU,EAAOC,cAAc,GACtDnC,QAAS,CAAEiC,MAAOjC,EAASkC,UAAU,EAAOC,cAAc,GAC1DI,QAAS,CAAEN,MArDf,WACIlD,EAAOlB,IAAI,qBACX2B,IACA/B,EAAa+E,OAAOf,EACxB,EAiD+BS,UAAU,EAAOC,cAAc,KAGvDV,CACX,C","sources":["webpack://@avatijs/debounce/webpack/bootstrap","webpack://@avatijs/debounce/webpack/runtime/define property getters","webpack://@avatijs/debounce/webpack/runtime/hasOwnProperty shorthand","webpack://@avatijs/debounce/./src/debouce.ts"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","/**\n * Advanced debounce utility with TypeScript support\n * Provides a way to limit the rate at which a function can fire by delaying its execution\n * until after a specified amount of time has elapsed since its last invocation.\n * @module debounce\n */\n\n/**\n * Timer ID type returned by setTimeout\n * Used for managing timers internally\n */\ntype TimerId = ReturnType<typeof setTimeout>;\n\n/**\n * Generic function type that can accept any arguments and return any value\n * Used as a constraint for functions that can be debounced\n */\ntype AnyFunction = (...args: any[]) => any;\n\n/**\n * Configuration options for the debounce function\n * @interface DebounceOptions\n */\ninterface DebounceOptions {\n /** Number of milliseconds to delay execution (default: 0) */\n readonly wait?: number;\n /** Whether to execute on the leading edge of the timeout (default: false) */\n readonly leading?: boolean;\n /** Whether to execute on the trailing edge of the timeout (default: true) */\n readonly trailing?: boolean;\n /** Maximum time the function can be delayed before forced execution */\n readonly maxWait?: number;\n /** Enable debug logging for troubleshooting */\n readonly debug?: boolean;\n /** AbortController signal for cancellation */\n readonly signal?: AbortSignal;\n\n onError?: (error: Error) => void;\n}\n\n/**\n * Interface for the debounced function, including utility methods\n * @interface DebouncedFunction\n * @template T - The type of the original function\n */\ninterface DebouncedFunction<T extends AnyFunction> {\n /** Cancels any pending function invocations */\n readonly cancel: () => void;\n /** Immediately executes any pending function call */\n readonly flush: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;\n /** Checks if there are any pending invocations */\n readonly pending: () => boolean;\n /** Cleans up resources used by the debounced function */\n readonly cleanup: () => void;\n\n /** The debounced function that wraps the original */\n (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;\n}\n\n/**\n * Internal state management for the debounced function\n * @interface PrivateState\n * @template T - The type of the original function\n * @private\n */\ninterface PrivateState<T extends AnyFunction> {\n /** Current timer ID for the debounce delay */\n timerId?: TimerId;\n /** Timer ID for the maximum wait limit */\n maxTimerId?: TimerId;\n /** Timestamp of the last function call */\n lastCallTime?: number;\n /** Timestamp of the last successful function invocation */\n lastInvokeTime: number;\n /** Arguments from the most recent function call */\n lastArgs?: Parameters<T>;\n /** Execution context (this) from the most recent call */\n lastThis?: any;\n /** Result from the last function execution */\n result?: Awaited<ReturnType<T>>;\n /** Array of pending promises waiting for resolution */\n pendingPromises: Array<{\n resolve: (value: Awaited<ReturnType<T>>) => void;\n reject: (reason?: any) => void;\n }>;\n /** Flag indicating if the function has been aborted */\n aborted: boolean;\n}\n\n/** WeakMap to store private state for each debounced function */\nconst privateState = new WeakMap<DebouncedFunction<any>, PrivateState<any>>();\n\n/**\n * Creates a logger instance based on debug flag\n * @param debug - Whether debug logging is enabled\n * @returns Object with logging methods\n * @private\n */\nconst createLogger = (debug: boolean) => ({\n log: (...args: any[]) => debug && console.log('[Debounce]', ...args),\n warn: (...args: any[]) => debug && console.warn('[Debounce]', ...args),\n error: (...args: any[]) => debug && console.error('[Debounce]', ...args),\n});\n\n/**\n * Creates a debounced version of the provided function that delays invoking func until after\n * wait milliseconds have elapsed since the last time the debounced function was invoked.\n *\n * @template T - The type of the function to debounce\n * @param {T} func - The function to debounce\n * @param {DebounceOptions} [options={}] - Configuration options\n * @returns {DebouncedFunction<T>} The debounced function\n * @throws {TypeError} If func is not a function\n * @throws {RangeError} If wait or maxWait values are invalid\n * @throws {Error} If neither leading nor trailing is true\n *\n * @example\n * const debouncedFn = debounce(async (x: number) => x * 2, { wait: 1000 });\n * await debouncedFn(5); // Will execute after 1000ms of inactivity\n * const debouncedFn = debounce(\n * async (x: number) => x * 2,\n * {\n * wait: 1000,\n * onError: (error) => console.error('Error in debounced function:', error)\n * }\n * );\n */\nfunction debounce<T extends AnyFunction>(\n func: T,\n options: DebounceOptions = {},\n): DebouncedFunction<T> {\n // Input validation\n if (typeof func !== 'function') {\n throw new TypeError('Expected a function');\n }\n\n const {\n wait = 0,\n leading = false,\n trailing = true,\n maxWait,\n debug = false,\n signal,\n onError,\n } = options;\n\n // Validate options\n if (wait < 0 || (maxWait !== undefined && maxWait < wait)) {\n throw new RangeError('Invalid wait/maxWait values');\n }\n\n if (!leading && !trailing) {\n throw new Error('At least one of leading or trailing must be true');\n }\n\n const logger = createLogger(debug);\n const state: PrivateState<T> = {\n lastInvokeTime: 0,\n pendingPromises: [],\n aborted: false,\n };\n\n // Setup abort controller handling\n if (signal) {\n signal.addEventListener('abort', () => {\n state.aborted = true;\n cancel();\n });\n }\n\n /**\n * Cancels all active timers\n * @private\n */\n function cancelTimers(): void {\n if (state.timerId !== undefined) {\n clearTimeout(state.timerId);\n state.timerId = undefined;\n logger.log('Cleared debounce timer');\n }\n if (state.maxTimerId !== undefined) {\n clearTimeout(state.maxTimerId);\n state.maxTimerId = undefined;\n logger.log('Cleared max wait timer');\n }\n }\n\n /**\n * Cancels any pending function invocations\n * Rejects all pending promises and resets internal state\n */\n function cancel(): void {\n logger.log('Cancelling pending invocations');\n cancelTimers();\n state.lastInvokeTime = 0;\n state.lastArgs = undefined;\n state.lastThis = undefined;\n state.lastCallTime = undefined;\n const error = new Error('Debounced function cancelled');\n handleError(error);\n state.pendingPromises.forEach(({ reject }) =>\n reject(new Error('Debounced function cancelled')),\n );\n state.pendingPromises = [];\n }\n\n /**\n * Handles errors during function execution\n * @param {Error} error - The error that occurred\n * @private\n */\n function handleError(error: Error): void {\n logger.error('Error occurred:', error);\n if (onError) {\n try {\n onError(error);\n } catch (callbackError) {\n logger.error('Error in onError callback:', callbackError);\n }\n }\n }\n\n /**\n * Checks if there are any pending function invocations\n * @returns {boolean} True if there are pending invocations\n */\n function pending(): boolean {\n return state.timerId !== undefined;\n }\n\n /**\n * Determines if the function should be invoked based on timing conditions\n * @param {number} time - Current timestamp\n * @returns {boolean} True if function should be invoked\n * @private\n */\n function shouldInvoke(time: number): boolean {\n if (state.aborted) return false;\n\n const timeSinceLastCall = state.lastCallTime === undefined ? 0 : time - state.lastCallTime;\n const timeSinceLastInvoke = time - state.lastInvokeTime;\n\n return (\n state.lastCallTime === undefined ||\n timeSinceLastCall >= wait ||\n timeSinceLastCall < 0 ||\n (maxWait !== undefined && timeSinceLastInvoke >= maxWait)\n );\n }\n\n /**\n * Executes the underlying function and manages promise resolution\n * @param {number} time - Current timestamp\n * @returns {Promise} Promise resolving to function result\n * @private\n */\n async function invokeFunc(time: number): Promise<Awaited<ReturnType<T>> | void> {\n logger.log(`Invoking function at ${time}`);\n state.lastInvokeTime = time;\n const args = state.lastArgs!;\n const thisArg = state.lastThis;\n\n state.lastArgs = undefined;\n state.lastThis = undefined;\n\n try {\n const result = await func.apply(thisArg, args);\n state.result = result;\n state.pendingPromises.forEach(({ resolve }) => resolve(result));\n state.pendingPromises = [];\n logger.log('Function invoked successfully', result);\n return result;\n } catch (error) {\n const wrappedError = error instanceof Error ? error : new Error(String(error));\n logger.error('Error in function invocation:', wrappedError);\n handleError(wrappedError);\n\n // Clear pending promises after handling error\n const currentPromises = [...state.pendingPromises];\n state.pendingPromises = [];\n\n // Reject all pending promises\n currentPromises.forEach(({ reject }) => reject(wrappedError));\n }\n }\n\n /**\n * Starts both the debounce timer and maxWait timer if configured\n * @param {number} time - Current timestamp\n * @private\n */\n function startTimer(time: number): void {\n const remainingTime = remainingWait(time);\n state.timerId = setTimeout(timerExpired, remainingTime);\n logger.log(`Started debounce timer for ${remainingTime}ms`);\n\n if (maxWait !== undefined && !state.maxTimerId) {\n const timeToMaxWait = maxWait - (time - state.lastCallTime!);\n state.maxTimerId = setTimeout(\n () => {\n logger.log('Max wait timer expired');\n cancelTimers();\n invokeFunc(Date.now());\n },\n Math.max(0, timeToMaxWait),\n );\n logger.log(`Started max wait timer for ${timeToMaxWait}ms`);\n }\n }\n\n /**\n * Calculates remaining wait time before next execution\n * @param {number} time - Current timestamp\n * @returns {number} Milliseconds until next allowed execution\n * @private\n */\n function remainingWait(time: number): number {\n const timeSinceLastCall = state.lastCallTime ? time - state.lastCallTime : 0;\n return Math.max(0, wait - timeSinceLastCall);\n }\n\n /**\n * Handles timer expiration\n * @private\n */\n function timerExpired(): void {\n const time = Date.now();\n logger.log('Debounce timer expired');\n\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n\n startTimer(time);\n }\n\n /**\n * Handles leading edge execution\n * @param {number} time - Current timestamp\n * @private\n */\n function leadingEdge(time: number): void {\n logger.log('Leading edge triggered');\n state.lastInvokeTime = time;\n startTimer(time);\n\n if (leading) {\n invokeFunc(time);\n }\n }\n\n /**\n * Handles trailing edge execution\n * @param {number} time - Current timestamp\n * @private\n */\n function trailingEdge(time: number): void {\n logger.log('Trailing edge triggered');\n cancelTimers();\n\n if (trailing && state.lastArgs) {\n invokeFunc(time);\n } else {\n state.pendingPromises.forEach(({ resolve }) => {\n resolve(state.result as Awaited<ReturnType<T>>);\n });\n state.pendingPromises = [];\n }\n }\n\n /**\n * Immediately executes the debounced function\n * @param {...Parameters<T>} args - Function arguments\n * @returns {Promise<ReturnType<T>>} Promise resolving to function result\n */\n async function flush(...args: Parameters<T>): Promise<Awaited<ReturnType<T>> | void> {\n logger.log('Flush requested');\n const argsToUse = args.length > 0 ? args : state.lastArgs;\n const thisArg = state.lastThis;\n\n cancelTimers();\n\n if (argsToUse) {\n state.lastArgs = argsToUse;\n state.lastThis = thisArg;\n return invokeFunc(Date.now());\n }\n\n return Promise.resolve(state.result!);\n }\n\n /**\n * Cleans up resources used by the debounced function\n */\n function cleanup(): void {\n logger.log('Cleanup initiated');\n cancel();\n privateState.delete(debounced);\n }\n\n /**\n * The debounced function that wraps the original\n * @param {...Parameters<T>} args - Function arguments\n * @returns {Promise<ReturnType<T>>} Promise resolving to function result\n */\n const debounced = function(\n this: any,\n ...args: Parameters<T>\n ): Promise<Awaited<ReturnType<T>>> {\n if (state.aborted) {\n return Promise.reject(new Error('Debounced function aborted'));\n }\n\n const time = Date.now();\n const isInvoking = shouldInvoke(time);\n\n state.lastArgs = args;\n state.lastThis = this;\n state.lastCallTime = time;\n\n logger.log('Function called', {\n time,\n isInvoking,\n args,\n pending: pending(),\n });\n\n return new Promise((resolve, reject) => {\n state.pendingPromises.push({ resolve, reject });\n\n if (state.timerId === undefined) {\n leadingEdge(time);\n } else {\n cancelTimers();\n startTimer(time);\n }\n });\n } as DebouncedFunction<T>;\n\n // Store private state\n privateState.set(debounced, state);\n\n // Add utility methods\n Object.defineProperties(debounced, {\n cancel: { value: cancel, writable: false, configurable: false },\n flush: { value: flush, writable: false, configurable: false },\n pending: { value: pending, writable: false, configurable: false },\n cleanup: { value: cleanup, writable: false, configurable: false },\n });\n\n return debounced;\n}\n\nexport { debounce, type DebouncedFunction, type DebounceOptions };\n"],"names":["__webpack_require__","exports","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","privateState","WeakMap","createLogger","debug","log","args","console","warn","error","debounce","func","options","TypeError","wait","leading","trailing","maxWait","signal","onError","undefined","RangeError","Error","logger","state","lastInvokeTime","pendingPromises","aborted","cancelTimers","timerId","clearTimeout","maxTimerId","cancel","lastArgs","lastThis","lastCallTime","handleError","forEach","reject","callbackError","pending","shouldInvoke","time","timeSinceLastCall","async","invokeFunc","thisArg","result","apply","resolve","wrappedError","String","currentPromises","startTimer","remainingTime","Math","max","remainingWait","setTimeout","timerExpired","timeToMaxWait","Date","now","trailingEdge","addEventListener","debounced","Promise","isInvoking","this","push","leadingEdge","set","defineProperties","value","writable","configurable","flush","argsToUse","length","cleanup","delete"],"sourceRoot":""}
@@ -0,0 +1 @@
1
+ export * from './debouce';
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Advanced debounce utility with TypeScript support
3
+ * Provides a way to limit the rate at which a function can fire by delaying its execution
4
+ * until after a specified amount of time has elapsed since its last invocation.
5
+ * @module debounce
6
+ */
7
+ /**
8
+ * Generic function type that can accept any arguments and return any value
9
+ * Used as a constraint for functions that can be debounced
10
+ */
11
+ type AnyFunction = (...args: any[]) => any;
12
+ /**
13
+ * Configuration options for the debounce function
14
+ * @interface DebounceOptions
15
+ */
16
+ interface DebounceOptions {
17
+ /** Number of milliseconds to delay execution (default: 0) */
18
+ readonly wait?: number;
19
+ /** Whether to execute on the leading edge of the timeout (default: false) */
20
+ readonly leading?: boolean;
21
+ /** Whether to execute on the trailing edge of the timeout (default: true) */
22
+ readonly trailing?: boolean;
23
+ /** Maximum time the function can be delayed before forced execution */
24
+ readonly maxWait?: number;
25
+ /** Enable debug logging for troubleshooting */
26
+ readonly debug?: boolean;
27
+ /** AbortController signal for cancellation */
28
+ readonly signal?: AbortSignal;
29
+ onError?: (error: Error) => void;
30
+ }
31
+ /**
32
+ * Interface for the debounced function, including utility methods
33
+ * @interface DebouncedFunction
34
+ * @template T - The type of the original function
35
+ */
36
+ interface DebouncedFunction<T extends AnyFunction> {
37
+ /** Cancels any pending function invocations */
38
+ readonly cancel: () => void;
39
+ /** Immediately executes any pending function call */
40
+ readonly flush: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;
41
+ /** Checks if there are any pending invocations */
42
+ readonly pending: () => boolean;
43
+ /** Cleans up resources used by the debounced function */
44
+ readonly cleanup: () => void;
45
+ /** The debounced function that wraps the original */
46
+ (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
47
+ }
48
+ /**
49
+ * Creates a debounced version of the provided function that delays invoking func until after
50
+ * wait milliseconds have elapsed since the last time the debounced function was invoked.
51
+ *
52
+ * @template T - The type of the function to debounce
53
+ * @param {T} func - The function to debounce
54
+ * @param {DebounceOptions} [options={}] - Configuration options
55
+ * @returns {DebouncedFunction<T>} The debounced function
56
+ * @throws {TypeError} If func is not a function
57
+ * @throws {RangeError} If wait or maxWait values are invalid
58
+ * @throws {Error} If neither leading nor trailing is true
59
+ *
60
+ * @example
61
+ * const debouncedFn = debounce(async (x: number) => x * 2, { wait: 1000 });
62
+ * await debouncedFn(5); // Will execute after 1000ms of inactivity
63
+ * const debouncedFn = debounce(
64
+ * async (x: number) => x * 2,
65
+ * {
66
+ * wait: 1000,
67
+ * onError: (error) => console.error('Error in debounced function:', error)
68
+ * }
69
+ * );
70
+ */
71
+ declare function debounce<T extends AnyFunction>(func: T, options?: DebounceOptions): DebouncedFunction<T>;
72
+ export { debounce, type DebouncedFunction, type DebounceOptions };
@@ -0,0 +1 @@
1
+ export * from './debouce';
@@ -0,0 +1,8 @@
1
+ /*!
2
+ * @avatijs/debounce 0.1.1
3
+ * Copyright (c) 2024 Khaled Sameer <khaled.smq@hotmail.com>
4
+ * Licensed under MIT, https://opensource.org/licenses/MIT/
5
+ * Please visit https://avati.io/ for details.
6
+ */
7
+ !function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("Avati",[],n):"object"==typeof exports?exports.Avati=n():e.Avati=n()}("undefined"!=typeof self?self:this,(()=>(()=>{"use strict";var e={d:(n,o)=>{for(var t in o)e.o(o,t)&&!e.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:o[t]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"t",{value:!0})}},n={};e.r(n),e.d(n,{debounce:()=>i});const o=new WeakMap,t=e=>({log:(...n)=>e&&void 0,warn:(...n)=>e&&void 0,error:(...n)=>e&&void 0});function i(e,n={}){if("function"!=typeof e)throw new TypeError("Expected a function");const{wait:i=0,leading:r=!1,trailing:c=!0,maxWait:a,debug:u=!1,signal:d,onError:l}=n;if(0>i||void 0!==a&&i>a)throw new RangeError("Invalid wait/maxWait values");if(!r&&!c)throw Error("At least one of leading or trailing must be true");const f=t(u),s={lastInvokeTime:0,pendingPromises:[],aborted:!1};function v(){void 0!==s.timerId&&(clearTimeout(s.timerId),s.timerId=void 0,f.log("Cleared debounce timer")),void 0!==s.maxTimerId&&(clearTimeout(s.maxTimerId),s.maxTimerId=void 0,f.log("Cleared max wait timer"))}function b(){f.log("Cancelling pending invocations"),v(),s.lastInvokeTime=0,s.lastArgs=void 0,s.lastThis=void 0,s.lastCallTime=void 0,g(Error("Debounced function cancelled")),s.pendingPromises.forEach((({reject:e})=>e(Error("Debounced function cancelled")))),s.pendingPromises=[]}function g(e){if(f.error("Error occurred:",e),l)try{l(e)}catch(e){f.error("Error in onError callback:",e)}}function m(){return void 0!==s.timerId}function p(e){if(s.aborted)return!1;const n=void 0===s.lastCallTime?0:e-s.lastCallTime;return void 0===s.lastCallTime||n>=i||0>n||void 0!==a&&e-s.lastInvokeTime>=a}async function w(n){f.log("Invoking function at "+n),s.lastInvokeTime=n;const o=s.lastArgs,t=s.lastThis;s.lastArgs=void 0,s.lastThis=void 0;try{const n=await e.apply(t,o);return s.result=n,s.pendingPromises.forEach((({resolve:e})=>e(n))),s.pendingPromises=[],f.log("Function invoked successfully",n),n}catch(e){const n=e instanceof Error?e:Error(e+"");f.error("Error in function invocation:",n),g(n);const o=[...s.pendingPromises];s.pendingPromises=[],o.forEach((({reject:e})=>e(n)))}}function y(e){const n=function(e){return Math.max(0,i-(s.lastCallTime?e-s.lastCallTime:0))}(e);if(s.timerId=setTimeout(E,n),f.log(`Started debounce timer for ${n}ms`),void 0!==a&&!s.maxTimerId){const n=a-(e-s.lastCallTime);s.maxTimerId=setTimeout((()=>{f.log("Max wait timer expired"),v(),w(Date.now())}),Math.max(0,n)),f.log(`Started max wait timer for ${n}ms`)}}function E(){const e=Date.now();if(f.log("Debounce timer expired"),p(e))return function(e){f.log("Trailing edge triggered"),v(),c&&s.lastArgs?w(e):(s.pendingPromises.forEach((({resolve:e})=>{e(s.result)})),s.pendingPromises=[])}(e);y(e)}d&&d.addEventListener("abort",(()=>{s.aborted=!0,b()}));const h=function(...e){if(s.aborted)return Promise.reject(Error("Debounced function aborted"));const n=Date.now(),o=p(n);return s.lastArgs=e,s.lastThis=this,s.lastCallTime=n,f.log("Function called",{time:n,isInvoking:o,args:e,pending:m()}),new Promise(((e,o)=>{s.pendingPromises.push({resolve:e,reject:o}),void 0===s.timerId?function(e){f.log("Leading edge triggered"),s.lastInvokeTime=e,y(e),r&&w(e)}(n):(v(),y(n))}))};return o.set(h,s),Object.defineProperties(h,{cancel:{value:b,writable:!1,configurable:!1},flush:{value:async function(...e){f.log("Flush requested");const n=e.length>0?e:s.lastArgs,o=s.lastThis;return v(),n?(s.lastArgs=n,s.lastThis=o,w(Date.now())):Promise.resolve(s.result)},writable:!1,configurable:!1},pending:{value:m,writable:!1,configurable:!1},cleanup:{value:function(){f.log("Cleanup initiated"),b(),o.delete(h)},writable:!1,configurable:!1}}),h}return n})()));
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","mappings":"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","sources":["webpack://Avati/webpack/universalModuleDefinition","webpack://Avati/webpack/bootstrap","webpack://Avati/webpack/runtime/define property getters","webpack://Avati/webpack/runtime/hasOwnProperty shorthand","webpack://Avati/webpack/runtime/make namespace object","webpack://Avati/./src/debouce.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"Avati\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"Avati\"] = factory();\n\telse\n\t\troot[\"Avati\"] = factory();\n})(typeof self !== 'undefined' ? self : this, () => {\nreturn ","// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Advanced debounce utility with TypeScript support\n * Provides a way to limit the rate at which a function can fire by delaying its execution\n * until after a specified amount of time has elapsed since its last invocation.\n * @module debounce\n */\n\n/**\n * Timer ID type returned by setTimeout\n * Used for managing timers internally\n */\ntype TimerId = ReturnType<typeof setTimeout>;\n\n/**\n * Generic function type that can accept any arguments and return any value\n * Used as a constraint for functions that can be debounced\n */\ntype AnyFunction = (...args: any[]) => any;\n\n/**\n * Configuration options for the debounce function\n * @interface DebounceOptions\n */\ninterface DebounceOptions {\n /** Number of milliseconds to delay execution (default: 0) */\n readonly wait?: number;\n /** Whether to execute on the leading edge of the timeout (default: false) */\n readonly leading?: boolean;\n /** Whether to execute on the trailing edge of the timeout (default: true) */\n readonly trailing?: boolean;\n /** Maximum time the function can be delayed before forced execution */\n readonly maxWait?: number;\n /** Enable debug logging for troubleshooting */\n readonly debug?: boolean;\n /** AbortController signal for cancellation */\n readonly signal?: AbortSignal;\n\n onError?: (error: Error) => void;\n}\n\n/**\n * Interface for the debounced function, including utility methods\n * @interface DebouncedFunction\n * @template T - The type of the original function\n */\ninterface DebouncedFunction<T extends AnyFunction> {\n /** Cancels any pending function invocations */\n readonly cancel: () => void;\n /** Immediately executes any pending function call */\n readonly flush: (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;\n /** Checks if there are any pending invocations */\n readonly pending: () => boolean;\n /** Cleans up resources used by the debounced function */\n readonly cleanup: () => void;\n\n /** The debounced function that wraps the original */\n (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;\n}\n\n/**\n * Internal state management for the debounced function\n * @interface PrivateState\n * @template T - The type of the original function\n * @private\n */\ninterface PrivateState<T extends AnyFunction> {\n /** Current timer ID for the debounce delay */\n timerId?: TimerId;\n /** Timer ID for the maximum wait limit */\n maxTimerId?: TimerId;\n /** Timestamp of the last function call */\n lastCallTime?: number;\n /** Timestamp of the last successful function invocation */\n lastInvokeTime: number;\n /** Arguments from the most recent function call */\n lastArgs?: Parameters<T>;\n /** Execution context (this) from the most recent call */\n lastThis?: any;\n /** Result from the last function execution */\n result?: Awaited<ReturnType<T>>;\n /** Array of pending promises waiting for resolution */\n pendingPromises: Array<{\n resolve: (value: Awaited<ReturnType<T>>) => void;\n reject: (reason?: any) => void;\n }>;\n /** Flag indicating if the function has been aborted */\n aborted: boolean;\n}\n\n/** WeakMap to store private state for each debounced function */\nconst privateState = new WeakMap<DebouncedFunction<any>, PrivateState<any>>();\n\n/**\n * Creates a logger instance based on debug flag\n * @param debug - Whether debug logging is enabled\n * @returns Object with logging methods\n * @private\n */\nconst createLogger = (debug: boolean) => ({\n log: (...args: any[]) => debug && console.log('[Debounce]', ...args),\n warn: (...args: any[]) => debug && console.warn('[Debounce]', ...args),\n error: (...args: any[]) => debug && console.error('[Debounce]', ...args),\n});\n\n/**\n * Creates a debounced version of the provided function that delays invoking func until after\n * wait milliseconds have elapsed since the last time the debounced function was invoked.\n *\n * @template T - The type of the function to debounce\n * @param {T} func - The function to debounce\n * @param {DebounceOptions} [options={}] - Configuration options\n * @returns {DebouncedFunction<T>} The debounced function\n * @throws {TypeError} If func is not a function\n * @throws {RangeError} If wait or maxWait values are invalid\n * @throws {Error} If neither leading nor trailing is true\n *\n * @example\n * const debouncedFn = debounce(async (x: number) => x * 2, { wait: 1000 });\n * await debouncedFn(5); // Will execute after 1000ms of inactivity\n * const debouncedFn = debounce(\n * async (x: number) => x * 2,\n * {\n * wait: 1000,\n * onError: (error) => console.error('Error in debounced function:', error)\n * }\n * );\n */\nfunction debounce<T extends AnyFunction>(\n func: T,\n options: DebounceOptions = {},\n): DebouncedFunction<T> {\n // Input validation\n if (typeof func !== 'function') {\n throw new TypeError('Expected a function');\n }\n\n const {\n wait = 0,\n leading = false,\n trailing = true,\n maxWait,\n debug = false,\n signal,\n onError,\n } = options;\n\n // Validate options\n if (wait < 0 || (maxWait !== undefined && maxWait < wait)) {\n throw new RangeError('Invalid wait/maxWait values');\n }\n\n if (!leading && !trailing) {\n throw new Error('At least one of leading or trailing must be true');\n }\n\n const logger = createLogger(debug);\n const state: PrivateState<T> = {\n lastInvokeTime: 0,\n pendingPromises: [],\n aborted: false,\n };\n\n // Setup abort controller handling\n if (signal) {\n signal.addEventListener('abort', () => {\n state.aborted = true;\n cancel();\n });\n }\n\n /**\n * Cancels all active timers\n * @private\n */\n function cancelTimers(): void {\n if (state.timerId !== undefined) {\n clearTimeout(state.timerId);\n state.timerId = undefined;\n logger.log('Cleared debounce timer');\n }\n if (state.maxTimerId !== undefined) {\n clearTimeout(state.maxTimerId);\n state.maxTimerId = undefined;\n logger.log('Cleared max wait timer');\n }\n }\n\n /**\n * Cancels any pending function invocations\n * Rejects all pending promises and resets internal state\n */\n function cancel(): void {\n logger.log('Cancelling pending invocations');\n cancelTimers();\n state.lastInvokeTime = 0;\n state.lastArgs = undefined;\n state.lastThis = undefined;\n state.lastCallTime = undefined;\n const error = new Error('Debounced function cancelled');\n handleError(error);\n state.pendingPromises.forEach(({ reject }) =>\n reject(new Error('Debounced function cancelled')),\n );\n state.pendingPromises = [];\n }\n\n /**\n * Handles errors during function execution\n * @param {Error} error - The error that occurred\n * @private\n */\n function handleError(error: Error): void {\n logger.error('Error occurred:', error);\n if (onError) {\n try {\n onError(error);\n } catch (callbackError) {\n logger.error('Error in onError callback:', callbackError);\n }\n }\n }\n\n /**\n * Checks if there are any pending function invocations\n * @returns {boolean} True if there are pending invocations\n */\n function pending(): boolean {\n return state.timerId !== undefined;\n }\n\n /**\n * Determines if the function should be invoked based on timing conditions\n * @param {number} time - Current timestamp\n * @returns {boolean} True if function should be invoked\n * @private\n */\n function shouldInvoke(time: number): boolean {\n if (state.aborted) return false;\n\n const timeSinceLastCall = state.lastCallTime === undefined ? 0 : time - state.lastCallTime;\n const timeSinceLastInvoke = time - state.lastInvokeTime;\n\n return (\n state.lastCallTime === undefined ||\n timeSinceLastCall >= wait ||\n timeSinceLastCall < 0 ||\n (maxWait !== undefined && timeSinceLastInvoke >= maxWait)\n );\n }\n\n /**\n * Executes the underlying function and manages promise resolution\n * @param {number} time - Current timestamp\n * @returns {Promise} Promise resolving to function result\n * @private\n */\n async function invokeFunc(time: number): Promise<Awaited<ReturnType<T>> | void> {\n logger.log(`Invoking function at ${time}`);\n state.lastInvokeTime = time;\n const args = state.lastArgs!;\n const thisArg = state.lastThis;\n\n state.lastArgs = undefined;\n state.lastThis = undefined;\n\n try {\n const result = await func.apply(thisArg, args);\n state.result = result;\n state.pendingPromises.forEach(({ resolve }) => resolve(result));\n state.pendingPromises = [];\n logger.log('Function invoked successfully', result);\n return result;\n } catch (error) {\n const wrappedError = error instanceof Error ? error : new Error(String(error));\n logger.error('Error in function invocation:', wrappedError);\n handleError(wrappedError);\n\n // Clear pending promises after handling error\n const currentPromises = [...state.pendingPromises];\n state.pendingPromises = [];\n\n // Reject all pending promises\n currentPromises.forEach(({ reject }) => reject(wrappedError));\n }\n }\n\n /**\n * Starts both the debounce timer and maxWait timer if configured\n * @param {number} time - Current timestamp\n * @private\n */\n function startTimer(time: number): void {\n const remainingTime = remainingWait(time);\n state.timerId = setTimeout(timerExpired, remainingTime);\n logger.log(`Started debounce timer for ${remainingTime}ms`);\n\n if (maxWait !== undefined && !state.maxTimerId) {\n const timeToMaxWait = maxWait - (time - state.lastCallTime!);\n state.maxTimerId = setTimeout(\n () => {\n logger.log('Max wait timer expired');\n cancelTimers();\n invokeFunc(Date.now());\n },\n Math.max(0, timeToMaxWait),\n );\n logger.log(`Started max wait timer for ${timeToMaxWait}ms`);\n }\n }\n\n /**\n * Calculates remaining wait time before next execution\n * @param {number} time - Current timestamp\n * @returns {number} Milliseconds until next allowed execution\n * @private\n */\n function remainingWait(time: number): number {\n const timeSinceLastCall = state.lastCallTime ? time - state.lastCallTime : 0;\n return Math.max(0, wait - timeSinceLastCall);\n }\n\n /**\n * Handles timer expiration\n * @private\n */\n function timerExpired(): void {\n const time = Date.now();\n logger.log('Debounce timer expired');\n\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n\n startTimer(time);\n }\n\n /**\n * Handles leading edge execution\n * @param {number} time - Current timestamp\n * @private\n */\n function leadingEdge(time: number): void {\n logger.log('Leading edge triggered');\n state.lastInvokeTime = time;\n startTimer(time);\n\n if (leading) {\n invokeFunc(time);\n }\n }\n\n /**\n * Handles trailing edge execution\n * @param {number} time - Current timestamp\n * @private\n */\n function trailingEdge(time: number): void {\n logger.log('Trailing edge triggered');\n cancelTimers();\n\n if (trailing && state.lastArgs) {\n invokeFunc(time);\n } else {\n state.pendingPromises.forEach(({ resolve }) => {\n resolve(state.result as Awaited<ReturnType<T>>);\n });\n state.pendingPromises = [];\n }\n }\n\n /**\n * Immediately executes the debounced function\n * @param {...Parameters<T>} args - Function arguments\n * @returns {Promise<ReturnType<T>>} Promise resolving to function result\n */\n async function flush(...args: Parameters<T>): Promise<Awaited<ReturnType<T>> | void> {\n logger.log('Flush requested');\n const argsToUse = args.length > 0 ? args : state.lastArgs;\n const thisArg = state.lastThis;\n\n cancelTimers();\n\n if (argsToUse) {\n state.lastArgs = argsToUse;\n state.lastThis = thisArg;\n return invokeFunc(Date.now());\n }\n\n return Promise.resolve(state.result!);\n }\n\n /**\n * Cleans up resources used by the debounced function\n */\n function cleanup(): void {\n logger.log('Cleanup initiated');\n cancel();\n privateState.delete(debounced);\n }\n\n /**\n * The debounced function that wraps the original\n * @param {...Parameters<T>} args - Function arguments\n * @returns {Promise<ReturnType<T>>} Promise resolving to function result\n */\n const debounced = function(\n this: any,\n ...args: Parameters<T>\n ): Promise<Awaited<ReturnType<T>>> {\n if (state.aborted) {\n return Promise.reject(new Error('Debounced function aborted'));\n }\n\n const time = Date.now();\n const isInvoking = shouldInvoke(time);\n\n state.lastArgs = args;\n state.lastThis = this;\n state.lastCallTime = time;\n\n logger.log('Function called', {\n time,\n isInvoking,\n args,\n pending: pending(),\n });\n\n return new Promise((resolve, reject) => {\n state.pendingPromises.push({ resolve, reject });\n\n if (state.timerId === undefined) {\n leadingEdge(time);\n } else {\n cancelTimers();\n startTimer(time);\n }\n });\n } as DebouncedFunction<T>;\n\n // Store private state\n privateState.set(debounced, state);\n\n // Add utility methods\n Object.defineProperties(debounced, {\n cancel: { value: cancel, writable: false, configurable: false },\n flush: { value: flush, writable: false, configurable: false },\n pending: { value: pending, writable: false, configurable: false },\n cleanup: { value: cleanup, writable: false, configurable: false },\n });\n\n return debounced;\n}\n\nexport { debounce, type DebouncedFunction, type DebounceOptions };\n"],"names":["root","factory","exports","module","define","amd","self","this","__webpack_require__","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","Symbol","toStringTag","value","privateState","WeakMap","createLogger","debug","log","args","console","warn","error","debounce","func","options","TypeError","wait","leading","trailing","maxWait","signal","onError","undefined","RangeError","Error","logger","state","lastInvokeTime","pendingPromises","aborted","cancelTimers","timerId","clearTimeout","maxTimerId","cancel","lastArgs","lastThis","lastCallTime","handleError","forEach","reject","callbackError","pending","shouldInvoke","time","timeSinceLastCall","async","invokeFunc","thisArg","result","apply","resolve","wrappedError","String","currentPromises","startTimer","remainingTime","Math","max","remainingWait","setTimeout","timerExpired","timeToMaxWait","Date","now","trailingEdge","addEventListener","debounced","Promise","isInvoking","push","leadingEdge","set","defineProperties","writable","configurable","flush","argsToUse","length","cleanup","delete"],"sourceRoot":""}
package/package.json ADDED
@@ -0,0 +1,135 @@
1
+ {
2
+ "name": "@avatijs/debounce",
3
+ "version": "0.1.1",
4
+ "description": "Debounce package part of Avati project",
5
+ "main": "./dist/cjs/index.js",
6
+ "module": "./dist/esm/index.js",
7
+ "types": "./dist/types/index.d.ts",
8
+ "browser": "./dist/umd/index.js",
9
+ "unpkg": "./dist/umd/index.min.js",
10
+ "jsdelivr": "./dist/umd/index.min.js",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/types/index.d.ts",
14
+ "import": "./dist/esm/index.js",
15
+ "require": "./dist/cjs/index.js",
16
+ "default": "./dist/umd/index.js"
17
+ },
18
+ "./package.json": "./package.json"
19
+ },
20
+ "sideEffects": false,
21
+ "engines": {
22
+ "node": ">=14.0.0"
23
+ },
24
+ "bundlesize": [
25
+ {
26
+ "path": "./dist/esm/index.js",
27
+ "maxSize": "3 kB",
28
+ "compression": "brotli"
29
+ },
30
+ {
31
+ "path": "./dist/cjs/index.js",
32
+ "maxSize": "3 kB",
33
+ "compression": "brotli"
34
+ },
35
+ {
36
+ "path": "./dist/umd/*.js",
37
+ "maxSize": "3 kB",
38
+ "compression": "brotli"
39
+ }
40
+ ],
41
+ "scripts": {
42
+ "build": "npm run clean && npm run build:types && npm run build:prod",
43
+ "build:dev": "webpack --mode development --progress",
44
+ "build:prod": "webpack --mode production --progress",
45
+ "build:types": "tsc --emitDeclarationOnly --outDir dist/types",
46
+ "watch": "webpack --mode=development --watch",
47
+ "watch:silent": "webpack --mode=development --watch --silent",
48
+ "clean": "rimraf dist",
49
+ "prepublishOnly": "npm run build",
50
+ "test": "jest",
51
+ "typecheck": "tsc --noEmit",
52
+ "size": "webpack --mode production --json > stats.json && webpack-bundle-analyzer stats.json",
53
+ "analyze:deps": "madge --circular --extensions ts ./src/index.ts",
54
+ "size:check": "bundlesize",
55
+ "size:watch": "bundlesize --watch",
56
+ "size:compression": "bundlesize --compression",
57
+ "analyze": "npm run analyze:size && npm run analyze:deps && npm run analyze:duplicates",
58
+ "analyze:size": "webpack --mode production --json > stats.json && webpack-bundle-analyzer stats.json",
59
+ "analyze:detailed": "webpack --config webpack.analysis.config.js",
60
+ "analyze:duplicates": "jscpd src",
61
+ "analyze:why": "webpack --mode production --display-reasons",
62
+ "analyze:tree": "webpack --mode production --display-used-exports",
63
+ "analyze:modules": "webpack --mode production --display-modules",
64
+ "analyze:full": "webpack --mode production --stats detailed"
65
+ },
66
+ "files": [
67
+ "dist",
68
+ "LICENSE",
69
+ "README.md",
70
+ "CHANGELOG.md"
71
+ ],
72
+ "author": {
73
+ "name": "Khaled Sameer",
74
+ "email": "khaled.smq@hotmail.com",
75
+ "url": "https://khaled.ee/"
76
+ },
77
+ "homepage": "https://avati.io/",
78
+ "bugs": {
79
+ "url": "https://github.com/KhaledSMQ/avati/issues",
80
+ "email": "khaled.smq@hotmail.com"
81
+ },
82
+ "repository": {
83
+ "type": "git",
84
+ "url": "git+https://github.com/KhaledSMQ/avati.git",
85
+ "directory": "packages/debounce"
86
+ },
87
+ "license": "MIT",
88
+ "publishConfig": {
89
+ "access": "public"
90
+ },
91
+ "keywords": [
92
+ "avati",
93
+ "typescript",
94
+ "debounce",
95
+ "debouncer",
96
+ "throttle",
97
+ "throttling",
98
+ "delay",
99
+ "function control",
100
+ "rate limit",
101
+ "rate limiting",
102
+ "utility",
103
+ "helper",
104
+ "JavaScript",
105
+ "timing",
106
+ "event handling",
107
+ "event control",
108
+ "performance",
109
+ "optimization",
110
+ "function delay",
111
+ "input control",
112
+ "API calls"
113
+ ],
114
+ "devDependencies": {
115
+ "@types/jest": "^29.5.14",
116
+ "@types/node": "^22.9.1",
117
+ "@typescript-eslint/eslint-plugin": "^8.15.0",
118
+ "@typescript-eslint/parser": "^8.15.0",
119
+ "bundlesize": "^0.18.2",
120
+ "dependency-cruiser": "^16.6.0",
121
+ "eslint": "^8.57.1",
122
+ "jest": "^29.7.0",
123
+ "jscpd": "^4.0.5",
124
+ "madge": "^8.0.0",
125
+ "rimraf": "^6.0.1",
126
+ "source-map-explorer": "^2.5.3",
127
+ "terser-webpack-plugin": "^5.3.10",
128
+ "ts-jest": "^29.2.5",
129
+ "ts-loader": "^9.5.1",
130
+ "typescript": "^5.6.3",
131
+ "webpack": "^5.96.1",
132
+ "webpack-bundle-analyzer": "^4.10.2",
133
+ "webpack-cli": "^5.1.4"
134
+ }
135
+ }