@umituz/react-native-storage 2.6.23 → 2.6.25

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.
@@ -0,0 +1,522 @@
1
+ # Domain Types
2
+
3
+ Storage domain için TypeScript tipleri ve interface'ler.
4
+
5
+ ## Types
6
+
7
+ ```tsx
8
+ import type {
9
+ StoreConfig,
10
+ PersistedState,
11
+ SetState,
12
+ GetState,
13
+ ActionsCreator,
14
+ } from '@umituz/react-native-storage';
15
+
16
+ import type {
17
+ StoreApi,
18
+ UseBoundStore,
19
+ } from 'zustand';
20
+
21
+ import type {
22
+ StateCreator,
23
+ StoreMutatorIdentifier,
24
+ } from 'zustand/vanilla';
25
+ ```
26
+
27
+ ## Store Types
28
+
29
+ ### StoreConfig
30
+
31
+ Store konfigürasyonu için tip.
32
+
33
+ ```tsx
34
+ interface StoreConfig<TState, TActions> {
35
+ name: string;
36
+ initialState: TState;
37
+ actions?: ActionsCreator<TState, TActions>;
38
+ persist?: boolean;
39
+ version?: number;
40
+ partialize?: (state: TState & TActions) => Partial<TState>;
41
+ onRehydrate?: (state: TState & TActions) => void;
42
+ migrate?: (persistedState: unknown, version: number) => TState & TActions;
43
+ }
44
+ ```
45
+
46
+ ### PersistedState
47
+
48
+ Persist edilmiş state için tip.
49
+
50
+ ```tsx
51
+ interface PersistedState<T> {
52
+ version: number;
53
+ state: T;
54
+ }
55
+ ```
56
+
57
+ ### SetState
58
+
59
+ State güncelleme fonksiyonu tipi.
60
+
61
+ ```tsx
62
+ type SetState<T> = (
63
+ partial: Partial<T> | ((state: T) => Partial<T>),
64
+ replace?: boolean
65
+ ) => void;
66
+ ```
67
+
68
+ ### GetState
69
+
70
+ State okuma fonksiyonu tipi.
71
+
72
+ ```tsx
73
+ type GetState<T> = () => T;
74
+ ```
75
+
76
+ ### ActionsCreator
77
+
78
+ Action oluşturucu fonksiyon tipi.
79
+
80
+ ```tsx
81
+ type ActionsCreator<TState, TActions> = (
82
+ set: SetState<TState & TActions>,
83
+ get: GetState<TState & TActions>
84
+ ) => TActions;
85
+ ```
86
+
87
+ ## Zustand Types
88
+
89
+ ### StoreApi
90
+
91
+ Zustand store API tipi.
92
+
93
+ ```tsx
94
+ interface StoreApi<T> {
95
+ getState: () => T;
96
+ setState: (partial: Partial<T> | ((state: T) => Partial<T>), replace?: boolean) => void;
97
+ subscribe: (listener: (state: T, prevState: T) => void) => () => void;
98
+ destroy: () => void;
99
+ }
100
+ ```
101
+
102
+ ### UseBoundStore
103
+
104
+ React hook tipi.
105
+
106
+ ```tsx
107
+ type UseBoundStore<T> = {
108
+ (): T;
109
+ <U>(selector: (state: T) => U, equalityFn?: (a: U, b: U) => boolean): U;
110
+ };
111
+ ```
112
+
113
+ ### StateCreator
114
+
115
+ State oluşturucu tipi.
116
+
117
+ ```tsx
118
+ type StateCreator<T, Mis = []> = (
119
+ set: SetState<T>,
120
+ get: GetState<T>,
121
+ api: StoreApi<T>,
122
+ ) => T;
123
+ ```
124
+
125
+ ## Kullanım Örnekleri
126
+
127
+ ### Basit Store Type
128
+
129
+ ```tsx
130
+ import type { StoreConfig } from '@umituz/react-native-storage';
131
+
132
+ interface CounterState {
133
+ count: number;
134
+ }
135
+
136
+ interface CounterActions {
137
+ increment: () => void;
138
+ decrement: () => void;
139
+ reset: () => void;
140
+ }
141
+
142
+ type CounterStore = CounterState & CounterActions;
143
+
144
+ const config: StoreConfig<CounterState, CounterActions> = {
145
+ name: 'counter',
146
+ initialState: { count: 0 },
147
+ actions: (set) => ({
148
+ increment: () => set((state) => ({ count: state.count + 1 })),
149
+ decrement: () => set((state) => ({ count: state.count - 1 })),
150
+ reset: () => set({ count: 0 }),
151
+ }),
152
+ };
153
+ ```
154
+
155
+ ### Generic Store Type
156
+
157
+ ```tsx
158
+ import type { StoreConfig, ActionsCreator } from '@umituz/react-native-storage';
159
+
160
+ interface ListState<T> {
161
+ items: T[];
162
+ loading: boolean;
163
+ }
164
+
165
+ interface ListActions<T> {
166
+ setItems: (items: T[]) => void;
167
+ addItem: (item: T) => void;
168
+ removeItem: (id: string) => void;
169
+ loadItems: () => Promise<void>;
170
+ }
171
+
172
+ function createListStore<T>(config: {
173
+ name: string;
174
+ fetcher: () => Promise<T[]>;
175
+ }) {
176
+ return createStore<ListState<T>, ListActions<T>>({
177
+ name: config.name,
178
+ initialState: {
179
+ items: [],
180
+ loading: false,
181
+ },
182
+ actions: (set, get) => ({
183
+ setItems: (items) => set({ items }),
184
+ addItem: (item) => set((state) => ({ items: [...state.items, item] })),
185
+ removeItem: (id) => set((state) => ({
186
+ items: state.items.filter((item) => (item as any).id !== id),
187
+ })),
188
+ loadItems: async () => {
189
+ set({ loading: true });
190
+ const items = await config.fetcher();
191
+ set({ items, loading: false });
192
+ },
193
+ }),
194
+ });
195
+ }
196
+
197
+ // Kullanım
198
+ const userStore = createListStore<User>({
199
+ name: 'users',
200
+ fetcher: () => fetch('/api/users').then(r => r.json()),
201
+ });
202
+ ```
203
+
204
+ ### Union Type State
205
+
206
+ ```tsx
207
+ type Theme = 'light' | 'dark';
208
+
209
+ interface SettingsState {
210
+ theme: Theme;
211
+ language: 'en' | 'tr';
212
+ }
213
+
214
+ const settingsStore = createStore<SettingsState>({
215
+ name: 'settings',
216
+ initialState: {
217
+ theme: 'light',
218
+ language: 'en',
219
+ },
220
+ });
221
+ ```
222
+
223
+ ### Discriminated Union
224
+
225
+ ```tsx
226
+ type LoadingState = {
227
+ status: 'loading';
228
+ };
229
+
230
+ type SuccessState<T> = {
231
+ status: 'success';
232
+ data: T;
233
+ };
234
+
235
+ type ErrorState = {
236
+ status: 'error';
237
+ error: Error;
238
+ };
239
+
240
+ type AsyncState<T> = LoadingState | SuccessState<T> | ErrorState;
241
+
242
+ interface DataState {
243
+ user: AsyncState<User>;
244
+ posts: AsyncState<Post[]>;
245
+ }
246
+
247
+ const dataStore = createStore<DataState>({
248
+ name: 'data',
249
+ initialState: {
250
+ user: { status: 'loading' },
251
+ posts: { status: 'loading' },
252
+ },
253
+ actions: (set) => ({
254
+ loadUser: async () => {
255
+ set({ user: { status: 'loading' } });
256
+
257
+ try {
258
+ const user = await fetchUser();
259
+ set({ user: { status: 'success', data: user } });
260
+ } catch (error) {
261
+ set({ user: { status: 'error', error: error as Error } });
262
+ }
263
+ },
264
+ }),
265
+ });
266
+ ```
267
+
268
+ ### Recursive Type
269
+
270
+ ```tsx
271
+ interface TreeNode {
272
+ id: string;
273
+ value: any;
274
+ children: TreeNode[];
275
+ }
276
+
277
+ interface TreeState {
278
+ root: TreeNode | null;
279
+ }
280
+
281
+ const treeStore = createStore<TreeState>({
282
+ name: 'tree',
283
+ initialState: { root: null },
284
+ actions: (set, get) => ({
285
+ setRoot: (root: TreeNode) => set({ root }),
286
+
287
+ findNode: (id: string): TreeNode | null => {
288
+ const { root } = get();
289
+
290
+ const search = (node: TreeNode | null): TreeNode | null => {
291
+ if (!node) return null;
292
+ if (node.id === id) return node;
293
+
294
+ for (const child of node.children) {
295
+ const found = search(child);
296
+ if (found) return found;
297
+ }
298
+
299
+ return null;
300
+ };
301
+
302
+ return search(root);
303
+ },
304
+ }),
305
+ });
306
+ ```
307
+
308
+ ### Conditional Type
309
+
310
+ ```tsx
311
+ type StoreType<T> = T extends true
312
+ ? PersistedStore<T>
313
+ : EphemeralStore<T>;
314
+
315
+ interface PersistedStore<T> {
316
+ getState: () => T;
317
+ setState: (partial: Partial<T>) => void;
318
+ persist: true;
319
+ }
320
+
321
+ interface EphemeralStore<T> {
322
+ getState: () => T;
323
+ setState: (partial: Partial<T>) => void;
324
+ }
325
+ ```
326
+
327
+ ### Utility Types
328
+
329
+ ```tsx
330
+ // DeepPartial - tüm nested özellikler optional
331
+ type DeepPartial<T> = {
332
+ [P in keyof T]?: T[P] extends object
333
+ ? DeepPartial<T[P]>
334
+ : T[P];
335
+ };
336
+
337
+ // ReadOnly
338
+ type ReadOnlyState<T> = {
339
+ readonly [P in keyof T]: T[P];
340
+ };
341
+
342
+ // Optional
343
+ type OptionalState<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
344
+
345
+ // Required
346
+ type RequiredState<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
347
+ ```
348
+
349
+ ## Type Guards
350
+
351
+ ```tsx
352
+ function isSuccessState<T>(state: AsyncState<T>): state is SuccessState<T> {
353
+ return state.status === 'success';
354
+ }
355
+
356
+ function isErrorState<T>(state: AsyncState<T>): state is ErrorState {
357
+ return state.status === 'error';
358
+ }
359
+
360
+ function isLoadingState<T>(state: AsyncState<T>): state is LoadingState {
361
+ return state.status === 'loading';
362
+ }
363
+
364
+ // Kullanım
365
+ const { user } = dataStore.getState();
366
+
367
+ if (isSuccessState(user)) {
368
+ console.log(user.data.name); // Type narrowing: user.data exists
369
+ } else if (isErrorState(user)) {
370
+ console.error(user.error.message); // Type narrowing: user.error exists
371
+ }
372
+ ```
373
+
374
+ ## Type Inference
375
+
376
+ ### Infer State from Store
377
+
378
+ ```tsx
379
+ import { createStore } from '@umituz/react-native-storage';
380
+
381
+ const store = createStore({
382
+ name: 'counter',
383
+ initialState: { count: 0 },
384
+ actions: (set) => ({
385
+ increment: () => set((state) => ({ count: state.count + 1 })),
386
+ }),
387
+ });
388
+
389
+ // State tipi otomatik çıkarılır
390
+ type CounterState = ReturnType<typeof store.getState>;
391
+ // { count: number; increment: () => void; }
392
+ ```
393
+
394
+ ### Extract Actions
395
+
396
+ ```tsx
397
+ type Actions = Pick<CounterState, 'increment'>;
398
+ // { increment: () => void; }
399
+ ```
400
+
401
+ ### Extract State
402
+
403
+ ```tsx
404
+ type State = Omit<CounterState, 'increment'>;
405
+ // { count: number; }
406
+ ```
407
+
408
+ ## Branded Types
409
+
410
+ ```tsx
411
+ type UserId = string & { readonly __brand: unique symbol };
412
+ type PostId = string & { readonly __brand: unique symbol };
413
+
414
+ function createUserId(id: string): UserId {
415
+ return id as UserId;
416
+ }
417
+
418
+ function createPostId(id: string): PostId {
419
+ return id as PostId;
420
+ }
421
+
422
+ // Yanlış kullanım engellenir
423
+ const userId: UserId = createUserId('user-123');
424
+ const postId: PostId = createPostId('post-456');
425
+
426
+ // postId = userId; // Type error!
427
+ ```
428
+
429
+ ## Template Literal Types
430
+
431
+ ```tsx
432
+ type StorageKey = `user:${string}` | `post:${string}`;
433
+
434
+ function getStorage<T extends StorageKey>(key: T): any {
435
+ // ...
436
+ }
437
+
438
+ const userKey: StorageKey = 'user:123'; // OK
439
+ const postKey: StorageKey = 'post:456'; // OK
440
+ const invalidKey: StorageKey = 'data'; // Type error!
441
+ ```
442
+
443
+ ## Generic Constraints
444
+
445
+ ```tsx
446
+ interface Entity {
447
+ id: string;
448
+ }
449
+
450
+ interface EntityState<T extends Entity> {
451
+ items: T[];
452
+ selectedId: string | null;
453
+ }
454
+
455
+ function createStoreWithEntity<T extends Entity>(config: {
456
+ name: string;
457
+ initialState: EntityState<T>;
458
+ }) {
459
+ return createStore<EntityState<T>>({
460
+ name: config.name,
461
+ initialState: config.initialState,
462
+ actions: (set) => ({
463
+ setSelected: (id: string) => set({ selectedId: id }),
464
+ clearSelected: () => set({ selectedId: null }),
465
+ }),
466
+ });
467
+ }
468
+
469
+ // Kullanım
470
+ interface User extends Entity {
471
+ name: string;
472
+ }
473
+
474
+ interface Product extends Entity {
475
+ price: number;
476
+ }
477
+
478
+ const userStore = createStoreWithEntity<User>({
479
+ name: 'users',
480
+ initialState: { items: [], selectedId: null },
481
+ });
482
+
483
+ const productStore = createStoreWithEntity<Product>({
484
+ name: 'products',
485
+ initialState: { items: [], selectedId: null },
486
+ });
487
+ ```
488
+
489
+ ## Mapped Types
490
+
491
+ ```tsx
492
+ type Getters<T> = {
493
+ [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
494
+ };
495
+
496
+ interface Settings {
497
+ theme: string;
498
+ language: string;
499
+ }
500
+
501
+ type SettingsGetters = Getters<Settings>;
502
+ // {
503
+ // getTheme: () => string;
504
+ // getLanguage: () => string;
505
+ // }
506
+ ```
507
+
508
+ ## Conditional Types with Enums
509
+
510
+ ```tsx
511
+ enum Status {
512
+ Loading = 'loading',
513
+ Success = 'success',
514
+ Error = 'error',
515
+ }
516
+
517
+ type StateByStatus<S extends Status> =
518
+ S extends Status.Loading ? { loading: true } :
519
+ S extends Status.Success ? { data: any } :
520
+ S extends Status.Error ? { error: Error } :
521
+ never;
522
+ ```
@@ -0,0 +1,127 @@
1
+ # Domain Utilities
2
+
3
+ Helper functions for cache key generation and development utilities.
4
+
5
+ ## Overview
6
+
7
+ Utility functions for cache operations and development-only features. Located at `src/domain/utils/`.
8
+
9
+ ## Strategies
10
+
11
+ ### Cache Key Generation
12
+ - Use generateCacheKey() for single items
13
+ - Use generateListCacheKey() for collections
14
+ - Include version in cache keys
15
+ - Support key parsing and validation
16
+
17
+ ### Key Format
18
+ - Follow consistent format: `cache:type:id:version`
19
+ - For lists: `cache:type:list:params:version`
20
+ - Use colon (`:`) as separator
21
+ - Enable pattern matching
22
+
23
+ ### Development Utilities
24
+ - Use isDev() for environment detection
25
+ - Use devWarn/devError/devLog for dev-only logging
26
+ - Provide no-op functions in production
27
+ - Enable debug features without performance cost
28
+
29
+ ### Key Validation
30
+ - Use isCacheKey() for validation
31
+ - Use parseCacheKey() for extraction
32
+ - Support type checking
33
+ - Enable safe key operations
34
+
35
+ ## Restrictions
36
+
37
+ ### Key Generation
38
+ - DO NOT generate keys manually
39
+ - DO NOT mix key formats
40
+ - DO NOT use inconsistent separators
41
+ - DO NOT omit version from keys
42
+
43
+ ### Development Utilities
44
+ - DO NOT log in production (use dev functions)
45
+ - DO NOT include debug code in production builds
46
+ - DO NOT bypass isDev() checks
47
+ - DO NOT leave development code in production
48
+
49
+ ### Key Parsing
50
+ - DO NOT parse keys with string methods
51
+ - DO NOT assume key format
52
+ - DO NOT skip validation
53
+ - DO NOT ignore parse errors
54
+
55
+ ## Rules
56
+
57
+ ### Key Generation Functions
58
+ - MUST provide generateCacheKey(type, id)
59
+ - MUST provide generateListCacheKey(type, params)
60
+ - MUST include version in generated keys
61
+ - MUST use consistent separator
62
+ - MUST validate input parameters
63
+
64
+ ### Key Format
65
+ - MUST use format: `cache:{type}:{id}:v{version}`
66
+ - MUST use `:` as separator
67
+ - MUST include version prefix `v`
68
+ - MUST be parseable by parseCacheKey()
69
+ - MUST be unique across different entities
70
+
71
+ ### Key Parsing
72
+ - MUST provide parseCacheKey() function
73
+ - MUST return structured data (type, id, version, isList)
74
+ - MUST handle invalid keys gracefully
75
+ - MUST return null for invalid format
76
+ - MUST extract parameters for list keys
77
+
78
+ ### Key Validation
79
+ - MUST provide isCacheKey() function
80
+ - MUST validate format string
81
+ - MUST check for required parts
82
+ - MUST return boolean result
83
+ - MUST be used before parsing
84
+
85
+ ### Development Functions
86
+ - MUST provide isDev() function
87
+ - MUST provide devWarn() for warnings
88
+ - MUST provide devError() for errors
89
+ - MUST provide devLog() for general logging
90
+ - MUST no-op in production
91
+
92
+ ### Environment Detection
93
+ - MUST check __DEV__ or equivalent
94
+ - MUST return boolean for isDev()
95
+ - MUST be compile-time constant when possible
96
+ - MUST not have runtime overhead in production
97
+
98
+ ### Logging Functions
99
+ - MUST only log in development mode
100
+ - MUST accept variable arguments
101
+ - MUST use console methods appropriately
102
+ - MUST not expose sensitive data
103
+
104
+ ### TypeScript Types
105
+ - MUST provide ParsedCacheKey interface
106
+ - MUST specify function signatures
107
+ - MUST enable type inference
108
+ - MUST use generic types where appropriate
109
+
110
+ ### Performance
111
+ - MUST not perform expensive operations in dev checks
112
+ - MUST provide no-op implementations in production
113
+ - MUST minimize bundle size impact
114
+ - MUST not include dev tools in production builds
115
+
116
+ ### Export Rules
117
+ - MUST export all utility functions
118
+ - MUST organize exports by category
119
+ - MUST provide TypeScript types
120
+ - MUST document function behavior
121
+
122
+ ### Testing Requirements
123
+ - MUST test key generation with various inputs
124
+ - MUST test key parsing with valid and invalid keys
125
+ - MUST test validation functions
126
+ - MUST test development mode detection
127
+ - MUST verify production no-op behavior