strata-storage 2.6.0 → 2.7.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/AI-INTEGRATION-GUIDE.md +97 -10
- package/README.md +70 -70
- package/android/AGENTS.md +18 -3
- package/android/CLAUDE.md +36 -3
- package/android/build.gradle +5 -1
- package/android/src/main/java/com/strata/storage/EncryptedStorage.java +31 -18
- package/android/src/main/java/com/strata/storage/FilesystemStorage.java +62 -10
- package/android/src/main/java/com/strata/storage/SQLiteStorage.java +65 -13
- package/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +63 -51
- package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +80 -11
- package/dist/README.md +70 -70
- package/dist/adapters/capacitor/FilesystemAdapter.d.ts +2 -2
- package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/FilesystemAdapter.js +6 -2
- package/dist/adapters/capacitor/PreferencesAdapter.d.ts +2 -2
- package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/PreferencesAdapter.js +6 -2
- package/dist/adapters/capacitor/SecureAdapter.d.ts +3 -3
- package/dist/adapters/capacitor/SecureAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/SecureAdapter.js +6 -2
- package/dist/adapters/capacitor/SqliteAdapter.d.ts +24 -3
- package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/SqliteAdapter.js +105 -23
- package/dist/adapters/capacitor/index.d.ts +4 -4
- package/dist/adapters/web/CacheAdapter.d.ts +2 -2
- package/dist/adapters/web/CookieAdapter.d.ts +2 -2
- package/dist/adapters/web/IndexedDBAdapter.d.ts +10 -3
- package/dist/adapters/web/IndexedDBAdapter.d.ts.map +1 -1
- package/dist/adapters/web/IndexedDBAdapter.js +14 -3
- package/dist/adapters/web/LocalStorageAdapter.d.ts +2 -2
- package/dist/adapters/web/MemoryAdapter.d.ts +2 -2
- package/dist/adapters/web/SessionStorageAdapter.d.ts +10 -10
- package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/SessionStorageAdapter.js +3 -2
- package/dist/adapters/web/URLAdapter.d.ts +2 -2
- package/dist/adapters/web/index.d.ts +7 -7
- package/dist/capacitor.d.ts +6 -6
- package/dist/capacitor.d.ts.map +1 -1
- package/dist/capacitor.js +5 -4
- package/dist/core/AdapterRegistry.d.ts +1 -1
- package/dist/core/BaseAdapter.d.ts +21 -5
- package/dist/core/BaseAdapter.d.ts.map +1 -1
- package/dist/core/BaseAdapter.js +29 -1
- package/dist/core/Strata.d.ts +41 -7
- package/dist/core/Strata.d.ts.map +1 -1
- package/dist/core/Strata.js +476 -118
- package/dist/features/compression/index.d.ts +1 -1
- package/dist/features/compression.d.ts +5 -1
- package/dist/features/compression.d.ts.map +1 -1
- package/dist/features/encryption/index.d.ts +1 -1
- package/dist/features/encryption.d.ts +55 -2
- package/dist/features/encryption.d.ts.map +1 -1
- package/dist/features/encryption.js +139 -26
- package/dist/features/migration.d.ts +1 -1
- package/dist/features/observer/index.d.ts +1 -1
- package/dist/features/observer.d.ts +1 -1
- package/dist/features/query/index.d.ts +1 -1
- package/dist/features/query.d.ts +1 -1
- package/dist/features/query.d.ts.map +1 -1
- package/dist/features/query.js +3 -1
- package/dist/features/sync/index.d.ts +1 -1
- package/dist/features/sync.d.ts +19 -3
- package/dist/features/sync.d.ts.map +1 -1
- package/dist/features/sync.js +57 -9
- package/dist/features/ttl/index.d.ts +1 -1
- package/dist/features/ttl.d.ts +2 -2
- package/dist/firebase.d.ts +1 -1
- package/dist/firebase.d.ts.map +1 -1
- package/dist/firebase.js +34 -9
- package/dist/index.d.ts +24 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/integrations/angular/index.d.ts +2 -2
- package/dist/integrations/angular/index.d.ts.map +1 -1
- package/dist/integrations/angular/index.js +7 -8
- package/dist/integrations/react/index.d.ts +3 -3
- package/dist/integrations/react/index.d.ts.map +1 -1
- package/dist/integrations/react/index.js +16 -4
- package/dist/integrations/vue/index.d.ts +2 -2
- package/dist/integrations/vue/index.d.ts.map +1 -1
- package/dist/integrations/vue/index.js +5 -2
- package/dist/package.json +11 -2
- package/dist/plugin/definitions.d.ts +29 -3
- package/dist/plugin/definitions.d.ts.map +1 -1
- package/dist/plugin/index.d.ts +2 -2
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +3 -0
- package/dist/plugin/web.d.ts +11 -2
- package/dist/plugin/web.d.ts.map +1 -1
- package/dist/plugin/web.js +23 -4
- package/dist/types/index.d.ts +50 -20
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -10
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +7 -0
- package/ios/AGENTS.md +14 -3
- package/ios/CLAUDE.md +25 -3
- package/ios/Plugin/FilesystemStorage.swift +19 -0
- package/ios/Plugin/SQLiteStorage.swift +59 -9
- package/ios/Plugin/StrataStoragePlugin.m +1 -0
- package/ios/Plugin/StrataStoragePlugin.swift +87 -34
- package/ios/Plugin/UserDefaultsStorage.swift +47 -46
- package/package.json +29 -26
- package/scripts/build.js +16 -14
- package/scripts/cli.js +1 -1
- package/scripts/configure.js +2 -2
- package/scripts/postinstall.js +3 -2
- package/dist/android/AGENTS.md +0 -51
- package/dist/android/CLAUDE.md +0 -89
- package/dist/android/build.gradle +0 -58
- package/dist/android/proguard-rules.pro +0 -11
- package/dist/android/settings.gradle +0 -2
- package/dist/android/src/main/AndroidManifest.xml +0 -2
- package/dist/android/src/main/java/com/strata/storage/EncryptedStorage.java +0 -218
- package/dist/android/src/main/java/com/strata/storage/FilesystemStorage.java +0 -287
- package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +0 -371
- package/dist/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +0 -209
- package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +0 -616
- package/dist/core/StorageStrategy.d.ts +0 -55
- package/dist/core/StorageStrategy.d.ts.map +0 -1
- package/dist/core/StorageStrategy.js +0 -200
- package/dist/ios/AGENTS.md +0 -48
- package/dist/ios/CLAUDE.md +0 -84
- package/dist/ios/Plugin/FilesystemStorage.swift +0 -218
- package/dist/ios/Plugin/KeychainStorage.swift +0 -233
- package/dist/ios/Plugin/SQLiteStorage.swift +0 -426
- package/dist/ios/Plugin/StrataStoragePlugin.m +0 -23
- package/dist/ios/Plugin/StrataStoragePlugin.swift +0 -411
- package/dist/ios/Plugin/UserDefaultsStorage.swift +0 -87
|
@@ -1,616 +0,0 @@
|
|
|
1
|
-
package com.stratastorage;
|
|
2
|
-
|
|
3
|
-
import com.getcapacitor.JSObject;
|
|
4
|
-
import com.getcapacitor.JSArray;
|
|
5
|
-
import com.getcapacitor.Plugin;
|
|
6
|
-
import com.getcapacitor.PluginCall;
|
|
7
|
-
import com.getcapacitor.PluginMethod;
|
|
8
|
-
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
9
|
-
import com.strata.storage.SharedPreferencesStorage;
|
|
10
|
-
import com.strata.storage.EncryptedStorage;
|
|
11
|
-
import com.strata.storage.FilesystemStorage;
|
|
12
|
-
import com.strata.storage.SQLiteStorage;
|
|
13
|
-
import android.util.Log;
|
|
14
|
-
import org.json.JSONArray;
|
|
15
|
-
import java.util.HashMap;
|
|
16
|
-
import java.util.List;
|
|
17
|
-
import java.util.Map;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Main Capacitor plugin for Strata Storage
|
|
21
|
-
* Coordinates between different storage types on Android.
|
|
22
|
-
*
|
|
23
|
-
* Storage types with a real native backend: preferences, secure, sqlite,
|
|
24
|
-
* filesystem.
|
|
25
|
-
*
|
|
26
|
-
* SQLite supports multi-store: the `database` option selects the DB file and
|
|
27
|
-
* `table` selects the table within it. SQLite helper instances are cached per
|
|
28
|
-
* database name so the connection is not reopened per call.
|
|
29
|
-
*/
|
|
30
|
-
@CapacitorPlugin(name = "StrataStorage")
|
|
31
|
-
public class StrataStoragePlugin extends Plugin {
|
|
32
|
-
private static final String DEFAULT_DATABASE = "strata_storage";
|
|
33
|
-
private static final String DEFAULT_TABLE = "storage";
|
|
34
|
-
|
|
35
|
-
private SharedPreferencesStorage sharedPrefsStorage;
|
|
36
|
-
private EncryptedStorage encryptedStorage;
|
|
37
|
-
private FilesystemStorage filesystemStorage;
|
|
38
|
-
|
|
39
|
-
/** SQLite helper cache keyed by resolved database name (without ".db"). */
|
|
40
|
-
private final Map<String, SQLiteStorage> sqliteStores = new HashMap<>();
|
|
41
|
-
|
|
42
|
-
@Override
|
|
43
|
-
public void load() {
|
|
44
|
-
try {
|
|
45
|
-
sharedPrefsStorage = new SharedPreferencesStorage(getContext());
|
|
46
|
-
} catch (Exception e) {
|
|
47
|
-
Log.e("StrataStorage", "Failed to initialize preferences storage", e);
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
encryptedStorage = new EncryptedStorage(getContext());
|
|
51
|
-
} catch (Exception e) {
|
|
52
|
-
// Secure storage may be unavailable on some devices/keystores —
|
|
53
|
-
// keep the rest of the plugin functional.
|
|
54
|
-
Log.e("StrataStorage", "Failed to initialize encrypted storage", e);
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
filesystemStorage = new FilesystemStorage(getContext());
|
|
58
|
-
} catch (Exception e) {
|
|
59
|
-
Log.e("StrataStorage", "Failed to initialize filesystem storage", e);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Sanitize a database name to a safe file stem ({@code ^[A-Za-z0-9_]+$})
|
|
65
|
-
* and return the resolved stem. The ".db" suffix is appended when opening.
|
|
66
|
-
*/
|
|
67
|
-
private static String sanitizeDatabase(String database) {
|
|
68
|
-
if (database == null || database.isEmpty()) {
|
|
69
|
-
return DEFAULT_DATABASE;
|
|
70
|
-
}
|
|
71
|
-
String cleaned = database.replaceAll("[^A-Za-z0-9_]", "");
|
|
72
|
-
return cleaned.isEmpty() ? DEFAULT_DATABASE : cleaned;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Return (creating + caching on first use) the SQLite helper for the given
|
|
77
|
-
* database name. The cache is keyed by the sanitized DB stem so the
|
|
78
|
-
* connection is reused across bridge calls. May return {@code null} if the
|
|
79
|
-
* helper cannot be constructed.
|
|
80
|
-
*/
|
|
81
|
-
private synchronized SQLiteStorage getSqliteStore(String database) {
|
|
82
|
-
String dbStem = sanitizeDatabase(database);
|
|
83
|
-
SQLiteStorage store = sqliteStores.get(dbStem);
|
|
84
|
-
if (store == null) {
|
|
85
|
-
try {
|
|
86
|
-
store = new SQLiteStorage(getContext(), dbStem + ".db");
|
|
87
|
-
sqliteStores.put(dbStem, store);
|
|
88
|
-
} catch (Exception e) {
|
|
89
|
-
Log.e("StrataStorage", "Failed to open SQLite database " + dbStem, e);
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return store;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Check if a specific storage type is available.
|
|
98
|
-
* Matches the JS contract: resolves { available: boolean }.
|
|
99
|
-
*/
|
|
100
|
-
@PluginMethod
|
|
101
|
-
public void isAvailable(PluginCall call) {
|
|
102
|
-
String storage = call.getString("storage", "preferences");
|
|
103
|
-
boolean available;
|
|
104
|
-
switch (storage) {
|
|
105
|
-
case "secure":
|
|
106
|
-
available = encryptedStorage != null;
|
|
107
|
-
break;
|
|
108
|
-
case "sqlite":
|
|
109
|
-
available = getSqliteStore(call.getString("database", DEFAULT_DATABASE)) != null;
|
|
110
|
-
break;
|
|
111
|
-
case "filesystem":
|
|
112
|
-
available = filesystemStorage != null;
|
|
113
|
-
break;
|
|
114
|
-
case "preferences":
|
|
115
|
-
default:
|
|
116
|
-
available = sharedPrefsStorage != null;
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
JSObject result = new JSObject();
|
|
121
|
-
result.put("available", available);
|
|
122
|
-
call.resolve(result);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get value from storage.
|
|
127
|
-
*
|
|
128
|
-
* For sqlite/filesystem the resolved `value` is the full wrapper object
|
|
129
|
-
* (parsed back from JSON). A miss resolves `value` = null.
|
|
130
|
-
*/
|
|
131
|
-
@PluginMethod
|
|
132
|
-
public void get(PluginCall call) {
|
|
133
|
-
String key = call.getString("key");
|
|
134
|
-
if (key == null) {
|
|
135
|
-
call.reject("Key is required");
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
String storage = call.getString("storage", "preferences");
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
switch (storage) {
|
|
143
|
-
case "secure": {
|
|
144
|
-
if (encryptedStorage == null) {
|
|
145
|
-
call.reject("Encrypted storage not available");
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
resolveValue(call, encryptedStorage.get(key));
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
case "sqlite": {
|
|
152
|
-
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
153
|
-
if (store == null) {
|
|
154
|
-
call.reject("SQLite storage not available");
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
String table = call.getString("table", DEFAULT_TABLE);
|
|
158
|
-
resolveValue(call, store.get(table, key));
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
case "filesystem": {
|
|
162
|
-
if (filesystemStorage == null) {
|
|
163
|
-
call.reject("Filesystem storage not available");
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
resolveValue(call, filesystemStorage.get(key));
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
case "preferences":
|
|
170
|
-
default: {
|
|
171
|
-
if (sharedPrefsStorage == null) {
|
|
172
|
-
call.reject("Preferences storage not available");
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
resolveValue(call, sharedPrefsStorage.get(key));
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
} catch (Exception e) {
|
|
180
|
-
call.reject("Failed to get value", e);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Resolve a get() call, mapping a Java {@code null} to a JS {@code null}
|
|
186
|
-
* value so the TS adapters treat it as a miss.
|
|
187
|
-
*/
|
|
188
|
-
private void resolveValue(PluginCall call, Object value) {
|
|
189
|
-
JSObject result = new JSObject();
|
|
190
|
-
if (value == null) {
|
|
191
|
-
result.put("value", JSObject.NULL);
|
|
192
|
-
} else {
|
|
193
|
-
result.put("value", value);
|
|
194
|
-
}
|
|
195
|
-
call.resolve(result);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Set value in storage.
|
|
200
|
-
*
|
|
201
|
-
* For sqlite/filesystem the `value` is the FULL wrapper object
|
|
202
|
-
* ({ value, created, updated, expires?, tags?, metadata? }); it is read via
|
|
203
|
-
* call.getObject("value") and stored verbatim (with TTL/query columns
|
|
204
|
-
* extracted for sqlite). For preferences/secure the raw value is forwarded
|
|
205
|
-
* unchanged.
|
|
206
|
-
*/
|
|
207
|
-
@PluginMethod
|
|
208
|
-
public void set(PluginCall call) {
|
|
209
|
-
String key = call.getString("key");
|
|
210
|
-
if (key == null) {
|
|
211
|
-
call.reject("Key is required");
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
String storage = call.getString("storage", "preferences");
|
|
216
|
-
|
|
217
|
-
try {
|
|
218
|
-
boolean ok;
|
|
219
|
-
switch (storage) {
|
|
220
|
-
case "secure":
|
|
221
|
-
if (encryptedStorage == null) {
|
|
222
|
-
call.reject("Encrypted storage not available");
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
ok = encryptedStorage.set(key, call.getData().opt("value"));
|
|
226
|
-
break;
|
|
227
|
-
case "sqlite": {
|
|
228
|
-
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
229
|
-
if (store == null) {
|
|
230
|
-
call.reject("SQLite storage not available");
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
JSObject wrapper = call.getObject("value");
|
|
234
|
-
if (wrapper == null) {
|
|
235
|
-
call.reject("A wrapper object 'value' is required for sqlite storage");
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
ok = store.set(call.getString("table", DEFAULT_TABLE), key, wrapper);
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
case "filesystem": {
|
|
242
|
-
if (filesystemStorage == null) {
|
|
243
|
-
call.reject("Filesystem storage not available");
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
JSObject wrapper = call.getObject("value");
|
|
247
|
-
if (wrapper == null) {
|
|
248
|
-
call.reject("A wrapper object 'value' is required for filesystem storage");
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
ok = filesystemStorage.set(key, wrapper);
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
case "preferences":
|
|
255
|
-
default:
|
|
256
|
-
if (sharedPrefsStorage == null) {
|
|
257
|
-
call.reject("Preferences storage not available");
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
ok = sharedPrefsStorage.set(key, call.getData().opt("value"));
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (!ok) {
|
|
265
|
-
call.reject("Failed to persist value to " + storage + " storage");
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
call.resolve();
|
|
269
|
-
} catch (Exception e) {
|
|
270
|
-
call.reject("Failed to set value", e);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Remove value from storage
|
|
276
|
-
*/
|
|
277
|
-
@PluginMethod
|
|
278
|
-
public void remove(PluginCall call) {
|
|
279
|
-
String key = call.getString("key");
|
|
280
|
-
if (key == null) {
|
|
281
|
-
call.reject("Key is required");
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
String storage = call.getString("storage", "preferences");
|
|
286
|
-
|
|
287
|
-
try {
|
|
288
|
-
switch (storage) {
|
|
289
|
-
case "secure":
|
|
290
|
-
if (encryptedStorage == null) {
|
|
291
|
-
call.reject("Encrypted storage not available");
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
encryptedStorage.remove(key);
|
|
295
|
-
break;
|
|
296
|
-
case "sqlite": {
|
|
297
|
-
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
298
|
-
if (store == null) {
|
|
299
|
-
call.reject("SQLite storage not available");
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
store.remove(call.getString("table", DEFAULT_TABLE), key);
|
|
303
|
-
break;
|
|
304
|
-
}
|
|
305
|
-
case "filesystem":
|
|
306
|
-
if (filesystemStorage == null) {
|
|
307
|
-
call.reject("Filesystem storage not available");
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
filesystemStorage.remove(key);
|
|
311
|
-
break;
|
|
312
|
-
case "preferences":
|
|
313
|
-
default:
|
|
314
|
-
if (sharedPrefsStorage == null) {
|
|
315
|
-
call.reject("Preferences storage not available");
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
sharedPrefsStorage.remove(key);
|
|
319
|
-
break;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
call.resolve();
|
|
323
|
-
} catch (Exception e) {
|
|
324
|
-
call.reject("Failed to remove value", e);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Clear storage.
|
|
330
|
-
* Accepts the JS `pattern` (used as a key prefix) and a legacy `prefix`.
|
|
331
|
-
*/
|
|
332
|
-
@PluginMethod
|
|
333
|
-
public void clear(PluginCall call) {
|
|
334
|
-
String storage = call.getString("storage", "preferences");
|
|
335
|
-
String prefix = call.getString("pattern");
|
|
336
|
-
if (prefix == null) {
|
|
337
|
-
prefix = call.getString("prefix");
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
try {
|
|
341
|
-
switch (storage) {
|
|
342
|
-
case "secure":
|
|
343
|
-
if (encryptedStorage == null) {
|
|
344
|
-
call.reject("Encrypted storage not available");
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
encryptedStorage.clear(prefix);
|
|
348
|
-
break;
|
|
349
|
-
case "sqlite": {
|
|
350
|
-
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
351
|
-
if (store == null) {
|
|
352
|
-
call.reject("SQLite storage not available");
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
store.clear(call.getString("table", DEFAULT_TABLE), prefix);
|
|
356
|
-
break;
|
|
357
|
-
}
|
|
358
|
-
case "filesystem":
|
|
359
|
-
if (filesystemStorage == null) {
|
|
360
|
-
call.reject("Filesystem storage not available");
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
filesystemStorage.clear(prefix);
|
|
364
|
-
break;
|
|
365
|
-
case "preferences":
|
|
366
|
-
default:
|
|
367
|
-
if (sharedPrefsStorage == null) {
|
|
368
|
-
call.reject("Preferences storage not available");
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
sharedPrefsStorage.clear(prefix);
|
|
372
|
-
break;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
call.resolve();
|
|
376
|
-
} catch (Exception e) {
|
|
377
|
-
call.reject("Failed to clear storage", e);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Get all keys from storage
|
|
383
|
-
*/
|
|
384
|
-
@PluginMethod
|
|
385
|
-
public void keys(PluginCall call) {
|
|
386
|
-
String storage = call.getString("storage", "preferences");
|
|
387
|
-
String pattern = call.getString("pattern");
|
|
388
|
-
|
|
389
|
-
try {
|
|
390
|
-
List<String> keys;
|
|
391
|
-
|
|
392
|
-
switch (storage) {
|
|
393
|
-
case "secure":
|
|
394
|
-
if (encryptedStorage == null) {
|
|
395
|
-
call.reject("Encrypted storage not available");
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
keys = encryptedStorage.keys(pattern);
|
|
399
|
-
break;
|
|
400
|
-
case "sqlite": {
|
|
401
|
-
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
402
|
-
if (store == null) {
|
|
403
|
-
call.reject("SQLite storage not available");
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
keys = store.keys(call.getString("table", DEFAULT_TABLE), pattern);
|
|
407
|
-
break;
|
|
408
|
-
}
|
|
409
|
-
case "filesystem":
|
|
410
|
-
if (filesystemStorage == null) {
|
|
411
|
-
call.reject("Filesystem storage not available");
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
keys = filesystemStorage.keys(pattern);
|
|
415
|
-
break;
|
|
416
|
-
case "preferences":
|
|
417
|
-
default:
|
|
418
|
-
if (sharedPrefsStorage == null) {
|
|
419
|
-
call.reject("Preferences storage not available");
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
keys = sharedPrefsStorage.keys(pattern);
|
|
423
|
-
break;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
JSObject result = new JSObject();
|
|
427
|
-
result.put("keys", new JSONArray(keys));
|
|
428
|
-
call.resolve(result);
|
|
429
|
-
} catch (Exception e) {
|
|
430
|
-
call.reject("Failed to get keys", e);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Get storage size information.
|
|
436
|
-
*
|
|
437
|
-
* When `detailed` is true the result also carries a byte breakdown
|
|
438
|
-
* { detailed: { keys, values, metadata } }.
|
|
439
|
-
*/
|
|
440
|
-
@PluginMethod
|
|
441
|
-
public void size(PluginCall call) {
|
|
442
|
-
String storage = call.getString("storage", "preferences");
|
|
443
|
-
boolean detailed = Boolean.TRUE.equals(call.getBoolean("detailed", false));
|
|
444
|
-
|
|
445
|
-
try {
|
|
446
|
-
JSObject result = new JSObject();
|
|
447
|
-
|
|
448
|
-
switch (storage) {
|
|
449
|
-
case "secure": {
|
|
450
|
-
if (encryptedStorage == null) {
|
|
451
|
-
call.reject("Encrypted storage not available");
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
EncryptedStorage.SizeInfo encryptedSizeInfo = encryptedStorage.size();
|
|
455
|
-
result.put("total", encryptedSizeInfo.total);
|
|
456
|
-
result.put("count", encryptedSizeInfo.count);
|
|
457
|
-
break;
|
|
458
|
-
}
|
|
459
|
-
case "sqlite": {
|
|
460
|
-
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
461
|
-
if (store == null) {
|
|
462
|
-
call.reject("SQLite storage not available");
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
SQLiteStorage.SizeInfo sqliteSizeInfo =
|
|
466
|
-
store.size(call.getString("table", DEFAULT_TABLE), detailed);
|
|
467
|
-
putSizeInfo(result, sqliteSizeInfo);
|
|
468
|
-
break;
|
|
469
|
-
}
|
|
470
|
-
case "filesystem": {
|
|
471
|
-
if (filesystemStorage == null) {
|
|
472
|
-
call.reject("Filesystem storage not available");
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
|
-
SQLiteStorage.SizeInfo fsSizeInfo = filesystemStorage.size(detailed);
|
|
476
|
-
putSizeInfo(result, fsSizeInfo);
|
|
477
|
-
break;
|
|
478
|
-
}
|
|
479
|
-
case "preferences":
|
|
480
|
-
default: {
|
|
481
|
-
if (sharedPrefsStorage == null) {
|
|
482
|
-
call.reject("Preferences storage not available");
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
SharedPreferencesStorage.SizeInfo prefsSizeInfo = sharedPrefsStorage.size();
|
|
486
|
-
result.put("total", prefsSizeInfo.total);
|
|
487
|
-
result.put("count", prefsSizeInfo.count);
|
|
488
|
-
break;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
call.resolve(result);
|
|
493
|
-
} catch (Exception e) {
|
|
494
|
-
call.reject("Failed to get size", e);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Populate a size result, including the detailed byte breakdown when the
|
|
500
|
-
* {@link SQLiteStorage.SizeInfo} carries one.
|
|
501
|
-
*/
|
|
502
|
-
private void putSizeInfo(JSObject result, SQLiteStorage.SizeInfo info) {
|
|
503
|
-
result.put("total", info.total);
|
|
504
|
-
result.put("count", info.count);
|
|
505
|
-
if (info.detailed) {
|
|
506
|
-
JSObject breakdown = new JSObject();
|
|
507
|
-
breakdown.put("keys", info.keysBytes);
|
|
508
|
-
breakdown.put("values", info.valuesBytes);
|
|
509
|
-
breakdown.put("metadata", info.metadataBytes);
|
|
510
|
-
result.put("detailed", breakdown);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/**
|
|
515
|
-
* Query SQLite-backed storage.
|
|
516
|
-
* Matches the optional `query` method in the JS contract:
|
|
517
|
-
* resolves { results: [{ key }] }. The JS SqliteAdapter applies the real
|
|
518
|
-
* condition by re-fetching/filtering, so this enumerates candidate keys.
|
|
519
|
-
*/
|
|
520
|
-
@PluginMethod
|
|
521
|
-
public void query(PluginCall call) {
|
|
522
|
-
String storage = call.getString("storage", "sqlite");
|
|
523
|
-
if (!"sqlite".equals(storage)) {
|
|
524
|
-
call.reject("Query is only supported for the 'sqlite' storage type");
|
|
525
|
-
return;
|
|
526
|
-
}
|
|
527
|
-
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
528
|
-
if (store == null) {
|
|
529
|
-
call.reject("SQLite storage not available");
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
try {
|
|
534
|
-
List<Map<String, Object>> rows = store.query(call.getString("table", DEFAULT_TABLE));
|
|
535
|
-
JSArray results = new JSArray();
|
|
536
|
-
for (Map<String, Object> row : rows) {
|
|
537
|
-
JSObject obj = new JSObject();
|
|
538
|
-
obj.put("key", row.get("key"));
|
|
539
|
-
results.put(obj);
|
|
540
|
-
}
|
|
541
|
-
JSObject result = new JSObject();
|
|
542
|
-
result.put("results", results);
|
|
543
|
-
call.resolve(result);
|
|
544
|
-
} catch (Exception e) {
|
|
545
|
-
call.reject("Failed to query SQLite", e);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Android-specific: read an encrypted preference.
|
|
551
|
-
* Resolves { value: unknown }. Honors an optional `fileName`.
|
|
552
|
-
*/
|
|
553
|
-
@PluginMethod
|
|
554
|
-
public void getEncryptedPreference(PluginCall call) {
|
|
555
|
-
String key = call.getString("key");
|
|
556
|
-
if (key == null) {
|
|
557
|
-
call.reject("Key is required");
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
String fileName = call.getString("fileName");
|
|
561
|
-
|
|
562
|
-
try {
|
|
563
|
-
EncryptedStorage store = resolveEncryptedStore(fileName);
|
|
564
|
-
if (store == null) {
|
|
565
|
-
call.reject("Encrypted storage not available");
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
JSObject result = new JSObject();
|
|
569
|
-
result.put("value", store.get(key));
|
|
570
|
-
call.resolve(result);
|
|
571
|
-
} catch (Exception e) {
|
|
572
|
-
call.reject("Failed to read encrypted preference", e);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
/**
|
|
577
|
-
* Android-specific: write an encrypted preference. Honors an optional
|
|
578
|
-
* `fileName`.
|
|
579
|
-
*/
|
|
580
|
-
@PluginMethod
|
|
581
|
-
public void setEncryptedPreference(PluginCall call) {
|
|
582
|
-
String key = call.getString("key");
|
|
583
|
-
if (key == null) {
|
|
584
|
-
call.reject("Key is required");
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
Object value = call.getData().opt("value");
|
|
588
|
-
String fileName = call.getString("fileName");
|
|
589
|
-
|
|
590
|
-
try {
|
|
591
|
-
EncryptedStorage store = resolveEncryptedStore(fileName);
|
|
592
|
-
if (store == null) {
|
|
593
|
-
call.reject("Encrypted storage not available");
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
|
-
if (!store.set(key, value)) {
|
|
597
|
-
call.reject("Failed to persist encrypted preference");
|
|
598
|
-
return;
|
|
599
|
-
}
|
|
600
|
-
call.resolve();
|
|
601
|
-
} catch (Exception e) {
|
|
602
|
-
call.reject("Failed to write encrypted preference", e);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* Returns the default encrypted store, or builds a file-specific one when a
|
|
608
|
-
* custom file name is supplied.
|
|
609
|
-
*/
|
|
610
|
-
private EncryptedStorage resolveEncryptedStore(String fileName) throws Exception {
|
|
611
|
-
if (fileName == null || fileName.isEmpty()) {
|
|
612
|
-
return encryptedStorage;
|
|
613
|
-
}
|
|
614
|
-
return new EncryptedStorage(getContext(), fileName);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Storage strategy implementation for automatic adapter selection
|
|
3
|
-
*/
|
|
4
|
-
import type { StorageAdapter, StorageType, StorageCapabilities } from '@/types';
|
|
5
|
-
import { StorageStrategy } from '@/types';
|
|
6
|
-
import { AdapterRegistry } from './AdapterRegistry';
|
|
7
|
-
/**
|
|
8
|
-
* Strategy manager for selecting appropriate storage adapters
|
|
9
|
-
*/
|
|
10
|
-
export declare class StrategyManager {
|
|
11
|
-
private registry;
|
|
12
|
-
private strategy;
|
|
13
|
-
constructor(registry: AdapterRegistry, strategy?: StorageStrategy);
|
|
14
|
-
/**
|
|
15
|
-
* Get the best adapter based on current strategy
|
|
16
|
-
*/
|
|
17
|
-
getBestAdapter(preferredTypes?: StorageType[], requirements?: Partial<StorageCapabilities>): Promise<StorageAdapter | null>;
|
|
18
|
-
/**
|
|
19
|
-
* Get multiple adapters sorted by preference
|
|
20
|
-
*/
|
|
21
|
-
getAdapterChain(count: number, preferredTypes?: StorageType[], requirements?: Partial<StorageCapabilities>): Promise<StorageAdapter[]>;
|
|
22
|
-
/**
|
|
23
|
-
* Check if capabilities meet requirements
|
|
24
|
-
*/
|
|
25
|
-
private meetsRequirements;
|
|
26
|
-
/**
|
|
27
|
-
* Compare two adapters based on current strategy
|
|
28
|
-
*/
|
|
29
|
-
private compareAdapters;
|
|
30
|
-
/**
|
|
31
|
-
* Compare adapters by performance
|
|
32
|
-
*/
|
|
33
|
-
private comparePerformance;
|
|
34
|
-
/**
|
|
35
|
-
* Compare adapters by persistence
|
|
36
|
-
*/
|
|
37
|
-
private comparePersistence;
|
|
38
|
-
/**
|
|
39
|
-
* Compare adapters by security
|
|
40
|
-
*/
|
|
41
|
-
private compareSecurity;
|
|
42
|
-
/**
|
|
43
|
-
* Compare adapters by capacity
|
|
44
|
-
*/
|
|
45
|
-
private compareCapacity;
|
|
46
|
-
/**
|
|
47
|
-
* Update strategy
|
|
48
|
-
*/
|
|
49
|
-
setStrategy(strategy: StorageStrategy): void;
|
|
50
|
-
/**
|
|
51
|
-
* Get current strategy
|
|
52
|
-
*/
|
|
53
|
-
getStrategy(): StorageStrategy;
|
|
54
|
-
}
|
|
55
|
-
//# sourceMappingURL=StorageStrategy.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StorageStrategy.d.ts","sourceRoot":"","sources":["../../src/core/StorageStrategy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;GAEG;AACH,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,QAAQ;gBADR,QAAQ,EAAE,eAAe,EACzB,QAAQ,GAAE,eAAmD;IAGvE;;OAEG;IACG,cAAc,CAClB,cAAc,CAAC,EAAE,WAAW,EAAE,EAC9B,YAAY,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAC1C,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAqBjC;;OAEG;IACG,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,WAAW,EAAE,EAC9B,YAAY,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAC1C,OAAO,CAAC,cAAc,EAAE,CAAC;IAkB5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsBzB;;OAEG;IACH,OAAO,CAAC,eAAe;IAmBvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA0B1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA0B1B;;OAEG;IACH,OAAO,CAAC,eAAe;IA0BvB;;OAEG;IACH,OAAO,CAAC,eAAe;IA+BvB;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAI5C;;OAEG;IACH,WAAW,IAAI,eAAe;CAG/B"}
|