ts-cachecraft 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,2281 @@
1
+ // src/base-cache.ts
2
+ var BaseCache = class {
3
+ _capacity;
4
+ _hits = 0;
5
+ _misses = 0;
6
+ _evictions = 0;
7
+ onEvict;
8
+ listeners = /* @__PURE__ */ new Map();
9
+ constructor(options) {
10
+ const capacity = typeof options === "number" ? options : options.capacity;
11
+ if (capacity < 1) throw new RangeError("Cache capacity must be at least 1");
12
+ this._capacity = capacity;
13
+ if (typeof options === "object") {
14
+ this.onEvict = options.onEvict;
15
+ }
16
+ }
17
+ get capacity() {
18
+ return this._capacity;
19
+ }
20
+ stats() {
21
+ const total = this._hits + this._misses;
22
+ return {
23
+ hits: this._hits,
24
+ misses: this._misses,
25
+ evictions: this._evictions,
26
+ size: this.size,
27
+ capacity: this._capacity,
28
+ hitRate: total === 0 ? 0 : this._hits / total
29
+ };
30
+ }
31
+ snapshot() {
32
+ return {
33
+ entries: this.collectEntries(),
34
+ stats: this.stats(),
35
+ strategy: this.strategy
36
+ };
37
+ }
38
+ on(event, listener) {
39
+ if (!this.listeners.has(event)) {
40
+ this.listeners.set(event, /* @__PURE__ */ new Set());
41
+ }
42
+ this.listeners.get(event).add(listener);
43
+ }
44
+ off(event, listener) {
45
+ this.listeners.get(event)?.delete(listener);
46
+ }
47
+ emit(detail) {
48
+ const set = this.listeners.get(detail.event);
49
+ if (set) {
50
+ for (const listener of set) {
51
+ listener(detail);
52
+ }
53
+ }
54
+ }
55
+ now() {
56
+ return Date.now();
57
+ }
58
+ };
59
+
60
+ // src/structures/doubly-linked-list.ts
61
+ function createNode(key, value) {
62
+ return { key, value, prev: null, next: null, accessCount: 0 };
63
+ }
64
+ var DoublyLinkedList = class {
65
+ head;
66
+ tail;
67
+ _size = 0;
68
+ constructor() {
69
+ this.head = createNode("__head__", void 0);
70
+ this.tail = createNode("__tail__", void 0);
71
+ this.head.next = this.tail;
72
+ this.tail.prev = this.head;
73
+ }
74
+ get size() {
75
+ return this._size;
76
+ }
77
+ addToFront(node) {
78
+ node.next = this.head.next;
79
+ node.prev = this.head;
80
+ this.head.next.prev = node;
81
+ this.head.next = node;
82
+ this._size++;
83
+ }
84
+ addToBack(node) {
85
+ node.prev = this.tail.prev;
86
+ node.next = this.tail;
87
+ this.tail.prev.next = node;
88
+ this.tail.prev = node;
89
+ this._size++;
90
+ }
91
+ remove(node) {
92
+ if (!node.prev || !node.next) return;
93
+ node.prev.next = node.next;
94
+ node.next.prev = node.prev;
95
+ node.prev = null;
96
+ node.next = null;
97
+ this._size--;
98
+ }
99
+ moveToFront(node) {
100
+ this.remove(node);
101
+ this.addToFront(node);
102
+ }
103
+ moveToBack(node) {
104
+ this.remove(node);
105
+ this.addToBack(node);
106
+ }
107
+ removeLast() {
108
+ if (this._size === 0) return null;
109
+ const node = this.tail.prev;
110
+ this.remove(node);
111
+ return node;
112
+ }
113
+ removeFirst() {
114
+ if (this._size === 0) return null;
115
+ const node = this.head.next;
116
+ this.remove(node);
117
+ return node;
118
+ }
119
+ peekFirst() {
120
+ return this._size === 0 ? null : this.head.next;
121
+ }
122
+ peekLast() {
123
+ return this._size === 0 ? null : this.tail.prev;
124
+ }
125
+ clear() {
126
+ this.head.next = this.tail;
127
+ this.tail.prev = this.head;
128
+ this._size = 0;
129
+ }
130
+ *[Symbol.iterator]() {
131
+ let current = this.head.next;
132
+ while (current && current !== this.tail) {
133
+ yield current;
134
+ current = current.next;
135
+ }
136
+ }
137
+ toArray() {
138
+ const result = [];
139
+ for (const node of this) {
140
+ result.push(node);
141
+ }
142
+ return result;
143
+ }
144
+ };
145
+
146
+ // src/caches/dll-cache.ts
147
+ var DLLCache = class extends BaseCache {
148
+ list = new DoublyLinkedList();
149
+ map = /* @__PURE__ */ new Map();
150
+ defaultTTL;
151
+ config;
152
+ constructor(options, config) {
153
+ super(options);
154
+ this.defaultTTL = options.ttl;
155
+ this.config = config;
156
+ }
157
+ get(key) {
158
+ const node = this.map.get(key);
159
+ if (!node) {
160
+ this._misses++;
161
+ this.emit({ event: "get", key, timestamp: this.now() });
162
+ return void 0;
163
+ }
164
+ if (node.expiry && node.expiry <= this.now()) {
165
+ this.deleteNode(key, node);
166
+ this._misses++;
167
+ this.emit({ event: "expire", key, value: node.value, timestamp: this.now() });
168
+ this.emit({ event: "get", key, timestamp: this.now() });
169
+ return void 0;
170
+ }
171
+ node.lastAccessed = this.now();
172
+ node.accessCount = (node.accessCount ?? 0) + 1;
173
+ if (this.config.reorderOnGet) {
174
+ this.list.moveToFront(node);
175
+ }
176
+ this._hits++;
177
+ this.emit({ event: "get", key, value: node.value, timestamp: this.now() });
178
+ return node.value;
179
+ }
180
+ set(key, value, ttl) {
181
+ const now = this.now();
182
+ const effectiveTTL = ttl ?? this.defaultTTL;
183
+ const expiry = effectiveTTL ? now + effectiveTTL : void 0;
184
+ const existing = this.map.get(key);
185
+ if (existing) {
186
+ existing.value = value;
187
+ existing.lastAccessed = now;
188
+ existing.expiry = expiry;
189
+ existing.metadata = { ...existing.metadata, createdAt: existing.metadata?.createdAt ?? now };
190
+ if (this.config.reorderOnUpdate) {
191
+ this.list.moveToFront(existing);
192
+ }
193
+ this.emit({ event: "set", key, value, timestamp: now });
194
+ return;
195
+ }
196
+ if (this.map.size >= this._capacity) {
197
+ const evicted = this.config.evictPosition === "back" ? this.list.removeLast() : this.list.removeFirst();
198
+ if (evicted) {
199
+ this.map.delete(evicted.key);
200
+ this._evictions++;
201
+ this.onEvict?.(evicted.key, evicted.value);
202
+ this.emit({ event: "evict", key, value, evictedKey: evicted.key, evictedValue: evicted.value, timestamp: now });
203
+ }
204
+ }
205
+ const node = createNode(key, value);
206
+ node.metadata = { createdAt: now };
207
+ node.lastAccessed = now;
208
+ node.accessCount = 0;
209
+ node.expiry = expiry;
210
+ if (this.config.addPosition === "front") {
211
+ this.list.addToFront(node);
212
+ } else {
213
+ this.list.addToBack(node);
214
+ }
215
+ this.map.set(key, node);
216
+ this.emit({ event: "set", key, value, timestamp: now });
217
+ }
218
+ delete(key) {
219
+ const node = this.map.get(key);
220
+ if (!node) return false;
221
+ this.deleteNode(key, node);
222
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
223
+ return true;
224
+ }
225
+ has(key) {
226
+ const node = this.map.get(key);
227
+ if (!node) return false;
228
+ if (node.expiry && node.expiry <= this.now()) {
229
+ return false;
230
+ }
231
+ return true;
232
+ }
233
+ clear() {
234
+ this.list.clear();
235
+ this.map.clear();
236
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
237
+ }
238
+ get size() {
239
+ return this.map.size;
240
+ }
241
+ *keys() {
242
+ for (const node of this.list) {
243
+ yield node.key;
244
+ }
245
+ }
246
+ *values() {
247
+ for (const node of this.list) {
248
+ yield node.value;
249
+ }
250
+ }
251
+ *entries() {
252
+ for (const node of this.list) {
253
+ yield [node.key, node.value];
254
+ }
255
+ }
256
+ collectEntries() {
257
+ const result = [];
258
+ for (const node of this.list) {
259
+ result.push({
260
+ key: node.key,
261
+ value: node.value,
262
+ createdAt: node.metadata?.createdAt ?? 0,
263
+ lastAccessed: node.lastAccessed ?? 0,
264
+ accessCount: node.accessCount ?? 0
265
+ });
266
+ }
267
+ return result;
268
+ }
269
+ deleteNode(key, node) {
270
+ this.list.remove(node);
271
+ this.map.delete(key);
272
+ }
273
+ };
274
+
275
+ // src/caches/lru.ts
276
+ var LRUCache = class extends DLLCache {
277
+ constructor(options) {
278
+ super(options, {
279
+ reorderOnGet: true,
280
+ reorderOnUpdate: true,
281
+ addPosition: "front",
282
+ evictPosition: "back"
283
+ });
284
+ }
285
+ get strategy() {
286
+ return "LRU";
287
+ }
288
+ };
289
+
290
+ // src/caches/mru.ts
291
+ var MRUCache = class extends DLLCache {
292
+ constructor(options) {
293
+ super(options, {
294
+ reorderOnGet: true,
295
+ reorderOnUpdate: true,
296
+ addPosition: "front",
297
+ evictPosition: "front"
298
+ });
299
+ }
300
+ get strategy() {
301
+ return "MRU";
302
+ }
303
+ };
304
+
305
+ // src/caches/lfu.ts
306
+ var LFUCache = class extends BaseCache {
307
+ store = /* @__PURE__ */ new Map();
308
+ freqBuckets = /* @__PURE__ */ new Map();
309
+ minFrequency = 0;
310
+ constructor(options) {
311
+ super(options);
312
+ }
313
+ getOrCreateBucket(freq) {
314
+ let bucket = this.freqBuckets.get(freq);
315
+ if (!bucket) {
316
+ bucket = new DoublyLinkedList();
317
+ this.freqBuckets.set(freq, bucket);
318
+ }
319
+ return bucket;
320
+ }
321
+ incrementFrequency(meta) {
322
+ const oldFreq = meta.frequency;
323
+ const oldBucket = this.freqBuckets.get(oldFreq);
324
+ oldBucket.remove(meta.node);
325
+ if (oldBucket.size === 0 && this.minFrequency === oldFreq) {
326
+ this.minFrequency = oldFreq + 1;
327
+ }
328
+ meta.frequency = oldFreq + 1;
329
+ const newBucket = this.getOrCreateBucket(meta.frequency);
330
+ newBucket.addToFront(meta.node);
331
+ }
332
+ get(key) {
333
+ const meta = this.store.get(key);
334
+ if (!meta) {
335
+ this._misses++;
336
+ this.emit({ event: "get", key, timestamp: this.now() });
337
+ return void 0;
338
+ }
339
+ this._hits++;
340
+ meta.accessCount++;
341
+ meta.lastAccessed = this.now();
342
+ this.incrementFrequency(meta);
343
+ this.emit({ event: "get", key, value: meta.node.value, timestamp: this.now() });
344
+ return meta.node.value;
345
+ }
346
+ set(key, value, _ttl) {
347
+ const existing = this.store.get(key);
348
+ if (existing) {
349
+ existing.node.value = value;
350
+ existing.lastAccessed = this.now();
351
+ existing.accessCount++;
352
+ this.incrementFrequency(existing);
353
+ this.emit({ event: "set", key, value, timestamp: this.now() });
354
+ return;
355
+ }
356
+ if (this.store.size >= this._capacity) {
357
+ this.evict();
358
+ }
359
+ const node = createNode(key, value);
360
+ const now = this.now();
361
+ const meta = {
362
+ createdAt: now,
363
+ lastAccessed: now,
364
+ accessCount: 1,
365
+ frequency: 1,
366
+ node
367
+ };
368
+ this.store.set(key, meta);
369
+ const bucket = this.getOrCreateBucket(1);
370
+ bucket.addToFront(node);
371
+ this.minFrequency = 1;
372
+ this.emit({ event: "set", key, value, timestamp: this.now() });
373
+ }
374
+ evict() {
375
+ const bucket = this.freqBuckets.get(this.minFrequency);
376
+ if (!bucket || bucket.size === 0) return;
377
+ const evicted = bucket.removeLast();
378
+ if (!evicted) return;
379
+ this.store.delete(evicted.key);
380
+ this._evictions++;
381
+ this.onEvict?.(evicted.key, evicted.value);
382
+ this.emit({
383
+ event: "evict",
384
+ key: evicted.key,
385
+ evictedKey: evicted.key,
386
+ evictedValue: evicted.value,
387
+ timestamp: this.now()
388
+ });
389
+ }
390
+ delete(key) {
391
+ const meta = this.store.get(key);
392
+ if (!meta) return false;
393
+ const bucket = this.freqBuckets.get(meta.frequency);
394
+ if (bucket) {
395
+ bucket.remove(meta.node);
396
+ }
397
+ this.store.delete(key);
398
+ this.emit({ event: "delete", key, value: meta.node.value, timestamp: this.now() });
399
+ return true;
400
+ }
401
+ has(key) {
402
+ return this.store.has(key);
403
+ }
404
+ clear() {
405
+ this.store.clear();
406
+ this.freqBuckets.clear();
407
+ this.minFrequency = 0;
408
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
409
+ }
410
+ get size() {
411
+ return this.store.size;
412
+ }
413
+ *keys() {
414
+ for (const key of this.store.keys()) {
415
+ yield key;
416
+ }
417
+ }
418
+ *values() {
419
+ for (const meta of this.store.values()) {
420
+ yield meta.node.value;
421
+ }
422
+ }
423
+ *entries() {
424
+ for (const [key, meta] of this.store.entries()) {
425
+ yield [key, meta.node.value];
426
+ }
427
+ }
428
+ get strategy() {
429
+ return "LFU";
430
+ }
431
+ collectEntries() {
432
+ const result = [];
433
+ for (const [key, meta] of this.store.entries()) {
434
+ result.push({
435
+ key,
436
+ value: meta.node.value,
437
+ createdAt: meta.createdAt,
438
+ lastAccessed: meta.lastAccessed,
439
+ accessCount: meta.accessCount
440
+ });
441
+ }
442
+ return result;
443
+ }
444
+ };
445
+
446
+ // src/caches/ttl.ts
447
+ var TTLCache = class extends BaseCache {
448
+ store = /* @__PURE__ */ new Map();
449
+ defaultTTL;
450
+ cleanupTimer = null;
451
+ constructor(options) {
452
+ super(options);
453
+ this.defaultTTL = options.ttl ?? 0;
454
+ if (this.defaultTTL > 0) {
455
+ this.cleanupTimer = setInterval(() => this.cleanup(), this.defaultTTL);
456
+ }
457
+ }
458
+ isExpired(entry) {
459
+ return entry.expiry > 0 && this.now() >= entry.expiry;
460
+ }
461
+ cleanup() {
462
+ for (const [key, entry] of this.store.entries()) {
463
+ if (this.isExpired(entry)) {
464
+ this.store.delete(key);
465
+ this.emit({
466
+ event: "expire",
467
+ key,
468
+ value: entry.value,
469
+ timestamp: this.now()
470
+ });
471
+ }
472
+ }
473
+ }
474
+ get(key) {
475
+ const entry = this.store.get(key);
476
+ if (!entry) {
477
+ this._misses++;
478
+ this.emit({ event: "get", key, timestamp: this.now() });
479
+ return void 0;
480
+ }
481
+ if (this.isExpired(entry)) {
482
+ this.store.delete(key);
483
+ this.emit({ event: "expire", key, value: entry.value, timestamp: this.now() });
484
+ this._misses++;
485
+ this.emit({ event: "get", key, timestamp: this.now() });
486
+ return void 0;
487
+ }
488
+ this._hits++;
489
+ entry.accessCount++;
490
+ entry.lastAccessed = this.now();
491
+ this.emit({ event: "get", key, value: entry.value, timestamp: this.now() });
492
+ return entry.value;
493
+ }
494
+ set(key, value, ttl) {
495
+ const existing = this.store.get(key);
496
+ const now = this.now();
497
+ const effectiveTTL = ttl ?? this.defaultTTL;
498
+ const expiry = effectiveTTL > 0 ? now + effectiveTTL : 0;
499
+ if (existing && !this.isExpired(existing)) {
500
+ existing.value = value;
501
+ existing.lastAccessed = now;
502
+ existing.accessCount++;
503
+ existing.expiry = expiry;
504
+ existing.ttl = effectiveTTL;
505
+ this.emit({ event: "set", key, value, timestamp: now });
506
+ return;
507
+ }
508
+ if (existing) {
509
+ this.store.delete(key);
510
+ }
511
+ if (this.store.size >= this._capacity) {
512
+ this.evict();
513
+ }
514
+ this.store.set(key, {
515
+ value,
516
+ createdAt: now,
517
+ lastAccessed: now,
518
+ accessCount: 1,
519
+ expiry,
520
+ ttl: effectiveTTL
521
+ });
522
+ this.emit({ event: "set", key, value, timestamp: now });
523
+ }
524
+ evict() {
525
+ let oldestKey = null;
526
+ let oldestTime = Infinity;
527
+ for (const [key, entry] of this.store.entries()) {
528
+ if (this.isExpired(entry)) {
529
+ this.store.delete(key);
530
+ this._evictions++;
531
+ this.onEvict?.(key, entry.value);
532
+ this.emit({
533
+ event: "evict",
534
+ key,
535
+ evictedKey: key,
536
+ evictedValue: entry.value,
537
+ timestamp: this.now()
538
+ });
539
+ return;
540
+ }
541
+ if (entry.createdAt < oldestTime) {
542
+ oldestTime = entry.createdAt;
543
+ oldestKey = key;
544
+ }
545
+ }
546
+ if (oldestKey !== null) {
547
+ const entry = this.store.get(oldestKey);
548
+ this.store.delete(oldestKey);
549
+ this._evictions++;
550
+ this.onEvict?.(oldestKey, entry.value);
551
+ this.emit({
552
+ event: "evict",
553
+ key: oldestKey,
554
+ evictedKey: oldestKey,
555
+ evictedValue: entry.value,
556
+ timestamp: this.now()
557
+ });
558
+ }
559
+ }
560
+ delete(key) {
561
+ const entry = this.store.get(key);
562
+ if (!entry) return false;
563
+ this.store.delete(key);
564
+ this.emit({ event: "delete", key, value: entry.value, timestamp: this.now() });
565
+ return true;
566
+ }
567
+ has(key) {
568
+ const entry = this.store.get(key);
569
+ if (!entry) return false;
570
+ return !this.isExpired(entry);
571
+ }
572
+ clear() {
573
+ this.store.clear();
574
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
575
+ }
576
+ get size() {
577
+ let count = 0;
578
+ for (const entry of this.store.values()) {
579
+ if (!this.isExpired(entry)) {
580
+ count++;
581
+ }
582
+ }
583
+ return count;
584
+ }
585
+ *keys() {
586
+ for (const [key, entry] of this.store.entries()) {
587
+ if (!this.isExpired(entry)) {
588
+ yield key;
589
+ }
590
+ }
591
+ }
592
+ *values() {
593
+ for (const [, entry] of this.store.entries()) {
594
+ if (!this.isExpired(entry)) {
595
+ yield entry.value;
596
+ }
597
+ }
598
+ }
599
+ *entries() {
600
+ for (const [key, entry] of this.store.entries()) {
601
+ if (!this.isExpired(entry)) {
602
+ yield [key, entry.value];
603
+ }
604
+ }
605
+ }
606
+ get strategy() {
607
+ return "TTL";
608
+ }
609
+ collectEntries() {
610
+ const result = [];
611
+ for (const [key, entry] of this.store.entries()) {
612
+ if (!this.isExpired(entry)) {
613
+ result.push({
614
+ key,
615
+ value: entry.value,
616
+ createdAt: entry.createdAt,
617
+ lastAccessed: entry.lastAccessed,
618
+ accessCount: entry.accessCount,
619
+ ttl: entry.ttl
620
+ });
621
+ }
622
+ }
623
+ return result;
624
+ }
625
+ destroy() {
626
+ if (this.cleanupTimer !== null) {
627
+ clearInterval(this.cleanupTimer);
628
+ this.cleanupTimer = null;
629
+ }
630
+ this.clear();
631
+ }
632
+ };
633
+
634
+ // src/caches/fifo.ts
635
+ var FIFOCache = class extends DLLCache {
636
+ constructor(options) {
637
+ super(options, {
638
+ reorderOnGet: false,
639
+ reorderOnUpdate: false,
640
+ addPosition: "back",
641
+ evictPosition: "front"
642
+ });
643
+ }
644
+ get strategy() {
645
+ return "FIFO";
646
+ }
647
+ };
648
+
649
+ // src/caches/lifo.ts
650
+ var LIFOCache = class extends DLLCache {
651
+ constructor(options) {
652
+ super(options, {
653
+ reorderOnGet: false,
654
+ reorderOnUpdate: true,
655
+ addPosition: "front",
656
+ evictPosition: "front"
657
+ });
658
+ }
659
+ get strategy() {
660
+ return "LIFO";
661
+ }
662
+ };
663
+
664
+ // src/caches/rr.ts
665
+ var RRCache = class extends BaseCache {
666
+ store = /* @__PURE__ */ new Map();
667
+ keyList = [];
668
+ constructor(options) {
669
+ super(options);
670
+ }
671
+ get(key) {
672
+ const entry = this.store.get(key);
673
+ if (!entry) {
674
+ this._misses++;
675
+ this.emit({ event: "get", key, timestamp: this.now() });
676
+ return void 0;
677
+ }
678
+ this._hits++;
679
+ entry.accessCount++;
680
+ entry.lastAccessed = this.now();
681
+ this.emit({ event: "get", key, value: entry.value, timestamp: this.now() });
682
+ return entry.value;
683
+ }
684
+ set(key, value, _ttl) {
685
+ const existing = this.store.get(key);
686
+ if (existing) {
687
+ existing.value = value;
688
+ existing.lastAccessed = this.now();
689
+ existing.accessCount++;
690
+ this.emit({ event: "set", key, value, timestamp: this.now() });
691
+ return;
692
+ }
693
+ if (this.store.size >= this._capacity) {
694
+ this.evict();
695
+ }
696
+ const now = this.now();
697
+ const keyIndex = this.keyList.length;
698
+ this.keyList.push(key);
699
+ this.store.set(key, {
700
+ value,
701
+ createdAt: now,
702
+ lastAccessed: now,
703
+ accessCount: 1,
704
+ keyIndex
705
+ });
706
+ this.emit({ event: "set", key, value, timestamp: now });
707
+ }
708
+ evict() {
709
+ if (this.keyList.length === 0) return;
710
+ const randomIndex = Math.floor(Math.random() * this.keyList.length);
711
+ const evictedKey = this.keyList[randomIndex];
712
+ const entry = this.store.get(evictedKey);
713
+ this.removeKeyAtIndex(randomIndex);
714
+ this.store.delete(evictedKey);
715
+ this._evictions++;
716
+ this.onEvict?.(evictedKey, entry.value);
717
+ this.emit({
718
+ event: "evict",
719
+ key: evictedKey,
720
+ evictedKey,
721
+ evictedValue: entry.value,
722
+ timestamp: this.now()
723
+ });
724
+ }
725
+ removeKeyAtIndex(index) {
726
+ const lastIndex = this.keyList.length - 1;
727
+ if (index !== lastIndex) {
728
+ const lastKey = this.keyList[lastIndex];
729
+ this.keyList[index] = lastKey;
730
+ const lastEntry = this.store.get(lastKey);
731
+ if (lastEntry) {
732
+ lastEntry.keyIndex = index;
733
+ }
734
+ }
735
+ this.keyList.pop();
736
+ }
737
+ delete(key) {
738
+ const entry = this.store.get(key);
739
+ if (!entry) return false;
740
+ this.removeKeyAtIndex(entry.keyIndex);
741
+ this.store.delete(key);
742
+ this.emit({ event: "delete", key, value: entry.value, timestamp: this.now() });
743
+ return true;
744
+ }
745
+ has(key) {
746
+ return this.store.has(key);
747
+ }
748
+ clear() {
749
+ this.store.clear();
750
+ this.keyList.length = 0;
751
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
752
+ }
753
+ get size() {
754
+ return this.store.size;
755
+ }
756
+ *keys() {
757
+ for (const key of this.store.keys()) {
758
+ yield key;
759
+ }
760
+ }
761
+ *values() {
762
+ for (const entry of this.store.values()) {
763
+ yield entry.value;
764
+ }
765
+ }
766
+ *entries() {
767
+ for (const [key, entry] of this.store.entries()) {
768
+ yield [key, entry.value];
769
+ }
770
+ }
771
+ get strategy() {
772
+ return "RR";
773
+ }
774
+ collectEntries() {
775
+ const result = [];
776
+ for (const [key, entry] of this.store.entries()) {
777
+ result.push({
778
+ key,
779
+ value: entry.value,
780
+ createdAt: entry.createdAt,
781
+ lastAccessed: entry.lastAccessed,
782
+ accessCount: entry.accessCount
783
+ });
784
+ }
785
+ return result;
786
+ }
787
+ };
788
+
789
+ // src/caches/arc.ts
790
+ var ARCCache = class extends BaseCache {
791
+ /** Adaptation parameter: target size of T1. */
792
+ p = 0;
793
+ /** T1: recent cache entries (seen once recently). */
794
+ t1 = new DoublyLinkedList();
795
+ /** T2: frequent cache entries (seen at least twice recently). */
796
+ t2 = new DoublyLinkedList();
797
+ /** B1: ghost list for recently evicted from T1 (keys only). */
798
+ b1 = new DoublyLinkedList();
799
+ /** B2: ghost list for recently evicted from T2 (keys only). */
800
+ b2 = new DoublyLinkedList();
801
+ t1Map = /* @__PURE__ */ new Map();
802
+ t2Map = /* @__PURE__ */ new Map();
803
+ b1Map = /* @__PURE__ */ new Map();
804
+ b2Map = /* @__PURE__ */ new Map();
805
+ metaMap = /* @__PURE__ */ new Map();
806
+ constructor(options) {
807
+ super(options);
808
+ }
809
+ get strategy() {
810
+ return "ARC";
811
+ }
812
+ get size() {
813
+ return this.t1.size + this.t2.size;
814
+ }
815
+ get(key) {
816
+ const now = this.now();
817
+ if (this.t1Map.has(key)) {
818
+ const node = this.t1Map.get(key);
819
+ this.t1.remove(node);
820
+ this.t1Map.delete(key);
821
+ this.t2.addToFront(node);
822
+ this.t2Map.set(key, node);
823
+ const meta = this.metaMap.get(key);
824
+ meta.lastAccessed = now;
825
+ meta.accessCount++;
826
+ this._hits++;
827
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
828
+ return node.value;
829
+ }
830
+ if (this.t2Map.has(key)) {
831
+ const node = this.t2Map.get(key);
832
+ this.t2.moveToFront(node);
833
+ const meta = this.metaMap.get(key);
834
+ meta.lastAccessed = now;
835
+ meta.accessCount++;
836
+ this._hits++;
837
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
838
+ return node.value;
839
+ }
840
+ this._misses++;
841
+ this.emit({ event: "get", key, value: void 0, timestamp: now });
842
+ return void 0;
843
+ }
844
+ set(key, value, _ttl) {
845
+ const now = this.now();
846
+ const c = this._capacity;
847
+ if (this.t1Map.has(key)) {
848
+ const node2 = this.t1Map.get(key);
849
+ node2.value = value;
850
+ this.t1.remove(node2);
851
+ this.t1Map.delete(key);
852
+ this.t2.addToFront(node2);
853
+ this.t2Map.set(key, node2);
854
+ const meta = this.metaMap.get(key);
855
+ meta.lastAccessed = now;
856
+ meta.accessCount++;
857
+ this.emit({ event: "set", key, value, timestamp: now });
858
+ return;
859
+ }
860
+ if (this.t2Map.has(key)) {
861
+ const node2 = this.t2Map.get(key);
862
+ node2.value = value;
863
+ this.t2.moveToFront(node2);
864
+ const meta = this.metaMap.get(key);
865
+ meta.lastAccessed = now;
866
+ meta.accessCount++;
867
+ this.emit({ event: "set", key, value, timestamp: now });
868
+ return;
869
+ }
870
+ if (this.b1Map.has(key)) {
871
+ const delta = this.b2.size >= this.b1.size ? 1 : Math.ceil(this.b2.size / (this.b1.size || 1));
872
+ this.p = Math.min(this.p + delta, c);
873
+ this.replace(key);
874
+ const ghostNode = this.b1Map.get(key);
875
+ this.b1.remove(ghostNode);
876
+ this.b1Map.delete(key);
877
+ const node2 = createNode(key, value);
878
+ this.t2.addToFront(node2);
879
+ this.t2Map.set(key, node2);
880
+ this.metaMap.set(key, { createdAt: now, lastAccessed: now, accessCount: 1 });
881
+ this.emit({ event: "set", key, value, timestamp: now });
882
+ return;
883
+ }
884
+ if (this.b2Map.has(key)) {
885
+ const delta = this.b1.size >= this.b2.size ? 1 : Math.ceil(this.b1.size / (this.b2.size || 1));
886
+ this.p = Math.max(this.p - delta, 0);
887
+ this.replace(key);
888
+ const ghostNode = this.b2Map.get(key);
889
+ this.b2.remove(ghostNode);
890
+ this.b2Map.delete(key);
891
+ const node2 = createNode(key, value);
892
+ this.t2.addToFront(node2);
893
+ this.t2Map.set(key, node2);
894
+ this.metaMap.set(key, { createdAt: now, lastAccessed: now, accessCount: 1 });
895
+ this.emit({ event: "set", key, value, timestamp: now });
896
+ return;
897
+ }
898
+ const l1 = this.t1.size + this.b1.size;
899
+ const l2 = this.t2.size + this.b2.size;
900
+ if (l1 === c) {
901
+ if (this.t1.size < c) {
902
+ const ghost = this.b1.removeLast();
903
+ if (ghost) {
904
+ this.b1Map.delete(ghost.key);
905
+ }
906
+ this.replace(key);
907
+ } else {
908
+ const evicted = this.t1.removeLast();
909
+ if (evicted) {
910
+ this.t1Map.delete(evicted.key);
911
+ this.metaMap.delete(evicted.key);
912
+ this._evictions++;
913
+ this.onEvict?.(evicted.key, evicted.value);
914
+ this.emit({
915
+ event: "evict",
916
+ key,
917
+ evictedKey: evicted.key,
918
+ evictedValue: evicted.value,
919
+ timestamp: now
920
+ });
921
+ }
922
+ }
923
+ } else if (l1 < c && l1 + l2 >= c) {
924
+ if (l1 + l2 >= 2 * c) {
925
+ const ghost = this.b2.removeLast();
926
+ if (ghost) {
927
+ this.b2Map.delete(ghost.key);
928
+ }
929
+ }
930
+ this.replace(key);
931
+ }
932
+ const node = createNode(key, value);
933
+ this.t1.addToFront(node);
934
+ this.t1Map.set(key, node);
935
+ this.metaMap.set(key, { createdAt: now, lastAccessed: now, accessCount: 1 });
936
+ this.emit({ event: "set", key, value, timestamp: now });
937
+ }
938
+ delete(key) {
939
+ const now = this.now();
940
+ if (this.t1Map.has(key)) {
941
+ const node = this.t1Map.get(key);
942
+ this.t1.remove(node);
943
+ this.t1Map.delete(key);
944
+ this.metaMap.delete(key);
945
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
946
+ return true;
947
+ }
948
+ if (this.t2Map.has(key)) {
949
+ const node = this.t2Map.get(key);
950
+ this.t2.remove(node);
951
+ this.t2Map.delete(key);
952
+ this.metaMap.delete(key);
953
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
954
+ return true;
955
+ }
956
+ return false;
957
+ }
958
+ has(key) {
959
+ return this.t1Map.has(key) || this.t2Map.has(key);
960
+ }
961
+ clear() {
962
+ this.t1.clear();
963
+ this.t2.clear();
964
+ this.b1.clear();
965
+ this.b2.clear();
966
+ this.t1Map.clear();
967
+ this.t2Map.clear();
968
+ this.b1Map.clear();
969
+ this.b2Map.clear();
970
+ this.metaMap.clear();
971
+ this.p = 0;
972
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
973
+ }
974
+ *keys() {
975
+ for (const node of this.t1) {
976
+ yield node.key;
977
+ }
978
+ for (const node of this.t2) {
979
+ yield node.key;
980
+ }
981
+ }
982
+ *values() {
983
+ for (const node of this.t1) {
984
+ yield node.value;
985
+ }
986
+ for (const node of this.t2) {
987
+ yield node.value;
988
+ }
989
+ }
990
+ *entries() {
991
+ for (const node of this.t1) {
992
+ yield [node.key, node.value];
993
+ }
994
+ for (const node of this.t2) {
995
+ yield [node.key, node.value];
996
+ }
997
+ }
998
+ collectEntries() {
999
+ const result = [];
1000
+ for (const node of this.t1) {
1001
+ const meta = this.metaMap.get(node.key);
1002
+ result.push({
1003
+ key: node.key,
1004
+ value: node.value,
1005
+ createdAt: meta?.createdAt ?? 0,
1006
+ lastAccessed: meta?.lastAccessed ?? 0,
1007
+ accessCount: meta?.accessCount ?? 0
1008
+ });
1009
+ }
1010
+ for (const node of this.t2) {
1011
+ const meta = this.metaMap.get(node.key);
1012
+ result.push({
1013
+ key: node.key,
1014
+ value: node.value,
1015
+ createdAt: meta?.createdAt ?? 0,
1016
+ lastAccessed: meta?.lastAccessed ?? 0,
1017
+ accessCount: meta?.accessCount ?? 0
1018
+ });
1019
+ }
1020
+ return result;
1021
+ }
1022
+ /**
1023
+ * Replace: evict an entry from either T1 or T2 to make room.
1024
+ * The evicted entry's key is moved to the corresponding ghost list.
1025
+ */
1026
+ replace(incomingKey) {
1027
+ const now = this.now();
1028
+ if (this.t1.size > 0 && (this.t1.size > this.p || this.t1.size === this.p && this.b2Map.has(incomingKey))) {
1029
+ const evicted = this.t1.removeLast();
1030
+ this.t1Map.delete(evicted.key);
1031
+ this.metaMap.delete(evicted.key);
1032
+ const ghost = createNode(evicted.key, void 0);
1033
+ this.b1.addToFront(ghost);
1034
+ this.b1Map.set(evicted.key, ghost);
1035
+ this.trimGhostList(this.b1, this.b1Map);
1036
+ this._evictions++;
1037
+ this.onEvict?.(evicted.key, evicted.value);
1038
+ this.emit({
1039
+ event: "evict",
1040
+ key: incomingKey,
1041
+ evictedKey: evicted.key,
1042
+ evictedValue: evicted.value,
1043
+ timestamp: now
1044
+ });
1045
+ } else if (this.t2.size > 0) {
1046
+ const evicted = this.t2.removeLast();
1047
+ this.t2Map.delete(evicted.key);
1048
+ this.metaMap.delete(evicted.key);
1049
+ const ghost = createNode(evicted.key, void 0);
1050
+ this.b2.addToFront(ghost);
1051
+ this.b2Map.set(evicted.key, ghost);
1052
+ this.trimGhostList(this.b2, this.b2Map);
1053
+ this._evictions++;
1054
+ this.onEvict?.(evicted.key, evicted.value);
1055
+ this.emit({
1056
+ event: "evict",
1057
+ key: incomingKey,
1058
+ evictedKey: evicted.key,
1059
+ evictedValue: evicted.value,
1060
+ timestamp: now
1061
+ });
1062
+ }
1063
+ }
1064
+ /** Cap a ghost list at capacity to prevent unbounded memory growth. */
1065
+ trimGhostList(list, map) {
1066
+ while (list.size > this._capacity) {
1067
+ const removed = list.removeLast();
1068
+ if (removed) {
1069
+ map.delete(removed.key);
1070
+ }
1071
+ }
1072
+ }
1073
+ };
1074
+
1075
+ // src/caches/two-tier.ts
1076
+ var TwoTierCache = class extends BaseCache {
1077
+ hotList = new DoublyLinkedList();
1078
+ coldList = new DoublyLinkedList();
1079
+ hotMap = /* @__PURE__ */ new Map();
1080
+ coldMap = /* @__PURE__ */ new Map();
1081
+ metaMap = /* @__PURE__ */ new Map();
1082
+ hotCapacity;
1083
+ coldCapacity;
1084
+ promoteThreshold;
1085
+ constructor(options) {
1086
+ super({ capacity: options.hotCapacity + options.coldCapacity, onEvict: options.onEvict });
1087
+ this.hotCapacity = options.hotCapacity;
1088
+ this.coldCapacity = options.coldCapacity;
1089
+ this.promoteThreshold = options.promoteThreshold ?? 2;
1090
+ }
1091
+ get strategy() {
1092
+ return "TWO-TIER";
1093
+ }
1094
+ get size() {
1095
+ return this.hotMap.size + this.coldMap.size;
1096
+ }
1097
+ get(key) {
1098
+ const now = this.now();
1099
+ if (this.hotMap.has(key)) {
1100
+ const node = this.hotMap.get(key);
1101
+ this.hotList.moveToFront(node);
1102
+ const meta = this.metaMap.get(key);
1103
+ meta.lastAccessed = now;
1104
+ meta.accessCount++;
1105
+ this._hits++;
1106
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1107
+ return node.value;
1108
+ }
1109
+ if (this.coldMap.has(key)) {
1110
+ const node = this.coldMap.get(key);
1111
+ const meta = this.metaMap.get(key);
1112
+ meta.lastAccessed = now;
1113
+ meta.accessCount++;
1114
+ if (meta.accessCount >= this.promoteThreshold) {
1115
+ this.coldList.remove(node);
1116
+ this.coldMap.delete(key);
1117
+ this.ensureHotCapacity(now, key);
1118
+ this.hotList.addToFront(node);
1119
+ this.hotMap.set(key, node);
1120
+ meta.tier = "hot";
1121
+ } else {
1122
+ this.coldList.moveToFront(node);
1123
+ }
1124
+ this._hits++;
1125
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1126
+ return node.value;
1127
+ }
1128
+ this._misses++;
1129
+ this.emit({ event: "get", key, value: void 0, timestamp: now });
1130
+ return void 0;
1131
+ }
1132
+ set(key, value, _ttl) {
1133
+ const now = this.now();
1134
+ if (this.hotMap.has(key)) {
1135
+ const node2 = this.hotMap.get(key);
1136
+ node2.value = value;
1137
+ this.hotList.moveToFront(node2);
1138
+ const meta = this.metaMap.get(key);
1139
+ meta.lastAccessed = now;
1140
+ meta.accessCount++;
1141
+ this.emit({ event: "set", key, value, timestamp: now });
1142
+ return;
1143
+ }
1144
+ if (this.coldMap.has(key)) {
1145
+ const node2 = this.coldMap.get(key);
1146
+ node2.value = value;
1147
+ this.coldList.moveToFront(node2);
1148
+ const meta = this.metaMap.get(key);
1149
+ meta.lastAccessed = now;
1150
+ meta.accessCount++;
1151
+ this.emit({ event: "set", key, value, timestamp: now });
1152
+ return;
1153
+ }
1154
+ this.ensureColdCapacity(now, key);
1155
+ const node = createNode(key, value);
1156
+ this.coldList.addToFront(node);
1157
+ this.coldMap.set(key, node);
1158
+ this.metaMap.set(key, {
1159
+ createdAt: now,
1160
+ lastAccessed: now,
1161
+ accessCount: 1,
1162
+ tier: "cold"
1163
+ });
1164
+ this.emit({ event: "set", key, value, timestamp: now });
1165
+ }
1166
+ delete(key) {
1167
+ const now = this.now();
1168
+ if (this.hotMap.has(key)) {
1169
+ const node = this.hotMap.get(key);
1170
+ this.hotList.remove(node);
1171
+ this.hotMap.delete(key);
1172
+ this.metaMap.delete(key);
1173
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
1174
+ return true;
1175
+ }
1176
+ if (this.coldMap.has(key)) {
1177
+ const node = this.coldMap.get(key);
1178
+ this.coldList.remove(node);
1179
+ this.coldMap.delete(key);
1180
+ this.metaMap.delete(key);
1181
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
1182
+ return true;
1183
+ }
1184
+ return false;
1185
+ }
1186
+ has(key) {
1187
+ return this.hotMap.has(key) || this.coldMap.has(key);
1188
+ }
1189
+ clear() {
1190
+ this.hotList.clear();
1191
+ this.coldList.clear();
1192
+ this.hotMap.clear();
1193
+ this.coldMap.clear();
1194
+ this.metaMap.clear();
1195
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1196
+ }
1197
+ *keys() {
1198
+ for (const node of this.hotList) {
1199
+ yield node.key;
1200
+ }
1201
+ for (const node of this.coldList) {
1202
+ yield node.key;
1203
+ }
1204
+ }
1205
+ *values() {
1206
+ for (const node of this.hotList) {
1207
+ yield node.value;
1208
+ }
1209
+ for (const node of this.coldList) {
1210
+ yield node.value;
1211
+ }
1212
+ }
1213
+ *entries() {
1214
+ for (const node of this.hotList) {
1215
+ yield [node.key, node.value];
1216
+ }
1217
+ for (const node of this.coldList) {
1218
+ yield [node.key, node.value];
1219
+ }
1220
+ }
1221
+ collectEntries() {
1222
+ const result = [];
1223
+ for (const node of this.hotList) {
1224
+ const meta = this.metaMap.get(node.key);
1225
+ result.push({
1226
+ key: node.key,
1227
+ value: node.value,
1228
+ createdAt: meta?.createdAt ?? 0,
1229
+ lastAccessed: meta?.lastAccessed ?? 0,
1230
+ accessCount: meta?.accessCount ?? 0,
1231
+ tier: "hot"
1232
+ });
1233
+ }
1234
+ for (const node of this.coldList) {
1235
+ const meta = this.metaMap.get(node.key);
1236
+ result.push({
1237
+ key: node.key,
1238
+ value: node.value,
1239
+ createdAt: meta?.createdAt ?? 0,
1240
+ lastAccessed: meta?.lastAccessed ?? 0,
1241
+ accessCount: meta?.accessCount ?? 0,
1242
+ tier: "cold"
1243
+ });
1244
+ }
1245
+ return result;
1246
+ }
1247
+ /** Evict from hot tier if full, demoting LRU to cold tier. */
1248
+ ensureHotCapacity(now, triggerKey) {
1249
+ if (this.hotList.size >= this.hotCapacity) {
1250
+ const evicted = this.hotList.removeLast();
1251
+ if (evicted) {
1252
+ this.hotMap.delete(evicted.key);
1253
+ this.ensureColdCapacity(now, triggerKey);
1254
+ this.coldList.addToBack(evicted);
1255
+ this.coldMap.set(evicted.key, evicted);
1256
+ const meta = this.metaMap.get(evicted.key);
1257
+ if (meta) meta.tier = "cold";
1258
+ }
1259
+ }
1260
+ }
1261
+ /** Evict LRU from cold tier if full (permanent eviction). */
1262
+ ensureColdCapacity(now, triggerKey) {
1263
+ if (this.coldList.size >= this.coldCapacity) {
1264
+ const evicted = this.coldList.removeLast();
1265
+ if (evicted) {
1266
+ this.coldMap.delete(evicted.key);
1267
+ this.metaMap.delete(evicted.key);
1268
+ this._evictions++;
1269
+ this.onEvict?.(evicted.key, evicted.value);
1270
+ this.emit({
1271
+ event: "evict",
1272
+ key: triggerKey ?? evicted.key,
1273
+ evictedKey: evicted.key,
1274
+ evictedValue: evicted.value,
1275
+ timestamp: now
1276
+ });
1277
+ }
1278
+ }
1279
+ }
1280
+ };
1281
+
1282
+ // src/caches/slru.ts
1283
+ var SLRUCache = class extends BaseCache {
1284
+ probationList = new DoublyLinkedList();
1285
+ protectedList = new DoublyLinkedList();
1286
+ probationMap = /* @__PURE__ */ new Map();
1287
+ protectedMap = /* @__PURE__ */ new Map();
1288
+ metaMap = /* @__PURE__ */ new Map();
1289
+ protectedCapacity;
1290
+ probationCapacity;
1291
+ constructor(options) {
1292
+ super(options);
1293
+ const ratio = options.protectedRatio ?? 0.8;
1294
+ this.protectedCapacity = Math.max(1, Math.floor(options.capacity * ratio));
1295
+ this.probationCapacity = Math.max(1, options.capacity - this.protectedCapacity);
1296
+ }
1297
+ get strategy() {
1298
+ return "SLRU";
1299
+ }
1300
+ get size() {
1301
+ return this.probationMap.size + this.protectedMap.size;
1302
+ }
1303
+ get(key) {
1304
+ const now = this.now();
1305
+ if (this.protectedMap.has(key)) {
1306
+ const node = this.protectedMap.get(key);
1307
+ this.protectedList.moveToFront(node);
1308
+ const meta = this.metaMap.get(key);
1309
+ meta.lastAccessed = now;
1310
+ meta.accessCount++;
1311
+ this._hits++;
1312
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1313
+ return node.value;
1314
+ }
1315
+ if (this.probationMap.has(key)) {
1316
+ const node = this.probationMap.get(key);
1317
+ const meta = this.metaMap.get(key);
1318
+ meta.lastAccessed = now;
1319
+ meta.accessCount++;
1320
+ this.probationList.remove(node);
1321
+ this.probationMap.delete(key);
1322
+ this.ensureProtectedCapacity(now, key);
1323
+ this.protectedList.addToFront(node);
1324
+ this.protectedMap.set(key, node);
1325
+ meta.segment = "protected";
1326
+ this._hits++;
1327
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1328
+ return node.value;
1329
+ }
1330
+ this._misses++;
1331
+ this.emit({ event: "get", key, value: void 0, timestamp: now });
1332
+ return void 0;
1333
+ }
1334
+ set(key, value, _ttl) {
1335
+ const now = this.now();
1336
+ if (this.protectedMap.has(key)) {
1337
+ const node2 = this.protectedMap.get(key);
1338
+ node2.value = value;
1339
+ this.protectedList.moveToFront(node2);
1340
+ const meta = this.metaMap.get(key);
1341
+ meta.lastAccessed = now;
1342
+ meta.accessCount++;
1343
+ this.emit({ event: "set", key, value, timestamp: now });
1344
+ return;
1345
+ }
1346
+ if (this.probationMap.has(key)) {
1347
+ const node2 = this.probationMap.get(key);
1348
+ node2.value = value;
1349
+ this.probationList.moveToFront(node2);
1350
+ const meta = this.metaMap.get(key);
1351
+ meta.lastAccessed = now;
1352
+ meta.accessCount++;
1353
+ this.emit({ event: "set", key, value, timestamp: now });
1354
+ return;
1355
+ }
1356
+ this.ensureProbationCapacity(now, key);
1357
+ const node = createNode(key, value);
1358
+ this.probationList.addToFront(node);
1359
+ this.probationMap.set(key, node);
1360
+ this.metaMap.set(key, {
1361
+ createdAt: now,
1362
+ lastAccessed: now,
1363
+ accessCount: 1,
1364
+ segment: "probation"
1365
+ });
1366
+ this.emit({ event: "set", key, value, timestamp: now });
1367
+ }
1368
+ delete(key) {
1369
+ const now = this.now();
1370
+ if (this.protectedMap.has(key)) {
1371
+ const node = this.protectedMap.get(key);
1372
+ this.protectedList.remove(node);
1373
+ this.protectedMap.delete(key);
1374
+ this.metaMap.delete(key);
1375
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
1376
+ return true;
1377
+ }
1378
+ if (this.probationMap.has(key)) {
1379
+ const node = this.probationMap.get(key);
1380
+ this.probationList.remove(node);
1381
+ this.probationMap.delete(key);
1382
+ this.metaMap.delete(key);
1383
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
1384
+ return true;
1385
+ }
1386
+ return false;
1387
+ }
1388
+ has(key) {
1389
+ return this.protectedMap.has(key) || this.probationMap.has(key);
1390
+ }
1391
+ clear() {
1392
+ this.probationList.clear();
1393
+ this.protectedList.clear();
1394
+ this.probationMap.clear();
1395
+ this.protectedMap.clear();
1396
+ this.metaMap.clear();
1397
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1398
+ }
1399
+ *keys() {
1400
+ for (const node of this.protectedList) {
1401
+ yield node.key;
1402
+ }
1403
+ for (const node of this.probationList) {
1404
+ yield node.key;
1405
+ }
1406
+ }
1407
+ *values() {
1408
+ for (const node of this.protectedList) {
1409
+ yield node.value;
1410
+ }
1411
+ for (const node of this.probationList) {
1412
+ yield node.value;
1413
+ }
1414
+ }
1415
+ *entries() {
1416
+ for (const node of this.protectedList) {
1417
+ yield [node.key, node.value];
1418
+ }
1419
+ for (const node of this.probationList) {
1420
+ yield [node.key, node.value];
1421
+ }
1422
+ }
1423
+ collectEntries() {
1424
+ const result = [];
1425
+ for (const node of this.protectedList) {
1426
+ const meta = this.metaMap.get(node.key);
1427
+ result.push({
1428
+ key: node.key,
1429
+ value: node.value,
1430
+ createdAt: meta?.createdAt ?? 0,
1431
+ lastAccessed: meta?.lastAccessed ?? 0,
1432
+ accessCount: meta?.accessCount ?? 0,
1433
+ metadata: { segment: "protected" }
1434
+ });
1435
+ }
1436
+ for (const node of this.probationList) {
1437
+ const meta = this.metaMap.get(node.key);
1438
+ result.push({
1439
+ key: node.key,
1440
+ value: node.value,
1441
+ createdAt: meta?.createdAt ?? 0,
1442
+ lastAccessed: meta?.lastAccessed ?? 0,
1443
+ accessCount: meta?.accessCount ?? 0,
1444
+ metadata: { segment: "probation" }
1445
+ });
1446
+ }
1447
+ return result;
1448
+ }
1449
+ /** If protected is full, demote LRU from protected to probation. */
1450
+ ensureProtectedCapacity(now, triggerKey) {
1451
+ if (this.protectedList.size >= this.protectedCapacity) {
1452
+ const demoted = this.protectedList.removeLast();
1453
+ if (demoted) {
1454
+ this.protectedMap.delete(demoted.key);
1455
+ this.ensureProbationCapacity(now, triggerKey);
1456
+ this.probationList.addToBack(demoted);
1457
+ this.probationMap.set(demoted.key, demoted);
1458
+ const meta = this.metaMap.get(demoted.key);
1459
+ if (meta) meta.segment = "probation";
1460
+ }
1461
+ }
1462
+ }
1463
+ /** Evict LRU from probation if full. */
1464
+ ensureProbationCapacity(now, triggerKey) {
1465
+ if (this.probationList.size >= this.probationCapacity) {
1466
+ const evicted = this.probationList.removeLast();
1467
+ if (evicted) {
1468
+ this.probationMap.delete(evicted.key);
1469
+ this.metaMap.delete(evicted.key);
1470
+ this._evictions++;
1471
+ this.onEvict?.(evicted.key, evicted.value);
1472
+ this.emit({
1473
+ event: "evict",
1474
+ key: triggerKey ?? evicted.key,
1475
+ evictedKey: evicted.key,
1476
+ evictedValue: evicted.value,
1477
+ timestamp: now
1478
+ });
1479
+ }
1480
+ }
1481
+ }
1482
+ };
1483
+
1484
+ // src/caches/clock.ts
1485
+ var ClockCache = class extends BaseCache {
1486
+ buffer;
1487
+ map = /* @__PURE__ */ new Map();
1488
+ // key -> index in buffer
1489
+ hand = 0;
1490
+ constructor(options) {
1491
+ super(options);
1492
+ this.buffer = Array.from({ length: this._capacity }).fill(null);
1493
+ }
1494
+ get(key) {
1495
+ const idx = this.map.get(key);
1496
+ if (idx === void 0) {
1497
+ this._misses++;
1498
+ this.emit({ event: "get", key, timestamp: this.now() });
1499
+ return void 0;
1500
+ }
1501
+ const entry = this.buffer[idx];
1502
+ entry.refBit = true;
1503
+ entry.lastAccessed = this.now();
1504
+ entry.accessCount++;
1505
+ this._hits++;
1506
+ this.emit({ event: "get", key, value: entry.value, timestamp: this.now() });
1507
+ return entry.value;
1508
+ }
1509
+ set(key, value, _ttl) {
1510
+ const now = this.now();
1511
+ const existingIdx = this.map.get(key);
1512
+ if (existingIdx !== void 0) {
1513
+ const entry = this.buffer[existingIdx];
1514
+ entry.value = value;
1515
+ entry.refBit = true;
1516
+ entry.lastAccessed = now;
1517
+ this.emit({ event: "set", key, value, timestamp: now });
1518
+ return;
1519
+ }
1520
+ if (this.map.size >= this._capacity) {
1521
+ this.evict(key, value, now);
1522
+ }
1523
+ let idx = this.findEmptySlot();
1524
+ if (idx === -1) {
1525
+ idx = this.hand;
1526
+ }
1527
+ this.buffer[idx] = {
1528
+ key,
1529
+ value,
1530
+ refBit: false,
1531
+ createdAt: now,
1532
+ lastAccessed: now,
1533
+ accessCount: 0
1534
+ };
1535
+ this.map.set(key, idx);
1536
+ this.emit({ event: "set", key, value, timestamp: now });
1537
+ }
1538
+ findEmptySlot() {
1539
+ for (let i = 0; i < this._capacity; i++) {
1540
+ if (this.buffer[i] === null) return i;
1541
+ }
1542
+ return -1;
1543
+ }
1544
+ evict(newKey, newValue, now) {
1545
+ while (true) {
1546
+ const entry = this.buffer[this.hand];
1547
+ if (entry) {
1548
+ if (entry.refBit) {
1549
+ entry.refBit = false;
1550
+ this.hand = (this.hand + 1) % this._capacity;
1551
+ } else {
1552
+ this.map.delete(entry.key);
1553
+ this._evictions++;
1554
+ this.onEvict?.(entry.key, entry.value);
1555
+ this.emit({
1556
+ event: "evict",
1557
+ key: newKey,
1558
+ value: newValue,
1559
+ evictedKey: entry.key,
1560
+ evictedValue: entry.value,
1561
+ timestamp: now
1562
+ });
1563
+ this.buffer[this.hand] = null;
1564
+ this.hand = (this.hand + 1) % this._capacity;
1565
+ return;
1566
+ }
1567
+ } else {
1568
+ this.hand = (this.hand + 1) % this._capacity;
1569
+ return;
1570
+ }
1571
+ }
1572
+ }
1573
+ delete(key) {
1574
+ const idx = this.map.get(key);
1575
+ if (idx === void 0) return false;
1576
+ const entry = this.buffer[idx];
1577
+ this.buffer[idx] = null;
1578
+ this.map.delete(key);
1579
+ this.emit({ event: "delete", key, value: entry.value, timestamp: this.now() });
1580
+ return true;
1581
+ }
1582
+ has(key) {
1583
+ return this.map.has(key);
1584
+ }
1585
+ clear() {
1586
+ this.buffer.fill(null);
1587
+ this.map.clear();
1588
+ this.hand = 0;
1589
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1590
+ }
1591
+ get size() {
1592
+ return this.map.size;
1593
+ }
1594
+ *keys() {
1595
+ for (const entry of this.buffer) {
1596
+ if (entry) yield entry.key;
1597
+ }
1598
+ }
1599
+ *values() {
1600
+ for (const entry of this.buffer) {
1601
+ if (entry) yield entry.value;
1602
+ }
1603
+ }
1604
+ *entries() {
1605
+ for (const entry of this.buffer) {
1606
+ if (entry) yield [entry.key, entry.value];
1607
+ }
1608
+ }
1609
+ get strategy() {
1610
+ return "CLOCK";
1611
+ }
1612
+ collectEntries() {
1613
+ const result = [];
1614
+ for (const entry of this.buffer) {
1615
+ if (entry) {
1616
+ result.push({
1617
+ key: entry.key,
1618
+ value: entry.value,
1619
+ createdAt: entry.createdAt,
1620
+ lastAccessed: entry.lastAccessed,
1621
+ accessCount: entry.accessCount
1622
+ });
1623
+ }
1624
+ }
1625
+ return result;
1626
+ }
1627
+ };
1628
+
1629
+ // src/structures/count-min-sketch.ts
1630
+ var CountMinSketch = class {
1631
+ table;
1632
+ width;
1633
+ depth;
1634
+ seeds;
1635
+ _totalCount = 0;
1636
+ maxCount;
1637
+ constructor(width = 1024, depth = 4) {
1638
+ this.width = width;
1639
+ this.depth = depth;
1640
+ this.maxCount = width * 10;
1641
+ this.table = Array.from({ length: depth }, () => new Uint32Array(width));
1642
+ this.seeds = Array.from({ length: depth }, (_, i) => i * 2654435769 + 1779033703);
1643
+ }
1644
+ hash(key, seed) {
1645
+ let h = seed;
1646
+ for (let i = 0; i < key.length; i++) {
1647
+ h = Math.imul(h ^ key.charCodeAt(i), 1540483477);
1648
+ h ^= h >>> 13;
1649
+ h = Math.imul(h, 1540483477);
1650
+ h ^= h >>> 15;
1651
+ }
1652
+ return (h >>> 0) % this.width;
1653
+ }
1654
+ increment(key) {
1655
+ for (let i = 0; i < this.depth; i++) {
1656
+ const idx = this.hash(key, this.seeds[i]);
1657
+ this.table[i][idx]++;
1658
+ }
1659
+ this._totalCount++;
1660
+ if (this._totalCount >= this.maxCount) {
1661
+ this.halve();
1662
+ }
1663
+ }
1664
+ estimate(key) {
1665
+ let min = Infinity;
1666
+ for (let i = 0; i < this.depth; i++) {
1667
+ const idx = this.hash(key, this.seeds[i]);
1668
+ min = Math.min(min, this.table[i][idx]);
1669
+ }
1670
+ return min;
1671
+ }
1672
+ halve() {
1673
+ for (let i = 0; i < this.depth; i++) {
1674
+ for (let j = 0; j < this.width; j++) {
1675
+ this.table[i][j] = this.table[i][j] >>> 1;
1676
+ }
1677
+ }
1678
+ this._totalCount = Math.floor(this._totalCount / 2);
1679
+ }
1680
+ reset() {
1681
+ for (let i = 0; i < this.depth; i++) {
1682
+ this.table[i].fill(0);
1683
+ }
1684
+ this._totalCount = 0;
1685
+ }
1686
+ get totalCount() {
1687
+ return this._totalCount;
1688
+ }
1689
+ };
1690
+
1691
+ // src/caches/w-tiny-lfu.ts
1692
+ var WTinyLFUCache = class extends BaseCache {
1693
+ sketch;
1694
+ // Window LRU
1695
+ windowList = new DoublyLinkedList();
1696
+ windowMap = /* @__PURE__ */ new Map();
1697
+ windowCapacity;
1698
+ // Main cache: probation (cold) + protected (hot) segments
1699
+ probationList = new DoublyLinkedList();
1700
+ probationMap = /* @__PURE__ */ new Map();
1701
+ protectedList = new DoublyLinkedList();
1702
+ protectedMap = /* @__PURE__ */ new Map();
1703
+ protectedCapacity;
1704
+ mainCapacity;
1705
+ constructor(options) {
1706
+ super(options);
1707
+ const windowRatio = options.windowRatio ?? 0.01;
1708
+ this.windowCapacity = Math.max(1, Math.floor(this._capacity * windowRatio));
1709
+ this.mainCapacity = this._capacity - this.windowCapacity;
1710
+ this.protectedCapacity = Math.max(1, Math.floor(this.mainCapacity * 0.8));
1711
+ this.sketch = new CountMinSketch(Math.max(256, this._capacity * 10), 4);
1712
+ }
1713
+ get(key) {
1714
+ const now = this.now();
1715
+ let node = this.windowMap.get(key);
1716
+ if (node) {
1717
+ node.lastAccessed = now;
1718
+ node.accessCount = (node.accessCount ?? 0) + 1;
1719
+ this.windowList.moveToFront(node);
1720
+ this.sketch.increment(key);
1721
+ this._hits++;
1722
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1723
+ return node.value;
1724
+ }
1725
+ node = this.probationMap.get(key);
1726
+ if (node) {
1727
+ node.lastAccessed = now;
1728
+ node.accessCount = (node.accessCount ?? 0) + 1;
1729
+ this.sketch.increment(key);
1730
+ this.probationList.remove(node);
1731
+ this.probationMap.delete(key);
1732
+ this.ensureProtectedCapacity(key, node.value, now);
1733
+ this.protectedList.addToFront(node);
1734
+ this.protectedMap.set(key, node);
1735
+ this._hits++;
1736
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1737
+ return node.value;
1738
+ }
1739
+ node = this.protectedMap.get(key);
1740
+ if (node) {
1741
+ node.lastAccessed = now;
1742
+ node.accessCount = (node.accessCount ?? 0) + 1;
1743
+ this.protectedList.moveToFront(node);
1744
+ this.sketch.increment(key);
1745
+ this._hits++;
1746
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1747
+ return node.value;
1748
+ }
1749
+ this._misses++;
1750
+ this.emit({ event: "get", key, timestamp: now });
1751
+ return void 0;
1752
+ }
1753
+ set(key, value, _ttl) {
1754
+ const now = this.now();
1755
+ let node = this.windowMap.get(key);
1756
+ if (node) {
1757
+ node.value = value;
1758
+ node.lastAccessed = now;
1759
+ this.windowList.moveToFront(node);
1760
+ this.sketch.increment(key);
1761
+ this.emit({ event: "set", key, value, timestamp: now });
1762
+ return;
1763
+ }
1764
+ node = this.probationMap.get(key);
1765
+ if (node) {
1766
+ node.value = value;
1767
+ node.lastAccessed = now;
1768
+ this.sketch.increment(key);
1769
+ this.emit({ event: "set", key, value, timestamp: now });
1770
+ return;
1771
+ }
1772
+ node = this.protectedMap.get(key);
1773
+ if (node) {
1774
+ node.value = value;
1775
+ node.lastAccessed = now;
1776
+ this.protectedList.moveToFront(node);
1777
+ this.sketch.increment(key);
1778
+ this.emit({ event: "set", key, value, timestamp: now });
1779
+ return;
1780
+ }
1781
+ this.sketch.increment(key);
1782
+ if (this.windowMap.size >= this.windowCapacity) {
1783
+ this.evictFromWindow(key, value, now);
1784
+ }
1785
+ const newNode = createNode(key, value);
1786
+ newNode.metadata = { createdAt: now };
1787
+ newNode.lastAccessed = now;
1788
+ newNode.accessCount = 0;
1789
+ this.windowList.addToFront(newNode);
1790
+ this.windowMap.set(key, newNode);
1791
+ this.emit({ event: "set", key, value, timestamp: now });
1792
+ }
1793
+ evictFromWindow(newKey, newValue, now) {
1794
+ const windowVictim = this.windowList.removeLast();
1795
+ if (!windowVictim) return;
1796
+ this.windowMap.delete(windowVictim.key);
1797
+ const mainSize = this.probationMap.size + this.protectedMap.size;
1798
+ if (mainSize < this.mainCapacity) {
1799
+ this.probationList.addToFront(windowVictim);
1800
+ this.probationMap.set(windowVictim.key, windowVictim);
1801
+ return;
1802
+ }
1803
+ const mainVictim = this.probationList.peekLast();
1804
+ if (!mainVictim) {
1805
+ this._evictions++;
1806
+ this.onEvict?.(windowVictim.key, windowVictim.value);
1807
+ this.emit({
1808
+ event: "evict",
1809
+ key: newKey,
1810
+ value: newValue,
1811
+ evictedKey: windowVictim.key,
1812
+ evictedValue: windowVictim.value,
1813
+ timestamp: now
1814
+ });
1815
+ return;
1816
+ }
1817
+ const candidateFreq = this.sketch.estimate(windowVictim.key);
1818
+ const victimFreq = this.sketch.estimate(mainVictim.key);
1819
+ if (candidateFreq > victimFreq) {
1820
+ this.probationList.removeLast();
1821
+ this.probationMap.delete(mainVictim.key);
1822
+ this._evictions++;
1823
+ this.onEvict?.(mainVictim.key, mainVictim.value);
1824
+ this.emit({
1825
+ event: "evict",
1826
+ key: newKey,
1827
+ value: newValue,
1828
+ evictedKey: mainVictim.key,
1829
+ evictedValue: mainVictim.value,
1830
+ timestamp: now
1831
+ });
1832
+ this.probationList.addToFront(windowVictim);
1833
+ this.probationMap.set(windowVictim.key, windowVictim);
1834
+ } else {
1835
+ this._evictions++;
1836
+ this.onEvict?.(windowVictim.key, windowVictim.value);
1837
+ this.emit({
1838
+ event: "evict",
1839
+ key: newKey,
1840
+ value: newValue,
1841
+ evictedKey: windowVictim.key,
1842
+ evictedValue: windowVictim.value,
1843
+ timestamp: now
1844
+ });
1845
+ }
1846
+ }
1847
+ ensureProtectedCapacity(newKey, newValue, now) {
1848
+ if (this.protectedMap.size >= this.protectedCapacity) {
1849
+ const demoted = this.protectedList.removeLast();
1850
+ if (demoted) {
1851
+ this.protectedMap.delete(demoted.key);
1852
+ this.probationList.addToFront(demoted);
1853
+ this.probationMap.set(demoted.key, demoted);
1854
+ }
1855
+ }
1856
+ const mainSize = this.probationMap.size + this.protectedMap.size;
1857
+ if (mainSize >= this.mainCapacity) {
1858
+ const victim = this.probationList.removeLast();
1859
+ if (victim) {
1860
+ this.probationMap.delete(victim.key);
1861
+ this._evictions++;
1862
+ this.onEvict?.(victim.key, victim.value);
1863
+ this.emit({
1864
+ event: "evict",
1865
+ key: newKey,
1866
+ value: newValue,
1867
+ evictedKey: victim.key,
1868
+ evictedValue: victim.value,
1869
+ timestamp: now
1870
+ });
1871
+ }
1872
+ }
1873
+ }
1874
+ delete(key) {
1875
+ let node = this.windowMap.get(key);
1876
+ if (node) {
1877
+ this.windowList.remove(node);
1878
+ this.windowMap.delete(key);
1879
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
1880
+ return true;
1881
+ }
1882
+ node = this.probationMap.get(key);
1883
+ if (node) {
1884
+ this.probationList.remove(node);
1885
+ this.probationMap.delete(key);
1886
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
1887
+ return true;
1888
+ }
1889
+ node = this.protectedMap.get(key);
1890
+ if (node) {
1891
+ this.protectedList.remove(node);
1892
+ this.protectedMap.delete(key);
1893
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
1894
+ return true;
1895
+ }
1896
+ return false;
1897
+ }
1898
+ has(key) {
1899
+ return this.windowMap.has(key) || this.probationMap.has(key) || this.protectedMap.has(key);
1900
+ }
1901
+ clear() {
1902
+ this.windowList.clear();
1903
+ this.windowMap.clear();
1904
+ this.probationList.clear();
1905
+ this.probationMap.clear();
1906
+ this.protectedList.clear();
1907
+ this.protectedMap.clear();
1908
+ this.sketch.reset();
1909
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1910
+ }
1911
+ get size() {
1912
+ return this.windowMap.size + this.probationMap.size + this.protectedMap.size;
1913
+ }
1914
+ *keys() {
1915
+ for (const node of this.windowList) yield node.key;
1916
+ for (const node of this.protectedList) yield node.key;
1917
+ for (const node of this.probationList) yield node.key;
1918
+ }
1919
+ *values() {
1920
+ for (const node of this.windowList) yield node.value;
1921
+ for (const node of this.protectedList) yield node.value;
1922
+ for (const node of this.probationList) yield node.value;
1923
+ }
1924
+ *entries() {
1925
+ for (const node of this.windowList) yield [node.key, node.value];
1926
+ for (const node of this.protectedList) yield [node.key, node.value];
1927
+ for (const node of this.probationList) yield [node.key, node.value];
1928
+ }
1929
+ get strategy() {
1930
+ return "W-TINYLFU";
1931
+ }
1932
+ collectEntries() {
1933
+ const result = [];
1934
+ const collect = (list, tier) => {
1935
+ for (const node of list) {
1936
+ result.push({
1937
+ key: node.key,
1938
+ value: node.value,
1939
+ createdAt: node.metadata?.createdAt ?? 0,
1940
+ lastAccessed: node.lastAccessed ?? 0,
1941
+ accessCount: node.accessCount ?? 0,
1942
+ tier
1943
+ });
1944
+ }
1945
+ };
1946
+ collect(this.windowList, "cold");
1947
+ collect(this.protectedList, "hot");
1948
+ collect(this.probationList, "cold");
1949
+ return result;
1950
+ }
1951
+ };
1952
+
1953
+ // src/caches/lru-k.ts
1954
+ var LRUKCache = class extends BaseCache {
1955
+ store = /* @__PURE__ */ new Map();
1956
+ k;
1957
+ /** Keys with < K accesses, in insertion order for FIFO eviction. */
1958
+ correlatedKeys = /* @__PURE__ */ new Set();
1959
+ constructor(options) {
1960
+ super(options);
1961
+ this.k = options.k ?? 2;
1962
+ }
1963
+ get(key) {
1964
+ const entry = this.store.get(key);
1965
+ if (!entry) {
1966
+ this._misses++;
1967
+ this.emit({ event: "get", key, timestamp: this.now() });
1968
+ return void 0;
1969
+ }
1970
+ const now = this.now();
1971
+ const hadFullHistory = entry.history.length >= this.k;
1972
+ entry.lastAccessed = now;
1973
+ entry.accessCount++;
1974
+ entry.history.push(now);
1975
+ if (entry.history.length > this.k) {
1976
+ entry.history.shift();
1977
+ }
1978
+ if (!hadFullHistory && entry.history.length >= this.k) {
1979
+ this.correlatedKeys.delete(key);
1980
+ }
1981
+ this._hits++;
1982
+ this.emit({ event: "get", key, value: entry.value, timestamp: now });
1983
+ return entry.value;
1984
+ }
1985
+ set(key, value, _ttl) {
1986
+ const now = this.now();
1987
+ const existing = this.store.get(key);
1988
+ if (existing) {
1989
+ existing.value = value;
1990
+ existing.lastAccessed = now;
1991
+ this.emit({ event: "set", key, value, timestamp: now });
1992
+ return;
1993
+ }
1994
+ if (this.store.size >= this._capacity) {
1995
+ this.evict(key, value, now);
1996
+ }
1997
+ this.store.set(key, {
1998
+ key,
1999
+ value,
2000
+ createdAt: now,
2001
+ lastAccessed: now,
2002
+ accessCount: 0,
2003
+ history: [now]
2004
+ });
2005
+ if (this.k > 1) {
2006
+ this.correlatedKeys.add(key);
2007
+ }
2008
+ this.emit({ event: "set", key, value, timestamp: now });
2009
+ }
2010
+ evict(newKey, newValue, now) {
2011
+ let victimKey;
2012
+ if (this.correlatedKeys.size > 0) {
2013
+ let oldestTime = Infinity;
2014
+ for (const key of this.correlatedKeys) {
2015
+ const entry = this.store.get(key);
2016
+ const firstAccess = entry.history[0];
2017
+ if (firstAccess < oldestTime) {
2018
+ oldestTime = firstAccess;
2019
+ victimKey = key;
2020
+ }
2021
+ }
2022
+ if (victimKey !== void 0) {
2023
+ this.correlatedKeys.delete(victimKey);
2024
+ }
2025
+ } else {
2026
+ let oldestKth = Infinity;
2027
+ for (const [key, entry] of this.store) {
2028
+ if (this.correlatedKeys.has(key)) continue;
2029
+ const kthAccess = entry.history[0];
2030
+ if (kthAccess < oldestKth) {
2031
+ oldestKth = kthAccess;
2032
+ victimKey = key;
2033
+ }
2034
+ }
2035
+ }
2036
+ if (victimKey !== void 0) {
2037
+ const victim = this.store.get(victimKey);
2038
+ this.store.delete(victimKey);
2039
+ this._evictions++;
2040
+ this.onEvict?.(victimKey, victim.value);
2041
+ this.emit({
2042
+ event: "evict",
2043
+ key: newKey,
2044
+ value: newValue,
2045
+ evictedKey: victimKey,
2046
+ evictedValue: victim.value,
2047
+ timestamp: now
2048
+ });
2049
+ }
2050
+ }
2051
+ delete(key) {
2052
+ const entry = this.store.get(key);
2053
+ if (!entry) return false;
2054
+ this.store.delete(key);
2055
+ this.correlatedKeys.delete(key);
2056
+ this.emit({ event: "delete", key, value: entry.value, timestamp: this.now() });
2057
+ return true;
2058
+ }
2059
+ has(key) {
2060
+ return this.store.has(key);
2061
+ }
2062
+ clear() {
2063
+ this.store.clear();
2064
+ this.correlatedKeys.clear();
2065
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
2066
+ }
2067
+ get size() {
2068
+ return this.store.size;
2069
+ }
2070
+ *keys() {
2071
+ for (const key of this.store.keys()) {
2072
+ yield key;
2073
+ }
2074
+ }
2075
+ *values() {
2076
+ for (const entry of this.store.values()) {
2077
+ yield entry.value;
2078
+ }
2079
+ }
2080
+ *entries() {
2081
+ for (const entry of this.store.values()) {
2082
+ yield [entry.key, entry.value];
2083
+ }
2084
+ }
2085
+ get strategy() {
2086
+ return "LRU-K";
2087
+ }
2088
+ collectEntries() {
2089
+ const result = [];
2090
+ for (const entry of this.store.values()) {
2091
+ result.push({
2092
+ key: entry.key,
2093
+ value: entry.value,
2094
+ createdAt: entry.createdAt,
2095
+ lastAccessed: entry.lastAccessed,
2096
+ accessCount: entry.accessCount
2097
+ });
2098
+ }
2099
+ return result;
2100
+ }
2101
+ };
2102
+
2103
+ // src/caches/sieve.ts
2104
+ var SieveCache = class extends BaseCache {
2105
+ head = null;
2106
+ tail = null;
2107
+ hand = null;
2108
+ map = /* @__PURE__ */ new Map();
2109
+ constructor(options) {
2110
+ super(options);
2111
+ }
2112
+ get(key) {
2113
+ const node = this.map.get(key);
2114
+ if (!node) {
2115
+ this._misses++;
2116
+ this.emit({ event: "get", key, timestamp: this.now() });
2117
+ return void 0;
2118
+ }
2119
+ node.visited = true;
2120
+ node.lastAccessed = this.now();
2121
+ node.accessCount++;
2122
+ this._hits++;
2123
+ this.emit({ event: "get", key, value: node.value, timestamp: this.now() });
2124
+ return node.value;
2125
+ }
2126
+ set(key, value, _ttl) {
2127
+ const now = this.now();
2128
+ const existing = this.map.get(key);
2129
+ if (existing) {
2130
+ existing.value = value;
2131
+ existing.visited = true;
2132
+ existing.lastAccessed = now;
2133
+ this.emit({ event: "set", key, value, timestamp: now });
2134
+ return;
2135
+ }
2136
+ if (this.map.size >= this._capacity) {
2137
+ this.evict(key, value, now);
2138
+ }
2139
+ const node = {
2140
+ key,
2141
+ value,
2142
+ visited: false,
2143
+ createdAt: now,
2144
+ lastAccessed: now,
2145
+ accessCount: 0,
2146
+ prev: null,
2147
+ next: null
2148
+ };
2149
+ if (this.head) {
2150
+ node.next = this.head;
2151
+ this.head.prev = node;
2152
+ this.head = node;
2153
+ } else {
2154
+ this.head = node;
2155
+ this.tail = node;
2156
+ }
2157
+ this.map.set(key, node);
2158
+ this.emit({ event: "set", key, value, timestamp: now });
2159
+ }
2160
+ evict(newKey, newValue, now) {
2161
+ let candidate = this.hand ?? this.tail;
2162
+ if (!candidate) return;
2163
+ while (candidate.visited) {
2164
+ candidate.visited = false;
2165
+ candidate = candidate.next ?? this.head;
2166
+ }
2167
+ this.hand = candidate.next ?? this.head;
2168
+ if (this.hand === candidate) {
2169
+ this.hand = null;
2170
+ }
2171
+ this.removeNode(candidate);
2172
+ this.map.delete(candidate.key);
2173
+ this._evictions++;
2174
+ this.onEvict?.(candidate.key, candidate.value);
2175
+ this.emit({
2176
+ event: "evict",
2177
+ key: newKey,
2178
+ value: newValue,
2179
+ evictedKey: candidate.key,
2180
+ evictedValue: candidate.value,
2181
+ timestamp: now
2182
+ });
2183
+ }
2184
+ delete(key) {
2185
+ const node = this.map.get(key);
2186
+ if (!node) return false;
2187
+ if (this.hand === node) {
2188
+ this.hand = node.next ?? this.head;
2189
+ if (this.hand === node) {
2190
+ this.hand = null;
2191
+ }
2192
+ }
2193
+ this.removeNode(node);
2194
+ this.map.delete(key);
2195
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
2196
+ return true;
2197
+ }
2198
+ has(key) {
2199
+ return this.map.has(key);
2200
+ }
2201
+ clear() {
2202
+ this.head = null;
2203
+ this.tail = null;
2204
+ this.hand = null;
2205
+ this.map.clear();
2206
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
2207
+ }
2208
+ get size() {
2209
+ return this.map.size;
2210
+ }
2211
+ *keys() {
2212
+ let current = this.head;
2213
+ while (current) {
2214
+ yield current.key;
2215
+ current = current.next;
2216
+ }
2217
+ }
2218
+ *values() {
2219
+ let current = this.head;
2220
+ while (current) {
2221
+ yield current.value;
2222
+ current = current.next;
2223
+ }
2224
+ }
2225
+ *entries() {
2226
+ let current = this.head;
2227
+ while (current) {
2228
+ yield [current.key, current.value];
2229
+ current = current.next;
2230
+ }
2231
+ }
2232
+ get strategy() {
2233
+ return "SIEVE";
2234
+ }
2235
+ collectEntries() {
2236
+ const result = [];
2237
+ let current = this.head;
2238
+ while (current) {
2239
+ result.push({
2240
+ key: current.key,
2241
+ value: current.value,
2242
+ createdAt: current.createdAt,
2243
+ lastAccessed: current.lastAccessed,
2244
+ accessCount: current.accessCount
2245
+ });
2246
+ current = current.next;
2247
+ }
2248
+ return result;
2249
+ }
2250
+ removeNode(node) {
2251
+ if (node.prev) {
2252
+ node.prev.next = node.next;
2253
+ } else {
2254
+ this.head = node.next;
2255
+ }
2256
+ if (node.next) {
2257
+ node.next.prev = node.prev;
2258
+ } else {
2259
+ this.tail = node.prev;
2260
+ }
2261
+ node.prev = null;
2262
+ node.next = null;
2263
+ }
2264
+ };
2265
+ export {
2266
+ ARCCache,
2267
+ BaseCache,
2268
+ ClockCache,
2269
+ FIFOCache,
2270
+ LFUCache,
2271
+ LIFOCache,
2272
+ LRUCache,
2273
+ LRUKCache,
2274
+ MRUCache,
2275
+ RRCache,
2276
+ SLRUCache,
2277
+ SieveCache,
2278
+ TTLCache,
2279
+ TwoTierCache,
2280
+ WTinyLFUCache
2281
+ };