@zucker-framework/rate-limiter 1.0.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.js ADDED
@@ -0,0 +1,574 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ DynamicLimiterManager: () => DynamicLimiterManager,
25
+ RATE_LIMIT_KEY: () => RATE_LIMIT_KEY,
26
+ RateLimit: () => RateLimit,
27
+ RateLimitGuard: () => RateLimitGuard,
28
+ RateLimiterService: () => RateLimiterService,
29
+ TooManyRequestsException: () => TooManyRequestsException,
30
+ ZuckerRateLimiterModule: () => ZuckerRateLimiterModule,
31
+ deriveRateLimitKey: () => deriveRateLimitKey
32
+ });
33
+ module.exports = __toCommonJS(index_exports);
34
+
35
+ // src/rate-limiter.service.ts
36
+ var import_common = require("@nestjs/common");
37
+ var import_rate_limiter_flexible = require("rate-limiter-flexible");
38
+ var import_core = require("@zucker-framework/core");
39
+ var import_node_crypto = require("crypto");
40
+ function _ts_decorate(decorators, target, key, desc) {
41
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
42
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
43
+ r = Reflect.decorate(decorators, target, key, desc);
44
+ } else {
45
+ for (var i = decorators.length - 1; i >= 0; i--) {
46
+ if (d = decorators[i]) {
47
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
48
+ }
49
+ }
50
+ }
51
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
52
+ }
53
+ __name(_ts_decorate, "_ts_decorate");
54
+ function _ts_metadata(metadataKey, metadataValue) {
55
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
56
+ return Reflect.metadata(metadataKey, metadataValue);
57
+ }
58
+ }
59
+ __name(_ts_metadata, "_ts_metadata");
60
+ function deriveRateLimitKey(key, secret) {
61
+ if (!secret) return key;
62
+ return `v1:${(0, import_node_crypto.createHmac)("sha256", secret).update(key).digest("hex")}`;
63
+ }
64
+ __name(deriveRateLimitKey, "deriveRateLimitKey");
65
+ var TooManyRequestsException = class extends import_common.HttpException {
66
+ static {
67
+ __name(this, "TooManyRequestsException");
68
+ }
69
+ retryAfter;
70
+ constructor(message, retryAfter) {
71
+ super({
72
+ statusCode: import_common.HttpStatus.TOO_MANY_REQUESTS,
73
+ message,
74
+ retryAfter
75
+ }, import_common.HttpStatus.TOO_MANY_REQUESTS);
76
+ this.retryAfter = retryAfter;
77
+ }
78
+ };
79
+ var RateLimiterService = class _RateLimiterService {
80
+ static {
81
+ __name(this, "RateLimiterService");
82
+ }
83
+ options;
84
+ logger = new import_common.Logger(_RateLimiterService.name);
85
+ limiters = /* @__PURE__ */ new Map();
86
+ useRedis = false;
87
+ constructor(options) {
88
+ this.options = options;
89
+ }
90
+ async onModuleInit() {
91
+ if (this.options.redisClient) {
92
+ this.useRedis = true;
93
+ this.logger.log("RateLimiterService \u4F7F\u7528 Redis \u5206\u5E03\u5F0F\u9650\u6D41");
94
+ }
95
+ for (const [name, config] of Object.entries(this.options.limiters)) {
96
+ if (config.points <= 0 || config.duration <= 0) {
97
+ this.logger.warn(`\u9650\u6D41\u5668 '${name}' \u914D\u7F6E\u65E0\u6548 (points=${config.points}, duration=${config.duration})\uFF0C\u5DF2\u8DF3\u8FC7`);
98
+ continue;
99
+ }
100
+ const opts = {
101
+ points: config.points,
102
+ duration: config.duration,
103
+ blockDuration: config.blockDuration ?? config.duration
104
+ };
105
+ if (this.useRedis) {
106
+ this.limiters.set(name, new import_rate_limiter_flexible.RateLimiterRedis({
107
+ ...opts,
108
+ storeClient: this.options.redisClient,
109
+ keyPrefix: config.keyPrefix ?? `rl:${name}:`
110
+ }));
111
+ } else {
112
+ this.limiters.set(name, new import_rate_limiter_flexible.RateLimiterMemory(opts));
113
+ }
114
+ }
115
+ this.logger.log(`RateLimiterService \u521D\u59CB\u5316\u5B8C\u6210 (${this.useRedis ? "Redis" : "Memory"}), ${this.limiters.size} \u4E2A\u9650\u6D41\u5668`);
116
+ }
117
+ onModuleDestroy() {
118
+ this.limiters.clear();
119
+ this.logger.log("RateLimiterService \u5DF2\u6E05\u7406");
120
+ }
121
+ /**
122
+ * Consume points from a rate limiter.
123
+ * Throws TooManyRequestsException (429) when limit is exceeded.
124
+ */
125
+ async consume(limiterName, key, pointsToConsume = 1, errorMessage = "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5") {
126
+ const limiter = this.getLimiter(limiterName);
127
+ const storageKey = this.toStorageKey(key);
128
+ if (pointsToConsume <= 0 || !Number.isFinite(pointsToConsume)) {
129
+ throw new import_core.BusinessException(`\u6D88\u8D39\u70B9\u6570\u65E0\u6548: ${pointsToConsume}`, "INVALID_POINTS", 400);
130
+ }
131
+ try {
132
+ const res = await limiter.consume(storageKey, pointsToConsume);
133
+ return {
134
+ remaining: res.remainingPoints,
135
+ msBeforeNext: res.msBeforeNext,
136
+ consumedPoints: res.consumedPoints
137
+ };
138
+ } catch (error) {
139
+ if (error && typeof error === "object" && "msBeforeNext" in error) {
140
+ const res = error;
141
+ const retryAfter = Math.ceil(res.msBeforeNext / 1e3);
142
+ this.logger.warn(`\u9650\u6D41\u89E6\u53D1: limiter=${limiterName}, retryAfter=${retryAfter}s`);
143
+ throw new TooManyRequestsException(errorMessage, retryAfter);
144
+ }
145
+ throw error;
146
+ }
147
+ }
148
+ /**
149
+ * Apply a penalty by consuming extra points, extending the block time.
150
+ * Useful for failed login attempts, abuse detection, etc.
151
+ */
152
+ async penalty(limiterName, key, points = 1) {
153
+ const limiter = this.getLimiter(limiterName);
154
+ await limiter.penalty(this.toStorageKey(key), points);
155
+ this.logger.log(`\u9650\u6D41\u60E9\u7F5A: limiter=${limiterName}, points=${points}`);
156
+ }
157
+ /**
158
+ * Reward by reducing consumed points (opposite of penalty).
159
+ */
160
+ async reward(limiterName, key, points = 1) {
161
+ const limiter = this.getLimiter(limiterName);
162
+ await limiter.reward(this.toStorageKey(key), points);
163
+ }
164
+ async getRemaining(limiterName, key) {
165
+ const limiter = this.getLimiter(limiterName);
166
+ const res = await limiter.get(this.toStorageKey(key));
167
+ if (!res) {
168
+ const config = this.options.limiters[limiterName];
169
+ return {
170
+ remaining: config.points,
171
+ resetAt: new Date(Date.now() + config.duration * 1e3)
172
+ };
173
+ }
174
+ return {
175
+ remaining: res.remainingPoints,
176
+ resetAt: new Date(Date.now() + res.msBeforeNext)
177
+ };
178
+ }
179
+ async reset(limiterName, key) {
180
+ const limiter = this.getLimiter(limiterName);
181
+ await limiter.delete(this.toStorageKey(key));
182
+ }
183
+ /**
184
+ * Convenience method for public API rate limiting.
185
+ * Consumes 1 point from the named limiter using the given key.
186
+ * Throws TooManyRequestsException (429) when limit is exceeded.
187
+ *
188
+ * @param key - Unique identifier for the consumer (e.g., IP address)
189
+ * @param limiterName - Name of the registered rate limiter
190
+ */
191
+ async checkPublicApiLimit(key, limiterName) {
192
+ await this.consume(limiterName, key, 1, "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5");
193
+ }
194
+ /**
195
+ * Check AI operation rate limit for a user.
196
+ * Falls back gracefully if the limiter doesn't exist (AI ops are best-effort limited).
197
+ *
198
+ * @param userId - User identifier
199
+ * @param operation - Human-readable description of the AI operation
200
+ * @param points - Points to consume (default: 1)
201
+ */
202
+ async checkAILimit(userId, operation, points = 1) {
203
+ const limiterName = "ai-default";
204
+ if (!this.has(limiterName)) return;
205
+ await this.consume(limiterName, userId, points, `AI \u64CD\u4F5C"${operation}"\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5`);
206
+ }
207
+ /** Check if a limiter exists by name */
208
+ has(limiterName) {
209
+ return this.limiters.has(limiterName);
210
+ }
211
+ /** Get all registered limiter names */
212
+ getLimiterNames() {
213
+ return [
214
+ ...this.limiters.keys()
215
+ ];
216
+ }
217
+ isDistributed() {
218
+ return this.useRedis;
219
+ }
220
+ /** Get a limiter by name, throwing if not found */
221
+ getLimiter(limiterName) {
222
+ const limiter = this.limiters.get(limiterName);
223
+ if (!limiter) {
224
+ throw new import_core.NotFoundException(`\u9650\u6D41\u5668 '${limiterName}' \u4E0D\u5B58\u5728 (\u53EF\u7528: ${this.getLimiterNames().join(", ")})`);
225
+ }
226
+ return limiter;
227
+ }
228
+ toStorageKey(key) {
229
+ return deriveRateLimitKey(key, this.options.keyHashSecret);
230
+ }
231
+ };
232
+ RateLimiterService = _ts_decorate([
233
+ (0, import_common.Injectable)(),
234
+ _ts_metadata("design:type", Function),
235
+ _ts_metadata("design:paramtypes", [
236
+ typeof RateLimiterModuleOptions === "undefined" ? Object : RateLimiterModuleOptions
237
+ ])
238
+ ], RateLimiterService);
239
+
240
+ // src/rate-limiter.module.ts
241
+ var import_common4 = require("@nestjs/common");
242
+ var import_core3 = require("@nestjs/core");
243
+
244
+ // src/guards/rate-limit.guard.ts
245
+ var import_common3 = require("@nestjs/common");
246
+ var import_core2 = require("@nestjs/core");
247
+
248
+ // src/decorators/rate-limit.decorator.ts
249
+ var import_common2 = require("@nestjs/common");
250
+ var RATE_LIMIT_KEY = "ZUCKER_RATE_LIMIT";
251
+ function RateLimit(options) {
252
+ const opts = typeof options === "string" ? {
253
+ limiter: options
254
+ } : options;
255
+ return (0, import_common2.SetMetadata)(RATE_LIMIT_KEY, opts);
256
+ }
257
+ __name(RateLimit, "RateLimit");
258
+
259
+ // src/guards/rate-limit.guard.ts
260
+ function _ts_decorate2(decorators, target, key, desc) {
261
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
262
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
263
+ r = Reflect.decorate(decorators, target, key, desc);
264
+ } else {
265
+ for (var i = decorators.length - 1; i >= 0; i--) {
266
+ if (d = decorators[i]) {
267
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
268
+ }
269
+ }
270
+ }
271
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
272
+ }
273
+ __name(_ts_decorate2, "_ts_decorate");
274
+ function _ts_metadata2(metadataKey, metadataValue) {
275
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
276
+ return Reflect.metadata(metadataKey, metadataValue);
277
+ }
278
+ }
279
+ __name(_ts_metadata2, "_ts_metadata");
280
+ function _ts_param(paramIndex, decorator) {
281
+ return function(target, key) {
282
+ decorator(target, key, paramIndex);
283
+ };
284
+ }
285
+ __name(_ts_param, "_ts_param");
286
+ var RateLimitGuard = class {
287
+ static {
288
+ __name(this, "RateLimitGuard");
289
+ }
290
+ reflector;
291
+ rateLimiterService;
292
+ constructor(reflector, rateLimiterService) {
293
+ this.reflector = reflector;
294
+ this.rateLimiterService = rateLimiterService;
295
+ }
296
+ async canActivate(context) {
297
+ const options = this.reflector.getAllAndOverride(RATE_LIMIT_KEY, [
298
+ context.getHandler(),
299
+ context.getClass()
300
+ ]);
301
+ if (!options || !this.rateLimiterService) return true;
302
+ const request = context.switchToHttp().getRequest();
303
+ const key = this.extractKey(request, options);
304
+ try {
305
+ await this.rateLimiterService.consume(options.limiter, key);
306
+ return true;
307
+ } catch (err) {
308
+ if (err instanceof TooManyRequestsException) {
309
+ throw new TooManyRequestsException(options.message ?? "Too many requests", err.retryAfter);
310
+ }
311
+ throw err;
312
+ }
313
+ }
314
+ extractKey(request, options) {
315
+ const networkKey = request.ip ?? request.socket?.remoteAddress ?? "unknown-client";
316
+ switch (options.keyExtractor) {
317
+ case "#userId":
318
+ return request.user?.id ?? networkKey;
319
+ case "#username":
320
+ return request.user?.username ?? networkKey;
321
+ default:
322
+ return networkKey;
323
+ }
324
+ }
325
+ };
326
+ RateLimitGuard = _ts_decorate2([
327
+ (0, import_common3.Injectable)(),
328
+ _ts_param(1, (0, import_common3.Inject)("RATE_LIMITER_SERVICE")),
329
+ _ts_param(1, (0, import_common3.Optional)()),
330
+ _ts_metadata2("design:type", Function),
331
+ _ts_metadata2("design:paramtypes", [
332
+ typeof import_core2.Reflector === "undefined" ? Object : import_core2.Reflector,
333
+ Object
334
+ ])
335
+ ], RateLimitGuard);
336
+
337
+ // src/rate-limiter.module.ts
338
+ function _ts_decorate3(decorators, target, key, desc) {
339
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
340
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
341
+ r = Reflect.decorate(decorators, target, key, desc);
342
+ } else {
343
+ for (var i = decorators.length - 1; i >= 0; i--) {
344
+ if (d = decorators[i]) {
345
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
346
+ }
347
+ }
348
+ }
349
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
350
+ }
351
+ __name(_ts_decorate3, "_ts_decorate");
352
+ var RATE_LIMITER_MODULE_OPTIONS = /* @__PURE__ */ Symbol("RATE_LIMITER_MODULE_OPTIONS");
353
+ var ZuckerRateLimiterModule = class _ZuckerRateLimiterModule {
354
+ static {
355
+ __name(this, "ZuckerRateLimiterModule");
356
+ }
357
+ static forRoot(options) {
358
+ const providers = [
359
+ {
360
+ provide: RateLimiterService,
361
+ useFactory: /* @__PURE__ */ __name(() => new RateLimiterService(options), "useFactory")
362
+ },
363
+ {
364
+ provide: "RATE_LIMITER_SERVICE",
365
+ useExisting: RateLimiterService
366
+ },
367
+ RateLimitGuard
368
+ ];
369
+ if (options.globalGuard !== false) {
370
+ providers.push({
371
+ provide: import_core3.APP_GUARD,
372
+ useExisting: RateLimitGuard
373
+ });
374
+ }
375
+ return {
376
+ module: _ZuckerRateLimiterModule,
377
+ global: true,
378
+ providers,
379
+ exports: [
380
+ RateLimiterService,
381
+ RateLimitGuard,
382
+ "RATE_LIMITER_SERVICE"
383
+ ]
384
+ };
385
+ }
386
+ static forRootAsync(options) {
387
+ const asyncProviders = this.createAsyncProviders(options);
388
+ const providers = [
389
+ ...asyncProviders,
390
+ {
391
+ provide: RateLimiterService,
392
+ useFactory: /* @__PURE__ */ __name((opts) => new RateLimiterService(opts), "useFactory"),
393
+ inject: [
394
+ RATE_LIMITER_MODULE_OPTIONS
395
+ ]
396
+ },
397
+ {
398
+ provide: "RATE_LIMITER_SERVICE",
399
+ useExisting: RateLimiterService
400
+ },
401
+ RateLimitGuard
402
+ ];
403
+ if (options.globalGuard !== false) {
404
+ providers.push({
405
+ provide: import_core3.APP_GUARD,
406
+ useExisting: RateLimitGuard
407
+ });
408
+ }
409
+ return {
410
+ module: _ZuckerRateLimiterModule,
411
+ global: true,
412
+ imports: options.imports ?? [],
413
+ providers,
414
+ exports: [
415
+ RateLimiterService,
416
+ RateLimitGuard,
417
+ "RATE_LIMITER_SERVICE"
418
+ ]
419
+ };
420
+ }
421
+ static createAsyncProviders(options) {
422
+ if (options.useFactory) {
423
+ return [
424
+ {
425
+ provide: RATE_LIMITER_MODULE_OPTIONS,
426
+ useFactory: options.useFactory,
427
+ inject: options.inject ?? []
428
+ }
429
+ ];
430
+ }
431
+ const optionsProvider = {
432
+ provide: RATE_LIMITER_MODULE_OPTIONS,
433
+ useFactory: /* @__PURE__ */ __name(async (factory) => factory.createRateLimiterOptions(), "useFactory"),
434
+ inject: [
435
+ options.useClass ?? options.useExisting
436
+ ]
437
+ };
438
+ if (options.useClass) {
439
+ return [
440
+ {
441
+ provide: options.useClass,
442
+ useClass: options.useClass
443
+ },
444
+ optionsProvider
445
+ ];
446
+ }
447
+ return [
448
+ optionsProvider
449
+ ];
450
+ }
451
+ };
452
+ ZuckerRateLimiterModule = _ts_decorate3([
453
+ (0, import_common4.Global)(),
454
+ (0, import_common4.Module)({})
455
+ ], ZuckerRateLimiterModule);
456
+
457
+ // src/dynamic-limiter.ts
458
+ var import_common5 = require("@nestjs/common");
459
+ function _ts_decorate4(decorators, target, key, desc) {
460
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
461
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
462
+ r = Reflect.decorate(decorators, target, key, desc);
463
+ } else {
464
+ for (var i = decorators.length - 1; i >= 0; i--) {
465
+ if (d = decorators[i]) {
466
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
467
+ }
468
+ }
469
+ }
470
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
471
+ }
472
+ __name(_ts_decorate4, "_ts_decorate");
473
+ var DynamicLimiterManager = class _DynamicLimiterManager {
474
+ static {
475
+ __name(this, "DynamicLimiterManager");
476
+ }
477
+ logger = new import_common5.Logger(_DynamicLimiterManager.name);
478
+ rules = /* @__PURE__ */ new Map();
479
+ listeners = [];
480
+ /** 添加或更新限流规则 */
481
+ setRule(rule) {
482
+ rule.createdAt = rule.createdAt ?? Date.now();
483
+ this.rules.set(rule.id, rule);
484
+ this.notifyListeners();
485
+ this.logger.log(`Dynamic limiter rule set: ${rule.id} (${rule.points}/${rule.duration}s)`);
486
+ }
487
+ /** 删除限流规则 */
488
+ removeRule(id) {
489
+ const removed = this.rules.delete(id);
490
+ if (removed) {
491
+ this.notifyListeners();
492
+ this.logger.log(`Dynamic limiter rule removed: ${id}`);
493
+ }
494
+ return removed;
495
+ }
496
+ /** 获取所有规则(按优先级排序) */
497
+ getRules() {
498
+ return Array.from(this.rules.values()).filter((r) => r.enabled).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
499
+ }
500
+ /** 根据路径和角色匹配限流规则 */
501
+ matchRule(path, roles) {
502
+ for (const rule of this.getRules()) {
503
+ if (rule.pathPattern) {
504
+ const regex = this.globToRegex(rule.pathPattern);
505
+ if (!regex.test(path)) continue;
506
+ }
507
+ if (rule.roles?.length) {
508
+ if (!roles?.some((r) => rule.roles.includes(r))) continue;
509
+ }
510
+ return rule;
511
+ }
512
+ return void 0;
513
+ }
514
+ /** 批量导入规则 */
515
+ importRules(rules) {
516
+ for (const rule of rules) {
517
+ this.rules.set(rule.id, {
518
+ ...rule,
519
+ createdAt: rule.createdAt ?? Date.now()
520
+ });
521
+ }
522
+ this.notifyListeners();
523
+ this.logger.log(`Imported ${rules.length} dynamic limiter rules`);
524
+ }
525
+ /** 导出所有规则 */
526
+ exportRules() {
527
+ return Array.from(this.rules.values());
528
+ }
529
+ /** 监听规则变更 */
530
+ onRulesChanged(listener) {
531
+ this.listeners.push(listener);
532
+ return {
533
+ unsubscribe: /* @__PURE__ */ __name(() => {
534
+ const idx = this.listeners.indexOf(listener);
535
+ if (idx >= 0) this.listeners.splice(idx, 1);
536
+ }, "unsubscribe")
537
+ };
538
+ }
539
+ /** 启用/禁用规则 */
540
+ toggleRule(id, enabled) {
541
+ const rule = this.rules.get(id);
542
+ if (!rule) return false;
543
+ rule.enabled = enabled;
544
+ this.notifyListeners();
545
+ return true;
546
+ }
547
+ notifyListeners() {
548
+ const rules = this.getRules();
549
+ for (const listener of this.listeners) {
550
+ try {
551
+ listener(rules);
552
+ } catch {
553
+ }
554
+ }
555
+ }
556
+ globToRegex(glob) {
557
+ const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
558
+ return new RegExp(`^${escaped}$`);
559
+ }
560
+ };
561
+ DynamicLimiterManager = _ts_decorate4([
562
+ (0, import_common5.Injectable)()
563
+ ], DynamicLimiterManager);
564
+ // Annotate the CommonJS export names for ESM import in node:
565
+ 0 && (module.exports = {
566
+ DynamicLimiterManager,
567
+ RATE_LIMIT_KEY,
568
+ RateLimit,
569
+ RateLimitGuard,
570
+ RateLimiterService,
571
+ TooManyRequestsException,
572
+ ZuckerRateLimiterModule,
573
+ deriveRateLimitKey
574
+ });