strata-storage 2.4.0 → 2.4.1

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 (29) hide show
  1. package/android/src/main/java/com/strata/storage/EncryptedStorage.java +27 -18
  2. package/android/src/main/java/com/strata/storage/SQLiteStorage.java +85 -58
  3. package/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +9 -2
  4. package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +83 -10
  5. package/dist/adapters/web/MemoryAdapter.d.ts.map +1 -1
  6. package/dist/adapters/web/MemoryAdapter.js +7 -1
  7. package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
  8. package/dist/adapters/web/SessionStorageAdapter.js +3 -2
  9. package/dist/android/src/main/java/com/strata/storage/EncryptedStorage.java +27 -18
  10. package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +85 -58
  11. package/dist/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +9 -2
  12. package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +83 -10
  13. package/dist/core/Strata.d.ts.map +1 -1
  14. package/dist/core/Strata.js +4 -6
  15. package/dist/firebase.d.ts.map +1 -1
  16. package/dist/firebase.js +75 -13
  17. package/dist/ios/Plugin/SQLiteStorage.swift +100 -30
  18. package/dist/ios/Plugin/UserDefaultsStorage.swift +13 -2
  19. package/dist/package.json +5 -5
  20. package/dist/plugin/index.d.ts.map +1 -1
  21. package/dist/plugin/index.js +31 -6
  22. package/dist/plugin/web.d.ts +5 -1
  23. package/dist/plugin/web.d.ts.map +1 -1
  24. package/dist/plugin/web.js +55 -32
  25. package/dist/utils/index.d.ts.map +1 -1
  26. package/dist/utils/index.js +7 -2
  27. package/ios/Plugin/SQLiteStorage.swift +100 -30
  28. package/ios/Plugin/UserDefaultsStorage.swift +13 -2
  29. package/package.json +17 -19
@@ -5,6 +5,7 @@ import android.database.Cursor;
5
5
  import android.database.sqlite.SQLiteDatabase;
6
6
  import android.database.sqlite.SQLiteOpenHelper;
7
7
  import android.content.ContentValues;
8
+ import android.util.Log;
8
9
  import java.util.ArrayList;
9
10
  import java.util.List;
10
11
  import java.util.HashMap;
@@ -78,7 +79,7 @@ public class SQLiteStorage extends SQLiteOpenHelper {
78
79
  valueBytes = json.getBytes(StandardCharsets.UTF_8);
79
80
  }
80
81
  } catch (Exception e) {
81
- e.printStackTrace();
82
+ Log.e("StrataStorage", "Failed to set value in SQLite", e);
82
83
  return false;
83
84
  }
84
85
  SQLiteDatabase db = this.getWritableDatabase();
@@ -112,36 +113,41 @@ public class SQLiteStorage extends SQLiteOpenHelper {
112
113
 
113
114
  public Map<String, Object> get(String key) {
114
115
  SQLiteDatabase db = this.getReadableDatabase();
115
- Cursor cursor = db.query(TABLE_NAME, null, KEY_ID + "=?",
116
- new String[]{key}, null, null, null, null);
117
-
118
- Map<String, Object> result = null;
119
- if (cursor != null && cursor.moveToFirst()) {
120
- result = new HashMap<>();
121
- result.put("key", key);
122
- result.put("value", cursor.getBlob(cursor.getColumnIndex(KEY_VALUE)));
123
- result.put("created", cursor.getLong(cursor.getColumnIndex(KEY_CREATED)));
124
- result.put("updated", cursor.getLong(cursor.getColumnIndex(KEY_UPDATED)));
125
-
126
- int expiresIndex = cursor.getColumnIndex(KEY_EXPIRES);
127
- if (!cursor.isNull(expiresIndex)) {
128
- result.put("expires", cursor.getLong(expiresIndex));
129
- }
130
-
131
- int tagsIndex = cursor.getColumnIndex(KEY_TAGS);
132
- if (!cursor.isNull(tagsIndex)) {
133
- result.put("tags", cursor.getString(tagsIndex));
116
+ Cursor cursor = null;
117
+ try {
118
+ cursor = db.query(TABLE_NAME, null, KEY_ID + "=?",
119
+ new String[]{key}, null, null, null, null);
120
+
121
+ Map<String, Object> result = null;
122
+ if (cursor != null && cursor.moveToFirst()) {
123
+ result = new HashMap<>();
124
+ result.put("key", key);
125
+ result.put("value", cursor.getBlob(cursor.getColumnIndex(KEY_VALUE)));
126
+ result.put("created", cursor.getLong(cursor.getColumnIndex(KEY_CREATED)));
127
+ result.put("updated", cursor.getLong(cursor.getColumnIndex(KEY_UPDATED)));
128
+
129
+ int expiresIndex = cursor.getColumnIndex(KEY_EXPIRES);
130
+ if (!cursor.isNull(expiresIndex)) {
131
+ result.put("expires", cursor.getLong(expiresIndex));
132
+ }
133
+
134
+ int tagsIndex = cursor.getColumnIndex(KEY_TAGS);
135
+ if (!cursor.isNull(tagsIndex)) {
136
+ result.put("tags", cursor.getString(tagsIndex));
137
+ }
138
+
139
+ int metadataIndex = cursor.getColumnIndex(KEY_METADATA);
140
+ if (!cursor.isNull(metadataIndex)) {
141
+ result.put("metadata", cursor.getString(metadataIndex));
142
+ }
134
143
  }
135
-
136
- int metadataIndex = cursor.getColumnIndex(KEY_METADATA);
137
- if (!cursor.isNull(metadataIndex)) {
138
- result.put("metadata", cursor.getString(metadataIndex));
144
+ return result;
145
+ } finally {
146
+ if (cursor != null) {
147
+ cursor.close();
139
148
  }
140
-
141
- cursor.close();
149
+ db.close();
142
150
  }
143
- db.close();
144
- return result;
145
151
  }
146
152
 
147
153
  public boolean remove(String key) {
@@ -179,52 +185,73 @@ public class SQLiteStorage extends SQLiteOpenHelper {
179
185
  List<String> keys = new ArrayList<>();
180
186
  String selectQuery;
181
187
  String[] selectionArgs = null;
182
-
188
+
183
189
  if (pattern != null) {
184
190
  selectQuery = "SELECT " + KEY_ID + " FROM " + TABLE_NAME + " WHERE " + KEY_ID + " LIKE ?";
185
- selectionArgs = new String[]{"% " + pattern + "%"};
191
+ selectionArgs = new String[]{"%" + pattern + "%"};
186
192
  } else {
187
193
  selectQuery = "SELECT " + KEY_ID + " FROM " + TABLE_NAME;
188
194
  }
189
-
195
+
190
196
  SQLiteDatabase db = this.getReadableDatabase();
191
- Cursor cursor = db.rawQuery(selectQuery, selectionArgs);
192
-
193
- if (cursor.moveToFirst()) {
194
- do {
195
- keys.add(cursor.getString(0));
196
- } while (cursor.moveToNext());
197
+ Cursor cursor = null;
198
+ try {
199
+ cursor = db.rawQuery(selectQuery, selectionArgs);
200
+
201
+ if (cursor != null && cursor.moveToFirst()) {
202
+ do {
203
+ keys.add(cursor.getString(0));
204
+ } while (cursor.moveToNext());
205
+ }
206
+ return keys;
207
+ } finally {
208
+ if (cursor != null) {
209
+ cursor.close();
210
+ }
211
+ db.close();
197
212
  }
198
- cursor.close();
199
- db.close();
200
- return keys;
201
213
  }
202
214
 
203
215
  public boolean has(String key) {
204
216
  SQLiteDatabase db = this.getReadableDatabase();
205
- Cursor cursor = db.query(TABLE_NAME, new String[]{KEY_ID}, KEY_ID + "=?",
206
- new String[]{key}, null, null, null, null);
207
- boolean exists = cursor.getCount() > 0;
208
- cursor.close();
209
- db.close();
210
- return exists;
217
+ Cursor cursor = null;
218
+ try {
219
+ cursor = db.query(TABLE_NAME, new String[]{KEY_ID}, KEY_ID + "=?",
220
+ new String[]{key}, null, null, null, null);
221
+ boolean exists = cursor != null && cursor.getCount() > 0;
222
+ return exists;
223
+ } finally {
224
+ if (cursor != null) {
225
+ cursor.close();
226
+ }
227
+ db.close();
228
+ }
211
229
  }
212
230
 
213
231
  public SizeInfo size() {
214
232
  SQLiteDatabase db = this.getReadableDatabase();
215
- Cursor cursor = db.rawQuery("SELECT COUNT(*), SUM(LENGTH(" + KEY_VALUE + ")) FROM " + TABLE_NAME, null);
216
-
217
- long totalSize = 0;
218
- int count = 0;
219
-
220
- if (cursor != null && cursor.moveToFirst()) {
221
- count = cursor.getInt(0);
222
- totalSize = cursor.getLong(1);
223
- cursor.close();
233
+ Cursor cursor = null;
234
+ try {
235
+ cursor = db.rawQuery("SELECT COUNT(*), SUM(LENGTH(" + KEY_VALUE + ")) FROM " + TABLE_NAME, null);
236
+
237
+ long totalSize = 0;
238
+ int count = 0;
239
+
240
+ if (cursor != null && cursor.moveToFirst()) {
241
+ count = cursor.getInt(0);
242
+ // Check for NULL values from SQL SUM function
243
+ if (!cursor.isNull(1)) {
244
+ totalSize = cursor.getLong(1);
245
+ }
246
+ }
247
+
248
+ return new SizeInfo(totalSize, count);
249
+ } finally {
250
+ if (cursor != null) {
251
+ cursor.close();
252
+ }
253
+ db.close();
224
254
  }
225
-
226
- db.close();
227
- return new SizeInfo(totalSize, count);
228
255
  }
229
256
 
230
257
  /**
@@ -2,6 +2,7 @@ package com.strata.storage;
2
2
 
3
3
  import android.content.Context;
4
4
  import android.content.SharedPreferences;
5
+ import android.util.Log;
5
6
  import java.util.Map;
6
7
  import java.util.Set;
7
8
  import java.util.HashSet;
@@ -37,7 +38,13 @@ public class SharedPreferencesStorage {
37
38
  } else if (value instanceof Boolean) {
38
39
  editor.putBoolean(key, (Boolean) value);
39
40
  } else if (value instanceof Set) {
40
- editor.putStringSet(key, (Set<String>) value);
41
+ // Safely convert to Set<String>
42
+ Set<?> rawSet = (Set<?>) value;
43
+ Set<String> stringSet = new HashSet<>();
44
+ for (Object item : rawSet) {
45
+ stringSet.add(item != null ? item.toString() : "null");
46
+ }
47
+ editor.putStringSet(key, stringSet);
41
48
  } else {
42
49
  // Convert complex objects to JSON
43
50
  String json;
@@ -56,7 +63,7 @@ public class SharedPreferencesStorage {
56
63
  }
57
64
  return editor.commit();
58
65
  } catch (Exception e) {
59
- e.printStackTrace();
66
+ Log.e("StrataStorage", "Failed to set value in SharedPreferences", e);
60
67
  return false;
61
68
  }
62
69
  }
@@ -8,6 +8,7 @@ import com.getcapacitor.annotation.CapacitorPlugin;
8
8
  import com.strata.storage.SharedPreferencesStorage;
9
9
  import com.strata.storage.EncryptedStorage;
10
10
  import com.strata.storage.SQLiteStorage;
11
+ import android.util.Log;
11
12
  import org.json.JSONArray;
12
13
  import org.json.JSONException;
13
14
  import java.util.List;
@@ -30,7 +31,7 @@ public class StrataStoragePlugin extends Plugin {
30
31
  sqliteStorage = new SQLiteStorage(getContext());
31
32
  } catch (Exception e) {
32
33
  // Log error but don't crash - some storage types may not be available
33
- e.printStackTrace();
34
+ Log.e("StrataStorage", "Failed to initialize storage", e);
34
35
  }
35
36
  }
36
37
 
@@ -68,20 +69,32 @@ public class StrataStoragePlugin extends Plugin {
68
69
 
69
70
  try {
70
71
  Object value = null;
71
-
72
+
72
73
  switch (storage) {
73
74
  case "secure":
75
+ if (encryptedStorage == null) {
76
+ call.reject("Encrypted storage not available");
77
+ return;
78
+ }
74
79
  value = encryptedStorage.get(key);
75
80
  break;
76
81
  case "sqlite":
82
+ if (sqliteStorage == null) {
83
+ call.reject("SQLite storage not available");
84
+ return;
85
+ }
77
86
  value = sqliteStorage.get(key);
78
87
  break;
79
88
  case "preferences":
80
89
  default:
90
+ if (sharedPrefsStorage == null) {
91
+ call.reject("Preferences storage not available");
92
+ return;
93
+ }
81
94
  value = sharedPrefsStorage.get(key);
82
95
  break;
83
96
  }
84
-
97
+
85
98
  JSObject result = new JSObject();
86
99
  result.put("value", value);
87
100
  call.resolve(result);
@@ -107,17 +120,29 @@ public class StrataStoragePlugin extends Plugin {
107
120
  try {
108
121
  switch (storage) {
109
122
  case "secure":
123
+ if (encryptedStorage == null) {
124
+ call.reject("Encrypted storage not available");
125
+ return;
126
+ }
110
127
  encryptedStorage.set(key, value);
111
128
  break;
112
129
  case "sqlite":
130
+ if (sqliteStorage == null) {
131
+ call.reject("SQLite storage not available");
132
+ return;
133
+ }
113
134
  sqliteStorage.set(key, value);
114
135
  break;
115
136
  case "preferences":
116
137
  default:
138
+ if (sharedPrefsStorage == null) {
139
+ call.reject("Preferences storage not available");
140
+ return;
141
+ }
117
142
  sharedPrefsStorage.set(key, value);
118
143
  break;
119
144
  }
120
-
145
+
121
146
  call.resolve();
122
147
  } catch (Exception e) {
123
148
  call.reject("Failed to set value", e);
@@ -140,17 +165,29 @@ public class StrataStoragePlugin extends Plugin {
140
165
  try {
141
166
  switch (storage) {
142
167
  case "secure":
168
+ if (encryptedStorage == null) {
169
+ call.reject("Encrypted storage not available");
170
+ return;
171
+ }
143
172
  encryptedStorage.remove(key);
144
173
  break;
145
174
  case "sqlite":
175
+ if (sqliteStorage == null) {
176
+ call.reject("SQLite storage not available");
177
+ return;
178
+ }
146
179
  sqliteStorage.remove(key);
147
180
  break;
148
181
  case "preferences":
149
182
  default:
183
+ if (sharedPrefsStorage == null) {
184
+ call.reject("Preferences storage not available");
185
+ return;
186
+ }
150
187
  sharedPrefsStorage.remove(key);
151
188
  break;
152
189
  }
153
-
190
+
154
191
  call.resolve();
155
192
  } catch (Exception e) {
156
193
  call.reject("Failed to remove value", e);
@@ -168,17 +205,29 @@ public class StrataStoragePlugin extends Plugin {
168
205
  try {
169
206
  switch (storage) {
170
207
  case "secure":
208
+ if (encryptedStorage == null) {
209
+ call.reject("Encrypted storage not available");
210
+ return;
211
+ }
171
212
  encryptedStorage.clear(prefix);
172
213
  break;
173
214
  case "sqlite":
215
+ if (sqliteStorage == null) {
216
+ call.reject("SQLite storage not available");
217
+ return;
218
+ }
174
219
  sqliteStorage.clear(prefix);
175
220
  break;
176
221
  case "preferences":
177
222
  default:
223
+ if (sharedPrefsStorage == null) {
224
+ call.reject("Preferences storage not available");
225
+ return;
226
+ }
178
227
  sharedPrefsStorage.clear(prefix);
179
228
  break;
180
229
  }
181
-
230
+
182
231
  call.resolve();
183
232
  } catch (Exception e) {
184
233
  call.reject("Failed to clear storage", e);
@@ -195,20 +244,32 @@ public class StrataStoragePlugin extends Plugin {
195
244
 
196
245
  try {
197
246
  List<String> keys = null;
198
-
247
+
199
248
  switch (storage) {
200
249
  case "secure":
250
+ if (encryptedStorage == null) {
251
+ call.reject("Encrypted storage not available");
252
+ return;
253
+ }
201
254
  keys = encryptedStorage.keys(pattern);
202
255
  break;
203
256
  case "sqlite":
257
+ if (sqliteStorage == null) {
258
+ call.reject("SQLite storage not available");
259
+ return;
260
+ }
204
261
  keys = sqliteStorage.keys(pattern);
205
262
  break;
206
263
  case "preferences":
207
264
  default:
265
+ if (sharedPrefsStorage == null) {
266
+ call.reject("Preferences storage not available");
267
+ return;
268
+ }
208
269
  keys = sharedPrefsStorage.keys(pattern);
209
270
  break;
210
271
  }
211
-
272
+
212
273
  JSObject result = new JSObject();
213
274
  result.put("keys", new JSONArray(keys));
214
275
  call.resolve(result);
@@ -226,26 +287,38 @@ public class StrataStoragePlugin extends Plugin {
226
287
 
227
288
  try {
228
289
  JSObject result = new JSObject();
229
-
290
+
230
291
  switch (storage) {
231
292
  case "secure":
293
+ if (encryptedStorage == null) {
294
+ call.reject("Encrypted storage not available");
295
+ return;
296
+ }
232
297
  EncryptedStorage.SizeInfo encryptedSizeInfo = encryptedStorage.size();
233
298
  result.put("total", encryptedSizeInfo.total);
234
299
  result.put("count", encryptedSizeInfo.count);
235
300
  break;
236
301
  case "sqlite":
302
+ if (sqliteStorage == null) {
303
+ call.reject("SQLite storage not available");
304
+ return;
305
+ }
237
306
  SQLiteStorage.SizeInfo sqliteSizeInfo = sqliteStorage.size();
238
307
  result.put("total", sqliteSizeInfo.total);
239
308
  result.put("count", sqliteSizeInfo.count);
240
309
  break;
241
310
  case "preferences":
242
311
  default:
312
+ if (sharedPrefsStorage == null) {
313
+ call.reject("Preferences storage not available");
314
+ return;
315
+ }
243
316
  SharedPreferencesStorage.SizeInfo prefsSizeInfo = sharedPrefsStorage.size();
244
317
  result.put("total", prefsSizeInfo.total);
245
318
  result.put("count", prefsSizeInfo.count);
246
319
  break;
247
320
  }
248
-
321
+
249
322
  call.resolve(result);
250
323
  } catch (Exception e) {
251
324
  call.reject("Failed to get size", e);
@@ -1 +1 @@
1
- {"version":3,"file":"Strata.d.ts","sourceRoot":"","sources":["../../src/core/Strata.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Strata.d.ts","sourceRoot":"","sources":["../../src/core/Strata.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  * Zero-dependency universal storage solution
4
4
  */
5
5
  import { AdapterRegistry } from "./AdapterRegistry.js";
6
- import { isBrowser, isNode } from "../utils/index.js";
6
+ import { isBrowser, isNode, deepMerge } from "../utils/index.js";
7
7
  import { StorageError, EncryptionError } from "../utils/errors.js";
8
8
  import { EncryptionManager } from "../features/encryption.js";
9
9
  import { CompressionManager } from "../features/compression.js";
@@ -474,11 +474,9 @@ export class Strata {
474
474
  else if (options?.merge) {
475
475
  const existing = await this.get(key);
476
476
  if (options.merge === 'deep' && typeof existing === 'object' && typeof value === 'object') {
477
- // Deep merge will be implemented with utils
478
- await this.set(key, {
479
- ...existing,
480
- ...value,
481
- });
477
+ // Use deep merge utility for proper nested object merging
478
+ const merged = deepMerge(existing, value);
479
+ await this.set(key, merged);
482
480
  }
483
481
  else {
484
482
  await this.set(key, value);
@@ -1 +1 @@
1
- {"version":3,"file":"firebase.d.ts","sourceRoot":"","sources":["../src/firebase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAG5C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CA8Jf;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAQ5D"}
1
+ {"version":3,"file":"firebase.d.ts","sourceRoot":"","sources":["../src/firebase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CAyOf;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAQ5D"}
package/dist/firebase.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { StorageError } from "./utils/errors.js";
1
2
  /**
2
3
  * Enable Firebase sync for Strata Storage
3
4
  * This dynamically imports Firebase SDK only when needed
@@ -19,8 +20,9 @@ export async function enableFirebaseSync(storage, config) {
19
20
  });
20
21
  }
21
22
  if (config.firestore) {
23
+ const { getFirestore, doc, setDoc, getDoc, deleteDoc, collection, getDocs, onSnapshot } =
22
24
  // @ts-expect-error - Firebase is an optional peer dependency
23
- const { getFirestore, doc, setDoc, getDoc, deleteDoc } = await import('firebase/firestore');
25
+ await import('firebase/firestore');
24
26
  const db = getFirestore();
25
27
  const collectionName = config.collectionName || 'strata-storage';
26
28
  // Create custom adapter for Firestore
@@ -56,12 +58,31 @@ export async function enableFirebaseSync(storage, config) {
56
58
  return docSnap.exists();
57
59
  },
58
60
  async clear() {
59
- // Firestore doesn't have a direct clear method
60
- console.warn('Clear operation not supported for Firestore adapter');
61
+ try {
62
+ const collectionRef = collection(db, collectionName);
63
+ const snapshot = await getDocs(collectionRef);
64
+ const deletePromises = snapshot.docs.map((docSnapshot) => deleteDoc(doc(db, collectionName, docSnapshot.id)));
65
+ await Promise.all(deletePromises);
66
+ }
67
+ catch (error) {
68
+ throw new StorageError('Failed to clear Firestore collection', {
69
+ collectionName,
70
+ originalError: error,
71
+ });
72
+ }
61
73
  },
62
74
  async keys() {
63
- // Would need to implement with queries
64
- return [];
75
+ try {
76
+ const collectionRef = collection(db, collectionName);
77
+ const snapshot = await getDocs(collectionRef);
78
+ return snapshot.docs.map((docSnapshot) => docSnapshot.id);
79
+ }
80
+ catch (error) {
81
+ throw new StorageError('Failed to retrieve keys from Firestore', {
82
+ collectionName,
83
+ originalError: error,
84
+ });
85
+ }
65
86
  },
66
87
  async size() {
67
88
  return { total: 0, count: 0 };
@@ -72,9 +93,24 @@ export async function enableFirebaseSync(storage, config) {
72
93
  async isAvailable() {
73
94
  return true;
74
95
  },
75
- subscribe() {
76
- // Not implemented for Firebase adapter
77
- return () => { };
96
+ subscribe(callback) {
97
+ const collectionRef = collection(db, collectionName);
98
+ const unsubscribe = onSnapshot(collectionRef, (snapshot) => {
99
+ snapshot
100
+ .docChanges()
101
+ .forEach((change) => {
102
+ const docData = change.doc.data();
103
+ callback({
104
+ key: change.doc.id,
105
+ oldValue: change.type === 'removed' ? docData.value : undefined,
106
+ newValue: change.type !== 'removed' ? docData.value : undefined,
107
+ source: 'remote',
108
+ storage: 'firestore',
109
+ timestamp: Date.now(),
110
+ });
111
+ });
112
+ });
113
+ return unsubscribe;
78
114
  },
79
115
  async close() {
80
116
  // No cleanup needed
@@ -86,7 +122,7 @@ export async function enableFirebaseSync(storage, config) {
86
122
  }
87
123
  if (config.realtimeDatabase) {
88
124
  // @ts-expect-error - Firebase is an optional peer dependency
89
- const { getDatabase, ref, set, get, remove } = await import('firebase/database');
125
+ const { getDatabase, ref, set, get, remove, onValue } = await import('firebase/database');
90
126
  const db = getDatabase();
91
127
  // Create custom adapter for Realtime Database
92
128
  const realtimeAdapter = {
@@ -134,9 +170,32 @@ export async function enableFirebaseSync(storage, config) {
134
170
  async isAvailable() {
135
171
  return true;
136
172
  },
137
- subscribe() {
138
- // Not implemented for Firebase adapter
139
- return () => { };
173
+ subscribe(callback) {
174
+ const dbRef = ref(db, 'strata-storage');
175
+ let previousData = {};
176
+ const unsubscribe = onValue(dbRef, (snapshot) => {
177
+ const snapshotTyped = snapshot;
178
+ const currentData = snapshotTyped.exists()
179
+ ? snapshotTyped.val()
180
+ : {};
181
+ const allKeys = new Set([...Object.keys(previousData), ...Object.keys(currentData)]);
182
+ allKeys.forEach((key) => {
183
+ const oldValue = previousData[key];
184
+ const newValue = currentData[key];
185
+ if (oldValue !== newValue) {
186
+ callback({
187
+ key,
188
+ oldValue,
189
+ newValue,
190
+ source: 'remote',
191
+ storage: 'realtime',
192
+ timestamp: Date.now(),
193
+ });
194
+ }
195
+ });
196
+ previousData = { ...currentData };
197
+ });
198
+ return unsubscribe;
140
199
  },
141
200
  async close() {
142
201
  // No cleanup needed
@@ -149,7 +208,10 @@ export async function enableFirebaseSync(storage, config) {
149
208
  // Firebase sync enabled successfully
150
209
  }
151
210
  catch (error) {
152
- throw new Error(`Failed to enable Firebase sync: ${error instanceof Error ? error.message : 'Unknown error'}`);
211
+ throw new StorageError('Failed to enable Firebase sync', {
212
+ originalError: error,
213
+ config,
214
+ });
153
215
  }
154
216
  }
155
217
  /**