@umituz/react-native-settings 4.20.57 → 4.20.59
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/.github/ISSUE_TEMPLATE/bug_report.md +51 -0
- package/.github/ISSUE_TEMPLATE/documentation.md +52 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +63 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +84 -0
- package/AI_AGENT_GUIDELINES.md +367 -0
- package/ARCHITECTURE.md +246 -0
- package/CHANGELOG.md +67 -0
- package/CODE_OF_CONDUCT.md +75 -0
- package/CONTRIBUTING.md +107 -0
- package/DOCUMENTATION_MIGRATION.md +319 -0
- package/DOCUMENTATION_TEMPLATE.md +155 -0
- package/LICENSE +21 -0
- package/README.md +321 -498
- package/SECURITY.md +98 -0
- package/SETTINGS_SCREEN_GUIDE.md +185 -0
- package/TESTING.md +358 -0
- package/package.json +13 -2
- package/src/__tests__/setup.ts +1 -4
- package/src/application/README.md +85 -271
- package/src/domains/about/README.md +85 -440
- package/src/domains/about/presentation/hooks/README.md +93 -348
- package/src/domains/appearance/README.md +95 -584
- package/src/domains/appearance/hooks/README.md +95 -303
- package/src/domains/appearance/infrastructure/services/README.md +83 -397
- package/src/domains/appearance/presentation/components/README.md +99 -0
- package/src/domains/cloud-sync/README.md +73 -439
- package/src/domains/cloud-sync/presentation/components/README.md +95 -493
- package/src/domains/dev/README.md +71 -457
- package/src/domains/disclaimer/README.md +77 -411
- package/src/domains/disclaimer/presentation/components/README.md +95 -392
- package/src/domains/faqs/README.md +86 -574
- package/src/domains/feedback/README.md +79 -553
- package/src/domains/feedback/presentation/hooks/README.md +93 -426
- package/src/domains/legal/README.md +88 -537
- package/src/domains/rating/README.md +73 -440
- package/src/domains/rating/presentation/components/README.md +95 -475
- package/src/domains/video-tutorials/README.md +77 -470
- package/src/domains/video-tutorials/presentation/components/README.md +95 -431
- package/src/infrastructure/README.md +78 -425
- package/src/infrastructure/repositories/README.md +88 -420
- package/src/infrastructure/services/README.md +74 -460
- package/src/presentation/components/README.md +97 -480
- package/src/presentation/components/SettingsErrorBoundary/README.md +48 -442
- package/src/presentation/components/SettingsFooter/README.md +48 -427
- package/src/presentation/components/SettingsItemCard/README.md +153 -392
- package/src/presentation/components/SettingsItemCard/STRATEGY.md +164 -0
- package/src/presentation/components/SettingsSection/README.md +47 -401
- package/src/presentation/hooks/README.md +95 -389
- package/src/presentation/hooks/mutations/README.md +99 -376
- package/src/presentation/hooks/queries/README.md +111 -353
- package/src/presentation/navigation/README.md +70 -502
- package/src/presentation/navigation/components/README.md +70 -295
- package/src/presentation/navigation/hooks/README.md +75 -367
- package/src/presentation/navigation/utils/README.md +100 -380
- package/src/presentation/screens/README.md +53 -504
- package/src/presentation/screens/components/SettingsContent/README.md +53 -382
- package/src/presentation/screens/components/SettingsHeader/README.md +48 -303
- package/src/presentation/screens/components/sections/CustomSettingsList/README.md +47 -359
- package/src/presentation/screens/components/sections/FeatureSettingsSection/README.md +81 -176
- package/src/presentation/screens/components/sections/IdentitySettingsSection/README.md +40 -297
- package/src/presentation/screens/components/sections/ProfileSectionLoader/README.md +47 -451
- package/src/presentation/screens/components/sections/SupportSettingsSection/README.md +45 -361
- package/src/presentation/screens/hooks/README.md +64 -354
- package/src/presentation/screens/types/README.md +79 -409
- package/src/presentation/screens/utils/README.md +65 -255
|
@@ -1,458 +1,132 @@
|
|
|
1
1
|
# Settings Repository
|
|
2
2
|
|
|
3
|
-
Repository implementation for settings data persistence using
|
|
3
|
+
Repository implementation for settings data persistence using storage abstraction.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Purpose
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Automatic Defaults**: Creates default settings for new users
|
|
9
|
-
- **Type Safety**: Full TypeScript support
|
|
10
|
-
- **Error Handling**: Comprehensive error catching
|
|
11
|
-
- **Storage Integration**: Uses storage repository
|
|
12
|
-
- **Performance**: Optimized for frequent reads
|
|
7
|
+
Provides concrete implementation of the settings repository interface, handling all data persistence operations including CRUD operations, defaults creation, and storage management.
|
|
13
8
|
|
|
14
|
-
##
|
|
9
|
+
## File Paths
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
### Basic Usage
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
import { SettingsRepository } from '@umituz/react-native-settings';
|
|
24
|
-
|
|
25
|
-
const repository = new SettingsRepository();
|
|
26
|
-
|
|
27
|
-
// Get settings
|
|
28
|
-
const settings = await repository.get('user123');
|
|
29
|
-
|
|
30
|
-
// Update settings
|
|
31
|
-
const updated = await repository.update('user123', {
|
|
32
|
-
theme: 'dark',
|
|
33
|
-
language: 'tr-TR',
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Reset settings
|
|
37
|
-
const defaults = await repository.reset('user123');
|
|
11
|
+
```
|
|
12
|
+
src/infrastructure/repositories/
|
|
13
|
+
└── SettingsRepository.ts # Settings repository implementation
|
|
38
14
|
```
|
|
39
15
|
|
|
40
|
-
|
|
16
|
+
## Strategy
|
|
41
17
|
|
|
42
|
-
|
|
43
|
-
|
|
18
|
+
1. **Interface Implementation**: Implement ISettingsRepository from application layer
|
|
19
|
+
2. **Automatic Defaults**: Create defaults for new users automatically
|
|
20
|
+
3. **Error Transformation**: Convert storage errors to domain errors
|
|
21
|
+
4. **Performance**: Optimize for frequent reads with optional caching
|
|
22
|
+
5. **Migration Support**: Handle schema versioning and migrations
|
|
44
23
|
|
|
45
|
-
|
|
46
|
-
const repository = new SettingsRepository(storage);
|
|
24
|
+
## Restrictions
|
|
47
25
|
|
|
48
|
-
|
|
49
|
-
```
|
|
26
|
+
### DO NOT
|
|
50
27
|
|
|
51
|
-
|
|
28
|
+
- ❌ DO NOT include business logic that belongs in services
|
|
29
|
+
- ❌ DO NOT expose storage-specific implementation details
|
|
30
|
+
- ❌ DO NOT make assumptions about storage backend
|
|
31
|
+
- ❌ DO NOT use synchronous operations
|
|
32
|
+
- ❌ DO NOT expose raw storage errors to upper layers
|
|
52
33
|
|
|
53
|
-
###
|
|
34
|
+
### NEVER
|
|
54
35
|
|
|
55
|
-
|
|
36
|
+
- ❌ NEVER return data without applying defaults
|
|
37
|
+
- ❌ NEVER assume storage always succeeds
|
|
38
|
+
- ❌ EVER bypass storage abstraction
|
|
39
|
+
- ❌ EVER cache without invalidation strategy
|
|
56
40
|
|
|
57
|
-
|
|
58
|
-
const settings = await repository.get('user123');
|
|
41
|
+
### AVOID
|
|
59
42
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
43
|
+
- ❌ AVOID hardcoding storage keys or formats
|
|
44
|
+
- ❌ AVOID tight coupling to specific storage implementation
|
|
45
|
+
- ❌ AVOID blocking operations on main thread
|
|
46
|
+
- ❌ AVOID ignoring storage capacity limits
|
|
64
47
|
|
|
65
|
-
|
|
48
|
+
## Rules
|
|
66
49
|
|
|
67
|
-
|
|
50
|
+
### ALWAYS
|
|
68
51
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
} catch (error) {
|
|
75
|
-
console.error('Failed to load settings:', error);
|
|
76
|
-
throw error;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
```
|
|
52
|
+
- ✅ ALWAYS implement the full repository interface
|
|
53
|
+
- ✅ ALWAYS provide default values for new users
|
|
54
|
+
- ✅ ALWAYS handle storage errors gracefully
|
|
55
|
+
- ✅ ALWAYS use async/await for I/O operations
|
|
56
|
+
- ✅ ALWAYS return typed results
|
|
80
57
|
|
|
81
|
-
###
|
|
58
|
+
### MUST
|
|
82
59
|
|
|
83
|
-
|
|
60
|
+
- ✅ MUST validate data before storage
|
|
61
|
+
- ✅ MUST transform storage errors to domain errors
|
|
62
|
+
- ✅ MUST use dependency injection for storage
|
|
63
|
+
- ✅ MUST handle concurrent operations safely
|
|
84
64
|
|
|
85
|
-
|
|
86
|
-
const updated = await repository.update('user123', {
|
|
87
|
-
theme: 'dark',
|
|
88
|
-
notificationsEnabled: false,
|
|
89
|
-
});
|
|
65
|
+
### SHOULD
|
|
90
66
|
|
|
91
|
-
|
|
92
|
-
|
|
67
|
+
- ✅ SHOULD cache frequently accessed data
|
|
68
|
+
- ✅ SHOULD provide migration path for schema changes
|
|
69
|
+
- ✅ SHOULD handle storage unavailability
|
|
70
|
+
- ✅ SHOULD log storage operations for debugging
|
|
93
71
|
|
|
94
|
-
|
|
72
|
+
## AI Agent Guidelines
|
|
95
73
|
|
|
96
|
-
**
|
|
74
|
+
1. **When implementing repositories**: Always inject storage dependencies
|
|
75
|
+
2. **When handling errors**: Transform technical errors to domain errors
|
|
76
|
+
3. **When adding caching**: Implement proper invalidation strategy
|
|
77
|
+
4. **When creating defaults**: Match application's expected behavior
|
|
78
|
+
5. **When handling migrations**: Ensure backward compatibility
|
|
97
79
|
|
|
98
|
-
|
|
99
|
-
async function updateTheme(userId: string, theme: 'light' | 'dark') {
|
|
100
|
-
try {
|
|
101
|
-
const updated = await repository.update(userId, { theme });
|
|
102
|
-
return updated;
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error('Failed to update theme:', error);
|
|
105
|
-
throw error;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
```
|
|
80
|
+
## Repository Reference
|
|
109
81
|
|
|
110
|
-
###
|
|
82
|
+
### SettingsRepository
|
|
111
83
|
|
|
112
|
-
|
|
84
|
+
Concrete implementation of ISettingsRepository using storage abstraction.
|
|
113
85
|
|
|
114
|
-
|
|
115
|
-
const defaults = await repository.reset('user123');
|
|
116
|
-
|
|
117
|
-
console.log(defaults.theme); // 'light' (default)
|
|
118
|
-
console.log(defaults.language); // 'en-US' (default)
|
|
119
|
-
```
|
|
86
|
+
**Location**: `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-settings/src/infrastructure/repositories/SettingsRepository.ts`
|
|
120
87
|
|
|
121
|
-
**
|
|
88
|
+
**Methods**:
|
|
89
|
+
- `get(userId: string): Promise<UserSettings>` - Get with auto-defaults
|
|
90
|
+
- `update(userId: string, updates: Partial<UserSettings>): Promise<UserSettings>` - Update settings
|
|
91
|
+
- `reset(userId: string): Promise<UserSettings>` - Reset to defaults
|
|
122
92
|
|
|
123
|
-
|
|
93
|
+
## Storage Keys
|
|
124
94
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
const defaults = await repository.reset(userId);
|
|
129
|
-
return defaults;
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error('Failed to reset settings:', error);
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
```
|
|
95
|
+
**Pattern**: `settings:{userId}`
|
|
96
|
+
**Example**: `settings:user123`, `settings:admin`
|
|
136
97
|
|
|
137
98
|
## Data Structure
|
|
138
99
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
pushNotifications: boolean; // Push notification preference
|
|
149
|
-
soundEnabled: boolean; // Sound effects toggle
|
|
150
|
-
vibrationEnabled: boolean; // Haptic feedback toggle
|
|
151
|
-
quietHoursEnabled: boolean; // Quiet hours feature
|
|
152
|
-
quietHoursStart: string; // Start time (HH:MM format)
|
|
153
|
-
quietHoursEnd: string; // End time (HH:MM format)
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Storage Format
|
|
158
|
-
|
|
159
|
-
Settings are stored in the following format:
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
{
|
|
163
|
-
"settings:user123": {
|
|
164
|
-
"userId": "user123",
|
|
165
|
-
"theme": "dark",
|
|
166
|
-
"language": "tr-TR",
|
|
167
|
-
"notificationsEnabled": true,
|
|
168
|
-
"emailNotifications": true,
|
|
169
|
-
"pushNotifications": true,
|
|
170
|
-
"soundEnabled": true,
|
|
171
|
-
"vibrationEnabled": true,
|
|
172
|
-
"quietHoursEnabled": false,
|
|
173
|
-
"quietHoursStart": "22:00",
|
|
174
|
-
"quietHoursEnd": "08:00"
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
```
|
|
100
|
+
Settings are stored as JSON containing all user preferences:
|
|
101
|
+
- User identification (userId)
|
|
102
|
+
- Theme preferences (theme, customColors)
|
|
103
|
+
- Localization (language)
|
|
104
|
+
- Notifications (enabled, email, push, quietHours)
|
|
105
|
+
- Audio (sound, vibration)
|
|
106
|
+
- Privacy (privacyMode)
|
|
107
|
+
- Legal (disclaimerAccepted)
|
|
108
|
+
- Metadata (updatedAt)
|
|
178
109
|
|
|
179
110
|
## Default Values
|
|
180
111
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
soundEnabled: true,
|
|
192
|
-
vibrationEnabled: true,
|
|
193
|
-
quietHoursEnabled: false,
|
|
194
|
-
quietHoursStart: '22:00',
|
|
195
|
-
quietHoursEnd: '08:00',
|
|
196
|
-
};
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Applying Defaults
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
function applyDefaults(
|
|
203
|
-
userId: string,
|
|
204
|
-
existing?: Partial<UserSettings>
|
|
205
|
-
): UserSettings {
|
|
206
|
-
return {
|
|
207
|
-
...defaultSettings,
|
|
208
|
-
userId,
|
|
209
|
-
...existing,
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
## Storage Keys
|
|
215
|
-
|
|
216
|
-
### Key Format
|
|
217
|
-
|
|
218
|
-
```typescript
|
|
219
|
-
function getStorageKey(userId: string): string {
|
|
220
|
-
return `settings:${userId}`;
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
**Examples**:
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
getStorageKey('user123'); // 'settings:user123'
|
|
228
|
-
getStorageKey('admin'); // 'settings:admin'
|
|
229
|
-
```
|
|
112
|
+
**Applied automatically** for new users or when data is missing:
|
|
113
|
+
- theme: 'auto'
|
|
114
|
+
- language: 'en-US'
|
|
115
|
+
- notificationsEnabled: true
|
|
116
|
+
- emailNotifications: true
|
|
117
|
+
- pushNotifications: true
|
|
118
|
+
- soundEnabled: true
|
|
119
|
+
- vibrationEnabled: true
|
|
120
|
+
- privacyMode: false
|
|
121
|
+
- disclaimerAccepted: false
|
|
230
122
|
|
|
231
123
|
## Error Handling
|
|
232
124
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
} catch (error) {
|
|
239
|
-
if (error.code === 'STORAGE_ERROR') {
|
|
240
|
-
console.error('Storage operation failed:', error.message);
|
|
241
|
-
} else if (error.code === 'NETWORK_ERROR') {
|
|
242
|
-
console.error('Network error:', error.message);
|
|
243
|
-
} else {
|
|
244
|
-
console.error('Unknown error:', error.message);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### Error Types
|
|
250
|
-
|
|
251
|
-
```typescript
|
|
252
|
-
enum SettingsErrorCode {
|
|
253
|
-
NOT_FOUND = 'NOT_FOUND',
|
|
254
|
-
STORAGE_ERROR = 'STORAGE_ERROR',
|
|
255
|
-
NETWORK_ERROR = 'NETWORK_ERROR',
|
|
256
|
-
VALIDATION_ERROR = 'VALIDATION_ERROR',
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
class SettingsRepositoryError extends Error {
|
|
260
|
-
constructor(
|
|
261
|
-
message: string,
|
|
262
|
-
public code: SettingsErrorCode,
|
|
263
|
-
public originalError?: Error
|
|
264
|
-
) {
|
|
265
|
-
super(message);
|
|
266
|
-
this.name = 'SettingsRepositoryError';
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
## Performance
|
|
272
|
-
|
|
273
|
-
### Optimized Reads
|
|
274
|
-
|
|
275
|
-
```typescript
|
|
276
|
-
class SettingsRepository {
|
|
277
|
-
private cache = new Map<string, UserSettings>();
|
|
278
|
-
|
|
279
|
-
async get(userId: string): Promise<UserSettings> {
|
|
280
|
-
// Check cache first
|
|
281
|
-
if (this.cache.has(userId)) {
|
|
282
|
-
return this.cache.get(userId)!;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Load from storage
|
|
286
|
-
const settings = await this.loadFromStorage(userId);
|
|
287
|
-
|
|
288
|
-
// Cache result
|
|
289
|
-
this.cache.set(userId, settings);
|
|
290
|
-
|
|
291
|
-
return settings;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async update(
|
|
295
|
-
userId: string,
|
|
296
|
-
updates: Partial<UserSettings>
|
|
297
|
-
): Promise<UserSettings> {
|
|
298
|
-
const settings = await this.get(userId);
|
|
299
|
-
|
|
300
|
-
const updated = {
|
|
301
|
-
...settings,
|
|
302
|
-
...updates,
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
// Save to storage
|
|
306
|
-
await this.saveToStorage(userId, updated);
|
|
307
|
-
|
|
308
|
-
// Update cache
|
|
309
|
-
this.cache.set(userId, updated);
|
|
310
|
-
|
|
311
|
-
return updated;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
invalidateCache(userId?: string): void {
|
|
315
|
-
if (userId) {
|
|
316
|
-
this.cache.delete(userId);
|
|
317
|
-
} else {
|
|
318
|
-
this.cache.clear();
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
## Migrations
|
|
325
|
-
|
|
326
|
-
### Schema Versioning
|
|
327
|
-
|
|
328
|
-
```typescript
|
|
329
|
-
interface SettingsSchema {
|
|
330
|
-
version: number;
|
|
331
|
-
settings: UserSettings;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
async function migrateSettings(
|
|
335
|
-
oldVersion: number,
|
|
336
|
-
newVersion: number,
|
|
337
|
-
settings: any
|
|
338
|
-
): Promise<UserSettings> {
|
|
339
|
-
if (oldVersion === 1 && newVersion === 2) {
|
|
340
|
-
// Migration from v1 to v2
|
|
341
|
-
return {
|
|
342
|
-
...settings,
|
|
343
|
-
newField: defaultSettings.newField,
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
return settings;
|
|
348
|
-
}
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### Running Migrations
|
|
352
|
-
|
|
353
|
-
```typescript
|
|
354
|
-
class SettingsRepository {
|
|
355
|
-
private readonly CURRENT_VERSION = 2;
|
|
356
|
-
|
|
357
|
-
async get(userId: string): Promise<UserSettings> {
|
|
358
|
-
const stored = await storage.get(`settings:${userId}`);
|
|
359
|
-
|
|
360
|
-
if (!stored) {
|
|
361
|
-
return this.createDefaults(userId);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Check version
|
|
365
|
-
if (stored.version < this.CURRENT_VERSION) {
|
|
366
|
-
return this.migrate(stored);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
return stored.settings;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
private async migrate(stored: any): Promise<UserSettings> {
|
|
373
|
-
const settings = await migrateSettings(
|
|
374
|
-
stored.version,
|
|
375
|
-
this.CURRENT_VERSION,
|
|
376
|
-
stored.settings
|
|
377
|
-
);
|
|
378
|
-
|
|
379
|
-
// Save migrated settings
|
|
380
|
-
await this.saveToStorage(stored.userId, settings);
|
|
381
|
-
|
|
382
|
-
return settings;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
## Testing
|
|
388
|
-
|
|
389
|
-
### Mock Repository
|
|
390
|
-
|
|
391
|
-
```typescript
|
|
392
|
-
class MockSettingsRepository implements ISettingsRepository {
|
|
393
|
-
private storage = new Map<string, UserSettings>();
|
|
394
|
-
|
|
395
|
-
async get(userId: string): Promise<UserSettings> {
|
|
396
|
-
if (!this.storage.has(userId)) {
|
|
397
|
-
const defaults = applyDefaults(userId);
|
|
398
|
-
this.storage.set(userId, defaults);
|
|
399
|
-
}
|
|
400
|
-
return this.storage.get(userId)!;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
async update(
|
|
404
|
-
userId: string,
|
|
405
|
-
updates: Partial<UserSettings>
|
|
406
|
-
): Promise<UserSettings> {
|
|
407
|
-
const current = await this.get(userId);
|
|
408
|
-
const updated = { ...current, ...updates };
|
|
409
|
-
this.storage.set(userId, updated);
|
|
410
|
-
return updated;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
async reset(userId: string): Promise<UserSettings> {
|
|
414
|
-
const defaults = applyDefaults(userId);
|
|
415
|
-
this.storage.set(userId, defaults);
|
|
416
|
-
return defaults;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
clear(): void {
|
|
420
|
-
this.storage.clear();
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
### Usage in Tests
|
|
426
|
-
|
|
427
|
-
```typescript
|
|
428
|
-
describe('SettingsService', () => {
|
|
429
|
-
let repository: MockSettingsRepository;
|
|
430
|
-
let service: SettingsService;
|
|
431
|
-
|
|
432
|
-
beforeEach(() => {
|
|
433
|
-
repository = new MockSettingsRepository();
|
|
434
|
-
service = new SettingsService(repository);
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
afterEach(() => {
|
|
438
|
-
repository.clear();
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
it('should return default settings for new user', async () => {
|
|
442
|
-
const settings = await repository.get('new-user');
|
|
443
|
-
|
|
444
|
-
expect(settings.theme).toBe('auto');
|
|
445
|
-
expect(settings.language).toBe('en-US');
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
it('should update settings', async () => {
|
|
449
|
-
await repository.update('user123', { theme: 'dark' });
|
|
450
|
-
|
|
451
|
-
const settings = await repository.get('user123');
|
|
452
|
-
expect(settings.theme).toBe('dark');
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
```
|
|
125
|
+
**Transformed Errors**:
|
|
126
|
+
- `NOT_FOUND` - Settings don't exist (returns defaults)
|
|
127
|
+
- `STORAGE_ERROR` - Storage operation failed
|
|
128
|
+
- `NETWORK_ERROR` - Network communication failed
|
|
129
|
+
- `VALIDATION_ERROR` - Data validation failed
|
|
456
130
|
|
|
457
131
|
## Best Practices
|
|
458
132
|
|
|
@@ -464,12 +138,6 @@ describe('SettingsService', () => {
|
|
|
464
138
|
6. **Immutability**: Don't mutate stored objects
|
|
465
139
|
7. **Migrations**: Handle schema changes gracefully
|
|
466
140
|
|
|
467
|
-
## Related
|
|
468
|
-
|
|
469
|
-
- **Settings Service**: Business logic layer
|
|
470
|
-
- **Application Layer**: Interface definitions
|
|
471
|
-
- **Storage Package**: Data persistence
|
|
472
|
-
|
|
473
141
|
## License
|
|
474
142
|
|
|
475
143
|
MIT
|