@fjell/cache 4.7.0 → 4.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CACHE_EVENTS.md +306 -0
  2. package/CACHE_IMPLEMENTATIONS.md +117 -0
  3. package/MEMORY_LEAK_FIXES.md +270 -0
  4. package/README.md +7 -0
  5. package/dist/Aggregator.d.ts +27 -16
  6. package/dist/Cache.d.ts +55 -0
  7. package/dist/CacheContext.d.ts +13 -5
  8. package/dist/CacheMap.d.ts +59 -16
  9. package/dist/CacheStats.d.ts +51 -0
  10. package/dist/Operations.d.ts +20 -17
  11. package/dist/Options.d.ts +1 -3
  12. package/dist/browser/AsyncIndexDBCacheMap.d.ts +1 -1
  13. package/dist/browser/IndexDBCacheMap.d.ts +26 -11
  14. package/dist/browser/LocalStorageCacheMap.d.ts +30 -14
  15. package/dist/browser/SessionStorageCacheMap.d.ts +27 -11
  16. package/dist/events/CacheEventEmitter.d.ts +82 -0
  17. package/dist/events/CacheEventFactory.d.ts +121 -0
  18. package/dist/events/CacheEventTypes.d.ts +122 -0
  19. package/dist/events/index.d.ts +3 -0
  20. package/dist/eviction/EvictionManager.d.ts +57 -0
  21. package/dist/eviction/EvictionStrategy.d.ts +102 -10
  22. package/dist/eviction/index.d.ts +2 -1
  23. package/dist/eviction/strategies/ARCEvictionStrategy.d.ts +10 -5
  24. package/dist/eviction/strategies/FIFOEvictionStrategy.d.ts +6 -5
  25. package/dist/eviction/strategies/LFUEvictionStrategy.d.ts +6 -5
  26. package/dist/eviction/strategies/LRUEvictionStrategy.d.ts +6 -5
  27. package/dist/eviction/strategies/MRUEvictionStrategy.d.ts +6 -5
  28. package/dist/eviction/strategies/RandomEvictionStrategy.d.ts +6 -5
  29. package/dist/eviction/strategies/TwoQueueEvictionStrategy.d.ts +6 -5
  30. package/dist/index.d.ts +9 -3
  31. package/dist/index.js +4739 -2843
  32. package/dist/index.js.map +4 -4
  33. package/dist/memory/EnhancedMemoryCacheMap.d.ts +28 -22
  34. package/dist/memory/MemoryCacheMap.d.ts +26 -11
  35. package/dist/normalization.d.ts +1 -2
  36. package/dist/ops/get.d.ts +1 -0
  37. package/dist/ttl/TTLManager.d.ts +100 -0
  38. package/dist/ttl/index.d.ts +2 -0
  39. package/dist/utils/CacheSize.d.ts +0 -7
  40. package/fix-async-tests.js +116 -0
  41. package/package.json +16 -13
  42. package/debug_test2.js +0 -0
  43. package/debug_test3.js +0 -0
@@ -1,43 +1,59 @@
1
1
  import { AllItemTypeArrays, ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
2
  import { CacheMap } from "../CacheMap";
3
+ import { CacheItemMetadata } from "../eviction/EvictionStrategy";
3
4
  /**
4
5
  * LocalStorage implementation of CacheMap for browser environments.
5
6
  * Data persists across browser sessions and page reloads.
6
7
  *
7
8
  * Note: LocalStorage has a ~5-10MB limit and stores strings only.
8
9
  * Data is synchronous and survives browser restarts.
10
+ * Will throw errors if storage quota is exceeded, though it attempts
11
+ * to clean up old entries first.
9
12
  */
10
13
  export declare class LocalStorageCacheMap<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> extends CacheMap<V, S, L1, L2, L3, L4, L5> {
14
+ readonly implementationType = "browser/localStorage";
11
15
  private keyPrefix;
12
16
  private normalizedHashFunction;
13
- private fallbackCache;
14
- private quotaExceeded;
17
+ private readonly MAX_RETRY_ATTEMPTS;
18
+ private readonly AGGRESSIVE_CLEANUP_PERCENTAGE;
15
19
  constructor(types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>, keyPrefix?: string);
16
20
  private getStorageKey;
17
- private initializeFallbackCache;
18
21
  private isQuotaExceededError;
22
+ private getAllKeysStartingWith;
19
23
  private tryCleanupOldEntries;
20
24
  private collectCacheEntries;
21
25
  private removeOldestEntries;
22
26
  private getAllStorageKeys;
23
- get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): V | null;
24
- getWithTTL(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, ttl: number): V | null;
27
+ get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
25
28
  set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V): void;
26
- includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): boolean;
29
+ includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<boolean>;
27
30
  delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): void;
28
- allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): V[];
29
- contains(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): boolean;
30
- queryIn(query: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): V[];
31
- clone(): LocalStorageCacheMap<V, S, L1, L2, L3, L4, L5>;
31
+ allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
32
+ contains(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<boolean>;
33
+ queryIn(query: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
34
+ clone(): Promise<LocalStorageCacheMap<V, S, L1, L2, L3, L4, L5>>;
32
35
  private parseStorageEntry;
33
36
  keys(): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
34
- values(): V[];
37
+ values(): Promise<V[]>;
35
38
  clear(): void;
36
- setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[], ttl?: number): void;
37
- getQueryResult(queryHash: string): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null;
39
+ setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void;
40
+ getQueryResult(queryHash: string): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null>;
38
41
  hasQueryResult(queryHash: string): boolean;
39
42
  deleteQueryResult(queryHash: string): void;
40
43
  invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void;
41
- invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): void;
44
+ invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<void>;
42
45
  clearQueryResults(): void;
46
+ getMetadata(key: string): CacheItemMetadata | null;
47
+ setMetadata(key: string, metadata: CacheItemMetadata): void;
48
+ deleteMetadata(key: string): void;
49
+ getAllMetadata(): Map<string, CacheItemMetadata>;
50
+ clearMetadata(): void;
51
+ getCurrentSize(): {
52
+ itemCount: number;
53
+ sizeBytes: number;
54
+ };
55
+ getSizeLimits(): {
56
+ maxItems: number | null;
57
+ maxSizeBytes: number | null;
58
+ };
43
59
  }
@@ -1,5 +1,6 @@
1
1
  import { AllItemTypeArrays, ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
2
  import { CacheMap } from "../CacheMap";
3
+ import { CacheItemMetadata } from "../eviction/EvictionStrategy";
3
4
  /**
4
5
  * SessionStorage implementation of CacheMap for browser environments.
5
6
  * Data persists only for the current browser tab/session.
@@ -8,28 +9,43 @@ import { CacheMap } from "../CacheMap";
8
9
  * Data is synchronous but is lost when the tab is closed.
9
10
  */
10
11
  export declare class SessionStorageCacheMap<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> extends CacheMap<V, S, L1, L2, L3, L4, L5> {
12
+ readonly implementationType = "browser/sessionStorage";
11
13
  private keyPrefix;
12
14
  private normalizedHashFunction;
15
+ private readonly verificationHashFunction;
13
16
  constructor(types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>, keyPrefix?: string);
14
17
  private getStorageKey;
15
18
  private getAllStorageKeys;
16
- get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): V | null;
17
- getWithTTL(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, ttl: number): V | null;
19
+ private hasCollisionForHash;
20
+ get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
18
21
  set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V): void;
19
- includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): boolean;
22
+ includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<boolean>;
20
23
  delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): void;
21
- allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): V[];
22
- contains(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): boolean;
23
- queryIn(query: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): V[];
24
- clone(): SessionStorageCacheMap<V, S, L1, L2, L3, L4, L5>;
24
+ allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
25
+ contains(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<boolean>;
26
+ queryIn(query: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
27
+ clone(): Promise<SessionStorageCacheMap<V, S, L1, L2, L3, L4, L5>>;
25
28
  keys(): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
26
- values(): V[];
29
+ values(): Promise<V[]>;
27
30
  clear(): void;
28
- setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[], ttl?: number): void;
29
- getQueryResult(queryHash: string): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null;
31
+ setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void;
32
+ getQueryResult(queryHash: string): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null>;
30
33
  hasQueryResult(queryHash: string): boolean;
31
34
  deleteQueryResult(queryHash: string): void;
32
35
  invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void;
33
- invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): void;
36
+ invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<void>;
34
37
  clearQueryResults(): void;
38
+ getMetadata(key: string): CacheItemMetadata | null;
39
+ setMetadata(key: string, metadata: CacheItemMetadata): void;
40
+ deleteMetadata(key: string): void;
41
+ getAllMetadata(): Map<string, CacheItemMetadata>;
42
+ clearMetadata(): void;
43
+ getCurrentSize(): {
44
+ itemCount: number;
45
+ sizeBytes: number;
46
+ };
47
+ getSizeLimits(): {
48
+ maxItems: number | null;
49
+ maxSizeBytes: number | null;
50
+ };
35
51
  }
@@ -0,0 +1,82 @@
1
+ import { Item } from "@fjell/core";
2
+ import { AnyCacheEvent, CacheEventListener, CacheSubscription, CacheSubscriptionOptions } from "./CacheEventTypes";
3
+ /**
4
+ * Cache event emitter that manages subscriptions and event dispatching
5
+ */
6
+ export declare class CacheEventEmitter<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> {
7
+ private subscriptions;
8
+ private nextSubscriptionId;
9
+ private isDestroyed;
10
+ private cleanupInterval;
11
+ private readonly CLEANUP_INTERVAL_MS;
12
+ private readonly MAX_INACTIVE_TIME_MS;
13
+ private readonly WEAK_REF_ENABLED;
14
+ constructor();
15
+ /**
16
+ * Start periodic cleanup of inactive subscriptions
17
+ */
18
+ private startPeriodicCleanup;
19
+ /**
20
+ * Perform periodic cleanup of inactive subscriptions
21
+ */
22
+ private performPeriodicCleanup;
23
+ /**
24
+ * Subscribe to cache events
25
+ */
26
+ subscribe(listener: CacheEventListener<V, S, L1, L2, L3, L4, L5>, options?: CacheSubscriptionOptions<S, L1, L2, L3, L4, L5>): CacheSubscription;
27
+ /**
28
+ * Unsubscribe from events
29
+ */
30
+ unsubscribe(subscriptionId: string): boolean;
31
+ /**
32
+ * Emit an event to all matching subscriptions
33
+ */
34
+ emit(event: AnyCacheEvent<V, S, L1, L2, L3, L4, L5>): void;
35
+ /**
36
+ * Get count of active subscriptions
37
+ */
38
+ getSubscriptionCount(): number;
39
+ /**
40
+ * Get subscription details (for debugging)
41
+ */
42
+ getSubscriptions(): Array<{
43
+ id: string;
44
+ options: CacheSubscriptionOptions<S, L1, L2, L3, L4, L5>;
45
+ }>;
46
+ /**
47
+ * Destroy the event emitter and clean up all subscriptions
48
+ */
49
+ destroy(): void;
50
+ /**
51
+ * Check if an event should be emitted to a specific subscription
52
+ */
53
+ private shouldEmitToSubscription;
54
+ /**
55
+ * Emit event to a specific subscription, handling debouncing
56
+ */
57
+ private emitToSubscription;
58
+ /**
59
+ * Normalize a key for comparison
60
+ */
61
+ private normalizeKey;
62
+ /**
63
+ * Normalize a location key for comparison
64
+ */
65
+ private normalizeLocKey;
66
+ /**
67
+ * Check if two location arrays match
68
+ */
69
+ private locationsMatch;
70
+ /**
71
+ * Check if a key matches location filters
72
+ */
73
+ private keyMatchesLocations;
74
+ /**
75
+ * Check if two queries match (improved comparison)
76
+ */
77
+ private queriesMatch;
78
+ /**
79
+ * Handle errors that occur in event listeners
80
+ */
81
+ private handleListenerError;
82
+ }
@@ -0,0 +1,121 @@
1
+ import { ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
+ import { CacheClearedEvent, ItemEvent, LocationInvalidatedEvent, QueryEvent, QueryInvalidatedEvent } from "./CacheEventTypes";
3
+ /**
4
+ * Factory functions for creating cache events
5
+ */
6
+ export declare class CacheEventFactory {
7
+ private static lastTimestamp;
8
+ private static cleanupInterval;
9
+ private static instanceCount;
10
+ private static readonly CLEANUP_INTERVAL_MS;
11
+ private static readonly MAX_TIMESTAMP_AGE_MS;
12
+ /**
13
+ * Initialize cleanup mechanism when first instance is created
14
+ */
15
+ private static initializeCleanup;
16
+ /**
17
+ * Cleanup mechanism when instance is destroyed
18
+ */
19
+ static destroyInstance(): void;
20
+ /**
21
+ * Start automatic cleanup timer
22
+ */
23
+ private static startCleanupTimer;
24
+ /**
25
+ * Stop automatic cleanup timer
26
+ */
27
+ private static stopCleanupTimer;
28
+ /**
29
+ * Perform periodic cleanup of stale timestamp state
30
+ */
31
+ private static performCleanup;
32
+ /**
33
+ * Reset the timestamp state (useful for testing)
34
+ */
35
+ static resetTimestamp(): void;
36
+ /**
37
+ * Generate a unique timestamp that is always greater than the previous one
38
+ */
39
+ private static generateTimestamp;
40
+ /**
41
+ * Extract affected locations from an item key
42
+ */
43
+ private static extractAffectedLocations;
44
+ /**
45
+ * Create an item-related event
46
+ */
47
+ static createItemEvent<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(type: 'item_created' | 'item_updated' | 'item_removed' | 'item_retrieved' | 'item_set', key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: V | null, options?: {
48
+ previousItem?: V | null | null;
49
+ source?: 'api' | 'cache' | 'operation';
50
+ affectedLocations?: LocKeyArray<L1, L2, L3, L4, L5> | [];
51
+ context?: {
52
+ operation?: string;
53
+ requestId?: string;
54
+ userId?: string;
55
+ };
56
+ }): ItemEvent<V, S, L1, L2, L3, L4, L5>;
57
+ /**
58
+ * Create a query event
59
+ */
60
+ static createQueryEvent<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | [], items: V[], options?: {
61
+ source?: 'api' | 'cache' | 'operation';
62
+ context?: {
63
+ operation?: string;
64
+ requestId?: string;
65
+ userId?: string;
66
+ };
67
+ }): QueryEvent<V, S, L1, L2, L3, L4, L5>;
68
+ /**
69
+ * Create a cache cleared event
70
+ */
71
+ static createCacheClearedEvent(itemsCleared: number, queryCacheCleared?: boolean, options?: {
72
+ source?: 'api' | 'cache' | 'operation';
73
+ context?: {
74
+ operation?: string;
75
+ requestId?: string;
76
+ userId?: string;
77
+ };
78
+ }): CacheClearedEvent;
79
+ /**
80
+ * Create a location invalidated event
81
+ */
82
+ static createLocationInvalidatedEvent<S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(locations: LocKeyArray<L1, L2, L3, L4, L5> | [], affectedKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[], options?: {
83
+ source?: 'api' | 'cache' | 'operation';
84
+ context?: {
85
+ operation?: string;
86
+ requestId?: string;
87
+ userId?: string;
88
+ };
89
+ }): LocationInvalidatedEvent<S, L1, L2, L3, L4, L5>;
90
+ /**
91
+ * Create a query invalidated event
92
+ */
93
+ static createQueryInvalidatedEvent(invalidatedQueries: string[], reason: 'manual' | 'item_changed' | 'location_changed' | 'ttl_expired', options?: {
94
+ source?: 'api' | 'cache' | 'operation';
95
+ context?: {
96
+ operation?: string;
97
+ requestId?: string;
98
+ userId?: string;
99
+ };
100
+ }): QueryInvalidatedEvent;
101
+ /**
102
+ * Create an item created event
103
+ */
104
+ static itemCreated<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: V, source?: 'api' | 'cache' | 'operation'): ItemEvent<V, S, L1, L2, L3, L4, L5>;
105
+ /**
106
+ * Create an item updated event
107
+ */
108
+ static itemUpdated<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: V, previousItem?: V | null, source?: 'api' | 'cache' | 'operation'): ItemEvent<V, S, L1, L2, L3, L4, L5>;
109
+ /**
110
+ * Create an item removed event
111
+ */
112
+ static itemRemoved<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, previousItem?: V | null, source?: 'api' | 'cache' | 'operation'): ItemEvent<V, S, L1, L2, L3, L4, L5>;
113
+ /**
114
+ * Create an item retrieved event
115
+ */
116
+ static itemRetrieved<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: V, source?: 'api' | 'cache' | 'operation'): ItemEvent<V, S, L1, L2, L3, L4, L5>;
117
+ /**
118
+ * Create an item set event (direct cache operation)
119
+ */
120
+ static itemSet<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: V, previousItem?: V | null): ItemEvent<V, S, L1, L2, L3, L4, L5>;
121
+ }
@@ -0,0 +1,122 @@
1
+ import { ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
+ /**
3
+ * Types of events that can be emitted by the cache system
4
+ */
5
+ export type CacheEventType = 'item_created' | 'item_updated' | 'item_removed' | 'item_retrieved' | 'item_set' | 'items_queried' | 'cache_cleared' | 'location_invalidated' | 'query_invalidated';
6
+ /**
7
+ * Base interface for all cache events
8
+ */
9
+ export interface CacheEvent {
10
+ /** Type of the event */
11
+ type: CacheEventType;
12
+ /** Timestamp when the event occurred */
13
+ timestamp: number;
14
+ /** Source of the event */
15
+ source: 'api' | 'cache' | 'operation';
16
+ /** Optional context about what triggered this event */
17
+ context?: {
18
+ operation?: string;
19
+ requestId?: string;
20
+ userId?: string;
21
+ };
22
+ }
23
+ /**
24
+ * Event emitted when a single item is affected
25
+ */
26
+ export interface ItemEvent<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> extends CacheEvent {
27
+ type: 'item_created' | 'item_updated' | 'item_removed' | 'item_retrieved' | 'item_set';
28
+ /** The key of the affected item */
29
+ key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>;
30
+ /** The current item (null for 'item_removed') */
31
+ item: V | null;
32
+ /** The previous item before the change (for updates/removals) */
33
+ previousItem?: V | null;
34
+ /** Locations affected by this change */
35
+ affectedLocations?: LocKeyArray<L1, L2, L3, L4, L5> | [];
36
+ }
37
+ /**
38
+ * Event emitted when multiple items are affected by a query
39
+ */
40
+ export interface QueryEvent<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> extends CacheEvent {
41
+ type: 'items_queried';
42
+ /** The query that was executed */
43
+ query: ItemQuery;
44
+ /** Locations where the query was executed */
45
+ locations: LocKeyArray<L1, L2, L3, L4, L5> | [];
46
+ /** Items returned by the query */
47
+ items: V[];
48
+ /** Keys of all items affected by this query */
49
+ affectedKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
50
+ }
51
+ /**
52
+ * Event emitted when the entire cache is cleared
53
+ */
54
+ export interface CacheClearedEvent extends CacheEvent {
55
+ type: 'cache_cleared';
56
+ /** Number of items that were cleared */
57
+ itemsCleared: number;
58
+ /** Whether query cache was also cleared */
59
+ queryCacheCleared: boolean;
60
+ }
61
+ /**
62
+ * Event emitted when specific locations are invalidated
63
+ */
64
+ export interface LocationInvalidatedEvent<S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> extends CacheEvent {
65
+ type: 'location_invalidated';
66
+ /** Locations that were invalidated */
67
+ locations: LocKeyArray<L1, L2, L3, L4, L5> | [];
68
+ /** Keys of items that were affected by the invalidation */
69
+ affectedKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
70
+ }
71
+ /**
72
+ * Event emitted when cached query results are invalidated
73
+ */
74
+ export interface QueryInvalidatedEvent extends CacheEvent {
75
+ type: 'query_invalidated';
76
+ /** Queries that were invalidated (query hashes) */
77
+ invalidatedQueries: string[];
78
+ /** Reason for invalidation */
79
+ reason: 'manual' | 'item_changed' | 'location_changed' | 'ttl_expired';
80
+ }
81
+ /**
82
+ * Union type of all possible cache events
83
+ */
84
+ export type AnyCacheEvent<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> = ItemEvent<V, S, L1, L2, L3, L4, L5> | QueryEvent<V, S, L1, L2, L3, L4, L5> | CacheClearedEvent | LocationInvalidatedEvent<S, L1, L2, L3, L4, L5> | QueryInvalidatedEvent;
85
+ /**
86
+ * Function type for cache event listeners
87
+ */
88
+ export type CacheEventListener<V extends Item<S, L1, L2, L3, L4, L5>, S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> = (event: AnyCacheEvent<V, S, L1, L2, L3, L4, L5>) => void;
89
+ /**
90
+ * Options for subscribing to cache events
91
+ */
92
+ export interface CacheSubscriptionOptions<S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> {
93
+ /** Only emit events for specific keys */
94
+ keys?: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
95
+ /** Only emit events for specific locations */
96
+ locations?: LocKeyArray<L1, L2, L3, L4, L5> | [];
97
+ /** Only emit events matching this query */
98
+ query?: ItemQuery;
99
+ /** Filter by event types */
100
+ eventTypes?: CacheEventType[];
101
+ /** Debounce events by this many milliseconds */
102
+ debounceMs?: number;
103
+ /** Whether to emit events for items that match the subscription criteria */
104
+ includeExistingItems?: boolean;
105
+ /** Optional error handler for listener errors */
106
+ onError?: (error: Error, event: any) => void;
107
+ /** Use weak references for the listener (default: true if WeakRef is available) */
108
+ useWeakRef?: boolean;
109
+ }
110
+ /**
111
+ * Represents an active subscription to cache events
112
+ */
113
+ export interface CacheSubscription {
114
+ /** Unique identifier for this subscription */
115
+ id: string;
116
+ /** Unsubscribe from events */
117
+ unsubscribe: () => void;
118
+ /** Check if this subscription is still active */
119
+ isActive: () => boolean;
120
+ /** Get subscription options */
121
+ getOptions: () => CacheSubscriptionOptions<any, any, any, any, any, any>;
122
+ }
@@ -0,0 +1,3 @@
1
+ export * from './CacheEventTypes';
2
+ export * from './CacheEventEmitter';
3
+ export * from './CacheEventFactory';
@@ -0,0 +1,57 @@
1
+ import { CacheMapMetadataProvider, EvictionStrategy } from './EvictionStrategy';
2
+ /**
3
+ * Manages eviction logic independently of CacheMap implementations.
4
+ * This class coordinates between eviction strategies and cache metadata.
5
+ */
6
+ export declare class EvictionManager {
7
+ private evictionStrategy;
8
+ constructor(evictionStrategy?: EvictionStrategy);
9
+ /**
10
+ * Set or update the eviction strategy
11
+ * @param strategy - The eviction strategy to use
12
+ */
13
+ setEvictionStrategy(strategy: EvictionStrategy | null): void;
14
+ /**
15
+ * Get the current eviction strategy name
16
+ * @returns Strategy name or null if no eviction
17
+ */
18
+ getEvictionStrategyName(): string | null;
19
+ /**
20
+ * Handle item access - update metadata for eviction strategy
21
+ * @param key - Item key
22
+ * @param metadataProvider - Cache metadata provider
23
+ */
24
+ onItemAccessed(key: string, metadataProvider: CacheMapMetadataProvider): void;
25
+ /**
26
+ * Handle item addition - update metadata and perform eviction if needed
27
+ * @param key - Item key
28
+ * @param value - Item value (for size estimation)
29
+ * @param metadataProvider - Cache metadata provider
30
+ * @returns Array of keys that were evicted
31
+ */
32
+ onItemAdded<T>(key: string, value: T, metadataProvider: CacheMapMetadataProvider): string[];
33
+ /**
34
+ * Handle item removal - clean up metadata
35
+ * @param key - Item key
36
+ * @param metadataProvider - Cache metadata provider
37
+ */
38
+ onItemRemoved(key: string, metadataProvider: CacheMapMetadataProvider): void;
39
+ /**
40
+ * Perform manual eviction check
41
+ * @param metadataProvider - Cache metadata provider
42
+ * @returns Array of keys that were evicted
43
+ */
44
+ performEviction(metadataProvider: CacheMapMetadataProvider): string[];
45
+ /**
46
+ * Check if eviction is supported (i.e., strategy is set)
47
+ * @returns True if eviction is supported
48
+ */
49
+ isEvictionSupported(): boolean;
50
+ /**
51
+ * Create eviction context from current cache state
52
+ * @param metadataProvider - Cache metadata provider
53
+ * @param newItemSize - Size of item being added (optional)
54
+ * @returns Eviction context
55
+ */
56
+ private createEvictionContext;
57
+ }
@@ -18,33 +18,125 @@ export interface CacheItemMetadata {
18
18
  lastFrequencyUpdate?: number;
19
19
  /** Raw frequency count before decay */
20
20
  rawFrequency?: number;
21
+ /** Additional strategy-specific metadata */
22
+ strategyData?: {
23
+ [key: string]: any;
24
+ };
25
+ }
26
+ /**
27
+ * Interface for CacheMap implementations to support metadata storage
28
+ * This allows eviction strategies to store and retrieve metadata independently of the storage mechanism
29
+ */
30
+ export interface CacheMapMetadataProvider {
31
+ /**
32
+ * Get metadata for a specific item
33
+ * @param key - Item key
34
+ * @returns Metadata if exists, null otherwise
35
+ */
36
+ getMetadata(key: string): CacheItemMetadata | null;
37
+ /**
38
+ * Set metadata for a specific item
39
+ * @param key - Item key
40
+ * @param metadata - Metadata to store
41
+ */
42
+ setMetadata(key: string, metadata: CacheItemMetadata): void;
43
+ /**
44
+ * Delete metadata for a specific item
45
+ * @param key - Item key
46
+ */
47
+ deleteMetadata(key: string): void;
48
+ /**
49
+ * Get all metadata entries
50
+ * @returns Map of all metadata entries
51
+ */
52
+ getAllMetadata(): Map<string, CacheItemMetadata>;
53
+ /**
54
+ * Clear all metadata
55
+ */
56
+ clearMetadata(): void;
57
+ /**
58
+ * Get current cache size information
59
+ * @returns Object with current size metrics
60
+ */
61
+ getCurrentSize(): {
62
+ itemCount: number;
63
+ sizeBytes: number;
64
+ };
65
+ /**
66
+ * Get cache size limits
67
+ * @returns Object with size limits (null means unlimited)
68
+ */
69
+ getSizeLimits(): {
70
+ maxItems: number | null;
71
+ maxSizeBytes: number | null;
72
+ };
73
+ }
74
+ /**
75
+ * Context provided to eviction strategies for decision making
76
+ */
77
+ export interface EvictionContext {
78
+ /** Current cache size information */
79
+ currentSize: {
80
+ itemCount: number;
81
+ sizeBytes: number;
82
+ };
83
+ /** Cache size limits */
84
+ limits: {
85
+ maxItems: number | null;
86
+ maxSizeBytes: number | null;
87
+ };
88
+ /** Size of the item being added (for proactive eviction) */
89
+ newItemSize?: number;
21
90
  }
22
91
  /**
23
92
  * Abstract base class for cache eviction strategies.
24
93
  * Defines the core contract that all eviction policies must implement.
94
+ *
95
+ * Eviction strategies are now completely independent of CacheMap implementations
96
+ * and interact through the CacheMapMetadataProvider interface.
25
97
  */
26
98
  export declare abstract class EvictionStrategy {
27
99
  /**
28
- * Select which item should be evicted based on the strategy
29
- * @param items - Map of items with their metadata
30
- * @returns Key of the item to evict, or null if no eviction needed
100
+ * Select which items should be evicted based on the strategy and context
101
+ * @param metadataProvider - Provider for accessing cache metadata
102
+ * @param context - Current cache state and limits
103
+ * @returns Array of keys to evict (empty array if no eviction needed)
31
104
  */
32
- abstract selectForEviction(items: Map<string, CacheItemMetadata>): string | null;
105
+ abstract selectForEviction(metadataProvider: CacheMapMetadataProvider, context: EvictionContext): string[];
33
106
  /**
34
107
  * Update metadata when an item is accessed
35
108
  * @param key - Item key
36
- * @param metadata - Current metadata
109
+ * @param metadataProvider - Provider for accessing cache metadata
37
110
  */
38
- abstract onItemAccessed(key: string, metadata: CacheItemMetadata): void;
111
+ abstract onItemAccessed(key: string, metadataProvider: CacheMapMetadataProvider): void;
39
112
  /**
40
113
  * Update metadata when an item is added
41
114
  * @param key - Item key
42
- * @param metadata - Initial metadata
115
+ * @param estimatedSize - Estimated size of the item in bytes
116
+ * @param metadataProvider - Provider for accessing cache metadata
43
117
  */
44
- abstract onItemAdded(key: string, metadata: CacheItemMetadata): void;
118
+ abstract onItemAdded(key: string, estimatedSize: number, metadataProvider: CacheMapMetadataProvider): void;
45
119
  /**
46
120
  * Clean up when an item is removed
47
- * @param key - Item key (optional for some strategies)
121
+ * @param key - Item key
122
+ * @param metadataProvider - Provider for accessing cache metadata
123
+ */
124
+ abstract onItemRemoved(key: string, metadataProvider: CacheMapMetadataProvider): void;
125
+ /**
126
+ * Get the name/identifier of this eviction strategy
127
+ * @returns String identifier for the strategy
128
+ */
129
+ abstract getStrategyName(): string;
130
+ /**
131
+ * Determine if eviction is needed based on current context
132
+ * @param context - Current cache state and limits
133
+ * @returns True if eviction should occur
134
+ */
135
+ protected isEvictionNeeded(context: EvictionContext): boolean;
136
+ /**
137
+ * Calculate how many items need to be evicted
138
+ * @param context - Current cache state and limits
139
+ * @returns Number of items that should be evicted
48
140
  */
49
- abstract onItemRemoved(key?: string): void;
141
+ protected calculateEvictionCount(context: EvictionContext): number;
50
142
  }