@fjell/cache 4.6.22 → 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 (62) hide show
  1. package/CACHE_EVENTS.md +306 -0
  2. package/CACHE_IMPLEMENTATIONS.md +315 -0
  3. package/CONFIGURATION_GUIDE.md +167 -0
  4. package/CRITICAL_FIXES.md +68 -0
  5. package/MEMORY_LEAK_FIXES.md +270 -0
  6. package/README.md +513 -2
  7. package/dist/Aggregator.d.ts +27 -16
  8. package/dist/Cache.d.ts +59 -1
  9. package/dist/CacheContext.d.ts +35 -0
  10. package/dist/CacheMap.d.ts +132 -14
  11. package/dist/CacheStats.d.ts +51 -0
  12. package/dist/Instance.d.ts +4 -2
  13. package/dist/InstanceFactory.d.ts +3 -2
  14. package/dist/Operations.d.ts +21 -17
  15. package/dist/Options.d.ts +98 -0
  16. package/dist/browser/AsyncIndexDBCacheMap.d.ts +38 -0
  17. package/dist/browser/IndexDBCacheMap.d.ts +69 -0
  18. package/dist/browser/LocalStorageCacheMap.d.ts +59 -0
  19. package/dist/browser/SessionStorageCacheMap.d.ts +51 -0
  20. package/dist/events/CacheEventEmitter.d.ts +82 -0
  21. package/dist/events/CacheEventFactory.d.ts +121 -0
  22. package/dist/events/CacheEventTypes.d.ts +122 -0
  23. package/dist/events/index.d.ts +3 -0
  24. package/dist/eviction/EvictionManager.d.ts +57 -0
  25. package/dist/eviction/EvictionStrategy.d.ts +142 -0
  26. package/dist/eviction/EvictionStrategyConfig.d.ts +97 -0
  27. package/dist/eviction/EvictionStrategyFactory.d.ts +12 -0
  28. package/dist/eviction/EvictionStrategyValidation.d.ts +36 -0
  29. package/dist/eviction/index.d.ts +10 -0
  30. package/dist/eviction/strategies/ARCEvictionStrategy.d.ts +73 -0
  31. package/dist/eviction/strategies/FIFOEvictionStrategy.d.ts +12 -0
  32. package/dist/eviction/strategies/LFUEvictionStrategy.d.ts +38 -0
  33. package/dist/eviction/strategies/LRUEvictionStrategy.d.ts +12 -0
  34. package/dist/eviction/strategies/MRUEvictionStrategy.d.ts +12 -0
  35. package/dist/eviction/strategies/RandomEvictionStrategy.d.ts +12 -0
  36. package/dist/eviction/strategies/TwoQueueEvictionStrategy.d.ts +54 -0
  37. package/dist/index.d.ts +29 -6
  38. package/dist/index.js +5764 -435
  39. package/dist/index.js.map +4 -4
  40. package/dist/memory/EnhancedMemoryCacheMap.d.ts +81 -0
  41. package/dist/memory/MemoryCacheMap.d.ts +48 -0
  42. package/dist/normalization.d.ts +19 -0
  43. package/dist/ops/action.d.ts +2 -3
  44. package/dist/ops/all.d.ts +2 -3
  45. package/dist/ops/allAction.d.ts +2 -3
  46. package/dist/ops/allFacet.d.ts +2 -3
  47. package/dist/ops/create.d.ts +2 -3
  48. package/dist/ops/facet.d.ts +2 -3
  49. package/dist/ops/find.d.ts +2 -3
  50. package/dist/ops/findOne.d.ts +2 -3
  51. package/dist/ops/get.d.ts +3 -3
  52. package/dist/ops/one.d.ts +2 -3
  53. package/dist/ops/remove.d.ts +2 -3
  54. package/dist/ops/reset.d.ts +2 -1
  55. package/dist/ops/retrieve.d.ts +2 -3
  56. package/dist/ops/set.d.ts +2 -2
  57. package/dist/ops/update.d.ts +2 -3
  58. package/dist/ttl/TTLManager.d.ts +100 -0
  59. package/dist/ttl/index.d.ts +2 -0
  60. package/dist/utils/CacheSize.d.ts +30 -0
  61. package/fix-async-tests.js +116 -0
  62. package/package.json +16 -13
@@ -0,0 +1,81 @@
1
+ import { AllItemTypeArrays, ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
+ import { CacheMap } from "../CacheMap";
3
+ import { CacheSizeConfig } from "../Options";
4
+ import { CacheItemMetadata } from "../eviction";
5
+ /**
6
+ * Enhanced in-memory implementation of CacheMap with size limits and eviction policies.
7
+ * Supports byte-based and item-count limits with configurable eviction strategies.
8
+ */
9
+ export declare class EnhancedMemoryCacheMap<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> {
10
+ readonly implementationType = "memory/enhanced";
11
+ private map;
12
+ private normalizedHashFunction;
13
+ private queryResultCache;
14
+ private currentSizeBytes;
15
+ private currentItemCount;
16
+ private queryResultsCacheSize;
17
+ private readonly maxSizeBytes?;
18
+ private readonly maxItems?;
19
+ constructor(types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>, sizeConfig?: CacheSizeConfig, initialData?: {
20
+ [key: string]: V;
21
+ });
22
+ get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
23
+ set(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, value: V): void;
24
+ includesKey(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<boolean>;
25
+ delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): void;
26
+ private deleteInternal;
27
+ keys(): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
28
+ values(): Promise<V[]>;
29
+ clear(): void;
30
+ allIn(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
31
+ contains(query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<boolean>;
32
+ queryIn(query: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<V[]>;
33
+ clone(): Promise<CacheMap<V, S, L1, L2, L3, L4, L5>>;
34
+ /**
35
+ * Get current cache statistics
36
+ */
37
+ getStats(): {
38
+ currentSizeBytes: number;
39
+ currentItemCount: number;
40
+ maxSizeBytes?: number;
41
+ maxItems?: number;
42
+ utilizationPercent: {
43
+ bytes?: number;
44
+ items?: number;
45
+ };
46
+ };
47
+ setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void;
48
+ getQueryResult(queryHash: string): Promise<(ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[] | null>;
49
+ hasQueryResult(queryHash: string): boolean;
50
+ deleteQueryResult(queryHash: string): void;
51
+ clearQueryResults(): void;
52
+ invalidateItemKeys(keys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void;
53
+ private filterQueriesReferencingKeys;
54
+ private invalidateQueriesReferencingKeys;
55
+ invalidateLocation(locations: LocKeyArray<L1, L2, L3, L4, L5> | []): Promise<void>;
56
+ /**
57
+ * Add query result to size tracking
58
+ */
59
+ private addQueryResultToSizeTracking;
60
+ /**
61
+ * Remove query result from size tracking
62
+ */
63
+ private removeQueryResultFromSizeTracking;
64
+ /**
65
+ * Get total cache size including query results
66
+ */
67
+ getTotalSizeBytes(): number;
68
+ getMetadata(key: string): CacheItemMetadata | null;
69
+ setMetadata(key: string, metadata: CacheItemMetadata): void;
70
+ deleteMetadata(_key: string): void;
71
+ getAllMetadata(): Map<string, CacheItemMetadata>;
72
+ clearMetadata(): void;
73
+ getCurrentSize(): {
74
+ itemCount: number;
75
+ sizeBytes: number;
76
+ };
77
+ getSizeLimits(): {
78
+ maxItems: number | null;
79
+ maxSizeBytes: number | null;
80
+ };
81
+ }
@@ -0,0 +1,48 @@
1
+ import { AllItemTypeArrays, ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
2
+ import { CacheMap } from "../CacheMap";
3
+ import { CacheItemMetadata } from "../eviction/EvictionStrategy";
4
+ /**
5
+ * In-memory implementation of CacheMap using a plain object as the underlying storage.
6
+ * This implementation stores all data in memory and will be lost when the application restarts.
7
+ */
8
+ export declare class MemoryCacheMap<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> {
9
+ readonly implementationType = "memory/memory";
10
+ private map;
11
+ private normalizedHashFunction;
12
+ private queryResultCache;
13
+ private metadataMap;
14
+ constructor(types: AllItemTypeArrays<S, L1, L2, L3, L4, L5>, initialData?: {
15
+ [key: string]: V;
16
+ });
17
+ get(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): Promise<V | null>;
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>): Promise<boolean>;
20
+ delete(key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>): void;
21
+ keys(): (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
22
+ values(): Promise<V[]>;
23
+ clear(): 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<MemoryCacheMap<V, S, L1, L2, L3, L4, L5>>;
28
+ setQueryResult(queryHash: string, itemKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[]): void;
29
+ getQueryResult(queryHash: string): Promise<(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> | []): Promise<void>;
34
+ clearQueryResults(): void;
35
+ getMetadata(key: string): CacheItemMetadata | null;
36
+ setMetadata(key: string, metadata: CacheItemMetadata): void;
37
+ deleteMetadata(key: string): void;
38
+ getAllMetadata(): Map<string, CacheItemMetadata>;
39
+ clearMetadata(): void;
40
+ getCurrentSize(): {
41
+ itemCount: number;
42
+ sizeBytes: number;
43
+ };
44
+ getSizeLimits(): {
45
+ maxItems: number | null;
46
+ maxSizeBytes: number | null;
47
+ };
48
+ }
@@ -0,0 +1,19 @@
1
+ import { ItemQuery, LocKeyArray } from "@fjell/core";
2
+ export declare const normalizeKeyValue: (value: string | number) => string;
3
+ export declare const createNormalizedHashFunction: <T>() => (key: T) => string;
4
+ export declare const isLocKeyArrayEqual: (a: any[], b: any[]) => boolean;
5
+ export declare const normalizeLocKeyItem: (item: any) => any;
6
+ /**
7
+ * Interface for storing query results
8
+ */
9
+ export interface QueryCacheEntry {
10
+ itemKeys: (any)[];
11
+ }
12
+ /**
13
+ * Generate a safe hash for all/one query parameters
14
+ */
15
+ export declare const createQueryHash: <S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(pkType: S, query: ItemQuery, locations: LocKeyArray<L1, L2, L3, L4, L5> | []) => string;
16
+ /**
17
+ * Generate a safe hash for find/findOne query parameters
18
+ */
19
+ export declare const createFinderHash: <L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(finder: string, params: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations: LocKeyArray<L1, L2, L3, L4, L5> | []) => string;
@@ -1,4 +1,3 @@
1
1
  import { ComKey, Item, PriKey } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const action: <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, key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, action: string, body?: any) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const action: <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>, action: string, body: any | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V]>;
package/dist/ops/all.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  import { Item, ItemQuery, LocKeyArray } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const all: <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, query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V[]]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const all: <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 | undefined, locations: (LocKeyArray<L1, L2, L3, L4, L5> | []) | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V[]]>;
@@ -1,4 +1,3 @@
1
1
  import { Item, LocKeyArray } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const allAction: <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, action: string, body?: any, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V[]]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const allAction: <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>(action: string, body: any | undefined, locations: (LocKeyArray<L1, L2, L3, L4, L5> | []) | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V[]]>;
@@ -1,4 +1,3 @@
1
1
  import { Item, LocKeyArray } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const allFacet: <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>, 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]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const allFacet: <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>(facet: string, params: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>> | undefined, locations: (LocKeyArray<L1, L2, L3, L4, L5> | []) | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<any>;
@@ -1,4 +1,3 @@
1
1
  import { Item, LocKeyArray } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const create: <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, v: 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]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const create: <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>(v: Partial<Item<S, L1, L2, L3, L4, L5>>, locations: (LocKeyArray<L1, L2, L3, L4, L5> | []) | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V]>;
@@ -1,4 +1,3 @@
1
1
  import { ComKey, Item, PriKey } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const facet: <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>, 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]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const facet: <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>, facet: string, params: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>> | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<any>;
@@ -1,4 +1,3 @@
1
1
  import { Item, LocKeyArray } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const find: <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, 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[]]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const find: <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>(finder: string, params: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>> | undefined, locations: (LocKeyArray<L1, L2, L3, L4, L5> | []) | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V[]]>;
@@ -1,4 +1,3 @@
1
1
  import { Item, LocKeyArray } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const findOne: <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, finder: string, finderParams?: 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]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const findOne: <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>(finder: string, finderParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>> | undefined, locations: (LocKeyArray<L1, L2, L3, L4, L5> | []) | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V]>;
package/dist/ops/get.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { ComKey, Item, PriKey } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const get: <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, key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V | null]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const cleanup: () => void;
4
+ export declare const get: <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>, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V | null]>;
package/dist/ops/one.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  import { Item, ItemQuery, LocKeyArray } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const one: <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, query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V | null]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const one: <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 | undefined, locations: (LocKeyArray<L1, L2, L3, L4, L5> | []) | undefined, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V | null]>;
@@ -1,4 +1,3 @@
1
1
  import { ComKey, Item, PriKey } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const remove: <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>, key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<CacheMap<V, S, L1, L2, L3, L4, L5>>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const remove: <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>, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<CacheContext<V, S, L1, L2, L3, L4, L5>>;
@@ -1,4 +1,5 @@
1
1
  import { Item } from "@fjell/core";
2
2
  import { CacheMap } from "../CacheMap";
3
+ import { Options } from "../Options";
3
4
  import { Coordinate } from "@fjell/registry";
4
- export declare const reset: <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>(coordinate: Coordinate<S, L1, L2, L3, L4, L5>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>]>;
5
+ export declare const reset: <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>(coordinate: Coordinate<S, L1, L2, L3, L4, L5>, options: Options<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>]>;
@@ -1,4 +1,3 @@
1
1
  import { ComKey, Item, PriKey } from "@fjell/core";
2
- import { CacheMap } from "../CacheMap";
3
- import { ClientApi } from "@fjell/client-api";
4
- export declare const retrieve: <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, key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5> | null, V | null]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const retrieve: <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>, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5> | null, V | null]>;
package/dist/ops/set.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { ComKey, Item, PriKey } from "@fjell/core";
2
- import { CacheMap } from "../CacheMap";
3
- export declare const set: <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>(cacheMap: CacheMap<V, S, L1, L2, L3, L4, L5>, pkType: S, key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, v: Item<S, L1, L2, L3, L4, L5>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const set: <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>, v: Item<S, L1, L2, L3, L4, L5>, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V]>;
@@ -1,4 +1,3 @@
1
1
  import { ComKey, Item, PriKey } from "@fjell/core";
2
- import { ClientApi } from "@fjell/client-api";
3
- import { CacheMap } from "../CacheMap";
4
- export declare const update: <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, key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, v: Partial<Item<S, L1, L2, L3, L4, L5>>) => Promise<[CacheMap<V, S, L1, L2, L3, L4, L5>, V]>;
2
+ import { CacheContext } from "../CacheContext";
3
+ export declare const update: <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>, v: Partial<Item<S, L1, L2, L3, L4, L5>>, context: CacheContext<V, S, L1, L2, L3, L4, L5>) => Promise<[CacheContext<V, S, L1, L2, L3, L4, L5>, V]>;
@@ -0,0 +1,100 @@
1
+ import { CacheItemMetadata, CacheMapMetadataProvider } from '../eviction/EvictionStrategy';
2
+ /**
3
+ * Configuration for TTL behavior
4
+ */
5
+ export interface TTLConfig {
6
+ /** Default TTL in milliseconds for all items */
7
+ defaultTTL?: number;
8
+ /** Whether to automatically clean up expired items */
9
+ autoCleanup?: boolean;
10
+ /** Interval for automatic cleanup in milliseconds */
11
+ cleanupInterval?: number;
12
+ /** Whether to validate TTL on access */
13
+ validateOnAccess?: boolean;
14
+ }
15
+ /**
16
+ * TTL-aware item wrapper that extends cache metadata
17
+ */
18
+ export interface TTLItemMetadata extends CacheItemMetadata {
19
+ /** Expiration timestamp (addedAt + TTL) */
20
+ expiresAt?: number;
21
+ /** TTL value used for this specific item */
22
+ ttl?: number;
23
+ }
24
+ /**
25
+ * Manages TTL (Time To Live) logic independently of CacheMap implementations.
26
+ * This allows any CacheMap to support TTL without implementing TTL-specific logic.
27
+ */
28
+ export declare class TTLManager {
29
+ private config;
30
+ private cleanupTimer?;
31
+ constructor(config?: TTLConfig);
32
+ /**
33
+ * Check if TTL is enabled
34
+ */
35
+ isTTLEnabled(): boolean;
36
+ /**
37
+ * Get the default TTL value
38
+ */
39
+ getDefaultTTL(): number | undefined;
40
+ /**
41
+ * Update TTL configuration
42
+ */
43
+ updateConfig(config: Partial<TTLConfig>): void;
44
+ /**
45
+ * Set TTL metadata for an item when it's added
46
+ */
47
+ onItemAdded(key: string, metadataProvider: CacheMapMetadataProvider, itemTTL?: number): void;
48
+ /**
49
+ * Check if an item has expired
50
+ */
51
+ isExpired(key: string, metadataProvider: CacheMapMetadataProvider): boolean;
52
+ /**
53
+ * Check if an item is valid (not expired) before returning it
54
+ * Returns true if item is valid, false if expired
55
+ */
56
+ validateItem(key: string, metadataProvider: CacheMapMetadataProvider): boolean;
57
+ /**
58
+ * Get TTL information for an item
59
+ */
60
+ getItemTTLInfo(key: string, metadataProvider: CacheMapMetadataProvider): {
61
+ hasTTL: boolean;
62
+ ttl?: number;
63
+ expiresAt?: number;
64
+ remainingTTL?: number;
65
+ isExpired: boolean;
66
+ };
67
+ /**
68
+ * Find all expired items
69
+ */
70
+ findExpiredItems(metadataProvider: CacheMapMetadataProvider): string[];
71
+ /**
72
+ * Manually clean up expired items
73
+ * Returns the keys of items that were expired
74
+ */
75
+ cleanupExpiredItems(metadataProvider: CacheMapMetadataProvider): string[];
76
+ /**
77
+ * Get remaining TTL for an item in milliseconds
78
+ */
79
+ getRemainingTTL(key: string, metadataProvider: CacheMapMetadataProvider): number | null;
80
+ /**
81
+ * Extend TTL for an item
82
+ */
83
+ extendTTL(key: string, metadataProvider: CacheMapMetadataProvider, additionalTTL: number): boolean;
84
+ /**
85
+ * Reset TTL for an item (refresh expiration)
86
+ */
87
+ refreshTTL(key: string, metadataProvider: CacheMapMetadataProvider, newTTL?: number): boolean;
88
+ /**
89
+ * Start automatic cleanup of expired items
90
+ */
91
+ private startAutoCleanup;
92
+ /**
93
+ * Stop automatic cleanup
94
+ */
95
+ private stopAutoCleanup;
96
+ /**
97
+ * Cleanup resources
98
+ */
99
+ destroy(): void;
100
+ }
@@ -0,0 +1,2 @@
1
+ export { TTLManager } from './TTLManager';
2
+ export type { TTLConfig, TTLItemMetadata } from './TTLManager';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Utility functions for parsing and managing cache sizes
3
+ */
4
+ /**
5
+ * Parse a size string and return the size in bytes
6
+ *
7
+ * @param sizeStr - Size string (e.g., '300', '3kb', '5MB', '2GiB')
8
+ * @returns Size in bytes
9
+ * @throws Error if the size string is invalid
10
+ */
11
+ export declare function parseSizeString(sizeStr: string): number;
12
+ /**
13
+ * Format bytes as a human-readable string
14
+ *
15
+ * @param bytes - Size in bytes
16
+ * @param binary - Use binary units (1024) instead of decimal (1000)
17
+ * @returns Formatted size string
18
+ */
19
+ export declare function formatBytes(bytes: number, binary?: boolean): string;
20
+ export declare function estimateValueSize(value: any): number;
21
+ /**
22
+ * Check if a size configuration is valid
23
+ *
24
+ * @param config - Size configuration to validate
25
+ * @throws Error if configuration is invalid
26
+ */
27
+ export declare function validateSizeConfig(config: {
28
+ maxSizeBytes?: string;
29
+ maxItems?: number;
30
+ }): void;
@@ -0,0 +1,116 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ // List of async methods that need await
5
+ const asyncMethods = [
6
+ 'get',
7
+ 'includesKey',
8
+ 'values',
9
+ 'allIn',
10
+ 'contains',
11
+ 'queryIn',
12
+ 'clone',
13
+ 'getQueryResult',
14
+ 'invalidateLocation'
15
+ ];
16
+
17
+ // Function to fix async calls in a file
18
+ function fixAsyncCalls(content) {
19
+ let updatedContent = content;
20
+
21
+ // First pass: Add await to all async method calls
22
+ asyncMethods.forEach(method => {
23
+ // Fix direct method calls that need await (but don't already have it)
24
+ // Match cache variable names (cache, locCache, containedCache, cacheMap, etc.) but avoid things like mockLocalStorage.store
25
+ const methodCallRegex = new RegExp(`(?<!await\\s)((cache|locCache|containedCache|cacheMap|cache1|cache2|complexCacheMap)\\s*\\.\\s*${method}\\s*\\([^)]*\\))`, 'g');
26
+ updatedContent = updatedContent.replace(methodCallRegex, (match, methodCall) => {
27
+ // Don't add await if it's already there
28
+ return `await ${methodCall}`;
29
+ });
30
+
31
+ // Fix method calls in expect statements
32
+ const expectRegex = new RegExp(`expect\\((?!await\\s)((cache|locCache|containedCache|cacheMap|cache1|cache2|complexCacheMap)\\s*\\.\\s*${method}\\s*\\([^)]*\\))\\)`, 'g');
33
+ updatedContent = updatedContent.replace(expectRegex, 'expect(await $1)');
34
+ });
35
+
36
+ // Second pass: Find all it() functions that contain await and make them async
37
+ const lines = updatedContent.split('\n');
38
+ const updatedLines = [];
39
+ let inTestFunction = false;
40
+ let testFunctionStart = -1;
41
+ let braceCount = 0;
42
+ let hasAwait = false;
43
+
44
+ for (let i = 0; i < lines.length; i++) {
45
+ const line = lines[i];
46
+
47
+ // Check if this line starts a test function
48
+ const testMatch = line.match(/(\s*)(it\s*\(\s*['"][^'"]*['"],\s*)(\(\)\s*=>\s*\{)/);
49
+ if (testMatch) {
50
+ inTestFunction = true;
51
+ testFunctionStart = i;
52
+ braceCount = 1;
53
+ hasAwait = false;
54
+ updatedLines.push(line);
55
+ continue;
56
+ }
57
+
58
+ if (inTestFunction) {
59
+ // Count braces to track when we're out of the test function
60
+ const openBraces = (line.match(/\{/g) || []).length;
61
+ const closeBraces = (line.match(/\}/g) || []).length;
62
+ braceCount += openBraces - closeBraces;
63
+
64
+ // Check if this line contains await
65
+ if (line.includes('await ')) {
66
+ hasAwait = true;
67
+ }
68
+
69
+ // If we've closed all braces, we're done with this test function
70
+ if (braceCount === 0) {
71
+ inTestFunction = false;
72
+
73
+ // If this test function contains await, make it async
74
+ if (hasAwait) {
75
+ const testLine = updatedLines[testFunctionStart];
76
+ const testMatch = testLine.match(/(\s*)(it\s*\(\s*['"][^'"]*['"],\s*)(\(\)\s*=>\s*\{)/);
77
+ if (testMatch && !testMatch[3].includes('async')) {
78
+ updatedLines[testFunctionStart] = testMatch[1] + testMatch[2] + 'async () => {';
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ updatedLines.push(line);
85
+ }
86
+
87
+ return updatedLines.join('\n');
88
+ }
89
+
90
+ // Process all browser cache test files
91
+ const testFiles = [
92
+ '/Users/tobrien/gitw/getfjell/fjell-cache/tests/browser/LocalStorageCacheMap.test.ts',
93
+ '/Users/tobrien/gitw/getfjell/fjell-cache/tests/browser/SessionStorageCacheMap.test.ts',
94
+ '/Users/tobrien/gitw/getfjell/fjell-cache/tests/browser/IndexDBCacheMap.test.ts',
95
+ '/Users/tobrien/gitw/getfjell/fjell-cache/tests/browser/AsyncIndexDBCacheMap.test.ts'
96
+ ];
97
+
98
+ testFiles.forEach(testFile => {
99
+ try {
100
+ if (fs.existsSync(testFile)) {
101
+ const content = fs.readFileSync(testFile, 'utf8');
102
+ const fixedContent = fixAsyncCalls(content);
103
+
104
+ if (content !== fixedContent) {
105
+ fs.writeFileSync(testFile, fixedContent, 'utf8');
106
+ console.log(`Fixed async calls in ${path.basename(testFile)}`);
107
+ } else {
108
+ console.log(`No changes needed in ${path.basename(testFile)}`);
109
+ }
110
+ } else {
111
+ console.log(`File not found: ${testFile}`);
112
+ }
113
+ } catch (error) {
114
+ console.error(`Error fixing file ${path.basename(testFile)}: ${error.message}`);
115
+ }
116
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fjell/cache",
3
3
  "description": "Cache for Fjell",
4
- "version": "4.6.22",
4
+ "version": "4.7.2",
5
5
  "keywords": [
6
6
  "cache",
7
7
  "fjell"
@@ -13,7 +13,8 @@
13
13
  "exports": {
14
14
  ".": {
15
15
  "types": "./dist/index.d.ts",
16
- "import": "./dist/index.js"
16
+ "import": "./dist/index.js",
17
+ "default": "./dist/index.js"
17
18
  }
18
19
  },
19
20
  "scripts": {
@@ -22,7 +23,7 @@
22
23
  "typecheck": "tsc --noEmit",
23
24
  "lint": "eslint . --ext .ts --fix",
24
25
  "clean": "rm -rf dist",
25
- "test": "npm run lint && vitest run --coverage",
26
+ "test": "vitest run --coverage",
26
27
  "prepublishOnly": "npm run clean && npm run build",
27
28
  "docs:dev": "cd docs && npm run dev",
28
29
  "docs:build": "cd docs && npm run build",
@@ -30,31 +31,33 @@
30
31
  "docs:test": "cd docs && npm run test"
31
32
  },
32
33
  "dependencies": {
33
- "@fjell/client-api": "^4.4.20",
34
+ "@fjell/client-api": "^4.4.22",
34
35
  "@fjell/core": "^4.4.29",
35
- "@fjell/http-api": "^4.4.26",
36
+ "@fjell/http-api": "^4.4.29",
36
37
  "@fjell/logging": "^4.4.36",
37
- "@fjell/registry": "^4.4.24"
38
+ "@fjell/registry": "^4.4.24",
39
+ "fast-safe-stringify": "^2.1.1",
40
+ "flatted": "^3.3.3"
38
41
  },
39
42
  "devDependencies": {
40
43
  "@eslint/eslintrc": "^3.3.1",
41
- "@eslint/js": "^9.32.0",
44
+ "@eslint/js": "^9.33.0",
42
45
  "@fjell/eslint-config": "^1.1.11",
43
- "@swc/core": "^1.13.2",
46
+ "@swc/core": "^1.13.3",
44
47
  "@tsconfig/recommended": "^1.0.10",
45
48
  "@types/multer": "^2.0.0",
46
- "@types/node": "^24.1.0",
47
- "@typescript-eslint/eslint-plugin": "^8.38.0",
48
- "@typescript-eslint/parser": "^8.38.0",
49
+ "@types/node": "^24.2.1",
50
+ "@typescript-eslint/eslint-plugin": "^8.39.0",
51
+ "@typescript-eslint/parser": "^8.39.0",
49
52
  "@vitest/coverage-v8": "^3.2.4",
50
53
  "@vitest/ui": "^3.2.4",
51
54
  "concurrently": "^9.2.0",
52
55
  "esbuild": "^0.25.8",
53
- "eslint": "^9.32.0",
56
+ "eslint": "^9.33.0",
54
57
  "nodemon": "^3.1.10",
55
58
  "ts-node": "^10.9.2",
56
59
  "tsc-alias": "^1.8.16",
57
- "typescript": "^5.8.3",
60
+ "typescript": "^5.9.2",
58
61
  "vitest": "^3.2.4"
59
62
  },
60
63
  "repository": {