@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.
- package/CACHE_EVENTS.md +306 -0
- package/CACHE_IMPLEMENTATIONS.md +315 -0
- package/CONFIGURATION_GUIDE.md +167 -0
- package/CRITICAL_FIXES.md +68 -0
- package/MEMORY_LEAK_FIXES.md +270 -0
- package/README.md +513 -2
- package/dist/Aggregator.d.ts +27 -16
- package/dist/Cache.d.ts +59 -1
- package/dist/CacheContext.d.ts +35 -0
- package/dist/CacheMap.d.ts +132 -14
- package/dist/CacheStats.d.ts +51 -0
- package/dist/Instance.d.ts +4 -2
- package/dist/InstanceFactory.d.ts +3 -2
- package/dist/Operations.d.ts +21 -17
- package/dist/Options.d.ts +98 -0
- package/dist/browser/AsyncIndexDBCacheMap.d.ts +38 -0
- package/dist/browser/IndexDBCacheMap.d.ts +69 -0
- package/dist/browser/LocalStorageCacheMap.d.ts +59 -0
- package/dist/browser/SessionStorageCacheMap.d.ts +51 -0
- package/dist/events/CacheEventEmitter.d.ts +82 -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 +142 -0
- package/dist/eviction/EvictionStrategyConfig.d.ts +97 -0
- package/dist/eviction/EvictionStrategyFactory.d.ts +12 -0
- package/dist/eviction/EvictionStrategyValidation.d.ts +36 -0
- package/dist/eviction/index.d.ts +10 -0
- package/dist/eviction/strategies/ARCEvictionStrategy.d.ts +73 -0
- package/dist/eviction/strategies/FIFOEvictionStrategy.d.ts +12 -0
- package/dist/eviction/strategies/LFUEvictionStrategy.d.ts +38 -0
- package/dist/eviction/strategies/LRUEvictionStrategy.d.ts +12 -0
- package/dist/eviction/strategies/MRUEvictionStrategy.d.ts +12 -0
- package/dist/eviction/strategies/RandomEvictionStrategy.d.ts +12 -0
- package/dist/eviction/strategies/TwoQueueEvictionStrategy.d.ts +54 -0
- package/dist/index.d.ts +29 -6
- package/dist/index.js +5764 -435
- package/dist/index.js.map +4 -4
- package/dist/memory/EnhancedMemoryCacheMap.d.ts +81 -0
- package/dist/memory/MemoryCacheMap.d.ts +48 -0
- package/dist/normalization.d.ts +19 -0
- package/dist/ops/action.d.ts +2 -3
- package/dist/ops/all.d.ts +2 -3
- package/dist/ops/allAction.d.ts +2 -3
- package/dist/ops/allFacet.d.ts +2 -3
- package/dist/ops/create.d.ts +2 -3
- package/dist/ops/facet.d.ts +2 -3
- package/dist/ops/find.d.ts +2 -3
- package/dist/ops/findOne.d.ts +2 -3
- package/dist/ops/get.d.ts +3 -3
- package/dist/ops/one.d.ts +2 -3
- package/dist/ops/remove.d.ts +2 -3
- package/dist/ops/reset.d.ts +2 -1
- package/dist/ops/retrieve.d.ts +2 -3
- package/dist/ops/set.d.ts +2 -2
- package/dist/ops/update.d.ts +2 -3
- package/dist/ttl/TTLManager.d.ts +100 -0
- package/dist/ttl/index.d.ts +2 -0
- package/dist/utils/CacheSize.d.ts +30 -0
- package/fix-async-tests.js +116 -0
- package/package.json +16 -13
package/README.md
CHANGED
|
@@ -9,11 +9,19 @@ Fjell Cache provides intelligent caching capabilities for complex data models an
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
11
|
- **Smart Caching**: Intelligent cache operations with automatic cache hits/misses
|
|
12
|
+
- **Multiple Cache Implementations**: In-memory, localStorage, sessionStorage, and IndexedDB support
|
|
13
|
+
- **Comprehensive Configuration**: Rich options system for performance tuning and environment optimization
|
|
12
14
|
- **Business Relationships**: Automatic population of related entities through aggregation
|
|
13
15
|
- **Performance Optimized**: High-performance cache operations with bulk processing
|
|
16
|
+
- **Environment Aware**: Automatic environment detection with fallback strategies
|
|
14
17
|
- **Location-Based**: Support for contained items with location hierarchies
|
|
18
|
+
- **Browser-Ready**: Native browser storage implementations for client-side caching
|
|
15
19
|
- **Framework Integration**: Seamless integration with Fjell Core, Registry, and Client API
|
|
16
20
|
- **TypeScript First**: Full TypeScript support with comprehensive type safety
|
|
21
|
+
- **Cache Size Limits**: Configure maximum cache size in bytes or item count with automatic eviction
|
|
22
|
+
- **Advanced Eviction Policies**: LRU, LFU, FIFO, MRU, Random, ARC, and 2Q strategies for optimal performance
|
|
23
|
+
- **Performance Monitoring**: Built-in cache statistics and utilization tracking
|
|
24
|
+
- **Cache Introspection**: Runtime visibility into cache implementation type, eviction policies, and capabilities
|
|
17
25
|
|
|
18
26
|
## Installation
|
|
19
27
|
|
|
@@ -28,7 +36,7 @@ yarn add @fjell/cache
|
|
|
28
36
|
## Quick Start
|
|
29
37
|
|
|
30
38
|
```typescript
|
|
31
|
-
import { createCache } from '@fjell/cache';
|
|
39
|
+
import { createCache, MemoryCacheMap } from '@fjell/cache';
|
|
32
40
|
import { createCoordinate, createRegistry } from '@fjell/registry';
|
|
33
41
|
import { ClientApi } from '@fjell/client-api';
|
|
34
42
|
|
|
@@ -45,6 +53,443 @@ const [, cachedUser] = await userCache.operations.get(userKey);
|
|
|
45
53
|
const [, retrievedUser] = await userCache.operations.retrieve(userKey); // Cache hit!
|
|
46
54
|
|
|
47
55
|
await userCache.operations.set(userKey, updatedUser);
|
|
56
|
+
|
|
57
|
+
// Or use cache implementations directly
|
|
58
|
+
const memoryCache = new MemoryCacheMap<User>(['user']);
|
|
59
|
+
memoryCache.set(userKey, user);
|
|
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}`);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Configuration Options
|
|
70
|
+
|
|
71
|
+
Fjell Cache provides comprehensive configuration options to optimize caching behavior for your specific environment and performance requirements.
|
|
72
|
+
|
|
73
|
+
### Basic Configuration
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { createInstanceFactory, createCache, Options } from '@fjell/cache';
|
|
77
|
+
|
|
78
|
+
// Configure cache with options
|
|
79
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
80
|
+
cacheType: 'memory',
|
|
81
|
+
enableDebugLogging: true,
|
|
82
|
+
autoSync: true,
|
|
83
|
+
maxRetries: 3,
|
|
84
|
+
retryDelay: 1000,
|
|
85
|
+
ttl: 300000 // 5 minutes
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Use with InstanceFactory (recommended)
|
|
89
|
+
const factory = createInstanceFactory(userApi, options);
|
|
90
|
+
const cache = factory(coordinate, { registry });
|
|
91
|
+
|
|
92
|
+
// Or directly with createCache
|
|
93
|
+
const cache = createCache(userApi, coordinate, registry, options);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Cache Types
|
|
97
|
+
|
|
98
|
+
#### Memory Cache (Default)
|
|
99
|
+
Fast in-memory caching with optional size limits, TTL, and advanced eviction policies:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
103
|
+
cacheType: 'memory',
|
|
104
|
+
memoryConfig: {
|
|
105
|
+
maxItems: 1000, // Maximum number of items to cache
|
|
106
|
+
ttl: 300000, // Time-to-live in milliseconds (5 minutes)
|
|
107
|
+
size: {
|
|
108
|
+
maxSizeBytes: '10MB', // Maximum cache size in bytes
|
|
109
|
+
maxItems: 1000, // Alternative/additional item limit
|
|
110
|
+
evictionPolicy: 'lru' // Eviction strategy when limits exceeded
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Browser localStorage (Persistent)
|
|
117
|
+
Persistent storage that survives page reloads and browser restarts:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
121
|
+
cacheType: 'localStorage',
|
|
122
|
+
webStorageConfig: {
|
|
123
|
+
keyPrefix: 'myapp:users:', // Namespace your cache keys
|
|
124
|
+
compress: false // Enable/disable compression
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Browser sessionStorage (Session-only)
|
|
130
|
+
Session-based storage that's cleared when the tab closes:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
134
|
+
cacheType: 'sessionStorage',
|
|
135
|
+
webStorageConfig: {
|
|
136
|
+
keyPrefix: 'session:users:',
|
|
137
|
+
compress: true // Compress data to save space
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### IndexedDB (Large-scale, Synchronous)
|
|
143
|
+
For large amounts of structured data with synchronous API:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
147
|
+
cacheType: 'indexedDB',
|
|
148
|
+
indexedDBConfig: {
|
|
149
|
+
dbName: 'MyAppCache', // Database name
|
|
150
|
+
version: 2, // Database version
|
|
151
|
+
storeName: 'users' // Object store name
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### IndexedDB (Large-scale, Asynchronous)
|
|
157
|
+
Recommended IndexedDB implementation with full async support:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
161
|
+
cacheType: 'indexedDB',
|
|
162
|
+
indexedDBConfig: {
|
|
163
|
+
dbName: 'MyAppCache',
|
|
164
|
+
version: 1,
|
|
165
|
+
storeName: 'userData'
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Access async operations via the asyncCache property
|
|
170
|
+
const cache = createCache(api, coordinate, options);
|
|
171
|
+
const asyncValue = await cache.cacheMap.asyncCache.get(key);
|
|
172
|
+
await cache.cacheMap.asyncCache.set(key, value);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### Custom Cache Implementation
|
|
176
|
+
Bring your own cache implementation:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { CacheMap } from '@fjell/cache';
|
|
180
|
+
|
|
181
|
+
const customCacheFactory = (kta) => {
|
|
182
|
+
// Return your custom CacheMap implementation
|
|
183
|
+
return new MyCustomCacheMap(kta);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
187
|
+
cacheType: 'custom',
|
|
188
|
+
customCacheMapFactory: customCacheFactory
|
|
189
|
+
};
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Cache Size Limits and Eviction Policies
|
|
193
|
+
|
|
194
|
+
Fjell Cache supports sophisticated cache size management with automatic eviction when limits are exceeded. You can configure both byte-based and item-count-based limits, along with various eviction strategies to optimize performance for your specific use case.
|
|
195
|
+
|
|
196
|
+
#### Size Configuration
|
|
197
|
+
|
|
198
|
+
Configure cache limits using flexible size formats:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
202
|
+
cacheType: 'memory',
|
|
203
|
+
memoryConfig: {
|
|
204
|
+
size: {
|
|
205
|
+
// Byte-based limits (decimal units)
|
|
206
|
+
maxSizeBytes: '10MB', // 10 megabytes
|
|
207
|
+
maxSizeBytes: '500KB', // 500 kilobytes
|
|
208
|
+
maxSizeBytes: '2GB', // 2 gigabytes
|
|
209
|
+
|
|
210
|
+
// Byte-based limits (binary units)
|
|
211
|
+
maxSizeBytes: '10MiB', // 10 mebibytes (1024^2)
|
|
212
|
+
maxSizeBytes: '500KiB', // 500 kibibytes (1024)
|
|
213
|
+
maxSizeBytes: '2GiB', // 2 gibibytes (1024^3)
|
|
214
|
+
|
|
215
|
+
// Raw bytes
|
|
216
|
+
maxSizeBytes: '1048576', // 1MB in bytes
|
|
217
|
+
|
|
218
|
+
// Item count limit
|
|
219
|
+
maxItems: 1000, // Maximum number of cached items
|
|
220
|
+
|
|
221
|
+
// Eviction policy (required when limits are set)
|
|
222
|
+
evictionPolicy: 'lru' // Strategy for removing items
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### Eviction Policies
|
|
229
|
+
|
|
230
|
+
Choose from several battle-tested eviction strategies:
|
|
231
|
+
|
|
232
|
+
##### LRU (Least Recently Used) - Default
|
|
233
|
+
Removes the item that was accessed longest ago. Best general-purpose strategy.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
237
|
+
cacheType: 'memory',
|
|
238
|
+
memoryConfig: {
|
|
239
|
+
size: {
|
|
240
|
+
maxItems: 1000,
|
|
241
|
+
evictionPolicy: 'lru' // Remove least recently accessed items
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
##### LFU (Least Frequently Used)
|
|
248
|
+
Removes the item with the lowest access count. Good for workloads with stable access patterns.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
252
|
+
cacheType: 'memory',
|
|
253
|
+
memoryConfig: {
|
|
254
|
+
size: {
|
|
255
|
+
maxItems: 1000,
|
|
256
|
+
evictionPolicy: 'lfu' // Remove least frequently accessed items
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
##### FIFO (First-In, First-Out)
|
|
263
|
+
Removes the oldest added item regardless of usage. Simple and predictable.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
267
|
+
cacheType: 'memory',
|
|
268
|
+
memoryConfig: {
|
|
269
|
+
size: {
|
|
270
|
+
maxItems: 1000,
|
|
271
|
+
evictionPolicy: 'fifo' // Remove oldest items first
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
##### MRU (Most Recently Used)
|
|
278
|
+
Removes the most recently accessed item. Useful for specific access patterns.
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
282
|
+
cacheType: 'memory',
|
|
283
|
+
memoryConfig: {
|
|
284
|
+
size: {
|
|
285
|
+
maxItems: 1000,
|
|
286
|
+
evictionPolicy: 'mru' // Remove most recently accessed items
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
##### Random Replacement
|
|
293
|
+
Evicts a random item. Fast and low-overhead for uniform workloads.
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
297
|
+
cacheType: 'memory',
|
|
298
|
+
memoryConfig: {
|
|
299
|
+
size: {
|
|
300
|
+
maxItems: 1000,
|
|
301
|
+
evictionPolicy: 'random' // Remove random items
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
##### ARC (Adaptive Replacement Cache)
|
|
308
|
+
Balances between recency (LRU) and frequency (LFU) dynamically. Adapts to workload patterns.
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
312
|
+
cacheType: 'memory',
|
|
313
|
+
memoryConfig: {
|
|
314
|
+
size: {
|
|
315
|
+
maxItems: 1000,
|
|
316
|
+
evictionPolicy: 'arc' // Adaptive replacement cache
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
##### 2Q (Two Queues)
|
|
323
|
+
Maintains separate queues for recent and frequently accessed items. Reduces cache pollution.
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
327
|
+
cacheType: 'memory',
|
|
328
|
+
memoryConfig: {
|
|
329
|
+
size: {
|
|
330
|
+
maxItems: 1000,
|
|
331
|
+
evictionPolicy: '2q' // Two-queue algorithm
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### Combined Size and Item Limits
|
|
338
|
+
|
|
339
|
+
You can specify both size and item limits. The cache will respect whichever limit is reached first:
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
343
|
+
cacheType: 'memory',
|
|
344
|
+
memoryConfig: {
|
|
345
|
+
size: {
|
|
346
|
+
maxSizeBytes: '50MB', // Size limit
|
|
347
|
+
maxItems: 10000, // Item count limit
|
|
348
|
+
evictionPolicy: 'lru' // Eviction strategy
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### Performance Monitoring
|
|
355
|
+
|
|
356
|
+
Monitor cache performance and utilization:
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
import { createCache, formatBytes } from '@fjell/cache';
|
|
360
|
+
|
|
361
|
+
const cache = createCache(/* ... */);
|
|
362
|
+
|
|
363
|
+
// Get cache statistics
|
|
364
|
+
const stats = cache.getStats();
|
|
365
|
+
console.log(`Items: ${stats.currentItemCount}/${stats.maxItems}`);
|
|
366
|
+
console.log(`Size: ${formatBytes(stats.currentSizeBytes)}/${formatBytes(stats.maxSizeBytes)}`);
|
|
367
|
+
console.log(`Item utilization: ${stats.utilizationPercent.items?.toFixed(1)}%`);
|
|
368
|
+
console.log(`Size utilization: ${stats.utilizationPercent.bytes?.toFixed(1)}%`);
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Performance and Reliability Options
|
|
372
|
+
|
|
373
|
+
Configure retry logic, synchronization, and debugging:
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
const options: Partial<Options<User, 'user'>> = {
|
|
377
|
+
// Retry configuration
|
|
378
|
+
maxRetries: 5, // Number of retry attempts
|
|
379
|
+
retryDelay: 2000, // Delay between retries (ms)
|
|
380
|
+
|
|
381
|
+
// Synchronization
|
|
382
|
+
autoSync: true, // Auto-sync with API
|
|
383
|
+
ttl: 600000, // Default expiration (10 minutes)
|
|
384
|
+
|
|
385
|
+
// Debugging
|
|
386
|
+
enableDebugLogging: true // Enable detailed debug logs
|
|
387
|
+
};
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Environment-based Configuration
|
|
391
|
+
|
|
392
|
+
Automatically adapt cache strategy based on environment:
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
const getOptimalCacheOptions = (): Partial<Options<User, 'user'>> => {
|
|
396
|
+
// Browser environment with IndexedDB support
|
|
397
|
+
if (typeof window !== 'undefined' && 'indexedDB' in window) {
|
|
398
|
+
return {
|
|
399
|
+
cacheType: 'indexedDB',
|
|
400
|
+
indexedDBConfig: {
|
|
401
|
+
dbName: 'MyAppCache',
|
|
402
|
+
version: 1,
|
|
403
|
+
storeName: 'users'
|
|
404
|
+
},
|
|
405
|
+
enableDebugLogging: false
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Browser environment with localStorage
|
|
410
|
+
if (typeof window !== 'undefined' && 'localStorage' in window) {
|
|
411
|
+
return {
|
|
412
|
+
cacheType: 'localStorage',
|
|
413
|
+
webStorageConfig: {
|
|
414
|
+
keyPrefix: 'myapp:',
|
|
415
|
+
compress: true
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Node.js or other environments - use memory
|
|
421
|
+
return {
|
|
422
|
+
cacheType: 'memory',
|
|
423
|
+
memoryConfig: {
|
|
424
|
+
maxItems: 5000,
|
|
425
|
+
ttl: 300000
|
|
426
|
+
},
|
|
427
|
+
enableDebugLogging: true
|
|
428
|
+
};
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
const factory = createInstanceFactory(userApi, getOptimalCacheOptions());
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Complete Options Reference
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
interface Options<V extends Item<S>, S extends string> {
|
|
438
|
+
// Cache type selection
|
|
439
|
+
cacheType: 'memory' | 'localStorage' | 'sessionStorage' |
|
|
440
|
+
'indexedDB' | 'custom';
|
|
441
|
+
|
|
442
|
+
// Memory cache configuration
|
|
443
|
+
memoryConfig?: {
|
|
444
|
+
maxItems?: number; // Maximum items to store
|
|
445
|
+
ttl?: number; // Time-to-live in milliseconds
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// Web storage configuration (localStorage/sessionStorage)
|
|
449
|
+
webStorageConfig?: {
|
|
450
|
+
keyPrefix?: string; // Key prefix for namespacing
|
|
451
|
+
compress?: boolean; // Enable compression
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// IndexedDB configuration
|
|
455
|
+
indexedDBConfig?: {
|
|
456
|
+
dbName?: string; // Database name
|
|
457
|
+
version?: number; // Database version
|
|
458
|
+
storeName?: string; // Object store name
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// Custom cache factory
|
|
462
|
+
customCacheMapFactory?: (kta: AllItemTypeArrays) => CacheMap;
|
|
463
|
+
|
|
464
|
+
// Performance and reliability
|
|
465
|
+
maxRetries?: number; // Retry attempts (default: 3)
|
|
466
|
+
retryDelay?: number; // Retry delay in ms (default: 1000)
|
|
467
|
+
autoSync?: boolean; // Auto-sync with API (default: true)
|
|
468
|
+
ttl?: number; // Default expiration in ms
|
|
469
|
+
enableDebugLogging?: boolean; // Debug logging (default: false)
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Validation and Error Handling
|
|
474
|
+
|
|
475
|
+
The Options system includes automatic validation:
|
|
476
|
+
|
|
477
|
+
- **Environment Checks**: Validates browser API availability
|
|
478
|
+
- **Configuration Validation**: Ensures required options are provided
|
|
479
|
+
- **Type Safety**: Full TypeScript support with compile-time checks
|
|
480
|
+
- **Runtime Errors**: Clear error messages for invalid configurations
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
// This will throw a clear error in Node.js environment:
|
|
484
|
+
const options = { cacheType: 'localStorage' as const };
|
|
485
|
+
// Error: localStorage is not available in non-browser environments
|
|
486
|
+
|
|
487
|
+
// This will throw an error:
|
|
488
|
+
const options = {
|
|
489
|
+
cacheType: 'custom' as const
|
|
490
|
+
// Missing: customCacheMapFactory
|
|
491
|
+
};
|
|
492
|
+
// Error: customCacheMapFactory is required when cacheType is "custom"
|
|
48
493
|
```
|
|
49
494
|
|
|
50
495
|
## Core Components
|
|
@@ -59,19 +504,84 @@ await userCache.operations.set(userKey, updatedUser);
|
|
|
59
504
|
- **Required vs Optional**: Flexible relationship management
|
|
60
505
|
- **Business Logic**: Complex business scenarios with interconnected data
|
|
61
506
|
|
|
507
|
+
### Cache Implementations
|
|
508
|
+
- **MemoryCacheMap**: Fast in-memory caching (default)
|
|
509
|
+
- **LocalStorageCacheMap**: Persistent browser caching with localStorage
|
|
510
|
+
- **SessionStorageCacheMap**: Session-based browser caching with sessionStorage
|
|
511
|
+
- **AsyncIndexDBCacheMap**: Large-scale browser caching with IndexedDB
|
|
512
|
+
- **IndexDBCacheMap**: Synchronous wrapper for IndexedDB (throws errors, use async version)
|
|
513
|
+
|
|
62
514
|
### Direct Cache Management
|
|
63
|
-
- **CacheMap**:
|
|
515
|
+
- **CacheMap Interface**: Abstract interface for all cache implementations
|
|
64
516
|
- **Location Filtering**: Filter contained items by location hierarchy
|
|
65
517
|
- **Bulk Operations**: Efficient processing of multiple cache operations
|
|
518
|
+
- **Key Normalization**: Consistent string/number key handling across implementations
|
|
66
519
|
|
|
67
520
|
## Examples
|
|
68
521
|
|
|
69
522
|
Comprehensive examples are available in the [examples directory](./examples/):
|
|
70
523
|
|
|
71
524
|
- **[Basic Cache Example](./examples/basic-cache-example.ts)** - Start here! Fundamental caching operations
|
|
525
|
+
- **[Cache Configuration Example](./examples/cache-configuration-example.ts)** - Complete guide to cache options and configuration
|
|
526
|
+
- **[Cache Type Configurations Example](./examples/cache-type-configurations-example.ts)** - Practical setup for Memory, IndexedDB, and localStorage
|
|
72
527
|
- **[Aggregator Example](./examples/aggregator-example.ts)** - Advanced business relationships
|
|
73
528
|
- **[Cache Map Example](./examples/cache-map-example.ts)** - Low-level cache operations
|
|
74
529
|
|
|
530
|
+
## Browser Cache Implementations
|
|
531
|
+
|
|
532
|
+
Fjell Cache provides multiple cache implementations optimized for different environments:
|
|
533
|
+
|
|
534
|
+
### In-Memory Caching (Default)
|
|
535
|
+
```typescript
|
|
536
|
+
import { MemoryCacheMap } from '@fjell/cache';
|
|
537
|
+
|
|
538
|
+
const cache = new MemoryCacheMap<MyItem>(['myitem']);
|
|
539
|
+
cache.set(key, item);
|
|
540
|
+
const item = cache.get(key);
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Browser localStorage (Persistent)
|
|
544
|
+
```typescript
|
|
545
|
+
import { LocalStorageCacheMap } from '@fjell/cache';
|
|
546
|
+
|
|
547
|
+
// Survives page reloads and browser restarts
|
|
548
|
+
const cache = new LocalStorageCacheMap<MyItem>(['myitem'], 'my-app-cache');
|
|
549
|
+
cache.set(key, item);
|
|
550
|
+
const item = cache.get(key); // Retrieved from localStorage
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Browser sessionStorage (Session-only)
|
|
554
|
+
```typescript
|
|
555
|
+
import { SessionStorageCacheMap } from '@fjell/cache';
|
|
556
|
+
|
|
557
|
+
// Lost when tab is closed
|
|
558
|
+
const cache = new SessionStorageCacheMap<MyItem>(['myitem'], 'session-cache');
|
|
559
|
+
cache.set(key, item);
|
|
560
|
+
const item = cache.get(key); // Retrieved from sessionStorage
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### IndexedDB (Large-scale, Asynchronous)
|
|
564
|
+
```typescript
|
|
565
|
+
import { AsyncIndexDBCacheMap } from '@fjell/cache';
|
|
566
|
+
|
|
567
|
+
// For large amounts of structured data
|
|
568
|
+
const cache = new AsyncIndexDBCacheMap<MyItem>(['myitem'], 'MyAppDB', 'items', 1);
|
|
569
|
+
|
|
570
|
+
// All operations are async
|
|
571
|
+
await cache.set(key, item);
|
|
572
|
+
const item = await cache.get(key);
|
|
573
|
+
const allItems = await cache.values();
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Cache Implementation Comparison
|
|
577
|
+
|
|
578
|
+
| Implementation | Storage | Persistence | Size Limit | Sync/Async | Use Case |
|
|
579
|
+
|---|---|---|---|---|---|
|
|
580
|
+
| MemoryCacheMap | Memory | None | RAM | Sync | Default, fast access |
|
|
581
|
+
| LocalStorageCacheMap | localStorage | Permanent | ~5-10MB | Sync | User preferences, settings |
|
|
582
|
+
| SessionStorageCacheMap | sessionStorage | Session only | ~5MB | Sync | Temporary session data |
|
|
583
|
+
| AsyncIndexDBCacheMap | IndexedDB | Permanent | Hundreds of MB+ | Async | Large datasets, offline apps |
|
|
584
|
+
|
|
75
585
|
## Documentation
|
|
76
586
|
|
|
77
587
|
For detailed documentation, examples, and API reference, visit our [documentation site](https://getfjell.github.io/fjell-cache/).
|
|
@@ -94,3 +604,4 @@ Apache-2.0
|
|
|
94
604
|
We welcome contributions! Please see our contributing guidelines for more information.
|
|
95
605
|
|
|
96
606
|
Built with love by the Fjell team.
|
|
607
|
+
# Test fix for sendit config bug
|
package/dist/Aggregator.d.ts
CHANGED
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
import { ComKey, Item, ItemQuery, LocKeyArray, PriKey } from "@fjell/core";
|
|
2
2
|
import { Cache } from "./Cache";
|
|
3
|
-
import {
|
|
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<
|
|
6
|
-
one: (query?: ItemQuery, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<
|
|
7
|
-
action: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, action: string, body?: any) => Promise<
|
|
8
|
-
allAction: (action: string, body?: any, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<
|
|
9
|
-
allFacet: (facet: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<
|
|
10
|
-
create: (item: Partial<Item<S, L1, L2, L3, L4, L5>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<
|
|
11
|
-
get: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<
|
|
12
|
-
retrieve: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<
|
|
13
|
-
remove: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>) => Promise<
|
|
14
|
-
update: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Partial<Item<S, L1, L2, L3, L4, L5>>) => Promise<
|
|
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<
|
|
16
|
-
find: (finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<
|
|
17
|
-
findOne: (finder: string, params?: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations?: LocKeyArray<L1, L2, L3, L4, L5> | []) => Promise<
|
|
18
|
-
set: (key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>, item: Item<S, L1, L2, L3, L4, L5>) => Promise<
|
|
19
|
-
reset: () => Promise<
|
|
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
|
@@ -3,6 +3,27 @@ import { Instance as BaseInstance, Coordinate, Registry } from "@fjell/registry"
|
|
|
3
3
|
import { ClientApi } from "@fjell/client-api";
|
|
4
4
|
import { CacheMap } from "./CacheMap";
|
|
5
5
|
import { Operations } from "./Operations";
|
|
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
|
+
}
|
|
6
27
|
/**
|
|
7
28
|
* The Cache interface extends the base Instance from @fjell/registry and adds cache operations
|
|
8
29
|
* for interacting with cached data.
|
|
@@ -23,6 +44,43 @@ export interface Cache<V extends Item<S, L1, L2, L3, L4, L5>, S extends string,
|
|
|
23
44
|
cacheMap: CacheMap<V, S, L1, L2, L3, L4, L5>;
|
|
24
45
|
/** All cache operations that work with both cache and API */
|
|
25
46
|
operations: Operations<V, S, L1, L2, L3, L4, L5>;
|
|
47
|
+
/** Cache configuration options */
|
|
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;
|
|
26
84
|
}
|
|
27
|
-
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) => Cache<V, S, L1, L2, L3, L4, L5>;
|
|
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>;
|
|
28
86
|
export declare const isCache: (cache: any) => cache is Cache<any, any, any, any, any, any, any>;
|