strata-storage 2.0.3 → 2.1.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/Readme.md +109 -27
- package/android/src/main/java/com/strata/storage/EncryptedStorage.java +44 -3
- package/android/src/main/java/com/strata/storage/SQLiteStorage.java +35 -5
- package/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +43 -3
- package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +12 -3
- package/dist/android/src/main/java/com/strata/storage/EncryptedStorage.java +44 -3
- package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +35 -5
- package/dist/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +43 -3
- package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +12 -3
- package/dist/capacitor.d.ts.map +1 -1
- package/dist/capacitor.js +4 -3
- package/dist/core/Strata.d.ts +133 -2
- package/dist/core/Strata.d.ts.map +1 -1
- package/dist/core/Strata.js +133 -2
- package/dist/firebase.d.ts.map +1 -1
- package/dist/firebase.js +21 -1
- package/dist/ios/Plugin/KeychainStorage.swift +31 -9
- package/dist/ios/Plugin/SQLiteStorage.swift +29 -6
- package/dist/ios/Plugin/UserDefaultsStorage.swift +25 -7
- package/dist/package.json +5 -5
- package/dist/plugin/web.d.ts +10 -6
- package/dist/plugin/web.d.ts.map +1 -1
- package/dist/plugin/web.js +42 -13
- package/dist/utils/index.d.ts +0 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +0 -3
- package/ios/Plugin/KeychainStorage.swift +31 -9
- package/ios/Plugin/SQLiteStorage.swift +29 -6
- package/ios/Plugin/UserDefaultsStorage.swift +25 -7
- package/package.json +15 -15
- package/dist/README.md +0 -179
package/Readme.md
CHANGED
|
@@ -2,14 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
## 📚 Documentation
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### Getting Started
|
|
6
|
+
- **[Installation](./docs/getting-started/installation.md)** - Installation and setup
|
|
6
7
|
- **[Quick Start Guide](./docs/getting-started/quick-start.md)** - Get running in minutes
|
|
7
|
-
- **[API Reference](./docs/api/README.md)** - Complete API documentation
|
|
8
8
|
- **[Configuration](./docs/getting-started/configuration.md)** - Configuration options
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
### Core Documentation
|
|
11
|
+
- **[API Reference](./docs/api/README.md)** - Complete API documentation
|
|
12
|
+
- **[Core API](./docs/api/core/strata.md)** - Main Strata class
|
|
13
|
+
- **[Type Definitions](./docs/api/core/types.md)** - TypeScript types
|
|
14
|
+
- **[Error Handling](./docs/api/core/errors.md)** - Error types and handling
|
|
15
|
+
|
|
16
|
+
### Storage Adapters
|
|
17
|
+
- **[Web Adapters](./docs/api/adapters/README.md#web-adapters)** - Browser storage
|
|
18
|
+
- [localStorage](./docs/api/adapters/web/localstorage.md)
|
|
19
|
+
- [sessionStorage](./docs/api/adapters/web/sessionstorage.md)
|
|
20
|
+
- [IndexedDB](./docs/api/adapters/web/indexeddb.md)
|
|
21
|
+
- [Cookies](./docs/api/adapters/web/cookies.md)
|
|
22
|
+
- [Cache API](./docs/api/adapters/web/cache.md)
|
|
23
|
+
- [Memory](./docs/api/adapters/web/memory.md)
|
|
24
|
+
- **[Capacitor Adapters](./docs/api/adapters/README.md#capacitor-adapters)** - Native storage
|
|
25
|
+
- [Preferences](./docs/api/adapters/capacitor/preferences.md)
|
|
26
|
+
- [Secure Storage](./docs/api/adapters/capacitor/secure.md)
|
|
27
|
+
- [SQLite](./docs/api/adapters/capacitor/sqlite.md)
|
|
28
|
+
- [Filesystem](./docs/api/adapters/capacitor/filesystem.md)
|
|
29
|
+
|
|
30
|
+
### Advanced Features
|
|
31
|
+
- **[Encryption](./docs/guides/features/encryption.md)** - Data encryption guide
|
|
32
|
+
- **[Compression](./docs/guides/features/compression.md)** - Data compression
|
|
33
|
+
- **[TTL Management](./docs/api/features/ttl.md)** - Auto-expiration
|
|
34
|
+
- **[Cross-Tab Sync](./docs/guides/features/sync.md)** - Real-time synchronization
|
|
35
|
+
- **[Query Engine](./docs/guides/features/queries.md)** - MongoDB-like queries
|
|
36
|
+
- **[Migrations](./docs/guides/features/migrations.md)** - Data migration system
|
|
37
|
+
|
|
38
|
+
### Platform Guides
|
|
39
|
+
- **[Web Platform](./docs/guides/platforms/web.md)** - Browser-specific features
|
|
40
|
+
- **[iOS Platform](./docs/guides/platforms/ios.md)** - iOS implementation
|
|
41
|
+
- **[Android Platform](./docs/guides/platforms/android.md)** - Android implementation
|
|
42
|
+
- **[Capacitor](./docs/guides/platforms/capacitor.md)** - Capacitor integration
|
|
43
|
+
|
|
44
|
+
### Common Patterns
|
|
45
|
+
- **[Caching Strategies](./docs/guides/patterns/caching.md)** - Caching best practices
|
|
46
|
+
- **[Session Management](./docs/guides/patterns/sessions.md)** - User session handling
|
|
47
|
+
|
|
48
|
+
### Examples
|
|
49
|
+
- **[Basic Usage](./docs/examples/basic-usage.md)** - Simple examples
|
|
50
|
+
- **[React Integration](./docs/examples/frameworks/react.md)** - React hooks and providers
|
|
51
|
+
- **[Vue Integration](./docs/examples/frameworks/vue.md)** - Vue composables
|
|
52
|
+
- **[Angular Integration](./docs/examples/frameworks/angular.md)** - Angular services
|
|
53
|
+
- **[Authentication](./docs/examples/user-auth.md)** - User authentication
|
|
54
|
+
- **[Shopping Cart](./docs/examples/shopping-cart.md)** - E-commerce example
|
|
55
|
+
- **[Form Persistence](./docs/examples/form-persistence.md)** - Form data saving
|
|
56
|
+
- **[Offline Support](./docs/examples/offline-support.md)** - Offline-first apps
|
|
57
|
+
- **[All Examples](./docs/examples/README.md)** - Complete examples list
|
|
58
|
+
|
|
59
|
+
### Resources
|
|
11
60
|
- **[GitHub](https://github.com/aoneahsan/strata-storage)** - Source code
|
|
12
61
|
- **[NPM](https://www.npmjs.com/package/strata-storage)** - Package registry
|
|
62
|
+
- **[Example App](./examples/react-capacitor-app)** - Full demo application
|
|
13
63
|
|
|
14
64
|
---
|
|
15
65
|
|
|
@@ -108,13 +158,13 @@ await storage.set('data', value, { storage: 'firestore' });
|
|
|
108
158
|
- ✅ **Filesystem** - File-based storage
|
|
109
159
|
|
|
110
160
|
### Advanced Features
|
|
111
|
-
- ✅ **Encryption** - AES-GCM encryption with Web Crypto API
|
|
112
|
-
- ✅ **Compression** - LZ-string compression algorithm
|
|
113
|
-
- ✅ **Cross-Tab Sync** - Real-time synchronization across tabs
|
|
114
|
-
- ✅ **Query Engine** - MongoDB-like queries for filtering data
|
|
115
|
-
- ✅ **TTL Support** - Automatic expiration with sliding TTL
|
|
116
|
-
- ✅ **Migration System** - Version-based data migrations
|
|
117
|
-
-
|
|
161
|
+
- ✅ **[Encryption](./docs/guides/features/encryption.md)** - AES-GCM encryption with Web Crypto API
|
|
162
|
+
- ✅ **[Compression](./docs/guides/features/compression.md)** - LZ-string compression algorithm
|
|
163
|
+
- ✅ **[Cross-Tab Sync](./docs/guides/features/sync.md)** - Real-time synchronization across tabs
|
|
164
|
+
- ✅ **[Query Engine](./docs/guides/features/queries.md)** - MongoDB-like queries for filtering data
|
|
165
|
+
- ✅ **[TTL Support](./docs/api/features/ttl.md)** - Automatic expiration with sliding TTL
|
|
166
|
+
- ✅ **[Migration System](./docs/guides/features/migrations.md)** - Version-based data migrations
|
|
167
|
+
- ✅ **Framework Integrations** - [React](./docs/examples/frameworks/react.md), [Vue](./docs/examples/frameworks/vue.md), [Angular](./docs/examples/frameworks/angular.md)
|
|
118
168
|
|
|
119
169
|
## 📖 Basic Usage
|
|
120
170
|
|
|
@@ -135,40 +185,72 @@ await storage.set('key', value, {
|
|
|
135
185
|
ttl: 3600000, // Expire in 1 hour
|
|
136
186
|
encrypt: true, // Encrypt this value
|
|
137
187
|
compress: true, // Compress if beneficial
|
|
138
|
-
tags: ['user-data']
|
|
188
|
+
tags: ['user-data'], // Tag for grouping
|
|
189
|
+
metadata: { // Attach metadata
|
|
190
|
+
version: 1,
|
|
191
|
+
source: 'api'
|
|
192
|
+
}
|
|
139
193
|
});
|
|
140
194
|
|
|
141
|
-
// Query data
|
|
195
|
+
// Query data with MongoDB-like syntax
|
|
142
196
|
const results = await storage.query({
|
|
143
197
|
tags: { $in: ['user-data'] },
|
|
144
|
-
'value.age': { $gte: 18 }
|
|
198
|
+
'value.age': { $gte: 18 },
|
|
199
|
+
'metadata.version': 1
|
|
145
200
|
});
|
|
146
201
|
|
|
147
202
|
// Subscribe to changes
|
|
148
203
|
storage.subscribe((change) => {
|
|
149
204
|
console.log(`${change.key} changed from ${change.oldValue} to ${change.newValue}`);
|
|
150
205
|
});
|
|
206
|
+
|
|
207
|
+
// Check storage size
|
|
208
|
+
const size = await storage.size();
|
|
209
|
+
console.log(`Using ${size.total} bytes for ${size.count} items`);
|
|
151
210
|
```
|
|
152
211
|
|
|
153
|
-
## 🎯
|
|
212
|
+
## 🎯 Why Strata Storage?
|
|
213
|
+
|
|
214
|
+
### Provider-less Architecture
|
|
215
|
+
Like Zustand, Strata Storage works without providers, contexts, or wrappers. Just import and use - no setup required.
|
|
216
|
+
|
|
217
|
+
### Zero Dependencies
|
|
218
|
+
Truly zero runtime dependencies. Everything is implemented from scratch for maximum control and minimal bundle size.
|
|
219
|
+
|
|
220
|
+
### Universal Compatibility
|
|
221
|
+
- **One API** - Same code works on Web, iOS, and Android
|
|
222
|
+
- **Any Framework** - Works with React, Vue, Angular, or vanilla JavaScript
|
|
223
|
+
- **TypeScript First** - Full type safety and excellent IntelliSense
|
|
224
|
+
- **Tree-Shakeable** - Only bundle what you use
|
|
154
225
|
|
|
155
|
-
|
|
226
|
+
### Intelligent Storage Selection
|
|
227
|
+
Automatically selects the best available storage based on:
|
|
228
|
+
- Platform capabilities
|
|
229
|
+
- Data size and type
|
|
230
|
+
- Performance requirements
|
|
231
|
+
- Persistence needs
|
|
156
232
|
|
|
157
|
-
|
|
158
|
-
- **
|
|
159
|
-
- **
|
|
160
|
-
- **
|
|
233
|
+
### Enterprise Ready
|
|
234
|
+
- **Encryption** - Built-in AES-GCM encryption
|
|
235
|
+
- **Compression** - Automatic data compression
|
|
236
|
+
- **TTL/Expiration** - Auto-cleanup of expired data
|
|
237
|
+
- **Sync** - Real-time cross-tab/device synchronization
|
|
238
|
+
- **Migrations** - Version-based data migrations
|
|
239
|
+
- **Querying** - MongoDB-like query engine
|
|
161
240
|
|
|
162
241
|
## 🏗 Project Status
|
|
163
242
|
|
|
164
|
-
|
|
165
|
-
- ✅
|
|
166
|
-
- ✅
|
|
167
|
-
- ✅
|
|
243
|
+
**Production Ready** - All major features implemented:
|
|
244
|
+
- ✅ Zero-dependency architecture
|
|
245
|
+
- ✅ Provider-less design (like Zustand)
|
|
246
|
+
- ✅ All web storage adapters (localStorage, IndexedDB, etc.)
|
|
247
|
+
- ✅ Complete Capacitor integration (iOS/Android)
|
|
248
|
+
- ✅ Native implementations (iOS Swift, Android Java)
|
|
168
249
|
- ✅ Advanced features (encryption, compression, sync, query, TTL)
|
|
169
|
-
- ✅
|
|
170
|
-
-
|
|
171
|
-
-
|
|
250
|
+
- ✅ Framework integrations (React, Vue, Angular)
|
|
251
|
+
- ✅ Comprehensive documentation
|
|
252
|
+
- ✅ Full TypeScript support
|
|
253
|
+
- ✅ Example application with all features
|
|
172
254
|
|
|
173
255
|
## 📄 License
|
|
174
256
|
|
|
@@ -6,14 +6,20 @@ import android.os.Build;
|
|
|
6
6
|
import androidx.security.crypto.EncryptedSharedPreferences;
|
|
7
7
|
import androidx.security.crypto.MasterKey;
|
|
8
8
|
import java.util.Set;
|
|
9
|
+
import java.util.HashSet;
|
|
9
10
|
import java.util.Map;
|
|
10
11
|
|
|
11
12
|
public class EncryptedStorage {
|
|
12
13
|
private SharedPreferences encryptedPrefs;
|
|
13
14
|
private SharedPreferences.Editor editor;
|
|
15
|
+
private static final String DEFAULT_NAME = "StrataSecureStorage";
|
|
16
|
+
|
|
17
|
+
public EncryptedStorage(Context context) throws Exception {
|
|
18
|
+
this(context, DEFAULT_NAME);
|
|
19
|
+
}
|
|
14
20
|
|
|
15
21
|
public EncryptedStorage(Context context, String name) throws Exception {
|
|
16
|
-
String fileName = name != null ? name :
|
|
22
|
+
String fileName = name != null ? name : DEFAULT_NAME;
|
|
17
23
|
|
|
18
24
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
19
25
|
MasterKey masterKey = new MasterKey.Builder(context)
|
|
@@ -51,12 +57,47 @@ public class EncryptedStorage {
|
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
public boolean clear() {
|
|
54
|
-
|
|
60
|
+
return clear(null);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public boolean clear(String prefix) {
|
|
64
|
+
if (prefix != null) {
|
|
65
|
+
// Clear only keys with the given prefix
|
|
66
|
+
Set<String> keysToRemove = new HashSet<>();
|
|
67
|
+
for (String key : encryptedPrefs.getAll().keySet()) {
|
|
68
|
+
if (key.startsWith(prefix) || key.contains(prefix)) {
|
|
69
|
+
keysToRemove.add(key);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (String key : keysToRemove) {
|
|
73
|
+
editor.remove(key);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
// Clear all keys
|
|
77
|
+
editor.clear();
|
|
78
|
+
}
|
|
55
79
|
return editor.commit();
|
|
56
80
|
}
|
|
57
81
|
|
|
58
82
|
public Set<String> keys() {
|
|
59
|
-
return
|
|
83
|
+
return keys(null);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public Set<String> keys(String pattern) {
|
|
87
|
+
Set<String> allKeys = encryptedPrefs.getAll().keySet();
|
|
88
|
+
|
|
89
|
+
if (pattern == null) {
|
|
90
|
+
return allKeys;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Filter keys by pattern
|
|
94
|
+
Set<String> filteredKeys = new HashSet<>();
|
|
95
|
+
for (String key : allKeys) {
|
|
96
|
+
if (key.startsWith(pattern) || key.contains(pattern)) {
|
|
97
|
+
filteredKeys.add(key);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return filteredKeys;
|
|
60
101
|
}
|
|
61
102
|
|
|
62
103
|
public boolean has(String key) {
|
|
@@ -13,6 +13,7 @@ import java.util.Map;
|
|
|
13
13
|
public class SQLiteStorage extends SQLiteOpenHelper {
|
|
14
14
|
private static final int DATABASE_VERSION = 1;
|
|
15
15
|
private static final String TABLE_NAME = "strata_storage";
|
|
16
|
+
private static final String DEFAULT_DB_NAME = "strata.db";
|
|
16
17
|
|
|
17
18
|
private static final String KEY_ID = "key";
|
|
18
19
|
private static final String KEY_VALUE = "value";
|
|
@@ -22,8 +23,12 @@ public class SQLiteStorage extends SQLiteOpenHelper {
|
|
|
22
23
|
private static final String KEY_TAGS = "tags";
|
|
23
24
|
private static final String KEY_METADATA = "metadata";
|
|
24
25
|
|
|
26
|
+
public SQLiteStorage(Context context) {
|
|
27
|
+
this(context, DEFAULT_DB_NAME);
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
public SQLiteStorage(Context context, String dbName) {
|
|
26
|
-
super(context, dbName != null ? dbName :
|
|
31
|
+
super(context, dbName != null ? dbName : DEFAULT_DB_NAME, null, DATABASE_VERSION);
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
@Override
|
|
@@ -112,18 +117,43 @@ public class SQLiteStorage extends SQLiteOpenHelper {
|
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
public boolean clear() {
|
|
120
|
+
return clear(null);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public boolean clear(String prefix) {
|
|
115
124
|
SQLiteDatabase db = this.getWritableDatabase();
|
|
116
|
-
|
|
125
|
+
int result;
|
|
126
|
+
|
|
127
|
+
if (prefix != null) {
|
|
128
|
+
// Clear only keys with the given prefix
|
|
129
|
+
result = db.delete(TABLE_NAME, KEY_ID + " LIKE ?", new String[]{prefix + "%"});
|
|
130
|
+
} else {
|
|
131
|
+
// Clear all keys
|
|
132
|
+
result = db.delete(TABLE_NAME, null, null);
|
|
133
|
+
}
|
|
134
|
+
|
|
117
135
|
db.close();
|
|
118
|
-
return
|
|
136
|
+
return result >= 0;
|
|
119
137
|
}
|
|
120
138
|
|
|
121
139
|
public List<String> keys() {
|
|
140
|
+
return keys(null);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public List<String> keys(String pattern) {
|
|
122
144
|
List<String> keys = new ArrayList<>();
|
|
123
|
-
String selectQuery
|
|
145
|
+
String selectQuery;
|
|
146
|
+
String[] selectionArgs = null;
|
|
147
|
+
|
|
148
|
+
if (pattern != null) {
|
|
149
|
+
selectQuery = "SELECT " + KEY_ID + " FROM " + TABLE_NAME + " WHERE " + KEY_ID + " LIKE ?";
|
|
150
|
+
selectionArgs = new String[]{"% " + pattern + "%"};
|
|
151
|
+
} else {
|
|
152
|
+
selectQuery = "SELECT " + KEY_ID + " FROM " + TABLE_NAME;
|
|
153
|
+
}
|
|
124
154
|
|
|
125
155
|
SQLiteDatabase db = this.getReadableDatabase();
|
|
126
|
-
Cursor cursor = db.rawQuery(selectQuery,
|
|
156
|
+
Cursor cursor = db.rawQuery(selectQuery, selectionArgs);
|
|
127
157
|
|
|
128
158
|
if (cursor.moveToFirst()) {
|
|
129
159
|
do {
|
|
@@ -11,9 +11,14 @@ import org.json.JSONArray;
|
|
|
11
11
|
public class SharedPreferencesStorage {
|
|
12
12
|
private final SharedPreferences prefs;
|
|
13
13
|
private final SharedPreferences.Editor editor;
|
|
14
|
+
private static final String DEFAULT_NAME = "StrataStorage";
|
|
15
|
+
|
|
16
|
+
public SharedPreferencesStorage(Context context) {
|
|
17
|
+
this(context, DEFAULT_NAME);
|
|
18
|
+
}
|
|
14
19
|
|
|
15
20
|
public SharedPreferencesStorage(Context context, String name) {
|
|
16
|
-
this.prefs = context.getSharedPreferences(name != null ? name :
|
|
21
|
+
this.prefs = context.getSharedPreferences(name != null ? name : DEFAULT_NAME, Context.MODE_PRIVATE);
|
|
17
22
|
this.editor = prefs.edit();
|
|
18
23
|
}
|
|
19
24
|
|
|
@@ -56,12 +61,47 @@ public class SharedPreferencesStorage {
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
public boolean clear() {
|
|
59
|
-
|
|
64
|
+
return clear(null);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public boolean clear(String prefix) {
|
|
68
|
+
if (prefix != null) {
|
|
69
|
+
// Clear only keys with the given prefix
|
|
70
|
+
Set<String> keysToRemove = new HashSet<>();
|
|
71
|
+
for (String key : prefs.getAll().keySet()) {
|
|
72
|
+
if (key.startsWith(prefix) || key.contains(prefix)) {
|
|
73
|
+
keysToRemove.add(key);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (String key : keysToRemove) {
|
|
77
|
+
editor.remove(key);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
// Clear all keys
|
|
81
|
+
editor.clear();
|
|
82
|
+
}
|
|
60
83
|
return editor.commit();
|
|
61
84
|
}
|
|
62
85
|
|
|
63
86
|
public Set<String> keys() {
|
|
64
|
-
return
|
|
87
|
+
return keys(null);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public Set<String> keys(String pattern) {
|
|
91
|
+
Set<String> allKeys = prefs.getAll().keySet();
|
|
92
|
+
|
|
93
|
+
if (pattern == null) {
|
|
94
|
+
return allKeys;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Filter keys by pattern
|
|
98
|
+
Set<String> filteredKeys = new HashSet<>();
|
|
99
|
+
for (String key : allKeys) {
|
|
100
|
+
if (key.startsWith(pattern) || key.contains(pattern)) {
|
|
101
|
+
filteredKeys.add(key);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return filteredKeys;
|
|
65
105
|
}
|
|
66
106
|
|
|
67
107
|
public boolean has(String key) {
|
|
@@ -5,9 +5,13 @@ import com.getcapacitor.Plugin;
|
|
|
5
5
|
import com.getcapacitor.PluginCall;
|
|
6
6
|
import com.getcapacitor.PluginMethod;
|
|
7
7
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
8
|
+
import com.strata.storage.SharedPreferencesStorage;
|
|
9
|
+
import com.strata.storage.EncryptedStorage;
|
|
10
|
+
import com.strata.storage.SQLiteStorage;
|
|
8
11
|
import org.json.JSONArray;
|
|
9
12
|
import org.json.JSONException;
|
|
10
13
|
import java.util.List;
|
|
14
|
+
import java.util.Set;
|
|
11
15
|
|
|
12
16
|
/**
|
|
13
17
|
* Main Capacitor plugin for Strata Storage
|
|
@@ -21,9 +25,14 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
21
25
|
|
|
22
26
|
@Override
|
|
23
27
|
public void load() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
try {
|
|
29
|
+
sharedPrefsStorage = new SharedPreferencesStorage(getContext());
|
|
30
|
+
encryptedStorage = new EncryptedStorage(getContext());
|
|
31
|
+
sqliteStorage = new SQLiteStorage(getContext());
|
|
32
|
+
} catch (Exception e) {
|
|
33
|
+
// Log error but don't crash - some storage types may not be available
|
|
34
|
+
e.printStackTrace();
|
|
35
|
+
}
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
/**
|
|
@@ -6,14 +6,20 @@ import android.os.Build;
|
|
|
6
6
|
import androidx.security.crypto.EncryptedSharedPreferences;
|
|
7
7
|
import androidx.security.crypto.MasterKey;
|
|
8
8
|
import java.util.Set;
|
|
9
|
+
import java.util.HashSet;
|
|
9
10
|
import java.util.Map;
|
|
10
11
|
|
|
11
12
|
public class EncryptedStorage {
|
|
12
13
|
private SharedPreferences encryptedPrefs;
|
|
13
14
|
private SharedPreferences.Editor editor;
|
|
15
|
+
private static final String DEFAULT_NAME = "StrataSecureStorage";
|
|
16
|
+
|
|
17
|
+
public EncryptedStorage(Context context) throws Exception {
|
|
18
|
+
this(context, DEFAULT_NAME);
|
|
19
|
+
}
|
|
14
20
|
|
|
15
21
|
public EncryptedStorage(Context context, String name) throws Exception {
|
|
16
|
-
String fileName = name != null ? name :
|
|
22
|
+
String fileName = name != null ? name : DEFAULT_NAME;
|
|
17
23
|
|
|
18
24
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
19
25
|
MasterKey masterKey = new MasterKey.Builder(context)
|
|
@@ -51,12 +57,47 @@ public class EncryptedStorage {
|
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
public boolean clear() {
|
|
54
|
-
|
|
60
|
+
return clear(null);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public boolean clear(String prefix) {
|
|
64
|
+
if (prefix != null) {
|
|
65
|
+
// Clear only keys with the given prefix
|
|
66
|
+
Set<String> keysToRemove = new HashSet<>();
|
|
67
|
+
for (String key : encryptedPrefs.getAll().keySet()) {
|
|
68
|
+
if (key.startsWith(prefix) || key.contains(prefix)) {
|
|
69
|
+
keysToRemove.add(key);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (String key : keysToRemove) {
|
|
73
|
+
editor.remove(key);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
// Clear all keys
|
|
77
|
+
editor.clear();
|
|
78
|
+
}
|
|
55
79
|
return editor.commit();
|
|
56
80
|
}
|
|
57
81
|
|
|
58
82
|
public Set<String> keys() {
|
|
59
|
-
return
|
|
83
|
+
return keys(null);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public Set<String> keys(String pattern) {
|
|
87
|
+
Set<String> allKeys = encryptedPrefs.getAll().keySet();
|
|
88
|
+
|
|
89
|
+
if (pattern == null) {
|
|
90
|
+
return allKeys;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Filter keys by pattern
|
|
94
|
+
Set<String> filteredKeys = new HashSet<>();
|
|
95
|
+
for (String key : allKeys) {
|
|
96
|
+
if (key.startsWith(pattern) || key.contains(pattern)) {
|
|
97
|
+
filteredKeys.add(key);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return filteredKeys;
|
|
60
101
|
}
|
|
61
102
|
|
|
62
103
|
public boolean has(String key) {
|
|
@@ -13,6 +13,7 @@ import java.util.Map;
|
|
|
13
13
|
public class SQLiteStorage extends SQLiteOpenHelper {
|
|
14
14
|
private static final int DATABASE_VERSION = 1;
|
|
15
15
|
private static final String TABLE_NAME = "strata_storage";
|
|
16
|
+
private static final String DEFAULT_DB_NAME = "strata.db";
|
|
16
17
|
|
|
17
18
|
private static final String KEY_ID = "key";
|
|
18
19
|
private static final String KEY_VALUE = "value";
|
|
@@ -22,8 +23,12 @@ public class SQLiteStorage extends SQLiteOpenHelper {
|
|
|
22
23
|
private static final String KEY_TAGS = "tags";
|
|
23
24
|
private static final String KEY_METADATA = "metadata";
|
|
24
25
|
|
|
26
|
+
public SQLiteStorage(Context context) {
|
|
27
|
+
this(context, DEFAULT_DB_NAME);
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
public SQLiteStorage(Context context, String dbName) {
|
|
26
|
-
super(context, dbName != null ? dbName :
|
|
31
|
+
super(context, dbName != null ? dbName : DEFAULT_DB_NAME, null, DATABASE_VERSION);
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
@Override
|
|
@@ -112,18 +117,43 @@ public class SQLiteStorage extends SQLiteOpenHelper {
|
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
public boolean clear() {
|
|
120
|
+
return clear(null);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public boolean clear(String prefix) {
|
|
115
124
|
SQLiteDatabase db = this.getWritableDatabase();
|
|
116
|
-
|
|
125
|
+
int result;
|
|
126
|
+
|
|
127
|
+
if (prefix != null) {
|
|
128
|
+
// Clear only keys with the given prefix
|
|
129
|
+
result = db.delete(TABLE_NAME, KEY_ID + " LIKE ?", new String[]{prefix + "%"});
|
|
130
|
+
} else {
|
|
131
|
+
// Clear all keys
|
|
132
|
+
result = db.delete(TABLE_NAME, null, null);
|
|
133
|
+
}
|
|
134
|
+
|
|
117
135
|
db.close();
|
|
118
|
-
return
|
|
136
|
+
return result >= 0;
|
|
119
137
|
}
|
|
120
138
|
|
|
121
139
|
public List<String> keys() {
|
|
140
|
+
return keys(null);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public List<String> keys(String pattern) {
|
|
122
144
|
List<String> keys = new ArrayList<>();
|
|
123
|
-
String selectQuery
|
|
145
|
+
String selectQuery;
|
|
146
|
+
String[] selectionArgs = null;
|
|
147
|
+
|
|
148
|
+
if (pattern != null) {
|
|
149
|
+
selectQuery = "SELECT " + KEY_ID + " FROM " + TABLE_NAME + " WHERE " + KEY_ID + " LIKE ?";
|
|
150
|
+
selectionArgs = new String[]{"% " + pattern + "%"};
|
|
151
|
+
} else {
|
|
152
|
+
selectQuery = "SELECT " + KEY_ID + " FROM " + TABLE_NAME;
|
|
153
|
+
}
|
|
124
154
|
|
|
125
155
|
SQLiteDatabase db = this.getReadableDatabase();
|
|
126
|
-
Cursor cursor = db.rawQuery(selectQuery,
|
|
156
|
+
Cursor cursor = db.rawQuery(selectQuery, selectionArgs);
|
|
127
157
|
|
|
128
158
|
if (cursor.moveToFirst()) {
|
|
129
159
|
do {
|
|
@@ -11,9 +11,14 @@ import org.json.JSONArray;
|
|
|
11
11
|
public class SharedPreferencesStorage {
|
|
12
12
|
private final SharedPreferences prefs;
|
|
13
13
|
private final SharedPreferences.Editor editor;
|
|
14
|
+
private static final String DEFAULT_NAME = "StrataStorage";
|
|
15
|
+
|
|
16
|
+
public SharedPreferencesStorage(Context context) {
|
|
17
|
+
this(context, DEFAULT_NAME);
|
|
18
|
+
}
|
|
14
19
|
|
|
15
20
|
public SharedPreferencesStorage(Context context, String name) {
|
|
16
|
-
this.prefs = context.getSharedPreferences(name != null ? name :
|
|
21
|
+
this.prefs = context.getSharedPreferences(name != null ? name : DEFAULT_NAME, Context.MODE_PRIVATE);
|
|
17
22
|
this.editor = prefs.edit();
|
|
18
23
|
}
|
|
19
24
|
|
|
@@ -56,12 +61,47 @@ public class SharedPreferencesStorage {
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
public boolean clear() {
|
|
59
|
-
|
|
64
|
+
return clear(null);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public boolean clear(String prefix) {
|
|
68
|
+
if (prefix != null) {
|
|
69
|
+
// Clear only keys with the given prefix
|
|
70
|
+
Set<String> keysToRemove = new HashSet<>();
|
|
71
|
+
for (String key : prefs.getAll().keySet()) {
|
|
72
|
+
if (key.startsWith(prefix) || key.contains(prefix)) {
|
|
73
|
+
keysToRemove.add(key);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (String key : keysToRemove) {
|
|
77
|
+
editor.remove(key);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
// Clear all keys
|
|
81
|
+
editor.clear();
|
|
82
|
+
}
|
|
60
83
|
return editor.commit();
|
|
61
84
|
}
|
|
62
85
|
|
|
63
86
|
public Set<String> keys() {
|
|
64
|
-
return
|
|
87
|
+
return keys(null);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public Set<String> keys(String pattern) {
|
|
91
|
+
Set<String> allKeys = prefs.getAll().keySet();
|
|
92
|
+
|
|
93
|
+
if (pattern == null) {
|
|
94
|
+
return allKeys;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Filter keys by pattern
|
|
98
|
+
Set<String> filteredKeys = new HashSet<>();
|
|
99
|
+
for (String key : allKeys) {
|
|
100
|
+
if (key.startsWith(pattern) || key.contains(pattern)) {
|
|
101
|
+
filteredKeys.add(key);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return filteredKeys;
|
|
65
105
|
}
|
|
66
106
|
|
|
67
107
|
public boolean has(String key) {
|
|
@@ -5,9 +5,13 @@ import com.getcapacitor.Plugin;
|
|
|
5
5
|
import com.getcapacitor.PluginCall;
|
|
6
6
|
import com.getcapacitor.PluginMethod;
|
|
7
7
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
8
|
+
import com.strata.storage.SharedPreferencesStorage;
|
|
9
|
+
import com.strata.storage.EncryptedStorage;
|
|
10
|
+
import com.strata.storage.SQLiteStorage;
|
|
8
11
|
import org.json.JSONArray;
|
|
9
12
|
import org.json.JSONException;
|
|
10
13
|
import java.util.List;
|
|
14
|
+
import java.util.Set;
|
|
11
15
|
|
|
12
16
|
/**
|
|
13
17
|
* Main Capacitor plugin for Strata Storage
|
|
@@ -21,9 +25,14 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
21
25
|
|
|
22
26
|
@Override
|
|
23
27
|
public void load() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
try {
|
|
29
|
+
sharedPrefsStorage = new SharedPreferencesStorage(getContext());
|
|
30
|
+
encryptedStorage = new EncryptedStorage(getContext());
|
|
31
|
+
sqliteStorage = new SQLiteStorage(getContext());
|
|
32
|
+
} catch (Exception e) {
|
|
33
|
+
// Log error but don't crash - some storage types may not be available
|
|
34
|
+
e.printStackTrace();
|
|
35
|
+
}
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
/**
|
package/dist/capacitor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capacitor.d.ts","sourceRoot":"","sources":["../src/capacitor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAO5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAG3E,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"capacitor.d.ts","sourceRoot":"","sources":["../src/capacitor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAO5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAG3E,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB9E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAShD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,EAAE,CAEnD"}
|