@umituz/react-native-storage 2.0.0 → 2.3.3
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 +21 -5
- package/src/__tests__/integration.test.ts +391 -0
- package/src/__tests__/mocks/asyncStorage.mock.ts +52 -0
- package/src/__tests__/performance.test.ts +351 -0
- package/src/__tests__/setup.ts +63 -0
- package/src/application/ports/IStorageRepository.ts +0 -12
- package/src/domain/entities/StorageResult.ts +1 -3
- package/src/domain/entities/__tests__/CachedValue.test.ts +149 -0
- package/src/domain/entities/__tests__/StorageResult.test.ts +122 -0
- package/src/domain/errors/StorageError.ts +0 -2
- package/src/domain/errors/__tests__/StorageError.test.ts +127 -0
- package/src/domain/utils/__tests__/devUtils.test.ts +97 -0
- package/src/domain/utils/devUtils.ts +37 -0
- package/src/domain/value-objects/StorageKey.ts +27 -29
- package/src/index.ts +9 -1
- package/src/infrastructure/adapters/StorageService.ts +8 -6
- package/src/infrastructure/repositories/AsyncStorageRepository.ts +27 -108
- package/src/infrastructure/repositories/BaseStorageOperations.ts +101 -0
- package/src/infrastructure/repositories/BatchStorageOperations.ts +42 -0
- package/src/infrastructure/repositories/StringStorageOperations.ts +44 -0
- package/src/infrastructure/repositories/__tests__/AsyncStorageRepository.test.ts +169 -0
- package/src/infrastructure/repositories/__tests__/BaseStorageOperations.test.ts +200 -0
- package/src/presentation/hooks/CacheStorageOperations.ts +95 -0
- package/src/presentation/hooks/__tests__/usePersistentCache.test.ts +404 -0
- package/src/presentation/hooks/__tests__/useStorage.test.ts +246 -0
- package/src/presentation/hooks/__tests__/useStorageState.test.ts +292 -0
- package/src/presentation/hooks/useCacheState.ts +55 -0
- package/src/presentation/hooks/usePersistentCache.ts +30 -39
- package/src/presentation/hooks/useStorage.ts +4 -3
- package/src/presentation/hooks/useStorageState.ts +24 -8
- package/src/presentation/hooks/useStore.ts +3 -1
- package/src/types/global.d.ts +40 -0
- package/LICENSE +0 -22
- package/src/presentation/hooks/usePersistedState.ts +0 -34
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StorageResult Entity Tests
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for StorageResult entity
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { success, failure, unwrap, map, isSuccess, isFailure } from '../../domain/entities/StorageResult';
|
|
8
|
+
import { StorageError } from '../../domain/errors/StorageError';
|
|
9
|
+
|
|
10
|
+
describe('StorageResult Entity', () => {
|
|
11
|
+
describe('success', () => {
|
|
12
|
+
it('should create a successful result', () => {
|
|
13
|
+
const data = { test: 'value' };
|
|
14
|
+
const result = success(data);
|
|
15
|
+
|
|
16
|
+
expect(result.success).toBe(true);
|
|
17
|
+
expect(result.data).toBe(data);
|
|
18
|
+
expect(result.error).toBeUndefined();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('failure', () => {
|
|
23
|
+
it('should create a failure result', () => {
|
|
24
|
+
const error = new StorageError('test-key', new Error('Test error'));
|
|
25
|
+
const defaultValue = 'default';
|
|
26
|
+
const result = failure(error, defaultValue);
|
|
27
|
+
|
|
28
|
+
expect(result.success).toBe(false);
|
|
29
|
+
expect(result.data).toBe(defaultValue);
|
|
30
|
+
expect(result.error).toBe(error);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('unwrap', () => {
|
|
35
|
+
it('should return data for successful result', () => {
|
|
36
|
+
const data = { test: 'value' };
|
|
37
|
+
const result = success(data);
|
|
38
|
+
const defaultValue = 'default';
|
|
39
|
+
|
|
40
|
+
const unwrapped = unwrap(result, defaultValue);
|
|
41
|
+
|
|
42
|
+
expect(unwrapped).toBe(data);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should return default value for failure result', () => {
|
|
46
|
+
const error = new StorageError('test-key', new Error('Test error'));
|
|
47
|
+
const defaultValue = 'default';
|
|
48
|
+
const result = failure(error, defaultValue);
|
|
49
|
+
|
|
50
|
+
const unwrapped = unwrap(result, defaultValue);
|
|
51
|
+
|
|
52
|
+
expect(unwrapped).toBe(defaultValue);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('map', () => {
|
|
57
|
+
it('should map successful result', () => {
|
|
58
|
+
const data = { count: 1 };
|
|
59
|
+
const result = success(data);
|
|
60
|
+
const mapper = (value: typeof data) => ({ ...value, count: value.count + 1 });
|
|
61
|
+
|
|
62
|
+
const mapped = map(result, mapper);
|
|
63
|
+
|
|
64
|
+
expect(mapped.success).toBe(true);
|
|
65
|
+
expect(mapped.data).toEqual({ count: 2 });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should not map failure result', () => {
|
|
69
|
+
const error = new StorageError('test-key', new Error('Test error'));
|
|
70
|
+
const defaultValue = { count: 0 };
|
|
71
|
+
const result = failure(error, defaultValue);
|
|
72
|
+
const mapper = jest.fn();
|
|
73
|
+
|
|
74
|
+
const mapped = map(result, mapper);
|
|
75
|
+
|
|
76
|
+
expect(mapped.success).toBe(false);
|
|
77
|
+
expect(mapper).not.toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('isSuccess', () => {
|
|
82
|
+
it('should return true for successful result', () => {
|
|
83
|
+
const result = success('test');
|
|
84
|
+
expect(isSuccess(result)).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should return false for failure result', () => {
|
|
88
|
+
const error = new StorageError('test-key', new Error('Test error'));
|
|
89
|
+
const result = failure(error);
|
|
90
|
+
expect(isSuccess(result)).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('isFailure', () => {
|
|
95
|
+
it('should return false for successful result', () => {
|
|
96
|
+
const result = success('test');
|
|
97
|
+
expect(isFailure(result)).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should return true for failure result', () => {
|
|
101
|
+
const error = new StorageError('test-key', new Error('Test error'));
|
|
102
|
+
const result = failure(error);
|
|
103
|
+
expect(isFailure(result)).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('Type Safety', () => {
|
|
108
|
+
it('should maintain type information', () => {
|
|
109
|
+
interface TestData {
|
|
110
|
+
id: number;
|
|
111
|
+
name: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const data: TestData = { id: 1, name: 'test' };
|
|
115
|
+
const result = success<TestData>(data);
|
|
116
|
+
|
|
117
|
+
// TypeScript should infer the type correctly
|
|
118
|
+
const typedData: TestData = result.data;
|
|
119
|
+
expect(typedData).toEqual(data);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StorageError Tests
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for StorageError classes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
StorageError,
|
|
9
|
+
StorageReadError,
|
|
10
|
+
StorageWriteError,
|
|
11
|
+
StorageDeleteError,
|
|
12
|
+
StorageSerializationError,
|
|
13
|
+
StorageDeserializationError,
|
|
14
|
+
} from '../../domain/errors/StorageError';
|
|
15
|
+
|
|
16
|
+
describe('StorageError Classes', () => {
|
|
17
|
+
describe('StorageError', () => {
|
|
18
|
+
it('should create base storage error', () => {
|
|
19
|
+
const key = 'test-key';
|
|
20
|
+
const cause = new Error('Original error');
|
|
21
|
+
const error = new StorageError(key, cause);
|
|
22
|
+
|
|
23
|
+
expect(error.key).toBe(key);
|
|
24
|
+
expect(error.cause).toBe(cause);
|
|
25
|
+
expect(error.name).toBe('StorageError');
|
|
26
|
+
expect(error.message).toContain(key);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should serialize error details', () => {
|
|
30
|
+
const key = 'test-key';
|
|
31
|
+
const cause = new Error('Original error');
|
|
32
|
+
const error = new StorageError(key, cause);
|
|
33
|
+
|
|
34
|
+
const serialized = JSON.stringify(error);
|
|
35
|
+
const parsed = JSON.parse(serialized);
|
|
36
|
+
|
|
37
|
+
expect(parsed.key).toBe(key);
|
|
38
|
+
expect(parsed.message).toContain(key);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('StorageReadError', () => {
|
|
43
|
+
it('should create read error', () => {
|
|
44
|
+
const key = 'test-key';
|
|
45
|
+
const cause = new Error('Read failed');
|
|
46
|
+
const error = new StorageReadError(key, cause);
|
|
47
|
+
|
|
48
|
+
expect(error.key).toBe(key);
|
|
49
|
+
expect(error.cause).toBe(cause);
|
|
50
|
+
expect(error.name).toBe('StorageReadError');
|
|
51
|
+
expect(error.message).toContain('read');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('StorageWriteError', () => {
|
|
56
|
+
it('should create write error', () => {
|
|
57
|
+
const key = 'test-key';
|
|
58
|
+
const cause = new Error('Write failed');
|
|
59
|
+
const error = new StorageWriteError(key, cause);
|
|
60
|
+
|
|
61
|
+
expect(error.key).toBe(key);
|
|
62
|
+
expect(error.cause).toBe(cause);
|
|
63
|
+
expect(error.name).toBe('StorageWriteError');
|
|
64
|
+
expect(error.message).toContain('write');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('StorageDeleteError', () => {
|
|
69
|
+
it('should create delete error', () => {
|
|
70
|
+
const key = 'test-key';
|
|
71
|
+
const cause = new Error('Delete failed');
|
|
72
|
+
const error = new StorageDeleteError(key, cause);
|
|
73
|
+
|
|
74
|
+
expect(error.key).toBe(key);
|
|
75
|
+
expect(error.cause).toBe(cause);
|
|
76
|
+
expect(error.name).toBe('StorageDeleteError');
|
|
77
|
+
expect(error.message).toContain('delete');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('StorageSerializationError', () => {
|
|
82
|
+
it('should create serialization error', () => {
|
|
83
|
+
const key = 'test-key';
|
|
84
|
+
const cause = new Error('Serialization failed');
|
|
85
|
+
const error = new StorageSerializationError(key, cause);
|
|
86
|
+
|
|
87
|
+
expect(error.key).toBe(key);
|
|
88
|
+
expect(error.cause).toBe(cause);
|
|
89
|
+
expect(error.name).toBe('StorageSerializationError');
|
|
90
|
+
expect(error.message).toContain('serialize');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('StorageDeserializationError', () => {
|
|
95
|
+
it('should create deserialization error', () => {
|
|
96
|
+
const key = 'test-key';
|
|
97
|
+
const cause = new Error('Deserialization failed');
|
|
98
|
+
const error = new StorageDeserializationError(key, cause);
|
|
99
|
+
|
|
100
|
+
expect(error.key).toBe(key);
|
|
101
|
+
expect(error.cause).toBe(cause);
|
|
102
|
+
expect(error.name).toBe('StorageDeserializationError');
|
|
103
|
+
expect(error.message).toContain('deserialize');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('Error Inheritance', () => {
|
|
108
|
+
it('should maintain error chain', () => {
|
|
109
|
+
const key = 'test-key';
|
|
110
|
+
const cause = new Error('Original error');
|
|
111
|
+
const error = new StorageReadError(key, cause);
|
|
112
|
+
|
|
113
|
+
expect(error instanceof Error).toBe(true);
|
|
114
|
+
expect(error instanceof StorageError).toBe(true);
|
|
115
|
+
expect(error instanceof StorageReadError).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should preserve stack trace', () => {
|
|
119
|
+
const key = 'test-key';
|
|
120
|
+
const cause = new Error('Original error');
|
|
121
|
+
const error = new StorageReadError(key, cause);
|
|
122
|
+
|
|
123
|
+
expect(error.stack).toBeDefined();
|
|
124
|
+
expect(error.stack).toContain('StorageReadError');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Development Utilities Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { isDev, devWarn, devError, devLog } from '../devUtils';
|
|
6
|
+
|
|
7
|
+
// Mock console methods
|
|
8
|
+
const mockConsoleWarn = jest.fn();
|
|
9
|
+
const mockConsoleError = jest.fn();
|
|
10
|
+
const mockConsoleLog = jest.fn();
|
|
11
|
+
|
|
12
|
+
describe('Development Utilities', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
jest.clearAllMocks();
|
|
15
|
+
|
|
16
|
+
// Mock console methods
|
|
17
|
+
console.warn = mockConsoleWarn;
|
|
18
|
+
console.error = mockConsoleError;
|
|
19
|
+
console.log = mockConsoleLog;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('isDev', () => {
|
|
23
|
+
it('should return true when __DEV__ is true', () => {
|
|
24
|
+
(globalThis as any).__DEV__ = true;
|
|
25
|
+
expect(isDev()).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should return false when __DEV__ is false', () => {
|
|
29
|
+
(globalThis as any).__DEV__ = false;
|
|
30
|
+
expect(isDev()).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should return false when __DEV__ is undefined', () => {
|
|
34
|
+
delete (globalThis as any).__DEV__;
|
|
35
|
+
expect(isDev()).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('devWarn', () => {
|
|
40
|
+
it('should log warning when in development mode', () => {
|
|
41
|
+
(globalThis as any).__DEV__ = true;
|
|
42
|
+
|
|
43
|
+
devWarn('Test warning', { data: 'test' });
|
|
44
|
+
|
|
45
|
+
expect(mockConsoleWarn).toHaveBeenCalledWith('Test warning', { data: 'test' });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should not log warning when not in development mode', () => {
|
|
49
|
+
(globalThis as any).__DEV__ = false;
|
|
50
|
+
|
|
51
|
+
devWarn('Test warning', { data: 'test' });
|
|
52
|
+
|
|
53
|
+
expect(mockConsoleWarn).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('devError', () => {
|
|
58
|
+
it('should log error when in development mode', () => {
|
|
59
|
+
(globalThis as any).__DEV__ = true;
|
|
60
|
+
|
|
61
|
+
devError('Test error', new Error('test'));
|
|
62
|
+
|
|
63
|
+
expect(mockConsoleError).toHaveBeenCalledWith('Test error', new Error('test'));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should not log error when not in development mode', () => {
|
|
67
|
+
(globalThis as any).__DEV__ = false;
|
|
68
|
+
|
|
69
|
+
devError('Test error', new Error('test'));
|
|
70
|
+
|
|
71
|
+
expect(mockConsoleError).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('devLog', () => {
|
|
76
|
+
it('should log info when in development mode', () => {
|
|
77
|
+
(globalThis as any).__DEV__ = true;
|
|
78
|
+
|
|
79
|
+
devLog('Test log', { info: 'test' });
|
|
80
|
+
|
|
81
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('Test log', { info: 'test' });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should not log info when not in development mode', () => {
|
|
85
|
+
(globalThis as any).__DEV__ = false;
|
|
86
|
+
|
|
87
|
+
devLog('Test log', { info: 'test' });
|
|
88
|
+
|
|
89
|
+
expect(mockConsoleLog).not.toHaveBeenCalled();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
afterEach(() => {
|
|
94
|
+
// Clean up __DEV__ after each test
|
|
95
|
+
delete (globalThis as any).__DEV__;
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Development utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if running in development mode
|
|
7
|
+
*/
|
|
8
|
+
export const isDev = (): boolean => {
|
|
9
|
+
return (globalThis as any).__DEV__ === true;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Log warning in development mode only
|
|
14
|
+
*/
|
|
15
|
+
export const devWarn = (message: string, ...args: any[]): void => {
|
|
16
|
+
if (isDev()) {
|
|
17
|
+
console.warn(message, ...args);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Log error in development mode only
|
|
23
|
+
*/
|
|
24
|
+
export const devError = (message: string, ...args: any[]): void => {
|
|
25
|
+
if (isDev()) {
|
|
26
|
+
console.error(message, ...args);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Log info in development mode only
|
|
32
|
+
*/
|
|
33
|
+
export const devLog = (message: string, ...args: any[]): void => {
|
|
34
|
+
if (isDev()) {
|
|
35
|
+
console.log(message, ...args);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -3,39 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Domain-Driven Design: Value Object for storage keys
|
|
5
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
6
|
*/
|
|
14
|
-
export enum StorageKey {
|
|
15
|
-
// Onboarding
|
|
16
|
-
ONBOARDING_COMPLETED = '@onboarding_completed',
|
|
17
|
-
|
|
18
|
-
// Auth
|
|
19
|
-
AUTH_SHOW_REGISTER = '@auth_show_register',
|
|
20
|
-
|
|
21
|
-
// Localization
|
|
22
|
-
LANGUAGE = '@app_language',
|
|
23
|
-
|
|
24
|
-
// Theme
|
|
25
|
-
THEME_MODE = '@app_theme_mode',
|
|
26
|
-
|
|
27
|
-
// Settings (requires userId suffix)
|
|
28
|
-
SETTINGS = 'app_settings',
|
|
29
|
-
|
|
30
|
-
// Query Cache (requires app name prefix)
|
|
31
|
-
QUERY_CACHE = '{{APP_NAME}}_query_cache',
|
|
32
|
-
}
|
|
33
7
|
|
|
34
8
|
/**
|
|
35
9
|
* Storage key with dynamic suffix
|
|
36
10
|
*/
|
|
37
11
|
export type DynamicStorageKey = {
|
|
38
|
-
base:
|
|
12
|
+
base: string;
|
|
39
13
|
suffix: string;
|
|
40
14
|
};
|
|
41
15
|
|
|
@@ -46,7 +20,7 @@ export type DynamicStorageKey = {
|
|
|
46
20
|
* @param userId User identifier
|
|
47
21
|
* @returns User-specific key
|
|
48
22
|
*/
|
|
49
|
-
export const createUserKey = (baseKey:
|
|
23
|
+
export const createUserKey = (baseKey: string, userId: string): string => {
|
|
50
24
|
return `${baseKey}_${userId}`;
|
|
51
25
|
};
|
|
52
26
|
|
|
@@ -57,6 +31,30 @@ export const createUserKey = (baseKey: StorageKey, userId: string): string => {
|
|
|
57
31
|
* @param appName App identifier
|
|
58
32
|
* @returns App-specific key
|
|
59
33
|
*/
|
|
60
|
-
export const createAppKey = (baseKey:
|
|
34
|
+
export const createAppKey = (baseKey: string, appName: string): string => {
|
|
61
35
|
return `${appName}_${baseKey}`;
|
|
62
36
|
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Helper to create namespaced storage key
|
|
40
|
+
*
|
|
41
|
+
* @param namespace Key namespace
|
|
42
|
+
* @param key Specific key
|
|
43
|
+
* @returns Namespaced key
|
|
44
|
+
*/
|
|
45
|
+
export const createNamespacedKey = (namespace: string, key: string): string => {
|
|
46
|
+
return `${namespace}:${key}`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Legacy StorageKey enum for backward compatibility
|
|
51
|
+
* @deprecated Use createNamespacedKey instead
|
|
52
|
+
*/
|
|
53
|
+
export enum StorageKey {
|
|
54
|
+
USER_PREFERENCES = '@user_preferences',
|
|
55
|
+
APP_SETTINGS = '@app_settings',
|
|
56
|
+
LANGUAGE = '@language',
|
|
57
|
+
UI_PREFERENCES = '@ui_preferences',
|
|
58
|
+
QUERY_CACHE = '@query_cache',
|
|
59
|
+
DATA_CACHE = '@data_cache',
|
|
60
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -78,6 +78,12 @@ export {
|
|
|
78
78
|
|
|
79
79
|
export { TIME_MS, DEFAULT_TTL, CACHE_VERSION } from './domain/constants/CacheDefaults';
|
|
80
80
|
|
|
81
|
+
// =============================================================================
|
|
82
|
+
// DOMAIN LAYER - Development Utilities
|
|
83
|
+
// =============================================================================
|
|
84
|
+
|
|
85
|
+
export { isDev, devWarn, devError, devLog } from './domain/utils/devUtils';
|
|
86
|
+
|
|
81
87
|
// =============================================================================
|
|
82
88
|
// DOMAIN LAYER - Store Types
|
|
83
89
|
// =============================================================================
|
|
@@ -117,10 +123,12 @@ export {
|
|
|
117
123
|
export { useStorage } from './presentation/hooks/useStorage';
|
|
118
124
|
export { useStorageState } from './presentation/hooks/useStorageState';
|
|
119
125
|
export { useStore } from './presentation/hooks/useStore';
|
|
120
|
-
export { usePersistedState } from './presentation/hooks/usePersistedState';
|
|
121
126
|
|
|
122
127
|
export {
|
|
123
128
|
usePersistentCache,
|
|
124
129
|
type PersistentCacheOptions,
|
|
125
130
|
type PersistentCacheResult,
|
|
126
131
|
} from './presentation/hooks/usePersistentCache';
|
|
132
|
+
|
|
133
|
+
export { useCacheState } from './presentation/hooks/useCacheState';
|
|
134
|
+
export { CacheStorageOperations } from './presentation/hooks/CacheStorageOperations';
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
9
|
+
import { devWarn } from '../../domain/utils/devUtils';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* StateStorage interface for Zustand persist middleware
|
|
@@ -18,13 +19,14 @@ export interface StateStorage {
|
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Storage service for Zustand persist middleware
|
|
21
|
-
* Direct AsyncStorage implementation
|
|
22
|
+
* Direct AsyncStorage implementation with proper error handling
|
|
22
23
|
*/
|
|
23
24
|
export const storageService: StateStorage = {
|
|
24
25
|
getItem: async (name: string): Promise<string | null> => {
|
|
25
26
|
try {
|
|
26
27
|
return await AsyncStorage.getItem(name);
|
|
27
|
-
} catch {
|
|
28
|
+
} catch (error) {
|
|
29
|
+
devWarn(`StorageService: Failed to get item "${name}"`, error);
|
|
28
30
|
return null;
|
|
29
31
|
}
|
|
30
32
|
},
|
|
@@ -32,16 +34,16 @@ export const storageService: StateStorage = {
|
|
|
32
34
|
setItem: async (name: string, value: string): Promise<void> => {
|
|
33
35
|
try {
|
|
34
36
|
await AsyncStorage.setItem(name, value);
|
|
35
|
-
} catch {
|
|
36
|
-
|
|
37
|
+
} catch (error) {
|
|
38
|
+
devWarn(`StorageService: Failed to set item "${name}"`, error);
|
|
37
39
|
}
|
|
38
40
|
},
|
|
39
41
|
|
|
40
42
|
removeItem: async (name: string): Promise<void> => {
|
|
41
43
|
try {
|
|
42
44
|
await AsyncStorage.removeItem(name);
|
|
43
|
-
} catch {
|
|
44
|
-
|
|
45
|
+
} catch (error) {
|
|
46
|
+
devWarn(`StorageService: Failed to remove item "${name}"`, error);
|
|
45
47
|
}
|
|
46
48
|
},
|
|
47
49
|
};
|