react-native-nitro-storage 0.5.3 → 0.5.5
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/.watchmanconfig +6 -0
- package/README.md +45 -5
- package/android/build.gradle +5 -5
- package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +12 -25
- package/app.plugin.js +114 -9
- package/docs/api-reference.md +39 -36
- package/docs/batch-transactions-migrations.md +1 -1
- package/docs/recipes.md +1 -1
- package/docs/secure-storage.md +15 -4
- package/docs/web-backends.md +5 -0
- package/lib/commonjs/index.js +129 -27
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +169 -32
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/indexeddb-backend.js +28 -0
- package/lib/commonjs/indexeddb-backend.js.map +1 -1
- package/lib/commonjs/web-storage-backend.js.map +1 -1
- package/lib/module/index.js +129 -27
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +169 -32
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/indexeddb-backend.js +28 -0
- package/lib/module/indexeddb-backend.js.map +1 -1
- package/lib/module/web-storage-backend.js.map +1 -1
- package/lib/typescript/index.d.ts +10 -3
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +10 -3
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/indexeddb-backend.d.ts.map +1 -1
- package/lib/typescript/web-storage-backend.d.ts +1 -0
- package/lib/typescript/web-storage-backend.d.ts.map +1 -1
- package/package.json +5 -3
- package/src/index.ts +197 -32
- package/src/index.web.ts +250 -37
- package/src/indexeddb-backend.ts +30 -0
- package/src/web-storage-backend.ts +1 -0
package/lib/module/index.web.js
CHANGED
|
@@ -17,6 +17,20 @@ function isUpdater(valueOrFn) {
|
|
|
17
17
|
function typedKeys(record) {
|
|
18
18
|
return Object.keys(record);
|
|
19
19
|
}
|
|
20
|
+
function assertEnumInteger(value, min, max, label) {
|
|
21
|
+
if (!Number.isFinite(value) || value < min || value > max) {
|
|
22
|
+
throw new Error(`NitroStorage: Invalid ${label}`);
|
|
23
|
+
}
|
|
24
|
+
if (value !== Math.trunc(value)) {
|
|
25
|
+
throw new Error(`NitroStorage: Invalid ${label}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function assertAccessControlLevel(level) {
|
|
29
|
+
assertEnumInteger(level, 0, 4, "access control level");
|
|
30
|
+
}
|
|
31
|
+
function assertBiometricLevel(level) {
|
|
32
|
+
assertEnumInteger(level, 0, 2, "biometric level");
|
|
33
|
+
}
|
|
20
34
|
const registeredMigrations = new Map();
|
|
21
35
|
const runMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : task => {
|
|
22
36
|
Promise.resolve().then(task);
|
|
@@ -40,6 +54,7 @@ let hasWarnedAboutWebBiometricFallback = false;
|
|
|
40
54
|
let hasWindowStorageEventSubscription = false;
|
|
41
55
|
let metricsObserver;
|
|
42
56
|
let eventObserver;
|
|
57
|
+
let eventObserverRedactSecureValues = true;
|
|
43
58
|
const metricsCounters = new Map();
|
|
44
59
|
const storageEvents = new StorageEventRegistry();
|
|
45
60
|
function recordMetric(operation, scope, durationMs, keysCount = 1) {
|
|
@@ -235,6 +250,16 @@ function resetBackendChangeSubscription(scope) {
|
|
|
235
250
|
externalSyncUnsubscribers.get(scope)?.();
|
|
236
251
|
externalSyncUnsubscribers.delete(scope);
|
|
237
252
|
}
|
|
253
|
+
function closeWebBackend(scope, backend) {
|
|
254
|
+
if (!backend?.close) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
backend.close();
|
|
259
|
+
} catch (error) {
|
|
260
|
+
throw createWebStorageError(scope, "close", error, backend);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
238
263
|
function ensureExternalSyncSubscriptions() {
|
|
239
264
|
if (!hasWindowStorageEventSubscription && typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
240
265
|
window.addEventListener("storage", handleWebStorageEvent);
|
|
@@ -315,10 +340,42 @@ function createKeyChange(scope, key, oldValue, newValue, operation, source) {
|
|
|
315
340
|
function hasStorageChangeObservers(scope) {
|
|
316
341
|
return storageEvents.hasListeners(scope) || eventObserver !== undefined;
|
|
317
342
|
}
|
|
343
|
+
function shouldReadPreviousEventValues(scope) {
|
|
344
|
+
if (storageEvents.hasListeners(scope)) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
if (!eventObserver) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
return scope !== StorageScope.Secure || !eventObserverRedactSecureValues;
|
|
351
|
+
}
|
|
352
|
+
const SECURE_EVENT_REDACTED_VALUE = "[secure]";
|
|
353
|
+
function redactSecureKeyChange(event) {
|
|
354
|
+
if (event.scope !== StorageScope.Secure) {
|
|
355
|
+
return event;
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
...event,
|
|
359
|
+
oldValue: event.oldValue === undefined ? undefined : SECURE_EVENT_REDACTED_VALUE,
|
|
360
|
+
newValue: event.newValue === undefined ? undefined : SECURE_EVENT_REDACTED_VALUE
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function eventForGlobalObserver(event) {
|
|
364
|
+
if (!eventObserverRedactSecureValues || event.scope !== StorageScope.Secure) {
|
|
365
|
+
return event;
|
|
366
|
+
}
|
|
367
|
+
if (event.type === "key") {
|
|
368
|
+
return redactSecureKeyChange(event);
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
...event,
|
|
372
|
+
changes: event.changes.map(redactSecureKeyChange)
|
|
373
|
+
};
|
|
374
|
+
}
|
|
318
375
|
function emitKeyChange(scope, key, oldValue, newValue, operation, source) {
|
|
319
376
|
const event = createKeyChange(scope, key, oldValue, newValue, operation, source);
|
|
320
377
|
storageEvents.emitKey(event);
|
|
321
|
-
eventObserver?.(event);
|
|
378
|
+
eventObserver?.(eventForGlobalObserver(event));
|
|
322
379
|
}
|
|
323
380
|
function emitBatchChange(scope, operation, source, changes) {
|
|
324
381
|
if (changes.length === 0) {
|
|
@@ -332,7 +389,7 @@ function emitBatchChange(scope, operation, source, changes) {
|
|
|
332
389
|
changes
|
|
333
390
|
};
|
|
334
391
|
storageEvents.emitBatch(event);
|
|
335
|
-
eventObserver?.(event);
|
|
392
|
+
eventObserver?.(eventForGlobalObserver(event));
|
|
336
393
|
}
|
|
337
394
|
function readPendingSecureWrite(key) {
|
|
338
395
|
return pendingSecureWrites.get(key)?.value;
|
|
@@ -502,6 +559,9 @@ const WebStorage = {
|
|
|
502
559
|
if (scope !== StorageScope.Disk && scope !== StorageScope.Secure) {
|
|
503
560
|
return;
|
|
504
561
|
}
|
|
562
|
+
if (keys.length !== values.length) {
|
|
563
|
+
throw new Error("NitroStorage: Keys and values size mismatch in setBatch");
|
|
564
|
+
}
|
|
505
565
|
const entries = [];
|
|
506
566
|
keys.forEach((key, index) => {
|
|
507
567
|
const value = values[index];
|
|
@@ -520,7 +580,7 @@ const WebStorage = {
|
|
|
520
580
|
});
|
|
521
581
|
});
|
|
522
582
|
const keyIndex = ensureWebScopeKeyIndex(scope);
|
|
523
|
-
|
|
583
|
+
entries.forEach(([storageKey]) => keyIndex.add(scope === StorageScope.Secure ? storageKey.slice(SECURE_WEB_PREFIX.length) : storageKey));
|
|
524
584
|
const listeners = getScopedListeners(scope);
|
|
525
585
|
keys.forEach(key => notifyKeyListeners(listeners, key));
|
|
526
586
|
},
|
|
@@ -606,13 +666,25 @@ const WebStorage = {
|
|
|
606
666
|
}
|
|
607
667
|
return 0;
|
|
608
668
|
},
|
|
609
|
-
setSecureAccessControl:
|
|
669
|
+
setSecureAccessControl: level => {
|
|
670
|
+
assertAccessControlLevel(level);
|
|
671
|
+
},
|
|
610
672
|
setSecureWritesAsync: _enabled => {},
|
|
611
673
|
setKeychainAccessGroup: () => {},
|
|
612
674
|
setSecureBiometric: (key, value) => {
|
|
613
675
|
WebStorage.setSecureBiometricWithLevel(key, value, BiometricLevel.BiometryOnly);
|
|
614
676
|
},
|
|
615
|
-
setSecureBiometricWithLevel: (key, value,
|
|
677
|
+
setSecureBiometricWithLevel: (key, value, level) => {
|
|
678
|
+
assertBiometricLevel(level);
|
|
679
|
+
if (level === BiometricLevel.None) {
|
|
680
|
+
withWebBackendOperation(StorageScope.Secure, "setSecure", backend => {
|
|
681
|
+
backend.removeItem(toBiometricStorageKey(key));
|
|
682
|
+
backend.setItem(toSecureStorageKey(key), value);
|
|
683
|
+
});
|
|
684
|
+
ensureWebScopeKeyIndex(StorageScope.Secure).add(key);
|
|
685
|
+
notifyKeyListeners(getScopedListeners(StorageScope.Secure), key);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
616
688
|
if (typeof __DEV__ !== "undefined" && __DEV__ && !hasWarnedAboutWebBiometricFallback) {
|
|
617
689
|
hasWarnedAboutWebBiometricFallback = true;
|
|
618
690
|
console.warn("[NitroStorage] Biometric storage is not supported on web. Using localStorage.");
|
|
@@ -765,15 +837,16 @@ export const storage = {
|
|
|
765
837
|
subscribeNamespace: (namespace, scope, listener) => {
|
|
766
838
|
return storage.subscribePrefix(scope, prefixKey(namespace, ""), listener);
|
|
767
839
|
},
|
|
768
|
-
setEventObserver: observer => {
|
|
840
|
+
setEventObserver: (observer, options = {}) => {
|
|
769
841
|
eventObserver = observer;
|
|
842
|
+
eventObserverRedactSecureValues = options.redactSecureValues !== false;
|
|
770
843
|
if (observer) {
|
|
771
844
|
ensureExternalSyncSubscriptions();
|
|
772
845
|
}
|
|
773
846
|
},
|
|
774
847
|
clear: scope => {
|
|
775
848
|
measureOperation("storage:clear", scope, () => {
|
|
776
|
-
const previousValues =
|
|
849
|
+
const previousValues = shouldReadPreviousEventValues(scope) ? storage.getAll(scope) : {};
|
|
777
850
|
if (scope === StorageScope.Memory) {
|
|
778
851
|
memoryStore.clear();
|
|
779
852
|
notifyAllListeners(memoryListeners);
|
|
@@ -823,7 +896,7 @@ export const storage = {
|
|
|
823
896
|
return;
|
|
824
897
|
}
|
|
825
898
|
const keyPrefix = prefixKey(namespace, "");
|
|
826
|
-
const previousValues =
|
|
899
|
+
const previousValues = shouldReadPreviousEventValues(scope) ? storage.getByPrefix(keyPrefix, scope) : {};
|
|
827
900
|
if (scope === StorageScope.Disk) {
|
|
828
901
|
flushDiskWrites();
|
|
829
902
|
}
|
|
@@ -946,9 +1019,15 @@ export const storage = {
|
|
|
946
1019
|
return result;
|
|
947
1020
|
});
|
|
948
1021
|
},
|
|
949
|
-
export: scope => {
|
|
1022
|
+
export: (scope, options = {}) => {
|
|
1023
|
+
if (scope === StorageScope.Secure && options.includeSecureValues !== true) {
|
|
1024
|
+
throw new Error("NitroStorage: exporting Secure scope exposes raw secret values. Pass { includeSecureValues: true } or use exportSecureUnsafe().");
|
|
1025
|
+
}
|
|
950
1026
|
return measureOperation("storage:export", scope, () => storage.getAll(scope));
|
|
951
1027
|
},
|
|
1028
|
+
exportSecureUnsafe: () => {
|
|
1029
|
+
return measureOperation("storage:exportSecureUnsafe", StorageScope.Secure, () => storage.getAll(StorageScope.Secure));
|
|
1030
|
+
},
|
|
952
1031
|
size: scope => {
|
|
953
1032
|
return measureOperation("storage:size", scope, () => {
|
|
954
1033
|
assertValidScope(scope);
|
|
@@ -963,6 +1042,7 @@ export const storage = {
|
|
|
963
1042
|
});
|
|
964
1043
|
},
|
|
965
1044
|
setAccessControl: level => {
|
|
1045
|
+
assertAccessControlLevel(level);
|
|
966
1046
|
secureDefaultAccessControl = level;
|
|
967
1047
|
recordMetric("storage:setAccessControl", StorageScope.Secure, 0);
|
|
968
1048
|
},
|
|
@@ -1115,23 +1195,33 @@ export const storage = {
|
|
|
1115
1195
|
}
|
|
1116
1196
|
};
|
|
1117
1197
|
export function setWebSecureStorageBackend(backend) {
|
|
1198
|
+
const previousBackend = webSecureStorageBackend;
|
|
1199
|
+
const nextBackend = backend ?? createDefaultSecureBackend();
|
|
1118
1200
|
pendingSecureWrites.clear();
|
|
1119
|
-
webSecureStorageBackend = backend ?? createDefaultSecureBackend();
|
|
1120
1201
|
resetBackendChangeSubscription(StorageScope.Secure);
|
|
1202
|
+
webSecureStorageBackend = nextBackend;
|
|
1121
1203
|
hydratedWebScopeKeyIndex.delete(StorageScope.Secure);
|
|
1122
1204
|
clearScopeRawCache(StorageScope.Secure);
|
|
1123
1205
|
ensureExternalSyncSubscriptions();
|
|
1206
|
+
if (previousBackend !== nextBackend) {
|
|
1207
|
+
closeWebBackend(StorageScope.Secure, previousBackend);
|
|
1208
|
+
}
|
|
1124
1209
|
}
|
|
1125
1210
|
export function getWebSecureStorageBackend() {
|
|
1126
1211
|
return webSecureStorageBackend;
|
|
1127
1212
|
}
|
|
1128
1213
|
export function setWebDiskStorageBackend(backend) {
|
|
1214
|
+
const previousBackend = webDiskStorageBackend;
|
|
1215
|
+
const nextBackend = backend ?? createDefaultDiskBackend();
|
|
1129
1216
|
pendingDiskWrites.clear();
|
|
1130
|
-
webDiskStorageBackend = backend ?? createDefaultDiskBackend();
|
|
1131
1217
|
resetBackendChangeSubscription(StorageScope.Disk);
|
|
1218
|
+
webDiskStorageBackend = nextBackend;
|
|
1132
1219
|
hydratedWebScopeKeyIndex.delete(StorageScope.Disk);
|
|
1133
1220
|
clearScopeRawCache(StorageScope.Disk);
|
|
1134
1221
|
ensureExternalSyncSubscriptions();
|
|
1222
|
+
if (previousBackend !== nextBackend) {
|
|
1223
|
+
closeWebBackend(StorageScope.Disk, previousBackend);
|
|
1224
|
+
}
|
|
1135
1225
|
}
|
|
1136
1226
|
export function getWebDiskStorageBackend() {
|
|
1137
1227
|
return webDiskStorageBackend;
|
|
@@ -1184,6 +1274,12 @@ export function createStorageItem(config) {
|
|
|
1184
1274
|
if (expiration && expiration.ttlMs <= 0) {
|
|
1185
1275
|
throw new Error("expiration.ttlMs must be greater than 0.");
|
|
1186
1276
|
}
|
|
1277
|
+
if (config.scope === StorageScope.Secure) {
|
|
1278
|
+
assertBiometricLevel(resolvedBiometricLevel);
|
|
1279
|
+
if (secureAccessControl !== undefined) {
|
|
1280
|
+
assertAccessControlLevel(secureAccessControl);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1187
1283
|
const listeners = new Set();
|
|
1188
1284
|
let unsubscribe = null;
|
|
1189
1285
|
let lastRaw = undefined;
|
|
@@ -1523,6 +1619,7 @@ export function createStorageItem(config) {
|
|
|
1523
1619
|
_hasExpiration: expiration !== undefined,
|
|
1524
1620
|
_readCacheEnabled: readCache,
|
|
1525
1621
|
_isBiometric: isBiometric,
|
|
1622
|
+
_biometricLevel: resolvedBiometricLevel,
|
|
1526
1623
|
_defaultValue: defaultValue,
|
|
1527
1624
|
...(secureAccessControl !== undefined ? {
|
|
1528
1625
|
_secureAccessControl: secureAccessControl
|
|
@@ -1654,7 +1751,7 @@ export function setBatch(items, scope) {
|
|
|
1654
1751
|
const keys = secureEntries.map(({
|
|
1655
1752
|
item
|
|
1656
1753
|
}) => item.key);
|
|
1657
|
-
const oldValues =
|
|
1754
|
+
const oldValues = shouldReadPreviousEventValues(scope) ? WebStorage.getBatch(keys, scope) : [];
|
|
1658
1755
|
const groupedByAccessControl = new Map();
|
|
1659
1756
|
secureEntries.forEach(({
|
|
1660
1757
|
item,
|
|
@@ -1697,7 +1794,7 @@ export function setBatch(items, scope) {
|
|
|
1697
1794
|
}
|
|
1698
1795
|
const keys = items.map(entry => entry.item.key);
|
|
1699
1796
|
const values = items.map(entry => entry.item.serialize(entry.value));
|
|
1700
|
-
const oldValues =
|
|
1797
|
+
const oldValues = shouldReadPreviousEventValues(scope) ? WebStorage.getBatch(keys, scope) : [];
|
|
1701
1798
|
WebStorage.setBatch(keys, values, scope);
|
|
1702
1799
|
keys.forEach((key, index) => cacheRawValue(scope, key, values[index]));
|
|
1703
1800
|
emitBatchChange(scope, "setBatch", "web", keys.map((key, index) => createKeyChange(scope, key, oldValues[index], values[index], "setBatch", "web")));
|
|
@@ -1719,7 +1816,7 @@ export function removeBatch(items, scope) {
|
|
|
1719
1816
|
if (scope === StorageScope.Secure) {
|
|
1720
1817
|
flushSecureWrites();
|
|
1721
1818
|
}
|
|
1722
|
-
const oldValues =
|
|
1819
|
+
const oldValues = shouldReadPreviousEventValues(scope) ? WebStorage.getBatch(keys, scope) : [];
|
|
1723
1820
|
WebStorage.removeBatch(keys, scope);
|
|
1724
1821
|
keys.forEach(key => cacheRawValue(scope, key, undefined));
|
|
1725
1822
|
emitBatchChange(scope, "removeBatch", "web", keys.map((key, index) => createKeyChange(scope, key, oldValues[index], undefined, "removeBatch", "web")));
|
|
@@ -1771,14 +1868,32 @@ export function runTransaction(scope, transaction) {
|
|
|
1771
1868
|
}
|
|
1772
1869
|
const NOT_SET = Symbol();
|
|
1773
1870
|
const rollback = new Map();
|
|
1774
|
-
const rememberRollback = key => {
|
|
1871
|
+
const rememberRollback = (key, item) => {
|
|
1775
1872
|
if (rollback.has(key)) {
|
|
1776
1873
|
return;
|
|
1777
1874
|
}
|
|
1778
1875
|
if (scope === StorageScope.Memory) {
|
|
1779
|
-
rollback.set(key,
|
|
1876
|
+
rollback.set(key, {
|
|
1877
|
+
kind: "memory",
|
|
1878
|
+
value: memoryStore.has(key) ? memoryStore.get(key) : NOT_SET
|
|
1879
|
+
});
|
|
1780
1880
|
} else {
|
|
1781
|
-
|
|
1881
|
+
const internal = item ? item : undefined;
|
|
1882
|
+
if (scope === StorageScope.Secure && internal?._isBiometric === true) {
|
|
1883
|
+
rollback.set(key, {
|
|
1884
|
+
kind: "biometric",
|
|
1885
|
+
value: WebStorage.getSecureBiometric(key),
|
|
1886
|
+
level: internal._biometricLevel
|
|
1887
|
+
});
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
rollback.set(key, {
|
|
1891
|
+
kind: "raw",
|
|
1892
|
+
value: getRawValue(key, scope),
|
|
1893
|
+
...(scope === StorageScope.Secure && internal?._secureAccessControl !== undefined ? {
|
|
1894
|
+
accessControl: internal._secureAccessControl
|
|
1895
|
+
} : {})
|
|
1896
|
+
});
|
|
1782
1897
|
}
|
|
1783
1898
|
};
|
|
1784
1899
|
const tx = {
|
|
@@ -1798,12 +1913,12 @@ export function runTransaction(scope, transaction) {
|
|
|
1798
1913
|
},
|
|
1799
1914
|
setItem: (item, value) => {
|
|
1800
1915
|
assertBatchScope([item], scope);
|
|
1801
|
-
rememberRollback(item.key);
|
|
1916
|
+
rememberRollback(item.key, item);
|
|
1802
1917
|
item.set(value);
|
|
1803
1918
|
},
|
|
1804
1919
|
removeItem: item => {
|
|
1805
1920
|
assertBatchScope([item], scope);
|
|
1806
|
-
rememberRollback(item.key);
|
|
1921
|
+
rememberRollback(item.key, item);
|
|
1807
1922
|
item.delete();
|
|
1808
1923
|
}
|
|
1809
1924
|
};
|
|
@@ -1812,24 +1927,43 @@ export function runTransaction(scope, transaction) {
|
|
|
1812
1927
|
} catch (error) {
|
|
1813
1928
|
const rollbackEntries = Array.from(rollback.entries()).reverse();
|
|
1814
1929
|
if (scope === StorageScope.Memory) {
|
|
1815
|
-
rollbackEntries.forEach(([key,
|
|
1816
|
-
if (
|
|
1930
|
+
rollbackEntries.forEach(([key, record]) => {
|
|
1931
|
+
if (record.value === NOT_SET) {
|
|
1817
1932
|
memoryStore.delete(key);
|
|
1818
1933
|
} else {
|
|
1819
|
-
memoryStore.set(key,
|
|
1934
|
+
memoryStore.set(key, record.value);
|
|
1820
1935
|
}
|
|
1821
1936
|
notifyKeyListeners(memoryListeners, key);
|
|
1822
1937
|
});
|
|
1823
1938
|
} else {
|
|
1824
|
-
const
|
|
1825
|
-
const valuesToSet = [];
|
|
1939
|
+
const groupedKeysToSet = new Map();
|
|
1826
1940
|
const keysToRemove = [];
|
|
1827
|
-
rollbackEntries.forEach(([key,
|
|
1828
|
-
if (
|
|
1941
|
+
rollbackEntries.forEach(([key, record]) => {
|
|
1942
|
+
if (record.kind === "biometric") {
|
|
1943
|
+
if (record.value === undefined) {
|
|
1944
|
+
WebStorage.deleteSecureBiometric(key);
|
|
1945
|
+
} else {
|
|
1946
|
+
WebStorage.setSecureBiometricWithLevel(key, record.value, record.level);
|
|
1947
|
+
}
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1950
|
+
if (record.kind !== "raw") {
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
if (record.value === undefined) {
|
|
1829
1954
|
keysToRemove.push(key);
|
|
1830
1955
|
} else {
|
|
1831
|
-
|
|
1832
|
-
|
|
1956
|
+
const accessControl = record.accessControl ?? secureDefaultAccessControl;
|
|
1957
|
+
const existingGroup = groupedKeysToSet.get(accessControl);
|
|
1958
|
+
const group = existingGroup ?? {
|
|
1959
|
+
keys: [],
|
|
1960
|
+
values: []
|
|
1961
|
+
};
|
|
1962
|
+
group.keys.push(key);
|
|
1963
|
+
group.values.push(record.value);
|
|
1964
|
+
if (!existingGroup) {
|
|
1965
|
+
groupedKeysToSet.set(accessControl, group);
|
|
1966
|
+
}
|
|
1833
1967
|
}
|
|
1834
1968
|
});
|
|
1835
1969
|
if (scope === StorageScope.Disk) {
|
|
@@ -1838,10 +1972,13 @@ export function runTransaction(scope, transaction) {
|
|
|
1838
1972
|
if (scope === StorageScope.Secure) {
|
|
1839
1973
|
flushSecureWrites();
|
|
1840
1974
|
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1975
|
+
groupedKeysToSet.forEach((group, accessControl) => {
|
|
1976
|
+
if (scope === StorageScope.Secure) {
|
|
1977
|
+
WebStorage.setSecureAccessControl(accessControl);
|
|
1978
|
+
}
|
|
1979
|
+
WebStorage.setBatch(group.keys, group.values, scope);
|
|
1980
|
+
group.keys.forEach((key, index) => cacheRawValue(scope, key, group.values[index]));
|
|
1981
|
+
});
|
|
1845
1982
|
if (keysToRemove.length > 0) {
|
|
1846
1983
|
WebStorage.removeBatch(keysToRemove, scope);
|
|
1847
1984
|
keysToRemove.forEach(key => cacheRawValue(scope, key, undefined));
|