@resq-sw/decorators 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/README.md +277 -0
  2. package/lib/_utils.d.ts +46 -0
  3. package/lib/_utils.d.ts.map +1 -0
  4. package/lib/_utils.js +91 -0
  5. package/lib/_utils.js.map +1 -0
  6. package/lib/after/after.d.ts +60 -0
  7. package/lib/after/after.d.ts.map +1 -0
  8. package/lib/after/after.fn.d.ts +39 -0
  9. package/lib/after/after.fn.d.ts.map +1 -0
  10. package/lib/after/after.fn.js +59 -0
  11. package/lib/after/after.fn.js.map +1 -0
  12. package/lib/after/after.js +41 -0
  13. package/lib/after/after.js.map +1 -0
  14. package/lib/after/after.types.d.ts +86 -0
  15. package/lib/after/after.types.d.ts.map +1 -0
  16. package/lib/after/after.types.js +0 -0
  17. package/lib/after/index.d.ts +3 -0
  18. package/lib/after/index.js +2 -0
  19. package/lib/before/before.d.ts +61 -0
  20. package/lib/before/before.d.ts.map +1 -0
  21. package/lib/before/before.fn.d.ts +39 -0
  22. package/lib/before/before.fn.d.ts.map +1 -0
  23. package/lib/before/before.fn.js +51 -0
  24. package/lib/before/before.fn.js.map +1 -0
  25. package/lib/before/before.js +40 -0
  26. package/lib/before/before.js.map +1 -0
  27. package/lib/before/before.types.d.ts +48 -0
  28. package/lib/before/before.types.d.ts.map +1 -0
  29. package/lib/before/before.types.js +0 -0
  30. package/lib/before/index.d.ts +3 -0
  31. package/lib/before/index.js +2 -0
  32. package/lib/bind/bind.d.ts +75 -0
  33. package/lib/bind/bind.d.ts.map +1 -0
  34. package/lib/bind/bind.fn.d.ts +46 -0
  35. package/lib/bind/bind.fn.d.ts.map +1 -0
  36. package/lib/bind/bind.fn.js +39 -0
  37. package/lib/bind/bind.fn.js.map +1 -0
  38. package/lib/bind/bind.js +64 -0
  39. package/lib/bind/bind.js.map +1 -0
  40. package/lib/bind/bind.types.d.ts +36 -0
  41. package/lib/bind/bind.types.d.ts.map +1 -0
  42. package/lib/bind/bind.types.js +0 -0
  43. package/lib/bind/index.d.ts +3 -0
  44. package/lib/bind/index.js +2 -0
  45. package/lib/debounce/debounce.d.ts +34 -0
  46. package/lib/debounce/debounce.d.ts.map +1 -0
  47. package/lib/debounce/debounce.fn.d.ts +40 -0
  48. package/lib/debounce/debounce.fn.d.ts.map +1 -0
  49. package/lib/debounce/debounce.fn.js +47 -0
  50. package/lib/debounce/debounce.fn.js.map +1 -0
  51. package/lib/debounce/debounce.js +48 -0
  52. package/lib/debounce/debounce.js.map +1 -0
  53. package/lib/debounce/index.d.ts +2 -0
  54. package/lib/debounce/index.js +2 -0
  55. package/lib/delay/delay.d.ts +35 -0
  56. package/lib/delay/delay.d.ts.map +1 -0
  57. package/lib/delay/delay.fn.d.ts +33 -0
  58. package/lib/delay/delay.fn.d.ts.map +1 -0
  59. package/lib/delay/delay.fn.js +38 -0
  60. package/lib/delay/delay.fn.js.map +1 -0
  61. package/lib/delay/delay.js +43 -0
  62. package/lib/delay/delay.js.map +1 -0
  63. package/lib/delay/index.d.ts +2 -0
  64. package/lib/delay/index.js +2 -0
  65. package/lib/delegate/delegate.d.ts +48 -0
  66. package/lib/delegate/delegate.d.ts.map +1 -0
  67. package/lib/delegate/delegate.fn.d.ts +57 -0
  68. package/lib/delegate/delegate.fn.d.ts.map +1 -0
  69. package/lib/delegate/delegate.fn.js +55 -0
  70. package/lib/delegate/delegate.fn.js.map +1 -0
  71. package/lib/delegate/delegate.js +56 -0
  72. package/lib/delegate/delegate.js.map +1 -0
  73. package/lib/delegate/delegate.types.d.ts +45 -0
  74. package/lib/delegate/delegate.types.d.ts.map +1 -0
  75. package/lib/delegate/delegate.types.js +0 -0
  76. package/lib/delegate/index.d.ts +3 -0
  77. package/lib/delegate/index.js +2 -0
  78. package/lib/exec-time/exec-time.d.ts +42 -0
  79. package/lib/exec-time/exec-time.d.ts.map +1 -0
  80. package/lib/exec-time/exec-time.fn.d.ts +50 -0
  81. package/lib/exec-time/exec-time.fn.d.ts.map +1 -0
  82. package/lib/exec-time/exec-time.fn.js +91 -0
  83. package/lib/exec-time/exec-time.fn.js.map +1 -0
  84. package/lib/exec-time/exec-time.js +55 -0
  85. package/lib/exec-time/exec-time.js.map +1 -0
  86. package/lib/exec-time/exec-time.types.d.ts +70 -0
  87. package/lib/exec-time/exec-time.types.d.ts.map +1 -0
  88. package/lib/exec-time/exec-time.types.js +0 -0
  89. package/lib/exec-time/index.d.ts +4 -0
  90. package/lib/exec-time/index.js +3 -0
  91. package/lib/execute/execute.d.ts +78 -0
  92. package/lib/execute/execute.d.ts.map +1 -0
  93. package/lib/execute/execute.js +82 -0
  94. package/lib/execute/execute.js.map +1 -0
  95. package/lib/execute/index.d.ts +2 -0
  96. package/lib/execute/index.js +2 -0
  97. package/lib/index.d.ts +30 -0
  98. package/lib/index.js +19 -0
  99. package/lib/memoize/index.d.ts +3 -0
  100. package/lib/memoize/index.js +2 -0
  101. package/lib/memoize/memoize.d.ts +67 -0
  102. package/lib/memoize/memoize.d.ts.map +1 -0
  103. package/lib/memoize/memoize.fn.d.ts +69 -0
  104. package/lib/memoize/memoize.fn.d.ts.map +1 -0
  105. package/lib/memoize/memoize.fn.js +43 -0
  106. package/lib/memoize/memoize.fn.js.map +1 -0
  107. package/lib/memoize/memoize.js +40 -0
  108. package/lib/memoize/memoize.js.map +1 -0
  109. package/lib/memoize/memoize.types.d.ts +107 -0
  110. package/lib/memoize/memoize.types.d.ts.map +1 -0
  111. package/lib/memoize/memoize.types.js +0 -0
  112. package/lib/memoize-async/index.d.ts +4 -0
  113. package/lib/memoize-async/index.js +3 -0
  114. package/lib/memoize-async/memoize-async.d.ts +68 -0
  115. package/lib/memoize-async/memoize-async.d.ts.map +1 -0
  116. package/lib/memoize-async/memoize-async.fn.d.ts +69 -0
  117. package/lib/memoize-async/memoize-async.fn.d.ts.map +1 -0
  118. package/lib/memoize-async/memoize-async.fn.js +52 -0
  119. package/lib/memoize-async/memoize-async.fn.js.map +1 -0
  120. package/lib/memoize-async/memoize-async.js +15 -0
  121. package/lib/memoize-async/memoize-async.js.map +1 -0
  122. package/lib/memoize-async/memoize-async.types.d.ts +74 -0
  123. package/lib/memoize-async/memoize-async.types.d.ts.map +1 -0
  124. package/lib/memoize-async/memoize-async.types.js +0 -0
  125. package/lib/observer/index.d.ts +3 -0
  126. package/lib/observer/index.js +2 -0
  127. package/lib/observer/observer.d.ts +54 -0
  128. package/lib/observer/observer.d.ts.map +1 -0
  129. package/lib/observer/observer.js +85 -0
  130. package/lib/observer/observer.js.map +1 -0
  131. package/lib/observer/observer.types.d.ts +41 -0
  132. package/lib/observer/observer.types.d.ts.map +1 -0
  133. package/lib/observer/observer.types.js +0 -0
  134. package/lib/rate-limit/index.d.ts +4 -0
  135. package/lib/rate-limit/index.js +3 -0
  136. package/lib/rate-limit/rate-limit.d.ts +58 -0
  137. package/lib/rate-limit/rate-limit.d.ts.map +1 -0
  138. package/lib/rate-limit/rate-limit.fn.d.ts +43 -0
  139. package/lib/rate-limit/rate-limit.fn.d.ts.map +1 -0
  140. package/lib/rate-limit/rate-limit.fn.js +56 -0
  141. package/lib/rate-limit/rate-limit.fn.js.map +1 -0
  142. package/lib/rate-limit/rate-limit.js +65 -0
  143. package/lib/rate-limit/rate-limit.js.map +1 -0
  144. package/lib/rate-limit/rate-limit.types.d.ts +148 -0
  145. package/lib/rate-limit/rate-limit.types.d.ts.map +1 -0
  146. package/lib/rate-limit/rate-limit.types.js +0 -0
  147. package/lib/rate-limit/simple-rate-limit-counter.d.ts +89 -0
  148. package/lib/rate-limit/simple-rate-limit-counter.d.ts.map +1 -0
  149. package/lib/rate-limit/simple-rate-limit-counter.js +98 -0
  150. package/lib/rate-limit/simple-rate-limit-counter.js.map +1 -0
  151. package/lib/readonly/index.d.ts +3 -0
  152. package/lib/readonly/index.js +2 -0
  153. package/lib/readonly/readonly.d.ts +39 -0
  154. package/lib/readonly/readonly.d.ts.map +1 -0
  155. package/lib/readonly/readonly.js +43 -0
  156. package/lib/readonly/readonly.js.map +1 -0
  157. package/lib/readonly/readonly.types.d.ts +40 -0
  158. package/lib/readonly/readonly.types.d.ts.map +1 -0
  159. package/lib/readonly/readonly.types.js +0 -0
  160. package/lib/throttle/index.d.ts +2 -0
  161. package/lib/throttle/index.js +2 -0
  162. package/lib/throttle/throttle.d.ts +35 -0
  163. package/lib/throttle/throttle.d.ts.map +1 -0
  164. package/lib/throttle/throttle.fn.d.ts +42 -0
  165. package/lib/throttle/throttle.fn.d.ts.map +1 -0
  166. package/lib/throttle/throttle.fn.js +52 -0
  167. package/lib/throttle/throttle.fn.js.map +1 -0
  168. package/lib/throttle/throttle.js +43 -0
  169. package/lib/throttle/throttle.js.map +1 -0
  170. package/lib/throttle-async/index.d.ts +2 -0
  171. package/lib/throttle-async/index.js +2 -0
  172. package/lib/throttle-async/throttle-async-executor.d.ts +79 -0
  173. package/lib/throttle-async/throttle-async-executor.d.ts.map +1 -0
  174. package/lib/throttle-async/throttle-async-executor.js +122 -0
  175. package/lib/throttle-async/throttle-async-executor.js.map +1 -0
  176. package/lib/throttle-async/throttle-async.d.ts +68 -0
  177. package/lib/throttle-async/throttle-async.d.ts.map +1 -0
  178. package/lib/throttle-async/throttle-async.fn.d.ts +41 -0
  179. package/lib/throttle-async/throttle-async.fn.d.ts.map +1 -0
  180. package/lib/throttle-async/throttle-async.fn.js +46 -0
  181. package/lib/throttle-async/throttle-async.fn.js.map +1 -0
  182. package/lib/throttle-async/throttle-async.js +45 -0
  183. package/lib/throttle-async/throttle-async.js.map +1 -0
  184. package/lib/types.d.ts +81 -0
  185. package/lib/types.d.ts.map +1 -0
  186. package/lib/types.js +0 -0
  187. package/package.json +40 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind.types.d.ts","names":[],"sources":["../../src/bind/bind.types.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;UA0BiB,UAAA;;;;;EAKf,IAAA;AAAA"}
File without changes
@@ -0,0 +1,3 @@
1
+ import { bind } from "./bind.js";
2
+ import { BindConfig } from "./bind.types.js";
3
+ export { BindConfig, bind };
@@ -0,0 +1,2 @@
1
+ import { bind } from "./bind.js";
2
+ export { bind };
@@ -0,0 +1,34 @@
1
+ import { Decorator } from "../types.js";
2
+
3
+ //#region src/debounce/debounce.d.ts
4
+ /**
5
+ * Decorator that debounces method calls, ensuring the method only executes
6
+ * after the specified delay has passed since the last call.
7
+ *
8
+ * @template T - The type of the class containing the decorated method
9
+ * @param {number} delayMs - The debounce delay in milliseconds
10
+ * @returns {Decorator<T>} The decorator function
11
+ *
12
+ * @throws {Error} When applied to a non-method property
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * class AutoSave {
17
+ * @debounce(1000)
18
+ * saveDraft(content: string) {
19
+ * // Saves only 1 second after user stops typing
20
+ * localStorage.setItem('draft', content);
21
+ * }
22
+ * }
23
+ *
24
+ * // Usage
25
+ * const autoSave = new AutoSave();
26
+ * autoSave.saveDraft('Hello'); // Won't save yet
27
+ * autoSave.saveDraft('Hello World'); // Resets timer
28
+ * // After 1 second of inactivity, saveDraft executes once
29
+ * ```
30
+ */
31
+ declare function debounce<T = unknown>(delayMs: number): Decorator<T>;
32
+ //#endregion
33
+ export { debounce };
34
+ //# sourceMappingURL=debounce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounce.d.ts","names":[],"sources":["../../src/debounce/debounce.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8CgB,QAAA,aAAA,CAAsB,OAAA,WAAkB,SAAA,CAAU,CAAA"}
@@ -0,0 +1,40 @@
1
+ import { Method } from "../types.js";
2
+
3
+ //#region src/debounce/debounce.fn.d.ts
4
+ /**
5
+ * Wraps a method to debounce its execution.
6
+ * The method will only execute after the specified delay has passed
7
+ * since the last time it was called.
8
+ *
9
+ * @template D - The return type of the original method
10
+ * @template A - The argument types of the original method
11
+ * @param {Method<D, A>} originalMethod - The method to debounce
12
+ * @param {number} delayMs - The debounce delay in milliseconds
13
+ * @returns {Method<void, A>} The debounced method
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * class SearchService {
18
+ * search(query: string): void {
19
+ * console.log(`Searching for: ${query}`);
20
+ * }
21
+ * }
22
+ *
23
+ * const service = new SearchService();
24
+ * const debouncedSearch = debounceFn(
25
+ * service.search.bind(service),
26
+ * 300
27
+ * );
28
+ *
29
+ * // Rapid calls
30
+ * debouncedSearch('a');
31
+ * debouncedSearch('ab');
32
+ * debouncedSearch('abc');
33
+ *
34
+ * // Only "Searching for: abc" is logged after 300ms
35
+ * ```
36
+ */
37
+ declare function debounceFn<D = unknown, A extends unknown[] = unknown[]>(originalMethod: Method<D, A>, delayMs: number): Method<void, A>;
38
+ //#endregion
39
+ export { debounceFn };
40
+ //# sourceMappingURL=debounce.fn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounce.fn.d.ts","names":[],"sources":["../../src/debounce/debounce.fn.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmDgB,UAAA,8CAAA,CACd,cAAA,EAAgB,MAAA,CAAO,CAAA,EAAG,CAAA,GAC1B,OAAA,WACC,MAAA,OAAa,CAAA"}
@@ -0,0 +1,47 @@
1
+ //#region src/debounce/debounce.fn.ts
2
+ /**
3
+ * Wraps a method to debounce its execution.
4
+ * The method will only execute after the specified delay has passed
5
+ * since the last time it was called.
6
+ *
7
+ * @template D - The return type of the original method
8
+ * @template A - The argument types of the original method
9
+ * @param {Method<D, A>} originalMethod - The method to debounce
10
+ * @param {number} delayMs - The debounce delay in milliseconds
11
+ * @returns {Method<void, A>} The debounced method
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * class SearchService {
16
+ * search(query: string): void {
17
+ * console.log(`Searching for: ${query}`);
18
+ * }
19
+ * }
20
+ *
21
+ * const service = new SearchService();
22
+ * const debouncedSearch = debounceFn(
23
+ * service.search.bind(service),
24
+ * 300
25
+ * );
26
+ *
27
+ * // Rapid calls
28
+ * debouncedSearch('a');
29
+ * debouncedSearch('ab');
30
+ * debouncedSearch('abc');
31
+ *
32
+ * // Only "Searching for: abc" is logged after 300ms
33
+ * ```
34
+ */
35
+ function debounceFn(originalMethod, delayMs) {
36
+ let handler;
37
+ return function(...args) {
38
+ clearTimeout(handler);
39
+ handler = setTimeout(() => {
40
+ originalMethod.apply(this, args);
41
+ }, delayMs);
42
+ };
43
+ }
44
+ //#endregion
45
+ export { debounceFn };
46
+
47
+ //# sourceMappingURL=debounce.fn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounce.fn.js","names":[],"sources":["../../src/debounce/debounce.fn.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Method } from '../types.js';\n\n/**\n * Wraps a method to debounce its execution.\n * The method will only execute after the specified delay has passed\n * since the last time it was called.\n *\n * @template D - The return type of the original method\n * @template A - The argument types of the original method\n * @param {Method<D, A>} originalMethod - The method to debounce\n * @param {number} delayMs - The debounce delay in milliseconds\n * @returns {Method<void, A>} The debounced method\n *\n * @example\n * ```typescript\n * class SearchService {\n * search(query: string): void {\n * console.log(`Searching for: ${query}`);\n * }\n * }\n *\n * const service = new SearchService();\n * const debouncedSearch = debounceFn(\n * service.search.bind(service),\n * 300\n * );\n *\n * // Rapid calls\n * debouncedSearch('a');\n * debouncedSearch('ab');\n * debouncedSearch('abc');\n *\n * // Only \"Searching for: abc\" is logged after 300ms\n * ```\n */\nexport function debounceFn<D = unknown, A extends unknown[] = unknown[]>(\n originalMethod: Method<D, A>,\n delayMs: number,\n): Method<void, A> {\n let handler: ReturnType<typeof setTimeout> | undefined;\n\n return function (this: unknown, ...args: A): void {\n clearTimeout(handler);\n\n handler = setTimeout(() => {\n originalMethod.apply(this, args);\n }, delayMs);\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,SAAgB,WACd,gBACA,SACiB;CACjB,IAAI;AAEJ,QAAO,SAAyB,GAAG,MAAe;AAChD,eAAa,QAAQ;AAErB,YAAU,iBAAiB;AACzB,kBAAe,MAAM,MAAM,KAAK;KAC/B,QAAQ"}
@@ -0,0 +1,48 @@
1
+ import { debounceFn } from "./debounce.fn.js";
2
+ //#region src/debounce/debounce.ts
3
+ /**
4
+ * Decorator that debounces method calls, ensuring the method only executes
5
+ * after the specified delay has passed since the last call.
6
+ *
7
+ * @template T - The type of the class containing the decorated method
8
+ * @param {number} delayMs - The debounce delay in milliseconds
9
+ * @returns {Decorator<T>} The decorator function
10
+ *
11
+ * @throws {Error} When applied to a non-method property
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * class AutoSave {
16
+ * @debounce(1000)
17
+ * saveDraft(content: string) {
18
+ * // Saves only 1 second after user stops typing
19
+ * localStorage.setItem('draft', content);
20
+ * }
21
+ * }
22
+ *
23
+ * // Usage
24
+ * const autoSave = new AutoSave();
25
+ * autoSave.saveDraft('Hello'); // Won't save yet
26
+ * autoSave.saveDraft('Hello World'); // Resets timer
27
+ * // After 1 second of inactivity, saveDraft executes once
28
+ * ```
29
+ */
30
+ function debounce(delayMs) {
31
+ return (_target, _propertyName, descriptor) => {
32
+ if (descriptor.value) {
33
+ const methodsMap = /* @__PURE__ */ new WeakMap();
34
+ const originalMethod = descriptor.value;
35
+ descriptor.value = function(...args) {
36
+ if (!methodsMap.has(this)) methodsMap.set(this, debounceFn(originalMethod, delayMs).bind(this));
37
+ const method = methodsMap.get(this);
38
+ if (method) method(...args);
39
+ };
40
+ return descriptor;
41
+ }
42
+ throw new Error("@debounce is applicable only on a methods.");
43
+ };
44
+ }
45
+ //#endregion
46
+ export { debounce };
47
+
48
+ //# sourceMappingURL=debounce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounce.js","names":[],"sources":["../../src/debounce/debounce.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Decorator, Method } from '../types.js';\nimport { debounceFn } from './debounce.fn.js';\n\n/**\n * Decorator that debounces method calls, ensuring the method only executes\n * after the specified delay has passed since the last call.\n *\n * @template T - The type of the class containing the decorated method\n * @param {number} delayMs - The debounce delay in milliseconds\n * @returns {Decorator<T>} The decorator function\n *\n * @throws {Error} When applied to a non-method property\n *\n * @example\n * ```typescript\n * class AutoSave {\n * @debounce(1000)\n * saveDraft(content: string) {\n * // Saves only 1 second after user stops typing\n * localStorage.setItem('draft', content);\n * }\n * }\n *\n * // Usage\n * const autoSave = new AutoSave();\n * autoSave.saveDraft('Hello'); // Won't save yet\n * autoSave.saveDraft('Hello World'); // Resets timer\n * // After 1 second of inactivity, saveDraft executes once\n * ```\n */\nexport function debounce<T = unknown>(delayMs: number): Decorator<T> {\n return (\n _target: T,\n _propertyName: keyof T,\n descriptor: TypedPropertyDescriptor<Method<unknown>>,\n ): TypedPropertyDescriptor<Method<unknown>> => {\n if (descriptor.value) {\n const methodsMap = new WeakMap<object, Method<unknown>>();\n const originalMethod = descriptor.value;\n\n descriptor.value = function (this: object, ...args: unknown[]) {\n if (!methodsMap.has(this)) {\n methodsMap.set(this, debounceFn(originalMethod, delayMs).bind(this));\n }\n\n const method = methodsMap.get(this);\n if (method) {\n method(...args);\n }\n };\n\n return descriptor;\n }\n\n throw new Error('@debounce is applicable only on a methods.');\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,SAAgB,SAAsB,SAA+B;AACnE,SACE,SACA,eACA,eAC6C;AAC7C,MAAI,WAAW,OAAO;GACpB,MAAM,6BAAa,IAAI,SAAkC;GACzD,MAAM,iBAAiB,WAAW;AAElC,cAAW,QAAQ,SAAwB,GAAG,MAAiB;AAC7D,QAAI,CAAC,WAAW,IAAI,KAAK,CACvB,YAAW,IAAI,MAAM,WAAW,gBAAgB,QAAQ,CAAC,KAAK,KAAK,CAAC;IAGtE,MAAM,SAAS,WAAW,IAAI,KAAK;AACnC,QAAI,OACF,QAAO,GAAG,KAAK;;AAInB,UAAO;;AAGT,QAAM,IAAI,MAAM,6CAA6C"}
@@ -0,0 +1,2 @@
1
+ import { debounceFn } from "./debounce.fn.js";
2
+ export { debounceFn };
@@ -0,0 +1,2 @@
1
+ import { debounceFn } from "./debounce.fn.js";
2
+ export { debounceFn };
@@ -0,0 +1,35 @@
1
+ import { Decorator } from "../types.js";
2
+
3
+ //#region src/delay/delay.d.ts
4
+ /**
5
+ * Decorator that delays the execution of a method by the specified time.
6
+ *
7
+ * @template T - The type of the class containing the decorated method
8
+ * @param {number} delayMs - The delay time in milliseconds
9
+ * @returns {Decorator<T>} The decorator function
10
+ *
11
+ * @throws {Error} When applied to a non-method property
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * class AnimationController {
16
+ * @delay(500)
17
+ * fadeIn(element: HTMLElement) {
18
+ * element.style.opacity = '1';
19
+ * }
20
+ *
21
+ * @delay(1000)
22
+ * fadeOut(element: HTMLElement) {
23
+ * element.style.opacity = '0';
24
+ * }
25
+ * }
26
+ *
27
+ * const controller = new AnimationController();
28
+ * controller.fadeIn(element); // Fades in after 500ms
29
+ * controller.fadeOut(element); // Fades out after 1000ms
30
+ * ```
31
+ */
32
+ declare function delay<T = unknown>(delayMs: number): Decorator<T>;
33
+ //#endregion
34
+ export { delay };
35
+ //# sourceMappingURL=delay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delay.d.ts","names":[],"sources":["../../src/delay/delay.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+CgB,KAAA,aAAA,CAAmB,OAAA,WAAkB,SAAA,CAAU,CAAA"}
@@ -0,0 +1,33 @@
1
+ import { Method } from "../types.js";
2
+
3
+ //#region src/delay/delay.fn.d.ts
4
+ /**
5
+ * Wraps a method to delay its execution by the specified time.
6
+ *
7
+ * @template D - The return type of the original method
8
+ * @template A - The argument types of the original method
9
+ * @param {Method<D, A>} originalMethod - The method to delay
10
+ * @param {number} delayMs - The delay time in milliseconds
11
+ * @returns {Method<void, A>} The delayed method
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * class MessageService {
16
+ * send(message: string): void {
17
+ * console.log(`Sending: ${message}`);
18
+ * }
19
+ * }
20
+ *
21
+ * const service = new MessageService();
22
+ * const delayedSend = delayFn(
23
+ * service.send.bind(service),
24
+ * 2000
25
+ * );
26
+ *
27
+ * delayedSend('Hello'); // "Sending: Hello" appears after 2 seconds
28
+ * ```
29
+ */
30
+ declare function delayFn<D = unknown, A extends unknown[] = unknown[]>(originalMethod: Method<D, A>, delayMs: number): Method<void, A>;
31
+ //#endregion
32
+ export { delayFn };
33
+ //# sourceMappingURL=delay.fn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delay.fn.d.ts","names":[],"sources":["../../src/delay/delay.fn.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4CgB,OAAA,8CAAA,CACd,cAAA,EAAgB,MAAA,CAAO,CAAA,EAAG,CAAA,GAC1B,OAAA,WACC,MAAA,OAAa,CAAA"}
@@ -0,0 +1,38 @@
1
+ //#region src/delay/delay.fn.ts
2
+ /**
3
+ * Wraps a method to delay its execution by the specified time.
4
+ *
5
+ * @template D - The return type of the original method
6
+ * @template A - The argument types of the original method
7
+ * @param {Method<D, A>} originalMethod - The method to delay
8
+ * @param {number} delayMs - The delay time in milliseconds
9
+ * @returns {Method<void, A>} The delayed method
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * class MessageService {
14
+ * send(message: string): void {
15
+ * console.log(`Sending: ${message}`);
16
+ * }
17
+ * }
18
+ *
19
+ * const service = new MessageService();
20
+ * const delayedSend = delayFn(
21
+ * service.send.bind(service),
22
+ * 2000
23
+ * );
24
+ *
25
+ * delayedSend('Hello'); // "Sending: Hello" appears after 2 seconds
26
+ * ```
27
+ */
28
+ function delayFn(originalMethod, delayMs) {
29
+ return function(...args) {
30
+ setTimeout(() => {
31
+ originalMethod.apply(this, args);
32
+ }, delayMs);
33
+ };
34
+ }
35
+ //#endregion
36
+ export { delayFn };
37
+
38
+ //# sourceMappingURL=delay.fn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delay.fn.js","names":[],"sources":["../../src/delay/delay.fn.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Method } from '../types.js';\n\n/**\n * Wraps a method to delay its execution by the specified time.\n *\n * @template D - The return type of the original method\n * @template A - The argument types of the original method\n * @param {Method<D, A>} originalMethod - The method to delay\n * @param {number} delayMs - The delay time in milliseconds\n * @returns {Method<void, A>} The delayed method\n *\n * @example\n * ```typescript\n * class MessageService {\n * send(message: string): void {\n * console.log(`Sending: ${message}`);\n * }\n * }\n *\n * const service = new MessageService();\n * const delayedSend = delayFn(\n * service.send.bind(service),\n * 2000\n * );\n *\n * delayedSend('Hello'); // \"Sending: Hello\" appears after 2 seconds\n * ```\n */\nexport function delayFn<D = unknown, A extends unknown[] = unknown[]>(\n originalMethod: Method<D, A>,\n delayMs: number,\n): Method<void, A> {\n return function (this: unknown, ...args: A): void {\n setTimeout(() => {\n originalMethod.apply(this, args);\n }, delayMs);\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAgB,QACd,gBACA,SACiB;AACjB,QAAO,SAAyB,GAAG,MAAe;AAChD,mBAAiB;AACf,kBAAe,MAAM,MAAM,KAAK;KAC/B,QAAQ"}
@@ -0,0 +1,43 @@
1
+ import { delayFn } from "./delay.fn.js";
2
+ //#region src/delay/delay.ts
3
+ /**
4
+ * Decorator that delays the execution of a method by the specified time.
5
+ *
6
+ * @template T - The type of the class containing the decorated method
7
+ * @param {number} delayMs - The delay time in milliseconds
8
+ * @returns {Decorator<T>} The decorator function
9
+ *
10
+ * @throws {Error} When applied to a non-method property
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * class AnimationController {
15
+ * @delay(500)
16
+ * fadeIn(element: HTMLElement) {
17
+ * element.style.opacity = '1';
18
+ * }
19
+ *
20
+ * @delay(1000)
21
+ * fadeOut(element: HTMLElement) {
22
+ * element.style.opacity = '0';
23
+ * }
24
+ * }
25
+ *
26
+ * const controller = new AnimationController();
27
+ * controller.fadeIn(element); // Fades in after 500ms
28
+ * controller.fadeOut(element); // Fades out after 1000ms
29
+ * ```
30
+ */
31
+ function delay(delayMs) {
32
+ return (_target, _propertyName, descriptor) => {
33
+ if (descriptor.value) {
34
+ descriptor.value = delayFn(descriptor.value, delayMs);
35
+ return descriptor;
36
+ }
37
+ throw new Error("@delay is applicable only on a methods.");
38
+ };
39
+ }
40
+ //#endregion
41
+ export { delay };
42
+
43
+ //# sourceMappingURL=delay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delay.js","names":[],"sources":["../../src/delay/delay.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Decorator, Method } from '../types.js';\nimport { delayFn } from './delay.fn.js';\n\n/**\n * Decorator that delays the execution of a method by the specified time.\n *\n * @template T - The type of the class containing the decorated method\n * @param {number} delayMs - The delay time in milliseconds\n * @returns {Decorator<T>} The decorator function\n *\n * @throws {Error} When applied to a non-method property\n *\n * @example\n * ```typescript\n * class AnimationController {\n * @delay(500)\n * fadeIn(element: HTMLElement) {\n * element.style.opacity = '1';\n * }\n *\n * @delay(1000)\n * fadeOut(element: HTMLElement) {\n * element.style.opacity = '0';\n * }\n * }\n *\n * const controller = new AnimationController();\n * controller.fadeIn(element); // Fades in after 500ms\n * controller.fadeOut(element); // Fades out after 1000ms\n * ```\n */\nexport function delay<T = unknown>(delayMs: number): Decorator<T> {\n return (\n _target: T,\n _propertyName: keyof T,\n descriptor: TypedPropertyDescriptor<Method<unknown>>,\n ): TypedPropertyDescriptor<Method<unknown>> => {\n if (descriptor.value) {\n descriptor.value = delayFn(descriptor.value, delayMs);\n\n return descriptor;\n }\n throw new Error('@delay is applicable only on a methods.');\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,MAAmB,SAA+B;AAChE,SACE,SACA,eACA,eAC6C;AAC7C,MAAI,WAAW,OAAO;AACpB,cAAW,QAAQ,QAAQ,WAAW,OAAO,QAAQ;AAErD,UAAO;;AAET,QAAM,IAAI,MAAM,0CAA0C"}
@@ -0,0 +1,2 @@
1
+ import { delay } from "./delay.js";
2
+ export { delay };
@@ -0,0 +1,2 @@
1
+ import { delay } from "./delay.js";
2
+ export { delay };
@@ -0,0 +1,48 @@
1
+ import { Delegatable } from "./delegate.types.js";
2
+
3
+ //#region src/delegate/delegate.d.ts
4
+ /**
5
+ * Decorator that deduplicates concurrent async method calls.
6
+ * Multiple calls with the same arguments will share the same promise
7
+ * until the first one resolves or rejects.
8
+ *
9
+ * @template T - The type of the class containing the decorated method
10
+ * @template D - The return type of the decorated method (wrapped in Promise)
11
+ * @param {(...args: any[]) => string} [keyResolver] - Optional function to generate cache keys from arguments
12
+ * @returns {Delegatable<T, D>} The decorator function
13
+ *
14
+ * @throws {Error} When applied to a non-method property
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * class ApiService {
19
+ * // Basic usage - uses JSON.stringify(args) as key
20
+ * @delegate()
21
+ * async fetchData(id: string): Promise<Data> {
22
+ * return this.http.get(`/data/${id}`);
23
+ * }
24
+ *
25
+ * // Custom key resolver for complex arguments
26
+ * @delegate((userId, options) => `${userId}-${options.cacheKey}`)
27
+ * async getUser(userId: string, options: { cacheKey: string }): Promise<User> {
28
+ * return this.http.get(`/users/${userId}`);
29
+ * }
30
+ * }
31
+ *
32
+ * // Usage - concurrent calls with same args share the promise
33
+ * const api = new ApiService();
34
+ *
35
+ * // These share the same underlying promise
36
+ * const [user1, user2] = await Promise.all([
37
+ * api.getUser('123', { cacheKey: 'v1' }),
38
+ * api.getUser('123', { cacheKey: 'v1' }) // Same key, returns cached promise
39
+ * ]);
40
+ *
41
+ * // This creates a new promise (different cache key)
42
+ * const user3 = await api.getUser('123', { cacheKey: 'v2' });
43
+ * ```
44
+ */
45
+ declare function delegate<T = any, D = any>(keyResolver?: (...args: unknown[]) => string): Delegatable<T, D>;
46
+ //#endregion
47
+ export { delegate };
48
+ //# sourceMappingURL=delegate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegate.d.ts","names":[],"sources":["../../src/delegate/delegate.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyFgB,QAAA,kBAAA,CACd,WAAA,OAAkB,IAAA,yBACjB,WAAA,CAAY,CAAA,EAAG,CAAA"}
@@ -0,0 +1,57 @@
1
+ import { AsyncMethod } from "../types.js";
2
+
3
+ //#region src/delegate/delegate.fn.d.ts
4
+ /**
5
+ * @fileoverview Delegate function implementation - wraps an async method to
6
+ * deduplicate concurrent calls with the same arguments.
7
+ *
8
+ * @module @resq/typescript/decorators/delegate.fn
9
+ *
10
+ * @copyright Copyright (c) 2026 ResQ
11
+ * @license MIT
12
+ */
13
+ /**
14
+ * @fileoverview Delegate function implementation - wraps an async method to
15
+ * deduplicate concurrent calls with the same arguments.
16
+ *
17
+ * @module @resq/typescript/decorators/delegate.fn
18
+ *
19
+ * @copyright Copyright (c) 2026 ResQ
20
+ * @license MIT
21
+ */
22
+ /**
23
+ * Wraps an async method to deduplicate concurrent calls.
24
+ * Multiple calls with the same key will share the same promise
25
+ * until the first one completes.
26
+ *
27
+ * @template D - The resolved type of the promise
28
+ * @template A - The argument types of the original method
29
+ * @param {AsyncMethod<D, A>} originalMethod - The async method to wrap
30
+ * @param {(...args: A) => string} [keyResolver] - Optional function to generate cache keys
31
+ * @returns {AsyncMethod<D, A>} The delegated method
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * class Service {
36
+ * async fetchData(id: string): Promise<Data> {
37
+ * console.log(`Fetching ${id}`);
38
+ * return fetch(`/api/data/${id}`).then(r => r.json());
39
+ * }
40
+ * }
41
+ *
42
+ * const service = new Service();
43
+ * const delegated = delegateFn(
44
+ * service.fetchData.bind(service),
45
+ * (id) => id // Use id directly as key
46
+ * );
47
+ *
48
+ * // These share the same promise - "Fetching 123" is logged only once
49
+ * const p1 = delegated('123');
50
+ * const p2 = delegated('123');
51
+ * const [d1, d2] = await Promise.all([p1, p2]);
52
+ * ```
53
+ */
54
+ declare function delegateFn<D = any, A extends any[] = any[]>(originalMethod: AsyncMethod<D, A>, keyResolver?: (...args: A) => string): AsyncMethod<D, A>;
55
+ //#endregion
56
+ export { delegateFn };
57
+ //# sourceMappingURL=delegate.fn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegate.fn.d.ts","names":[],"sources":["../../src/delegate/delegate.fn.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4EgB,UAAA,kCAAA,CACd,cAAA,EAAgB,WAAA,CAAY,CAAA,EAAG,CAAA,GAC/B,WAAA,OAAkB,IAAA,EAAM,CAAA,cACvB,WAAA,CAAY,CAAA,EAAG,CAAA"}
@@ -0,0 +1,55 @@
1
+ //#region src/delegate/delegate.fn.ts
2
+ /**
3
+ * @fileoverview Delegate function implementation - wraps an async method to
4
+ * deduplicate concurrent calls with the same arguments.
5
+ *
6
+ * @module @resq/typescript/decorators/delegate.fn
7
+ *
8
+ * @copyright Copyright (c) 2026 ResQ
9
+ * @license MIT
10
+ */
11
+ /**
12
+ * Wraps an async method to deduplicate concurrent calls.
13
+ * Multiple calls with the same key will share the same promise
14
+ * until the first one completes.
15
+ *
16
+ * @template D - The resolved type of the promise
17
+ * @template A - The argument types of the original method
18
+ * @param {AsyncMethod<D, A>} originalMethod - The async method to wrap
19
+ * @param {(...args: A) => string} [keyResolver] - Optional function to generate cache keys
20
+ * @returns {AsyncMethod<D, A>} The delegated method
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * class Service {
25
+ * async fetchData(id: string): Promise<Data> {
26
+ * console.log(`Fetching ${id}`);
27
+ * return fetch(`/api/data/${id}`).then(r => r.json());
28
+ * }
29
+ * }
30
+ *
31
+ * const service = new Service();
32
+ * const delegated = delegateFn(
33
+ * service.fetchData.bind(service),
34
+ * (id) => id // Use id directly as key
35
+ * );
36
+ *
37
+ * // These share the same promise - "Fetching 123" is logged only once
38
+ * const p1 = delegated('123');
39
+ * const p2 = delegated('123');
40
+ * const [d1, d2] = await Promise.all([p1, p2]);
41
+ * ```
42
+ */
43
+ function delegateFn(originalMethod, keyResolver) {
44
+ const delegatedKeysMap = /* @__PURE__ */ new Map();
45
+ const keyGenerator = keyResolver ?? ((...args) => JSON.stringify(args));
46
+ return function(...args) {
47
+ const key = keyGenerator(...args);
48
+ if (!delegatedKeysMap.has(key)) delegatedKeysMap.set(key, originalMethod.apply(this, args).finally(() => delegatedKeysMap.delete(key)));
49
+ return delegatedKeysMap.get(key);
50
+ };
51
+ }
52
+ //#endregion
53
+ export { delegateFn };
54
+
55
+ //# sourceMappingURL=delegate.fn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegate.fn.js","names":[],"sources":["../../src/delegate/delegate.fn.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AsyncMethod } from '../types.js';\n\n/*\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview Delegate function implementation - wraps an async method to\n * deduplicate concurrent calls with the same arguments.\n *\n * @module @resq/typescript/decorators/delegate.fn\n *\n * @copyright Copyright (c) 2026 ResQ\n * @license MIT\n */\n\n/**\n * Wraps an async method to deduplicate concurrent calls.\n * Multiple calls with the same key will share the same promise\n * until the first one completes.\n *\n * @template D - The resolved type of the promise\n * @template A - The argument types of the original method\n * @param {AsyncMethod<D, A>} originalMethod - The async method to wrap\n * @param {(...args: A) => string} [keyResolver] - Optional function to generate cache keys\n * @returns {AsyncMethod<D, A>} The delegated method\n *\n * @example\n * ```typescript\n * class Service {\n * async fetchData(id: string): Promise<Data> {\n * console.log(`Fetching ${id}`);\n * return fetch(`/api/data/${id}`).then(r => r.json());\n * }\n * }\n *\n * const service = new Service();\n * const delegated = delegateFn(\n * service.fetchData.bind(service),\n * (id) => id // Use id directly as key\n * );\n *\n * // These share the same promise - \"Fetching 123\" is logged only once\n * const p1 = delegated('123');\n * const p2 = delegated('123');\n * const [d1, d2] = await Promise.all([p1, p2]);\n * ```\n */\nexport function delegateFn<D = any, A extends any[] = any[]>(\n originalMethod: AsyncMethod<D, A>,\n keyResolver?: (...args: A) => string,\n): AsyncMethod<D, A> {\n const delegatedKeysMap = new Map<string, Promise<D>>();\n const keyGenerator: (...args: unknown[]) => string =\n keyResolver ?? ((...args) => JSON.stringify(args));\n\n return function (this: any, ...args: A): Promise<D> {\n const key = keyGenerator(...args);\n\n if (!delegatedKeysMap.has(key)) {\n delegatedKeysMap.set(\n key,\n originalMethod.apply(this, args).finally(() => delegatedKeysMap.delete(key)),\n );\n }\n\n return delegatedKeysMap.get(key) as Promise<D>;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4EA,SAAgB,WACd,gBACA,aACmB;CACnB,MAAM,mCAAmB,IAAI,KAAyB;CACtD,MAAM,eACJ,iBAAiB,GAAG,SAAS,KAAK,UAAU,KAAK;AAEnD,QAAO,SAAqB,GAAG,MAAqB;EAClD,MAAM,MAAM,aAAa,GAAG,KAAK;AAEjC,MAAI,CAAC,iBAAiB,IAAI,IAAI,CAC5B,kBAAiB,IACf,KACA,eAAe,MAAM,MAAM,KAAK,CAAC,cAAc,iBAAiB,OAAO,IAAI,CAAC,CAC7E;AAGH,SAAO,iBAAiB,IAAI,IAAI"}
@@ -0,0 +1,56 @@
1
+ import { delegateFn } from "./delegate.fn.js";
2
+ //#region src/delegate/delegate.ts
3
+ /**
4
+ * Decorator that deduplicates concurrent async method calls.
5
+ * Multiple calls with the same arguments will share the same promise
6
+ * until the first one resolves or rejects.
7
+ *
8
+ * @template T - The type of the class containing the decorated method
9
+ * @template D - The return type of the decorated method (wrapped in Promise)
10
+ * @param {(...args: any[]) => string} [keyResolver] - Optional function to generate cache keys from arguments
11
+ * @returns {Delegatable<T, D>} The decorator function
12
+ *
13
+ * @throws {Error} When applied to a non-method property
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * class ApiService {
18
+ * // Basic usage - uses JSON.stringify(args) as key
19
+ * @delegate()
20
+ * async fetchData(id: string): Promise<Data> {
21
+ * return this.http.get(`/data/${id}`);
22
+ * }
23
+ *
24
+ * // Custom key resolver for complex arguments
25
+ * @delegate((userId, options) => `${userId}-${options.cacheKey}`)
26
+ * async getUser(userId: string, options: { cacheKey: string }): Promise<User> {
27
+ * return this.http.get(`/users/${userId}`);
28
+ * }
29
+ * }
30
+ *
31
+ * // Usage - concurrent calls with same args share the promise
32
+ * const api = new ApiService();
33
+ *
34
+ * // These share the same underlying promise
35
+ * const [user1, user2] = await Promise.all([
36
+ * api.getUser('123', { cacheKey: 'v1' }),
37
+ * api.getUser('123', { cacheKey: 'v1' }) // Same key, returns cached promise
38
+ * ]);
39
+ *
40
+ * // This creates a new promise (different cache key)
41
+ * const user3 = await api.getUser('123', { cacheKey: 'v2' });
42
+ * ```
43
+ */
44
+ function delegate(keyResolver) {
45
+ return (target, propertyName, descriptor) => {
46
+ if (descriptor.value) {
47
+ descriptor.value = delegateFn(descriptor.value, keyResolver);
48
+ return descriptor;
49
+ }
50
+ throw new Error("@delegate is applicable only on a methods.");
51
+ };
52
+ }
53
+ //#endregion
54
+ export { delegate };
55
+
56
+ //# sourceMappingURL=delegate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegate.js","names":[],"sources":["../../src/delegate/delegate.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview Delegate decorator - deduplicates concurrent async method calls\n * with the same arguments. If a method is called while another identical call\n * is in progress, it returns the same promise instead of making a new call.\n *\n * @module @resq/typescript/decorators/delegate\n *\n * @example\n * ```typescript\n * class DataService {\n * @delegate()\n * async fetchUser(userId: string): Promise<User> {\n * return fetch(`/api/users/${userId}`).then(r => r.json());\n * }\n * }\n *\n * const service = new DataService();\n *\n * // These two calls will share the same promise\n * const promise1 = service.fetchUser('123');\n * const promise2 = service.fetchUser('123');\n * console.log(promise1 === promise2); // true\n * ```\n *\n * @copyright Copyright (c) 2026 ResQ\n * @license MIT\n */\n\nimport type { AsyncMethod } from '../types.js';\nimport { delegateFn } from './delegate.fn.js';\nimport type { Delegatable } from './delegate.types.js';\n\n/**\n * Decorator that deduplicates concurrent async method calls.\n * Multiple calls with the same arguments will share the same promise\n * until the first one resolves or rejects.\n *\n * @template T - The type of the class containing the decorated method\n * @template D - The return type of the decorated method (wrapped in Promise)\n * @param {(...args: any[]) => string} [keyResolver] - Optional function to generate cache keys from arguments\n * @returns {Delegatable<T, D>} The decorator function\n *\n * @throws {Error} When applied to a non-method property\n *\n * @example\n * ```typescript\n * class ApiService {\n * // Basic usage - uses JSON.stringify(args) as key\n * @delegate()\n * async fetchData(id: string): Promise<Data> {\n * return this.http.get(`/data/${id}`);\n * }\n *\n * // Custom key resolver for complex arguments\n * @delegate((userId, options) => `${userId}-${options.cacheKey}`)\n * async getUser(userId: string, options: { cacheKey: string }): Promise<User> {\n * return this.http.get(`/users/${userId}`);\n * }\n * }\n *\n * // Usage - concurrent calls with same args share the promise\n * const api = new ApiService();\n *\n * // These share the same underlying promise\n * const [user1, user2] = await Promise.all([\n * api.getUser('123', { cacheKey: 'v1' }),\n * api.getUser('123', { cacheKey: 'v1' }) // Same key, returns cached promise\n * ]);\n *\n * // This creates a new promise (different cache key)\n * const user3 = await api.getUser('123', { cacheKey: 'v2' });\n * ```\n */\nexport function delegate<T = any, D = any>(\n keyResolver?: (...args: unknown[]) => string,\n): Delegatable<T, D> {\n return (\n target: T,\n propertyName: keyof T,\n descriptor: TypedPropertyDescriptor<AsyncMethod<D>>,\n ): TypedPropertyDescriptor<AsyncMethod<any>> => {\n if (descriptor.value) {\n descriptor.value = delegateFn(descriptor.value, keyResolver);\n\n return descriptor;\n }\n\n throw new Error('@delegate is applicable only on a methods.');\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyFA,SAAgB,SACd,aACmB;AACnB,SACE,QACA,cACA,eAC8C;AAC9C,MAAI,WAAW,OAAO;AACpB,cAAW,QAAQ,WAAW,WAAW,OAAO,YAAY;AAE5D,UAAO;;AAGT,QAAM,IAAI,MAAM,6CAA6C"}