@fjell/cache 4.7.0 → 4.7.4

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 +67 -24
  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 +19 -2
  13. package/dist/browser/IndexDBCacheMap.d.ts +49 -36
  14. package/dist/browser/LocalStorageCacheMap.d.ts +38 -22
  15. package/dist/browser/SessionStorageCacheMap.d.ts +35 -19
  16. package/dist/events/CacheEventEmitter.d.ts +83 -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 +4959 -2920
  32. package/dist/index.js.map +4 -4
  33. package/dist/memory/EnhancedMemoryCacheMap.d.ts +36 -30
  34. package/dist/memory/MemoryCacheMap.d.ts +34 -19
  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 +19 -16
  42. package/debug_test2.js +0 -0
  43. package/debug_test3.js +0 -0
package/README.md CHANGED
@@ -21,6 +21,7 @@ Fjell Cache provides intelligent caching capabilities for complex data models an
21
21
  - **Cache Size Limits**: Configure maximum cache size in bytes or item count with automatic eviction
22
22
  - **Advanced Eviction Policies**: LRU, LFU, FIFO, MRU, Random, ARC, and 2Q strategies for optimal performance
23
23
  - **Performance Monitoring**: Built-in cache statistics and utilization tracking
24
+ - **Cache Introspection**: Runtime visibility into cache implementation type, eviction policies, and capabilities
24
25
 
25
26
  ## Installation
26
27
 
@@ -57,6 +58,12 @@ await userCache.operations.set(userKey, updatedUser);
57
58
  const memoryCache = new MemoryCacheMap<User>(['user']);
58
59
  memoryCache.set(userKey, user);
59
60
  const cachedUser = memoryCache.get(userKey);
61
+
62
+ // Get cache information for debugging or monitoring
63
+ const cacheInfo = userCache.getCacheInfo();
64
+ console.log(`Using ${cacheInfo.implementationType} cache`);
65
+ console.log(`TTL support: ${cacheInfo.supportsTTL}`);
66
+ console.log(`Eviction support: ${cacheInfo.supportsEviction}`);
60
67
  ```
61
68
 
62
69
  ## Configuration Options
@@ -1,25 +1,36 @@
1
1
  import { ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
2
  import { Cache } from "./Cache";
3
- import { CacheMap } from "./CacheMap";
3
+ import { CacheEventEmitter } from "./events/CacheEventEmitter";
4
+ import { CacheEventListener, CacheSubscription, CacheSubscriptionOptions } from "./events/CacheEventTypes";
4
5
  export interface Aggregator<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 Cache<V, S, L1, L2, L3, L4, L5> {
5
- all: (query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V[]]>;
6
- one: (query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V | null]>;
7
- action: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, action: string, body?: any) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
8
- allAction: (action: string, body?: any, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V[]]>;
9
- allFacet: (facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, any]>;
10
- create: (item: Partial<Item<S, L1, L2, L3, L4, L5>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
11
- get: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V | null]>;
12
- retrieve: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5> | null, V | null]>;
13
- remove: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<CacheMap<V, S, L1, L2, L3, L4, L5>>;
14
- update: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Partial<Item<S, L1, L2, L3, L4, L5>>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
15
- facet: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, any]>;
16
- find: (finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V[]]>;
17
- findOne: (finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
18
- set: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Item<S, L1, L2, L3, L4, L5>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
19
- reset: () => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>]>;
6
+ all: (query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<V[]>;
7
+ one: (query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<V | null>;
8
+ action: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, action: string, body?: any) => Promise<V>;
9
+ allAction: (action: string, body?: any, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<V[]>;
10
+ allFacet: (facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<any>;
11
+ create: (item: Partial<Item<S, L1, L2, L3, L4, L5>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<V>;
12
+ get: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<V | null>;
13
+ retrieve: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<V | null>;
14
+ remove: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<void>;
15
+ update: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Partial<Item<S, L1, L2, L3, L4, L5>>) => Promise<V>;
16
+ facet: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>) => Promise<any>;
17
+ find: (finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<V[]>;
18
+ findOne: (finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<V>;
19
+ set: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Item<S, L1, L2, L3, L4, L5>) => Promise<V>;
20
+ reset: () => Promise<void>;
20
21
  populate: (item: V) => Promise<V>;
21
22
  populateAggregate: (key: string, item: V) => Promise<void>;
22
23
  populateEvent: (key: string, item: V) => Promise<void>;
24
+ /** Event emitter for cache events */
25
+ eventEmitter: CacheEventEmitter<V, S, L1, L2, L3, L4, L5>;
26
+ /**
27
+ * Subscribe to cache events
28
+ */
29
+ subscribe(listener: CacheEventListener<V, S, L1, L2, L3, L4, L5>, options?: CacheSubscriptionOptions<S, L1, L2, L3, L4, L5>): CacheSubscription;
30
+ /**
31
+ * Unsubscribe from cache events
32
+ */
33
+ unsubscribe(subscription: CacheSubscription): boolean;
23
34
  }
24
35
  export interface CacheConfig {
25
36
  cache: any;
package/dist/Cache.d.ts CHANGED
@@ -4,6 +4,26 @@ import { ClientApi } from "@fjell/client-api";
4
4
  import { CacheMap } from "./CacheMap";
5
5
  import { Operations } from "./Operations";
6
6
  import { Options } from "./Options";
7
+ import { EvictionManager } from "./eviction/EvictionManager";
8
+ import { TTLManager } from "./ttl/TTLManager";
9
+ import { CacheEventEmitter } from "./events/CacheEventEmitter";
10
+ import { CacheEventListener, CacheSubscription, CacheSubscriptionOptions } from "./events/CacheEventTypes";
11
+ import { CacheStats, CacheStatsManager } from "./CacheStats";
12
+ /**
13
+ * Cache configuration information exposed to client applications
14
+ */
15
+ export interface CacheInfo {
16
+ /** The implementation type in format "<category>/<implementation>" */
17
+ implementationType: string;
18
+ /** The eviction policy being used (if any) */
19
+ evictionPolicy?: string;
20
+ /** Default TTL in milliseconds (if configured) */
21
+ defaultTTL?: number;
22
+ /** Whether TTL is supported by this implementation */
23
+ supportsTTL: boolean;
24
+ /** Whether eviction is supported by this implementation */
25
+ supportsEviction: boolean;
26
+ }
7
27
  /**
8
28
  * The Cache interface extends the base Instance from @fjell/registry and adds cache operations
9
29
  * for interacting with cached data.
@@ -26,6 +46,41 @@ export interface Cache<V extends Item<S, L1, L2, L3, L4, L5>, S extends string,
26
46
  operations: Operations<V, S, L1, L2, L3, L4, L5>;
27
47
  /** Cache configuration options */
28
48
  options?: Options<V, S, L1, L2, L3, L4, L5>;
49
+ /** Event emitter for cache events */
50
+ eventEmitter: CacheEventEmitter<V, S, L1, L2, L3, L4, L5>;
51
+ /** Eviction manager for handling cache eviction independently of storage */
52
+ evictionManager: EvictionManager;
53
+ /** TTL manager for handling time-to-live independently of storage */
54
+ ttlManager: TTLManager;
55
+ /** Statistics manager for tracking cache metrics */
56
+ statsManager: CacheStatsManager;
57
+ /**
58
+ * Get cache configuration information for client applications
59
+ * Provides visibility into implementation type, eviction policy, TTL settings, and capabilities
60
+ */
61
+ getCacheInfo(): CacheInfo;
62
+ /**
63
+ * Get current cache statistics
64
+ * @returns Current cache statistics including hits, misses, requests, and subscription counts
65
+ */
66
+ getStats(): CacheStats;
67
+ /**
68
+ * Subscribe to cache events
69
+ * @param listener Function to call when events occur
70
+ * @param options Optional filters for which events to receive
71
+ * @returns Subscription object with unsubscribe method
72
+ */
73
+ subscribe(listener: CacheEventListener<V, S, L1, L2, L3, L4, L5>, options?: CacheSubscriptionOptions<S, L1, L2, L3, L4, L5>): CacheSubscription;
74
+ /**
75
+ * Unsubscribe from cache events
76
+ * @param subscription Subscription to cancel
77
+ * @returns True if subscription was found and cancelled
78
+ */
79
+ unsubscribe(subscription: CacheSubscription): boolean;
80
+ /**
81
+ * Destroy the cache and clean up all resources
82
+ */
83
+ destroy(): void;
29
84
  }
30
85
  export declare const createCache: <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>(api: ClientApi<V, S, L1, L2, L3, L4, L5>, coordinate: Coordinate<S, L1, L2, L3, L4, L5>, registry: Registry, options?: Partial<Options<V, S, L1, L2, L3, L4, L5>>) => Cache<V, S, L1, L2, L3, L4, L5>;
31
86
  export declare const isCache: (cache: any) => cache is Cache<any, any, any, any, any, any, any>;
@@ -2,6 +2,10 @@ import { Item } from "@fjell/core";
2
2
  import { ClientApi } from "@fjell/client-api";
3
3
  import { CacheMap } from "./CacheMap";
4
4
  import { Options } from "./Options";
5
+ import { CacheEventEmitter } from "./events/CacheEventEmitter";
6
+ import { TTLManager } from "./ttl/TTLManager";
7
+ import { EvictionManager } from "./eviction/EvictionManager";
8
+ import { CacheStatsManager } from "./CacheStats";
5
9
  /**
6
10
  * Context object that consolidates all cache-related parameters
7
11
  * passed to cache operations. This prevents cache concerns from
@@ -16,12 +20,16 @@ export interface CacheContext<V extends Item<S, L1, L2, L3, L4, L5>, S extends s
16
20
  pkType: S;
17
21
  /** Cache options including TTL configuration */
18
22
  options: Options<V, S, L1, L2, L3, L4, L5>;
19
- /** TTL for individual items (from memoryConfig.ttl or ttl) */
20
- itemTtl?: number;
21
- /** TTL for query results (from ttl) */
22
- queryTtl?: number;
23
+ /** Event emitter for cache events */
24
+ eventEmitter: CacheEventEmitter<V, S, L1, L2, L3, L4, L5>;
25
+ /** TTL manager for handling time-to-live independently of storage */
26
+ ttlManager: TTLManager;
27
+ /** Eviction manager for handling cache eviction independently of storage */
28
+ evictionManager: EvictionManager;
29
+ /** Statistics manager for tracking cache metrics */
30
+ statsManager: CacheStatsManager;
23
31
  }
24
32
  /**
25
33
  * Creates a CacheContext from the individual cache-related parameters
26
34
  */
27
- export declare const createCacheContext: <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>(api: ClientApi<V, S, L1, L2, L3, L4, L5>, cacheMap: CacheMap<V, S, L1, L2, L3, L4, L5>, pkType: S, options: Options<V, S, L1, L2, L3, L4, L5>) => CacheContext<V, S, L1, L2, L3, L4, L5>;
35
+ export declare const createCacheContext: <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>(api: ClientApi<V, S, L1, L2, L3, L4, L5>, cacheMap: CacheMap<V, S, L1, L2, L3, L4, L5>, pkType: S, options: Options<V, S, L1, L2, L3, L4, L5>, eventEmitter: CacheEventEmitter<V, S, L1, L2, L3, L4, L5>, ttlManager: TTLManager, evictionManager: EvictionManager, statsManager: CacheStatsManager) => CacheContext<V, S, L1, L2, L3, L4, L5>;
@@ -1,4 +1,5 @@
1
1
  import { AllItemTypeArrays, ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
+ import { CacheItemMetadata, CacheMapMetadataProvider } from "./eviction/EvictionStrategy";
2
3
  /**
3
4
  * Abstract base interface for cache map implementations.
4
5
  * Defines the contract that all cache map implementations must follow.
@@ -7,84 +8,126 @@ import { AllItemTypeArrays, ComKey, Item, ItemQuery, LocKeyArray, PriKey } from
7
8
  * @template S - The string literal type representing the model's key type
8
9
  * @template L1-L5 - Optional string literal types for location hierarchy levels
9
10
  */
10
- export declare abstract class CacheMap<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> {
11
+ export declare abstract class CacheMap<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> implements CacheMapMetadataProvider {
11
12
  protected types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>;
12
- constructor(types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>);
13
13
  /**
14
- * Retrieve an item by its key
14
+ * The implementation type identifier in the format "<category>/<implementation>"
15
+ * Examples: "memory/memory", "memory/enhanced", "browser/localStorage"
15
16
  */
16
- abstract get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): V | null;
17
+ abstract readonly implementationType: string;
18
+ constructor(types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>);
17
19
  /**
18
- * Retrieve an item by its key with TTL awareness
19
- * Returns null if item doesn't exist or has expired based on the provided TTL
20
+ * Retrieve an item by its key
20
21
  */
21
- abstract getWithTTL(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, ttl: number): V | null;
22
+ abstract get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
22
23
  /**
23
24
  * Store an item with its key
24
25
  */
25
- abstract set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V): void;
26
+ abstract set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V): Promise<void>;
26
27
  /**
27
28
  * Check if a key exists in the cache
28
29
  */
29
- abstract includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): boolean;
30
+ abstract includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<boolean>;
30
31
  /**
31
32
  * Delete an item by its key
32
33
  */
33
- abstract delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): void;
34
+ abstract delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<void>;
34
35
  /**
35
36
  * Get all items in the specified locations
36
37
  */
37
- abstract allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): V[];
38
+ abstract allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
38
39
  /**
39
40
  * Check if any items match the query in the specified locations
40
41
  */
41
- abstract contains(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): boolean;
42
+ abstract contains(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<boolean>;
42
43
  /**
43
44
  * Get all items that match the query in the specified locations
44
45
  */
45
- abstract queryIn(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): V[];
46
+ abstract queryIn(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
46
47
  /**
47
48
  * Create a clone of this cache map
48
49
  */
49
- abstract clone(): CacheMap<V, S, L1, L2, L3, L4, L5>;
50
+ abstract clone(): Promise<CacheMap<V, S, L1, L2, L3, L4, L5>>;
50
51
  /**
51
52
  * Get all keys in the cache
52
53
  */
53
- abstract keys(): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
54
+ abstract keys(): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]>;
54
55
  /**
55
56
  * Get all values in the cache
56
57
  */
57
- abstract values(): V[];
58
+ abstract values(): Promise<V[]>;
58
59
  /**
59
60
  * Clear all items from the cache
60
61
  */
61
- abstract clear(): void;
62
+ abstract clear(): Promise<void>;
62
63
  /**
63
64
  * Set a query result as a collection of item keys
64
65
  */
65
- abstract setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[], ttl?: number): void;
66
+ abstract setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
66
67
  /**
67
68
  * Get a query result as a collection of item keys
68
69
  */
69
- abstract getQueryResult(queryHash: string): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null;
70
+ abstract getQueryResult(queryHash: string): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null>;
70
71
  /**
71
72
  * Check if a query result exists in cache
72
73
  */
73
- abstract hasQueryResult(queryHash: string): boolean;
74
+ abstract hasQueryResult(queryHash: string): Promise<boolean>;
74
75
  /**
75
76
  * Delete a specific query result
76
77
  */
77
- abstract deleteQueryResult(queryHash: string): void;
78
+ abstract deleteQueryResult(queryHash: string): Promise<void>;
78
79
  /**
79
80
  * Invalidate all cached items by their keys
80
81
  */
81
- abstract invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void;
82
+ abstract invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
82
83
  /**
83
84
  * Invalidate all items in specified locations and clear related query results
84
85
  */
85
- abstract invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): void;
86
+ abstract invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<void>;
86
87
  /**
87
88
  * Clear all query result cache entries
88
89
  */
89
- abstract clearQueryResults(): void;
90
+ abstract clearQueryResults(): Promise<void>;
91
+ /**
92
+ * Get metadata for a specific item
93
+ * @param key - Item key
94
+ * @returns Metadata if exists, null otherwise
95
+ */
96
+ abstract getMetadata(key: string): Promise<CacheItemMetadata | null>;
97
+ /**
98
+ * Set metadata for a specific item
99
+ * @param key - Item key
100
+ * @param metadata - Metadata to store
101
+ */
102
+ abstract setMetadata(key: string, metadata: CacheItemMetadata): Promise<void>;
103
+ /**
104
+ * Delete metadata for a specific item
105
+ * @param key - Item key
106
+ */
107
+ abstract deleteMetadata(key: string): Promise<void>;
108
+ /**
109
+ * Get all metadata entries
110
+ * @returns Map of all metadata entries
111
+ */
112
+ abstract getAllMetadata(): Promise<Map<string, CacheItemMetadata>>;
113
+ /**
114
+ * Clear all metadata
115
+ */
116
+ abstract clearMetadata(): Promise<void>;
117
+ /**
118
+ * Get current cache size information
119
+ * @returns Object with current size metrics
120
+ */
121
+ abstract getCurrentSize(): Promise<{
122
+ itemCount: number;
123
+ sizeBytes: number;
124
+ }>;
125
+ /**
126
+ * Get cache size limits
127
+ * @returns Object with size limits (null means unlimited)
128
+ */
129
+ abstract getSizeLimits(): Promise<{
130
+ maxItems: number | null;
131
+ maxSizeBytes: number | null;
132
+ }>;
90
133
  }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Cache statistics tracking interface
3
+ */
4
+ export interface CacheStats {
5
+ /** Total number of cache requests (get/retrieve operations) */
6
+ numRequests: number;
7
+ /** Total number of cache misses (items not found in cache) */
8
+ numMisses: number;
9
+ /** Total number of cache hits (items found in cache) */
10
+ numHits: number;
11
+ /** Total number of subscription requests */
12
+ numSubscriptions: number;
13
+ /** Total number of unsubscription requests */
14
+ numUnsubscriptions: number;
15
+ /** Current number of active subscriptions */
16
+ activeSubscriptions: number;
17
+ }
18
+ /**
19
+ * Cache statistics manager that tracks various cache metrics
20
+ */
21
+ export declare class CacheStatsManager {
22
+ private stats;
23
+ /**
24
+ * Increment the request counter
25
+ */
26
+ incrementRequests(): void;
27
+ /**
28
+ * Increment the cache hit counter
29
+ */
30
+ incrementHits(): void;
31
+ /**
32
+ * Increment the cache miss counter
33
+ */
34
+ incrementMisses(): void;
35
+ /**
36
+ * Increment the subscription counter
37
+ */
38
+ incrementSubscriptions(): void;
39
+ /**
40
+ * Increment the unsubscription counter
41
+ */
42
+ incrementUnsubscriptions(): void;
43
+ /**
44
+ * Get a copy of the current statistics
45
+ */
46
+ getStats(): CacheStats;
47
+ /**
48
+ * Reset all statistics to zero
49
+ */
50
+ reset(): void;
51
+ }
@@ -2,70 +2,73 @@ import { ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
2
  import { ClientApi } from "@fjell/client-api";
3
3
  import { Coordinate } from "@fjell/registry";
4
4
  import { CacheMap } from "./CacheMap";
5
+ import { CacheEventEmitter } from "./events/CacheEventEmitter";
5
6
  import { Options } from "./Options";
7
+ import { TTLManager } from "./ttl/TTLManager";
8
+ import { EvictionManager } from "./eviction/EvictionManager";
9
+ import { CacheStatsManager } from "./CacheStats";
6
10
  export interface Operations<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
11
  /**
8
12
  * Retrieves all the items that match the query from cache or API.
9
13
  * Items are cached automatically after retrieval.
10
14
  */
11
- all(query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V[]]>;
15
+ all(query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
12
16
  /**
13
17
  * Retrieves the first item that matches the query from cache or API.
14
18
  * Item is cached automatically after retrieval.
15
19
  */
16
- one(query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V | null]>;
20
+ one(query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V | null>;
17
21
  /**
18
22
  * Creates a new item via API and caches it.
19
23
  */
20
- create(item: Partial<Item<S, L1, L2, L3, L4, L5>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
24
+ create(item: Partial<Item<S, L1, L2, L3, L4, L5>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V>;
21
25
  /**
22
26
  * Gets an item by key from cache or API and caches it.
23
27
  */
24
- get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V | null]>;
28
+ get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
25
29
  /**
26
30
  * Retrieves an item from cache if available, otherwise from API.
27
- * Returns null as first element if item was already in cache.
28
31
  */
29
- retrieve(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5> | null, V | null]>;
32
+ retrieve(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
30
33
  /**
31
34
  * Removes an item via API and from cache.
32
35
  */
33
- remove(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<CacheMap<V, S, L1, L2, L3, L4, L5>>;
36
+ remove(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<void>;
34
37
  /**
35
38
  * Updates an item via API and caches the result.
36
39
  */
37
- update(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Partial<Item<S, L1, L2, L3, L4, L5>>): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
40
+ update(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Partial<Item<S, L1, L2, L3, L4, L5>>): Promise<V>;
38
41
  /**
39
42
  * Executes an action on an item via API and caches the result.
40
43
  */
41
- action(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, action: string, body?: any): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
44
+ action(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, action: string, body?: any): Promise<V>;
42
45
  /**
43
46
  * Executes an action on all items matching criteria via API and caches results.
44
47
  */
45
- allAction(action: string, body?: any, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V[]]>;
48
+ allAction(action: string, body?: any, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
46
49
  /**
47
50
  * Executes a facet query on an item via API (pass-through, no caching).
48
51
  */
49
- facet(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, any]>;
52
+ facet(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>): Promise<any>;
50
53
  /**
51
54
  * Executes a facet query on all items matching criteria via API (pass-through, no caching).
52
55
  */
53
- allFacet(facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, any]>;
56
+ allFacet(facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<any>;
54
57
  /**
55
58
  * Finds items using a finder method via API and caches results.
56
59
  */
57
- find(finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V[]]>;
60
+ find(finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
58
61
  /**
59
62
  * Finds a single item using a finder method via API and caches result.
60
63
  */
61
- findOne(finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
64
+ findOne(finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V>;
62
65
  /**
63
66
  * Sets an item directly in cache without API call.
64
67
  */
65
- set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Item<S, L1, L2, L3, L4, L5>): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
68
+ set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Item<S, L1, L2, L3, L4, L5>): Promise<V>;
66
69
  /**
67
70
  * Resets the cache, clearing all cached items.
68
71
  */
69
- reset(): Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>]>;
72
+ reset(): Promise<void>;
70
73
  }
71
- export declare const createOperations: <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>(api: ClientApi<V, S, L1, L2, L3, L4, L5>, coordinate: Coordinate<S, L1, L2, L3, L4, L5>, cacheMap: CacheMap<V, S, L1, L2, L3, L4, L5>, pkType: S, options: Options<V, S, L1, L2, L3, L4, L5>) => Operations<V, S, L1, L2, L3, L4, L5>;
74
+ export declare const createOperations: <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>(api: ClientApi<V, S, L1, L2, L3, L4, L5>, coordinate: Coordinate<S, L1, L2, L3, L4, L5>, cacheMap: CacheMap<V, S, L1, L2, L3, L4, L5>, pkType: S, options: Options<V, S, L1, L2, L3, L4, L5>, eventEmitter: CacheEventEmitter<V, S, L1, L2, L3, L4, L5>, ttlManager: TTLManager, evictionManager: EvictionManager, statsManager: CacheStatsManager) => Operations<V, S, L1, L2, L3, L4, L5>;
package/dist/Options.d.ts CHANGED
@@ -17,7 +17,7 @@ export interface CacheSizeConfig {
17
17
  maxSizeBytes?: string;
18
18
  /** Maximum number of items in cache */
19
19
  maxItems?: number;
20
- /** Eviction policy to use when limits are exceeded (default: 'lru') */
20
+ /** @deprecated Eviction policy is now handled by Cache-level EvictionManager via evictionConfig */
21
21
  evictionPolicy?: EvictionPolicy;
22
22
  }
23
23
  /**
@@ -50,8 +50,6 @@ export interface WebStorageConfig {
50
50
  export interface MemoryConfig {
51
51
  /** Maximum number of items to keep in memory (default: unlimited) */
52
52
  maxItems?: number;
53
- /** Time to live for cached items in milliseconds (default: unlimited) */
54
- ttl?: number;
55
53
  /** Size configuration for memory cache */
56
54
  size?: CacheSizeConfig;
57
55
  }
@@ -1,4 +1,5 @@
1
1
  import { AllItemTypeArrays, ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
+ import { CacheItemMetadata } from "../eviction/EvictionStrategy";
2
3
  /**
3
4
  * IndexedDB implementation of CacheMap for browser environments.
4
5
  * Data persists long-term with much larger storage limits than localStorage/sessionStorage.
@@ -14,11 +15,23 @@ export declare class AsyncIndexDBCacheMap<V extends Item<S, L1, L2, L3, L4, L5>,
14
15
  private version;
15
16
  private normalizedHashFunction;
16
17
  private dbPromise;
18
+ private static readonly CURRENT_VERSION;
17
19
  constructor(types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>, dbName?: string, storeName?: string, version?: number);
18
20
  private getDB;
19
21
  private getStorageKey;
20
22
  get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
21
- set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V): Promise<void>;
23
+ /**
24
+ * Get both the value and metadata for an item
25
+ */
26
+ getWithMetadata(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<{
27
+ value: V;
28
+ metadata?: CacheItemMetadata;
29
+ } | null>;
30
+ set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V, metadata?: CacheItemMetadata): Promise<void>;
31
+ /**
32
+ * Update only the metadata for an existing item
33
+ */
34
+ setMetadata(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, metadata: CacheItemMetadata): Promise<void>;
22
35
  includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<boolean>;
23
36
  delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<void>;
24
37
  allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
@@ -26,9 +39,13 @@ export declare class AsyncIndexDBCacheMap<V extends Item<S, L1, L2, L3, L4, L5>,
26
39
  queryIn(query: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
27
40
  clone(): AsyncIndexDBCacheMap<V, S, L1, L2, L3, L4, L5>;
28
41
  keys(): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]>;
42
+ /**
43
+ * Get all metadata entries from IndexedDB
44
+ */
45
+ getAllMetadata(): Promise<Map<string, CacheItemMetadata>>;
29
46
  values(): Promise<V[]>;
30
47
  clear(): Promise<void>;
31
- setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[], ttl?: number): Promise<void>;
48
+ setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
32
49
  getQueryResult(queryHash: string): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null>;
33
50
  hasQueryResult(queryHash: string): Promise<boolean>;
34
51
  deleteQueryResult(queryHash: string): Promise<void>;