@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,148 @@
1
+ import { Method } from "../types.js";
2
+
3
+ //#region src/rate-limit/rate-limit.types.d.ts
4
+ /**
5
+ * @fileoverview Type definitions for the RateLimit decorator.
6
+ * Provides types for rate limiting configuration and counter implementations.
7
+ *
8
+ * @module @resq/typescript/decorators/rate-limit/types
9
+ *
10
+ * @copyright Copyright (c) 2026 ResQ
11
+ * @license MIT
12
+ */
13
+ /**
14
+ * @fileoverview Type definitions for the RateLimit decorator.
15
+ * Provides types for rate limiting configuration and counter implementations.
16
+ *
17
+ * @module @resq/typescript/decorators/rate-limit/types
18
+ *
19
+ * @copyright Copyright (c) 2026 ResQ
20
+ * @license MIT
21
+ */
22
+ /**
23
+ * Configuration options for rate limiting.
24
+ *
25
+ * @interface RateLimitConfigs
26
+ * @template T - The type of the class containing the decorated method
27
+ * @property {number} timeSpanMs - The time window in milliseconds
28
+ * @property {number} allowedCalls - Maximum number of calls allowed in the time window
29
+ * @property {((...args: any[]) => string) | keyof T} [keyResolver] - Function to generate rate limit keys (for per-user/entity limiting)
30
+ * @property {RateLimitCounter} [rateLimitCounter] - Custom counter implementation
31
+ * @property {RateLimitAsyncCounter} [rateLimitAsyncCounter] - Async counter implementation
32
+ * @property {() => void} [exceedHandler] - Handler called when rate limit is exceeded
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const config: RateLimitConfigs<ApiService> = {
37
+ * timeSpanMs: 60000, // 1 minute
38
+ * allowedCalls: 100, // 100 calls per minute
39
+ * keyResolver: (userId) => `user-${userId}`,
40
+ * exceedHandler: () => { throw new Error('Rate limit exceeded'); }
41
+ * };
42
+ * ```
43
+ */
44
+ interface RateLimitConfigs<T = any> {
45
+ /** The time window in milliseconds */
46
+ timeSpanMs: number;
47
+ /** Maximum number of calls allowed in the time window */
48
+ allowedCalls: number;
49
+ /** Function to generate rate limit keys (for per-user/entity limiting) */
50
+ keyResolver?: ((...args: unknown[]) => string) | keyof T;
51
+ /** Custom counter implementation */
52
+ rateLimitCounter?: RateLimitCounter;
53
+ /** Async counter implementation */
54
+ rateLimitAsyncCounter?: RateLimitAsyncCounter;
55
+ /** Handler called when rate limit is exceeded */
56
+ exceedHandler?: () => void;
57
+ }
58
+ /**
59
+ * Interface for rate limit counter implementations.
60
+ * Used to track call counts within time windows.
61
+ *
62
+ * @interface RateLimitCounter
63
+ * @property {(key: string) => void} inc - Increment the count for a key
64
+ * @property {(key: string) => void} dec - Decrement the count for a key
65
+ * @property {(key: string) => number} getCount - Get the current count for a key
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * class InMemoryCounter implements RateLimitCounter {
70
+ * private counts = new Map<string, number>();
71
+ *
72
+ * inc(key: string): void {
73
+ * this.counts.set(key, (this.counts.get(key) ?? 0) + 1);
74
+ * }
75
+ *
76
+ * dec(key: string): void {
77
+ * const count = this.counts.get(key) ?? 0;
78
+ * if (count <= 1) {
79
+ * this.counts.delete(key);
80
+ * } else {
81
+ * this.counts.set(key, count - 1);
82
+ * }
83
+ * }
84
+ *
85
+ * getCount(key: string): number {
86
+ * return this.counts.get(key) ?? 0;
87
+ * }
88
+ * }
89
+ * ```
90
+ */
91
+ interface RateLimitCounter {
92
+ /** Increment the count for a key */
93
+ inc: (key: string) => void;
94
+ /** Decrement the count for a key */
95
+ dec: (key: string) => void;
96
+ /** Get the current count for a key */
97
+ getCount: (key: string) => number;
98
+ }
99
+ /**
100
+ * Interface for async rate limit counter implementations.
101
+ * Use this when the counter needs to perform async operations (e.g., Redis, database).
102
+ *
103
+ * @interface RateLimitAsyncCounter
104
+ * @property {(key: string) => Promise<void>} inc - Increment the count for a key asynchronously
105
+ * @property {(key: string) => Promise<void>} dec - Decrement the count for a key asynchronously
106
+ * @property {(key: string) => Promise<number>} getCount - Get the current count for a key asynchronously
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * class RedisCounter implements RateLimitAsyncCounter {
111
+ * async inc(key: string): Promise<void> {
112
+ * await redis.incr(`ratelimit:${key}`);
113
+ * }
114
+ *
115
+ * async dec(key: string): Promise<void> {
116
+ * await redis.decr(`ratelimit:${key}`);
117
+ * }
118
+ *
119
+ * async getCount(key: string): Promise<number> {
120
+ * const count = await redis.get(`ratelimit:${key}`);
121
+ * return parseInt(count ?? '0', 10);
122
+ * }
123
+ * }
124
+ * ```
125
+ */
126
+ interface RateLimitAsyncCounter {
127
+ /** Increment the count for a key asynchronously */
128
+ inc: (key: string) => Promise<void>;
129
+ /** Decrement the count for a key asynchronously */
130
+ dec: (key: string) => Promise<void>;
131
+ /** Get the current count for a key asynchronously */
132
+ getCount: (key: string) => Promise<number>;
133
+ }
134
+ /**
135
+ * Type for the @rateLimit decorator function.
136
+ *
137
+ * @template T - The type of the class containing the decorated method
138
+ * @template D - The return type of the decorated method
139
+ *
140
+ * @param {T} target - The class prototype
141
+ * @param {keyof T} propertyName - The name of the method being decorated
142
+ * @param {TypedPropertyDescriptor<Method<D>>} descriptor - The property descriptor
143
+ * @returns {TypedPropertyDescriptor<Method<D>>} The modified descriptor
144
+ */
145
+ type RateLimitable<T, D> = (target: T, propertyName: keyof T, descriptor: TypedPropertyDescriptor<Method<D>>) => TypedPropertyDescriptor<Method<D>>;
146
+ //#endregion
147
+ export { RateLimitAsyncCounter, RateLimitConfigs, RateLimitCounter, RateLimitable };
148
+ //# sourceMappingURL=rate-limit.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.types.d.ts","names":[],"sources":["../../src/rate-limit/rate-limit.types.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiHA;;;;;;;;;;;;AAoCA;;UApFiB,gBAAA;EAsFO;EApFtB,UAAA;EAwF2B;EAtF3B,YAAA;EAsFkC;EApFlC,WAAA,QAAmB,IAAA,gCAAoC,CAAA;EAgFjD;EA9EN,gBAAA,GAAmB,gBAAA;EAgFnB;EA9EA,qBAAA,GAAwB,qBAAA;EA8EF;EA5EtB,aAAA;AAAA;;;;AA4FF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAxDiB,gBAAA;;EAEf,GAAA,GAAM,GAAA;;EAEN,GAAA,GAAM,GAAA;;EAEN,QAAA,GAAW,GAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA8BI,qBAAA;;EAEf,GAAA,GAAM,GAAA,aAAgB,OAAA;;EAEtB,GAAA,GAAM,GAAA,aAAgB,OAAA;;EAEtB,QAAA,GAAW,GAAA,aAAgB,OAAA;AAAA;;;;;;;;;;;;KAcjB,aAAA,UACV,MAAA,EAAQ,CAAA,EACR,YAAA,QAAoB,CAAA,EACpB,UAAA,EAAY,uBAAA,CAAwB,MAAA,CAAO,CAAA,OACxC,uBAAA,CAAwB,MAAA,CAAO,CAAA"}
File without changes
@@ -0,0 +1,89 @@
1
+ import { RateLimitCounter } from "./rate-limit.types.js";
2
+
3
+ //#region src/rate-limit/simple-rate-limit-counter.d.ts
4
+ /**
5
+ * Simple in-memory implementation of RateLimitCounter.
6
+ * Uses a Map to store counts for each key.
7
+ *
8
+ * @class SimpleRateLimitCounter
9
+ * @implements {RateLimitCounter}
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const counter = new SimpleRateLimitCounter();
14
+ *
15
+ * // Track API calls per user
16
+ * counter.inc('user-1');
17
+ * counter.inc('user-1');
18
+ * counter.inc('user-2');
19
+ *
20
+ * console.log(counter.getCount('user-1')); // 2
21
+ * console.log(counter.getCount('user-2')); // 1
22
+ * console.log(counter.getCount('user-3')); // 0
23
+ *
24
+ * // After some time, decrement
25
+ * counter.dec('user-1');
26
+ * console.log(counter.getCount('user-1')); // 1
27
+ * ```
28
+ */
29
+ declare class SimpleRateLimitCounter implements RateLimitCounter {
30
+ private readonly counterMap;
31
+ /**
32
+ * Creates a new SimpleRateLimitCounter instance.
33
+ *
34
+ * @param {Map<string, number>} [counterMap=new Map()] - Optional existing Map to use for storage
35
+ */
36
+ constructor(counterMap?: Map<string, number>);
37
+ /**
38
+ * Gets the current count for a key.
39
+ *
40
+ * @param {string} key - The key to get count for
41
+ * @returns {number} The current count (0 if key doesn't exist)
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const counter = new SimpleRateLimitCounter();
46
+ * console.log(counter.getCount('key')); // 0
47
+ * counter.inc('key');
48
+ * console.log(counter.getCount('key')); // 1
49
+ * ```
50
+ */
51
+ getCount(key: string): number;
52
+ /**
53
+ * Increments the count for a key.
54
+ *
55
+ * @param {string} key - The key to increment
56
+ * @returns {void}
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const counter = new SimpleRateLimitCounter();
61
+ * counter.inc('user-123');
62
+ * counter.inc('user-123');
63
+ * console.log(counter.getCount('user-123')); // 2
64
+ * ```
65
+ */
66
+ inc(key: string): void;
67
+ /**
68
+ * Decrements the count for a key.
69
+ * Removes the key from the map if count reaches 0.
70
+ *
71
+ * @param {string} key - The key to decrement
72
+ * @returns {void}
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const counter = new SimpleRateLimitCounter();
77
+ * counter.inc('key');
78
+ * counter.inc('key');
79
+ * counter.dec('key');
80
+ * console.log(counter.getCount('key')); // 1
81
+ * counter.dec('key');
82
+ * console.log(counter.getCount('key')); // 0 (key removed from map)
83
+ * ```
84
+ */
85
+ dec(key: string): void;
86
+ }
87
+ //#endregion
88
+ export { SimpleRateLimitCounter };
89
+ //# sourceMappingURL=simple-rate-limit-counter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-rate-limit-counter.d.ts","names":[],"sources":["../../src/rate-limit/simple-rate-limit-counter.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;cA2Ca,sBAAA,YAAkC,gBAAA;EAAA,iBAMhB,UAAA;;;;;;cAAA,UAAA,GAAU,GAAA;;;;;;;;;;;;;;;EAgBvC,QAAA,CAAS,GAAA;;;;;;;;;;;;;;;EAkBT,GAAA,CAAI,GAAA;;;;;;;;;;;;;;;;;;;EA0BJ,GAAA,CAAI,GAAA;AAAA"}
@@ -0,0 +1,98 @@
1
+ //#region src/rate-limit/simple-rate-limit-counter.ts
2
+ /**
3
+ * Simple in-memory implementation of RateLimitCounter.
4
+ * Uses a Map to store counts for each key.
5
+ *
6
+ * @class SimpleRateLimitCounter
7
+ * @implements {RateLimitCounter}
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const counter = new SimpleRateLimitCounter();
12
+ *
13
+ * // Track API calls per user
14
+ * counter.inc('user-1');
15
+ * counter.inc('user-1');
16
+ * counter.inc('user-2');
17
+ *
18
+ * console.log(counter.getCount('user-1')); // 2
19
+ * console.log(counter.getCount('user-2')); // 1
20
+ * console.log(counter.getCount('user-3')); // 0
21
+ *
22
+ * // After some time, decrement
23
+ * counter.dec('user-1');
24
+ * console.log(counter.getCount('user-1')); // 1
25
+ * ```
26
+ */
27
+ var SimpleRateLimitCounter = class {
28
+ /**
29
+ * Creates a new SimpleRateLimitCounter instance.
30
+ *
31
+ * @param {Map<string, number>} [counterMap=new Map()] - Optional existing Map to use for storage
32
+ */
33
+ constructor(counterMap = /* @__PURE__ */ new Map()) {
34
+ this.counterMap = counterMap;
35
+ }
36
+ /**
37
+ * Gets the current count for a key.
38
+ *
39
+ * @param {string} key - The key to get count for
40
+ * @returns {number} The current count (0 if key doesn't exist)
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const counter = new SimpleRateLimitCounter();
45
+ * console.log(counter.getCount('key')); // 0
46
+ * counter.inc('key');
47
+ * console.log(counter.getCount('key')); // 1
48
+ * ```
49
+ */
50
+ getCount(key) {
51
+ return this.counterMap.get(key) ?? 0;
52
+ }
53
+ /**
54
+ * Increments the count for a key.
55
+ *
56
+ * @param {string} key - The key to increment
57
+ * @returns {void}
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const counter = new SimpleRateLimitCounter();
62
+ * counter.inc('user-123');
63
+ * counter.inc('user-123');
64
+ * console.log(counter.getCount('user-123')); // 2
65
+ * ```
66
+ */
67
+ inc(key) {
68
+ if (!this.counterMap.has(key)) this.counterMap.set(key, 0);
69
+ this.counterMap.set(key, (this.counterMap.get(key) ?? 0) + 1);
70
+ }
71
+ /**
72
+ * Decrements the count for a key.
73
+ * Removes the key from the map if count reaches 0.
74
+ *
75
+ * @param {string} key - The key to decrement
76
+ * @returns {void}
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const counter = new SimpleRateLimitCounter();
81
+ * counter.inc('key');
82
+ * counter.inc('key');
83
+ * counter.dec('key');
84
+ * console.log(counter.getCount('key')); // 1
85
+ * counter.dec('key');
86
+ * console.log(counter.getCount('key')); // 0 (key removed from map)
87
+ * ```
88
+ */
89
+ dec(key) {
90
+ const currentCount = this.counterMap.get(key);
91
+ if (currentCount !== void 0) if (currentCount <= 1) this.counterMap.delete(key);
92
+ else this.counterMap.set(key, currentCount - 1);
93
+ }
94
+ };
95
+ //#endregion
96
+ export { SimpleRateLimitCounter };
97
+
98
+ //# sourceMappingURL=simple-rate-limit-counter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-rate-limit-counter.js","names":[],"sources":["../../src/rate-limit/simple-rate-limit-counter.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 { RateLimitCounter } from './index.js';\n\n/**\n * Simple in-memory implementation of RateLimitCounter.\n * Uses a Map to store counts for each key.\n *\n * @class SimpleRateLimitCounter\n * @implements {RateLimitCounter}\n *\n * @example\n * ```typescript\n * const counter = new SimpleRateLimitCounter();\n *\n * // Track API calls per user\n * counter.inc('user-1');\n * counter.inc('user-1');\n * counter.inc('user-2');\n *\n * console.log(counter.getCount('user-1')); // 2\n * console.log(counter.getCount('user-2')); // 1\n * console.log(counter.getCount('user-3')); // 0\n *\n * // After some time, decrement\n * counter.dec('user-1');\n * console.log(counter.getCount('user-1')); // 1\n * ```\n */\nexport class SimpleRateLimitCounter implements RateLimitCounter {\n /**\n * Creates a new SimpleRateLimitCounter instance.\n *\n * @param {Map<string, number>} [counterMap=new Map()] - Optional existing Map to use for storage\n */\n constructor(private readonly counterMap = new Map<string, number>()) {}\n\n /**\n * Gets the current count for a key.\n *\n * @param {string} key - The key to get count for\n * @returns {number} The current count (0 if key doesn't exist)\n *\n * @example\n * ```typescript\n * const counter = new SimpleRateLimitCounter();\n * console.log(counter.getCount('key')); // 0\n * counter.inc('key');\n * console.log(counter.getCount('key')); // 1\n * ```\n */\n getCount(key: string): number {\n return this.counterMap.get(key) ?? 0;\n }\n\n /**\n * Increments the count for a key.\n *\n * @param {string} key - The key to increment\n * @returns {void}\n *\n * @example\n * ```typescript\n * const counter = new SimpleRateLimitCounter();\n * counter.inc('user-123');\n * counter.inc('user-123');\n * console.log(counter.getCount('user-123')); // 2\n * ```\n */\n inc(key: string): void {\n if (!this.counterMap.has(key)) {\n this.counterMap.set(key, 0);\n }\n\n this.counterMap.set(key, (this.counterMap.get(key) ?? 0) + 1);\n }\n\n /**\n * Decrements the count for a key.\n * Removes the key from the map if count reaches 0.\n *\n * @param {string} key - The key to decrement\n * @returns {void}\n *\n * @example\n * ```typescript\n * const counter = new SimpleRateLimitCounter();\n * counter.inc('key');\n * counter.inc('key');\n * counter.dec('key');\n * console.log(counter.getCount('key')); // 1\n * counter.dec('key');\n * console.log(counter.getCount('key')); // 0 (key removed from map)\n * ```\n */\n dec(key: string): void {\n const currentCount = this.counterMap.get(key);\n\n if (currentCount !== undefined) {\n if (currentCount <= 1) {\n this.counterMap.delete(key);\n } else {\n this.counterMap.set(key, currentCount - 1);\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,IAAa,yBAAb,MAAgE;;;;;;CAM9D,YAAY,6BAA8B,IAAI,KAAqB,EAAE;AAAxC,OAAA,aAAA;;;;;;;;;;;;;;;;CAgB7B,SAAS,KAAqB;AAC5B,SAAO,KAAK,WAAW,IAAI,IAAI,IAAI;;;;;;;;;;;;;;;;CAiBrC,IAAI,KAAmB;AACrB,MAAI,CAAC,KAAK,WAAW,IAAI,IAAI,CAC3B,MAAK,WAAW,IAAI,KAAK,EAAE;AAG7B,OAAK,WAAW,IAAI,MAAM,KAAK,WAAW,IAAI,IAAI,IAAI,KAAK,EAAE;;;;;;;;;;;;;;;;;;;;CAqB/D,IAAI,KAAmB;EACrB,MAAM,eAAe,KAAK,WAAW,IAAI,IAAI;AAE7C,MAAI,iBAAiB,KAAA,EACnB,KAAI,gBAAgB,EAClB,MAAK,WAAW,OAAO,IAAI;MAE3B,MAAK,WAAW,IAAI,KAAK,eAAe,EAAE"}
@@ -0,0 +1,3 @@
1
+ import { readonly } from "./readonly.js";
2
+ import { Readonlyable } from "./readonly.types.js";
3
+ export { Readonlyable, readonly };
@@ -0,0 +1,2 @@
1
+ import { readonly } from "./readonly.js";
2
+ export { readonly };
@@ -0,0 +1,39 @@
1
+ import { Readonlyable } from "./readonly.types.js";
2
+
3
+ //#region src/readonly/readonly.d.ts
4
+ /**
5
+ * Decorator that makes a method read-only (non-writable).
6
+ * Prevents the method from being reassigned after class instantiation.
7
+ *
8
+ * @template T - The type of the class containing the decorated method
9
+ * @returns {Readonlyable<T>} The decorator function
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * class SecureApi {
14
+ * @readonly()
15
+ * authenticate(): Promise<AuthToken> {
16
+ * return this.performAuth();
17
+ * }
18
+ *
19
+ * @readonly()
20
+ * getBaseUrl(): string {
21
+ * return 'https://api.example.com';
22
+ * }
23
+ * }
24
+ *
25
+ * const api = new SecureApi();
26
+ *
27
+ * // These will throw TypeError
28
+ * // api.authenticate = () => Promise.resolve(fakeToken);
29
+ * // api.getBaseUrl = () => 'https://evil.com';
30
+ *
31
+ * // Calling the methods works normally
32
+ * const token = await api.authenticate();
33
+ * const url = api.getBaseUrl();
34
+ * ```
35
+ */
36
+ declare function readonly<T = any>(): Readonlyable<T>;
37
+ //#endregion
38
+ export { readonly };
39
+ //# sourceMappingURL=readonly.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readonly.d.ts","names":[],"sources":["../../src/readonly/readonly.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmDgB,QAAA,SAAA,CAAA,GAAqB,YAAA,CAAa,CAAA"}
@@ -0,0 +1,43 @@
1
+ //#region src/readonly/readonly.ts
2
+ /**
3
+ * Decorator that makes a method read-only (non-writable).
4
+ * Prevents the method from being reassigned after class instantiation.
5
+ *
6
+ * @template T - The type of the class containing the decorated method
7
+ * @returns {Readonlyable<T>} The decorator function
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * class SecureApi {
12
+ * @readonly()
13
+ * authenticate(): Promise<AuthToken> {
14
+ * return this.performAuth();
15
+ * }
16
+ *
17
+ * @readonly()
18
+ * getBaseUrl(): string {
19
+ * return 'https://api.example.com';
20
+ * }
21
+ * }
22
+ *
23
+ * const api = new SecureApi();
24
+ *
25
+ * // These will throw TypeError
26
+ * // api.authenticate = () => Promise.resolve(fakeToken);
27
+ * // api.getBaseUrl = () => 'https://evil.com';
28
+ *
29
+ * // Calling the methods works normally
30
+ * const token = await api.authenticate();
31
+ * const url = api.getBaseUrl();
32
+ * ```
33
+ */
34
+ function readonly() {
35
+ return (target, key, descriptor) => {
36
+ descriptor.writable = false;
37
+ return descriptor;
38
+ };
39
+ }
40
+ //#endregion
41
+ export { readonly };
42
+
43
+ //# sourceMappingURL=readonly.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readonly.js","names":[],"sources":["../../src/readonly/readonly.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';\nimport type { Readonlyable } from './index.js';\n\n/**\n * Decorator that makes a method read-only (non-writable).\n * Prevents the method from being reassigned after class instantiation.\n *\n * @template T - The type of the class containing the decorated method\n * @returns {Readonlyable<T>} The decorator function\n *\n * @example\n * ```typescript\n * class SecureApi {\n * @readonly()\n * authenticate(): Promise<AuthToken> {\n * return this.performAuth();\n * }\n *\n * @readonly()\n * getBaseUrl(): string {\n * return 'https://api.example.com';\n * }\n * }\n *\n * const api = new SecureApi();\n *\n * // These will throw TypeError\n * // api.authenticate = () => Promise.resolve(fakeToken);\n * // api.getBaseUrl = () => 'https://evil.com';\n *\n * // Calling the methods works normally\n * const token = await api.authenticate();\n * const url = api.getBaseUrl();\n * ```\n */\nexport function readonly<T = any>(): Readonlyable<T> {\n return (\n target: T,\n key: keyof T,\n descriptor: TypedPropertyDescriptor<Method<any>>,\n ): TypedPropertyDescriptor<Method<any>> => {\n descriptor.writable = false;\n\n return descriptor;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,SAAgB,WAAqC;AACnD,SACE,QACA,KACA,eACyC;AACzC,aAAW,WAAW;AAEtB,SAAO"}
@@ -0,0 +1,40 @@
1
+ //#region src/readonly/readonly.types.d.ts
2
+ /**
3
+ * Copyright 2026 ResQ
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Type for decorators that make methods read-only.
19
+ *
20
+ * @template T - The type of the class containing the decorated method
21
+ *
22
+ * @param {T} target - The class prototype
23
+ * @param {keyof T} propertyName - The name of the method being decorated
24
+ * @param {PropertyDescriptor} descriptor - The property descriptor
25
+ * @returns {PropertyDescriptor} The modified descriptor with writable set to false
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * type ReadonlyMethod = Readonlyable<MyClass>;
30
+ *
31
+ * const decorator: ReadonlyMethod = (target, key, descriptor) => {
32
+ * descriptor.writable = false;
33
+ * return descriptor;
34
+ * };
35
+ * ```
36
+ */
37
+ type Readonlyable<T = any> = (target: T, propertyName: keyof T, descriptor: PropertyDescriptor) => PropertyDescriptor;
38
+ //#endregion
39
+ export { Readonlyable };
40
+ //# sourceMappingURL=readonly.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readonly.types.d.ts","names":[],"sources":["../../src/readonly/readonly.types.ts"],"mappings":";;AAoCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAAY,YAAA,aACV,MAAA,EAAQ,CAAA,EACR,YAAA,QAAoB,CAAA,EACpB,UAAA,EAAY,kBAAA,KACT,kBAAA"}
File without changes
@@ -0,0 +1,2 @@
1
+ import { throttle } from "./throttle.js";
2
+ export { throttle };
@@ -0,0 +1,2 @@
1
+ import { throttle } from "./throttle.js";
2
+ export { throttle };
@@ -0,0 +1,35 @@
1
+ import { Decorator } from "../types.js";
2
+
3
+ //#region src/throttle/throttle.d.ts
4
+ /**
5
+ * Decorator that throttles method calls to once per specified time period.
6
+ *
7
+ * @template T - The type of the class containing the decorated method
8
+ * @param {number} delayMs - The throttle interval 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 ResizeHandler {
16
+ * private width = window.innerWidth;
17
+ * private height = window.innerHeight;
18
+ *
19
+ * @throttle(200)
20
+ * handleResize(): void {
21
+ * this.width = window.innerWidth;
22
+ * this.height = window.innerHeight;
23
+ * this.render();
24
+ * }
25
+ * }
26
+ *
27
+ * const handler = new ResizeHandler();
28
+ * window.addEventListener('resize', () => handler.handleResize());
29
+ * // handleResize executes at most once every 200ms during resize
30
+ * ```
31
+ */
32
+ declare function throttle<T = any>(delayMs: number): Decorator<T>;
33
+ //#endregion
34
+ export { throttle };
35
+ //# sourceMappingURL=throttle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"throttle.d.ts","names":[],"sources":["../../src/throttle/throttle.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+CgB,QAAA,SAAA,CAAkB,OAAA,WAAkB,SAAA,CAAU,CAAA"}
@@ -0,0 +1,42 @@
1
+ import { Method } from "../types.js";
2
+
3
+ //#region src/throttle/throttle.fn.d.ts
4
+ /**
5
+ * Wraps a method to throttle its execution to once per time period.
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 throttle
10
+ * @param {number} delayMs - The throttle interval in milliseconds
11
+ * @returns {Method<void, A>} The throttled method
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * class ScrollTracker {
16
+ * scrollY = 0;
17
+ *
18
+ * updatePosition(y: number): void {
19
+ * this.scrollY = y;
20
+ * console.log('Position updated:', y);
21
+ * }
22
+ * }
23
+ *
24
+ * const tracker = new ScrollTracker();
25
+ *
26
+ * // Throttle to once per 100ms
27
+ * const throttledUpdate = throttleFn(
28
+ * tracker.updatePosition.bind(tracker),
29
+ * 100
30
+ * );
31
+ *
32
+ * // Rapid scroll events
33
+ * window.addEventListener('scroll', (e) => {
34
+ * throttledUpdate(window.scrollY);
35
+ * // Only logs once every 100ms even during rapid scrolling
36
+ * });
37
+ * ```
38
+ */
39
+ declare function throttleFn<D = any, A extends any[] = any[]>(originalMethod: Method<D, A>, delayMs: number): Method<void, A>;
40
+ //#endregion
41
+ export { throttleFn };
42
+ //# sourceMappingURL=throttle.fn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"throttle.fn.d.ts","names":[],"sources":["../../src/throttle/throttle.fn.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqDgB,UAAA,kCAAA,CACd,cAAA,EAAgB,MAAA,CAAO,CAAA,EAAG,CAAA,GAC1B,OAAA,WACC,MAAA,OAAa,CAAA"}
@@ -0,0 +1,52 @@
1
+ //#region src/throttle/throttle.fn.ts
2
+ /**
3
+ * Wraps a method to throttle its execution to once per time period.
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 throttle
8
+ * @param {number} delayMs - The throttle interval in milliseconds
9
+ * @returns {Method<void, A>} The throttled method
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * class ScrollTracker {
14
+ * scrollY = 0;
15
+ *
16
+ * updatePosition(y: number): void {
17
+ * this.scrollY = y;
18
+ * console.log('Position updated:', y);
19
+ * }
20
+ * }
21
+ *
22
+ * const tracker = new ScrollTracker();
23
+ *
24
+ * // Throttle to once per 100ms
25
+ * const throttledUpdate = throttleFn(
26
+ * tracker.updatePosition.bind(tracker),
27
+ * 100
28
+ * );
29
+ *
30
+ * // Rapid scroll events
31
+ * window.addEventListener('scroll', (e) => {
32
+ * throttledUpdate(window.scrollY);
33
+ * // Only logs once every 100ms even during rapid scrolling
34
+ * });
35
+ * ```
36
+ */
37
+ function throttleFn(originalMethod, delayMs) {
38
+ let throttling = false;
39
+ return function(...args) {
40
+ if (!throttling) {
41
+ throttling = true;
42
+ originalMethod.apply(this, args);
43
+ setTimeout(() => {
44
+ throttling = false;
45
+ }, delayMs);
46
+ }
47
+ };
48
+ }
49
+ //#endregion
50
+ export { throttleFn };
51
+
52
+ //# sourceMappingURL=throttle.fn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"throttle.fn.js","names":[],"sources":["../../src/throttle/throttle.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 throttle its execution to once per time period.\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 throttle\n * @param {number} delayMs - The throttle interval in milliseconds\n * @returns {Method<void, A>} The throttled method\n *\n * @example\n * ```typescript\n * class ScrollTracker {\n * scrollY = 0;\n *\n * updatePosition(y: number): void {\n * this.scrollY = y;\n * console.log('Position updated:', y);\n * }\n * }\n *\n * const tracker = new ScrollTracker();\n *\n * // Throttle to once per 100ms\n * const throttledUpdate = throttleFn(\n * tracker.updatePosition.bind(tracker),\n * 100\n * );\n *\n * // Rapid scroll events\n * window.addEventListener('scroll', (e) => {\n * throttledUpdate(window.scrollY);\n * // Only logs once every 100ms even during rapid scrolling\n * });\n * ```\n */\nexport function throttleFn<D = any, A extends any[] = any[]>(\n originalMethod: Method<D, A>,\n delayMs: number,\n): Method<void, A> {\n let throttling = false;\n return function (this: any, ...args: A): void {\n if (!throttling) {\n throttling = true;\n originalMethod.apply(this, args);\n\n setTimeout(() => {\n throttling = false;\n }, delayMs);\n }\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,SAAgB,WACd,gBACA,SACiB;CACjB,IAAI,aAAa;AACjB,QAAO,SAAqB,GAAG,MAAe;AAC5C,MAAI,CAAC,YAAY;AACf,gBAAa;AACb,kBAAe,MAAM,MAAM,KAAK;AAEhC,oBAAiB;AACf,iBAAa;MACZ,QAAQ"}