@idealyst/storage 1.0.54 → 1.0.56
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 +360 -0
- package/package.json +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# @idealyst/storage
|
|
2
|
+
|
|
3
|
+
A universal, cross-platform storage solution for React and React Native applications. Provides a consistent API for persistent data storage with fallbacks from secure storage to async storage to local storage.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/@idealyst%2Fstorage)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🌐 **Cross-Platform**: Works seamlessly on React Native and Web
|
|
11
|
+
- 🔒 **Security First**: Automatic fallback from secure storage to less secure options
|
|
12
|
+
- 🚀 **Simple API**: Async/await based with consistent interface
|
|
13
|
+
- 📱 **React Native**: Uses MMKV for high-performance storage
|
|
14
|
+
- 🌍 **Web**: Uses localStorage with proper error handling
|
|
15
|
+
- 🔧 **TypeScript**: Full type safety and IntelliSense support
|
|
16
|
+
- 💾 **Automatic Fallbacks**: Graceful degradation when storage methods fail
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Using yarn (recommended)
|
|
22
|
+
yarn add @idealyst/storage
|
|
23
|
+
|
|
24
|
+
# Using npm
|
|
25
|
+
npm install @idealyst/storage
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Platform Dependencies
|
|
29
|
+
|
|
30
|
+
**React Native:**
|
|
31
|
+
```bash
|
|
32
|
+
# High-performance storage (recommended)
|
|
33
|
+
yarn add react-native-mmkv
|
|
34
|
+
|
|
35
|
+
# Follow installation instructions for react-native-mmkv
|
|
36
|
+
cd ios && pod install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Web:**
|
|
40
|
+
No additional dependencies required - uses native localStorage.
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { storage } from '@idealyst/storage';
|
|
46
|
+
|
|
47
|
+
// Store data
|
|
48
|
+
await storage.setItem('user', { name: 'John', id: 123 });
|
|
49
|
+
await storage.setItem('token', 'abc123');
|
|
50
|
+
await storage.setItem('settings', { theme: 'dark', notifications: true });
|
|
51
|
+
|
|
52
|
+
// Retrieve data
|
|
53
|
+
const user = await storage.getItem('user');
|
|
54
|
+
const token = await storage.getItem('token');
|
|
55
|
+
const settings = await storage.getItem('settings');
|
|
56
|
+
|
|
57
|
+
// Remove data
|
|
58
|
+
await storage.removeItem('token');
|
|
59
|
+
|
|
60
|
+
// Clear all data
|
|
61
|
+
await storage.clear();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## API Reference
|
|
65
|
+
|
|
66
|
+
### `setItem(key: string, value: any): Promise<void>`
|
|
67
|
+
|
|
68
|
+
Stores a value with the given key. Values are automatically serialized.
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
await storage.setItem('user', { name: 'John', age: 30 });
|
|
72
|
+
await storage.setItem('count', 42);
|
|
73
|
+
await storage.setItem('isEnabled', true);
|
|
74
|
+
await storage.setItem('tags', ['react', 'native']);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `getItem<T>(key: string): Promise<T | null>`
|
|
78
|
+
|
|
79
|
+
Retrieves a value by key. Returns `null` if the key doesn't exist.
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
const user = await storage.getItem<User>('user');
|
|
83
|
+
const count = await storage.getItem<number>('count');
|
|
84
|
+
const isEnabled = await storage.getItem<boolean>('isEnabled');
|
|
85
|
+
const tags = await storage.getItem<string[]>('tags');
|
|
86
|
+
|
|
87
|
+
if (user) {
|
|
88
|
+
console.log(user.name); // TypeScript knows this is a User object
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `removeItem(key: string): Promise<void>`
|
|
93
|
+
|
|
94
|
+
Removes a specific item from storage.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
await storage.removeItem('user');
|
|
98
|
+
await storage.removeItem('temporaryData');
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `clear(): Promise<void>`
|
|
102
|
+
|
|
103
|
+
Removes all items from storage.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
await storage.clear();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `getAllKeys(): Promise<string[]>`
|
|
110
|
+
|
|
111
|
+
Returns all keys currently in storage.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
const keys = await storage.getAllKeys();
|
|
115
|
+
console.log('Stored keys:', keys); // ['user', 'settings', 'token']
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Usage Examples
|
|
119
|
+
|
|
120
|
+
### User Session Management
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { storage } from '@idealyst/storage';
|
|
124
|
+
|
|
125
|
+
interface User {
|
|
126
|
+
id: number;
|
|
127
|
+
name: string;
|
|
128
|
+
email: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
class AuthService {
|
|
132
|
+
static async saveUserSession(user: User, token: string) {
|
|
133
|
+
await Promise.all([
|
|
134
|
+
storage.setItem('currentUser', user),
|
|
135
|
+
storage.setItem('authToken', token),
|
|
136
|
+
storage.setItem('loginTime', new Date().toISOString()),
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static async getUserSession() {
|
|
141
|
+
const user = await storage.getItem<User>('currentUser');
|
|
142
|
+
const token = await storage.getItem<string>('authToken');
|
|
143
|
+
|
|
144
|
+
return user && token ? { user, token } : null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static async clearSession() {
|
|
148
|
+
await Promise.all([
|
|
149
|
+
storage.removeItem('currentUser'),
|
|
150
|
+
storage.removeItem('authToken'),
|
|
151
|
+
storage.removeItem('loginTime'),
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Settings Management
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { storage } from '@idealyst/storage';
|
|
161
|
+
|
|
162
|
+
interface AppSettings {
|
|
163
|
+
theme: 'light' | 'dark';
|
|
164
|
+
notifications: boolean;
|
|
165
|
+
language: string;
|
|
166
|
+
fontSize: number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const defaultSettings: AppSettings = {
|
|
170
|
+
theme: 'light',
|
|
171
|
+
notifications: true,
|
|
172
|
+
language: 'en',
|
|
173
|
+
fontSize: 16,
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
class SettingsService {
|
|
177
|
+
static async getSettings(): Promise<AppSettings> {
|
|
178
|
+
const stored = await storage.getItem<AppSettings>('appSettings');
|
|
179
|
+
return stored ? { ...defaultSettings, ...stored } : defaultSettings;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static async updateSettings(newSettings: Partial<AppSettings>) {
|
|
183
|
+
const current = await this.getSettings();
|
|
184
|
+
const updated = { ...current, ...newSettings };
|
|
185
|
+
await storage.setItem('appSettings', updated);
|
|
186
|
+
return updated;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static async resetSettings() {
|
|
190
|
+
await storage.setItem('appSettings', defaultSettings);
|
|
191
|
+
return defaultSettings;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Cache Management
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { storage } from '@idealyst/storage';
|
|
200
|
+
|
|
201
|
+
interface CacheItem<T> {
|
|
202
|
+
data: T;
|
|
203
|
+
timestamp: number;
|
|
204
|
+
expiresIn: number; // milliseconds
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
class CacheService {
|
|
208
|
+
static async setCache<T>(key: string, data: T, expiresIn: number = 3600000) {
|
|
209
|
+
const cacheItem: CacheItem<T> = {
|
|
210
|
+
data,
|
|
211
|
+
timestamp: Date.now(),
|
|
212
|
+
expiresIn,
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
await storage.setItem(`cache_${key}`, cacheItem);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
static async getCache<T>(key: string): Promise<T | null> {
|
|
219
|
+
const cacheItem = await storage.getItem<CacheItem<T>>(`cache_${key}`);
|
|
220
|
+
|
|
221
|
+
if (!cacheItem) return null;
|
|
222
|
+
|
|
223
|
+
const isExpired = Date.now() - cacheItem.timestamp > cacheItem.expiresIn;
|
|
224
|
+
|
|
225
|
+
if (isExpired) {
|
|
226
|
+
await storage.removeItem(`cache_${key}`);
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return cacheItem.data;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static async clearExpiredCache() {
|
|
234
|
+
const keys = await storage.getAllKeys();
|
|
235
|
+
const cacheKeys = keys.filter(key => key.startsWith('cache_'));
|
|
236
|
+
|
|
237
|
+
for (const key of cacheKeys) {
|
|
238
|
+
const cacheItem = await storage.getItem<CacheItem<any>>(key);
|
|
239
|
+
if (cacheItem) {
|
|
240
|
+
const isExpired = Date.now() - cacheItem.timestamp > cacheItem.expiresIn;
|
|
241
|
+
if (isExpired) {
|
|
242
|
+
await storage.removeItem(key);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Platform Implementation Details
|
|
251
|
+
|
|
252
|
+
### React Native
|
|
253
|
+
- **Primary**: Uses `react-native-mmkv` for high-performance storage
|
|
254
|
+
- **Fallback**: Falls back to `AsyncStorage` if MMKV is unavailable
|
|
255
|
+
- **Security**: Data is stored securely on device
|
|
256
|
+
- **Performance**: MMKV provides near-instant read/write operations
|
|
257
|
+
|
|
258
|
+
### Web
|
|
259
|
+
- **Primary**: Uses browser `localStorage`
|
|
260
|
+
- **Fallback**: Graceful handling when localStorage is unavailable (private browsing)
|
|
261
|
+
- **Security**: Data persists across browser sessions
|
|
262
|
+
- **Limitations**: ~5-10MB storage limit per domain
|
|
263
|
+
|
|
264
|
+
## Error Handling
|
|
265
|
+
|
|
266
|
+
The storage system handles errors gracefully:
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
try {
|
|
270
|
+
await storage.setItem('data', largeObject);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
console.error('Storage failed:', error);
|
|
273
|
+
// Handle storage quota exceeded or other errors
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Or with error checking
|
|
277
|
+
const result = await storage.getItem('data');
|
|
278
|
+
if (result === null) {
|
|
279
|
+
// Key doesn't exist or retrieval failed
|
|
280
|
+
console.log('No data found or error occurred');
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## TypeScript Support
|
|
285
|
+
|
|
286
|
+
Full type safety with generics:
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
// Define your data types
|
|
290
|
+
interface UserPreferences {
|
|
291
|
+
theme: 'light' | 'dark';
|
|
292
|
+
language: string;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Type-safe storage operations
|
|
296
|
+
await storage.setItem('preferences', { theme: 'dark', language: 'en' });
|
|
297
|
+
const prefs = await storage.getItem<UserPreferences>('preferences');
|
|
298
|
+
|
|
299
|
+
if (prefs) {
|
|
300
|
+
// TypeScript knows the exact type
|
|
301
|
+
console.log(prefs.theme); // ✅ Type: 'light' | 'dark'
|
|
302
|
+
console.log(prefs.language); // ✅ Type: string
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Best Practices
|
|
307
|
+
|
|
308
|
+
1. **Use TypeScript**: Always specify types for better development experience
|
|
309
|
+
2. **Handle Nulls**: Always check for null returns from `getItem`
|
|
310
|
+
3. **Batch Operations**: Use `Promise.all` for multiple storage operations
|
|
311
|
+
4. **Error Handling**: Wrap storage operations in try-catch blocks for critical data
|
|
312
|
+
5. **Key Naming**: Use consistent, descriptive key names
|
|
313
|
+
6. **Data Size**: Keep stored objects reasonably sized
|
|
314
|
+
7. **Cleanup**: Periodically clean up unused data
|
|
315
|
+
|
|
316
|
+
## Performance Considerations
|
|
317
|
+
|
|
318
|
+
- **React Native**: MMKV provides excellent performance for frequent read/write operations
|
|
319
|
+
- **Web**: localStorage is synchronous but wrapped in async API for consistency
|
|
320
|
+
- **Large Data**: Consider chunking very large objects across multiple keys
|
|
321
|
+
- **Frequent Updates**: Storage operations are optimized but avoid excessive writes
|
|
322
|
+
|
|
323
|
+
## Migration Guide
|
|
324
|
+
|
|
325
|
+
If migrating from AsyncStorage or localStorage:
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
// Old AsyncStorage code
|
|
329
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
330
|
+
const value = await AsyncStorage.getItem('key');
|
|
331
|
+
|
|
332
|
+
// New @idealyst/storage code
|
|
333
|
+
import { storage } from '@idealyst/storage';
|
|
334
|
+
const value = await storage.getItem('key');
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
The API is nearly identical with these improvements:
|
|
338
|
+
- Automatic JSON serialization/deserialization
|
|
339
|
+
- Better TypeScript support
|
|
340
|
+
- Cross-platform compatibility
|
|
341
|
+
- Performance optimizations
|
|
342
|
+
|
|
343
|
+
## Contributing
|
|
344
|
+
|
|
345
|
+
We welcome contributions! Please see our [Contributing Guide](../../CONTRIBUTING.md) for details.
|
|
346
|
+
|
|
347
|
+
## License
|
|
348
|
+
|
|
349
|
+
MIT © [Idealyst](https://github.com/IdealystIO)
|
|
350
|
+
|
|
351
|
+
## Links
|
|
352
|
+
|
|
353
|
+
- [Documentation](https://github.com/IdealystIO/idealyst-framework/tree/main/packages/storage)
|
|
354
|
+
- [GitHub](https://github.com/IdealystIO/idealyst-framework)
|
|
355
|
+
- [Issues](https://github.com/IdealystIO/idealyst-framework/issues)
|
|
356
|
+
- [react-native-mmkv](https://github.com/mrousavy/react-native-mmkv)
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
Built with ❤️ by the Idealyst team
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idealyst/storage",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.56",
|
|
4
4
|
"description": "Cross-platform storage abstraction for React and React Native",
|
|
5
|
-
"documentation": "https://github.com/
|
|
5
|
+
"documentation": "https://github.com/IdealystIO/idealyst-framework/tree/main/packages/storage#readme",
|
|
6
|
+
"readme": "README.md",
|
|
6
7
|
"main": "src/index.ts",
|
|
7
8
|
"module": "src/index.ts",
|
|
8
9
|
"types": "src/index.ts",
|
|
9
10
|
"react-native": "src/index.native.ts",
|
|
10
11
|
"repository": {
|
|
11
12
|
"type": "git",
|
|
12
|
-
"url": "https://github.com/
|
|
13
|
+
"url": "https://github.com/IdealystIO/idealyst-framework.git",
|
|
13
14
|
"directory": "packages/storage"
|
|
14
15
|
},
|
|
15
16
|
"author": "Your Name <your.email@example.com>",
|