@umituz/react-native-storage 1.0.0
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/LICENSE +22 -0
- package/README.md +102 -0
- package/lib/application/ports/IStorageRepository.d.ts +48 -0
- package/lib/application/ports/IStorageRepository.d.ts.map +1 -0
- package/lib/application/ports/IStorageRepository.js +10 -0
- package/lib/application/ports/IStorageRepository.js.map +1 -0
- package/lib/domain/entities/StorageResult.d.ts +38 -0
- package/lib/domain/entities/StorageResult.d.ts.map +1 -0
- package/lib/domain/entities/StorageResult.js +42 -0
- package/lib/domain/entities/StorageResult.js.map +1 -0
- package/lib/domain/errors/StorageError.d.ts +51 -0
- package/lib/domain/errors/StorageError.d.ts.map +1 -0
- package/lib/domain/errors/StorageError.js +69 -0
- package/lib/domain/errors/StorageError.js.map +1 -0
- package/lib/domain/value-objects/StorageKey.d.ts +43 -0
- package/lib/domain/value-objects/StorageKey.d.ts.map +1 -0
- package/lib/domain/value-objects/StorageKey.js +46 -0
- package/lib/domain/value-objects/StorageKey.js.map +1 -0
- package/lib/index.d.ts +27 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +33 -0
- package/lib/index.js.map +1 -0
- package/lib/infrastructure/repositories/AsyncStorageRepository.d.ts +50 -0
- package/lib/infrastructure/repositories/AsyncStorageRepository.d.ts.map +1 -0
- package/lib/infrastructure/repositories/AsyncStorageRepository.js +137 -0
- package/lib/infrastructure/repositories/AsyncStorageRepository.js.map +1 -0
- package/lib/presentation/hooks/useStorage.d.ts +23 -0
- package/lib/presentation/hooks/useStorage.d.ts.map +1 -0
- package/lib/presentation/hooks/useStorage.js +87 -0
- package/lib/presentation/hooks/useStorage.js.map +1 -0
- package/lib/presentation/hooks/useStorageState.d.ts +21 -0
- package/lib/presentation/hooks/useStorageState.d.ts.map +1 -0
- package/lib/presentation/hooks/useStorageState.js +43 -0
- package/lib/presentation/hooks/useStorageState.js.map +1 -0
- package/package.json +55 -0
- package/src/application/ports/IStorageRepository.ts +56 -0
- package/src/domain/entities/StorageResult.ts +58 -0
- package/src/domain/errors/StorageError.ts +83 -0
- package/src/domain/value-objects/StorageKey.ts +59 -0
- package/src/index.ts +69 -0
- package/src/infrastructure/repositories/AsyncStorageRepository.ts +151 -0
- package/src/presentation/hooks/useStorage.ts +101 -0
- package/src/presentation/hooks/useStorageState.ts +55 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AsyncStorage Repository
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Infrastructure implementation of IStorageRepository
|
|
5
|
+
* Adapts React Native AsyncStorage to domain interface
|
|
6
|
+
*/
|
|
7
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
8
|
+
import { success, failure } from '../../domain/entities/StorageResult';
|
|
9
|
+
import { StorageReadError, StorageWriteError, StorageDeleteError, StorageSerializationError, StorageDeserializationError, } from '../../domain/errors/StorageError';
|
|
10
|
+
/**
|
|
11
|
+
* AsyncStorage Repository Implementation
|
|
12
|
+
*/
|
|
13
|
+
export class AsyncStorageRepository {
|
|
14
|
+
/**
|
|
15
|
+
* Get item from AsyncStorage with type safety
|
|
16
|
+
*/
|
|
17
|
+
async getItem(key, defaultValue) {
|
|
18
|
+
try {
|
|
19
|
+
const value = await AsyncStorage.getItem(key);
|
|
20
|
+
if (value === null) {
|
|
21
|
+
// Missing keys on first app launch are NORMAL, not errors
|
|
22
|
+
return success(defaultValue);
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const parsed = JSON.parse(value);
|
|
26
|
+
return success(parsed);
|
|
27
|
+
}
|
|
28
|
+
catch (parseError) {
|
|
29
|
+
return failure(new StorageDeserializationError(key, parseError), defaultValue);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return failure(new StorageReadError(key, error), defaultValue);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Set item in AsyncStorage with automatic JSON serialization
|
|
38
|
+
*/
|
|
39
|
+
async setItem(key, value) {
|
|
40
|
+
try {
|
|
41
|
+
let serialized;
|
|
42
|
+
try {
|
|
43
|
+
serialized = JSON.stringify(value);
|
|
44
|
+
}
|
|
45
|
+
catch (serializeError) {
|
|
46
|
+
return failure(new StorageSerializationError(key, serializeError));
|
|
47
|
+
}
|
|
48
|
+
await AsyncStorage.setItem(key, serialized);
|
|
49
|
+
return success(value);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return failure(new StorageWriteError(key, error));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get string value (no JSON parsing)
|
|
57
|
+
*/
|
|
58
|
+
async getString(key, defaultValue) {
|
|
59
|
+
try {
|
|
60
|
+
const value = await AsyncStorage.getItem(key);
|
|
61
|
+
if (value === null) {
|
|
62
|
+
// Missing keys on first app launch are NORMAL, not errors
|
|
63
|
+
return success(defaultValue);
|
|
64
|
+
}
|
|
65
|
+
return success(value);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
return failure(new StorageReadError(key, error), defaultValue);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Set string value (no JSON serialization)
|
|
73
|
+
*/
|
|
74
|
+
async setString(key, value) {
|
|
75
|
+
try {
|
|
76
|
+
await AsyncStorage.setItem(key, value);
|
|
77
|
+
return success(value);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return failure(new StorageWriteError(key, error));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Remove item from AsyncStorage
|
|
85
|
+
*/
|
|
86
|
+
async removeItem(key) {
|
|
87
|
+
try {
|
|
88
|
+
await AsyncStorage.removeItem(key);
|
|
89
|
+
return success(undefined);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return failure(new StorageDeleteError(key, error));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Check if key exists in storage
|
|
97
|
+
*/
|
|
98
|
+
async hasItem(key) {
|
|
99
|
+
try {
|
|
100
|
+
const value = await AsyncStorage.getItem(key);
|
|
101
|
+
return value !== null;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Clear all AsyncStorage data (use with caution!)
|
|
109
|
+
*/
|
|
110
|
+
async clearAll() {
|
|
111
|
+
try {
|
|
112
|
+
await AsyncStorage.clear();
|
|
113
|
+
return success(undefined);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
return failure(new StorageDeleteError('ALL_KEYS', error));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get multiple items at once (more efficient than multiple getItem calls)
|
|
121
|
+
*/
|
|
122
|
+
async getMultiple(keys) {
|
|
123
|
+
try {
|
|
124
|
+
const pairs = await AsyncStorage.multiGet(keys);
|
|
125
|
+
const result = Object.fromEntries(pairs);
|
|
126
|
+
return success(result);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
return failure(new StorageReadError('MULTIPLE_KEYS', error));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Singleton instance
|
|
135
|
+
*/
|
|
136
|
+
export const storageRepository = new AsyncStorageRepository();
|
|
137
|
+
//# sourceMappingURL=AsyncStorageRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncStorageRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/repositories/AsyncStorageRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useStorage Hook
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Presentation layer hook for storage operations
|
|
5
|
+
* Provides clean API for components to interact with storage domain
|
|
6
|
+
*/
|
|
7
|
+
import type { StorageResult } from '../../domain/entities/StorageResult';
|
|
8
|
+
import type { StorageKey } from '../../domain/value-objects/StorageKey';
|
|
9
|
+
/**
|
|
10
|
+
* Storage Hook
|
|
11
|
+
* Provides type-safe storage operations
|
|
12
|
+
*/
|
|
13
|
+
export declare const useStorage: () => {
|
|
14
|
+
getItem: <T>(key: string | StorageKey, defaultValue: T) => Promise<T>;
|
|
15
|
+
setItem: <T>(key: string | StorageKey, value: T) => Promise<boolean>;
|
|
16
|
+
getString: (key: string | StorageKey, defaultValue: string) => Promise<string>;
|
|
17
|
+
setString: (key: string | StorageKey, value: string) => Promise<boolean>;
|
|
18
|
+
removeItem: (key: string | StorageKey) => Promise<boolean>;
|
|
19
|
+
hasItem: (key: string | StorageKey) => Promise<boolean>;
|
|
20
|
+
clearAll: () => Promise<boolean>;
|
|
21
|
+
getItemWithResult: <T>(key: string | StorageKey, defaultValue: T) => Promise<StorageResult<T>>;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=useStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStorage.d.ts","sourceRoot":"","sources":["../../../src/presentation/hooks/useStorage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AAExE;;;GAGG;AACH,eAAO,MAAM,UAAU;cAIc,CAAC,OAAO,MAAM,GAAG,UAAU,gBAAgB,CAAC,KAAG,OAAO,CAAC,CAAC,CAAC;cASzD,CAAC,OAAO,MAAM,GAAG,UAAU,SAAS,CAAC,KAAG,OAAO,CAAC,OAAO,CAAC;qBASjD,MAAM,GAAG,UAAU,gBAAgB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;qBAS3D,MAAM,GAAG,UAAU,SAAS,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;sBASpD,MAAM,GAAG,UAAU,KAAG,OAAO,CAAC,OAAO,CAAC;mBASzC,MAAM,GAAG,UAAU,KAAG,OAAO,CAAC,OAAO,CAAC;oBAQvC,OAAO,CAAC,OAAO,CAAC;wBAQV,CAAC,OACvC,MAAM,GAAG,UAAU,gBACV,CAAC,KACd,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;CAe7B,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useStorage Hook
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Presentation layer hook for storage operations
|
|
5
|
+
* Provides clean API for components to interact with storage domain
|
|
6
|
+
*/
|
|
7
|
+
import { useCallback } from 'react';
|
|
8
|
+
import { storageRepository } from '../../infrastructure/repositories/AsyncStorageRepository';
|
|
9
|
+
import { unwrap } from '../../domain/entities/StorageResult';
|
|
10
|
+
/**
|
|
11
|
+
* Storage Hook
|
|
12
|
+
* Provides type-safe storage operations
|
|
13
|
+
*/
|
|
14
|
+
export const useStorage = () => {
|
|
15
|
+
/**
|
|
16
|
+
* Get item from storage
|
|
17
|
+
*/
|
|
18
|
+
const getItem = useCallback(async (key, defaultValue) => {
|
|
19
|
+
const keyString = typeof key === 'string' ? key : String(key);
|
|
20
|
+
const result = await storageRepository.getItem(keyString, defaultValue);
|
|
21
|
+
return unwrap(result, defaultValue);
|
|
22
|
+
}, []);
|
|
23
|
+
/**
|
|
24
|
+
* Set item in storage
|
|
25
|
+
*/
|
|
26
|
+
const setItem = useCallback(async (key, value) => {
|
|
27
|
+
const keyString = typeof key === 'string' ? key : String(key);
|
|
28
|
+
const result = await storageRepository.setItem(keyString, value);
|
|
29
|
+
return result.success;
|
|
30
|
+
}, []);
|
|
31
|
+
/**
|
|
32
|
+
* Get string from storage
|
|
33
|
+
*/
|
|
34
|
+
const getString = useCallback(async (key, defaultValue) => {
|
|
35
|
+
const keyString = typeof key === 'string' ? key : String(key);
|
|
36
|
+
const result = await storageRepository.getString(keyString, defaultValue);
|
|
37
|
+
return unwrap(result, defaultValue);
|
|
38
|
+
}, []);
|
|
39
|
+
/**
|
|
40
|
+
* Set string in storage
|
|
41
|
+
*/
|
|
42
|
+
const setString = useCallback(async (key, value) => {
|
|
43
|
+
const keyString = typeof key === 'string' ? key : String(key);
|
|
44
|
+
const result = await storageRepository.setString(keyString, value);
|
|
45
|
+
return result.success;
|
|
46
|
+
}, []);
|
|
47
|
+
/**
|
|
48
|
+
* Remove item from storage
|
|
49
|
+
*/
|
|
50
|
+
const removeItem = useCallback(async (key) => {
|
|
51
|
+
const keyString = typeof key === 'string' ? key : String(key);
|
|
52
|
+
const result = await storageRepository.removeItem(keyString);
|
|
53
|
+
return result.success;
|
|
54
|
+
}, []);
|
|
55
|
+
/**
|
|
56
|
+
* Check if item exists
|
|
57
|
+
*/
|
|
58
|
+
const hasItem = useCallback(async (key) => {
|
|
59
|
+
const keyString = typeof key === 'string' ? key : String(key);
|
|
60
|
+
return storageRepository.hasItem(keyString);
|
|
61
|
+
}, []);
|
|
62
|
+
/**
|
|
63
|
+
* Clear all storage
|
|
64
|
+
*/
|
|
65
|
+
const clearAll = useCallback(async () => {
|
|
66
|
+
const result = await storageRepository.clearAll();
|
|
67
|
+
return result.success;
|
|
68
|
+
}, []);
|
|
69
|
+
/**
|
|
70
|
+
* Get item with full result (success/error)
|
|
71
|
+
*/
|
|
72
|
+
const getItemWithResult = useCallback(async (key, defaultValue) => {
|
|
73
|
+
const keyString = typeof key === 'string' ? key : String(key);
|
|
74
|
+
return storageRepository.getItem(keyString, defaultValue);
|
|
75
|
+
}, []);
|
|
76
|
+
return {
|
|
77
|
+
getItem,
|
|
78
|
+
setItem,
|
|
79
|
+
getString,
|
|
80
|
+
setString,
|
|
81
|
+
removeItem,
|
|
82
|
+
hasItem,
|
|
83
|
+
clearAll,
|
|
84
|
+
getItemWithResult,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=useStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStorage.js","sourceRoot":"","sources":["../../../src/presentation/hooks/useStorage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useStorageState Hook
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Presentation layer hook for state + storage sync
|
|
5
|
+
* Combines React state with automatic storage persistence
|
|
6
|
+
*
|
|
7
|
+
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
8
|
+
*/
|
|
9
|
+
import type { StorageKey } from '../../domain/value-objects/StorageKey';
|
|
10
|
+
/**
|
|
11
|
+
* Storage State Hook
|
|
12
|
+
* Syncs React state with AsyncStorage automatically
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const [theme, setTheme] = useStorageState(StorageKey.THEME_MODE, 'light');
|
|
17
|
+
* // State is automatically persisted to storage
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare const useStorageState: <T>(key: string | StorageKey, defaultValue: T) => [T, (value: T) => Promise<void>, boolean];
|
|
21
|
+
//# sourceMappingURL=useStorageState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStorageState.d.ts","sourceRoot":"","sources":["../../../src/presentation/hooks/useStorageState.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AAExE;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,EAC/B,KAAK,MAAM,GAAG,UAAU,EACxB,cAAc,CAAC,KACd,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CA2B1C,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useStorageState Hook
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Presentation layer hook for state + storage sync
|
|
5
|
+
* Combines React state with automatic storage persistence
|
|
6
|
+
*
|
|
7
|
+
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
8
|
+
*/
|
|
9
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
10
|
+
import { storageRepository } from '../../infrastructure/repositories/AsyncStorageRepository';
|
|
11
|
+
import { unwrap } from '../../domain/entities/StorageResult';
|
|
12
|
+
/**
|
|
13
|
+
* Storage State Hook
|
|
14
|
+
* Syncs React state with AsyncStorage automatically
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const [theme, setTheme] = useStorageState(StorageKey.THEME_MODE, 'light');
|
|
19
|
+
* // State is automatically persisted to storage
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export const useStorageState = (key, defaultValue) => {
|
|
23
|
+
const keyString = typeof key === 'string' ? key : String(key);
|
|
24
|
+
const [state, setState] = useState(defaultValue);
|
|
25
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
26
|
+
// Load initial value from storage
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const loadFromStorage = async () => {
|
|
29
|
+
const result = await storageRepository.getItem(keyString, defaultValue);
|
|
30
|
+
const value = unwrap(result, defaultValue);
|
|
31
|
+
setState(value);
|
|
32
|
+
setIsLoading(false);
|
|
33
|
+
};
|
|
34
|
+
loadFromStorage();
|
|
35
|
+
}, [keyString, defaultValue]);
|
|
36
|
+
// Update state and persist to storage
|
|
37
|
+
const updateState = useCallback(async (value) => {
|
|
38
|
+
setState(value);
|
|
39
|
+
await storageRepository.setItem(keyString, value);
|
|
40
|
+
}, [keyString]);
|
|
41
|
+
return [state, updateState, isLoading];
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=useStorageState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStorageState.js","sourceRoot":"","sources":["../../../src/presentation/hooks/useStorageState.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0DAA0D,CAAC;AAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAG7D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,GAAwB,EACxB,YAAe,EAC4B,EAAE;IAC7C,MAAM,SAAS,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAI,YAAY,CAAC,CAAC;IACpD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEjD,kCAAkC;IAClC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,eAAe,GAAG,KAAK,IAAI,EAAE;YACjC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;YACxE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAC3C,QAAQ,CAAC,KAAK,CAAC,CAAC;YAChB,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC,CAAC;QAEF,eAAe,EAAE,CAAC;IACpB,CAAC,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IAE9B,sCAAsC;IACtC,MAAM,WAAW,GAAG,WAAW,CAC7B,KAAK,EAAE,KAAQ,EAAE,EAAE;QACjB,QAAQ,CAAC,KAAK,CAAC,CAAC;QAChB,MAAM,iBAAiB,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC,EACD,CAAC,SAAS,CAAC,CACZ,CAAC;IAEF,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AACzC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@umituz/react-native-storage",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Domain-Driven Design storage system for React Native apps with type-safe AsyncStorage operations",
|
|
5
|
+
"main": "./lib/index.js",
|
|
6
|
+
"types": "./lib/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"typecheck": "tsc --noEmit",
|
|
10
|
+
"lint": "tsc --noEmit",
|
|
11
|
+
"clean": "rm -rf lib",
|
|
12
|
+
"prebuild": "npm run clean",
|
|
13
|
+
"prepublishOnly": "npm run build",
|
|
14
|
+
"version:patch": "npm version patch -m 'chore: release v%s'",
|
|
15
|
+
"version:minor": "npm version minor -m 'chore: release v%s'",
|
|
16
|
+
"version:major": "npm version major -m 'chore: release v%s'"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"react-native",
|
|
20
|
+
"storage",
|
|
21
|
+
"async-storage",
|
|
22
|
+
"ddd",
|
|
23
|
+
"domain-driven-design",
|
|
24
|
+
"type-safe"
|
|
25
|
+
],
|
|
26
|
+
"author": "Ümit UZ <umit@umituz.com>",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/umituz/react-native-storage"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@react-native-async-storage/async-storage": "^1.21.0",
|
|
34
|
+
"react": ">=18.2.0",
|
|
35
|
+
"react-native": ">=0.74.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@react-native-async-storage/async-storage": "^1.24.0",
|
|
39
|
+
"@types/react": "^18.2.45",
|
|
40
|
+
"@types/react-native": "^0.73.0",
|
|
41
|
+
"react": "^18.2.0",
|
|
42
|
+
"react-native": "^0.74.0",
|
|
43
|
+
"typescript": "^5.3.3"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"lib",
|
|
50
|
+
"src",
|
|
51
|
+
"README.md",
|
|
52
|
+
"LICENSE"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Repository Interface (Port)
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Application port for storage operations
|
|
5
|
+
* Infrastructure layer implements this interface
|
|
6
|
+
*
|
|
7
|
+
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { StorageResult } from '../../domain/entities/StorageResult';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Storage Repository Interface
|
|
14
|
+
* Defines contract for storage operations
|
|
15
|
+
*/
|
|
16
|
+
export interface IStorageRepository {
|
|
17
|
+
/**
|
|
18
|
+
* Get item from storage with JSON parsing
|
|
19
|
+
*/
|
|
20
|
+
getItem<T>(key: string, defaultValue: T): Promise<StorageResult<T>>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Set item in storage with JSON serialization
|
|
24
|
+
*/
|
|
25
|
+
setItem<T>(key: string, value: T): Promise<StorageResult<T>>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get string value (no JSON parsing)
|
|
29
|
+
*/
|
|
30
|
+
getString(key: string, defaultValue: string): Promise<StorageResult<string>>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Set string value (no JSON serialization)
|
|
34
|
+
*/
|
|
35
|
+
setString(key: string, value: string): Promise<StorageResult<string>>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Remove item from storage
|
|
39
|
+
*/
|
|
40
|
+
removeItem(key: string): Promise<StorageResult<void>>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check if key exists in storage
|
|
44
|
+
*/
|
|
45
|
+
hasItem(key: string): Promise<boolean>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Clear all storage data
|
|
49
|
+
*/
|
|
50
|
+
clearAll(): Promise<StorageResult<void>>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get multiple items at once
|
|
54
|
+
*/
|
|
55
|
+
getMultiple(keys: string[]): Promise<StorageResult<Record<string, string | null>>>;
|
|
56
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Result Entity
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Entity representing storage operation result
|
|
5
|
+
* Functional programming pattern for error handling (Result type)
|
|
6
|
+
*
|
|
7
|
+
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { StorageError } from '../errors/StorageError';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Storage Operation Result
|
|
14
|
+
* Success/Failure pattern for type-safe error handling
|
|
15
|
+
*/
|
|
16
|
+
export type StorageResult<T> =
|
|
17
|
+
| { success: true; data: T }
|
|
18
|
+
| { success: false; error: StorageError; fallback?: T };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create success result
|
|
22
|
+
*/
|
|
23
|
+
export const success = <T>(data: T): StorageResult<T> => ({
|
|
24
|
+
success: true,
|
|
25
|
+
data,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create failure result
|
|
30
|
+
*/
|
|
31
|
+
export const failure = <T>(error: StorageError, fallback?: T): StorageResult<T> => ({
|
|
32
|
+
success: false,
|
|
33
|
+
error,
|
|
34
|
+
fallback,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Unwrap result with default value
|
|
39
|
+
*/
|
|
40
|
+
export const unwrap = <T>(result: StorageResult<T>, defaultValue: T): T => {
|
|
41
|
+
if (result.success) {
|
|
42
|
+
return result.data;
|
|
43
|
+
}
|
|
44
|
+
return result.fallback ?? defaultValue;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Map result data
|
|
49
|
+
*/
|
|
50
|
+
export const map = <T, U>(
|
|
51
|
+
result: StorageResult<T>,
|
|
52
|
+
fn: (data: T) => U
|
|
53
|
+
): StorageResult<U> => {
|
|
54
|
+
if (result.success) {
|
|
55
|
+
return success(fn(result.data));
|
|
56
|
+
}
|
|
57
|
+
return result as StorageResult<U>;
|
|
58
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Error Types
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Domain errors for storage operations
|
|
5
|
+
* Typed errors for better error handling and debugging
|
|
6
|
+
*
|
|
7
|
+
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base Storage Error
|
|
12
|
+
*/
|
|
13
|
+
export class StorageError extends Error {
|
|
14
|
+
constructor(message: string, public readonly key?: string) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'StorageError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Storage Read Error
|
|
22
|
+
*/
|
|
23
|
+
export class StorageReadError extends StorageError {
|
|
24
|
+
public readonly cause?: unknown;
|
|
25
|
+
|
|
26
|
+
constructor(key: string, cause?: unknown) {
|
|
27
|
+
super(`Failed to read from storage: ${key}`, key);
|
|
28
|
+
this.name = 'StorageReadError';
|
|
29
|
+
this.cause = cause;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Storage Write Error
|
|
35
|
+
*/
|
|
36
|
+
export class StorageWriteError extends StorageError {
|
|
37
|
+
public readonly cause?: unknown;
|
|
38
|
+
|
|
39
|
+
constructor(key: string, cause?: unknown) {
|
|
40
|
+
super(`Failed to write to storage: ${key}`, key);
|
|
41
|
+
this.name = 'StorageWriteError';
|
|
42
|
+
this.cause = cause;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Storage Delete Error
|
|
48
|
+
*/
|
|
49
|
+
export class StorageDeleteError extends StorageError {
|
|
50
|
+
public readonly cause?: unknown;
|
|
51
|
+
|
|
52
|
+
constructor(key: string, cause?: unknown) {
|
|
53
|
+
super(`Failed to delete from storage: ${key}`, key);
|
|
54
|
+
this.name = 'StorageDeleteError';
|
|
55
|
+
this.cause = cause;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Storage Serialization Error
|
|
61
|
+
*/
|
|
62
|
+
export class StorageSerializationError extends StorageError {
|
|
63
|
+
public readonly cause?: unknown;
|
|
64
|
+
|
|
65
|
+
constructor(key: string, cause?: unknown) {
|
|
66
|
+
super(`Failed to serialize data for key: ${key}`, key);
|
|
67
|
+
this.name = 'StorageSerializationError';
|
|
68
|
+
this.cause = cause;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Storage Deserialization Error
|
|
74
|
+
*/
|
|
75
|
+
export class StorageDeserializationError extends StorageError {
|
|
76
|
+
public readonly cause?: unknown;
|
|
77
|
+
|
|
78
|
+
constructor(key: string, cause?: unknown) {
|
|
79
|
+
super(`Failed to deserialize data for key: ${key}`, key);
|
|
80
|
+
this.name = 'StorageDeserializationError';
|
|
81
|
+
this.cause = cause;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Key Value Object
|
|
3
|
+
*
|
|
4
|
+
* Domain-Driven Design: Value Object for storage keys
|
|
5
|
+
* Ensures type safety and prevents invalid key usage
|
|
6
|
+
*
|
|
7
|
+
* Theme: {{THEME_NAME}} ({{CATEGORY}} category)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Storage Key Type
|
|
12
|
+
* All valid storage keys must be defined here
|
|
13
|
+
*/
|
|
14
|
+
export enum StorageKey {
|
|
15
|
+
// Onboarding
|
|
16
|
+
ONBOARDING_COMPLETED = '@onboarding_completed',
|
|
17
|
+
|
|
18
|
+
// Localization
|
|
19
|
+
LANGUAGE = '@app_language',
|
|
20
|
+
|
|
21
|
+
// Theme
|
|
22
|
+
THEME_MODE = '@app_theme_mode',
|
|
23
|
+
|
|
24
|
+
// Settings (requires userId suffix)
|
|
25
|
+
SETTINGS = 'app_settings',
|
|
26
|
+
|
|
27
|
+
// Query Cache (requires app name prefix)
|
|
28
|
+
QUERY_CACHE = '{{APP_NAME}}_query_cache',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Storage key with dynamic suffix
|
|
33
|
+
*/
|
|
34
|
+
export type DynamicStorageKey = {
|
|
35
|
+
base: StorageKey;
|
|
36
|
+
suffix: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Helper to create user-specific storage key
|
|
41
|
+
*
|
|
42
|
+
* @param baseKey Base storage key
|
|
43
|
+
* @param userId User identifier
|
|
44
|
+
* @returns User-specific key
|
|
45
|
+
*/
|
|
46
|
+
export const createUserKey = (baseKey: StorageKey, userId: string): string => {
|
|
47
|
+
return `${baseKey}_${userId}`;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Helper to create app-specific storage key
|
|
52
|
+
*
|
|
53
|
+
* @param baseKey Base storage key
|
|
54
|
+
* @param appName App identifier
|
|
55
|
+
* @returns App-specific key
|
|
56
|
+
*/
|
|
57
|
+
export const createAppKey = (baseKey: StorageKey, appName: string): string => {
|
|
58
|
+
return `${appName}_${baseKey}`;
|
|
59
|
+
};
|