@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,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Domain - Public API
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design (DDD) Architecture
|
|
5
|
+
*
|
|
6
|
+
* This is the SINGLE SOURCE OF TRUTH for all storage operations.
|
|
7
|
+
* ALL imports from the storage domain MUST go through this file.
|
|
8
|
+
*
|
|
9
|
+
* Architecture:
|
|
10
|
+
* - domain: Entities, value objects, errors (business logic)
|
|
11
|
+
* - application: Ports (interfaces), use cases (not needed for simple CRUD)
|
|
12
|
+
* - infrastructure: Repository implementation (AsyncStorage adapter)
|
|
13
|
+
* - presentation: Hooks (React integration)
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* import { useStorage, useStorageState, createStore } from '@umituz/react-native-design-system';
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// DOMAIN LAYER - Business Logic
|
|
21
|
+
// =============================================================================
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
StorageKey,
|
|
25
|
+
createUserKey,
|
|
26
|
+
createAppKey,
|
|
27
|
+
} from './domain/value-objects/StorageKey';
|
|
28
|
+
|
|
29
|
+
export type { DynamicStorageKey } from './domain/value-objects/StorageKey';
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
StorageError,
|
|
33
|
+
StorageReadError,
|
|
34
|
+
StorageWriteError,
|
|
35
|
+
StorageDeleteError,
|
|
36
|
+
StorageSerializationError,
|
|
37
|
+
StorageDeserializationError,
|
|
38
|
+
} from './domain/errors/StorageError';
|
|
39
|
+
|
|
40
|
+
export type { StorageResult } from './domain/entities/StorageResult';
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
success,
|
|
44
|
+
failure,
|
|
45
|
+
unwrap,
|
|
46
|
+
map,
|
|
47
|
+
isSuccess,
|
|
48
|
+
isFailure,
|
|
49
|
+
} from './domain/entities/StorageResult';
|
|
50
|
+
|
|
51
|
+
// =============================================================================
|
|
52
|
+
// DOMAIN LAYER - Cached Value Entity
|
|
53
|
+
// =============================================================================
|
|
54
|
+
|
|
55
|
+
export type { CachedValue } from './domain/entities/CachedValue';
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
createCachedValue,
|
|
59
|
+
isCacheExpired,
|
|
60
|
+
getRemainingTTL,
|
|
61
|
+
getCacheAge,
|
|
62
|
+
} from './domain/entities/CachedValue';
|
|
63
|
+
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// DOMAIN LAYER - Cache Utilities
|
|
66
|
+
// =============================================================================
|
|
67
|
+
|
|
68
|
+
export {
|
|
69
|
+
generateCacheKey,
|
|
70
|
+
generateListCacheKey,
|
|
71
|
+
parseCacheKey,
|
|
72
|
+
isCacheKey,
|
|
73
|
+
} from './domain/utils/CacheKeyGenerator';
|
|
74
|
+
|
|
75
|
+
// =============================================================================
|
|
76
|
+
// DOMAIN LAYER - Cache Constants
|
|
77
|
+
// =============================================================================
|
|
78
|
+
|
|
79
|
+
export { TIME_MS, DEFAULT_TTL, CACHE_VERSION } from './domain/constants/CacheDefaults';
|
|
80
|
+
|
|
81
|
+
// =============================================================================
|
|
82
|
+
// DOMAIN LAYER - Development Utilities
|
|
83
|
+
// =============================================================================
|
|
84
|
+
|
|
85
|
+
export { isDev, devWarn, devError, devLog } from './domain/utils/devUtils';
|
|
86
|
+
|
|
87
|
+
// =============================================================================
|
|
88
|
+
// DOMAIN LAYER - Store Types
|
|
89
|
+
// =============================================================================
|
|
90
|
+
|
|
91
|
+
export type {
|
|
92
|
+
StoreConfig,
|
|
93
|
+
PersistedState,
|
|
94
|
+
SetState,
|
|
95
|
+
GetState,
|
|
96
|
+
ActionsCreator,
|
|
97
|
+
} from './domain/types/Store';
|
|
98
|
+
|
|
99
|
+
// =============================================================================
|
|
100
|
+
// DOMAIN LAYER - Store Factory
|
|
101
|
+
// =============================================================================
|
|
102
|
+
|
|
103
|
+
export { createStore } from './domain/factories/StoreFactory';
|
|
104
|
+
|
|
105
|
+
// =============================================================================
|
|
106
|
+
// ZUSTAND - Type Re-exports for Compatibility
|
|
107
|
+
// =============================================================================
|
|
108
|
+
|
|
109
|
+
export type { StoreApi, UseBoundStore } from 'zustand';
|
|
110
|
+
export type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
|
111
|
+
|
|
112
|
+
// =============================================================================
|
|
113
|
+
// APPLICATION LAYER - Ports
|
|
114
|
+
// =============================================================================
|
|
115
|
+
|
|
116
|
+
export type { IStorageRepository } from './application/ports/IStorageRepository';
|
|
117
|
+
|
|
118
|
+
// =============================================================================
|
|
119
|
+
// INFRASTRUCTURE LAYER - Implementation
|
|
120
|
+
// =============================================================================
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
AsyncStorageRepository,
|
|
124
|
+
storageRepository,
|
|
125
|
+
} from './infrastructure/repositories/AsyncStorageRepository';
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
storageService,
|
|
129
|
+
type StateStorage,
|
|
130
|
+
} from './infrastructure/adapters/StorageService';
|
|
131
|
+
|
|
132
|
+
// =============================================================================
|
|
133
|
+
// PRESENTATION LAYER - Hooks
|
|
134
|
+
// =============================================================================
|
|
135
|
+
|
|
136
|
+
export { useStorage } from './presentation/hooks/useStorage';
|
|
137
|
+
export { useStorageState } from './presentation/hooks/useStorageState';
|
|
138
|
+
export { useStore } from './presentation/hooks/useStore';
|
|
139
|
+
|
|
140
|
+
export {
|
|
141
|
+
usePersistentCache,
|
|
142
|
+
type PersistentCacheOptions,
|
|
143
|
+
type PersistentCacheResult,
|
|
144
|
+
} from './presentation/hooks/usePersistentCache';
|
|
145
|
+
|
|
146
|
+
export { useCacheState } from './presentation/hooks/useCacheState';
|
|
147
|
+
export { CacheStorageOperations } from './presentation/hooks/CacheStorageOperations';
|
|
148
|
+
|
|
149
|
+
// =============================================================================
|
|
150
|
+
// IN-MEMORY CACHE LAYER (Merged from @umituz/react-native-cache)
|
|
151
|
+
// =============================================================================
|
|
152
|
+
|
|
153
|
+
export { Cache } from './cache/domain/Cache';
|
|
154
|
+
export { CacheManager, cacheManager } from './cache/domain/CacheManager';
|
|
155
|
+
export { CacheStatsTracker } from './cache/domain/CacheStatsTracker';
|
|
156
|
+
export { PatternMatcher } from './cache/domain/PatternMatcher';
|
|
157
|
+
export { ErrorHandler, CacheError } from './cache/domain/ErrorHandler';
|
|
158
|
+
export { TTLCache } from './cache/infrastructure/TTLCache';
|
|
159
|
+
|
|
160
|
+
export type {
|
|
161
|
+
CacheEntry,
|
|
162
|
+
CacheConfig,
|
|
163
|
+
CacheStats,
|
|
164
|
+
EvictionStrategy,
|
|
165
|
+
} from './cache/domain/types/Cache';
|
|
166
|
+
|
|
167
|
+
export type { EvictionStrategy as IEvictionStrategy } from './cache/domain/strategies/EvictionStrategy';
|
|
168
|
+
|
|
169
|
+
export { LRUStrategy } from './cache/domain/strategies/LRUStrategy';
|
|
170
|
+
export { LFUStrategy } from './cache/domain/strategies/LFUStrategy';
|
|
171
|
+
export { FIFOStrategy } from './cache/domain/strategies/FIFOStrategy';
|
|
172
|
+
export { TTLStrategy as TTLEvictionStrategy } from './cache/domain/strategies/TTLStrategy';
|
|
173
|
+
|
|
174
|
+
export { useCache } from './cache/presentation/useCache';
|
|
175
|
+
export { useCachedValue } from './cache/presentation/useCachedValue';
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Infrastructure Layer
|
|
2
|
+
|
|
3
|
+
External service adapters and storage repository implementations.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Infrastructure layer containing concrete implementations of storage operations. Located at `src/infrastructure/`.
|
|
8
|
+
|
|
9
|
+
## Directory Structure
|
|
10
|
+
|
|
11
|
+
- `adapters/` - External service adapters for Zustand persist middleware
|
|
12
|
+
- `repositories/` - Storage repository implementations with Result pattern
|
|
13
|
+
|
|
14
|
+
## Strategies
|
|
15
|
+
|
|
16
|
+
### Adapter Implementation
|
|
17
|
+
- Use StorageService adapter for Zustand persist middleware
|
|
18
|
+
- Implement StateStorage interface for Zustand integration
|
|
19
|
+
- Support AsyncStorage, MMKV, and SecureStore adapters
|
|
20
|
+
- Enable custom adapter creation for different storage backends
|
|
21
|
+
|
|
22
|
+
### Repository Pattern
|
|
23
|
+
- Use AsyncStorageRepository for primary storage operations
|
|
24
|
+
- Implement Result pattern for type-safe error handling
|
|
25
|
+
- Support generic type parameters for type safety
|
|
26
|
+
- Enable serialization/deserialization of complex objects
|
|
27
|
+
|
|
28
|
+
### Storage Adapters
|
|
29
|
+
- Use storageService for Zustand persist integration
|
|
30
|
+
- Create custom adapters for StateStorage interface
|
|
31
|
+
- Support SecureStore for sensitive data (tokens, credentials)
|
|
32
|
+
- Enable pluggable storage backends
|
|
33
|
+
|
|
34
|
+
### Error Handling
|
|
35
|
+
- Wrap all storage operations in try-catch blocks
|
|
36
|
+
- Return Result type instead of throwing exceptions
|
|
37
|
+
- Preserve original error context in cause property
|
|
38
|
+
- Support hierarchical error types for specific failures
|
|
39
|
+
|
|
40
|
+
### Serialization Strategy
|
|
41
|
+
- Use JSON.stringify for object serialization
|
|
42
|
+
- Use JSON.parse for deserialization with type safety
|
|
43
|
+
- Handle circular reference errors
|
|
44
|
+
- Support custom serialization for special types
|
|
45
|
+
|
|
46
|
+
## Restrictions
|
|
47
|
+
|
|
48
|
+
### Adapter Implementation
|
|
49
|
+
- DO NOT create adapters without implementing StateStorage interface
|
|
50
|
+
- DO NOT mix different storage backends in single adapter
|
|
51
|
+
- DO NOT skip error handling in adapter methods
|
|
52
|
+
- DO NOT store sensitive data without encryption
|
|
53
|
+
|
|
54
|
+
### Repository Usage
|
|
55
|
+
- DO NOT create new repository instances (use singleton)
|
|
56
|
+
- DO NOT bypass Result pattern error handling
|
|
57
|
+
- DO NOT use type assertions for type safety
|
|
58
|
+
- DO NOT ignore error codes from storage operations
|
|
59
|
+
|
|
60
|
+
### Storage Operations
|
|
61
|
+
- DO NOT perform operations without error handling
|
|
62
|
+
- DO NOT assume storage operations succeed
|
|
63
|
+
- DO NOT mix string and object storage methods
|
|
64
|
+
- DO NOT forget to handle null/undefined cases
|
|
65
|
+
|
|
66
|
+
### Error Handling
|
|
67
|
+
- DO NOT catch and ignore errors silently
|
|
68
|
+
- DO NOT expose sensitive data in error messages
|
|
69
|
+
- DO NOT lose error context when wrapping errors
|
|
70
|
+
- DO NOT create infinite error loops
|
|
71
|
+
|
|
72
|
+
### Serialization
|
|
73
|
+
- DO NOT serialize unsupported types (functions, symbols)
|
|
74
|
+
- DO NOT assume deserialization always succeeds
|
|
75
|
+
- DO NOT store raw data without validation
|
|
76
|
+
- DO NOT mix data formats in storage
|
|
77
|
+
|
|
78
|
+
## Rules
|
|
79
|
+
|
|
80
|
+
### Adapter Implementation
|
|
81
|
+
- MUST implement StateStorage interface for Zustand
|
|
82
|
+
- MUST provide getItem, setItem, removeItem methods
|
|
83
|
+
- MUST return Promise<string | null> from getItem
|
|
84
|
+
- MUST return Promise<void> from setItem and removeItem
|
|
85
|
+
- MUST handle errors gracefully in all methods
|
|
86
|
+
|
|
87
|
+
### AsyncStorageRepository
|
|
88
|
+
- MUST use singleton pattern (export storageRepository)
|
|
89
|
+
- MUST implement IStorageRepository interface
|
|
90
|
+
- MUST return StorageResult<T> from all methods
|
|
91
|
+
- MUST support generic type parameters
|
|
92
|
+
- MUST serialize objects with JSON.stringify
|
|
93
|
+
- MUST deserialize with JSON.parse and type validation
|
|
94
|
+
- MUST provide default value parameter for getItem
|
|
95
|
+
|
|
96
|
+
### Method Signatures
|
|
97
|
+
- MUST provide getItem<T>(key, defaultValue): Promise<StorageResult<T>>
|
|
98
|
+
- MUST provide setItem<T>(key, value): Promise<StorageResult<void>>
|
|
99
|
+
- MUST provide getString(key, defaultValue): Promise<StorageResult<string>>
|
|
100
|
+
- MUST provide setString(key, value): Promise<StorageResult<void>>
|
|
101
|
+
- MUST provide removeItem(key): Promise<StorageResult<void>>
|
|
102
|
+
- MUST provide hasItem(key): Promise<boolean>
|
|
103
|
+
- MUST provide clearAll(): Promise<StorageResult<void>>
|
|
104
|
+
|
|
105
|
+
### Error Handling
|
|
106
|
+
- MUST wrap all storage operations in try-catch
|
|
107
|
+
- MUST return failure() with StorageError on catch
|
|
108
|
+
- MUST preserve original error in cause property
|
|
109
|
+
- MUST include storage key in error context
|
|
110
|
+
- MUST use specific error types (StorageReadError, StorageWriteError)
|
|
111
|
+
- MUST not expose sensitive data in error messages
|
|
112
|
+
|
|
113
|
+
### Result Pattern
|
|
114
|
+
- MUST return success(data) on successful operations
|
|
115
|
+
- MUST return failure(error) on failed operations
|
|
116
|
+
- MUST check result.success before accessing result.data
|
|
117
|
+
- MUST handle result.error when success is false
|
|
118
|
+
- MUST not throw exceptions from repository methods
|
|
119
|
+
|
|
120
|
+
### Type Safety
|
|
121
|
+
- MUST use generic type parameters for all value operations
|
|
122
|
+
- MUST infer types from default value parameter
|
|
123
|
+
- MUST not use type assertions for type safety
|
|
124
|
+
- MUST validate types at runtime when deserializing
|
|
125
|
+
- MUST support complex types (objects, arrays)
|
|
126
|
+
|
|
127
|
+
### Singleton Pattern
|
|
128
|
+
- MUST export single storageRepository instance
|
|
129
|
+
- MUST use singleton for production code
|
|
130
|
+
- MUST enable instance creation for testing
|
|
131
|
+
- MUST not create multiple instances in production
|
|
132
|
+
|
|
133
|
+
### Custom Adapters
|
|
134
|
+
- MUST implement StateStorage interface
|
|
135
|
+
- MUST handle all required methods
|
|
136
|
+
- MUST support async operations
|
|
137
|
+
- MUST provide error handling
|
|
138
|
+
- MUST be compatible with Zustand persist
|
|
139
|
+
|
|
140
|
+
### SecureStore Integration
|
|
141
|
+
- MUST use SecureStore for sensitive data only
|
|
142
|
+
- MUST create separate adapter for SecureStore
|
|
143
|
+
- MUST not mix secure and non-secure storage
|
|
144
|
+
- MUST handle SecureStore-specific errors
|
|
145
|
+
|
|
146
|
+
### Testing Support
|
|
147
|
+
- MUST enable mocking for all methods
|
|
148
|
+
- MUST provide test double support
|
|
149
|
+
- MUST clear state between tests
|
|
150
|
+
- MUST not have hidden dependencies
|
|
151
|
+
- MUST support dependency injection
|
|
152
|
+
|
|
153
|
+
### Export Rules
|
|
154
|
+
- MUST export storageRepository singleton
|
|
155
|
+
- MUST export AsyncStorageRepository class
|
|
156
|
+
- MUST export storageService adapter
|
|
157
|
+
- MUST export all error types
|
|
158
|
+
- MUST export interface types
|
|
159
|
+
|
|
160
|
+
### Documentation
|
|
161
|
+
- MUST document all public methods
|
|
162
|
+
- MUST specify error types thrown
|
|
163
|
+
- MUST provide usage examples in separate files
|
|
164
|
+
- MUST warn about common mistakes
|
|
165
|
+
- MUST not include code in README files
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Storage Adapters
|
|
2
|
+
|
|
3
|
+
Adapters for integrating Zustand persist middleware with various storage backends.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Storage adapter implementations for Zustand persist middleware. Located at `src/infrastructure/adapters/`.
|
|
8
|
+
|
|
9
|
+
## Strategies
|
|
10
|
+
|
|
11
|
+
### Adapter Pattern
|
|
12
|
+
- Use StorageService adapter for AsyncStorage integration
|
|
13
|
+
- Implement StateStorage interface for Zustand compatibility
|
|
14
|
+
- Support multiple storage backends (AsyncStorage, MMKV, SecureStore)
|
|
15
|
+
- Enable custom adapter creation for specific needs
|
|
16
|
+
|
|
17
|
+
### Storage Backend Selection
|
|
18
|
+
- Use AsyncStorage for general-purpose storage
|
|
19
|
+
- Use MMKV for high-performance key-value storage
|
|
20
|
+
- Use SecureStore for sensitive data (tokens, credentials)
|
|
21
|
+
- Use SQLite for complex relational data
|
|
22
|
+
- Use file system for large data or binary files
|
|
23
|
+
|
|
24
|
+
### Adapter Composition
|
|
25
|
+
- Use namespaced adapters for key isolation
|
|
26
|
+
- Use hybrid adapters for multi-level caching
|
|
27
|
+
- Use encrypted adapters for data security
|
|
28
|
+
- Use migrating adapters for version management
|
|
29
|
+
|
|
30
|
+
### Error Handling
|
|
31
|
+
- Wrap all storage operations in try-catch blocks
|
|
32
|
+
- Return null on read failures for graceful degradation
|
|
33
|
+
- Log errors for debugging
|
|
34
|
+
- Implement retry logic for transient failures
|
|
35
|
+
|
|
36
|
+
## Restrictions
|
|
37
|
+
|
|
38
|
+
### Adapter Implementation
|
|
39
|
+
- DO NOT create adapters without implementing StateStorage interface
|
|
40
|
+
- DO NOT mix synchronous and asynchronous operations
|
|
41
|
+
- DO NOT ignore errors in adapter methods
|
|
42
|
+
- DO NOT create infinite loops in error handlers
|
|
43
|
+
|
|
44
|
+
### Storage Selection
|
|
45
|
+
- DO NOT use SecureStore for large data
|
|
46
|
+
- DO NOT use AsyncStorage for frequently accessed data
|
|
47
|
+
- DO NOT use file system for simple key-value storage
|
|
48
|
+
- DO NOT use sensitive storage for non-sensitive data
|
|
49
|
+
|
|
50
|
+
### Adapter Usage
|
|
51
|
+
- DO NOT use the same adapter instance for different purposes
|
|
52
|
+
- DO NOT create adapters without proper error handling
|
|
53
|
+
- DO NOT share adapters between incompatible stores
|
|
54
|
+
- DO NOT forget to clean up resources
|
|
55
|
+
|
|
56
|
+
### Custom Adapters
|
|
57
|
+
- DO NOT implement custom adapters without necessity
|
|
58
|
+
- DO NOT skip implementing required interface methods
|
|
59
|
+
- DO NOT create adapters with hidden dependencies
|
|
60
|
+
- DO NOT use adapters without testing
|
|
61
|
+
|
|
62
|
+
## Rules
|
|
63
|
+
|
|
64
|
+
### StateStorage Interface
|
|
65
|
+
- MUST implement getItem(key): Promise<string | null>
|
|
66
|
+
- MUST implement setItem(key, value): Promise<void>
|
|
67
|
+
- MUST implement removeItem(key): Promise<void>
|
|
68
|
+
- MUST handle all errors gracefully
|
|
69
|
+
- MUST return Promise for all methods
|
|
70
|
+
- MUST be compatible with Zustand persist middleware
|
|
71
|
+
|
|
72
|
+
### StorageService Adapter
|
|
73
|
+
- MUST use AsyncStorage for storage operations
|
|
74
|
+
- MUST handle serialization/deserialization
|
|
75
|
+
- MUST provide null for missing keys
|
|
76
|
+
- MUST not throw exceptions for missing data
|
|
77
|
+
- MUST be the default adapter for Zustand stores
|
|
78
|
+
|
|
79
|
+
### Custom Adapter Creation
|
|
80
|
+
- MUST implement StateStorage interface completely
|
|
81
|
+
- MUST handle all three required methods
|
|
82
|
+
- MUST provide async method implementations
|
|
83
|
+
- MUST include error handling
|
|
84
|
+
- MUST be compatible with Zustand persist
|
|
85
|
+
|
|
86
|
+
### SecureStore Adapter
|
|
87
|
+
- MUST use expo-secure-store for implementation
|
|
88
|
+
- MUST handle SecureStore-specific errors
|
|
89
|
+
- MUST be used only for sensitive data
|
|
90
|
+
- MUST not store large amounts of data
|
|
91
|
+
- MUST provide proper error messages
|
|
92
|
+
|
|
93
|
+
### MMKV Adapter
|
|
94
|
+
- MUST use react-native-mmkv for implementation
|
|
95
|
+
- MUST initialize MMKV instance properly
|
|
96
|
+
- MUST handle type conversions
|
|
97
|
+
- MUST provide high-performance storage
|
|
98
|
+
- MUST support synchronous operations if needed
|
|
99
|
+
|
|
100
|
+
### SQLite Adapter
|
|
101
|
+
- MUST initialize database schema on first use
|
|
102
|
+
- MUST use transactions for data integrity
|
|
103
|
+
- MUST handle database connection errors
|
|
104
|
+
- MUST use parameterized queries
|
|
105
|
+
- MUST close connections properly
|
|
106
|
+
|
|
107
|
+
### File System Adapter
|
|
108
|
+
- MUST validate file paths
|
|
109
|
+
- MUST handle file system permissions
|
|
110
|
+
- MUST provide proper error messages
|
|
111
|
+
- MUST clean up temporary files
|
|
112
|
+
- MUST handle concurrent access safely
|
|
113
|
+
|
|
114
|
+
### Encrypted Adapter
|
|
115
|
+
- MUST use strong encryption algorithms
|
|
116
|
+
- MUST properly manage encryption keys
|
|
117
|
+
- MUST handle encryption/decryption errors
|
|
118
|
+
- MUST not expose keys in logs
|
|
119
|
+
- MUST use secure key storage
|
|
120
|
+
|
|
121
|
+
### Namespaced Adapter
|
|
122
|
+
- MUST prefix all keys with namespace
|
|
123
|
+
- MUST use consistent separator (:) in keys
|
|
124
|
+
- MUST enable key isolation between stores
|
|
125
|
+
- MUST prevent key collisions
|
|
126
|
+
- MUST be composable with other adapters
|
|
127
|
+
|
|
128
|
+
### Hybrid Adapter
|
|
129
|
+
- MUST define clear fallback strategy
|
|
130
|
+
- MUST handle consistency between storages
|
|
131
|
+
- MUST implement read-through caching
|
|
132
|
+
- MUST implement write-through caching
|
|
133
|
+
- MUST handle partial failures gracefully
|
|
134
|
+
|
|
135
|
+
### Migrating Adapter
|
|
136
|
+
- MUST support version management
|
|
137
|
+
- MUST migrate data on read
|
|
138
|
+
- MUST clean up old data after migration
|
|
139
|
+
- MUST handle migration failures
|
|
140
|
+
- MUST be backward compatible
|
|
141
|
+
|
|
142
|
+
### Error Handling
|
|
143
|
+
- MUST catch all exceptions in adapter methods
|
|
144
|
+
- MUST return null on read failures
|
|
145
|
+
- MUST log errors for debugging
|
|
146
|
+
- MUST not expose sensitive data in errors
|
|
147
|
+
- MUST provide meaningful error context
|
|
148
|
+
|
|
149
|
+
### Performance Considerations
|
|
150
|
+
- MUST minimize storage operations
|
|
151
|
+
- MUST batch operations when possible
|
|
152
|
+
- MUST use appropriate storage for data size
|
|
153
|
+
- MUST consider synchronous vs asynchronous operations
|
|
154
|
+
- MUST optimize for read-heavy or write-heavy patterns
|
|
155
|
+
|
|
156
|
+
### Testing Support
|
|
157
|
+
- MUST enable adapter mocking
|
|
158
|
+
- MUST provide test implementations
|
|
159
|
+
- MUST support dependency injection
|
|
160
|
+
- MUST clear state between tests
|
|
161
|
+
- MUST not have hidden dependencies
|
|
162
|
+
|
|
163
|
+
### Export Rules
|
|
164
|
+
- MUST export storageService as default adapter
|
|
165
|
+
- MUST export adapter types
|
|
166
|
+
- MUST export adapter utilities
|
|
167
|
+
- MUST document adapter behavior
|
|
168
|
+
- MUST provide usage examples separately
|
|
169
|
+
|
|
170
|
+
### Documentation
|
|
171
|
+
- MUST document all custom adapters
|
|
172
|
+
- MUST specify storage backend requirements
|
|
173
|
+
- MUST explain adapter behavior
|
|
174
|
+
- MUST warn about limitations
|
|
175
|
+
- MUST not include code in README files
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Storage Service
|
|
2
|
+
|
|
3
|
+
Zustand persist middleware adapter for AsyncStorage integration.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
StorageService adapts AsyncStorage for use with Zustand's persist middleware, providing automatic state persistence. Located at `src/infrastructure/adapters/StorageService.ts`.
|
|
8
|
+
|
|
9
|
+
## Strategies
|
|
10
|
+
|
|
11
|
+
### Storage Adapter Pattern
|
|
12
|
+
- Implement StateStorage interface for Zustand compatibility
|
|
13
|
+
- Wrap AsyncStorage operations in try-catch blocks
|
|
14
|
+
- Provide graceful error handling with logging
|
|
15
|
+
- Return null/undefined on errors to prevent app crashes
|
|
16
|
+
|
|
17
|
+
### Error Handling Strategy
|
|
18
|
+
- Log all storage errors with context
|
|
19
|
+
- Return null on getItem errors
|
|
20
|
+
- Throw errors on setItem/removeItem for persist middleware
|
|
21
|
+
- Include key name in error messages
|
|
22
|
+
|
|
23
|
+
### Custom Adapters
|
|
24
|
+
- Create SecureStore adapter for sensitive data (tokens, credentials)
|
|
25
|
+
- Create encrypted storage adapter for high-security requirements
|
|
26
|
+
- Create namespaced adapters for data isolation
|
|
27
|
+
- Create platform-specific adapters (web localStorage vs native)
|
|
28
|
+
|
|
29
|
+
## Restrictions
|
|
30
|
+
|
|
31
|
+
### Storage Operations
|
|
32
|
+
- DO NOT use StorageService outside Zustand persist middleware
|
|
33
|
+
- DO NOT store non-serializable data (functions, class instances)
|
|
34
|
+
- DO NOT store large payloads (> 1MB) without chunking strategy
|
|
35
|
+
- DO NOT mix data types in same storage key
|
|
36
|
+
|
|
37
|
+
### Error Handling
|
|
38
|
+
- DO NOT ignore storage errors in production
|
|
39
|
+
- DO NOT throw on getItem errors (return null instead)
|
|
40
|
+
- DO NOT suppress setItem/removeItem errors
|
|
41
|
+
- DO NOT log sensitive data in error messages
|
|
42
|
+
|
|
43
|
+
### Custom Adapters
|
|
44
|
+
- DO NOT create adapters without implementing StateStorage interface
|
|
45
|
+
- DO NOT use SecureStore for non-sensitive data (performance)
|
|
46
|
+
- DO NOT use encryption without secure key management
|
|
47
|
+
- DO NOT create platform-specific adapters without Platform checks
|
|
48
|
+
|
|
49
|
+
## Rules
|
|
50
|
+
|
|
51
|
+
### Interface Implementation
|
|
52
|
+
- MUST implement `getItem(key: string): Promise<string | null>`
|
|
53
|
+
- MUST implement `setItem(key: string, value: string): Promise<void>`
|
|
54
|
+
- MUST implement `removeItem(key: string): Promise<void>`
|
|
55
|
+
- MUST return Promise for all methods
|
|
56
|
+
|
|
57
|
+
### Error Handling
|
|
58
|
+
- MUST wrap all AsyncStorage operations in try-catch
|
|
59
|
+
- MUST log errors with key name for debugging
|
|
60
|
+
- MUST return null on getItem errors
|
|
61
|
+
- MUST throw original error on setItem/removeItem errors
|
|
62
|
+
|
|
63
|
+
### Store Configuration
|
|
64
|
+
- MUST use unique store names across all stores
|
|
65
|
+
- MUST pass storageService as storage option
|
|
66
|
+
- MUST specify store name in persist config
|
|
67
|
+
- MUST handle migration when store schema changes
|
|
68
|
+
|
|
69
|
+
### Multiple Stores
|
|
70
|
+
- MUST use different store names for different stores
|
|
71
|
+
- MUST ensure store names are unique across app
|
|
72
|
+
- MUST document each store's purpose
|
|
73
|
+
- MUST consider storage key conflicts
|
|
74
|
+
|
|
75
|
+
### Custom Adapter Creation
|
|
76
|
+
- MUST implement complete StateStorage interface
|
|
77
|
+
- MUST handle errors consistently with base adapter
|
|
78
|
+
- MUST log errors with context
|
|
79
|
+
- MUST document adapter purpose and security model
|
|
80
|
+
|
|
81
|
+
### Secure Storage
|
|
82
|
+
- MUST use SecureStore for sensitive data only
|
|
83
|
+
- MUST document what data is secure vs regular storage
|
|
84
|
+
- MUST handle SecureStore unavailability (web platform)
|
|
85
|
+
- MUST provide fallback for secure storage failures
|
|
86
|
+
|
|
87
|
+
### Testing
|
|
88
|
+
- MUST mock StorageService in tests
|
|
89
|
+
- MUST clear storage in test setup
|
|
90
|
+
- MUST test error scenarios
|
|
91
|
+
- MUST test serialization/deserialization
|
|
92
|
+
|
|
93
|
+
### Version Control
|
|
94
|
+
- MUST increment version when store schema changes
|
|
95
|
+
- MUST implement migrate function for schema changes
|
|
96
|
+
- MUST test migration with old persisted data
|
|
97
|
+
- MUST document migration path
|
|
98
|
+
|
|
99
|
+
### Performance
|
|
100
|
+
- MUST consider storage operation performance
|
|
101
|
+
- MUST avoid frequent setItem calls (debounce if needed)
|
|
102
|
+
- MUST batch operations when possible
|
|
103
|
+
- MUST monitor storage size limits
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Service
|
|
3
|
+
*
|
|
4
|
+
* Zustand persist middleware compatible StateStorage implementation.
|
|
5
|
+
* Uses AsyncStorage under the hood for React Native persistence.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
9
|
+
import { devWarn } from '../../domain/utils/devUtils';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* StateStorage interface for Zustand persist middleware
|
|
13
|
+
*/
|
|
14
|
+
export interface StateStorage {
|
|
15
|
+
getItem: (name: string) => string | null | Promise<string | null>;
|
|
16
|
+
setItem: (name: string, value: string) => void | Promise<void>;
|
|
17
|
+
removeItem: (name: string) => void | Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Storage service for Zustand persist middleware
|
|
22
|
+
* Direct AsyncStorage implementation with proper error handling
|
|
23
|
+
*/
|
|
24
|
+
export const storageService: StateStorage = {
|
|
25
|
+
getItem: async (name: string): Promise<string | null> => {
|
|
26
|
+
try {
|
|
27
|
+
return await AsyncStorage.getItem(name);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
devWarn(`StorageService: Failed to get item "${name}"`, error);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
setItem: async (name: string, value: string): Promise<void> => {
|
|
35
|
+
try {
|
|
36
|
+
await AsyncStorage.setItem(name, value);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
devWarn(`StorageService: Failed to set item "${name}"`, error);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
removeItem: async (name: string): Promise<void> => {
|
|
43
|
+
try {
|
|
44
|
+
await AsyncStorage.removeItem(name);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
devWarn(`StorageService: Failed to remove item "${name}"`, error);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|