strata-storage 2.4.3 → 2.6.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 +115 -261
- package/README.md +426 -182
- package/android/AGENTS.md +51 -0
- package/android/CLAUDE.md +89 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/strata/storage/FilesystemStorage.java +287 -0
- package/android/src/main/java/com/strata/storage/SQLiteStorage.java +260 -203
- package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +357 -69
- package/dist/README.md +426 -182
- package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/FilesystemAdapter.js +2 -1
- package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/PreferencesAdapter.js +2 -1
- package/dist/adapters/capacitor/SecureAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/SecureAdapter.js +2 -1
- package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/SqliteAdapter.js +2 -1
- package/dist/adapters/web/CacheAdapter.d.ts.map +1 -1
- package/dist/adapters/web/CacheAdapter.js +11 -3
- package/dist/adapters/web/CookieAdapter.d.ts +37 -1
- package/dist/adapters/web/CookieAdapter.d.ts.map +1 -1
- package/dist/adapters/web/CookieAdapter.js +89 -9
- package/dist/adapters/web/IndexedDBAdapter.d.ts.map +1 -1
- package/dist/adapters/web/IndexedDBAdapter.js +10 -2
- package/dist/adapters/web/LocalStorageAdapter.d.ts +31 -0
- package/dist/adapters/web/LocalStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/LocalStorageAdapter.js +92 -19
- package/dist/adapters/web/MemoryAdapter.d.ts +24 -0
- package/dist/adapters/web/MemoryAdapter.d.ts.map +1 -1
- package/dist/adapters/web/MemoryAdapter.js +69 -18
- package/dist/adapters/web/SessionStorageAdapter.d.ts +24 -0
- package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/SessionStorageAdapter.js +71 -9
- package/dist/adapters/web/URLAdapter.d.ts +59 -0
- package/dist/adapters/web/URLAdapter.d.ts.map +1 -0
- package/dist/adapters/web/URLAdapter.js +234 -0
- package/dist/adapters/web/index.d.ts +1 -0
- package/dist/adapters/web/index.d.ts.map +1 -1
- package/dist/adapters/web/index.js +1 -0
- package/dist/android/AGENTS.md +51 -0
- package/dist/android/CLAUDE.md +89 -0
- package/dist/android/build.gradle +1 -1
- package/dist/android/src/main/java/com/strata/storage/FilesystemStorage.java +287 -0
- package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +260 -203
- package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +357 -69
- package/dist/capacitor.d.ts.map +1 -1
- package/dist/capacitor.js +2 -1
- package/dist/core/BaseAdapter.d.ts +8 -0
- package/dist/core/BaseAdapter.d.ts.map +1 -1
- package/dist/core/BaseAdapter.js +34 -14
- package/dist/core/Strata.d.ts +56 -2
- package/dist/core/Strata.d.ts.map +1 -1
- package/dist/core/Strata.js +501 -53
- package/dist/features/encryption.d.ts.map +1 -1
- package/dist/features/encryption.js +3 -2
- package/dist/features/integrity.d.ts +16 -0
- package/dist/features/integrity.d.ts.map +1 -0
- package/dist/features/integrity.js +28 -0
- package/dist/features/observer.d.ts.map +1 -1
- package/dist/features/observer.js +2 -1
- package/dist/features/query.d.ts +7 -1
- package/dist/features/query.d.ts.map +1 -1
- package/dist/features/query.js +9 -2
- package/dist/features/sync.d.ts.map +1 -1
- package/dist/features/sync.js +4 -3
- package/dist/index.d.ts +35 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -30
- package/dist/integrations/angular/index.d.ts +158 -0
- package/dist/integrations/angular/index.d.ts.map +1 -0
- package/dist/integrations/angular/index.js +395 -0
- package/dist/integrations/index.d.ts +15 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +18 -0
- package/dist/integrations/react/index.d.ts +75 -0
- package/dist/integrations/react/index.d.ts.map +1 -0
- package/dist/integrations/react/index.js +191 -0
- package/dist/integrations/vue/index.d.ts +103 -0
- package/dist/integrations/vue/index.d.ts.map +1 -0
- package/dist/integrations/vue/index.js +274 -0
- package/dist/ios/AGENTS.md +48 -0
- package/dist/ios/CLAUDE.md +84 -0
- package/dist/ios/Plugin/FilesystemStorage.swift +218 -0
- package/dist/ios/Plugin/KeychainStorage.swift +139 -50
- package/dist/ios/Plugin/SQLiteStorage.swift +279 -147
- package/dist/ios/Plugin/StrataStoragePlugin.m +23 -0
- package/dist/ios/Plugin/StrataStoragePlugin.swift +272 -65
- package/dist/package.json +21 -5
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +2 -1
- package/dist/types/index.d.ts +58 -9
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -13
- package/dist/utils/errors.d.ts +7 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +15 -3
- package/dist/utils/index.d.ts +63 -5
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +109 -16
- package/dist/utils/logger.d.ts +31 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +63 -0
- package/ios/AGENTS.md +48 -0
- package/ios/CLAUDE.md +84 -0
- package/ios/Plugin/FilesystemStorage.swift +218 -0
- package/ios/Plugin/KeychainStorage.swift +139 -50
- package/ios/Plugin/SQLiteStorage.swift +279 -147
- package/ios/Plugin/StrataStoragePlugin.m +23 -0
- package/ios/Plugin/StrataStoragePlugin.swift +272 -65
- package/package.json +31 -20
- package/scripts/build.js +16 -5
- package/scripts/configure.js +2 -6
- package/scripts/postinstall.js +2 -2
- package/Readme.md +0 -271
|
@@ -1,61 +1,132 @@
|
|
|
1
1
|
package com.stratastorage;
|
|
2
2
|
|
|
3
3
|
import com.getcapacitor.JSObject;
|
|
4
|
+
import com.getcapacitor.JSArray;
|
|
4
5
|
import com.getcapacitor.Plugin;
|
|
5
6
|
import com.getcapacitor.PluginCall;
|
|
6
7
|
import com.getcapacitor.PluginMethod;
|
|
7
8
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
8
9
|
import com.strata.storage.SharedPreferencesStorage;
|
|
9
10
|
import com.strata.storage.EncryptedStorage;
|
|
11
|
+
import com.strata.storage.FilesystemStorage;
|
|
10
12
|
import com.strata.storage.SQLiteStorage;
|
|
11
13
|
import android.util.Log;
|
|
12
14
|
import org.json.JSONArray;
|
|
13
|
-
import
|
|
15
|
+
import java.util.HashMap;
|
|
14
16
|
import java.util.List;
|
|
17
|
+
import java.util.Map;
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Main Capacitor plugin for Strata Storage
|
|
18
|
-
* Coordinates between different storage types on Android
|
|
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.
|
|
19
29
|
*/
|
|
20
30
|
@CapacitorPlugin(name = "StrataStorage")
|
|
21
31
|
public class StrataStoragePlugin extends Plugin {
|
|
32
|
+
private static final String DEFAULT_DATABASE = "strata_storage";
|
|
33
|
+
private static final String DEFAULT_TABLE = "storage";
|
|
34
|
+
|
|
22
35
|
private SharedPreferencesStorage sharedPrefsStorage;
|
|
23
36
|
private EncryptedStorage encryptedStorage;
|
|
24
|
-
private
|
|
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<>();
|
|
25
41
|
|
|
26
42
|
@Override
|
|
27
43
|
public void load() {
|
|
28
44
|
try {
|
|
29
45
|
sharedPrefsStorage = new SharedPreferencesStorage(getContext());
|
|
46
|
+
} catch (Exception e) {
|
|
47
|
+
Log.e("StrataStorage", "Failed to initialize preferences storage", e);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
30
50
|
encryptedStorage = new EncryptedStorage(getContext());
|
|
31
|
-
sqliteStorage = new SQLiteStorage(getContext());
|
|
32
51
|
} catch (Exception e) {
|
|
33
|
-
//
|
|
34
|
-
|
|
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
|
+
}
|
|
35
92
|
}
|
|
93
|
+
return store;
|
|
36
94
|
}
|
|
37
95
|
|
|
38
96
|
/**
|
|
39
|
-
* Check if storage is available
|
|
97
|
+
* Check if a specific storage type is available.
|
|
98
|
+
* Matches the JS contract: resolves { available: boolean }.
|
|
40
99
|
*/
|
|
41
100
|
@PluginMethod
|
|
42
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
|
+
|
|
43
120
|
JSObject result = new JSObject();
|
|
44
|
-
result.put("available",
|
|
45
|
-
result.put("platform", "android");
|
|
46
|
-
|
|
47
|
-
JSObject adapters = new JSObject();
|
|
48
|
-
adapters.put("preferences", true);
|
|
49
|
-
adapters.put("secure", true);
|
|
50
|
-
adapters.put("sqlite", true);
|
|
51
|
-
adapters.put("filesystem", true);
|
|
52
|
-
result.put("adapters", adapters);
|
|
53
|
-
|
|
121
|
+
result.put("available", available);
|
|
54
122
|
call.resolve(result);
|
|
55
123
|
}
|
|
56
124
|
|
|
57
125
|
/**
|
|
58
|
-
* Get value from storage
|
|
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.
|
|
59
130
|
*/
|
|
60
131
|
@PluginMethod
|
|
61
132
|
public void get(PluginCall call) {
|
|
@@ -66,45 +137,72 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
66
137
|
}
|
|
67
138
|
|
|
68
139
|
String storage = call.getString("storage", "preferences");
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
Object value = null;
|
|
72
140
|
|
|
141
|
+
try {
|
|
73
142
|
switch (storage) {
|
|
74
|
-
case "secure":
|
|
143
|
+
case "secure": {
|
|
75
144
|
if (encryptedStorage == null) {
|
|
76
145
|
call.reject("Encrypted storage not available");
|
|
77
146
|
return;
|
|
78
147
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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) {
|
|
83
154
|
call.reject("SQLite storage not available");
|
|
84
155
|
return;
|
|
85
156
|
}
|
|
86
|
-
|
|
87
|
-
|
|
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
|
+
}
|
|
88
169
|
case "preferences":
|
|
89
|
-
default:
|
|
170
|
+
default: {
|
|
90
171
|
if (sharedPrefsStorage == null) {
|
|
91
172
|
call.reject("Preferences storage not available");
|
|
92
173
|
return;
|
|
93
174
|
}
|
|
94
|
-
|
|
95
|
-
|
|
175
|
+
resolveValue(call, sharedPrefsStorage.get(key));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
96
178
|
}
|
|
97
|
-
|
|
98
|
-
JSObject result = new JSObject();
|
|
99
|
-
result.put("value", value);
|
|
100
|
-
call.resolve(result);
|
|
101
179
|
} catch (Exception e) {
|
|
102
180
|
call.reject("Failed to get value", e);
|
|
103
181
|
}
|
|
104
182
|
}
|
|
105
183
|
|
|
106
184
|
/**
|
|
107
|
-
*
|
|
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.
|
|
108
206
|
*/
|
|
109
207
|
@PluginMethod
|
|
110
208
|
public void set(PluginCall call) {
|
|
@@ -114,35 +212,59 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
114
212
|
return;
|
|
115
213
|
}
|
|
116
214
|
|
|
117
|
-
Object value = call.getData().opt("value");
|
|
118
215
|
String storage = call.getString("storage", "preferences");
|
|
119
|
-
|
|
216
|
+
|
|
120
217
|
try {
|
|
218
|
+
boolean ok;
|
|
121
219
|
switch (storage) {
|
|
122
220
|
case "secure":
|
|
123
221
|
if (encryptedStorage == null) {
|
|
124
222
|
call.reject("Encrypted storage not available");
|
|
125
223
|
return;
|
|
126
224
|
}
|
|
127
|
-
encryptedStorage.set(key, value);
|
|
225
|
+
ok = encryptedStorage.set(key, call.getData().opt("value"));
|
|
128
226
|
break;
|
|
129
|
-
case "sqlite":
|
|
130
|
-
|
|
227
|
+
case "sqlite": {
|
|
228
|
+
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
229
|
+
if (store == null) {
|
|
131
230
|
call.reject("SQLite storage not available");
|
|
132
231
|
return;
|
|
133
232
|
}
|
|
134
|
-
|
|
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);
|
|
135
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
|
+
}
|
|
136
254
|
case "preferences":
|
|
137
255
|
default:
|
|
138
256
|
if (sharedPrefsStorage == null) {
|
|
139
257
|
call.reject("Preferences storage not available");
|
|
140
258
|
return;
|
|
141
259
|
}
|
|
142
|
-
sharedPrefsStorage.set(key, value);
|
|
260
|
+
ok = sharedPrefsStorage.set(key, call.getData().opt("value"));
|
|
143
261
|
break;
|
|
144
262
|
}
|
|
145
263
|
|
|
264
|
+
if (!ok) {
|
|
265
|
+
call.reject("Failed to persist value to " + storage + " storage");
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
146
268
|
call.resolve();
|
|
147
269
|
} catch (Exception e) {
|
|
148
270
|
call.reject("Failed to set value", e);
|
|
@@ -161,7 +283,7 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
161
283
|
}
|
|
162
284
|
|
|
163
285
|
String storage = call.getString("storage", "preferences");
|
|
164
|
-
|
|
286
|
+
|
|
165
287
|
try {
|
|
166
288
|
switch (storage) {
|
|
167
289
|
case "secure":
|
|
@@ -171,12 +293,21 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
171
293
|
}
|
|
172
294
|
encryptedStorage.remove(key);
|
|
173
295
|
break;
|
|
174
|
-
case "sqlite":
|
|
175
|
-
|
|
296
|
+
case "sqlite": {
|
|
297
|
+
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
298
|
+
if (store == null) {
|
|
176
299
|
call.reject("SQLite storage not available");
|
|
177
300
|
return;
|
|
178
301
|
}
|
|
179
|
-
|
|
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);
|
|
180
311
|
break;
|
|
181
312
|
case "preferences":
|
|
182
313
|
default:
|
|
@@ -195,13 +326,17 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
195
326
|
}
|
|
196
327
|
|
|
197
328
|
/**
|
|
198
|
-
* Clear storage
|
|
329
|
+
* Clear storage.
|
|
330
|
+
* Accepts the JS `pattern` (used as a key prefix) and a legacy `prefix`.
|
|
199
331
|
*/
|
|
200
332
|
@PluginMethod
|
|
201
333
|
public void clear(PluginCall call) {
|
|
202
334
|
String storage = call.getString("storage", "preferences");
|
|
203
|
-
String prefix = call.getString("
|
|
204
|
-
|
|
335
|
+
String prefix = call.getString("pattern");
|
|
336
|
+
if (prefix == null) {
|
|
337
|
+
prefix = call.getString("prefix");
|
|
338
|
+
}
|
|
339
|
+
|
|
205
340
|
try {
|
|
206
341
|
switch (storage) {
|
|
207
342
|
case "secure":
|
|
@@ -211,12 +346,21 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
211
346
|
}
|
|
212
347
|
encryptedStorage.clear(prefix);
|
|
213
348
|
break;
|
|
214
|
-
case "sqlite":
|
|
215
|
-
|
|
349
|
+
case "sqlite": {
|
|
350
|
+
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
351
|
+
if (store == null) {
|
|
216
352
|
call.reject("SQLite storage not available");
|
|
217
353
|
return;
|
|
218
354
|
}
|
|
219
|
-
|
|
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);
|
|
220
364
|
break;
|
|
221
365
|
case "preferences":
|
|
222
366
|
default:
|
|
@@ -241,9 +385,9 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
241
385
|
public void keys(PluginCall call) {
|
|
242
386
|
String storage = call.getString("storage", "preferences");
|
|
243
387
|
String pattern = call.getString("pattern");
|
|
244
|
-
|
|
388
|
+
|
|
245
389
|
try {
|
|
246
|
-
List<String> keys
|
|
390
|
+
List<String> keys;
|
|
247
391
|
|
|
248
392
|
switch (storage) {
|
|
249
393
|
case "secure":
|
|
@@ -253,12 +397,21 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
253
397
|
}
|
|
254
398
|
keys = encryptedStorage.keys(pattern);
|
|
255
399
|
break;
|
|
256
|
-
case "sqlite":
|
|
257
|
-
|
|
400
|
+
case "sqlite": {
|
|
401
|
+
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
402
|
+
if (store == null) {
|
|
258
403
|
call.reject("SQLite storage not available");
|
|
259
404
|
return;
|
|
260
405
|
}
|
|
261
|
-
keys =
|
|
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);
|
|
262
415
|
break;
|
|
263
416
|
case "preferences":
|
|
264
417
|
default:
|
|
@@ -279,17 +432,21 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
279
432
|
}
|
|
280
433
|
|
|
281
434
|
/**
|
|
282
|
-
* Get storage size information
|
|
435
|
+
* Get storage size information.
|
|
436
|
+
*
|
|
437
|
+
* When `detailed` is true the result also carries a byte breakdown
|
|
438
|
+
* { detailed: { keys, values, metadata } }.
|
|
283
439
|
*/
|
|
284
440
|
@PluginMethod
|
|
285
441
|
public void size(PluginCall call) {
|
|
286
442
|
String storage = call.getString("storage", "preferences");
|
|
287
|
-
|
|
443
|
+
boolean detailed = Boolean.TRUE.equals(call.getBoolean("detailed", false));
|
|
444
|
+
|
|
288
445
|
try {
|
|
289
446
|
JSObject result = new JSObject();
|
|
290
447
|
|
|
291
448
|
switch (storage) {
|
|
292
|
-
case "secure":
|
|
449
|
+
case "secure": {
|
|
293
450
|
if (encryptedStorage == null) {
|
|
294
451
|
call.reject("Encrypted storage not available");
|
|
295
452
|
return;
|
|
@@ -298,17 +455,29 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
298
455
|
result.put("total", encryptedSizeInfo.total);
|
|
299
456
|
result.put("count", encryptedSizeInfo.count);
|
|
300
457
|
break;
|
|
301
|
-
|
|
302
|
-
|
|
458
|
+
}
|
|
459
|
+
case "sqlite": {
|
|
460
|
+
SQLiteStorage store = getSqliteStore(call.getString("database", DEFAULT_DATABASE));
|
|
461
|
+
if (store == null) {
|
|
303
462
|
call.reject("SQLite storage not available");
|
|
304
463
|
return;
|
|
305
464
|
}
|
|
306
|
-
SQLiteStorage.SizeInfo sqliteSizeInfo =
|
|
307
|
-
|
|
308
|
-
result
|
|
465
|
+
SQLiteStorage.SizeInfo sqliteSizeInfo =
|
|
466
|
+
store.size(call.getString("table", DEFAULT_TABLE), detailed);
|
|
467
|
+
putSizeInfo(result, sqliteSizeInfo);
|
|
309
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
|
+
}
|
|
310
479
|
case "preferences":
|
|
311
|
-
default:
|
|
480
|
+
default: {
|
|
312
481
|
if (sharedPrefsStorage == null) {
|
|
313
482
|
call.reject("Preferences storage not available");
|
|
314
483
|
return;
|
|
@@ -317,6 +486,7 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
317
486
|
result.put("total", prefsSizeInfo.total);
|
|
318
487
|
result.put("count", prefsSizeInfo.count);
|
|
319
488
|
break;
|
|
489
|
+
}
|
|
320
490
|
}
|
|
321
491
|
|
|
322
492
|
call.resolve(result);
|
|
@@ -324,5 +494,123 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
324
494
|
call.reject("Failed to get size", e);
|
|
325
495
|
}
|
|
326
496
|
}
|
|
327
|
-
|
|
328
|
-
|
|
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
|
+
}
|
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;
|
|
1
|
+
{"version":3,"file":"capacitor.d.ts","sourceRoot":"","sources":["../src/capacitor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAQ5C,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"}
|
package/dist/capacitor.js
CHANGED
|
@@ -2,6 +2,7 @@ import { PreferencesAdapter } from "./adapters/capacitor/PreferencesAdapter.js";
|
|
|
2
2
|
import { SqliteAdapter } from "./adapters/capacitor/SqliteAdapter.js";
|
|
3
3
|
import { SecureAdapter } from "./adapters/capacitor/SecureAdapter.js";
|
|
4
4
|
import { FilesystemAdapter } from "./adapters/capacitor/FilesystemAdapter.js";
|
|
5
|
+
import { logger } from "./utils/logger.js";
|
|
5
6
|
// Export Capacitor adapters
|
|
6
7
|
export { PreferencesAdapter } from "./adapters/capacitor/PreferencesAdapter.js";
|
|
7
8
|
export { SqliteAdapter } from "./adapters/capacitor/SqliteAdapter.js";
|
|
@@ -19,7 +20,7 @@ export async function registerCapacitorAdapters(storage) {
|
|
|
19
20
|
window.Capacitor &&
|
|
20
21
|
window.Capacitor?.isNativePlatform?.();
|
|
21
22
|
if (!hasCapacitor) {
|
|
22
|
-
|
|
23
|
+
logger.warn('Capacitor not detected. Capacitor adapters will not be registered.');
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
26
|
// Register Capacitor adapters
|
|
@@ -38,6 +38,14 @@ export declare abstract class BaseAdapter implements StorageAdapter {
|
|
|
38
38
|
* Calculate size of storage value
|
|
39
39
|
*/
|
|
40
40
|
protected calculateSize(value: StorageValue): number;
|
|
41
|
+
/**
|
|
42
|
+
* Determine whether a query targets wrapper metadata instead of the stored value.
|
|
43
|
+
*/
|
|
44
|
+
protected isStorageMetadataQuery(condition: QueryCondition): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Normalize value-targeted queries so callers can use either `name` or `value.name`.
|
|
47
|
+
*/
|
|
48
|
+
protected normalizeValueQueryCondition(condition: unknown): unknown;
|
|
41
49
|
/**
|
|
42
50
|
* Default has implementation using get
|
|
43
51
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseAdapter.d.ts","sourceRoot":"","sources":["../../src/core/BaseAdapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,WAAW,EACX,mBAAmB,EAEnB,YAAY,EACZ,QAAQ,EACR,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACf,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,YAAY,EAA4B,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"BaseAdapter.d.ts","sourceRoot":"","sources":["../../src/core/BaseAdapter.ts"],"names":[],"mappings":"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"}
|