@avatijs/debounce 0.1.1

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/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":"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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/./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
+ }