strata-storage 2.4.3 → 2.5.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.
Files changed (108) hide show
  1. package/AI-INTEGRATION-GUIDE.md +115 -261
  2. package/README.md +426 -182
  3. package/android/AGENTS.md +34 -0
  4. package/android/CLAUDE.md +51 -0
  5. package/android/src/main/java/com/strata/storage/SQLiteStorage.java +35 -0
  6. package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +191 -27
  7. package/dist/README.md +426 -182
  8. package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +1 -1
  9. package/dist/adapters/capacitor/FilesystemAdapter.js +2 -1
  10. package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +1 -1
  11. package/dist/adapters/capacitor/PreferencesAdapter.js +2 -1
  12. package/dist/adapters/capacitor/SecureAdapter.d.ts.map +1 -1
  13. package/dist/adapters/capacitor/SecureAdapter.js +2 -1
  14. package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +1 -1
  15. package/dist/adapters/capacitor/SqliteAdapter.js +2 -1
  16. package/dist/adapters/web/CacheAdapter.d.ts.map +1 -1
  17. package/dist/adapters/web/CacheAdapter.js +11 -3
  18. package/dist/adapters/web/CookieAdapter.d.ts +37 -1
  19. package/dist/adapters/web/CookieAdapter.d.ts.map +1 -1
  20. package/dist/adapters/web/CookieAdapter.js +89 -9
  21. package/dist/adapters/web/IndexedDBAdapter.d.ts.map +1 -1
  22. package/dist/adapters/web/IndexedDBAdapter.js +10 -2
  23. package/dist/adapters/web/LocalStorageAdapter.d.ts +31 -0
  24. package/dist/adapters/web/LocalStorageAdapter.d.ts.map +1 -1
  25. package/dist/adapters/web/LocalStorageAdapter.js +92 -19
  26. package/dist/adapters/web/MemoryAdapter.d.ts +24 -0
  27. package/dist/adapters/web/MemoryAdapter.d.ts.map +1 -1
  28. package/dist/adapters/web/MemoryAdapter.js +69 -18
  29. package/dist/adapters/web/SessionStorageAdapter.d.ts +24 -0
  30. package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
  31. package/dist/adapters/web/SessionStorageAdapter.js +71 -9
  32. package/dist/adapters/web/URLAdapter.d.ts +59 -0
  33. package/dist/adapters/web/URLAdapter.d.ts.map +1 -0
  34. package/dist/adapters/web/URLAdapter.js +234 -0
  35. package/dist/adapters/web/index.d.ts +1 -0
  36. package/dist/adapters/web/index.d.ts.map +1 -1
  37. package/dist/adapters/web/index.js +1 -0
  38. package/dist/android/AGENTS.md +34 -0
  39. package/dist/android/CLAUDE.md +51 -0
  40. package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +35 -0
  41. package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +191 -27
  42. package/dist/capacitor.d.ts.map +1 -1
  43. package/dist/capacitor.js +2 -1
  44. package/dist/core/BaseAdapter.d.ts +8 -0
  45. package/dist/core/BaseAdapter.d.ts.map +1 -1
  46. package/dist/core/BaseAdapter.js +34 -14
  47. package/dist/core/Strata.d.ts +56 -2
  48. package/dist/core/Strata.d.ts.map +1 -1
  49. package/dist/core/Strata.js +501 -53
  50. package/dist/features/encryption.d.ts.map +1 -1
  51. package/dist/features/encryption.js +3 -2
  52. package/dist/features/integrity.d.ts +16 -0
  53. package/dist/features/integrity.d.ts.map +1 -0
  54. package/dist/features/integrity.js +28 -0
  55. package/dist/features/observer.d.ts.map +1 -1
  56. package/dist/features/observer.js +2 -1
  57. package/dist/features/query.d.ts +7 -1
  58. package/dist/features/query.d.ts.map +1 -1
  59. package/dist/features/query.js +9 -2
  60. package/dist/features/sync.d.ts.map +1 -1
  61. package/dist/features/sync.js +4 -3
  62. package/dist/index.d.ts +35 -2
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +55 -30
  65. package/dist/integrations/angular/index.d.ts +158 -0
  66. package/dist/integrations/angular/index.d.ts.map +1 -0
  67. package/dist/integrations/angular/index.js +395 -0
  68. package/dist/integrations/index.d.ts +15 -0
  69. package/dist/integrations/index.d.ts.map +1 -0
  70. package/dist/integrations/index.js +18 -0
  71. package/dist/integrations/react/index.d.ts +75 -0
  72. package/dist/integrations/react/index.d.ts.map +1 -0
  73. package/dist/integrations/react/index.js +191 -0
  74. package/dist/integrations/vue/index.d.ts +103 -0
  75. package/dist/integrations/vue/index.d.ts.map +1 -0
  76. package/dist/integrations/vue/index.js +274 -0
  77. package/dist/ios/AGENTS.md +33 -0
  78. package/dist/ios/CLAUDE.md +49 -0
  79. package/dist/ios/Plugin/KeychainStorage.swift +139 -50
  80. package/dist/ios/Plugin/SQLiteStorage.swift +40 -0
  81. package/dist/ios/Plugin/StrataStoragePlugin.m +23 -0
  82. package/dist/ios/Plugin/StrataStoragePlugin.swift +201 -52
  83. package/dist/package.json +21 -5
  84. package/dist/plugin/index.d.ts.map +1 -1
  85. package/dist/plugin/index.js +2 -1
  86. package/dist/types/index.d.ts +58 -9
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/dist/types/index.js +0 -13
  89. package/dist/utils/errors.d.ts +7 -0
  90. package/dist/utils/errors.d.ts.map +1 -1
  91. package/dist/utils/errors.js +15 -3
  92. package/dist/utils/index.d.ts +63 -5
  93. package/dist/utils/index.d.ts.map +1 -1
  94. package/dist/utils/index.js +109 -16
  95. package/dist/utils/logger.d.ts +31 -0
  96. package/dist/utils/logger.d.ts.map +1 -0
  97. package/dist/utils/logger.js +63 -0
  98. package/ios/AGENTS.md +33 -0
  99. package/ios/CLAUDE.md +49 -0
  100. package/ios/Plugin/KeychainStorage.swift +139 -50
  101. package/ios/Plugin/SQLiteStorage.swift +40 -0
  102. package/ios/Plugin/StrataStoragePlugin.m +23 -0
  103. package/ios/Plugin/StrataStoragePlugin.swift +201 -52
  104. package/package.json +31 -20
  105. package/scripts/build.js +16 -5
  106. package/scripts/configure.js +2 -6
  107. package/scripts/postinstall.js +2 -2
  108. package/Readme.md +0 -271
@@ -0,0 +1,34 @@
1
+ # AGENTS.md — android/
2
+
3
+ Last Updated: 2026-04-03
4
+
5
+ > Agent instructions for Android native development.
6
+
7
+ ## Files
8
+
9
+ | File | Purpose |
10
+ |------|---------|
11
+ | `StrataStoragePlugin.java` | Capacitor plugin entry (com.stratastorage) |
12
+ | `SharedPreferencesStorage.java` | General key-value storage (com.strata.storage) |
13
+ | `EncryptedStorage.java` | Secure storage (com.strata.storage) |
14
+ | `SQLiteStorage.java` | Database storage (com.strata.storage) |
15
+
16
+ ## Agent Rules
17
+
18
+ ### Security (IRON-SOLID)
19
+ - Sensitive data MUST use `EncryptedStorage`
20
+ - NEVER store secrets in `SharedPreferencesStorage`
21
+
22
+ ### SQL Safety (IRON-SOLID)
23
+ - ALWAYS use parameterized queries
24
+ - NEVER concatenate user input into SQL strings
25
+
26
+ ### Plugin Architecture
27
+ - Methods exposed through `StrataStoragePlugin.java`
28
+ - Each storage backend is a separate Java class
29
+ - Two package paths: `com.stratastorage` (plugin) and `com.strata.storage` (impl)
30
+
31
+ ### Before Modifying
32
+ - Understand Capacitor plugin protocol for Android
33
+ - Test on Android emulator after changes
34
+ - Verify Gradle build succeeds
@@ -0,0 +1,51 @@
1
+ # CLAUDE.md — android/
2
+
3
+ Last Updated: 2026-04-03
4
+
5
+ ## Android Native Plugin
6
+
7
+ Java implementation of native storage backends for Capacitor.
8
+
9
+ ### Files
10
+
11
+ | File | Path | Purpose |
12
+ |------|------|---------|
13
+ | `StrataStoragePlugin.java` | `src/main/java/com/stratastorage/` | Main Capacitor plugin entry |
14
+ | `SharedPreferencesStorage.java` | `src/main/java/com/strata/storage/` | SharedPreferences general storage |
15
+ | `EncryptedStorage.java` | `src/main/java/com/strata/storage/` | EncryptedSharedPreferences secure storage |
16
+ | `SQLiteStorage.java` | `src/main/java/com/strata/storage/` | SQLite database storage |
17
+
18
+ ### Configuration
19
+
20
+ - Build: `build.gradle`
21
+ - Proguard: `proguard-rules.pro`
22
+ - Manifest: `src/main/AndroidManifest.xml`
23
+
24
+ **Note**: There are two Java package paths — `com.stratastorage` (plugin) and `com.strata.storage` (implementations).
25
+
26
+ ## Rules
27
+
28
+ ### Security (IRON-SOLID)
29
+ - Sensitive data MUST use `EncryptedStorage` (EncryptedSharedPreferences)
30
+ - NEVER store credentials, tokens, or secrets in `SharedPreferencesStorage`
31
+ - Follow Android Keystore best practices
32
+
33
+ ### SQL Safety (IRON-SOLID)
34
+ - ALWAYS use parameterized queries in `SQLiteStorage`
35
+ - NEVER concatenate user input into SQL strings
36
+ - Use `SQLiteDatabase.query()` or prepared statements
37
+
38
+ ### Plugin Architecture
39
+ - All native methods exposed through `StrataStoragePlugin.java`
40
+ - Plugin bridges Capacitor JS calls to Java implementations
41
+ - Each storage backend is a separate Java class
42
+
43
+ ### Build
44
+ - Gradle-based build system
45
+ - Proguard rules configured for release builds
46
+ - Test on Android emulator after changes
47
+
48
+ ### Before Modifying
49
+ - Understand the Capacitor plugin protocol for Android
50
+ - Test on Android emulator after changes
51
+ - Verify Gradle build succeeds
@@ -227,6 +227,41 @@ public class SQLiteStorage extends SQLiteOpenHelper {
227
227
  db.close();
228
228
  }
229
229
  }
230
+
231
+ /**
232
+ * Returns every row as a map of { key, value } where value is the decoded
233
+ * stored payload (UTF-8 string of the BLOB). The JS SqliteAdapter applies
234
+ * the real query condition by re-fetching/filtering each key, so this only
235
+ * needs to enumerate candidate rows.
236
+ */
237
+ public List<Map<String, Object>> query() {
238
+ List<Map<String, Object>> rows = new ArrayList<>();
239
+ SQLiteDatabase db = this.getReadableDatabase();
240
+ Cursor cursor = null;
241
+ try {
242
+ cursor = db.query(TABLE_NAME, new String[]{KEY_ID, KEY_VALUE},
243
+ null, null, null, null, null);
244
+ if (cursor != null && cursor.moveToFirst()) {
245
+ do {
246
+ Map<String, Object> row = new HashMap<>();
247
+ row.put("key", cursor.getString(0));
248
+ byte[] valueBytes = cursor.getBlob(1);
249
+ if (valueBytes != null) {
250
+ row.put("value", new String(valueBytes, StandardCharsets.UTF_8));
251
+ } else {
252
+ row.put("value", null);
253
+ }
254
+ rows.add(row);
255
+ } while (cursor.moveToNext());
256
+ }
257
+ return rows;
258
+ } finally {
259
+ if (cursor != null) {
260
+ cursor.close();
261
+ }
262
+ db.close();
263
+ }
264
+ }
230
265
 
231
266
  public SizeInfo size() {
232
267
  SQLiteDatabase db = this.getReadableDatabase();
@@ -1,6 +1,7 @@
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;
@@ -12,10 +13,15 @@ import android.util.Log;
12
13
  import org.json.JSONArray;
13
14
  import org.json.JSONException;
14
15
  import java.util.List;
16
+ import java.util.Map;
15
17
 
16
18
  /**
17
19
  * Main Capacitor plugin for Strata Storage
18
- * Coordinates between different storage types on Android
20
+ * Coordinates between different storage types on Android.
21
+ *
22
+ * Storage types with a real native backend: preferences, secure, sqlite.
23
+ * `filesystem` is NOT implemented natively and is rejected explicitly rather
24
+ * than silently falling through to SharedPreferences.
19
25
  */
20
26
  @CapacitorPlugin(name = "StrataStorage")
21
27
  public class StrataStoragePlugin extends Plugin {
@@ -27,30 +33,58 @@ public class StrataStoragePlugin extends Plugin {
27
33
  public void load() {
28
34
  try {
29
35
  sharedPrefsStorage = new SharedPreferencesStorage(getContext());
36
+ } catch (Exception e) {
37
+ Log.e("StrataStorage", "Failed to initialize preferences storage", e);
38
+ }
39
+ try {
30
40
  encryptedStorage = new EncryptedStorage(getContext());
41
+ } catch (Exception e) {
42
+ // Secure storage may be unavailable on some devices/keystores —
43
+ // keep the rest of the plugin functional.
44
+ Log.e("StrataStorage", "Failed to initialize encrypted storage", e);
45
+ }
46
+ try {
31
47
  sqliteStorage = new SQLiteStorage(getContext());
32
48
  } catch (Exception e) {
33
- // Log error but don't crash - some storage types may not be available
34
- Log.e("StrataStorage", "Failed to initialize storage", e);
49
+ Log.e("StrataStorage", "Failed to initialize SQLite storage", e);
35
50
  }
36
51
  }
37
52
 
53
+ private void rejectUnsupportedFilesystem(PluginCall call) {
54
+ call.reject(
55
+ "Filesystem storage is not implemented in the native Android plugin. " +
56
+ "Use the 'preferences', 'secure', or 'sqlite' storage types, or a " +
57
+ "web/Capacitor Filesystem-backed adapter."
58
+ );
59
+ }
60
+
38
61
  /**
39
- * Check if storage is available
62
+ * Check if a specific storage type is available.
63
+ * Matches the JS contract: resolves { available: boolean }.
40
64
  */
41
65
  @PluginMethod
42
66
  public void isAvailable(PluginCall call) {
67
+ String storage = call.getString("storage", "preferences");
68
+ boolean available;
69
+ switch (storage) {
70
+ case "secure":
71
+ available = encryptedStorage != null;
72
+ break;
73
+ case "sqlite":
74
+ available = sqliteStorage != null;
75
+ break;
76
+ case "filesystem":
77
+ // No native filesystem backend.
78
+ available = false;
79
+ break;
80
+ case "preferences":
81
+ default:
82
+ available = sharedPrefsStorage != null;
83
+ break;
84
+ }
85
+
43
86
  JSObject result = new JSObject();
44
- result.put("available", true);
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
-
87
+ result.put("available", available);
54
88
  call.resolve(result);
55
89
  }
56
90
 
@@ -66,7 +100,7 @@ public class StrataStoragePlugin extends Plugin {
66
100
  }
67
101
 
68
102
  String storage = call.getString("storage", "preferences");
69
-
103
+
70
104
  try {
71
105
  Object value = null;
72
106
 
@@ -85,6 +119,9 @@ public class StrataStoragePlugin extends Plugin {
85
119
  }
86
120
  value = sqliteStorage.get(key);
87
121
  break;
122
+ case "filesystem":
123
+ rejectUnsupportedFilesystem(call);
124
+ return;
88
125
  case "preferences":
89
126
  default:
90
127
  if (sharedPrefsStorage == null) {
@@ -116,33 +153,41 @@ public class StrataStoragePlugin extends Plugin {
116
153
 
117
154
  Object value = call.getData().opt("value");
118
155
  String storage = call.getString("storage", "preferences");
119
-
156
+
120
157
  try {
158
+ boolean ok;
121
159
  switch (storage) {
122
160
  case "secure":
123
161
  if (encryptedStorage == null) {
124
162
  call.reject("Encrypted storage not available");
125
163
  return;
126
164
  }
127
- encryptedStorage.set(key, value);
165
+ ok = encryptedStorage.set(key, value);
128
166
  break;
129
167
  case "sqlite":
130
168
  if (sqliteStorage == null) {
131
169
  call.reject("SQLite storage not available");
132
170
  return;
133
171
  }
134
- sqliteStorage.set(key, value);
172
+ ok = sqliteStorage.set(key, value);
135
173
  break;
174
+ case "filesystem":
175
+ rejectUnsupportedFilesystem(call);
176
+ return;
136
177
  case "preferences":
137
178
  default:
138
179
  if (sharedPrefsStorage == null) {
139
180
  call.reject("Preferences storage not available");
140
181
  return;
141
182
  }
142
- sharedPrefsStorage.set(key, value);
183
+ ok = sharedPrefsStorage.set(key, value);
143
184
  break;
144
185
  }
145
186
 
187
+ if (!ok) {
188
+ call.reject("Failed to persist value to " + storage + " storage");
189
+ return;
190
+ }
146
191
  call.resolve();
147
192
  } catch (Exception e) {
148
193
  call.reject("Failed to set value", e);
@@ -161,7 +206,7 @@ public class StrataStoragePlugin extends Plugin {
161
206
  }
162
207
 
163
208
  String storage = call.getString("storage", "preferences");
164
-
209
+
165
210
  try {
166
211
  switch (storage) {
167
212
  case "secure":
@@ -178,6 +223,9 @@ public class StrataStoragePlugin extends Plugin {
178
223
  }
179
224
  sqliteStorage.remove(key);
180
225
  break;
226
+ case "filesystem":
227
+ rejectUnsupportedFilesystem(call);
228
+ return;
181
229
  case "preferences":
182
230
  default:
183
231
  if (sharedPrefsStorage == null) {
@@ -195,13 +243,17 @@ public class StrataStoragePlugin extends Plugin {
195
243
  }
196
244
 
197
245
  /**
198
- * Clear storage
246
+ * Clear storage.
247
+ * Accepts the JS `pattern` (used as a key prefix) and a legacy `prefix`.
199
248
  */
200
249
  @PluginMethod
201
250
  public void clear(PluginCall call) {
202
251
  String storage = call.getString("storage", "preferences");
203
- String prefix = call.getString("prefix");
204
-
252
+ String prefix = call.getString("pattern");
253
+ if (prefix == null) {
254
+ prefix = call.getString("prefix");
255
+ }
256
+
205
257
  try {
206
258
  switch (storage) {
207
259
  case "secure":
@@ -218,6 +270,9 @@ public class StrataStoragePlugin extends Plugin {
218
270
  }
219
271
  sqliteStorage.clear(prefix);
220
272
  break;
273
+ case "filesystem":
274
+ rejectUnsupportedFilesystem(call);
275
+ return;
221
276
  case "preferences":
222
277
  default:
223
278
  if (sharedPrefsStorage == null) {
@@ -241,7 +296,7 @@ public class StrataStoragePlugin extends Plugin {
241
296
  public void keys(PluginCall call) {
242
297
  String storage = call.getString("storage", "preferences");
243
298
  String pattern = call.getString("pattern");
244
-
299
+
245
300
  try {
246
301
  List<String> keys = null;
247
302
 
@@ -260,6 +315,9 @@ public class StrataStoragePlugin extends Plugin {
260
315
  }
261
316
  keys = sqliteStorage.keys(pattern);
262
317
  break;
318
+ case "filesystem":
319
+ rejectUnsupportedFilesystem(call);
320
+ return;
263
321
  case "preferences":
264
322
  default:
265
323
  if (sharedPrefsStorage == null) {
@@ -284,7 +342,7 @@ public class StrataStoragePlugin extends Plugin {
284
342
  @PluginMethod
285
343
  public void size(PluginCall call) {
286
344
  String storage = call.getString("storage", "preferences");
287
-
345
+
288
346
  try {
289
347
  JSObject result = new JSObject();
290
348
 
@@ -307,6 +365,9 @@ public class StrataStoragePlugin extends Plugin {
307
365
  result.put("total", sqliteSizeInfo.total);
308
366
  result.put("count", sqliteSizeInfo.count);
309
367
  break;
368
+ case "filesystem":
369
+ rejectUnsupportedFilesystem(call);
370
+ return;
310
371
  case "preferences":
311
372
  default:
312
373
  if (sharedPrefsStorage == null) {
@@ -324,5 +385,108 @@ public class StrataStoragePlugin extends Plugin {
324
385
  call.reject("Failed to get size", e);
325
386
  }
326
387
  }
327
-
328
- }
388
+
389
+ /**
390
+ * Query SQLite-backed storage.
391
+ * Matches the optional `query` method in the JS contract:
392
+ * resolves { results: [{ key, value }] }. The JS SqliteAdapter applies the
393
+ * real condition by re-fetching/filtering, so this enumerates candidate
394
+ * rows.
395
+ */
396
+ @PluginMethod
397
+ public void query(PluginCall call) {
398
+ String storage = call.getString("storage", "sqlite");
399
+ if (!"sqlite".equals(storage)) {
400
+ call.reject("Query is only supported for the 'sqlite' storage type");
401
+ return;
402
+ }
403
+ if (sqliteStorage == null) {
404
+ call.reject("SQLite storage not available");
405
+ return;
406
+ }
407
+
408
+ try {
409
+ List<Map<String, Object>> rows = sqliteStorage.query();
410
+ JSArray results = new JSArray();
411
+ for (Map<String, Object> row : rows) {
412
+ JSObject obj = new JSObject();
413
+ obj.put("key", row.get("key"));
414
+ obj.put("value", row.get("value"));
415
+ results.put(obj);
416
+ }
417
+ JSObject result = new JSObject();
418
+ result.put("results", results);
419
+ call.resolve(result);
420
+ } catch (Exception e) {
421
+ call.reject("Failed to query SQLite", e);
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Android-specific: read an encrypted preference.
427
+ * Resolves { value: unknown }. Honors an optional `fileName`.
428
+ */
429
+ @PluginMethod
430
+ public void getEncryptedPreference(PluginCall call) {
431
+ String key = call.getString("key");
432
+ if (key == null) {
433
+ call.reject("Key is required");
434
+ return;
435
+ }
436
+ String fileName = call.getString("fileName");
437
+
438
+ try {
439
+ EncryptedStorage store = resolveEncryptedStore(fileName);
440
+ if (store == null) {
441
+ call.reject("Encrypted storage not available");
442
+ return;
443
+ }
444
+ JSObject result = new JSObject();
445
+ result.put("value", store.get(key));
446
+ call.resolve(result);
447
+ } catch (Exception e) {
448
+ call.reject("Failed to read encrypted preference", e);
449
+ }
450
+ }
451
+
452
+ /**
453
+ * Android-specific: write an encrypted preference. Honors an optional
454
+ * `fileName`.
455
+ */
456
+ @PluginMethod
457
+ public void setEncryptedPreference(PluginCall call) {
458
+ String key = call.getString("key");
459
+ if (key == null) {
460
+ call.reject("Key is required");
461
+ return;
462
+ }
463
+ Object value = call.getData().opt("value");
464
+ String fileName = call.getString("fileName");
465
+
466
+ try {
467
+ EncryptedStorage store = resolveEncryptedStore(fileName);
468
+ if (store == null) {
469
+ call.reject("Encrypted storage not available");
470
+ return;
471
+ }
472
+ if (!store.set(key, value)) {
473
+ call.reject("Failed to persist encrypted preference");
474
+ return;
475
+ }
476
+ call.resolve();
477
+ } catch (Exception e) {
478
+ call.reject("Failed to write encrypted preference", e);
479
+ }
480
+ }
481
+
482
+ /**
483
+ * Returns the default encrypted store, or builds a file-specific one when a
484
+ * custom file name is supplied.
485
+ */
486
+ private EncryptedStorage resolveEncryptedStore(String fileName) throws Exception {
487
+ if (fileName == null || fileName.isEmpty()) {
488
+ return encryptedStorage;
489
+ }
490
+ return new EncryptedStorage(getContext(), fileName);
491
+ }
492
+ }