react-native-nitro-storage 0.5.9 → 0.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +171 -7
  3. package/cpp/bindings/HybridStorage.cpp +25 -9
  4. package/cpp/bindings/HybridStorage.hpp +5 -0
  5. package/lib/commonjs/index.js +19 -2
  6. package/lib/commonjs/index.js.map +1 -1
  7. package/lib/commonjs/index.web.js +19 -2
  8. package/lib/commonjs/index.web.js.map +1 -1
  9. package/lib/commonjs/shared.js.map +1 -1
  10. package/lib/commonjs/storage-core.js +306 -10
  11. package/lib/commonjs/storage-core.js.map +1 -1
  12. package/lib/commonjs/storage-events.js.map +1 -1
  13. package/lib/commonjs/storage-hooks.js +16 -1
  14. package/lib/commonjs/storage-hooks.js.map +1 -1
  15. package/lib/commonjs/testing.js +267 -0
  16. package/lib/commonjs/testing.js.map +1 -0
  17. package/lib/module/index.js +5 -1
  18. package/lib/module/index.js.map +1 -1
  19. package/lib/module/index.web.js +5 -1
  20. package/lib/module/index.web.js.map +1 -1
  21. package/lib/module/shared.js.map +1 -1
  22. package/lib/module/storage-core.js +307 -11
  23. package/lib/module/storage-core.js.map +1 -1
  24. package/lib/module/storage-events.js.map +1 -1
  25. package/lib/module/storage-hooks.js +15 -2
  26. package/lib/module/storage-hooks.js.map +1 -1
  27. package/lib/module/testing.js +188 -0
  28. package/lib/module/testing.js.map +1 -0
  29. package/lib/typescript/index.d.ts +22 -4
  30. package/lib/typescript/index.d.ts.map +1 -1
  31. package/lib/typescript/index.web.d.ts +22 -4
  32. package/lib/typescript/index.web.d.ts.map +1 -1
  33. package/lib/typescript/shared.d.ts +1 -0
  34. package/lib/typescript/shared.d.ts.map +1 -1
  35. package/lib/typescript/storage-core.d.ts +51 -2
  36. package/lib/typescript/storage-core.d.ts.map +1 -1
  37. package/lib/typescript/storage-events.d.ts +1 -1
  38. package/lib/typescript/storage-events.d.ts.map +1 -1
  39. package/lib/typescript/storage-hooks.d.ts +18 -1
  40. package/lib/typescript/storage-hooks.d.ts.map +1 -1
  41. package/lib/typescript/testing.d.ts +148 -0
  42. package/lib/typescript/testing.d.ts.map +1 -0
  43. package/package.json +7 -1
  44. package/src/index.ts +16 -2
  45. package/src/index.web.ts +16 -2
  46. package/src/shared.ts +1 -0
  47. package/src/storage-core.ts +446 -11
  48. package/src/storage-events.ts +2 -0
  49. package/src/storage-hooks.ts +42 -3
  50. package/src/testing.ts +270 -0
@@ -1 +1 @@
1
- {"version":3,"names":["_Storage","require","_internal","_storageRuntime","isUpdater","valueOrFn","typedKeys","record","Object","keys","assertEnumInteger","value","min","max","label","Number","isFinite","Error","Math","trunc","assertAccessControlLevel","level","assertBiometricLevel","runMicrotask","exports","queueMicrotask","task","Promise","resolve","then","now","performance","Date","notifyKeyListeners","registry","key","listeners","get","listener","notifyAllListeners","values","createKeyChange","scope","oldValue","newValue","operation","source","type","SECURE_EVENT_REDACTED_VALUE","redactSecureKeyChange","event","StorageScope","Secure","undefined","canUseRawBatchPath","item","_hasExpiration","_hasValidation","_isBiometric","_secureAccessControl","canUseSecureRawBatchPath","defaultSerialize","serializeWithPrimitiveFastPath","defaultDeserialize","deserializeWithPrimitiveFastPath","isKeychainLockedError","err","isLockedStorageErrorCode","getStorageErrorCode"],"sourceRoot":"../../src","sources":["shared.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_Storage","require","_internal","_storageRuntime","isUpdater","valueOrFn","typedKeys","record","Object","keys","assertEnumInteger","value","min","max","label","Number","isFinite","Error","Math","trunc","assertAccessControlLevel","level","assertBiometricLevel","runMicrotask","exports","queueMicrotask","task","Promise","resolve","then","now","performance","Date","notifyKeyListeners","registry","key","listeners","get","listener","notifyAllListeners","values","createKeyChange","scope","oldValue","newValue","operation","source","type","SECURE_EVENT_REDACTED_VALUE","redactSecureKeyChange","event","StorageScope","Secure","undefined","canUseRawBatchPath","item","_hasExpiration","_hasValidation","_isBiometric","_secureAccessControl","canUseSecureRawBatchPath","defaultSerialize","serializeWithPrimitiveFastPath","defaultDeserialize","deserializeWithPrimitiveFastPath","isKeychainLockedError","err","isLockedStorageErrorCode","getStorageErrorCode"],"sourceRoot":"../../src","sources":["shared.ts"],"mappings":"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","ignoreList":[]}
@@ -8,11 +8,14 @@ var _shared = require("./shared");
8
8
  var _Storage = require("./Storage.types");
9
9
  var _internal = require("./internal");
10
10
  var _storageEvents = require("./storage-events");
11
+ const EMPTY_KEYS = Object.freeze([]);
11
12
  function asInternal(item) {
12
13
  return item;
13
14
  }
14
15
  function createStorageCore(buildAdapter) {
15
16
  const registeredMigrations = new Map();
17
+ const itemGroups = new Map();
18
+ const registeredKeyCounts = new Map();
16
19
  const memoryStore = new Map();
17
20
  const memoryListeners = new Map();
18
21
  const scopedListeners = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
@@ -359,6 +362,40 @@ function createStorageCore(buildAdapter) {
359
362
  }
360
363
  };
361
364
  const adapter = buildAdapter(internals);
365
+ function resolveKeyRef(ref) {
366
+ return typeof ref === "string" ? ref : ref.key;
367
+ }
368
+ function clearScopeExcept(scope, exceptRefs) {
369
+ measureOperation("storage:clearExcept", scope, () => {
370
+ (0, _internal.assertValidScope)(scope);
371
+ const keep = new Set(exceptRefs.map(resolveKeyRef));
372
+ if (scope === _Storage.StorageScope.Memory) {
373
+ const removeKeys = Array.from(memoryStore.keys()).filter(key => !keep.has(key));
374
+ if (removeKeys.length === 0) {
375
+ return;
376
+ }
377
+ const previousValues = shouldReadPreviousEventValues(scope) ? removeKeys.map(key => getEventRawValue(scope, key)) : [];
378
+ removeKeys.forEach(key => memoryStore.delete(key));
379
+ removeKeys.forEach(key => (0, _shared.notifyKeyListeners)(memoryListeners, key));
380
+ emitBatchChange(scope, "clear", "memory", removeKeys.map((key, index) => (0, _shared.createKeyChange)(scope, key, previousValues[index], undefined, "clear", "memory")));
381
+ return;
382
+ }
383
+ if (scope === _Storage.StorageScope.Disk) {
384
+ flushDiskWrites();
385
+ }
386
+ if (scope === _Storage.StorageScope.Secure) {
387
+ flushSecureWrites();
388
+ }
389
+ const removeKeys = adapter.backend.getAllKeys(scope).filter(key => !keep.has(key));
390
+ if (removeKeys.length === 0) {
391
+ return;
392
+ }
393
+ const previousValues = shouldReadPreviousEventValues(scope) ? adapter.backend.getBatch(removeKeys, scope) : [];
394
+ adapter.backend.removeBatch(removeKeys, scope);
395
+ removeKeys.forEach(key => cacheRawValue(scope, key, undefined));
396
+ emitBatchChange(scope, "clear", adapter.changeSource, removeKeys.map((key, index) => (0, _shared.createKeyChange)(scope, key, previousValues[index], undefined, "clear", adapter.changeSource)));
397
+ });
398
+ }
362
399
  const storage = {
363
400
  subscribe: (scope, listener) => {
364
401
  (0, _internal.assertValidScope)(scope);
@@ -410,7 +447,11 @@ function createStorageCore(buildAdapter) {
410
447
  adapter.maybeCleanupScopeSubscription(_Storage.StorageScope.Disk);
411
448
  adapter.maybeCleanupScopeSubscription(_Storage.StorageScope.Secure);
412
449
  },
413
- clear: scope => {
450
+ clear: (scope, options) => {
451
+ if (options?.except && options.except.length > 0) {
452
+ clearScopeExcept(scope, options.except);
453
+ return;
454
+ }
414
455
  measureOperation("storage:clear", scope, () => {
415
456
  const previousValues = shouldReadPreviousEventValues(scope) ? storage.getAll(scope) : {};
416
457
  if (scope === _Storage.StorageScope.Memory) {
@@ -439,6 +480,71 @@ function createStorageCore(buildAdapter) {
439
480
  storage.clear(_Storage.StorageScope.Secure);
440
481
  }, 3);
441
482
  },
483
+ clearGroup: group => {
484
+ const items = itemGroups.get(group);
485
+ if (!items || items.size === 0) {
486
+ return;
487
+ }
488
+ measureOperation("storage:clearGroup", _Storage.StorageScope.Memory, () => {
489
+ const byScope = new Map();
490
+ for (const item of items) {
491
+ const scoped = byScope.get(item.scope);
492
+ if (scoped) {
493
+ scoped.push(item);
494
+ } else {
495
+ byScope.set(item.scope, [item]);
496
+ }
497
+ }
498
+ byScope.forEach((groupItems, scope) => {
499
+ removeBatch(groupItems, scope);
500
+ });
501
+ }, items.size);
502
+ },
503
+ getGroupItems: group => {
504
+ const items = itemGroups.get(group);
505
+ return items ? Array.from(items) : [];
506
+ },
507
+ subscribeExpired: (scope, listener) => {
508
+ return storage.subscribe(scope, event => {
509
+ if (event.type === "key") {
510
+ if (event.operation === "expire") {
511
+ listener(event);
512
+ }
513
+ return;
514
+ }
515
+ event.changes.forEach(change => {
516
+ if (change.operation === "expire") {
517
+ listener(change);
518
+ }
519
+ });
520
+ });
521
+ },
522
+ findDuplicateKeys: () => {
523
+ const duplicates = [];
524
+ registeredKeyCounts.forEach((count, registryKey) => {
525
+ if (count <= 1) {
526
+ return;
527
+ }
528
+ const separatorIndex = registryKey.indexOf(":");
529
+ duplicates.push({
530
+ scope: Number(registryKey.slice(0, separatorIndex)),
531
+ key: registryKey.slice(separatorIndex + 1),
532
+ count
533
+ });
534
+ });
535
+ return duplicates;
536
+ },
537
+ getRegisteredKeys: () => {
538
+ const result = [];
539
+ registeredKeyCounts.forEach((_count, registryKey) => {
540
+ const separatorIndex = registryKey.indexOf(":");
541
+ result.push({
542
+ scope: Number(registryKey.slice(0, separatorIndex)),
543
+ key: registryKey.slice(separatorIndex + 1)
544
+ });
545
+ });
546
+ return result;
547
+ },
442
548
  clearNamespace: (namespace, scope) => {
443
549
  measureOperation("storage:clearNamespace", scope, () => {
444
550
  (0, _internal.assertValidScope)(scope);
@@ -738,6 +844,10 @@ function createStorageCore(buildAdapter) {
738
844
  const coalesceSecureWrites = config.scope === _Storage.StorageScope.Secure && config.coalesceSecureWrites === true && !isBiometric;
739
845
  const defaultValue = config.defaultValue;
740
846
  const nonMemoryScope = config.scope === _Storage.StorageScope.Disk ? _Storage.StorageScope.Disk : config.scope === _Storage.StorageScope.Secure ? _Storage.StorageScope.Secure : null;
847
+ const renameFromKeys = config.renameFrom === undefined ? EMPTY_KEYS : typeof config.renameFrom === "string" ? [config.renameFrom] : config.renameFrom;
848
+ const fallbackToCacheOnReadError = config.fallbackToCacheOnReadError === true;
849
+ const onReadError = config.onReadError;
850
+ let renamesMigrated = isMemory || renameFromKeys.length === 0;
741
851
  if (expiration && expiration.ttlMs <= 0) {
742
852
  throw new Error("expiration.ttlMs must be greater than 0.");
743
853
  }
@@ -779,15 +889,18 @@ function createStorageCore(buildAdapter) {
779
889
  if (memoryExpiration) {
780
890
  const expiresAt = memoryExpiration.get(storageKey);
781
891
  if (expiresAt !== undefined && expiresAt <= Date.now()) {
892
+ const expiredRaw = memoryStore.get(storageKey);
782
893
  memoryExpiration.delete(storageKey);
783
894
  memoryStore.delete(storageKey);
784
895
  (0, _shared.notifyKeyListeners)(memoryListeners, storageKey);
896
+ emitKeyChange(config.scope, storageKey, typeof expiredRaw === "string" ? expiredRaw : undefined, undefined, "expire", "memory");
785
897
  onExpired?.(storageKey);
786
898
  return undefined;
787
899
  }
788
900
  }
789
901
  return memoryStore.get(storageKey);
790
902
  }
903
+ migrateRenamesIfNeeded();
791
904
  if (nonMemoryScope === _Storage.StorageScope.Disk) {
792
905
  const pending = pendingDiskWrites.get(storageKey);
793
906
  if (pending !== undefined) {
@@ -808,12 +921,27 @@ function createStorageCore(buildAdapter) {
808
921
  }
809
922
  }
810
923
  if (isBiometric) {
811
- return adapter.backend.getSecureBiometric(storageKey);
924
+ return readBackendRaw(() => adapter.backend.getSecureBiometric(storageKey));
812
925
  }
813
- const raw = adapter.backend.get(storageKey, config.scope);
926
+ const raw = readBackendRaw(() => adapter.backend.get(storageKey, config.scope));
814
927
  cacheRawValue(nonMemoryScope, storageKey, raw);
815
928
  return raw;
816
929
  };
930
+ const readBackendRaw = read => {
931
+ try {
932
+ return read();
933
+ } catch (error) {
934
+ onReadError?.(error);
935
+ if (fallbackToCacheOnReadError) {
936
+ const cached = getScopeRawCache(nonMemoryScope).get(storageKey);
937
+ if (cached !== undefined) {
938
+ return cached;
939
+ }
940
+ return typeof lastRaw === "string" ? lastRaw : undefined;
941
+ }
942
+ throw error;
943
+ }
944
+ };
817
945
  const writeStoredRaw = rawValue => {
818
946
  const oldValue = undefined;
819
947
  if (isBiometric) {
@@ -844,32 +972,73 @@ function createStorageCore(buildAdapter) {
844
972
  adapter.backend.set(storageKey, rawValue, config.scope);
845
973
  emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", adapter.changeSource);
846
974
  };
847
- const removeStoredRaw = () => {
975
+ const migrateRenamesIfNeeded = () => {
976
+ if (renamesMigrated) {
977
+ return;
978
+ }
979
+ try {
980
+ const hasCurrent = isBiometric ? adapter.backend.hasSecureBiometric(storageKey) : adapter.backend.has(storageKey, config.scope);
981
+ if (hasCurrent) {
982
+ for (const legacyKey of renameFromKeys) {
983
+ if (isBiometric) {
984
+ if (adapter.backend.hasSecureBiometric(legacyKey)) {
985
+ adapter.backend.deleteSecureBiometric(legacyKey);
986
+ }
987
+ } else if (adapter.backend.has(legacyKey, config.scope)) {
988
+ adapter.backend.remove(legacyKey, config.scope);
989
+ }
990
+ }
991
+ renamesMigrated = true;
992
+ return;
993
+ }
994
+ for (const legacyKey of renameFromKeys) {
995
+ const legacyRaw = isBiometric ? adapter.backend.getSecureBiometric(legacyKey) : adapter.backend.get(legacyKey, config.scope);
996
+ if (legacyRaw === undefined) {
997
+ continue;
998
+ }
999
+ writeStoredRaw(legacyRaw);
1000
+ if (isBiometric) {
1001
+ adapter.backend.deleteSecureBiometric(legacyKey);
1002
+ } else {
1003
+ adapter.backend.remove(legacyKey, config.scope);
1004
+ }
1005
+ break;
1006
+ }
1007
+ renamesMigrated = true;
1008
+ } catch (error) {
1009
+ if ((0, _shared.isKeychainLockedError)(error)) {
1010
+ onReadError?.(error);
1011
+ return;
1012
+ }
1013
+ throw error;
1014
+ }
1015
+ };
1016
+ const removeStoredRaw = (operation = "remove") => {
848
1017
  const oldValue = getEventRawValue(config.scope, storageKey);
849
1018
  if (isBiometric) {
850
1019
  adapter.backend.deleteSecureBiometric(storageKey);
851
- emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", adapter.changeSource);
1020
+ emitKeyChange(config.scope, storageKey, oldValue, undefined, operation, adapter.changeSource);
852
1021
  return;
853
1022
  }
854
1023
  cacheRawValue(nonMemoryScope, storageKey, undefined);
855
1024
  if (nonMemoryScope === _Storage.StorageScope.Disk) {
856
1025
  if (coalesceDiskWrites || diskWritesAsync) {
857
1026
  scheduleDiskWrite(storageKey, undefined);
858
- emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", adapter.changeSource);
1027
+ emitKeyChange(config.scope, storageKey, oldValue, undefined, operation, adapter.changeSource);
859
1028
  return;
860
1029
  }
861
1030
  clearPendingDiskWrite(storageKey);
862
1031
  }
863
1032
  if (coalesceSecureWrites) {
864
1033
  scheduleSecureWrite(storageKey, undefined, secureAccessControl ?? secureDefaultAccessControl);
865
- emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", adapter.changeSource);
1034
+ emitKeyChange(config.scope, storageKey, oldValue, undefined, operation, adapter.changeSource);
866
1035
  return;
867
1036
  }
868
1037
  if (nonMemoryScope === _Storage.StorageScope.Secure) {
869
1038
  clearPendingSecureWrite(storageKey);
870
1039
  }
871
1040
  adapter.backend.remove(storageKey, config.scope);
872
- emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", adapter.changeSource);
1041
+ emitKeyChange(config.scope, storageKey, oldValue, undefined, operation, adapter.changeSource);
873
1042
  };
874
1043
  const writeValueWithoutValidation = value => {
875
1044
  if (isMemory) {
@@ -923,7 +1092,7 @@ function createStorageCore(buildAdapter) {
923
1092
  if (lastExpiresAt > Date.now()) {
924
1093
  return lastValue;
925
1094
  }
926
- removeStoredRaw();
1095
+ removeStoredRaw("expire");
927
1096
  invalidateParsedCache();
928
1097
  onExpired?.(storageKey);
929
1098
  lastValue = ensureValidatedValue(defaultValue, false);
@@ -959,7 +1128,7 @@ function createStorageCore(buildAdapter) {
959
1128
  if ((0, _internal.isStoredEnvelope)(parsed)) {
960
1129
  envelopeExpiresAt = parsed.expiresAt;
961
1130
  if (parsed.expiresAt <= Date.now()) {
962
- removeStoredRaw();
1131
+ removeStoredRaw("expire");
963
1132
  invalidateParsedCache();
964
1133
  onExpired?.(storageKey);
965
1134
  lastValue = ensureValidatedValue(defaultValue, false);
@@ -1023,6 +1192,27 @@ function createStorageCore(buildAdapter) {
1023
1192
  removeStoredRaw();
1024
1193
  });
1025
1194
  };
1195
+ const merge = partial => {
1196
+ set(prev => {
1197
+ if (prev === null || typeof prev !== "object") {
1198
+ return partial;
1199
+ }
1200
+ return {
1201
+ ...prev,
1202
+ ...partial
1203
+ };
1204
+ });
1205
+ };
1206
+ const reset = () => {
1207
+ deleteItem();
1208
+ };
1209
+ const setOrDelete = value => {
1210
+ if (value === null || value === undefined) {
1211
+ deleteItem();
1212
+ return;
1213
+ }
1214
+ set(value);
1215
+ };
1026
1216
  const hasItem = () => measureOperation("item:has", config.scope, () => {
1027
1217
  if (isMemory) return memoryStore.has(storageKey);
1028
1218
  if (isBiometric) return adapter.backend.hasSecureBiometric(storageKey);
@@ -1075,6 +1265,9 @@ function createStorageCore(buildAdapter) {
1075
1265
  getWithVersion,
1076
1266
  set,
1077
1267
  setIfVersion,
1268
+ merge,
1269
+ reset,
1270
+ setOrDelete,
1078
1271
  delete: deleteItem,
1079
1272
  has: hasItem,
1080
1273
  subscribe,
@@ -1097,9 +1290,22 @@ function createStorageCore(buildAdapter) {
1097
1290
  ...(secureAccessControl !== undefined ? {
1098
1291
  _secureAccessControl: secureAccessControl
1099
1292
  } : {}),
1293
+ ...(config.group !== undefined ? {
1294
+ _group: config.group
1295
+ } : {}),
1100
1296
  scope: config.scope,
1101
1297
  key: storageKey
1102
1298
  };
1299
+ if (config.group !== undefined) {
1300
+ let groupSet = itemGroups.get(config.group);
1301
+ if (!groupSet) {
1302
+ groupSet = new Set();
1303
+ itemGroups.set(config.group, groupSet);
1304
+ }
1305
+ groupSet.add(storageItem);
1306
+ }
1307
+ const registryKey = `${config.scope}:${storageKey}`;
1308
+ registeredKeyCounts.set(registryKey, (registeredKeyCounts.get(registryKey) ?? 0) + 1);
1103
1309
  return storageItem;
1104
1310
  }
1105
1311
  function getBatch(items, scope) {
@@ -1484,14 +1690,104 @@ function createStorageCore(buildAdapter) {
1484
1690
  } : {}),
1485
1691
  ...(expirationConfig !== undefined ? {
1486
1692
  expiration: expirationConfig
1693
+ } : {}),
1694
+ ...(itemConfig.renameFrom !== undefined ? {
1695
+ renameFrom: itemConfig.renameFrom
1696
+ } : {}),
1697
+ ...(options?.group !== undefined ? {
1698
+ group: options.group
1699
+ } : {}),
1700
+ ...(options?.fallbackToCacheOnReadError !== undefined ? {
1701
+ fallbackToCacheOnReadError: options.fallbackToCacheOnReadError
1487
1702
  } : {})
1488
1703
  });
1489
1704
  }
1490
1705
  return result;
1491
1706
  }
1707
+ function memoryItem(config) {
1708
+ return createStorageItem({
1709
+ ...config,
1710
+ scope: _Storage.StorageScope.Memory
1711
+ });
1712
+ }
1713
+ function diskItem(config) {
1714
+ return createStorageItem({
1715
+ ...config,
1716
+ scope: _Storage.StorageScope.Disk
1717
+ });
1718
+ }
1719
+ function secureItem(config) {
1720
+ return createStorageItem({
1721
+ ...config,
1722
+ scope: _Storage.StorageScope.Secure
1723
+ });
1724
+ }
1725
+ function createSetItem(config) {
1726
+ const {
1727
+ defaultValue,
1728
+ ...rest
1729
+ } = config;
1730
+ const initial = {};
1731
+ if (defaultValue) {
1732
+ for (const id of defaultValue) {
1733
+ initial[id] = true;
1734
+ }
1735
+ }
1736
+ const item = createStorageItem({
1737
+ ...rest,
1738
+ defaultValue: initial
1739
+ });
1740
+ const has = id => item.get()[id] === true;
1741
+ const add = id => {
1742
+ if (item.get()[id] === true) {
1743
+ return;
1744
+ }
1745
+ item.merge({
1746
+ [id]: true
1747
+ });
1748
+ };
1749
+ const deleteId = id => {
1750
+ const current = item.get();
1751
+ if (current[id] !== true) {
1752
+ return;
1753
+ }
1754
+ const next = {
1755
+ ...current
1756
+ };
1757
+ delete next[id];
1758
+ item.set(next);
1759
+ };
1760
+ const toggle = id => {
1761
+ if (has(id)) {
1762
+ deleteId(id);
1763
+ return false;
1764
+ }
1765
+ add(id);
1766
+ return true;
1767
+ };
1768
+ return {
1769
+ get: item.get,
1770
+ has,
1771
+ add,
1772
+ delete: deleteId,
1773
+ toggle,
1774
+ values: () => Object.keys(item.get()),
1775
+ size: () => Object.keys(item.get()).length,
1776
+ clear: () => item.set({}),
1777
+ reset: item.reset,
1778
+ subscribe: item.subscribe,
1779
+ scope: item.scope,
1780
+ key: item.key,
1781
+ item
1782
+ };
1783
+ }
1492
1784
  return {
1493
1785
  storage,
1494
1786
  createStorageItem,
1787
+ memoryItem,
1788
+ diskItem,
1789
+ secureItem,
1790
+ createSetItem,
1495
1791
  getBatch,
1496
1792
  setBatch,
1497
1793
  removeBatch,