@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.
Files changed (128) hide show
  1. package/package.json +5 -6
  2. package/src/device/infrastructure/repositories/LegacyDeviceIdRepository.ts +1 -1
  3. package/src/device/infrastructure/services/DeviceFeatureService.ts +1 -1
  4. package/src/exception/infrastructure/services/ExceptionLogger.ts +1 -1
  5. package/src/exception/infrastructure/storage/ExceptionStore.ts +1 -1
  6. package/src/exports/filesystem.ts +1 -0
  7. package/src/exports/storage.ts +1 -0
  8. package/src/filesystem/domain/constants/FileConstants.ts +20 -0
  9. package/src/filesystem/domain/entities/File.ts +20 -0
  10. package/src/filesystem/domain/types/FileTypes.ts +43 -0
  11. package/src/filesystem/domain/utils/FileUtils.ts +86 -0
  12. package/src/filesystem/index.ts +23 -0
  13. package/src/filesystem/infrastructure/services/FileSystemService.ts +45 -0
  14. package/src/filesystem/infrastructure/services/cache.service.ts +48 -0
  15. package/src/filesystem/infrastructure/services/directory.service.ts +66 -0
  16. package/src/filesystem/infrastructure/services/download.constants.ts +6 -0
  17. package/src/filesystem/infrastructure/services/download.service.ts +74 -0
  18. package/src/filesystem/infrastructure/services/download.types.ts +7 -0
  19. package/src/filesystem/infrastructure/services/encoding.service.ts +25 -0
  20. package/src/filesystem/infrastructure/services/file-info.service.ts +52 -0
  21. package/src/filesystem/infrastructure/services/file-manager.service.ts +81 -0
  22. package/src/filesystem/infrastructure/services/file-path.service.ts +22 -0
  23. package/src/filesystem/infrastructure/services/file-reader.service.ts +52 -0
  24. package/src/filesystem/infrastructure/services/file-writer.service.ts +32 -0
  25. package/src/filesystem/infrastructure/utils/blob.utils.ts +20 -0
  26. package/src/image/infrastructure/services/ImageStorageService.ts +1 -1
  27. package/src/index.ts +9 -0
  28. package/src/molecules/alerts/AlertStore.ts +1 -1
  29. package/src/molecules/calendar/infrastructure/storage/EventActions.ts +1 -1
  30. package/src/molecules/calendar/infrastructure/stores/storageAdapter.ts +1 -1
  31. package/src/offline/infrastructure/storage/OfflineStore.ts +1 -1
  32. package/src/onboarding/infrastructure/storage/OnboardingStore.ts +2 -2
  33. package/src/onboarding/infrastructure/storage/__tests__/OnboardingStore.test.ts +1 -1
  34. package/src/onboarding/infrastructure/storage/actions/answerActions.ts +1 -1
  35. package/src/onboarding/infrastructure/storage/actions/storageHelpers.ts +1 -1
  36. package/src/storage/README.md +185 -0
  37. package/src/storage/__tests__/integration.test.ts +391 -0
  38. package/src/storage/__tests__/mocks/asyncStorage.mock.ts +52 -0
  39. package/src/storage/__tests__/performance.test.tsx +352 -0
  40. package/src/storage/__tests__/setup.ts +63 -0
  41. package/src/storage/application/README.md +158 -0
  42. package/src/storage/application/ports/IStorageRepository.ts +61 -0
  43. package/src/storage/application/ports/README.md +127 -0
  44. package/src/storage/cache/README.md +154 -0
  45. package/src/storage/cache/__tests__/PerformanceAndMemory.test.ts +387 -0
  46. package/src/storage/cache/__tests__/setup.ts +19 -0
  47. package/src/storage/cache/domain/Cache.ts +146 -0
  48. package/src/storage/cache/domain/CacheManager.md +83 -0
  49. package/src/storage/cache/domain/CacheManager.ts +48 -0
  50. package/src/storage/cache/domain/CacheStatsTracker.md +169 -0
  51. package/src/storage/cache/domain/CacheStatsTracker.ts +49 -0
  52. package/src/storage/cache/domain/CachedValue.md +97 -0
  53. package/src/storage/cache/domain/ErrorHandler.md +99 -0
  54. package/src/storage/cache/domain/ErrorHandler.ts +42 -0
  55. package/src/storage/cache/domain/PatternMatcher.md +122 -0
  56. package/src/storage/cache/domain/PatternMatcher.ts +30 -0
  57. package/src/storage/cache/domain/README.md +118 -0
  58. package/src/storage/cache/domain/__tests__/Cache.test.ts +293 -0
  59. package/src/storage/cache/domain/__tests__/CacheManager.test.ts +276 -0
  60. package/src/storage/cache/domain/__tests__/ErrorHandler.test.ts +303 -0
  61. package/src/storage/cache/domain/__tests__/PatternMatcher.test.ts +261 -0
  62. package/src/storage/cache/domain/strategies/EvictionStrategy.ts +9 -0
  63. package/src/storage/cache/domain/strategies/FIFOStrategy.ts +12 -0
  64. package/src/storage/cache/domain/strategies/LFUStrategy.ts +22 -0
  65. package/src/storage/cache/domain/strategies/LRUStrategy.ts +22 -0
  66. package/src/storage/cache/domain/strategies/README.md +117 -0
  67. package/src/storage/cache/domain/strategies/TTLStrategy.ts +23 -0
  68. package/src/storage/cache/domain/strategies/__tests__/EvictionStrategies.test.ts +293 -0
  69. package/src/storage/cache/domain/types/Cache.ts +28 -0
  70. package/src/storage/cache/domain/types/README.md +107 -0
  71. package/src/storage/cache/index.ts +28 -0
  72. package/src/storage/cache/infrastructure/README.md +126 -0
  73. package/src/storage/cache/infrastructure/TTLCache.ts +103 -0
  74. package/src/storage/cache/infrastructure/__tests__/TTLCache.test.ts +303 -0
  75. package/src/storage/cache/presentation/README.md +123 -0
  76. package/src/storage/cache/presentation/__tests__/ReactHooks.test.ts +514 -0
  77. package/src/storage/cache/presentation/useCache.ts +76 -0
  78. package/src/storage/cache/presentation/useCachedValue.ts +88 -0
  79. package/src/storage/cache/types.d.ts +3 -0
  80. package/src/storage/domain/README.md +128 -0
  81. package/src/storage/domain/constants/CacheDefaults.ts +64 -0
  82. package/src/storage/domain/constants/README.md +105 -0
  83. package/src/storage/domain/entities/CachedValue.ts +86 -0
  84. package/src/storage/domain/entities/README.md +109 -0
  85. package/src/storage/domain/entities/StorageResult.ts +75 -0
  86. package/src/storage/domain/entities/__tests__/CachedValue.test.ts +149 -0
  87. package/src/storage/domain/entities/__tests__/StorageResult.test.ts +122 -0
  88. package/src/storage/domain/errors/README.md +126 -0
  89. package/src/storage/domain/errors/StorageError.ts +81 -0
  90. package/src/storage/domain/errors/__tests__/StorageError.test.ts +127 -0
  91. package/src/storage/domain/factories/README.md +138 -0
  92. package/src/storage/domain/factories/StoreFactory.ts +59 -0
  93. package/src/storage/domain/types/README.md +522 -0
  94. package/src/storage/domain/types/Store.ts +44 -0
  95. package/src/storage/domain/utils/CacheKeyGenerator.ts +66 -0
  96. package/src/storage/domain/utils/README.md +127 -0
  97. package/src/storage/domain/utils/__tests__/devUtils.test.ts +97 -0
  98. package/src/storage/domain/utils/devUtils.ts +37 -0
  99. package/src/storage/domain/value-objects/README.md +120 -0
  100. package/src/storage/domain/value-objects/StorageKey.ts +60 -0
  101. package/src/storage/index.ts +175 -0
  102. package/src/storage/infrastructure/README.md +165 -0
  103. package/src/storage/infrastructure/adapters/README.md +175 -0
  104. package/src/storage/infrastructure/adapters/StorageService.md +103 -0
  105. package/src/storage/infrastructure/adapters/StorageService.ts +49 -0
  106. package/src/storage/infrastructure/repositories/AsyncStorageRepository.ts +98 -0
  107. package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +100 -0
  108. package/src/storage/infrastructure/repositories/BatchStorageOperations.ts +42 -0
  109. package/src/storage/infrastructure/repositories/README.md +121 -0
  110. package/src/storage/infrastructure/repositories/StringStorageOperations.ts +44 -0
  111. package/src/storage/infrastructure/repositories/__tests__/AsyncStorageRepository.test.ts +170 -0
  112. package/src/storage/infrastructure/repositories/__tests__/BaseStorageOperations.test.ts +201 -0
  113. package/src/storage/presentation/README.md +181 -0
  114. package/src/storage/presentation/hooks/CacheStorageOperations.ts +94 -0
  115. package/src/storage/presentation/hooks/README.md +128 -0
  116. package/src/storage/presentation/hooks/__tests__/usePersistentCache.test.ts +405 -0
  117. package/src/storage/presentation/hooks/__tests__/useStorage.test.ts +247 -0
  118. package/src/storage/presentation/hooks/__tests__/useStorageState.test.ts +293 -0
  119. package/src/storage/presentation/hooks/useCacheState.ts +53 -0
  120. package/src/storage/presentation/hooks/usePersistentCache.ts +154 -0
  121. package/src/storage/presentation/hooks/useStorage.ts +102 -0
  122. package/src/storage/presentation/hooks/useStorageState.ts +71 -0
  123. package/src/storage/presentation/hooks/useStore.ts +15 -0
  124. package/src/storage/types/README.md +103 -0
  125. package/src/theme/infrastructure/globalThemeStore.ts +1 -1
  126. package/src/theme/infrastructure/storage/ThemeStorage.ts +1 -1
  127. package/src/theme/infrastructure/stores/themeStore.ts +1 -1
  128. package/src/utilities/sharing/infrastructure/services/SharingService.ts +1 -1
@@ -0,0 +1,261 @@
1
+ /**
2
+ * PatternMatcher Tests
3
+ */
4
+
5
+ import { PatternMatcher } from '../PatternMatcher';
6
+
7
+ describe('PatternMatcher', () => {
8
+ beforeEach(() => {
9
+ PatternMatcher.clearCache();
10
+ });
11
+
12
+ describe('convertPatternToRegex', () => {
13
+ test('should handle simple patterns', () => {
14
+ const regex = PatternMatcher.convertPatternToRegex('user:*');
15
+ expect(regex.test('user:1')).toBe(true);
16
+ expect(regex.test('user:123')).toBe(true);
17
+ expect(regex.test('user:abc')).toBe(true);
18
+ expect(regex.test('admin:1')).toBe(false);
19
+ });
20
+
21
+ test('should handle multiple wildcards', () => {
22
+ const regex = PatternMatcher.convertPatternToRegex('*:*:*');
23
+ expect(regex.test('user:1:profile')).toBe(true);
24
+ expect(regex.test('post:2:comments')).toBe(true);
25
+ expect(regex.test('user:1')).toBe(false);
26
+ expect(regex.test('user')).toBe(false);
27
+ });
28
+
29
+ test('should handle exact matches', () => {
30
+ const regex = PatternMatcher.convertPatternToRegex('exact-key');
31
+ expect(regex.test('exact-key')).toBe(true);
32
+ expect(regex.test('exact-key-123')).toBe(false);
33
+ expect(regex.test('exact')).toBe(false);
34
+ });
35
+
36
+ test('should handle patterns with special characters', () => {
37
+ const regex = PatternMatcher.convertPatternToRegex('user.*profile');
38
+ expect(regex.test('user.123.profile')).toBe(true);
39
+ expect(regex.test('user.abc.profile')).toBe(true);
40
+ expect(regex.test('user.profile')).toBe(false);
41
+ });
42
+
43
+ test('should escape regex special characters', () => {
44
+ const regex = PatternMatcher.convertPatternToRegex('user.+?^${}()|[]\\');
45
+ expect(regex.test('user.+?^${}()|[]\\')).toBe(true);
46
+ expect(regex.test('user-something')).toBe(false);
47
+ });
48
+
49
+ test('should handle empty pattern', () => {
50
+ const regex = PatternMatcher.convertPatternToRegex('');
51
+ expect(regex.test('')).toBe(true);
52
+ expect(regex.test('anything')).toBe(false);
53
+ });
54
+
55
+ test('should handle pattern with only wildcards', () => {
56
+ const regex = PatternMatcher.convertPatternToRegex('*');
57
+ expect(regex.test('anything')).toBe(true);
58
+ expect(regex.test('')).toBe(true);
59
+ });
60
+
61
+ test('should handle complex patterns', () => {
62
+ const regex = PatternMatcher.convertPatternToRegex('cache:*:data:*');
63
+ expect(regex.test('cache:user:data:123')).toBe(true);
64
+ expect(regex.test('cache:post:data:456')).toBe(true);
65
+ expect(regex.test('cache:user:meta:123')).toBe(false);
66
+ expect(regex.test('user:data:123')).toBe(false);
67
+ });
68
+
69
+ test('should handle patterns with dots and dashes', () => {
70
+ const regex = PatternMatcher.convertPatternToRegex('module.*-service.*');
71
+ expect(regex.test('module.auth-service.v1')).toBe(true);
72
+ expect(regex.test('module.user-service.v2')).toBe(true);
73
+ expect(regex.test('module.auth')).toBe(false);
74
+ });
75
+ });
76
+
77
+ describe('matchesPattern', () => {
78
+ test('should return true for matching patterns', () => {
79
+ expect(PatternMatcher.matchesPattern('user:1', 'user:*')).toBe(true);
80
+ expect(PatternMatcher.matchesPattern('post:123:comments', '*:*:*')).toBe(true);
81
+ expect(PatternMatcher.matchesPattern('exact', 'exact')).toBe(true);
82
+ });
83
+
84
+ test('should return false for non-matching patterns', () => {
85
+ expect(PatternMatcher.matchesPattern('admin:1', 'user:*')).toBe(false);
86
+ expect(PatternMatcher.matchesPattern('user:1', '*:*:*')).toBe(false);
87
+ expect(PatternMatcher.matchesPattern('exact', 'different')).toBe(false);
88
+ });
89
+
90
+ test('should handle case-sensitive matching', () => {
91
+ expect(PatternMatcher.matchesPattern('User:1', 'user:*')).toBe(false);
92
+ expect(PatternMatcher.matchesPattern('user:1', 'User:*')).toBe(false);
93
+ expect(PatternMatcher.matchesPattern('USER:1', 'USER:*')).toBe(true);
94
+ });
95
+
96
+ test('should handle empty strings', () => {
97
+ expect(PatternMatcher.matchesPattern('', '')).toBe(true);
98
+ expect(PatternMatcher.matchesPattern('', '*')).toBe(true);
99
+ expect(PatternMatcher.matchesPattern('test', '')).toBe(false);
100
+ });
101
+ });
102
+
103
+ describe('Regex Caching', () => {
104
+ test('should cache converted regex patterns', () => {
105
+ const pattern = 'user:*';
106
+
107
+ const regex1 = PatternMatcher.convertPatternToRegex(pattern);
108
+ const regex2 = PatternMatcher.convertPatternToRegex(pattern);
109
+
110
+ expect(regex1).toBe(regex2); // Same reference
111
+ });
112
+
113
+ test('should create different regex for different patterns', () => {
114
+ const regex1 = PatternMatcher.convertPatternToRegex('user:*');
115
+ const regex2 = PatternMatcher.convertPatternToRegex('post:*');
116
+
117
+ expect(regex1).not.toBe(regex2); // Different references
118
+ expect(regex1.test('user:1')).toBe(true);
119
+ expect(regex1.test('post:1')).toBe(false);
120
+ expect(regex2.test('post:1')).toBe(true);
121
+ expect(regex2.test('user:1')).toBe(false);
122
+ });
123
+
124
+ test('should clear cache', () => {
125
+ const pattern = 'user:*';
126
+
127
+ const regex1 = PatternMatcher.convertPatternToRegex(pattern);
128
+ PatternMatcher.clearCache();
129
+ const regex2 = PatternMatcher.convertPatternToRegex(pattern);
130
+
131
+ expect(regex1).not.toBe(regex2); // Different references after clear
132
+ });
133
+
134
+ test('should maintain cache performance', () => {
135
+ const pattern = 'very:complex:pattern:*:with:many:parts:*';
136
+
137
+ // First call - should create new regex
138
+ const start1 = performance.now();
139
+ const regex1 = PatternMatcher.convertPatternToRegex(pattern);
140
+ const end1 = performance.now();
141
+
142
+ // Second call - should use cached regex
143
+ const start2 = performance.now();
144
+ const regex2 = PatternMatcher.convertPatternToRegex(pattern);
145
+ const end2 = performance.now();
146
+
147
+ expect(regex1).toBe(regex2);
148
+ // Second call should be faster (though this might not always be true in tests)
149
+ expect(end2 - start2).toBeLessThanOrEqual(end1 - start1);
150
+ });
151
+ });
152
+
153
+ describe('Edge Cases', () => {
154
+ test('should handle very long patterns', () => {
155
+ const longPattern = 'a'.repeat(1000) + '*';
156
+ const longKey = 'a'.repeat(1000) + 'suffix';
157
+
158
+ expect(PatternMatcher.matchesPattern(longKey, longPattern)).toBe(true);
159
+ expect(PatternMatcher.matchesPattern('a'.repeat(999), longPattern)).toBe(false);
160
+ });
161
+
162
+ test('should handle patterns with only special characters', () => {
163
+ const regex = PatternMatcher.convertPatternToRegex('.+?^${}()|[]\\');
164
+ expect(regex.test('.+?^${}()|[]\\')).toBe(true);
165
+ });
166
+
167
+ test('should handle Unicode characters', () => {
168
+ expect(PatternMatcher.matchesPattern('üser:1', 'üser:*')).toBe(true);
169
+ expect(PatternMatcher.matchesPattern('用户:1', '用户:*')).toBe(true);
170
+ expect(PatternMatcher.matchesPattern('🚀:launch', '🚀:*')).toBe(true);
171
+ });
172
+
173
+ test('should handle null and undefined inputs gracefully', () => {
174
+ expect(() => {
175
+ PatternMatcher.convertPatternToRegex(null as any);
176
+ }).toThrow();
177
+
178
+ expect(() => {
179
+ PatternMatcher.convertPatternToRegex(undefined as any);
180
+ }).toThrow();
181
+ });
182
+
183
+ test('should handle non-string inputs', () => {
184
+ expect(() => {
185
+ PatternMatcher.convertPatternToRegex(123 as any);
186
+ }).toThrow();
187
+
188
+ expect(() => {
189
+ PatternMatcher.convertPatternToRegex({} as any);
190
+ }).toThrow();
191
+ });
192
+ });
193
+
194
+ describe('Performance Considerations', () => {
195
+ test('should handle large number of pattern matches efficiently', () => {
196
+ const pattern = 'cache:*:data:*';
197
+ const keys = Array.from({ length: 1000 }, (_, i) => `cache:${i}:data:${i * 2}`);
198
+
199
+ const start = performance.now();
200
+
201
+ keys.forEach(key => {
202
+ PatternMatcher.matchesPattern(key, pattern);
203
+ });
204
+
205
+ const end = performance.now();
206
+
207
+ // Should complete within reasonable time (adjust threshold as needed)
208
+ expect(end - start).toBeLessThan(100); // 100ms
209
+ });
210
+
211
+ test('should reuse cached regex for many matches', () => {
212
+ const pattern = 'user:*';
213
+ const keys = Array.from({ length: 1000 }, (_, i) => `user:${i}`);
214
+
215
+ // Pre-cache the regex
216
+ PatternMatcher.convertPatternToRegex(pattern);
217
+
218
+ const start = performance.now();
219
+
220
+ keys.forEach(key => {
221
+ PatternMatcher.matchesPattern(key, pattern);
222
+ });
223
+
224
+ const end = performance.now();
225
+
226
+ // Should be faster with cached regex
227
+ expect(end - start).toBeLessThan(50); // 50ms
228
+ });
229
+ });
230
+
231
+ describe('Real-world Scenarios', () => {
232
+ test('should handle common cache key patterns', () => {
233
+ const scenarios = [
234
+ { key: 'user:123:profile', pattern: 'user:*:profile', expected: true },
235
+ { key: 'user:123:settings', pattern: 'user:*:profile', expected: false },
236
+ { key: 'post:456:comments:789', pattern: 'post:*:comments:*', expected: true },
237
+ { key: 'post:456:likes', pattern: 'post:*:comments:*', expected: false },
238
+ { key: 'session:abc123', pattern: 'session:*', expected: true },
239
+ { key: 'cache:api:user:123', pattern: 'cache:api:*', expected: true },
240
+ { key: 'cache:db:user:123', pattern: 'cache:api:*', expected: false },
241
+ ];
242
+
243
+ scenarios.forEach(({ key, pattern, expected }) => {
244
+ expect(PatternMatcher.matchesPattern(key, pattern)).toBe(expected);
245
+ });
246
+ });
247
+
248
+ test('should handle API endpoint patterns', () => {
249
+ const apiPatterns = [
250
+ { endpoint: '/api/v1/users/123', pattern: '/api/v1/users/*', expected: true },
251
+ { endpoint: '/api/v1/posts/456/comments', pattern: '/api/v1/posts/*/comments', expected: true },
252
+ { endpoint: '/api/v2/users/123', pattern: '/api/v1/users/*', expected: false },
253
+ { endpoint: '/api/v1/users', pattern: '/api/v1/users/*', expected: false },
254
+ ];
255
+
256
+ apiPatterns.forEach(({ endpoint, pattern, expected }) => {
257
+ expect(PatternMatcher.matchesPattern(endpoint, pattern)).toBe(expected);
258
+ });
259
+ });
260
+ });
261
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Eviction Strategy Interface
3
+ */
4
+
5
+ import type { CacheEntry } from '../types/Cache';
6
+
7
+ export interface EvictionStrategy<T> {
8
+ findKeyToEvict(entries: Map<string, CacheEntry<T>>): string | undefined;
9
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * FIFO (First In First Out) Eviction Strategy
3
+ */
4
+
5
+ import type { EvictionStrategy } from './EvictionStrategy';
6
+ import type { CacheEntry } from '../types/Cache';
7
+
8
+ export class FIFOStrategy<T> implements EvictionStrategy<T> {
9
+ findKeyToEvict(entries: Map<string, CacheEntry<T>>): string | undefined {
10
+ return entries.keys().next().value;
11
+ }
12
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * LFU (Least Frequently Used) Eviction Strategy
3
+ */
4
+
5
+ import type { EvictionStrategy } from './EvictionStrategy';
6
+ import type { CacheEntry } from '../types/Cache';
7
+
8
+ export class LFUStrategy<T> implements EvictionStrategy<T> {
9
+ findKeyToEvict(entries: Map<string, CacheEntry<T>>): string | undefined {
10
+ let least: string | undefined;
11
+ let leastCount = Infinity;
12
+
13
+ for (const [key, entry] of entries.entries()) {
14
+ if (entry.accessCount < leastCount) {
15
+ leastCount = entry.accessCount;
16
+ least = key;
17
+ }
18
+ }
19
+
20
+ return least;
21
+ }
22
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * LRU (Least Recently Used) Eviction Strategy
3
+ */
4
+
5
+ import type { EvictionStrategy } from './EvictionStrategy';
6
+ import type { CacheEntry } from '../types/Cache';
7
+
8
+ export class LRUStrategy<T> implements EvictionStrategy<T> {
9
+ findKeyToEvict(entries: Map<string, CacheEntry<T>>): string | undefined {
10
+ let oldest: string | undefined;
11
+ let oldestTime = Infinity;
12
+
13
+ for (const [key, entry] of entries.entries()) {
14
+ if (entry.lastAccess < oldestTime) {
15
+ oldestTime = entry.lastAccess;
16
+ oldest = key;
17
+ }
18
+ }
19
+
20
+ return oldest;
21
+ }
22
+ }
@@ -0,0 +1,117 @@
1
+ # Cache Eviction Strategies
2
+
3
+ Algorithms for determining which cache entries to evict when cache is full.
4
+
5
+ ## Overview
6
+
7
+ Eviction strategies determine which cache entries to remove when the cache reaches its maximum size. Located at `src/cache/domain/strategies/`.
8
+
9
+ ## Strategies
10
+
11
+ ### Strategy Selection
12
+ - Use LRU (Least Recently Used) for most use cases - best general performance
13
+ - Use LFU (Least Frequently Used) for popularity-based caching - keeps frequently accessed items
14
+ - Use FIFO (First In First Out) for simple queue-based caching - lowest overhead
15
+ - Use TTL (Time To Live) for time-sensitive data - required for expiration
16
+
17
+ ### Performance Considerations
18
+ - LRU provides O(1) eviction time with proper data structures
19
+ - LFU provides O(n) eviction time but better for read-heavy workloads
20
+ - FIFO provides O(1) eviction time with minimal overhead
21
+ - TTL requires periodic cleanup but essential for freshness
22
+
23
+ ### Access Pattern Analysis
24
+ - Consider data access patterns when choosing strategy
25
+ - Use LRU for temporal locality (recently accessed likely to be accessed again)
26
+ - Use LFU for frequency-based patterns (popular items should stay)
27
+ - Use FIFO for sequential access patterns
28
+ - Use TTL when data freshness is critical
29
+
30
+ ### Implementation Strategy
31
+ - Implement EvictionStrategy interface for custom strategies
32
+ - Track necessary metadata (access count, last access, timestamp)
33
+ - Provide findKeyToEvict method for selection
34
+ - Update metadata on cache operations
35
+
36
+ ## Restrictions
37
+
38
+ ### Strategy Usage
39
+ - DO NOT use LFU for write-heavy workloads (expensive)
40
+ - DO NOT use FIFO when access patterns matter
41
+ - DO NOT use TTL when data staleness is acceptable
42
+ - DO NOT change strategies after cache creation
43
+
44
+ ### Performance
45
+ - DO NOT implement O(n²) eviction algorithms
46
+ - DO NOT scan entire cache for eviction on every operation
47
+ - DO NOT track unnecessary metadata for chosen strategy
48
+ - DO NOT use complex algorithms for simple use cases
49
+
50
+ ### Custom Strategies
51
+ - DO NOT implement custom strategies without thorough testing
52
+ - DO NOT ignore edge cases (empty cache, single entry)
53
+ - DO NOT create strategies without clear performance benefits
54
+ - DO NOT mix multiple eviction strategies in same cache
55
+
56
+ ## Rules
57
+
58
+ ### EvictionStrategy Interface
59
+ - MUST implement findKeyToEvict(store: Map): string | undefined
60
+ - MUST return undefined when store is empty
61
+ - MUST return single key for eviction
62
+ - MUST handle all cache states correctly
63
+
64
+ ### LRU Strategy
65
+ - MUST track lastAccess timestamp for each entry
66
+ - MUST update lastAccess on every get operation
67
+ - MUST select entry with oldest lastAccess time
68
+ - MUST provide O(1) or O(log n) time complexity
69
+
70
+ ### LFU Strategy
71
+ - MUST track accessCount for each entry
72
+ - MUST increment accessCount on every get operation
73
+ - MUST select entry with lowest accessCount
74
+ - MUST handle ties consistently (use LRU as tiebreaker)
75
+
76
+ ### FIFO Strategy
77
+ - MUST track insertion order for each entry
78
+ - MUST select oldest entry (first inserted)
79
+ - MUST NOT consider access patterns
80
+ - MUST provide O(1) time complexity
81
+
82
+ ### TTL Strategy
83
+ - MUST check timestamp + ttl against current time
84
+ - MUST select expired entries first
85
+ - MUST fall back to secondary strategy if no expired entries
86
+ - MUST handle zero TTL entries (immediate eviction)
87
+
88
+ ### Metadata Updates
89
+ - MUST update eviction metadata on every cache operation
90
+ - MUST update metadata on cache set operations
91
+ - MUST update metadata on cache get operations
92
+ - MUST reset metadata appropriately on cache updates
93
+
94
+ ### Edge Cases
95
+ - MUST handle empty cache (return undefined)
96
+ - MUST handle single entry cache
97
+ - MUST handle all entries with same metadata
98
+ - MUST handle concurrent access safely
99
+
100
+ ### Strategy Selection
101
+ - MUST use LRU as default strategy
102
+ - MUST allow strategy override in configuration
103
+ - MUST validate strategy choice
104
+ - MUST document strategy behavior
105
+
106
+ ### Testing Requirements
107
+ - MUST test eviction with full cache
108
+ - MUST test eviction with empty cache
109
+ - MUST test metadata tracking accuracy
110
+ - MUST test edge cases
111
+ - MUST measure time complexity
112
+
113
+ ### Performance Rules
114
+ - MUST not exceed O(n) for eviction selection
115
+ - MUST not allocate memory during eviction
116
+ - MUST not use blocking operations
117
+ - MUST minimize CPU overhead
@@ -0,0 +1,23 @@
1
+ /**
2
+ * TTL (Time To Live) Eviction Strategy
3
+ */
4
+
5
+ import type { EvictionStrategy } from './EvictionStrategy';
6
+ import type { CacheEntry } from '../types/Cache';
7
+
8
+ export class TTLStrategy<T> implements EvictionStrategy<T> {
9
+ findKeyToEvict(entries: Map<string, CacheEntry<T>>): string | undefined {
10
+ let nearest: string | undefined;
11
+ let nearestExpiry = Infinity;
12
+
13
+ for (const [key, entry] of entries.entries()) {
14
+ const expiry = entry.timestamp + entry.ttl;
15
+ if (expiry < nearestExpiry) {
16
+ nearestExpiry = expiry;
17
+ nearest = key;
18
+ }
19
+ }
20
+
21
+ return nearest;
22
+ }
23
+ }