@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.
- package/CACHE_EVENTS.md +306 -0
- package/CACHE_IMPLEMENTATIONS.md +117 -0
- package/MEMORY_LEAK_FIXES.md +270 -0
- package/README.md +7 -0
- package/dist/Aggregator.d.ts +27 -16
- package/dist/Cache.d.ts +55 -0
- package/dist/CacheContext.d.ts +13 -5
- package/dist/CacheMap.d.ts +67 -24
- package/dist/CacheStats.d.ts +51 -0
- package/dist/Operations.d.ts +20 -17
- package/dist/Options.d.ts +1 -3
- package/dist/browser/AsyncIndexDBCacheMap.d.ts +19 -2
- package/dist/browser/IndexDBCacheMap.d.ts +49 -36
- package/dist/browser/LocalStorageCacheMap.d.ts +38 -22
- package/dist/browser/SessionStorageCacheMap.d.ts +35 -19
- package/dist/events/CacheEventEmitter.d.ts +83 -0
- package/dist/events/CacheEventFactory.d.ts +121 -0
- package/dist/events/CacheEventTypes.d.ts +122 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/eviction/EvictionManager.d.ts +57 -0
- package/dist/eviction/EvictionStrategy.d.ts +102 -10
- package/dist/eviction/index.d.ts +2 -1
- package/dist/eviction/strategies/ARCEvictionStrategy.d.ts +10 -5
- package/dist/eviction/strategies/FIFOEvictionStrategy.d.ts +6 -5
- package/dist/eviction/strategies/LFUEvictionStrategy.d.ts +6 -5
- package/dist/eviction/strategies/LRUEvictionStrategy.d.ts +6 -5
- package/dist/eviction/strategies/MRUEvictionStrategy.d.ts +6 -5
- package/dist/eviction/strategies/RandomEvictionStrategy.d.ts +6 -5
- package/dist/eviction/strategies/TwoQueueEvictionStrategy.d.ts +6 -5
- package/dist/index.d.ts +9 -3
- package/dist/index.js +4959 -2920
- package/dist/index.js.map +4 -4
- package/dist/memory/EnhancedMemoryCacheMap.d.ts +36 -30
- package/dist/memory/MemoryCacheMap.d.ts +34 -19
- package/dist/normalization.d.ts +1 -2
- package/dist/ops/get.d.ts +1 -0
- package/dist/ttl/TTLManager.d.ts +100 -0
- package/dist/ttl/index.d.ts +2 -0
- package/dist/utils/CacheSize.d.ts +0 -7
- package/fix-async-tests.js +116 -0
- package/package.json +19 -16
- package/debug_test2.js +0 -0
- package/debug_test3.js +0 -0
|
@@ -1,52 +1,65 @@
|
|
|
1
1
|
import { AllItemTypeArrays, ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
|
|
2
|
-
import {
|
|
2
|
+
import { CacheItemMetadata } from "../eviction/EvictionStrategy";
|
|
3
3
|
import { AsyncIndexDBCacheMap } from "./AsyncIndexDBCacheMap";
|
|
4
|
+
import { CacheMap } from "../CacheMap";
|
|
4
5
|
/**
|
|
5
|
-
* Synchronous
|
|
6
|
+
* Synchronous IndexedDB CacheMap wrapper implementation.
|
|
6
7
|
*
|
|
7
|
-
* This implementation provides
|
|
8
|
-
*
|
|
9
|
-
* with IndexedDB storage. For full async capabilities, use AsyncIndexDBCacheMap.
|
|
8
|
+
* This implementation provides synchronous memory operations with background IndexedDB persistence.
|
|
9
|
+
* Memory operations are immediate while IndexedDB operations happen asynchronously in the background.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Benefits:
|
|
12
|
+
* - Fast memory access for immediate operations
|
|
13
|
+
* - Background persistence to IndexedDB for durability
|
|
14
|
+
* - Synchronous API compatible with other CacheMap implementations
|
|
15
|
+
* - Automatic sync between memory and IndexedDB
|
|
13
16
|
*/
|
|
14
17
|
export declare class IndexDBCacheMap<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> {
|
|
18
|
+
readonly implementationType = "browser/indexedDB";
|
|
19
|
+
private memoryMap;
|
|
20
|
+
private queryResultCache;
|
|
21
|
+
private metadataMap;
|
|
22
|
+
private normalizedHashFunction;
|
|
23
|
+
protected types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>;
|
|
15
24
|
asyncCache: AsyncIndexDBCacheMap<V, S, L1, L2, L3, L4, L5>;
|
|
16
|
-
private memoryCache;
|
|
17
25
|
private syncInterval;
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
private initializationPromise;
|
|
21
|
-
private isInitialized;
|
|
22
|
-
private readonly MAX_RETRY_ATTEMPTS;
|
|
26
|
+
private pendingOperations;
|
|
27
|
+
private sequenceCounter;
|
|
23
28
|
constructor(types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>, dbName?: string, storeName?: string, version?: number);
|
|
24
29
|
private initializeFromIndexedDB;
|
|
25
30
|
private startPeriodicSync;
|
|
26
|
-
private syncToIndexedDB;
|
|
27
31
|
private processPendingOperations;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
32
|
+
get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
|
|
33
|
+
set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V): Promise<void>;
|
|
34
|
+
includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<boolean>;
|
|
35
|
+
delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<void>;
|
|
36
|
+
keys(): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]>;
|
|
37
|
+
values(): Promise<V[]>;
|
|
38
|
+
clear(): Promise<void>;
|
|
39
|
+
allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
|
|
40
|
+
contains(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<boolean>;
|
|
41
|
+
queryIn(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
|
|
42
|
+
setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
|
|
43
|
+
getQueryResult(queryHash: string): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null>;
|
|
44
|
+
hasQueryResult(queryHash: string): Promise<boolean>;
|
|
45
|
+
deleteQueryResult(queryHash: string): Promise<void>;
|
|
46
|
+
clearQueryResults(): Promise<void>;
|
|
47
|
+
invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
|
|
48
|
+
invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<void>;
|
|
49
|
+
getMetadata(key: string): Promise<CacheItemMetadata | null>;
|
|
50
|
+
setMetadata(key: string, metadata: CacheItemMetadata): Promise<void>;
|
|
51
|
+
deleteMetadata(key: string): Promise<void>;
|
|
52
|
+
getAllMetadata(): Promise<Map<string, CacheItemMetadata>>;
|
|
53
|
+
clearMetadata(): Promise<void>;
|
|
54
|
+
getCurrentSize(): Promise<{
|
|
55
|
+
itemCount: number;
|
|
56
|
+
sizeBytes: number;
|
|
57
|
+
}>;
|
|
58
|
+
getSizeLimits(): Promise<{
|
|
59
|
+
maxItems: number | null;
|
|
60
|
+
maxSizeBytes: number | null;
|
|
61
|
+
}>;
|
|
62
|
+
clone(): Promise<CacheMap<V, S, L1, L2, L3, L4, L5>>;
|
|
50
63
|
/**
|
|
51
64
|
* Clean up resources when the cache is no longer needed
|
|
52
65
|
*/
|
|
@@ -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
|
|
14
|
-
private
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
clone(): LocalStorageCacheMap<V, S, L1, L2, L3, L4, L5>;
|
|
27
|
+
get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
|
|
28
|
+
set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V): Promise<void>;
|
|
29
|
+
includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<boolean>;
|
|
30
|
+
delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<void>;
|
|
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
|
-
keys(): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]
|
|
34
|
-
values(): V[]
|
|
35
|
-
clear(): void
|
|
36
|
-
setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]
|
|
37
|
-
getQueryResult(queryHash: string): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null
|
|
38
|
-
hasQueryResult(queryHash: string): boolean
|
|
39
|
-
deleteQueryResult(queryHash: string): void
|
|
40
|
-
invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void
|
|
41
|
-
invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): void
|
|
42
|
-
clearQueryResults(): void
|
|
36
|
+
keys(): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]>;
|
|
37
|
+
values(): Promise<V[]>;
|
|
38
|
+
clear(): Promise<void>;
|
|
39
|
+
setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
|
|
40
|
+
getQueryResult(queryHash: string): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null>;
|
|
41
|
+
hasQueryResult(queryHash: string): Promise<boolean>;
|
|
42
|
+
deleteQueryResult(queryHash: string): Promise<void>;
|
|
43
|
+
invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
|
|
44
|
+
invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<void>;
|
|
45
|
+
clearQueryResults(): Promise<void>;
|
|
46
|
+
getMetadata(key: string): Promise<CacheItemMetadata | null>;
|
|
47
|
+
setMetadata(key: string, metadata: CacheItemMetadata): Promise<void>;
|
|
48
|
+
deleteMetadata(key: string): Promise<void>;
|
|
49
|
+
getAllMetadata(): Promise<Map<string, CacheItemMetadata>>;
|
|
50
|
+
clearMetadata(): Promise<void>;
|
|
51
|
+
getCurrentSize(): Promise<{
|
|
52
|
+
itemCount: number;
|
|
53
|
+
sizeBytes: number;
|
|
54
|
+
}>;
|
|
55
|
+
getSizeLimits(): Promise<{
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
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
|
|
20
|
-
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
|
|
25
|
-
keys(): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]
|
|
26
|
-
values(): V[]
|
|
27
|
-
clear(): void
|
|
28
|
-
setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]
|
|
29
|
-
getQueryResult(queryHash: string): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null
|
|
30
|
-
hasQueryResult(queryHash: string): boolean
|
|
31
|
-
deleteQueryResult(queryHash: string): void
|
|
32
|
-
invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void
|
|
33
|
-
invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): void
|
|
34
|
-
clearQueryResults(): void
|
|
19
|
+
private hasCollisionForHash;
|
|
20
|
+
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>;
|
|
22
|
+
includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<boolean>;
|
|
23
|
+
delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<void>;
|
|
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>>;
|
|
28
|
+
keys(): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]>;
|
|
29
|
+
values(): Promise<V[]>;
|
|
30
|
+
clear(): Promise<void>;
|
|
31
|
+
setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
|
|
32
|
+
getQueryResult(queryHash: string): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null>;
|
|
33
|
+
hasQueryResult(queryHash: string): Promise<boolean>;
|
|
34
|
+
deleteQueryResult(queryHash: string): Promise<void>;
|
|
35
|
+
invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): Promise<void>;
|
|
36
|
+
invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<void>;
|
|
37
|
+
clearQueryResults(): Promise<void>;
|
|
38
|
+
getMetadata(key: string): Promise<CacheItemMetadata | null>;
|
|
39
|
+
setMetadata(key: string, metadata: CacheItemMetadata): Promise<void>;
|
|
40
|
+
deleteMetadata(key: string): Promise<void>;
|
|
41
|
+
getAllMetadata(): Promise<Map<string, CacheItemMetadata>>;
|
|
42
|
+
clearMetadata(): Promise<void>;
|
|
43
|
+
getCurrentSize(): Promise<{
|
|
44
|
+
itemCount: number;
|
|
45
|
+
sizeBytes: number;
|
|
46
|
+
}>;
|
|
47
|
+
getSizeLimits(): Promise<{
|
|
48
|
+
maxItems: number | null;
|
|
49
|
+
maxSizeBytes: number | null;
|
|
50
|
+
}>;
|
|
35
51
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
* Filter locations must be a prefix of event locations (in order)
|
|
69
|
+
*/
|
|
70
|
+
private locationsMatch;
|
|
71
|
+
/**
|
|
72
|
+
* Check if a key matches location filters
|
|
73
|
+
*/
|
|
74
|
+
private keyMatchesLocations;
|
|
75
|
+
/**
|
|
76
|
+
* Check if two queries match (improved comparison)
|
|
77
|
+
*/
|
|
78
|
+
private queriesMatch;
|
|
79
|
+
/**
|
|
80
|
+
* Handle errors that occur in event listeners
|
|
81
|
+
*/
|
|
82
|
+
private handleListenerError;
|
|
83
|
+
}
|
|
@@ -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,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): Promise<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): Promise<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): Promise<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
|
+
}
|