@http-client-toolkit/store-memory 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs ADDED
@@ -0,0 +1,761 @@
1
+ 'use strict';
2
+
3
+ var safeStringify = require('fast-safe-stringify');
4
+ var crypto = require('crypto');
5
+ var core = require('@http-client-toolkit/core');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var safeStringify__default = /*#__PURE__*/_interopDefault(safeStringify);
10
+
11
+ var __async = (__this, __arguments, generator) => {
12
+ return new Promise((resolve, reject) => {
13
+ var fulfilled = (value) => {
14
+ try {
15
+ step(generator.next(value));
16
+ } catch (e) {
17
+ reject(e);
18
+ }
19
+ };
20
+ var rejected = (value) => {
21
+ try {
22
+ step(generator.throw(value));
23
+ } catch (e) {
24
+ reject(e);
25
+ }
26
+ };
27
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
28
+ step((generator = generator.apply(__this, __arguments)).next());
29
+ });
30
+ };
31
+ var InMemoryCacheStore = class {
32
+ // running total of memory usage in bytes
33
+ constructor(options = {}) {
34
+ this.cache = /* @__PURE__ */ new Map();
35
+ this.totalSize = 0;
36
+ var _a, _b, _c, _d;
37
+ const cleanupIntervalMs = (_a = options.cleanupIntervalMs) != null ? _a : 6e4;
38
+ this.maxItems = (_b = options.maxItems) != null ? _b : 1e3;
39
+ this.maxMemoryBytes = (_c = options.maxMemoryBytes) != null ? _c : 50 * 1024 * 1024;
40
+ this.evictionRatio = (_d = options.evictionRatio) != null ? _d : 0.1;
41
+ if (cleanupIntervalMs > 0) {
42
+ this.cleanupInterval = setInterval(() => {
43
+ this.cleanup();
44
+ }, cleanupIntervalMs);
45
+ if (typeof this.cleanupInterval.unref === "function") {
46
+ this.cleanupInterval.unref();
47
+ }
48
+ }
49
+ }
50
+ get(hash) {
51
+ return __async(this, null, function* () {
52
+ const item = this.cache.get(hash);
53
+ if (!item) {
54
+ return void 0;
55
+ }
56
+ if (item.expiresAt > 0 && Date.now() > item.expiresAt) {
57
+ this.totalSize -= item.size;
58
+ this.cache.delete(hash);
59
+ return void 0;
60
+ }
61
+ item.lastAccessed = Date.now();
62
+ this.cache.set(hash, item);
63
+ return item.value;
64
+ });
65
+ }
66
+ set(hash, value, ttlSeconds) {
67
+ return __async(this, null, function* () {
68
+ const now = Date.now();
69
+ const expiresAt = ttlSeconds === 0 ? 0 : now + ttlSeconds * 1e3;
70
+ const existing = this.cache.get(hash);
71
+ if (existing) {
72
+ this.totalSize -= existing.size;
73
+ }
74
+ const entrySize = this.estimateEntrySize(hash, value);
75
+ this.totalSize += entrySize;
76
+ this.cache.set(hash, {
77
+ value,
78
+ expiresAt,
79
+ lastAccessed: now,
80
+ size: entrySize
81
+ });
82
+ this.enforceMemoryLimits();
83
+ });
84
+ }
85
+ delete(hash) {
86
+ return __async(this, null, function* () {
87
+ const existing = this.cache.get(hash);
88
+ if (existing) {
89
+ this.totalSize -= existing.size;
90
+ }
91
+ this.cache.delete(hash);
92
+ });
93
+ }
94
+ clear() {
95
+ return __async(this, null, function* () {
96
+ this.cache.clear();
97
+ this.totalSize = 0;
98
+ });
99
+ }
100
+ /**
101
+ * Get statistics about cache usage
102
+ */
103
+ getStats() {
104
+ const now = Date.now();
105
+ let expired = 0;
106
+ for (const [_hash, item] of this.cache) {
107
+ if (item.expiresAt > 0 && now > item.expiresAt) {
108
+ expired++;
109
+ }
110
+ }
111
+ const memoryUsageBytes = this.calculateMemoryUsage();
112
+ return {
113
+ totalItems: this.cache.size,
114
+ expired,
115
+ memoryUsageBytes,
116
+ maxItems: this.maxItems,
117
+ maxMemoryBytes: this.maxMemoryBytes,
118
+ memoryUtilization: memoryUsageBytes / this.maxMemoryBytes,
119
+ itemUtilization: this.cache.size / this.maxItems
120
+ };
121
+ }
122
+ /**
123
+ * Clean up expired cache entries
124
+ */
125
+ cleanup() {
126
+ const now = Date.now();
127
+ const toDelete = [];
128
+ for (const [hash, item] of this.cache) {
129
+ if (item.expiresAt > 0 && now > item.expiresAt) {
130
+ toDelete.push(hash);
131
+ }
132
+ }
133
+ for (const hash of toDelete) {
134
+ const item = this.cache.get(hash);
135
+ if (item) {
136
+ this.totalSize -= item.size;
137
+ }
138
+ this.cache.delete(hash);
139
+ }
140
+ }
141
+ /**
142
+ * Enforce memory and item count limits using LRU eviction
143
+ */
144
+ enforceMemoryLimits() {
145
+ if (this.cache.size > this.maxItems) {
146
+ this.evictLRUItems(this.cache.size - this.maxItems);
147
+ return;
148
+ }
149
+ const memoryUsage = this.totalSize;
150
+ if (memoryUsage > this.maxMemoryBytes) {
151
+ const itemsToEvict = Math.max(
152
+ 1,
153
+ Math.floor(this.cache.size * this.evictionRatio)
154
+ );
155
+ this.evictLRUItems(itemsToEvict);
156
+ }
157
+ }
158
+ /**
159
+ * Evict the least recently used items
160
+ */
161
+ evictLRUItems(count) {
162
+ const entries = Array.from(this.cache.entries()).sort(
163
+ ([, a], [, b]) => a.lastAccessed - b.lastAccessed
164
+ );
165
+ for (let i = 0; i < count && i < entries.length; i++) {
166
+ const entry = entries[i];
167
+ if (entry) {
168
+ const [key, item] = entry;
169
+ this.totalSize -= item.size;
170
+ this.cache.delete(key);
171
+ }
172
+ }
173
+ }
174
+ /**
175
+ * Calculate rough memory usage
176
+ */
177
+ calculateMemoryUsage() {
178
+ return this.totalSize;
179
+ }
180
+ /**
181
+ * Get items sorted by last accessed time (for debugging/monitoring)
182
+ */
183
+ getLRUItems(limit = 10) {
184
+ const entries = Array.from(this.cache.entries()).sort(([, a], [, b]) => a.lastAccessed - b.lastAccessed).slice(0, limit);
185
+ return entries.map(([hash, item]) => ({
186
+ hash,
187
+ lastAccessed: new Date(item.lastAccessed),
188
+ size: item.size
189
+ }));
190
+ }
191
+ /**
192
+ * Destroy the cache and cleanup resources
193
+ */
194
+ destroy() {
195
+ if (this.cleanupInterval) {
196
+ clearInterval(this.cleanupInterval);
197
+ this.cleanupInterval = void 0;
198
+ }
199
+ this.cache.clear();
200
+ this.totalSize = 0;
201
+ }
202
+ /**
203
+ * Estimate the size in bytes of a cache entry (key + value + metadata)
204
+ */
205
+ estimateEntrySize(hash, value) {
206
+ var _a;
207
+ let size = 0;
208
+ size += hash.length * 2;
209
+ size += 16;
210
+ try {
211
+ const json = (_a = safeStringify__default.default(value)) != null ? _a : "";
212
+ size += json.length * 2;
213
+ } catch (e) {
214
+ size += 1024;
215
+ }
216
+ return size;
217
+ }
218
+ };
219
+ function deferred() {
220
+ let resolve;
221
+ let reject;
222
+ const promise = new Promise((res, rej) => {
223
+ resolve = res;
224
+ reject = rej;
225
+ });
226
+ return { promise, resolve, reject };
227
+ }
228
+ var InMemoryDedupeStore = class {
229
+ constructor({
230
+ /** Job timeout in milliseconds. Defaults to 5 minutes. */
231
+ jobTimeoutMs = 3e5,
232
+ /** Cleanup interval in milliseconds. Defaults to 1 minute. */
233
+ cleanupIntervalMs = 6e4
234
+ } = {}) {
235
+ this.jobs = /* @__PURE__ */ new Map();
236
+ this.totalJobsProcessed = 0;
237
+ this.destroyed = false;
238
+ this.jobTimeoutMs = jobTimeoutMs;
239
+ if (cleanupIntervalMs > 0) {
240
+ this.cleanupInterval = setInterval(() => {
241
+ this.cleanup();
242
+ }, cleanupIntervalMs);
243
+ if (typeof this.cleanupInterval.unref === "function") {
244
+ this.cleanupInterval.unref();
245
+ }
246
+ }
247
+ }
248
+ waitFor(hash) {
249
+ return __async(this, null, function* () {
250
+ var _a;
251
+ if (this.destroyed) {
252
+ return void 0;
253
+ }
254
+ const job = this.jobs.get(hash);
255
+ if (!job) {
256
+ return void 0;
257
+ }
258
+ const jobTimedOut = this.jobTimeoutMs > 0 && Date.now() - job.createdAt > this.jobTimeoutMs;
259
+ if (jobTimedOut) {
260
+ this.cleanup();
261
+ return void 0;
262
+ }
263
+ if (job.completed) {
264
+ if (job.error) {
265
+ return void 0;
266
+ }
267
+ return (_a = job.result) != null ? _a : void 0;
268
+ }
269
+ try {
270
+ return yield job.promise;
271
+ } catch (e) {
272
+ return void 0;
273
+ }
274
+ });
275
+ }
276
+ register(hash) {
277
+ return __async(this, null, function* () {
278
+ const registration = yield this.registerOrJoin(hash);
279
+ return registration.jobId;
280
+ });
281
+ }
282
+ registerOrJoin(hash) {
283
+ return __async(this, null, function* () {
284
+ const existingJob = this.jobs.get(hash);
285
+ if (existingJob) {
286
+ return {
287
+ jobId: existingJob.jobId,
288
+ isOwner: false
289
+ };
290
+ }
291
+ const jobId = crypto.randomUUID();
292
+ const { promise, resolve, reject } = deferred();
293
+ const job = {
294
+ jobId,
295
+ promise,
296
+ resolve,
297
+ reject,
298
+ createdAt: Date.now(),
299
+ completed: false
300
+ };
301
+ this.jobs.set(hash, job);
302
+ this.totalJobsProcessed++;
303
+ return {
304
+ jobId,
305
+ isOwner: true
306
+ };
307
+ });
308
+ }
309
+ complete(hash, value) {
310
+ return __async(this, null, function* () {
311
+ const job = this.jobs.get(hash);
312
+ if (job && !job.completed) {
313
+ job.completed = true;
314
+ job.result = value;
315
+ job.resolve(value);
316
+ }
317
+ });
318
+ }
319
+ fail(hash, error) {
320
+ return __async(this, null, function* () {
321
+ const job = this.jobs.get(hash);
322
+ if (job && !job.completed) {
323
+ job.completed = true;
324
+ job.error = error;
325
+ job.reject(error);
326
+ }
327
+ });
328
+ }
329
+ isInProgress(hash) {
330
+ return __async(this, null, function* () {
331
+ const job = this.jobs.get(hash);
332
+ if (!job) {
333
+ return false;
334
+ }
335
+ const isJobExpired = this.jobTimeoutMs > 0 && Date.now() - job.createdAt > this.jobTimeoutMs;
336
+ if (isJobExpired) {
337
+ this.cleanup();
338
+ return false;
339
+ }
340
+ return !job.completed;
341
+ });
342
+ }
343
+ /**
344
+ * Get statistics about current dedupe jobs
345
+ */
346
+ getStats() {
347
+ const now = Date.now();
348
+ let expiredJobs = 0;
349
+ let oldestJobAgeMs = 0;
350
+ let activeJobs = 0;
351
+ for (const [_hash, job] of this.jobs) {
352
+ const ageMs = now - job.createdAt;
353
+ if (this.jobTimeoutMs > 0 && ageMs > this.jobTimeoutMs) {
354
+ expiredJobs++;
355
+ }
356
+ if (ageMs > oldestJobAgeMs) {
357
+ oldestJobAgeMs = ageMs;
358
+ }
359
+ if (!job.completed) {
360
+ activeJobs++;
361
+ }
362
+ }
363
+ return {
364
+ activeJobs,
365
+ totalJobsProcessed: this.totalJobsProcessed,
366
+ expiredJobs,
367
+ oldestJobAgeMs
368
+ };
369
+ }
370
+ /**
371
+ * Clean up expired jobs
372
+ */
373
+ cleanup() {
374
+ if (this.jobTimeoutMs <= 0) {
375
+ return;
376
+ }
377
+ const now = Date.now();
378
+ const toDelete = [];
379
+ for (const [hash, job] of this.jobs) {
380
+ if (now - job.createdAt > this.jobTimeoutMs) {
381
+ if (!job.completed) {
382
+ job.completed = true;
383
+ job.error = new Error(
384
+ "Job timeout: Request took too long to complete"
385
+ );
386
+ job.reject(job.error);
387
+ }
388
+ toDelete.push(hash);
389
+ }
390
+ }
391
+ for (const hash of toDelete) {
392
+ this.jobs.delete(hash);
393
+ }
394
+ }
395
+ /**
396
+ * Clear all jobs
397
+ */
398
+ clear() {
399
+ for (const [_hash, job] of this.jobs) {
400
+ if (!job.completed) {
401
+ job.completed = true;
402
+ job.error = new Error("DedupeStore cleared");
403
+ job.reject(job.error);
404
+ }
405
+ }
406
+ this.jobs.clear();
407
+ }
408
+ /**
409
+ * Destroy the store and clean up resources
410
+ */
411
+ destroy() {
412
+ if (this.cleanupInterval) {
413
+ clearInterval(this.cleanupInterval);
414
+ this.cleanupInterval = void 0;
415
+ }
416
+ this.clear();
417
+ this.destroyed = true;
418
+ }
419
+ };
420
+ var InMemoryRateLimitStore = class {
421
+ constructor({
422
+ /** Global/default rate-limit config applied when a resource-specific override is not provided. */
423
+ defaultConfig = core.DEFAULT_RATE_LIMIT,
424
+ /** Optional per-resource overrides. */
425
+ resourceConfigs = /* @__PURE__ */ new Map(),
426
+ /** Cleanup interval in milliseconds. Defaults to 1 minute. */
427
+ cleanupIntervalMs = 6e4
428
+ } = {}) {
429
+ this.limits = /* @__PURE__ */ new Map();
430
+ this.resourceConfigs = /* @__PURE__ */ new Map();
431
+ this.totalRequests = 0;
432
+ this.defaultConfig = defaultConfig;
433
+ this.resourceConfigs = resourceConfigs;
434
+ if (cleanupIntervalMs > 0) {
435
+ this.cleanupInterval = setInterval(() => {
436
+ this.cleanup();
437
+ }, cleanupIntervalMs);
438
+ if (typeof this.cleanupInterval.unref === "function") {
439
+ this.cleanupInterval.unref();
440
+ }
441
+ }
442
+ }
443
+ canProceed(resource) {
444
+ return __async(this, null, function* () {
445
+ const config = this.resourceConfigs.get(resource) || this.defaultConfig;
446
+ const info = this.getOrCreateRateLimitInfo(resource, config);
447
+ this.cleanupExpiredRequests(info);
448
+ return info.requests.length < info.limit;
449
+ });
450
+ }
451
+ record(resource) {
452
+ return __async(this, null, function* () {
453
+ const config = this.resourceConfigs.get(resource) || this.defaultConfig;
454
+ const info = this.getOrCreateRateLimitInfo(resource, config);
455
+ this.cleanupExpiredRequests(info);
456
+ const now = Date.now();
457
+ info.requests.push(now);
458
+ this.totalRequests++;
459
+ info.resetTime = now + config.windowMs;
460
+ });
461
+ }
462
+ getStatus(resource) {
463
+ return __async(this, null, function* () {
464
+ const config = this.resourceConfigs.get(resource) || this.defaultConfig;
465
+ const info = this.getOrCreateRateLimitInfo(resource, config);
466
+ this.cleanupExpiredRequests(info);
467
+ return {
468
+ remaining: Math.max(0, info.limit - info.requests.length),
469
+ resetTime: new Date(info.resetTime),
470
+ limit: info.limit
471
+ };
472
+ });
473
+ }
474
+ reset(resource) {
475
+ return __async(this, null, function* () {
476
+ const info = this.limits.get(resource);
477
+ if (info) {
478
+ this.totalRequests = Math.max(
479
+ 0,
480
+ this.totalRequests - info.requests.length
481
+ );
482
+ }
483
+ this.limits.delete(resource);
484
+ });
485
+ }
486
+ getWaitTime(resource) {
487
+ return __async(this, null, function* () {
488
+ const config = this.resourceConfigs.get(resource) || this.defaultConfig;
489
+ const info = this.getOrCreateRateLimitInfo(resource, config);
490
+ this.cleanupExpiredRequests(info);
491
+ if (info.limit === 0) {
492
+ return Math.max(0, info.resetTime - Date.now());
493
+ }
494
+ if (info.requests.length < info.limit) {
495
+ return 0;
496
+ }
497
+ const oldestRequest = info.requests[0];
498
+ if (oldestRequest === void 0) {
499
+ return 0;
500
+ }
501
+ const timeUntilOldestExpires = oldestRequest + config.windowMs - Date.now();
502
+ return Math.max(0, timeUntilOldestExpires);
503
+ });
504
+ }
505
+ /**
506
+ * Set rate limit configuration for a specific resource
507
+ */
508
+ setResourceConfig(resource, config) {
509
+ this.resourceConfigs.set(resource, config);
510
+ this.limits.delete(resource);
511
+ }
512
+ /**
513
+ * Get rate limit configuration for a resource
514
+ */
515
+ getResourceConfig(resource) {
516
+ return this.resourceConfigs.get(resource) || this.defaultConfig;
517
+ }
518
+ /**
519
+ * Get statistics for all resources
520
+ */
521
+ getStats() {
522
+ let activeResources = 0;
523
+ let rateLimitedResources = 0;
524
+ for (const [_resource, info] of this.limits) {
525
+ this.cleanupExpiredRequests(info);
526
+ if (info.requests.length > 0) {
527
+ activeResources++;
528
+ if (info.requests.length >= info.limit) {
529
+ rateLimitedResources++;
530
+ }
531
+ }
532
+ }
533
+ return {
534
+ totalResources: this.limits.size,
535
+ activeResources,
536
+ rateLimitedResources,
537
+ totalRequests: this.totalRequests
538
+ };
539
+ }
540
+ /**
541
+ * Clear all rate limit data
542
+ */
543
+ clear() {
544
+ this.limits.clear();
545
+ this.totalRequests = 0;
546
+ }
547
+ /**
548
+ * Clean up expired requests for all resources
549
+ */
550
+ cleanup() {
551
+ for (const [_resource, info] of this.limits) {
552
+ this.cleanupExpiredRequests(info);
553
+ }
554
+ }
555
+ /**
556
+ * Destroy the store and clean up resources
557
+ */
558
+ destroy() {
559
+ if (this.cleanupInterval) {
560
+ clearInterval(this.cleanupInterval);
561
+ this.cleanupInterval = void 0;
562
+ }
563
+ this.clear();
564
+ }
565
+ getOrCreateRateLimitInfo(resource, config) {
566
+ let info = this.limits.get(resource);
567
+ if (!info) {
568
+ info = {
569
+ requests: [],
570
+ limit: config.limit,
571
+ windowMs: config.windowMs,
572
+ resetTime: Date.now() + config.windowMs
573
+ };
574
+ this.limits.set(resource, info);
575
+ }
576
+ return info;
577
+ }
578
+ cleanupExpiredRequests(info) {
579
+ const now = Date.now();
580
+ const cutoff = now - info.windowMs;
581
+ const initialLength = info.requests.length;
582
+ while (info.requests.length > 0 && info.requests[0] < cutoff) {
583
+ info.requests.shift();
584
+ }
585
+ const expiredCount = initialLength - info.requests.length;
586
+ this.totalRequests = Math.max(0, this.totalRequests - expiredCount);
587
+ if (info.requests.length === 0) {
588
+ info.resetTime = now + info.windowMs;
589
+ }
590
+ }
591
+ };
592
+ var AdaptiveRateLimitStore = class {
593
+ constructor(options = {}) {
594
+ this.activityMetrics = /* @__PURE__ */ new Map();
595
+ this.lastCapacityUpdate = /* @__PURE__ */ new Map();
596
+ this.cachedCapacity = /* @__PURE__ */ new Map();
597
+ var _a, _b;
598
+ this.defaultConfig = (_a = options.defaultConfig) != null ? _a : core.DEFAULT_RATE_LIMIT;
599
+ this.resourceConfigs = (_b = options.resourceConfigs) != null ? _b : /* @__PURE__ */ new Map();
600
+ this.capacityCalculator = new core.AdaptiveCapacityCalculator(
601
+ options.adaptiveConfig
602
+ );
603
+ }
604
+ canProceed(resource, priority = "background") {
605
+ return __async(this, null, function* () {
606
+ const metrics = this.getOrCreateActivityMetrics(resource);
607
+ const capacity = this.calculateCurrentCapacity(resource, metrics);
608
+ if (priority === "background" && capacity.backgroundPaused) {
609
+ return false;
610
+ }
611
+ const currentUserRequests = this.getCurrentUsage(
612
+ resource,
613
+ metrics.recentUserRequests
614
+ );
615
+ const currentBackgroundRequests = this.getCurrentUsage(
616
+ resource,
617
+ metrics.recentBackgroundRequests
618
+ );
619
+ if (priority === "user") {
620
+ return currentUserRequests < capacity.userReserved;
621
+ } else {
622
+ return currentBackgroundRequests < capacity.backgroundMax;
623
+ }
624
+ });
625
+ }
626
+ record(resource, priority = "background") {
627
+ return __async(this, null, function* () {
628
+ const metrics = this.getOrCreateActivityMetrics(resource);
629
+ const now = Date.now();
630
+ if (priority === "user") {
631
+ metrics.recentUserRequests.push(now);
632
+ this.cleanupOldRequests(metrics.recentUserRequests);
633
+ } else {
634
+ metrics.recentBackgroundRequests.push(now);
635
+ this.cleanupOldRequests(metrics.recentBackgroundRequests);
636
+ }
637
+ metrics.userActivityTrend = this.capacityCalculator.calculateActivityTrend(
638
+ metrics.recentUserRequests
639
+ );
640
+ });
641
+ }
642
+ getStatus(resource) {
643
+ return __async(this, null, function* () {
644
+ var _a;
645
+ const metrics = this.getOrCreateActivityMetrics(resource);
646
+ const capacity = this.calculateCurrentCapacity(resource, metrics);
647
+ const currentUserUsage = this.getCurrentUsage(
648
+ resource,
649
+ metrics.recentUserRequests
650
+ );
651
+ const currentBackgroundUsage = this.getCurrentUsage(
652
+ resource,
653
+ metrics.recentBackgroundRequests
654
+ );
655
+ const config = (_a = this.resourceConfigs.get(resource)) != null ? _a : this.defaultConfig;
656
+ return {
657
+ remaining: capacity.userReserved - currentUserUsage + (capacity.backgroundMax - currentBackgroundUsage),
658
+ resetTime: new Date(Date.now() + config.windowMs),
659
+ limit: this.getResourceLimit(resource),
660
+ adaptive: {
661
+ userReserved: capacity.userReserved,
662
+ backgroundMax: capacity.backgroundMax,
663
+ backgroundPaused: capacity.backgroundPaused,
664
+ recentUserActivity: this.capacityCalculator.getRecentActivity(
665
+ metrics.recentUserRequests
666
+ ),
667
+ reason: capacity.reason
668
+ }
669
+ };
670
+ });
671
+ }
672
+ reset(resource) {
673
+ return __async(this, null, function* () {
674
+ this.activityMetrics.delete(resource);
675
+ this.cachedCapacity.delete(resource);
676
+ this.lastCapacityUpdate.delete(resource);
677
+ });
678
+ }
679
+ getWaitTime(resource, priority = "background") {
680
+ return __async(this, null, function* () {
681
+ const canProceed = yield this.canProceed(resource, priority);
682
+ if (canProceed) {
683
+ return 0;
684
+ }
685
+ const metrics = this.getOrCreateActivityMetrics(resource);
686
+ const capacity = this.calculateCurrentCapacity(resource, metrics);
687
+ if (priority === "background" && capacity.backgroundPaused) {
688
+ const lastUpdate = this.lastCapacityUpdate.get(resource) || 0;
689
+ const nextUpdate = lastUpdate + this.capacityCalculator.config.recalculationIntervalMs;
690
+ return Math.max(0, nextUpdate - Date.now());
691
+ }
692
+ const monitoringWindow = this.capacityCalculator.config.monitoringWindowMs;
693
+ const requests = priority === "user" ? metrics.recentUserRequests : metrics.recentBackgroundRequests;
694
+ if (requests.length === 0) {
695
+ return 0;
696
+ }
697
+ const oldestRequest = Math.min(...requests);
698
+ const waitTime = oldestRequest + monitoringWindow - Date.now();
699
+ return Math.max(0, waitTime);
700
+ });
701
+ }
702
+ calculateCurrentCapacity(resource, metrics) {
703
+ const lastUpdate = this.lastCapacityUpdate.get(resource) || 0;
704
+ const recalcInterval = this.capacityCalculator.config.recalculationIntervalMs;
705
+ if (Date.now() - lastUpdate < recalcInterval) {
706
+ return this.cachedCapacity.get(resource) || this.getDefaultCapacity(resource);
707
+ }
708
+ const totalLimit = this.getResourceLimit(resource);
709
+ const capacity = this.capacityCalculator.calculateDynamicCapacity(
710
+ resource,
711
+ totalLimit,
712
+ metrics
713
+ );
714
+ this.cachedCapacity.set(resource, capacity);
715
+ this.lastCapacityUpdate.set(resource, Date.now());
716
+ return capacity;
717
+ }
718
+ getOrCreateActivityMetrics(resource) {
719
+ if (!this.activityMetrics.has(resource)) {
720
+ this.activityMetrics.set(resource, {
721
+ recentUserRequests: [],
722
+ recentBackgroundRequests: [],
723
+ userActivityTrend: "none"
724
+ });
725
+ }
726
+ return this.activityMetrics.get(resource);
727
+ }
728
+ getCurrentUsage(resource, requests) {
729
+ var _a;
730
+ const config = (_a = this.resourceConfigs.get(resource)) != null ? _a : this.defaultConfig;
731
+ const windowStart = Date.now() - config.windowMs;
732
+ return requests.filter((timestamp) => timestamp > windowStart).length;
733
+ }
734
+ cleanupOldRequests(requests) {
735
+ const cutoff = Date.now() - this.capacityCalculator.config.monitoringWindowMs;
736
+ while (requests.length > 0 && requests[0] < cutoff) {
737
+ requests.shift();
738
+ }
739
+ }
740
+ getResourceLimit(resource) {
741
+ var _a;
742
+ const config = (_a = this.resourceConfigs.get(resource)) != null ? _a : this.defaultConfig;
743
+ return config.limit;
744
+ }
745
+ getDefaultCapacity(resource) {
746
+ const totalLimit = this.getResourceLimit(resource);
747
+ return {
748
+ userReserved: Math.floor(totalLimit * 0.3),
749
+ backgroundMax: Math.floor(totalLimit * 0.7),
750
+ backgroundPaused: false,
751
+ reason: "Default capacity allocation"
752
+ };
753
+ }
754
+ };
755
+
756
+ exports.AdaptiveRateLimitStore = AdaptiveRateLimitStore;
757
+ exports.InMemoryCacheStore = InMemoryCacheStore;
758
+ exports.InMemoryDedupeStore = InMemoryDedupeStore;
759
+ exports.InMemoryRateLimitStore = InMemoryRateLimitStore;
760
+ //# sourceMappingURL=index.cjs.map
761
+ //# sourceMappingURL=index.cjs.map