@lara-node/cache 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.
- package/dist/index.cjs +796 -0
- package/dist/index.d.cts +227 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +227 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +754 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { ServiceProvider } from "@lara-node/core";
|
|
2
|
+
|
|
3
|
+
//#region src/RateLimiter.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Rate Limiter - Laravel-style rate limiting using cache drivers
|
|
7
|
+
*
|
|
8
|
+
* Supports multiple algorithms:
|
|
9
|
+
* - Fixed Window: Simple counter reset after window expires
|
|
10
|
+
* - Sliding Window: More accurate rate limiting using timestamps
|
|
11
|
+
* - Token Bucket: Gradual replenishment of tokens
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* import { RateLimiter } from '@/cache/RateLimiter';
|
|
15
|
+
*
|
|
16
|
+
* // Check if too many attempts
|
|
17
|
+
* const limiter = new RateLimiter();
|
|
18
|
+
* if (await limiter.tooManyAttempts('login:user@example.com', 5, 60)) {
|
|
19
|
+
* const retryAfter = await limiter.availableIn('login:user@example.com', 60);
|
|
20
|
+
* throw new Error(`Too many attempts. Retry after ${retryAfter} seconds.`);
|
|
21
|
+
* }
|
|
22
|
+
* await limiter.hit('login:user@example.com', 60);
|
|
23
|
+
*/
|
|
24
|
+
interface RateLimiterConfig {
|
|
25
|
+
/** Prefix for rate limiter cache keys */
|
|
26
|
+
prefix?: string;
|
|
27
|
+
/** Default max attempts */
|
|
28
|
+
maxAttempts?: number;
|
|
29
|
+
/** Default decay time in seconds */
|
|
30
|
+
decaySeconds?: number;
|
|
31
|
+
}
|
|
32
|
+
interface RateLimitInfo {
|
|
33
|
+
/** Whether the rate limit has been exceeded */
|
|
34
|
+
limited: boolean;
|
|
35
|
+
/** Current number of attempts */
|
|
36
|
+
attempts: number;
|
|
37
|
+
/** Maximum allowed attempts */
|
|
38
|
+
maxAttempts: number;
|
|
39
|
+
/** Remaining attempts */
|
|
40
|
+
remaining: number;
|
|
41
|
+
/** Seconds until the rate limit resets */
|
|
42
|
+
retryAfter: number;
|
|
43
|
+
/** Timestamp when the rate limit resets (Unix timestamp in seconds) */
|
|
44
|
+
resetsAt: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Rate Limiter class using cache backend
|
|
48
|
+
*/
|
|
49
|
+
declare class RateLimiter {
|
|
50
|
+
private prefix;
|
|
51
|
+
private defaultMaxAttempts;
|
|
52
|
+
private defaultDecaySeconds;
|
|
53
|
+
constructor(config?: RateLimiterConfig);
|
|
54
|
+
/**
|
|
55
|
+
* Get the cache key for a given key
|
|
56
|
+
*/
|
|
57
|
+
private cacheKey;
|
|
58
|
+
/**
|
|
59
|
+
* Get the timer cache key for a given key (stores the reset timestamp)
|
|
60
|
+
*/
|
|
61
|
+
private timerKey;
|
|
62
|
+
/**
|
|
63
|
+
* Determine if the given key has been "accessed" too many times
|
|
64
|
+
*/
|
|
65
|
+
tooManyAttempts(key: string, maxAttempts?: number, _decaySeconds?: number): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Increment the counter for a given key
|
|
68
|
+
* Returns the new number of attempts
|
|
69
|
+
*/
|
|
70
|
+
hit(key: string, decaySeconds?: number): Promise<number>;
|
|
71
|
+
/**
|
|
72
|
+
* Get the number of attempts for the given key
|
|
73
|
+
*/
|
|
74
|
+
attempts(key: string): Promise<number>;
|
|
75
|
+
/**
|
|
76
|
+
* Reset the number of attempts for the given key
|
|
77
|
+
*/
|
|
78
|
+
resetAttempts(key: string): Promise<boolean>;
|
|
79
|
+
/**
|
|
80
|
+
* Get the number of retries remaining
|
|
81
|
+
*/
|
|
82
|
+
retriesLeft(key: string, maxAttempts?: number): Promise<number>;
|
|
83
|
+
/**
|
|
84
|
+
* Clear the hits and lockout timer for the given key
|
|
85
|
+
*/
|
|
86
|
+
clear(key: string): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Get the number of seconds until the key is accessible again
|
|
89
|
+
*/
|
|
90
|
+
availableIn(key: string, _decaySeconds?: number): Promise<number>;
|
|
91
|
+
/**
|
|
92
|
+
* Get the timestamp when the key becomes available again
|
|
93
|
+
*/
|
|
94
|
+
availableAt(key: string): Promise<number>;
|
|
95
|
+
/**
|
|
96
|
+
* Attempt to execute a callback if the rate limit allows
|
|
97
|
+
* Returns the callback result or throws if rate limited
|
|
98
|
+
*/
|
|
99
|
+
attempt<T>(key: string, maxAttempts: number, callback: () => T | Promise<T>, decaySeconds?: number): Promise<T>;
|
|
100
|
+
/**
|
|
101
|
+
* Get complete rate limit info for a key
|
|
102
|
+
*/
|
|
103
|
+
getInfo(key: string, maxAttempts?: number, decaySeconds?: number): Promise<RateLimitInfo>;
|
|
104
|
+
/**
|
|
105
|
+
* Execute a callback with rate limiting, using a limiter definition
|
|
106
|
+
*/
|
|
107
|
+
limiter<T>(name: string, key: string, maxAttempts: number, decaySeconds: number, callback: () => T | Promise<T>): Promise<T>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Exception thrown when rate limit is exceeded
|
|
111
|
+
*/
|
|
112
|
+
declare class RateLimitExceededException extends Error {
|
|
113
|
+
readonly retryAfter: number;
|
|
114
|
+
readonly maxAttempts: number;
|
|
115
|
+
readonly statusCode: number;
|
|
116
|
+
constructor(message: string, retryAfter: number, maxAttempts: number);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Register a named rate limiter
|
|
120
|
+
*/
|
|
121
|
+
declare function defineRateLimiter(name: string, config: () => {
|
|
122
|
+
maxAttempts: number;
|
|
123
|
+
decaySeconds: number;
|
|
124
|
+
}): void;
|
|
125
|
+
/**
|
|
126
|
+
* Get a named rate limiter configuration
|
|
127
|
+
*/
|
|
128
|
+
declare function getNamedLimiter(name: string): {
|
|
129
|
+
maxAttempts: number;
|
|
130
|
+
decaySeconds: number;
|
|
131
|
+
} | null;
|
|
132
|
+
declare const RateLimiterFacade: {
|
|
133
|
+
/** Check if too many attempts have been made */
|
|
134
|
+
tooManyAttempts: (key: string, maxAttempts?: number, decaySeconds?: number) => Promise<boolean>;
|
|
135
|
+
/** Increment the attempt counter */
|
|
136
|
+
hit: (key: string, decaySeconds?: number) => Promise<number>;
|
|
137
|
+
/** Get current number of attempts */
|
|
138
|
+
attempts: (key: string) => Promise<number>;
|
|
139
|
+
/** Reset attempt counter */
|
|
140
|
+
resetAttempts: (key: string) => Promise<boolean>;
|
|
141
|
+
/** Get remaining retries */
|
|
142
|
+
retriesLeft: (key: string, maxAttempts?: number) => Promise<number>;
|
|
143
|
+
/** Clear rate limiter for key */
|
|
144
|
+
clear: (key: string) => Promise<void>;
|
|
145
|
+
/** Get seconds until rate limit resets */
|
|
146
|
+
availableIn: (key: string, decaySeconds?: number) => Promise<number>;
|
|
147
|
+
/** Get timestamp when rate limit resets */
|
|
148
|
+
availableAt: (key: string) => Promise<number>;
|
|
149
|
+
/** Attempt to execute callback with rate limiting */
|
|
150
|
+
attempt: <T>(key: string, maxAttempts: number, callback: () => T | Promise<T>, decaySeconds?: number) => Promise<T>;
|
|
151
|
+
/** Get rate limit info for a key */
|
|
152
|
+
getInfo: (key: string, maxAttempts?: number, decaySeconds?: number) => Promise<RateLimitInfo>;
|
|
153
|
+
/** Define a named rate limiter */
|
|
154
|
+
define: typeof defineRateLimiter;
|
|
155
|
+
/** Get named limiter config */
|
|
156
|
+
limiter: typeof getNamedLimiter;
|
|
157
|
+
/** Execute with named limiter */
|
|
158
|
+
for: <T>(name: string, key: string, callback: () => T | Promise<T>) => Promise<T>;
|
|
159
|
+
};
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/CacheManager.d.ts
|
|
162
|
+
/** Optional watcher hook — registered by @lara-node/telescope at boot to avoid circular deps. */
|
|
163
|
+
type CacheEventType = "get" | "set" | "del" | "has" | "clear";
|
|
164
|
+
interface CacheWatchEvent {
|
|
165
|
+
type: CacheEventType;
|
|
166
|
+
key: string;
|
|
167
|
+
hit?: boolean;
|
|
168
|
+
value?: any;
|
|
169
|
+
ttlSeconds?: number | null;
|
|
170
|
+
}
|
|
171
|
+
declare function setCacheWatchHook(hook: (event: CacheWatchEvent) => void): void;
|
|
172
|
+
interface CacheDriver {
|
|
173
|
+
init(): Promise<void>;
|
|
174
|
+
get(key: string): Promise<any | null>;
|
|
175
|
+
set(key: string, value: any, ttlSeconds?: number | null): Promise<void>;
|
|
176
|
+
del(key: string): Promise<boolean>;
|
|
177
|
+
has(key: string): Promise<boolean>;
|
|
178
|
+
clear(): Promise<void>;
|
|
179
|
+
keys(): Promise<string[]>;
|
|
180
|
+
}
|
|
181
|
+
declare function generateCacheKey(...parts: Array<string | number | boolean | Date | null | undefined>): string;
|
|
182
|
+
declare class CacheManager implements CacheDriver {
|
|
183
|
+
private driver;
|
|
184
|
+
private initializing;
|
|
185
|
+
private createDriver;
|
|
186
|
+
private ensureInit;
|
|
187
|
+
init(): Promise<void>;
|
|
188
|
+
get(key: string): Promise<any>;
|
|
189
|
+
set(key: string, value: any, ttlSeconds?: number | null): Promise<void>;
|
|
190
|
+
del(key: string): Promise<boolean>;
|
|
191
|
+
has(key: string): Promise<boolean>;
|
|
192
|
+
clear(): Promise<void>;
|
|
193
|
+
keys(): Promise<string[]>;
|
|
194
|
+
}
|
|
195
|
+
declare const Cache: {
|
|
196
|
+
get: (k: string) => Promise<any>;
|
|
197
|
+
set: (k: string, v: any, ttlSeconds?: number | null) => Promise<void>;
|
|
198
|
+
del: (k: string) => Promise<boolean>;
|
|
199
|
+
has: (k: string) => Promise<boolean>;
|
|
200
|
+
clear: () => Promise<void>;
|
|
201
|
+
keys: () => Promise<string[]>;
|
|
202
|
+
forget: (k: string) => Promise<boolean>;
|
|
203
|
+
flush: () => Promise<void>;
|
|
204
|
+
remember: <T>(key: string, ttlSeconds: number | null, callback: () => Promise<T>) => Promise<T>;
|
|
205
|
+
};
|
|
206
|
+
declare const getCacheDriverName: () => string;
|
|
207
|
+
declare const getCacheDriver: () => CacheManager;
|
|
208
|
+
declare const initCache: () => Promise<void>;
|
|
209
|
+
declare const cacheGet: (k: string) => Promise<any>;
|
|
210
|
+
declare const cacheSet: (k: string, v: any, ttlSeconds?: number | null) => Promise<void>;
|
|
211
|
+
declare const cacheDel: (k: string) => Promise<boolean>;
|
|
212
|
+
declare const cacheHas: (k: string) => Promise<boolean>;
|
|
213
|
+
declare const cacheClear: () => Promise<void>;
|
|
214
|
+
declare const cacheKeys: () => Promise<string[]>;
|
|
215
|
+
declare const cacheDelPrefix: (prefix: string) => Promise<number>;
|
|
216
|
+
//# sourceMappingURL=CacheManager.d.ts.map
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/CacheServiceProvider.d.ts
|
|
219
|
+
declare class CacheServiceProvider extends ServiceProvider {
|
|
220
|
+
register(): void;
|
|
221
|
+
boot(): Promise<void>;
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=CacheServiceProvider.d.ts.map
|
|
224
|
+
|
|
225
|
+
//#endregion
|
|
226
|
+
export { Cache, type CacheDriver, CacheServiceProvider, RateLimitExceededException, type RateLimitInfo, RateLimiter, type RateLimiterConfig, RateLimiterFacade, cacheClear, cacheDel, cacheDelPrefix, cacheGet, cacheHas, cacheKeys, cacheSet, defineRateLimiter, generateCacheKey, getCacheDriver, getCacheDriverName, getNamedLimiter, initCache, setCacheWatchHook };
|
|
227
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/RateLimiter.ts","../src/CacheManager.ts","../src/CacheServiceProvider.ts"],"mappings":";;;;;;;AAsBA;AASA;AAkBA;;;;;;;;;;;;;;AA8Ia,UAzKI,iBAAA,CAyKJ;;QAmBsE,CAAA,EAAA,MAAA;;aA0B/D,CAAA,EAAA,MAAA;;cAAI,CAAA,EAAA,MAAA;;AACnB,UA9MY,aAAA,CA8MZ;EAAO;EASC,OAAA,EAAA,OAAA;EAmBG;EAUA,QAAA,EAAA,MAAA;EAWH;EAoDZ,WAAA,EAAA,MAAA;;WA9CyC,EAAA,MAAA;;YAMb,EAAA,MAAA;;UAMR,EAAA,MAAA;;;;;AAYG,cA3QX,WAAA,CA2QW;UACC,MAAA;UAAA,kBAAA;UAI2C,mBAAA;aAAA,CAAA,MAAA,CAAA,EA3Q9C,iBA2Q8C;;;;UAUI,QAAA;;;;EAAY,QAAA,QAAA;;;;EClU/E,eAAA,CAAA,GAAc,EAAA,MAAA,EAAA,WAAA,CAAA,EAAA,MAAA,EAAA,aAAA,CAAA,EAAA,MAAA,CAAA,EDwEd,OCxEc,CAAA,OAAA,CAAA;EACT;AAQV;AAsBA;;KACU,CAAA,GAAA,EAAA,MAAA,EAAA,YAAA,CAAA,EAAA,MAAA,CAAA,EDyDuC,OCzDvC,CAAA,MAAA,CAAA;;;;UAIU,CAAA,GAAA,EAAA,MAAA,CAAA,EDqFW,OCrFX,CAAA,MAAA,CAAA;;;AAEH;EAkGD,aAAA,CAAA,GAAA,EAAgB,MAAA,CAAA,EDPI,OCOJ,CAAA,OAAA,CAAA;EAAA;;;EACf,WAAA,CAAA,GAAA,EAAA,MAAA,EAAA,WAAA,CAAA,EAAA,MAAA,CAAA,EDCuC,OCDvC,CAAA,MAAA,CAAA;EAkTX;;;OA2BiB,CAAA,GAAA,EAAA,MAAA,CAAA,EDnUK,OCmUL,CAAA,IAAA,CAAA;;;;aAoBV,CAAA,GAAA,EAAA,MAAA,EAAA,aAAA,CAAA,EAAA,MAAA,CAAA,EDhV6C,OCgV7C,CAAA,MAAA,CAAA;;;AA/C4B;EA+D5B,WAkDZ,CAAA,GAAA,EAAA,MAAA,CAAA,EDpYiC,OCoYjC,CAAA,MAAA,CAAA;EAAA;;;;SAnCsB,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,MAAA,EAAA,WAAA,EAAA,MAAA,EAAA,QAAA,EAAA,GAAA,GDrVH,CCqVG,GDrVC,OCqVD,CDrVS,CCqVT,CAAA,EAAA,YAAA,CAAA,EAAA,MAAA,CAAA,EDnVlB,OCmVkB,CDnVV,CCmVU,CAAA;;;;qEDhUoD,QAAQ;;;;SCuV9E,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,EAAA,WAAA,EAAA,MAAA,EAAA,YAAA,EAAA,MAAA,EAAA,QAAA,EAAA,GAAA,GD7Te,CC6Tf,GD7TmB,OC6TnB,CD7T2B,CC6T3B,CAAA,CAAA,ED5TA,OC4TA,CD5TQ,CC4TR,CAAA;AAAO;AAeZ;AAKA;AAGA;AACa,cD3UA,0BAAA,SAAmC,KAAK,CC2Ub;EAC3B,SAAA,UACkB,EAAA,MAD6C;EAE/D,SAAA,WAA8C,EAAnB,MAAA;EAC3B,SAAA,UAA8C,EAAA,MAAnB;EAC3B,WAAA,CAAA,OAAwC,EAAA,MAA9B,EAAA,UAAA,EAAA,MAAA,EAAA,WAAA,EAAA,MAAA;AACvB;AAIA;;;iBDlUgB,iBAAA;EEtQH,WAAA,EAAA,MAAA;EAAqB,YAAA,EAAA,MAAA;QAKlB;;AALyC;;iBFgRzC,eAAA;;;;cAWH;;iFAE+D;;+CAIlC;;6BAGlB;;kCAGK;;sDAGoB;;0BAG5B;;uDAG6B;;gCAGvB;;iEAMP,IAAI,QAAQ,8BACP,QAAA;;yEAI2C,QAAA;;;;;;sDAUR,IAAI,QAAQ,OAAK,QAAQ;;;;;KClUhF,cAAA;UACK,eAAA;EDYO,IAAA,ECXT,cDW0B;EASjB,GAAA,EAAA,MAAA;EAkBJ,GAAA,CAAA,EAAA,OAAA;EAAW,KAAA,CAAA,EAAA,GAAA;YAKF,CAAA,EAAA,MAAA,GAAA,IAAA;;AA4C2B,iBChFjC,iBAAA,CDgFiC,IAAA,EAAA,CAAA,KAAA,EChFD,eDgFC,EAAA,GAAA,IAAA,CAAA,EAAA,IAAA;AAiDO,UC3GvC,WAAA,CD2GuC;MAS5B,EAAA,ECnHlB,ODmHkB,CAAA,IAAA,CAAA;KAO8B,CAAA,GAAA,EAAA,MAAA,CAAA,ECzHtC,ODyHsC,CAAA,GAAA,GAAA,IAAA,CAAA;KAcxB,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,EAAA,UAAA,CAAA,EAAA,MAAA,GAAA,IAAA,CAAA,ECtI0B,ODsI1B,CAAA,IAAA,CAAA;KAYd,CAAA,GAAA,EAAA,MAAA,CAAA,ECjJA,ODiJA,CAAA,OAAA,CAAA;KAAY,CAAA,GAAA,EAAA,MAAA,CAAA,EChJZ,ODgJY,CAAA,OAAA,CAAA;OAAR,EAAA,EC/Ib,OD+Ia,CAAA,IAAA,CAAA;MAEX,EAAA,EChJH,ODgJG,CAAA,MAAA,EAAA,CAAA;;AAmBsE,iBCjEnE,gBAAA,CDiEmE,GAAA,KAAA,EChEvE,KDgEuE,CAAA,MAAA,GAAA,MAAA,GAAA,OAAA,GChErC,IDgEqC,GAAA,IAAA,GAAA,SAAA,CAAA,CAAA,EAAA,MAAA;cCkP7E,YAAA,YAAwB,WDlP6C,CAAA;UA0BvD,MAAA;UAAY,YAAA;UAAR,YAAA;UACX,UAAA;MAAR,CAAA,CAAA,EC8OO,OD9OP,CAAA,IAAA,CAAA;EAAO,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,ECkPW,ODlPX,CAAA,GAAA,CAAA;EASC,GAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,EAA2B,UAAa,CAAL,EAAA,MAAK,GAAA,IAAA,CAAA,EC8OU,OD9OV,CAAA,IAAA,CAAA;EAmBrC,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,ECgOO,ODhOU,CAAA,OAAA,CAAA;EAUjB,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EC2NO,OD3NQ,CAAA,OAAA,CAAA;EAWlB,KAAA,CAAA,CAAA,ECqNA,ODrNA,CAAA,IAoDZ,CAAA;EAAA,IAAA,CAAA,CAAA,ECsKW,ODtKX,CAAA,MAAA,EAAA,CAAA;;AAxC4B,cCyNhB,KDzNgB,EAAA;KAGoB,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,GCuN1B,ODvN0B,CAAA,GAAA,CAAA;KAG5B,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,GAAA,EAAA,UAAA,CAAA,EAAA,MAAA,GAAA,IAAA,EAAA,GCyNsC,ODzNtC,CAAA,IAAA,CAAA;KAG6B,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,GC0N3B,OD1N2B,CAAA,OAAA,CAAA;KAGvB,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,GC4NJ,OD5NI,CAAA,OAAA,CAAA;OAMP,EAAA,GAAA,UAAA,CAAA,IAAA,CAAA;MAAY,EAAA,GAAA,UAAA,CAAA,MAAA,EAAA,CAAA;QAAR,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,GCgOE,ODhOF,CAAA,OAAA,CAAA;OACC,EAAA,GAAA,UAAA,CAAA,IAAA,CAAA;UAAA,EAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,GAAA,IAAA,EAAA,QAAA,EAAA,GAAA,GC2OL,OD3OK,CC2OG,CD3OH,CAAA,EAAA,GC4OpB,OD5OoB,CC4OZ,CD5OY,CAAA;;AAI2C,cCuPvD,kBDvPuD,EAAA,GAAA,GAAA,MAAA;cC4PvD,sBAAc;cAGd,iBAAS;ADrPsC,cCsP/C,QDtP+C,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,GCsPpB,ODtPoB,CAAA,GAAA,CAAA;AAAY,cCuP3D,QDvP2D,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,GAAA,EAAA,UAAA,CAAA,EAAA,MAAA,GAAA,IAAA,EAAA,GCuPI,ODvPJ,CAAA,IAAA,CAAA;AAAR,cCyPnD,QDzPmD,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,GCyPxB,ODzPwB,CAAA,OAAA,CAAA;AAAqB,cC0PxE,QD1PwE,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,GC0P7C,OD1P6C,CAAA,OAAA,CAAA;AAAR,cC2PhE,UD3PgE,EAAA,GAAA,GC2PtD,OD3PsD,CAAA,IAAA,CAAA;AAAO,cC4PvE,SD5PuE,EAAA,GAAA,GC4P9D,OD5P8D,CAAA,MAAA,EAAA,CAAA;cCgQvE,oCAAyC;;;;cCxkBzC,oBAAA,SAA6B,eAAA;;EFmBzB,IAAA,CAAA,CAAA,EEdD,OFcC,CAAA,IAAiB,CAAA;AASlC;AAkBA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { ServiceProvider } from "@lara-node/core";
|
|
2
|
+
|
|
3
|
+
//#region src/RateLimiter.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Rate Limiter - Laravel-style rate limiting using cache drivers
|
|
7
|
+
*
|
|
8
|
+
* Supports multiple algorithms:
|
|
9
|
+
* - Fixed Window: Simple counter reset after window expires
|
|
10
|
+
* - Sliding Window: More accurate rate limiting using timestamps
|
|
11
|
+
* - Token Bucket: Gradual replenishment of tokens
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* import { RateLimiter } from '@/cache/RateLimiter';
|
|
15
|
+
*
|
|
16
|
+
* // Check if too many attempts
|
|
17
|
+
* const limiter = new RateLimiter();
|
|
18
|
+
* if (await limiter.tooManyAttempts('login:user@example.com', 5, 60)) {
|
|
19
|
+
* const retryAfter = await limiter.availableIn('login:user@example.com', 60);
|
|
20
|
+
* throw new Error(`Too many attempts. Retry after ${retryAfter} seconds.`);
|
|
21
|
+
* }
|
|
22
|
+
* await limiter.hit('login:user@example.com', 60);
|
|
23
|
+
*/
|
|
24
|
+
interface RateLimiterConfig {
|
|
25
|
+
/** Prefix for rate limiter cache keys */
|
|
26
|
+
prefix?: string;
|
|
27
|
+
/** Default max attempts */
|
|
28
|
+
maxAttempts?: number;
|
|
29
|
+
/** Default decay time in seconds */
|
|
30
|
+
decaySeconds?: number;
|
|
31
|
+
}
|
|
32
|
+
interface RateLimitInfo {
|
|
33
|
+
/** Whether the rate limit has been exceeded */
|
|
34
|
+
limited: boolean;
|
|
35
|
+
/** Current number of attempts */
|
|
36
|
+
attempts: number;
|
|
37
|
+
/** Maximum allowed attempts */
|
|
38
|
+
maxAttempts: number;
|
|
39
|
+
/** Remaining attempts */
|
|
40
|
+
remaining: number;
|
|
41
|
+
/** Seconds until the rate limit resets */
|
|
42
|
+
retryAfter: number;
|
|
43
|
+
/** Timestamp when the rate limit resets (Unix timestamp in seconds) */
|
|
44
|
+
resetsAt: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Rate Limiter class using cache backend
|
|
48
|
+
*/
|
|
49
|
+
declare class RateLimiter {
|
|
50
|
+
private prefix;
|
|
51
|
+
private defaultMaxAttempts;
|
|
52
|
+
private defaultDecaySeconds;
|
|
53
|
+
constructor(config?: RateLimiterConfig);
|
|
54
|
+
/**
|
|
55
|
+
* Get the cache key for a given key
|
|
56
|
+
*/
|
|
57
|
+
private cacheKey;
|
|
58
|
+
/**
|
|
59
|
+
* Get the timer cache key for a given key (stores the reset timestamp)
|
|
60
|
+
*/
|
|
61
|
+
private timerKey;
|
|
62
|
+
/**
|
|
63
|
+
* Determine if the given key has been "accessed" too many times
|
|
64
|
+
*/
|
|
65
|
+
tooManyAttempts(key: string, maxAttempts?: number, _decaySeconds?: number): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Increment the counter for a given key
|
|
68
|
+
* Returns the new number of attempts
|
|
69
|
+
*/
|
|
70
|
+
hit(key: string, decaySeconds?: number): Promise<number>;
|
|
71
|
+
/**
|
|
72
|
+
* Get the number of attempts for the given key
|
|
73
|
+
*/
|
|
74
|
+
attempts(key: string): Promise<number>;
|
|
75
|
+
/**
|
|
76
|
+
* Reset the number of attempts for the given key
|
|
77
|
+
*/
|
|
78
|
+
resetAttempts(key: string): Promise<boolean>;
|
|
79
|
+
/**
|
|
80
|
+
* Get the number of retries remaining
|
|
81
|
+
*/
|
|
82
|
+
retriesLeft(key: string, maxAttempts?: number): Promise<number>;
|
|
83
|
+
/**
|
|
84
|
+
* Clear the hits and lockout timer for the given key
|
|
85
|
+
*/
|
|
86
|
+
clear(key: string): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Get the number of seconds until the key is accessible again
|
|
89
|
+
*/
|
|
90
|
+
availableIn(key: string, _decaySeconds?: number): Promise<number>;
|
|
91
|
+
/**
|
|
92
|
+
* Get the timestamp when the key becomes available again
|
|
93
|
+
*/
|
|
94
|
+
availableAt(key: string): Promise<number>;
|
|
95
|
+
/**
|
|
96
|
+
* Attempt to execute a callback if the rate limit allows
|
|
97
|
+
* Returns the callback result or throws if rate limited
|
|
98
|
+
*/
|
|
99
|
+
attempt<T>(key: string, maxAttempts: number, callback: () => T | Promise<T>, decaySeconds?: number): Promise<T>;
|
|
100
|
+
/**
|
|
101
|
+
* Get complete rate limit info for a key
|
|
102
|
+
*/
|
|
103
|
+
getInfo(key: string, maxAttempts?: number, decaySeconds?: number): Promise<RateLimitInfo>;
|
|
104
|
+
/**
|
|
105
|
+
* Execute a callback with rate limiting, using a limiter definition
|
|
106
|
+
*/
|
|
107
|
+
limiter<T>(name: string, key: string, maxAttempts: number, decaySeconds: number, callback: () => T | Promise<T>): Promise<T>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Exception thrown when rate limit is exceeded
|
|
111
|
+
*/
|
|
112
|
+
declare class RateLimitExceededException extends Error {
|
|
113
|
+
readonly retryAfter: number;
|
|
114
|
+
readonly maxAttempts: number;
|
|
115
|
+
readonly statusCode: number;
|
|
116
|
+
constructor(message: string, retryAfter: number, maxAttempts: number);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Register a named rate limiter
|
|
120
|
+
*/
|
|
121
|
+
declare function defineRateLimiter(name: string, config: () => {
|
|
122
|
+
maxAttempts: number;
|
|
123
|
+
decaySeconds: number;
|
|
124
|
+
}): void;
|
|
125
|
+
/**
|
|
126
|
+
* Get a named rate limiter configuration
|
|
127
|
+
*/
|
|
128
|
+
declare function getNamedLimiter(name: string): {
|
|
129
|
+
maxAttempts: number;
|
|
130
|
+
decaySeconds: number;
|
|
131
|
+
} | null;
|
|
132
|
+
declare const RateLimiterFacade: {
|
|
133
|
+
/** Check if too many attempts have been made */
|
|
134
|
+
tooManyAttempts: (key: string, maxAttempts?: number, decaySeconds?: number) => Promise<boolean>;
|
|
135
|
+
/** Increment the attempt counter */
|
|
136
|
+
hit: (key: string, decaySeconds?: number) => Promise<number>;
|
|
137
|
+
/** Get current number of attempts */
|
|
138
|
+
attempts: (key: string) => Promise<number>;
|
|
139
|
+
/** Reset attempt counter */
|
|
140
|
+
resetAttempts: (key: string) => Promise<boolean>;
|
|
141
|
+
/** Get remaining retries */
|
|
142
|
+
retriesLeft: (key: string, maxAttempts?: number) => Promise<number>;
|
|
143
|
+
/** Clear rate limiter for key */
|
|
144
|
+
clear: (key: string) => Promise<void>;
|
|
145
|
+
/** Get seconds until rate limit resets */
|
|
146
|
+
availableIn: (key: string, decaySeconds?: number) => Promise<number>;
|
|
147
|
+
/** Get timestamp when rate limit resets */
|
|
148
|
+
availableAt: (key: string) => Promise<number>;
|
|
149
|
+
/** Attempt to execute callback with rate limiting */
|
|
150
|
+
attempt: <T>(key: string, maxAttempts: number, callback: () => T | Promise<T>, decaySeconds?: number) => Promise<T>;
|
|
151
|
+
/** Get rate limit info for a key */
|
|
152
|
+
getInfo: (key: string, maxAttempts?: number, decaySeconds?: number) => Promise<RateLimitInfo>;
|
|
153
|
+
/** Define a named rate limiter */
|
|
154
|
+
define: typeof defineRateLimiter;
|
|
155
|
+
/** Get named limiter config */
|
|
156
|
+
limiter: typeof getNamedLimiter;
|
|
157
|
+
/** Execute with named limiter */
|
|
158
|
+
for: <T>(name: string, key: string, callback: () => T | Promise<T>) => Promise<T>;
|
|
159
|
+
};
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/CacheManager.d.ts
|
|
162
|
+
/** Optional watcher hook — registered by @lara-node/telescope at boot to avoid circular deps. */
|
|
163
|
+
type CacheEventType = "get" | "set" | "del" | "has" | "clear";
|
|
164
|
+
interface CacheWatchEvent {
|
|
165
|
+
type: CacheEventType;
|
|
166
|
+
key: string;
|
|
167
|
+
hit?: boolean;
|
|
168
|
+
value?: any;
|
|
169
|
+
ttlSeconds?: number | null;
|
|
170
|
+
}
|
|
171
|
+
declare function setCacheWatchHook(hook: (event: CacheWatchEvent) => void): void;
|
|
172
|
+
interface CacheDriver {
|
|
173
|
+
init(): Promise<void>;
|
|
174
|
+
get(key: string): Promise<any | null>;
|
|
175
|
+
set(key: string, value: any, ttlSeconds?: number | null): Promise<void>;
|
|
176
|
+
del(key: string): Promise<boolean>;
|
|
177
|
+
has(key: string): Promise<boolean>;
|
|
178
|
+
clear(): Promise<void>;
|
|
179
|
+
keys(): Promise<string[]>;
|
|
180
|
+
}
|
|
181
|
+
declare function generateCacheKey(...parts: Array<string | number | boolean | Date | null | undefined>): string;
|
|
182
|
+
declare class CacheManager implements CacheDriver {
|
|
183
|
+
private driver;
|
|
184
|
+
private initializing;
|
|
185
|
+
private createDriver;
|
|
186
|
+
private ensureInit;
|
|
187
|
+
init(): Promise<void>;
|
|
188
|
+
get(key: string): Promise<any>;
|
|
189
|
+
set(key: string, value: any, ttlSeconds?: number | null): Promise<void>;
|
|
190
|
+
del(key: string): Promise<boolean>;
|
|
191
|
+
has(key: string): Promise<boolean>;
|
|
192
|
+
clear(): Promise<void>;
|
|
193
|
+
keys(): Promise<string[]>;
|
|
194
|
+
}
|
|
195
|
+
declare const Cache: {
|
|
196
|
+
get: (k: string) => Promise<any>;
|
|
197
|
+
set: (k: string, v: any, ttlSeconds?: number | null) => Promise<void>;
|
|
198
|
+
del: (k: string) => Promise<boolean>;
|
|
199
|
+
has: (k: string) => Promise<boolean>;
|
|
200
|
+
clear: () => Promise<void>;
|
|
201
|
+
keys: () => Promise<string[]>;
|
|
202
|
+
forget: (k: string) => Promise<boolean>;
|
|
203
|
+
flush: () => Promise<void>;
|
|
204
|
+
remember: <T>(key: string, ttlSeconds: number | null, callback: () => Promise<T>) => Promise<T>;
|
|
205
|
+
};
|
|
206
|
+
declare const getCacheDriverName: () => string;
|
|
207
|
+
declare const getCacheDriver: () => CacheManager;
|
|
208
|
+
declare const initCache: () => Promise<void>;
|
|
209
|
+
declare const cacheGet: (k: string) => Promise<any>;
|
|
210
|
+
declare const cacheSet: (k: string, v: any, ttlSeconds?: number | null) => Promise<void>;
|
|
211
|
+
declare const cacheDel: (k: string) => Promise<boolean>;
|
|
212
|
+
declare const cacheHas: (k: string) => Promise<boolean>;
|
|
213
|
+
declare const cacheClear: () => Promise<void>;
|
|
214
|
+
declare const cacheKeys: () => Promise<string[]>;
|
|
215
|
+
declare const cacheDelPrefix: (prefix: string) => Promise<number>;
|
|
216
|
+
//# sourceMappingURL=CacheManager.d.ts.map
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/CacheServiceProvider.d.ts
|
|
219
|
+
declare class CacheServiceProvider extends ServiceProvider {
|
|
220
|
+
register(): void;
|
|
221
|
+
boot(): Promise<void>;
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=CacheServiceProvider.d.ts.map
|
|
224
|
+
|
|
225
|
+
//#endregion
|
|
226
|
+
export { Cache, type CacheDriver, CacheServiceProvider, RateLimitExceededException, type RateLimitInfo, RateLimiter, type RateLimiterConfig, RateLimiterFacade, cacheClear, cacheDel, cacheDelPrefix, cacheGet, cacheHas, cacheKeys, cacheSet, defineRateLimiter, generateCacheKey, getCacheDriver, getCacheDriverName, getNamedLimiter, initCache, setCacheWatchHook };
|
|
227
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/RateLimiter.ts","../src/CacheManager.ts","../src/CacheServiceProvider.ts"],"mappings":"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"}
|