@fjell/cache 4.7.35 → 4.7.37
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/dist/browser/SessionStorageCacheMap.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/package.json +19 -19
- package/CACHE_EVENTS.md +0 -306
- package/CACHE_IMPLEMENTATIONS.md +0 -315
- package/CONFIGURATION_GUIDE.md +0 -209
- package/CRITICAL_FIXES.md +0 -68
- package/MEMORY_LEAK_FIXES.md +0 -270
- package/MIGRATION_v3.md +0 -249
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionStorageCacheMap.d.ts","sourceRoot":"","sources":["../../src/browser/SessionStorageCacheMap.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SessionStorageCacheMap.d.ts","sourceRoot":"","sources":["../../src/browser/SessionStorageCacheMap.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -3016,7 +3016,7 @@ var SessionStorageCacheMap = class _SessionStorageCacheMap extends CacheMap {
|
|
|
3016
3016
|
if (!stored) continue;
|
|
3017
3017
|
try {
|
|
3018
3018
|
const parsed = JSON.parse(stored);
|
|
3019
|
-
if (parsed.originalKey) {
|
|
3019
|
+
if (parsed.originalKey && parsed.originalVerificationHash && this.verificationHashFunction(parsed.originalKey) === parsed.originalVerificationHash) {
|
|
3020
3020
|
keys.push(parsed.originalKey);
|
|
3021
3021
|
}
|
|
3022
3022
|
} catch (itemError) {
|
|
@@ -3037,7 +3037,7 @@ var SessionStorageCacheMap = class _SessionStorageCacheMap extends CacheMap {
|
|
|
3037
3037
|
if (!stored) continue;
|
|
3038
3038
|
try {
|
|
3039
3039
|
const parsed = JSON.parse(stored);
|
|
3040
|
-
if (parsed.value != null) {
|
|
3040
|
+
if (parsed.value != null && parsed.originalKey && parsed.originalVerificationHash && this.verificationHashFunction(parsed.originalKey) === parsed.originalVerificationHash) {
|
|
3041
3041
|
values.push(parsed.value);
|
|
3042
3042
|
}
|
|
3043
3043
|
} catch (itemError) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjell/cache",
|
|
3
3
|
"description": "Cache for Fjell",
|
|
4
|
-
"version": "4.7.
|
|
4
|
+
"version": "4.7.37",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cache",
|
|
7
7
|
"fjell"
|
|
@@ -37,35 +37,35 @@
|
|
|
37
37
|
"docs:test": "cd docs && npm run test"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@fjell/client-api": "^4.4.
|
|
41
|
-
"@fjell/core": "^4.4.
|
|
42
|
-
"@fjell/http-api": "^4.4.
|
|
43
|
-
"@fjell/logging": "^4.4.
|
|
44
|
-
"@fjell/registry": "^4.4.
|
|
40
|
+
"@fjell/client-api": "^4.4.48",
|
|
41
|
+
"@fjell/core": "^4.4.53",
|
|
42
|
+
"@fjell/http-api": "^4.4.45",
|
|
43
|
+
"@fjell/logging": "^4.4.52",
|
|
44
|
+
"@fjell/registry": "^4.4.55",
|
|
45
45
|
"fast-safe-stringify": "^2.1.1",
|
|
46
46
|
"flatted": "^3.3.3",
|
|
47
47
|
"yocto-queue": "^1.2.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@eslint/eslintrc": "^3.3.1",
|
|
51
|
-
"@eslint/js": "^9.
|
|
52
|
-
"@fjell/
|
|
53
|
-
"@swc/core": "^1.13.
|
|
51
|
+
"@eslint/js": "^9.38.0",
|
|
52
|
+
"@fjell/common-config": "^1.1.29",
|
|
53
|
+
"@swc/core": "^1.13.5",
|
|
54
54
|
"@tsconfig/recommended": "^1.0.10",
|
|
55
55
|
"@types/multer": "^2.0.0",
|
|
56
|
-
"@types/node": "^24.
|
|
57
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
58
|
-
"@typescript-eslint/parser": "^8.
|
|
59
|
-
"@vitest/coverage-v8": "^
|
|
60
|
-
"@vitest/ui": "^
|
|
61
|
-
"concurrently": "^9.2.
|
|
62
|
-
"esbuild": "0.25.
|
|
63
|
-
"eslint": "^9.
|
|
56
|
+
"@types/node": "^24.9.1",
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "^8.46.2",
|
|
58
|
+
"@typescript-eslint/parser": "^8.46.2",
|
|
59
|
+
"@vitest/coverage-v8": "^4.0.1",
|
|
60
|
+
"@vitest/ui": "^4.0.1",
|
|
61
|
+
"concurrently": "^9.2.1",
|
|
62
|
+
"esbuild": "0.25.11",
|
|
63
|
+
"eslint": "^9.38.0",
|
|
64
64
|
"nodemon": "^3.1.10",
|
|
65
65
|
"ts-node": "^10.9.2",
|
|
66
66
|
"tsc-alias": "^1.8.16",
|
|
67
|
-
"typescript": "^5.9.
|
|
68
|
-
"vitest": "^
|
|
67
|
+
"typescript": "^5.9.3",
|
|
68
|
+
"vitest": "^4.0.1"
|
|
69
69
|
},
|
|
70
70
|
"repository": {
|
|
71
71
|
"type": "git",
|
package/CACHE_EVENTS.md
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
# Cache Event System
|
|
2
|
-
|
|
3
|
-
The fjell-cache event system provides real-time notifications when cache operations occur. This enables reactive patterns where components can subscribe to cache changes and update automatically.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The event system is built into the core Cache interface and provides:
|
|
8
|
-
|
|
9
|
-
- **Event emission** for all cache operations (create, update, remove, query, etc.)
|
|
10
|
-
- **Subscription management** with filtering options
|
|
11
|
-
- **Event types** covering all cache state changes
|
|
12
|
-
- **Debouncing** support for high-frequency updates
|
|
13
|
-
- **Type safety** with full TypeScript support
|
|
14
|
-
|
|
15
|
-
## Basic Usage
|
|
16
|
-
|
|
17
|
-
### Subscribing to Events
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
import { createCache, CacheEventListener } from '@fjell/cache';
|
|
21
|
-
|
|
22
|
-
// Create cache
|
|
23
|
-
const cache = createCache(api, coordinate, registry);
|
|
24
|
-
|
|
25
|
-
// Subscribe to all events
|
|
26
|
-
const listener: CacheEventListener<MyItem, 'myType'> = (event) => {
|
|
27
|
-
console.log('Cache event:', event.type, event);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const subscription = cache.subscribe(listener);
|
|
31
|
-
|
|
32
|
-
// Later: unsubscribe
|
|
33
|
-
subscription.unsubscribe();
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Filtering Events
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
// Subscribe only to item creation events
|
|
40
|
-
const subscription = cache.subscribe(listener, {
|
|
41
|
-
eventTypes: ['item_created', 'item_updated']
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Subscribe only to events for specific keys
|
|
45
|
-
const subscription = cache.subscribe(listener, {
|
|
46
|
-
keys: [{ pk: 'user-123' }]
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// Subscribe only to events in specific locations
|
|
50
|
-
const subscription = cache.subscribe(listener, {
|
|
51
|
-
locations: [{ lk: 'container-1' }]
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// Subscribe with debouncing (useful for UI updates)
|
|
55
|
-
const subscription = cache.subscribe(listener, {
|
|
56
|
-
debounceMs: 100 // Debounce events by 100ms
|
|
57
|
-
});
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Event Types
|
|
61
|
-
|
|
62
|
-
### Item Events
|
|
63
|
-
|
|
64
|
-
These events are emitted when individual items are affected:
|
|
65
|
-
|
|
66
|
-
- **`item_created`** - Item was created via API and cached
|
|
67
|
-
- **`item_updated`** - Item was updated via API and cache updated
|
|
68
|
-
- **`item_removed`** - Item was removed via API and from cache
|
|
69
|
-
- **`item_retrieved`** - Item was retrieved from API and cached
|
|
70
|
-
- **`item_set`** - Item was set directly in cache (no API call)
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
interface ItemEvent<V, S, L1, L2, L3, L4, L5> {
|
|
74
|
-
type: 'item_created' | 'item_updated' | 'item_removed' | 'item_retrieved' | 'item_set';
|
|
75
|
-
key: ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>;
|
|
76
|
-
item: V | null; // null for removed items
|
|
77
|
-
previousItem?: V | null; // Previous state before change
|
|
78
|
-
affectedLocations?: LocKeyArray<L1, L2, L3, L4, L5> | [];
|
|
79
|
-
timestamp: number;
|
|
80
|
-
source: 'api' | 'cache' | 'operation';
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Query Events
|
|
85
|
-
|
|
86
|
-
These events are emitted when multiple items are queried:
|
|
87
|
-
|
|
88
|
-
- **`items_queried`** - Multiple items were queried and cached
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
interface QueryEvent<V, S, L1, L2, L3, L4, L5> {
|
|
92
|
-
type: 'items_queried';
|
|
93
|
-
query: ItemQuery;
|
|
94
|
-
locations: LocKeyArray<L1, L2, L3, L4, L5> | [];
|
|
95
|
-
items: V[];
|
|
96
|
-
affectedKeys: (ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>)[];
|
|
97
|
-
timestamp: number;
|
|
98
|
-
source: 'api' | 'cache' | 'operation';
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Cache Management Events
|
|
103
|
-
|
|
104
|
-
These events are emitted for cache-wide operations:
|
|
105
|
-
|
|
106
|
-
- **`cache_cleared`** - Entire cache was cleared
|
|
107
|
-
- **`location_invalidated`** - Specific location(s) were invalidated
|
|
108
|
-
- **`query_invalidated`** - Cached query results were invalidated
|
|
109
|
-
|
|
110
|
-
## Advanced Usage
|
|
111
|
-
|
|
112
|
-
### React Integration Example
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
import { useEffect, useState } from 'react';
|
|
116
|
-
import { Cache, CacheSubscription } from '@fjell/cache';
|
|
117
|
-
|
|
118
|
-
function useItem<T>(cache: Cache<T, any>, key: any): T | null {
|
|
119
|
-
const [item, setItem] = useState<T | null>(() =>
|
|
120
|
-
cache.cacheMap.get(key)
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
useEffect(() => {
|
|
124
|
-
const subscription = cache.subscribe((event) => {
|
|
125
|
-
if (event.type === 'item_changed' &&
|
|
126
|
-
JSON.stringify(event.key) === JSON.stringify(key)) {
|
|
127
|
-
setItem(event.item);
|
|
128
|
-
} else if (event.type === 'item_removed' &&
|
|
129
|
-
JSON.stringify(event.key) === JSON.stringify(key)) {
|
|
130
|
-
setItem(null);
|
|
131
|
-
}
|
|
132
|
-
}, {
|
|
133
|
-
keys: [key],
|
|
134
|
-
eventTypes: ['item_updated', 'item_removed', 'item_set']
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
return () => subscription.unsubscribe();
|
|
138
|
-
}, [cache, key]);
|
|
139
|
-
|
|
140
|
-
return item;
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Listening to Multiple Caches
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
class CacheEventHub {
|
|
148
|
-
private subscriptions: CacheSubscription[] = [];
|
|
149
|
-
|
|
150
|
-
subscribeTo<T>(cache: Cache<T, any>, listener: CacheEventListener<T, any>) {
|
|
151
|
-
const subscription = cache.subscribe(listener);
|
|
152
|
-
this.subscriptions.push(subscription);
|
|
153
|
-
return subscription;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
unsubscribeAll() {
|
|
157
|
-
this.subscriptions.forEach(sub => sub.unsubscribe());
|
|
158
|
-
this.subscriptions = [];
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const hub = new CacheEventHub();
|
|
163
|
-
|
|
164
|
-
// Subscribe to multiple caches
|
|
165
|
-
hub.subscribeTo(userCache, (event) => console.log('User event:', event));
|
|
166
|
-
hub.subscribeTo(orderCache, (event) => console.log('Order event:', event));
|
|
167
|
-
|
|
168
|
-
// Later: clean up all subscriptions
|
|
169
|
-
hub.unsubscribeAll();
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Event Logging and Debugging
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
// Log all cache events for debugging
|
|
176
|
-
const debugSubscription = cache.subscribe((event) => {
|
|
177
|
-
console.log(`[${new Date(event.timestamp).toISOString()}] ${event.type}:`, {
|
|
178
|
-
source: event.source,
|
|
179
|
-
...('key' in event ? { key: event.key } : {}),
|
|
180
|
-
...('query' in event ? { query: event.query } : {}),
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// Performance monitoring
|
|
185
|
-
let eventCounts = new Map<string, number>();
|
|
186
|
-
|
|
187
|
-
cache.subscribe((event) => {
|
|
188
|
-
const count = eventCounts.get(event.type) || 0;
|
|
189
|
-
eventCounts.set(event.type, count + 1);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
setInterval(() => {
|
|
193
|
-
console.log('Event counts:', Object.fromEntries(eventCounts));
|
|
194
|
-
eventCounts.clear();
|
|
195
|
-
}, 10000);
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Best Practices
|
|
199
|
-
|
|
200
|
-
### 1. Use Specific Event Filters
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
// Good: Filter by specific event types and keys
|
|
204
|
-
cache.subscribe(listener, {
|
|
205
|
-
eventTypes: ['item_updated'],
|
|
206
|
-
keys: [userKey]
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// Avoid: Subscribing to all events when you only need specific ones
|
|
210
|
-
cache.subscribe(listener); // Too broad
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### 2. Debounce High-Frequency Updates
|
|
214
|
-
|
|
215
|
-
```typescript
|
|
216
|
-
// Good: Debounce UI updates
|
|
217
|
-
cache.subscribe(updateUI, {
|
|
218
|
-
debounceMs: 100
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// Good: Don't debounce critical business logic
|
|
222
|
-
cache.subscribe(saveToDisk, {
|
|
223
|
-
// No debouncing for critical operations
|
|
224
|
-
});
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### 3. Clean Up Subscriptions
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
useEffect(() => {
|
|
231
|
-
const subscription = cache.subscribe(listener);
|
|
232
|
-
|
|
233
|
-
// Always clean up
|
|
234
|
-
return () => subscription.unsubscribe();
|
|
235
|
-
}, []);
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### 4. Handle Errors in Listeners
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
cache.subscribe((event) => {
|
|
242
|
-
try {
|
|
243
|
-
// Your event handling logic
|
|
244
|
-
handleEvent(event);
|
|
245
|
-
} catch (error) {
|
|
246
|
-
console.error('Error handling cache event:', error);
|
|
247
|
-
// Don't let errors break other listeners
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
## Event Sources
|
|
253
|
-
|
|
254
|
-
Events include a `source` field indicating where they originated:
|
|
255
|
-
|
|
256
|
-
- **`api`** - Event from API operation (create, update, remove, etc.)
|
|
257
|
-
- **`cache`** - Event from direct cache operation (set, invalidate)
|
|
258
|
-
- **`operation`** - Event from internal cache operation
|
|
259
|
-
|
|
260
|
-
## Performance Considerations
|
|
261
|
-
|
|
262
|
-
- **Subscription count**: Each subscription has minimal overhead, but avoid creating unnecessary subscriptions
|
|
263
|
-
- **Event frequency**: Use debouncing for high-frequency UI updates
|
|
264
|
-
- **Memory leaks**: Always unsubscribe when components unmount
|
|
265
|
-
- **Event filtering**: Use specific filters to reduce unnecessary event processing
|
|
266
|
-
|
|
267
|
-
## Error Handling
|
|
268
|
-
|
|
269
|
-
The event system is designed to be resilient:
|
|
270
|
-
|
|
271
|
-
- Listener errors don't affect other listeners or cache operations
|
|
272
|
-
- Failed subscriptions are automatically cleaned up
|
|
273
|
-
- Event emission continues even if some listeners fail
|
|
274
|
-
|
|
275
|
-
## Migration from Manual State Management
|
|
276
|
-
|
|
277
|
-
If you're currently using manual state management patterns:
|
|
278
|
-
|
|
279
|
-
```typescript
|
|
280
|
-
// Before: Manual state management
|
|
281
|
-
const [items, setItems] = useState([]);
|
|
282
|
-
|
|
283
|
-
const addItem = async (item) => {
|
|
284
|
-
const newItem = await cache.operations.create(item);
|
|
285
|
-
setItems(prev => [...prev, newItem]); // Manual update
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
// After: Event-driven updates
|
|
289
|
-
const [items, setItems] = useState([]);
|
|
290
|
-
|
|
291
|
-
useEffect(() => {
|
|
292
|
-
const subscription = cache.subscribe((event) => {
|
|
293
|
-
if (event.type === 'item_created') {
|
|
294
|
-
setItems(prev => [...prev, event.item]);
|
|
295
|
-
}
|
|
296
|
-
}, { eventTypes: ['item_created'] });
|
|
297
|
-
|
|
298
|
-
return () => subscription.unsubscribe();
|
|
299
|
-
}, []);
|
|
300
|
-
|
|
301
|
-
const addItem = async (item) => {
|
|
302
|
-
await cache.operations.create(item); // Event automatically updates state
|
|
303
|
-
};
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
This approach eliminates the need for manual state synchronization and ensures your UI always reflects the current cache state.
|