@umituz/react-native-storage 2.6.22 → 2.6.24
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/README.md +137 -0
- package/package.json +2 -1
- package/src/README.md +185 -0
- package/src/application/README.md +158 -0
- package/src/application/ports/README.md +127 -0
- package/src/cache/README.md +154 -0
- package/src/cache/domain/CacheManager.md +83 -0
- package/src/cache/domain/CacheStatsTracker.md +169 -0
- package/src/cache/domain/CachedValue.md +97 -0
- package/src/cache/domain/ErrorHandler.md +99 -0
- package/src/cache/domain/PatternMatcher.md +122 -0
- package/src/cache/domain/README.md +118 -0
- package/src/cache/domain/strategies/README.md +117 -0
- package/src/cache/domain/types/README.md +107 -0
- package/src/cache/infrastructure/README.md +126 -0
- package/src/cache/presentation/README.md +123 -0
- package/src/domain/README.md +128 -0
- package/src/domain/constants/README.md +105 -0
- package/src/domain/entities/README.md +109 -0
- package/src/domain/errors/README.md +126 -0
- package/src/domain/factories/README.md +138 -0
- package/src/domain/types/README.md +522 -0
- package/src/domain/utils/README.md +127 -0
- package/src/domain/value-objects/README.md +120 -0
- package/src/infrastructure/README.md +165 -0
- package/src/infrastructure/adapters/README.md +175 -0
- package/src/infrastructure/adapters/StorageService.md +103 -0
- package/src/infrastructure/repositories/README.md +121 -0
- package/src/presentation/README.md +181 -0
- package/src/presentation/hooks/README.md +128 -0
- package/src/types/README.md +103 -0
|
@@ -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
|