@umituz/react-native-design-system 2.8.7 → 2.8.8
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/package.json +5 -6
- package/src/device/infrastructure/repositories/LegacyDeviceIdRepository.ts +1 -1
- package/src/device/infrastructure/services/DeviceFeatureService.ts +1 -1
- package/src/exception/infrastructure/services/ExceptionLogger.ts +1 -1
- package/src/exception/infrastructure/storage/ExceptionStore.ts +1 -1
- package/src/exports/filesystem.ts +1 -0
- package/src/exports/storage.ts +1 -0
- package/src/filesystem/domain/constants/FileConstants.ts +20 -0
- package/src/filesystem/domain/entities/File.ts +20 -0
- package/src/filesystem/domain/types/FileTypes.ts +43 -0
- package/src/filesystem/domain/utils/FileUtils.ts +86 -0
- package/src/filesystem/index.ts +23 -0
- package/src/filesystem/infrastructure/services/FileSystemService.ts +45 -0
- package/src/filesystem/infrastructure/services/cache.service.ts +48 -0
- package/src/filesystem/infrastructure/services/directory.service.ts +66 -0
- package/src/filesystem/infrastructure/services/download.constants.ts +6 -0
- package/src/filesystem/infrastructure/services/download.service.ts +74 -0
- package/src/filesystem/infrastructure/services/download.types.ts +7 -0
- package/src/filesystem/infrastructure/services/encoding.service.ts +25 -0
- package/src/filesystem/infrastructure/services/file-info.service.ts +52 -0
- package/src/filesystem/infrastructure/services/file-manager.service.ts +81 -0
- package/src/filesystem/infrastructure/services/file-path.service.ts +22 -0
- package/src/filesystem/infrastructure/services/file-reader.service.ts +52 -0
- package/src/filesystem/infrastructure/services/file-writer.service.ts +32 -0
- package/src/filesystem/infrastructure/utils/blob.utils.ts +20 -0
- package/src/image/infrastructure/services/ImageStorageService.ts +1 -1
- package/src/index.ts +9 -0
- package/src/molecules/alerts/AlertStore.ts +1 -1
- package/src/molecules/calendar/infrastructure/storage/EventActions.ts +1 -1
- package/src/molecules/calendar/infrastructure/stores/storageAdapter.ts +1 -1
- package/src/offline/infrastructure/storage/OfflineStore.ts +1 -1
- package/src/onboarding/infrastructure/storage/OnboardingStore.ts +2 -2
- package/src/onboarding/infrastructure/storage/__tests__/OnboardingStore.test.ts +1 -1
- package/src/onboarding/infrastructure/storage/actions/answerActions.ts +1 -1
- package/src/onboarding/infrastructure/storage/actions/storageHelpers.ts +1 -1
- package/src/storage/README.md +185 -0
- package/src/storage/__tests__/integration.test.ts +391 -0
- package/src/storage/__tests__/mocks/asyncStorage.mock.ts +52 -0
- package/src/storage/__tests__/performance.test.tsx +352 -0
- package/src/storage/__tests__/setup.ts +63 -0
- package/src/storage/application/README.md +158 -0
- package/src/storage/application/ports/IStorageRepository.ts +61 -0
- package/src/storage/application/ports/README.md +127 -0
- package/src/storage/cache/README.md +154 -0
- package/src/storage/cache/__tests__/PerformanceAndMemory.test.ts +387 -0
- package/src/storage/cache/__tests__/setup.ts +19 -0
- package/src/storage/cache/domain/Cache.ts +146 -0
- package/src/storage/cache/domain/CacheManager.md +83 -0
- package/src/storage/cache/domain/CacheManager.ts +48 -0
- package/src/storage/cache/domain/CacheStatsTracker.md +169 -0
- package/src/storage/cache/domain/CacheStatsTracker.ts +49 -0
- package/src/storage/cache/domain/CachedValue.md +97 -0
- package/src/storage/cache/domain/ErrorHandler.md +99 -0
- package/src/storage/cache/domain/ErrorHandler.ts +42 -0
- package/src/storage/cache/domain/PatternMatcher.md +122 -0
- package/src/storage/cache/domain/PatternMatcher.ts +30 -0
- package/src/storage/cache/domain/README.md +118 -0
- package/src/storage/cache/domain/__tests__/Cache.test.ts +293 -0
- package/src/storage/cache/domain/__tests__/CacheManager.test.ts +276 -0
- package/src/storage/cache/domain/__tests__/ErrorHandler.test.ts +303 -0
- package/src/storage/cache/domain/__tests__/PatternMatcher.test.ts +261 -0
- package/src/storage/cache/domain/strategies/EvictionStrategy.ts +9 -0
- package/src/storage/cache/domain/strategies/FIFOStrategy.ts +12 -0
- package/src/storage/cache/domain/strategies/LFUStrategy.ts +22 -0
- package/src/storage/cache/domain/strategies/LRUStrategy.ts +22 -0
- package/src/storage/cache/domain/strategies/README.md +117 -0
- package/src/storage/cache/domain/strategies/TTLStrategy.ts +23 -0
- package/src/storage/cache/domain/strategies/__tests__/EvictionStrategies.test.ts +293 -0
- package/src/storage/cache/domain/types/Cache.ts +28 -0
- package/src/storage/cache/domain/types/README.md +107 -0
- package/src/storage/cache/index.ts +28 -0
- package/src/storage/cache/infrastructure/README.md +126 -0
- package/src/storage/cache/infrastructure/TTLCache.ts +103 -0
- package/src/storage/cache/infrastructure/__tests__/TTLCache.test.ts +303 -0
- package/src/storage/cache/presentation/README.md +123 -0
- package/src/storage/cache/presentation/__tests__/ReactHooks.test.ts +514 -0
- package/src/storage/cache/presentation/useCache.ts +76 -0
- package/src/storage/cache/presentation/useCachedValue.ts +88 -0
- package/src/storage/cache/types.d.ts +3 -0
- package/src/storage/domain/README.md +128 -0
- package/src/storage/domain/constants/CacheDefaults.ts +64 -0
- package/src/storage/domain/constants/README.md +105 -0
- package/src/storage/domain/entities/CachedValue.ts +86 -0
- package/src/storage/domain/entities/README.md +109 -0
- package/src/storage/domain/entities/StorageResult.ts +75 -0
- package/src/storage/domain/entities/__tests__/CachedValue.test.ts +149 -0
- package/src/storage/domain/entities/__tests__/StorageResult.test.ts +122 -0
- package/src/storage/domain/errors/README.md +126 -0
- package/src/storage/domain/errors/StorageError.ts +81 -0
- package/src/storage/domain/errors/__tests__/StorageError.test.ts +127 -0
- package/src/storage/domain/factories/README.md +138 -0
- package/src/storage/domain/factories/StoreFactory.ts +59 -0
- package/src/storage/domain/types/README.md +522 -0
- package/src/storage/domain/types/Store.ts +44 -0
- package/src/storage/domain/utils/CacheKeyGenerator.ts +66 -0
- package/src/storage/domain/utils/README.md +127 -0
- package/src/storage/domain/utils/__tests__/devUtils.test.ts +97 -0
- package/src/storage/domain/utils/devUtils.ts +37 -0
- package/src/storage/domain/value-objects/README.md +120 -0
- package/src/storage/domain/value-objects/StorageKey.ts +60 -0
- package/src/storage/index.ts +175 -0
- package/src/storage/infrastructure/README.md +165 -0
- package/src/storage/infrastructure/adapters/README.md +175 -0
- package/src/storage/infrastructure/adapters/StorageService.md +103 -0
- package/src/storage/infrastructure/adapters/StorageService.ts +49 -0
- package/src/storage/infrastructure/repositories/AsyncStorageRepository.ts +98 -0
- package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +100 -0
- package/src/storage/infrastructure/repositories/BatchStorageOperations.ts +42 -0
- package/src/storage/infrastructure/repositories/README.md +121 -0
- package/src/storage/infrastructure/repositories/StringStorageOperations.ts +44 -0
- package/src/storage/infrastructure/repositories/__tests__/AsyncStorageRepository.test.ts +170 -0
- package/src/storage/infrastructure/repositories/__tests__/BaseStorageOperations.test.ts +201 -0
- package/src/storage/presentation/README.md +181 -0
- package/src/storage/presentation/hooks/CacheStorageOperations.ts +94 -0
- package/src/storage/presentation/hooks/README.md +128 -0
- package/src/storage/presentation/hooks/__tests__/usePersistentCache.test.ts +405 -0
- package/src/storage/presentation/hooks/__tests__/useStorage.test.ts +247 -0
- package/src/storage/presentation/hooks/__tests__/useStorageState.test.ts +293 -0
- package/src/storage/presentation/hooks/useCacheState.ts +53 -0
- package/src/storage/presentation/hooks/usePersistentCache.ts +154 -0
- package/src/storage/presentation/hooks/useStorage.ts +102 -0
- package/src/storage/presentation/hooks/useStorageState.ts +71 -0
- package/src/storage/presentation/hooks/useStore.ts +15 -0
- package/src/storage/types/README.md +103 -0
- package/src/theme/infrastructure/globalThemeStore.ts +1 -1
- package/src/theme/infrastructure/storage/ThemeStorage.ts +1 -1
- package/src/theme/infrastructure/stores/themeStore.ts +1 -1
- package/src/utilities/sharing/infrastructure/services/SharingService.ts +1 -1
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTLCache Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { TTLCache } from '../TTLCache';
|
|
6
|
+
import type { CacheConfig } from '../domain/types/Cache';
|
|
7
|
+
|
|
8
|
+
describe('TTLCache', () => {
|
|
9
|
+
let cache: TTLCache<string>;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
jest.useFakeTimers();
|
|
13
|
+
cache = new TTLCache<string>({
|
|
14
|
+
maxSize: 5,
|
|
15
|
+
defaultTTL: 1000,
|
|
16
|
+
cleanupIntervalMs: 500
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
jest.useRealTimers();
|
|
22
|
+
cache.destroy();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('Basic Functionality', () => {
|
|
26
|
+
test('should inherit from Cache', () => {
|
|
27
|
+
expect(cache).toHaveProperty('set');
|
|
28
|
+
expect(cache).toHaveProperty('get');
|
|
29
|
+
expect(cache).toHaveProperty('has');
|
|
30
|
+
expect(cache).toHaveProperty('delete');
|
|
31
|
+
expect(cache).toHaveProperty('clear');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should set and get values', () => {
|
|
35
|
+
cache.set('key1', 'value1');
|
|
36
|
+
expect(cache.get('key1')).toBe('value1');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should use default TTL', () => {
|
|
40
|
+
cache.set('key1', 'value1');
|
|
41
|
+
expect(cache.get('key1')).toBe('value1');
|
|
42
|
+
|
|
43
|
+
jest.advanceTimersByTime(1001);
|
|
44
|
+
expect(cache.get('key1')).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should use custom TTL', () => {
|
|
48
|
+
cache.set('key1', 'value1', 2000);
|
|
49
|
+
expect(cache.get('key1')).toBe('value1');
|
|
50
|
+
|
|
51
|
+
jest.advanceTimersByTime(1001);
|
|
52
|
+
expect(cache.get('key1')).toBe('value1'); // Should still exist
|
|
53
|
+
|
|
54
|
+
jest.advanceTimersByTime(1000);
|
|
55
|
+
expect(cache.get('key1')).toBeUndefined(); // Should be expired
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('Automatic Cleanup', () => {
|
|
60
|
+
test('should start cleanup interval on creation', () => {
|
|
61
|
+
const setIntervalSpy = jest.spyOn(global, 'setInterval');
|
|
62
|
+
new TTLCache<string>({ cleanupIntervalMs: 1000 });
|
|
63
|
+
|
|
64
|
+
expect(setIntervalSpy).toHaveBeenCalledWith(expect.any(Function), 1000);
|
|
65
|
+
setIntervalSpy.mockRestore();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should cleanup expired entries automatically', () => {
|
|
69
|
+
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
70
|
+
|
|
71
|
+
cache.set('key1', 'value1', 500);
|
|
72
|
+
cache.set('key2', 'value2', 1500);
|
|
73
|
+
|
|
74
|
+
// Fast forward to trigger first cleanup
|
|
75
|
+
jest.advanceTimersByTime(500);
|
|
76
|
+
|
|
77
|
+
// key1 should be cleaned up, key2 should remain
|
|
78
|
+
expect(cache.get('key1')).toBeUndefined();
|
|
79
|
+
expect(cache.get('key2')).toBe('value2');
|
|
80
|
+
|
|
81
|
+
expect(consoleSpy).toHaveBeenCalledWith('TTLCache: Cleaned up 1 expired entries');
|
|
82
|
+
|
|
83
|
+
consoleSpy.mockRestore();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('should not log when no entries are cleaned up', () => {
|
|
87
|
+
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
88
|
+
|
|
89
|
+
cache.set('key1', 'value1', 2000);
|
|
90
|
+
|
|
91
|
+
// Fast forward, but no entries should be expired yet
|
|
92
|
+
jest.advanceTimersByTime(500);
|
|
93
|
+
|
|
94
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
95
|
+
|
|
96
|
+
consoleSpy.mockRestore();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('should handle multiple cleanup cycles', () => {
|
|
100
|
+
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
101
|
+
|
|
102
|
+
cache.set('key1', 'value1', 300);
|
|
103
|
+
cache.set('key2', 'value2', 800);
|
|
104
|
+
cache.set('key3', 'value3', 1300);
|
|
105
|
+
|
|
106
|
+
// First cleanup - key1 expires
|
|
107
|
+
jest.advanceTimersByTime(500);
|
|
108
|
+
expect(cache.get('key1')).toBeUndefined();
|
|
109
|
+
expect(cache.get('key2')).toBe('value2');
|
|
110
|
+
expect(cache.get('key3')).toBe('value3');
|
|
111
|
+
|
|
112
|
+
// Second cleanup - key2 expires
|
|
113
|
+
jest.advanceTimersByTime(500);
|
|
114
|
+
expect(cache.get('key2')).toBeUndefined();
|
|
115
|
+
expect(cache.get('key3')).toBe('value3');
|
|
116
|
+
|
|
117
|
+
// Third cleanup - key3 expires
|
|
118
|
+
jest.advanceTimersByTime(500);
|
|
119
|
+
expect(cache.get('key3')).toBeUndefined();
|
|
120
|
+
|
|
121
|
+
expect(consoleSpy).toHaveBeenCalledTimes(3);
|
|
122
|
+
|
|
123
|
+
consoleSpy.mockRestore();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('Destroy Method', () => {
|
|
128
|
+
test('should clear cleanup interval on destroy', () => {
|
|
129
|
+
const clearIntervalSpy = jest.spyOn(global, 'clearInterval');
|
|
130
|
+
|
|
131
|
+
cache.destroy();
|
|
132
|
+
|
|
133
|
+
expect(clearIntervalSpy).toHaveBeenCalled();
|
|
134
|
+
clearIntervalSpy.mockRestore();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('should clear all data on destroy', () => {
|
|
138
|
+
cache.set('key1', 'value1');
|
|
139
|
+
cache.set('key2', 'value2');
|
|
140
|
+
|
|
141
|
+
expect(cache.getStats().size).toBe(2);
|
|
142
|
+
|
|
143
|
+
cache.destroy();
|
|
144
|
+
|
|
145
|
+
expect(cache.getStats().size).toBe(0);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('should handle multiple destroy calls', () => {
|
|
149
|
+
const clearIntervalSpy = jest.spyOn(global, 'clearInterval');
|
|
150
|
+
|
|
151
|
+
cache.destroy();
|
|
152
|
+
cache.destroy();
|
|
153
|
+
cache.destroy();
|
|
154
|
+
|
|
155
|
+
// Should only call clearInterval once
|
|
156
|
+
expect(clearIntervalSpy).toHaveBeenCalledTimes(1);
|
|
157
|
+
|
|
158
|
+
clearIntervalSpy.mockRestore();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('should not cleanup after destroy', () => {
|
|
162
|
+
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
163
|
+
|
|
164
|
+
cache.set('key1', 'value1', 300);
|
|
165
|
+
|
|
166
|
+
cache.destroy();
|
|
167
|
+
|
|
168
|
+
// Advance time - should not trigger cleanup
|
|
169
|
+
jest.advanceTimersByTime(1000);
|
|
170
|
+
|
|
171
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
172
|
+
|
|
173
|
+
consoleSpy.mockRestore();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe('Destroyed State Handling', () => {
|
|
178
|
+
beforeEach(() => {
|
|
179
|
+
cache.destroy();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('should warn on set after destroy', () => {
|
|
183
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
184
|
+
|
|
185
|
+
cache.set('key1', 'value1');
|
|
186
|
+
|
|
187
|
+
expect(consoleSpy).toHaveBeenCalledWith('TTLCache: Attempted to set value on destroyed cache');
|
|
188
|
+
expect(cache.get('key1')).toBeUndefined();
|
|
189
|
+
|
|
190
|
+
consoleSpy.mockRestore();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test('should warn on get after destroy', () => {
|
|
194
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
195
|
+
|
|
196
|
+
const result = cache.get('key1');
|
|
197
|
+
|
|
198
|
+
expect(consoleSpy).toHaveBeenCalledWith('TTLCache: Attempted to get value from destroyed cache');
|
|
199
|
+
expect(result).toBeUndefined();
|
|
200
|
+
|
|
201
|
+
consoleSpy.mockRestore();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('should return false for has after destroy', () => {
|
|
205
|
+
expect(cache.has('key1')).toBe(false);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('should return false for delete after destroy', () => {
|
|
209
|
+
expect(cache.delete('key1')).toBe(false);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test('should not throw on clear after destroy', () => {
|
|
213
|
+
expect(() => cache.clear()).not.toThrow();
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe('Configuration', () => {
|
|
218
|
+
test('should use custom cleanup interval', () => {
|
|
219
|
+
const setIntervalSpy = jest.spyOn(global, 'setInterval');
|
|
220
|
+
|
|
221
|
+
new TTLCache<string>({ cleanupIntervalMs: 2000 });
|
|
222
|
+
|
|
223
|
+
expect(setIntervalSpy).toHaveBeenCalledWith(expect.any(Function), 2000);
|
|
224
|
+
setIntervalSpy.mockRestore();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('should use default cleanup interval when not specified', () => {
|
|
228
|
+
const setIntervalSpy = jest.spyOn(global, 'setInterval');
|
|
229
|
+
|
|
230
|
+
new TTLCache<string>();
|
|
231
|
+
|
|
232
|
+
expect(setIntervalSpy).toHaveBeenCalledWith(expect.any(Function), 60000);
|
|
233
|
+
setIntervalSpy.mockRestore();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('should pass configuration to parent Cache', () => {
|
|
237
|
+
const config: CacheConfig = {
|
|
238
|
+
maxSize: 10,
|
|
239
|
+
defaultTTL: 5000,
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const customCache = new TTLCache<string>(config);
|
|
243
|
+
|
|
244
|
+
customCache.set('key1', 'value1');
|
|
245
|
+
expect(customCache.get('key1')).toBe('value1');
|
|
246
|
+
|
|
247
|
+
// Should use custom default TTL
|
|
248
|
+
jest.advanceTimersByTime(5001);
|
|
249
|
+
expect(customCache.get('key1')).toBeUndefined();
|
|
250
|
+
|
|
251
|
+
customCache.destroy();
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
describe('Memory Management', () => {
|
|
256
|
+
test('should not memory leak with many entries', () => {
|
|
257
|
+
const entryCount = 1000;
|
|
258
|
+
|
|
259
|
+
// Create many entries with short TTL
|
|
260
|
+
for (let i = 0; i < entryCount; i++) {
|
|
261
|
+
cache.set(`key${i}`, `value${i}`, 100);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
expect(cache.getStats().size).toBe(entryCount);
|
|
265
|
+
|
|
266
|
+
// Let all entries expire and cleanup
|
|
267
|
+
jest.advanceTimersByTime(500);
|
|
268
|
+
|
|
269
|
+
expect(cache.getStats().size).toBe(0);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
test('should handle rapid create/destroy cycles', () => {
|
|
273
|
+
for (let i = 0; i < 10; i++) {
|
|
274
|
+
const tempCache = new TTLCache<string>({ cleanupIntervalMs: 100 });
|
|
275
|
+
tempCache.set('key', 'value');
|
|
276
|
+
tempCache.destroy();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Should not throw or cause issues
|
|
280
|
+
expect(true).toBe(true);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe('Edge Cases', () => {
|
|
285
|
+
test('should handle zero cleanup interval', () => {
|
|
286
|
+
expect(() => {
|
|
287
|
+
new TTLCache<string>({ cleanupIntervalMs: 0 });
|
|
288
|
+
}).not.toThrow();
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test('should handle negative cleanup interval', () => {
|
|
292
|
+
expect(() => {
|
|
293
|
+
new TTLCache<string>({ cleanupIntervalMs: -100 });
|
|
294
|
+
}).not.toThrow();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test('should handle very large cleanup interval', () => {
|
|
298
|
+
expect(() => {
|
|
299
|
+
new TTLCache<string>({ cleanupIntervalMs: Number.MAX_SAFE_INTEGER });
|
|
300
|
+
}).not.toThrow();
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Cache Presentation
|
|
2
|
+
|
|
3
|
+
React hooks and UI integration for cache system.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Presentation layer provides React hooks and components for integrating cache functionality with React applications. Located at `src/cache/presentation/`.
|
|
8
|
+
|
|
9
|
+
## Strategies
|
|
10
|
+
|
|
11
|
+
### Hook Design
|
|
12
|
+
- Create hooks for common caching patterns
|
|
13
|
+
- Provide simple, composable APIs
|
|
14
|
+
- Support React Suspense where applicable
|
|
15
|
+
- Handle loading and error states
|
|
16
|
+
|
|
17
|
+
### React Integration
|
|
18
|
+
- Follow React rules of hooks
|
|
19
|
+
- Support dependency arrays correctly
|
|
20
|
+
- Clean up on component unmount
|
|
21
|
+
- Avoid unnecessary re-renders
|
|
22
|
+
|
|
23
|
+
### State Management
|
|
24
|
+
- Expose cache state reactively
|
|
25
|
+
- Provide update mechanisms
|
|
26
|
+
- Support invalidation and refresh
|
|
27
|
+
- Handle stale data appropriately
|
|
28
|
+
|
|
29
|
+
### Performance
|
|
30
|
+
- Use memoization to prevent redundant operations
|
|
31
|
+
- Implement efficient re-render strategies
|
|
32
|
+
- Debounce rapid cache operations
|
|
33
|
+
- Minimize hook overhead
|
|
34
|
+
|
|
35
|
+
## Restrictions
|
|
36
|
+
|
|
37
|
+
### Hook Usage
|
|
38
|
+
- DO NOT call hooks outside React components
|
|
39
|
+
- DO NOT call hooks conditionally
|
|
40
|
+
- DO NOT call hooks in loops
|
|
41
|
+
- DO NOT create new cache instances on every render
|
|
42
|
+
|
|
43
|
+
### State Management
|
|
44
|
+
- DO NOT cause infinite re-render loops
|
|
45
|
+
- DO NOT mutate state directly
|
|
46
|
+
- DO NOT ignore loading states
|
|
47
|
+
- DO NOT swallow errors silently
|
|
48
|
+
|
|
49
|
+
### Performance
|
|
50
|
+
- DO NOT recreate functions on every render
|
|
51
|
+
- DO NOT subscribe to entire cache when slice needed
|
|
52
|
+
- DO NOT perform expensive operations in render
|
|
53
|
+
- DO NOT cache large computed values in hook state
|
|
54
|
+
|
|
55
|
+
### Cleanup
|
|
56
|
+
- DO NOT leak subscriptions
|
|
57
|
+
- DO NOT forget cleanup on unmount
|
|
58
|
+
- DO NOT create memory leaks
|
|
59
|
+
- DO NOT leave timers running
|
|
60
|
+
|
|
61
|
+
## Rules
|
|
62
|
+
|
|
63
|
+
### Hook Implementation
|
|
64
|
+
- MUST follow React rules of hooks
|
|
65
|
+
- MUST use `use` prefix for hook names
|
|
66
|
+
- MUST provide TypeScript types
|
|
67
|
+
- MUST handle errors gracefully
|
|
68
|
+
|
|
69
|
+
### useCache Hook
|
|
70
|
+
- MUST accept cache name parameter
|
|
71
|
+
- MUST return cache interface methods
|
|
72
|
+
- MUST provide consistent API across renders
|
|
73
|
+
- MUST handle non-existent cache gracefully
|
|
74
|
+
|
|
75
|
+
### useCachedValue Hook
|
|
76
|
+
- MUST accept key and fetcher function
|
|
77
|
+
- MUST accept optional TTL parameter
|
|
78
|
+
- MUST return value, setter, and invalidate function
|
|
79
|
+
- MUST handle loading state
|
|
80
|
+
- MUST handle error state
|
|
81
|
+
|
|
82
|
+
### State Updates
|
|
83
|
+
- MUST trigger re-renders on cache changes
|
|
84
|
+
- MUST use React state for reactive values
|
|
85
|
+
- MUST memoize callbacks to prevent re-renders
|
|
86
|
+
- MUST update state atomically
|
|
87
|
+
|
|
88
|
+
### Cleanup Behavior
|
|
89
|
+
- MUST clean up subscriptions on unmount
|
|
90
|
+
- MUST cancel pending operations
|
|
91
|
+
- MUST clear timers
|
|
92
|
+
- MUST not leak memory
|
|
93
|
+
|
|
94
|
+
### Error Handling
|
|
95
|
+
- MUST expose error state to caller
|
|
96
|
+
- MUST allow error recovery
|
|
97
|
+
- MUST log errors in development
|
|
98
|
+
- MUST provide error boundaries for usage
|
|
99
|
+
|
|
100
|
+
### TypeScript Types
|
|
101
|
+
- MUST provide generic type parameters
|
|
102
|
+
- MUST infer types from cache
|
|
103
|
+
- MUST enforce type safety
|
|
104
|
+
- MUST document complex types
|
|
105
|
+
|
|
106
|
+
### Performance Rules
|
|
107
|
+
- MUST use useCallback for stable function references
|
|
108
|
+
- MUST use useMemo for expensive computations
|
|
109
|
+
- MUST provide stable references across renders
|
|
110
|
+
- MUST minimize re-render frequency
|
|
111
|
+
|
|
112
|
+
### Testing Requirements
|
|
113
|
+
- MUST test with @testing-library/react-hooks
|
|
114
|
+
- MUST test cleanup behavior
|
|
115
|
+
- MUST test error scenarios
|
|
116
|
+
- MUST test type safety
|
|
117
|
+
- MUST test re-render behavior
|
|
118
|
+
|
|
119
|
+
### Export Rules
|
|
120
|
+
- MUST export hooks from index file
|
|
121
|
+
- MUST provide consistent naming
|
|
122
|
+
- MUST document hook contracts
|
|
123
|
+
- MUST maintain backward compatibility
|