react-native-nitro-storage 0.10.3 → 0.11.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 (87) hide show
  1. package/CHANGELOG.md +85 -14
  2. package/README.md +148 -41
  3. package/SECURITY.md +16 -6
  4. package/android/build.gradle +0 -1
  5. package/android/consumer-rules.pro +0 -3
  6. package/android/src/main/cpp/AndroidStorageAdapterCpp.cpp +48 -33
  7. package/android/src/main/cpp/AndroidStorageAdapterCpp.hpp +3 -3
  8. package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +73 -23
  9. package/android/src/main/java/com/nitrostorage/DiskSqliteStore.kt +22 -4
  10. package/app.plugin.js +51 -51
  11. package/cpp/bindings/HybridStorage.cpp +25 -6
  12. package/cpp/core/NativeStorageAdapter.hpp +14 -1
  13. package/cpp/core/SqliteDiskStore.cpp +94 -17
  14. package/cpp/core/SqliteDiskStore.hpp +10 -0
  15. package/docs/api-reference.md +73 -28
  16. package/docs/benchmarks.md +41 -12
  17. package/docs/mmkv-migration.md +3 -1
  18. package/docs/native-libraries.md +10 -4
  19. package/docs/secure-storage.md +26 -12
  20. package/docs/web-backends.md +6 -2
  21. package/indexeddb-backend/package.json +6 -0
  22. package/ios/IOSStorageAdapterCpp.hpp +4 -0
  23. package/ios/IOSStorageAdapterCpp.mm +149 -57
  24. package/lib/commonjs/capabilities.js +3 -8
  25. package/lib/commonjs/capabilities.js.map +1 -1
  26. package/lib/commonjs/index.js +23 -8
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/index.web.js +61 -19
  29. package/lib/commonjs/index.web.js.map +1 -1
  30. package/lib/commonjs/indexeddb-backend.js +21 -37
  31. package/lib/commonjs/indexeddb-backend.js.map +1 -1
  32. package/lib/commonjs/internal.js +6 -0
  33. package/lib/commonjs/internal.js.map +1 -1
  34. package/lib/commonjs/storage-core.js +61 -22
  35. package/lib/commonjs/storage-core.js.map +1 -1
  36. package/lib/commonjs/storage-runtime.js +1 -1
  37. package/lib/commonjs/storage-runtime.js.map +1 -1
  38. package/lib/commonjs/testing.js +68 -23
  39. package/lib/commonjs/testing.js.map +1 -1
  40. package/lib/commonjs/web-backend-contract.js +6 -2
  41. package/lib/commonjs/web-backend-contract.js.map +1 -1
  42. package/lib/module/capabilities.js +3 -8
  43. package/lib/module/capabilities.js.map +1 -1
  44. package/lib/module/index.js +14 -5
  45. package/lib/module/index.js.map +1 -1
  46. package/lib/module/index.web.js +61 -12
  47. package/lib/module/index.web.js.map +1 -1
  48. package/lib/module/indexeddb-backend.js +21 -37
  49. package/lib/module/indexeddb-backend.js.map +1 -1
  50. package/lib/module/internal.js +5 -0
  51. package/lib/module/internal.js.map +1 -1
  52. package/lib/module/storage-core.js +62 -23
  53. package/lib/module/storage-core.js.map +1 -1
  54. package/lib/module/storage-runtime.js +1 -1
  55. package/lib/module/storage-runtime.js.map +1 -1
  56. package/lib/module/testing.js +59 -16
  57. package/lib/module/testing.js.map +1 -1
  58. package/lib/module/web-backend-contract.js +5 -2
  59. package/lib/module/web-backend-contract.js.map +1 -1
  60. package/lib/typescript/capabilities.d.ts.map +1 -1
  61. package/lib/typescript/index.d.ts +8 -1
  62. package/lib/typescript/index.d.ts.map +1 -1
  63. package/lib/typescript/index.web.d.ts +7 -1
  64. package/lib/typescript/index.web.d.ts.map +1 -1
  65. package/lib/typescript/indexeddb-backend.d.ts.map +1 -1
  66. package/lib/typescript/internal.d.ts +1 -0
  67. package/lib/typescript/internal.d.ts.map +1 -1
  68. package/lib/typescript/storage-core.d.ts +1 -1
  69. package/lib/typescript/storage-core.d.ts.map +1 -1
  70. package/lib/typescript/storage-runtime.d.ts +1 -1
  71. package/lib/typescript/storage-runtime.d.ts.map +1 -1
  72. package/lib/typescript/testing.d.ts +15 -2
  73. package/lib/typescript/testing.d.ts.map +1 -1
  74. package/lib/typescript/web-backend-contract.d.ts +1 -0
  75. package/lib/typescript/web-backend-contract.d.ts.map +1 -1
  76. package/package.json +14 -5
  77. package/react-native-nitro-storage.podspec +4 -2
  78. package/src/capabilities.ts +4 -9
  79. package/src/index.ts +19 -5
  80. package/src/index.web.ts +86 -19
  81. package/src/indexeddb-backend.ts +20 -42
  82. package/src/internal.ts +8 -0
  83. package/src/storage-core.ts +84 -33
  84. package/src/storage-runtime.ts +3 -1
  85. package/src/testing.ts +91 -18
  86. package/src/web-backend-contract.ts +6 -2
  87. package/testing/package.json +8 -0
@@ -9,6 +9,7 @@ var _metrics = require("./core/metrics");
9
9
  var _internal = require("./internal");
10
10
  var _shared = require("./shared");
11
11
  var _storageEvents = require("./storage-events");
12
+ var _storageRuntime = require("./storage-runtime");
12
13
  var _Storage = require("./Storage.types");
13
14
  const EMPTY_KEYS = Object.freeze([]);
14
15
  function asInternal(item) {
@@ -39,6 +40,14 @@ function createStorageCore(buildAdapter) {
39
40
  let eventObserverRedactSecureValues = true;
40
41
  const storageEvents = new _storageEvents.StorageEventRegistry();
41
42
  const metrics = (0, _metrics.createMetricsRegistry)();
43
+ function setOwnDataProperty(target, key, value) {
44
+ Object.defineProperty(target, key, {
45
+ configurable: true,
46
+ enumerable: true,
47
+ value,
48
+ writable: true
49
+ });
50
+ }
42
51
  const durability = (0, _durability.createDurabilityCoordinator)({
43
52
  backend: {
44
53
  setBatch: (keys, values, scope) => {
@@ -147,6 +156,19 @@ function createStorageCore(buildAdapter) {
147
156
  }
148
157
  return scope !== _Storage.StorageScope.Secure || !eventObserverRedactSecureValues;
149
158
  }
159
+ function readPreviousEventValue(scope, key, representation = "plain") {
160
+ if (!shouldReadPreviousEventValues(scope)) {
161
+ return undefined;
162
+ }
163
+ return getEventRawValueForRepresentation(scope, key, representation);
164
+ }
165
+ function toMemoryStoredValue(value) {
166
+ return typeof value === "string" ? (0, _internal.escapeCollidingRawValue)(value) : value;
167
+ }
168
+ function deleteMemoryKey(key) {
169
+ memoryStore.delete(key);
170
+ memoryExpirationDeadlines.delete(key);
171
+ }
150
172
  function eventForGlobalObserver(event) {
151
173
  if (!eventObserverRedactSecureValues || event.scope !== _Storage.StorageScope.Secure) {
152
174
  return event;
@@ -261,6 +283,7 @@ function createStorageCore(buildAdapter) {
261
283
  }
262
284
  function setRawValue(key, value, scope) {
263
285
  (0, _internal.assertValidScope)(scope);
286
+ (0, _internal.assertValidStorageKey)(key);
264
287
  const storedValue = (0, _internal.escapeCollidingRawValue)(value);
265
288
  const oldValue = scope === _Storage.StorageScope.Memory ? getEventRawValue(scope, key) : undefined;
266
289
  if (scope === _Storage.StorageScope.Memory) {
@@ -293,9 +316,10 @@ function createStorageCore(buildAdapter) {
293
316
  }
294
317
  function removeRawValue(key, scope) {
295
318
  (0, _internal.assertValidScope)(scope);
296
- const oldValue = getEventRawValue(scope, key);
319
+ (0, _internal.assertValidStorageKey)(key);
320
+ const oldValue = readPreviousEventValue(scope, key);
297
321
  if (scope === _Storage.StorageScope.Memory) {
298
- memoryStore.delete(key);
322
+ deleteMemoryKey(key);
299
323
  (0, _shared.notifyKeyListeners)(memoryListeners, key);
300
324
  emitKeyChange(scope, key, oldValue, undefined, "remove", "memory");
301
325
  return;
@@ -367,7 +391,7 @@ function createStorageCore(buildAdapter) {
367
391
  return;
368
392
  }
369
393
  const previousValues = shouldReadPreviousEventValues(scope) ? removeKeys.map(key => getEventRawValue(scope, key)) : [];
370
- removeKeys.forEach(key => memoryStore.delete(key));
394
+ removeKeys.forEach(deleteMemoryKey);
371
395
  removeKeys.forEach(key => {
372
396
  (0, _shared.notifyKeyListeners)(memoryListeners, key);
373
397
  });
@@ -643,7 +667,11 @@ function createStorageCore(buildAdapter) {
643
667
  return measureOperation("storage:getKeysByPrefix", scope, () => {
644
668
  (0, _internal.assertValidScope)(scope);
645
669
  if (scope === _Storage.StorageScope.Memory) {
646
- return Array.from(memoryStore.keys()).filter(key => key.startsWith(prefix));
670
+ const keys = [];
671
+ for (const key of memoryStore.keys()) {
672
+ if (key.startsWith(prefix)) keys.push(key);
673
+ }
674
+ return keys;
647
675
  }
648
676
  if (scope === _Storage.StorageScope.Disk) {
649
677
  flushDiskWrites();
@@ -665,7 +693,7 @@ function createStorageCore(buildAdapter) {
665
693
  keys.forEach(key => {
666
694
  const value = memoryStore.get(key);
667
695
  if (typeof value === "string") {
668
- result[key] = value;
696
+ setOwnDataProperty(result, key, (0, _internal.unescapeCollidingRawValue)(value));
669
697
  }
670
698
  });
671
699
  return result;
@@ -680,7 +708,7 @@ function createStorageCore(buildAdapter) {
680
708
  keys.forEach((key, idx) => {
681
709
  const value = values[idx];
682
710
  if (value !== undefined) {
683
- result[key] = (0, _internal.unescapeCollidingRawValue)(value);
711
+ setOwnDataProperty(result, key, (0, _internal.unescapeCollidingRawValue)(value));
684
712
  }
685
713
  });
686
714
  return result;
@@ -691,10 +719,11 @@ function createStorageCore(buildAdapter) {
691
719
  (0, _internal.assertValidScope)(scope);
692
720
  const result = {};
693
721
  if (scope === _Storage.StorageScope.Memory) {
694
- for (const key of memoryStore.keys()) {
695
- const value = memoryStore.get(key);
696
- if (typeof value === "string") result[key] = (0, _internal.unescapeCollidingRawValue)(value);
697
- }
722
+ memoryStore.forEach((value, key) => {
723
+ if (typeof value === "string") {
724
+ setOwnDataProperty(result, key, (0, _internal.unescapeCollidingRawValue)(value));
725
+ }
726
+ });
698
727
  return result;
699
728
  }
700
729
  if (scope === _Storage.StorageScope.Disk) {
@@ -708,7 +737,9 @@ function createStorageCore(buildAdapter) {
708
737
  const values = adapter.backend.getBatch(keys, scope);
709
738
  keys.forEach((key, idx) => {
710
739
  const val = values[idx];
711
- if (val !== undefined) result[key] = (0, _internal.unescapeCollidingRawValue)(val);
740
+ if (val !== undefined) {
741
+ setOwnDataProperty(result, key, (0, _internal.unescapeCollidingRawValue)(val));
742
+ }
712
743
  });
713
744
  return result;
714
745
  });
@@ -819,10 +850,12 @@ function createStorageCore(buildAdapter) {
819
850
  const keys = Object.keys(data);
820
851
  measureOperation("storage:import", scope, () => {
821
852
  (0, _internal.assertValidScope)(scope);
853
+ keys.forEach(_internal.assertValidStorageKey);
822
854
  if (keys.length === 0) return;
823
855
  const values = keys.map(k => data[k]);
824
856
  const storedValues = values.map(_internal.escapeCollidingRawValue);
825
- const changes = keys.map((key, index) => (0, _shared.createKeyChange)(scope, key, getEventRawValue(scope, key), values[index], "import", scope === _Storage.StorageScope.Memory ? "memory" : adapter.changeSource));
857
+ const readPrevious = scope === _Storage.StorageScope.Memory || shouldReadPreviousEventValues(scope);
858
+ const changes = keys.map((key, index) => (0, _shared.createKeyChange)(scope, key, readPrevious ? getEventRawValue(scope, key) : undefined, values[index], "import", scope === _Storage.StorageScope.Memory ? "memory" : adapter.changeSource));
826
859
  if (scope === _Storage.StorageScope.Memory) {
827
860
  keys.forEach((key, index) => {
828
861
  memoryStore.set(key, storedValues[index]);
@@ -852,6 +885,7 @@ function createStorageCore(buildAdapter) {
852
885
  }
853
886
  };
854
887
  function createStorageItem(config) {
888
+ (0, _internal.assertValidStorageKey)(config.key);
855
889
  const storageKey = (0, _internal.prefixKey)(config.namespace, config.key);
856
890
  const serialize = config.serialize ?? _shared.defaultSerialize;
857
891
  const deserialize = config.deserialize ?? _shared.defaultDeserialize;
@@ -972,13 +1006,15 @@ function createStorageCore(buildAdapter) {
972
1006
  }
973
1007
  if (isBiometric) {
974
1008
  const raw = readBackendRaw(() => adapter.backend.getSecureBiometric(storageKey));
975
- if (readCache) {
1009
+ if (readCache || fallbackToCacheOnReadError) {
976
1010
  cacheRawValue(resolveNonMemoryScope(), storageKey, raw, rawCacheRepresentation);
977
1011
  }
978
1012
  return raw;
979
1013
  }
980
1014
  const raw = readBackendRaw(() => adapter.backend.get(storageKey, config.scope));
981
- cacheRawValue(resolveNonMemoryScope(), storageKey, raw);
1015
+ if (readCache || fallbackToCacheOnReadError) {
1016
+ cacheRawValue(resolveNonMemoryScope(), storageKey, raw);
1017
+ }
982
1018
  return raw;
983
1019
  };
984
1020
  const readBackendRaw = read => {
@@ -986,7 +1022,7 @@ function createStorageCore(buildAdapter) {
986
1022
  return read();
987
1023
  } catch (error) {
988
1024
  onReadError?.(error);
989
- if (fallbackToCacheOnReadError) {
1025
+ if (fallbackToCacheOnReadError && (0, _storageRuntime.isStorageError)(error, "keychain_locked")) {
990
1026
  const scope = resolveNonMemoryScope();
991
1027
  const cached = readCachedRawValue(scope, storageKey, rawCacheRepresentation);
992
1028
  if (cached !== undefined) {
@@ -1482,7 +1518,7 @@ function createStorageCore(buildAdapter) {
1482
1518
  }
1483
1519
  };
1484
1520
  const removeStoredRaw = (operation = "remove") => {
1485
- const oldValue = isBiometric ? getEventRawValueForRepresentation(config.scope, storageKey, "biometric") : getEventRawValue(config.scope, storageKey);
1521
+ const oldValue = readPreviousEventValue(config.scope, storageKey, isBiometric ? "biometric" : "plain");
1486
1522
  if (isBiometric) {
1487
1523
  invalidateRawCache(_Storage.StorageScope.Secure, storageKey);
1488
1524
  scheduleRenameSourceCleanup();
@@ -1524,8 +1560,7 @@ function createStorageCore(buildAdapter) {
1524
1560
  } else {
1525
1561
  memoryExpirationDeadlines.delete(storageKey);
1526
1562
  }
1527
- const storedValue = typeof value === "string" ? (0, _internal.escapeCollidingRawValue)(value) : value;
1528
- memoryStore.set(storageKey, storedValue);
1563
+ memoryStore.set(storageKey, toMemoryStoredValue(value));
1529
1564
  (0, _shared.notifyKeyListeners)(memoryListeners, storageKey);
1530
1565
  emitKeyChange(config.scope, storageKey, oldValue, typeof value === "string" ? value : undefined, "set", "memory");
1531
1566
  return;
@@ -1918,7 +1953,7 @@ function createStorageCore(buildAdapter) {
1918
1953
  item,
1919
1954
  value
1920
1955
  }) => {
1921
- memoryStore.set(item.key, value);
1956
+ memoryStore.set(item.key, toMemoryStoredValue(value));
1922
1957
  asInternal(item)._invalidateParsedCacheOnly();
1923
1958
  });
1924
1959
  items.forEach(({
@@ -2211,7 +2246,11 @@ function createStorageCore(buildAdapter) {
2211
2246
  const rollbackEntries = Array.from(rollback.values()).reverse();
2212
2247
  const rollbackSource = scope === _Storage.StorageScope.Memory ? "memory" : adapter.changeSource;
2213
2248
  const rollbackErrors = [];
2249
+ const readRollbackEvents = shouldReadPreviousEventValues(scope);
2214
2250
  const readRollbackEventValue = entry => {
2251
+ if (!readRollbackEvents) {
2252
+ return undefined;
2253
+ }
2215
2254
  try {
2216
2255
  return getEventRawValueForRepresentation(scope, entry.key, entry.representation);
2217
2256
  } catch (readError) {
@@ -2455,7 +2494,7 @@ function createStorageCore(buildAdapter) {
2455
2494
  const initial = {};
2456
2495
  if (defaultValue) {
2457
2496
  for (const id of defaultValue) {
2458
- initial[id] = true;
2497
+ setOwnDataProperty(initial, id, true);
2459
2498
  }
2460
2499
  }
2461
2500
  const item = createStorageItem({
@@ -2471,7 +2510,7 @@ function createStorageCore(buildAdapter) {
2471
2510
  const next = {
2472
2511
  ...current
2473
2512
  };
2474
- next[id] = true;
2513
+ setOwnDataProperty(next, id, true);
2475
2514
  item.set(next);
2476
2515
  };
2477
2516
  const deleteId = id => {
@@ -2496,7 +2535,7 @@ function createStorageCore(buildAdapter) {
2496
2535
  const getTyped = () => {
2497
2536
  const typed = {};
2498
2537
  for (const id of Object.keys(item.get())) {
2499
- typed[id] = true;
2538
+ setOwnDataProperty(typed, id, true);
2500
2539
  }
2501
2540
  return typed;
2502
2541
  };