@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.
@@ -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.35",
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.46",
41
- "@fjell/core": "^4.4.50",
42
- "@fjell/http-api": "^4.4.42",
43
- "@fjell/logging": "^4.4.49",
44
- "@fjell/registry": "^4.4.52",
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.33.0",
52
- "@fjell/eslint-config": "^1.1.25",
53
- "@swc/core": "^1.13.3",
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.2.1",
57
- "@typescript-eslint/eslint-plugin": "^8.39.0",
58
- "@typescript-eslint/parser": "^8.39.0",
59
- "@vitest/coverage-v8": "^3.2.4",
60
- "@vitest/ui": "^3.2.4",
61
- "concurrently": "^9.2.0",
62
- "esbuild": "0.25.9",
63
- "eslint": "^9.33.0",
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.2",
68
- "vitest": "^3.2.4"
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.